diff --git a/mkvmuxer.cpp b/mkvmuxer.cpp index 354025a..d53b20b 100644 --- a/mkvmuxer.cpp +++ b/mkvmuxer.cpp @@ -77,7 +77,8 @@ Frame::~Frame() { } bool Frame::Init(const uint8* frame, uint64 length) { - uint8* const data = new (std::nothrow) uint8[static_cast(length)]; + uint8* const data = + new (std::nothrow) uint8[static_cast(length)]; // NOLINT if (!data) return false; @@ -198,7 +199,8 @@ bool Cues::AddCue(CuePoint* cue) { if (new_capacity < 1) return false; - CuePoint** const cues = new (std::nothrow) CuePoint*[new_capacity]; + CuePoint** const cues = + new (std::nothrow) CuePoint*[new_capacity]; // NOLINT if (!cues) return false; @@ -265,6 +267,45 @@ bool Cues::Write(IMkvWriter* writer) const { return true; } +/////////////////////////////////////////////////////////////// +// +// ContentEncAESSettings Class + +ContentEncAESSettings::ContentEncAESSettings() : cipher_mode_(kCTR) {} + +uint64 ContentEncAESSettings::Size() const { + const uint64 payload = PayloadSize(); + const uint64 size = + EbmlMasterElementSize(kMkvContentEncAESSettings, payload) + payload; + return size; +} + +bool ContentEncAESSettings::Write(IMkvWriter* writer) const { + const uint64 payload = PayloadSize(); + + if (!WriteEbmlMasterElement(writer, kMkvContentEncAESSettings, payload)) + return false; + + const int64 payload_position = writer->Position(); + if (payload_position < 0) + return false; + + if (!WriteEbmlElement(writer, kMkvAESSettingsCipherMode, cipher_mode_)) + return false; + + const int64 stop_position = writer->Position(); + if (stop_position < 0 || + stop_position - payload_position != static_cast(payload)) + return false; + + return true; +} + +uint64 ContentEncAESSettings::PayloadSize() const { + uint64 size = EbmlElementSize(kMkvAESSettingsCipherMode, cipher_mode_); + return size; +} + /////////////////////////////////////////////////////////////// // // ContentEncoding Class @@ -288,7 +329,8 @@ bool ContentEncoding::SetEncryptionID(const uint8* id, uint64 length) { delete [] enc_key_id_; - enc_key_id_ = new (std::nothrow) uint8[static_cast(length)]; + enc_key_id_ = + new (std::nothrow) uint8[static_cast(length)]; // NOLINT if (!enc_key_id_) return false; @@ -338,6 +380,9 @@ bool ContentEncoding::Write(IMkvWriter* writer) const { enc_key_id_length_)) return false; + if (!enc_aes_settings_.Write(writer)) + return false; + const int64 stop_position = writer->Position(); if (stop_position < 0 || stop_position - payload_position != static_cast(size)) @@ -367,12 +412,14 @@ uint64 ContentEncoding::EncodingSize(uint64 compresion_size, } uint64 ContentEncoding::EncryptionSize() const { + const uint64 aes_size = enc_aes_settings_.Size(); + uint64 encryption_size = EbmlElementSize(kMkvContentEncKeyID, enc_key_id_, enc_key_id_length_); encryption_size += EbmlElementSize(kMkvContentEncAlgo, enc_algo_); - return encryption_size; + return encryption_size + aes_size; } /////////////////////////////////////////////////////////////// @@ -411,12 +458,12 @@ bool Track::AddContentEncoding() { const uint32 count = content_encoding_entries_size_ + 1; ContentEncoding** const content_encoding_entries = - new (std::nothrow) ContentEncoding*[count]; + new (std::nothrow) ContentEncoding*[count]; // NOLINT if (!content_encoding_entries) return false; ContentEncoding* const content_encoding = - new (std::nothrow) ContentEncoding(); + new (std::nothrow) ContentEncoding(); // NOLINT if (!content_encoding) { delete [] content_encoding_entries; return false; @@ -572,7 +619,7 @@ bool Track::SetCodecPrivate(const uint8* codec_private, uint64 length) { delete [] codec_private_; codec_private_ = - new (std::nothrow) uint8[static_cast(length)]; + new (std::nothrow) uint8[static_cast(length)]; // NOLINT if (!codec_private_) return false; @@ -587,7 +634,7 @@ void Track::set_codec_id(const char* codec_id) { delete [] codec_id_; const size_t length = strlen(codec_id) + 1; - codec_id_ = new (std::nothrow) char[length]; + codec_id_ = new (std::nothrow) char[length]; // NOLINT if (codec_id_) { #ifdef _MSC_VER strcpy_s(codec_id_, length, codec_id); @@ -604,7 +651,7 @@ void Track::set_language(const char* language) { delete [] language_; const size_t length = strlen(language) + 1; - language_ = new (std::nothrow) char[length]; + language_ = new (std::nothrow) char[length]; // NOLINT if (language_) { #ifdef _MSC_VER strcpy_s(language_, length, language); @@ -620,7 +667,7 @@ void Track::set_name(const char* name) { delete [] name_; const size_t length = strlen(name) + 1; - name_ = new (std::nothrow) char[length]; + name_ = new (std::nothrow) char[length]; // NOLINT if (name_) { #ifdef _MSC_VER strcpy_s(name_, length, name); @@ -842,7 +889,7 @@ bool Tracks::AddTrack(Track* track, int32 number) { const uint32 count = track_entries_size_ + 1; - Track** const track_entries = new (std::nothrow) Track*[count]; + Track** const track_entries = new (std::nothrow) Track*[count]; // NOLINT if (!track_entries) return false; @@ -977,7 +1024,7 @@ bool Cluster::Init(IMkvWriter* ptr_writer) { bool Cluster::AddFrame(const uint8* frame, uint64 length, uint64 track_number, - short timecode, + int16 timecode, bool is_key) { if (finalized_) return false; @@ -1191,7 +1238,7 @@ bool SegmentInfo::Init() { int32 minor; int32 build; int32 revision; - GetVersion(major, minor, build, revision); + GetVersion(&major, &minor, &build, &revision); char temp[256]; #ifdef _MSC_VER sprintf_s(temp, @@ -1215,7 +1262,7 @@ bool SegmentInfo::Init() { delete [] muxing_app_; - muxing_app_ = new (std::nothrow) char[app_len]; + muxing_app_ = new (std::nothrow) char[app_len]; // NOLINT if (!muxing_app_) return false; @@ -1304,7 +1351,7 @@ void SegmentInfo::set_writing_app(const char* app) { delete [] writing_app_; const size_t length = strlen(app) + 1; - writing_app_ = new (std::nothrow) char[length]; + writing_app_ = new (std::nothrow) char[length]; // NOLINT if (writing_app_) { #ifdef _MSC_VER strcpy_s(writing_app_, length, app); @@ -1483,7 +1530,7 @@ uint64 Segment::AddVideoTrack(int32 width, int32 height) { } uint64 Segment::AddVideoTrack(int32 width, int32 height, int32 number) { - VideoTrack* const vid_track = new (std::nothrow) VideoTrack(); + VideoTrack* const vid_track = new (std::nothrow) VideoTrack(); // NOLINT if (!vid_track) return 0; @@ -1505,7 +1552,7 @@ uint64 Segment::AddAudioTrack(int32 sample_rate, int32 channels) { uint64 Segment::AddAudioTrack(int32 sample_rate, int32 channels, int32 number) { - AudioTrack* const aud_track = new (std::nothrow) AudioTrack(); + AudioTrack* const aud_track = new (std::nothrow) AudioTrack(); // NOLINT if (!aud_track) return 0; @@ -1584,7 +1631,8 @@ bool Segment::AddFrame(const uint8* frame, if (new_capacity < 1) return false; - Cluster** const clusters = new (std::nothrow) Cluster*[new_capacity]; + Cluster** const clusters = + new (std::nothrow) Cluster*[new_capacity]; // NOLINT if (!clusters) return false; @@ -1636,7 +1684,7 @@ bool Segment::AddFrame(const uint8* frame, } cluster_list_[cluster_list_size_] = - new (std::nothrow) Cluster(timecode, MaxOffset()); + new (std::nothrow) Cluster(timecode, MaxOffset()); // NOLINT if (!cluster_list_[cluster_list_size_]) return false; @@ -1676,7 +1724,7 @@ bool Segment::AddFrame(const uint8* frame, if (!cluster->AddFrame(frame, length, track_number, - static_cast(block_timecode), + static_cast(block_timecode), is_key)) return false; @@ -1703,7 +1751,7 @@ bool Segment::SetChunking(bool chunking, const char* filename) { return true; const size_t name_length = strlen(filename) + 1; - char* const temp = new (std::nothrow) char[name_length]; + char* const temp = new (std::nothrow) char[name_length]; // NOLINT if (!temp) return false; @@ -1720,19 +1768,19 @@ bool Segment::SetChunking(bool chunking, const char* filename) { return false; if (!chunk_writer_cluster_) { - chunk_writer_cluster_ = new (std::nothrow) MkvWriter(); + chunk_writer_cluster_ = new (std::nothrow) MkvWriter(); // NOLINT if (!chunk_writer_cluster_) return false; } if (!chunk_writer_cues_) { - chunk_writer_cues_ = new (std::nothrow) MkvWriter(); + chunk_writer_cues_ = new (std::nothrow) MkvWriter(); // NOLINT if (!chunk_writer_cues_) return false; } if (!chunk_writer_header_) { - chunk_writer_header_ = new (std::nothrow) MkvWriter(); + chunk_writer_header_ = new (std::nothrow) MkvWriter(); // NOLINT if (!chunk_writer_header_) return false; } @@ -1741,7 +1789,7 @@ bool Segment::SetChunking(bool chunking, const char* filename) { return false; const size_t header_length = strlen(filename) + strlen(".hdr") + 1; - char* const header = new (std::nothrow) char[header_length]; + char* const header = new (std::nothrow) char[header_length]; // NOLINT if (!header) return false; @@ -1877,7 +1925,7 @@ bool Segment::AddCuePoint(uint64 timestamp) { if (!cluster) return false; - CuePoint* const cue = new (std::nothrow) CuePoint(); + CuePoint* const cue = new (std::nothrow) CuePoint(); // NOLINT if (!cue) return false; @@ -1898,13 +1946,13 @@ bool Segment::UpdateChunkName(const char* ext, char** name) const { char ext_chk[64]; #ifdef _MSC_VER - sprintf_s(ext_chk, 64, "_%06d.%s", chunk_count_, ext); + sprintf_s(ext_chk, sizeof(ext_chk), "_%06d.%s", chunk_count_, ext); #else - snprintf(ext_chk, 64, "_%06d.%s", chunk_count_, ext); + snprintf(ext_chk, sizeof(ext_chk), "_%06d.%s", chunk_count_, ext); #endif const size_t length = strlen(chunking_base_name_) + strlen(ext_chk) + 1; - char* const str = new (std::nothrow) char[length]; + char* const str = new (std::nothrow) char[length]; // NOLINT if (!str) return false; @@ -1951,7 +1999,7 @@ bool Segment::QueueFrame(Frame* frame) { if (new_capacity < 1) return false; - Frame** const frames = new (std::nothrow) Frame*[new_capacity]; + Frame** const frames = new (std::nothrow) Frame*[new_capacity]; // NOLINT if (!frames) return false; @@ -1997,7 +2045,7 @@ bool Segment::WriteFramesAll() { if (!cluster->AddFrame(frame->frame(), frame->length(), frame->track_number(), - static_cast(block_timecode), + static_cast(block_timecode), frame->is_key())) return false; @@ -2053,7 +2101,7 @@ bool Segment::WriteFramesLessThan(uint64 timestamp) { if (!cluster->AddFrame(frame_prev->frame(), frame_prev->length(), frame_prev->track_number(), - static_cast(block_timecode), + static_cast(block_timecode), frame_prev->is_key())) return false; diff --git a/mkvmuxer.hpp b/mkvmuxer.hpp index a081c7d..b93c3e5 100644 --- a/mkvmuxer.hpp +++ b/mkvmuxer.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The WebM project authors. All Rights Reserved. +// Copyright (c) 2012 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 @@ -179,23 +179,49 @@ class Cues { LIBWEBM_DISALLOW_COPY_AND_ASSIGN(Cues); }; +/////////////////////////////////////////////////////////////// +// ContentEncAESSettings element +class ContentEncAESSettings { + public: + enum { + kCTR = 1 + }; + + ContentEncAESSettings(); + ~ContentEncAESSettings() {} + + // Returns the size in bytes for the ContentEncAESSettings element. + uint64 Size() const; + + // Writes out the ContentEncAESSettings element to |writer|. Returns true on + // success. + bool Write(IMkvWriter* writer) const; + + uint64 cipher_mode() const { return cipher_mode_; } + + private: + // Returns the size in bytes for the payload of the ContentEncAESSettings + // element. + uint64 PayloadSize() const; + + // Sub elements + uint64 cipher_mode_; + + LIBWEBM_DISALLOW_COPY_AND_ASSIGN(ContentEncAESSettings); +}; + /////////////////////////////////////////////////////////////// // ContentEncoding element // Elements used to describe if the track data has been encrypted or // compressed with zlib or header stripping. -// Currently only whole frames can only be encrypted once with AES. This -// dictates that ContentEncodingOrder will be 0, ContentEncodingScope will -// be 1, ContentEncodingType will be 1, and ContentEncAlgo will be 5. +// Currently only whole frames can be encrypted with AES. This dictates that +// ContentEncodingOrder will be 0, ContentEncodingScope will be 1, +// ContentEncodingType will be 1, and ContentEncAlgo will be 5. class ContentEncoding { public: ContentEncoding(); ~ContentEncoding(); - uint64 enc_algo() const { return enc_algo_; } - uint64 encoding_order() const { return encoding_order_; } - uint64 encoding_scope() const { return encoding_scope_; } - uint64 encoding_type() const { return encoding_type_; } - // Sets the content encryption id. Copies |length| bytes from |id| to // |enc_key_id_|. Returns true on success. bool SetEncryptionID(const uint8* id, uint64 length); @@ -207,6 +233,12 @@ class ContentEncoding { // success. bool Write(IMkvWriter* writer) const; + uint64 enc_algo() const { return enc_algo_; } + uint64 encoding_order() const { return encoding_order_; } + uint64 encoding_scope() const { return encoding_scope_; } + uint64 encoding_type() const { return encoding_type_; } + ContentEncAESSettings* enc_aes_settings() { return &enc_aes_settings_; } + private: // Returns the size in bytes for the encoding elements. uint64 EncodingSize(uint64 compresion_size, uint64 encryption_size) const; @@ -221,6 +253,9 @@ class ContentEncoding { uint64 encoding_scope_; uint64 encoding_type_; + // ContentEncAESSettings element. + ContentEncAESSettings enc_aes_settings_; + // Size of the ContentEncKeyID data in bytes. uint64 enc_key_id_length_; diff --git a/mkvmuxertypes.hpp b/mkvmuxertypes.hpp index 810f2fe..2c66fd2 100644 --- a/mkvmuxertypes.hpp +++ b/mkvmuxertypes.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The WebM project authors. All Rights Reserved. +// Copyright (c) 2012 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 @@ -19,6 +19,7 @@ namespace mkvmuxer { typedef unsigned char uint8; +typedef short int16; typedef int int32; typedef unsigned int uint32; typedef long long int64; diff --git a/mkvmuxerutil.cpp b/mkvmuxerutil.cpp index 98ce0c9..4c90fe3 100644 --- a/mkvmuxerutil.cpp +++ b/mkvmuxerutil.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The WebM project authors. All Rights Reserved. +// Copyright (c) 2012 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 @@ -22,7 +22,6 @@ namespace mkvmuxer { int32 GetCodedUIntSize(uint64 value) { - if (value < 0x000000000000007FULL) return 1; else if (value < 0x0000000000003FFFULL) @@ -41,7 +40,6 @@ int32 GetCodedUIntSize(uint64 value) { } int32 GetUIntSize(uint64 value) { - if (value < 0x0000000000000100ULL) return 1; else if (value < 0x0000000000010000ULL) @@ -309,9 +307,8 @@ uint64 WriteSimpleBlock(IMkvWriter* writer, const uint8* data, uint64 length, char track_number, - short timecode, + int16 timecode, bool is_key) { - if (!writer || !data || length < 1 || track_number < 1 || timecode < 0) return false; @@ -329,7 +326,7 @@ uint64 WriteSimpleBlock(IMkvWriter* writer, return 0; uint64 flags = 0; - if(is_key) + if (is_key) flags |= 0x80; if (SerializeInt(writer, flags, 1)) @@ -380,11 +377,11 @@ uint64 WriteVoidElement(IMkvWriter* writer, uint64 size) { return void_size; } -void GetVersion(int32& major, int32& minor, int32& build, int32& revision) { - major = 0; - minor = 0; - build = 1; - revision = 0; +void GetVersion(int32* major, int32* minor, int32* build, int32* revision) { + *major = 0; + *minor = 1; + *build = 0; + *revision = 0; } } // namespace mkvmuxer diff --git a/mkvmuxerutil.hpp b/mkvmuxerutil.hpp index a14292f..5544f12 100644 --- a/mkvmuxerutil.hpp +++ b/mkvmuxerutil.hpp @@ -75,7 +75,7 @@ uint64 WriteVoidElement(IMkvWriter* writer, uint64 size); // Returns the version number of the muxer in |major|, |minor|, |build|, // and |revision|. -void GetVersion(int32& major, int32& minor, int32& build, int32& revision); +void GetVersion(int32* major, int32* minor, int32* build, int32* revision); } //end namespace mkvmuxer diff --git a/mkvparser.cpp b/mkvparser.cpp index ae9b9be..6f7098e 100644 --- a/mkvparser.cpp +++ b/mkvparser.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The WebM project authors. All Rights Reserved. +// Copyright (c) 2012 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 @@ -4478,11 +4478,147 @@ unsigned long ContentEncoding::GetEncryptionCount() const { return static_cast(count); } -void ContentEncoding::ParseEncryptionEntry( +long ContentEncoding::ParseContentEncAESSettingsEntry( long long start, long long size, - IMkvReader* const pReader, - ContentEncryption* const encryption) { + IMkvReader* pReader, + ContentEncAESSettings* aes) { + assert(pReader); + assert(aes); + + long long pos = start; + const long long stop = start + size; + + while (pos < stop) { + long long id, size; + const long status = ParseElementHeader(pReader, + pos, + stop, + id, + size); + if (status < 0) //error + return status; + + if (id == 0x7E8) { + // AESSettingsCipherMode + aes->cipher_mode = UnserializeUInt(pReader, pos, size); + if (aes->cipher_mode != 1) + return E_FILE_FORMAT_INVALID; + } + + pos += size; //consume payload + assert(pos <= stop); + } + + return 0; +} + +long ContentEncoding::ParseContentEncodingEntry(long long start, + long long size, + IMkvReader* pReader) { + assert(pReader); + + long long pos = start; + const long long stop = start + size; + + // Count ContentCompression and ContentEncryption elements. + int compression_count = 0; + int encryption_count = 0; + + while (pos < stop) { + long long id, size; + const long status = ParseElementHeader(pReader, + pos, + stop, + id, + size); + if (status < 0) //error + return status; + + if (id == 0x1034) // ContentCompression ID + ++compression_count; + + if (id == 0x1035) // ContentEncryption ID + ++encryption_count; + + pos += size; //consume payload + assert(pos <= stop); + } + + if (compression_count <= 0 && encryption_count <= 0) + return -1; + + if (compression_count > 0) { + compression_entries_ = + new (std::nothrow) ContentCompression*[compression_count]; + if (!compression_entries_) + return -1; + compression_entries_end_ = compression_entries_; + } + + if (encryption_count > 0) { + encryption_entries_ = + new (std::nothrow) ContentEncryption*[encryption_count]; + if (!encryption_entries_) { + delete [] compression_entries_; + return -1; + } + encryption_entries_end_ = encryption_entries_; + } + + pos = start; + while (pos < stop) { + long long id, size; + long status = ParseElementHeader(pReader, + pos, + stop, + id, + size); + if (status < 0) //error + return status; + + if (id == 0x1031) { + // ContentEncodingOrder + encoding_order_ = UnserializeUInt(pReader, pos, size); + } else if (id == 0x1032) { + // ContentEncodingScope + encoding_scope_ = UnserializeUInt(pReader, pos, size); + if (encoding_scope_ < 1) + return -1; + } else if (id == 0x1033) { + // ContentEncodingType + encoding_type_ = UnserializeUInt(pReader, pos, size); + } else if (id == 0x1034) { + // ContentCompression ID + // TODO(fgaligan): Add code to parse ContentCompression elements. + } else if (id == 0x1035) { + // ContentEncryption ID + ContentEncryption* const encryption = + new (std::nothrow) ContentEncryption(); + if (!encryption) + return -1; + + status = ParseEncryptionEntry(pos, size, pReader, encryption); + if (status) { + delete encryption; + return status; + } + *encryption_entries_end_++ = encryption; + } + + pos += size; //consume payload + assert(pos <= stop); + } + + assert(pos == stop); + return 0; +} + +long ContentEncoding::ParseEncryptionEntry( + long long start, + long long size, + IMkvReader* pReader, + ContentEncryption* encryption) { assert(pReader); assert(encryption); @@ -4490,166 +4626,111 @@ void ContentEncoding::ParseEncryptionEntry( const long long stop = start + size; while (pos < stop) { -#ifdef _DEBUG - long len; - const long long id = ReadUInt(pReader, pos, len); - assert(id >= 0); //TODO: handle error case - assert((pos + len) <= stop); -#endif + long long id, size; + const long status = ParseElementHeader(pReader, + pos, + stop, + id, + size); + if (status < 0) //error + return status; - long long value; - unsigned char* buf; - size_t buf_len; - - if (Match(pReader, pos, 0x7E1, value)) { + if (id == 0x7E1) { // ContentEncAlgo - encryption->algo = value; - } else if (Match(pReader, pos, 0x7E2, buf, buf_len)) { + encryption->algo = UnserializeUInt(pReader, pos, size); + if (encryption->algo != 5) + return E_FILE_FORMAT_INVALID; + } else if (id == 0x7E2) { // ContentEncKeyID - encryption->key_id = buf; - encryption->key_id_len = buf_len; - } else if (Match(pReader, pos, 0x7E3, buf, buf_len)) { - // ContentSignature - encryption->signature = buf; - encryption->signature_len = buf_len; - } else if (Match(pReader, pos, 0x7E4, buf, buf_len)) { - // ContentSigKeyID - encryption->sig_key_id = buf; - encryption->sig_key_id_len = buf_len; - } else if (Match(pReader, pos, 0x7E5, value)) { - // ContentSigAlgo - encoding_type_ = value; - } else if (Match(pReader, pos, 0x7E6, value)) { - // ContentSigHashAlgo - encoding_type_ = value; - } else { - long len; - const long long id = ReadUInt(pReader, pos, len); - assert(id >= 0); //TODO: handle error case - assert((pos + len) <= stop); + delete[] encryption->key_id; + encryption->key_id = NULL; + encryption->key_id_len = 0; - pos += len; //consume id + if (size <= 0) + return E_FILE_FORMAT_INVALID; - const long long size = ReadUInt(pReader, pos, len); - assert(size >= 0); //TODO: handle error case - assert((pos + len) <= stop); + const size_t buflen = static_cast(size); + typedef unsigned char* buf_t; + const buf_t buf = new (std::nothrow) unsigned char[buflen]; + if (buf == NULL) + return -1; - pos += len; //consume length of size - assert((pos + size) <= stop); - - pos += size; //consume payload - assert(pos <= stop); - } - } -} - -bool ContentEncoding::ParseContentEncodingEntry(long long start, - long long size, - IMkvReader* const pReader) { - assert(pReader); - - long long pos = start; - const long long stop = start + size; - - // Count ContentCompression and ContentEncryption elements. - long long pos1 = start; - int compression_count = 0; - int encryption_count = 0; - - while (pos1 < stop) { - long len; - const long long id = ReadUInt(pReader, pos1, len); - assert(id >= 0); - assert((pos1 + len) <= stop); - - pos1 += len; //consume id - - const long long size = ReadUInt(pReader, pos1, len); - assert(size >= 0); - assert((pos1 + len) <= stop); - - pos1 += len; //consume length of size - - //pos now designates start of element - if (id == 0x1034) // ContentCompression ID - ++compression_count; - - if (id == 0x1035) // ContentEncryption ID - ++encryption_count; - - pos1 += size; //consume payload - assert(pos1 <= stop); - } - - if (compression_count <= 0 && encryption_count <= 0) - return false; - - if (compression_count > 0) { - compression_entries_ = new ContentCompression*[compression_count]; - compression_entries_end_ = compression_entries_; - } - - if (encryption_count > 0) { - encryption_entries_ = new ContentEncryption*[encryption_count]; - encryption_entries_end_ = encryption_entries_; - } - - while (pos < stop) { -#ifdef _DEBUG - long len; - const long long id = ReadUInt(pReader, pos, len); - assert(id >= 0); //TODO: handle error case - assert((pos + len) <= stop); -#endif - - long long value; - if (Match(pReader, pos, 0x1031, value)) { - // ContentEncodingOrder - encoding_order_ = value; - } else if (Match(pReader, pos, 0x1032, value)) { - // ContentEncodingScope - encoding_scope_ = value; - assert(encoding_scope_ > 0); - } else if (Match(pReader, pos, 0x1033, value)) { - // ContentEncodingType - encoding_type_ = value; - } else { - long len; - const long long id = ReadUInt(pReader, pos, len); - assert(id >= 0); //TODO: handle error case - assert((pos + len) <= stop); - - pos += len; //consume id - - const long long size = ReadUInt(pReader, pos, len); - assert(size >= 0); //TODO: handle error case - assert((pos + len) <= stop); - - pos += len; //consume length of size - assert((pos + size) <= stop); - - //pos now designates start of payload - - if (id == 0x1034) { - // ContentCompression ID - // TODO(fgaligan): Add code to parse ContentCompression elements. - } else if (id == 0x1035) { - // ContentEncryption ID - ContentEncryption* const encryption = new ContentEncryption(); - - ParseEncryptionEntry(pos, size, pReader, encryption); - *encryption_entries_end_ = encryption; - ++encryption_entries_end_; + const int read_status = pReader->Read(pos, buflen, buf); + if (read_status) { + delete [] buf; + return status; } - pos += size; //consume payload - assert(pos <= stop); + encryption->key_id = buf; + encryption->key_id_len = buflen; + } else if (id == 0x7E3) { + // ContentSignature + delete[] encryption->signature; + encryption->signature = NULL; + encryption->signature_len = 0; + + if (size <= 0) + return E_FILE_FORMAT_INVALID; + + const size_t buflen = static_cast(size); + typedef unsigned char* buf_t; + const buf_t buf = new (std::nothrow) unsigned char[buflen]; + if (buf == NULL) + return -1; + + const int read_status = pReader->Read(pos, buflen, buf); + if (read_status) { + delete [] buf; + return status; + } + + encryption->signature = buf; + encryption->signature_len = buflen; + } else if (id == 0x7E4) { + // ContentSigKeyID + delete[] encryption->sig_key_id; + encryption->sig_key_id = NULL; + encryption->sig_key_id_len = 0; + + if (size <= 0) + return E_FILE_FORMAT_INVALID; + + const size_t buflen = static_cast(size); + typedef unsigned char* buf_t; + const buf_t buf = new (std::nothrow) unsigned char[buflen]; + if (buf == NULL) + return -1; + + const int read_status = pReader->Read(pos, buflen, buf); + if (read_status) { + delete [] buf; + return status; + } + + encryption->sig_key_id = buf; + encryption->sig_key_id_len = buflen; + } else if (id == 0x7E5) { + // ContentSigAlgo + encryption->sig_algo = UnserializeUInt(pReader, pos, size); + } else if (id == 0x7E6) { + // ContentSigHashAlgo + encryption->sig_hash_algo = UnserializeUInt(pReader, pos, size); + } else if (id == 0x7E7) { + // ContentEncAESSettings + const long status = ParseContentEncAESSettingsEntry( + pos, + size, + pReader, + &encryption->aes_settings); + if (status) + return status; } + + pos += size; //consume payload + assert(pos <= stop); } - assert(pos == stop); - - return true; + return 0; } Track::Track( @@ -5038,7 +5119,7 @@ unsigned long Track::GetContentEncodingCount() const { return static_cast(count); } -void Track::ParseContentEncodingsEntry(long long start, long long size) { +long Track::ParseContentEncodingsEntry(long long start, long long size) { IMkvReader* const pReader = m_pSegment->m_pReader; assert(pReader); @@ -5046,70 +5127,71 @@ void Track::ParseContentEncodingsEntry(long long start, long long size) { const long long stop = start + size; // Count ContentEncoding elements. - long long pos1 = start; int count = 0; + while (pos < stop) { + long long id, size; + const long status = ParseElementHeader(pReader, + pos, + stop, + id, + size); + if (status < 0) //error + return status; - while (pos1 < stop) { - long len; - const long long id = ReadUInt(pReader, pos1, len); - assert(id >= 0); - assert((pos1 + len) <= stop); - - pos1 += len; //consume id - - const long long size = ReadUInt(pReader, pos1, len); - assert(size >= 0); - assert((pos1 + len) <= stop); - - pos1 += len; //consume length of size //pos now designates start of element if (id == 0x2240) // ContentEncoding ID ++count; - pos1 += size; //consume payload - assert(pos1 <= stop); + pos += size; //consume payload + assert(pos <= stop); } if (count <= 0) - return; + return -1; + + content_encoding_entries_ = new (std::nothrow) ContentEncoding*[count]; + if (!content_encoding_entries_) + return -1; - content_encoding_entries_ = new ContentEncoding*[count]; content_encoding_entries_end_ = content_encoding_entries_; + pos = start; while (pos < stop) { - long len; - const long long id = ReadUInt(pReader, pos, len); - assert(id >= 0); - assert((pos + len) <= stop); - - pos += len; //consume id - - const long long size1 = ReadUInt(pReader, pos, len); - assert(size1 >= 0); - assert((pos + len) <= stop); - - pos += len; //consume length of size + long long id, size; + long status = ParseElementHeader(pReader, + pos, + stop, + id, + size); + if (status < 0) //error + return status; //pos now designates start of element if (id == 0x2240) { // ContentEncoding ID - ContentEncoding* const content_encoding = new ContentEncoding(); + ContentEncoding* const content_encoding = + new (std::nothrow) ContentEncoding(); + if (!content_encoding) + return -1; - if (!content_encoding->ParseContentEncodingEntry(pos, size1, pReader)) { + status = content_encoding->ParseContentEncodingEntry(pos, + size, + pReader); + if (status) { delete content_encoding; - } else { - *content_encoding_entries_end_ = content_encoding; - ++content_encoding_entries_end_; + return status; } + + *content_encoding_entries_end_++ = content_encoding; } - pos += size1; //consume payload + pos += size; //consume payload assert(pos <= stop); } assert(pos == stop); - return; + return 0; } Track::EOSBlock::EOSBlock() : diff --git a/mkvparser.hpp b/mkvparser.hpp index 76f79bb..107d95a 100644 --- a/mkvparser.hpp +++ b/mkvparser.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The WebM project authors. All Rights Reserved. +// Copyright (c) 2012 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 @@ -203,6 +203,10 @@ private: // compressed with zlib or header stripping. class ContentEncoding { public: + enum { + kCTR = 1 + }; + ContentEncoding(); ~ContentEncoding(); @@ -215,6 +219,14 @@ public: unsigned char* settings; }; + // ContentEncAESSettings element names + struct ContentEncAESSettings { + ContentEncAESSettings() : cipher_mode(kCTR) {} + ~ContentEncAESSettings() {} + + unsigned long long cipher_mode; + }; + // ContentEncryption element names struct ContentEncryption { ContentEncryption(); @@ -229,6 +241,8 @@ public: long long sig_key_id_len; unsigned long long sig_algo; unsigned long long sig_hash_algo; + + ContentEncAESSettings aes_settings; }; // Returns ContentCompression represented by |idx|. Returns NULL if |idx| @@ -247,21 +261,30 @@ public: // element. unsigned long GetEncryptionCount() const; + // Parses the ContentEncAESSettings element from |pReader|. |start| is the + // starting offset of the ContentEncAESSettings payload. |size| is the + // size in bytes of the ContentEncAESSettings payload. |encryption| is + // where the parsed values will be stored. + long ParseContentEncAESSettingsEntry(long long start, + long long size, + IMkvReader* pReader, + ContentEncAESSettings* aes); + // Parses the ContentEncoding element from |pReader|. |start| is the // starting offset of the ContentEncoding payload. |size| is the size in // bytes of the ContentEncoding payload. Returns true on success. - bool ParseContentEncodingEntry(long long start, + long ParseContentEncodingEntry(long long start, long long size, - IMkvReader* const pReader); + IMkvReader* pReader); // Parses the ContentEncryption element from |pReader|. |start| is the // starting offset of the ContentEncryption payload. |size| is the size in // bytes of the ContentEncryption payload. |encryption| is where the parsed // values will be stored. - void ParseEncryptionEntry(long long start, + long ParseEncryptionEntry(long long start, long long size, - IMkvReader* const pReader, - ContentEncryption* const encryption); + IMkvReader* pReader, + ContentEncryption* encryption); unsigned long long encoding_order() const { return encoding_order_; } unsigned long long encoding_scope() const { return encoding_scope_; } @@ -349,7 +372,7 @@ public: const ContentEncoding* GetContentEncodingByIndex(unsigned long idx) const; unsigned long GetContentEncodingCount() const; - void ParseContentEncodingsEntry(long long start, long long size); + long ParseContentEncodingsEntry(long long start, long long size); protected: Track( diff --git a/mkvwriter.cpp b/mkvwriter.cpp index 3492141..788aa15 100644 --- a/mkvwriter.cpp +++ b/mkvwriter.cpp @@ -1,94 +1,94 @@ -// Copyright (c) 2011 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 "mkvwriter.hpp" - -#ifdef _MSC_VER -#include // for _SH_DENYWR -#endif - -#include - -namespace mkvmuxer { - -MkvWriter::MkvWriter() : file_(NULL) { -} - -MkvWriter::~MkvWriter() { - Close(); -} - -int32 MkvWriter::Write(const void* buffer, uint32 length) { - if (!file_) - return -1; - - if (length == 0) - return 0; - - if (buffer == NULL) - return -1; - - const size_t bytes_written = fwrite(buffer, 1, length, file_); - - return (bytes_written == length) ? 0 : -1; -} - -bool MkvWriter::Open(const char* filename) { - if (filename == NULL) - return false; - - if (file_) - return false; - -#ifdef _MSC_VER - file_ = _fsopen(filename, "wb", _SH_DENYWR); -#else - file_ = fopen(filename, "wb"); -#endif - if (file_ == NULL) - return false; - return true; -} - -void MkvWriter::Close() { - if (file_) { - fclose(file_); - file_ = NULL; - } -} - -int64 MkvWriter::Position() const { - if (!file_) - return 0; - -#ifdef _MSC_VER - return _ftelli64(file_); -#else - return ftell(file_); -#endif -} - -int32 MkvWriter::Position(int64 position) { - if (!file_) - return -1; - -#ifdef _MSC_VER - return _fseeki64(file_, position, SEEK_SET); -#else - return fseek(file_, position, SEEK_SET); -#endif -} - -bool MkvWriter::Seekable() const { - return true; -} - -void MkvWriter::ElementStartNotify(uint64, int64) { -} - -} // namespace mkvmuxer +// Copyright (c) 2012 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 "mkvwriter.hpp" + +#ifdef _MSC_VER +#include // for _SH_DENYWR +#endif + +#include + +namespace mkvmuxer { + +MkvWriter::MkvWriter() : file_(NULL) { +} + +MkvWriter::~MkvWriter() { + Close(); +} + +int32 MkvWriter::Write(const void* buffer, uint32 length) { + if (!file_) + return -1; + + if (length == 0) + return 0; + + if (buffer == NULL) + return -1; + + const size_t bytes_written = fwrite(buffer, 1, length, file_); + + return (bytes_written == length) ? 0 : -1; +} + +bool MkvWriter::Open(const char* filename) { + if (filename == NULL) + return false; + + if (file_) + return false; + +#ifdef _MSC_VER + file_ = _fsopen(filename, "wb", _SH_DENYWR); +#else + file_ = fopen(filename, "wb"); +#endif + if (file_ == NULL) + return false; + return true; +} + +void MkvWriter::Close() { + if (file_) { + fclose(file_); + file_ = NULL; + } +} + +int64 MkvWriter::Position() const { + if (!file_) + return 0; + +#ifdef _MSC_VER + return _ftelli64(file_); +#else + return ftell(file_); +#endif +} + +int32 MkvWriter::Position(int64 position) { + if (!file_) + return -1; + +#ifdef _MSC_VER + return _fseeki64(file_, position, SEEK_SET); +#else + return fseek(file_, position, SEEK_SET); +#endif +} + +bool MkvWriter::Seekable() const { + return true; +} + +void MkvWriter::ElementStartNotify(uint64, int64) { +} + +} // namespace mkvmuxer diff --git a/mkvwriter.hpp b/mkvwriter.hpp index f41f359..fe5c3d4 100644 --- a/mkvwriter.hpp +++ b/mkvwriter.hpp @@ -1,49 +1,49 @@ -// Copyright (c) 2012 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. - -#ifndef MKVWRITER_HPP -#define MKVWRITER_HPP - -#include - -#include "mkvmuxer.hpp" -#include "mkvmuxertypes.hpp" - -namespace mkvmuxer { - -// Default implementation of the IMkvWriter interface on Windows. -class MkvWriter : public IMkvWriter { - public: - MkvWriter(); - virtual ~MkvWriter(); - - // IMkvWriter interface - virtual int64 Position() const; - virtual int32 Position(int64 position); - virtual bool Seekable() const; - virtual int32 Write(const void* buffer, uint32 length); - virtual void ElementStartNotify(uint64 element_id, int64 position); - - // Creates and opens a file for writing. |filename| is the name of the file - // to open. This function will overwrite the contents of |filename|. Returns - // true on success. - bool Open(const char* filename); - - // Closes an opened file. - void Close(); - - private: - // File handle to output file. - FILE* file_; - - LIBWEBM_DISALLOW_COPY_AND_ASSIGN(MkvWriter); -}; - -} //end namespace mkvmuxer - -#endif // MKVWRITER_HPP +// Copyright (c) 2012 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. + +#ifndef MKVWRITER_HPP +#define MKVWRITER_HPP + +#include + +#include "mkvmuxer.hpp" +#include "mkvmuxertypes.hpp" + +namespace mkvmuxer { + +// Default implementation of the IMkvWriter interface on Windows. +class MkvWriter : public IMkvWriter { + public: + MkvWriter(); + virtual ~MkvWriter(); + + // IMkvWriter interface + virtual int64 Position() const; + virtual int32 Position(int64 position); + virtual bool Seekable() const; + virtual int32 Write(const void* buffer, uint32 length); + virtual void ElementStartNotify(uint64 element_id, int64 position); + + // Creates and opens a file for writing. |filename| is the name of the file + // to open. This function will overwrite the contents of |filename|. Returns + // true on success. + bool Open(const char* filename); + + // Closes an opened file. + void Close(); + + private: + // File handle to output file. + FILE* file_; + + LIBWEBM_DISALLOW_COPY_AND_ASSIGN(MkvWriter); +}; + +} //end namespace mkvmuxer + +#endif // MKVWRITER_HPP diff --git a/webmids.hpp b/webmids.hpp index 2e756cd..07827c4 100644 --- a/webmids.hpp +++ b/webmids.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The WebM project authors. All Rights Reserved. +// Copyright (c) 2012 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 @@ -101,6 +101,9 @@ enum MkvId { kMkvContentEncryption = 0x5035, kMkvContentEncAlgo = 0x47E1, kMkvContentEncKeyID = 0x47E2, + kMkvContentEncAESSettings = 0x47E7, + kMkvAESSettingsCipherMode = 0x47E8, + kMkvAESSettingsCipherInitData = 0x47E9, //end ContentEncodings //Cueing Data kMkvCues = 0x1C53BB6B,