| OLD | NEW |
| 1 // Copyright (c) 2012 The WebM project authors. All Rights Reserved. | 1 // Copyright (c) 2012 The WebM project authors. All Rights Reserved. |
| 2 // | 2 // |
| 3 // Use of this source code is governed by a BSD-style license | 3 // Use of this source code is governed by a BSD-style license |
| 4 // that can be found in the LICENSE file in the root of the source | 4 // that can be found in the LICENSE file in the root of the source |
| 5 // tree. An additional intellectual property rights grant can be found | 5 // tree. An additional intellectual property rights grant can be found |
| 6 // in the file PATENTS. All contributing project authors may | 6 // in the file PATENTS. All contributing project authors may |
| 7 // be found in the AUTHORS file in the root of the source tree. | 7 // be found in the AUTHORS file in the root of the source tree. |
| 8 | 8 |
| 9 #include "mkvparser.hpp" | 9 #include "mkvparser.hpp" |
| 10 |
| 10 #include <cassert> | 11 #include <cassert> |
| 12 #include <climits> |
| 13 #include <cmath> |
| 11 #include <cstring> | 14 #include <cstring> |
| 12 #include <new> | 15 #include <new> |
| 13 #include <climits> | 16 |
| 17 #include "webmids.hpp" |
| 14 | 18 |
| 15 #ifdef _MSC_VER | 19 #ifdef _MSC_VER |
| 16 // Disable MSVC warnings that suggest making code non-portable. | 20 // Disable MSVC warnings that suggest making code non-portable. |
| 17 #pragma warning(disable : 4996) | 21 #pragma warning(disable : 4996) |
| 18 #endif | 22 #endif |
| 19 | 23 |
| 20 mkvparser::IMkvReader::~IMkvReader() {} | 24 namespace mkvparser { |
| 21 | 25 |
| 22 void mkvparser::GetVersion(int& major, int& minor, int& build, int& revision) { | 26 IMkvReader::~IMkvReader() {} |
| 27 |
| 28 template<typename Type> Type* SafeArrayAlloc(unsigned long long num_elements, |
| 29 unsigned long long element_size) { |
| 30 if (num_elements == 0 || element_size == 0) |
| 31 return NULL; |
| 32 |
| 33 const size_t kMaxAllocSize = 0x80000000; // 2GiB |
| 34 const unsigned long long num_bytes = num_elements * element_size; |
| 35 if (element_size > (kMaxAllocSize / num_elements)) |
| 36 return NULL; |
| 37 |
| 38 return new (std::nothrow) Type[num_bytes]; |
| 39 } |
| 40 |
| 41 void GetVersion(int& major, int& minor, int& build, int& revision) { |
| 23 major = 1; | 42 major = 1; |
| 24 minor = 0; | 43 minor = 0; |
| 25 build = 0; | 44 build = 0; |
| 26 revision = 30; | 45 revision = 30; |
| 27 } | 46 } |
| 28 | 47 |
| 29 long long mkvparser::ReadUInt(IMkvReader* pReader, long long pos, long& len) { | 48 long long ReadUInt(IMkvReader* pReader, long long pos, long& len) { |
| 30 assert(pReader); | 49 if (!pReader || pos < 0) |
| 31 assert(pos >= 0); | 50 return E_FILE_FORMAT_INVALID; |
| 32 | |
| 33 int status; | |
| 34 | |
| 35 //#ifdef _DEBUG | |
| 36 // long long total, available; | |
| 37 // status = pReader->Length(&total, &available); | |
| 38 // assert(status >= 0); | |
| 39 // assert((total < 0) || (available <= total)); | |
| 40 // assert(pos < available); | |
| 41 // assert((available - pos) >= 1); //assume here max u-int len is 8 | |
| 42 //#endif | |
| 43 | 51 |
| 44 len = 1; | 52 len = 1; |
| 45 | |
| 46 unsigned char b; | 53 unsigned char b; |
| 47 | 54 int status = pReader->Read(pos, 1, &b); |
| 48 status = pReader->Read(pos, 1, &b); | |
| 49 | 55 |
| 50 if (status < 0) // error or underflow | 56 if (status < 0) // error or underflow |
| 51 return status; | 57 return status; |
| 52 | 58 |
| 53 if (status > 0) // interpreted as "underflow" | 59 if (status > 0) // interpreted as "underflow" |
| 54 return E_BUFFER_NOT_FULL; | 60 return E_BUFFER_NOT_FULL; |
| 55 | 61 |
| 56 if (b == 0) // we can't handle u-int values larger than 8 bytes | 62 if (b == 0) // we can't handle u-int values larger than 8 bytes |
| 57 return E_FILE_FORMAT_INVALID; | 63 return E_FILE_FORMAT_INVALID; |
| 58 | 64 |
| 59 unsigned char m = 0x80; | 65 unsigned char m = 0x80; |
| 60 | 66 |
| 61 while (!(b & m)) { | 67 while (!(b & m)) { |
| 62 m >>= 1; | 68 m >>= 1; |
| 63 ++len; | 69 ++len; |
| 64 } | 70 } |
| 65 | 71 |
| 66 //#ifdef _DEBUG | |
| 67 // assert((available - pos) >= len); | |
| 68 //#endif | |
| 69 | |
| 70 long long result = b & (~m); | 72 long long result = b & (~m); |
| 71 ++pos; | 73 ++pos; |
| 72 | 74 |
| 73 for (int i = 1; i < len; ++i) { | 75 for (int i = 1; i < len; ++i) { |
| 74 status = pReader->Read(pos, 1, &b); | 76 status = pReader->Read(pos, 1, &b); |
| 75 | 77 |
| 76 if (status < 0) { | 78 if (status < 0) { |
| 77 len = 1; | 79 len = 1; |
| 78 return status; | 80 return status; |
| 79 } | 81 } |
| 80 | 82 |
| 81 if (status > 0) { | 83 if (status > 0) { |
| 82 len = 1; | 84 len = 1; |
| 83 return E_BUFFER_NOT_FULL; | 85 return E_BUFFER_NOT_FULL; |
| 84 } | 86 } |
| 85 | 87 |
| 86 result <<= 8; | 88 result <<= 8; |
| 87 result |= b; | 89 result |= b; |
| 88 | 90 |
| 89 ++pos; | 91 ++pos; |
| 90 } | 92 } |
| 91 | 93 |
| 92 return result; | 94 return result; |
| 93 } | 95 } |
| 94 | 96 |
| 95 long long mkvparser::GetUIntLength(IMkvReader* pReader, long long pos, | 97 // Reads an EBML ID and returns it. |
| 96 long& len) { | 98 // An ID must at least 1 byte long, cannot exceed 4, and its value must be |
| 97 assert(pReader); | 99 // greater than 0. |
| 98 assert(pos >= 0); | 100 // See known EBML values and EBMLMaxIDLength: |
| 101 // http://www.matroska.org/technical/specs/index.html |
| 102 // Returns the ID, or a value less than 0 to report an error while reading the |
| 103 // ID. |
| 104 long long ReadID(IMkvReader* pReader, long long pos, long& len) { |
| 105 if (pReader == NULL || pos < 0) |
| 106 return E_FILE_FORMAT_INVALID; |
| 107 |
| 108 // Read the first byte. The length in bytes of the ID is determined by |
| 109 // finding the first set bit in the first byte of the ID. |
| 110 unsigned char temp_byte = 0; |
| 111 int read_status = pReader->Read(pos, 1, &temp_byte); |
| 112 |
| 113 if (read_status < 0) |
| 114 return E_FILE_FORMAT_INVALID; |
| 115 else if (read_status > 0) // No data to read. |
| 116 return E_BUFFER_NOT_FULL; |
| 117 |
| 118 if (temp_byte == 0) // ID length > 8 bytes; invalid file. |
| 119 return E_FILE_FORMAT_INVALID; |
| 120 |
| 121 int bit_pos = 0; |
| 122 const int kMaxIdLengthInBytes = 4; |
| 123 const int kCheckByte = 0x80; |
| 124 |
| 125 // Find the first bit that's set. |
| 126 bool found_bit = false; |
| 127 for (; bit_pos < kMaxIdLengthInBytes; ++bit_pos) { |
| 128 if ((kCheckByte >> bit_pos) & temp_byte) { |
| 129 found_bit = true; |
| 130 break; |
| 131 } |
| 132 } |
| 133 |
| 134 if (!found_bit) { |
| 135 // The value is too large to be a valid ID. |
| 136 return E_FILE_FORMAT_INVALID; |
| 137 } |
| 138 |
| 139 // Read the remaining bytes of the ID (if any). |
| 140 const int id_length = bit_pos + 1; |
| 141 long long ebml_id = temp_byte; |
| 142 for (int i = 1; i < id_length; ++i) { |
| 143 ebml_id <<= 8; |
| 144 read_status = pReader->Read(pos + i, 1, &temp_byte); |
| 145 |
| 146 if (read_status < 0) |
| 147 return E_FILE_FORMAT_INVALID; |
| 148 else if (read_status > 0) |
| 149 return E_BUFFER_NOT_FULL; |
| 150 |
| 151 ebml_id |= temp_byte; |
| 152 } |
| 153 |
| 154 len = id_length; |
| 155 return ebml_id; |
| 156 } |
| 157 |
| 158 long long GetUIntLength(IMkvReader* pReader, long long pos, long& len) { |
| 159 if (!pReader || pos < 0) |
| 160 return E_FILE_FORMAT_INVALID; |
| 99 | 161 |
| 100 long long total, available; | 162 long long total, available; |
| 101 | 163 |
| 102 int status = pReader->Length(&total, &available); | 164 int status = pReader->Length(&total, &available); |
| 103 assert(status >= 0); | 165 if (status < 0 || (total >= 0 && available > total)) |
| 104 assert((total < 0) || (available <= total)); | 166 return E_FILE_FORMAT_INVALID; |
| 105 | 167 |
| 106 len = 1; | 168 len = 1; |
| 107 | 169 |
| 108 if (pos >= available) | 170 if (pos >= available) |
| 109 return pos; // too few bytes available | 171 return pos; // too few bytes available |
| 110 | 172 |
| 111 unsigned char b; | 173 unsigned char b; |
| 112 | 174 |
| 113 status = pReader->Read(pos, 1, &b); | 175 status = pReader->Read(pos, 1, &b); |
| 114 | 176 |
| 115 if (status < 0) | 177 if (status != 0) |
| 116 return status; | 178 return status; |
| 117 | 179 |
| 118 assert(status == 0); | |
| 119 | |
| 120 if (b == 0) // we can't handle u-int values larger than 8 bytes | 180 if (b == 0) // we can't handle u-int values larger than 8 bytes |
| 121 return E_FILE_FORMAT_INVALID; | 181 return E_FILE_FORMAT_INVALID; |
| 122 | 182 |
| 123 unsigned char m = 0x80; | 183 unsigned char m = 0x80; |
| 124 | 184 |
| 125 while (!(b & m)) { | 185 while (!(b & m)) { |
| 126 m >>= 1; | 186 m >>= 1; |
| 127 ++len; | 187 ++len; |
| 128 } | 188 } |
| 129 | 189 |
| 130 return 0; // success | 190 return 0; // success |
| 131 } | 191 } |
| 132 | 192 |
| 133 // TODO(vigneshv): This function assumes that unsigned values never have their | 193 // TODO(vigneshv): This function assumes that unsigned values never have their |
| 134 // high bit set. | 194 // high bit set. |
| 135 long long mkvparser::UnserializeUInt(IMkvReader* pReader, long long pos, | 195 long long UnserializeUInt(IMkvReader* pReader, long long pos, long long size) { |
| 136 long long size) { | 196 if (!pReader || pos < 0 || (size <= 0) || (size > 8)) |
| 137 assert(pReader); | |
| 138 assert(pos >= 0); | |
| 139 | |
| 140 if ((size <= 0) || (size > 8)) | |
| 141 return E_FILE_FORMAT_INVALID; | 197 return E_FILE_FORMAT_INVALID; |
| 142 | 198 |
| 143 long long result = 0; | 199 long long result = 0; |
| 144 | 200 |
| 145 for (long long i = 0; i < size; ++i) { | 201 for (long long i = 0; i < size; ++i) { |
| 146 unsigned char b; | 202 unsigned char b; |
| 147 | 203 |
| 148 const long status = pReader->Read(pos, 1, &b); | 204 const long status = pReader->Read(pos, 1, &b); |
| 149 | 205 |
| 150 if (status < 0) | 206 if (status < 0) |
| 151 return status; | 207 return status; |
| 152 | 208 |
| 153 result <<= 8; | 209 result <<= 8; |
| 154 result |= b; | 210 result |= b; |
| 155 | 211 |
| 156 ++pos; | 212 ++pos; |
| 157 } | 213 } |
| 158 | 214 |
| 159 return result; | 215 return result; |
| 160 } | 216 } |
| 161 | 217 |
| 162 long mkvparser::UnserializeFloat(IMkvReader* pReader, long long pos, | 218 long UnserializeFloat(IMkvReader* pReader, long long pos, long long size_, |
| 163 long long size_, double& result) { | 219 double& result) { |
| 164 assert(pReader); | 220 if (!pReader || pos < 0 || ((size_ != 4) && (size_ != 8))) |
| 165 assert(pos >= 0); | |
| 166 | |
| 167 if ((size_ != 4) && (size_ != 8)) | |
| 168 return E_FILE_FORMAT_INVALID; | 221 return E_FILE_FORMAT_INVALID; |
| 169 | 222 |
| 170 const long size = static_cast<long>(size_); | 223 const long size = static_cast<long>(size_); |
| 171 | 224 |
| 172 unsigned char buf[8]; | 225 unsigned char buf[8]; |
| 173 | 226 |
| 174 const int status = pReader->Read(pos, size, buf); | 227 const int status = pReader->Read(pos, size, buf); |
| 175 | 228 |
| 176 if (status < 0) // error | 229 if (status < 0) // error |
| 177 return status; | 230 return status; |
| (...skipping 10 matching lines...) Expand all Loading... |
| 188 ff |= buf[i]; | 241 ff |= buf[i]; |
| 189 | 242 |
| 190 if (++i >= 4) | 243 if (++i >= 4) |
| 191 break; | 244 break; |
| 192 | 245 |
| 193 ff <<= 8; | 246 ff <<= 8; |
| 194 } | 247 } |
| 195 | 248 |
| 196 result = f; | 249 result = f; |
| 197 } else { | 250 } else { |
| 198 assert(size == 8); | |
| 199 | |
| 200 union { | 251 union { |
| 201 double d; | 252 double d; |
| 202 unsigned long long dd; | 253 unsigned long long dd; |
| 203 }; | 254 }; |
| 204 | 255 |
| 205 dd = 0; | 256 dd = 0; |
| 206 | 257 |
| 207 for (int i = 0;;) { | 258 for (int i = 0;;) { |
| 208 dd |= buf[i]; | 259 dd |= buf[i]; |
| 209 | 260 |
| 210 if (++i >= 8) | 261 if (++i >= 8) |
| 211 break; | 262 break; |
| 212 | 263 |
| 213 dd <<= 8; | 264 dd <<= 8; |
| 214 } | 265 } |
| 215 | 266 |
| 216 result = d; | 267 result = d; |
| 217 } | 268 } |
| 218 | 269 |
| 270 if (std::isinf(result) || std::isnan(result)) |
| 271 return E_FILE_FORMAT_INVALID; |
| 272 |
| 219 return 0; | 273 return 0; |
| 220 } | 274 } |
| 221 | 275 |
| 222 long mkvparser::UnserializeInt(IMkvReader* pReader, long long pos, | 276 long UnserializeInt(IMkvReader* pReader, long long pos, long long size, |
| 223 long long size, long long& result) { | 277 long long& result_ref) { |
| 224 assert(pReader); | 278 if (!pReader || pos < 0 || size < 1 || size > 8) |
| 225 assert(pos >= 0); | 279 return E_FILE_FORMAT_INVALID; |
| 226 assert(size > 0); | |
| 227 assert(size <= 8); | |
| 228 | 280 |
| 229 { | 281 signed char first_byte = 0; |
| 230 signed char b; | 282 const long status = pReader->Read(pos, 1, (unsigned char*)&first_byte); |
| 231 | 283 |
| 232 const long status = pReader->Read(pos, 1, (unsigned char*)&b); | 284 if (status < 0) |
| 285 return status; |
| 233 | 286 |
| 234 if (status < 0) | 287 unsigned long long result = first_byte; |
| 235 return status; | 288 ++pos; |
| 236 | |
| 237 result = b; | |
| 238 | |
| 239 ++pos; | |
| 240 } | |
| 241 | 289 |
| 242 for (long i = 1; i < size; ++i) { | 290 for (long i = 1; i < size; ++i) { |
| 243 unsigned char b; | 291 unsigned char b; |
| 244 | 292 |
| 245 const long status = pReader->Read(pos, 1, &b); | 293 const long status = pReader->Read(pos, 1, &b); |
| 246 | 294 |
| 247 if (status < 0) | 295 if (status < 0) |
| 248 return status; | 296 return status; |
| 249 | 297 |
| 250 result <<= 8; | 298 result <<= 8; |
| 251 result |= b; | 299 result |= b; |
| 252 | 300 |
| 253 ++pos; | 301 ++pos; |
| 254 } | 302 } |
| 255 | 303 |
| 256 return 0; // success | 304 result_ref = static_cast<long long>(result); |
| 305 return 0; |
| 257 } | 306 } |
| 258 | 307 |
| 259 long mkvparser::UnserializeString(IMkvReader* pReader, long long pos, | 308 long UnserializeString(IMkvReader* pReader, long long pos, long long size, |
| 260 long long size_, char*& str) { | 309 char*& str) { |
| 261 delete[] str; | 310 delete[] str; |
| 262 str = NULL; | 311 str = NULL; |
| 263 | 312 |
| 264 if (size_ >= LONG_MAX) // we need (size+1) chars | 313 if (size >= LONG_MAX || size < 0) |
| 265 return E_FILE_FORMAT_INVALID; | 314 return E_FILE_FORMAT_INVALID; |
| 266 | 315 |
| 267 const long size = static_cast<long>(size_); | 316 // +1 for '\0' terminator |
| 317 const long required_size = static_cast<long>(size) + 1; |
| 268 | 318 |
| 269 str = new (std::nothrow) char[size + 1]; | 319 str = SafeArrayAlloc<char>(1, required_size); |
| 270 | |
| 271 if (str == NULL) | 320 if (str == NULL) |
| 272 return -1; | 321 return E_FILE_FORMAT_INVALID; |
| 273 | 322 |
| 274 unsigned char* const buf = reinterpret_cast<unsigned char*>(str); | 323 unsigned char* const buf = reinterpret_cast<unsigned char*>(str); |
| 275 | 324 |
| 276 const long status = pReader->Read(pos, size, buf); | 325 const long status = pReader->Read(pos, size, buf); |
| 277 | 326 |
| 278 if (status) { | 327 if (status) { |
| 279 delete[] str; | 328 delete[] str; |
| 280 str = NULL; | 329 str = NULL; |
| 281 | 330 |
| 282 return status; | 331 return status; |
| 283 } | 332 } |
| 284 | 333 |
| 285 str[size] = '\0'; | 334 str[required_size - 1] = '\0'; |
| 286 | 335 return 0; |
| 287 return 0; // success | |
| 288 } | 336 } |
| 289 | 337 |
| 290 long mkvparser::ParseElementHeader(IMkvReader* pReader, long long& pos, | 338 long ParseElementHeader(IMkvReader* pReader, long long& pos, |
| 291 long long stop, long long& id, | 339 long long stop, long long& id, |
| 292 long long& size) { | 340 long long& size) { |
| 293 if ((stop >= 0) && (pos >= stop)) | 341 if (stop >= 0 && pos >= stop) |
| 294 return E_FILE_FORMAT_INVALID; | 342 return E_FILE_FORMAT_INVALID; |
| 295 | 343 |
| 296 long len; | 344 long len; |
| 297 | 345 |
| 298 id = ReadUInt(pReader, pos, len); | 346 id = ReadID(pReader, pos, len); |
| 299 | 347 |
| 300 if (id < 0) | 348 if (id < 0) |
| 301 return E_FILE_FORMAT_INVALID; | 349 return E_FILE_FORMAT_INVALID; |
| 302 | 350 |
| 303 pos += len; // consume id | 351 pos += len; // consume id |
| 304 | 352 |
| 305 if ((stop >= 0) && (pos >= stop)) | 353 if (stop >= 0 && pos >= stop) |
| 306 return E_FILE_FORMAT_INVALID; | 354 return E_FILE_FORMAT_INVALID; |
| 307 | 355 |
| 308 size = ReadUInt(pReader, pos, len); | 356 size = ReadUInt(pReader, pos, len); |
| 309 | 357 |
| 310 if (size < 0) | 358 if (size < 0 || len < 1 || len > 8) { |
| 359 // Invalid: Negative payload size, negative or 0 length integer, or integer |
| 360 // larger than 64 bits (libwebm cannot handle them). |
| 361 return E_FILE_FORMAT_INVALID; |
| 362 } |
| 363 |
| 364 // Avoid rolling over pos when very close to LONG_LONG_MAX. |
| 365 const unsigned long long rollover_check = |
| 366 static_cast<unsigned long long>(pos) + len; |
| 367 if (rollover_check > LONG_LONG_MAX) |
| 311 return E_FILE_FORMAT_INVALID; | 368 return E_FILE_FORMAT_INVALID; |
| 312 | 369 |
| 313 pos += len; // consume length of size | 370 pos += len; // consume length of size |
| 314 | 371 |
| 315 // pos now designates payload | 372 // pos now designates payload |
| 316 | 373 |
| 317 if ((stop >= 0) && ((pos + size) > stop)) | 374 if (stop >= 0 && pos >= stop) |
| 318 return E_FILE_FORMAT_INVALID; | 375 return E_FILE_FORMAT_INVALID; |
| 319 | 376 |
| 320 return 0; // success | 377 return 0; // success |
| 321 } | 378 } |
| 322 | 379 |
| 323 bool mkvparser::Match(IMkvReader* pReader, long long& pos, unsigned long id_, | 380 bool Match(IMkvReader* pReader, long long& pos, unsigned long expected_id, |
| 324 long long& val) { | 381 long long& val) { |
| 325 assert(pReader); | 382 if (!pReader || pos < 0) |
| 326 assert(pos >= 0); | 383 return false; |
| 327 | 384 |
| 328 long long total, available; | 385 long long total = 0; |
| 386 long long available = 0; |
| 329 | 387 |
| 330 const long status = pReader->Length(&total, &available); | 388 const long status = pReader->Length(&total, &available); |
| 331 assert(status >= 0); | 389 if (status < 0 || (total >= 0 && available > total)) |
| 332 assert((total < 0) || (available <= total)); | |
| 333 if (status < 0) | |
| 334 return false; | 390 return false; |
| 335 | 391 |
| 336 long len; | 392 long len = 0; |
| 337 | 393 |
| 338 const long long id = ReadUInt(pReader, pos, len); | 394 const long long id = ReadID(pReader, pos, len); |
| 339 assert(id >= 0); | 395 if (id < 0 || (available - pos) > len) |
| 340 assert(len > 0); | 396 return false; |
| 341 assert(len <= 8); | |
| 342 assert((pos + len) <= available); | |
| 343 | 397 |
| 344 if ((unsigned long)id != id_) | 398 if (static_cast<unsigned long>(id) != expected_id) |
| 345 return false; | 399 return false; |
| 346 | 400 |
| 347 pos += len; // consume id | 401 pos += len; // consume id |
| 348 | 402 |
| 349 const long long size = ReadUInt(pReader, pos, len); | 403 const long long size = ReadUInt(pReader, pos, len); |
| 350 assert(size >= 0); | 404 if (size < 0 || size > 8 || len < 1 || len > 8 || (available - pos) > len) |
| 351 assert(size <= 8); | 405 return false; |
| 352 assert(len > 0); | |
| 353 assert(len <= 8); | |
| 354 assert((pos + len) <= available); | |
| 355 | 406 |
| 356 pos += len; // consume length of size of payload | 407 pos += len; // consume length of size of payload |
| 357 | 408 |
| 358 val = UnserializeUInt(pReader, pos, size); | 409 val = UnserializeUInt(pReader, pos, size); |
| 359 assert(val >= 0); | 410 if (val < 0) |
| 411 return false; |
| 360 | 412 |
| 361 pos += size; // consume size of payload | 413 pos += size; // consume size of payload |
| 362 | 414 |
| 363 return true; | 415 return true; |
| 364 } | 416 } |
| 365 | 417 |
| 366 bool mkvparser::Match(IMkvReader* pReader, long long& pos, unsigned long id_, | 418 bool Match(IMkvReader* pReader, long long& pos, unsigned long expected_id, |
| 367 unsigned char*& buf, size_t& buflen) { | 419 unsigned char*& buf, size_t& buflen) { |
| 368 assert(pReader); | 420 if (!pReader || pos < 0) |
| 369 assert(pos >= 0); | 421 return false; |
| 370 | 422 |
| 371 long long total, available; | 423 long long total = 0; |
| 424 long long available = 0; |
| 372 | 425 |
| 373 long status = pReader->Length(&total, &available); | 426 long status = pReader->Length(&total, &available); |
| 374 assert(status >= 0); | 427 if (status < 0 || (total >= 0 && available > total)) |
| 375 assert((total < 0) || (available <= total)); | |
| 376 if (status < 0) | |
| 377 return false; | 428 return false; |
| 378 | 429 |
| 379 long len; | 430 long len = 0; |
| 380 const long long id = ReadUInt(pReader, pos, len); | 431 const long long id = ReadID(pReader, pos, len); |
| 381 assert(id >= 0); | 432 if (id < 0 || (available - pos) > len) |
| 382 assert(len > 0); | 433 return false; |
| 383 assert(len <= 8); | |
| 384 assert((pos + len) <= available); | |
| 385 | 434 |
| 386 if ((unsigned long)id != id_) | 435 if (static_cast<unsigned long>(id) != expected_id) |
| 387 return false; | 436 return false; |
| 388 | 437 |
| 389 pos += len; // consume id | 438 pos += len; // consume id |
| 390 | 439 |
| 391 const long long size_ = ReadUInt(pReader, pos, len); | 440 const long long size = ReadUInt(pReader, pos, len); |
| 392 assert(size_ >= 0); | 441 if (size < 0 || len <= 0 || len > 8 || (available - pos) > len) |
| 393 assert(len > 0); | 442 return false; |
| 394 assert(len <= 8); | 443 |
| 395 assert((pos + len) <= available); | 444 unsigned long long rollover_check = |
| 445 static_cast<unsigned long long>(pos) + len; |
| 446 if (rollover_check > LONG_LONG_MAX) |
| 447 return false; |
| 396 | 448 |
| 397 pos += len; // consume length of size of payload | 449 pos += len; // consume length of size of payload |
| 398 assert((pos + size_) <= available); | |
| 399 | 450 |
| 400 const long buflen_ = static_cast<long>(size_); | 451 rollover_check = static_cast<unsigned long long>(pos) + size; |
| 452 if (rollover_check > LONG_LONG_MAX) |
| 453 return false; |
| 401 | 454 |
| 402 buf = new (std::nothrow) unsigned char[buflen_]; | 455 if ((pos + size) > available) |
| 403 assert(buf); // TODO | 456 return false; |
| 457 |
| 458 if (size >= LONG_MAX) |
| 459 return false; |
| 460 |
| 461 const long buflen_ = static_cast<long>(size); |
| 462 |
| 463 buf = SafeArrayAlloc<unsigned char>(1, buflen_); |
| 464 if (!buf) |
| 465 return false; |
| 404 | 466 |
| 405 status = pReader->Read(pos, buflen_, buf); | 467 status = pReader->Read(pos, buflen_, buf); |
| 406 assert(status == 0); // TODO | 468 if (status != 0) |
| 469 return false; |
| 407 | 470 |
| 408 buflen = buflen_; | 471 buflen = buflen_; |
| 409 | 472 |
| 410 pos += size_; // consume size of payload | 473 pos += size; // consume size of payload |
| 411 return true; | 474 return true; |
| 412 } | 475 } |
| 413 | 476 |
| 414 namespace mkvparser { | |
| 415 | |
| 416 EBMLHeader::EBMLHeader() : m_docType(NULL) { Init(); } | 477 EBMLHeader::EBMLHeader() : m_docType(NULL) { Init(); } |
| 417 | 478 |
| 418 EBMLHeader::~EBMLHeader() { delete[] m_docType; } | 479 EBMLHeader::~EBMLHeader() { delete[] m_docType; } |
| 419 | 480 |
| 420 void EBMLHeader::Init() { | 481 void EBMLHeader::Init() { |
| 421 m_version = 1; | 482 m_version = 1; |
| 422 m_readVersion = 1; | 483 m_readVersion = 1; |
| 423 m_maxIdLength = 4; | 484 m_maxIdLength = 4; |
| 424 m_maxSizeLength = 8; | 485 m_maxSizeLength = 8; |
| 425 | 486 |
| 426 if (m_docType) { | 487 if (m_docType) { |
| 427 delete[] m_docType; | 488 delete[] m_docType; |
| 428 m_docType = NULL; | 489 m_docType = NULL; |
| 429 } | 490 } |
| 430 | 491 |
| 431 m_docTypeVersion = 1; | 492 m_docTypeVersion = 1; |
| 432 m_docTypeReadVersion = 1; | 493 m_docTypeReadVersion = 1; |
| 433 } | 494 } |
| 434 | 495 |
| 435 long long EBMLHeader::Parse(IMkvReader* pReader, long long& pos) { | 496 long long EBMLHeader::Parse(IMkvReader* pReader, long long& pos) { |
| 436 assert(pReader); | 497 if (!pReader) |
| 498 return E_FILE_FORMAT_INVALID; |
| 437 | 499 |
| 438 long long total, available; | 500 long long total, available; |
| 439 | 501 |
| 440 long status = pReader->Length(&total, &available); | 502 long status = pReader->Length(&total, &available); |
| 441 | 503 |
| 442 if (status < 0) // error | 504 if (status < 0) // error |
| 443 return status; | 505 return status; |
| 444 | 506 |
| 445 pos = 0; | 507 pos = 0; |
| 446 long long end = (available >= 1024) ? 1024 : available; | 508 long long end = (available >= 1024) ? 1024 : available; |
| 447 | 509 |
| 448 for (;;) { | 510 // Scan until we find what looks like the first byte of the EBML header. |
| 449 unsigned char b = 0; | 511 const int kMaxScanBytes = (available >= 1024) ? 1024 : available; |
| 512 const unsigned char kEbmlByte0 = 0x1A; |
| 513 unsigned char scan_byte = 0; |
| 450 | 514 |
| 451 while (pos < end) { | 515 while (pos < kMaxScanBytes) { |
| 452 status = pReader->Read(pos, 1, &b); | 516 status = pReader->Read(pos, 1, &scan_byte); |
| 453 | 517 |
| 454 if (status < 0) // error | 518 if (status < 0) // error |
| 455 return status; | 519 return status; |
| 520 else if (status > 0) |
| 521 return E_BUFFER_NOT_FULL; |
| 456 | 522 |
| 457 if (b == 0x1A) | 523 if (scan_byte == kEbmlByte0) |
| 458 break; | 524 break; |
| 459 | 525 |
| 460 ++pos; | 526 ++pos; |
| 461 } | |
| 462 | |
| 463 if (b != 0x1A) { | |
| 464 if (pos >= 1024) | |
| 465 return E_FILE_FORMAT_INVALID; // don't bother looking anymore | |
| 466 | |
| 467 if ((total >= 0) && ((total - available) < 5)) | |
| 468 return E_FILE_FORMAT_INVALID; | |
| 469 | |
| 470 return available + 5; // 5 = 4-byte ID + 1st byte of size | |
| 471 } | |
| 472 | |
| 473 if ((total >= 0) && ((total - pos) < 5)) | |
| 474 return E_FILE_FORMAT_INVALID; | |
| 475 | |
| 476 if ((available - pos) < 5) | |
| 477 return pos + 5; // try again later | |
| 478 | |
| 479 long len; | |
| 480 | |
| 481 const long long result = ReadUInt(pReader, pos, len); | |
| 482 | |
| 483 if (result < 0) // error | |
| 484 return result; | |
| 485 | |
| 486 if (result == 0x0A45DFA3) { // EBML Header ID | |
| 487 pos += len; // consume ID | |
| 488 break; | |
| 489 } | |
| 490 | |
| 491 ++pos; // throw away just the 0x1A byte, and try again | |
| 492 } | 527 } |
| 493 | 528 |
| 494 // pos designates start of size field | 529 long len = 0; |
| 530 const long long ebml_id = ReadID(pReader, pos, len); |
| 495 | 531 |
| 496 // get length of size field | 532 // TODO(tomfinegan): Move Matroska ID constants into a common namespace. |
| 533 if (len != 4 || ebml_id != mkvmuxer::kMkvEBML) |
| 534 return E_FILE_FORMAT_INVALID; |
| 497 | 535 |
| 498 long len; | 536 // Move read pos forward to the EBML header size field. |
| 537 pos += 4; |
| 538 |
| 539 // Read length of size field. |
| 499 long long result = GetUIntLength(pReader, pos, len); | 540 long long result = GetUIntLength(pReader, pos, len); |
| 500 | 541 |
| 501 if (result < 0) // error | 542 if (result < 0) // error |
| 502 return result; | 543 return E_FILE_FORMAT_INVALID; |
| 544 else if (result > 0) // need more data |
| 545 return E_BUFFER_NOT_FULL; |
| 503 | 546 |
| 504 if (result > 0) // need more data | 547 if (len < 1 || len > 8) |
| 505 return result; | 548 return E_FILE_FORMAT_INVALID; |
| 506 | |
| 507 assert(len > 0); | |
| 508 assert(len <= 8); | |
| 509 | 549 |
| 510 if ((total >= 0) && ((total - pos) < len)) | 550 if ((total >= 0) && ((total - pos) < len)) |
| 511 return E_FILE_FORMAT_INVALID; | 551 return E_FILE_FORMAT_INVALID; |
| 512 | 552 |
| 513 if ((available - pos) < len) | 553 if ((available - pos) < len) |
| 514 return pos + len; // try again later | 554 return pos + len; // try again later |
| 515 | 555 |
| 516 // get the EBML header size | 556 // Read the EBML header size. |
| 517 | |
| 518 result = ReadUInt(pReader, pos, len); | 557 result = ReadUInt(pReader, pos, len); |
| 519 | 558 |
| 520 if (result < 0) // error | 559 if (result < 0) // error |
| 521 return result; | 560 return result; |
| 522 | 561 |
| 523 pos += len; // consume size field | 562 pos += len; // consume size field |
| 524 | 563 |
| 525 // pos now designates start of payload | 564 // pos now designates start of payload |
| 526 | 565 |
| 527 if ((total >= 0) && ((total - pos) < result)) | 566 if ((total >= 0) && ((total - pos) < result)) |
| 528 return E_FILE_FORMAT_INVALID; | 567 return E_FILE_FORMAT_INVALID; |
| 529 | 568 |
| 530 if ((available - pos) < result) | 569 if ((available - pos) < result) |
| 531 return pos + result; | 570 return pos + result; |
| 532 | 571 |
| 533 end = pos + result; | 572 end = pos + result; |
| 534 | 573 |
| 535 Init(); | 574 Init(); |
| 536 | 575 |
| 537 while (pos < end) { | 576 while (pos < end) { |
| 538 long long id, size; | 577 long long id, size; |
| 539 | 578 |
| 540 status = ParseElementHeader(pReader, pos, end, id, size); | 579 status = ParseElementHeader(pReader, pos, end, id, size); |
| 541 | 580 |
| 542 if (status < 0) // error | 581 if (status < 0) // error |
| 543 return status; | 582 return status; |
| 544 | 583 |
| 545 if (size == 0) // weird | 584 if (size == 0) |
| 546 return E_FILE_FORMAT_INVALID; | 585 return E_FILE_FORMAT_INVALID; |
| 547 | 586 |
| 548 if (id == 0x0286) { // version | 587 if (id == mkvmuxer::kMkvEBMLVersion) { |
| 549 m_version = UnserializeUInt(pReader, pos, size); | 588 m_version = UnserializeUInt(pReader, pos, size); |
| 550 | 589 |
| 551 if (m_version <= 0) | 590 if (m_version <= 0) |
| 552 return E_FILE_FORMAT_INVALID; | 591 return E_FILE_FORMAT_INVALID; |
| 553 } else if (id == 0x02F7) { // read version | 592 } else if (id == mkvmuxer::kMkvEBMLReadVersion) { |
| 554 m_readVersion = UnserializeUInt(pReader, pos, size); | 593 m_readVersion = UnserializeUInt(pReader, pos, size); |
| 555 | 594 |
| 556 if (m_readVersion <= 0) | 595 if (m_readVersion <= 0) |
| 557 return E_FILE_FORMAT_INVALID; | 596 return E_FILE_FORMAT_INVALID; |
| 558 } else if (id == 0x02F2) { // max id length | 597 } else if (id == mkvmuxer::kMkvEBMLMaxIDLength) { |
| 559 m_maxIdLength = UnserializeUInt(pReader, pos, size); | 598 m_maxIdLength = UnserializeUInt(pReader, pos, size); |
| 560 | 599 |
| 561 if (m_maxIdLength <= 0) | 600 if (m_maxIdLength <= 0) |
| 562 return E_FILE_FORMAT_INVALID; | 601 return E_FILE_FORMAT_INVALID; |
| 563 } else if (id == 0x02F3) { // max size length | 602 } else if (id == mkvmuxer::kMkvEBMLMaxSizeLength) { |
| 564 m_maxSizeLength = UnserializeUInt(pReader, pos, size); | 603 m_maxSizeLength = UnserializeUInt(pReader, pos, size); |
| 565 | 604 |
| 566 if (m_maxSizeLength <= 0) | 605 if (m_maxSizeLength <= 0) |
| 567 return E_FILE_FORMAT_INVALID; | 606 return E_FILE_FORMAT_INVALID; |
| 568 } else if (id == 0x0282) { // doctype | 607 } else if (id == mkvmuxer::kMkvDocType) { |
| 569 if (m_docType) | 608 if (m_docType) |
| 570 return E_FILE_FORMAT_INVALID; | 609 return E_FILE_FORMAT_INVALID; |
| 571 | 610 |
| 572 status = UnserializeString(pReader, pos, size, m_docType); | 611 status = UnserializeString(pReader, pos, size, m_docType); |
| 573 | 612 |
| 574 if (status) // error | 613 if (status) // error |
| 575 return status; | 614 return status; |
| 576 } else if (id == 0x0287) { // doctype version | 615 } else if (id == mkvmuxer::kMkvDocTypeVersion) { |
| 577 m_docTypeVersion = UnserializeUInt(pReader, pos, size); | 616 m_docTypeVersion = UnserializeUInt(pReader, pos, size); |
| 578 | 617 |
| 579 if (m_docTypeVersion <= 0) | 618 if (m_docTypeVersion <= 0) |
| 580 return E_FILE_FORMAT_INVALID; | 619 return E_FILE_FORMAT_INVALID; |
| 581 } else if (id == 0x0285) { // doctype read version | 620 } else if (id == mkvmuxer::kMkvDocTypeReadVersion) { |
| 582 m_docTypeReadVersion = UnserializeUInt(pReader, pos, size); | 621 m_docTypeReadVersion = UnserializeUInt(pReader, pos, size); |
| 583 | 622 |
| 584 if (m_docTypeReadVersion <= 0) | 623 if (m_docTypeReadVersion <= 0) |
| 585 return E_FILE_FORMAT_INVALID; | 624 return E_FILE_FORMAT_INVALID; |
| 586 } | 625 } |
| 587 | 626 |
| 588 pos += size; | 627 pos += size; |
| 589 } | 628 } |
| 590 | 629 |
| 591 assert(pos == end); | 630 if (pos != end) |
| 631 return E_FILE_FORMAT_INVALID; |
| 632 |
| 633 // Make sure DocType, DocTypeReadVersion, and DocTypeVersion are valid. |
| 634 if (m_docType == NULL || m_docTypeReadVersion <= 0 || m_docTypeVersion <= 0) |
| 635 return E_FILE_FORMAT_INVALID; |
| 636 |
| 637 // Make sure EBMLMaxIDLength and EBMLMaxSizeLength are valid. |
| 638 if (m_maxIdLength <= 0 || m_maxIdLength > 4 || |
| 639 m_maxSizeLength <= 0 || m_maxSizeLength > 8) |
| 640 return E_FILE_FORMAT_INVALID; |
| 641 |
| 592 return 0; | 642 return 0; |
| 593 } | 643 } |
| 594 | 644 |
| 595 Segment::Segment(IMkvReader* pReader, long long elem_start, | 645 Segment::Segment(IMkvReader* pReader, long long elem_start, |
| 596 // long long elem_size, | 646 // long long elem_size, |
| 597 long long start, long long size) | 647 long long start, long long size) |
| 598 : m_pReader(pReader), | 648 : m_pReader(pReader), |
| 599 m_element_start(elem_start), | 649 m_element_start(elem_start), |
| 600 // m_element_size(elem_size), | 650 // m_element_size(elem_size), |
| 601 m_start(start), | 651 m_start(start), |
| (...skipping 12 matching lines...) Expand all Loading... |
| 614 m_clusterSize(0) {} | 664 m_clusterSize(0) {} |
| 615 | 665 |
| 616 Segment::~Segment() { | 666 Segment::~Segment() { |
| 617 const long count = m_clusterCount + m_clusterPreloadCount; | 667 const long count = m_clusterCount + m_clusterPreloadCount; |
| 618 | 668 |
| 619 Cluster** i = m_clusters; | 669 Cluster** i = m_clusters; |
| 620 Cluster** j = m_clusters + count; | 670 Cluster** j = m_clusters + count; |
| 621 | 671 |
| 622 while (i != j) { | 672 while (i != j) { |
| 623 Cluster* const p = *i++; | 673 Cluster* const p = *i++; |
| 624 assert(p); | |
| 625 | |
| 626 delete p; | 674 delete p; |
| 627 } | 675 } |
| 628 | 676 |
| 629 delete[] m_clusters; | 677 delete[] m_clusters; |
| 630 | 678 |
| 631 delete m_pTracks; | 679 delete m_pTracks; |
| 632 delete m_pInfo; | 680 delete m_pInfo; |
| 633 delete m_pCues; | 681 delete m_pCues; |
| 634 delete m_pChapters; | 682 delete m_pChapters; |
| 635 delete m_pTags; | 683 delete m_pTags; |
| 636 delete m_pSeekHead; | 684 delete m_pSeekHead; |
| 637 } | 685 } |
| 638 | 686 |
| 639 long long Segment::CreateInstance(IMkvReader* pReader, long long pos, | 687 long long Segment::CreateInstance(IMkvReader* pReader, long long pos, |
| 640 Segment*& pSegment) { | 688 Segment*& pSegment) { |
| 641 assert(pReader); | 689 if (pReader == NULL || pos < 0) |
| 642 assert(pos >= 0); | 690 return E_PARSE_FAILED; |
| 643 | 691 |
| 644 pSegment = NULL; | 692 pSegment = NULL; |
| 645 | 693 |
| 646 long long total, available; | 694 long long total, available; |
| 647 | 695 |
| 648 const long status = pReader->Length(&total, &available); | 696 const long status = pReader->Length(&total, &available); |
| 649 | 697 |
| 650 if (status < 0) // error | 698 if (status < 0) // error |
| 651 return status; | 699 return status; |
| 652 | 700 |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 684 if (result) // error, or too few available bytes | 732 if (result) // error, or too few available bytes |
| 685 return result; | 733 return result; |
| 686 | 734 |
| 687 if ((total >= 0) && ((pos + len) > total)) | 735 if ((total >= 0) && ((pos + len) > total)) |
| 688 return E_FILE_FORMAT_INVALID; | 736 return E_FILE_FORMAT_INVALID; |
| 689 | 737 |
| 690 if ((pos + len) > available) | 738 if ((pos + len) > available) |
| 691 return pos + len; | 739 return pos + len; |
| 692 | 740 |
| 693 const long long idpos = pos; | 741 const long long idpos = pos; |
| 694 const long long id = ReadUInt(pReader, pos, len); | 742 const long long id = ReadID(pReader, pos, len); |
| 695 | 743 |
| 696 if (id < 0) // error | 744 if (id < 0) |
| 697 return id; | 745 return E_FILE_FORMAT_INVALID; |
| 698 | 746 |
| 699 pos += len; // consume ID | 747 pos += len; // consume ID |
| 700 | 748 |
| 701 // Read Size | 749 // Read Size |
| 702 | 750 |
| 703 result = GetUIntLength(pReader, pos, len); | 751 result = GetUIntLength(pReader, pos, len); |
| 704 | 752 |
| 705 if (result) // error, or too few available bytes | 753 if (result) // error, or too few available bytes |
| 706 return result; | 754 return result; |
| 707 | 755 |
| 708 if ((total >= 0) && ((pos + len) > total)) | 756 if ((total >= 0) && ((pos + len) > total)) |
| 709 return E_FILE_FORMAT_INVALID; | 757 return E_FILE_FORMAT_INVALID; |
| 710 | 758 |
| 711 if ((pos + len) > available) | 759 if ((pos + len) > available) |
| 712 return pos + len; | 760 return pos + len; |
| 713 | 761 |
| 714 long long size = ReadUInt(pReader, pos, len); | 762 long long size = ReadUInt(pReader, pos, len); |
| 715 | 763 |
| 716 if (size < 0) // error | 764 if (size < 0) // error |
| 717 return size; | 765 return size; |
| 718 | 766 |
| 719 pos += len; // consume length of size of element | 767 pos += len; // consume length of size of element |
| 720 | 768 |
| 721 // Pos now points to start of payload | 769 // Pos now points to start of payload |
| 722 | 770 |
| 723 // Handle "unknown size" for live streaming of webm files. | 771 // Handle "unknown size" for live streaming of webm files. |
| 724 const long long unknown_size = (1LL << (7 * len)) - 1; | 772 const long long unknown_size = (1LL << (7 * len)) - 1; |
| 725 | 773 |
| 726 if (id == 0x08538067) { // Segment ID | 774 if (id == mkvmuxer::kMkvSegment) { |
| 727 if (size == unknown_size) | 775 if (size == unknown_size) |
| 728 size = -1; | 776 size = -1; |
| 729 | 777 |
| 730 else if (total < 0) | 778 else if (total < 0) |
| 731 size = -1; | 779 size = -1; |
| 732 | 780 |
| 733 else if ((pos + size) > total) | 781 else if ((pos + size) > total) |
| 734 size = -1; | 782 size = -1; |
| 735 | 783 |
| 736 pSegment = new (std::nothrow) Segment(pReader, idpos, | 784 pSegment = new (std::nothrow) Segment(pReader, idpos, pos, size); |
| 737 // elem_size | 785 if (pSegment == NULL) |
| 738 pos, size); | 786 return E_PARSE_FAILED; |
| 739 | |
| 740 if (pSegment == 0) | |
| 741 return -1; // generic error | |
| 742 | 787 |
| 743 return 0; // success | 788 return 0; // success |
| 744 } | 789 } |
| 745 | 790 |
| 746 if (size == unknown_size) | 791 if (size == unknown_size) |
| 747 return E_FILE_FORMAT_INVALID; | 792 return E_FILE_FORMAT_INVALID; |
| 748 | 793 |
| 749 if ((total >= 0) && ((pos + size) > total)) | 794 if ((total >= 0) && ((pos + size) > total)) |
| 750 return E_FILE_FORMAT_INVALID; | 795 return E_FILE_FORMAT_INVALID; |
| 751 | 796 |
| 752 if ((pos + size) > available) | 797 if ((pos + size) > available) |
| 753 return pos + size; | 798 return pos + size; |
| 754 | 799 |
| 755 pos += size; // consume payload | 800 pos += size; // consume payload |
| 756 } | 801 } |
| 757 } | 802 } |
| 758 | 803 |
| 759 long long Segment::ParseHeaders() { | 804 long long Segment::ParseHeaders() { |
| 760 // Outermost (level 0) segment object has been constructed, | 805 // Outermost (level 0) segment object has been constructed, |
| 761 // and pos designates start of payload. We need to find the | 806 // and pos designates start of payload. We need to find the |
| 762 // inner (level 1) elements. | 807 // inner (level 1) elements. |
| 763 long long total, available; | 808 long long total, available; |
| 764 | 809 |
| 765 const int status = m_pReader->Length(&total, &available); | 810 const int status = m_pReader->Length(&total, &available); |
| 766 | 811 |
| 767 if (status < 0) // error | 812 if (status < 0) // error |
| 768 return status; | 813 return status; |
| 769 | 814 |
| 770 assert((total < 0) || (available <= total)); | 815 if (total > 0 && available > total) |
| 816 return E_FILE_FORMAT_INVALID; |
| 771 | 817 |
| 772 const long long segment_stop = (m_size < 0) ? -1 : m_start + m_size; | 818 const long long segment_stop = (m_size < 0) ? -1 : m_start + m_size; |
| 773 assert((segment_stop < 0) || (total < 0) || (segment_stop <= total)); | 819 |
| 774 assert((segment_stop < 0) || (m_pos <= segment_stop)); | 820 if ((segment_stop >= 0 && total >= 0 && segment_stop > total) || |
| 821 (segment_stop >= 0 && m_pos > segment_stop)) { |
| 822 return E_FILE_FORMAT_INVALID; |
| 823 } |
| 775 | 824 |
| 776 for (;;) { | 825 for (;;) { |
| 777 if ((total >= 0) && (m_pos >= total)) | 826 if ((total >= 0) && (m_pos >= total)) |
| 778 break; | 827 break; |
| 779 | 828 |
| 780 if ((segment_stop >= 0) && (m_pos >= segment_stop)) | 829 if ((segment_stop >= 0) && (m_pos >= segment_stop)) |
| 781 break; | 830 break; |
| 782 | 831 |
| 783 long long pos = m_pos; | 832 long long pos = m_pos; |
| 784 const long long element_start = pos; | 833 const long long element_start = pos; |
| 785 | 834 |
| 835 // Avoid rolling over pos when very close to LONG_LONG_MAX. |
| 836 unsigned long long rollover_check = pos + 1ULL; |
| 837 if (rollover_check > LONG_LONG_MAX) |
| 838 return E_FILE_FORMAT_INVALID; |
| 839 |
| 786 if ((pos + 1) > available) | 840 if ((pos + 1) > available) |
| 787 return (pos + 1); | 841 return (pos + 1); |
| 788 | 842 |
| 789 long len; | 843 long len; |
| 790 long long result = GetUIntLength(m_pReader, pos, len); | 844 long long result = GetUIntLength(m_pReader, pos, len); |
| 791 | 845 |
| 792 if (result < 0) // error | 846 if (result < 0) // error |
| 793 return result; | 847 return result; |
| 794 | 848 |
| 795 if (result > 0) // underflow (weird) | 849 if (result > 0) { |
| 850 // MkvReader doesn't have enough data to satisfy this read attempt. |
| 796 return (pos + 1); | 851 return (pos + 1); |
| 852 } |
| 797 | 853 |
| 798 if ((segment_stop >= 0) && ((pos + len) > segment_stop)) | 854 if ((segment_stop >= 0) && ((pos + len) > segment_stop)) |
| 799 return E_FILE_FORMAT_INVALID; | 855 return E_FILE_FORMAT_INVALID; |
| 800 | 856 |
| 801 if ((pos + len) > available) | 857 if ((pos + len) > available) |
| 802 return pos + len; | 858 return pos + len; |
| 803 | 859 |
| 804 const long long idpos = pos; | 860 const long long idpos = pos; |
| 805 const long long id = ReadUInt(m_pReader, idpos, len); | 861 const long long id = ReadID(m_pReader, idpos, len); |
| 806 | 862 |
| 807 if (id < 0) // error | 863 if (id < 0) |
| 808 return id; | 864 return E_FILE_FORMAT_INVALID; |
| 809 | 865 |
| 810 if (id == 0x0F43B675) // Cluster ID | 866 if (id == mkvmuxer::kMkvCluster) |
| 811 break; | 867 break; |
| 812 | 868 |
| 813 pos += len; // consume ID | 869 pos += len; // consume ID |
| 814 | 870 |
| 815 if ((pos + 1) > available) | 871 if ((pos + 1) > available) |
| 816 return (pos + 1); | 872 return (pos + 1); |
| 817 | 873 |
| 818 // Read Size | 874 // Read Size |
| 819 result = GetUIntLength(m_pReader, pos, len); | 875 result = GetUIntLength(m_pReader, pos, len); |
| 820 | 876 |
| 821 if (result < 0) // error | 877 if (result < 0) // error |
| 822 return result; | 878 return result; |
| 823 | 879 |
| 824 if (result > 0) // underflow (weird) | 880 if (result > 0) { |
| 881 // MkvReader doesn't have enough data to satisfy this read attempt. |
| 825 return (pos + 1); | 882 return (pos + 1); |
| 883 } |
| 826 | 884 |
| 827 if ((segment_stop >= 0) && ((pos + len) > segment_stop)) | 885 if ((segment_stop >= 0) && ((pos + len) > segment_stop)) |
| 828 return E_FILE_FORMAT_INVALID; | 886 return E_FILE_FORMAT_INVALID; |
| 829 | 887 |
| 830 if ((pos + len) > available) | 888 if ((pos + len) > available) |
| 831 return pos + len; | 889 return pos + len; |
| 832 | 890 |
| 833 const long long size = ReadUInt(m_pReader, pos, len); | 891 const long long size = ReadUInt(m_pReader, pos, len); |
| 834 | 892 |
| 835 if (size < 0) // error | 893 if (size < 0 || len < 1 || len > 8) { |
| 894 // TODO(tomfinegan): ReadUInt should return an error when len is < 1 or |
| 895 // len > 8 is true instead of checking this _everywhere_. |
| 836 return size; | 896 return size; |
| 897 } |
| 837 | 898 |
| 838 pos += len; // consume length of size of element | 899 pos += len; // consume length of size of element |
| 839 | 900 |
| 901 // Avoid rolling over pos when very close to LONG_LONG_MAX. |
| 902 rollover_check = static_cast<unsigned long long>(pos) + size; |
| 903 if (rollover_check > LONG_LONG_MAX) |
| 904 return E_FILE_FORMAT_INVALID; |
| 905 |
| 840 const long long element_size = size + pos - element_start; | 906 const long long element_size = size + pos - element_start; |
| 841 | 907 |
| 842 // Pos now points to start of payload | 908 // Pos now points to start of payload |
| 843 | 909 |
| 844 if ((segment_stop >= 0) && ((pos + size) > segment_stop)) | 910 if ((segment_stop >= 0) && ((pos + size) > segment_stop)) |
| 845 return E_FILE_FORMAT_INVALID; | 911 return E_FILE_FORMAT_INVALID; |
| 846 | 912 |
| 847 // We read EBML elements either in total or nothing at all. | 913 // We read EBML elements either in total or nothing at all. |
| 848 | 914 |
| 849 if ((pos + size) > available) | 915 if ((pos + size) > available) |
| 850 return pos + size; | 916 return pos + size; |
| 851 | 917 |
| 852 if (id == 0x0549A966) { // Segment Info ID | 918 if (id == mkvmuxer::kMkvInfo) { |
| 853 if (m_pInfo) | 919 if (m_pInfo) |
| 854 return E_FILE_FORMAT_INVALID; | 920 return E_FILE_FORMAT_INVALID; |
| 855 | 921 |
| 856 m_pInfo = new (std::nothrow) | 922 m_pInfo = new (std::nothrow) |
| 857 SegmentInfo(this, pos, size, element_start, element_size); | 923 SegmentInfo(this, pos, size, element_start, element_size); |
| 858 | 924 |
| 859 if (m_pInfo == NULL) | 925 if (m_pInfo == NULL) |
| 860 return -1; | 926 return -1; |
| 861 | 927 |
| 862 const long status = m_pInfo->Parse(); | 928 const long status = m_pInfo->Parse(); |
| 863 | 929 |
| 864 if (status) | 930 if (status) |
| 865 return status; | 931 return status; |
| 866 } else if (id == 0x0654AE6B) { // Tracks ID | 932 } else if (id == mkvmuxer::kMkvTracks) { |
| 867 if (m_pTracks) | 933 if (m_pTracks) |
| 868 return E_FILE_FORMAT_INVALID; | 934 return E_FILE_FORMAT_INVALID; |
| 869 | 935 |
| 870 m_pTracks = new (std::nothrow) | 936 m_pTracks = new (std::nothrow) |
| 871 Tracks(this, pos, size, element_start, element_size); | 937 Tracks(this, pos, size, element_start, element_size); |
| 872 | 938 |
| 873 if (m_pTracks == NULL) | 939 if (m_pTracks == NULL) |
| 874 return -1; | 940 return -1; |
| 875 | 941 |
| 876 const long status = m_pTracks->Parse(); | 942 const long status = m_pTracks->Parse(); |
| 877 | 943 |
| 878 if (status) | 944 if (status) |
| 879 return status; | 945 return status; |
| 880 } else if (id == 0x0C53BB6B) { // Cues ID | 946 } else if (id == mkvmuxer::kMkvCues) { |
| 881 if (m_pCues == NULL) { | 947 if (m_pCues == NULL) { |
| 882 m_pCues = new (std::nothrow) | 948 m_pCues = new (std::nothrow) |
| 883 Cues(this, pos, size, element_start, element_size); | 949 Cues(this, pos, size, element_start, element_size); |
| 884 | 950 |
| 885 if (m_pCues == NULL) | 951 if (m_pCues == NULL) |
| 886 return -1; | 952 return -1; |
| 887 } | 953 } |
| 888 } else if (id == 0x014D9B74) { // SeekHead ID | 954 } else if (id == mkvmuxer::kMkvSeekHead) { |
| 889 if (m_pSeekHead == NULL) { | 955 if (m_pSeekHead == NULL) { |
| 890 m_pSeekHead = new (std::nothrow) | 956 m_pSeekHead = new (std::nothrow) |
| 891 SeekHead(this, pos, size, element_start, element_size); | 957 SeekHead(this, pos, size, element_start, element_size); |
| 892 | 958 |
| 893 if (m_pSeekHead == NULL) | 959 if (m_pSeekHead == NULL) |
| 894 return -1; | 960 return -1; |
| 895 | 961 |
| 896 const long status = m_pSeekHead->Parse(); | 962 const long status = m_pSeekHead->Parse(); |
| 897 | 963 |
| 898 if (status) | 964 if (status) |
| 899 return status; | 965 return status; |
| 900 } | 966 } |
| 901 } else if (id == 0x0043A770) { // Chapters ID | 967 } else if (id == mkvmuxer::kMkvChapters) { |
| 902 if (m_pChapters == NULL) { | 968 if (m_pChapters == NULL) { |
| 903 m_pChapters = new (std::nothrow) | 969 m_pChapters = new (std::nothrow) |
| 904 Chapters(this, pos, size, element_start, element_size); | 970 Chapters(this, pos, size, element_start, element_size); |
| 905 | 971 |
| 906 if (m_pChapters == NULL) | 972 if (m_pChapters == NULL) |
| 907 return -1; | 973 return -1; |
| 908 | 974 |
| 909 const long status = m_pChapters->Parse(); | 975 const long status = m_pChapters->Parse(); |
| 910 | 976 |
| 911 if (status) | 977 if (status) |
| 912 return status; | 978 return status; |
| 913 } | 979 } |
| 914 } else if (id == 0x0254C367) { // Tags ID | 980 } else if (id == mkvmuxer::kMkvTags) { |
| 915 if (m_pTags == NULL) { | 981 if (m_pTags == NULL) { |
| 916 m_pTags = new (std::nothrow) | 982 m_pTags = new (std::nothrow) |
| 917 Tags(this, pos, size, element_start, element_size); | 983 Tags(this, pos, size, element_start, element_size); |
| 918 | 984 |
| 919 if (m_pTags == NULL) | 985 if (m_pTags == NULL) |
| 920 return -1; | 986 return -1; |
| 921 | 987 |
| 922 const long status = m_pTags->Parse(); | 988 const long status = m_pTags->Parse(); |
| 923 | 989 |
| 924 if (status) | 990 if (status) |
| 925 return status; | 991 return status; |
| 926 } | 992 } |
| 927 } | 993 } |
| 928 | 994 |
| 929 m_pos = pos + size; // consume payload | 995 m_pos = pos + size; // consume payload |
| 930 } | 996 } |
| 931 | 997 |
| 932 assert((segment_stop < 0) || (m_pos <= segment_stop)); | 998 if (segment_stop >= 0 && m_pos > segment_stop) |
| 999 return E_FILE_FORMAT_INVALID; |
| 933 | 1000 |
| 934 if (m_pInfo == NULL) // TODO: liberalize this behavior | 1001 if (m_pInfo == NULL) // TODO: liberalize this behavior |
| 935 return E_FILE_FORMAT_INVALID; | 1002 return E_FILE_FORMAT_INVALID; |
| 936 | 1003 |
| 937 if (m_pTracks == NULL) | 1004 if (m_pTracks == NULL) |
| 938 return E_FILE_FORMAT_INVALID; | 1005 return E_FILE_FORMAT_INVALID; |
| 939 | 1006 |
| 940 return 0; // success | 1007 return 0; // success |
| 941 } | 1008 } |
| 942 | 1009 |
| (...skipping 10 matching lines...) Expand all Loading... |
| 953 if (m_pos < 0) | 1020 if (m_pos < 0) |
| 954 return DoLoadClusterUnknownSize(pos, len); | 1021 return DoLoadClusterUnknownSize(pos, len); |
| 955 | 1022 |
| 956 long long total, avail; | 1023 long long total, avail; |
| 957 | 1024 |
| 958 long status = m_pReader->Length(&total, &avail); | 1025 long status = m_pReader->Length(&total, &avail); |
| 959 | 1026 |
| 960 if (status < 0) // error | 1027 if (status < 0) // error |
| 961 return status; | 1028 return status; |
| 962 | 1029 |
| 963 assert((total < 0) || (avail <= total)); | 1030 if (total >= 0 && avail > total) |
| 1031 return E_FILE_FORMAT_INVALID; |
| 964 | 1032 |
| 965 const long long segment_stop = (m_size < 0) ? -1 : m_start + m_size; | 1033 const long long segment_stop = (m_size < 0) ? -1 : m_start + m_size; |
| 966 | 1034 |
| 967 long long cluster_off = -1; // offset relative to start of segment | 1035 long long cluster_off = -1; // offset relative to start of segment |
| 968 long long cluster_size = -1; // size of cluster payload | 1036 long long cluster_size = -1; // size of cluster payload |
| 969 | 1037 |
| 970 for (;;) { | 1038 for (;;) { |
| 971 if ((total >= 0) && (m_pos >= total)) | 1039 if ((total >= 0) && (m_pos >= total)) |
| 972 return 1; // no more clusters | 1040 return 1; // no more clusters |
| 973 | 1041 |
| 974 if ((segment_stop >= 0) && (m_pos >= segment_stop)) | 1042 if ((segment_stop >= 0) && (m_pos >= segment_stop)) |
| 975 return 1; // no more clusters | 1043 return 1; // no more clusters |
| 976 | 1044 |
| 977 pos = m_pos; | 1045 pos = m_pos; |
| 978 | 1046 |
| 979 // Read ID | 1047 // Read ID |
| 980 | 1048 |
| 981 if ((pos + 1) > avail) { | 1049 if ((pos + 1) > avail) { |
| 982 len = 1; | 1050 len = 1; |
| 983 return E_BUFFER_NOT_FULL; | 1051 return E_BUFFER_NOT_FULL; |
| 984 } | 1052 } |
| 985 | 1053 |
| 986 long long result = GetUIntLength(m_pReader, pos, len); | 1054 long long result = GetUIntLength(m_pReader, pos, len); |
| 987 | 1055 |
| 988 if (result < 0) // error | 1056 if (result < 0) // error |
| 989 return static_cast<long>(result); | 1057 return static_cast<long>(result); |
| 990 | 1058 |
| 991 if (result > 0) // weird | 1059 if (result > 0) |
| 992 return E_BUFFER_NOT_FULL; | 1060 return E_BUFFER_NOT_FULL; |
| 993 | 1061 |
| 994 if ((segment_stop >= 0) && ((pos + len) > segment_stop)) | 1062 if ((segment_stop >= 0) && ((pos + len) > segment_stop)) |
| 995 return E_FILE_FORMAT_INVALID; | 1063 return E_FILE_FORMAT_INVALID; |
| 996 | 1064 |
| 997 if ((pos + len) > avail) | 1065 if ((pos + len) > avail) |
| 998 return E_BUFFER_NOT_FULL; | 1066 return E_BUFFER_NOT_FULL; |
| 999 | 1067 |
| 1000 const long long idpos = pos; | 1068 const long long idpos = pos; |
| 1001 const long long id = ReadUInt(m_pReader, idpos, len); | 1069 const long long id = ReadID(m_pReader, idpos, len); |
| 1002 | 1070 |
| 1003 if (id < 0) // error (or underflow) | 1071 if (id < 0) |
| 1004 return static_cast<long>(id); | 1072 return E_FILE_FORMAT_INVALID; |
| 1005 | 1073 |
| 1006 pos += len; // consume ID | 1074 pos += len; // consume ID |
| 1007 | 1075 |
| 1008 // Read Size | 1076 // Read Size |
| 1009 | 1077 |
| 1010 if ((pos + 1) > avail) { | 1078 if ((pos + 1) > avail) { |
| 1011 len = 1; | 1079 len = 1; |
| 1012 return E_BUFFER_NOT_FULL; | 1080 return E_BUFFER_NOT_FULL; |
| 1013 } | 1081 } |
| 1014 | 1082 |
| 1015 result = GetUIntLength(m_pReader, pos, len); | 1083 result = GetUIntLength(m_pReader, pos, len); |
| 1016 | 1084 |
| 1017 if (result < 0) // error | 1085 if (result < 0) // error |
| 1018 return static_cast<long>(result); | 1086 return static_cast<long>(result); |
| 1019 | 1087 |
| 1020 if (result > 0) // weird | 1088 if (result > 0) |
| 1021 return E_BUFFER_NOT_FULL; | 1089 return E_BUFFER_NOT_FULL; |
| 1022 | 1090 |
| 1023 if ((segment_stop >= 0) && ((pos + len) > segment_stop)) | 1091 if ((segment_stop >= 0) && ((pos + len) > segment_stop)) |
| 1024 return E_FILE_FORMAT_INVALID; | 1092 return E_FILE_FORMAT_INVALID; |
| 1025 | 1093 |
| 1026 if ((pos + len) > avail) | 1094 if ((pos + len) > avail) |
| 1027 return E_BUFFER_NOT_FULL; | 1095 return E_BUFFER_NOT_FULL; |
| 1028 | 1096 |
| 1029 const long long size = ReadUInt(m_pReader, pos, len); | 1097 const long long size = ReadUInt(m_pReader, pos, len); |
| 1030 | 1098 |
| 1031 if (size < 0) // error | 1099 if (size < 0) // error |
| 1032 return static_cast<long>(size); | 1100 return static_cast<long>(size); |
| 1033 | 1101 |
| 1034 pos += len; // consume length of size of element | 1102 pos += len; // consume length of size of element |
| 1035 | 1103 |
| 1036 // pos now points to start of payload | 1104 // pos now points to start of payload |
| 1037 | 1105 |
| 1038 if (size == 0) { // weird | 1106 if (size == 0) { |
| 1107 // Missing element payload: move on. |
| 1039 m_pos = pos; | 1108 m_pos = pos; |
| 1040 continue; | 1109 continue; |
| 1041 } | 1110 } |
| 1042 | 1111 |
| 1043 const long long unknown_size = (1LL << (7 * len)) - 1; | 1112 const long long unknown_size = (1LL << (7 * len)) - 1; |
| 1044 | 1113 |
| 1045 if ((segment_stop >= 0) && (size != unknown_size) && | 1114 if ((segment_stop >= 0) && (size != unknown_size) && |
| 1046 ((pos + size) > segment_stop)) { | 1115 ((pos + size) > segment_stop)) { |
| 1047 return E_FILE_FORMAT_INVALID; | 1116 return E_FILE_FORMAT_INVALID; |
| 1048 } | 1117 } |
| 1049 | 1118 |
| 1050 if (id == 0x0C53BB6B) { // Cues ID | 1119 if (id == mkvmuxer::kMkvCues) { |
| 1051 if (size == unknown_size) | 1120 if (size == unknown_size) { |
| 1052 return E_FILE_FORMAT_INVALID; // TODO: liberalize | 1121 // Cues element of unknown size: Not supported. |
| 1122 return E_FILE_FORMAT_INVALID; |
| 1123 } |
| 1053 | 1124 |
| 1054 if (m_pCues == NULL) { | 1125 if (m_pCues == NULL) { |
| 1055 const long long element_size = (pos - idpos) + size; | 1126 const long long element_size = (pos - idpos) + size; |
| 1056 | 1127 |
| 1057 m_pCues = new Cues(this, pos, size, idpos, element_size); | 1128 m_pCues = new (std::nothrow) Cues(this, pos, size, idpos, element_size); |
| 1058 assert(m_pCues); // TODO | 1129 if (m_pCues == NULL) |
| 1130 return -1; |
| 1059 } | 1131 } |
| 1060 | 1132 |
| 1061 m_pos = pos + size; // consume payload | 1133 m_pos = pos + size; // consume payload |
| 1062 continue; | 1134 continue; |
| 1063 } | 1135 } |
| 1064 | 1136 |
| 1065 if (id != 0x0F43B675) { // Cluster ID | 1137 if (id != mkvmuxer::kMkvCluster) { |
| 1138 // Besides the Segment, Libwebm allows only cluster elements of unknown |
| 1139 // size. Fail the parse upon encountering a non-cluster element reporting |
| 1140 // unknown size. |
| 1066 if (size == unknown_size) | 1141 if (size == unknown_size) |
| 1067 return E_FILE_FORMAT_INVALID; // TODO: liberalize | 1142 return E_FILE_FORMAT_INVALID; |
| 1068 | 1143 |
| 1069 m_pos = pos + size; // consume payload | 1144 m_pos = pos + size; // consume payload |
| 1070 continue; | 1145 continue; |
| 1071 } | 1146 } |
| 1072 | 1147 |
| 1073 // We have a cluster. | 1148 // We have a cluster. |
| 1074 | 1149 |
| 1075 cluster_off = idpos - m_start; // relative pos | 1150 cluster_off = idpos - m_start; // relative pos |
| 1076 | 1151 |
| 1077 if (size != unknown_size) | 1152 if (size != unknown_size) |
| 1078 cluster_size = size; | 1153 cluster_size = size; |
| 1079 | 1154 |
| 1080 break; | 1155 break; |
| 1081 } | 1156 } |
| 1082 | 1157 |
| 1083 assert(cluster_off >= 0); // have cluster | 1158 if (cluster_off < 0) { |
| 1159 // No cluster, die. |
| 1160 return E_FILE_FORMAT_INVALID; |
| 1161 } |
| 1084 | 1162 |
| 1085 long long pos_; | 1163 long long pos_; |
| 1086 long len_; | 1164 long len_; |
| 1087 | 1165 |
| 1088 status = Cluster::HasBlockEntries(this, cluster_off, pos_, len_); | 1166 status = Cluster::HasBlockEntries(this, cluster_off, pos_, len_); |
| 1089 | 1167 |
| 1090 if (status < 0) { // error, or underflow | 1168 if (status < 0) { // error, or underflow |
| 1091 pos = pos_; | 1169 pos = pos_; |
| 1092 len = len_; | 1170 len = len_; |
| 1093 | 1171 |
| (...skipping 25 matching lines...) Expand all Loading... |
| 1119 // | 1197 // |
| 1120 // The problem is that we're asserting in asyncreadinit, | 1198 // The problem is that we're asserting in asyncreadinit, |
| 1121 // because we adjust the pos down to the curr seek pos, | 1199 // because we adjust the pos down to the curr seek pos, |
| 1122 // and the resulting adjusted len is > 2GB. I'm suspicious | 1200 // and the resulting adjusted len is > 2GB. I'm suspicious |
| 1123 // that this is even correct, but even if it is, we can't | 1201 // that this is even correct, but even if it is, we can't |
| 1124 // be loading that much data in the cache anyway. | 1202 // be loading that much data in the cache anyway. |
| 1125 | 1203 |
| 1126 const long idx = m_clusterCount; | 1204 const long idx = m_clusterCount; |
| 1127 | 1205 |
| 1128 if (m_clusterPreloadCount > 0) { | 1206 if (m_clusterPreloadCount > 0) { |
| 1129 assert(idx < m_clusterSize); | 1207 if (idx >= m_clusterSize) |
| 1208 return E_FILE_FORMAT_INVALID; |
| 1130 | 1209 |
| 1131 Cluster* const pCluster = m_clusters[idx]; | 1210 Cluster* const pCluster = m_clusters[idx]; |
| 1132 assert(pCluster); | 1211 if (pCluster == NULL || pCluster->m_index >= 0) |
| 1133 assert(pCluster->m_index < 0); | 1212 return E_FILE_FORMAT_INVALID; |
| 1134 | 1213 |
| 1135 const long long off = pCluster->GetPosition(); | 1214 const long long off = pCluster->GetPosition(); |
| 1136 assert(off >= 0); | 1215 if (off < 0) |
| 1216 return E_FILE_FORMAT_INVALID; |
| 1137 | 1217 |
| 1138 if (off == cluster_off) { // preloaded already | 1218 if (off == cluster_off) { // preloaded already |
| 1139 if (status == 0) // no entries found | 1219 if (status == 0) // no entries found |
| 1140 return E_FILE_FORMAT_INVALID; | 1220 return E_FILE_FORMAT_INVALID; |
| 1141 | 1221 |
| 1142 if (cluster_size >= 0) | 1222 if (cluster_size >= 0) |
| 1143 pos += cluster_size; | 1223 pos += cluster_size; |
| 1144 else { | 1224 else { |
| 1145 const long long element_size = pCluster->GetElementSize(); | 1225 const long long element_size = pCluster->GetElementSize(); |
| 1146 | 1226 |
| 1147 if (element_size <= 0) | 1227 if (element_size <= 0) |
| 1148 return E_FILE_FORMAT_INVALID; // TODO: handle this case | 1228 return E_FILE_FORMAT_INVALID; // TODO: handle this case |
| 1149 | 1229 |
| 1150 pos = pCluster->m_element_start + element_size; | 1230 pos = pCluster->m_element_start + element_size; |
| 1151 } | 1231 } |
| 1152 | 1232 |
| 1153 pCluster->m_index = idx; // move from preloaded to loaded | 1233 pCluster->m_index = idx; // move from preloaded to loaded |
| 1154 ++m_clusterCount; | 1234 ++m_clusterCount; |
| 1155 --m_clusterPreloadCount; | 1235 --m_clusterPreloadCount; |
| 1156 | 1236 |
| 1157 m_pos = pos; // consume payload | 1237 m_pos = pos; // consume payload |
| 1158 assert((segment_stop < 0) || (m_pos <= segment_stop)); | 1238 if (segment_stop >= 0 && m_pos > segment_stop) |
| 1239 return E_FILE_FORMAT_INVALID; |
| 1159 | 1240 |
| 1160 return 0; // success | 1241 return 0; // success |
| 1161 } | 1242 } |
| 1162 } | 1243 } |
| 1163 | 1244 |
| 1164 if (status == 0) { // no entries found | 1245 if (status == 0) { // no entries found |
| 1165 if (cluster_size >= 0) | 1246 if (cluster_size >= 0) |
| 1166 pos += cluster_size; | 1247 pos += cluster_size; |
| 1167 | 1248 |
| 1168 if ((total >= 0) && (pos >= total)) { | 1249 if ((total >= 0) && (pos >= total)) { |
| 1169 m_pos = total; | 1250 m_pos = total; |
| 1170 return 1; // no more clusters | 1251 return 1; // no more clusters |
| 1171 } | 1252 } |
| 1172 | 1253 |
| 1173 if ((segment_stop >= 0) && (pos >= segment_stop)) { | 1254 if ((segment_stop >= 0) && (pos >= segment_stop)) { |
| 1174 m_pos = segment_stop; | 1255 m_pos = segment_stop; |
| 1175 return 1; // no more clusters | 1256 return 1; // no more clusters |
| 1176 } | 1257 } |
| 1177 | 1258 |
| 1178 m_pos = pos; | 1259 m_pos = pos; |
| 1179 return 2; // try again | 1260 return 2; // try again |
| 1180 } | 1261 } |
| 1181 | 1262 |
| 1182 // status > 0 means we have an entry | 1263 // status > 0 means we have an entry |
| 1183 | 1264 |
| 1184 Cluster* const pCluster = Cluster::Create(this, idx, cluster_off); | 1265 Cluster* const pCluster = Cluster::Create(this, idx, cluster_off); |
| 1185 // element_size); | 1266 if (pCluster == NULL) |
| 1186 assert(pCluster); | 1267 return -1; |
| 1187 | 1268 |
| 1188 AppendCluster(pCluster); | 1269 if (!AppendCluster(pCluster)) { |
| 1189 assert(m_clusters); | 1270 delete pCluster; |
| 1190 assert(idx < m_clusterSize); | 1271 return -1; |
| 1191 assert(m_clusters[idx] == pCluster); | 1272 } |
| 1192 | 1273 |
| 1193 if (cluster_size >= 0) { | 1274 if (cluster_size >= 0) { |
| 1194 pos += cluster_size; | 1275 pos += cluster_size; |
| 1195 | 1276 |
| 1196 m_pos = pos; | 1277 m_pos = pos; |
| 1197 assert((segment_stop < 0) || (m_pos <= segment_stop)); | 1278 |
| 1279 if (segment_stop > 0 && m_pos > segment_stop) |
| 1280 return E_FILE_FORMAT_INVALID; |
| 1198 | 1281 |
| 1199 return 0; | 1282 return 0; |
| 1200 } | 1283 } |
| 1201 | 1284 |
| 1202 m_pUnknownSize = pCluster; | 1285 m_pUnknownSize = pCluster; |
| 1203 m_pos = -pos; | 1286 m_pos = -pos; |
| 1204 | 1287 |
| 1205 return 0; // partial success, since we have a new cluster | 1288 return 0; // partial success, since we have a new cluster |
| 1206 | 1289 |
| 1207 // status == 0 means "no block entries found" | 1290 // status == 0 means "no block entries found" |
| 1208 // pos designates start of payload | 1291 // pos designates start of payload |
| 1209 // m_pos has NOT been adjusted yet (in case we need to come back here) | 1292 // m_pos has NOT been adjusted yet (in case we need to come back here) |
| 1210 } | 1293 } |
| 1211 | 1294 |
| 1212 long Segment::DoLoadClusterUnknownSize(long long& pos, long& len) { | 1295 long Segment::DoLoadClusterUnknownSize(long long& pos, long& len) { |
| 1213 assert(m_pos < 0); | 1296 if (m_pos >= 0 || m_pUnknownSize == NULL) |
| 1214 assert(m_pUnknownSize); | 1297 return E_PARSE_FAILED; |
| 1215 | 1298 |
| 1216 const long status = m_pUnknownSize->Parse(pos, len); | 1299 const long status = m_pUnknownSize->Parse(pos, len); |
| 1217 | 1300 |
| 1218 if (status < 0) // error or underflow | 1301 if (status < 0) // error or underflow |
| 1219 return status; | 1302 return status; |
| 1220 | 1303 |
| 1221 if (status == 0) // parsed a block | 1304 if (status == 0) // parsed a block |
| 1222 return 2; // continue parsing | 1305 return 2; // continue parsing |
| 1223 | 1306 |
| 1224 assert(status > 0); // nothing left to parse of this cluster | 1307 const long long start = m_pUnknownSize->m_element_start; |
| 1308 const long long size = m_pUnknownSize->GetElementSize(); |
| 1225 | 1309 |
| 1226 const long long start = m_pUnknownSize->m_element_start; | 1310 if (size < 0) |
| 1227 | 1311 return E_FILE_FORMAT_INVALID; |
| 1228 const long long size = m_pUnknownSize->GetElementSize(); | |
| 1229 assert(size >= 0); | |
| 1230 | 1312 |
| 1231 pos = start + size; | 1313 pos = start + size; |
| 1232 m_pos = pos; | 1314 m_pos = pos; |
| 1233 | 1315 |
| 1234 m_pUnknownSize = 0; | 1316 m_pUnknownSize = 0; |
| 1235 | 1317 |
| 1236 return 2; // continue parsing | 1318 return 2; // continue parsing |
| 1237 } | 1319 } |
| 1238 | 1320 |
| 1239 void Segment::AppendCluster(Cluster* pCluster) { | 1321 bool Segment::AppendCluster(Cluster* pCluster) { |
| 1240 assert(pCluster); | 1322 if (pCluster == NULL || pCluster->m_index < 0) |
| 1241 assert(pCluster->m_index >= 0); | 1323 return false; |
| 1242 | 1324 |
| 1243 const long count = m_clusterCount + m_clusterPreloadCount; | 1325 const long count = m_clusterCount + m_clusterPreloadCount; |
| 1244 | 1326 |
| 1245 long& size = m_clusterSize; | 1327 long& size = m_clusterSize; |
| 1246 assert(size >= count); | 1328 const long idx = pCluster->m_index; |
| 1247 | 1329 |
| 1248 const long idx = pCluster->m_index; | 1330 if (size < count || idx != m_clusterCount) |
| 1249 assert(idx == m_clusterCount); | 1331 return false; |
| 1250 | 1332 |
| 1251 if (count >= size) { | 1333 if (count >= size) { |
| 1252 const long n = (size <= 0) ? 2048 : 2 * size; | 1334 const long n = (size <= 0) ? 2048 : 2 * size; |
| 1253 | 1335 |
| 1254 Cluster** const qq = new Cluster*[n]; | 1336 Cluster** const qq = new (std::nothrow) Cluster*[n]; |
| 1337 if (qq == NULL) |
| 1338 return false; |
| 1339 |
| 1255 Cluster** q = qq; | 1340 Cluster** q = qq; |
| 1256 | |
| 1257 Cluster** p = m_clusters; | 1341 Cluster** p = m_clusters; |
| 1258 Cluster** const pp = p + count; | 1342 Cluster** const pp = p + count; |
| 1259 | 1343 |
| 1260 while (p != pp) | 1344 while (p != pp) |
| 1261 *q++ = *p++; | 1345 *q++ = *p++; |
| 1262 | 1346 |
| 1263 delete[] m_clusters; | 1347 delete[] m_clusters; |
| 1264 | 1348 |
| 1265 m_clusters = qq; | 1349 m_clusters = qq; |
| 1266 size = n; | 1350 size = n; |
| 1267 } | 1351 } |
| 1268 | 1352 |
| 1269 if (m_clusterPreloadCount > 0) { | 1353 if (m_clusterPreloadCount > 0) { |
| 1270 assert(m_clusters); | |
| 1271 | |
| 1272 Cluster** const p = m_clusters + m_clusterCount; | 1354 Cluster** const p = m_clusters + m_clusterCount; |
| 1273 assert(*p); | 1355 if (*p == NULL || (*p)->m_index >= 0) |
| 1274 assert((*p)->m_index < 0); | 1356 return false; |
| 1275 | 1357 |
| 1276 Cluster** q = p + m_clusterPreloadCount; | 1358 Cluster** q = p + m_clusterPreloadCount; |
| 1277 assert(q < (m_clusters + size)); | 1359 if (q >= (m_clusters + size)) |
| 1360 return false; |
| 1278 | 1361 |
| 1279 for (;;) { | 1362 for (;;) { |
| 1280 Cluster** const qq = q - 1; | 1363 Cluster** const qq = q - 1; |
| 1281 assert((*qq)->m_index < 0); | 1364 if ((*qq)->m_index >= 0) |
| 1365 return false; |
| 1282 | 1366 |
| 1283 *q = *qq; | 1367 *q = *qq; |
| 1284 q = qq; | 1368 q = qq; |
| 1285 | 1369 |
| 1286 if (q == p) | 1370 if (q == p) |
| 1287 break; | 1371 break; |
| 1288 } | 1372 } |
| 1289 } | 1373 } |
| 1290 | 1374 |
| 1291 m_clusters[idx] = pCluster; | 1375 m_clusters[idx] = pCluster; |
| 1292 ++m_clusterCount; | 1376 ++m_clusterCount; |
| 1377 return true; |
| 1293 } | 1378 } |
| 1294 | 1379 |
| 1295 void Segment::PreloadCluster(Cluster* pCluster, ptrdiff_t idx) { | 1380 bool Segment::PreloadCluster(Cluster* pCluster, ptrdiff_t idx) { |
| 1296 assert(pCluster); | 1381 if (pCluster == NULL || pCluster->m_index >= 0 || idx < m_clusterCount) |
| 1297 assert(pCluster->m_index < 0); | 1382 return false; |
| 1298 assert(idx >= m_clusterCount); | |
| 1299 | 1383 |
| 1300 const long count = m_clusterCount + m_clusterPreloadCount; | 1384 const long count = m_clusterCount + m_clusterPreloadCount; |
| 1301 | 1385 |
| 1302 long& size = m_clusterSize; | 1386 long& size = m_clusterSize; |
| 1303 assert(size >= count); | 1387 if (size < count) |
| 1388 return false; |
| 1304 | 1389 |
| 1305 if (count >= size) { | 1390 if (count >= size) { |
| 1306 const long n = (size <= 0) ? 2048 : 2 * size; | 1391 const long n = (size <= 0) ? 2048 : 2 * size; |
| 1307 | 1392 |
| 1308 Cluster** const qq = new Cluster*[n]; | 1393 Cluster** const qq = new (std::nothrow) Cluster*[n]; |
| 1394 if (qq == NULL) |
| 1395 return false; |
| 1309 Cluster** q = qq; | 1396 Cluster** q = qq; |
| 1310 | 1397 |
| 1311 Cluster** p = m_clusters; | 1398 Cluster** p = m_clusters; |
| 1312 Cluster** const pp = p + count; | 1399 Cluster** const pp = p + count; |
| 1313 | 1400 |
| 1314 while (p != pp) | 1401 while (p != pp) |
| 1315 *q++ = *p++; | 1402 *q++ = *p++; |
| 1316 | 1403 |
| 1317 delete[] m_clusters; | 1404 delete[] m_clusters; |
| 1318 | 1405 |
| 1319 m_clusters = qq; | 1406 m_clusters = qq; |
| 1320 size = n; | 1407 size = n; |
| 1321 } | 1408 } |
| 1322 | 1409 |
| 1323 assert(m_clusters); | 1410 if (m_clusters == NULL) |
| 1411 return false; |
| 1324 | 1412 |
| 1325 Cluster** const p = m_clusters + idx; | 1413 Cluster** const p = m_clusters + idx; |
| 1326 | 1414 |
| 1327 Cluster** q = m_clusters + count; | 1415 Cluster** q = m_clusters + count; |
| 1328 assert(q >= p); | 1416 if (q < p || q >= (m_clusters + size)) |
| 1329 assert(q < (m_clusters + size)); | 1417 return false; |
| 1330 | 1418 |
| 1331 while (q > p) { | 1419 while (q > p) { |
| 1332 Cluster** const qq = q - 1; | 1420 Cluster** const qq = q - 1; |
| 1333 assert((*qq)->m_index < 0); | 1421 |
| 1422 if ((*qq)->m_index >= 0) |
| 1423 return false; |
| 1334 | 1424 |
| 1335 *q = *qq; | 1425 *q = *qq; |
| 1336 q = qq; | 1426 q = qq; |
| 1337 } | 1427 } |
| 1338 | 1428 |
| 1339 m_clusters[idx] = pCluster; | 1429 m_clusters[idx] = pCluster; |
| 1340 ++m_clusterPreloadCount; | 1430 ++m_clusterPreloadCount; |
| 1431 return true; |
| 1341 } | 1432 } |
| 1342 | 1433 |
| 1343 long Segment::Load() { | 1434 long Segment::Load() { |
| 1344 assert(m_clusters == NULL); | 1435 if (m_clusters != NULL || m_clusterSize != 0 || m_clusterCount != 0) |
| 1345 assert(m_clusterSize == 0); | 1436 return E_PARSE_FAILED; |
| 1346 assert(m_clusterCount == 0); | |
| 1347 // assert(m_size >= 0); | |
| 1348 | 1437 |
| 1349 // Outermost (level 0) segment object has been constructed, | 1438 // Outermost (level 0) segment object has been constructed, |
| 1350 // and pos designates start of payload. We need to find the | 1439 // and pos designates start of payload. We need to find the |
| 1351 // inner (level 1) elements. | 1440 // inner (level 1) elements. |
| 1352 | 1441 |
| 1353 const long long header_status = ParseHeaders(); | 1442 const long long header_status = ParseHeaders(); |
| 1354 | 1443 |
| 1355 if (header_status < 0) // error | 1444 if (header_status < 0) // error |
| 1356 return static_cast<long>(header_status); | 1445 return static_cast<long>(header_status); |
| 1357 | 1446 |
| 1358 if (header_status > 0) // underflow | 1447 if (header_status > 0) // underflow |
| 1359 return E_BUFFER_NOT_FULL; | 1448 return E_BUFFER_NOT_FULL; |
| 1360 | 1449 |
| 1361 assert(m_pInfo); | 1450 if (m_pInfo == NULL || m_pTracks == NULL) |
| 1362 assert(m_pTracks); | 1451 return E_FILE_FORMAT_INVALID; |
| 1363 | 1452 |
| 1364 for (;;) { | 1453 for (;;) { |
| 1365 const int status = LoadCluster(); | 1454 const int status = LoadCluster(); |
| 1366 | 1455 |
| 1367 if (status < 0) // error | 1456 if (status < 0) // error |
| 1368 return status; | 1457 return status; |
| 1369 | 1458 |
| 1370 if (status >= 1) // no more clusters | 1459 if (status >= 1) // no more clusters |
| 1371 return 0; | 1460 return 0; |
| 1372 } | 1461 } |
| (...skipping 28 matching lines...) Expand all Loading... |
| 1401 int void_element_count = 0; | 1490 int void_element_count = 0; |
| 1402 | 1491 |
| 1403 while (pos < stop) { | 1492 while (pos < stop) { |
| 1404 long long id, size; | 1493 long long id, size; |
| 1405 | 1494 |
| 1406 const long status = ParseElementHeader(pReader, pos, stop, id, size); | 1495 const long status = ParseElementHeader(pReader, pos, stop, id, size); |
| 1407 | 1496 |
| 1408 if (status < 0) // error | 1497 if (status < 0) // error |
| 1409 return status; | 1498 return status; |
| 1410 | 1499 |
| 1411 if (id == 0x0DBB) // SeekEntry ID | 1500 if (id == mkvmuxer::kMkvSeek) |
| 1412 ++entry_count; | 1501 ++entry_count; |
| 1413 else if (id == 0x6C) // Void ID | 1502 else if (id == mkvmuxer::kMkvVoid) |
| 1414 ++void_element_count; | 1503 ++void_element_count; |
| 1415 | 1504 |
| 1416 pos += size; // consume payload | 1505 pos += size; // consume payload |
| 1417 assert(pos <= stop); | 1506 |
| 1507 if (pos > stop) |
| 1508 return E_FILE_FORMAT_INVALID; |
| 1418 } | 1509 } |
| 1419 | 1510 |
| 1420 assert(pos == stop); | 1511 if (pos != stop) |
| 1512 return E_FILE_FORMAT_INVALID; |
| 1421 | 1513 |
| 1422 m_entries = new (std::nothrow) Entry[entry_count]; | 1514 m_entries = new (std::nothrow) Entry[entry_count]; |
| 1423 | 1515 |
| 1424 if (m_entries == NULL) | 1516 if (m_entries == NULL) |
| 1425 return -1; | 1517 return -1; |
| 1426 | 1518 |
| 1427 m_void_elements = new (std::nothrow) VoidElement[void_element_count]; | 1519 m_void_elements = new (std::nothrow) VoidElement[void_element_count]; |
| 1428 | 1520 |
| 1429 if (m_void_elements == NULL) | 1521 if (m_void_elements == NULL) |
| 1430 return -1; | 1522 return -1; |
| 1431 | 1523 |
| 1432 // now parse the entries and void elements | 1524 // now parse the entries and void elements |
| 1433 | 1525 |
| 1434 Entry* pEntry = m_entries; | 1526 Entry* pEntry = m_entries; |
| 1435 VoidElement* pVoidElement = m_void_elements; | 1527 VoidElement* pVoidElement = m_void_elements; |
| 1436 | 1528 |
| 1437 pos = m_start; | 1529 pos = m_start; |
| 1438 | 1530 |
| 1439 while (pos < stop) { | 1531 while (pos < stop) { |
| 1440 const long long idpos = pos; | 1532 const long long idpos = pos; |
| 1441 | 1533 |
| 1442 long long id, size; | 1534 long long id, size; |
| 1443 | 1535 |
| 1444 const long status = ParseElementHeader(pReader, pos, stop, id, size); | 1536 const long status = ParseElementHeader(pReader, pos, stop, id, size); |
| 1445 | 1537 |
| 1446 if (status < 0) // error | 1538 if (status < 0) // error |
| 1447 return status; | 1539 return status; |
| 1448 | 1540 |
| 1449 if (id == 0x0DBB) { // SeekEntry ID | 1541 if (id == mkvmuxer::kMkvSeek) { |
| 1450 if (ParseEntry(pReader, pos, size, pEntry)) { | 1542 if (ParseEntry(pReader, pos, size, pEntry)) { |
| 1451 Entry& e = *pEntry++; | 1543 Entry& e = *pEntry++; |
| 1452 | 1544 |
| 1453 e.element_start = idpos; | 1545 e.element_start = idpos; |
| 1454 e.element_size = (pos + size) - idpos; | 1546 e.element_size = (pos + size) - idpos; |
| 1455 } | 1547 } |
| 1456 } else if (id == 0x6C) { // Void ID | 1548 } else if (id == mkvmuxer::kMkvVoid) { |
| 1457 VoidElement& e = *pVoidElement++; | 1549 VoidElement& e = *pVoidElement++; |
| 1458 | 1550 |
| 1459 e.element_start = idpos; | 1551 e.element_start = idpos; |
| 1460 e.element_size = (pos + size) - idpos; | 1552 e.element_size = (pos + size) - idpos; |
| 1461 } | 1553 } |
| 1462 | 1554 |
| 1463 pos += size; // consume payload | 1555 pos += size; // consume payload |
| 1464 assert(pos <= stop); | 1556 if (pos > stop) |
| 1557 return E_FILE_FORMAT_INVALID; |
| 1465 } | 1558 } |
| 1466 | 1559 |
| 1467 assert(pos == stop); | 1560 if (pos != stop) |
| 1561 return E_FILE_FORMAT_INVALID; |
| 1468 | 1562 |
| 1469 ptrdiff_t count_ = ptrdiff_t(pEntry - m_entries); | 1563 ptrdiff_t count_ = ptrdiff_t(pEntry - m_entries); |
| 1470 assert(count_ >= 0); | 1564 assert(count_ >= 0); |
| 1471 assert(count_ <= entry_count); | 1565 assert(count_ <= entry_count); |
| 1472 | 1566 |
| 1473 m_entry_count = static_cast<int>(count_); | 1567 m_entry_count = static_cast<int>(count_); |
| 1474 | 1568 |
| 1475 count_ = ptrdiff_t(pVoidElement - m_void_elements); | 1569 count_ = ptrdiff_t(pVoidElement - m_void_elements); |
| 1476 assert(count_ >= 0); | 1570 assert(count_ >= 0); |
| 1477 assert(count_ <= void_element_count); | 1571 assert(count_ <= void_element_count); |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1546 } | 1640 } |
| 1547 | 1641 |
| 1548 if ((segment_stop >= 0) && ((pos + len) > segment_stop)) | 1642 if ((segment_stop >= 0) && ((pos + len) > segment_stop)) |
| 1549 return E_FILE_FORMAT_INVALID; | 1643 return E_FILE_FORMAT_INVALID; |
| 1550 | 1644 |
| 1551 if ((pos + len) > avail) | 1645 if ((pos + len) > avail) |
| 1552 return E_BUFFER_NOT_FULL; | 1646 return E_BUFFER_NOT_FULL; |
| 1553 | 1647 |
| 1554 const long long idpos = pos; | 1648 const long long idpos = pos; |
| 1555 | 1649 |
| 1556 const long long id = ReadUInt(m_pReader, idpos, len); | 1650 const long long id = ReadID(m_pReader, idpos, len); |
| 1557 | 1651 |
| 1558 if (id != 0x0C53BB6B) // Cues ID | 1652 if (id != mkvmuxer::kMkvCues) |
| 1559 return E_FILE_FORMAT_INVALID; | 1653 return E_FILE_FORMAT_INVALID; |
| 1560 | 1654 |
| 1561 pos += len; // consume ID | 1655 pos += len; // consume ID |
| 1562 assert((segment_stop < 0) || (pos <= segment_stop)); | 1656 assert((segment_stop < 0) || (pos <= segment_stop)); |
| 1563 | 1657 |
| 1564 // Read Size | 1658 // Read Size |
| 1565 | 1659 |
| 1566 if ((pos + 1) > avail) { | 1660 if ((pos + 1) > avail) { |
| 1567 len = 1; | 1661 len = 1; |
| 1568 return E_BUFFER_NOT_FULL; | 1662 return E_BUFFER_NOT_FULL; |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1608 | 1702 |
| 1609 len = static_cast<long>(size); | 1703 len = static_cast<long>(size); |
| 1610 | 1704 |
| 1611 if (element_stop > avail) | 1705 if (element_stop > avail) |
| 1612 return E_BUFFER_NOT_FULL; | 1706 return E_BUFFER_NOT_FULL; |
| 1613 | 1707 |
| 1614 const long long element_size = element_stop - element_start; | 1708 const long long element_size = element_stop - element_start; |
| 1615 | 1709 |
| 1616 m_pCues = | 1710 m_pCues = |
| 1617 new (std::nothrow) Cues(this, pos, size, element_start, element_size); | 1711 new (std::nothrow) Cues(this, pos, size, element_start, element_size); |
| 1618 assert(m_pCues); // TODO | 1712 if (m_pCues == NULL) |
| 1713 return -1; |
| 1619 | 1714 |
| 1620 return 0; // success | 1715 return 0; // success |
| 1621 } | 1716 } |
| 1622 | 1717 |
| 1623 bool SeekHead::ParseEntry(IMkvReader* pReader, long long start, long long size_, | 1718 bool SeekHead::ParseEntry(IMkvReader* pReader, long long start, long long size_, |
| 1624 Entry* pEntry) { | 1719 Entry* pEntry) { |
| 1625 if (size_ <= 0) | 1720 if (size_ <= 0) |
| 1626 return false; | 1721 return false; |
| 1627 | 1722 |
| 1628 long long pos = start; | 1723 long long pos = start; |
| 1629 const long long stop = start + size_; | 1724 const long long stop = start + size_; |
| 1630 | 1725 |
| 1631 long len; | 1726 long len; |
| 1632 | 1727 |
| 1633 // parse the container for the level-1 element ID | 1728 // parse the container for the level-1 element ID |
| 1634 | 1729 |
| 1635 const long long seekIdId = ReadUInt(pReader, pos, len); | 1730 const long long seekIdId = ReadID(pReader, pos, len); |
| 1636 // seekIdId; | 1731 if (seekIdId < 0) |
| 1732 return false; |
| 1637 | 1733 |
| 1638 if (seekIdId != 0x13AB) // SeekID ID | 1734 if (seekIdId != mkvmuxer::kMkvSeekID) |
| 1639 return false; | 1735 return false; |
| 1640 | 1736 |
| 1641 if ((pos + len) > stop) | 1737 if ((pos + len) > stop) |
| 1642 return false; | 1738 return false; |
| 1643 | 1739 |
| 1644 pos += len; // consume SeekID id | 1740 pos += len; // consume SeekID id |
| 1645 | 1741 |
| 1646 const long long seekIdSize = ReadUInt(pReader, pos, len); | 1742 const long long seekIdSize = ReadUInt(pReader, pos, len); |
| 1647 | 1743 |
| 1648 if (seekIdSize <= 0) | 1744 if (seekIdSize <= 0) |
| (...skipping 21 matching lines...) Expand all Loading... |
| 1670 pEntry->id = ReadUInt(pReader, pos, len); // payload | 1766 pEntry->id = ReadUInt(pReader, pos, len); // payload |
| 1671 | 1767 |
| 1672 if (pEntry->id <= 0) | 1768 if (pEntry->id <= 0) |
| 1673 return false; | 1769 return false; |
| 1674 | 1770 |
| 1675 if (len != seekIdSize) | 1771 if (len != seekIdSize) |
| 1676 return false; | 1772 return false; |
| 1677 | 1773 |
| 1678 pos += seekIdSize; // consume SeekID payload | 1774 pos += seekIdSize; // consume SeekID payload |
| 1679 | 1775 |
| 1680 const long long seekPosId = ReadUInt(pReader, pos, len); | 1776 const long long seekPosId = ReadID(pReader, pos, len); |
| 1681 | 1777 |
| 1682 if (seekPosId != 0x13AC) // SeekPos ID | 1778 if (seekPosId != mkvmuxer::kMkvSeekPosition) |
| 1683 return false; | 1779 return false; |
| 1684 | 1780 |
| 1685 if ((pos + len) > stop) | 1781 if ((pos + len) > stop) |
| 1686 return false; | 1782 return false; |
| 1687 | 1783 |
| 1688 pos += len; // consume id | 1784 pos += len; // consume id |
| 1689 | 1785 |
| 1690 const long long seekPosSize = ReadUInt(pReader, pos, len); | 1786 const long long seekPosSize = ReadUInt(pReader, pos, len); |
| 1691 | 1787 |
| 1692 if (seekPosSize <= 0) | 1788 if (seekPosSize <= 0) |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1750 | 1846 |
| 1751 bool Cues::DoneParsing() const { | 1847 bool Cues::DoneParsing() const { |
| 1752 const long long stop = m_start + m_size; | 1848 const long long stop = m_start + m_size; |
| 1753 return (m_pos >= stop); | 1849 return (m_pos >= stop); |
| 1754 } | 1850 } |
| 1755 | 1851 |
| 1756 bool Cues::Init() const { | 1852 bool Cues::Init() const { |
| 1757 if (m_cue_points) | 1853 if (m_cue_points) |
| 1758 return true; | 1854 return true; |
| 1759 | 1855 |
| 1760 assert(m_count == 0); | 1856 if (m_count != 0 || m_preload_count != 0) |
| 1761 assert(m_preload_count == 0); | 1857 return false; |
| 1762 | 1858 |
| 1763 IMkvReader* const pReader = m_pSegment->m_pReader; | 1859 IMkvReader* const pReader = m_pSegment->m_pReader; |
| 1764 | 1860 |
| 1765 const long long stop = m_start + m_size; | 1861 const long long stop = m_start + m_size; |
| 1766 long long pos = m_start; | 1862 long long pos = m_start; |
| 1767 | 1863 |
| 1768 long cue_points_size = 0; | 1864 long cue_points_size = 0; |
| 1769 | 1865 |
| 1770 while (pos < stop) { | 1866 while (pos < stop) { |
| 1771 const long long idpos = pos; | 1867 const long long idpos = pos; |
| 1772 | 1868 |
| 1773 long len; | 1869 long len; |
| 1774 | 1870 |
| 1775 const long long id = ReadUInt(pReader, pos, len); | 1871 const long long id = ReadID(pReader, pos, len); |
| 1776 if (id < 0 || (pos + len) > stop) { | 1872 if (id < 0 || (pos + len) > stop) { |
| 1777 return false; | 1873 return false; |
| 1778 } | 1874 } |
| 1779 | 1875 |
| 1780 pos += len; // consume ID | 1876 pos += len; // consume ID |
| 1781 | 1877 |
| 1782 const long long size = ReadUInt(pReader, pos, len); | 1878 const long long size = ReadUInt(pReader, pos, len); |
| 1783 if (size < 0 || (pos + len > stop)) { | 1879 if (size < 0 || (pos + len > stop)) { |
| 1784 return false; | 1880 return false; |
| 1785 } | 1881 } |
| 1786 | 1882 |
| 1787 pos += len; // consume Size field | 1883 pos += len; // consume Size field |
| 1788 if (pos + size > stop) { | 1884 if (pos + size > stop) { |
| 1789 return false; | 1885 return false; |
| 1790 } | 1886 } |
| 1791 | 1887 |
| 1792 if (id == 0x3B) // CuePoint ID | 1888 if (id == mkvmuxer::kMkvCuePoint) { |
| 1793 PreloadCuePoint(cue_points_size, idpos); | 1889 if (!PreloadCuePoint(cue_points_size, idpos)) |
| 1890 return false; |
| 1891 } |
| 1794 | 1892 |
| 1795 pos += size; // skip payload | 1893 pos += size; // skip payload |
| 1796 } | 1894 } |
| 1797 return true; | 1895 return true; |
| 1798 } | 1896 } |
| 1799 | 1897 |
| 1800 void Cues::PreloadCuePoint(long& cue_points_size, long long pos) const { | 1898 bool Cues::PreloadCuePoint(long& cue_points_size, long long pos) const { |
| 1801 assert(m_count == 0); | 1899 if (m_count != 0) |
| 1900 return false; |
| 1802 | 1901 |
| 1803 if (m_preload_count >= cue_points_size) { | 1902 if (m_preload_count >= cue_points_size) { |
| 1804 const long n = (cue_points_size <= 0) ? 2048 : 2 * cue_points_size; | 1903 const long n = (cue_points_size <= 0) ? 2048 : 2 * cue_points_size; |
| 1805 | 1904 |
| 1806 CuePoint** const qq = new CuePoint*[n]; | 1905 CuePoint** const qq = new (std::nothrow) CuePoint*[n]; |
| 1906 if (qq == NULL) |
| 1907 return false; |
| 1908 |
| 1807 CuePoint** q = qq; // beginning of target | 1909 CuePoint** q = qq; // beginning of target |
| 1808 | 1910 |
| 1809 CuePoint** p = m_cue_points; // beginning of source | 1911 CuePoint** p = m_cue_points; // beginning of source |
| 1810 CuePoint** const pp = p + m_preload_count; // end of source | 1912 CuePoint** const pp = p + m_preload_count; // end of source |
| 1811 | 1913 |
| 1812 while (p != pp) | 1914 while (p != pp) |
| 1813 *q++ = *p++; | 1915 *q++ = *p++; |
| 1814 | 1916 |
| 1815 delete[] m_cue_points; | 1917 delete[] m_cue_points; |
| 1816 | 1918 |
| 1817 m_cue_points = qq; | 1919 m_cue_points = qq; |
| 1818 cue_points_size = n; | 1920 cue_points_size = n; |
| 1819 } | 1921 } |
| 1820 | 1922 |
| 1821 CuePoint* const pCP = new CuePoint(m_preload_count, pos); | 1923 CuePoint* const pCP = new (std::nothrow) CuePoint(m_preload_count, pos); |
| 1924 if (pCP == NULL) |
| 1925 return false; |
| 1926 |
| 1822 m_cue_points[m_preload_count++] = pCP; | 1927 m_cue_points[m_preload_count++] = pCP; |
| 1928 return true; |
| 1823 } | 1929 } |
| 1824 | 1930 |
| 1825 bool Cues::LoadCuePoint() const { | 1931 bool Cues::LoadCuePoint() const { |
| 1826 // odbgstream os; | |
| 1827 // os << "Cues::LoadCuePoint" << endl; | |
| 1828 | |
| 1829 const long long stop = m_start + m_size; | 1932 const long long stop = m_start + m_size; |
| 1830 | 1933 |
| 1831 if (m_pos >= stop) | 1934 if (m_pos >= stop) |
| 1832 return false; // nothing else to do | 1935 return false; // nothing else to do |
| 1833 | 1936 |
| 1834 if (!Init()) { | 1937 if (!Init()) { |
| 1835 m_pos = stop; | 1938 m_pos = stop; |
| 1836 return false; | 1939 return false; |
| 1837 } | 1940 } |
| 1838 | 1941 |
| 1839 IMkvReader* const pReader = m_pSegment->m_pReader; | 1942 IMkvReader* const pReader = m_pSegment->m_pReader; |
| 1840 | 1943 |
| 1841 while (m_pos < stop) { | 1944 while (m_pos < stop) { |
| 1842 const long long idpos = m_pos; | 1945 const long long idpos = m_pos; |
| 1843 | 1946 |
| 1844 long len; | 1947 long len; |
| 1845 | 1948 |
| 1846 const long long id = ReadUInt(pReader, m_pos, len); | 1949 const long long id = ReadID(pReader, m_pos, len); |
| 1847 assert(id >= 0); // TODO | 1950 if (id < 0 || (m_pos + len) > stop) |
| 1848 assert((m_pos + len) <= stop); | 1951 return false; |
| 1849 | 1952 |
| 1850 m_pos += len; // consume ID | 1953 m_pos += len; // consume ID |
| 1851 | 1954 |
| 1852 const long long size = ReadUInt(pReader, m_pos, len); | 1955 const long long size = ReadUInt(pReader, m_pos, len); |
| 1853 assert(size >= 0); | 1956 if (size < 0 || (m_pos + len) > stop) |
| 1854 assert((m_pos + len) <= stop); | 1957 return false; |
| 1855 | 1958 |
| 1856 m_pos += len; // consume Size field | 1959 m_pos += len; // consume Size field |
| 1857 assert((m_pos + size) <= stop); | 1960 if ((m_pos + size) > stop) |
| 1961 return false; |
| 1858 | 1962 |
| 1859 if (id != 0x3B) { // CuePoint ID | 1963 if (id != mkvmuxer::kMkvCuePoint) { |
| 1860 m_pos += size; // consume payload | 1964 m_pos += size; // consume payload |
| 1861 assert(m_pos <= stop); | 1965 if (m_pos > stop) |
| 1966 return false; |
| 1862 | 1967 |
| 1863 continue; | 1968 continue; |
| 1864 } | 1969 } |
| 1865 | 1970 |
| 1866 assert(m_preload_count > 0); | 1971 if (m_preload_count < 1) |
| 1972 return false; |
| 1867 | 1973 |
| 1868 CuePoint* const pCP = m_cue_points[m_count]; | 1974 CuePoint* const pCP = m_cue_points[m_count]; |
| 1869 assert(pCP); | 1975 if (!pCP || (pCP->GetTimeCode() < 0 && (-pCP->GetTimeCode() != idpos))) |
| 1870 assert((pCP->GetTimeCode() >= 0) || (-pCP->GetTimeCode() == idpos)); | |
| 1871 if (pCP->GetTimeCode() < 0 && (-pCP->GetTimeCode() != idpos)) | |
| 1872 return false; | 1976 return false; |
| 1873 | 1977 |
| 1874 if (!pCP->Load(pReader)) { | 1978 if (!pCP->Load(pReader)) { |
| 1875 m_pos = stop; | 1979 m_pos = stop; |
| 1876 return false; | 1980 return false; |
| 1877 } | 1981 } |
| 1878 ++m_count; | 1982 ++m_count; |
| 1879 --m_preload_count; | 1983 --m_preload_count; |
| 1880 | 1984 |
| 1881 m_pos += size; // consume payload | 1985 m_pos += size; // consume payload |
| 1882 assert(m_pos <= stop); | 1986 if (m_pos > stop) |
| 1987 return false; |
| 1883 | 1988 |
| 1884 return true; // yes, we loaded a cue point | 1989 return true; // yes, we loaded a cue point |
| 1885 } | 1990 } |
| 1886 | 1991 |
| 1887 // return (m_pos < stop); | |
| 1888 return false; // no, we did not load a cue point | 1992 return false; // no, we did not load a cue point |
| 1889 } | 1993 } |
| 1890 | 1994 |
| 1891 bool Cues::Find(long long time_ns, const Track* pTrack, const CuePoint*& pCP, | 1995 bool Cues::Find(long long time_ns, const Track* pTrack, const CuePoint*& pCP, |
| 1892 const CuePoint::TrackPosition*& pTP) const { | 1996 const CuePoint::TrackPosition*& pTP) const { |
| 1893 assert(time_ns >= 0); | 1997 if (time_ns < 0 || pTrack == NULL || m_cue_points == NULL || m_count == 0) |
| 1894 assert(pTrack); | |
| 1895 | |
| 1896 if (m_cue_points == NULL) | |
| 1897 return false; | |
| 1898 | |
| 1899 if (m_count == 0) | |
| 1900 return false; | 1998 return false; |
| 1901 | 1999 |
| 1902 CuePoint** const ii = m_cue_points; | 2000 CuePoint** const ii = m_cue_points; |
| 1903 CuePoint** i = ii; | 2001 CuePoint** i = ii; |
| 1904 | 2002 |
| 1905 CuePoint** const jj = ii + m_count; | 2003 CuePoint** const jj = ii + m_count; |
| 1906 CuePoint** j = jj; | 2004 CuePoint** j = jj; |
| 1907 | 2005 |
| 1908 pCP = *i; | 2006 pCP = *i; |
| 1909 assert(pCP); | 2007 if (pCP == NULL) |
| 2008 return false; |
| 1910 | 2009 |
| 1911 if (time_ns <= pCP->GetTime(m_pSegment)) { | 2010 if (time_ns <= pCP->GetTime(m_pSegment)) { |
| 1912 pTP = pCP->Find(pTrack); | 2011 pTP = pCP->Find(pTrack); |
| 1913 return (pTP != NULL); | 2012 return (pTP != NULL); |
| 1914 } | 2013 } |
| 1915 | 2014 |
| 1916 while (i < j) { | 2015 while (i < j) { |
| 1917 // INVARIANT: | 2016 // INVARIANT: |
| 1918 //[ii, i) <= time_ns | 2017 //[ii, i) <= time_ns |
| 1919 //[i, j) ? | 2018 //[i, j) ? |
| 1920 //[j, jj) > time_ns | 2019 //[j, jj) > time_ns |
| 1921 | 2020 |
| 1922 CuePoint** const k = i + (j - i) / 2; | 2021 CuePoint** const k = i + (j - i) / 2; |
| 1923 assert(k < jj); | 2022 if (k >= jj) |
| 2023 return false; |
| 1924 | 2024 |
| 1925 CuePoint* const pCP = *k; | 2025 CuePoint* const pCP = *k; |
| 1926 assert(pCP); | 2026 if (pCP == NULL) |
| 2027 return false; |
| 1927 | 2028 |
| 1928 const long long t = pCP->GetTime(m_pSegment); | 2029 const long long t = pCP->GetTime(m_pSegment); |
| 1929 | 2030 |
| 1930 if (t <= time_ns) | 2031 if (t <= time_ns) |
| 1931 i = k + 1; | 2032 i = k + 1; |
| 1932 else | 2033 else |
| 1933 j = k; | 2034 j = k; |
| 1934 | 2035 |
| 1935 assert(i <= j); | 2036 if (i > j) |
| 2037 return false; |
| 1936 } | 2038 } |
| 1937 | 2039 |
| 1938 assert(i == j); | 2040 if (i != j || i > jj || i <= ii) |
| 1939 assert(i <= jj); | 2041 return false; |
| 1940 assert(i > ii); | |
| 1941 | 2042 |
| 1942 pCP = *--i; | 2043 pCP = *--i; |
| 1943 assert(pCP); | 2044 |
| 1944 assert(pCP->GetTime(m_pSegment) <= time_ns); | 2045 if (pCP == NULL || pCP->GetTime(m_pSegment) > time_ns) |
| 2046 return false; |
| 1945 | 2047 |
| 1946 // TODO: here and elsewhere, it's probably not correct to search | 2048 // TODO: here and elsewhere, it's probably not correct to search |
| 1947 // for the cue point with this time, and then search for a matching | 2049 // for the cue point with this time, and then search for a matching |
| 1948 // track. In principle, the matching track could be on some earlier | 2050 // track. In principle, the matching track could be on some earlier |
| 1949 // cue point, and with our current algorithm, we'd miss it. To make | 2051 // cue point, and with our current algorithm, we'd miss it. To make |
| 1950 // this bullet-proof, we'd need to create a secondary structure, | 2052 // this bullet-proof, we'd need to create a secondary structure, |
| 1951 // with a list of cue points that apply to a track, and then search | 2053 // with a list of cue points that apply to a track, and then search |
| 1952 // that track-based structure for a matching cue point. | 2054 // that track-based structure for a matching cue point. |
| 1953 | 2055 |
| 1954 pTP = pCP->Find(pTrack); | 2056 pTP = pCP->Find(pTrack); |
| 1955 return (pTP != NULL); | 2057 return (pTP != NULL); |
| 1956 } | 2058 } |
| 1957 | 2059 |
| 1958 const CuePoint* Cues::GetFirst() const { | 2060 const CuePoint* Cues::GetFirst() const { |
| 1959 if (m_cue_points == NULL) | 2061 if (m_cue_points == NULL || m_count == 0) |
| 1960 return NULL; | |
| 1961 | |
| 1962 if (m_count == 0) | |
| 1963 return NULL; | 2062 return NULL; |
| 1964 | 2063 |
| 1965 CuePoint* const* const pp = m_cue_points; | 2064 CuePoint* const* const pp = m_cue_points; |
| 1966 assert(pp); | 2065 if (pp == NULL) |
| 2066 return NULL; |
| 1967 | 2067 |
| 1968 CuePoint* const pCP = pp[0]; | 2068 CuePoint* const pCP = pp[0]; |
| 1969 assert(pCP); | 2069 if (pCP == NULL || pCP->GetTimeCode() < 0) |
| 1970 assert(pCP->GetTimeCode() >= 0); | 2070 return NULL; |
| 1971 | 2071 |
| 1972 return pCP; | 2072 return pCP; |
| 1973 } | 2073 } |
| 1974 | 2074 |
| 1975 const CuePoint* Cues::GetLast() const { | 2075 const CuePoint* Cues::GetLast() const { |
| 1976 if (m_cue_points == NULL) | 2076 if (m_cue_points == NULL || m_count <= 0) |
| 1977 return NULL; | |
| 1978 | |
| 1979 if (m_count <= 0) | |
| 1980 return NULL; | 2077 return NULL; |
| 1981 | 2078 |
| 1982 const long index = m_count - 1; | 2079 const long index = m_count - 1; |
| 1983 | 2080 |
| 1984 CuePoint* const* const pp = m_cue_points; | 2081 CuePoint* const* const pp = m_cue_points; |
| 1985 assert(pp); | 2082 if (pp == NULL) |
| 2083 return NULL; |
| 1986 | 2084 |
| 1987 CuePoint* const pCP = pp[index]; | 2085 CuePoint* const pCP = pp[index]; |
| 1988 assert(pCP); | 2086 if (pCP == NULL || pCP->GetTimeCode() < 0) |
| 1989 assert(pCP->GetTimeCode() >= 0); | 2087 return NULL; |
| 1990 | 2088 |
| 1991 return pCP; | 2089 return pCP; |
| 1992 } | 2090 } |
| 1993 | 2091 |
| 1994 const CuePoint* Cues::GetNext(const CuePoint* pCurr) const { | 2092 const CuePoint* Cues::GetNext(const CuePoint* pCurr) const { |
| 1995 if (pCurr == NULL) | 2093 if (pCurr == NULL || pCurr->GetTimeCode() < 0 || |
| 2094 m_cue_points == NULL || m_count < 1) { |
| 2095 return NULL; |
| 2096 } |
| 2097 |
| 2098 long index = pCurr->m_index; |
| 2099 if (index >= m_count) |
| 1996 return NULL; | 2100 return NULL; |
| 1997 | 2101 |
| 1998 assert(pCurr->GetTimeCode() >= 0); | |
| 1999 assert(m_cue_points); | |
| 2000 assert(m_count >= 1); | |
| 2001 | |
| 2002 long index = pCurr->m_index; | |
| 2003 assert(index < m_count); | |
| 2004 | |
| 2005 CuePoint* const* const pp = m_cue_points; | 2102 CuePoint* const* const pp = m_cue_points; |
| 2006 assert(pp); | 2103 if (pp == NULL || pp[index] != pCurr) |
| 2007 assert(pp[index] == pCurr); | 2104 return NULL; |
| 2008 | 2105 |
| 2009 ++index; | 2106 ++index; |
| 2010 | 2107 |
| 2011 if (index >= m_count) | 2108 if (index >= m_count) |
| 2012 return NULL; | 2109 return NULL; |
| 2013 | 2110 |
| 2014 CuePoint* const pNext = pp[index]; | 2111 CuePoint* const pNext = pp[index]; |
| 2015 assert(pNext); | 2112 |
| 2016 assert(pNext->GetTimeCode() >= 0); | 2113 if (pNext == NULL || pNext->GetTimeCode() < 0) |
| 2114 return NULL; |
| 2017 | 2115 |
| 2018 return pNext; | 2116 return pNext; |
| 2019 } | 2117 } |
| 2020 | 2118 |
| 2021 const BlockEntry* Cues::GetBlock(const CuePoint* pCP, | 2119 const BlockEntry* Cues::GetBlock(const CuePoint* pCP, |
| 2022 const CuePoint::TrackPosition* pTP) const { | 2120 const CuePoint::TrackPosition* pTP) const { |
| 2023 if (pCP == NULL) | 2121 if (pCP == NULL || pTP == NULL) |
| 2024 return NULL; | |
| 2025 | |
| 2026 if (pTP == NULL) | |
| 2027 return NULL; | 2122 return NULL; |
| 2028 | 2123 |
| 2029 return m_pSegment->GetBlock(*pCP, *pTP); | 2124 return m_pSegment->GetBlock(*pCP, *pTP); |
| 2030 } | 2125 } |
| 2031 | 2126 |
| 2032 const BlockEntry* Segment::GetBlock(const CuePoint& cp, | 2127 const BlockEntry* Segment::GetBlock(const CuePoint& cp, |
| 2033 const CuePoint::TrackPosition& tp) { | 2128 const CuePoint::TrackPosition& tp) { |
| 2034 Cluster** const ii = m_clusters; | 2129 Cluster** const ii = m_clusters; |
| 2035 Cluster** i = ii; | 2130 Cluster** i = ii; |
| 2036 | 2131 |
| (...skipping 26 matching lines...) Expand all Loading... |
| 2063 else if (pos > tp.m_pos) | 2158 else if (pos > tp.m_pos) |
| 2064 j = k; | 2159 j = k; |
| 2065 else | 2160 else |
| 2066 return pCluster->GetEntry(cp, tp); | 2161 return pCluster->GetEntry(cp, tp); |
| 2067 } | 2162 } |
| 2068 | 2163 |
| 2069 assert(i == j); | 2164 assert(i == j); |
| 2070 // assert(Cluster::HasBlockEntries(this, tp.m_pos)); | 2165 // assert(Cluster::HasBlockEntries(this, tp.m_pos)); |
| 2071 | 2166 |
| 2072 Cluster* const pCluster = Cluster::Create(this, -1, tp.m_pos); //, -1); | 2167 Cluster* const pCluster = Cluster::Create(this, -1, tp.m_pos); //, -1); |
| 2073 assert(pCluster); | 2168 if (pCluster == NULL) |
| 2169 return NULL; |
| 2074 | 2170 |
| 2075 const ptrdiff_t idx = i - m_clusters; | 2171 const ptrdiff_t idx = i - m_clusters; |
| 2076 | 2172 |
| 2077 PreloadCluster(pCluster, idx); | 2173 if (!PreloadCluster(pCluster, idx)) { |
| 2174 delete pCluster; |
| 2175 return NULL; |
| 2176 } |
| 2078 assert(m_clusters); | 2177 assert(m_clusters); |
| 2079 assert(m_clusterPreloadCount > 0); | 2178 assert(m_clusterPreloadCount > 0); |
| 2080 assert(m_clusters[idx] == pCluster); | 2179 assert(m_clusters[idx] == pCluster); |
| 2081 | 2180 |
| 2082 return pCluster->GetEntry(cp, tp); | 2181 return pCluster->GetEntry(cp, tp); |
| 2083 } | 2182 } |
| 2084 | 2183 |
| 2085 const Cluster* Segment::FindOrPreloadCluster(long long requested_pos) { | 2184 const Cluster* Segment::FindOrPreloadCluster(long long requested_pos) { |
| 2086 if (requested_pos < 0) | 2185 if (requested_pos < 0) |
| 2087 return 0; | 2186 return 0; |
| (...skipping 30 matching lines...) Expand all Loading... |
| 2118 else if (pos > requested_pos) | 2217 else if (pos > requested_pos) |
| 2119 j = k; | 2218 j = k; |
| 2120 else | 2219 else |
| 2121 return pCluster; | 2220 return pCluster; |
| 2122 } | 2221 } |
| 2123 | 2222 |
| 2124 assert(i == j); | 2223 assert(i == j); |
| 2125 // assert(Cluster::HasBlockEntries(this, tp.m_pos)); | 2224 // assert(Cluster::HasBlockEntries(this, tp.m_pos)); |
| 2126 | 2225 |
| 2127 Cluster* const pCluster = Cluster::Create(this, -1, requested_pos); | 2226 Cluster* const pCluster = Cluster::Create(this, -1, requested_pos); |
| 2128 //-1); | 2227 if (pCluster == NULL) |
| 2129 assert(pCluster); | 2228 return NULL; |
| 2130 | 2229 |
| 2131 const ptrdiff_t idx = i - m_clusters; | 2230 const ptrdiff_t idx = i - m_clusters; |
| 2132 | 2231 |
| 2133 PreloadCluster(pCluster, idx); | 2232 if (!PreloadCluster(pCluster, idx)) { |
| 2233 delete pCluster; |
| 2234 return NULL; |
| 2235 } |
| 2134 assert(m_clusters); | 2236 assert(m_clusters); |
| 2135 assert(m_clusterPreloadCount > 0); | 2237 assert(m_clusterPreloadCount > 0); |
| 2136 assert(m_clusters[idx] == pCluster); | 2238 assert(m_clusters[idx] == pCluster); |
| 2137 | 2239 |
| 2138 return pCluster; | 2240 return pCluster; |
| 2139 } | 2241 } |
| 2140 | 2242 |
| 2141 CuePoint::CuePoint(long idx, long long pos) | 2243 CuePoint::CuePoint(long idx, long long pos) |
| 2142 : m_element_start(0), | 2244 : m_element_start(0), |
| 2143 m_element_size(0), | 2245 m_element_size(0), |
| (...skipping 17 matching lines...) Expand all Loading... |
| 2161 assert(m_track_positions_count == 0); | 2263 assert(m_track_positions_count == 0); |
| 2162 | 2264 |
| 2163 long long pos_ = -m_timecode; | 2265 long long pos_ = -m_timecode; |
| 2164 const long long element_start = pos_; | 2266 const long long element_start = pos_; |
| 2165 | 2267 |
| 2166 long long stop; | 2268 long long stop; |
| 2167 | 2269 |
| 2168 { | 2270 { |
| 2169 long len; | 2271 long len; |
| 2170 | 2272 |
| 2171 const long long id = ReadUInt(pReader, pos_, len); | 2273 const long long id = ReadID(pReader, pos_, len); |
| 2172 assert(id == 0x3B); // CuePoint ID | 2274 if (id != mkvmuxer::kMkvCuePoint) |
| 2173 if (id != 0x3B) | |
| 2174 return false; | 2275 return false; |
| 2175 | 2276 |
| 2176 pos_ += len; // consume ID | 2277 pos_ += len; // consume ID |
| 2177 | 2278 |
| 2178 const long long size = ReadUInt(pReader, pos_, len); | 2279 const long long size = ReadUInt(pReader, pos_, len); |
| 2179 assert(size >= 0); | 2280 assert(size >= 0); |
| 2180 | 2281 |
| 2181 pos_ += len; // consume Size field | 2282 pos_ += len; // consume Size field |
| 2182 // pos_ now points to start of payload | 2283 // pos_ now points to start of payload |
| 2183 | 2284 |
| 2184 stop = pos_ + size; | 2285 stop = pos_ + size; |
| 2185 } | 2286 } |
| 2186 | 2287 |
| 2187 const long long element_size = stop - element_start; | 2288 const long long element_size = stop - element_start; |
| 2188 | 2289 |
| 2189 long long pos = pos_; | 2290 long long pos = pos_; |
| 2190 | 2291 |
| 2191 // First count number of track positions | 2292 // First count number of track positions |
| 2192 | 2293 |
| 2193 while (pos < stop) { | 2294 while (pos < stop) { |
| 2194 long len; | 2295 long len; |
| 2195 | 2296 |
| 2196 const long long id = ReadUInt(pReader, pos, len); | 2297 const long long id = ReadID(pReader, pos, len); |
| 2197 if ((id < 0) || (pos + len > stop)) { | 2298 if ((id < 0) || (pos + len > stop)) { |
| 2198 return false; | 2299 return false; |
| 2199 } | 2300 } |
| 2200 | 2301 |
| 2201 pos += len; // consume ID | 2302 pos += len; // consume ID |
| 2202 | 2303 |
| 2203 const long long size = ReadUInt(pReader, pos, len); | 2304 const long long size = ReadUInt(pReader, pos, len); |
| 2204 if ((size < 0) || (pos + len > stop)) { | 2305 if ((size < 0) || (pos + len > stop)) { |
| 2205 return false; | 2306 return false; |
| 2206 } | 2307 } |
| 2207 | 2308 |
| 2208 pos += len; // consume Size field | 2309 pos += len; // consume Size field |
| 2209 if ((pos + size) > stop) { | 2310 if ((pos + size) > stop) { |
| 2210 return false; | 2311 return false; |
| 2211 } | 2312 } |
| 2212 | 2313 |
| 2213 if (id == 0x33) // CueTime ID | 2314 if (id == mkvmuxer::kMkvCueTime) |
| 2214 m_timecode = UnserializeUInt(pReader, pos, size); | 2315 m_timecode = UnserializeUInt(pReader, pos, size); |
| 2215 | 2316 |
| 2216 else if (id == 0x37) // CueTrackPosition(s) ID | 2317 else if (id == mkvmuxer::kMkvCueTrackPositions) |
| 2217 ++m_track_positions_count; | 2318 ++m_track_positions_count; |
| 2218 | 2319 |
| 2219 pos += size; // consume payload | 2320 pos += size; // consume payload |
| 2220 } | 2321 } |
| 2221 | 2322 |
| 2222 if (m_timecode < 0 || m_track_positions_count <= 0) { | 2323 if (m_timecode < 0 || m_track_positions_count <= 0) { |
| 2223 return false; | 2324 return false; |
| 2224 } | 2325 } |
| 2225 | 2326 |
| 2226 // os << "CuePoint::Load(cont'd): idpos=" << idpos | 2327 // os << "CuePoint::Load(cont'd): idpos=" << idpos |
| 2227 // << " timecode=" << m_timecode | 2328 // << " timecode=" << m_timecode |
| 2228 // << endl; | 2329 // << endl; |
| 2229 | 2330 |
| 2230 m_track_positions = new TrackPosition[m_track_positions_count]; | 2331 m_track_positions = new (std::nothrow) TrackPosition[m_track_positions_count]; |
| 2332 if (m_track_positions == NULL) |
| 2333 return false; |
| 2231 | 2334 |
| 2232 // Now parse track positions | 2335 // Now parse track positions |
| 2233 | 2336 |
| 2234 TrackPosition* p = m_track_positions; | 2337 TrackPosition* p = m_track_positions; |
| 2235 pos = pos_; | 2338 pos = pos_; |
| 2236 | 2339 |
| 2237 while (pos < stop) { | 2340 while (pos < stop) { |
| 2238 long len; | 2341 long len; |
| 2239 | 2342 |
| 2240 const long long id = ReadUInt(pReader, pos, len); | 2343 const long long id = ReadID(pReader, pos, len); |
| 2241 assert(id >= 0); | 2344 if (id < 0 || (pos + len) > stop) |
| 2242 assert((pos + len) <= stop); | 2345 return false; |
| 2243 | 2346 |
| 2244 pos += len; // consume ID | 2347 pos += len; // consume ID |
| 2245 | 2348 |
| 2246 const long long size = ReadUInt(pReader, pos, len); | 2349 const long long size = ReadUInt(pReader, pos, len); |
| 2247 assert(size >= 0); | 2350 assert(size >= 0); |
| 2248 assert((pos + len) <= stop); | 2351 assert((pos + len) <= stop); |
| 2249 | 2352 |
| 2250 pos += len; // consume Size field | 2353 pos += len; // consume Size field |
| 2251 assert((pos + size) <= stop); | 2354 assert((pos + size) <= stop); |
| 2252 | 2355 |
| 2253 if (id == 0x37) { // CueTrackPosition(s) ID | 2356 if (id == mkvmuxer::kMkvCueTrackPositions) { |
| 2254 TrackPosition& tp = *p++; | 2357 TrackPosition& tp = *p++; |
| 2255 if (!tp.Parse(pReader, pos, size)) { | 2358 if (!tp.Parse(pReader, pos, size)) { |
| 2256 return false; | 2359 return false; |
| 2257 } | 2360 } |
| 2258 } | 2361 } |
| 2259 | 2362 |
| 2260 pos += size; // consume payload | 2363 pos += size; // consume payload |
| 2261 assert(pos <= stop); | 2364 if (pos > stop) |
| 2365 return false; |
| 2262 } | 2366 } |
| 2263 | 2367 |
| 2264 assert(size_t(p - m_track_positions) == m_track_positions_count); | 2368 assert(size_t(p - m_track_positions) == m_track_positions_count); |
| 2265 | 2369 |
| 2266 m_element_start = element_start; | 2370 m_element_start = element_start; |
| 2267 m_element_size = element_size; | 2371 m_element_size = element_size; |
| 2268 | 2372 |
| 2269 return true; | 2373 return true; |
| 2270 } | 2374 } |
| 2271 | 2375 |
| 2272 bool CuePoint::TrackPosition::Parse(IMkvReader* pReader, long long start_, | 2376 bool CuePoint::TrackPosition::Parse(IMkvReader* pReader, long long start_, |
| 2273 long long size_) { | 2377 long long size_) { |
| 2274 const long long stop = start_ + size_; | 2378 const long long stop = start_ + size_; |
| 2275 long long pos = start_; | 2379 long long pos = start_; |
| 2276 | 2380 |
| 2277 m_track = -1; | 2381 m_track = -1; |
| 2278 m_pos = -1; | 2382 m_pos = -1; |
| 2279 m_block = 1; // default | 2383 m_block = 1; // default |
| 2280 | 2384 |
| 2281 while (pos < stop) { | 2385 while (pos < stop) { |
| 2282 long len; | 2386 long len; |
| 2283 | 2387 |
| 2284 const long long id = ReadUInt(pReader, pos, len); | 2388 const long long id = ReadID(pReader, pos, len); |
| 2285 if ((id < 0) || ((pos + len) > stop)) { | 2389 if ((id < 0) || ((pos + len) > stop)) { |
| 2286 return false; | 2390 return false; |
| 2287 } | 2391 } |
| 2288 | 2392 |
| 2289 pos += len; // consume ID | 2393 pos += len; // consume ID |
| 2290 | 2394 |
| 2291 const long long size = ReadUInt(pReader, pos, len); | 2395 const long long size = ReadUInt(pReader, pos, len); |
| 2292 if ((size < 0) || ((pos + len) > stop)) { | 2396 if ((size < 0) || ((pos + len) > stop)) { |
| 2293 return false; | 2397 return false; |
| 2294 } | 2398 } |
| 2295 | 2399 |
| 2296 pos += len; // consume Size field | 2400 pos += len; // consume Size field |
| 2297 if ((pos + size) > stop) { | 2401 if ((pos + size) > stop) { |
| 2298 return false; | 2402 return false; |
| 2299 } | 2403 } |
| 2300 | 2404 |
| 2301 if (id == 0x77) // CueTrack ID | 2405 if (id == mkvmuxer::kMkvCueTrack) |
| 2302 m_track = UnserializeUInt(pReader, pos, size); | 2406 m_track = UnserializeUInt(pReader, pos, size); |
| 2303 | 2407 else if (id == mkvmuxer::kMkvCueClusterPosition) |
| 2304 else if (id == 0x71) // CueClusterPos ID | |
| 2305 m_pos = UnserializeUInt(pReader, pos, size); | 2408 m_pos = UnserializeUInt(pReader, pos, size); |
| 2306 | 2409 else if (id == mkvmuxer::kMkvCueBlockNumber) |
| 2307 else if (id == 0x1378) // CueBlockNumber | |
| 2308 m_block = UnserializeUInt(pReader, pos, size); | 2410 m_block = UnserializeUInt(pReader, pos, size); |
| 2309 | 2411 |
| 2310 pos += size; // consume payload | 2412 pos += size; // consume payload |
| 2311 } | 2413 } |
| 2312 | 2414 |
| 2313 if ((m_pos < 0) || (m_track <= 0)) { | 2415 if ((m_pos < 0) || (m_track <= 0)) { |
| 2314 return false; | 2416 return false; |
| 2315 } | 2417 } |
| 2316 | 2418 |
| 2317 return true; | 2419 return true; |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2430 | 2532 |
| 2431 { | 2533 { |
| 2432 long len; | 2534 long len; |
| 2433 | 2535 |
| 2434 long long result = GetUIntLength(m_pReader, pos, len); | 2536 long long result = GetUIntLength(m_pReader, pos, len); |
| 2435 assert(result == 0); | 2537 assert(result == 0); |
| 2436 assert((pos + len) <= stop); // TODO | 2538 assert((pos + len) <= stop); // TODO |
| 2437 if (result != 0) | 2539 if (result != 0) |
| 2438 return NULL; | 2540 return NULL; |
| 2439 | 2541 |
| 2440 const long long id = ReadUInt(m_pReader, pos, len); | 2542 const long long id = ReadID(m_pReader, pos, len); |
| 2441 assert(id == 0x0F43B675); // Cluster ID | 2543 if (id != mkvmuxer::kMkvCluster) |
| 2442 if (id != 0x0F43B675) | |
| 2443 return NULL; | 2544 return NULL; |
| 2444 | 2545 |
| 2445 pos += len; // consume ID | 2546 pos += len; // consume ID |
| 2446 | 2547 |
| 2447 // Read Size | 2548 // Read Size |
| 2448 result = GetUIntLength(m_pReader, pos, len); | 2549 result = GetUIntLength(m_pReader, pos, len); |
| 2449 assert(result == 0); // TODO | 2550 assert(result == 0); // TODO |
| 2450 assert((pos + len) <= stop); // TODO | 2551 assert((pos + len) <= stop); // TODO |
| 2451 | 2552 |
| 2452 const long long size = ReadUInt(m_pReader, pos, len); | 2553 const long long size = ReadUInt(m_pReader, pos, len); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 2467 long len; | 2568 long len; |
| 2468 | 2569 |
| 2469 long long result = GetUIntLength(m_pReader, pos, len); | 2570 long long result = GetUIntLength(m_pReader, pos, len); |
| 2470 assert(result == 0); | 2571 assert(result == 0); |
| 2471 assert((pos + len) <= stop); // TODO | 2572 assert((pos + len) <= stop); // TODO |
| 2472 if (result != 0) | 2573 if (result != 0) |
| 2473 return NULL; | 2574 return NULL; |
| 2474 | 2575 |
| 2475 const long long idpos = pos; // pos of next (potential) cluster | 2576 const long long idpos = pos; // pos of next (potential) cluster |
| 2476 | 2577 |
| 2477 const long long id = ReadUInt(m_pReader, idpos, len); | 2578 const long long id = ReadID(m_pReader, idpos, len); |
| 2478 assert(id > 0); // TODO | 2579 if (id < 0) |
| 2580 return NULL; |
| 2479 | 2581 |
| 2480 pos += len; // consume ID | 2582 pos += len; // consume ID |
| 2481 | 2583 |
| 2482 // Read Size | 2584 // Read Size |
| 2483 result = GetUIntLength(m_pReader, pos, len); | 2585 result = GetUIntLength(m_pReader, pos, len); |
| 2484 assert(result == 0); // TODO | 2586 assert(result == 0); // TODO |
| 2485 assert((pos + len) <= stop); // TODO | 2587 assert((pos + len) <= stop); // TODO |
| 2486 | 2588 |
| 2487 const long long size = ReadUInt(m_pReader, pos, len); | 2589 const long long size = ReadUInt(m_pReader, pos, len); |
| 2488 assert(size >= 0); // TODO | 2590 assert(size >= 0); // TODO |
| 2489 | 2591 |
| 2490 pos += len; // consume length of size of element | 2592 pos += len; // consume length of size of element |
| 2491 assert((pos + size) <= stop); // TODO | 2593 assert((pos + size) <= stop); // TODO |
| 2492 | 2594 |
| 2493 // Pos now points to start of payload | 2595 // Pos now points to start of payload |
| 2494 | 2596 |
| 2495 if (size == 0) // weird | 2597 if (size == 0) // weird |
| 2496 continue; | 2598 continue; |
| 2497 | 2599 |
| 2498 if (id == 0x0F43B675) { // Cluster ID | 2600 if (id == mkvmuxer::kMkvCluster) { |
| 2499 const long long off_next_ = idpos - m_start; | 2601 const long long off_next_ = idpos - m_start; |
| 2500 | 2602 |
| 2501 long long pos_; | 2603 long long pos_; |
| 2502 long len_; | 2604 long len_; |
| 2503 | 2605 |
| 2504 const long status = Cluster::HasBlockEntries(this, off_next_, pos_, len_); | 2606 const long status = Cluster::HasBlockEntries(this, off_next_, pos_, len_); |
| 2505 | 2607 |
| 2506 assert(status >= 0); | 2608 assert(status >= 0); |
| 2507 | 2609 |
| 2508 if (status > 0) { | 2610 if (status > 0) { |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2546 i = k + 1; | 2648 i = k + 1; |
| 2547 else if (pos > off_next) | 2649 else if (pos > off_next) |
| 2548 j = k; | 2650 j = k; |
| 2549 else | 2651 else |
| 2550 return pNext; | 2652 return pNext; |
| 2551 } | 2653 } |
| 2552 | 2654 |
| 2553 assert(i == j); | 2655 assert(i == j); |
| 2554 | 2656 |
| 2555 Cluster* const pNext = Cluster::Create(this, -1, off_next); | 2657 Cluster* const pNext = Cluster::Create(this, -1, off_next); |
| 2556 assert(pNext); | 2658 if (pNext == NULL) |
| 2659 return NULL; |
| 2557 | 2660 |
| 2558 const ptrdiff_t idx_next = i - m_clusters; // insertion position | 2661 const ptrdiff_t idx_next = i - m_clusters; // insertion position |
| 2559 | 2662 |
| 2560 PreloadCluster(pNext, idx_next); | 2663 if (!PreloadCluster(pNext, idx_next)) { |
| 2664 delete pNext; |
| 2665 return NULL; |
| 2666 } |
| 2561 assert(m_clusters); | 2667 assert(m_clusters); |
| 2562 assert(idx_next < m_clusterSize); | 2668 assert(idx_next < m_clusterSize); |
| 2563 assert(m_clusters[idx_next] == pNext); | 2669 assert(m_clusters[idx_next] == pNext); |
| 2564 | 2670 |
| 2565 return pNext; | 2671 return pNext; |
| 2566 } | 2672 } |
| 2567 | 2673 |
| 2568 long Segment::ParseNext(const Cluster* pCurr, const Cluster*& pResult, | 2674 long Segment::ParseNext(const Cluster* pCurr, const Cluster*& pResult, |
| 2569 long long& pos, long& len) { | 2675 long long& pos, long& len) { |
| 2570 assert(pCurr); | 2676 assert(pCurr); |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2634 return E_BUFFER_NOT_FULL; | 2740 return E_BUFFER_NOT_FULL; |
| 2635 | 2741 |
| 2636 if ((segment_stop >= 0) && ((pos + len) > segment_stop)) | 2742 if ((segment_stop >= 0) && ((pos + len) > segment_stop)) |
| 2637 return E_FILE_FORMAT_INVALID; | 2743 return E_FILE_FORMAT_INVALID; |
| 2638 | 2744 |
| 2639 if ((pos + len) > avail) | 2745 if ((pos + len) > avail) |
| 2640 return E_BUFFER_NOT_FULL; | 2746 return E_BUFFER_NOT_FULL; |
| 2641 | 2747 |
| 2642 const long long id = ReadUInt(m_pReader, pos, len); | 2748 const long long id = ReadUInt(m_pReader, pos, len); |
| 2643 | 2749 |
| 2644 if (id != 0x0F43B675) // weird: not Cluster ID | 2750 if (id != mkvmuxer::kMkvCluster) |
| 2645 return -1; | 2751 return -1; |
| 2646 | 2752 |
| 2647 pos += len; // consume ID | 2753 pos += len; // consume ID |
| 2648 | 2754 |
| 2649 // Read Size | 2755 // Read Size |
| 2650 | 2756 |
| 2651 if ((pos + 1) > avail) { | 2757 if ((pos + 1) > avail) { |
| 2652 len = 1; | 2758 len = 1; |
| 2653 return E_BUFFER_NOT_FULL; | 2759 return E_BUFFER_NOT_FULL; |
| 2654 } | 2760 } |
| (...skipping 25 matching lines...) Expand all Loading... |
| 2680 return E_FILE_FORMAT_INVALID; // TODO: resolve this | 2786 return E_FILE_FORMAT_INVALID; // TODO: resolve this |
| 2681 | 2787 |
| 2682 // assert((pCurr->m_size <= 0) || (pCurr->m_size == size)); | 2788 // assert((pCurr->m_size <= 0) || (pCurr->m_size == size)); |
| 2683 | 2789 |
| 2684 if ((segment_stop >= 0) && ((pos + size) > segment_stop)) | 2790 if ((segment_stop >= 0) && ((pos + size) > segment_stop)) |
| 2685 return E_FILE_FORMAT_INVALID; | 2791 return E_FILE_FORMAT_INVALID; |
| 2686 | 2792 |
| 2687 // Pos now points to start of payload | 2793 // Pos now points to start of payload |
| 2688 | 2794 |
| 2689 pos += size; // consume payload (that is, the current cluster) | 2795 pos += size; // consume payload (that is, the current cluster) |
| 2690 assert((segment_stop < 0) || (pos <= segment_stop)); | 2796 if (segment_stop >= 0 && pos > segment_stop) |
| 2797 return E_FILE_FORMAT_INVALID; |
| 2691 | 2798 |
| 2692 // By consuming the payload, we are assuming that the curr | 2799 // By consuming the payload, we are assuming that the curr |
| 2693 // cluster isn't interesting. That is, we don't bother checking | 2800 // cluster isn't interesting. That is, we don't bother checking |
| 2694 // whether the payload of the curr cluster is less than what | 2801 // whether the payload of the curr cluster is less than what |
| 2695 // happens to be available (obtained via IMkvReader::Length). | 2802 // happens to be available (obtained via IMkvReader::Length). |
| 2696 // Presumably the caller has already dispensed with the current | 2803 // Presumably the caller has already dispensed with the current |
| 2697 // cluster, and really does want the next cluster. | 2804 // cluster, and really does want the next cluster. |
| 2698 } | 2805 } |
| 2699 | 2806 |
| 2700 // pos now points to just beyond the last fully-loaded cluster | 2807 // pos now points to just beyond the last fully-loaded cluster |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2748 | 2855 |
| 2749 if ((segment_stop >= 0) && ((pos + len) > segment_stop)) | 2856 if ((segment_stop >= 0) && ((pos + len) > segment_stop)) |
| 2750 return E_FILE_FORMAT_INVALID; | 2857 return E_FILE_FORMAT_INVALID; |
| 2751 | 2858 |
| 2752 if ((pos + len) > avail) | 2859 if ((pos + len) > avail) |
| 2753 return E_BUFFER_NOT_FULL; | 2860 return E_BUFFER_NOT_FULL; |
| 2754 | 2861 |
| 2755 const long long idpos = pos; // absolute | 2862 const long long idpos = pos; // absolute |
| 2756 const long long idoff = pos - m_start; // relative | 2863 const long long idoff = pos - m_start; // relative |
| 2757 | 2864 |
| 2758 const long long id = ReadUInt(m_pReader, idpos, len); // absolute | 2865 const long long id = ReadID(m_pReader, idpos, len); // absolute |
| 2759 | 2866 |
| 2760 if (id < 0) // error | 2867 if (id < 0) // error |
| 2761 return static_cast<long>(id); | 2868 return static_cast<long>(id); |
| 2762 | 2869 |
| 2763 if (id == 0) // weird | 2870 if (id == 0) // weird |
| 2764 return -1; // generic error | 2871 return -1; // generic error |
| 2765 | 2872 |
| 2766 pos += len; // consume ID | 2873 pos += len; // consume ID |
| 2767 | 2874 |
| 2768 // Read Size | 2875 // Read Size |
| (...skipping 29 matching lines...) Expand all Loading... |
| 2798 if (size == 0) // weird | 2905 if (size == 0) // weird |
| 2799 continue; | 2906 continue; |
| 2800 | 2907 |
| 2801 const long long unknown_size = (1LL << (7 * len)) - 1; | 2908 const long long unknown_size = (1LL << (7 * len)) - 1; |
| 2802 | 2909 |
| 2803 if ((segment_stop >= 0) && (size != unknown_size) && | 2910 if ((segment_stop >= 0) && (size != unknown_size) && |
| 2804 ((pos + size) > segment_stop)) { | 2911 ((pos + size) > segment_stop)) { |
| 2805 return E_FILE_FORMAT_INVALID; | 2912 return E_FILE_FORMAT_INVALID; |
| 2806 } | 2913 } |
| 2807 | 2914 |
| 2808 if (id == 0x0C53BB6B) { // Cues ID | 2915 if (id == mkvmuxer::kMkvCues) { |
| 2809 if (size == unknown_size) | 2916 if (size == unknown_size) |
| 2810 return E_FILE_FORMAT_INVALID; | 2917 return E_FILE_FORMAT_INVALID; |
| 2811 | 2918 |
| 2812 const long long element_stop = pos + size; | 2919 const long long element_stop = pos + size; |
| 2813 | 2920 |
| 2814 if ((segment_stop >= 0) && (element_stop > segment_stop)) | 2921 if ((segment_stop >= 0) && (element_stop > segment_stop)) |
| 2815 return E_FILE_FORMAT_INVALID; | 2922 return E_FILE_FORMAT_INVALID; |
| 2816 | 2923 |
| 2817 const long long element_start = idpos; | 2924 const long long element_start = idpos; |
| 2818 const long long element_size = element_stop - element_start; | 2925 const long long element_size = element_stop - element_start; |
| 2819 | 2926 |
| 2820 if (m_pCues == NULL) { | 2927 if (m_pCues == NULL) { |
| 2821 m_pCues = new Cues(this, pos, size, element_start, element_size); | 2928 m_pCues = new (std::nothrow) |
| 2822 assert(m_pCues); // TODO | 2929 Cues(this, pos, size, element_start, element_size); |
| 2930 if (m_pCues == NULL) |
| 2931 return false; |
| 2823 } | 2932 } |
| 2824 | 2933 |
| 2825 pos += size; // consume payload | 2934 pos += size; // consume payload |
| 2826 assert((segment_stop < 0) || (pos <= segment_stop)); | 2935 if (segment_stop >= 0 && pos > segment_stop) |
| 2936 return E_FILE_FORMAT_INVALID; |
| 2827 | 2937 |
| 2828 continue; | 2938 continue; |
| 2829 } | 2939 } |
| 2830 | 2940 |
| 2831 if (id != 0x0F43B675) { // not a Cluster ID | 2941 if (id != mkvmuxer::kMkvCluster) { // not a Cluster ID |
| 2832 if (size == unknown_size) | 2942 if (size == unknown_size) |
| 2833 return E_FILE_FORMAT_INVALID; | 2943 return E_FILE_FORMAT_INVALID; |
| 2834 | 2944 |
| 2835 pos += size; // consume payload | 2945 pos += size; // consume payload |
| 2836 assert((segment_stop < 0) || (pos <= segment_stop)); | 2946 if (segment_stop >= 0 && pos > segment_stop) |
| 2947 return E_FILE_FORMAT_INVALID; |
| 2837 | 2948 |
| 2838 continue; | 2949 continue; |
| 2839 } | 2950 } |
| 2840 | 2951 |
| 2841 // We have a cluster. | 2952 // We have a cluster. |
| 2842 off_next = idoff; | 2953 off_next = idoff; |
| 2843 | 2954 |
| 2844 if (size != unknown_size) | 2955 if (size != unknown_size) |
| 2845 cluster_size = size; | 2956 cluster_size = size; |
| 2846 | 2957 |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2898 pos = pos_; | 3009 pos = pos_; |
| 2899 len = len_; | 3010 len = len_; |
| 2900 | 3011 |
| 2901 return status; | 3012 return status; |
| 2902 } | 3013 } |
| 2903 | 3014 |
| 2904 if (status > 0) { // means "found at least one block entry" | 3015 if (status > 0) { // means "found at least one block entry" |
| 2905 Cluster* const pNext = Cluster::Create(this, | 3016 Cluster* const pNext = Cluster::Create(this, |
| 2906 -1, // preloaded | 3017 -1, // preloaded |
| 2907 off_next); | 3018 off_next); |
| 2908 // element_size); | 3019 if (pNext == NULL) |
| 2909 assert(pNext); | 3020 return -1; |
| 2910 | 3021 |
| 2911 const ptrdiff_t idx_next = i - m_clusters; // insertion position | 3022 const ptrdiff_t idx_next = i - m_clusters; // insertion position |
| 2912 | 3023 |
| 2913 PreloadCluster(pNext, idx_next); | 3024 if (!PreloadCluster(pNext, idx_next)) { |
| 3025 delete pNext; |
| 3026 return -1; |
| 3027 } |
| 2914 assert(m_clusters); | 3028 assert(m_clusters); |
| 2915 assert(idx_next < m_clusterSize); | 3029 assert(idx_next < m_clusterSize); |
| 2916 assert(m_clusters[idx_next] == pNext); | 3030 assert(m_clusters[idx_next] == pNext); |
| 2917 | 3031 |
| 2918 pResult = pNext; | 3032 pResult = pNext; |
| 2919 return 0; // success | 3033 return 0; // success |
| 2920 } | 3034 } |
| 2921 | 3035 |
| 2922 // status == 0 means "no block entries found" | 3036 // status == 0 means "no block entries found" |
| 2923 | 3037 |
| (...skipping 22 matching lines...) Expand all Loading... |
| 2946 if (result > 0) // weird | 3060 if (result > 0) // weird |
| 2947 return E_BUFFER_NOT_FULL; | 3061 return E_BUFFER_NOT_FULL; |
| 2948 | 3062 |
| 2949 if ((segment_stop >= 0) && ((pos + len) > segment_stop)) | 3063 if ((segment_stop >= 0) && ((pos + len) > segment_stop)) |
| 2950 return E_FILE_FORMAT_INVALID; | 3064 return E_FILE_FORMAT_INVALID; |
| 2951 | 3065 |
| 2952 if ((pos + len) > avail) | 3066 if ((pos + len) > avail) |
| 2953 return E_BUFFER_NOT_FULL; | 3067 return E_BUFFER_NOT_FULL; |
| 2954 | 3068 |
| 2955 const long long idpos = pos; | 3069 const long long idpos = pos; |
| 2956 const long long id = ReadUInt(m_pReader, idpos, len); | 3070 const long long id = ReadID(m_pReader, idpos, len); |
| 2957 | 3071 |
| 2958 if (id < 0) // error (or underflow) | 3072 if (id < 0) // error (or underflow) |
| 2959 return static_cast<long>(id); | 3073 return static_cast<long>(id); |
| 2960 | 3074 |
| 2961 // This is the distinguished set of ID's we use to determine | 3075 // This is the distinguished set of ID's we use to determine |
| 2962 // that we have exhausted the sub-element's inside the cluster | 3076 // that we have exhausted the sub-element's inside the cluster |
| 2963 // whose ID we parsed earlier. | 3077 // whose ID we parsed earlier. |
| 2964 | 3078 |
| 2965 if (id == 0x0F43B675) // Cluster ID | 3079 if (id == mkvmuxer::kMkvCluster || id == mkvmuxer::kMkvCues) |
| 2966 break; | |
| 2967 | |
| 2968 if (id == 0x0C53BB6B) // Cues ID | |
| 2969 break; | 3080 break; |
| 2970 | 3081 |
| 2971 pos += len; // consume ID (of sub-element) | 3082 pos += len; // consume ID (of sub-element) |
| 2972 | 3083 |
| 2973 // Read Size | 3084 // Read Size |
| 2974 | 3085 |
| 2975 if ((pos + 1) > avail) { | 3086 if ((pos + 1) > avail) { |
| 2976 len = 1; | 3087 len = 1; |
| 2977 return E_BUFFER_NOT_FULL; | 3088 return E_BUFFER_NOT_FULL; |
| 2978 } | 3089 } |
| (...skipping 26 matching lines...) Expand all Loading... |
| 3005 | 3116 |
| 3006 const long long unknown_size = (1LL << (7 * len)) - 1; | 3117 const long long unknown_size = (1LL << (7 * len)) - 1; |
| 3007 | 3118 |
| 3008 if (size == unknown_size) | 3119 if (size == unknown_size) |
| 3009 return E_FILE_FORMAT_INVALID; // not allowed for sub-elements | 3120 return E_FILE_FORMAT_INVALID; // not allowed for sub-elements |
| 3010 | 3121 |
| 3011 if ((segment_stop >= 0) && ((pos + size) > segment_stop)) // weird | 3122 if ((segment_stop >= 0) && ((pos + size) > segment_stop)) // weird |
| 3012 return E_FILE_FORMAT_INVALID; | 3123 return E_FILE_FORMAT_INVALID; |
| 3013 | 3124 |
| 3014 pos += size; // consume payload of sub-element | 3125 pos += size; // consume payload of sub-element |
| 3015 assert((segment_stop < 0) || (pos <= segment_stop)); | 3126 if (segment_stop >= 0 && pos > segment_stop) |
| 3127 return E_FILE_FORMAT_INVALID; |
| 3016 } // determine cluster size | 3128 } // determine cluster size |
| 3017 | 3129 |
| 3018 cluster_size = pos - payload_pos; | 3130 cluster_size = pos - payload_pos; |
| 3019 assert(cluster_size >= 0); // TODO: handle cluster_size = 0 | 3131 assert(cluster_size >= 0); // TODO: handle cluster_size = 0 |
| 3020 | 3132 |
| 3021 pos = payload_pos; // reset and re-parse original cluster | 3133 pos = payload_pos; // reset and re-parse original cluster |
| 3022 } | 3134 } |
| 3023 | 3135 |
| 3024 pos += cluster_size; // consume payload | 3136 pos += cluster_size; // consume payload |
| 3025 assert((segment_stop < 0) || (pos <= segment_stop)); | 3137 if (segment_stop >= 0 && pos > segment_stop) |
| 3138 return E_FILE_FORMAT_INVALID; |
| 3026 | 3139 |
| 3027 return 2; // try to find a cluster that follows next | 3140 return 2; // try to find a cluster that follows next |
| 3028 } | 3141 } |
| 3029 | 3142 |
| 3030 const Cluster* Segment::FindCluster(long long time_ns) const { | 3143 const Cluster* Segment::FindCluster(long long time_ns) const { |
| 3031 if ((m_clusters == NULL) || (m_clusterCount <= 0)) | 3144 if ((m_clusters == NULL) || (m_clusterCount <= 0)) |
| 3032 return &m_eos; | 3145 return &m_eos; |
| 3033 | 3146 |
| 3034 { | 3147 { |
| 3035 Cluster* const pCluster = m_clusters[0]; | 3148 Cluster* const pCluster = m_clusters[0]; |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3124 long long id, size; | 3237 long long id, size; |
| 3125 | 3238 |
| 3126 long status = ParseElementHeader(pReader, pos, stop, id, size); | 3239 long status = ParseElementHeader(pReader, pos, stop, id, size); |
| 3127 | 3240 |
| 3128 if (status < 0) // error | 3241 if (status < 0) // error |
| 3129 return status; | 3242 return status; |
| 3130 | 3243 |
| 3131 if (size == 0) // weird | 3244 if (size == 0) // weird |
| 3132 continue; | 3245 continue; |
| 3133 | 3246 |
| 3134 if (id == 0x05B9) { // EditionEntry ID | 3247 if (id == mkvmuxer::kMkvEditionEntry) { |
| 3135 status = ParseEdition(pos, size); | 3248 status = ParseEdition(pos, size); |
| 3136 | 3249 |
| 3137 if (status < 0) // error | 3250 if (status < 0) // error |
| 3138 return status; | 3251 return status; |
| 3139 } | 3252 } |
| 3140 | 3253 |
| 3141 pos += size; | 3254 pos += size; |
| 3142 assert(pos <= stop); | 3255 if (pos > stop) |
| 3256 return E_FILE_FORMAT_INVALID; |
| 3143 } | 3257 } |
| 3144 | 3258 |
| 3145 assert(pos == stop); | 3259 if (pos != stop) |
| 3260 return E_FILE_FORMAT_INVALID; |
| 3146 return 0; | 3261 return 0; |
| 3147 } | 3262 } |
| 3148 | 3263 |
| 3149 int Chapters::GetEditionCount() const { return m_editions_count; } | 3264 int Chapters::GetEditionCount() const { return m_editions_count; } |
| 3150 | 3265 |
| 3151 const Chapters::Edition* Chapters::GetEdition(int idx) const { | 3266 const Chapters::Edition* Chapters::GetEdition(int idx) const { |
| 3152 if (idx < 0) | 3267 if (idx < 0) |
| 3153 return NULL; | 3268 return NULL; |
| 3154 | 3269 |
| 3155 if (idx >= m_editions_count) | 3270 if (idx >= m_editions_count) |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3235 const long long stop = pos + size; | 3350 const long long stop = pos + size; |
| 3236 | 3351 |
| 3237 while (pos < stop) { | 3352 while (pos < stop) { |
| 3238 long long id, size; | 3353 long long id, size; |
| 3239 | 3354 |
| 3240 long status = ParseElementHeader(pReader, pos, stop, id, size); | 3355 long status = ParseElementHeader(pReader, pos, stop, id, size); |
| 3241 | 3356 |
| 3242 if (status < 0) // error | 3357 if (status < 0) // error |
| 3243 return status; | 3358 return status; |
| 3244 | 3359 |
| 3245 if (size == 0) // weird | 3360 if (size == 0) |
| 3246 continue; | 3361 continue; |
| 3247 | 3362 |
| 3248 if (id == 0x36) { // Atom ID | 3363 if (id == mkvmuxer::kMkvChapterAtom) { |
| 3249 status = ParseAtom(pReader, pos, size); | 3364 status = ParseAtom(pReader, pos, size); |
| 3250 | 3365 |
| 3251 if (status < 0) // error | 3366 if (status < 0) // error |
| 3252 return status; | 3367 return status; |
| 3253 } | 3368 } |
| 3254 | 3369 |
| 3255 pos += size; | 3370 pos += size; |
| 3256 assert(pos <= stop); | 3371 if (pos > stop) |
| 3372 return E_FILE_FORMAT_INVALID; |
| 3257 } | 3373 } |
| 3258 | 3374 |
| 3259 assert(pos == stop); | 3375 if (pos != stop) |
| 3376 return E_FILE_FORMAT_INVALID; |
| 3260 return 0; | 3377 return 0; |
| 3261 } | 3378 } |
| 3262 | 3379 |
| 3263 long Chapters::Edition::ParseAtom(IMkvReader* pReader, long long pos, | 3380 long Chapters::Edition::ParseAtom(IMkvReader* pReader, long long pos, |
| 3264 long long size) { | 3381 long long size) { |
| 3265 if (!ExpandAtomsArray()) | 3382 if (!ExpandAtomsArray()) |
| 3266 return -1; | 3383 return -1; |
| 3267 | 3384 |
| 3268 Atom& a = m_atoms[m_atoms_count++]; | 3385 Atom& a = m_atoms[m_atoms_count++]; |
| 3269 a.Init(); | 3386 a.Init(); |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3366 const long long stop = pos + size; | 3483 const long long stop = pos + size; |
| 3367 | 3484 |
| 3368 while (pos < stop) { | 3485 while (pos < stop) { |
| 3369 long long id, size; | 3486 long long id, size; |
| 3370 | 3487 |
| 3371 long status = ParseElementHeader(pReader, pos, stop, id, size); | 3488 long status = ParseElementHeader(pReader, pos, stop, id, size); |
| 3372 | 3489 |
| 3373 if (status < 0) // error | 3490 if (status < 0) // error |
| 3374 return status; | 3491 return status; |
| 3375 | 3492 |
| 3376 if (size == 0) // weird | 3493 if (size == 0) // 0 length payload, skip. |
| 3377 continue; | 3494 continue; |
| 3378 | 3495 |
| 3379 if (id == 0x00) { // Display ID | 3496 if (id == mkvmuxer::kMkvChapterDisplay) { |
| 3380 status = ParseDisplay(pReader, pos, size); | 3497 status = ParseDisplay(pReader, pos, size); |
| 3381 | 3498 |
| 3382 if (status < 0) // error | 3499 if (status < 0) // error |
| 3383 return status; | 3500 return status; |
| 3384 } else if (id == 0x1654) { // StringUID ID | 3501 } else if (id == mkvmuxer::kMkvChapterStringUID) { |
| 3385 status = UnserializeString(pReader, pos, size, m_string_uid); | 3502 status = UnserializeString(pReader, pos, size, m_string_uid); |
| 3386 | 3503 |
| 3387 if (status < 0) // error | 3504 if (status < 0) // error |
| 3388 return status; | 3505 return status; |
| 3389 } else if (id == 0x33C4) { // UID ID | 3506 } else if (id == mkvmuxer::kMkvChapterUID) { |
| 3390 long long val; | 3507 long long val; |
| 3391 status = UnserializeInt(pReader, pos, size, val); | 3508 status = UnserializeInt(pReader, pos, size, val); |
| 3392 | 3509 |
| 3393 if (status < 0) // error | 3510 if (status < 0) // error |
| 3394 return status; | 3511 return status; |
| 3395 | 3512 |
| 3396 m_uid = static_cast<unsigned long long>(val); | 3513 m_uid = static_cast<unsigned long long>(val); |
| 3397 } else if (id == 0x11) { // TimeStart ID | 3514 } else if (id == mkvmuxer::kMkvChapterTimeStart) { |
| 3398 const long long val = UnserializeUInt(pReader, pos, size); | 3515 const long long val = UnserializeUInt(pReader, pos, size); |
| 3399 | 3516 |
| 3400 if (val < 0) // error | 3517 if (val < 0) // error |
| 3401 return static_cast<long>(val); | 3518 return static_cast<long>(val); |
| 3402 | 3519 |
| 3403 m_start_timecode = val; | 3520 m_start_timecode = val; |
| 3404 } else if (id == 0x12) { // TimeEnd ID | 3521 } else if (id == mkvmuxer::kMkvChapterTimeEnd) { |
| 3405 const long long val = UnserializeUInt(pReader, pos, size); | 3522 const long long val = UnserializeUInt(pReader, pos, size); |
| 3406 | 3523 |
| 3407 if (val < 0) // error | 3524 if (val < 0) // error |
| 3408 return static_cast<long>(val); | 3525 return static_cast<long>(val); |
| 3409 | 3526 |
| 3410 m_stop_timecode = val; | 3527 m_stop_timecode = val; |
| 3411 } | 3528 } |
| 3412 | 3529 |
| 3413 pos += size; | 3530 pos += size; |
| 3414 assert(pos <= stop); | 3531 if (pos > stop) |
| 3532 return E_FILE_FORMAT_INVALID; |
| 3415 } | 3533 } |
| 3416 | 3534 |
| 3417 assert(pos == stop); | 3535 if (pos != stop) |
| 3536 return E_FILE_FORMAT_INVALID; |
| 3418 return 0; | 3537 return 0; |
| 3419 } | 3538 } |
| 3420 | 3539 |
| 3421 long long Chapters::Atom::GetTime(const Chapters* pChapters, | 3540 long long Chapters::Atom::GetTime(const Chapters* pChapters, |
| 3422 long long timecode) { | 3541 long long timecode) { |
| 3423 if (pChapters == NULL) | 3542 if (pChapters == NULL) |
| 3424 return -1; | 3543 return -1; |
| 3425 | 3544 |
| 3426 Segment* const pSegment = pChapters->m_pSegment; | 3545 Segment* const pSegment = pChapters->m_pSegment; |
| 3427 | 3546 |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3517 const long long stop = pos + size; | 3636 const long long stop = pos + size; |
| 3518 | 3637 |
| 3519 while (pos < stop) { | 3638 while (pos < stop) { |
| 3520 long long id, size; | 3639 long long id, size; |
| 3521 | 3640 |
| 3522 long status = ParseElementHeader(pReader, pos, stop, id, size); | 3641 long status = ParseElementHeader(pReader, pos, stop, id, size); |
| 3523 | 3642 |
| 3524 if (status < 0) // error | 3643 if (status < 0) // error |
| 3525 return status; | 3644 return status; |
| 3526 | 3645 |
| 3527 if (size == 0) // weird | 3646 if (size == 0) // No payload. |
| 3528 continue; | 3647 continue; |
| 3529 | 3648 |
| 3530 if (id == 0x05) { // ChapterString ID | 3649 if (id == mkvmuxer::kMkvChapString) { |
| 3531 status = UnserializeString(pReader, pos, size, m_string); | 3650 status = UnserializeString(pReader, pos, size, m_string); |
| 3532 | 3651 |
| 3533 if (status) | 3652 if (status) |
| 3534 return status; | 3653 return status; |
| 3535 } else if (id == 0x037C) { // ChapterLanguage ID | 3654 } else if (id == mkvmuxer::kMkvChapLanguage) { |
| 3536 status = UnserializeString(pReader, pos, size, m_language); | 3655 status = UnserializeString(pReader, pos, size, m_language); |
| 3537 | 3656 |
| 3538 if (status) | 3657 if (status) |
| 3539 return status; | 3658 return status; |
| 3540 } else if (id == 0x037E) { // ChapterCountry ID | 3659 } else if (id == mkvmuxer::kMkvChapCountry) { |
| 3541 status = UnserializeString(pReader, pos, size, m_country); | 3660 status = UnserializeString(pReader, pos, size, m_country); |
| 3542 | 3661 |
| 3543 if (status) | 3662 if (status) |
| 3544 return status; | 3663 return status; |
| 3545 } | 3664 } |
| 3546 | 3665 |
| 3547 pos += size; | 3666 pos += size; |
| 3548 assert(pos <= stop); | 3667 if (pos > stop) |
| 3668 return E_FILE_FORMAT_INVALID; |
| 3549 } | 3669 } |
| 3550 | 3670 |
| 3551 assert(pos == stop); | 3671 if (pos != stop) |
| 3672 return E_FILE_FORMAT_INVALID; |
| 3552 return 0; | 3673 return 0; |
| 3553 } | 3674 } |
| 3554 | 3675 |
| 3555 Tags::Tags(Segment* pSegment, long long payload_start, long long payload_size, | 3676 Tags::Tags(Segment* pSegment, long long payload_start, long long payload_size, |
| 3556 long long element_start, long long element_size) | 3677 long long element_start, long long element_size) |
| 3557 : m_pSegment(pSegment), | 3678 : m_pSegment(pSegment), |
| 3558 m_start(payload_start), | 3679 m_start(payload_start), |
| 3559 m_size(payload_size), | 3680 m_size(payload_size), |
| 3560 m_element_start(element_start), | 3681 m_element_start(element_start), |
| 3561 m_element_size(element_size), | 3682 m_element_size(element_size), |
| (...skipping 19 matching lines...) Expand all Loading... |
| 3581 long long id, size; | 3702 long long id, size; |
| 3582 | 3703 |
| 3583 long status = ParseElementHeader(pReader, pos, stop, id, size); | 3704 long status = ParseElementHeader(pReader, pos, stop, id, size); |
| 3584 | 3705 |
| 3585 if (status < 0) | 3706 if (status < 0) |
| 3586 return status; | 3707 return status; |
| 3587 | 3708 |
| 3588 if (size == 0) // 0 length tag, read another | 3709 if (size == 0) // 0 length tag, read another |
| 3589 continue; | 3710 continue; |
| 3590 | 3711 |
| 3591 if (id == 0x3373) { // Tag ID | 3712 if (id == mkvmuxer::kMkvTag) { |
| 3592 status = ParseTag(pos, size); | 3713 status = ParseTag(pos, size); |
| 3593 | 3714 |
| 3594 if (status < 0) | 3715 if (status < 0) |
| 3595 return status; | 3716 return status; |
| 3596 } | 3717 } |
| 3597 | 3718 |
| 3598 pos += size; | 3719 pos += size; |
| 3599 assert(pos <= stop); | |
| 3600 if (pos > stop) | 3720 if (pos > stop) |
| 3601 return -1; | 3721 return E_FILE_FORMAT_INVALID; |
| 3602 } | 3722 } |
| 3603 | 3723 |
| 3604 assert(pos == stop); | |
| 3605 if (pos != stop) | 3724 if (pos != stop) |
| 3606 return -1; | 3725 return E_FILE_FORMAT_INVALID; |
| 3607 | 3726 |
| 3608 return 0; | 3727 return 0; |
| 3609 } | 3728 } |
| 3610 | 3729 |
| 3611 int Tags::GetTagCount() const { return m_tags_count; } | 3730 int Tags::GetTagCount() const { return m_tags_count; } |
| 3612 | 3731 |
| 3613 const Tags::Tag* Tags::GetTag(int idx) const { | 3732 const Tags::Tag* Tags::GetTag(int idx) const { |
| 3614 if (idx < 0) | 3733 if (idx < 0) |
| 3615 return NULL; | 3734 return NULL; |
| 3616 | 3735 |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3699 long long id, size; | 3818 long long id, size; |
| 3700 | 3819 |
| 3701 long status = ParseElementHeader(pReader, pos, stop, id, size); | 3820 long status = ParseElementHeader(pReader, pos, stop, id, size); |
| 3702 | 3821 |
| 3703 if (status < 0) | 3822 if (status < 0) |
| 3704 return status; | 3823 return status; |
| 3705 | 3824 |
| 3706 if (size == 0) // 0 length tag, read another | 3825 if (size == 0) // 0 length tag, read another |
| 3707 continue; | 3826 continue; |
| 3708 | 3827 |
| 3709 if (id == 0x27C8) { // SimpleTag ID | 3828 if (id == mkvmuxer::kMkvSimpleTag) { |
| 3710 status = ParseSimpleTag(pReader, pos, size); | 3829 status = ParseSimpleTag(pReader, pos, size); |
| 3711 | 3830 |
| 3712 if (status < 0) | 3831 if (status < 0) |
| 3713 return status; | 3832 return status; |
| 3714 } | 3833 } |
| 3715 | 3834 |
| 3716 pos += size; | 3835 pos += size; |
| 3717 assert(pos <= stop); | |
| 3718 if (pos > stop) | 3836 if (pos > stop) |
| 3719 return -1; | 3837 return E_FILE_FORMAT_INVALID; |
| 3720 } | 3838 } |
| 3721 | 3839 |
| 3722 assert(pos == stop); | |
| 3723 if (pos != stop) | 3840 if (pos != stop) |
| 3724 return -1; | 3841 return E_FILE_FORMAT_INVALID; |
| 3725 return 0; | 3842 return 0; |
| 3726 } | 3843 } |
| 3727 | 3844 |
| 3728 long Tags::Tag::ParseSimpleTag(IMkvReader* pReader, long long pos, | 3845 long Tags::Tag::ParseSimpleTag(IMkvReader* pReader, long long pos, |
| 3729 long long size) { | 3846 long long size) { |
| 3730 if (!ExpandSimpleTagsArray()) | 3847 if (!ExpandSimpleTagsArray()) |
| 3731 return -1; | 3848 return -1; |
| 3732 | 3849 |
| 3733 SimpleTag& st = m_simple_tags[m_simple_tags_count++]; | 3850 SimpleTag& st = m_simple_tags[m_simple_tags_count++]; |
| 3734 st.Init(); | 3851 st.Init(); |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3792 long long id, size; | 3909 long long id, size; |
| 3793 | 3910 |
| 3794 long status = ParseElementHeader(pReader, pos, stop, id, size); | 3911 long status = ParseElementHeader(pReader, pos, stop, id, size); |
| 3795 | 3912 |
| 3796 if (status < 0) // error | 3913 if (status < 0) // error |
| 3797 return status; | 3914 return status; |
| 3798 | 3915 |
| 3799 if (size == 0) // weird | 3916 if (size == 0) // weird |
| 3800 continue; | 3917 continue; |
| 3801 | 3918 |
| 3802 if (id == 0x5A3) { // TagName ID | 3919 if (id == mkvmuxer::kMkvTagName) { |
| 3803 status = UnserializeString(pReader, pos, size, m_tag_name); | 3920 status = UnserializeString(pReader, pos, size, m_tag_name); |
| 3804 | 3921 |
| 3805 if (status) | 3922 if (status) |
| 3806 return status; | 3923 return status; |
| 3807 } else if (id == 0x487) { // TagString ID | 3924 } else if (id == mkvmuxer::kMkvTagString) { |
| 3808 status = UnserializeString(pReader, pos, size, m_tag_string); | 3925 status = UnserializeString(pReader, pos, size, m_tag_string); |
| 3809 | 3926 |
| 3810 if (status) | 3927 if (status) |
| 3811 return status; | 3928 return status; |
| 3812 } | 3929 } |
| 3813 | 3930 |
| 3814 pos += size; | 3931 pos += size; |
| 3815 assert(pos <= stop); | |
| 3816 if (pos > stop) | 3932 if (pos > stop) |
| 3817 return -1; | 3933 return E_FILE_FORMAT_INVALID; |
| 3818 } | 3934 } |
| 3819 | 3935 |
| 3820 assert(pos == stop); | |
| 3821 if (pos != stop) | 3936 if (pos != stop) |
| 3822 return -1; | 3937 return E_FILE_FORMAT_INVALID; |
| 3823 return 0; | 3938 return 0; |
| 3824 } | 3939 } |
| 3825 | 3940 |
| 3826 SegmentInfo::SegmentInfo(Segment* pSegment, long long start, long long size_, | 3941 SegmentInfo::SegmentInfo(Segment* pSegment, long long start, long long size_, |
| 3827 long long element_start, long long element_size) | 3942 long long element_start, long long element_size) |
| 3828 : m_pSegment(pSegment), | 3943 : m_pSegment(pSegment), |
| 3829 m_start(start), | 3944 m_start(start), |
| 3830 m_size(size_), | 3945 m_size(size_), |
| 3831 m_element_start(element_start), | 3946 m_element_start(element_start), |
| 3832 m_element_size(element_size), | 3947 m_element_size(element_size), |
| (...skipping 26 matching lines...) Expand all Loading... |
| 3859 m_duration = -1; | 3974 m_duration = -1; |
| 3860 | 3975 |
| 3861 while (pos < stop) { | 3976 while (pos < stop) { |
| 3862 long long id, size; | 3977 long long id, size; |
| 3863 | 3978 |
| 3864 const long status = ParseElementHeader(pReader, pos, stop, id, size); | 3979 const long status = ParseElementHeader(pReader, pos, stop, id, size); |
| 3865 | 3980 |
| 3866 if (status < 0) // error | 3981 if (status < 0) // error |
| 3867 return status; | 3982 return status; |
| 3868 | 3983 |
| 3869 if (id == 0x0AD7B1) { // Timecode Scale | 3984 if (id == mkvmuxer::kMkvTimecodeScale) { |
| 3870 m_timecodeScale = UnserializeUInt(pReader, pos, size); | 3985 m_timecodeScale = UnserializeUInt(pReader, pos, size); |
| 3871 | 3986 |
| 3872 if (m_timecodeScale <= 0) | 3987 if (m_timecodeScale <= 0) |
| 3873 return E_FILE_FORMAT_INVALID; | 3988 return E_FILE_FORMAT_INVALID; |
| 3874 } else if (id == 0x0489) { // Segment duration | 3989 } else if (id == mkvmuxer::kMkvDuration) { |
| 3875 const long status = UnserializeFloat(pReader, pos, size, m_duration); | 3990 const long status = UnserializeFloat(pReader, pos, size, m_duration); |
| 3876 | 3991 |
| 3877 if (status < 0) | 3992 if (status < 0) |
| 3878 return status; | 3993 return status; |
| 3879 | 3994 |
| 3880 if (m_duration < 0) | 3995 if (m_duration < 0) |
| 3881 return E_FILE_FORMAT_INVALID; | 3996 return E_FILE_FORMAT_INVALID; |
| 3882 } else if (id == 0x0D80) { // MuxingApp | 3997 } else if (id == mkvmuxer::kMkvMuxingApp) { |
| 3883 const long status = | 3998 const long status = |
| 3884 UnserializeString(pReader, pos, size, m_pMuxingAppAsUTF8); | 3999 UnserializeString(pReader, pos, size, m_pMuxingAppAsUTF8); |
| 3885 | 4000 |
| 3886 if (status) | 4001 if (status) |
| 3887 return status; | 4002 return status; |
| 3888 } else if (id == 0x1741) { // WritingApp | 4003 } else if (id == mkvmuxer::kMkvWritingApp) { |
| 3889 const long status = | 4004 const long status = |
| 3890 UnserializeString(pReader, pos, size, m_pWritingAppAsUTF8); | 4005 UnserializeString(pReader, pos, size, m_pWritingAppAsUTF8); |
| 3891 | 4006 |
| 3892 if (status) | 4007 if (status) |
| 3893 return status; | 4008 return status; |
| 3894 } else if (id == 0x3BA9) { // Title | 4009 } else if (id == mkvmuxer::kMkvTitle) { |
| 3895 const long status = UnserializeString(pReader, pos, size, m_pTitleAsUTF8); | 4010 const long status = UnserializeString(pReader, pos, size, m_pTitleAsUTF8); |
| 3896 | 4011 |
| 3897 if (status) | 4012 if (status) |
| 3898 return status; | 4013 return status; |
| 3899 } | 4014 } |
| 3900 | 4015 |
| 3901 pos += size; | 4016 pos += size; |
| 3902 assert(pos <= stop); | 4017 |
| 4018 if (pos > stop) |
| 4019 return E_FILE_FORMAT_INVALID; |
| 3903 } | 4020 } |
| 3904 | 4021 |
| 3905 assert(pos == stop); | 4022 const double rollover_check = m_duration * m_timecodeScale; |
| 4023 if (rollover_check > LONG_LONG_MAX) |
| 4024 return E_FILE_FORMAT_INVALID; |
| 4025 |
| 4026 if (pos != stop) |
| 4027 return E_FILE_FORMAT_INVALID; |
| 3906 | 4028 |
| 3907 return 0; | 4029 return 0; |
| 3908 } | 4030 } |
| 3909 | 4031 |
| 3910 long long SegmentInfo::GetTimeCodeScale() const { return m_timecodeScale; } | 4032 long long SegmentInfo::GetTimeCodeScale() const { return m_timecodeScale; } |
| 3911 | 4033 |
| 3912 long long SegmentInfo::GetDuration() const { | 4034 long long SegmentInfo::GetDuration() const { |
| 3913 if (m_duration < 0) | 4035 if (m_duration < 0) |
| 3914 return -1; | 4036 return -1; |
| 3915 | 4037 |
| (...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4032 | 4154 |
| 4033 long long pos = start; | 4155 long long pos = start; |
| 4034 const long long stop = start + size; | 4156 const long long stop = start + size; |
| 4035 | 4157 |
| 4036 while (pos < stop) { | 4158 while (pos < stop) { |
| 4037 long long id, size; | 4159 long long id, size; |
| 4038 const long status = ParseElementHeader(pReader, pos, stop, id, size); | 4160 const long status = ParseElementHeader(pReader, pos, stop, id, size); |
| 4039 if (status < 0) // error | 4161 if (status < 0) // error |
| 4040 return status; | 4162 return status; |
| 4041 | 4163 |
| 4042 if (id == 0x7E8) { | 4164 if (id == mkvmuxer::kMkvAESSettingsCipherMode) { |
| 4043 // AESSettingsCipherMode | |
| 4044 aes->cipher_mode = UnserializeUInt(pReader, pos, size); | 4165 aes->cipher_mode = UnserializeUInt(pReader, pos, size); |
| 4045 if (aes->cipher_mode != 1) | 4166 if (aes->cipher_mode != 1) |
| 4046 return E_FILE_FORMAT_INVALID; | 4167 return E_FILE_FORMAT_INVALID; |
| 4047 } | 4168 } |
| 4048 | 4169 |
| 4049 pos += size; // consume payload | 4170 pos += size; // consume payload |
| 4050 assert(pos <= stop); | 4171 if (pos > stop) |
| 4172 return E_FILE_FORMAT_INVALID; |
| 4051 } | 4173 } |
| 4052 | 4174 |
| 4053 return 0; | 4175 return 0; |
| 4054 } | 4176 } |
| 4055 | 4177 |
| 4056 long ContentEncoding::ParseContentEncodingEntry(long long start, long long size, | 4178 long ContentEncoding::ParseContentEncodingEntry(long long start, long long size, |
| 4057 IMkvReader* pReader) { | 4179 IMkvReader* pReader) { |
| 4058 assert(pReader); | 4180 assert(pReader); |
| 4059 | 4181 |
| 4060 long long pos = start; | 4182 long long pos = start; |
| 4061 const long long stop = start + size; | 4183 const long long stop = start + size; |
| 4062 | 4184 |
| 4063 // Count ContentCompression and ContentEncryption elements. | 4185 // Count ContentCompression and ContentEncryption elements. |
| 4064 int compression_count = 0; | 4186 int compression_count = 0; |
| 4065 int encryption_count = 0; | 4187 int encryption_count = 0; |
| 4066 | 4188 |
| 4067 while (pos < stop) { | 4189 while (pos < stop) { |
| 4068 long long id, size; | 4190 long long id, size; |
| 4069 const long status = ParseElementHeader(pReader, pos, stop, id, size); | 4191 const long status = ParseElementHeader(pReader, pos, stop, id, size); |
| 4070 if (status < 0) // error | 4192 if (status < 0) // error |
| 4071 return status; | 4193 return status; |
| 4072 | 4194 |
| 4073 if (id == 0x1034) // ContentCompression ID | 4195 if (id == mkvmuxer::kMkvContentCompression) |
| 4074 ++compression_count; | 4196 ++compression_count; |
| 4075 | 4197 |
| 4076 if (id == 0x1035) // ContentEncryption ID | 4198 if (id == mkvmuxer::kMkvContentEncryption) |
| 4077 ++encryption_count; | 4199 ++encryption_count; |
| 4078 | 4200 |
| 4079 pos += size; // consume payload | 4201 pos += size; // consume payload |
| 4080 assert(pos <= stop); | 4202 if (pos > stop) |
| 4203 return E_FILE_FORMAT_INVALID; |
| 4081 } | 4204 } |
| 4082 | 4205 |
| 4083 if (compression_count <= 0 && encryption_count <= 0) | 4206 if (compression_count <= 0 && encryption_count <= 0) |
| 4084 return -1; | 4207 return -1; |
| 4085 | 4208 |
| 4086 if (compression_count > 0) { | 4209 if (compression_count > 0) { |
| 4087 compression_entries_ = | 4210 compression_entries_ = |
| 4088 new (std::nothrow) ContentCompression*[compression_count]; | 4211 new (std::nothrow) ContentCompression*[compression_count]; |
| 4089 if (!compression_entries_) | 4212 if (!compression_entries_) |
| 4090 return -1; | 4213 return -1; |
| (...skipping 10 matching lines...) Expand all Loading... |
| 4101 encryption_entries_end_ = encryption_entries_; | 4224 encryption_entries_end_ = encryption_entries_; |
| 4102 } | 4225 } |
| 4103 | 4226 |
| 4104 pos = start; | 4227 pos = start; |
| 4105 while (pos < stop) { | 4228 while (pos < stop) { |
| 4106 long long id, size; | 4229 long long id, size; |
| 4107 long status = ParseElementHeader(pReader, pos, stop, id, size); | 4230 long status = ParseElementHeader(pReader, pos, stop, id, size); |
| 4108 if (status < 0) // error | 4231 if (status < 0) // error |
| 4109 return status; | 4232 return status; |
| 4110 | 4233 |
| 4111 if (id == 0x1031) { | 4234 if (id == mkvmuxer::kMkvContentEncodingOrder) { |
| 4112 // ContentEncodingOrder | |
| 4113 encoding_order_ = UnserializeUInt(pReader, pos, size); | 4235 encoding_order_ = UnserializeUInt(pReader, pos, size); |
| 4114 } else if (id == 0x1032) { | 4236 } else if (id == mkvmuxer::kMkvContentEncodingScope) { |
| 4115 // ContentEncodingScope | |
| 4116 encoding_scope_ = UnserializeUInt(pReader, pos, size); | 4237 encoding_scope_ = UnserializeUInt(pReader, pos, size); |
| 4117 if (encoding_scope_ < 1) | 4238 if (encoding_scope_ < 1) |
| 4118 return -1; | 4239 return -1; |
| 4119 } else if (id == 0x1033) { | 4240 } else if (id == mkvmuxer::kMkvContentEncodingType) { |
| 4120 // ContentEncodingType | |
| 4121 encoding_type_ = UnserializeUInt(pReader, pos, size); | 4241 encoding_type_ = UnserializeUInt(pReader, pos, size); |
| 4122 } else if (id == 0x1034) { | 4242 } else if (id == mkvmuxer::kMkvContentCompression) { |
| 4123 // ContentCompression ID | |
| 4124 ContentCompression* const compression = | 4243 ContentCompression* const compression = |
| 4125 new (std::nothrow) ContentCompression(); | 4244 new (std::nothrow) ContentCompression(); |
| 4126 if (!compression) | 4245 if (!compression) |
| 4127 return -1; | 4246 return -1; |
| 4128 | 4247 |
| 4129 status = ParseCompressionEntry(pos, size, pReader, compression); | 4248 status = ParseCompressionEntry(pos, size, pReader, compression); |
| 4130 if (status) { | 4249 if (status) { |
| 4131 delete compression; | 4250 delete compression; |
| 4132 return status; | 4251 return status; |
| 4133 } | 4252 } |
| 4134 *compression_entries_end_++ = compression; | 4253 *compression_entries_end_++ = compression; |
| 4135 } else if (id == 0x1035) { | 4254 } else if (id == mkvmuxer::kMkvContentEncryption) { |
| 4136 // ContentEncryption ID | |
| 4137 ContentEncryption* const encryption = | 4255 ContentEncryption* const encryption = |
| 4138 new (std::nothrow) ContentEncryption(); | 4256 new (std::nothrow) ContentEncryption(); |
| 4139 if (!encryption) | 4257 if (!encryption) |
| 4140 return -1; | 4258 return -1; |
| 4141 | 4259 |
| 4142 status = ParseEncryptionEntry(pos, size, pReader, encryption); | 4260 status = ParseEncryptionEntry(pos, size, pReader, encryption); |
| 4143 if (status) { | 4261 if (status) { |
| 4144 delete encryption; | 4262 delete encryption; |
| 4145 return status; | 4263 return status; |
| 4146 } | 4264 } |
| 4147 *encryption_entries_end_++ = encryption; | 4265 *encryption_entries_end_++ = encryption; |
| 4148 } | 4266 } |
| 4149 | 4267 |
| 4150 pos += size; // consume payload | 4268 pos += size; // consume payload |
| 4151 assert(pos <= stop); | 4269 if (pos > stop) |
| 4270 return E_FILE_FORMAT_INVALID; |
| 4152 } | 4271 } |
| 4153 | 4272 |
| 4154 assert(pos == stop); | 4273 if (pos != stop) |
| 4274 return E_FILE_FORMAT_INVALID; |
| 4155 return 0; | 4275 return 0; |
| 4156 } | 4276 } |
| 4157 | 4277 |
| 4158 long ContentEncoding::ParseCompressionEntry(long long start, long long size, | 4278 long ContentEncoding::ParseCompressionEntry(long long start, long long size, |
| 4159 IMkvReader* pReader, | 4279 IMkvReader* pReader, |
| 4160 ContentCompression* compression) { | 4280 ContentCompression* compression) { |
| 4161 assert(pReader); | 4281 assert(pReader); |
| 4162 assert(compression); | 4282 assert(compression); |
| 4163 | 4283 |
| 4164 long long pos = start; | 4284 long long pos = start; |
| 4165 const long long stop = start + size; | 4285 const long long stop = start + size; |
| 4166 | 4286 |
| 4167 bool valid = false; | 4287 bool valid = false; |
| 4168 | 4288 |
| 4169 while (pos < stop) { | 4289 while (pos < stop) { |
| 4170 long long id, size; | 4290 long long id, size; |
| 4171 const long status = ParseElementHeader(pReader, pos, stop, id, size); | 4291 const long status = ParseElementHeader(pReader, pos, stop, id, size); |
| 4172 if (status < 0) // error | 4292 if (status < 0) // error |
| 4173 return status; | 4293 return status; |
| 4174 | 4294 |
| 4175 if (id == 0x254) { | 4295 if (id == mkvmuxer::kMkvContentCompAlgo) { |
| 4176 // ContentCompAlgo | |
| 4177 long long algo = UnserializeUInt(pReader, pos, size); | 4296 long long algo = UnserializeUInt(pReader, pos, size); |
| 4178 if (algo < 0) | 4297 if (algo < 0) |
| 4179 return E_FILE_FORMAT_INVALID; | 4298 return E_FILE_FORMAT_INVALID; |
| 4180 compression->algo = algo; | 4299 compression->algo = algo; |
| 4181 valid = true; | 4300 valid = true; |
| 4182 } else if (id == 0x255) { | 4301 } else if (id == mkvmuxer::kMkvContentCompSettings) { |
| 4183 // ContentCompSettings | |
| 4184 if (size <= 0) | 4302 if (size <= 0) |
| 4185 return E_FILE_FORMAT_INVALID; | 4303 return E_FILE_FORMAT_INVALID; |
| 4186 | 4304 |
| 4187 const size_t buflen = static_cast<size_t>(size); | 4305 const size_t buflen = static_cast<size_t>(size); |
| 4188 typedef unsigned char* buf_t; | 4306 unsigned char* buf = SafeArrayAlloc<unsigned char>(1, buflen); |
| 4189 const buf_t buf = new (std::nothrow) unsigned char[buflen]; | |
| 4190 if (buf == NULL) | 4307 if (buf == NULL) |
| 4191 return -1; | 4308 return -1; |
| 4192 | 4309 |
| 4193 const int read_status = | 4310 const int read_status = |
| 4194 pReader->Read(pos, static_cast<long>(buflen), buf); | 4311 pReader->Read(pos, static_cast<long>(buflen), buf); |
| 4195 if (read_status) { | 4312 if (read_status) { |
| 4196 delete[] buf; | 4313 delete[] buf; |
| 4197 return status; | 4314 return status; |
| 4198 } | 4315 } |
| 4199 | 4316 |
| 4200 compression->settings = buf; | 4317 compression->settings = buf; |
| 4201 compression->settings_len = buflen; | 4318 compression->settings_len = buflen; |
| 4202 } | 4319 } |
| 4203 | 4320 |
| 4204 pos += size; // consume payload | 4321 pos += size; // consume payload |
| 4205 assert(pos <= stop); | 4322 if (pos > stop) |
| 4323 return E_FILE_FORMAT_INVALID; |
| 4206 } | 4324 } |
| 4207 | 4325 |
| 4208 // ContentCompAlgo is mandatory | 4326 // ContentCompAlgo is mandatory |
| 4209 if (!valid) | 4327 if (!valid) |
| 4210 return E_FILE_FORMAT_INVALID; | 4328 return E_FILE_FORMAT_INVALID; |
| 4211 | 4329 |
| 4212 return 0; | 4330 return 0; |
| 4213 } | 4331 } |
| 4214 | 4332 |
| 4215 long ContentEncoding::ParseEncryptionEntry(long long start, long long size, | 4333 long ContentEncoding::ParseEncryptionEntry(long long start, long long size, |
| 4216 IMkvReader* pReader, | 4334 IMkvReader* pReader, |
| 4217 ContentEncryption* encryption) { | 4335 ContentEncryption* encryption) { |
| 4218 assert(pReader); | 4336 assert(pReader); |
| 4219 assert(encryption); | 4337 assert(encryption); |
| 4220 | 4338 |
| 4221 long long pos = start; | 4339 long long pos = start; |
| 4222 const long long stop = start + size; | 4340 const long long stop = start + size; |
| 4223 | 4341 |
| 4224 while (pos < stop) { | 4342 while (pos < stop) { |
| 4225 long long id, size; | 4343 long long id, size; |
| 4226 const long status = ParseElementHeader(pReader, pos, stop, id, size); | 4344 const long status = ParseElementHeader(pReader, pos, stop, id, size); |
| 4227 if (status < 0) // error | 4345 if (status < 0) // error |
| 4228 return status; | 4346 return status; |
| 4229 | 4347 |
| 4230 if (id == 0x7E1) { | 4348 if (id == mkvmuxer::kMkvContentEncAlgo) { |
| 4231 // ContentEncAlgo | |
| 4232 encryption->algo = UnserializeUInt(pReader, pos, size); | 4349 encryption->algo = UnserializeUInt(pReader, pos, size); |
| 4233 if (encryption->algo != 5) | 4350 if (encryption->algo != 5) |
| 4234 return E_FILE_FORMAT_INVALID; | 4351 return E_FILE_FORMAT_INVALID; |
| 4235 } else if (id == 0x7E2) { | 4352 } else if (id == mkvmuxer::kMkvContentEncKeyID) { |
| 4236 // ContentEncKeyID | |
| 4237 delete[] encryption->key_id; | 4353 delete[] encryption->key_id; |
| 4238 encryption->key_id = NULL; | 4354 encryption->key_id = NULL; |
| 4239 encryption->key_id_len = 0; | 4355 encryption->key_id_len = 0; |
| 4240 | 4356 |
| 4241 if (size <= 0) | 4357 if (size <= 0) |
| 4242 return E_FILE_FORMAT_INVALID; | 4358 return E_FILE_FORMAT_INVALID; |
| 4243 | 4359 |
| 4244 const size_t buflen = static_cast<size_t>(size); | 4360 const size_t buflen = static_cast<size_t>(size); |
| 4245 typedef unsigned char* buf_t; | 4361 unsigned char* buf = SafeArrayAlloc<unsigned char>(1, buflen); |
| 4246 const buf_t buf = new (std::nothrow) unsigned char[buflen]; | |
| 4247 if (buf == NULL) | 4362 if (buf == NULL) |
| 4248 return -1; | 4363 return -1; |
| 4249 | 4364 |
| 4250 const int read_status = | 4365 const int read_status = |
| 4251 pReader->Read(pos, static_cast<long>(buflen), buf); | 4366 pReader->Read(pos, static_cast<long>(buflen), buf); |
| 4252 if (read_status) { | 4367 if (read_status) { |
| 4253 delete[] buf; | 4368 delete[] buf; |
| 4254 return status; | 4369 return status; |
| 4255 } | 4370 } |
| 4256 | 4371 |
| 4257 encryption->key_id = buf; | 4372 encryption->key_id = buf; |
| 4258 encryption->key_id_len = buflen; | 4373 encryption->key_id_len = buflen; |
| 4259 } else if (id == 0x7E3) { | 4374 } else if (id == mkvmuxer::kMkvContentSignature) { |
| 4260 // ContentSignature | |
| 4261 delete[] encryption->signature; | 4375 delete[] encryption->signature; |
| 4262 encryption->signature = NULL; | 4376 encryption->signature = NULL; |
| 4263 encryption->signature_len = 0; | 4377 encryption->signature_len = 0; |
| 4264 | 4378 |
| 4265 if (size <= 0) | 4379 if (size <= 0) |
| 4266 return E_FILE_FORMAT_INVALID; | 4380 return E_FILE_FORMAT_INVALID; |
| 4267 | 4381 |
| 4268 const size_t buflen = static_cast<size_t>(size); | 4382 const size_t buflen = static_cast<size_t>(size); |
| 4269 typedef unsigned char* buf_t; | 4383 unsigned char* buf = SafeArrayAlloc<unsigned char>(1, buflen); |
| 4270 const buf_t buf = new (std::nothrow) unsigned char[buflen]; | |
| 4271 if (buf == NULL) | 4384 if (buf == NULL) |
| 4272 return -1; | 4385 return -1; |
| 4273 | 4386 |
| 4274 const int read_status = | 4387 const int read_status = |
| 4275 pReader->Read(pos, static_cast<long>(buflen), buf); | 4388 pReader->Read(pos, static_cast<long>(buflen), buf); |
| 4276 if (read_status) { | 4389 if (read_status) { |
| 4277 delete[] buf; | 4390 delete[] buf; |
| 4278 return status; | 4391 return status; |
| 4279 } | 4392 } |
| 4280 | 4393 |
| 4281 encryption->signature = buf; | 4394 encryption->signature = buf; |
| 4282 encryption->signature_len = buflen; | 4395 encryption->signature_len = buflen; |
| 4283 } else if (id == 0x7E4) { | 4396 } else if (id == mkvmuxer::kMkvContentSigKeyID) { |
| 4284 // ContentSigKeyID | |
| 4285 delete[] encryption->sig_key_id; | 4397 delete[] encryption->sig_key_id; |
| 4286 encryption->sig_key_id = NULL; | 4398 encryption->sig_key_id = NULL; |
| 4287 encryption->sig_key_id_len = 0; | 4399 encryption->sig_key_id_len = 0; |
| 4288 | 4400 |
| 4289 if (size <= 0) | 4401 if (size <= 0) |
| 4290 return E_FILE_FORMAT_INVALID; | 4402 return E_FILE_FORMAT_INVALID; |
| 4291 | 4403 |
| 4292 const size_t buflen = static_cast<size_t>(size); | 4404 const size_t buflen = static_cast<size_t>(size); |
| 4293 typedef unsigned char* buf_t; | 4405 unsigned char* buf = SafeArrayAlloc<unsigned char>(1, buflen); |
| 4294 const buf_t buf = new (std::nothrow) unsigned char[buflen]; | |
| 4295 if (buf == NULL) | 4406 if (buf == NULL) |
| 4296 return -1; | 4407 return -1; |
| 4297 | 4408 |
| 4298 const int read_status = | 4409 const int read_status = |
| 4299 pReader->Read(pos, static_cast<long>(buflen), buf); | 4410 pReader->Read(pos, static_cast<long>(buflen), buf); |
| 4300 if (read_status) { | 4411 if (read_status) { |
| 4301 delete[] buf; | 4412 delete[] buf; |
| 4302 return status; | 4413 return status; |
| 4303 } | 4414 } |
| 4304 | 4415 |
| 4305 encryption->sig_key_id = buf; | 4416 encryption->sig_key_id = buf; |
| 4306 encryption->sig_key_id_len = buflen; | 4417 encryption->sig_key_id_len = buflen; |
| 4307 } else if (id == 0x7E5) { | 4418 } else if (id == mkvmuxer::kMkvContentSigAlgo) { |
| 4308 // ContentSigAlgo | |
| 4309 encryption->sig_algo = UnserializeUInt(pReader, pos, size); | 4419 encryption->sig_algo = UnserializeUInt(pReader, pos, size); |
| 4310 } else if (id == 0x7E6) { | 4420 } else if (id == mkvmuxer::kMkvContentSigHashAlgo) { |
| 4311 // ContentSigHashAlgo | |
| 4312 encryption->sig_hash_algo = UnserializeUInt(pReader, pos, size); | 4421 encryption->sig_hash_algo = UnserializeUInt(pReader, pos, size); |
| 4313 } else if (id == 0x7E7) { | 4422 } else if (id == mkvmuxer::kMkvContentEncAESSettings) { |
| 4314 // ContentEncAESSettings | |
| 4315 const long status = ParseContentEncAESSettingsEntry( | 4423 const long status = ParseContentEncAESSettingsEntry( |
| 4316 pos, size, pReader, &encryption->aes_settings); | 4424 pos, size, pReader, &encryption->aes_settings); |
| 4317 if (status) | 4425 if (status) |
| 4318 return status; | 4426 return status; |
| 4319 } | 4427 } |
| 4320 | 4428 |
| 4321 pos += size; // consume payload | 4429 pos += size; // consume payload |
| 4322 assert(pos <= stop); | 4430 if (pos > stop) |
| 4431 return E_FILE_FORMAT_INVALID; |
| 4323 } | 4432 } |
| 4324 | 4433 |
| 4325 return 0; | 4434 return 0; |
| 4326 } | 4435 } |
| 4327 | 4436 |
| 4328 Track::Track(Segment* pSegment, long long element_start, long long element_size) | 4437 Track::Track(Segment* pSegment, long long element_start, long long element_size) |
| 4329 : m_pSegment(pSegment), | 4438 : m_pSegment(pSegment), |
| 4330 m_element_start(element_start), | 4439 m_element_start(element_start), |
| 4331 m_element_size(element_size), | 4440 m_element_size(element_size), |
| 4332 content_encoding_entries_(NULL), | 4441 content_encoding_entries_(NULL), |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4411 if (dst) // should be NULL already | 4520 if (dst) // should be NULL already |
| 4412 return -1; | 4521 return -1; |
| 4413 | 4522 |
| 4414 const char* const src = this->*str; | 4523 const char* const src = this->*str; |
| 4415 | 4524 |
| 4416 if (src == NULL) | 4525 if (src == NULL) |
| 4417 return 0; | 4526 return 0; |
| 4418 | 4527 |
| 4419 const size_t len = strlen(src); | 4528 const size_t len = strlen(src); |
| 4420 | 4529 |
| 4421 dst = new (std::nothrow) char[len + 1]; | 4530 dst = SafeArrayAlloc<char>(1, len + 1); |
| 4422 | 4531 |
| 4423 if (dst == NULL) | 4532 if (dst == NULL) |
| 4424 return -1; | 4533 return -1; |
| 4425 | 4534 |
| 4426 strcpy(dst, src); | 4535 strcpy(dst, src); |
| 4427 | 4536 |
| 4428 return 0; | 4537 return 0; |
| 4429 } | 4538 } |
| 4430 | 4539 |
| 4431 int Track::Info::Copy(Info& dst) const { | 4540 int Track::Info::Copy(Info& dst) const { |
| (...skipping 30 matching lines...) Expand all Loading... |
| 4462 if (codecPrivateSize > 0) { | 4571 if (codecPrivateSize > 0) { |
| 4463 if (codecPrivate == NULL) | 4572 if (codecPrivate == NULL) |
| 4464 return -1; | 4573 return -1; |
| 4465 | 4574 |
| 4466 if (dst.codecPrivate) | 4575 if (dst.codecPrivate) |
| 4467 return -1; | 4576 return -1; |
| 4468 | 4577 |
| 4469 if (dst.codecPrivateSize != 0) | 4578 if (dst.codecPrivateSize != 0) |
| 4470 return -1; | 4579 return -1; |
| 4471 | 4580 |
| 4472 dst.codecPrivate = new (std::nothrow) unsigned char[codecPrivateSize]; | 4581 dst.codecPrivate = SafeArrayAlloc<unsigned char>(1, codecPrivateSize); |
| 4473 | 4582 |
| 4474 if (dst.codecPrivate == NULL) | 4583 if (dst.codecPrivate == NULL) |
| 4475 return -1; | 4584 return -1; |
| 4476 | 4585 |
| 4477 memcpy(dst.codecPrivate, codecPrivate, codecPrivateSize); | 4586 memcpy(dst.codecPrivate, codecPrivate, codecPrivateSize); |
| 4478 dst.codecPrivateSize = codecPrivateSize; | 4587 dst.codecPrivateSize = codecPrivateSize; |
| 4479 } | 4588 } |
| 4480 | 4589 |
| 4481 return 0; | 4590 return 0; |
| 4482 } | 4591 } |
| (...skipping 307 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4790 | 4899 |
| 4791 // Count ContentEncoding elements. | 4900 // Count ContentEncoding elements. |
| 4792 int count = 0; | 4901 int count = 0; |
| 4793 while (pos < stop) { | 4902 while (pos < stop) { |
| 4794 long long id, size; | 4903 long long id, size; |
| 4795 const long status = ParseElementHeader(pReader, pos, stop, id, size); | 4904 const long status = ParseElementHeader(pReader, pos, stop, id, size); |
| 4796 if (status < 0) // error | 4905 if (status < 0) // error |
| 4797 return status; | 4906 return status; |
| 4798 | 4907 |
| 4799 // pos now designates start of element | 4908 // pos now designates start of element |
| 4800 if (id == 0x2240) // ContentEncoding ID | 4909 if (id == mkvmuxer::kMkvContentEncoding) |
| 4801 ++count; | 4910 ++count; |
| 4802 | 4911 |
| 4803 pos += size; // consume payload | 4912 pos += size; // consume payload |
| 4804 assert(pos <= stop); | 4913 if (pos > stop) |
| 4914 return E_FILE_FORMAT_INVALID; |
| 4805 } | 4915 } |
| 4806 | 4916 |
| 4807 if (count <= 0) | 4917 if (count <= 0) |
| 4808 return -1; | 4918 return -1; |
| 4809 | 4919 |
| 4810 content_encoding_entries_ = new (std::nothrow) ContentEncoding*[count]; | 4920 content_encoding_entries_ = new (std::nothrow) ContentEncoding*[count]; |
| 4811 if (!content_encoding_entries_) | 4921 if (!content_encoding_entries_) |
| 4812 return -1; | 4922 return -1; |
| 4813 | 4923 |
| 4814 content_encoding_entries_end_ = content_encoding_entries_; | 4924 content_encoding_entries_end_ = content_encoding_entries_; |
| 4815 | 4925 |
| 4816 pos = start; | 4926 pos = start; |
| 4817 while (pos < stop) { | 4927 while (pos < stop) { |
| 4818 long long id, size; | 4928 long long id, size; |
| 4819 long status = ParseElementHeader(pReader, pos, stop, id, size); | 4929 long status = ParseElementHeader(pReader, pos, stop, id, size); |
| 4820 if (status < 0) // error | 4930 if (status < 0) // error |
| 4821 return status; | 4931 return status; |
| 4822 | 4932 |
| 4823 // pos now designates start of element | 4933 // pos now designates start of element |
| 4824 if (id == 0x2240) { // ContentEncoding ID | 4934 if (id == mkvmuxer::kMkvContentEncoding) { |
| 4825 ContentEncoding* const content_encoding = | 4935 ContentEncoding* const content_encoding = |
| 4826 new (std::nothrow) ContentEncoding(); | 4936 new (std::nothrow) ContentEncoding(); |
| 4827 if (!content_encoding) | 4937 if (!content_encoding) |
| 4828 return -1; | 4938 return -1; |
| 4829 | 4939 |
| 4830 status = content_encoding->ParseContentEncodingEntry(pos, size, pReader); | 4940 status = content_encoding->ParseContentEncodingEntry(pos, size, pReader); |
| 4831 if (status) { | 4941 if (status) { |
| 4832 delete content_encoding; | 4942 delete content_encoding; |
| 4833 return status; | 4943 return status; |
| 4834 } | 4944 } |
| 4835 | 4945 |
| 4836 *content_encoding_entries_end_++ = content_encoding; | 4946 *content_encoding_entries_end_++ = content_encoding; |
| 4837 } | 4947 } |
| 4838 | 4948 |
| 4839 pos += size; // consume payload | 4949 pos += size; // consume payload |
| 4840 assert(pos <= stop); | 4950 if (pos > stop) |
| 4951 return E_FILE_FORMAT_INVALID; |
| 4841 } | 4952 } |
| 4842 | 4953 |
| 4843 assert(pos == stop); | 4954 if (pos != stop) |
| 4955 return E_FILE_FORMAT_INVALID; |
| 4844 | 4956 |
| 4845 return 0; | 4957 return 0; |
| 4846 } | 4958 } |
| 4847 | 4959 |
| 4848 Track::EOSBlock::EOSBlock() : BlockEntry(NULL, LONG_MIN) {} | 4960 Track::EOSBlock::EOSBlock() : BlockEntry(NULL, LONG_MIN) {} |
| 4849 | 4961 |
| 4850 BlockEntry::Kind Track::EOSBlock::GetKind() const { return kBlockEOS; } | 4962 BlockEntry::Kind Track::EOSBlock::GetKind() const { return kBlockEOS; } |
| 4851 | 4963 |
| 4852 const Block* Track::EOSBlock::GetBlock() const { return NULL; } | 4964 const Block* Track::EOSBlock::GetBlock() const { return NULL; } |
| 4853 | 4965 |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4885 const long long stop = pos + s.size; | 4997 const long long stop = pos + s.size; |
| 4886 | 4998 |
| 4887 while (pos < stop) { | 4999 while (pos < stop) { |
| 4888 long long id, size; | 5000 long long id, size; |
| 4889 | 5001 |
| 4890 const long status = ParseElementHeader(pReader, pos, stop, id, size); | 5002 const long status = ParseElementHeader(pReader, pos, stop, id, size); |
| 4891 | 5003 |
| 4892 if (status < 0) // error | 5004 if (status < 0) // error |
| 4893 return status; | 5005 return status; |
| 4894 | 5006 |
| 4895 if (id == 0x30) { // pixel width | 5007 if (id == mkvmuxer::kMkvPixelWidth) { |
| 4896 width = UnserializeUInt(pReader, pos, size); | 5008 width = UnserializeUInt(pReader, pos, size); |
| 4897 | 5009 |
| 4898 if (width <= 0) | 5010 if (width <= 0) |
| 4899 return E_FILE_FORMAT_INVALID; | 5011 return E_FILE_FORMAT_INVALID; |
| 4900 } else if (id == 0x3A) { // pixel height | 5012 } else if (id == mkvmuxer::kMkvPixelHeight) { |
| 4901 height = UnserializeUInt(pReader, pos, size); | 5013 height = UnserializeUInt(pReader, pos, size); |
| 4902 | 5014 |
| 4903 if (height <= 0) | 5015 if (height <= 0) |
| 4904 return E_FILE_FORMAT_INVALID; | 5016 return E_FILE_FORMAT_INVALID; |
| 4905 } else if (id == 0x14B0) { // display width | 5017 } else if (id == mkvmuxer::kMkvDisplayWidth) { |
| 4906 display_width = UnserializeUInt(pReader, pos, size); | 5018 display_width = UnserializeUInt(pReader, pos, size); |
| 4907 | 5019 |
| 4908 if (display_width <= 0) | 5020 if (display_width <= 0) |
| 4909 return E_FILE_FORMAT_INVALID; | 5021 return E_FILE_FORMAT_INVALID; |
| 4910 } else if (id == 0x14BA) { // display height | 5022 } else if (id == mkvmuxer::kMkvDisplayHeight) { |
| 4911 display_height = UnserializeUInt(pReader, pos, size); | 5023 display_height = UnserializeUInt(pReader, pos, size); |
| 4912 | 5024 |
| 4913 if (display_height <= 0) | 5025 if (display_height <= 0) |
| 4914 return E_FILE_FORMAT_INVALID; | 5026 return E_FILE_FORMAT_INVALID; |
| 4915 } else if (id == 0x14B2) { // display unit | 5027 } else if (id == mkvmuxer::kMkvDisplayUnit) { |
| 4916 display_unit = UnserializeUInt(pReader, pos, size); | 5028 display_unit = UnserializeUInt(pReader, pos, size); |
| 4917 | 5029 |
| 4918 if (display_unit < 0) | 5030 if (display_unit < 0) |
| 4919 return E_FILE_FORMAT_INVALID; | 5031 return E_FILE_FORMAT_INVALID; |
| 4920 } else if (id == 0x13B8) { // stereo mode | 5032 } else if (id == mkvmuxer::kMkvStereoMode) { |
| 4921 stereo_mode = UnserializeUInt(pReader, pos, size); | 5033 stereo_mode = UnserializeUInt(pReader, pos, size); |
| 4922 | 5034 |
| 4923 if (stereo_mode < 0) | 5035 if (stereo_mode < 0) |
| 4924 return E_FILE_FORMAT_INVALID; | 5036 return E_FILE_FORMAT_INVALID; |
| 4925 } else if (id == 0x0383E3) { // frame rate | 5037 } else if (id == mkvmuxer::kMkvFrameRate) { |
| 4926 const long status = UnserializeFloat(pReader, pos, size, rate); | 5038 const long status = UnserializeFloat(pReader, pos, size, rate); |
| 4927 | 5039 |
| 4928 if (status < 0) | 5040 if (status < 0) |
| 4929 return status; | 5041 return status; |
| 4930 | 5042 |
| 4931 if (rate <= 0) | 5043 if (rate <= 0) |
| 4932 return E_FILE_FORMAT_INVALID; | 5044 return E_FILE_FORMAT_INVALID; |
| 4933 } | 5045 } |
| 4934 | 5046 |
| 4935 pos += size; // consume payload | 5047 pos += size; // consume payload |
| 4936 assert(pos <= stop); | 5048 if (pos > stop) |
| 5049 return E_FILE_FORMAT_INVALID; |
| 4937 } | 5050 } |
| 4938 | 5051 |
| 4939 assert(pos == stop); | 5052 if (pos != stop) |
| 5053 return E_FILE_FORMAT_INVALID; |
| 4940 | 5054 |
| 4941 VideoTrack* const pTrack = | 5055 VideoTrack* const pTrack = |
| 4942 new (std::nothrow) VideoTrack(pSegment, element_start, element_size); | 5056 new (std::nothrow) VideoTrack(pSegment, element_start, element_size); |
| 4943 | 5057 |
| 4944 if (pTrack == NULL) | 5058 if (pTrack == NULL) |
| 4945 return -1; // generic error | 5059 return -1; // generic error |
| 4946 | 5060 |
| 4947 const int status = info.Copy(pTrack->m_info); | 5061 const int status = info.Copy(pTrack->m_info); |
| 4948 | 5062 |
| 4949 if (status) { // error | 5063 if (status) { // error |
| (...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5103 long long bit_depth = 0; | 5217 long long bit_depth = 0; |
| 5104 | 5218 |
| 5105 while (pos < stop) { | 5219 while (pos < stop) { |
| 5106 long long id, size; | 5220 long long id, size; |
| 5107 | 5221 |
| 5108 long status = ParseElementHeader(pReader, pos, stop, id, size); | 5222 long status = ParseElementHeader(pReader, pos, stop, id, size); |
| 5109 | 5223 |
| 5110 if (status < 0) // error | 5224 if (status < 0) // error |
| 5111 return status; | 5225 return status; |
| 5112 | 5226 |
| 5113 if (id == 0x35) { // Sample Rate | 5227 if (id == mkvmuxer::kMkvSamplingFrequency) { |
| 5114 status = UnserializeFloat(pReader, pos, size, rate); | 5228 status = UnserializeFloat(pReader, pos, size, rate); |
| 5115 | 5229 |
| 5116 if (status < 0) | 5230 if (status < 0) |
| 5117 return status; | 5231 return status; |
| 5118 | 5232 |
| 5119 if (rate <= 0) | 5233 if (rate <= 0) |
| 5120 return E_FILE_FORMAT_INVALID; | 5234 return E_FILE_FORMAT_INVALID; |
| 5121 } else if (id == 0x1F) { // Channel Count | 5235 } else if (id == mkvmuxer::kMkvChannels) { |
| 5122 channels = UnserializeUInt(pReader, pos, size); | 5236 channels = UnserializeUInt(pReader, pos, size); |
| 5123 | 5237 |
| 5124 if (channels <= 0) | 5238 if (channels <= 0) |
| 5125 return E_FILE_FORMAT_INVALID; | 5239 return E_FILE_FORMAT_INVALID; |
| 5126 } else if (id == 0x2264) { // Bit Depth | 5240 } else if (id == mkvmuxer::kMkvBitDepth) { |
| 5127 bit_depth = UnserializeUInt(pReader, pos, size); | 5241 bit_depth = UnserializeUInt(pReader, pos, size); |
| 5128 | 5242 |
| 5129 if (bit_depth <= 0) | 5243 if (bit_depth <= 0) |
| 5130 return E_FILE_FORMAT_INVALID; | 5244 return E_FILE_FORMAT_INVALID; |
| 5131 } | 5245 } |
| 5132 | 5246 |
| 5133 pos += size; // consume payload | 5247 pos += size; // consume payload |
| 5134 assert(pos <= stop); | 5248 if (pos > stop) |
| 5249 return E_FILE_FORMAT_INVALID; |
| 5135 } | 5250 } |
| 5136 | 5251 |
| 5137 assert(pos == stop); | 5252 if (pos != stop) |
| 5253 return E_FILE_FORMAT_INVALID; |
| 5138 | 5254 |
| 5139 AudioTrack* const pTrack = | 5255 AudioTrack* const pTrack = |
| 5140 new (std::nothrow) AudioTrack(pSegment, element_start, element_size); | 5256 new (std::nothrow) AudioTrack(pSegment, element_start, element_size); |
| 5141 | 5257 |
| 5142 if (pTrack == NULL) | 5258 if (pTrack == NULL) |
| 5143 return -1; // generic error | 5259 return -1; // generic error |
| 5144 | 5260 |
| 5145 const int status = info.Copy(pTrack->m_info); | 5261 const int status = info.Copy(pTrack->m_info); |
| 5146 | 5262 |
| 5147 if (status) { | 5263 if (status) { |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5187 long long id, size; | 5303 long long id, size; |
| 5188 | 5304 |
| 5189 const long status = ParseElementHeader(pReader, pos, stop, id, size); | 5305 const long status = ParseElementHeader(pReader, pos, stop, id, size); |
| 5190 | 5306 |
| 5191 if (status < 0) // error | 5307 if (status < 0) // error |
| 5192 return status; | 5308 return status; |
| 5193 | 5309 |
| 5194 if (size == 0) // weird | 5310 if (size == 0) // weird |
| 5195 continue; | 5311 continue; |
| 5196 | 5312 |
| 5197 if (id == 0x2E) // TrackEntry ID | 5313 if (id == mkvmuxer::kMkvTrackEntry) |
| 5198 ++count; | 5314 ++count; |
| 5199 | 5315 |
| 5200 pos += size; // consume payload | 5316 pos += size; // consume payload |
| 5201 assert(pos <= stop); | 5317 if (pos > stop) |
| 5318 return E_FILE_FORMAT_INVALID; |
| 5202 } | 5319 } |
| 5203 | 5320 |
| 5204 assert(pos == stop); | 5321 if (pos != stop) |
| 5322 return E_FILE_FORMAT_INVALID; |
| 5205 | 5323 |
| 5206 if (count <= 0) | 5324 if (count <= 0) |
| 5207 return 0; // success | 5325 return 0; // success |
| 5208 | 5326 |
| 5209 m_trackEntries = new (std::nothrow) Track*[count]; | 5327 m_trackEntries = new (std::nothrow) Track*[count]; |
| 5210 | 5328 |
| 5211 if (m_trackEntries == NULL) | 5329 if (m_trackEntries == NULL) |
| 5212 return -1; | 5330 return -1; |
| 5213 | 5331 |
| 5214 m_trackEntriesEnd = m_trackEntries; | 5332 m_trackEntriesEnd = m_trackEntries; |
| (...skipping 12 matching lines...) Expand all Loading... |
| 5227 return status; | 5345 return status; |
| 5228 | 5346 |
| 5229 if (payload_size == 0) // weird | 5347 if (payload_size == 0) // weird |
| 5230 continue; | 5348 continue; |
| 5231 | 5349 |
| 5232 const long long payload_stop = pos + payload_size; | 5350 const long long payload_stop = pos + payload_size; |
| 5233 assert(payload_stop <= stop); // checked in ParseElement | 5351 assert(payload_stop <= stop); // checked in ParseElement |
| 5234 | 5352 |
| 5235 const long long element_size = payload_stop - element_start; | 5353 const long long element_size = payload_stop - element_start; |
| 5236 | 5354 |
| 5237 if (id == 0x2E) { // TrackEntry ID | 5355 if (id == mkvmuxer::kMkvTrackEntry) { |
| 5238 Track*& pTrack = *m_trackEntriesEnd; | 5356 Track*& pTrack = *m_trackEntriesEnd; |
| 5239 pTrack = NULL; | 5357 pTrack = NULL; |
| 5240 | 5358 |
| 5241 const long status = ParseTrackEntry(pos, payload_size, element_start, | 5359 const long status = ParseTrackEntry(pos, payload_size, element_start, |
| 5242 element_size, pTrack); | 5360 element_size, pTrack); |
| 5243 | |
| 5244 if (status) | 5361 if (status) |
| 5245 return status; | 5362 return status; |
| 5246 | 5363 |
| 5247 if (pTrack) | 5364 if (pTrack) |
| 5248 ++m_trackEntriesEnd; | 5365 ++m_trackEntriesEnd; |
| 5249 } | 5366 } |
| 5250 | 5367 |
| 5251 pos = payload_stop; | 5368 pos = payload_stop; |
| 5252 assert(pos <= stop); | 5369 if (pos > stop) |
| 5370 return E_FILE_FORMAT_INVALID; |
| 5253 } | 5371 } |
| 5254 | 5372 |
| 5255 assert(pos == stop); | 5373 if (pos != stop) |
| 5374 return E_FILE_FORMAT_INVALID; |
| 5256 | 5375 |
| 5257 return 0; // success | 5376 return 0; // success |
| 5258 } | 5377 } |
| 5259 | 5378 |
| 5260 unsigned long Tracks::GetTracksCount() const { | 5379 unsigned long Tracks::GetTracksCount() const { |
| 5261 const ptrdiff_t result = m_trackEntriesEnd - m_trackEntries; | 5380 const ptrdiff_t result = m_trackEntriesEnd - m_trackEntries; |
| 5262 assert(result >= 0); | 5381 assert(result >= 0); |
| 5263 | 5382 |
| 5264 return static_cast<unsigned long>(result); | 5383 return static_cast<unsigned long>(result); |
| 5265 } | 5384 } |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5302 const long status = ParseElementHeader(pReader, pos, track_stop, id, size); | 5421 const long status = ParseElementHeader(pReader, pos, track_stop, id, size); |
| 5303 | 5422 |
| 5304 if (status < 0) // error | 5423 if (status < 0) // error |
| 5305 return status; | 5424 return status; |
| 5306 | 5425 |
| 5307 if (size < 0) | 5426 if (size < 0) |
| 5308 return E_FILE_FORMAT_INVALID; | 5427 return E_FILE_FORMAT_INVALID; |
| 5309 | 5428 |
| 5310 const long long start = pos; | 5429 const long long start = pos; |
| 5311 | 5430 |
| 5312 if (id == 0x60) { // VideoSettings ID | 5431 if (id == mkvmuxer::kMkvVideo) { |
| 5313 v.start = start; | 5432 v.start = start; |
| 5314 v.size = size; | 5433 v.size = size; |
| 5315 } else if (id == 0x61) { // AudioSettings ID | 5434 } else if (id == mkvmuxer::kMkvAudio) { |
| 5316 a.start = start; | 5435 a.start = start; |
| 5317 a.size = size; | 5436 a.size = size; |
| 5318 } else if (id == 0x2D80) { // ContentEncodings ID | 5437 } else if (id == mkvmuxer::kMkvContentEncodings) { |
| 5319 e.start = start; | 5438 e.start = start; |
| 5320 e.size = size; | 5439 e.size = size; |
| 5321 } else if (id == 0x33C5) { // Track UID | 5440 } else if (id == mkvmuxer::kMkvTrackUID) { |
| 5322 if (size > 8) | 5441 if (size > 8) |
| 5323 return E_FILE_FORMAT_INVALID; | 5442 return E_FILE_FORMAT_INVALID; |
| 5324 | 5443 |
| 5325 info.uid = 0; | 5444 info.uid = 0; |
| 5326 | 5445 |
| 5327 long long pos_ = start; | 5446 long long pos_ = start; |
| 5328 const long long pos_end = start + size; | 5447 const long long pos_end = start + size; |
| 5329 | 5448 |
| 5330 while (pos_ != pos_end) { | 5449 while (pos_ != pos_end) { |
| 5331 unsigned char b; | 5450 unsigned char b; |
| 5332 | 5451 |
| 5333 const int status = pReader->Read(pos_, 1, &b); | 5452 const int status = pReader->Read(pos_, 1, &b); |
| 5334 | 5453 |
| 5335 if (status) | 5454 if (status) |
| 5336 return status; | 5455 return status; |
| 5337 | 5456 |
| 5338 info.uid <<= 8; | 5457 info.uid <<= 8; |
| 5339 info.uid |= b; | 5458 info.uid |= b; |
| 5340 | 5459 |
| 5341 ++pos_; | 5460 ++pos_; |
| 5342 } | 5461 } |
| 5343 } else if (id == 0x57) { // Track Number | 5462 } else if (id == mkvmuxer::kMkvTrackNumber) { |
| 5344 const long long num = UnserializeUInt(pReader, pos, size); | 5463 const long long num = UnserializeUInt(pReader, pos, size); |
| 5345 | 5464 |
| 5346 if ((num <= 0) || (num > 127)) | 5465 if ((num <= 0) || (num > 127)) |
| 5347 return E_FILE_FORMAT_INVALID; | 5466 return E_FILE_FORMAT_INVALID; |
| 5348 | 5467 |
| 5349 info.number = static_cast<long>(num); | 5468 info.number = static_cast<long>(num); |
| 5350 } else if (id == 0x03) { // Track Type | 5469 } else if (id == mkvmuxer::kMkvTrackType) { |
| 5351 const long long type = UnserializeUInt(pReader, pos, size); | 5470 const long long type = UnserializeUInt(pReader, pos, size); |
| 5352 | 5471 |
| 5353 if ((type <= 0) || (type > 254)) | 5472 if ((type <= 0) || (type > 254)) |
| 5354 return E_FILE_FORMAT_INVALID; | 5473 return E_FILE_FORMAT_INVALID; |
| 5355 | 5474 |
| 5356 info.type = static_cast<long>(type); | 5475 info.type = static_cast<long>(type); |
| 5357 } else if (id == 0x136E) { // Track Name | 5476 } else if (id == mkvmuxer::kMkvName) { |
| 5358 const long status = | 5477 const long status = |
| 5359 UnserializeString(pReader, pos, size, info.nameAsUTF8); | 5478 UnserializeString(pReader, pos, size, info.nameAsUTF8); |
| 5360 | 5479 |
| 5361 if (status) | 5480 if (status) |
| 5362 return status; | 5481 return status; |
| 5363 } else if (id == 0x02B59C) { // Track Language | 5482 } else if (id == mkvmuxer::kMkvLanguage) { |
| 5364 const long status = UnserializeString(pReader, pos, size, info.language); | 5483 const long status = UnserializeString(pReader, pos, size, info.language); |
| 5365 | 5484 |
| 5366 if (status) | 5485 if (status) |
| 5367 return status; | 5486 return status; |
| 5368 } else if (id == 0x03E383) { // Default Duration | 5487 } else if (id == mkvmuxer::kMkvDefaultDuration) { |
| 5369 const long long duration = UnserializeUInt(pReader, pos, size); | 5488 const long long duration = UnserializeUInt(pReader, pos, size); |
| 5370 | 5489 |
| 5371 if (duration < 0) | 5490 if (duration < 0) |
| 5372 return E_FILE_FORMAT_INVALID; | 5491 return E_FILE_FORMAT_INVALID; |
| 5373 | 5492 |
| 5374 info.defaultDuration = static_cast<unsigned long long>(duration); | 5493 info.defaultDuration = static_cast<unsigned long long>(duration); |
| 5375 } else if (id == 0x06) { // CodecID | 5494 } else if (id == mkvmuxer::kMkvCodecID) { |
| 5376 const long status = UnserializeString(pReader, pos, size, info.codecId); | 5495 const long status = UnserializeString(pReader, pos, size, info.codecId); |
| 5377 | 5496 |
| 5378 if (status) | 5497 if (status) |
| 5379 return status; | 5498 return status; |
| 5380 } else if (id == 0x1C) { // lacing | 5499 } else if (id == mkvmuxer::kMkvFlagLacing) { |
| 5381 lacing = UnserializeUInt(pReader, pos, size); | 5500 lacing = UnserializeUInt(pReader, pos, size); |
| 5382 | 5501 |
| 5383 if ((lacing < 0) || (lacing > 1)) | 5502 if ((lacing < 0) || (lacing > 1)) |
| 5384 return E_FILE_FORMAT_INVALID; | 5503 return E_FILE_FORMAT_INVALID; |
| 5385 } else if (id == 0x23A2) { // Codec Private | 5504 } else if (id == mkvmuxer::kMkvCodecPrivate) { |
| 5386 delete[] info.codecPrivate; | 5505 delete[] info.codecPrivate; |
| 5387 info.codecPrivate = NULL; | 5506 info.codecPrivate = NULL; |
| 5388 info.codecPrivateSize = 0; | 5507 info.codecPrivateSize = 0; |
| 5389 | 5508 |
| 5390 const size_t buflen = static_cast<size_t>(size); | 5509 const size_t buflen = static_cast<size_t>(size); |
| 5391 | 5510 |
| 5392 if (buflen) { | 5511 if (buflen) { |
| 5393 typedef unsigned char* buf_t; | 5512 unsigned char* buf = SafeArrayAlloc<unsigned char>(1, buflen); |
| 5394 | |
| 5395 const buf_t buf = new (std::nothrow) unsigned char[buflen]; | |
| 5396 | 5513 |
| 5397 if (buf == NULL) | 5514 if (buf == NULL) |
| 5398 return -1; | 5515 return -1; |
| 5399 | 5516 |
| 5400 const int status = pReader->Read(pos, static_cast<long>(buflen), buf); | 5517 const int status = pReader->Read(pos, static_cast<long>(buflen), buf); |
| 5401 | 5518 |
| 5402 if (status) { | 5519 if (status) { |
| 5403 delete[] buf; | 5520 delete[] buf; |
| 5404 return status; | 5521 return status; |
| 5405 } | 5522 } |
| 5406 | 5523 |
| 5407 info.codecPrivate = buf; | 5524 info.codecPrivate = buf; |
| 5408 info.codecPrivateSize = buflen; | 5525 info.codecPrivateSize = buflen; |
| 5409 } | 5526 } |
| 5410 } else if (id == 0x058688) { // Codec Name | 5527 } else if (id == mkvmuxer::kMkvCodecName) { |
| 5411 const long status = | 5528 const long status = |
| 5412 UnserializeString(pReader, pos, size, info.codecNameAsUTF8); | 5529 UnserializeString(pReader, pos, size, info.codecNameAsUTF8); |
| 5413 | 5530 |
| 5414 if (status) | 5531 if (status) |
| 5415 return status; | 5532 return status; |
| 5416 } else if (id == 0x16AA) { // Codec Delay | 5533 } else if (id == mkvmuxer::kMkvCodecDelay) { |
| 5417 info.codecDelay = UnserializeUInt(pReader, pos, size); | 5534 info.codecDelay = UnserializeUInt(pReader, pos, size); |
| 5418 } else if (id == 0x16BB) { // Seek Pre Roll | 5535 } else if (id == mkvmuxer::kMkvSeekPreRoll) { |
| 5419 info.seekPreRoll = UnserializeUInt(pReader, pos, size); | 5536 info.seekPreRoll = UnserializeUInt(pReader, pos, size); |
| 5420 } | 5537 } |
| 5421 | 5538 |
| 5422 pos += size; // consume payload | 5539 pos += size; // consume payload |
| 5423 assert(pos <= track_stop); | 5540 if (pos > track_stop) |
| 5541 return E_FILE_FORMAT_INVALID; |
| 5424 } | 5542 } |
| 5425 | 5543 |
| 5426 assert(pos == track_stop); | 5544 if (pos != track_stop) |
| 5545 return E_FILE_FORMAT_INVALID; |
| 5427 | 5546 |
| 5428 if (info.number <= 0) // not specified | 5547 if (info.number <= 0) // not specified |
| 5429 return E_FILE_FORMAT_INVALID; | 5548 return E_FILE_FORMAT_INVALID; |
| 5430 | 5549 |
| 5431 if (GetTrackByNumber(info.number)) | 5550 if (GetTrackByNumber(info.number)) |
| 5432 return E_FILE_FORMAT_INVALID; | 5551 return E_FILE_FORMAT_INVALID; |
| 5433 | 5552 |
| 5434 if (info.type <= 0) // not specified | 5553 if (info.type <= 0) // not specified |
| 5435 return E_FILE_FORMAT_INVALID; | 5554 return E_FILE_FORMAT_INVALID; |
| 5436 | 5555 |
| (...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5545 const Track* Tracks::GetTrackByIndex(unsigned long idx) const { | 5664 const Track* Tracks::GetTrackByIndex(unsigned long idx) const { |
| 5546 const ptrdiff_t count = m_trackEntriesEnd - m_trackEntries; | 5665 const ptrdiff_t count = m_trackEntriesEnd - m_trackEntries; |
| 5547 | 5666 |
| 5548 if (idx >= static_cast<unsigned long>(count)) | 5667 if (idx >= static_cast<unsigned long>(count)) |
| 5549 return NULL; | 5668 return NULL; |
| 5550 | 5669 |
| 5551 return m_trackEntries[idx]; | 5670 return m_trackEntries[idx]; |
| 5552 } | 5671 } |
| 5553 | 5672 |
| 5554 long Cluster::Load(long long& pos, long& len) const { | 5673 long Cluster::Load(long long& pos, long& len) const { |
| 5555 assert(m_pSegment); | 5674 if (m_pSegment == NULL) |
| 5556 assert(m_pos >= m_element_start); | 5675 return E_PARSE_FAILED; |
| 5557 | 5676 |
| 5558 if (m_timecode >= 0) // at least partially loaded | 5677 if (m_timecode >= 0) // at least partially loaded |
| 5559 return 0; | 5678 return 0; |
| 5560 | 5679 |
| 5561 assert(m_pos == m_element_start); | 5680 if (m_pos != m_element_start || m_element_size >= 0) |
| 5562 assert(m_element_size < 0); | 5681 return E_PARSE_FAILED; |
| 5563 | 5682 |
| 5564 IMkvReader* const pReader = m_pSegment->m_pReader; | 5683 IMkvReader* const pReader = m_pSegment->m_pReader; |
| 5565 | |
| 5566 long long total, avail; | 5684 long long total, avail; |
| 5567 | |
| 5568 const int status = pReader->Length(&total, &avail); | 5685 const int status = pReader->Length(&total, &avail); |
| 5569 | 5686 |
| 5570 if (status < 0) // error | 5687 if (status < 0) // error |
| 5571 return status; | 5688 return status; |
| 5572 | 5689 |
| 5573 assert((total < 0) || (avail <= total)); | 5690 if (total >= 0 && (avail > total || m_pos > total)) |
| 5574 assert((total < 0) || (m_pos <= total)); // TODO: verify this | 5691 return E_FILE_FORMAT_INVALID; |
| 5575 | 5692 |
| 5576 pos = m_pos; | 5693 pos = m_pos; |
| 5577 | 5694 |
| 5578 long long cluster_size = -1; | 5695 long long cluster_size = -1; |
| 5579 | 5696 |
| 5580 { | 5697 if ((pos + 1) > avail) { |
| 5581 if ((pos + 1) > avail) { | 5698 len = 1; |
| 5582 len = 1; | 5699 return E_BUFFER_NOT_FULL; |
| 5583 return E_BUFFER_NOT_FULL; | 5700 } |
| 5584 } | |
| 5585 | 5701 |
| 5586 long long result = GetUIntLength(pReader, pos, len); | 5702 long long result = GetUIntLength(pReader, pos, len); |
| 5587 | 5703 |
| 5588 if (result < 0) // error or underflow | 5704 if (result < 0) // error or underflow |
| 5589 return static_cast<long>(result); | 5705 return static_cast<long>(result); |
| 5590 | 5706 |
| 5591 if (result > 0) // underflow (weird) | 5707 if (result > 0) |
| 5592 return E_BUFFER_NOT_FULL; | 5708 return E_BUFFER_NOT_FULL; |
| 5593 | 5709 |
| 5594 // if ((pos + len) > segment_stop) | 5710 if ((pos + len) > avail) |
| 5595 // return E_FILE_FORMAT_INVALID; | 5711 return E_BUFFER_NOT_FULL; |
| 5596 | 5712 |
| 5597 if ((pos + len) > avail) | 5713 const long long id_ = ReadID(pReader, pos, len); |
| 5598 return E_BUFFER_NOT_FULL; | |
| 5599 | 5714 |
| 5600 const long long id_ = ReadUInt(pReader, pos, len); | 5715 if (id_ < 0) // error |
| 5716 return static_cast<long>(id_); |
| 5601 | 5717 |
| 5602 if (id_ < 0) // error | 5718 if (id_ != mkvmuxer::kMkvCluster) |
| 5603 return static_cast<long>(id_); | 5719 return E_FILE_FORMAT_INVALID; |
| 5604 | 5720 |
| 5605 if (id_ != 0x0F43B675) // Cluster ID | 5721 pos += len; // consume id |
| 5606 return E_FILE_FORMAT_INVALID; | |
| 5607 | 5722 |
| 5608 pos += len; // consume id | 5723 // read cluster size |
| 5609 | 5724 |
| 5610 // read cluster size | 5725 if ((pos + 1) > avail) { |
| 5726 len = 1; |
| 5727 return E_BUFFER_NOT_FULL; |
| 5728 } |
| 5611 | 5729 |
| 5612 if ((pos + 1) > avail) { | 5730 result = GetUIntLength(pReader, pos, len); |
| 5613 len = 1; | |
| 5614 return E_BUFFER_NOT_FULL; | |
| 5615 } | |
| 5616 | 5731 |
| 5617 result = GetUIntLength(pReader, pos, len); | 5732 if (result < 0) // error |
| 5733 return static_cast<long>(result); |
| 5618 | 5734 |
| 5619 if (result < 0) // error | 5735 if (result > 0) |
| 5620 return static_cast<long>(result); | 5736 return E_BUFFER_NOT_FULL; |
| 5621 | 5737 |
| 5622 if (result > 0) // weird | 5738 if ((pos + len) > avail) |
| 5623 return E_BUFFER_NOT_FULL; | 5739 return E_BUFFER_NOT_FULL; |
| 5624 | 5740 |
| 5625 // if ((pos + len) > segment_stop) | 5741 const long long size = ReadUInt(pReader, pos, len); |
| 5626 // return E_FILE_FORMAT_INVALID; | |
| 5627 | 5742 |
| 5628 if ((pos + len) > avail) | 5743 if (size < 0) // error |
| 5629 return E_BUFFER_NOT_FULL; | 5744 return static_cast<long>(cluster_size); |
| 5630 | 5745 |
| 5631 const long long size = ReadUInt(pReader, pos, len); | 5746 if (size == 0) |
| 5747 return E_FILE_FORMAT_INVALID; |
| 5632 | 5748 |
| 5633 if (size < 0) // error | 5749 pos += len; // consume length of size of element |
| 5634 return static_cast<long>(cluster_size); | |
| 5635 | 5750 |
| 5636 if (size == 0) | 5751 const long long unknown_size = (1LL << (7 * len)) - 1; |
| 5637 return E_FILE_FORMAT_INVALID; // TODO: verify this | |
| 5638 | 5752 |
| 5639 pos += len; // consume length of size of element | 5753 if (size != unknown_size) |
| 5640 | 5754 cluster_size = size; |
| 5641 const long long unknown_size = (1LL << (7 * len)) - 1; | |
| 5642 | |
| 5643 if (size != unknown_size) | |
| 5644 cluster_size = size; | |
| 5645 } | |
| 5646 | 5755 |
| 5647 // pos points to start of payload | 5756 // pos points to start of payload |
| 5648 long long timecode = -1; | 5757 long long timecode = -1; |
| 5649 long long new_pos = -1; | 5758 long long new_pos = -1; |
| 5650 bool bBlock = false; | 5759 bool bBlock = false; |
| 5651 | 5760 |
| 5652 long long cluster_stop = (cluster_size < 0) ? -1 : pos + cluster_size; | 5761 long long cluster_stop = (cluster_size < 0) ? -1 : pos + cluster_size; |
| 5653 | 5762 |
| 5654 for (;;) { | 5763 for (;;) { |
| 5655 if ((cluster_stop >= 0) && (pos >= cluster_stop)) | 5764 if ((cluster_stop >= 0) && (pos >= cluster_stop)) |
| 5656 break; | 5765 break; |
| 5657 | 5766 |
| 5658 // Parse ID | 5767 // Parse ID |
| 5659 | 5768 |
| 5660 if ((pos + 1) > avail) { | 5769 if ((pos + 1) > avail) { |
| 5661 len = 1; | 5770 len = 1; |
| 5662 return E_BUFFER_NOT_FULL; | 5771 return E_BUFFER_NOT_FULL; |
| 5663 } | 5772 } |
| 5664 | 5773 |
| 5665 long long result = GetUIntLength(pReader, pos, len); | 5774 long long result = GetUIntLength(pReader, pos, len); |
| 5666 | 5775 |
| 5667 if (result < 0) // error | 5776 if (result < 0) // error |
| 5668 return static_cast<long>(result); | 5777 return static_cast<long>(result); |
| 5669 | 5778 |
| 5670 if (result > 0) // weird | 5779 if (result > 0) |
| 5671 return E_BUFFER_NOT_FULL; | 5780 return E_BUFFER_NOT_FULL; |
| 5672 | 5781 |
| 5673 if ((cluster_stop >= 0) && ((pos + len) > cluster_stop)) | 5782 if ((cluster_stop >= 0) && ((pos + len) > cluster_stop)) |
| 5674 return E_FILE_FORMAT_INVALID; | 5783 return E_FILE_FORMAT_INVALID; |
| 5675 | 5784 |
| 5676 if ((pos + len) > avail) | 5785 if ((pos + len) > avail) |
| 5677 return E_BUFFER_NOT_FULL; | 5786 return E_BUFFER_NOT_FULL; |
| 5678 | 5787 |
| 5679 const long long id = ReadUInt(pReader, pos, len); | 5788 const long long id = ReadID(pReader, pos, len); |
| 5680 | 5789 |
| 5681 if (id < 0) // error | 5790 if (id < 0) // error |
| 5682 return static_cast<long>(id); | 5791 return static_cast<long>(id); |
| 5683 | 5792 |
| 5684 if (id == 0) | 5793 if (id == 0) |
| 5685 return E_FILE_FORMAT_INVALID; | 5794 return E_FILE_FORMAT_INVALID; |
| 5686 | 5795 |
| 5687 // This is the distinguished set of ID's we use to determine | 5796 // This is the distinguished set of ID's we use to determine |
| 5688 // that we have exhausted the sub-element's inside the cluster | 5797 // that we have exhausted the sub-element's inside the cluster |
| 5689 // whose ID we parsed earlier. | 5798 // whose ID we parsed earlier. |
| 5690 | 5799 |
| 5691 if (id == 0x0F43B675) // Cluster ID | 5800 if (id == mkvmuxer::kMkvCluster) |
| 5692 break; | 5801 break; |
| 5693 | 5802 |
| 5694 if (id == 0x0C53BB6B) // Cues ID | 5803 if (id == mkvmuxer::kMkvCues) |
| 5695 break; | 5804 break; |
| 5696 | 5805 |
| 5697 pos += len; // consume ID field | 5806 pos += len; // consume ID field |
| 5698 | 5807 |
| 5699 // Parse Size | 5808 // Parse Size |
| 5700 | 5809 |
| 5701 if ((pos + 1) > avail) { | 5810 if ((pos + 1) > avail) { |
| 5702 len = 1; | 5811 len = 1; |
| 5703 return E_BUFFER_NOT_FULL; | 5812 return E_BUFFER_NOT_FULL; |
| 5704 } | 5813 } |
| 5705 | 5814 |
| 5706 result = GetUIntLength(pReader, pos, len); | 5815 result = GetUIntLength(pReader, pos, len); |
| 5707 | 5816 |
| 5708 if (result < 0) // error | 5817 if (result < 0) // error |
| 5709 return static_cast<long>(result); | 5818 return static_cast<long>(result); |
| 5710 | 5819 |
| 5711 if (result > 0) // weird | 5820 if (result > 0) |
| 5712 return E_BUFFER_NOT_FULL; | 5821 return E_BUFFER_NOT_FULL; |
| 5713 | 5822 |
| 5714 if ((cluster_stop >= 0) && ((pos + len) > cluster_stop)) | 5823 if ((cluster_stop >= 0) && ((pos + len) > cluster_stop)) |
| 5715 return E_FILE_FORMAT_INVALID; | 5824 return E_FILE_FORMAT_INVALID; |
| 5716 | 5825 |
| 5717 if ((pos + len) > avail) | 5826 if ((pos + len) > avail) |
| 5718 return E_BUFFER_NOT_FULL; | 5827 return E_BUFFER_NOT_FULL; |
| 5719 | 5828 |
| 5720 const long long size = ReadUInt(pReader, pos, len); | 5829 const long long size = ReadUInt(pReader, pos, len); |
| 5721 | 5830 |
| 5722 if (size < 0) // error | 5831 if (size < 0) // error |
| 5723 return static_cast<long>(size); | 5832 return static_cast<long>(size); |
| 5724 | 5833 |
| 5725 const long long unknown_size = (1LL << (7 * len)) - 1; | 5834 const long long unknown_size = (1LL << (7 * len)) - 1; |
| 5726 | 5835 |
| 5727 if (size == unknown_size) | 5836 if (size == unknown_size) |
| 5728 return E_FILE_FORMAT_INVALID; | 5837 return E_FILE_FORMAT_INVALID; |
| 5729 | 5838 |
| 5730 pos += len; // consume size field | 5839 pos += len; // consume size field |
| 5731 | 5840 |
| 5732 if ((cluster_stop >= 0) && (pos > cluster_stop)) | 5841 if ((cluster_stop >= 0) && (pos > cluster_stop)) |
| 5733 return E_FILE_FORMAT_INVALID; | 5842 return E_FILE_FORMAT_INVALID; |
| 5734 | 5843 |
| 5735 // pos now points to start of payload | 5844 // pos now points to start of payload |
| 5736 | 5845 |
| 5737 if (size == 0) // weird | 5846 if (size == 0) |
| 5738 continue; | 5847 continue; |
| 5739 | 5848 |
| 5740 if ((cluster_stop >= 0) && ((pos + size) > cluster_stop)) | 5849 if ((cluster_stop >= 0) && ((pos + size) > cluster_stop)) |
| 5741 return E_FILE_FORMAT_INVALID; | 5850 return E_FILE_FORMAT_INVALID; |
| 5742 | 5851 |
| 5743 if (id == 0x67) { // TimeCode ID | 5852 if (id == mkvmuxer::kMkvTimecode) { |
| 5744 len = static_cast<long>(size); | 5853 len = static_cast<long>(size); |
| 5745 | 5854 |
| 5746 if ((pos + size) > avail) | 5855 if ((pos + size) > avail) |
| 5747 return E_BUFFER_NOT_FULL; | 5856 return E_BUFFER_NOT_FULL; |
| 5748 | 5857 |
| 5749 timecode = UnserializeUInt(pReader, pos, size); | 5858 timecode = UnserializeUInt(pReader, pos, size); |
| 5750 | 5859 |
| 5751 if (timecode < 0) // error (or underflow) | 5860 if (timecode < 0) // error (or underflow) |
| 5752 return static_cast<long>(timecode); | 5861 return static_cast<long>(timecode); |
| 5753 | 5862 |
| 5754 new_pos = pos + size; | 5863 new_pos = pos + size; |
| 5755 | 5864 |
| 5756 if (bBlock) | 5865 if (bBlock) |
| 5757 break; | 5866 break; |
| 5758 } else if (id == 0x20) { // BlockGroup ID | 5867 } else if (id == mkvmuxer::kMkvBlockGroup) { |
| 5759 bBlock = true; | 5868 bBlock = true; |
| 5760 break; | 5869 break; |
| 5761 } else if (id == 0x23) { // SimpleBlock ID | 5870 } else if (id == mkvmuxer::kMkvSimpleBlock) { |
| 5762 bBlock = true; | 5871 bBlock = true; |
| 5763 break; | 5872 break; |
| 5764 } | 5873 } |
| 5765 | 5874 |
| 5766 pos += size; // consume payload | 5875 pos += size; // consume payload |
| 5767 assert((cluster_stop < 0) || (pos <= cluster_stop)); | 5876 if (cluster_stop >= 0 && pos > cluster_stop) |
| 5877 return E_FILE_FORMAT_INVALID; |
| 5768 } | 5878 } |
| 5769 | 5879 |
| 5770 assert((cluster_stop < 0) || (pos <= cluster_stop)); | 5880 if (cluster_stop >= 0 && pos > cluster_stop) |
| 5881 return E_FILE_FORMAT_INVALID; |
| 5771 | 5882 |
| 5772 if (timecode < 0) // no timecode found | 5883 if (timecode < 0) // no timecode found |
| 5773 return E_FILE_FORMAT_INVALID; | 5884 return E_FILE_FORMAT_INVALID; |
| 5774 | 5885 |
| 5775 if (!bBlock) | 5886 if (!bBlock) |
| 5776 return E_FILE_FORMAT_INVALID; | 5887 return E_FILE_FORMAT_INVALID; |
| 5777 | 5888 |
| 5778 m_pos = new_pos; // designates position just beyond timecode payload | 5889 m_pos = new_pos; // designates position just beyond timecode payload |
| 5779 m_timecode = timecode; // m_timecode >= 0 means we're partially loaded | 5890 m_timecode = timecode; // m_timecode >= 0 means we're partially loaded |
| 5780 | 5891 |
| 5781 if (cluster_size >= 0) | 5892 if (cluster_size >= 0) |
| 5782 m_element_size = cluster_stop - m_element_start; | 5893 m_element_size = cluster_stop - m_element_start; |
| 5783 | 5894 |
| 5784 return 0; | 5895 return 0; |
| 5785 } | 5896 } |
| 5786 | 5897 |
| 5787 long Cluster::Parse(long long& pos, long& len) const { | 5898 long Cluster::Parse(long long& pos, long& len) const { |
| 5788 long status = Load(pos, len); | 5899 long status = Load(pos, len); |
| 5789 | 5900 |
| 5790 if (status < 0) | 5901 if (status < 0) |
| 5791 return status; | 5902 return status; |
| 5792 | 5903 |
| 5793 assert(m_pos >= m_element_start); | 5904 if (m_pos < m_element_start || m_timecode < 0) |
| 5794 assert(m_timecode >= 0); | 5905 return E_PARSE_FAILED; |
| 5795 // assert(m_size > 0); | |
| 5796 // assert(m_element_size > m_size); | |
| 5797 | 5906 |
| 5798 const long long cluster_stop = | 5907 const long long cluster_stop = |
| 5799 (m_element_size < 0) ? -1 : m_element_start + m_element_size; | 5908 (m_element_size < 0) ? -1 : m_element_start + m_element_size; |
| 5800 | 5909 |
| 5801 if ((cluster_stop >= 0) && (m_pos >= cluster_stop)) | 5910 if ((cluster_stop >= 0) && (m_pos >= cluster_stop)) |
| 5802 return 1; // nothing else to do | 5911 return 1; // nothing else to do |
| 5803 | 5912 |
| 5804 IMkvReader* const pReader = m_pSegment->m_pReader; | 5913 IMkvReader* const pReader = m_pSegment->m_pReader; |
| 5805 | 5914 |
| 5806 long long total, avail; | 5915 long long total, avail; |
| 5807 | 5916 |
| 5808 status = pReader->Length(&total, &avail); | 5917 status = pReader->Length(&total, &avail); |
| 5809 | 5918 |
| 5810 if (status < 0) // error | 5919 if (status < 0) // error |
| 5811 return status; | 5920 return status; |
| 5812 | 5921 |
| 5813 assert((total < 0) || (avail <= total)); | 5922 if (total >= 0 && avail > total) |
| 5923 return E_FILE_FORMAT_INVALID; |
| 5814 | 5924 |
| 5815 pos = m_pos; | 5925 pos = m_pos; |
| 5816 | 5926 |
| 5817 for (;;) { | 5927 for (;;) { |
| 5818 if ((cluster_stop >= 0) && (pos >= cluster_stop)) | 5928 if ((cluster_stop >= 0) && (pos >= cluster_stop)) |
| 5819 break; | 5929 break; |
| 5820 | 5930 |
| 5821 if ((total >= 0) && (pos >= total)) { | 5931 if ((total >= 0) && (pos >= total)) { |
| 5822 if (m_element_size < 0) | 5932 if (m_element_size < 0) |
| 5823 m_element_size = pos - m_element_start; | 5933 m_element_size = pos - m_element_start; |
| 5824 | 5934 |
| 5825 break; | 5935 break; |
| 5826 } | 5936 } |
| 5827 | 5937 |
| 5828 // Parse ID | 5938 // Parse ID |
| 5829 | 5939 |
| 5830 if ((pos + 1) > avail) { | 5940 if ((pos + 1) > avail) { |
| 5831 len = 1; | 5941 len = 1; |
| 5832 return E_BUFFER_NOT_FULL; | 5942 return E_BUFFER_NOT_FULL; |
| 5833 } | 5943 } |
| 5834 | 5944 |
| 5835 long long result = GetUIntLength(pReader, pos, len); | 5945 long long result = GetUIntLength(pReader, pos, len); |
| 5836 | 5946 |
| 5837 if (result < 0) // error | 5947 if (result < 0) // error |
| 5838 return static_cast<long>(result); | 5948 return static_cast<long>(result); |
| 5839 | 5949 |
| 5840 if (result > 0) // weird | 5950 if (result > 0) |
| 5841 return E_BUFFER_NOT_FULL; | 5951 return E_BUFFER_NOT_FULL; |
| 5842 | 5952 |
| 5843 if ((cluster_stop >= 0) && ((pos + len) > cluster_stop)) | 5953 if ((cluster_stop >= 0) && ((pos + len) > cluster_stop)) |
| 5844 return E_FILE_FORMAT_INVALID; | 5954 return E_FILE_FORMAT_INVALID; |
| 5845 | 5955 |
| 5846 if ((pos + len) > avail) | 5956 if ((pos + len) > avail) |
| 5847 return E_BUFFER_NOT_FULL; | 5957 return E_BUFFER_NOT_FULL; |
| 5848 | 5958 |
| 5849 const long long id = ReadUInt(pReader, pos, len); | 5959 const long long id = ReadID(pReader, pos, len); |
| 5850 | 5960 |
| 5851 if (id < 0) // error | 5961 if (id < 0) |
| 5852 return static_cast<long>(id); | |
| 5853 | |
| 5854 if (id == 0) // weird | |
| 5855 return E_FILE_FORMAT_INVALID; | 5962 return E_FILE_FORMAT_INVALID; |
| 5856 | 5963 |
| 5857 // This is the distinguished set of ID's we use to determine | 5964 // This is the distinguished set of ID's we use to determine |
| 5858 // that we have exhausted the sub-element's inside the cluster | 5965 // that we have exhausted the sub-element's inside the cluster |
| 5859 // whose ID we parsed earlier. | 5966 // whose ID we parsed earlier. |
| 5860 | 5967 |
| 5861 if ((id == 0x0F43B675) || (id == 0x0C53BB6B)) { // Cluster or Cues ID | 5968 if ((id == mkvmuxer::kMkvCluster) || (id == mkvmuxer::kMkvCues)) { |
| 5862 if (m_element_size < 0) | 5969 if (m_element_size < 0) |
| 5863 m_element_size = pos - m_element_start; | 5970 m_element_size = pos - m_element_start; |
| 5864 | 5971 |
| 5865 break; | 5972 break; |
| 5866 } | 5973 } |
| 5867 | 5974 |
| 5868 pos += len; // consume ID field | 5975 pos += len; // consume ID field |
| 5869 | 5976 |
| 5870 // Parse Size | 5977 // Parse Size |
| 5871 | 5978 |
| 5872 if ((pos + 1) > avail) { | 5979 if ((pos + 1) > avail) { |
| 5873 len = 1; | 5980 len = 1; |
| 5874 return E_BUFFER_NOT_FULL; | 5981 return E_BUFFER_NOT_FULL; |
| 5875 } | 5982 } |
| 5876 | 5983 |
| 5877 result = GetUIntLength(pReader, pos, len); | 5984 result = GetUIntLength(pReader, pos, len); |
| 5878 | 5985 |
| 5879 if (result < 0) // error | 5986 if (result < 0) // error |
| 5880 return static_cast<long>(result); | 5987 return static_cast<long>(result); |
| 5881 | 5988 |
| 5882 if (result > 0) // weird | 5989 if (result > 0) |
| 5883 return E_BUFFER_NOT_FULL; | 5990 return E_BUFFER_NOT_FULL; |
| 5884 | 5991 |
| 5885 if ((cluster_stop >= 0) && ((pos + len) > cluster_stop)) | 5992 if ((cluster_stop >= 0) && ((pos + len) > cluster_stop)) |
| 5886 return E_FILE_FORMAT_INVALID; | 5993 return E_FILE_FORMAT_INVALID; |
| 5887 | 5994 |
| 5888 if ((pos + len) > avail) | 5995 if ((pos + len) > avail) |
| 5889 return E_BUFFER_NOT_FULL; | 5996 return E_BUFFER_NOT_FULL; |
| 5890 | 5997 |
| 5891 const long long size = ReadUInt(pReader, pos, len); | 5998 const long long size = ReadUInt(pReader, pos, len); |
| 5892 | 5999 |
| 5893 if (size < 0) // error | 6000 if (size < 0) // error |
| 5894 return static_cast<long>(size); | 6001 return static_cast<long>(size); |
| 5895 | 6002 |
| 5896 const long long unknown_size = (1LL << (7 * len)) - 1; | 6003 const long long unknown_size = (1LL << (7 * len)) - 1; |
| 5897 | 6004 |
| 5898 if (size == unknown_size) | 6005 if (size == unknown_size) |
| 5899 return E_FILE_FORMAT_INVALID; | 6006 return E_FILE_FORMAT_INVALID; |
| 5900 | 6007 |
| 5901 pos += len; // consume size field | 6008 pos += len; // consume size field |
| 5902 | 6009 |
| 5903 if ((cluster_stop >= 0) && (pos > cluster_stop)) | 6010 if ((cluster_stop >= 0) && (pos > cluster_stop)) |
| 5904 return E_FILE_FORMAT_INVALID; | 6011 return E_FILE_FORMAT_INVALID; |
| 5905 | 6012 |
| 5906 // pos now points to start of payload | 6013 // pos now points to start of payload |
| 5907 | 6014 |
| 5908 if (size == 0) // weird | 6015 if (size == 0) |
| 5909 continue; | 6016 continue; |
| 5910 | 6017 |
| 5911 // const long long block_start = pos; | 6018 // const long long block_start = pos; |
| 5912 const long long block_stop = pos + size; | 6019 const long long block_stop = pos + size; |
| 5913 | 6020 |
| 5914 if (cluster_stop >= 0) { | 6021 if (cluster_stop >= 0) { |
| 5915 if (block_stop > cluster_stop) { | 6022 if (block_stop > cluster_stop) { |
| 5916 if ((id == 0x20) || (id == 0x23)) | 6023 if (id == mkvmuxer::kMkvBlockGroup || |
| 6024 id == mkvmuxer::kMkvSimpleBlock) { |
| 5917 return E_FILE_FORMAT_INVALID; | 6025 return E_FILE_FORMAT_INVALID; |
| 6026 } |
| 5918 | 6027 |
| 5919 pos = cluster_stop; | 6028 pos = cluster_stop; |
| 5920 break; | 6029 break; |
| 5921 } | 6030 } |
| 5922 } else if ((total >= 0) && (block_stop > total)) { | 6031 } else if ((total >= 0) && (block_stop > total)) { |
| 5923 m_element_size = total - m_element_start; | 6032 m_element_size = total - m_element_start; |
| 5924 pos = total; | 6033 pos = total; |
| 5925 break; | 6034 break; |
| 5926 } else if (block_stop > avail) { | 6035 } else if (block_stop > avail) { |
| 5927 len = static_cast<long>(size); | 6036 len = static_cast<long>(size); |
| 5928 return E_BUFFER_NOT_FULL; | 6037 return E_BUFFER_NOT_FULL; |
| 5929 } | 6038 } |
| 5930 | 6039 |
| 5931 Cluster* const this_ = const_cast<Cluster*>(this); | 6040 Cluster* const this_ = const_cast<Cluster*>(this); |
| 5932 | 6041 |
| 5933 if (id == 0x20) // BlockGroup | 6042 if (id == mkvmuxer::kMkvBlockGroup) |
| 5934 return this_->ParseBlockGroup(size, pos, len); | 6043 return this_->ParseBlockGroup(size, pos, len); |
| 5935 | 6044 |
| 5936 if (id == 0x23) // SimpleBlock | 6045 if (id == mkvmuxer::kMkvSimpleBlock) |
| 5937 return this_->ParseSimpleBlock(size, pos, len); | 6046 return this_->ParseSimpleBlock(size, pos, len); |
| 5938 | 6047 |
| 5939 pos += size; // consume payload | 6048 pos += size; // consume payload |
| 5940 assert((cluster_stop < 0) || (pos <= cluster_stop)); | 6049 if (cluster_stop >= 0 && pos > cluster_stop) |
| 6050 return E_FILE_FORMAT_INVALID; |
| 5941 } | 6051 } |
| 5942 | 6052 |
| 5943 assert(m_element_size > 0); | 6053 if (m_element_size < 1) |
| 6054 return E_FILE_FORMAT_INVALID; |
| 5944 | 6055 |
| 5945 m_pos = pos; | 6056 m_pos = pos; |
| 5946 assert((cluster_stop < 0) || (m_pos <= cluster_stop)); | 6057 if (cluster_stop >= 0 && m_pos > cluster_stop) |
| 6058 return E_FILE_FORMAT_INVALID; |
| 5947 | 6059 |
| 5948 if (m_entries_count > 0) { | 6060 if (m_entries_count > 0) { |
| 5949 const long idx = m_entries_count - 1; | 6061 const long idx = m_entries_count - 1; |
| 5950 | 6062 |
| 5951 const BlockEntry* const pLast = m_entries[idx]; | 6063 const BlockEntry* const pLast = m_entries[idx]; |
| 5952 assert(pLast); | 6064 if (pLast == NULL) |
| 6065 return E_PARSE_FAILED; |
| 5953 | 6066 |
| 5954 const Block* const pBlock = pLast->GetBlock(); | 6067 const Block* const pBlock = pLast->GetBlock(); |
| 5955 assert(pBlock); | 6068 if (pBlock == NULL) |
| 6069 return E_PARSE_FAILED; |
| 5956 | 6070 |
| 5957 const long long start = pBlock->m_start; | 6071 const long long start = pBlock->m_start; |
| 5958 | 6072 |
| 5959 if ((total >= 0) && (start > total)) | 6073 if ((total >= 0) && (start > total)) |
| 5960 return -1; // defend against trucated stream | 6074 return E_PARSE_FAILED; // defend against trucated stream |
| 5961 | 6075 |
| 5962 const long long size = pBlock->m_size; | 6076 const long long size = pBlock->m_size; |
| 5963 | 6077 |
| 5964 const long long stop = start + size; | 6078 const long long stop = start + size; |
| 5965 assert((cluster_stop < 0) || (stop <= cluster_stop)); | 6079 if (cluster_stop >= 0 && stop > cluster_stop) |
| 6080 return E_FILE_FORMAT_INVALID; |
| 5966 | 6081 |
| 5967 if ((total >= 0) && (stop > total)) | 6082 if ((total >= 0) && (stop > total)) |
| 5968 return -1; // defend against trucated stream | 6083 return E_PARSE_FAILED; // defend against trucated stream |
| 5969 } | 6084 } |
| 5970 | 6085 |
| 5971 return 1; // no more entries | 6086 return 1; // no more entries |
| 5972 } | 6087 } |
| 5973 | 6088 |
| 5974 long Cluster::ParseSimpleBlock(long long block_size, long long& pos, | 6089 long Cluster::ParseSimpleBlock(long long block_size, long long& pos, |
| 5975 long& len) { | 6090 long& len) { |
| 5976 const long long block_start = pos; | 6091 const long long block_start = pos; |
| 5977 const long long block_stop = pos + block_size; | 6092 const long long block_stop = pos + block_size; |
| 5978 | 6093 |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6051 if (pos >= block_stop) | 6166 if (pos >= block_stop) |
| 6052 return E_FILE_FORMAT_INVALID; | 6167 return E_FILE_FORMAT_INVALID; |
| 6053 | 6168 |
| 6054 const int lacing = int(flags & 0x06) >> 1; | 6169 const int lacing = int(flags & 0x06) >> 1; |
| 6055 | 6170 |
| 6056 if ((lacing != 0) && (block_stop > avail)) { | 6171 if ((lacing != 0) && (block_stop > avail)) { |
| 6057 len = static_cast<long>(block_stop - pos); | 6172 len = static_cast<long>(block_stop - pos); |
| 6058 return E_BUFFER_NOT_FULL; | 6173 return E_BUFFER_NOT_FULL; |
| 6059 } | 6174 } |
| 6060 | 6175 |
| 6061 status = CreateBlock(0x23, // simple block id | 6176 status = CreateBlock(mkvmuxer::kMkvSimpleBlock, |
| 6062 block_start, block_size, | 6177 block_start, block_size, |
| 6063 0); // DiscardPadding | 6178 0); // DiscardPadding |
| 6064 | 6179 |
| 6065 if (status != 0) | 6180 if (status != 0) |
| 6066 return status; | 6181 return status; |
| 6067 | 6182 |
| 6068 m_pos = block_stop; | 6183 m_pos = block_stop; |
| 6069 | 6184 |
| 6070 return 0; // success | 6185 return 0; // success |
| 6071 } | 6186 } |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6111 | 6226 |
| 6112 if (result > 0) // weird | 6227 if (result > 0) // weird |
| 6113 return E_BUFFER_NOT_FULL; | 6228 return E_BUFFER_NOT_FULL; |
| 6114 | 6229 |
| 6115 if ((pos + len) > payload_stop) | 6230 if ((pos + len) > payload_stop) |
| 6116 return E_FILE_FORMAT_INVALID; | 6231 return E_FILE_FORMAT_INVALID; |
| 6117 | 6232 |
| 6118 if ((pos + len) > avail) | 6233 if ((pos + len) > avail) |
| 6119 return E_BUFFER_NOT_FULL; | 6234 return E_BUFFER_NOT_FULL; |
| 6120 | 6235 |
| 6121 const long long id = ReadUInt(pReader, pos, len); | 6236 const long long id = ReadID(pReader, pos, len); |
| 6122 | 6237 |
| 6123 if (id < 0) // error | 6238 if (id < 0) // error |
| 6124 return static_cast<long>(id); | 6239 return static_cast<long>(id); |
| 6125 | 6240 |
| 6126 if (id == 0) // not a value ID | 6241 if (id == 0) // not a valid ID |
| 6127 return E_FILE_FORMAT_INVALID; | 6242 return E_FILE_FORMAT_INVALID; |
| 6128 | 6243 |
| 6129 pos += len; // consume ID field | 6244 pos += len; // consume ID field |
| 6130 | 6245 |
| 6131 // Parse Size | 6246 // Parse Size |
| 6132 | 6247 |
| 6133 if ((pos + 1) > avail) { | 6248 if ((pos + 1) > avail) { |
| 6134 len = 1; | 6249 len = 1; |
| 6135 return E_BUFFER_NOT_FULL; | 6250 return E_BUFFER_NOT_FULL; |
| 6136 } | 6251 } |
| (...skipping 25 matching lines...) Expand all Loading... |
| 6162 return E_FILE_FORMAT_INVALID; | 6277 return E_FILE_FORMAT_INVALID; |
| 6163 | 6278 |
| 6164 if (size == 0) // weird | 6279 if (size == 0) // weird |
| 6165 continue; | 6280 continue; |
| 6166 | 6281 |
| 6167 const long long unknown_size = (1LL << (7 * len)) - 1; | 6282 const long long unknown_size = (1LL << (7 * len)) - 1; |
| 6168 | 6283 |
| 6169 if (size == unknown_size) | 6284 if (size == unknown_size) |
| 6170 return E_FILE_FORMAT_INVALID; | 6285 return E_FILE_FORMAT_INVALID; |
| 6171 | 6286 |
| 6172 if (id == 0x35A2) { // DiscardPadding | 6287 if (id == mkvmuxer::kMkvDiscardPadding) { |
| 6173 status = UnserializeInt(pReader, pos, size, discard_padding); | 6288 status = UnserializeInt(pReader, pos, size, discard_padding); |
| 6174 | 6289 |
| 6175 if (status < 0) // error | 6290 if (status < 0) // error |
| 6176 return status; | 6291 return status; |
| 6177 } | 6292 } |
| 6178 | 6293 |
| 6179 if (id != 0x21) { // sub-part of BlockGroup is not a Block | 6294 if (id != mkvmuxer::kMkvBlock) { |
| 6180 pos += size; // consume sub-part of block group | 6295 pos += size; // consume sub-part of block group |
| 6181 | 6296 |
| 6182 if (pos > payload_stop) | 6297 if (pos > payload_stop) |
| 6183 return E_FILE_FORMAT_INVALID; | 6298 return E_FILE_FORMAT_INVALID; |
| 6184 | 6299 |
| 6185 continue; | 6300 continue; |
| 6186 } | 6301 } |
| 6187 | 6302 |
| 6188 const long long block_stop = pos + size; | 6303 const long long block_stop = pos + size; |
| 6189 | 6304 |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6255 return E_FILE_FORMAT_INVALID; | 6370 return E_FILE_FORMAT_INVALID; |
| 6256 | 6371 |
| 6257 const int lacing = int(flags & 0x06) >> 1; | 6372 const int lacing = int(flags & 0x06) >> 1; |
| 6258 | 6373 |
| 6259 if ((lacing != 0) && (block_stop > avail)) { | 6374 if ((lacing != 0) && (block_stop > avail)) { |
| 6260 len = static_cast<long>(block_stop - pos); | 6375 len = static_cast<long>(block_stop - pos); |
| 6261 return E_BUFFER_NOT_FULL; | 6376 return E_BUFFER_NOT_FULL; |
| 6262 } | 6377 } |
| 6263 | 6378 |
| 6264 pos = block_stop; // consume block-part of block group | 6379 pos = block_stop; // consume block-part of block group |
| 6265 assert(pos <= payload_stop); | 6380 if (pos > payload_stop) |
| 6381 return E_FILE_FORMAT_INVALID; |
| 6266 } | 6382 } |
| 6267 | 6383 |
| 6268 assert(pos == payload_stop); | 6384 if (pos != payload_stop) |
| 6385 return E_FILE_FORMAT_INVALID; |
| 6269 | 6386 |
| 6270 status = CreateBlock(0x20, // BlockGroup ID | 6387 status = CreateBlock(mkvmuxer::kMkvBlockGroup, |
| 6271 payload_start, payload_size, discard_padding); | 6388 payload_start, payload_size, discard_padding); |
| 6272 if (status != 0) | 6389 if (status != 0) |
| 6273 return status; | 6390 return status; |
| 6274 | 6391 |
| 6275 m_pos = payload_stop; | 6392 m_pos = payload_stop; |
| 6276 | 6393 |
| 6277 return 0; // success | 6394 return 0; // success |
| 6278 } | 6395 } |
| 6279 | 6396 |
| 6280 long Cluster::GetEntry(long index, const mkvparser::BlockEntry*& pEntry) const { | 6397 long Cluster::GetEntry(long index, const mkvparser::BlockEntry*& pEntry) const { |
| (...skipping 22 matching lines...) Expand all Loading... |
| 6303 return E_BUFFER_NOT_FULL; // underflow | 6420 return E_BUFFER_NOT_FULL; // underflow |
| 6304 | 6421 |
| 6305 const long long element_stop = m_element_start + m_element_size; | 6422 const long long element_stop = m_element_start + m_element_size; |
| 6306 | 6423 |
| 6307 if (m_pos >= element_stop) | 6424 if (m_pos >= element_stop) |
| 6308 return 0; // nothing left to parse | 6425 return 0; // nothing left to parse |
| 6309 | 6426 |
| 6310 return E_BUFFER_NOT_FULL; // underflow, since more remains to be parsed | 6427 return E_BUFFER_NOT_FULL; // underflow, since more remains to be parsed |
| 6311 } | 6428 } |
| 6312 | 6429 |
| 6313 Cluster* Cluster::Create(Segment* pSegment, long idx, long long off) | 6430 Cluster* Cluster::Create(Segment* pSegment, long idx, long long off) { |
| 6314 // long long element_size) | 6431 if (!pSegment || off < 0) |
| 6315 { | 6432 return NULL; |
| 6316 assert(pSegment); | |
| 6317 assert(off >= 0); | |
| 6318 | 6433 |
| 6319 const long long element_start = pSegment->m_start + off; | 6434 const long long element_start = pSegment->m_start + off; |
| 6320 | 6435 |
| 6321 Cluster* const pCluster = new Cluster(pSegment, idx, element_start); | 6436 Cluster* const pCluster = |
| 6322 // element_size); | 6437 new (std::nothrow) Cluster(pSegment, idx, element_start); |
| 6323 assert(pCluster); | |
| 6324 | 6438 |
| 6325 return pCluster; | 6439 return pCluster; |
| 6326 } | 6440 } |
| 6327 | 6441 |
| 6328 Cluster::Cluster() | 6442 Cluster::Cluster() |
| 6329 : m_pSegment(NULL), | 6443 : m_pSegment(NULL), |
| 6330 m_element_start(0), | 6444 m_element_start(0), |
| 6331 m_index(0), | 6445 m_index(0), |
| 6332 m_pos(0), | 6446 m_pos(0), |
| 6333 m_element_size(0), | 6447 m_element_size(0), |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6424 | 6538 |
| 6425 if ((segment_stop >= 0) && ((pos + len) > segment_stop)) | 6539 if ((segment_stop >= 0) && ((pos + len) > segment_stop)) |
| 6426 return E_FILE_FORMAT_INVALID; | 6540 return E_FILE_FORMAT_INVALID; |
| 6427 | 6541 |
| 6428 if ((total >= 0) && ((pos + len) > total)) | 6542 if ((total >= 0) && ((pos + len) > total)) |
| 6429 return 0; | 6543 return 0; |
| 6430 | 6544 |
| 6431 if ((pos + len) > avail) | 6545 if ((pos + len) > avail) |
| 6432 return E_BUFFER_NOT_FULL; | 6546 return E_BUFFER_NOT_FULL; |
| 6433 | 6547 |
| 6434 const long long id = ReadUInt(pReader, pos, len); | 6548 const long long id = ReadID(pReader, pos, len); |
| 6435 | 6549 |
| 6436 if (id < 0) // error | 6550 if (id < 0) // error |
| 6437 return static_cast<long>(id); | 6551 return static_cast<long>(id); |
| 6438 | 6552 |
| 6439 if (id != 0x0F43B675) // weird: not cluster ID | 6553 if (id != mkvmuxer::kMkvCluster) |
| 6440 return -1; // generic error | 6554 return E_PARSE_FAILED; |
| 6441 | 6555 |
| 6442 pos += len; // consume Cluster ID field | 6556 pos += len; // consume Cluster ID field |
| 6443 | 6557 |
| 6444 // read size field | 6558 // read size field |
| 6445 | 6559 |
| 6446 if ((pos + 1) > avail) { | 6560 if ((pos + 1) > avail) { |
| 6447 len = 1; | 6561 len = 1; |
| 6448 return E_BUFFER_NOT_FULL; | 6562 return E_BUFFER_NOT_FULL; |
| 6449 } | 6563 } |
| 6450 | 6564 |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6508 | 6622 |
| 6509 if (result > 0) // need more data | 6623 if (result > 0) // need more data |
| 6510 return E_BUFFER_NOT_FULL; | 6624 return E_BUFFER_NOT_FULL; |
| 6511 | 6625 |
| 6512 if ((cluster_stop >= 0) && ((pos + len) > cluster_stop)) | 6626 if ((cluster_stop >= 0) && ((pos + len) > cluster_stop)) |
| 6513 return E_FILE_FORMAT_INVALID; | 6627 return E_FILE_FORMAT_INVALID; |
| 6514 | 6628 |
| 6515 if ((pos + len) > avail) | 6629 if ((pos + len) > avail) |
| 6516 return E_BUFFER_NOT_FULL; | 6630 return E_BUFFER_NOT_FULL; |
| 6517 | 6631 |
| 6518 const long long id = ReadUInt(pReader, pos, len); | 6632 const long long id = ReadID(pReader, pos, len); |
| 6519 | 6633 |
| 6520 if (id < 0) // error | 6634 if (id < 0) // error |
| 6521 return static_cast<long>(id); | 6635 return static_cast<long>(id); |
| 6522 | 6636 |
| 6523 // This is the distinguished set of ID's we use to determine | 6637 // This is the distinguished set of ID's we use to determine |
| 6524 // that we have exhausted the sub-element's inside the cluster | 6638 // that we have exhausted the sub-element's inside the cluster |
| 6525 // whose ID we parsed earlier. | 6639 // whose ID we parsed earlier. |
| 6526 | 6640 |
| 6527 if (id == 0x0F43B675) // Cluster ID | 6641 if (id == mkvmuxer::kMkvCluster) |
| 6528 return 0; // no entries found | 6642 return 0; // no entries found |
| 6529 | 6643 |
| 6530 if (id == 0x0C53BB6B) // Cues ID | 6644 if (id == mkvmuxer::kMkvCues) |
| 6531 return 0; // no entries found | 6645 return 0; // no entries found |
| 6532 | 6646 |
| 6533 pos += len; // consume id field | 6647 pos += len; // consume id field |
| 6534 | 6648 |
| 6535 if ((cluster_stop >= 0) && (pos >= cluster_stop)) | 6649 if ((cluster_stop >= 0) && (pos >= cluster_stop)) |
| 6536 return E_FILE_FORMAT_INVALID; | 6650 return E_FILE_FORMAT_INVALID; |
| 6537 | 6651 |
| 6538 // read size field | 6652 // read size field |
| 6539 | 6653 |
| 6540 if ((pos + 1) > avail) { | 6654 if ((pos + 1) > avail) { |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6572 continue; | 6686 continue; |
| 6573 | 6687 |
| 6574 const long long unknown_size = (1LL << (7 * len)) - 1; | 6688 const long long unknown_size = (1LL << (7 * len)) - 1; |
| 6575 | 6689 |
| 6576 if (size == unknown_size) | 6690 if (size == unknown_size) |
| 6577 return E_FILE_FORMAT_INVALID; // not supported inside cluster | 6691 return E_FILE_FORMAT_INVALID; // not supported inside cluster |
| 6578 | 6692 |
| 6579 if ((cluster_stop >= 0) && ((pos + size) > cluster_stop)) | 6693 if ((cluster_stop >= 0) && ((pos + size) > cluster_stop)) |
| 6580 return E_FILE_FORMAT_INVALID; | 6694 return E_FILE_FORMAT_INVALID; |
| 6581 | 6695 |
| 6582 if (id == 0x20) // BlockGroup ID | 6696 if (id == mkvmuxer::kMkvBlockGroup) |
| 6583 return 1; // have at least one entry | 6697 return 1; // have at least one entry |
| 6584 | 6698 |
| 6585 if (id == 0x23) // SimpleBlock ID | 6699 if (id == mkvmuxer::kMkvSimpleBlock) |
| 6586 return 1; // have at least one entry | 6700 return 1; // have at least one entry |
| 6587 | 6701 |
| 6588 pos += size; // consume payload | 6702 pos += size; // consume payload |
| 6589 assert((cluster_stop < 0) || (pos <= cluster_stop)); | 6703 if (cluster_stop >= 0 && pos > cluster_stop) |
| 6704 return E_FILE_FORMAT_INVALID; |
| 6590 } | 6705 } |
| 6591 } | 6706 } |
| 6592 | 6707 |
| 6593 long long Cluster::GetTimeCode() const { | 6708 long long Cluster::GetTimeCode() const { |
| 6594 long long pos; | 6709 long long pos; |
| 6595 long len; | 6710 long len; |
| 6596 | 6711 |
| 6597 const long status = Load(pos, len); | 6712 const long status = Load(pos, len); |
| 6598 | 6713 |
| 6599 if (status < 0) // error | 6714 if (status < 0) // error |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6649 | 6764 |
| 6650 const Block* const pBlock = pEntry->GetBlock(); | 6765 const Block* const pBlock = pEntry->GetBlock(); |
| 6651 assert(pBlock); | 6766 assert(pBlock); |
| 6652 | 6767 |
| 6653 return pBlock->GetTime(this); | 6768 return pBlock->GetTime(this); |
| 6654 } | 6769 } |
| 6655 | 6770 |
| 6656 long Cluster::CreateBlock(long long id, | 6771 long Cluster::CreateBlock(long long id, |
| 6657 long long pos, // absolute pos of payload | 6772 long long pos, // absolute pos of payload |
| 6658 long long size, long long discard_padding) { | 6773 long long size, long long discard_padding) { |
| 6659 assert((id == 0x20) || (id == 0x23)); // BlockGroup or SimpleBlock | 6774 if (id != mkvmuxer::kMkvBlockGroup && id != mkvmuxer::kMkvSimpleBlock) |
| 6775 return E_PARSE_FAILED; |
| 6660 | 6776 |
| 6661 if (m_entries_count < 0) { // haven't parsed anything yet | 6777 if (m_entries_count < 0) { // haven't parsed anything yet |
| 6662 assert(m_entries == NULL); | 6778 assert(m_entries == NULL); |
| 6663 assert(m_entries_size == 0); | 6779 assert(m_entries_size == 0); |
| 6664 | 6780 |
| 6665 m_entries_size = 1024; | 6781 m_entries_size = 1024; |
| 6666 m_entries = new BlockEntry*[m_entries_size]; | 6782 m_entries = new (std::nothrow) BlockEntry*[m_entries_size]; |
| 6783 if (m_entries == NULL) |
| 6784 return -1; |
| 6667 | 6785 |
| 6668 m_entries_count = 0; | 6786 m_entries_count = 0; |
| 6669 } else { | 6787 } else { |
| 6670 assert(m_entries); | 6788 assert(m_entries); |
| 6671 assert(m_entries_size > 0); | 6789 assert(m_entries_size > 0); |
| 6672 assert(m_entries_count <= m_entries_size); | 6790 assert(m_entries_count <= m_entries_size); |
| 6673 | 6791 |
| 6674 if (m_entries_count >= m_entries_size) { | 6792 if (m_entries_count >= m_entries_size) { |
| 6675 const long entries_size = 2 * m_entries_size; | 6793 const long entries_size = 2 * m_entries_size; |
| 6676 | 6794 |
| 6677 BlockEntry** const entries = new BlockEntry*[entries_size]; | 6795 BlockEntry** const entries = new (std::nothrow) BlockEntry*[entries_size]; |
| 6678 assert(entries); | 6796 if (entries == NULL) |
| 6797 return -1; |
| 6679 | 6798 |
| 6680 BlockEntry** src = m_entries; | 6799 BlockEntry** src = m_entries; |
| 6681 BlockEntry** const src_end = src + m_entries_count; | 6800 BlockEntry** const src_end = src + m_entries_count; |
| 6682 | 6801 |
| 6683 BlockEntry** dst = entries; | 6802 BlockEntry** dst = entries; |
| 6684 | 6803 |
| 6685 while (src != src_end) | 6804 while (src != src_end) |
| 6686 *dst++ = *src++; | 6805 *dst++ = *src++; |
| 6687 | 6806 |
| 6688 delete[] m_entries; | 6807 delete[] m_entries; |
| 6689 | 6808 |
| 6690 m_entries = entries; | 6809 m_entries = entries; |
| 6691 m_entries_size = entries_size; | 6810 m_entries_size = entries_size; |
| 6692 } | 6811 } |
| 6693 } | 6812 } |
| 6694 | 6813 |
| 6695 if (id == 0x20) // BlockGroup ID | 6814 if (id == mkvmuxer::kMkvBlockGroup) |
| 6696 return CreateBlockGroup(pos, size, discard_padding); | 6815 return CreateBlockGroup(pos, size, discard_padding); |
| 6697 else // SimpleBlock ID | 6816 else |
| 6698 return CreateSimpleBlock(pos, size); | 6817 return CreateSimpleBlock(pos, size); |
| 6699 } | 6818 } |
| 6700 | 6819 |
| 6701 long Cluster::CreateBlockGroup(long long start_offset, long long size, | 6820 long Cluster::CreateBlockGroup(long long start_offset, long long size, |
| 6702 long long discard_padding) { | 6821 long long discard_padding) { |
| 6703 assert(m_entries); | 6822 assert(m_entries); |
| 6704 assert(m_entries_size > 0); | 6823 assert(m_entries_size > 0); |
| 6705 assert(m_entries_count >= 0); | 6824 assert(m_entries_count >= 0); |
| 6706 assert(m_entries_count < m_entries_size); | 6825 assert(m_entries_count < m_entries_size); |
| 6707 | 6826 |
| (...skipping 10 matching lines...) Expand all Loading... |
| 6718 | 6837 |
| 6719 long long prev = 1; // nonce | 6838 long long prev = 1; // nonce |
| 6720 long long next = 0; // nonce | 6839 long long next = 0; // nonce |
| 6721 long long duration = -1; // really, this is unsigned | 6840 long long duration = -1; // really, this is unsigned |
| 6722 | 6841 |
| 6723 long long bpos = -1; | 6842 long long bpos = -1; |
| 6724 long long bsize = -1; | 6843 long long bsize = -1; |
| 6725 | 6844 |
| 6726 while (pos < stop) { | 6845 while (pos < stop) { |
| 6727 long len; | 6846 long len; |
| 6728 const long long id = ReadUInt(pReader, pos, len); | 6847 const long long id = ReadID(pReader, pos, len); |
| 6729 assert(id >= 0); // TODO | 6848 if (id < 0 || (pos + len) > stop) |
| 6730 assert((pos + len) <= stop); | 6849 return E_FILE_FORMAT_INVALID; |
| 6731 | 6850 |
| 6732 pos += len; // consume ID | 6851 pos += len; // consume ID |
| 6733 | 6852 |
| 6734 const long long size = ReadUInt(pReader, pos, len); | 6853 const long long size = ReadUInt(pReader, pos, len); |
| 6735 assert(size >= 0); // TODO | 6854 assert(size >= 0); // TODO |
| 6736 assert((pos + len) <= stop); | 6855 assert((pos + len) <= stop); |
| 6737 | 6856 |
| 6738 pos += len; // consume size | 6857 pos += len; // consume size |
| 6739 | 6858 |
| 6740 if (id == 0x21) { // Block ID | 6859 if (id == mkvmuxer::kMkvBlock) { |
| 6741 if (bpos < 0) { // Block ID | 6860 if (bpos < 0) { // Block ID |
| 6742 bpos = pos; | 6861 bpos = pos; |
| 6743 bsize = size; | 6862 bsize = size; |
| 6744 } | 6863 } |
| 6745 } else if (id == 0x1B) { // Duration ID | 6864 } else if (id == mkvmuxer::kMkvBlockDuration) { |
| 6746 if (size > 8) | 6865 if (size > 8) |
| 6747 return E_FILE_FORMAT_INVALID; | 6866 return E_FILE_FORMAT_INVALID; |
| 6748 | 6867 |
| 6749 duration = UnserializeUInt(pReader, pos, size); | 6868 duration = UnserializeUInt(pReader, pos, size); |
| 6750 | 6869 |
| 6751 if (duration < 0) | 6870 if (duration < 0) |
| 6752 return E_FILE_FORMAT_INVALID; | 6871 return E_FILE_FORMAT_INVALID; |
| 6753 } else if (id == 0x7B) { // ReferenceBlock | 6872 } else if (id == mkvmuxer::kMkvReferenceBlock) { |
| 6754 if (size > 8 || size <= 0) | 6873 if (size > 8 || size <= 0) |
| 6755 return E_FILE_FORMAT_INVALID; | 6874 return E_FILE_FORMAT_INVALID; |
| 6756 const long size_ = static_cast<long>(size); | 6875 const long size_ = static_cast<long>(size); |
| 6757 | 6876 |
| 6758 long long time; | 6877 long long time; |
| 6759 | 6878 |
| 6760 long status = UnserializeInt(pReader, pos, size_, time); | 6879 long status = UnserializeInt(pReader, pos, size_, time); |
| 6761 assert(status == 0); | 6880 assert(status == 0); |
| 6762 if (status != 0) | 6881 if (status != 0) |
| 6763 return -1; | 6882 return -1; |
| 6764 | 6883 |
| 6765 if (time <= 0) // see note above | 6884 if (time <= 0) // see note above |
| 6766 prev = time; | 6885 prev = time; |
| 6767 else // weird | 6886 else |
| 6768 next = time; | 6887 next = time; |
| 6769 } | 6888 } |
| 6770 | 6889 |
| 6771 pos += size; // consume payload | 6890 pos += size; // consume payload |
| 6772 assert(pos <= stop); | 6891 if (pos > stop) |
| 6892 return E_FILE_FORMAT_INVALID; |
| 6773 } | 6893 } |
| 6774 if (bpos < 0) | 6894 if (bpos < 0) |
| 6775 return E_FILE_FORMAT_INVALID; | 6895 return E_FILE_FORMAT_INVALID; |
| 6776 | 6896 |
| 6777 assert(pos == stop); | 6897 if (pos != stop) |
| 6898 return E_FILE_FORMAT_INVALID; |
| 6778 assert(bsize >= 0); | 6899 assert(bsize >= 0); |
| 6779 | 6900 |
| 6780 const long idx = m_entries_count; | 6901 const long idx = m_entries_count; |
| 6781 | 6902 |
| 6782 BlockEntry** const ppEntry = m_entries + idx; | 6903 BlockEntry** const ppEntry = m_entries + idx; |
| 6783 BlockEntry*& pEntry = *ppEntry; | 6904 BlockEntry*& pEntry = *ppEntry; |
| 6784 | 6905 |
| 6785 pEntry = new (std::nothrow) | 6906 pEntry = new (std::nothrow) |
| 6786 BlockGroup(this, idx, bpos, bsize, prev, next, duration, discard_padding); | 6907 BlockGroup(this, idx, bpos, bsize, prev, next, duration, discard_padding); |
| 6787 | 6908 |
| (...skipping 418 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7206 | 7327 |
| 7207 const int lacing = int(m_flags & 0x06) >> 1; | 7328 const int lacing = int(m_flags & 0x06) >> 1; |
| 7208 | 7329 |
| 7209 ++pos; // consume flags byte | 7330 ++pos; // consume flags byte |
| 7210 | 7331 |
| 7211 if (lacing == 0) { // no lacing | 7332 if (lacing == 0) { // no lacing |
| 7212 if (pos > stop) | 7333 if (pos > stop) |
| 7213 return E_FILE_FORMAT_INVALID; | 7334 return E_FILE_FORMAT_INVALID; |
| 7214 | 7335 |
| 7215 m_frame_count = 1; | 7336 m_frame_count = 1; |
| 7216 m_frames = new Frame[m_frame_count]; | 7337 m_frames = new (std::nothrow) Frame[m_frame_count]; |
| 7338 if (m_frames == NULL) |
| 7339 return -1; |
| 7217 | 7340 |
| 7218 Frame& f = m_frames[0]; | 7341 Frame& f = m_frames[0]; |
| 7219 f.pos = pos; | 7342 f.pos = pos; |
| 7220 | 7343 |
| 7221 const long long frame_size = stop - pos; | 7344 const long long frame_size = stop - pos; |
| 7222 | 7345 |
| 7223 if (frame_size > LONG_MAX || frame_size <= 0) | 7346 if (frame_size > LONG_MAX || frame_size <= 0) |
| 7224 return E_FILE_FORMAT_INVALID; | 7347 return E_FILE_FORMAT_INVALID; |
| 7225 | 7348 |
| 7226 f.len = static_cast<long>(frame_size); | 7349 f.len = static_cast<long>(frame_size); |
| 7227 | 7350 |
| 7228 return 0; // success | 7351 return 0; // success |
| 7229 } | 7352 } |
| 7230 | 7353 |
| 7231 if (pos >= stop) | 7354 if (pos >= stop) |
| 7232 return E_FILE_FORMAT_INVALID; | 7355 return E_FILE_FORMAT_INVALID; |
| 7233 | 7356 |
| 7234 unsigned char biased_count; | 7357 unsigned char biased_count; |
| 7235 | 7358 |
| 7236 status = pReader->Read(pos, 1, &biased_count); | 7359 status = pReader->Read(pos, 1, &biased_count); |
| 7237 | 7360 |
| 7238 if (status) | 7361 if (status) |
| 7239 return E_FILE_FORMAT_INVALID; | 7362 return E_FILE_FORMAT_INVALID; |
| 7240 | 7363 |
| 7241 ++pos; // consume frame count | 7364 ++pos; // consume frame count |
| 7242 assert(pos <= stop); | 7365 if (pos > stop) |
| 7366 return E_FILE_FORMAT_INVALID; |
| 7243 | 7367 |
| 7244 m_frame_count = int(biased_count) + 1; | 7368 m_frame_count = int(biased_count) + 1; |
| 7245 | 7369 |
| 7246 m_frames = new Frame[m_frame_count]; | 7370 m_frames = new (std::nothrow) Frame[m_frame_count]; |
| 7247 assert(m_frames); | 7371 if (m_frames == NULL) |
| 7372 return -1; |
| 7373 |
| 7374 if (!m_frames) |
| 7375 return E_FILE_FORMAT_INVALID; |
| 7248 | 7376 |
| 7249 if (lacing == 1) { // Xiph | 7377 if (lacing == 1) { // Xiph |
| 7250 Frame* pf = m_frames; | 7378 Frame* pf = m_frames; |
| 7251 Frame* const pf_end = pf + m_frame_count; | 7379 Frame* const pf_end = pf + m_frame_count; |
| 7252 | 7380 |
| 7253 long size = 0; | 7381 long long size = 0; |
| 7254 int frame_count = m_frame_count; | 7382 int frame_count = m_frame_count; |
| 7255 | 7383 |
| 7256 while (frame_count > 1) { | 7384 while (frame_count > 1) { |
| 7257 long frame_size = 0; | 7385 long frame_size = 0; |
| 7258 | 7386 |
| 7259 for (;;) { | 7387 for (;;) { |
| 7260 unsigned char val; | 7388 unsigned char val; |
| 7261 | 7389 |
| 7262 if (pos >= stop) | 7390 if (pos >= stop) |
| 7263 return E_FILE_FORMAT_INVALID; | 7391 return E_FILE_FORMAT_INVALID; |
| 7264 | 7392 |
| 7265 status = pReader->Read(pos, 1, &val); | 7393 status = pReader->Read(pos, 1, &val); |
| 7266 | 7394 |
| 7267 if (status) | 7395 if (status) |
| 7268 return E_FILE_FORMAT_INVALID; | 7396 return E_FILE_FORMAT_INVALID; |
| 7269 | 7397 |
| 7270 ++pos; // consume xiph size byte | 7398 ++pos; // consume xiph size byte |
| 7271 | 7399 |
| 7272 frame_size += val; | 7400 frame_size += val; |
| 7273 | 7401 |
| 7274 if (val < 255) | 7402 if (val < 255) |
| 7275 break; | 7403 break; |
| 7276 } | 7404 } |
| 7277 | 7405 |
| 7278 Frame& f = *pf++; | 7406 Frame& f = *pf++; |
| 7279 assert(pf < pf_end); | 7407 assert(pf < pf_end); |
| 7408 if (pf >= pf_end) |
| 7409 return E_FILE_FORMAT_INVALID; |
| 7280 | 7410 |
| 7281 f.pos = 0; // patch later | 7411 f.pos = 0; // patch later |
| 7282 | 7412 |
| 7283 if (frame_size <= 0) | 7413 if (frame_size <= 0) |
| 7284 return E_FILE_FORMAT_INVALID; | 7414 return E_FILE_FORMAT_INVALID; |
| 7285 | 7415 |
| 7286 f.len = frame_size; | 7416 f.len = frame_size; |
| 7287 size += frame_size; // contribution of this frame | 7417 size += frame_size; // contribution of this frame |
| 7288 | 7418 |
| 7289 --frame_count; | 7419 --frame_count; |
| 7290 } | 7420 } |
| 7291 | 7421 |
| 7292 assert(pf < pf_end); | 7422 if (pf >= pf_end || pos > stop) |
| 7293 assert(pos <= stop); | 7423 return E_FILE_FORMAT_INVALID; |
| 7294 | 7424 |
| 7295 { | 7425 { |
| 7296 Frame& f = *pf++; | 7426 Frame& f = *pf++; |
| 7297 | 7427 |
| 7298 if (pf != pf_end) | 7428 if (pf != pf_end) |
| 7299 return E_FILE_FORMAT_INVALID; | 7429 return E_FILE_FORMAT_INVALID; |
| 7300 | 7430 |
| 7301 f.pos = 0; // patch later | 7431 f.pos = 0; // patch later |
| 7302 | 7432 |
| 7303 const long long total_size = stop - pos; | 7433 const long long total_size = stop - pos; |
| 7304 | 7434 |
| 7305 if (total_size < size) | 7435 if (total_size < size) |
| 7306 return E_FILE_FORMAT_INVALID; | 7436 return E_FILE_FORMAT_INVALID; |
| 7307 | 7437 |
| 7308 const long long frame_size = total_size - size; | 7438 const long long frame_size = total_size - size; |
| 7309 | 7439 |
| 7310 if (frame_size > LONG_MAX || frame_size <= 0) | 7440 if (frame_size > LONG_MAX || frame_size <= 0) |
| 7311 return E_FILE_FORMAT_INVALID; | 7441 return E_FILE_FORMAT_INVALID; |
| 7312 | 7442 |
| 7313 f.len = static_cast<long>(frame_size); | 7443 f.len = static_cast<long>(frame_size); |
| 7314 } | 7444 } |
| 7315 | 7445 |
| 7316 pf = m_frames; | 7446 pf = m_frames; |
| 7317 while (pf != pf_end) { | 7447 while (pf != pf_end) { |
| 7318 Frame& f = *pf++; | 7448 Frame& f = *pf++; |
| 7319 assert((pos + f.len) <= stop); | 7449 assert((pos + f.len) <= stop); |
| 7320 | 7450 |
| 7451 if ((pos + f.len) > stop) |
| 7452 return E_FILE_FORMAT_INVALID; |
| 7453 |
| 7321 f.pos = pos; | 7454 f.pos = pos; |
| 7322 pos += f.len; | 7455 pos += f.len; |
| 7323 } | 7456 } |
| 7324 | 7457 |
| 7325 assert(pos == stop); | 7458 assert(pos == stop); |
| 7459 if (pos != stop) |
| 7460 return E_FILE_FORMAT_INVALID; |
| 7461 |
| 7326 } else if (lacing == 2) { // fixed-size lacing | 7462 } else if (lacing == 2) { // fixed-size lacing |
| 7327 if (pos >= stop) | 7463 if (pos >= stop) |
| 7328 return E_FILE_FORMAT_INVALID; | 7464 return E_FILE_FORMAT_INVALID; |
| 7329 | 7465 |
| 7330 const long long total_size = stop - pos; | 7466 const long long total_size = stop - pos; |
| 7331 | 7467 |
| 7332 if ((total_size % m_frame_count) != 0) | 7468 if ((total_size % m_frame_count) != 0) |
| 7333 return E_FILE_FORMAT_INVALID; | 7469 return E_FILE_FORMAT_INVALID; |
| 7334 | 7470 |
| 7335 const long long frame_size = total_size / m_frame_count; | 7471 const long long frame_size = total_size / m_frame_count; |
| 7336 | 7472 |
| 7337 if (frame_size > LONG_MAX || frame_size <= 0) | 7473 if (frame_size > LONG_MAX || frame_size <= 0) |
| 7338 return E_FILE_FORMAT_INVALID; | 7474 return E_FILE_FORMAT_INVALID; |
| 7339 | 7475 |
| 7340 Frame* pf = m_frames; | 7476 Frame* pf = m_frames; |
| 7341 Frame* const pf_end = pf + m_frame_count; | 7477 Frame* const pf_end = pf + m_frame_count; |
| 7342 | 7478 |
| 7343 while (pf != pf_end) { | 7479 while (pf != pf_end) { |
| 7344 assert((pos + frame_size) <= stop); | 7480 assert((pos + frame_size) <= stop); |
| 7481 if ((pos + frame_size) > stop) |
| 7482 return E_FILE_FORMAT_INVALID; |
| 7345 | 7483 |
| 7346 Frame& f = *pf++; | 7484 Frame& f = *pf++; |
| 7347 | 7485 |
| 7348 f.pos = pos; | 7486 f.pos = pos; |
| 7349 f.len = static_cast<long>(frame_size); | 7487 f.len = static_cast<long>(frame_size); |
| 7350 | 7488 |
| 7351 pos += frame_size; | 7489 pos += frame_size; |
| 7352 } | 7490 } |
| 7353 | 7491 |
| 7354 assert(pos == stop); | 7492 assert(pos == stop); |
| 7493 if (pos != stop) |
| 7494 return E_FILE_FORMAT_INVALID; |
| 7495 |
| 7355 } else { | 7496 } else { |
| 7356 assert(lacing == 3); // EBML lacing | 7497 assert(lacing == 3); // EBML lacing |
| 7357 | 7498 |
| 7358 if (pos >= stop) | 7499 if (pos >= stop) |
| 7359 return E_FILE_FORMAT_INVALID; | 7500 return E_FILE_FORMAT_INVALID; |
| 7360 | 7501 |
| 7361 long size = 0; | 7502 long long size = 0; |
| 7362 int frame_count = m_frame_count; | 7503 int frame_count = m_frame_count; |
| 7363 | 7504 |
| 7364 long long frame_size = ReadUInt(pReader, pos, len); | 7505 long long frame_size = ReadUInt(pReader, pos, len); |
| 7365 | 7506 |
| 7366 if (frame_size <= 0) | 7507 if (frame_size <= 0) |
| 7367 return E_FILE_FORMAT_INVALID; | 7508 return E_FILE_FORMAT_INVALID; |
| 7368 | 7509 |
| 7369 if (frame_size > LONG_MAX) | 7510 if (frame_size > LONG_MAX) |
| 7370 return E_FILE_FORMAT_INVALID; | 7511 return E_FILE_FORMAT_INVALID; |
| 7371 | 7512 |
| (...skipping 17 matching lines...) Expand all Loading... |
| 7389 size += curr.len; // contribution of this frame | 7530 size += curr.len; // contribution of this frame |
| 7390 } | 7531 } |
| 7391 | 7532 |
| 7392 --frame_count; | 7533 --frame_count; |
| 7393 | 7534 |
| 7394 while (frame_count > 1) { | 7535 while (frame_count > 1) { |
| 7395 if (pos >= stop) | 7536 if (pos >= stop) |
| 7396 return E_FILE_FORMAT_INVALID; | 7537 return E_FILE_FORMAT_INVALID; |
| 7397 | 7538 |
| 7398 assert(pf < pf_end); | 7539 assert(pf < pf_end); |
| 7540 if (pf >= pf_end) |
| 7541 return E_FILE_FORMAT_INVALID; |
| 7542 |
| 7399 | 7543 |
| 7400 const Frame& prev = *pf++; | 7544 const Frame& prev = *pf++; |
| 7401 assert(prev.len == frame_size); | 7545 assert(prev.len == frame_size); |
| 7402 if (prev.len != frame_size) | 7546 if (prev.len != frame_size) |
| 7403 return E_FILE_FORMAT_INVALID; | 7547 return E_FILE_FORMAT_INVALID; |
| 7404 | 7548 |
| 7405 assert(pf < pf_end); | 7549 assert(pf < pf_end); |
| 7550 if (pf >= pf_end) |
| 7551 return E_FILE_FORMAT_INVALID; |
| 7406 | 7552 |
| 7407 Frame& curr = *pf; | 7553 Frame& curr = *pf; |
| 7408 | 7554 |
| 7409 curr.pos = 0; // patch later | 7555 curr.pos = 0; // patch later |
| 7410 | 7556 |
| 7411 const long long delta_size_ = ReadUInt(pReader, pos, len); | 7557 const long long delta_size_ = ReadUInt(pReader, pos, len); |
| 7412 | 7558 |
| 7413 if (delta_size_ < 0) | 7559 if (delta_size_ < 0) |
| 7414 return E_FILE_FORMAT_INVALID; | 7560 return E_FILE_FORMAT_INVALID; |
| 7415 | 7561 |
| 7416 if ((pos + len) > stop) | 7562 if ((pos + len) > stop) |
| 7417 return E_FILE_FORMAT_INVALID; | 7563 return E_FILE_FORMAT_INVALID; |
| 7418 | 7564 |
| 7419 pos += len; // consume length of (delta) size | 7565 pos += len; // consume length of (delta) size |
| 7420 assert(pos <= stop); | 7566 if (pos > stop) |
| 7567 return E_FILE_FORMAT_INVALID; |
| 7421 | 7568 |
| 7422 const int exp = 7 * len - 1; | 7569 const int exp = 7 * len - 1; |
| 7423 const long long bias = (1LL << exp) - 1LL; | 7570 const long long bias = (1LL << exp) - 1LL; |
| 7424 const long long delta_size = delta_size_ - bias; | 7571 const long long delta_size = delta_size_ - bias; |
| 7425 | 7572 |
| 7426 frame_size += delta_size; | 7573 frame_size += delta_size; |
| 7427 | 7574 |
| 7428 if (frame_size <= 0) | 7575 if (frame_size <= 0) |
| 7429 return E_FILE_FORMAT_INVALID; | 7576 return E_FILE_FORMAT_INVALID; |
| 7430 | 7577 |
| 7431 if (frame_size > LONG_MAX) | 7578 if (frame_size > LONG_MAX) |
| 7432 return E_FILE_FORMAT_INVALID; | 7579 return E_FILE_FORMAT_INVALID; |
| 7433 | 7580 |
| 7434 curr.len = static_cast<long>(frame_size); | 7581 curr.len = static_cast<long>(frame_size); |
| 7435 size += curr.len; // contribution of this frame | 7582 size += curr.len; // contribution of this frame |
| 7436 | 7583 |
| 7437 --frame_count; | 7584 --frame_count; |
| 7438 } | 7585 } |
| 7439 | 7586 |
| 7440 // parse last frame | 7587 // parse last frame |
| 7441 if (frame_count > 0) { | 7588 if (frame_count > 0) { |
| 7442 assert(pos <= stop); | 7589 if (pos > stop || pf >= pf_end) |
| 7443 assert(pf < pf_end); | 7590 return E_FILE_FORMAT_INVALID; |
| 7444 | 7591 |
| 7445 const Frame& prev = *pf++; | 7592 const Frame& prev = *pf++; |
| 7446 assert(prev.len == frame_size); | 7593 assert(prev.len == frame_size); |
| 7447 if (prev.len != frame_size) | 7594 if (prev.len != frame_size) |
| 7448 return E_FILE_FORMAT_INVALID; | 7595 return E_FILE_FORMAT_INVALID; |
| 7449 | 7596 |
| 7450 assert(pf < pf_end); | 7597 if (pf >= pf_end) |
| 7598 return E_FILE_FORMAT_INVALID; |
| 7451 | 7599 |
| 7452 Frame& curr = *pf++; | 7600 Frame& curr = *pf++; |
| 7453 assert(pf == pf_end); | 7601 if (pf != pf_end) |
| 7602 return E_FILE_FORMAT_INVALID; |
| 7454 | 7603 |
| 7455 curr.pos = 0; // patch later | 7604 curr.pos = 0; // patch later |
| 7456 | 7605 |
| 7457 const long long total_size = stop - pos; | 7606 const long long total_size = stop - pos; |
| 7458 | 7607 |
| 7459 if (total_size < size) | 7608 if (total_size < size) |
| 7460 return E_FILE_FORMAT_INVALID; | 7609 return E_FILE_FORMAT_INVALID; |
| 7461 | 7610 |
| 7462 frame_size = total_size - size; | 7611 frame_size = total_size - size; |
| 7463 | 7612 |
| 7464 if (frame_size > LONG_MAX || frame_size <= 0) | 7613 if (frame_size > LONG_MAX || frame_size <= 0) |
| 7465 return E_FILE_FORMAT_INVALID; | 7614 return E_FILE_FORMAT_INVALID; |
| 7466 | 7615 |
| 7467 curr.len = static_cast<long>(frame_size); | 7616 curr.len = static_cast<long>(frame_size); |
| 7468 } | 7617 } |
| 7469 | 7618 |
| 7470 pf = m_frames; | 7619 pf = m_frames; |
| 7471 while (pf != pf_end) { | 7620 while (pf != pf_end) { |
| 7472 Frame& f = *pf++; | 7621 Frame& f = *pf++; |
| 7473 assert((pos + f.len) <= stop); | 7622 assert((pos + f.len) <= stop); |
| 7623 if ((pos + f.len) > stop) |
| 7624 return E_FILE_FORMAT_INVALID; |
| 7474 | 7625 |
| 7475 f.pos = pos; | 7626 f.pos = pos; |
| 7476 pos += f.len; | 7627 pos += f.len; |
| 7477 } | 7628 } |
| 7478 | 7629 |
| 7479 if (pos != stop) | 7630 if (pos != stop) |
| 7480 return E_FILE_FORMAT_INVALID; | 7631 return E_FILE_FORMAT_INVALID; |
| 7481 } | 7632 } |
| 7482 | 7633 |
| 7483 return 0; // success | 7634 return 0; // success |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7549 assert(pReader); | 7700 assert(pReader); |
| 7550 assert(buf); | 7701 assert(buf); |
| 7551 | 7702 |
| 7552 const long status = pReader->Read(pos, len, buf); | 7703 const long status = pReader->Read(pos, len, buf); |
| 7553 return status; | 7704 return status; |
| 7554 } | 7705 } |
| 7555 | 7706 |
| 7556 long long Block::GetDiscardPadding() const { return m_discard_padding; } | 7707 long long Block::GetDiscardPadding() const { return m_discard_padding; } |
| 7557 | 7708 |
| 7558 } // end namespace mkvparser | 7709 } // end namespace mkvparser |
| OLD | NEW |