| // 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.h" | |
| #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); | |
| } |