blob: 17fb7c7e208a419d2f282dfa8e12ca43fd8ac0b0 [file] [log] [blame]
// Copyright (c) 2010 The WebM project authors. All Rights Reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree. An additional intellectual property rights grant can be found
// in the file PATENTS. All contributing project authors may
// be found in the AUTHORS file in the root of the source tree.
#include <strmif.h>
#include "webmmuxebmlio.hpp"
#include <cassert>
#include <limits>
#include <malloc.h> //_malloca
EbmlIO::File::File() : m_pStream(0)
{
}
EbmlIO::File::~File()
{
assert(m_pStream == 0);
}
void EbmlIO::File::SetStream(IStream* p)
{
assert((m_pStream == 0) || (p == 0));
m_pStream = p;
}
IStream* EbmlIO::File::GetStream() const
{
return m_pStream;
}
HRESULT EbmlIO::File::SetSize(__int64 size)
{
return EbmlIO::SetSize(m_pStream, size);
}
__int64 EbmlIO::File::SetPosition(
__int64 pos,
STREAM_SEEK origin)
{
return EbmlIO::SetPosition(m_pStream, pos, origin);
}
__int64 EbmlIO::File::GetPosition() const
{
File* const const_file = const_cast<File*>(this);
return const_file->SetPosition(0, STREAM_SEEK_CUR);
}
void EbmlIO::File::Write(const void* buf, ULONG cb)
{
EbmlIO::Write(m_pStream, buf, cb);
}
void EbmlIO::File::Serialize8UInt(__int64 val)
{
EbmlIO::Serialize(m_pStream, &val, 8);
}
void EbmlIO::File::Serialize4UInt(ULONG val)
{
EbmlIO::Serialize(m_pStream, &val, 4);
}
void EbmlIO::File::Serialize2UInt(USHORT val)
{
EbmlIO::Serialize(m_pStream, &val, 2);
}
void EbmlIO::File::Serialize1UInt(BYTE val)
{
EbmlIO::Serialize(m_pStream, &val, 1);
}
BYTE EbmlIO::File::GetSerializeUIntSize(__int64 val)
{
assert(val >= 0);
for (int size = 1; size < 8; ++size)
{
const LONGLONG max = 1LL << (8 * size);
if (val < max)
return static_cast<BYTE>(size);
++size;
}
return 8;
}
void EbmlIO::File::SerializeUInt(__int64 val, BYTE size)
{
EbmlIO::Serialize(m_pStream, &val, size);
}
void EbmlIO::File::Serialize2SInt(SHORT val)
{
EbmlIO::Serialize(m_pStream, &val, 2);
}
void EbmlIO::File::Serialize4Float(float val)
{
EbmlIO::Serialize(m_pStream, &val, 4);
}
void EbmlIO::File::WriteID4(ULONG id)
{
EbmlIO::WriteID4(m_pStream, id);
}
void EbmlIO::File::WriteID3(ULONG id)
{
EbmlIO::WriteID3(m_pStream, id);
}
void EbmlIO::File::WriteID2(USHORT id)
{
EbmlIO::WriteID2(m_pStream, id);
}
void EbmlIO::File::WriteID1(BYTE id)
{
EbmlIO::WriteID1(m_pStream, id);
}
ULONG EbmlIO::File::ReadID4()
{
return EbmlIO::ReadID4(m_pStream);
}
void EbmlIO::File::Write8UInt(__int64 val)
{
EbmlIO::Write8UInt(m_pStream, val);
}
void EbmlIO::File::Write4UInt(ULONG val)
{
EbmlIO::Write4UInt(m_pStream, val);
}
void EbmlIO::File::Write2UInt(USHORT val)
{
EbmlIO::Write2UInt(m_pStream, val);
}
void EbmlIO::File::Write1UInt(BYTE val)
{
EbmlIO::Write1UInt(m_pStream, val);
}
void EbmlIO::File::WriteUInt(__int64 val, ULONG size)
{
return EbmlIO::WriteUInt(m_pStream, val, size);
}
void EbmlIO::File::Write1String(const char* str)
{
EbmlIO::Write1String(m_pStream, str);
}
//void EbmlIO::File::Write1String(const char* str, size_t len)
//{
// EbmlIO::Write1String(m_pStream, str, len);
//}
void EbmlIO::File::Write1UTF8(const wchar_t* str)
{
EbmlIO::Write1UTF8(m_pStream, str);
}
HRESULT EbmlIO::SetSize(IStream* pStream, __int64 size_)
{
assert(pStream);
assert(size_ >= 0);
ULARGE_INTEGER size;
size.QuadPart = size_;
return pStream->SetSize(size);
}
__int64 EbmlIO::SetPosition(
IStream* pStream,
__int64 move_,
STREAM_SEEK origin)
{
assert(pStream);
LARGE_INTEGER move;
move.QuadPart = move_;
ULARGE_INTEGER newpos;
const HRESULT hr = pStream->Seek(move, origin, &newpos);
assert(SUCCEEDED(hr));
hr;
return newpos.QuadPart;
}
void EbmlIO::Write(
ISequentialStream* pStream,
const void* buf,
ULONG cb)
{
assert(pStream);
ULONG cbWritten;
const HRESULT hr = pStream->Write(buf, cb, &cbWritten);
assert(SUCCEEDED(hr));
assert(cbWritten == cb);
hr;
}
void EbmlIO::Write8UInt(ISequentialStream* pStream, __int64 val)
{
assert(val <= 0x00FFFFFFFFFFFFFE); //0000 000x 1111 1111 ...
val |= 0x0100000000000000; //always write 8 bytes
Serialize(pStream, &val, 8);
}
void EbmlIO::Write4UInt(ISequentialStream* pStream, ULONG val)
{
assert(val <= 0x0FFFFFFE); //000x 1111 1111 ...
val |= 0x10000000; //always write 4 bytes
Serialize(pStream, &val, 4);
}
void EbmlIO::Write2UInt(ISequentialStream* pStream, USHORT val)
{
assert(val <= 0x3FFE); //0x11 1111 1111 1110
val |= 0x4000; //always write 2 bytes
Serialize(pStream, &val, 2);
}
void EbmlIO::Write1UInt(ISequentialStream* pStream, BYTE val)
{
assert(val <= 0x7E); //x111 1110
val |= 0x80; //always write 1 byte
Serialize(pStream, &val, 1);
}
void EbmlIO::WriteUInt(
ISequentialStream* pStream,
__int64 val,
ULONG size)
{
assert(pStream);
assert(val >= 0);
assert(size <= 8);
//size = 8
//assert(val <= 0x00FFFFFFFFFFFFFE); //0000 000x 1111 1111 ...
//val |= 0x0100000000000000; //always write 8 bytes
//(1 << 56) - 1
//max = (1 << (n * 7)) - 2
//size = 4
//assert(val <= 0x0FFFFFFE); //000x 1111 1111 ...
//val |= 0x10000000; //always write 4 bytes
//(1 << 28) - 1
//max = (1 << (n * 7)) - 2
//size = 2
//assert(val <= 0x3FFE); //0x11 1111 1111 1110
//val |= 0x4000; //always write 2 bytes
//(1 << 14) - 1
//max = (1 << (n * 7)) - 2
//size = 1
//assert(val <= 0x7E); //x111 1110
//val |= 0x80; //always write 1 byte
//(1 << 7) - 1
//max = (1 << (n * 7)) - 2
if (size > 0)
{
const LONGLONG bit = 1LL << (size * 7);
assert(val <= (bit - 2));
val |= bit;
Serialize(pStream, &val, size);
return;
}
size = 1;
LONGLONG bit;
for (;;)
{
bit = 1LL << (size * 7);
const LONGLONG max = bit - 2;
if (val <= max)
break;
++size;
}
assert(size <= 8);
val |= bit;
Serialize(pStream, &val, size);
}
void EbmlIO::WriteID4(ISequentialStream* pStream, ULONG id)
{
assert(pStream);
assert(id & 0x10000000); //always write 4 bytes
assert(id <= 0x1FFFFFFE);
Serialize(pStream, &id, 4);
}
ULONG EbmlIO::ReadID4(ISequentialStream* pStream)
{
assert(pStream);
ULONG id;
BYTE* const p = reinterpret_cast<BYTE*>(&id);
BYTE* q = p + 4;
for (;;)
{
ULONG cb;
const HRESULT hr = pStream->Read(--q, 1, &cb);
assert(hr == S_OK);
assert(cb == 1);
hr;
if (q == p)
break;
}
assert(id & 0x10000000);
assert(id <= 0x1FFFFFFE);
return id;
}
void EbmlIO::WriteID3(ISequentialStream* pStream, ULONG id)
{
assert(pStream);
assert(id & 0x200000); //always write 3 bytes
assert(id <= 0x3FFFFE);
Serialize(pStream, &id, 3);
}
void EbmlIO::WriteID2(ISequentialStream* pStream, USHORT id)
{
assert(pStream);
assert(id & 0x4000); //always write 2 bytes
assert(id <= 0x7FFE);
Serialize(pStream, &id, 2);
}
void EbmlIO::WriteID1(ISequentialStream* pStream, BYTE id)
{
assert(pStream);
assert(id & 0x80); //always write 1 byte
assert(id <= 0xFE);
Serialize(pStream, &id, 1);
}
void EbmlIO::Write1String(
ISequentialStream* pStream,
const char* str)
{
assert(pStream);
assert(str);
const size_t size_ = strlen(str);
assert(size_ <= 255);
const BYTE size = static_cast<BYTE>(size_);
Write1UInt(pStream, size);
Write(pStream, str, size);
}
#if 0
void EbmlIO::Write1String(
ISequentialStream* pStream,
const char* str,
size_t buflen)
{
assert(pStream);
assert(str);
const size_t strlen_ = strlen(str);
const size_t size_ = (strlen_ >= buflen) ? strlen_ : buflen;
assert(size_ <= 255);
Write1UInt(pStream, static_cast<BYTE>(size_));
Write(pStream, str, static_cast<ULONG>(strlen_));
if (strlen_ >= buflen)
return;
const BYTE b = 0;
const size_t count = buflen - strlen_;
for (size_t i = 0; i < count; ++i)
Write(pStream, &b, 1);
}
#endif
void EbmlIO::Write1UTF8(
ISequentialStream* pStream,
const wchar_t* str)
{
assert(pStream);
assert(str);
const int cb = WideCharToMultiByte(
CP_UTF8,
0, //flags (must be 0 for UTF-8 conversion)
str,
-1, //assume NUL-terminated, and calculate length
0, //buf
0, //count
0,
0);
assert(cb > 0);
char* const buf = (char*)_malloca(cb);
const int n = WideCharToMultiByte(
CP_UTF8,
0,
str,
-1,
buf,
cb,
0,
0);
assert(n == cb);
assert(n > 0);
const size_t nn = n - 1;
assert(nn <= 255);
#ifdef _DEBUG
const size_t strlen_ = strlen(buf);
assert(strlen_ == nn);
assert(buf[nn] == '\0');
#endif
const BYTE size = static_cast<BYTE>(nn);
Write1UInt(pStream, size);
Write(pStream, buf, size);
}
void EbmlIO::Serialize(
ISequentialStream* pStream,
const BYTE* p,
const BYTE* q)
{
assert(pStream);
assert(p);
assert(q);
assert(q >= p);
while (q != p)
{
--q;
ULONG cbWritten;
const HRESULT hr = pStream->Write(q, 1, &cbWritten);
assert(SUCCEEDED(hr));
assert(cbWritten == 1);
hr;
}
}
void EbmlIO::Serialize(
ISequentialStream* pStream,
const void* buf,
ULONG len)
{
assert(buf);
const BYTE* const p = static_cast<const BYTE*>(buf);
const BYTE* const q = p + len;
Serialize(pStream, p, q);
}