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 |