xref: /aosp_15_r20/external/libwebm/mkvparser/mkvparser.cc (revision 103e46e4cd4b6efcf6001f23fa8665fb110abf8d)
1*103e46e4SHarish Mahendrakar // Copyright (c) 2012 The WebM project authors. All Rights Reserved.
2*103e46e4SHarish Mahendrakar //
3*103e46e4SHarish Mahendrakar // Use of this source code is governed by a BSD-style license
4*103e46e4SHarish Mahendrakar // that can be found in the LICENSE file in the root of the source
5*103e46e4SHarish Mahendrakar // tree. An additional intellectual property rights grant can be found
6*103e46e4SHarish Mahendrakar // in the file PATENTS.  All contributing project authors may
7*103e46e4SHarish Mahendrakar // be found in the AUTHORS file in the root of the source tree.
8*103e46e4SHarish Mahendrakar #include "mkvparser/mkvparser.h"
9*103e46e4SHarish Mahendrakar 
10*103e46e4SHarish Mahendrakar #if defined(_MSC_VER) && _MSC_VER < 1800
11*103e46e4SHarish Mahendrakar #include <float.h>  // _isnan() / _finite()
12*103e46e4SHarish Mahendrakar #define MSC_COMPAT
13*103e46e4SHarish Mahendrakar #endif
14*103e46e4SHarish Mahendrakar 
15*103e46e4SHarish Mahendrakar #include <cassert>
16*103e46e4SHarish Mahendrakar #include <cfloat>
17*103e46e4SHarish Mahendrakar #include <climits>
18*103e46e4SHarish Mahendrakar #include <cmath>
19*103e46e4SHarish Mahendrakar #include <cstring>
20*103e46e4SHarish Mahendrakar #include <memory>
21*103e46e4SHarish Mahendrakar #include <new>
22*103e46e4SHarish Mahendrakar 
23*103e46e4SHarish Mahendrakar #include "common/webmids.h"
24*103e46e4SHarish Mahendrakar 
25*103e46e4SHarish Mahendrakar namespace mkvparser {
26*103e46e4SHarish Mahendrakar const long long kStringElementSizeLimit = 20 * 1000 * 1000;
27*103e46e4SHarish Mahendrakar const float MasteringMetadata::kValueNotPresent = FLT_MAX;
28*103e46e4SHarish Mahendrakar const long long Colour::kValueNotPresent = LLONG_MAX;
29*103e46e4SHarish Mahendrakar const float Projection::kValueNotPresent = FLT_MAX;
30*103e46e4SHarish Mahendrakar 
31*103e46e4SHarish Mahendrakar #ifdef MSC_COMPAT
isnan(double val)32*103e46e4SHarish Mahendrakar inline bool isnan(double val) { return !!_isnan(val); }
isinf(double val)33*103e46e4SHarish Mahendrakar inline bool isinf(double val) { return !_finite(val); }
34*103e46e4SHarish Mahendrakar #else
isnan(double val)35*103e46e4SHarish Mahendrakar inline bool isnan(double val) { return std::isnan(val); }
isinf(double val)36*103e46e4SHarish Mahendrakar inline bool isinf(double val) { return std::isinf(val); }
37*103e46e4SHarish Mahendrakar #endif  // MSC_COMPAT
38*103e46e4SHarish Mahendrakar 
39*103e46e4SHarish Mahendrakar template <typename Type>
SafeArrayAlloc(unsigned long long num_elements,unsigned long long element_size)40*103e46e4SHarish Mahendrakar Type* SafeArrayAlloc(unsigned long long num_elements,
41*103e46e4SHarish Mahendrakar                      unsigned long long element_size) {
42*103e46e4SHarish Mahendrakar   if (num_elements == 0 || element_size == 0)
43*103e46e4SHarish Mahendrakar     return NULL;
44*103e46e4SHarish Mahendrakar 
45*103e46e4SHarish Mahendrakar   const size_t kMaxAllocSize = 0x80000000;  // 2GiB
46*103e46e4SHarish Mahendrakar   const unsigned long long num_bytes = num_elements * element_size;
47*103e46e4SHarish Mahendrakar   if (element_size > (kMaxAllocSize / num_elements))
48*103e46e4SHarish Mahendrakar     return NULL;
49*103e46e4SHarish Mahendrakar   if (num_bytes != static_cast<size_t>(num_bytes))
50*103e46e4SHarish Mahendrakar     return NULL;
51*103e46e4SHarish Mahendrakar 
52*103e46e4SHarish Mahendrakar   return new (std::nothrow) Type[static_cast<size_t>(num_bytes)];
53*103e46e4SHarish Mahendrakar }
54*103e46e4SHarish Mahendrakar 
GetVersion(int & major,int & minor,int & build,int & revision)55*103e46e4SHarish Mahendrakar void GetVersion(int& major, int& minor, int& build, int& revision) {
56*103e46e4SHarish Mahendrakar   major = 1;
57*103e46e4SHarish Mahendrakar   minor = 1;
58*103e46e4SHarish Mahendrakar   build = 3;
59*103e46e4SHarish Mahendrakar   revision = 0;
60*103e46e4SHarish Mahendrakar }
61*103e46e4SHarish Mahendrakar 
ReadUInt(IMkvReader * pReader,long long pos,long & len)62*103e46e4SHarish Mahendrakar long long ReadUInt(IMkvReader* pReader, long long pos, long& len) {
63*103e46e4SHarish Mahendrakar   if (!pReader || pos < 0)
64*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
65*103e46e4SHarish Mahendrakar 
66*103e46e4SHarish Mahendrakar   len = 1;
67*103e46e4SHarish Mahendrakar   unsigned char b;
68*103e46e4SHarish Mahendrakar   int status = pReader->Read(pos, 1, &b);
69*103e46e4SHarish Mahendrakar 
70*103e46e4SHarish Mahendrakar   if (status < 0)  // error or underflow
71*103e46e4SHarish Mahendrakar     return status;
72*103e46e4SHarish Mahendrakar 
73*103e46e4SHarish Mahendrakar   if (status > 0)  // interpreted as "underflow"
74*103e46e4SHarish Mahendrakar     return E_BUFFER_NOT_FULL;
75*103e46e4SHarish Mahendrakar 
76*103e46e4SHarish Mahendrakar   if (b == 0)  // we can't handle u-int values larger than 8 bytes
77*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
78*103e46e4SHarish Mahendrakar 
79*103e46e4SHarish Mahendrakar   unsigned char m = 0x80;
80*103e46e4SHarish Mahendrakar 
81*103e46e4SHarish Mahendrakar   while (!(b & m)) {
82*103e46e4SHarish Mahendrakar     m >>= 1;
83*103e46e4SHarish Mahendrakar     ++len;
84*103e46e4SHarish Mahendrakar   }
85*103e46e4SHarish Mahendrakar 
86*103e46e4SHarish Mahendrakar   long long result = b & (~m);
87*103e46e4SHarish Mahendrakar   ++pos;
88*103e46e4SHarish Mahendrakar 
89*103e46e4SHarish Mahendrakar   for (int i = 1; i < len; ++i) {
90*103e46e4SHarish Mahendrakar     status = pReader->Read(pos, 1, &b);
91*103e46e4SHarish Mahendrakar 
92*103e46e4SHarish Mahendrakar     if (status < 0) {
93*103e46e4SHarish Mahendrakar       len = 1;
94*103e46e4SHarish Mahendrakar       return status;
95*103e46e4SHarish Mahendrakar     }
96*103e46e4SHarish Mahendrakar 
97*103e46e4SHarish Mahendrakar     if (status > 0) {
98*103e46e4SHarish Mahendrakar       len = 1;
99*103e46e4SHarish Mahendrakar       return E_BUFFER_NOT_FULL;
100*103e46e4SHarish Mahendrakar     }
101*103e46e4SHarish Mahendrakar 
102*103e46e4SHarish Mahendrakar     result <<= 8;
103*103e46e4SHarish Mahendrakar     result |= b;
104*103e46e4SHarish Mahendrakar 
105*103e46e4SHarish Mahendrakar     ++pos;
106*103e46e4SHarish Mahendrakar   }
107*103e46e4SHarish Mahendrakar 
108*103e46e4SHarish Mahendrakar   return result;
109*103e46e4SHarish Mahendrakar }
110*103e46e4SHarish Mahendrakar 
111*103e46e4SHarish Mahendrakar // Reads an EBML ID and returns it.
112*103e46e4SHarish Mahendrakar // An ID must at least 1 byte long, cannot exceed 4, and its value must be
113*103e46e4SHarish Mahendrakar // greater than 0.
114*103e46e4SHarish Mahendrakar // See known EBML values and EBMLMaxIDLength:
115*103e46e4SHarish Mahendrakar // http://www.matroska.org/technical/specs/index.html
116*103e46e4SHarish Mahendrakar // Returns the ID, or a value less than 0 to report an error while reading the
117*103e46e4SHarish Mahendrakar // ID.
ReadID(IMkvReader * pReader,long long pos,long & len)118*103e46e4SHarish Mahendrakar long long ReadID(IMkvReader* pReader, long long pos, long& len) {
119*103e46e4SHarish Mahendrakar   if (pReader == NULL || pos < 0)
120*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
121*103e46e4SHarish Mahendrakar 
122*103e46e4SHarish Mahendrakar   // Read the first byte. The length in bytes of the ID is determined by
123*103e46e4SHarish Mahendrakar   // finding the first set bit in the first byte of the ID.
124*103e46e4SHarish Mahendrakar   unsigned char temp_byte = 0;
125*103e46e4SHarish Mahendrakar   int read_status = pReader->Read(pos, 1, &temp_byte);
126*103e46e4SHarish Mahendrakar 
127*103e46e4SHarish Mahendrakar   if (read_status < 0)
128*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
129*103e46e4SHarish Mahendrakar   else if (read_status > 0)  // No data to read.
130*103e46e4SHarish Mahendrakar     return E_BUFFER_NOT_FULL;
131*103e46e4SHarish Mahendrakar 
132*103e46e4SHarish Mahendrakar   if (temp_byte == 0)  // ID length > 8 bytes; invalid file.
133*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
134*103e46e4SHarish Mahendrakar 
135*103e46e4SHarish Mahendrakar   int bit_pos = 0;
136*103e46e4SHarish Mahendrakar   const int kMaxIdLengthInBytes = 4;
137*103e46e4SHarish Mahendrakar   const int kCheckByte = 0x80;
138*103e46e4SHarish Mahendrakar 
139*103e46e4SHarish Mahendrakar   // Find the first bit that's set.
140*103e46e4SHarish Mahendrakar   bool found_bit = false;
141*103e46e4SHarish Mahendrakar   for (; bit_pos < kMaxIdLengthInBytes; ++bit_pos) {
142*103e46e4SHarish Mahendrakar     if ((kCheckByte >> bit_pos) & temp_byte) {
143*103e46e4SHarish Mahendrakar       found_bit = true;
144*103e46e4SHarish Mahendrakar       break;
145*103e46e4SHarish Mahendrakar     }
146*103e46e4SHarish Mahendrakar   }
147*103e46e4SHarish Mahendrakar 
148*103e46e4SHarish Mahendrakar   if (!found_bit) {
149*103e46e4SHarish Mahendrakar     // The value is too large to be a valid ID.
150*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
151*103e46e4SHarish Mahendrakar   }
152*103e46e4SHarish Mahendrakar 
153*103e46e4SHarish Mahendrakar   // Read the remaining bytes of the ID (if any).
154*103e46e4SHarish Mahendrakar   const int id_length = bit_pos + 1;
155*103e46e4SHarish Mahendrakar   long long ebml_id = temp_byte;
156*103e46e4SHarish Mahendrakar   for (int i = 1; i < id_length; ++i) {
157*103e46e4SHarish Mahendrakar     ebml_id <<= 8;
158*103e46e4SHarish Mahendrakar     read_status = pReader->Read(pos + i, 1, &temp_byte);
159*103e46e4SHarish Mahendrakar 
160*103e46e4SHarish Mahendrakar     if (read_status < 0)
161*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
162*103e46e4SHarish Mahendrakar     else if (read_status > 0)
163*103e46e4SHarish Mahendrakar       return E_BUFFER_NOT_FULL;
164*103e46e4SHarish Mahendrakar 
165*103e46e4SHarish Mahendrakar     ebml_id |= temp_byte;
166*103e46e4SHarish Mahendrakar   }
167*103e46e4SHarish Mahendrakar 
168*103e46e4SHarish Mahendrakar   len = id_length;
169*103e46e4SHarish Mahendrakar   return ebml_id;
170*103e46e4SHarish Mahendrakar }
171*103e46e4SHarish Mahendrakar 
GetUIntLength(IMkvReader * pReader,long long pos,long & len)172*103e46e4SHarish Mahendrakar long long GetUIntLength(IMkvReader* pReader, long long pos, long& len) {
173*103e46e4SHarish Mahendrakar   if (!pReader || pos < 0)
174*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
175*103e46e4SHarish Mahendrakar 
176*103e46e4SHarish Mahendrakar   long long total, available;
177*103e46e4SHarish Mahendrakar 
178*103e46e4SHarish Mahendrakar   int status = pReader->Length(&total, &available);
179*103e46e4SHarish Mahendrakar   if (status < 0 || (total >= 0 && available > total))
180*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
181*103e46e4SHarish Mahendrakar 
182*103e46e4SHarish Mahendrakar   len = 1;
183*103e46e4SHarish Mahendrakar 
184*103e46e4SHarish Mahendrakar   if (pos >= available)
185*103e46e4SHarish Mahendrakar     return pos;  // too few bytes available
186*103e46e4SHarish Mahendrakar 
187*103e46e4SHarish Mahendrakar   unsigned char b;
188*103e46e4SHarish Mahendrakar 
189*103e46e4SHarish Mahendrakar   status = pReader->Read(pos, 1, &b);
190*103e46e4SHarish Mahendrakar 
191*103e46e4SHarish Mahendrakar   if (status != 0)
192*103e46e4SHarish Mahendrakar     return status;
193*103e46e4SHarish Mahendrakar 
194*103e46e4SHarish Mahendrakar   if (b == 0)  // we can't handle u-int values larger than 8 bytes
195*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
196*103e46e4SHarish Mahendrakar 
197*103e46e4SHarish Mahendrakar   unsigned char m = 0x80;
198*103e46e4SHarish Mahendrakar 
199*103e46e4SHarish Mahendrakar   while (!(b & m)) {
200*103e46e4SHarish Mahendrakar     m >>= 1;
201*103e46e4SHarish Mahendrakar     ++len;
202*103e46e4SHarish Mahendrakar   }
203*103e46e4SHarish Mahendrakar 
204*103e46e4SHarish Mahendrakar   return 0;  // success
205*103e46e4SHarish Mahendrakar }
206*103e46e4SHarish Mahendrakar 
207*103e46e4SHarish Mahendrakar // TODO(vigneshv): This function assumes that unsigned values never have their
208*103e46e4SHarish Mahendrakar // high bit set.
UnserializeUInt(IMkvReader * pReader,long long pos,long long size)209*103e46e4SHarish Mahendrakar long long UnserializeUInt(IMkvReader* pReader, long long pos, long long size) {
210*103e46e4SHarish Mahendrakar   if (!pReader || pos < 0 || (size <= 0) || (size > 8))
211*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
212*103e46e4SHarish Mahendrakar 
213*103e46e4SHarish Mahendrakar   long long result = 0;
214*103e46e4SHarish Mahendrakar 
215*103e46e4SHarish Mahendrakar   for (long long i = 0; i < size; ++i) {
216*103e46e4SHarish Mahendrakar     unsigned char b;
217*103e46e4SHarish Mahendrakar 
218*103e46e4SHarish Mahendrakar     const long status = pReader->Read(pos, 1, &b);
219*103e46e4SHarish Mahendrakar 
220*103e46e4SHarish Mahendrakar     if (status < 0)
221*103e46e4SHarish Mahendrakar       return status;
222*103e46e4SHarish Mahendrakar 
223*103e46e4SHarish Mahendrakar     result <<= 8;
224*103e46e4SHarish Mahendrakar     result |= b;
225*103e46e4SHarish Mahendrakar 
226*103e46e4SHarish Mahendrakar     ++pos;
227*103e46e4SHarish Mahendrakar   }
228*103e46e4SHarish Mahendrakar 
229*103e46e4SHarish Mahendrakar   return result;
230*103e46e4SHarish Mahendrakar }
231*103e46e4SHarish Mahendrakar 
UnserializeFloat(IMkvReader * pReader,long long pos,long long size_,double & result)232*103e46e4SHarish Mahendrakar long UnserializeFloat(IMkvReader* pReader, long long pos, long long size_,
233*103e46e4SHarish Mahendrakar                       double& result) {
234*103e46e4SHarish Mahendrakar   if (!pReader || pos < 0 || ((size_ != 4) && (size_ != 8)))
235*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
236*103e46e4SHarish Mahendrakar 
237*103e46e4SHarish Mahendrakar   const long size = static_cast<long>(size_);
238*103e46e4SHarish Mahendrakar 
239*103e46e4SHarish Mahendrakar   unsigned char buf[8];
240*103e46e4SHarish Mahendrakar 
241*103e46e4SHarish Mahendrakar   const int status = pReader->Read(pos, size, buf);
242*103e46e4SHarish Mahendrakar 
243*103e46e4SHarish Mahendrakar   if (status < 0)  // error
244*103e46e4SHarish Mahendrakar     return status;
245*103e46e4SHarish Mahendrakar 
246*103e46e4SHarish Mahendrakar   if (size == 4) {
247*103e46e4SHarish Mahendrakar     union {
248*103e46e4SHarish Mahendrakar       float f;
249*103e46e4SHarish Mahendrakar       uint32_t ff;
250*103e46e4SHarish Mahendrakar       static_assert(sizeof(float) == sizeof(uint32_t), "");
251*103e46e4SHarish Mahendrakar     };
252*103e46e4SHarish Mahendrakar 
253*103e46e4SHarish Mahendrakar     ff = 0;
254*103e46e4SHarish Mahendrakar 
255*103e46e4SHarish Mahendrakar     for (int i = 0;;) {
256*103e46e4SHarish Mahendrakar       ff |= buf[i];
257*103e46e4SHarish Mahendrakar 
258*103e46e4SHarish Mahendrakar       if (++i >= 4)
259*103e46e4SHarish Mahendrakar         break;
260*103e46e4SHarish Mahendrakar 
261*103e46e4SHarish Mahendrakar       ff <<= 8;
262*103e46e4SHarish Mahendrakar     }
263*103e46e4SHarish Mahendrakar 
264*103e46e4SHarish Mahendrakar     result = f;
265*103e46e4SHarish Mahendrakar   } else {
266*103e46e4SHarish Mahendrakar     union {
267*103e46e4SHarish Mahendrakar       double d;
268*103e46e4SHarish Mahendrakar       uint64_t dd;
269*103e46e4SHarish Mahendrakar       static_assert(sizeof(double) == sizeof(uint64_t), "");
270*103e46e4SHarish Mahendrakar     };
271*103e46e4SHarish Mahendrakar 
272*103e46e4SHarish Mahendrakar     dd = 0;
273*103e46e4SHarish Mahendrakar 
274*103e46e4SHarish Mahendrakar     for (int i = 0;;) {
275*103e46e4SHarish Mahendrakar       dd |= buf[i];
276*103e46e4SHarish Mahendrakar 
277*103e46e4SHarish Mahendrakar       if (++i >= 8)
278*103e46e4SHarish Mahendrakar         break;
279*103e46e4SHarish Mahendrakar 
280*103e46e4SHarish Mahendrakar       dd <<= 8;
281*103e46e4SHarish Mahendrakar     }
282*103e46e4SHarish Mahendrakar 
283*103e46e4SHarish Mahendrakar     result = d;
284*103e46e4SHarish Mahendrakar   }
285*103e46e4SHarish Mahendrakar 
286*103e46e4SHarish Mahendrakar   if (mkvparser::isinf(result) || mkvparser::isnan(result))
287*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
288*103e46e4SHarish Mahendrakar 
289*103e46e4SHarish Mahendrakar   return 0;
290*103e46e4SHarish Mahendrakar }
291*103e46e4SHarish Mahendrakar 
UnserializeInt(IMkvReader * pReader,long long pos,long long size,long long & result_ref)292*103e46e4SHarish Mahendrakar long UnserializeInt(IMkvReader* pReader, long long pos, long long size,
293*103e46e4SHarish Mahendrakar                     long long& result_ref) {
294*103e46e4SHarish Mahendrakar   if (!pReader || pos < 0 || size < 1 || size > 8)
295*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
296*103e46e4SHarish Mahendrakar 
297*103e46e4SHarish Mahendrakar   signed char first_byte = 0;
298*103e46e4SHarish Mahendrakar   const long status = pReader->Read(pos, 1, (unsigned char*)&first_byte);
299*103e46e4SHarish Mahendrakar 
300*103e46e4SHarish Mahendrakar   if (status < 0)
301*103e46e4SHarish Mahendrakar     return status;
302*103e46e4SHarish Mahendrakar 
303*103e46e4SHarish Mahendrakar   unsigned long long result = static_cast<unsigned long long>(first_byte);
304*103e46e4SHarish Mahendrakar   ++pos;
305*103e46e4SHarish Mahendrakar 
306*103e46e4SHarish Mahendrakar   for (long i = 1; i < size; ++i) {
307*103e46e4SHarish Mahendrakar     unsigned char b;
308*103e46e4SHarish Mahendrakar 
309*103e46e4SHarish Mahendrakar     const long status = pReader->Read(pos, 1, &b);
310*103e46e4SHarish Mahendrakar 
311*103e46e4SHarish Mahendrakar     if (status < 0)
312*103e46e4SHarish Mahendrakar       return status;
313*103e46e4SHarish Mahendrakar 
314*103e46e4SHarish Mahendrakar     result <<= 8;
315*103e46e4SHarish Mahendrakar     result |= b;
316*103e46e4SHarish Mahendrakar 
317*103e46e4SHarish Mahendrakar     ++pos;
318*103e46e4SHarish Mahendrakar   }
319*103e46e4SHarish Mahendrakar 
320*103e46e4SHarish Mahendrakar   result_ref = static_cast<long long>(result);
321*103e46e4SHarish Mahendrakar   return 0;
322*103e46e4SHarish Mahendrakar }
323*103e46e4SHarish Mahendrakar 
UnserializeString(IMkvReader * pReader,long long pos,long long size,char * & str)324*103e46e4SHarish Mahendrakar long UnserializeString(IMkvReader* pReader, long long pos, long long size,
325*103e46e4SHarish Mahendrakar                        char*& str) {
326*103e46e4SHarish Mahendrakar   delete[] str;
327*103e46e4SHarish Mahendrakar   str = NULL;
328*103e46e4SHarish Mahendrakar 
329*103e46e4SHarish Mahendrakar   if (size >= LONG_MAX || size < 0 || size > kStringElementSizeLimit)
330*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
331*103e46e4SHarish Mahendrakar 
332*103e46e4SHarish Mahendrakar   // +1 for '\0' terminator
333*103e46e4SHarish Mahendrakar   const long required_size = static_cast<long>(size) + 1;
334*103e46e4SHarish Mahendrakar 
335*103e46e4SHarish Mahendrakar   str = SafeArrayAlloc<char>(1, required_size);
336*103e46e4SHarish Mahendrakar   if (str == NULL)
337*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
338*103e46e4SHarish Mahendrakar 
339*103e46e4SHarish Mahendrakar   unsigned char* const buf = reinterpret_cast<unsigned char*>(str);
340*103e46e4SHarish Mahendrakar 
341*103e46e4SHarish Mahendrakar   const long status = pReader->Read(pos, static_cast<long>(size), buf);
342*103e46e4SHarish Mahendrakar 
343*103e46e4SHarish Mahendrakar   if (status) {
344*103e46e4SHarish Mahendrakar     delete[] str;
345*103e46e4SHarish Mahendrakar     str = NULL;
346*103e46e4SHarish Mahendrakar 
347*103e46e4SHarish Mahendrakar     return status;
348*103e46e4SHarish Mahendrakar   }
349*103e46e4SHarish Mahendrakar 
350*103e46e4SHarish Mahendrakar   str[required_size - 1] = '\0';
351*103e46e4SHarish Mahendrakar   return 0;
352*103e46e4SHarish Mahendrakar }
353*103e46e4SHarish Mahendrakar 
ParseElementHeader(IMkvReader * pReader,long long & pos,long long stop,long long & id,long long & size)354*103e46e4SHarish Mahendrakar long ParseElementHeader(IMkvReader* pReader, long long& pos, long long stop,
355*103e46e4SHarish Mahendrakar                         long long& id, long long& size) {
356*103e46e4SHarish Mahendrakar   if (stop >= 0 && pos >= stop)
357*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
358*103e46e4SHarish Mahendrakar 
359*103e46e4SHarish Mahendrakar   long len;
360*103e46e4SHarish Mahendrakar 
361*103e46e4SHarish Mahendrakar   id = ReadID(pReader, pos, len);
362*103e46e4SHarish Mahendrakar 
363*103e46e4SHarish Mahendrakar   if (id < 0)
364*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
365*103e46e4SHarish Mahendrakar 
366*103e46e4SHarish Mahendrakar   pos += len;  // consume id
367*103e46e4SHarish Mahendrakar 
368*103e46e4SHarish Mahendrakar   if (stop >= 0 && pos >= stop)
369*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
370*103e46e4SHarish Mahendrakar 
371*103e46e4SHarish Mahendrakar   size = ReadUInt(pReader, pos, len);
372*103e46e4SHarish Mahendrakar 
373*103e46e4SHarish Mahendrakar   if (size < 0 || len < 1 || len > 8) {
374*103e46e4SHarish Mahendrakar     // Invalid: Negative payload size, negative or 0 length integer, or integer
375*103e46e4SHarish Mahendrakar     // larger than 64 bits (libwebm cannot handle them).
376*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
377*103e46e4SHarish Mahendrakar   }
378*103e46e4SHarish Mahendrakar 
379*103e46e4SHarish Mahendrakar   // Avoid rolling over pos when very close to LLONG_MAX.
380*103e46e4SHarish Mahendrakar   const unsigned long long rollover_check =
381*103e46e4SHarish Mahendrakar       static_cast<unsigned long long>(pos) + len;
382*103e46e4SHarish Mahendrakar   if (rollover_check > LLONG_MAX)
383*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
384*103e46e4SHarish Mahendrakar 
385*103e46e4SHarish Mahendrakar   pos += len;  // consume length of size
386*103e46e4SHarish Mahendrakar 
387*103e46e4SHarish Mahendrakar   // pos now designates payload
388*103e46e4SHarish Mahendrakar 
389*103e46e4SHarish Mahendrakar   if (stop >= 0 && pos > stop)
390*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
391*103e46e4SHarish Mahendrakar 
392*103e46e4SHarish Mahendrakar   return 0;  // success
393*103e46e4SHarish Mahendrakar }
394*103e46e4SHarish Mahendrakar 
Match(IMkvReader * pReader,long long & pos,unsigned long expected_id,long long & val)395*103e46e4SHarish Mahendrakar bool Match(IMkvReader* pReader, long long& pos, unsigned long expected_id,
396*103e46e4SHarish Mahendrakar            long long& val) {
397*103e46e4SHarish Mahendrakar   if (!pReader || pos < 0)
398*103e46e4SHarish Mahendrakar     return false;
399*103e46e4SHarish Mahendrakar 
400*103e46e4SHarish Mahendrakar   long long total = 0;
401*103e46e4SHarish Mahendrakar   long long available = 0;
402*103e46e4SHarish Mahendrakar 
403*103e46e4SHarish Mahendrakar   const long status = pReader->Length(&total, &available);
404*103e46e4SHarish Mahendrakar   if (status < 0 || (total >= 0 && available > total))
405*103e46e4SHarish Mahendrakar     return false;
406*103e46e4SHarish Mahendrakar 
407*103e46e4SHarish Mahendrakar   long len = 0;
408*103e46e4SHarish Mahendrakar 
409*103e46e4SHarish Mahendrakar   const long long id = ReadID(pReader, pos, len);
410*103e46e4SHarish Mahendrakar   if (id < 0 || (available - pos) > len)
411*103e46e4SHarish Mahendrakar     return false;
412*103e46e4SHarish Mahendrakar 
413*103e46e4SHarish Mahendrakar   if (static_cast<unsigned long>(id) != expected_id)
414*103e46e4SHarish Mahendrakar     return false;
415*103e46e4SHarish Mahendrakar 
416*103e46e4SHarish Mahendrakar   pos += len;  // consume id
417*103e46e4SHarish Mahendrakar 
418*103e46e4SHarish Mahendrakar   const long long size = ReadUInt(pReader, pos, len);
419*103e46e4SHarish Mahendrakar   if (size < 0 || size > 8 || len < 1 || len > 8 || (available - pos) > len)
420*103e46e4SHarish Mahendrakar     return false;
421*103e46e4SHarish Mahendrakar 
422*103e46e4SHarish Mahendrakar   pos += len;  // consume length of size of payload
423*103e46e4SHarish Mahendrakar 
424*103e46e4SHarish Mahendrakar   val = UnserializeUInt(pReader, pos, size);
425*103e46e4SHarish Mahendrakar   if (val < 0)
426*103e46e4SHarish Mahendrakar     return false;
427*103e46e4SHarish Mahendrakar 
428*103e46e4SHarish Mahendrakar   pos += size;  // consume size of payload
429*103e46e4SHarish Mahendrakar 
430*103e46e4SHarish Mahendrakar   return true;
431*103e46e4SHarish Mahendrakar }
432*103e46e4SHarish Mahendrakar 
Match(IMkvReader * pReader,long long & pos,unsigned long expected_id,unsigned char * & buf,size_t & buflen)433*103e46e4SHarish Mahendrakar bool Match(IMkvReader* pReader, long long& pos, unsigned long expected_id,
434*103e46e4SHarish Mahendrakar            unsigned char*& buf, size_t& buflen) {
435*103e46e4SHarish Mahendrakar   if (!pReader || pos < 0)
436*103e46e4SHarish Mahendrakar     return false;
437*103e46e4SHarish Mahendrakar 
438*103e46e4SHarish Mahendrakar   long long total = 0;
439*103e46e4SHarish Mahendrakar   long long available = 0;
440*103e46e4SHarish Mahendrakar 
441*103e46e4SHarish Mahendrakar   long status = pReader->Length(&total, &available);
442*103e46e4SHarish Mahendrakar   if (status < 0 || (total >= 0 && available > total))
443*103e46e4SHarish Mahendrakar     return false;
444*103e46e4SHarish Mahendrakar 
445*103e46e4SHarish Mahendrakar   long len = 0;
446*103e46e4SHarish Mahendrakar   const long long id = ReadID(pReader, pos, len);
447*103e46e4SHarish Mahendrakar   if (id < 0 || (available - pos) > len)
448*103e46e4SHarish Mahendrakar     return false;
449*103e46e4SHarish Mahendrakar 
450*103e46e4SHarish Mahendrakar   if (static_cast<unsigned long>(id) != expected_id)
451*103e46e4SHarish Mahendrakar     return false;
452*103e46e4SHarish Mahendrakar 
453*103e46e4SHarish Mahendrakar   pos += len;  // consume id
454*103e46e4SHarish Mahendrakar 
455*103e46e4SHarish Mahendrakar   const long long size = ReadUInt(pReader, pos, len);
456*103e46e4SHarish Mahendrakar   if (size < 0 || len <= 0 || len > 8 || (available - pos) > len)
457*103e46e4SHarish Mahendrakar     return false;
458*103e46e4SHarish Mahendrakar 
459*103e46e4SHarish Mahendrakar   unsigned long long rollover_check =
460*103e46e4SHarish Mahendrakar       static_cast<unsigned long long>(pos) + len;
461*103e46e4SHarish Mahendrakar   if (rollover_check > LLONG_MAX)
462*103e46e4SHarish Mahendrakar     return false;
463*103e46e4SHarish Mahendrakar 
464*103e46e4SHarish Mahendrakar   pos += len;  // consume length of size of payload
465*103e46e4SHarish Mahendrakar 
466*103e46e4SHarish Mahendrakar   rollover_check = static_cast<unsigned long long>(pos) + size;
467*103e46e4SHarish Mahendrakar   if (rollover_check > LLONG_MAX)
468*103e46e4SHarish Mahendrakar     return false;
469*103e46e4SHarish Mahendrakar 
470*103e46e4SHarish Mahendrakar   if ((pos + size) > available)
471*103e46e4SHarish Mahendrakar     return false;
472*103e46e4SHarish Mahendrakar 
473*103e46e4SHarish Mahendrakar   if (size >= LONG_MAX)
474*103e46e4SHarish Mahendrakar     return false;
475*103e46e4SHarish Mahendrakar 
476*103e46e4SHarish Mahendrakar   const long buflen_ = static_cast<long>(size);
477*103e46e4SHarish Mahendrakar 
478*103e46e4SHarish Mahendrakar   buf = SafeArrayAlloc<unsigned char>(1, buflen_);
479*103e46e4SHarish Mahendrakar   if (!buf)
480*103e46e4SHarish Mahendrakar     return false;
481*103e46e4SHarish Mahendrakar 
482*103e46e4SHarish Mahendrakar   status = pReader->Read(pos, buflen_, buf);
483*103e46e4SHarish Mahendrakar   if (status != 0)
484*103e46e4SHarish Mahendrakar     return false;
485*103e46e4SHarish Mahendrakar 
486*103e46e4SHarish Mahendrakar   buflen = buflen_;
487*103e46e4SHarish Mahendrakar 
488*103e46e4SHarish Mahendrakar   pos += size;  // consume size of payload
489*103e46e4SHarish Mahendrakar   return true;
490*103e46e4SHarish Mahendrakar }
491*103e46e4SHarish Mahendrakar 
EBMLHeader()492*103e46e4SHarish Mahendrakar EBMLHeader::EBMLHeader() : m_docType(NULL) { Init(); }
493*103e46e4SHarish Mahendrakar 
~EBMLHeader()494*103e46e4SHarish Mahendrakar EBMLHeader::~EBMLHeader() { delete[] m_docType; }
495*103e46e4SHarish Mahendrakar 
Init()496*103e46e4SHarish Mahendrakar void EBMLHeader::Init() {
497*103e46e4SHarish Mahendrakar   m_version = 1;
498*103e46e4SHarish Mahendrakar   m_readVersion = 1;
499*103e46e4SHarish Mahendrakar   m_maxIdLength = 4;
500*103e46e4SHarish Mahendrakar   m_maxSizeLength = 8;
501*103e46e4SHarish Mahendrakar 
502*103e46e4SHarish Mahendrakar   if (m_docType) {
503*103e46e4SHarish Mahendrakar     delete[] m_docType;
504*103e46e4SHarish Mahendrakar     m_docType = NULL;
505*103e46e4SHarish Mahendrakar   }
506*103e46e4SHarish Mahendrakar 
507*103e46e4SHarish Mahendrakar   m_docTypeVersion = 1;
508*103e46e4SHarish Mahendrakar   m_docTypeReadVersion = 1;
509*103e46e4SHarish Mahendrakar }
510*103e46e4SHarish Mahendrakar 
Parse(IMkvReader * pReader,long long & pos)511*103e46e4SHarish Mahendrakar long long EBMLHeader::Parse(IMkvReader* pReader, long long& pos) {
512*103e46e4SHarish Mahendrakar   if (!pReader)
513*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
514*103e46e4SHarish Mahendrakar 
515*103e46e4SHarish Mahendrakar   long long total, available;
516*103e46e4SHarish Mahendrakar 
517*103e46e4SHarish Mahendrakar   long status = pReader->Length(&total, &available);
518*103e46e4SHarish Mahendrakar 
519*103e46e4SHarish Mahendrakar   if (status < 0)  // error
520*103e46e4SHarish Mahendrakar     return status;
521*103e46e4SHarish Mahendrakar 
522*103e46e4SHarish Mahendrakar   pos = 0;
523*103e46e4SHarish Mahendrakar 
524*103e46e4SHarish Mahendrakar   // Scan until we find what looks like the first byte of the EBML header.
525*103e46e4SHarish Mahendrakar   const long long kMaxScanBytes = (available >= 1024) ? 1024 : available;
526*103e46e4SHarish Mahendrakar   const unsigned char kEbmlByte0 = 0x1A;
527*103e46e4SHarish Mahendrakar   unsigned char scan_byte = 0;
528*103e46e4SHarish Mahendrakar 
529*103e46e4SHarish Mahendrakar   while (pos < kMaxScanBytes) {
530*103e46e4SHarish Mahendrakar     status = pReader->Read(pos, 1, &scan_byte);
531*103e46e4SHarish Mahendrakar 
532*103e46e4SHarish Mahendrakar     if (status < 0)  // error
533*103e46e4SHarish Mahendrakar       return status;
534*103e46e4SHarish Mahendrakar     else if (status > 0)
535*103e46e4SHarish Mahendrakar       return E_BUFFER_NOT_FULL;
536*103e46e4SHarish Mahendrakar 
537*103e46e4SHarish Mahendrakar     if (scan_byte == kEbmlByte0)
538*103e46e4SHarish Mahendrakar       break;
539*103e46e4SHarish Mahendrakar 
540*103e46e4SHarish Mahendrakar     ++pos;
541*103e46e4SHarish Mahendrakar   }
542*103e46e4SHarish Mahendrakar 
543*103e46e4SHarish Mahendrakar   long len = 0;
544*103e46e4SHarish Mahendrakar   const long long ebml_id = ReadID(pReader, pos, len);
545*103e46e4SHarish Mahendrakar 
546*103e46e4SHarish Mahendrakar   if (ebml_id == E_BUFFER_NOT_FULL)
547*103e46e4SHarish Mahendrakar     return E_BUFFER_NOT_FULL;
548*103e46e4SHarish Mahendrakar 
549*103e46e4SHarish Mahendrakar   if (len != 4 || ebml_id != libwebm::kMkvEBML)
550*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
551*103e46e4SHarish Mahendrakar 
552*103e46e4SHarish Mahendrakar   // Move read pos forward to the EBML header size field.
553*103e46e4SHarish Mahendrakar   pos += 4;
554*103e46e4SHarish Mahendrakar 
555*103e46e4SHarish Mahendrakar   // Read length of size field.
556*103e46e4SHarish Mahendrakar   long long result = GetUIntLength(pReader, pos, len);
557*103e46e4SHarish Mahendrakar 
558*103e46e4SHarish Mahendrakar   if (result < 0)  // error
559*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
560*103e46e4SHarish Mahendrakar   else if (result > 0)  // need more data
561*103e46e4SHarish Mahendrakar     return E_BUFFER_NOT_FULL;
562*103e46e4SHarish Mahendrakar 
563*103e46e4SHarish Mahendrakar   if (len < 1 || len > 8)
564*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
565*103e46e4SHarish Mahendrakar 
566*103e46e4SHarish Mahendrakar   if ((total >= 0) && ((total - pos) < len))
567*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
568*103e46e4SHarish Mahendrakar 
569*103e46e4SHarish Mahendrakar   if ((available - pos) < len)
570*103e46e4SHarish Mahendrakar     return pos + len;  // try again later
571*103e46e4SHarish Mahendrakar 
572*103e46e4SHarish Mahendrakar   // Read the EBML header size.
573*103e46e4SHarish Mahendrakar   result = ReadUInt(pReader, pos, len);
574*103e46e4SHarish Mahendrakar 
575*103e46e4SHarish Mahendrakar   if (result < 0)  // error
576*103e46e4SHarish Mahendrakar     return result;
577*103e46e4SHarish Mahendrakar 
578*103e46e4SHarish Mahendrakar   pos += len;  // consume size field
579*103e46e4SHarish Mahendrakar 
580*103e46e4SHarish Mahendrakar   // pos now designates start of payload
581*103e46e4SHarish Mahendrakar 
582*103e46e4SHarish Mahendrakar   if ((total >= 0) && ((total - pos) < result))
583*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
584*103e46e4SHarish Mahendrakar 
585*103e46e4SHarish Mahendrakar   if ((available - pos) < result)
586*103e46e4SHarish Mahendrakar     return pos + result;
587*103e46e4SHarish Mahendrakar 
588*103e46e4SHarish Mahendrakar   const long long end = pos + result;
589*103e46e4SHarish Mahendrakar 
590*103e46e4SHarish Mahendrakar   Init();
591*103e46e4SHarish Mahendrakar 
592*103e46e4SHarish Mahendrakar   while (pos < end) {
593*103e46e4SHarish Mahendrakar     long long id, size;
594*103e46e4SHarish Mahendrakar 
595*103e46e4SHarish Mahendrakar     status = ParseElementHeader(pReader, pos, end, id, size);
596*103e46e4SHarish Mahendrakar 
597*103e46e4SHarish Mahendrakar     if (status < 0)  // error
598*103e46e4SHarish Mahendrakar       return status;
599*103e46e4SHarish Mahendrakar 
600*103e46e4SHarish Mahendrakar     if (size == 0)
601*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
602*103e46e4SHarish Mahendrakar 
603*103e46e4SHarish Mahendrakar     if (id == libwebm::kMkvEBMLVersion) {
604*103e46e4SHarish Mahendrakar       m_version = UnserializeUInt(pReader, pos, size);
605*103e46e4SHarish Mahendrakar 
606*103e46e4SHarish Mahendrakar       if (m_version <= 0)
607*103e46e4SHarish Mahendrakar         return E_FILE_FORMAT_INVALID;
608*103e46e4SHarish Mahendrakar     } else if (id == libwebm::kMkvEBMLReadVersion) {
609*103e46e4SHarish Mahendrakar       m_readVersion = UnserializeUInt(pReader, pos, size);
610*103e46e4SHarish Mahendrakar 
611*103e46e4SHarish Mahendrakar       if (m_readVersion <= 0)
612*103e46e4SHarish Mahendrakar         return E_FILE_FORMAT_INVALID;
613*103e46e4SHarish Mahendrakar     } else if (id == libwebm::kMkvEBMLMaxIDLength) {
614*103e46e4SHarish Mahendrakar       m_maxIdLength = UnserializeUInt(pReader, pos, size);
615*103e46e4SHarish Mahendrakar 
616*103e46e4SHarish Mahendrakar       if (m_maxIdLength <= 0)
617*103e46e4SHarish Mahendrakar         return E_FILE_FORMAT_INVALID;
618*103e46e4SHarish Mahendrakar     } else if (id == libwebm::kMkvEBMLMaxSizeLength) {
619*103e46e4SHarish Mahendrakar       m_maxSizeLength = UnserializeUInt(pReader, pos, size);
620*103e46e4SHarish Mahendrakar 
621*103e46e4SHarish Mahendrakar       if (m_maxSizeLength <= 0)
622*103e46e4SHarish Mahendrakar         return E_FILE_FORMAT_INVALID;
623*103e46e4SHarish Mahendrakar     } else if (id == libwebm::kMkvDocType) {
624*103e46e4SHarish Mahendrakar       if (m_docType)
625*103e46e4SHarish Mahendrakar         return E_FILE_FORMAT_INVALID;
626*103e46e4SHarish Mahendrakar 
627*103e46e4SHarish Mahendrakar       status = UnserializeString(pReader, pos, size, m_docType);
628*103e46e4SHarish Mahendrakar 
629*103e46e4SHarish Mahendrakar       if (status)  // error
630*103e46e4SHarish Mahendrakar         return status;
631*103e46e4SHarish Mahendrakar     } else if (id == libwebm::kMkvDocTypeVersion) {
632*103e46e4SHarish Mahendrakar       m_docTypeVersion = UnserializeUInt(pReader, pos, size);
633*103e46e4SHarish Mahendrakar 
634*103e46e4SHarish Mahendrakar       if (m_docTypeVersion <= 0)
635*103e46e4SHarish Mahendrakar         return E_FILE_FORMAT_INVALID;
636*103e46e4SHarish Mahendrakar     } else if (id == libwebm::kMkvDocTypeReadVersion) {
637*103e46e4SHarish Mahendrakar       m_docTypeReadVersion = UnserializeUInt(pReader, pos, size);
638*103e46e4SHarish Mahendrakar 
639*103e46e4SHarish Mahendrakar       if (m_docTypeReadVersion <= 0)
640*103e46e4SHarish Mahendrakar         return E_FILE_FORMAT_INVALID;
641*103e46e4SHarish Mahendrakar     }
642*103e46e4SHarish Mahendrakar 
643*103e46e4SHarish Mahendrakar     pos += size;
644*103e46e4SHarish Mahendrakar   }
645*103e46e4SHarish Mahendrakar 
646*103e46e4SHarish Mahendrakar   if (pos != end)
647*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
648*103e46e4SHarish Mahendrakar 
649*103e46e4SHarish Mahendrakar   // Make sure DocType, DocTypeReadVersion, and DocTypeVersion are valid.
650*103e46e4SHarish Mahendrakar   if (m_docType == NULL || m_docTypeReadVersion <= 0 || m_docTypeVersion <= 0)
651*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
652*103e46e4SHarish Mahendrakar 
653*103e46e4SHarish Mahendrakar   // Make sure EBMLMaxIDLength and EBMLMaxSizeLength are valid.
654*103e46e4SHarish Mahendrakar   if (m_maxIdLength <= 0 || m_maxIdLength > 4 || m_maxSizeLength <= 0 ||
655*103e46e4SHarish Mahendrakar       m_maxSizeLength > 8)
656*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
657*103e46e4SHarish Mahendrakar 
658*103e46e4SHarish Mahendrakar   return 0;
659*103e46e4SHarish Mahendrakar }
660*103e46e4SHarish Mahendrakar 
Segment(IMkvReader * pReader,long long elem_start,long long start,long long size)661*103e46e4SHarish Mahendrakar Segment::Segment(IMkvReader* pReader, long long elem_start,
662*103e46e4SHarish Mahendrakar                  // long long elem_size,
663*103e46e4SHarish Mahendrakar                  long long start, long long size)
664*103e46e4SHarish Mahendrakar     : m_pReader(pReader),
665*103e46e4SHarish Mahendrakar       m_element_start(elem_start),
666*103e46e4SHarish Mahendrakar       // m_element_size(elem_size),
667*103e46e4SHarish Mahendrakar       m_start(start),
668*103e46e4SHarish Mahendrakar       m_size(size),
669*103e46e4SHarish Mahendrakar       m_pos(start),
670*103e46e4SHarish Mahendrakar       m_pUnknownSize(0),
671*103e46e4SHarish Mahendrakar       m_pSeekHead(NULL),
672*103e46e4SHarish Mahendrakar       m_pInfo(NULL),
673*103e46e4SHarish Mahendrakar       m_pTracks(NULL),
674*103e46e4SHarish Mahendrakar       m_pCues(NULL),
675*103e46e4SHarish Mahendrakar       m_pChapters(NULL),
676*103e46e4SHarish Mahendrakar       m_pTags(NULL),
677*103e46e4SHarish Mahendrakar       m_clusters(NULL),
678*103e46e4SHarish Mahendrakar       m_clusterCount(0),
679*103e46e4SHarish Mahendrakar       m_clusterPreloadCount(0),
680*103e46e4SHarish Mahendrakar       m_clusterSize(0) {}
681*103e46e4SHarish Mahendrakar 
~Segment()682*103e46e4SHarish Mahendrakar Segment::~Segment() {
683*103e46e4SHarish Mahendrakar   const long count = m_clusterCount + m_clusterPreloadCount;
684*103e46e4SHarish Mahendrakar 
685*103e46e4SHarish Mahendrakar   Cluster** i = m_clusters;
686*103e46e4SHarish Mahendrakar   Cluster** j = m_clusters + count;
687*103e46e4SHarish Mahendrakar 
688*103e46e4SHarish Mahendrakar   while (i != j) {
689*103e46e4SHarish Mahendrakar     Cluster* const p = *i++;
690*103e46e4SHarish Mahendrakar     delete p;
691*103e46e4SHarish Mahendrakar   }
692*103e46e4SHarish Mahendrakar 
693*103e46e4SHarish Mahendrakar   delete[] m_clusters;
694*103e46e4SHarish Mahendrakar 
695*103e46e4SHarish Mahendrakar   delete m_pTracks;
696*103e46e4SHarish Mahendrakar   delete m_pInfo;
697*103e46e4SHarish Mahendrakar   delete m_pCues;
698*103e46e4SHarish Mahendrakar   delete m_pChapters;
699*103e46e4SHarish Mahendrakar   delete m_pTags;
700*103e46e4SHarish Mahendrakar   delete m_pSeekHead;
701*103e46e4SHarish Mahendrakar }
702*103e46e4SHarish Mahendrakar 
CreateInstance(IMkvReader * pReader,long long pos,Segment * & pSegment)703*103e46e4SHarish Mahendrakar long long Segment::CreateInstance(IMkvReader* pReader, long long pos,
704*103e46e4SHarish Mahendrakar                                   Segment*& pSegment) {
705*103e46e4SHarish Mahendrakar   if (pReader == NULL || pos < 0)
706*103e46e4SHarish Mahendrakar     return E_PARSE_FAILED;
707*103e46e4SHarish Mahendrakar 
708*103e46e4SHarish Mahendrakar   pSegment = NULL;
709*103e46e4SHarish Mahendrakar 
710*103e46e4SHarish Mahendrakar   long long total, available;
711*103e46e4SHarish Mahendrakar 
712*103e46e4SHarish Mahendrakar   const long status = pReader->Length(&total, &available);
713*103e46e4SHarish Mahendrakar 
714*103e46e4SHarish Mahendrakar   if (status < 0)  // error
715*103e46e4SHarish Mahendrakar     return status;
716*103e46e4SHarish Mahendrakar 
717*103e46e4SHarish Mahendrakar   if (available < 0)
718*103e46e4SHarish Mahendrakar     return -1;
719*103e46e4SHarish Mahendrakar 
720*103e46e4SHarish Mahendrakar   if ((total >= 0) && (available > total))
721*103e46e4SHarish Mahendrakar     return -1;
722*103e46e4SHarish Mahendrakar 
723*103e46e4SHarish Mahendrakar   // I would assume that in practice this loop would execute
724*103e46e4SHarish Mahendrakar   // exactly once, but we allow for other elements (e.g. Void)
725*103e46e4SHarish Mahendrakar   // to immediately follow the EBML header.  This is fine for
726*103e46e4SHarish Mahendrakar   // the source filter case (since the entire file is available),
727*103e46e4SHarish Mahendrakar   // but in the splitter case over a network we should probably
728*103e46e4SHarish Mahendrakar   // just give up early.  We could for example decide only to
729*103e46e4SHarish Mahendrakar   // execute this loop a maximum of, say, 10 times.
730*103e46e4SHarish Mahendrakar   // TODO:
731*103e46e4SHarish Mahendrakar   // There is an implied "give up early" by only parsing up
732*103e46e4SHarish Mahendrakar   // to the available limit.  We do do that, but only if the
733*103e46e4SHarish Mahendrakar   // total file size is unknown.  We could decide to always
734*103e46e4SHarish Mahendrakar   // use what's available as our limit (irrespective of whether
735*103e46e4SHarish Mahendrakar   // we happen to know the total file length).  This would have
736*103e46e4SHarish Mahendrakar   // as its sense "parse this much of the file before giving up",
737*103e46e4SHarish Mahendrakar   // which a slightly different sense from "try to parse up to
738*103e46e4SHarish Mahendrakar   // 10 EMBL elements before giving up".
739*103e46e4SHarish Mahendrakar 
740*103e46e4SHarish Mahendrakar   for (;;) {
741*103e46e4SHarish Mahendrakar     if ((total >= 0) && (pos >= total))
742*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
743*103e46e4SHarish Mahendrakar 
744*103e46e4SHarish Mahendrakar     // Read ID
745*103e46e4SHarish Mahendrakar     long len;
746*103e46e4SHarish Mahendrakar     long long result = GetUIntLength(pReader, pos, len);
747*103e46e4SHarish Mahendrakar 
748*103e46e4SHarish Mahendrakar     if (result)  // error, or too few available bytes
749*103e46e4SHarish Mahendrakar       return result;
750*103e46e4SHarish Mahendrakar 
751*103e46e4SHarish Mahendrakar     if ((total >= 0) && ((pos + len) > total))
752*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
753*103e46e4SHarish Mahendrakar 
754*103e46e4SHarish Mahendrakar     if ((pos + len) > available)
755*103e46e4SHarish Mahendrakar       return pos + len;
756*103e46e4SHarish Mahendrakar 
757*103e46e4SHarish Mahendrakar     const long long idpos = pos;
758*103e46e4SHarish Mahendrakar     const long long id = ReadID(pReader, pos, len);
759*103e46e4SHarish Mahendrakar 
760*103e46e4SHarish Mahendrakar     if (id < 0)
761*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
762*103e46e4SHarish Mahendrakar 
763*103e46e4SHarish Mahendrakar     pos += len;  // consume ID
764*103e46e4SHarish Mahendrakar 
765*103e46e4SHarish Mahendrakar     // Read Size
766*103e46e4SHarish Mahendrakar 
767*103e46e4SHarish Mahendrakar     result = GetUIntLength(pReader, pos, len);
768*103e46e4SHarish Mahendrakar 
769*103e46e4SHarish Mahendrakar     if (result)  // error, or too few available bytes
770*103e46e4SHarish Mahendrakar       return result;
771*103e46e4SHarish Mahendrakar 
772*103e46e4SHarish Mahendrakar     if ((total >= 0) && ((pos + len) > total))
773*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
774*103e46e4SHarish Mahendrakar 
775*103e46e4SHarish Mahendrakar     if ((pos + len) > available)
776*103e46e4SHarish Mahendrakar       return pos + len;
777*103e46e4SHarish Mahendrakar 
778*103e46e4SHarish Mahendrakar     long long size = ReadUInt(pReader, pos, len);
779*103e46e4SHarish Mahendrakar 
780*103e46e4SHarish Mahendrakar     if (size < 0)  // error
781*103e46e4SHarish Mahendrakar       return size;
782*103e46e4SHarish Mahendrakar 
783*103e46e4SHarish Mahendrakar     pos += len;  // consume length of size of element
784*103e46e4SHarish Mahendrakar 
785*103e46e4SHarish Mahendrakar     // Pos now points to start of payload
786*103e46e4SHarish Mahendrakar 
787*103e46e4SHarish Mahendrakar     // Handle "unknown size" for live streaming of webm files.
788*103e46e4SHarish Mahendrakar     const long long unknown_size = (1LL << (7 * len)) - 1;
789*103e46e4SHarish Mahendrakar 
790*103e46e4SHarish Mahendrakar     if (id == libwebm::kMkvSegment) {
791*103e46e4SHarish Mahendrakar       if (size == unknown_size)
792*103e46e4SHarish Mahendrakar         size = -1;
793*103e46e4SHarish Mahendrakar 
794*103e46e4SHarish Mahendrakar       else if (total < 0)
795*103e46e4SHarish Mahendrakar         size = -1;
796*103e46e4SHarish Mahendrakar 
797*103e46e4SHarish Mahendrakar       else if ((pos + size) > total)
798*103e46e4SHarish Mahendrakar         size = -1;
799*103e46e4SHarish Mahendrakar 
800*103e46e4SHarish Mahendrakar       pSegment = new (std::nothrow) Segment(pReader, idpos, pos, size);
801*103e46e4SHarish Mahendrakar       if (pSegment == NULL)
802*103e46e4SHarish Mahendrakar         return E_PARSE_FAILED;
803*103e46e4SHarish Mahendrakar 
804*103e46e4SHarish Mahendrakar       return 0;  // success
805*103e46e4SHarish Mahendrakar     }
806*103e46e4SHarish Mahendrakar 
807*103e46e4SHarish Mahendrakar     if (size == unknown_size)
808*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
809*103e46e4SHarish Mahendrakar 
810*103e46e4SHarish Mahendrakar     if ((total >= 0) && ((pos + size) > total))
811*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
812*103e46e4SHarish Mahendrakar 
813*103e46e4SHarish Mahendrakar     if ((pos + size) > available)
814*103e46e4SHarish Mahendrakar       return pos + size;
815*103e46e4SHarish Mahendrakar 
816*103e46e4SHarish Mahendrakar     pos += size;  // consume payload
817*103e46e4SHarish Mahendrakar   }
818*103e46e4SHarish Mahendrakar }
819*103e46e4SHarish Mahendrakar 
ParseHeaders()820*103e46e4SHarish Mahendrakar long long Segment::ParseHeaders() {
821*103e46e4SHarish Mahendrakar   // Outermost (level 0) segment object has been constructed,
822*103e46e4SHarish Mahendrakar   // and pos designates start of payload.  We need to find the
823*103e46e4SHarish Mahendrakar   // inner (level 1) elements.
824*103e46e4SHarish Mahendrakar   long long total, available;
825*103e46e4SHarish Mahendrakar 
826*103e46e4SHarish Mahendrakar   const int status = m_pReader->Length(&total, &available);
827*103e46e4SHarish Mahendrakar 
828*103e46e4SHarish Mahendrakar   if (status < 0)  // error
829*103e46e4SHarish Mahendrakar     return status;
830*103e46e4SHarish Mahendrakar 
831*103e46e4SHarish Mahendrakar   if (total > 0 && available > total)
832*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
833*103e46e4SHarish Mahendrakar 
834*103e46e4SHarish Mahendrakar   const long long segment_stop = (m_size < 0) ? -1 : m_start + m_size;
835*103e46e4SHarish Mahendrakar 
836*103e46e4SHarish Mahendrakar   if ((segment_stop >= 0 && total >= 0 && segment_stop > total) ||
837*103e46e4SHarish Mahendrakar       (segment_stop >= 0 && m_pos > segment_stop)) {
838*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
839*103e46e4SHarish Mahendrakar   }
840*103e46e4SHarish Mahendrakar 
841*103e46e4SHarish Mahendrakar   for (;;) {
842*103e46e4SHarish Mahendrakar     if ((total >= 0) && (m_pos >= total))
843*103e46e4SHarish Mahendrakar       break;
844*103e46e4SHarish Mahendrakar 
845*103e46e4SHarish Mahendrakar     if ((segment_stop >= 0) && (m_pos >= segment_stop))
846*103e46e4SHarish Mahendrakar       break;
847*103e46e4SHarish Mahendrakar 
848*103e46e4SHarish Mahendrakar     long long pos = m_pos;
849*103e46e4SHarish Mahendrakar     const long long element_start = pos;
850*103e46e4SHarish Mahendrakar 
851*103e46e4SHarish Mahendrakar     // Avoid rolling over pos when very close to LLONG_MAX.
852*103e46e4SHarish Mahendrakar     unsigned long long rollover_check = pos + 1ULL;
853*103e46e4SHarish Mahendrakar     if (rollover_check > LLONG_MAX)
854*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
855*103e46e4SHarish Mahendrakar 
856*103e46e4SHarish Mahendrakar     if ((pos + 1) > available)
857*103e46e4SHarish Mahendrakar       return (pos + 1);
858*103e46e4SHarish Mahendrakar 
859*103e46e4SHarish Mahendrakar     long len;
860*103e46e4SHarish Mahendrakar     long long result = GetUIntLength(m_pReader, pos, len);
861*103e46e4SHarish Mahendrakar 
862*103e46e4SHarish Mahendrakar     if (result < 0)  // error
863*103e46e4SHarish Mahendrakar       return result;
864*103e46e4SHarish Mahendrakar 
865*103e46e4SHarish Mahendrakar     if (result > 0) {
866*103e46e4SHarish Mahendrakar       // MkvReader doesn't have enough data to satisfy this read attempt.
867*103e46e4SHarish Mahendrakar       return (pos + 1);
868*103e46e4SHarish Mahendrakar     }
869*103e46e4SHarish Mahendrakar 
870*103e46e4SHarish Mahendrakar     if ((segment_stop >= 0) && ((pos + len) > segment_stop))
871*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
872*103e46e4SHarish Mahendrakar 
873*103e46e4SHarish Mahendrakar     if ((pos + len) > available)
874*103e46e4SHarish Mahendrakar       return pos + len;
875*103e46e4SHarish Mahendrakar 
876*103e46e4SHarish Mahendrakar     const long long idpos = pos;
877*103e46e4SHarish Mahendrakar     const long long id = ReadID(m_pReader, idpos, len);
878*103e46e4SHarish Mahendrakar 
879*103e46e4SHarish Mahendrakar     if (id < 0)
880*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
881*103e46e4SHarish Mahendrakar 
882*103e46e4SHarish Mahendrakar     if (id == libwebm::kMkvCluster)
883*103e46e4SHarish Mahendrakar       break;
884*103e46e4SHarish Mahendrakar 
885*103e46e4SHarish Mahendrakar     pos += len;  // consume ID
886*103e46e4SHarish Mahendrakar 
887*103e46e4SHarish Mahendrakar     if ((pos + 1) > available)
888*103e46e4SHarish Mahendrakar       return (pos + 1);
889*103e46e4SHarish Mahendrakar 
890*103e46e4SHarish Mahendrakar     // Read Size
891*103e46e4SHarish Mahendrakar     result = GetUIntLength(m_pReader, pos, len);
892*103e46e4SHarish Mahendrakar 
893*103e46e4SHarish Mahendrakar     if (result < 0)  // error
894*103e46e4SHarish Mahendrakar       return result;
895*103e46e4SHarish Mahendrakar 
896*103e46e4SHarish Mahendrakar     if (result > 0) {
897*103e46e4SHarish Mahendrakar       // MkvReader doesn't have enough data to satisfy this read attempt.
898*103e46e4SHarish Mahendrakar       return (pos + 1);
899*103e46e4SHarish Mahendrakar     }
900*103e46e4SHarish Mahendrakar 
901*103e46e4SHarish Mahendrakar     if ((segment_stop >= 0) && ((pos + len) > segment_stop))
902*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
903*103e46e4SHarish Mahendrakar 
904*103e46e4SHarish Mahendrakar     if ((pos + len) > available)
905*103e46e4SHarish Mahendrakar       return pos + len;
906*103e46e4SHarish Mahendrakar 
907*103e46e4SHarish Mahendrakar     const long long size = ReadUInt(m_pReader, pos, len);
908*103e46e4SHarish Mahendrakar 
909*103e46e4SHarish Mahendrakar     if (size < 0 || len < 1 || len > 8) {
910*103e46e4SHarish Mahendrakar       // TODO(tomfinegan): ReadUInt should return an error when len is < 1 or
911*103e46e4SHarish Mahendrakar       // len > 8 is true instead of checking this _everywhere_.
912*103e46e4SHarish Mahendrakar       return size;
913*103e46e4SHarish Mahendrakar     }
914*103e46e4SHarish Mahendrakar 
915*103e46e4SHarish Mahendrakar     pos += len;  // consume length of size of element
916*103e46e4SHarish Mahendrakar 
917*103e46e4SHarish Mahendrakar     // Avoid rolling over pos when very close to LLONG_MAX.
918*103e46e4SHarish Mahendrakar     rollover_check = static_cast<unsigned long long>(pos) + size;
919*103e46e4SHarish Mahendrakar     if (rollover_check > LLONG_MAX)
920*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
921*103e46e4SHarish Mahendrakar 
922*103e46e4SHarish Mahendrakar     const long long element_size = size + pos - element_start;
923*103e46e4SHarish Mahendrakar 
924*103e46e4SHarish Mahendrakar     // Pos now points to start of payload
925*103e46e4SHarish Mahendrakar 
926*103e46e4SHarish Mahendrakar     if ((segment_stop >= 0) && ((pos + size) > segment_stop))
927*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
928*103e46e4SHarish Mahendrakar 
929*103e46e4SHarish Mahendrakar     // We read EBML elements either in total or nothing at all.
930*103e46e4SHarish Mahendrakar 
931*103e46e4SHarish Mahendrakar     if ((pos + size) > available)
932*103e46e4SHarish Mahendrakar       return pos + size;
933*103e46e4SHarish Mahendrakar 
934*103e46e4SHarish Mahendrakar     if (id == libwebm::kMkvInfo) {
935*103e46e4SHarish Mahendrakar       if (m_pInfo)
936*103e46e4SHarish Mahendrakar         return E_FILE_FORMAT_INVALID;
937*103e46e4SHarish Mahendrakar 
938*103e46e4SHarish Mahendrakar       m_pInfo = new (std::nothrow)
939*103e46e4SHarish Mahendrakar           SegmentInfo(this, pos, size, element_start, element_size);
940*103e46e4SHarish Mahendrakar 
941*103e46e4SHarish Mahendrakar       if (m_pInfo == NULL)
942*103e46e4SHarish Mahendrakar         return -1;
943*103e46e4SHarish Mahendrakar 
944*103e46e4SHarish Mahendrakar       const long status = m_pInfo->Parse();
945*103e46e4SHarish Mahendrakar 
946*103e46e4SHarish Mahendrakar       if (status)
947*103e46e4SHarish Mahendrakar         return status;
948*103e46e4SHarish Mahendrakar     } else if (id == libwebm::kMkvTracks) {
949*103e46e4SHarish Mahendrakar       if (m_pTracks)
950*103e46e4SHarish Mahendrakar         return E_FILE_FORMAT_INVALID;
951*103e46e4SHarish Mahendrakar 
952*103e46e4SHarish Mahendrakar       m_pTracks = new (std::nothrow)
953*103e46e4SHarish Mahendrakar           Tracks(this, pos, size, element_start, element_size);
954*103e46e4SHarish Mahendrakar 
955*103e46e4SHarish Mahendrakar       if (m_pTracks == NULL)
956*103e46e4SHarish Mahendrakar         return -1;
957*103e46e4SHarish Mahendrakar 
958*103e46e4SHarish Mahendrakar       const long status = m_pTracks->Parse();
959*103e46e4SHarish Mahendrakar 
960*103e46e4SHarish Mahendrakar       if (status)
961*103e46e4SHarish Mahendrakar         return status;
962*103e46e4SHarish Mahendrakar     } else if (id == libwebm::kMkvCues) {
963*103e46e4SHarish Mahendrakar       if (m_pCues == NULL) {
964*103e46e4SHarish Mahendrakar         m_pCues = new (std::nothrow)
965*103e46e4SHarish Mahendrakar             Cues(this, pos, size, element_start, element_size);
966*103e46e4SHarish Mahendrakar 
967*103e46e4SHarish Mahendrakar         if (m_pCues == NULL)
968*103e46e4SHarish Mahendrakar           return -1;
969*103e46e4SHarish Mahendrakar       }
970*103e46e4SHarish Mahendrakar     } else if (id == libwebm::kMkvSeekHead) {
971*103e46e4SHarish Mahendrakar       if (m_pSeekHead == NULL) {
972*103e46e4SHarish Mahendrakar         m_pSeekHead = new (std::nothrow)
973*103e46e4SHarish Mahendrakar             SeekHead(this, pos, size, element_start, element_size);
974*103e46e4SHarish Mahendrakar 
975*103e46e4SHarish Mahendrakar         if (m_pSeekHead == NULL)
976*103e46e4SHarish Mahendrakar           return -1;
977*103e46e4SHarish Mahendrakar 
978*103e46e4SHarish Mahendrakar         const long status = m_pSeekHead->Parse();
979*103e46e4SHarish Mahendrakar 
980*103e46e4SHarish Mahendrakar         if (status)
981*103e46e4SHarish Mahendrakar           return status;
982*103e46e4SHarish Mahendrakar       }
983*103e46e4SHarish Mahendrakar     } else if (id == libwebm::kMkvChapters) {
984*103e46e4SHarish Mahendrakar       if (m_pChapters == NULL) {
985*103e46e4SHarish Mahendrakar         m_pChapters = new (std::nothrow)
986*103e46e4SHarish Mahendrakar             Chapters(this, pos, size, element_start, element_size);
987*103e46e4SHarish Mahendrakar 
988*103e46e4SHarish Mahendrakar         if (m_pChapters == NULL)
989*103e46e4SHarish Mahendrakar           return -1;
990*103e46e4SHarish Mahendrakar 
991*103e46e4SHarish Mahendrakar         const long status = m_pChapters->Parse();
992*103e46e4SHarish Mahendrakar 
993*103e46e4SHarish Mahendrakar         if (status)
994*103e46e4SHarish Mahendrakar           return status;
995*103e46e4SHarish Mahendrakar       }
996*103e46e4SHarish Mahendrakar     } else if (id == libwebm::kMkvTags) {
997*103e46e4SHarish Mahendrakar       if (m_pTags == NULL) {
998*103e46e4SHarish Mahendrakar         m_pTags = new (std::nothrow)
999*103e46e4SHarish Mahendrakar             Tags(this, pos, size, element_start, element_size);
1000*103e46e4SHarish Mahendrakar 
1001*103e46e4SHarish Mahendrakar         if (m_pTags == NULL)
1002*103e46e4SHarish Mahendrakar           return -1;
1003*103e46e4SHarish Mahendrakar 
1004*103e46e4SHarish Mahendrakar         const long status = m_pTags->Parse();
1005*103e46e4SHarish Mahendrakar 
1006*103e46e4SHarish Mahendrakar         if (status)
1007*103e46e4SHarish Mahendrakar           return status;
1008*103e46e4SHarish Mahendrakar       }
1009*103e46e4SHarish Mahendrakar     }
1010*103e46e4SHarish Mahendrakar 
1011*103e46e4SHarish Mahendrakar     m_pos = pos + size;  // consume payload
1012*103e46e4SHarish Mahendrakar   }
1013*103e46e4SHarish Mahendrakar 
1014*103e46e4SHarish Mahendrakar   if (segment_stop >= 0 && m_pos > segment_stop)
1015*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
1016*103e46e4SHarish Mahendrakar 
1017*103e46e4SHarish Mahendrakar   if (m_pInfo == NULL)  // TODO: liberalize this behavior
1018*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
1019*103e46e4SHarish Mahendrakar 
1020*103e46e4SHarish Mahendrakar   if (m_pTracks == NULL)
1021*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
1022*103e46e4SHarish Mahendrakar 
1023*103e46e4SHarish Mahendrakar   return 0;  // success
1024*103e46e4SHarish Mahendrakar }
1025*103e46e4SHarish Mahendrakar 
LoadCluster(long long & pos,long & len)1026*103e46e4SHarish Mahendrakar long Segment::LoadCluster(long long& pos, long& len) {
1027*103e46e4SHarish Mahendrakar   for (;;) {
1028*103e46e4SHarish Mahendrakar     const long result = DoLoadCluster(pos, len);
1029*103e46e4SHarish Mahendrakar 
1030*103e46e4SHarish Mahendrakar     if (result <= 1)
1031*103e46e4SHarish Mahendrakar       return result;
1032*103e46e4SHarish Mahendrakar   }
1033*103e46e4SHarish Mahendrakar }
1034*103e46e4SHarish Mahendrakar 
DoLoadCluster(long long & pos,long & len)1035*103e46e4SHarish Mahendrakar long Segment::DoLoadCluster(long long& pos, long& len) {
1036*103e46e4SHarish Mahendrakar   if (m_pos < 0)
1037*103e46e4SHarish Mahendrakar     return DoLoadClusterUnknownSize(pos, len);
1038*103e46e4SHarish Mahendrakar 
1039*103e46e4SHarish Mahendrakar   long long total, avail;
1040*103e46e4SHarish Mahendrakar 
1041*103e46e4SHarish Mahendrakar   long status = m_pReader->Length(&total, &avail);
1042*103e46e4SHarish Mahendrakar 
1043*103e46e4SHarish Mahendrakar   if (status < 0)  // error
1044*103e46e4SHarish Mahendrakar     return status;
1045*103e46e4SHarish Mahendrakar 
1046*103e46e4SHarish Mahendrakar   if (total >= 0 && avail > total)
1047*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
1048*103e46e4SHarish Mahendrakar 
1049*103e46e4SHarish Mahendrakar   const long long segment_stop = (m_size < 0) ? -1 : m_start + m_size;
1050*103e46e4SHarish Mahendrakar 
1051*103e46e4SHarish Mahendrakar   long long cluster_off = -1;  // offset relative to start of segment
1052*103e46e4SHarish Mahendrakar   long long cluster_size = -1;  // size of cluster payload
1053*103e46e4SHarish Mahendrakar 
1054*103e46e4SHarish Mahendrakar   for (;;) {
1055*103e46e4SHarish Mahendrakar     if ((total >= 0) && (m_pos >= total))
1056*103e46e4SHarish Mahendrakar       return 1;  // no more clusters
1057*103e46e4SHarish Mahendrakar 
1058*103e46e4SHarish Mahendrakar     if ((segment_stop >= 0) && (m_pos >= segment_stop))
1059*103e46e4SHarish Mahendrakar       return 1;  // no more clusters
1060*103e46e4SHarish Mahendrakar 
1061*103e46e4SHarish Mahendrakar     pos = m_pos;
1062*103e46e4SHarish Mahendrakar 
1063*103e46e4SHarish Mahendrakar     // Read ID
1064*103e46e4SHarish Mahendrakar 
1065*103e46e4SHarish Mahendrakar     if ((pos + 1) > avail) {
1066*103e46e4SHarish Mahendrakar       len = 1;
1067*103e46e4SHarish Mahendrakar       return E_BUFFER_NOT_FULL;
1068*103e46e4SHarish Mahendrakar     }
1069*103e46e4SHarish Mahendrakar 
1070*103e46e4SHarish Mahendrakar     long long result = GetUIntLength(m_pReader, pos, len);
1071*103e46e4SHarish Mahendrakar 
1072*103e46e4SHarish Mahendrakar     if (result < 0)  // error
1073*103e46e4SHarish Mahendrakar       return static_cast<long>(result);
1074*103e46e4SHarish Mahendrakar 
1075*103e46e4SHarish Mahendrakar     if (result > 0)
1076*103e46e4SHarish Mahendrakar       return E_BUFFER_NOT_FULL;
1077*103e46e4SHarish Mahendrakar 
1078*103e46e4SHarish Mahendrakar     if ((segment_stop >= 0) && ((pos + len) > segment_stop))
1079*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
1080*103e46e4SHarish Mahendrakar 
1081*103e46e4SHarish Mahendrakar     if ((pos + len) > avail)
1082*103e46e4SHarish Mahendrakar       return E_BUFFER_NOT_FULL;
1083*103e46e4SHarish Mahendrakar 
1084*103e46e4SHarish Mahendrakar     const long long idpos = pos;
1085*103e46e4SHarish Mahendrakar     const long long id = ReadID(m_pReader, idpos, len);
1086*103e46e4SHarish Mahendrakar 
1087*103e46e4SHarish Mahendrakar     if (id < 0)
1088*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
1089*103e46e4SHarish Mahendrakar 
1090*103e46e4SHarish Mahendrakar     pos += len;  // consume ID
1091*103e46e4SHarish Mahendrakar 
1092*103e46e4SHarish Mahendrakar     // Read Size
1093*103e46e4SHarish Mahendrakar 
1094*103e46e4SHarish Mahendrakar     if ((pos + 1) > avail) {
1095*103e46e4SHarish Mahendrakar       len = 1;
1096*103e46e4SHarish Mahendrakar       return E_BUFFER_NOT_FULL;
1097*103e46e4SHarish Mahendrakar     }
1098*103e46e4SHarish Mahendrakar 
1099*103e46e4SHarish Mahendrakar     result = GetUIntLength(m_pReader, pos, len);
1100*103e46e4SHarish Mahendrakar 
1101*103e46e4SHarish Mahendrakar     if (result < 0)  // error
1102*103e46e4SHarish Mahendrakar       return static_cast<long>(result);
1103*103e46e4SHarish Mahendrakar 
1104*103e46e4SHarish Mahendrakar     if (result > 0)
1105*103e46e4SHarish Mahendrakar       return E_BUFFER_NOT_FULL;
1106*103e46e4SHarish Mahendrakar 
1107*103e46e4SHarish Mahendrakar     if ((segment_stop >= 0) && ((pos + len) > segment_stop))
1108*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
1109*103e46e4SHarish Mahendrakar 
1110*103e46e4SHarish Mahendrakar     if ((pos + len) > avail)
1111*103e46e4SHarish Mahendrakar       return E_BUFFER_NOT_FULL;
1112*103e46e4SHarish Mahendrakar 
1113*103e46e4SHarish Mahendrakar     const long long size = ReadUInt(m_pReader, pos, len);
1114*103e46e4SHarish Mahendrakar 
1115*103e46e4SHarish Mahendrakar     if (size < 0)  // error
1116*103e46e4SHarish Mahendrakar       return static_cast<long>(size);
1117*103e46e4SHarish Mahendrakar 
1118*103e46e4SHarish Mahendrakar     pos += len;  // consume length of size of element
1119*103e46e4SHarish Mahendrakar 
1120*103e46e4SHarish Mahendrakar     // pos now points to start of payload
1121*103e46e4SHarish Mahendrakar 
1122*103e46e4SHarish Mahendrakar     if (size == 0) {
1123*103e46e4SHarish Mahendrakar       // Missing element payload: move on.
1124*103e46e4SHarish Mahendrakar       m_pos = pos;
1125*103e46e4SHarish Mahendrakar       continue;
1126*103e46e4SHarish Mahendrakar     }
1127*103e46e4SHarish Mahendrakar 
1128*103e46e4SHarish Mahendrakar     const long long unknown_size = (1LL << (7 * len)) - 1;
1129*103e46e4SHarish Mahendrakar 
1130*103e46e4SHarish Mahendrakar     if ((segment_stop >= 0) && (size != unknown_size) &&
1131*103e46e4SHarish Mahendrakar         ((pos + size) > segment_stop)) {
1132*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
1133*103e46e4SHarish Mahendrakar     }
1134*103e46e4SHarish Mahendrakar 
1135*103e46e4SHarish Mahendrakar     if (id == libwebm::kMkvCues) {
1136*103e46e4SHarish Mahendrakar       if (size == unknown_size) {
1137*103e46e4SHarish Mahendrakar         // Cues element of unknown size: Not supported.
1138*103e46e4SHarish Mahendrakar         return E_FILE_FORMAT_INVALID;
1139*103e46e4SHarish Mahendrakar       }
1140*103e46e4SHarish Mahendrakar 
1141*103e46e4SHarish Mahendrakar       if (m_pCues == NULL) {
1142*103e46e4SHarish Mahendrakar         const long long element_size = (pos - idpos) + size;
1143*103e46e4SHarish Mahendrakar 
1144*103e46e4SHarish Mahendrakar         m_pCues = new (std::nothrow) Cues(this, pos, size, idpos, element_size);
1145*103e46e4SHarish Mahendrakar         if (m_pCues == NULL)
1146*103e46e4SHarish Mahendrakar           return -1;
1147*103e46e4SHarish Mahendrakar       }
1148*103e46e4SHarish Mahendrakar 
1149*103e46e4SHarish Mahendrakar       m_pos = pos + size;  // consume payload
1150*103e46e4SHarish Mahendrakar       continue;
1151*103e46e4SHarish Mahendrakar     }
1152*103e46e4SHarish Mahendrakar 
1153*103e46e4SHarish Mahendrakar     if (id != libwebm::kMkvCluster) {
1154*103e46e4SHarish Mahendrakar       // Besides the Segment, Libwebm allows only cluster elements of unknown
1155*103e46e4SHarish Mahendrakar       // size. Fail the parse upon encountering a non-cluster element reporting
1156*103e46e4SHarish Mahendrakar       // unknown size.
1157*103e46e4SHarish Mahendrakar       if (size == unknown_size)
1158*103e46e4SHarish Mahendrakar         return E_FILE_FORMAT_INVALID;
1159*103e46e4SHarish Mahendrakar 
1160*103e46e4SHarish Mahendrakar       m_pos = pos + size;  // consume payload
1161*103e46e4SHarish Mahendrakar       continue;
1162*103e46e4SHarish Mahendrakar     }
1163*103e46e4SHarish Mahendrakar 
1164*103e46e4SHarish Mahendrakar     // We have a cluster.
1165*103e46e4SHarish Mahendrakar 
1166*103e46e4SHarish Mahendrakar     cluster_off = idpos - m_start;  // relative pos
1167*103e46e4SHarish Mahendrakar 
1168*103e46e4SHarish Mahendrakar     if (size != unknown_size)
1169*103e46e4SHarish Mahendrakar       cluster_size = size;
1170*103e46e4SHarish Mahendrakar 
1171*103e46e4SHarish Mahendrakar     break;
1172*103e46e4SHarish Mahendrakar   }
1173*103e46e4SHarish Mahendrakar 
1174*103e46e4SHarish Mahendrakar   if (cluster_off < 0) {
1175*103e46e4SHarish Mahendrakar     // No cluster, die.
1176*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
1177*103e46e4SHarish Mahendrakar   }
1178*103e46e4SHarish Mahendrakar 
1179*103e46e4SHarish Mahendrakar   long long pos_;
1180*103e46e4SHarish Mahendrakar   long len_;
1181*103e46e4SHarish Mahendrakar 
1182*103e46e4SHarish Mahendrakar   status = Cluster::HasBlockEntries(this, cluster_off, pos_, len_);
1183*103e46e4SHarish Mahendrakar 
1184*103e46e4SHarish Mahendrakar   if (status < 0) {  // error, or underflow
1185*103e46e4SHarish Mahendrakar     pos = pos_;
1186*103e46e4SHarish Mahendrakar     len = len_;
1187*103e46e4SHarish Mahendrakar 
1188*103e46e4SHarish Mahendrakar     return status;
1189*103e46e4SHarish Mahendrakar   }
1190*103e46e4SHarish Mahendrakar 
1191*103e46e4SHarish Mahendrakar   // status == 0 means "no block entries found"
1192*103e46e4SHarish Mahendrakar   // status > 0 means "found at least one block entry"
1193*103e46e4SHarish Mahendrakar 
1194*103e46e4SHarish Mahendrakar   // TODO:
1195*103e46e4SHarish Mahendrakar   // The issue here is that the segment increments its own
1196*103e46e4SHarish Mahendrakar   // pos ptr past the most recent cluster parsed, and then
1197*103e46e4SHarish Mahendrakar   // starts from there to parse the next cluster.  If we
1198*103e46e4SHarish Mahendrakar   // don't know the size of the current cluster, then we
1199*103e46e4SHarish Mahendrakar   // must either parse its payload (as we do below), looking
1200*103e46e4SHarish Mahendrakar   // for the cluster (or cues) ID to terminate the parse.
1201*103e46e4SHarish Mahendrakar   // This isn't really what we want: rather, we really need
1202*103e46e4SHarish Mahendrakar   // a way to create the curr cluster object immediately.
1203*103e46e4SHarish Mahendrakar   // The pity is that cluster::parse can determine its own
1204*103e46e4SHarish Mahendrakar   // boundary, and we largely duplicate that same logic here.
1205*103e46e4SHarish Mahendrakar   //
1206*103e46e4SHarish Mahendrakar   // Maybe we need to get rid of our look-ahead preloading
1207*103e46e4SHarish Mahendrakar   // in source::parse???
1208*103e46e4SHarish Mahendrakar   //
1209*103e46e4SHarish Mahendrakar   // As we're parsing the blocks in the curr cluster
1210*103e46e4SHarish Mahendrakar   //(in cluster::parse), we should have some way to signal
1211*103e46e4SHarish Mahendrakar   // to the segment that we have determined the boundary,
1212*103e46e4SHarish Mahendrakar   // so it can adjust its own segment::m_pos member.
1213*103e46e4SHarish Mahendrakar   //
1214*103e46e4SHarish Mahendrakar   // The problem is that we're asserting in asyncreadinit,
1215*103e46e4SHarish Mahendrakar   // because we adjust the pos down to the curr seek pos,
1216*103e46e4SHarish Mahendrakar   // and the resulting adjusted len is > 2GB.  I'm suspicious
1217*103e46e4SHarish Mahendrakar   // that this is even correct, but even if it is, we can't
1218*103e46e4SHarish Mahendrakar   // be loading that much data in the cache anyway.
1219*103e46e4SHarish Mahendrakar 
1220*103e46e4SHarish Mahendrakar   const long idx = m_clusterCount;
1221*103e46e4SHarish Mahendrakar 
1222*103e46e4SHarish Mahendrakar   if (m_clusterPreloadCount > 0) {
1223*103e46e4SHarish Mahendrakar     if (idx >= m_clusterSize)
1224*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
1225*103e46e4SHarish Mahendrakar 
1226*103e46e4SHarish Mahendrakar     Cluster* const pCluster = m_clusters[idx];
1227*103e46e4SHarish Mahendrakar     if (pCluster == NULL || pCluster->m_index >= 0)
1228*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
1229*103e46e4SHarish Mahendrakar 
1230*103e46e4SHarish Mahendrakar     const long long off = pCluster->GetPosition();
1231*103e46e4SHarish Mahendrakar     if (off < 0)
1232*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
1233*103e46e4SHarish Mahendrakar 
1234*103e46e4SHarish Mahendrakar     if (off == cluster_off) {  // preloaded already
1235*103e46e4SHarish Mahendrakar       if (status == 0)  // no entries found
1236*103e46e4SHarish Mahendrakar         return E_FILE_FORMAT_INVALID;
1237*103e46e4SHarish Mahendrakar 
1238*103e46e4SHarish Mahendrakar       if (cluster_size >= 0)
1239*103e46e4SHarish Mahendrakar         pos += cluster_size;
1240*103e46e4SHarish Mahendrakar       else {
1241*103e46e4SHarish Mahendrakar         const long long element_size = pCluster->GetElementSize();
1242*103e46e4SHarish Mahendrakar 
1243*103e46e4SHarish Mahendrakar         if (element_size <= 0)
1244*103e46e4SHarish Mahendrakar           return E_FILE_FORMAT_INVALID;  // TODO: handle this case
1245*103e46e4SHarish Mahendrakar 
1246*103e46e4SHarish Mahendrakar         pos = pCluster->m_element_start + element_size;
1247*103e46e4SHarish Mahendrakar       }
1248*103e46e4SHarish Mahendrakar 
1249*103e46e4SHarish Mahendrakar       pCluster->m_index = idx;  // move from preloaded to loaded
1250*103e46e4SHarish Mahendrakar       ++m_clusterCount;
1251*103e46e4SHarish Mahendrakar       --m_clusterPreloadCount;
1252*103e46e4SHarish Mahendrakar 
1253*103e46e4SHarish Mahendrakar       m_pos = pos;  // consume payload
1254*103e46e4SHarish Mahendrakar       if (segment_stop >= 0 && m_pos > segment_stop)
1255*103e46e4SHarish Mahendrakar         return E_FILE_FORMAT_INVALID;
1256*103e46e4SHarish Mahendrakar 
1257*103e46e4SHarish Mahendrakar       return 0;  // success
1258*103e46e4SHarish Mahendrakar     }
1259*103e46e4SHarish Mahendrakar   }
1260*103e46e4SHarish Mahendrakar 
1261*103e46e4SHarish Mahendrakar   if (status == 0) {  // no entries found
1262*103e46e4SHarish Mahendrakar     if (cluster_size >= 0)
1263*103e46e4SHarish Mahendrakar       pos += cluster_size;
1264*103e46e4SHarish Mahendrakar 
1265*103e46e4SHarish Mahendrakar     if ((total >= 0) && (pos >= total)) {
1266*103e46e4SHarish Mahendrakar       m_pos = total;
1267*103e46e4SHarish Mahendrakar       return 1;  // no more clusters
1268*103e46e4SHarish Mahendrakar     }
1269*103e46e4SHarish Mahendrakar 
1270*103e46e4SHarish Mahendrakar     if ((segment_stop >= 0) && (pos >= segment_stop)) {
1271*103e46e4SHarish Mahendrakar       m_pos = segment_stop;
1272*103e46e4SHarish Mahendrakar       return 1;  // no more clusters
1273*103e46e4SHarish Mahendrakar     }
1274*103e46e4SHarish Mahendrakar 
1275*103e46e4SHarish Mahendrakar     m_pos = pos;
1276*103e46e4SHarish Mahendrakar     return 2;  // try again
1277*103e46e4SHarish Mahendrakar   }
1278*103e46e4SHarish Mahendrakar 
1279*103e46e4SHarish Mahendrakar   // status > 0 means we have an entry
1280*103e46e4SHarish Mahendrakar 
1281*103e46e4SHarish Mahendrakar   Cluster* const pCluster = Cluster::Create(this, idx, cluster_off);
1282*103e46e4SHarish Mahendrakar   if (pCluster == NULL)
1283*103e46e4SHarish Mahendrakar     return -1;
1284*103e46e4SHarish Mahendrakar 
1285*103e46e4SHarish Mahendrakar   if (!AppendCluster(pCluster)) {
1286*103e46e4SHarish Mahendrakar     delete pCluster;
1287*103e46e4SHarish Mahendrakar     return -1;
1288*103e46e4SHarish Mahendrakar   }
1289*103e46e4SHarish Mahendrakar 
1290*103e46e4SHarish Mahendrakar   if (cluster_size >= 0) {
1291*103e46e4SHarish Mahendrakar     pos += cluster_size;
1292*103e46e4SHarish Mahendrakar 
1293*103e46e4SHarish Mahendrakar     m_pos = pos;
1294*103e46e4SHarish Mahendrakar 
1295*103e46e4SHarish Mahendrakar     if (segment_stop > 0 && m_pos > segment_stop)
1296*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
1297*103e46e4SHarish Mahendrakar 
1298*103e46e4SHarish Mahendrakar     return 0;
1299*103e46e4SHarish Mahendrakar   }
1300*103e46e4SHarish Mahendrakar 
1301*103e46e4SHarish Mahendrakar   m_pUnknownSize = pCluster;
1302*103e46e4SHarish Mahendrakar   m_pos = -pos;
1303*103e46e4SHarish Mahendrakar 
1304*103e46e4SHarish Mahendrakar   return 0;  // partial success, since we have a new cluster
1305*103e46e4SHarish Mahendrakar 
1306*103e46e4SHarish Mahendrakar   // status == 0 means "no block entries found"
1307*103e46e4SHarish Mahendrakar   // pos designates start of payload
1308*103e46e4SHarish Mahendrakar   // m_pos has NOT been adjusted yet (in case we need to come back here)
1309*103e46e4SHarish Mahendrakar }
1310*103e46e4SHarish Mahendrakar 
DoLoadClusterUnknownSize(long long & pos,long & len)1311*103e46e4SHarish Mahendrakar long Segment::DoLoadClusterUnknownSize(long long& pos, long& len) {
1312*103e46e4SHarish Mahendrakar   if (m_pos >= 0 || m_pUnknownSize == NULL)
1313*103e46e4SHarish Mahendrakar     return E_PARSE_FAILED;
1314*103e46e4SHarish Mahendrakar 
1315*103e46e4SHarish Mahendrakar   const long status = m_pUnknownSize->Parse(pos, len);
1316*103e46e4SHarish Mahendrakar 
1317*103e46e4SHarish Mahendrakar   if (status < 0)  // error or underflow
1318*103e46e4SHarish Mahendrakar     return status;
1319*103e46e4SHarish Mahendrakar 
1320*103e46e4SHarish Mahendrakar   if (status == 0)  // parsed a block
1321*103e46e4SHarish Mahendrakar     return 2;  // continue parsing
1322*103e46e4SHarish Mahendrakar 
1323*103e46e4SHarish Mahendrakar   const long long start = m_pUnknownSize->m_element_start;
1324*103e46e4SHarish Mahendrakar   const long long size = m_pUnknownSize->GetElementSize();
1325*103e46e4SHarish Mahendrakar 
1326*103e46e4SHarish Mahendrakar   if (size < 0)
1327*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
1328*103e46e4SHarish Mahendrakar 
1329*103e46e4SHarish Mahendrakar   pos = start + size;
1330*103e46e4SHarish Mahendrakar   m_pos = pos;
1331*103e46e4SHarish Mahendrakar 
1332*103e46e4SHarish Mahendrakar   m_pUnknownSize = 0;
1333*103e46e4SHarish Mahendrakar 
1334*103e46e4SHarish Mahendrakar   return 2;  // continue parsing
1335*103e46e4SHarish Mahendrakar }
1336*103e46e4SHarish Mahendrakar 
AppendCluster(Cluster * pCluster)1337*103e46e4SHarish Mahendrakar bool Segment::AppendCluster(Cluster* pCluster) {
1338*103e46e4SHarish Mahendrakar   if (pCluster == NULL || pCluster->m_index < 0)
1339*103e46e4SHarish Mahendrakar     return false;
1340*103e46e4SHarish Mahendrakar 
1341*103e46e4SHarish Mahendrakar   const long count = m_clusterCount + m_clusterPreloadCount;
1342*103e46e4SHarish Mahendrakar 
1343*103e46e4SHarish Mahendrakar   long& size = m_clusterSize;
1344*103e46e4SHarish Mahendrakar   const long idx = pCluster->m_index;
1345*103e46e4SHarish Mahendrakar 
1346*103e46e4SHarish Mahendrakar   if (size < count || idx != m_clusterCount)
1347*103e46e4SHarish Mahendrakar     return false;
1348*103e46e4SHarish Mahendrakar 
1349*103e46e4SHarish Mahendrakar   if (count >= size) {
1350*103e46e4SHarish Mahendrakar     const long n = (size <= 0) ? 2048 : 2 * size;
1351*103e46e4SHarish Mahendrakar 
1352*103e46e4SHarish Mahendrakar     Cluster** const qq = new (std::nothrow) Cluster*[n];
1353*103e46e4SHarish Mahendrakar     if (qq == NULL)
1354*103e46e4SHarish Mahendrakar       return false;
1355*103e46e4SHarish Mahendrakar 
1356*103e46e4SHarish Mahendrakar     Cluster** q = qq;
1357*103e46e4SHarish Mahendrakar     Cluster** p = m_clusters;
1358*103e46e4SHarish Mahendrakar     Cluster** const pp = p + count;
1359*103e46e4SHarish Mahendrakar 
1360*103e46e4SHarish Mahendrakar     while (p != pp)
1361*103e46e4SHarish Mahendrakar       *q++ = *p++;
1362*103e46e4SHarish Mahendrakar 
1363*103e46e4SHarish Mahendrakar     delete[] m_clusters;
1364*103e46e4SHarish Mahendrakar 
1365*103e46e4SHarish Mahendrakar     m_clusters = qq;
1366*103e46e4SHarish Mahendrakar     size = n;
1367*103e46e4SHarish Mahendrakar   }
1368*103e46e4SHarish Mahendrakar 
1369*103e46e4SHarish Mahendrakar   if (m_clusterPreloadCount > 0) {
1370*103e46e4SHarish Mahendrakar     Cluster** const p = m_clusters + m_clusterCount;
1371*103e46e4SHarish Mahendrakar     if (*p == NULL || (*p)->m_index >= 0)
1372*103e46e4SHarish Mahendrakar       return false;
1373*103e46e4SHarish Mahendrakar 
1374*103e46e4SHarish Mahendrakar     Cluster** q = p + m_clusterPreloadCount;
1375*103e46e4SHarish Mahendrakar     if (q >= (m_clusters + size))
1376*103e46e4SHarish Mahendrakar       return false;
1377*103e46e4SHarish Mahendrakar 
1378*103e46e4SHarish Mahendrakar     for (;;) {
1379*103e46e4SHarish Mahendrakar       Cluster** const qq = q - 1;
1380*103e46e4SHarish Mahendrakar       if ((*qq)->m_index >= 0)
1381*103e46e4SHarish Mahendrakar         return false;
1382*103e46e4SHarish Mahendrakar 
1383*103e46e4SHarish Mahendrakar       *q = *qq;
1384*103e46e4SHarish Mahendrakar       q = qq;
1385*103e46e4SHarish Mahendrakar 
1386*103e46e4SHarish Mahendrakar       if (q == p)
1387*103e46e4SHarish Mahendrakar         break;
1388*103e46e4SHarish Mahendrakar     }
1389*103e46e4SHarish Mahendrakar   }
1390*103e46e4SHarish Mahendrakar 
1391*103e46e4SHarish Mahendrakar   m_clusters[idx] = pCluster;
1392*103e46e4SHarish Mahendrakar   ++m_clusterCount;
1393*103e46e4SHarish Mahendrakar   return true;
1394*103e46e4SHarish Mahendrakar }
1395*103e46e4SHarish Mahendrakar 
PreloadCluster(Cluster * pCluster,ptrdiff_t idx)1396*103e46e4SHarish Mahendrakar bool Segment::PreloadCluster(Cluster* pCluster, ptrdiff_t idx) {
1397*103e46e4SHarish Mahendrakar   if (pCluster == NULL || pCluster->m_index >= 0 || idx < m_clusterCount)
1398*103e46e4SHarish Mahendrakar     return false;
1399*103e46e4SHarish Mahendrakar 
1400*103e46e4SHarish Mahendrakar   const long count = m_clusterCount + m_clusterPreloadCount;
1401*103e46e4SHarish Mahendrakar 
1402*103e46e4SHarish Mahendrakar   long& size = m_clusterSize;
1403*103e46e4SHarish Mahendrakar   if (size < count)
1404*103e46e4SHarish Mahendrakar     return false;
1405*103e46e4SHarish Mahendrakar 
1406*103e46e4SHarish Mahendrakar   if (count >= size) {
1407*103e46e4SHarish Mahendrakar     const long n = (size <= 0) ? 2048 : 2 * size;
1408*103e46e4SHarish Mahendrakar 
1409*103e46e4SHarish Mahendrakar     Cluster** const qq = new (std::nothrow) Cluster*[n];
1410*103e46e4SHarish Mahendrakar     if (qq == NULL)
1411*103e46e4SHarish Mahendrakar       return false;
1412*103e46e4SHarish Mahendrakar     Cluster** q = qq;
1413*103e46e4SHarish Mahendrakar 
1414*103e46e4SHarish Mahendrakar     Cluster** p = m_clusters;
1415*103e46e4SHarish Mahendrakar     Cluster** const pp = p + count;
1416*103e46e4SHarish Mahendrakar 
1417*103e46e4SHarish Mahendrakar     while (p != pp)
1418*103e46e4SHarish Mahendrakar       *q++ = *p++;
1419*103e46e4SHarish Mahendrakar 
1420*103e46e4SHarish Mahendrakar     delete[] m_clusters;
1421*103e46e4SHarish Mahendrakar 
1422*103e46e4SHarish Mahendrakar     m_clusters = qq;
1423*103e46e4SHarish Mahendrakar     size = n;
1424*103e46e4SHarish Mahendrakar   }
1425*103e46e4SHarish Mahendrakar 
1426*103e46e4SHarish Mahendrakar   if (m_clusters == NULL)
1427*103e46e4SHarish Mahendrakar     return false;
1428*103e46e4SHarish Mahendrakar 
1429*103e46e4SHarish Mahendrakar   Cluster** const p = m_clusters + idx;
1430*103e46e4SHarish Mahendrakar 
1431*103e46e4SHarish Mahendrakar   Cluster** q = m_clusters + count;
1432*103e46e4SHarish Mahendrakar   if (q < p || q >= (m_clusters + size))
1433*103e46e4SHarish Mahendrakar     return false;
1434*103e46e4SHarish Mahendrakar 
1435*103e46e4SHarish Mahendrakar   while (q > p) {
1436*103e46e4SHarish Mahendrakar     Cluster** const qq = q - 1;
1437*103e46e4SHarish Mahendrakar 
1438*103e46e4SHarish Mahendrakar     if ((*qq)->m_index >= 0)
1439*103e46e4SHarish Mahendrakar       return false;
1440*103e46e4SHarish Mahendrakar 
1441*103e46e4SHarish Mahendrakar     *q = *qq;
1442*103e46e4SHarish Mahendrakar     q = qq;
1443*103e46e4SHarish Mahendrakar   }
1444*103e46e4SHarish Mahendrakar 
1445*103e46e4SHarish Mahendrakar   m_clusters[idx] = pCluster;
1446*103e46e4SHarish Mahendrakar   ++m_clusterPreloadCount;
1447*103e46e4SHarish Mahendrakar   return true;
1448*103e46e4SHarish Mahendrakar }
1449*103e46e4SHarish Mahendrakar 
Load()1450*103e46e4SHarish Mahendrakar long Segment::Load() {
1451*103e46e4SHarish Mahendrakar   if (m_clusters != NULL || m_clusterSize != 0 || m_clusterCount != 0)
1452*103e46e4SHarish Mahendrakar     return E_PARSE_FAILED;
1453*103e46e4SHarish Mahendrakar 
1454*103e46e4SHarish Mahendrakar   // Outermost (level 0) segment object has been constructed,
1455*103e46e4SHarish Mahendrakar   // and pos designates start of payload.  We need to find the
1456*103e46e4SHarish Mahendrakar   // inner (level 1) elements.
1457*103e46e4SHarish Mahendrakar 
1458*103e46e4SHarish Mahendrakar   const long long header_status = ParseHeaders();
1459*103e46e4SHarish Mahendrakar 
1460*103e46e4SHarish Mahendrakar   if (header_status < 0)  // error
1461*103e46e4SHarish Mahendrakar     return static_cast<long>(header_status);
1462*103e46e4SHarish Mahendrakar 
1463*103e46e4SHarish Mahendrakar   if (header_status > 0)  // underflow
1464*103e46e4SHarish Mahendrakar     return E_BUFFER_NOT_FULL;
1465*103e46e4SHarish Mahendrakar 
1466*103e46e4SHarish Mahendrakar   if (m_pInfo == NULL || m_pTracks == NULL)
1467*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
1468*103e46e4SHarish Mahendrakar 
1469*103e46e4SHarish Mahendrakar   for (;;) {
1470*103e46e4SHarish Mahendrakar     const long status = LoadCluster();
1471*103e46e4SHarish Mahendrakar 
1472*103e46e4SHarish Mahendrakar     if (status < 0)  // error
1473*103e46e4SHarish Mahendrakar       return status;
1474*103e46e4SHarish Mahendrakar 
1475*103e46e4SHarish Mahendrakar     if (status >= 1)  // no more clusters
1476*103e46e4SHarish Mahendrakar       return 0;
1477*103e46e4SHarish Mahendrakar   }
1478*103e46e4SHarish Mahendrakar }
1479*103e46e4SHarish Mahendrakar 
Entry()1480*103e46e4SHarish Mahendrakar SeekHead::Entry::Entry() : id(0), pos(0), element_start(0), element_size(0) {}
1481*103e46e4SHarish Mahendrakar 
SeekHead(Segment * pSegment,long long start,long long size_,long long element_start,long long element_size)1482*103e46e4SHarish Mahendrakar SeekHead::SeekHead(Segment* pSegment, long long start, long long size_,
1483*103e46e4SHarish Mahendrakar                    long long element_start, long long element_size)
1484*103e46e4SHarish Mahendrakar     : m_pSegment(pSegment),
1485*103e46e4SHarish Mahendrakar       m_start(start),
1486*103e46e4SHarish Mahendrakar       m_size(size_),
1487*103e46e4SHarish Mahendrakar       m_element_start(element_start),
1488*103e46e4SHarish Mahendrakar       m_element_size(element_size),
1489*103e46e4SHarish Mahendrakar       m_entries(0),
1490*103e46e4SHarish Mahendrakar       m_entry_count(0),
1491*103e46e4SHarish Mahendrakar       m_void_elements(0),
1492*103e46e4SHarish Mahendrakar       m_void_element_count(0) {}
1493*103e46e4SHarish Mahendrakar 
~SeekHead()1494*103e46e4SHarish Mahendrakar SeekHead::~SeekHead() {
1495*103e46e4SHarish Mahendrakar   delete[] m_entries;
1496*103e46e4SHarish Mahendrakar   delete[] m_void_elements;
1497*103e46e4SHarish Mahendrakar }
1498*103e46e4SHarish Mahendrakar 
Parse()1499*103e46e4SHarish Mahendrakar long SeekHead::Parse() {
1500*103e46e4SHarish Mahendrakar   IMkvReader* const pReader = m_pSegment->m_pReader;
1501*103e46e4SHarish Mahendrakar 
1502*103e46e4SHarish Mahendrakar   long long pos = m_start;
1503*103e46e4SHarish Mahendrakar   const long long stop = m_start + m_size;
1504*103e46e4SHarish Mahendrakar 
1505*103e46e4SHarish Mahendrakar   // first count the seek head entries
1506*103e46e4SHarish Mahendrakar 
1507*103e46e4SHarish Mahendrakar   long long entry_count = 0;
1508*103e46e4SHarish Mahendrakar   long long void_element_count = 0;
1509*103e46e4SHarish Mahendrakar 
1510*103e46e4SHarish Mahendrakar   while (pos < stop) {
1511*103e46e4SHarish Mahendrakar     long long id, size;
1512*103e46e4SHarish Mahendrakar 
1513*103e46e4SHarish Mahendrakar     const long status = ParseElementHeader(pReader, pos, stop, id, size);
1514*103e46e4SHarish Mahendrakar 
1515*103e46e4SHarish Mahendrakar     if (status < 0)  // error
1516*103e46e4SHarish Mahendrakar       return status;
1517*103e46e4SHarish Mahendrakar 
1518*103e46e4SHarish Mahendrakar     if (id == libwebm::kMkvSeek) {
1519*103e46e4SHarish Mahendrakar       ++entry_count;
1520*103e46e4SHarish Mahendrakar       if (entry_count > INT_MAX)
1521*103e46e4SHarish Mahendrakar         return E_PARSE_FAILED;
1522*103e46e4SHarish Mahendrakar     } else if (id == libwebm::kMkvVoid) {
1523*103e46e4SHarish Mahendrakar       ++void_element_count;
1524*103e46e4SHarish Mahendrakar       if (void_element_count > INT_MAX)
1525*103e46e4SHarish Mahendrakar         return E_PARSE_FAILED;
1526*103e46e4SHarish Mahendrakar     }
1527*103e46e4SHarish Mahendrakar 
1528*103e46e4SHarish Mahendrakar     pos += size;  // consume payload
1529*103e46e4SHarish Mahendrakar 
1530*103e46e4SHarish Mahendrakar     if (pos > stop)
1531*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
1532*103e46e4SHarish Mahendrakar   }
1533*103e46e4SHarish Mahendrakar 
1534*103e46e4SHarish Mahendrakar   if (pos != stop)
1535*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
1536*103e46e4SHarish Mahendrakar 
1537*103e46e4SHarish Mahendrakar   if (entry_count > 0) {
1538*103e46e4SHarish Mahendrakar     m_entries = new (std::nothrow) Entry[static_cast<size_t>(entry_count)];
1539*103e46e4SHarish Mahendrakar 
1540*103e46e4SHarish Mahendrakar     if (m_entries == NULL)
1541*103e46e4SHarish Mahendrakar       return -1;
1542*103e46e4SHarish Mahendrakar   }
1543*103e46e4SHarish Mahendrakar 
1544*103e46e4SHarish Mahendrakar   if (void_element_count > 0) {
1545*103e46e4SHarish Mahendrakar     m_void_elements =
1546*103e46e4SHarish Mahendrakar         new (std::nothrow) VoidElement[static_cast<size_t>(void_element_count)];
1547*103e46e4SHarish Mahendrakar 
1548*103e46e4SHarish Mahendrakar     if (m_void_elements == NULL)
1549*103e46e4SHarish Mahendrakar       return -1;
1550*103e46e4SHarish Mahendrakar   }
1551*103e46e4SHarish Mahendrakar 
1552*103e46e4SHarish Mahendrakar   // now parse the entries and void elements
1553*103e46e4SHarish Mahendrakar 
1554*103e46e4SHarish Mahendrakar   Entry* pEntry = m_entries;
1555*103e46e4SHarish Mahendrakar   VoidElement* pVoidElement = m_void_elements;
1556*103e46e4SHarish Mahendrakar 
1557*103e46e4SHarish Mahendrakar   pos = m_start;
1558*103e46e4SHarish Mahendrakar 
1559*103e46e4SHarish Mahendrakar   while (pos < stop) {
1560*103e46e4SHarish Mahendrakar     const long long idpos = pos;
1561*103e46e4SHarish Mahendrakar 
1562*103e46e4SHarish Mahendrakar     long long id, size;
1563*103e46e4SHarish Mahendrakar 
1564*103e46e4SHarish Mahendrakar     const long status = ParseElementHeader(pReader, pos, stop, id, size);
1565*103e46e4SHarish Mahendrakar 
1566*103e46e4SHarish Mahendrakar     if (status < 0)  // error
1567*103e46e4SHarish Mahendrakar       return status;
1568*103e46e4SHarish Mahendrakar 
1569*103e46e4SHarish Mahendrakar     if (id == libwebm::kMkvSeek && entry_count > 0) {
1570*103e46e4SHarish Mahendrakar       if (ParseEntry(pReader, pos, size, pEntry)) {
1571*103e46e4SHarish Mahendrakar         Entry& e = *pEntry++;
1572*103e46e4SHarish Mahendrakar 
1573*103e46e4SHarish Mahendrakar         e.element_start = idpos;
1574*103e46e4SHarish Mahendrakar         e.element_size = (pos + size) - idpos;
1575*103e46e4SHarish Mahendrakar       }
1576*103e46e4SHarish Mahendrakar     } else if (id == libwebm::kMkvVoid && void_element_count > 0) {
1577*103e46e4SHarish Mahendrakar       VoidElement& e = *pVoidElement++;
1578*103e46e4SHarish Mahendrakar 
1579*103e46e4SHarish Mahendrakar       e.element_start = idpos;
1580*103e46e4SHarish Mahendrakar       e.element_size = (pos + size) - idpos;
1581*103e46e4SHarish Mahendrakar     }
1582*103e46e4SHarish Mahendrakar 
1583*103e46e4SHarish Mahendrakar     pos += size;  // consume payload
1584*103e46e4SHarish Mahendrakar     if (pos > stop)
1585*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
1586*103e46e4SHarish Mahendrakar   }
1587*103e46e4SHarish Mahendrakar 
1588*103e46e4SHarish Mahendrakar   if (pos != stop)
1589*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
1590*103e46e4SHarish Mahendrakar 
1591*103e46e4SHarish Mahendrakar   ptrdiff_t count_ = ptrdiff_t(pEntry - m_entries);
1592*103e46e4SHarish Mahendrakar   assert(count_ >= 0);
1593*103e46e4SHarish Mahendrakar   assert(static_cast<long long>(count_) <= entry_count);
1594*103e46e4SHarish Mahendrakar 
1595*103e46e4SHarish Mahendrakar   m_entry_count = static_cast<int>(count_);
1596*103e46e4SHarish Mahendrakar 
1597*103e46e4SHarish Mahendrakar   count_ = ptrdiff_t(pVoidElement - m_void_elements);
1598*103e46e4SHarish Mahendrakar   assert(count_ >= 0);
1599*103e46e4SHarish Mahendrakar   assert(static_cast<long long>(count_) <= void_element_count);
1600*103e46e4SHarish Mahendrakar 
1601*103e46e4SHarish Mahendrakar   m_void_element_count = static_cast<int>(count_);
1602*103e46e4SHarish Mahendrakar 
1603*103e46e4SHarish Mahendrakar   return 0;
1604*103e46e4SHarish Mahendrakar }
1605*103e46e4SHarish Mahendrakar 
GetCount() const1606*103e46e4SHarish Mahendrakar int SeekHead::GetCount() const { return m_entry_count; }
1607*103e46e4SHarish Mahendrakar 
GetEntry(int idx) const1608*103e46e4SHarish Mahendrakar const SeekHead::Entry* SeekHead::GetEntry(int idx) const {
1609*103e46e4SHarish Mahendrakar   if (idx < 0)
1610*103e46e4SHarish Mahendrakar     return 0;
1611*103e46e4SHarish Mahendrakar 
1612*103e46e4SHarish Mahendrakar   if (idx >= m_entry_count)
1613*103e46e4SHarish Mahendrakar     return 0;
1614*103e46e4SHarish Mahendrakar 
1615*103e46e4SHarish Mahendrakar   return m_entries + idx;
1616*103e46e4SHarish Mahendrakar }
1617*103e46e4SHarish Mahendrakar 
GetVoidElementCount() const1618*103e46e4SHarish Mahendrakar int SeekHead::GetVoidElementCount() const { return m_void_element_count; }
1619*103e46e4SHarish Mahendrakar 
GetVoidElement(int idx) const1620*103e46e4SHarish Mahendrakar const SeekHead::VoidElement* SeekHead::GetVoidElement(int idx) const {
1621*103e46e4SHarish Mahendrakar   if (idx < 0)
1622*103e46e4SHarish Mahendrakar     return 0;
1623*103e46e4SHarish Mahendrakar 
1624*103e46e4SHarish Mahendrakar   if (idx >= m_void_element_count)
1625*103e46e4SHarish Mahendrakar     return 0;
1626*103e46e4SHarish Mahendrakar 
1627*103e46e4SHarish Mahendrakar   return m_void_elements + idx;
1628*103e46e4SHarish Mahendrakar }
1629*103e46e4SHarish Mahendrakar 
ParseCues(long long off,long long & pos,long & len)1630*103e46e4SHarish Mahendrakar long Segment::ParseCues(long long off, long long& pos, long& len) {
1631*103e46e4SHarish Mahendrakar   if (m_pCues)
1632*103e46e4SHarish Mahendrakar     return 0;  // success
1633*103e46e4SHarish Mahendrakar 
1634*103e46e4SHarish Mahendrakar   if (off < 0)
1635*103e46e4SHarish Mahendrakar     return -1;
1636*103e46e4SHarish Mahendrakar 
1637*103e46e4SHarish Mahendrakar   long long total, avail;
1638*103e46e4SHarish Mahendrakar 
1639*103e46e4SHarish Mahendrakar   const int status = m_pReader->Length(&total, &avail);
1640*103e46e4SHarish Mahendrakar 
1641*103e46e4SHarish Mahendrakar   if (status < 0)  // error
1642*103e46e4SHarish Mahendrakar     return status;
1643*103e46e4SHarish Mahendrakar 
1644*103e46e4SHarish Mahendrakar   assert((total < 0) || (avail <= total));
1645*103e46e4SHarish Mahendrakar 
1646*103e46e4SHarish Mahendrakar   pos = m_start + off;
1647*103e46e4SHarish Mahendrakar 
1648*103e46e4SHarish Mahendrakar   if ((total < 0) || (pos >= total))
1649*103e46e4SHarish Mahendrakar     return 1;  // don't bother parsing cues
1650*103e46e4SHarish Mahendrakar 
1651*103e46e4SHarish Mahendrakar   const long long element_start = pos;
1652*103e46e4SHarish Mahendrakar   const long long segment_stop = (m_size < 0) ? -1 : m_start + m_size;
1653*103e46e4SHarish Mahendrakar 
1654*103e46e4SHarish Mahendrakar   if ((pos + 1) > avail) {
1655*103e46e4SHarish Mahendrakar     len = 1;
1656*103e46e4SHarish Mahendrakar     return E_BUFFER_NOT_FULL;
1657*103e46e4SHarish Mahendrakar   }
1658*103e46e4SHarish Mahendrakar 
1659*103e46e4SHarish Mahendrakar   long long result = GetUIntLength(m_pReader, pos, len);
1660*103e46e4SHarish Mahendrakar 
1661*103e46e4SHarish Mahendrakar   if (result < 0)  // error
1662*103e46e4SHarish Mahendrakar     return static_cast<long>(result);
1663*103e46e4SHarish Mahendrakar 
1664*103e46e4SHarish Mahendrakar   if (result > 0)  // underflow (weird)
1665*103e46e4SHarish Mahendrakar   {
1666*103e46e4SHarish Mahendrakar     len = 1;
1667*103e46e4SHarish Mahendrakar     return E_BUFFER_NOT_FULL;
1668*103e46e4SHarish Mahendrakar   }
1669*103e46e4SHarish Mahendrakar 
1670*103e46e4SHarish Mahendrakar   if ((segment_stop >= 0) && ((pos + len) > segment_stop))
1671*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
1672*103e46e4SHarish Mahendrakar 
1673*103e46e4SHarish Mahendrakar   if ((pos + len) > avail)
1674*103e46e4SHarish Mahendrakar     return E_BUFFER_NOT_FULL;
1675*103e46e4SHarish Mahendrakar 
1676*103e46e4SHarish Mahendrakar   const long long idpos = pos;
1677*103e46e4SHarish Mahendrakar 
1678*103e46e4SHarish Mahendrakar   const long long id = ReadID(m_pReader, idpos, len);
1679*103e46e4SHarish Mahendrakar 
1680*103e46e4SHarish Mahendrakar   if (id != libwebm::kMkvCues)
1681*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
1682*103e46e4SHarish Mahendrakar 
1683*103e46e4SHarish Mahendrakar   pos += len;  // consume ID
1684*103e46e4SHarish Mahendrakar   assert((segment_stop < 0) || (pos <= segment_stop));
1685*103e46e4SHarish Mahendrakar 
1686*103e46e4SHarish Mahendrakar   // Read Size
1687*103e46e4SHarish Mahendrakar 
1688*103e46e4SHarish Mahendrakar   if ((pos + 1) > avail) {
1689*103e46e4SHarish Mahendrakar     len = 1;
1690*103e46e4SHarish Mahendrakar     return E_BUFFER_NOT_FULL;
1691*103e46e4SHarish Mahendrakar   }
1692*103e46e4SHarish Mahendrakar 
1693*103e46e4SHarish Mahendrakar   result = GetUIntLength(m_pReader, pos, len);
1694*103e46e4SHarish Mahendrakar 
1695*103e46e4SHarish Mahendrakar   if (result < 0)  // error
1696*103e46e4SHarish Mahendrakar     return static_cast<long>(result);
1697*103e46e4SHarish Mahendrakar 
1698*103e46e4SHarish Mahendrakar   if (result > 0)  // underflow (weird)
1699*103e46e4SHarish Mahendrakar   {
1700*103e46e4SHarish Mahendrakar     len = 1;
1701*103e46e4SHarish Mahendrakar     return E_BUFFER_NOT_FULL;
1702*103e46e4SHarish Mahendrakar   }
1703*103e46e4SHarish Mahendrakar 
1704*103e46e4SHarish Mahendrakar   if ((segment_stop >= 0) && ((pos + len) > segment_stop))
1705*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
1706*103e46e4SHarish Mahendrakar 
1707*103e46e4SHarish Mahendrakar   if ((pos + len) > avail)
1708*103e46e4SHarish Mahendrakar     return E_BUFFER_NOT_FULL;
1709*103e46e4SHarish Mahendrakar 
1710*103e46e4SHarish Mahendrakar   const long long size = ReadUInt(m_pReader, pos, len);
1711*103e46e4SHarish Mahendrakar 
1712*103e46e4SHarish Mahendrakar   if (size < 0)  // error
1713*103e46e4SHarish Mahendrakar     return static_cast<long>(size);
1714*103e46e4SHarish Mahendrakar 
1715*103e46e4SHarish Mahendrakar   if (size == 0)  // weird, although technically not illegal
1716*103e46e4SHarish Mahendrakar     return 1;  // done
1717*103e46e4SHarish Mahendrakar 
1718*103e46e4SHarish Mahendrakar   pos += len;  // consume length of size of element
1719*103e46e4SHarish Mahendrakar   assert((segment_stop < 0) || (pos <= segment_stop));
1720*103e46e4SHarish Mahendrakar 
1721*103e46e4SHarish Mahendrakar   // Pos now points to start of payload
1722*103e46e4SHarish Mahendrakar 
1723*103e46e4SHarish Mahendrakar   const long long element_stop = pos + size;
1724*103e46e4SHarish Mahendrakar 
1725*103e46e4SHarish Mahendrakar   if ((segment_stop >= 0) && (element_stop > segment_stop))
1726*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
1727*103e46e4SHarish Mahendrakar 
1728*103e46e4SHarish Mahendrakar   if ((total >= 0) && (element_stop > total))
1729*103e46e4SHarish Mahendrakar     return 1;  // don't bother parsing anymore
1730*103e46e4SHarish Mahendrakar 
1731*103e46e4SHarish Mahendrakar   len = static_cast<long>(size);
1732*103e46e4SHarish Mahendrakar 
1733*103e46e4SHarish Mahendrakar   if (element_stop > avail)
1734*103e46e4SHarish Mahendrakar     return E_BUFFER_NOT_FULL;
1735*103e46e4SHarish Mahendrakar 
1736*103e46e4SHarish Mahendrakar   const long long element_size = element_stop - element_start;
1737*103e46e4SHarish Mahendrakar 
1738*103e46e4SHarish Mahendrakar   m_pCues =
1739*103e46e4SHarish Mahendrakar       new (std::nothrow) Cues(this, pos, size, element_start, element_size);
1740*103e46e4SHarish Mahendrakar   if (m_pCues == NULL)
1741*103e46e4SHarish Mahendrakar     return -1;
1742*103e46e4SHarish Mahendrakar 
1743*103e46e4SHarish Mahendrakar   return 0;  // success
1744*103e46e4SHarish Mahendrakar }
1745*103e46e4SHarish Mahendrakar 
ParseEntry(IMkvReader * pReader,long long start,long long size_,Entry * pEntry)1746*103e46e4SHarish Mahendrakar bool SeekHead::ParseEntry(IMkvReader* pReader, long long start, long long size_,
1747*103e46e4SHarish Mahendrakar                           Entry* pEntry) {
1748*103e46e4SHarish Mahendrakar   if (size_ <= 0)
1749*103e46e4SHarish Mahendrakar     return false;
1750*103e46e4SHarish Mahendrakar 
1751*103e46e4SHarish Mahendrakar   long long pos = start;
1752*103e46e4SHarish Mahendrakar   const long long stop = start + size_;
1753*103e46e4SHarish Mahendrakar 
1754*103e46e4SHarish Mahendrakar   long len;
1755*103e46e4SHarish Mahendrakar 
1756*103e46e4SHarish Mahendrakar   // parse the container for the level-1 element ID
1757*103e46e4SHarish Mahendrakar 
1758*103e46e4SHarish Mahendrakar   const long long seekIdId = ReadID(pReader, pos, len);
1759*103e46e4SHarish Mahendrakar   if (seekIdId < 0)
1760*103e46e4SHarish Mahendrakar     return false;
1761*103e46e4SHarish Mahendrakar 
1762*103e46e4SHarish Mahendrakar   if (seekIdId != libwebm::kMkvSeekID)
1763*103e46e4SHarish Mahendrakar     return false;
1764*103e46e4SHarish Mahendrakar 
1765*103e46e4SHarish Mahendrakar   if ((pos + len) > stop)
1766*103e46e4SHarish Mahendrakar     return false;
1767*103e46e4SHarish Mahendrakar 
1768*103e46e4SHarish Mahendrakar   pos += len;  // consume SeekID id
1769*103e46e4SHarish Mahendrakar 
1770*103e46e4SHarish Mahendrakar   const long long seekIdSize = ReadUInt(pReader, pos, len);
1771*103e46e4SHarish Mahendrakar 
1772*103e46e4SHarish Mahendrakar   if (seekIdSize <= 0)
1773*103e46e4SHarish Mahendrakar     return false;
1774*103e46e4SHarish Mahendrakar 
1775*103e46e4SHarish Mahendrakar   if ((pos + len) > stop)
1776*103e46e4SHarish Mahendrakar     return false;
1777*103e46e4SHarish Mahendrakar 
1778*103e46e4SHarish Mahendrakar   pos += len;  // consume size of field
1779*103e46e4SHarish Mahendrakar 
1780*103e46e4SHarish Mahendrakar   if ((pos + seekIdSize) > stop)
1781*103e46e4SHarish Mahendrakar     return false;
1782*103e46e4SHarish Mahendrakar 
1783*103e46e4SHarish Mahendrakar   pEntry->id = ReadID(pReader, pos, len);  // payload
1784*103e46e4SHarish Mahendrakar 
1785*103e46e4SHarish Mahendrakar   if (pEntry->id <= 0)
1786*103e46e4SHarish Mahendrakar     return false;
1787*103e46e4SHarish Mahendrakar 
1788*103e46e4SHarish Mahendrakar   if (len != seekIdSize)
1789*103e46e4SHarish Mahendrakar     return false;
1790*103e46e4SHarish Mahendrakar 
1791*103e46e4SHarish Mahendrakar   pos += seekIdSize;  // consume SeekID payload
1792*103e46e4SHarish Mahendrakar 
1793*103e46e4SHarish Mahendrakar   const long long seekPosId = ReadID(pReader, pos, len);
1794*103e46e4SHarish Mahendrakar 
1795*103e46e4SHarish Mahendrakar   if (seekPosId != libwebm::kMkvSeekPosition)
1796*103e46e4SHarish Mahendrakar     return false;
1797*103e46e4SHarish Mahendrakar 
1798*103e46e4SHarish Mahendrakar   if ((pos + len) > stop)
1799*103e46e4SHarish Mahendrakar     return false;
1800*103e46e4SHarish Mahendrakar 
1801*103e46e4SHarish Mahendrakar   pos += len;  // consume id
1802*103e46e4SHarish Mahendrakar 
1803*103e46e4SHarish Mahendrakar   const long long seekPosSize = ReadUInt(pReader, pos, len);
1804*103e46e4SHarish Mahendrakar 
1805*103e46e4SHarish Mahendrakar   if (seekPosSize <= 0)
1806*103e46e4SHarish Mahendrakar     return false;
1807*103e46e4SHarish Mahendrakar 
1808*103e46e4SHarish Mahendrakar   if ((pos + len) > stop)
1809*103e46e4SHarish Mahendrakar     return false;
1810*103e46e4SHarish Mahendrakar 
1811*103e46e4SHarish Mahendrakar   pos += len;  // consume size
1812*103e46e4SHarish Mahendrakar 
1813*103e46e4SHarish Mahendrakar   if ((pos + seekPosSize) > stop)
1814*103e46e4SHarish Mahendrakar     return false;
1815*103e46e4SHarish Mahendrakar 
1816*103e46e4SHarish Mahendrakar   pEntry->pos = UnserializeUInt(pReader, pos, seekPosSize);
1817*103e46e4SHarish Mahendrakar 
1818*103e46e4SHarish Mahendrakar   if (pEntry->pos < 0)
1819*103e46e4SHarish Mahendrakar     return false;
1820*103e46e4SHarish Mahendrakar 
1821*103e46e4SHarish Mahendrakar   pos += seekPosSize;  // consume payload
1822*103e46e4SHarish Mahendrakar 
1823*103e46e4SHarish Mahendrakar   if (pos != stop)
1824*103e46e4SHarish Mahendrakar     return false;
1825*103e46e4SHarish Mahendrakar 
1826*103e46e4SHarish Mahendrakar   return true;
1827*103e46e4SHarish Mahendrakar }
1828*103e46e4SHarish Mahendrakar 
Cues(Segment * pSegment,long long start_,long long size_,long long element_start,long long element_size)1829*103e46e4SHarish Mahendrakar Cues::Cues(Segment* pSegment, long long start_, long long size_,
1830*103e46e4SHarish Mahendrakar            long long element_start, long long element_size)
1831*103e46e4SHarish Mahendrakar     : m_pSegment(pSegment),
1832*103e46e4SHarish Mahendrakar       m_start(start_),
1833*103e46e4SHarish Mahendrakar       m_size(size_),
1834*103e46e4SHarish Mahendrakar       m_element_start(element_start),
1835*103e46e4SHarish Mahendrakar       m_element_size(element_size),
1836*103e46e4SHarish Mahendrakar       m_cue_points(NULL),
1837*103e46e4SHarish Mahendrakar       m_count(0),
1838*103e46e4SHarish Mahendrakar       m_preload_count(0),
1839*103e46e4SHarish Mahendrakar       m_pos(start_) {}
1840*103e46e4SHarish Mahendrakar 
~Cues()1841*103e46e4SHarish Mahendrakar Cues::~Cues() {
1842*103e46e4SHarish Mahendrakar   const long n = m_count + m_preload_count;
1843*103e46e4SHarish Mahendrakar 
1844*103e46e4SHarish Mahendrakar   CuePoint** p = m_cue_points;
1845*103e46e4SHarish Mahendrakar   CuePoint** const q = p + n;
1846*103e46e4SHarish Mahendrakar 
1847*103e46e4SHarish Mahendrakar   while (p != q) {
1848*103e46e4SHarish Mahendrakar     CuePoint* const pCP = *p++;
1849*103e46e4SHarish Mahendrakar     assert(pCP);
1850*103e46e4SHarish Mahendrakar 
1851*103e46e4SHarish Mahendrakar     delete pCP;
1852*103e46e4SHarish Mahendrakar   }
1853*103e46e4SHarish Mahendrakar 
1854*103e46e4SHarish Mahendrakar   delete[] m_cue_points;
1855*103e46e4SHarish Mahendrakar }
1856*103e46e4SHarish Mahendrakar 
GetCount() const1857*103e46e4SHarish Mahendrakar long Cues::GetCount() const {
1858*103e46e4SHarish Mahendrakar   if (m_cue_points == NULL)
1859*103e46e4SHarish Mahendrakar     return -1;
1860*103e46e4SHarish Mahendrakar 
1861*103e46e4SHarish Mahendrakar   return m_count;  // TODO: really ignore preload count?
1862*103e46e4SHarish Mahendrakar }
1863*103e46e4SHarish Mahendrakar 
DoneParsing() const1864*103e46e4SHarish Mahendrakar bool Cues::DoneParsing() const {
1865*103e46e4SHarish Mahendrakar   const long long stop = m_start + m_size;
1866*103e46e4SHarish Mahendrakar   return (m_pos >= stop);
1867*103e46e4SHarish Mahendrakar }
1868*103e46e4SHarish Mahendrakar 
Init() const1869*103e46e4SHarish Mahendrakar bool Cues::Init() const {
1870*103e46e4SHarish Mahendrakar   if (m_cue_points)
1871*103e46e4SHarish Mahendrakar     return true;
1872*103e46e4SHarish Mahendrakar 
1873*103e46e4SHarish Mahendrakar   if (m_count != 0 || m_preload_count != 0)
1874*103e46e4SHarish Mahendrakar     return false;
1875*103e46e4SHarish Mahendrakar 
1876*103e46e4SHarish Mahendrakar   IMkvReader* const pReader = m_pSegment->m_pReader;
1877*103e46e4SHarish Mahendrakar 
1878*103e46e4SHarish Mahendrakar   const long long stop = m_start + m_size;
1879*103e46e4SHarish Mahendrakar   long long pos = m_start;
1880*103e46e4SHarish Mahendrakar 
1881*103e46e4SHarish Mahendrakar   long cue_points_size = 0;
1882*103e46e4SHarish Mahendrakar 
1883*103e46e4SHarish Mahendrakar   while (pos < stop) {
1884*103e46e4SHarish Mahendrakar     const long long idpos = pos;
1885*103e46e4SHarish Mahendrakar 
1886*103e46e4SHarish Mahendrakar     long len;
1887*103e46e4SHarish Mahendrakar 
1888*103e46e4SHarish Mahendrakar     const long long id = ReadID(pReader, pos, len);
1889*103e46e4SHarish Mahendrakar     if (id < 0 || (pos + len) > stop) {
1890*103e46e4SHarish Mahendrakar       return false;
1891*103e46e4SHarish Mahendrakar     }
1892*103e46e4SHarish Mahendrakar 
1893*103e46e4SHarish Mahendrakar     pos += len;  // consume ID
1894*103e46e4SHarish Mahendrakar 
1895*103e46e4SHarish Mahendrakar     const long long size = ReadUInt(pReader, pos, len);
1896*103e46e4SHarish Mahendrakar     if (size < 0 || (pos + len > stop)) {
1897*103e46e4SHarish Mahendrakar       return false;
1898*103e46e4SHarish Mahendrakar     }
1899*103e46e4SHarish Mahendrakar 
1900*103e46e4SHarish Mahendrakar     pos += len;  // consume Size field
1901*103e46e4SHarish Mahendrakar     if (pos + size > stop) {
1902*103e46e4SHarish Mahendrakar       return false;
1903*103e46e4SHarish Mahendrakar     }
1904*103e46e4SHarish Mahendrakar 
1905*103e46e4SHarish Mahendrakar     if (id == libwebm::kMkvCuePoint) {
1906*103e46e4SHarish Mahendrakar       if (!PreloadCuePoint(cue_points_size, idpos))
1907*103e46e4SHarish Mahendrakar         return false;
1908*103e46e4SHarish Mahendrakar     }
1909*103e46e4SHarish Mahendrakar 
1910*103e46e4SHarish Mahendrakar     pos += size;  // skip payload
1911*103e46e4SHarish Mahendrakar   }
1912*103e46e4SHarish Mahendrakar   return true;
1913*103e46e4SHarish Mahendrakar }
1914*103e46e4SHarish Mahendrakar 
PreloadCuePoint(long & cue_points_size,long long pos) const1915*103e46e4SHarish Mahendrakar bool Cues::PreloadCuePoint(long& cue_points_size, long long pos) const {
1916*103e46e4SHarish Mahendrakar   if (m_count != 0)
1917*103e46e4SHarish Mahendrakar     return false;
1918*103e46e4SHarish Mahendrakar 
1919*103e46e4SHarish Mahendrakar   if (m_preload_count >= cue_points_size) {
1920*103e46e4SHarish Mahendrakar     const long n = (cue_points_size <= 0) ? 2048 : 2 * cue_points_size;
1921*103e46e4SHarish Mahendrakar 
1922*103e46e4SHarish Mahendrakar     CuePoint** const qq = new (std::nothrow) CuePoint*[n];
1923*103e46e4SHarish Mahendrakar     if (qq == NULL)
1924*103e46e4SHarish Mahendrakar       return false;
1925*103e46e4SHarish Mahendrakar 
1926*103e46e4SHarish Mahendrakar     CuePoint** q = qq;  // beginning of target
1927*103e46e4SHarish Mahendrakar 
1928*103e46e4SHarish Mahendrakar     CuePoint** p = m_cue_points;  // beginning of source
1929*103e46e4SHarish Mahendrakar     CuePoint** const pp = p + m_preload_count;  // end of source
1930*103e46e4SHarish Mahendrakar 
1931*103e46e4SHarish Mahendrakar     while (p != pp)
1932*103e46e4SHarish Mahendrakar       *q++ = *p++;
1933*103e46e4SHarish Mahendrakar 
1934*103e46e4SHarish Mahendrakar     delete[] m_cue_points;
1935*103e46e4SHarish Mahendrakar 
1936*103e46e4SHarish Mahendrakar     m_cue_points = qq;
1937*103e46e4SHarish Mahendrakar     cue_points_size = n;
1938*103e46e4SHarish Mahendrakar   }
1939*103e46e4SHarish Mahendrakar 
1940*103e46e4SHarish Mahendrakar   CuePoint* const pCP = new (std::nothrow) CuePoint(m_preload_count, pos);
1941*103e46e4SHarish Mahendrakar   if (pCP == NULL)
1942*103e46e4SHarish Mahendrakar     return false;
1943*103e46e4SHarish Mahendrakar 
1944*103e46e4SHarish Mahendrakar   m_cue_points[m_preload_count++] = pCP;
1945*103e46e4SHarish Mahendrakar   return true;
1946*103e46e4SHarish Mahendrakar }
1947*103e46e4SHarish Mahendrakar 
LoadCuePoint() const1948*103e46e4SHarish Mahendrakar bool Cues::LoadCuePoint() const {
1949*103e46e4SHarish Mahendrakar   const long long stop = m_start + m_size;
1950*103e46e4SHarish Mahendrakar 
1951*103e46e4SHarish Mahendrakar   if (m_pos >= stop)
1952*103e46e4SHarish Mahendrakar     return false;  // nothing else to do
1953*103e46e4SHarish Mahendrakar 
1954*103e46e4SHarish Mahendrakar   if (!Init()) {
1955*103e46e4SHarish Mahendrakar     m_pos = stop;
1956*103e46e4SHarish Mahendrakar     return false;
1957*103e46e4SHarish Mahendrakar   }
1958*103e46e4SHarish Mahendrakar 
1959*103e46e4SHarish Mahendrakar   IMkvReader* const pReader = m_pSegment->m_pReader;
1960*103e46e4SHarish Mahendrakar 
1961*103e46e4SHarish Mahendrakar   while (m_pos < stop) {
1962*103e46e4SHarish Mahendrakar     const long long idpos = m_pos;
1963*103e46e4SHarish Mahendrakar 
1964*103e46e4SHarish Mahendrakar     long len;
1965*103e46e4SHarish Mahendrakar 
1966*103e46e4SHarish Mahendrakar     const long long id = ReadID(pReader, m_pos, len);
1967*103e46e4SHarish Mahendrakar     if (id < 0 || (m_pos + len) > stop)
1968*103e46e4SHarish Mahendrakar       return false;
1969*103e46e4SHarish Mahendrakar 
1970*103e46e4SHarish Mahendrakar     m_pos += len;  // consume ID
1971*103e46e4SHarish Mahendrakar 
1972*103e46e4SHarish Mahendrakar     const long long size = ReadUInt(pReader, m_pos, len);
1973*103e46e4SHarish Mahendrakar     if (size < 0 || (m_pos + len) > stop)
1974*103e46e4SHarish Mahendrakar       return false;
1975*103e46e4SHarish Mahendrakar 
1976*103e46e4SHarish Mahendrakar     m_pos += len;  // consume Size field
1977*103e46e4SHarish Mahendrakar     if ((m_pos + size) > stop)
1978*103e46e4SHarish Mahendrakar       return false;
1979*103e46e4SHarish Mahendrakar 
1980*103e46e4SHarish Mahendrakar     if (id != libwebm::kMkvCuePoint) {
1981*103e46e4SHarish Mahendrakar       m_pos += size;  // consume payload
1982*103e46e4SHarish Mahendrakar       if (m_pos > stop)
1983*103e46e4SHarish Mahendrakar         return false;
1984*103e46e4SHarish Mahendrakar 
1985*103e46e4SHarish Mahendrakar       continue;
1986*103e46e4SHarish Mahendrakar     }
1987*103e46e4SHarish Mahendrakar 
1988*103e46e4SHarish Mahendrakar     if (m_preload_count < 1)
1989*103e46e4SHarish Mahendrakar       return false;
1990*103e46e4SHarish Mahendrakar 
1991*103e46e4SHarish Mahendrakar     CuePoint* const pCP = m_cue_points[m_count];
1992*103e46e4SHarish Mahendrakar     if (!pCP || (pCP->GetTimeCode() < 0 && (-pCP->GetTimeCode() != idpos)))
1993*103e46e4SHarish Mahendrakar       return false;
1994*103e46e4SHarish Mahendrakar 
1995*103e46e4SHarish Mahendrakar     if (!pCP->Load(pReader)) {
1996*103e46e4SHarish Mahendrakar       m_pos = stop;
1997*103e46e4SHarish Mahendrakar       return false;
1998*103e46e4SHarish Mahendrakar     }
1999*103e46e4SHarish Mahendrakar     ++m_count;
2000*103e46e4SHarish Mahendrakar     --m_preload_count;
2001*103e46e4SHarish Mahendrakar 
2002*103e46e4SHarish Mahendrakar     m_pos += size;  // consume payload
2003*103e46e4SHarish Mahendrakar     if (m_pos > stop)
2004*103e46e4SHarish Mahendrakar       return false;
2005*103e46e4SHarish Mahendrakar 
2006*103e46e4SHarish Mahendrakar     return true;  // yes, we loaded a cue point
2007*103e46e4SHarish Mahendrakar   }
2008*103e46e4SHarish Mahendrakar 
2009*103e46e4SHarish Mahendrakar   return false;  // no, we did not load a cue point
2010*103e46e4SHarish Mahendrakar }
2011*103e46e4SHarish Mahendrakar 
Find(long long time_ns,const Track * pTrack,const CuePoint * & pCP,const CuePoint::TrackPosition * & pTP) const2012*103e46e4SHarish Mahendrakar bool Cues::Find(long long time_ns, const Track* pTrack, const CuePoint*& pCP,
2013*103e46e4SHarish Mahendrakar                 const CuePoint::TrackPosition*& pTP) const {
2014*103e46e4SHarish Mahendrakar   if (time_ns < 0 || pTrack == NULL || m_cue_points == NULL || m_count == 0)
2015*103e46e4SHarish Mahendrakar     return false;
2016*103e46e4SHarish Mahendrakar 
2017*103e46e4SHarish Mahendrakar   CuePoint** const ii = m_cue_points;
2018*103e46e4SHarish Mahendrakar   CuePoint** i = ii;
2019*103e46e4SHarish Mahendrakar 
2020*103e46e4SHarish Mahendrakar   CuePoint** const jj = ii + m_count;
2021*103e46e4SHarish Mahendrakar   CuePoint** j = jj;
2022*103e46e4SHarish Mahendrakar 
2023*103e46e4SHarish Mahendrakar   pCP = *i;
2024*103e46e4SHarish Mahendrakar   if (pCP == NULL)
2025*103e46e4SHarish Mahendrakar     return false;
2026*103e46e4SHarish Mahendrakar 
2027*103e46e4SHarish Mahendrakar   if (time_ns <= pCP->GetTime(m_pSegment)) {
2028*103e46e4SHarish Mahendrakar     pTP = pCP->Find(pTrack);
2029*103e46e4SHarish Mahendrakar     return (pTP != NULL);
2030*103e46e4SHarish Mahendrakar   }
2031*103e46e4SHarish Mahendrakar 
2032*103e46e4SHarish Mahendrakar   while (i < j) {
2033*103e46e4SHarish Mahendrakar     // INVARIANT:
2034*103e46e4SHarish Mahendrakar     //[ii, i) <= time_ns
2035*103e46e4SHarish Mahendrakar     //[i, j)  ?
2036*103e46e4SHarish Mahendrakar     //[j, jj) > time_ns
2037*103e46e4SHarish Mahendrakar 
2038*103e46e4SHarish Mahendrakar     CuePoint** const k = i + (j - i) / 2;
2039*103e46e4SHarish Mahendrakar     if (k >= jj)
2040*103e46e4SHarish Mahendrakar       return false;
2041*103e46e4SHarish Mahendrakar 
2042*103e46e4SHarish Mahendrakar     CuePoint* const pCP = *k;
2043*103e46e4SHarish Mahendrakar     if (pCP == NULL)
2044*103e46e4SHarish Mahendrakar       return false;
2045*103e46e4SHarish Mahendrakar 
2046*103e46e4SHarish Mahendrakar     const long long t = pCP->GetTime(m_pSegment);
2047*103e46e4SHarish Mahendrakar 
2048*103e46e4SHarish Mahendrakar     if (t <= time_ns)
2049*103e46e4SHarish Mahendrakar       i = k + 1;
2050*103e46e4SHarish Mahendrakar     else
2051*103e46e4SHarish Mahendrakar       j = k;
2052*103e46e4SHarish Mahendrakar 
2053*103e46e4SHarish Mahendrakar     if (i > j)
2054*103e46e4SHarish Mahendrakar       return false;
2055*103e46e4SHarish Mahendrakar   }
2056*103e46e4SHarish Mahendrakar 
2057*103e46e4SHarish Mahendrakar   if (i != j || i > jj || i <= ii)
2058*103e46e4SHarish Mahendrakar     return false;
2059*103e46e4SHarish Mahendrakar 
2060*103e46e4SHarish Mahendrakar   pCP = *--i;
2061*103e46e4SHarish Mahendrakar 
2062*103e46e4SHarish Mahendrakar   if (pCP == NULL || pCP->GetTime(m_pSegment) > time_ns)
2063*103e46e4SHarish Mahendrakar     return false;
2064*103e46e4SHarish Mahendrakar 
2065*103e46e4SHarish Mahendrakar   // TODO: here and elsewhere, it's probably not correct to search
2066*103e46e4SHarish Mahendrakar   // for the cue point with this time, and then search for a matching
2067*103e46e4SHarish Mahendrakar   // track.  In principle, the matching track could be on some earlier
2068*103e46e4SHarish Mahendrakar   // cue point, and with our current algorithm, we'd miss it.  To make
2069*103e46e4SHarish Mahendrakar   // this bullet-proof, we'd need to create a secondary structure,
2070*103e46e4SHarish Mahendrakar   // with a list of cue points that apply to a track, and then search
2071*103e46e4SHarish Mahendrakar   // that track-based structure for a matching cue point.
2072*103e46e4SHarish Mahendrakar 
2073*103e46e4SHarish Mahendrakar   pTP = pCP->Find(pTrack);
2074*103e46e4SHarish Mahendrakar   return (pTP != NULL);
2075*103e46e4SHarish Mahendrakar }
2076*103e46e4SHarish Mahendrakar 
GetFirst() const2077*103e46e4SHarish Mahendrakar const CuePoint* Cues::GetFirst() const {
2078*103e46e4SHarish Mahendrakar   if (m_cue_points == NULL || m_count == 0)
2079*103e46e4SHarish Mahendrakar     return NULL;
2080*103e46e4SHarish Mahendrakar 
2081*103e46e4SHarish Mahendrakar   CuePoint* const* const pp = m_cue_points;
2082*103e46e4SHarish Mahendrakar   if (pp == NULL)
2083*103e46e4SHarish Mahendrakar     return NULL;
2084*103e46e4SHarish Mahendrakar 
2085*103e46e4SHarish Mahendrakar   CuePoint* const pCP = pp[0];
2086*103e46e4SHarish Mahendrakar   if (pCP == NULL || pCP->GetTimeCode() < 0)
2087*103e46e4SHarish Mahendrakar     return NULL;
2088*103e46e4SHarish Mahendrakar 
2089*103e46e4SHarish Mahendrakar   return pCP;
2090*103e46e4SHarish Mahendrakar }
2091*103e46e4SHarish Mahendrakar 
GetLast() const2092*103e46e4SHarish Mahendrakar const CuePoint* Cues::GetLast() const {
2093*103e46e4SHarish Mahendrakar   if (m_cue_points == NULL || m_count <= 0)
2094*103e46e4SHarish Mahendrakar     return NULL;
2095*103e46e4SHarish Mahendrakar 
2096*103e46e4SHarish Mahendrakar   const long index = m_count - 1;
2097*103e46e4SHarish Mahendrakar 
2098*103e46e4SHarish Mahendrakar   CuePoint* const* const pp = m_cue_points;
2099*103e46e4SHarish Mahendrakar   if (pp == NULL)
2100*103e46e4SHarish Mahendrakar     return NULL;
2101*103e46e4SHarish Mahendrakar 
2102*103e46e4SHarish Mahendrakar   CuePoint* const pCP = pp[index];
2103*103e46e4SHarish Mahendrakar   if (pCP == NULL || pCP->GetTimeCode() < 0)
2104*103e46e4SHarish Mahendrakar     return NULL;
2105*103e46e4SHarish Mahendrakar 
2106*103e46e4SHarish Mahendrakar   return pCP;
2107*103e46e4SHarish Mahendrakar }
2108*103e46e4SHarish Mahendrakar 
GetNext(const CuePoint * pCurr) const2109*103e46e4SHarish Mahendrakar const CuePoint* Cues::GetNext(const CuePoint* pCurr) const {
2110*103e46e4SHarish Mahendrakar   if (pCurr == NULL || pCurr->GetTimeCode() < 0 || m_cue_points == NULL ||
2111*103e46e4SHarish Mahendrakar       m_count < 1) {
2112*103e46e4SHarish Mahendrakar     return NULL;
2113*103e46e4SHarish Mahendrakar   }
2114*103e46e4SHarish Mahendrakar 
2115*103e46e4SHarish Mahendrakar   long index = pCurr->m_index;
2116*103e46e4SHarish Mahendrakar   if (index >= m_count)
2117*103e46e4SHarish Mahendrakar     return NULL;
2118*103e46e4SHarish Mahendrakar 
2119*103e46e4SHarish Mahendrakar   CuePoint* const* const pp = m_cue_points;
2120*103e46e4SHarish Mahendrakar   if (pp == NULL || pp[index] != pCurr)
2121*103e46e4SHarish Mahendrakar     return NULL;
2122*103e46e4SHarish Mahendrakar 
2123*103e46e4SHarish Mahendrakar   ++index;
2124*103e46e4SHarish Mahendrakar 
2125*103e46e4SHarish Mahendrakar   if (index >= m_count)
2126*103e46e4SHarish Mahendrakar     return NULL;
2127*103e46e4SHarish Mahendrakar 
2128*103e46e4SHarish Mahendrakar   CuePoint* const pNext = pp[index];
2129*103e46e4SHarish Mahendrakar 
2130*103e46e4SHarish Mahendrakar   if (pNext == NULL || pNext->GetTimeCode() < 0)
2131*103e46e4SHarish Mahendrakar     return NULL;
2132*103e46e4SHarish Mahendrakar 
2133*103e46e4SHarish Mahendrakar   return pNext;
2134*103e46e4SHarish Mahendrakar }
2135*103e46e4SHarish Mahendrakar 
GetBlock(const CuePoint * pCP,const CuePoint::TrackPosition * pTP) const2136*103e46e4SHarish Mahendrakar const BlockEntry* Cues::GetBlock(const CuePoint* pCP,
2137*103e46e4SHarish Mahendrakar                                  const CuePoint::TrackPosition* pTP) const {
2138*103e46e4SHarish Mahendrakar   if (pCP == NULL || pTP == NULL)
2139*103e46e4SHarish Mahendrakar     return NULL;
2140*103e46e4SHarish Mahendrakar 
2141*103e46e4SHarish Mahendrakar   return m_pSegment->GetBlock(*pCP, *pTP);
2142*103e46e4SHarish Mahendrakar }
2143*103e46e4SHarish Mahendrakar 
GetBlock(const CuePoint & cp,const CuePoint::TrackPosition & tp)2144*103e46e4SHarish Mahendrakar const BlockEntry* Segment::GetBlock(const CuePoint& cp,
2145*103e46e4SHarish Mahendrakar                                     const CuePoint::TrackPosition& tp) {
2146*103e46e4SHarish Mahendrakar   Cluster** const ii = m_clusters;
2147*103e46e4SHarish Mahendrakar   Cluster** i = ii;
2148*103e46e4SHarish Mahendrakar 
2149*103e46e4SHarish Mahendrakar   const long count = m_clusterCount + m_clusterPreloadCount;
2150*103e46e4SHarish Mahendrakar 
2151*103e46e4SHarish Mahendrakar   Cluster** const jj = ii + count;
2152*103e46e4SHarish Mahendrakar   Cluster** j = jj;
2153*103e46e4SHarish Mahendrakar 
2154*103e46e4SHarish Mahendrakar   while (i < j) {
2155*103e46e4SHarish Mahendrakar     // INVARIANT:
2156*103e46e4SHarish Mahendrakar     //[ii, i) < pTP->m_pos
2157*103e46e4SHarish Mahendrakar     //[i, j) ?
2158*103e46e4SHarish Mahendrakar     //[j, jj)  > pTP->m_pos
2159*103e46e4SHarish Mahendrakar 
2160*103e46e4SHarish Mahendrakar     Cluster** const k = i + (j - i) / 2;
2161*103e46e4SHarish Mahendrakar     assert(k < jj);
2162*103e46e4SHarish Mahendrakar 
2163*103e46e4SHarish Mahendrakar     Cluster* const pCluster = *k;
2164*103e46e4SHarish Mahendrakar     assert(pCluster);
2165*103e46e4SHarish Mahendrakar 
2166*103e46e4SHarish Mahendrakar     // const long long pos_ = pCluster->m_pos;
2167*103e46e4SHarish Mahendrakar     // assert(pos_);
2168*103e46e4SHarish Mahendrakar     // const long long pos = pos_ * ((pos_ < 0) ? -1 : 1);
2169*103e46e4SHarish Mahendrakar 
2170*103e46e4SHarish Mahendrakar     const long long pos = pCluster->GetPosition();
2171*103e46e4SHarish Mahendrakar     assert(pos >= 0);
2172*103e46e4SHarish Mahendrakar 
2173*103e46e4SHarish Mahendrakar     if (pos < tp.m_pos)
2174*103e46e4SHarish Mahendrakar       i = k + 1;
2175*103e46e4SHarish Mahendrakar     else if (pos > tp.m_pos)
2176*103e46e4SHarish Mahendrakar       j = k;
2177*103e46e4SHarish Mahendrakar     else
2178*103e46e4SHarish Mahendrakar       return pCluster->GetEntry(cp, tp);
2179*103e46e4SHarish Mahendrakar   }
2180*103e46e4SHarish Mahendrakar 
2181*103e46e4SHarish Mahendrakar   assert(i == j);
2182*103e46e4SHarish Mahendrakar   // assert(Cluster::HasBlockEntries(this, tp.m_pos));
2183*103e46e4SHarish Mahendrakar 
2184*103e46e4SHarish Mahendrakar   Cluster* const pCluster = Cluster::Create(this, -1, tp.m_pos);  //, -1);
2185*103e46e4SHarish Mahendrakar   if (pCluster == NULL)
2186*103e46e4SHarish Mahendrakar     return NULL;
2187*103e46e4SHarish Mahendrakar 
2188*103e46e4SHarish Mahendrakar   const ptrdiff_t idx = i - m_clusters;
2189*103e46e4SHarish Mahendrakar 
2190*103e46e4SHarish Mahendrakar   if (!PreloadCluster(pCluster, idx)) {
2191*103e46e4SHarish Mahendrakar     delete pCluster;
2192*103e46e4SHarish Mahendrakar     return NULL;
2193*103e46e4SHarish Mahendrakar   }
2194*103e46e4SHarish Mahendrakar   assert(m_clusters);
2195*103e46e4SHarish Mahendrakar   assert(m_clusterPreloadCount > 0);
2196*103e46e4SHarish Mahendrakar   assert(m_clusters[idx] == pCluster);
2197*103e46e4SHarish Mahendrakar 
2198*103e46e4SHarish Mahendrakar   return pCluster->GetEntry(cp, tp);
2199*103e46e4SHarish Mahendrakar }
2200*103e46e4SHarish Mahendrakar 
FindOrPreloadCluster(long long requested_pos)2201*103e46e4SHarish Mahendrakar const Cluster* Segment::FindOrPreloadCluster(long long requested_pos) {
2202*103e46e4SHarish Mahendrakar   if (requested_pos < 0)
2203*103e46e4SHarish Mahendrakar     return 0;
2204*103e46e4SHarish Mahendrakar 
2205*103e46e4SHarish Mahendrakar   Cluster** const ii = m_clusters;
2206*103e46e4SHarish Mahendrakar   Cluster** i = ii;
2207*103e46e4SHarish Mahendrakar 
2208*103e46e4SHarish Mahendrakar   const long count = m_clusterCount + m_clusterPreloadCount;
2209*103e46e4SHarish Mahendrakar 
2210*103e46e4SHarish Mahendrakar   Cluster** const jj = ii + count;
2211*103e46e4SHarish Mahendrakar   Cluster** j = jj;
2212*103e46e4SHarish Mahendrakar 
2213*103e46e4SHarish Mahendrakar   while (i < j) {
2214*103e46e4SHarish Mahendrakar     // INVARIANT:
2215*103e46e4SHarish Mahendrakar     //[ii, i) < pTP->m_pos
2216*103e46e4SHarish Mahendrakar     //[i, j) ?
2217*103e46e4SHarish Mahendrakar     //[j, jj)  > pTP->m_pos
2218*103e46e4SHarish Mahendrakar 
2219*103e46e4SHarish Mahendrakar     Cluster** const k = i + (j - i) / 2;
2220*103e46e4SHarish Mahendrakar     assert(k < jj);
2221*103e46e4SHarish Mahendrakar 
2222*103e46e4SHarish Mahendrakar     Cluster* const pCluster = *k;
2223*103e46e4SHarish Mahendrakar     assert(pCluster);
2224*103e46e4SHarish Mahendrakar 
2225*103e46e4SHarish Mahendrakar     // const long long pos_ = pCluster->m_pos;
2226*103e46e4SHarish Mahendrakar     // assert(pos_);
2227*103e46e4SHarish Mahendrakar     // const long long pos = pos_ * ((pos_ < 0) ? -1 : 1);
2228*103e46e4SHarish Mahendrakar 
2229*103e46e4SHarish Mahendrakar     const long long pos = pCluster->GetPosition();
2230*103e46e4SHarish Mahendrakar     assert(pos >= 0);
2231*103e46e4SHarish Mahendrakar 
2232*103e46e4SHarish Mahendrakar     if (pos < requested_pos)
2233*103e46e4SHarish Mahendrakar       i = k + 1;
2234*103e46e4SHarish Mahendrakar     else if (pos > requested_pos)
2235*103e46e4SHarish Mahendrakar       j = k;
2236*103e46e4SHarish Mahendrakar     else
2237*103e46e4SHarish Mahendrakar       return pCluster;
2238*103e46e4SHarish Mahendrakar   }
2239*103e46e4SHarish Mahendrakar 
2240*103e46e4SHarish Mahendrakar   assert(i == j);
2241*103e46e4SHarish Mahendrakar   // assert(Cluster::HasBlockEntries(this, tp.m_pos));
2242*103e46e4SHarish Mahendrakar 
2243*103e46e4SHarish Mahendrakar   Cluster* const pCluster = Cluster::Create(this, -1, requested_pos);
2244*103e46e4SHarish Mahendrakar   if (pCluster == NULL)
2245*103e46e4SHarish Mahendrakar     return NULL;
2246*103e46e4SHarish Mahendrakar 
2247*103e46e4SHarish Mahendrakar   const ptrdiff_t idx = i - m_clusters;
2248*103e46e4SHarish Mahendrakar 
2249*103e46e4SHarish Mahendrakar   if (!PreloadCluster(pCluster, idx)) {
2250*103e46e4SHarish Mahendrakar     delete pCluster;
2251*103e46e4SHarish Mahendrakar     return NULL;
2252*103e46e4SHarish Mahendrakar   }
2253*103e46e4SHarish Mahendrakar   assert(m_clusters);
2254*103e46e4SHarish Mahendrakar   assert(m_clusterPreloadCount > 0);
2255*103e46e4SHarish Mahendrakar   assert(m_clusters[idx] == pCluster);
2256*103e46e4SHarish Mahendrakar 
2257*103e46e4SHarish Mahendrakar   return pCluster;
2258*103e46e4SHarish Mahendrakar }
2259*103e46e4SHarish Mahendrakar 
CuePoint(long idx,long long pos)2260*103e46e4SHarish Mahendrakar CuePoint::CuePoint(long idx, long long pos)
2261*103e46e4SHarish Mahendrakar     : m_element_start(0),
2262*103e46e4SHarish Mahendrakar       m_element_size(0),
2263*103e46e4SHarish Mahendrakar       m_index(idx),
2264*103e46e4SHarish Mahendrakar       m_timecode(-1 * pos),
2265*103e46e4SHarish Mahendrakar       m_track_positions(NULL),
2266*103e46e4SHarish Mahendrakar       m_track_positions_count(0) {
2267*103e46e4SHarish Mahendrakar   assert(pos > 0);
2268*103e46e4SHarish Mahendrakar }
2269*103e46e4SHarish Mahendrakar 
~CuePoint()2270*103e46e4SHarish Mahendrakar CuePoint::~CuePoint() { delete[] m_track_positions; }
2271*103e46e4SHarish Mahendrakar 
Load(IMkvReader * pReader)2272*103e46e4SHarish Mahendrakar bool CuePoint::Load(IMkvReader* pReader) {
2273*103e46e4SHarish Mahendrakar   // odbgstream os;
2274*103e46e4SHarish Mahendrakar   // os << "CuePoint::Load(begin): timecode=" << m_timecode << endl;
2275*103e46e4SHarish Mahendrakar 
2276*103e46e4SHarish Mahendrakar   if (m_timecode >= 0)  // already loaded
2277*103e46e4SHarish Mahendrakar     return true;
2278*103e46e4SHarish Mahendrakar 
2279*103e46e4SHarish Mahendrakar   assert(m_track_positions == NULL);
2280*103e46e4SHarish Mahendrakar   assert(m_track_positions_count == 0);
2281*103e46e4SHarish Mahendrakar 
2282*103e46e4SHarish Mahendrakar   long long pos_ = -m_timecode;
2283*103e46e4SHarish Mahendrakar   const long long element_start = pos_;
2284*103e46e4SHarish Mahendrakar 
2285*103e46e4SHarish Mahendrakar   long long stop;
2286*103e46e4SHarish Mahendrakar 
2287*103e46e4SHarish Mahendrakar   {
2288*103e46e4SHarish Mahendrakar     long len;
2289*103e46e4SHarish Mahendrakar 
2290*103e46e4SHarish Mahendrakar     const long long id = ReadID(pReader, pos_, len);
2291*103e46e4SHarish Mahendrakar     if (id != libwebm::kMkvCuePoint)
2292*103e46e4SHarish Mahendrakar       return false;
2293*103e46e4SHarish Mahendrakar 
2294*103e46e4SHarish Mahendrakar     pos_ += len;  // consume ID
2295*103e46e4SHarish Mahendrakar 
2296*103e46e4SHarish Mahendrakar     const long long size = ReadUInt(pReader, pos_, len);
2297*103e46e4SHarish Mahendrakar     assert(size >= 0);
2298*103e46e4SHarish Mahendrakar 
2299*103e46e4SHarish Mahendrakar     pos_ += len;  // consume Size field
2300*103e46e4SHarish Mahendrakar     // pos_ now points to start of payload
2301*103e46e4SHarish Mahendrakar 
2302*103e46e4SHarish Mahendrakar     stop = pos_ + size;
2303*103e46e4SHarish Mahendrakar   }
2304*103e46e4SHarish Mahendrakar 
2305*103e46e4SHarish Mahendrakar   const long long element_size = stop - element_start;
2306*103e46e4SHarish Mahendrakar 
2307*103e46e4SHarish Mahendrakar   long long pos = pos_;
2308*103e46e4SHarish Mahendrakar 
2309*103e46e4SHarish Mahendrakar   // First count number of track positions
2310*103e46e4SHarish Mahendrakar   unsigned long long track_positions_count = 0;
2311*103e46e4SHarish Mahendrakar   while (pos < stop) {
2312*103e46e4SHarish Mahendrakar     long len;
2313*103e46e4SHarish Mahendrakar 
2314*103e46e4SHarish Mahendrakar     const long long id = ReadID(pReader, pos, len);
2315*103e46e4SHarish Mahendrakar     if ((id < 0) || (pos + len > stop)) {
2316*103e46e4SHarish Mahendrakar       return false;
2317*103e46e4SHarish Mahendrakar     }
2318*103e46e4SHarish Mahendrakar 
2319*103e46e4SHarish Mahendrakar     pos += len;  // consume ID
2320*103e46e4SHarish Mahendrakar 
2321*103e46e4SHarish Mahendrakar     const long long size = ReadUInt(pReader, pos, len);
2322*103e46e4SHarish Mahendrakar     if ((size < 0) || (pos + len > stop)) {
2323*103e46e4SHarish Mahendrakar       return false;
2324*103e46e4SHarish Mahendrakar     }
2325*103e46e4SHarish Mahendrakar 
2326*103e46e4SHarish Mahendrakar     pos += len;  // consume Size field
2327*103e46e4SHarish Mahendrakar     if ((pos + size) > stop) {
2328*103e46e4SHarish Mahendrakar       return false;
2329*103e46e4SHarish Mahendrakar     }
2330*103e46e4SHarish Mahendrakar 
2331*103e46e4SHarish Mahendrakar     if (id == libwebm::kMkvCueTime)
2332*103e46e4SHarish Mahendrakar       m_timecode = UnserializeUInt(pReader, pos, size);
2333*103e46e4SHarish Mahendrakar 
2334*103e46e4SHarish Mahendrakar     else if (id == libwebm::kMkvCueTrackPositions) {
2335*103e46e4SHarish Mahendrakar       ++track_positions_count;
2336*103e46e4SHarish Mahendrakar       if (track_positions_count > UINT_MAX)
2337*103e46e4SHarish Mahendrakar         return E_PARSE_FAILED;
2338*103e46e4SHarish Mahendrakar     }
2339*103e46e4SHarish Mahendrakar 
2340*103e46e4SHarish Mahendrakar     pos += size;  // consume payload
2341*103e46e4SHarish Mahendrakar   }
2342*103e46e4SHarish Mahendrakar 
2343*103e46e4SHarish Mahendrakar   m_track_positions_count = static_cast<size_t>(track_positions_count);
2344*103e46e4SHarish Mahendrakar 
2345*103e46e4SHarish Mahendrakar   if (m_timecode < 0 || m_track_positions_count <= 0) {
2346*103e46e4SHarish Mahendrakar     return false;
2347*103e46e4SHarish Mahendrakar   }
2348*103e46e4SHarish Mahendrakar 
2349*103e46e4SHarish Mahendrakar   // os << "CuePoint::Load(cont'd): idpos=" << idpos
2350*103e46e4SHarish Mahendrakar   //   << " timecode=" << m_timecode
2351*103e46e4SHarish Mahendrakar   //   << endl;
2352*103e46e4SHarish Mahendrakar 
2353*103e46e4SHarish Mahendrakar   m_track_positions = new (std::nothrow) TrackPosition[m_track_positions_count];
2354*103e46e4SHarish Mahendrakar   if (m_track_positions == NULL)
2355*103e46e4SHarish Mahendrakar     return false;
2356*103e46e4SHarish Mahendrakar 
2357*103e46e4SHarish Mahendrakar   // Now parse track positions
2358*103e46e4SHarish Mahendrakar 
2359*103e46e4SHarish Mahendrakar   TrackPosition* p = m_track_positions;
2360*103e46e4SHarish Mahendrakar   pos = pos_;
2361*103e46e4SHarish Mahendrakar 
2362*103e46e4SHarish Mahendrakar   while (pos < stop) {
2363*103e46e4SHarish Mahendrakar     long len;
2364*103e46e4SHarish Mahendrakar 
2365*103e46e4SHarish Mahendrakar     const long long id = ReadID(pReader, pos, len);
2366*103e46e4SHarish Mahendrakar     if (id < 0 || (pos + len) > stop)
2367*103e46e4SHarish Mahendrakar       return false;
2368*103e46e4SHarish Mahendrakar 
2369*103e46e4SHarish Mahendrakar     pos += len;  // consume ID
2370*103e46e4SHarish Mahendrakar 
2371*103e46e4SHarish Mahendrakar     const long long size = ReadUInt(pReader, pos, len);
2372*103e46e4SHarish Mahendrakar     assert(size >= 0);
2373*103e46e4SHarish Mahendrakar     assert((pos + len) <= stop);
2374*103e46e4SHarish Mahendrakar 
2375*103e46e4SHarish Mahendrakar     pos += len;  // consume Size field
2376*103e46e4SHarish Mahendrakar     assert((pos + size) <= stop);
2377*103e46e4SHarish Mahendrakar 
2378*103e46e4SHarish Mahendrakar     if (id == libwebm::kMkvCueTrackPositions) {
2379*103e46e4SHarish Mahendrakar       TrackPosition& tp = *p++;
2380*103e46e4SHarish Mahendrakar       if (!tp.Parse(pReader, pos, size)) {
2381*103e46e4SHarish Mahendrakar         return false;
2382*103e46e4SHarish Mahendrakar       }
2383*103e46e4SHarish Mahendrakar     }
2384*103e46e4SHarish Mahendrakar 
2385*103e46e4SHarish Mahendrakar     pos += size;  // consume payload
2386*103e46e4SHarish Mahendrakar     if (pos > stop)
2387*103e46e4SHarish Mahendrakar       return false;
2388*103e46e4SHarish Mahendrakar   }
2389*103e46e4SHarish Mahendrakar 
2390*103e46e4SHarish Mahendrakar   assert(size_t(p - m_track_positions) == m_track_positions_count);
2391*103e46e4SHarish Mahendrakar 
2392*103e46e4SHarish Mahendrakar   m_element_start = element_start;
2393*103e46e4SHarish Mahendrakar   m_element_size = element_size;
2394*103e46e4SHarish Mahendrakar 
2395*103e46e4SHarish Mahendrakar   return true;
2396*103e46e4SHarish Mahendrakar }
2397*103e46e4SHarish Mahendrakar 
Parse(IMkvReader * pReader,long long start_,long long size_)2398*103e46e4SHarish Mahendrakar bool CuePoint::TrackPosition::Parse(IMkvReader* pReader, long long start_,
2399*103e46e4SHarish Mahendrakar                                     long long size_) {
2400*103e46e4SHarish Mahendrakar   const long long stop = start_ + size_;
2401*103e46e4SHarish Mahendrakar   long long pos = start_;
2402*103e46e4SHarish Mahendrakar 
2403*103e46e4SHarish Mahendrakar   m_track = -1;
2404*103e46e4SHarish Mahendrakar   m_pos = -1;
2405*103e46e4SHarish Mahendrakar   m_block = 1;  // default
2406*103e46e4SHarish Mahendrakar 
2407*103e46e4SHarish Mahendrakar   while (pos < stop) {
2408*103e46e4SHarish Mahendrakar     long len;
2409*103e46e4SHarish Mahendrakar 
2410*103e46e4SHarish Mahendrakar     const long long id = ReadID(pReader, pos, len);
2411*103e46e4SHarish Mahendrakar     if ((id < 0) || ((pos + len) > stop)) {
2412*103e46e4SHarish Mahendrakar       return false;
2413*103e46e4SHarish Mahendrakar     }
2414*103e46e4SHarish Mahendrakar 
2415*103e46e4SHarish Mahendrakar     pos += len;  // consume ID
2416*103e46e4SHarish Mahendrakar 
2417*103e46e4SHarish Mahendrakar     const long long size = ReadUInt(pReader, pos, len);
2418*103e46e4SHarish Mahendrakar     if ((size < 0) || ((pos + len) > stop)) {
2419*103e46e4SHarish Mahendrakar       return false;
2420*103e46e4SHarish Mahendrakar     }
2421*103e46e4SHarish Mahendrakar 
2422*103e46e4SHarish Mahendrakar     pos += len;  // consume Size field
2423*103e46e4SHarish Mahendrakar     if ((pos + size) > stop) {
2424*103e46e4SHarish Mahendrakar       return false;
2425*103e46e4SHarish Mahendrakar     }
2426*103e46e4SHarish Mahendrakar 
2427*103e46e4SHarish Mahendrakar     if (id == libwebm::kMkvCueTrack)
2428*103e46e4SHarish Mahendrakar       m_track = UnserializeUInt(pReader, pos, size);
2429*103e46e4SHarish Mahendrakar     else if (id == libwebm::kMkvCueClusterPosition)
2430*103e46e4SHarish Mahendrakar       m_pos = UnserializeUInt(pReader, pos, size);
2431*103e46e4SHarish Mahendrakar     else if (id == libwebm::kMkvCueBlockNumber)
2432*103e46e4SHarish Mahendrakar       m_block = UnserializeUInt(pReader, pos, size);
2433*103e46e4SHarish Mahendrakar 
2434*103e46e4SHarish Mahendrakar     pos += size;  // consume payload
2435*103e46e4SHarish Mahendrakar   }
2436*103e46e4SHarish Mahendrakar 
2437*103e46e4SHarish Mahendrakar   if ((m_pos < 0) || (m_track <= 0) || (m_block < 0) || (m_block > LONG_MAX)) {
2438*103e46e4SHarish Mahendrakar     return false;
2439*103e46e4SHarish Mahendrakar   }
2440*103e46e4SHarish Mahendrakar 
2441*103e46e4SHarish Mahendrakar   return true;
2442*103e46e4SHarish Mahendrakar }
2443*103e46e4SHarish Mahendrakar 
Find(const Track * pTrack) const2444*103e46e4SHarish Mahendrakar const CuePoint::TrackPosition* CuePoint::Find(const Track* pTrack) const {
2445*103e46e4SHarish Mahendrakar   if (pTrack == NULL) {
2446*103e46e4SHarish Mahendrakar     return NULL;
2447*103e46e4SHarish Mahendrakar   }
2448*103e46e4SHarish Mahendrakar 
2449*103e46e4SHarish Mahendrakar   const long long n = pTrack->GetNumber();
2450*103e46e4SHarish Mahendrakar 
2451*103e46e4SHarish Mahendrakar   const TrackPosition* i = m_track_positions;
2452*103e46e4SHarish Mahendrakar   const TrackPosition* const j = i + m_track_positions_count;
2453*103e46e4SHarish Mahendrakar 
2454*103e46e4SHarish Mahendrakar   while (i != j) {
2455*103e46e4SHarish Mahendrakar     const TrackPosition& p = *i++;
2456*103e46e4SHarish Mahendrakar 
2457*103e46e4SHarish Mahendrakar     if (p.m_track == n)
2458*103e46e4SHarish Mahendrakar       return &p;
2459*103e46e4SHarish Mahendrakar   }
2460*103e46e4SHarish Mahendrakar 
2461*103e46e4SHarish Mahendrakar   return NULL;  // no matching track number found
2462*103e46e4SHarish Mahendrakar }
2463*103e46e4SHarish Mahendrakar 
GetTimeCode() const2464*103e46e4SHarish Mahendrakar long long CuePoint::GetTimeCode() const { return m_timecode; }
2465*103e46e4SHarish Mahendrakar 
GetTime(const Segment * pSegment) const2466*103e46e4SHarish Mahendrakar long long CuePoint::GetTime(const Segment* pSegment) const {
2467*103e46e4SHarish Mahendrakar   assert(pSegment);
2468*103e46e4SHarish Mahendrakar   assert(m_timecode >= 0);
2469*103e46e4SHarish Mahendrakar 
2470*103e46e4SHarish Mahendrakar   const SegmentInfo* const pInfo = pSegment->GetInfo();
2471*103e46e4SHarish Mahendrakar   assert(pInfo);
2472*103e46e4SHarish Mahendrakar 
2473*103e46e4SHarish Mahendrakar   const long long scale = pInfo->GetTimeCodeScale();
2474*103e46e4SHarish Mahendrakar   assert(scale >= 1);
2475*103e46e4SHarish Mahendrakar 
2476*103e46e4SHarish Mahendrakar   const long long time = scale * m_timecode;
2477*103e46e4SHarish Mahendrakar 
2478*103e46e4SHarish Mahendrakar   return time;
2479*103e46e4SHarish Mahendrakar }
2480*103e46e4SHarish Mahendrakar 
DoneParsing() const2481*103e46e4SHarish Mahendrakar bool Segment::DoneParsing() const {
2482*103e46e4SHarish Mahendrakar   if (m_size < 0) {
2483*103e46e4SHarish Mahendrakar     long long total, avail;
2484*103e46e4SHarish Mahendrakar 
2485*103e46e4SHarish Mahendrakar     const int status = m_pReader->Length(&total, &avail);
2486*103e46e4SHarish Mahendrakar 
2487*103e46e4SHarish Mahendrakar     if (status < 0)  // error
2488*103e46e4SHarish Mahendrakar       return true;  // must assume done
2489*103e46e4SHarish Mahendrakar 
2490*103e46e4SHarish Mahendrakar     if (total < 0)
2491*103e46e4SHarish Mahendrakar       return false;  // assume live stream
2492*103e46e4SHarish Mahendrakar 
2493*103e46e4SHarish Mahendrakar     return (m_pos >= total);
2494*103e46e4SHarish Mahendrakar   }
2495*103e46e4SHarish Mahendrakar 
2496*103e46e4SHarish Mahendrakar   const long long stop = m_start + m_size;
2497*103e46e4SHarish Mahendrakar 
2498*103e46e4SHarish Mahendrakar   return (m_pos >= stop);
2499*103e46e4SHarish Mahendrakar }
2500*103e46e4SHarish Mahendrakar 
GetFirst() const2501*103e46e4SHarish Mahendrakar const Cluster* Segment::GetFirst() const {
2502*103e46e4SHarish Mahendrakar   if ((m_clusters == NULL) || (m_clusterCount <= 0))
2503*103e46e4SHarish Mahendrakar     return &m_eos;
2504*103e46e4SHarish Mahendrakar 
2505*103e46e4SHarish Mahendrakar   Cluster* const pCluster = m_clusters[0];
2506*103e46e4SHarish Mahendrakar   assert(pCluster);
2507*103e46e4SHarish Mahendrakar 
2508*103e46e4SHarish Mahendrakar   return pCluster;
2509*103e46e4SHarish Mahendrakar }
2510*103e46e4SHarish Mahendrakar 
GetLast() const2511*103e46e4SHarish Mahendrakar const Cluster* Segment::GetLast() const {
2512*103e46e4SHarish Mahendrakar   if ((m_clusters == NULL) || (m_clusterCount <= 0))
2513*103e46e4SHarish Mahendrakar     return &m_eos;
2514*103e46e4SHarish Mahendrakar 
2515*103e46e4SHarish Mahendrakar   const long idx = m_clusterCount - 1;
2516*103e46e4SHarish Mahendrakar 
2517*103e46e4SHarish Mahendrakar   Cluster* const pCluster = m_clusters[idx];
2518*103e46e4SHarish Mahendrakar   assert(pCluster);
2519*103e46e4SHarish Mahendrakar 
2520*103e46e4SHarish Mahendrakar   return pCluster;
2521*103e46e4SHarish Mahendrakar }
2522*103e46e4SHarish Mahendrakar 
GetCount() const2523*103e46e4SHarish Mahendrakar unsigned long Segment::GetCount() const { return m_clusterCount; }
2524*103e46e4SHarish Mahendrakar 
GetNext(const Cluster * pCurr)2525*103e46e4SHarish Mahendrakar const Cluster* Segment::GetNext(const Cluster* pCurr) {
2526*103e46e4SHarish Mahendrakar   assert(pCurr);
2527*103e46e4SHarish Mahendrakar   assert(pCurr != &m_eos);
2528*103e46e4SHarish Mahendrakar   assert(m_clusters);
2529*103e46e4SHarish Mahendrakar 
2530*103e46e4SHarish Mahendrakar   long idx = pCurr->m_index;
2531*103e46e4SHarish Mahendrakar 
2532*103e46e4SHarish Mahendrakar   if (idx >= 0) {
2533*103e46e4SHarish Mahendrakar     assert(m_clusterCount > 0);
2534*103e46e4SHarish Mahendrakar     assert(idx < m_clusterCount);
2535*103e46e4SHarish Mahendrakar     assert(pCurr == m_clusters[idx]);
2536*103e46e4SHarish Mahendrakar 
2537*103e46e4SHarish Mahendrakar     ++idx;
2538*103e46e4SHarish Mahendrakar 
2539*103e46e4SHarish Mahendrakar     if (idx >= m_clusterCount)
2540*103e46e4SHarish Mahendrakar       return &m_eos;  // caller will LoadCluster as desired
2541*103e46e4SHarish Mahendrakar 
2542*103e46e4SHarish Mahendrakar     Cluster* const pNext = m_clusters[idx];
2543*103e46e4SHarish Mahendrakar     assert(pNext);
2544*103e46e4SHarish Mahendrakar     assert(pNext->m_index >= 0);
2545*103e46e4SHarish Mahendrakar     assert(pNext->m_index == idx);
2546*103e46e4SHarish Mahendrakar 
2547*103e46e4SHarish Mahendrakar     return pNext;
2548*103e46e4SHarish Mahendrakar   }
2549*103e46e4SHarish Mahendrakar 
2550*103e46e4SHarish Mahendrakar   assert(m_clusterPreloadCount > 0);
2551*103e46e4SHarish Mahendrakar 
2552*103e46e4SHarish Mahendrakar   long long pos = pCurr->m_element_start;
2553*103e46e4SHarish Mahendrakar 
2554*103e46e4SHarish Mahendrakar   assert(m_size >= 0);  // TODO
2555*103e46e4SHarish Mahendrakar   const long long stop = m_start + m_size;  // end of segment
2556*103e46e4SHarish Mahendrakar 
2557*103e46e4SHarish Mahendrakar   {
2558*103e46e4SHarish Mahendrakar     long len;
2559*103e46e4SHarish Mahendrakar 
2560*103e46e4SHarish Mahendrakar     long long result = GetUIntLength(m_pReader, pos, len);
2561*103e46e4SHarish Mahendrakar     assert(result == 0);
2562*103e46e4SHarish Mahendrakar     assert((pos + len) <= stop);  // TODO
2563*103e46e4SHarish Mahendrakar     if (result != 0)
2564*103e46e4SHarish Mahendrakar       return NULL;
2565*103e46e4SHarish Mahendrakar 
2566*103e46e4SHarish Mahendrakar     const long long id = ReadID(m_pReader, pos, len);
2567*103e46e4SHarish Mahendrakar     if (id != libwebm::kMkvCluster)
2568*103e46e4SHarish Mahendrakar       return NULL;
2569*103e46e4SHarish Mahendrakar 
2570*103e46e4SHarish Mahendrakar     pos += len;  // consume ID
2571*103e46e4SHarish Mahendrakar 
2572*103e46e4SHarish Mahendrakar     // Read Size
2573*103e46e4SHarish Mahendrakar     result = GetUIntLength(m_pReader, pos, len);
2574*103e46e4SHarish Mahendrakar     assert(result == 0);  // TODO
2575*103e46e4SHarish Mahendrakar     assert((pos + len) <= stop);  // TODO
2576*103e46e4SHarish Mahendrakar 
2577*103e46e4SHarish Mahendrakar     const long long size = ReadUInt(m_pReader, pos, len);
2578*103e46e4SHarish Mahendrakar     assert(size > 0);  // TODO
2579*103e46e4SHarish Mahendrakar     // assert((pCurr->m_size <= 0) || (pCurr->m_size == size));
2580*103e46e4SHarish Mahendrakar 
2581*103e46e4SHarish Mahendrakar     pos += len;  // consume length of size of element
2582*103e46e4SHarish Mahendrakar     assert((pos + size) <= stop);  // TODO
2583*103e46e4SHarish Mahendrakar 
2584*103e46e4SHarish Mahendrakar     // Pos now points to start of payload
2585*103e46e4SHarish Mahendrakar 
2586*103e46e4SHarish Mahendrakar     pos += size;  // consume payload
2587*103e46e4SHarish Mahendrakar   }
2588*103e46e4SHarish Mahendrakar 
2589*103e46e4SHarish Mahendrakar   long long off_next = 0;
2590*103e46e4SHarish Mahendrakar 
2591*103e46e4SHarish Mahendrakar   while (pos < stop) {
2592*103e46e4SHarish Mahendrakar     long len;
2593*103e46e4SHarish Mahendrakar 
2594*103e46e4SHarish Mahendrakar     long long result = GetUIntLength(m_pReader, pos, len);
2595*103e46e4SHarish Mahendrakar     assert(result == 0);
2596*103e46e4SHarish Mahendrakar     assert((pos + len) <= stop);  // TODO
2597*103e46e4SHarish Mahendrakar     if (result != 0)
2598*103e46e4SHarish Mahendrakar       return NULL;
2599*103e46e4SHarish Mahendrakar 
2600*103e46e4SHarish Mahendrakar     const long long idpos = pos;  // pos of next (potential) cluster
2601*103e46e4SHarish Mahendrakar 
2602*103e46e4SHarish Mahendrakar     const long long id = ReadID(m_pReader, idpos, len);
2603*103e46e4SHarish Mahendrakar     if (id < 0)
2604*103e46e4SHarish Mahendrakar       return NULL;
2605*103e46e4SHarish Mahendrakar 
2606*103e46e4SHarish Mahendrakar     pos += len;  // consume ID
2607*103e46e4SHarish Mahendrakar 
2608*103e46e4SHarish Mahendrakar     // Read Size
2609*103e46e4SHarish Mahendrakar     result = GetUIntLength(m_pReader, pos, len);
2610*103e46e4SHarish Mahendrakar     assert(result == 0);  // TODO
2611*103e46e4SHarish Mahendrakar     assert((pos + len) <= stop);  // TODO
2612*103e46e4SHarish Mahendrakar 
2613*103e46e4SHarish Mahendrakar     const long long size = ReadUInt(m_pReader, pos, len);
2614*103e46e4SHarish Mahendrakar     assert(size >= 0);  // TODO
2615*103e46e4SHarish Mahendrakar 
2616*103e46e4SHarish Mahendrakar     pos += len;  // consume length of size of element
2617*103e46e4SHarish Mahendrakar     assert((pos + size) <= stop);  // TODO
2618*103e46e4SHarish Mahendrakar 
2619*103e46e4SHarish Mahendrakar     // Pos now points to start of payload
2620*103e46e4SHarish Mahendrakar 
2621*103e46e4SHarish Mahendrakar     if (size == 0)  // weird
2622*103e46e4SHarish Mahendrakar       continue;
2623*103e46e4SHarish Mahendrakar 
2624*103e46e4SHarish Mahendrakar     if (id == libwebm::kMkvCluster) {
2625*103e46e4SHarish Mahendrakar       const long long off_next_ = idpos - m_start;
2626*103e46e4SHarish Mahendrakar 
2627*103e46e4SHarish Mahendrakar       long long pos_;
2628*103e46e4SHarish Mahendrakar       long len_;
2629*103e46e4SHarish Mahendrakar 
2630*103e46e4SHarish Mahendrakar       const long status = Cluster::HasBlockEntries(this, off_next_, pos_, len_);
2631*103e46e4SHarish Mahendrakar 
2632*103e46e4SHarish Mahendrakar       assert(status >= 0);
2633*103e46e4SHarish Mahendrakar 
2634*103e46e4SHarish Mahendrakar       if (status > 0) {
2635*103e46e4SHarish Mahendrakar         off_next = off_next_;
2636*103e46e4SHarish Mahendrakar         break;
2637*103e46e4SHarish Mahendrakar       }
2638*103e46e4SHarish Mahendrakar     }
2639*103e46e4SHarish Mahendrakar 
2640*103e46e4SHarish Mahendrakar     pos += size;  // consume payload
2641*103e46e4SHarish Mahendrakar   }
2642*103e46e4SHarish Mahendrakar 
2643*103e46e4SHarish Mahendrakar   if (off_next <= 0)
2644*103e46e4SHarish Mahendrakar     return 0;
2645*103e46e4SHarish Mahendrakar 
2646*103e46e4SHarish Mahendrakar   Cluster** const ii = m_clusters + m_clusterCount;
2647*103e46e4SHarish Mahendrakar   Cluster** i = ii;
2648*103e46e4SHarish Mahendrakar 
2649*103e46e4SHarish Mahendrakar   Cluster** const jj = ii + m_clusterPreloadCount;
2650*103e46e4SHarish Mahendrakar   Cluster** j = jj;
2651*103e46e4SHarish Mahendrakar 
2652*103e46e4SHarish Mahendrakar   while (i < j) {
2653*103e46e4SHarish Mahendrakar     // INVARIANT:
2654*103e46e4SHarish Mahendrakar     //[0, i) < pos_next
2655*103e46e4SHarish Mahendrakar     //[i, j) ?
2656*103e46e4SHarish Mahendrakar     //[j, jj)  > pos_next
2657*103e46e4SHarish Mahendrakar 
2658*103e46e4SHarish Mahendrakar     Cluster** const k = i + (j - i) / 2;
2659*103e46e4SHarish Mahendrakar     assert(k < jj);
2660*103e46e4SHarish Mahendrakar 
2661*103e46e4SHarish Mahendrakar     Cluster* const pNext = *k;
2662*103e46e4SHarish Mahendrakar     assert(pNext);
2663*103e46e4SHarish Mahendrakar     assert(pNext->m_index < 0);
2664*103e46e4SHarish Mahendrakar 
2665*103e46e4SHarish Mahendrakar     // const long long pos_ = pNext->m_pos;
2666*103e46e4SHarish Mahendrakar     // assert(pos_);
2667*103e46e4SHarish Mahendrakar     // pos = pos_ * ((pos_ < 0) ? -1 : 1);
2668*103e46e4SHarish Mahendrakar 
2669*103e46e4SHarish Mahendrakar     pos = pNext->GetPosition();
2670*103e46e4SHarish Mahendrakar 
2671*103e46e4SHarish Mahendrakar     if (pos < off_next)
2672*103e46e4SHarish Mahendrakar       i = k + 1;
2673*103e46e4SHarish Mahendrakar     else if (pos > off_next)
2674*103e46e4SHarish Mahendrakar       j = k;
2675*103e46e4SHarish Mahendrakar     else
2676*103e46e4SHarish Mahendrakar       return pNext;
2677*103e46e4SHarish Mahendrakar   }
2678*103e46e4SHarish Mahendrakar 
2679*103e46e4SHarish Mahendrakar   assert(i == j);
2680*103e46e4SHarish Mahendrakar 
2681*103e46e4SHarish Mahendrakar   Cluster* const pNext = Cluster::Create(this, -1, off_next);
2682*103e46e4SHarish Mahendrakar   if (pNext == NULL)
2683*103e46e4SHarish Mahendrakar     return NULL;
2684*103e46e4SHarish Mahendrakar 
2685*103e46e4SHarish Mahendrakar   const ptrdiff_t idx_next = i - m_clusters;  // insertion position
2686*103e46e4SHarish Mahendrakar 
2687*103e46e4SHarish Mahendrakar   if (!PreloadCluster(pNext, idx_next)) {
2688*103e46e4SHarish Mahendrakar     delete pNext;
2689*103e46e4SHarish Mahendrakar     return NULL;
2690*103e46e4SHarish Mahendrakar   }
2691*103e46e4SHarish Mahendrakar   assert(m_clusters);
2692*103e46e4SHarish Mahendrakar   assert(idx_next < m_clusterSize);
2693*103e46e4SHarish Mahendrakar   assert(m_clusters[idx_next] == pNext);
2694*103e46e4SHarish Mahendrakar 
2695*103e46e4SHarish Mahendrakar   return pNext;
2696*103e46e4SHarish Mahendrakar }
2697*103e46e4SHarish Mahendrakar 
ParseNext(const Cluster * pCurr,const Cluster * & pResult,long long & pos,long & len)2698*103e46e4SHarish Mahendrakar long Segment::ParseNext(const Cluster* pCurr, const Cluster*& pResult,
2699*103e46e4SHarish Mahendrakar                         long long& pos, long& len) {
2700*103e46e4SHarish Mahendrakar   assert(pCurr);
2701*103e46e4SHarish Mahendrakar   assert(!pCurr->EOS());
2702*103e46e4SHarish Mahendrakar   assert(m_clusters);
2703*103e46e4SHarish Mahendrakar 
2704*103e46e4SHarish Mahendrakar   pResult = 0;
2705*103e46e4SHarish Mahendrakar 
2706*103e46e4SHarish Mahendrakar   if (pCurr->m_index >= 0) {  // loaded (not merely preloaded)
2707*103e46e4SHarish Mahendrakar     assert(m_clusters[pCurr->m_index] == pCurr);
2708*103e46e4SHarish Mahendrakar 
2709*103e46e4SHarish Mahendrakar     const long next_idx = pCurr->m_index + 1;
2710*103e46e4SHarish Mahendrakar 
2711*103e46e4SHarish Mahendrakar     if (next_idx < m_clusterCount) {
2712*103e46e4SHarish Mahendrakar       pResult = m_clusters[next_idx];
2713*103e46e4SHarish Mahendrakar       return 0;  // success
2714*103e46e4SHarish Mahendrakar     }
2715*103e46e4SHarish Mahendrakar 
2716*103e46e4SHarish Mahendrakar     // curr cluster is last among loaded
2717*103e46e4SHarish Mahendrakar 
2718*103e46e4SHarish Mahendrakar     const long result = LoadCluster(pos, len);
2719*103e46e4SHarish Mahendrakar 
2720*103e46e4SHarish Mahendrakar     if (result < 0)  // error or underflow
2721*103e46e4SHarish Mahendrakar       return result;
2722*103e46e4SHarish Mahendrakar 
2723*103e46e4SHarish Mahendrakar     if (result > 0)  // no more clusters
2724*103e46e4SHarish Mahendrakar     {
2725*103e46e4SHarish Mahendrakar       // pResult = &m_eos;
2726*103e46e4SHarish Mahendrakar       return 1;
2727*103e46e4SHarish Mahendrakar     }
2728*103e46e4SHarish Mahendrakar 
2729*103e46e4SHarish Mahendrakar     pResult = GetLast();
2730*103e46e4SHarish Mahendrakar     return 0;  // success
2731*103e46e4SHarish Mahendrakar   }
2732*103e46e4SHarish Mahendrakar 
2733*103e46e4SHarish Mahendrakar   assert(m_pos > 0);
2734*103e46e4SHarish Mahendrakar 
2735*103e46e4SHarish Mahendrakar   long long total, avail;
2736*103e46e4SHarish Mahendrakar 
2737*103e46e4SHarish Mahendrakar   long status = m_pReader->Length(&total, &avail);
2738*103e46e4SHarish Mahendrakar 
2739*103e46e4SHarish Mahendrakar   if (status < 0)  // error
2740*103e46e4SHarish Mahendrakar     return status;
2741*103e46e4SHarish Mahendrakar 
2742*103e46e4SHarish Mahendrakar   assert((total < 0) || (avail <= total));
2743*103e46e4SHarish Mahendrakar 
2744*103e46e4SHarish Mahendrakar   const long long segment_stop = (m_size < 0) ? -1 : m_start + m_size;
2745*103e46e4SHarish Mahendrakar 
2746*103e46e4SHarish Mahendrakar   // interrogate curr cluster
2747*103e46e4SHarish Mahendrakar 
2748*103e46e4SHarish Mahendrakar   pos = pCurr->m_element_start;
2749*103e46e4SHarish Mahendrakar 
2750*103e46e4SHarish Mahendrakar   if (pCurr->m_element_size >= 0)
2751*103e46e4SHarish Mahendrakar     pos += pCurr->m_element_size;
2752*103e46e4SHarish Mahendrakar   else {
2753*103e46e4SHarish Mahendrakar     if ((pos + 1) > avail) {
2754*103e46e4SHarish Mahendrakar       len = 1;
2755*103e46e4SHarish Mahendrakar       return E_BUFFER_NOT_FULL;
2756*103e46e4SHarish Mahendrakar     }
2757*103e46e4SHarish Mahendrakar 
2758*103e46e4SHarish Mahendrakar     long long result = GetUIntLength(m_pReader, pos, len);
2759*103e46e4SHarish Mahendrakar 
2760*103e46e4SHarish Mahendrakar     if (result < 0)  // error
2761*103e46e4SHarish Mahendrakar       return static_cast<long>(result);
2762*103e46e4SHarish Mahendrakar 
2763*103e46e4SHarish Mahendrakar     if (result > 0)  // weird
2764*103e46e4SHarish Mahendrakar       return E_BUFFER_NOT_FULL;
2765*103e46e4SHarish Mahendrakar 
2766*103e46e4SHarish Mahendrakar     if ((segment_stop >= 0) && ((pos + len) > segment_stop))
2767*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
2768*103e46e4SHarish Mahendrakar 
2769*103e46e4SHarish Mahendrakar     if ((pos + len) > avail)
2770*103e46e4SHarish Mahendrakar       return E_BUFFER_NOT_FULL;
2771*103e46e4SHarish Mahendrakar 
2772*103e46e4SHarish Mahendrakar     const long long id = ReadUInt(m_pReader, pos, len);
2773*103e46e4SHarish Mahendrakar 
2774*103e46e4SHarish Mahendrakar     if (id != libwebm::kMkvCluster)
2775*103e46e4SHarish Mahendrakar       return -1;
2776*103e46e4SHarish Mahendrakar 
2777*103e46e4SHarish Mahendrakar     pos += len;  // consume ID
2778*103e46e4SHarish Mahendrakar 
2779*103e46e4SHarish Mahendrakar     // Read Size
2780*103e46e4SHarish Mahendrakar 
2781*103e46e4SHarish Mahendrakar     if ((pos + 1) > avail) {
2782*103e46e4SHarish Mahendrakar       len = 1;
2783*103e46e4SHarish Mahendrakar       return E_BUFFER_NOT_FULL;
2784*103e46e4SHarish Mahendrakar     }
2785*103e46e4SHarish Mahendrakar 
2786*103e46e4SHarish Mahendrakar     result = GetUIntLength(m_pReader, pos, len);
2787*103e46e4SHarish Mahendrakar 
2788*103e46e4SHarish Mahendrakar     if (result < 0)  // error
2789*103e46e4SHarish Mahendrakar       return static_cast<long>(result);
2790*103e46e4SHarish Mahendrakar 
2791*103e46e4SHarish Mahendrakar     if (result > 0)  // weird
2792*103e46e4SHarish Mahendrakar       return E_BUFFER_NOT_FULL;
2793*103e46e4SHarish Mahendrakar 
2794*103e46e4SHarish Mahendrakar     if ((segment_stop >= 0) && ((pos + len) > segment_stop))
2795*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
2796*103e46e4SHarish Mahendrakar 
2797*103e46e4SHarish Mahendrakar     if ((pos + len) > avail)
2798*103e46e4SHarish Mahendrakar       return E_BUFFER_NOT_FULL;
2799*103e46e4SHarish Mahendrakar 
2800*103e46e4SHarish Mahendrakar     const long long size = ReadUInt(m_pReader, pos, len);
2801*103e46e4SHarish Mahendrakar 
2802*103e46e4SHarish Mahendrakar     if (size < 0)  // error
2803*103e46e4SHarish Mahendrakar       return static_cast<long>(size);
2804*103e46e4SHarish Mahendrakar 
2805*103e46e4SHarish Mahendrakar     pos += len;  // consume size field
2806*103e46e4SHarish Mahendrakar 
2807*103e46e4SHarish Mahendrakar     const long long unknown_size = (1LL << (7 * len)) - 1;
2808*103e46e4SHarish Mahendrakar 
2809*103e46e4SHarish Mahendrakar     if (size == unknown_size)  // TODO: should never happen
2810*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;  // TODO: resolve this
2811*103e46e4SHarish Mahendrakar 
2812*103e46e4SHarish Mahendrakar     // assert((pCurr->m_size <= 0) || (pCurr->m_size == size));
2813*103e46e4SHarish Mahendrakar 
2814*103e46e4SHarish Mahendrakar     if ((segment_stop >= 0) && ((pos + size) > segment_stop))
2815*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
2816*103e46e4SHarish Mahendrakar 
2817*103e46e4SHarish Mahendrakar     // Pos now points to start of payload
2818*103e46e4SHarish Mahendrakar 
2819*103e46e4SHarish Mahendrakar     pos += size;  // consume payload (that is, the current cluster)
2820*103e46e4SHarish Mahendrakar     if (segment_stop >= 0 && pos > segment_stop)
2821*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
2822*103e46e4SHarish Mahendrakar 
2823*103e46e4SHarish Mahendrakar     // By consuming the payload, we are assuming that the curr
2824*103e46e4SHarish Mahendrakar     // cluster isn't interesting.  That is, we don't bother checking
2825*103e46e4SHarish Mahendrakar     // whether the payload of the curr cluster is less than what
2826*103e46e4SHarish Mahendrakar     // happens to be available (obtained via IMkvReader::Length).
2827*103e46e4SHarish Mahendrakar     // Presumably the caller has already dispensed with the current
2828*103e46e4SHarish Mahendrakar     // cluster, and really does want the next cluster.
2829*103e46e4SHarish Mahendrakar   }
2830*103e46e4SHarish Mahendrakar 
2831*103e46e4SHarish Mahendrakar   // pos now points to just beyond the last fully-loaded cluster
2832*103e46e4SHarish Mahendrakar 
2833*103e46e4SHarish Mahendrakar   for (;;) {
2834*103e46e4SHarish Mahendrakar     const long status = DoParseNext(pResult, pos, len);
2835*103e46e4SHarish Mahendrakar 
2836*103e46e4SHarish Mahendrakar     if (status <= 1)
2837*103e46e4SHarish Mahendrakar       return status;
2838*103e46e4SHarish Mahendrakar   }
2839*103e46e4SHarish Mahendrakar }
2840*103e46e4SHarish Mahendrakar 
DoParseNext(const Cluster * & pResult,long long & pos,long & len)2841*103e46e4SHarish Mahendrakar long Segment::DoParseNext(const Cluster*& pResult, long long& pos, long& len) {
2842*103e46e4SHarish Mahendrakar   long long total, avail;
2843*103e46e4SHarish Mahendrakar 
2844*103e46e4SHarish Mahendrakar   long status = m_pReader->Length(&total, &avail);
2845*103e46e4SHarish Mahendrakar 
2846*103e46e4SHarish Mahendrakar   if (status < 0)  // error
2847*103e46e4SHarish Mahendrakar     return status;
2848*103e46e4SHarish Mahendrakar 
2849*103e46e4SHarish Mahendrakar   assert((total < 0) || (avail <= total));
2850*103e46e4SHarish Mahendrakar 
2851*103e46e4SHarish Mahendrakar   const long long segment_stop = (m_size < 0) ? -1 : m_start + m_size;
2852*103e46e4SHarish Mahendrakar 
2853*103e46e4SHarish Mahendrakar   // Parse next cluster.  This is strictly a parsing activity.
2854*103e46e4SHarish Mahendrakar   // Creation of a new cluster object happens later, after the
2855*103e46e4SHarish Mahendrakar   // parsing is done.
2856*103e46e4SHarish Mahendrakar 
2857*103e46e4SHarish Mahendrakar   long long off_next = 0;
2858*103e46e4SHarish Mahendrakar   long long cluster_size = -1;
2859*103e46e4SHarish Mahendrakar 
2860*103e46e4SHarish Mahendrakar   for (;;) {
2861*103e46e4SHarish Mahendrakar     if ((total >= 0) && (pos >= total))
2862*103e46e4SHarish Mahendrakar       return 1;  // EOF
2863*103e46e4SHarish Mahendrakar 
2864*103e46e4SHarish Mahendrakar     if ((segment_stop >= 0) && (pos >= segment_stop))
2865*103e46e4SHarish Mahendrakar       return 1;  // EOF
2866*103e46e4SHarish Mahendrakar 
2867*103e46e4SHarish Mahendrakar     if ((pos + 1) > avail) {
2868*103e46e4SHarish Mahendrakar       len = 1;
2869*103e46e4SHarish Mahendrakar       return E_BUFFER_NOT_FULL;
2870*103e46e4SHarish Mahendrakar     }
2871*103e46e4SHarish Mahendrakar 
2872*103e46e4SHarish Mahendrakar     long long result = GetUIntLength(m_pReader, pos, len);
2873*103e46e4SHarish Mahendrakar 
2874*103e46e4SHarish Mahendrakar     if (result < 0)  // error
2875*103e46e4SHarish Mahendrakar       return static_cast<long>(result);
2876*103e46e4SHarish Mahendrakar 
2877*103e46e4SHarish Mahendrakar     if (result > 0)  // weird
2878*103e46e4SHarish Mahendrakar       return E_BUFFER_NOT_FULL;
2879*103e46e4SHarish Mahendrakar 
2880*103e46e4SHarish Mahendrakar     if ((segment_stop >= 0) && ((pos + len) > segment_stop))
2881*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
2882*103e46e4SHarish Mahendrakar 
2883*103e46e4SHarish Mahendrakar     if ((pos + len) > avail)
2884*103e46e4SHarish Mahendrakar       return E_BUFFER_NOT_FULL;
2885*103e46e4SHarish Mahendrakar 
2886*103e46e4SHarish Mahendrakar     const long long idpos = pos;  // absolute
2887*103e46e4SHarish Mahendrakar     const long long idoff = pos - m_start;  // relative
2888*103e46e4SHarish Mahendrakar 
2889*103e46e4SHarish Mahendrakar     const long long id = ReadID(m_pReader, idpos, len);  // absolute
2890*103e46e4SHarish Mahendrakar 
2891*103e46e4SHarish Mahendrakar     if (id < 0)  // error
2892*103e46e4SHarish Mahendrakar       return static_cast<long>(id);
2893*103e46e4SHarish Mahendrakar 
2894*103e46e4SHarish Mahendrakar     if (id == 0)  // weird
2895*103e46e4SHarish Mahendrakar       return -1;  // generic error
2896*103e46e4SHarish Mahendrakar 
2897*103e46e4SHarish Mahendrakar     pos += len;  // consume ID
2898*103e46e4SHarish Mahendrakar 
2899*103e46e4SHarish Mahendrakar     // Read Size
2900*103e46e4SHarish Mahendrakar 
2901*103e46e4SHarish Mahendrakar     if ((pos + 1) > avail) {
2902*103e46e4SHarish Mahendrakar       len = 1;
2903*103e46e4SHarish Mahendrakar       return E_BUFFER_NOT_FULL;
2904*103e46e4SHarish Mahendrakar     }
2905*103e46e4SHarish Mahendrakar 
2906*103e46e4SHarish Mahendrakar     result = GetUIntLength(m_pReader, pos, len);
2907*103e46e4SHarish Mahendrakar 
2908*103e46e4SHarish Mahendrakar     if (result < 0)  // error
2909*103e46e4SHarish Mahendrakar       return static_cast<long>(result);
2910*103e46e4SHarish Mahendrakar 
2911*103e46e4SHarish Mahendrakar     if (result > 0)  // weird
2912*103e46e4SHarish Mahendrakar       return E_BUFFER_NOT_FULL;
2913*103e46e4SHarish Mahendrakar 
2914*103e46e4SHarish Mahendrakar     if ((segment_stop >= 0) && ((pos + len) > segment_stop))
2915*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
2916*103e46e4SHarish Mahendrakar 
2917*103e46e4SHarish Mahendrakar     if ((pos + len) > avail)
2918*103e46e4SHarish Mahendrakar       return E_BUFFER_NOT_FULL;
2919*103e46e4SHarish Mahendrakar 
2920*103e46e4SHarish Mahendrakar     const long long size = ReadUInt(m_pReader, pos, len);
2921*103e46e4SHarish Mahendrakar 
2922*103e46e4SHarish Mahendrakar     if (size < 0)  // error
2923*103e46e4SHarish Mahendrakar       return static_cast<long>(size);
2924*103e46e4SHarish Mahendrakar 
2925*103e46e4SHarish Mahendrakar     pos += len;  // consume length of size of element
2926*103e46e4SHarish Mahendrakar 
2927*103e46e4SHarish Mahendrakar     // Pos now points to start of payload
2928*103e46e4SHarish Mahendrakar 
2929*103e46e4SHarish Mahendrakar     if (size == 0)  // weird
2930*103e46e4SHarish Mahendrakar       continue;
2931*103e46e4SHarish Mahendrakar 
2932*103e46e4SHarish Mahendrakar     const long long unknown_size = (1LL << (7 * len)) - 1;
2933*103e46e4SHarish Mahendrakar 
2934*103e46e4SHarish Mahendrakar     if ((segment_stop >= 0) && (size != unknown_size) &&
2935*103e46e4SHarish Mahendrakar         ((pos + size) > segment_stop)) {
2936*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
2937*103e46e4SHarish Mahendrakar     }
2938*103e46e4SHarish Mahendrakar 
2939*103e46e4SHarish Mahendrakar     if (id == libwebm::kMkvCues) {
2940*103e46e4SHarish Mahendrakar       if (size == unknown_size)
2941*103e46e4SHarish Mahendrakar         return E_FILE_FORMAT_INVALID;
2942*103e46e4SHarish Mahendrakar 
2943*103e46e4SHarish Mahendrakar       const long long element_stop = pos + size;
2944*103e46e4SHarish Mahendrakar 
2945*103e46e4SHarish Mahendrakar       if ((segment_stop >= 0) && (element_stop > segment_stop))
2946*103e46e4SHarish Mahendrakar         return E_FILE_FORMAT_INVALID;
2947*103e46e4SHarish Mahendrakar 
2948*103e46e4SHarish Mahendrakar       const long long element_start = idpos;
2949*103e46e4SHarish Mahendrakar       const long long element_size = element_stop - element_start;
2950*103e46e4SHarish Mahendrakar 
2951*103e46e4SHarish Mahendrakar       if (m_pCues == NULL) {
2952*103e46e4SHarish Mahendrakar         m_pCues = new (std::nothrow)
2953*103e46e4SHarish Mahendrakar             Cues(this, pos, size, element_start, element_size);
2954*103e46e4SHarish Mahendrakar         if (m_pCues == NULL)
2955*103e46e4SHarish Mahendrakar           return false;
2956*103e46e4SHarish Mahendrakar       }
2957*103e46e4SHarish Mahendrakar 
2958*103e46e4SHarish Mahendrakar       pos += size;  // consume payload
2959*103e46e4SHarish Mahendrakar       if (segment_stop >= 0 && pos > segment_stop)
2960*103e46e4SHarish Mahendrakar         return E_FILE_FORMAT_INVALID;
2961*103e46e4SHarish Mahendrakar 
2962*103e46e4SHarish Mahendrakar       continue;
2963*103e46e4SHarish Mahendrakar     }
2964*103e46e4SHarish Mahendrakar 
2965*103e46e4SHarish Mahendrakar     if (id != libwebm::kMkvCluster) {  // not a Cluster ID
2966*103e46e4SHarish Mahendrakar       if (size == unknown_size)
2967*103e46e4SHarish Mahendrakar         return E_FILE_FORMAT_INVALID;
2968*103e46e4SHarish Mahendrakar 
2969*103e46e4SHarish Mahendrakar       pos += size;  // consume payload
2970*103e46e4SHarish Mahendrakar       if (segment_stop >= 0 && pos > segment_stop)
2971*103e46e4SHarish Mahendrakar         return E_FILE_FORMAT_INVALID;
2972*103e46e4SHarish Mahendrakar 
2973*103e46e4SHarish Mahendrakar       continue;
2974*103e46e4SHarish Mahendrakar     }
2975*103e46e4SHarish Mahendrakar 
2976*103e46e4SHarish Mahendrakar     // We have a cluster.
2977*103e46e4SHarish Mahendrakar     off_next = idoff;
2978*103e46e4SHarish Mahendrakar 
2979*103e46e4SHarish Mahendrakar     if (size != unknown_size)
2980*103e46e4SHarish Mahendrakar       cluster_size = size;
2981*103e46e4SHarish Mahendrakar 
2982*103e46e4SHarish Mahendrakar     break;
2983*103e46e4SHarish Mahendrakar   }
2984*103e46e4SHarish Mahendrakar 
2985*103e46e4SHarish Mahendrakar   assert(off_next > 0);  // have cluster
2986*103e46e4SHarish Mahendrakar 
2987*103e46e4SHarish Mahendrakar   // We have parsed the next cluster.
2988*103e46e4SHarish Mahendrakar   // We have not created a cluster object yet.  What we need
2989*103e46e4SHarish Mahendrakar   // to do now is determine whether it has already be preloaded
2990*103e46e4SHarish Mahendrakar   //(in which case, an object for this cluster has already been
2991*103e46e4SHarish Mahendrakar   // created), and if not, create a new cluster object.
2992*103e46e4SHarish Mahendrakar 
2993*103e46e4SHarish Mahendrakar   Cluster** const ii = m_clusters + m_clusterCount;
2994*103e46e4SHarish Mahendrakar   Cluster** i = ii;
2995*103e46e4SHarish Mahendrakar 
2996*103e46e4SHarish Mahendrakar   Cluster** const jj = ii + m_clusterPreloadCount;
2997*103e46e4SHarish Mahendrakar   Cluster** j = jj;
2998*103e46e4SHarish Mahendrakar 
2999*103e46e4SHarish Mahendrakar   while (i < j) {
3000*103e46e4SHarish Mahendrakar     // INVARIANT:
3001*103e46e4SHarish Mahendrakar     //[0, i) < pos_next
3002*103e46e4SHarish Mahendrakar     //[i, j) ?
3003*103e46e4SHarish Mahendrakar     //[j, jj)  > pos_next
3004*103e46e4SHarish Mahendrakar 
3005*103e46e4SHarish Mahendrakar     Cluster** const k = i + (j - i) / 2;
3006*103e46e4SHarish Mahendrakar     assert(k < jj);
3007*103e46e4SHarish Mahendrakar 
3008*103e46e4SHarish Mahendrakar     const Cluster* const pNext = *k;
3009*103e46e4SHarish Mahendrakar     assert(pNext);
3010*103e46e4SHarish Mahendrakar     assert(pNext->m_index < 0);
3011*103e46e4SHarish Mahendrakar 
3012*103e46e4SHarish Mahendrakar     pos = pNext->GetPosition();
3013*103e46e4SHarish Mahendrakar     assert(pos >= 0);
3014*103e46e4SHarish Mahendrakar 
3015*103e46e4SHarish Mahendrakar     if (pos < off_next)
3016*103e46e4SHarish Mahendrakar       i = k + 1;
3017*103e46e4SHarish Mahendrakar     else if (pos > off_next)
3018*103e46e4SHarish Mahendrakar       j = k;
3019*103e46e4SHarish Mahendrakar     else {
3020*103e46e4SHarish Mahendrakar       pResult = pNext;
3021*103e46e4SHarish Mahendrakar       return 0;  // success
3022*103e46e4SHarish Mahendrakar     }
3023*103e46e4SHarish Mahendrakar   }
3024*103e46e4SHarish Mahendrakar 
3025*103e46e4SHarish Mahendrakar   assert(i == j);
3026*103e46e4SHarish Mahendrakar 
3027*103e46e4SHarish Mahendrakar   long long pos_;
3028*103e46e4SHarish Mahendrakar   long len_;
3029*103e46e4SHarish Mahendrakar 
3030*103e46e4SHarish Mahendrakar   status = Cluster::HasBlockEntries(this, off_next, pos_, len_);
3031*103e46e4SHarish Mahendrakar 
3032*103e46e4SHarish Mahendrakar   if (status < 0) {  // error or underflow
3033*103e46e4SHarish Mahendrakar     pos = pos_;
3034*103e46e4SHarish Mahendrakar     len = len_;
3035*103e46e4SHarish Mahendrakar 
3036*103e46e4SHarish Mahendrakar     return status;
3037*103e46e4SHarish Mahendrakar   }
3038*103e46e4SHarish Mahendrakar 
3039*103e46e4SHarish Mahendrakar   if (status > 0) {  // means "found at least one block entry"
3040*103e46e4SHarish Mahendrakar     Cluster* const pNext = Cluster::Create(this,
3041*103e46e4SHarish Mahendrakar                                            -1,  // preloaded
3042*103e46e4SHarish Mahendrakar                                            off_next);
3043*103e46e4SHarish Mahendrakar     if (pNext == NULL)
3044*103e46e4SHarish Mahendrakar       return -1;
3045*103e46e4SHarish Mahendrakar 
3046*103e46e4SHarish Mahendrakar     const ptrdiff_t idx_next = i - m_clusters;  // insertion position
3047*103e46e4SHarish Mahendrakar 
3048*103e46e4SHarish Mahendrakar     if (!PreloadCluster(pNext, idx_next)) {
3049*103e46e4SHarish Mahendrakar       delete pNext;
3050*103e46e4SHarish Mahendrakar       return -1;
3051*103e46e4SHarish Mahendrakar     }
3052*103e46e4SHarish Mahendrakar     assert(m_clusters);
3053*103e46e4SHarish Mahendrakar     assert(idx_next < m_clusterSize);
3054*103e46e4SHarish Mahendrakar     assert(m_clusters[idx_next] == pNext);
3055*103e46e4SHarish Mahendrakar 
3056*103e46e4SHarish Mahendrakar     pResult = pNext;
3057*103e46e4SHarish Mahendrakar     return 0;  // success
3058*103e46e4SHarish Mahendrakar   }
3059*103e46e4SHarish Mahendrakar 
3060*103e46e4SHarish Mahendrakar   // status == 0 means "no block entries found"
3061*103e46e4SHarish Mahendrakar 
3062*103e46e4SHarish Mahendrakar   if (cluster_size < 0) {  // unknown size
3063*103e46e4SHarish Mahendrakar     const long long payload_pos = pos;  // absolute pos of cluster payload
3064*103e46e4SHarish Mahendrakar 
3065*103e46e4SHarish Mahendrakar     for (;;) {  // determine cluster size
3066*103e46e4SHarish Mahendrakar       if ((total >= 0) && (pos >= total))
3067*103e46e4SHarish Mahendrakar         break;
3068*103e46e4SHarish Mahendrakar 
3069*103e46e4SHarish Mahendrakar       if ((segment_stop >= 0) && (pos >= segment_stop))
3070*103e46e4SHarish Mahendrakar         break;  // no more clusters
3071*103e46e4SHarish Mahendrakar 
3072*103e46e4SHarish Mahendrakar       // Read ID
3073*103e46e4SHarish Mahendrakar 
3074*103e46e4SHarish Mahendrakar       if ((pos + 1) > avail) {
3075*103e46e4SHarish Mahendrakar         len = 1;
3076*103e46e4SHarish Mahendrakar         return E_BUFFER_NOT_FULL;
3077*103e46e4SHarish Mahendrakar       }
3078*103e46e4SHarish Mahendrakar 
3079*103e46e4SHarish Mahendrakar       long long result = GetUIntLength(m_pReader, pos, len);
3080*103e46e4SHarish Mahendrakar 
3081*103e46e4SHarish Mahendrakar       if (result < 0)  // error
3082*103e46e4SHarish Mahendrakar         return static_cast<long>(result);
3083*103e46e4SHarish Mahendrakar 
3084*103e46e4SHarish Mahendrakar       if (result > 0)  // weird
3085*103e46e4SHarish Mahendrakar         return E_BUFFER_NOT_FULL;
3086*103e46e4SHarish Mahendrakar 
3087*103e46e4SHarish Mahendrakar       if ((segment_stop >= 0) && ((pos + len) > segment_stop))
3088*103e46e4SHarish Mahendrakar         return E_FILE_FORMAT_INVALID;
3089*103e46e4SHarish Mahendrakar 
3090*103e46e4SHarish Mahendrakar       if ((pos + len) > avail)
3091*103e46e4SHarish Mahendrakar         return E_BUFFER_NOT_FULL;
3092*103e46e4SHarish Mahendrakar 
3093*103e46e4SHarish Mahendrakar       const long long idpos = pos;
3094*103e46e4SHarish Mahendrakar       const long long id = ReadID(m_pReader, idpos, len);
3095*103e46e4SHarish Mahendrakar 
3096*103e46e4SHarish Mahendrakar       if (id < 0)  // error (or underflow)
3097*103e46e4SHarish Mahendrakar         return static_cast<long>(id);
3098*103e46e4SHarish Mahendrakar 
3099*103e46e4SHarish Mahendrakar       // This is the distinguished set of ID's we use to determine
3100*103e46e4SHarish Mahendrakar       // that we have exhausted the sub-element's inside the cluster
3101*103e46e4SHarish Mahendrakar       // whose ID we parsed earlier.
3102*103e46e4SHarish Mahendrakar 
3103*103e46e4SHarish Mahendrakar       if (id == libwebm::kMkvCluster || id == libwebm::kMkvCues)
3104*103e46e4SHarish Mahendrakar         break;
3105*103e46e4SHarish Mahendrakar 
3106*103e46e4SHarish Mahendrakar       pos += len;  // consume ID (of sub-element)
3107*103e46e4SHarish Mahendrakar 
3108*103e46e4SHarish Mahendrakar       // Read Size
3109*103e46e4SHarish Mahendrakar 
3110*103e46e4SHarish Mahendrakar       if ((pos + 1) > avail) {
3111*103e46e4SHarish Mahendrakar         len = 1;
3112*103e46e4SHarish Mahendrakar         return E_BUFFER_NOT_FULL;
3113*103e46e4SHarish Mahendrakar       }
3114*103e46e4SHarish Mahendrakar 
3115*103e46e4SHarish Mahendrakar       result = GetUIntLength(m_pReader, pos, len);
3116*103e46e4SHarish Mahendrakar 
3117*103e46e4SHarish Mahendrakar       if (result < 0)  // error
3118*103e46e4SHarish Mahendrakar         return static_cast<long>(result);
3119*103e46e4SHarish Mahendrakar 
3120*103e46e4SHarish Mahendrakar       if (result > 0)  // weird
3121*103e46e4SHarish Mahendrakar         return E_BUFFER_NOT_FULL;
3122*103e46e4SHarish Mahendrakar 
3123*103e46e4SHarish Mahendrakar       if ((segment_stop >= 0) && ((pos + len) > segment_stop))
3124*103e46e4SHarish Mahendrakar         return E_FILE_FORMAT_INVALID;
3125*103e46e4SHarish Mahendrakar 
3126*103e46e4SHarish Mahendrakar       if ((pos + len) > avail)
3127*103e46e4SHarish Mahendrakar         return E_BUFFER_NOT_FULL;
3128*103e46e4SHarish Mahendrakar 
3129*103e46e4SHarish Mahendrakar       const long long size = ReadUInt(m_pReader, pos, len);
3130*103e46e4SHarish Mahendrakar 
3131*103e46e4SHarish Mahendrakar       if (size < 0)  // error
3132*103e46e4SHarish Mahendrakar         return static_cast<long>(size);
3133*103e46e4SHarish Mahendrakar 
3134*103e46e4SHarish Mahendrakar       pos += len;  // consume size field of element
3135*103e46e4SHarish Mahendrakar 
3136*103e46e4SHarish Mahendrakar       // pos now points to start of sub-element's payload
3137*103e46e4SHarish Mahendrakar 
3138*103e46e4SHarish Mahendrakar       if (size == 0)  // weird
3139*103e46e4SHarish Mahendrakar         continue;
3140*103e46e4SHarish Mahendrakar 
3141*103e46e4SHarish Mahendrakar       const long long unknown_size = (1LL << (7 * len)) - 1;
3142*103e46e4SHarish Mahendrakar 
3143*103e46e4SHarish Mahendrakar       if (size == unknown_size)
3144*103e46e4SHarish Mahendrakar         return E_FILE_FORMAT_INVALID;  // not allowed for sub-elements
3145*103e46e4SHarish Mahendrakar 
3146*103e46e4SHarish Mahendrakar       if ((segment_stop >= 0) && ((pos + size) > segment_stop))  // weird
3147*103e46e4SHarish Mahendrakar         return E_FILE_FORMAT_INVALID;
3148*103e46e4SHarish Mahendrakar 
3149*103e46e4SHarish Mahendrakar       pos += size;  // consume payload of sub-element
3150*103e46e4SHarish Mahendrakar       if (segment_stop >= 0 && pos > segment_stop)
3151*103e46e4SHarish Mahendrakar         return E_FILE_FORMAT_INVALID;
3152*103e46e4SHarish Mahendrakar     }  // determine cluster size
3153*103e46e4SHarish Mahendrakar 
3154*103e46e4SHarish Mahendrakar     cluster_size = pos - payload_pos;
3155*103e46e4SHarish Mahendrakar     assert(cluster_size >= 0);  // TODO: handle cluster_size = 0
3156*103e46e4SHarish Mahendrakar 
3157*103e46e4SHarish Mahendrakar     pos = payload_pos;  // reset and re-parse original cluster
3158*103e46e4SHarish Mahendrakar   }
3159*103e46e4SHarish Mahendrakar 
3160*103e46e4SHarish Mahendrakar   pos += cluster_size;  // consume payload
3161*103e46e4SHarish Mahendrakar   if (segment_stop >= 0 && pos > segment_stop)
3162*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
3163*103e46e4SHarish Mahendrakar 
3164*103e46e4SHarish Mahendrakar   return 2;  // try to find a cluster that follows next
3165*103e46e4SHarish Mahendrakar }
3166*103e46e4SHarish Mahendrakar 
FindCluster(long long time_ns) const3167*103e46e4SHarish Mahendrakar const Cluster* Segment::FindCluster(long long time_ns) const {
3168*103e46e4SHarish Mahendrakar   if ((m_clusters == NULL) || (m_clusterCount <= 0))
3169*103e46e4SHarish Mahendrakar     return &m_eos;
3170*103e46e4SHarish Mahendrakar 
3171*103e46e4SHarish Mahendrakar   {
3172*103e46e4SHarish Mahendrakar     Cluster* const pCluster = m_clusters[0];
3173*103e46e4SHarish Mahendrakar     assert(pCluster);
3174*103e46e4SHarish Mahendrakar     assert(pCluster->m_index == 0);
3175*103e46e4SHarish Mahendrakar 
3176*103e46e4SHarish Mahendrakar     if (time_ns <= pCluster->GetTime())
3177*103e46e4SHarish Mahendrakar       return pCluster;
3178*103e46e4SHarish Mahendrakar   }
3179*103e46e4SHarish Mahendrakar 
3180*103e46e4SHarish Mahendrakar   // Binary search of cluster array
3181*103e46e4SHarish Mahendrakar 
3182*103e46e4SHarish Mahendrakar   long i = 0;
3183*103e46e4SHarish Mahendrakar   long j = m_clusterCount;
3184*103e46e4SHarish Mahendrakar 
3185*103e46e4SHarish Mahendrakar   while (i < j) {
3186*103e46e4SHarish Mahendrakar     // INVARIANT:
3187*103e46e4SHarish Mahendrakar     //[0, i) <= time_ns
3188*103e46e4SHarish Mahendrakar     //[i, j) ?
3189*103e46e4SHarish Mahendrakar     //[j, m_clusterCount)  > time_ns
3190*103e46e4SHarish Mahendrakar 
3191*103e46e4SHarish Mahendrakar     const long k = i + (j - i) / 2;
3192*103e46e4SHarish Mahendrakar     assert(k < m_clusterCount);
3193*103e46e4SHarish Mahendrakar 
3194*103e46e4SHarish Mahendrakar     Cluster* const pCluster = m_clusters[k];
3195*103e46e4SHarish Mahendrakar     assert(pCluster);
3196*103e46e4SHarish Mahendrakar     assert(pCluster->m_index == k);
3197*103e46e4SHarish Mahendrakar 
3198*103e46e4SHarish Mahendrakar     const long long t = pCluster->GetTime();
3199*103e46e4SHarish Mahendrakar 
3200*103e46e4SHarish Mahendrakar     if (t <= time_ns)
3201*103e46e4SHarish Mahendrakar       i = k + 1;
3202*103e46e4SHarish Mahendrakar     else
3203*103e46e4SHarish Mahendrakar       j = k;
3204*103e46e4SHarish Mahendrakar 
3205*103e46e4SHarish Mahendrakar     assert(i <= j);
3206*103e46e4SHarish Mahendrakar   }
3207*103e46e4SHarish Mahendrakar 
3208*103e46e4SHarish Mahendrakar   assert(i == j);
3209*103e46e4SHarish Mahendrakar   assert(i > 0);
3210*103e46e4SHarish Mahendrakar   assert(i <= m_clusterCount);
3211*103e46e4SHarish Mahendrakar 
3212*103e46e4SHarish Mahendrakar   const long k = i - 1;
3213*103e46e4SHarish Mahendrakar 
3214*103e46e4SHarish Mahendrakar   Cluster* const pCluster = m_clusters[k];
3215*103e46e4SHarish Mahendrakar   assert(pCluster);
3216*103e46e4SHarish Mahendrakar   assert(pCluster->m_index == k);
3217*103e46e4SHarish Mahendrakar   assert(pCluster->GetTime() <= time_ns);
3218*103e46e4SHarish Mahendrakar 
3219*103e46e4SHarish Mahendrakar   return pCluster;
3220*103e46e4SHarish Mahendrakar }
3221*103e46e4SHarish Mahendrakar 
GetTracks() const3222*103e46e4SHarish Mahendrakar const Tracks* Segment::GetTracks() const { return m_pTracks; }
GetInfo() const3223*103e46e4SHarish Mahendrakar const SegmentInfo* Segment::GetInfo() const { return m_pInfo; }
GetCues() const3224*103e46e4SHarish Mahendrakar const Cues* Segment::GetCues() const { return m_pCues; }
GetChapters() const3225*103e46e4SHarish Mahendrakar const Chapters* Segment::GetChapters() const { return m_pChapters; }
GetTags() const3226*103e46e4SHarish Mahendrakar const Tags* Segment::GetTags() const { return m_pTags; }
GetSeekHead() const3227*103e46e4SHarish Mahendrakar const SeekHead* Segment::GetSeekHead() const { return m_pSeekHead; }
3228*103e46e4SHarish Mahendrakar 
GetDuration() const3229*103e46e4SHarish Mahendrakar long long Segment::GetDuration() const {
3230*103e46e4SHarish Mahendrakar   assert(m_pInfo);
3231*103e46e4SHarish Mahendrakar   return m_pInfo->GetDuration();
3232*103e46e4SHarish Mahendrakar }
3233*103e46e4SHarish Mahendrakar 
Chapters(Segment * pSegment,long long payload_start,long long payload_size,long long element_start,long long element_size)3234*103e46e4SHarish Mahendrakar Chapters::Chapters(Segment* pSegment, long long payload_start,
3235*103e46e4SHarish Mahendrakar                    long long payload_size, long long element_start,
3236*103e46e4SHarish Mahendrakar                    long long element_size)
3237*103e46e4SHarish Mahendrakar     : m_pSegment(pSegment),
3238*103e46e4SHarish Mahendrakar       m_start(payload_start),
3239*103e46e4SHarish Mahendrakar       m_size(payload_size),
3240*103e46e4SHarish Mahendrakar       m_element_start(element_start),
3241*103e46e4SHarish Mahendrakar       m_element_size(element_size),
3242*103e46e4SHarish Mahendrakar       m_editions(NULL),
3243*103e46e4SHarish Mahendrakar       m_editions_size(0),
3244*103e46e4SHarish Mahendrakar       m_editions_count(0) {}
3245*103e46e4SHarish Mahendrakar 
~Chapters()3246*103e46e4SHarish Mahendrakar Chapters::~Chapters() {
3247*103e46e4SHarish Mahendrakar   while (m_editions_count > 0) {
3248*103e46e4SHarish Mahendrakar     Edition& e = m_editions[--m_editions_count];
3249*103e46e4SHarish Mahendrakar     e.Clear();
3250*103e46e4SHarish Mahendrakar   }
3251*103e46e4SHarish Mahendrakar   delete[] m_editions;
3252*103e46e4SHarish Mahendrakar }
3253*103e46e4SHarish Mahendrakar 
Parse()3254*103e46e4SHarish Mahendrakar long Chapters::Parse() {
3255*103e46e4SHarish Mahendrakar   IMkvReader* const pReader = m_pSegment->m_pReader;
3256*103e46e4SHarish Mahendrakar 
3257*103e46e4SHarish Mahendrakar   long long pos = m_start;  // payload start
3258*103e46e4SHarish Mahendrakar   const long long stop = pos + m_size;  // payload stop
3259*103e46e4SHarish Mahendrakar 
3260*103e46e4SHarish Mahendrakar   while (pos < stop) {
3261*103e46e4SHarish Mahendrakar     long long id, size;
3262*103e46e4SHarish Mahendrakar 
3263*103e46e4SHarish Mahendrakar     long status = ParseElementHeader(pReader, pos, stop, id, size);
3264*103e46e4SHarish Mahendrakar 
3265*103e46e4SHarish Mahendrakar     if (status < 0)  // error
3266*103e46e4SHarish Mahendrakar       return status;
3267*103e46e4SHarish Mahendrakar 
3268*103e46e4SHarish Mahendrakar     if (size == 0)  // weird
3269*103e46e4SHarish Mahendrakar       continue;
3270*103e46e4SHarish Mahendrakar 
3271*103e46e4SHarish Mahendrakar     if (id == libwebm::kMkvEditionEntry) {
3272*103e46e4SHarish Mahendrakar       status = ParseEdition(pos, size);
3273*103e46e4SHarish Mahendrakar 
3274*103e46e4SHarish Mahendrakar       if (status < 0)  // error
3275*103e46e4SHarish Mahendrakar         return status;
3276*103e46e4SHarish Mahendrakar     }
3277*103e46e4SHarish Mahendrakar 
3278*103e46e4SHarish Mahendrakar     pos += size;
3279*103e46e4SHarish Mahendrakar     if (pos > stop)
3280*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
3281*103e46e4SHarish Mahendrakar   }
3282*103e46e4SHarish Mahendrakar 
3283*103e46e4SHarish Mahendrakar   if (pos != stop)
3284*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
3285*103e46e4SHarish Mahendrakar   return 0;
3286*103e46e4SHarish Mahendrakar }
3287*103e46e4SHarish Mahendrakar 
GetEditionCount() const3288*103e46e4SHarish Mahendrakar int Chapters::GetEditionCount() const { return m_editions_count; }
3289*103e46e4SHarish Mahendrakar 
GetEdition(int idx) const3290*103e46e4SHarish Mahendrakar const Chapters::Edition* Chapters::GetEdition(int idx) const {
3291*103e46e4SHarish Mahendrakar   if (idx < 0)
3292*103e46e4SHarish Mahendrakar     return NULL;
3293*103e46e4SHarish Mahendrakar 
3294*103e46e4SHarish Mahendrakar   if (idx >= m_editions_count)
3295*103e46e4SHarish Mahendrakar     return NULL;
3296*103e46e4SHarish Mahendrakar 
3297*103e46e4SHarish Mahendrakar   return m_editions + idx;
3298*103e46e4SHarish Mahendrakar }
3299*103e46e4SHarish Mahendrakar 
ExpandEditionsArray()3300*103e46e4SHarish Mahendrakar bool Chapters::ExpandEditionsArray() {
3301*103e46e4SHarish Mahendrakar   if (m_editions_size > m_editions_count)
3302*103e46e4SHarish Mahendrakar     return true;  // nothing else to do
3303*103e46e4SHarish Mahendrakar 
3304*103e46e4SHarish Mahendrakar   const int size = (m_editions_size == 0) ? 1 : 2 * m_editions_size;
3305*103e46e4SHarish Mahendrakar 
3306*103e46e4SHarish Mahendrakar   Edition* const editions = new (std::nothrow) Edition[size];
3307*103e46e4SHarish Mahendrakar 
3308*103e46e4SHarish Mahendrakar   if (editions == NULL)
3309*103e46e4SHarish Mahendrakar     return false;
3310*103e46e4SHarish Mahendrakar 
3311*103e46e4SHarish Mahendrakar   for (int idx = 0; idx < m_editions_count; ++idx) {
3312*103e46e4SHarish Mahendrakar     m_editions[idx].ShallowCopy(editions[idx]);
3313*103e46e4SHarish Mahendrakar   }
3314*103e46e4SHarish Mahendrakar 
3315*103e46e4SHarish Mahendrakar   delete[] m_editions;
3316*103e46e4SHarish Mahendrakar   m_editions = editions;
3317*103e46e4SHarish Mahendrakar 
3318*103e46e4SHarish Mahendrakar   m_editions_size = size;
3319*103e46e4SHarish Mahendrakar   return true;
3320*103e46e4SHarish Mahendrakar }
3321*103e46e4SHarish Mahendrakar 
ParseEdition(long long pos,long long size)3322*103e46e4SHarish Mahendrakar long Chapters::ParseEdition(long long pos, long long size) {
3323*103e46e4SHarish Mahendrakar   if (!ExpandEditionsArray())
3324*103e46e4SHarish Mahendrakar     return -1;
3325*103e46e4SHarish Mahendrakar 
3326*103e46e4SHarish Mahendrakar   Edition& e = m_editions[m_editions_count++];
3327*103e46e4SHarish Mahendrakar   e.Init();
3328*103e46e4SHarish Mahendrakar 
3329*103e46e4SHarish Mahendrakar   return e.Parse(m_pSegment->m_pReader, pos, size);
3330*103e46e4SHarish Mahendrakar }
3331*103e46e4SHarish Mahendrakar 
Edition()3332*103e46e4SHarish Mahendrakar Chapters::Edition::Edition() {}
3333*103e46e4SHarish Mahendrakar 
~Edition()3334*103e46e4SHarish Mahendrakar Chapters::Edition::~Edition() {}
3335*103e46e4SHarish Mahendrakar 
GetAtomCount() const3336*103e46e4SHarish Mahendrakar int Chapters::Edition::GetAtomCount() const { return m_atoms_count; }
3337*103e46e4SHarish Mahendrakar 
GetAtom(int index) const3338*103e46e4SHarish Mahendrakar const Chapters::Atom* Chapters::Edition::GetAtom(int index) const {
3339*103e46e4SHarish Mahendrakar   if (index < 0)
3340*103e46e4SHarish Mahendrakar     return NULL;
3341*103e46e4SHarish Mahendrakar 
3342*103e46e4SHarish Mahendrakar   if (index >= m_atoms_count)
3343*103e46e4SHarish Mahendrakar     return NULL;
3344*103e46e4SHarish Mahendrakar 
3345*103e46e4SHarish Mahendrakar   return m_atoms + index;
3346*103e46e4SHarish Mahendrakar }
3347*103e46e4SHarish Mahendrakar 
Init()3348*103e46e4SHarish Mahendrakar void Chapters::Edition::Init() {
3349*103e46e4SHarish Mahendrakar   m_atoms = NULL;
3350*103e46e4SHarish Mahendrakar   m_atoms_size = 0;
3351*103e46e4SHarish Mahendrakar   m_atoms_count = 0;
3352*103e46e4SHarish Mahendrakar }
3353*103e46e4SHarish Mahendrakar 
ShallowCopy(Edition & rhs) const3354*103e46e4SHarish Mahendrakar void Chapters::Edition::ShallowCopy(Edition& rhs) const {
3355*103e46e4SHarish Mahendrakar   rhs.m_atoms = m_atoms;
3356*103e46e4SHarish Mahendrakar   rhs.m_atoms_size = m_atoms_size;
3357*103e46e4SHarish Mahendrakar   rhs.m_atoms_count = m_atoms_count;
3358*103e46e4SHarish Mahendrakar }
3359*103e46e4SHarish Mahendrakar 
Clear()3360*103e46e4SHarish Mahendrakar void Chapters::Edition::Clear() {
3361*103e46e4SHarish Mahendrakar   while (m_atoms_count > 0) {
3362*103e46e4SHarish Mahendrakar     Atom& a = m_atoms[--m_atoms_count];
3363*103e46e4SHarish Mahendrakar     a.Clear();
3364*103e46e4SHarish Mahendrakar   }
3365*103e46e4SHarish Mahendrakar 
3366*103e46e4SHarish Mahendrakar   delete[] m_atoms;
3367*103e46e4SHarish Mahendrakar   m_atoms = NULL;
3368*103e46e4SHarish Mahendrakar 
3369*103e46e4SHarish Mahendrakar   m_atoms_size = 0;
3370*103e46e4SHarish Mahendrakar }
3371*103e46e4SHarish Mahendrakar 
Parse(IMkvReader * pReader,long long pos,long long size)3372*103e46e4SHarish Mahendrakar long Chapters::Edition::Parse(IMkvReader* pReader, long long pos,
3373*103e46e4SHarish Mahendrakar                               long long size) {
3374*103e46e4SHarish Mahendrakar   const long long stop = pos + size;
3375*103e46e4SHarish Mahendrakar 
3376*103e46e4SHarish Mahendrakar   while (pos < stop) {
3377*103e46e4SHarish Mahendrakar     long long id, size;
3378*103e46e4SHarish Mahendrakar 
3379*103e46e4SHarish Mahendrakar     long status = ParseElementHeader(pReader, pos, stop, id, size);
3380*103e46e4SHarish Mahendrakar 
3381*103e46e4SHarish Mahendrakar     if (status < 0)  // error
3382*103e46e4SHarish Mahendrakar       return status;
3383*103e46e4SHarish Mahendrakar 
3384*103e46e4SHarish Mahendrakar     if (size == 0)
3385*103e46e4SHarish Mahendrakar       continue;
3386*103e46e4SHarish Mahendrakar 
3387*103e46e4SHarish Mahendrakar     if (id == libwebm::kMkvChapterAtom) {
3388*103e46e4SHarish Mahendrakar       status = ParseAtom(pReader, pos, size);
3389*103e46e4SHarish Mahendrakar 
3390*103e46e4SHarish Mahendrakar       if (status < 0)  // error
3391*103e46e4SHarish Mahendrakar         return status;
3392*103e46e4SHarish Mahendrakar     }
3393*103e46e4SHarish Mahendrakar 
3394*103e46e4SHarish Mahendrakar     pos += size;
3395*103e46e4SHarish Mahendrakar     if (pos > stop)
3396*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
3397*103e46e4SHarish Mahendrakar   }
3398*103e46e4SHarish Mahendrakar 
3399*103e46e4SHarish Mahendrakar   if (pos != stop)
3400*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
3401*103e46e4SHarish Mahendrakar   return 0;
3402*103e46e4SHarish Mahendrakar }
3403*103e46e4SHarish Mahendrakar 
ParseAtom(IMkvReader * pReader,long long pos,long long size)3404*103e46e4SHarish Mahendrakar long Chapters::Edition::ParseAtom(IMkvReader* pReader, long long pos,
3405*103e46e4SHarish Mahendrakar                                   long long size) {
3406*103e46e4SHarish Mahendrakar   if (!ExpandAtomsArray())
3407*103e46e4SHarish Mahendrakar     return -1;
3408*103e46e4SHarish Mahendrakar 
3409*103e46e4SHarish Mahendrakar   Atom& a = m_atoms[m_atoms_count++];
3410*103e46e4SHarish Mahendrakar   a.Init();
3411*103e46e4SHarish Mahendrakar 
3412*103e46e4SHarish Mahendrakar   return a.Parse(pReader, pos, size);
3413*103e46e4SHarish Mahendrakar }
3414*103e46e4SHarish Mahendrakar 
ExpandAtomsArray()3415*103e46e4SHarish Mahendrakar bool Chapters::Edition::ExpandAtomsArray() {
3416*103e46e4SHarish Mahendrakar   if (m_atoms_size > m_atoms_count)
3417*103e46e4SHarish Mahendrakar     return true;  // nothing else to do
3418*103e46e4SHarish Mahendrakar 
3419*103e46e4SHarish Mahendrakar   const int size = (m_atoms_size == 0) ? 1 : 2 * m_atoms_size;
3420*103e46e4SHarish Mahendrakar 
3421*103e46e4SHarish Mahendrakar   Atom* const atoms = new (std::nothrow) Atom[size];
3422*103e46e4SHarish Mahendrakar 
3423*103e46e4SHarish Mahendrakar   if (atoms == NULL)
3424*103e46e4SHarish Mahendrakar     return false;
3425*103e46e4SHarish Mahendrakar 
3426*103e46e4SHarish Mahendrakar   for (int idx = 0; idx < m_atoms_count; ++idx) {
3427*103e46e4SHarish Mahendrakar     m_atoms[idx].ShallowCopy(atoms[idx]);
3428*103e46e4SHarish Mahendrakar   }
3429*103e46e4SHarish Mahendrakar 
3430*103e46e4SHarish Mahendrakar   delete[] m_atoms;
3431*103e46e4SHarish Mahendrakar   m_atoms = atoms;
3432*103e46e4SHarish Mahendrakar 
3433*103e46e4SHarish Mahendrakar   m_atoms_size = size;
3434*103e46e4SHarish Mahendrakar   return true;
3435*103e46e4SHarish Mahendrakar }
3436*103e46e4SHarish Mahendrakar 
Atom()3437*103e46e4SHarish Mahendrakar Chapters::Atom::Atom() {}
3438*103e46e4SHarish Mahendrakar 
~Atom()3439*103e46e4SHarish Mahendrakar Chapters::Atom::~Atom() {}
3440*103e46e4SHarish Mahendrakar 
GetUID() const3441*103e46e4SHarish Mahendrakar unsigned long long Chapters::Atom::GetUID() const { return m_uid; }
3442*103e46e4SHarish Mahendrakar 
GetStringUID() const3443*103e46e4SHarish Mahendrakar const char* Chapters::Atom::GetStringUID() const { return m_string_uid; }
3444*103e46e4SHarish Mahendrakar 
GetStartTimecode() const3445*103e46e4SHarish Mahendrakar long long Chapters::Atom::GetStartTimecode() const { return m_start_timecode; }
3446*103e46e4SHarish Mahendrakar 
GetStopTimecode() const3447*103e46e4SHarish Mahendrakar long long Chapters::Atom::GetStopTimecode() const { return m_stop_timecode; }
3448*103e46e4SHarish Mahendrakar 
GetStartTime(const Chapters * pChapters) const3449*103e46e4SHarish Mahendrakar long long Chapters::Atom::GetStartTime(const Chapters* pChapters) const {
3450*103e46e4SHarish Mahendrakar   return GetTime(pChapters, m_start_timecode);
3451*103e46e4SHarish Mahendrakar }
3452*103e46e4SHarish Mahendrakar 
GetStopTime(const Chapters * pChapters) const3453*103e46e4SHarish Mahendrakar long long Chapters::Atom::GetStopTime(const Chapters* pChapters) const {
3454*103e46e4SHarish Mahendrakar   return GetTime(pChapters, m_stop_timecode);
3455*103e46e4SHarish Mahendrakar }
3456*103e46e4SHarish Mahendrakar 
GetDisplayCount() const3457*103e46e4SHarish Mahendrakar int Chapters::Atom::GetDisplayCount() const { return m_displays_count; }
3458*103e46e4SHarish Mahendrakar 
GetDisplay(int index) const3459*103e46e4SHarish Mahendrakar const Chapters::Display* Chapters::Atom::GetDisplay(int index) const {
3460*103e46e4SHarish Mahendrakar   if (index < 0)
3461*103e46e4SHarish Mahendrakar     return NULL;
3462*103e46e4SHarish Mahendrakar 
3463*103e46e4SHarish Mahendrakar   if (index >= m_displays_count)
3464*103e46e4SHarish Mahendrakar     return NULL;
3465*103e46e4SHarish Mahendrakar 
3466*103e46e4SHarish Mahendrakar   return m_displays + index;
3467*103e46e4SHarish Mahendrakar }
3468*103e46e4SHarish Mahendrakar 
Init()3469*103e46e4SHarish Mahendrakar void Chapters::Atom::Init() {
3470*103e46e4SHarish Mahendrakar   m_string_uid = NULL;
3471*103e46e4SHarish Mahendrakar   m_uid = 0;
3472*103e46e4SHarish Mahendrakar   m_start_timecode = -1;
3473*103e46e4SHarish Mahendrakar   m_stop_timecode = -1;
3474*103e46e4SHarish Mahendrakar 
3475*103e46e4SHarish Mahendrakar   m_displays = NULL;
3476*103e46e4SHarish Mahendrakar   m_displays_size = 0;
3477*103e46e4SHarish Mahendrakar   m_displays_count = 0;
3478*103e46e4SHarish Mahendrakar }
3479*103e46e4SHarish Mahendrakar 
ShallowCopy(Atom & rhs) const3480*103e46e4SHarish Mahendrakar void Chapters::Atom::ShallowCopy(Atom& rhs) const {
3481*103e46e4SHarish Mahendrakar   rhs.m_string_uid = m_string_uid;
3482*103e46e4SHarish Mahendrakar   rhs.m_uid = m_uid;
3483*103e46e4SHarish Mahendrakar   rhs.m_start_timecode = m_start_timecode;
3484*103e46e4SHarish Mahendrakar   rhs.m_stop_timecode = m_stop_timecode;
3485*103e46e4SHarish Mahendrakar 
3486*103e46e4SHarish Mahendrakar   rhs.m_displays = m_displays;
3487*103e46e4SHarish Mahendrakar   rhs.m_displays_size = m_displays_size;
3488*103e46e4SHarish Mahendrakar   rhs.m_displays_count = m_displays_count;
3489*103e46e4SHarish Mahendrakar }
3490*103e46e4SHarish Mahendrakar 
Clear()3491*103e46e4SHarish Mahendrakar void Chapters::Atom::Clear() {
3492*103e46e4SHarish Mahendrakar   delete[] m_string_uid;
3493*103e46e4SHarish Mahendrakar   m_string_uid = NULL;
3494*103e46e4SHarish Mahendrakar 
3495*103e46e4SHarish Mahendrakar   while (m_displays_count > 0) {
3496*103e46e4SHarish Mahendrakar     Display& d = m_displays[--m_displays_count];
3497*103e46e4SHarish Mahendrakar     d.Clear();
3498*103e46e4SHarish Mahendrakar   }
3499*103e46e4SHarish Mahendrakar 
3500*103e46e4SHarish Mahendrakar   delete[] m_displays;
3501*103e46e4SHarish Mahendrakar   m_displays = NULL;
3502*103e46e4SHarish Mahendrakar 
3503*103e46e4SHarish Mahendrakar   m_displays_size = 0;
3504*103e46e4SHarish Mahendrakar }
3505*103e46e4SHarish Mahendrakar 
Parse(IMkvReader * pReader,long long pos,long long size)3506*103e46e4SHarish Mahendrakar long Chapters::Atom::Parse(IMkvReader* pReader, long long pos, long long size) {
3507*103e46e4SHarish Mahendrakar   const long long stop = pos + size;
3508*103e46e4SHarish Mahendrakar 
3509*103e46e4SHarish Mahendrakar   while (pos < stop) {
3510*103e46e4SHarish Mahendrakar     long long id, size;
3511*103e46e4SHarish Mahendrakar 
3512*103e46e4SHarish Mahendrakar     long status = ParseElementHeader(pReader, pos, stop, id, size);
3513*103e46e4SHarish Mahendrakar 
3514*103e46e4SHarish Mahendrakar     if (status < 0)  // error
3515*103e46e4SHarish Mahendrakar       return status;
3516*103e46e4SHarish Mahendrakar 
3517*103e46e4SHarish Mahendrakar     if (size == 0)  // 0 length payload, skip.
3518*103e46e4SHarish Mahendrakar       continue;
3519*103e46e4SHarish Mahendrakar 
3520*103e46e4SHarish Mahendrakar     if (id == libwebm::kMkvChapterDisplay) {
3521*103e46e4SHarish Mahendrakar       status = ParseDisplay(pReader, pos, size);
3522*103e46e4SHarish Mahendrakar 
3523*103e46e4SHarish Mahendrakar       if (status < 0)  // error
3524*103e46e4SHarish Mahendrakar         return status;
3525*103e46e4SHarish Mahendrakar     } else if (id == libwebm::kMkvChapterStringUID) {
3526*103e46e4SHarish Mahendrakar       status = UnserializeString(pReader, pos, size, m_string_uid);
3527*103e46e4SHarish Mahendrakar 
3528*103e46e4SHarish Mahendrakar       if (status < 0)  // error
3529*103e46e4SHarish Mahendrakar         return status;
3530*103e46e4SHarish Mahendrakar     } else if (id == libwebm::kMkvChapterUID) {
3531*103e46e4SHarish Mahendrakar       long long val;
3532*103e46e4SHarish Mahendrakar       status = UnserializeInt(pReader, pos, size, val);
3533*103e46e4SHarish Mahendrakar 
3534*103e46e4SHarish Mahendrakar       if (status < 0)  // error
3535*103e46e4SHarish Mahendrakar         return status;
3536*103e46e4SHarish Mahendrakar 
3537*103e46e4SHarish Mahendrakar       m_uid = static_cast<unsigned long long>(val);
3538*103e46e4SHarish Mahendrakar     } else if (id == libwebm::kMkvChapterTimeStart) {
3539*103e46e4SHarish Mahendrakar       const long long val = UnserializeUInt(pReader, pos, size);
3540*103e46e4SHarish Mahendrakar 
3541*103e46e4SHarish Mahendrakar       if (val < 0)  // error
3542*103e46e4SHarish Mahendrakar         return static_cast<long>(val);
3543*103e46e4SHarish Mahendrakar 
3544*103e46e4SHarish Mahendrakar       m_start_timecode = val;
3545*103e46e4SHarish Mahendrakar     } else if (id == libwebm::kMkvChapterTimeEnd) {
3546*103e46e4SHarish Mahendrakar       const long long val = UnserializeUInt(pReader, pos, size);
3547*103e46e4SHarish Mahendrakar 
3548*103e46e4SHarish Mahendrakar       if (val < 0)  // error
3549*103e46e4SHarish Mahendrakar         return static_cast<long>(val);
3550*103e46e4SHarish Mahendrakar 
3551*103e46e4SHarish Mahendrakar       m_stop_timecode = val;
3552*103e46e4SHarish Mahendrakar     }
3553*103e46e4SHarish Mahendrakar 
3554*103e46e4SHarish Mahendrakar     pos += size;
3555*103e46e4SHarish Mahendrakar     if (pos > stop)
3556*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
3557*103e46e4SHarish Mahendrakar   }
3558*103e46e4SHarish Mahendrakar 
3559*103e46e4SHarish Mahendrakar   if (pos != stop)
3560*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
3561*103e46e4SHarish Mahendrakar   return 0;
3562*103e46e4SHarish Mahendrakar }
3563*103e46e4SHarish Mahendrakar 
GetTime(const Chapters * pChapters,long long timecode)3564*103e46e4SHarish Mahendrakar long long Chapters::Atom::GetTime(const Chapters* pChapters,
3565*103e46e4SHarish Mahendrakar                                   long long timecode) {
3566*103e46e4SHarish Mahendrakar   if (pChapters == NULL)
3567*103e46e4SHarish Mahendrakar     return -1;
3568*103e46e4SHarish Mahendrakar 
3569*103e46e4SHarish Mahendrakar   Segment* const pSegment = pChapters->m_pSegment;
3570*103e46e4SHarish Mahendrakar 
3571*103e46e4SHarish Mahendrakar   if (pSegment == NULL)  // weird
3572*103e46e4SHarish Mahendrakar     return -1;
3573*103e46e4SHarish Mahendrakar 
3574*103e46e4SHarish Mahendrakar   const SegmentInfo* const pInfo = pSegment->GetInfo();
3575*103e46e4SHarish Mahendrakar 
3576*103e46e4SHarish Mahendrakar   if (pInfo == NULL)
3577*103e46e4SHarish Mahendrakar     return -1;
3578*103e46e4SHarish Mahendrakar 
3579*103e46e4SHarish Mahendrakar   const long long timecode_scale = pInfo->GetTimeCodeScale();
3580*103e46e4SHarish Mahendrakar 
3581*103e46e4SHarish Mahendrakar   if (timecode_scale < 1)  // weird
3582*103e46e4SHarish Mahendrakar     return -1;
3583*103e46e4SHarish Mahendrakar 
3584*103e46e4SHarish Mahendrakar   if (timecode < 0)
3585*103e46e4SHarish Mahendrakar     return -1;
3586*103e46e4SHarish Mahendrakar 
3587*103e46e4SHarish Mahendrakar   const long long result = timecode_scale * timecode;
3588*103e46e4SHarish Mahendrakar 
3589*103e46e4SHarish Mahendrakar   return result;
3590*103e46e4SHarish Mahendrakar }
3591*103e46e4SHarish Mahendrakar 
ParseDisplay(IMkvReader * pReader,long long pos,long long size)3592*103e46e4SHarish Mahendrakar long Chapters::Atom::ParseDisplay(IMkvReader* pReader, long long pos,
3593*103e46e4SHarish Mahendrakar                                   long long size) {
3594*103e46e4SHarish Mahendrakar   if (!ExpandDisplaysArray())
3595*103e46e4SHarish Mahendrakar     return -1;
3596*103e46e4SHarish Mahendrakar 
3597*103e46e4SHarish Mahendrakar   Display& d = m_displays[m_displays_count++];
3598*103e46e4SHarish Mahendrakar   d.Init();
3599*103e46e4SHarish Mahendrakar 
3600*103e46e4SHarish Mahendrakar   return d.Parse(pReader, pos, size);
3601*103e46e4SHarish Mahendrakar }
3602*103e46e4SHarish Mahendrakar 
ExpandDisplaysArray()3603*103e46e4SHarish Mahendrakar bool Chapters::Atom::ExpandDisplaysArray() {
3604*103e46e4SHarish Mahendrakar   if (m_displays_size > m_displays_count)
3605*103e46e4SHarish Mahendrakar     return true;  // nothing else to do
3606*103e46e4SHarish Mahendrakar 
3607*103e46e4SHarish Mahendrakar   const int size = (m_displays_size == 0) ? 1 : 2 * m_displays_size;
3608*103e46e4SHarish Mahendrakar 
3609*103e46e4SHarish Mahendrakar   Display* const displays = new (std::nothrow) Display[size];
3610*103e46e4SHarish Mahendrakar 
3611*103e46e4SHarish Mahendrakar   if (displays == NULL)
3612*103e46e4SHarish Mahendrakar     return false;
3613*103e46e4SHarish Mahendrakar 
3614*103e46e4SHarish Mahendrakar   for (int idx = 0; idx < m_displays_count; ++idx) {
3615*103e46e4SHarish Mahendrakar     m_displays[idx].ShallowCopy(displays[idx]);
3616*103e46e4SHarish Mahendrakar   }
3617*103e46e4SHarish Mahendrakar 
3618*103e46e4SHarish Mahendrakar   delete[] m_displays;
3619*103e46e4SHarish Mahendrakar   m_displays = displays;
3620*103e46e4SHarish Mahendrakar 
3621*103e46e4SHarish Mahendrakar   m_displays_size = size;
3622*103e46e4SHarish Mahendrakar   return true;
3623*103e46e4SHarish Mahendrakar }
3624*103e46e4SHarish Mahendrakar 
Display()3625*103e46e4SHarish Mahendrakar Chapters::Display::Display() {}
3626*103e46e4SHarish Mahendrakar 
~Display()3627*103e46e4SHarish Mahendrakar Chapters::Display::~Display() {}
3628*103e46e4SHarish Mahendrakar 
GetString() const3629*103e46e4SHarish Mahendrakar const char* Chapters::Display::GetString() const { return m_string; }
3630*103e46e4SHarish Mahendrakar 
GetLanguage() const3631*103e46e4SHarish Mahendrakar const char* Chapters::Display::GetLanguage() const { return m_language; }
3632*103e46e4SHarish Mahendrakar 
GetCountry() const3633*103e46e4SHarish Mahendrakar const char* Chapters::Display::GetCountry() const { return m_country; }
3634*103e46e4SHarish Mahendrakar 
Init()3635*103e46e4SHarish Mahendrakar void Chapters::Display::Init() {
3636*103e46e4SHarish Mahendrakar   m_string = NULL;
3637*103e46e4SHarish Mahendrakar   m_language = NULL;
3638*103e46e4SHarish Mahendrakar   m_country = NULL;
3639*103e46e4SHarish Mahendrakar }
3640*103e46e4SHarish Mahendrakar 
ShallowCopy(Display & rhs) const3641*103e46e4SHarish Mahendrakar void Chapters::Display::ShallowCopy(Display& rhs) const {
3642*103e46e4SHarish Mahendrakar   rhs.m_string = m_string;
3643*103e46e4SHarish Mahendrakar   rhs.m_language = m_language;
3644*103e46e4SHarish Mahendrakar   rhs.m_country = m_country;
3645*103e46e4SHarish Mahendrakar }
3646*103e46e4SHarish Mahendrakar 
Clear()3647*103e46e4SHarish Mahendrakar void Chapters::Display::Clear() {
3648*103e46e4SHarish Mahendrakar   delete[] m_string;
3649*103e46e4SHarish Mahendrakar   m_string = NULL;
3650*103e46e4SHarish Mahendrakar 
3651*103e46e4SHarish Mahendrakar   delete[] m_language;
3652*103e46e4SHarish Mahendrakar   m_language = NULL;
3653*103e46e4SHarish Mahendrakar 
3654*103e46e4SHarish Mahendrakar   delete[] m_country;
3655*103e46e4SHarish Mahendrakar   m_country = NULL;
3656*103e46e4SHarish Mahendrakar }
3657*103e46e4SHarish Mahendrakar 
Parse(IMkvReader * pReader,long long pos,long long size)3658*103e46e4SHarish Mahendrakar long Chapters::Display::Parse(IMkvReader* pReader, long long pos,
3659*103e46e4SHarish Mahendrakar                               long long size) {
3660*103e46e4SHarish Mahendrakar   const long long stop = pos + size;
3661*103e46e4SHarish Mahendrakar 
3662*103e46e4SHarish Mahendrakar   while (pos < stop) {
3663*103e46e4SHarish Mahendrakar     long long id, size;
3664*103e46e4SHarish Mahendrakar 
3665*103e46e4SHarish Mahendrakar     long status = ParseElementHeader(pReader, pos, stop, id, size);
3666*103e46e4SHarish Mahendrakar 
3667*103e46e4SHarish Mahendrakar     if (status < 0)  // error
3668*103e46e4SHarish Mahendrakar       return status;
3669*103e46e4SHarish Mahendrakar 
3670*103e46e4SHarish Mahendrakar     if (size == 0)  // No payload.
3671*103e46e4SHarish Mahendrakar       continue;
3672*103e46e4SHarish Mahendrakar 
3673*103e46e4SHarish Mahendrakar     if (id == libwebm::kMkvChapString) {
3674*103e46e4SHarish Mahendrakar       status = UnserializeString(pReader, pos, size, m_string);
3675*103e46e4SHarish Mahendrakar 
3676*103e46e4SHarish Mahendrakar       if (status)
3677*103e46e4SHarish Mahendrakar         return status;
3678*103e46e4SHarish Mahendrakar     } else if (id == libwebm::kMkvChapLanguage) {
3679*103e46e4SHarish Mahendrakar       status = UnserializeString(pReader, pos, size, m_language);
3680*103e46e4SHarish Mahendrakar 
3681*103e46e4SHarish Mahendrakar       if (status)
3682*103e46e4SHarish Mahendrakar         return status;
3683*103e46e4SHarish Mahendrakar     } else if (id == libwebm::kMkvChapCountry) {
3684*103e46e4SHarish Mahendrakar       status = UnserializeString(pReader, pos, size, m_country);
3685*103e46e4SHarish Mahendrakar 
3686*103e46e4SHarish Mahendrakar       if (status)
3687*103e46e4SHarish Mahendrakar         return status;
3688*103e46e4SHarish Mahendrakar     }
3689*103e46e4SHarish Mahendrakar 
3690*103e46e4SHarish Mahendrakar     pos += size;
3691*103e46e4SHarish Mahendrakar     if (pos > stop)
3692*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
3693*103e46e4SHarish Mahendrakar   }
3694*103e46e4SHarish Mahendrakar 
3695*103e46e4SHarish Mahendrakar   if (pos != stop)
3696*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
3697*103e46e4SHarish Mahendrakar   return 0;
3698*103e46e4SHarish Mahendrakar }
3699*103e46e4SHarish Mahendrakar 
Tags(Segment * pSegment,long long payload_start,long long payload_size,long long element_start,long long element_size)3700*103e46e4SHarish Mahendrakar Tags::Tags(Segment* pSegment, long long payload_start, long long payload_size,
3701*103e46e4SHarish Mahendrakar            long long element_start, long long element_size)
3702*103e46e4SHarish Mahendrakar     : m_pSegment(pSegment),
3703*103e46e4SHarish Mahendrakar       m_start(payload_start),
3704*103e46e4SHarish Mahendrakar       m_size(payload_size),
3705*103e46e4SHarish Mahendrakar       m_element_start(element_start),
3706*103e46e4SHarish Mahendrakar       m_element_size(element_size),
3707*103e46e4SHarish Mahendrakar       m_tags(NULL),
3708*103e46e4SHarish Mahendrakar       m_tags_size(0),
3709*103e46e4SHarish Mahendrakar       m_tags_count(0) {}
3710*103e46e4SHarish Mahendrakar 
~Tags()3711*103e46e4SHarish Mahendrakar Tags::~Tags() {
3712*103e46e4SHarish Mahendrakar   while (m_tags_count > 0) {
3713*103e46e4SHarish Mahendrakar     Tag& t = m_tags[--m_tags_count];
3714*103e46e4SHarish Mahendrakar     t.Clear();
3715*103e46e4SHarish Mahendrakar   }
3716*103e46e4SHarish Mahendrakar   delete[] m_tags;
3717*103e46e4SHarish Mahendrakar }
3718*103e46e4SHarish Mahendrakar 
Parse()3719*103e46e4SHarish Mahendrakar long Tags::Parse() {
3720*103e46e4SHarish Mahendrakar   IMkvReader* const pReader = m_pSegment->m_pReader;
3721*103e46e4SHarish Mahendrakar 
3722*103e46e4SHarish Mahendrakar   long long pos = m_start;  // payload start
3723*103e46e4SHarish Mahendrakar   const long long stop = pos + m_size;  // payload stop
3724*103e46e4SHarish Mahendrakar 
3725*103e46e4SHarish Mahendrakar   while (pos < stop) {
3726*103e46e4SHarish Mahendrakar     long long id, size;
3727*103e46e4SHarish Mahendrakar 
3728*103e46e4SHarish Mahendrakar     long status = ParseElementHeader(pReader, pos, stop, id, size);
3729*103e46e4SHarish Mahendrakar 
3730*103e46e4SHarish Mahendrakar     if (status < 0)
3731*103e46e4SHarish Mahendrakar       return status;
3732*103e46e4SHarish Mahendrakar 
3733*103e46e4SHarish Mahendrakar     if (size == 0)  // 0 length tag, read another
3734*103e46e4SHarish Mahendrakar       continue;
3735*103e46e4SHarish Mahendrakar 
3736*103e46e4SHarish Mahendrakar     if (id == libwebm::kMkvTag) {
3737*103e46e4SHarish Mahendrakar       status = ParseTag(pos, size);
3738*103e46e4SHarish Mahendrakar 
3739*103e46e4SHarish Mahendrakar       if (status < 0)
3740*103e46e4SHarish Mahendrakar         return status;
3741*103e46e4SHarish Mahendrakar     }
3742*103e46e4SHarish Mahendrakar 
3743*103e46e4SHarish Mahendrakar     pos += size;
3744*103e46e4SHarish Mahendrakar     if (pos > stop)
3745*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
3746*103e46e4SHarish Mahendrakar   }
3747*103e46e4SHarish Mahendrakar 
3748*103e46e4SHarish Mahendrakar   if (pos != stop)
3749*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
3750*103e46e4SHarish Mahendrakar 
3751*103e46e4SHarish Mahendrakar   return 0;
3752*103e46e4SHarish Mahendrakar }
3753*103e46e4SHarish Mahendrakar 
GetTagCount() const3754*103e46e4SHarish Mahendrakar int Tags::GetTagCount() const { return m_tags_count; }
3755*103e46e4SHarish Mahendrakar 
GetTag(int idx) const3756*103e46e4SHarish Mahendrakar const Tags::Tag* Tags::GetTag(int idx) const {
3757*103e46e4SHarish Mahendrakar   if (idx < 0)
3758*103e46e4SHarish Mahendrakar     return NULL;
3759*103e46e4SHarish Mahendrakar 
3760*103e46e4SHarish Mahendrakar   if (idx >= m_tags_count)
3761*103e46e4SHarish Mahendrakar     return NULL;
3762*103e46e4SHarish Mahendrakar 
3763*103e46e4SHarish Mahendrakar   return m_tags + idx;
3764*103e46e4SHarish Mahendrakar }
3765*103e46e4SHarish Mahendrakar 
ExpandTagsArray()3766*103e46e4SHarish Mahendrakar bool Tags::ExpandTagsArray() {
3767*103e46e4SHarish Mahendrakar   if (m_tags_size > m_tags_count)
3768*103e46e4SHarish Mahendrakar     return true;  // nothing else to do
3769*103e46e4SHarish Mahendrakar 
3770*103e46e4SHarish Mahendrakar   const int size = (m_tags_size == 0) ? 1 : 2 * m_tags_size;
3771*103e46e4SHarish Mahendrakar 
3772*103e46e4SHarish Mahendrakar   Tag* const tags = new (std::nothrow) Tag[size];
3773*103e46e4SHarish Mahendrakar 
3774*103e46e4SHarish Mahendrakar   if (tags == NULL)
3775*103e46e4SHarish Mahendrakar     return false;
3776*103e46e4SHarish Mahendrakar 
3777*103e46e4SHarish Mahendrakar   for (int idx = 0; idx < m_tags_count; ++idx) {
3778*103e46e4SHarish Mahendrakar     m_tags[idx].ShallowCopy(tags[idx]);
3779*103e46e4SHarish Mahendrakar   }
3780*103e46e4SHarish Mahendrakar 
3781*103e46e4SHarish Mahendrakar   delete[] m_tags;
3782*103e46e4SHarish Mahendrakar   m_tags = tags;
3783*103e46e4SHarish Mahendrakar 
3784*103e46e4SHarish Mahendrakar   m_tags_size = size;
3785*103e46e4SHarish Mahendrakar   return true;
3786*103e46e4SHarish Mahendrakar }
3787*103e46e4SHarish Mahendrakar 
ParseTag(long long pos,long long size)3788*103e46e4SHarish Mahendrakar long Tags::ParseTag(long long pos, long long size) {
3789*103e46e4SHarish Mahendrakar   if (!ExpandTagsArray())
3790*103e46e4SHarish Mahendrakar     return -1;
3791*103e46e4SHarish Mahendrakar 
3792*103e46e4SHarish Mahendrakar   Tag& t = m_tags[m_tags_count++];
3793*103e46e4SHarish Mahendrakar   t.Init();
3794*103e46e4SHarish Mahendrakar 
3795*103e46e4SHarish Mahendrakar   return t.Parse(m_pSegment->m_pReader, pos, size);
3796*103e46e4SHarish Mahendrakar }
3797*103e46e4SHarish Mahendrakar 
Tag()3798*103e46e4SHarish Mahendrakar Tags::Tag::Tag() {}
3799*103e46e4SHarish Mahendrakar 
~Tag()3800*103e46e4SHarish Mahendrakar Tags::Tag::~Tag() {}
3801*103e46e4SHarish Mahendrakar 
GetSimpleTagCount() const3802*103e46e4SHarish Mahendrakar int Tags::Tag::GetSimpleTagCount() const { return m_simple_tags_count; }
3803*103e46e4SHarish Mahendrakar 
GetSimpleTag(int index) const3804*103e46e4SHarish Mahendrakar const Tags::SimpleTag* Tags::Tag::GetSimpleTag(int index) const {
3805*103e46e4SHarish Mahendrakar   if (index < 0)
3806*103e46e4SHarish Mahendrakar     return NULL;
3807*103e46e4SHarish Mahendrakar 
3808*103e46e4SHarish Mahendrakar   if (index >= m_simple_tags_count)
3809*103e46e4SHarish Mahendrakar     return NULL;
3810*103e46e4SHarish Mahendrakar 
3811*103e46e4SHarish Mahendrakar   return m_simple_tags + index;
3812*103e46e4SHarish Mahendrakar }
3813*103e46e4SHarish Mahendrakar 
Init()3814*103e46e4SHarish Mahendrakar void Tags::Tag::Init() {
3815*103e46e4SHarish Mahendrakar   m_simple_tags = NULL;
3816*103e46e4SHarish Mahendrakar   m_simple_tags_size = 0;
3817*103e46e4SHarish Mahendrakar   m_simple_tags_count = 0;
3818*103e46e4SHarish Mahendrakar }
3819*103e46e4SHarish Mahendrakar 
ShallowCopy(Tag & rhs) const3820*103e46e4SHarish Mahendrakar void Tags::Tag::ShallowCopy(Tag& rhs) const {
3821*103e46e4SHarish Mahendrakar   rhs.m_simple_tags = m_simple_tags;
3822*103e46e4SHarish Mahendrakar   rhs.m_simple_tags_size = m_simple_tags_size;
3823*103e46e4SHarish Mahendrakar   rhs.m_simple_tags_count = m_simple_tags_count;
3824*103e46e4SHarish Mahendrakar }
3825*103e46e4SHarish Mahendrakar 
Clear()3826*103e46e4SHarish Mahendrakar void Tags::Tag::Clear() {
3827*103e46e4SHarish Mahendrakar   while (m_simple_tags_count > 0) {
3828*103e46e4SHarish Mahendrakar     SimpleTag& d = m_simple_tags[--m_simple_tags_count];
3829*103e46e4SHarish Mahendrakar     d.Clear();
3830*103e46e4SHarish Mahendrakar   }
3831*103e46e4SHarish Mahendrakar 
3832*103e46e4SHarish Mahendrakar   delete[] m_simple_tags;
3833*103e46e4SHarish Mahendrakar   m_simple_tags = NULL;
3834*103e46e4SHarish Mahendrakar 
3835*103e46e4SHarish Mahendrakar   m_simple_tags_size = 0;
3836*103e46e4SHarish Mahendrakar }
3837*103e46e4SHarish Mahendrakar 
Parse(IMkvReader * pReader,long long pos,long long size)3838*103e46e4SHarish Mahendrakar long Tags::Tag::Parse(IMkvReader* pReader, long long pos, long long size) {
3839*103e46e4SHarish Mahendrakar   const long long stop = pos + size;
3840*103e46e4SHarish Mahendrakar 
3841*103e46e4SHarish Mahendrakar   while (pos < stop) {
3842*103e46e4SHarish Mahendrakar     long long id, size;
3843*103e46e4SHarish Mahendrakar 
3844*103e46e4SHarish Mahendrakar     long status = ParseElementHeader(pReader, pos, stop, id, size);
3845*103e46e4SHarish Mahendrakar 
3846*103e46e4SHarish Mahendrakar     if (status < 0)
3847*103e46e4SHarish Mahendrakar       return status;
3848*103e46e4SHarish Mahendrakar 
3849*103e46e4SHarish Mahendrakar     if (size == 0)  // 0 length tag, read another
3850*103e46e4SHarish Mahendrakar       continue;
3851*103e46e4SHarish Mahendrakar 
3852*103e46e4SHarish Mahendrakar     if (id == libwebm::kMkvSimpleTag) {
3853*103e46e4SHarish Mahendrakar       status = ParseSimpleTag(pReader, pos, size);
3854*103e46e4SHarish Mahendrakar 
3855*103e46e4SHarish Mahendrakar       if (status < 0)
3856*103e46e4SHarish Mahendrakar         return status;
3857*103e46e4SHarish Mahendrakar     }
3858*103e46e4SHarish Mahendrakar 
3859*103e46e4SHarish Mahendrakar     pos += size;
3860*103e46e4SHarish Mahendrakar     if (pos > stop)
3861*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
3862*103e46e4SHarish Mahendrakar   }
3863*103e46e4SHarish Mahendrakar 
3864*103e46e4SHarish Mahendrakar   if (pos != stop)
3865*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
3866*103e46e4SHarish Mahendrakar   return 0;
3867*103e46e4SHarish Mahendrakar }
3868*103e46e4SHarish Mahendrakar 
ParseSimpleTag(IMkvReader * pReader,long long pos,long long size)3869*103e46e4SHarish Mahendrakar long Tags::Tag::ParseSimpleTag(IMkvReader* pReader, long long pos,
3870*103e46e4SHarish Mahendrakar                                long long size) {
3871*103e46e4SHarish Mahendrakar   if (!ExpandSimpleTagsArray())
3872*103e46e4SHarish Mahendrakar     return -1;
3873*103e46e4SHarish Mahendrakar 
3874*103e46e4SHarish Mahendrakar   SimpleTag& st = m_simple_tags[m_simple_tags_count++];
3875*103e46e4SHarish Mahendrakar   st.Init();
3876*103e46e4SHarish Mahendrakar 
3877*103e46e4SHarish Mahendrakar   return st.Parse(pReader, pos, size);
3878*103e46e4SHarish Mahendrakar }
3879*103e46e4SHarish Mahendrakar 
ExpandSimpleTagsArray()3880*103e46e4SHarish Mahendrakar bool Tags::Tag::ExpandSimpleTagsArray() {
3881*103e46e4SHarish Mahendrakar   if (m_simple_tags_size > m_simple_tags_count)
3882*103e46e4SHarish Mahendrakar     return true;  // nothing else to do
3883*103e46e4SHarish Mahendrakar 
3884*103e46e4SHarish Mahendrakar   const int size = (m_simple_tags_size == 0) ? 1 : 2 * m_simple_tags_size;
3885*103e46e4SHarish Mahendrakar 
3886*103e46e4SHarish Mahendrakar   SimpleTag* const displays = new (std::nothrow) SimpleTag[size];
3887*103e46e4SHarish Mahendrakar 
3888*103e46e4SHarish Mahendrakar   if (displays == NULL)
3889*103e46e4SHarish Mahendrakar     return false;
3890*103e46e4SHarish Mahendrakar 
3891*103e46e4SHarish Mahendrakar   for (int idx = 0; idx < m_simple_tags_count; ++idx) {
3892*103e46e4SHarish Mahendrakar     m_simple_tags[idx].ShallowCopy(displays[idx]);
3893*103e46e4SHarish Mahendrakar   }
3894*103e46e4SHarish Mahendrakar 
3895*103e46e4SHarish Mahendrakar   delete[] m_simple_tags;
3896*103e46e4SHarish Mahendrakar   m_simple_tags = displays;
3897*103e46e4SHarish Mahendrakar 
3898*103e46e4SHarish Mahendrakar   m_simple_tags_size = size;
3899*103e46e4SHarish Mahendrakar   return true;
3900*103e46e4SHarish Mahendrakar }
3901*103e46e4SHarish Mahendrakar 
SimpleTag()3902*103e46e4SHarish Mahendrakar Tags::SimpleTag::SimpleTag() {}
3903*103e46e4SHarish Mahendrakar 
~SimpleTag()3904*103e46e4SHarish Mahendrakar Tags::SimpleTag::~SimpleTag() {}
3905*103e46e4SHarish Mahendrakar 
GetTagName() const3906*103e46e4SHarish Mahendrakar const char* Tags::SimpleTag::GetTagName() const { return m_tag_name; }
3907*103e46e4SHarish Mahendrakar 
GetTagString() const3908*103e46e4SHarish Mahendrakar const char* Tags::SimpleTag::GetTagString() const { return m_tag_string; }
3909*103e46e4SHarish Mahendrakar 
Init()3910*103e46e4SHarish Mahendrakar void Tags::SimpleTag::Init() {
3911*103e46e4SHarish Mahendrakar   m_tag_name = NULL;
3912*103e46e4SHarish Mahendrakar   m_tag_string = NULL;
3913*103e46e4SHarish Mahendrakar }
3914*103e46e4SHarish Mahendrakar 
ShallowCopy(SimpleTag & rhs) const3915*103e46e4SHarish Mahendrakar void Tags::SimpleTag::ShallowCopy(SimpleTag& rhs) const {
3916*103e46e4SHarish Mahendrakar   rhs.m_tag_name = m_tag_name;
3917*103e46e4SHarish Mahendrakar   rhs.m_tag_string = m_tag_string;
3918*103e46e4SHarish Mahendrakar }
3919*103e46e4SHarish Mahendrakar 
Clear()3920*103e46e4SHarish Mahendrakar void Tags::SimpleTag::Clear() {
3921*103e46e4SHarish Mahendrakar   delete[] m_tag_name;
3922*103e46e4SHarish Mahendrakar   m_tag_name = NULL;
3923*103e46e4SHarish Mahendrakar 
3924*103e46e4SHarish Mahendrakar   delete[] m_tag_string;
3925*103e46e4SHarish Mahendrakar   m_tag_string = NULL;
3926*103e46e4SHarish Mahendrakar }
3927*103e46e4SHarish Mahendrakar 
Parse(IMkvReader * pReader,long long pos,long long size)3928*103e46e4SHarish Mahendrakar long Tags::SimpleTag::Parse(IMkvReader* pReader, long long pos,
3929*103e46e4SHarish Mahendrakar                             long long size) {
3930*103e46e4SHarish Mahendrakar   const long long stop = pos + size;
3931*103e46e4SHarish Mahendrakar 
3932*103e46e4SHarish Mahendrakar   while (pos < stop) {
3933*103e46e4SHarish Mahendrakar     long long id, size;
3934*103e46e4SHarish Mahendrakar 
3935*103e46e4SHarish Mahendrakar     long status = ParseElementHeader(pReader, pos, stop, id, size);
3936*103e46e4SHarish Mahendrakar 
3937*103e46e4SHarish Mahendrakar     if (status < 0)  // error
3938*103e46e4SHarish Mahendrakar       return status;
3939*103e46e4SHarish Mahendrakar 
3940*103e46e4SHarish Mahendrakar     if (size == 0)  // weird
3941*103e46e4SHarish Mahendrakar       continue;
3942*103e46e4SHarish Mahendrakar 
3943*103e46e4SHarish Mahendrakar     if (id == libwebm::kMkvTagName) {
3944*103e46e4SHarish Mahendrakar       status = UnserializeString(pReader, pos, size, m_tag_name);
3945*103e46e4SHarish Mahendrakar 
3946*103e46e4SHarish Mahendrakar       if (status)
3947*103e46e4SHarish Mahendrakar         return status;
3948*103e46e4SHarish Mahendrakar     } else if (id == libwebm::kMkvTagString) {
3949*103e46e4SHarish Mahendrakar       status = UnserializeString(pReader, pos, size, m_tag_string);
3950*103e46e4SHarish Mahendrakar 
3951*103e46e4SHarish Mahendrakar       if (status)
3952*103e46e4SHarish Mahendrakar         return status;
3953*103e46e4SHarish Mahendrakar     }
3954*103e46e4SHarish Mahendrakar 
3955*103e46e4SHarish Mahendrakar     pos += size;
3956*103e46e4SHarish Mahendrakar     if (pos > stop)
3957*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
3958*103e46e4SHarish Mahendrakar   }
3959*103e46e4SHarish Mahendrakar 
3960*103e46e4SHarish Mahendrakar   if (pos != stop)
3961*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
3962*103e46e4SHarish Mahendrakar   return 0;
3963*103e46e4SHarish Mahendrakar }
3964*103e46e4SHarish Mahendrakar 
SegmentInfo(Segment * pSegment,long long start,long long size_,long long element_start,long long element_size)3965*103e46e4SHarish Mahendrakar SegmentInfo::SegmentInfo(Segment* pSegment, long long start, long long size_,
3966*103e46e4SHarish Mahendrakar                          long long element_start, long long element_size)
3967*103e46e4SHarish Mahendrakar     : m_pSegment(pSegment),
3968*103e46e4SHarish Mahendrakar       m_start(start),
3969*103e46e4SHarish Mahendrakar       m_size(size_),
3970*103e46e4SHarish Mahendrakar       m_element_start(element_start),
3971*103e46e4SHarish Mahendrakar       m_element_size(element_size),
3972*103e46e4SHarish Mahendrakar       m_pMuxingAppAsUTF8(NULL),
3973*103e46e4SHarish Mahendrakar       m_pWritingAppAsUTF8(NULL),
3974*103e46e4SHarish Mahendrakar       m_pTitleAsUTF8(NULL) {}
3975*103e46e4SHarish Mahendrakar 
~SegmentInfo()3976*103e46e4SHarish Mahendrakar SegmentInfo::~SegmentInfo() {
3977*103e46e4SHarish Mahendrakar   delete[] m_pMuxingAppAsUTF8;
3978*103e46e4SHarish Mahendrakar   m_pMuxingAppAsUTF8 = NULL;
3979*103e46e4SHarish Mahendrakar 
3980*103e46e4SHarish Mahendrakar   delete[] m_pWritingAppAsUTF8;
3981*103e46e4SHarish Mahendrakar   m_pWritingAppAsUTF8 = NULL;
3982*103e46e4SHarish Mahendrakar 
3983*103e46e4SHarish Mahendrakar   delete[] m_pTitleAsUTF8;
3984*103e46e4SHarish Mahendrakar   m_pTitleAsUTF8 = NULL;
3985*103e46e4SHarish Mahendrakar }
3986*103e46e4SHarish Mahendrakar 
Parse()3987*103e46e4SHarish Mahendrakar long SegmentInfo::Parse() {
3988*103e46e4SHarish Mahendrakar   assert(m_pMuxingAppAsUTF8 == NULL);
3989*103e46e4SHarish Mahendrakar   assert(m_pWritingAppAsUTF8 == NULL);
3990*103e46e4SHarish Mahendrakar   assert(m_pTitleAsUTF8 == NULL);
3991*103e46e4SHarish Mahendrakar 
3992*103e46e4SHarish Mahendrakar   IMkvReader* const pReader = m_pSegment->m_pReader;
3993*103e46e4SHarish Mahendrakar 
3994*103e46e4SHarish Mahendrakar   long long pos = m_start;
3995*103e46e4SHarish Mahendrakar   const long long stop = m_start + m_size;
3996*103e46e4SHarish Mahendrakar 
3997*103e46e4SHarish Mahendrakar   m_timecodeScale = 1000000;
3998*103e46e4SHarish Mahendrakar   m_duration = -1;
3999*103e46e4SHarish Mahendrakar 
4000*103e46e4SHarish Mahendrakar   while (pos < stop) {
4001*103e46e4SHarish Mahendrakar     long long id, size;
4002*103e46e4SHarish Mahendrakar 
4003*103e46e4SHarish Mahendrakar     const long status = ParseElementHeader(pReader, pos, stop, id, size);
4004*103e46e4SHarish Mahendrakar 
4005*103e46e4SHarish Mahendrakar     if (status < 0)  // error
4006*103e46e4SHarish Mahendrakar       return status;
4007*103e46e4SHarish Mahendrakar 
4008*103e46e4SHarish Mahendrakar     if (id == libwebm::kMkvTimecodeScale) {
4009*103e46e4SHarish Mahendrakar       m_timecodeScale = UnserializeUInt(pReader, pos, size);
4010*103e46e4SHarish Mahendrakar 
4011*103e46e4SHarish Mahendrakar       if (m_timecodeScale <= 0)
4012*103e46e4SHarish Mahendrakar         return E_FILE_FORMAT_INVALID;
4013*103e46e4SHarish Mahendrakar     } else if (id == libwebm::kMkvDuration) {
4014*103e46e4SHarish Mahendrakar       const long status = UnserializeFloat(pReader, pos, size, m_duration);
4015*103e46e4SHarish Mahendrakar 
4016*103e46e4SHarish Mahendrakar       if (status < 0)
4017*103e46e4SHarish Mahendrakar         return status;
4018*103e46e4SHarish Mahendrakar 
4019*103e46e4SHarish Mahendrakar       if (m_duration < 0)
4020*103e46e4SHarish Mahendrakar         return E_FILE_FORMAT_INVALID;
4021*103e46e4SHarish Mahendrakar     } else if (id == libwebm::kMkvMuxingApp) {
4022*103e46e4SHarish Mahendrakar       const long status =
4023*103e46e4SHarish Mahendrakar           UnserializeString(pReader, pos, size, m_pMuxingAppAsUTF8);
4024*103e46e4SHarish Mahendrakar 
4025*103e46e4SHarish Mahendrakar       if (status)
4026*103e46e4SHarish Mahendrakar         return status;
4027*103e46e4SHarish Mahendrakar     } else if (id == libwebm::kMkvWritingApp) {
4028*103e46e4SHarish Mahendrakar       const long status =
4029*103e46e4SHarish Mahendrakar           UnserializeString(pReader, pos, size, m_pWritingAppAsUTF8);
4030*103e46e4SHarish Mahendrakar 
4031*103e46e4SHarish Mahendrakar       if (status)
4032*103e46e4SHarish Mahendrakar         return status;
4033*103e46e4SHarish Mahendrakar     } else if (id == libwebm::kMkvTitle) {
4034*103e46e4SHarish Mahendrakar       const long status = UnserializeString(pReader, pos, size, m_pTitleAsUTF8);
4035*103e46e4SHarish Mahendrakar 
4036*103e46e4SHarish Mahendrakar       if (status)
4037*103e46e4SHarish Mahendrakar         return status;
4038*103e46e4SHarish Mahendrakar     }
4039*103e46e4SHarish Mahendrakar 
4040*103e46e4SHarish Mahendrakar     pos += size;
4041*103e46e4SHarish Mahendrakar 
4042*103e46e4SHarish Mahendrakar     if (pos > stop)
4043*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
4044*103e46e4SHarish Mahendrakar   }
4045*103e46e4SHarish Mahendrakar 
4046*103e46e4SHarish Mahendrakar   const double rollover_check = m_duration * m_timecodeScale;
4047*103e46e4SHarish Mahendrakar   if (rollover_check > static_cast<double>(LLONG_MAX))
4048*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
4049*103e46e4SHarish Mahendrakar 
4050*103e46e4SHarish Mahendrakar   if (pos != stop)
4051*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
4052*103e46e4SHarish Mahendrakar 
4053*103e46e4SHarish Mahendrakar   return 0;
4054*103e46e4SHarish Mahendrakar }
4055*103e46e4SHarish Mahendrakar 
GetTimeCodeScale() const4056*103e46e4SHarish Mahendrakar long long SegmentInfo::GetTimeCodeScale() const { return m_timecodeScale; }
4057*103e46e4SHarish Mahendrakar 
GetDuration() const4058*103e46e4SHarish Mahendrakar long long SegmentInfo::GetDuration() const {
4059*103e46e4SHarish Mahendrakar   if (m_duration < 0)
4060*103e46e4SHarish Mahendrakar     return -1;
4061*103e46e4SHarish Mahendrakar 
4062*103e46e4SHarish Mahendrakar   assert(m_timecodeScale >= 1);
4063*103e46e4SHarish Mahendrakar 
4064*103e46e4SHarish Mahendrakar   const double dd = double(m_duration) * double(m_timecodeScale);
4065*103e46e4SHarish Mahendrakar   const long long d = static_cast<long long>(dd);
4066*103e46e4SHarish Mahendrakar 
4067*103e46e4SHarish Mahendrakar   return d;
4068*103e46e4SHarish Mahendrakar }
4069*103e46e4SHarish Mahendrakar 
GetMuxingAppAsUTF8() const4070*103e46e4SHarish Mahendrakar const char* SegmentInfo::GetMuxingAppAsUTF8() const {
4071*103e46e4SHarish Mahendrakar   return m_pMuxingAppAsUTF8;
4072*103e46e4SHarish Mahendrakar }
4073*103e46e4SHarish Mahendrakar 
GetWritingAppAsUTF8() const4074*103e46e4SHarish Mahendrakar const char* SegmentInfo::GetWritingAppAsUTF8() const {
4075*103e46e4SHarish Mahendrakar   return m_pWritingAppAsUTF8;
4076*103e46e4SHarish Mahendrakar }
4077*103e46e4SHarish Mahendrakar 
GetTitleAsUTF8() const4078*103e46e4SHarish Mahendrakar const char* SegmentInfo::GetTitleAsUTF8() const { return m_pTitleAsUTF8; }
4079*103e46e4SHarish Mahendrakar 
4080*103e46e4SHarish Mahendrakar ///////////////////////////////////////////////////////////////
4081*103e46e4SHarish Mahendrakar // ContentEncoding element
ContentCompression()4082*103e46e4SHarish Mahendrakar ContentEncoding::ContentCompression::ContentCompression()
4083*103e46e4SHarish Mahendrakar     : algo(0), settings(NULL), settings_len(0) {}
4084*103e46e4SHarish Mahendrakar 
~ContentCompression()4085*103e46e4SHarish Mahendrakar ContentEncoding::ContentCompression::~ContentCompression() {
4086*103e46e4SHarish Mahendrakar   delete[] settings;
4087*103e46e4SHarish Mahendrakar }
4088*103e46e4SHarish Mahendrakar 
ContentEncryption()4089*103e46e4SHarish Mahendrakar ContentEncoding::ContentEncryption::ContentEncryption()
4090*103e46e4SHarish Mahendrakar     : algo(0),
4091*103e46e4SHarish Mahendrakar       key_id(NULL),
4092*103e46e4SHarish Mahendrakar       key_id_len(0),
4093*103e46e4SHarish Mahendrakar       signature(NULL),
4094*103e46e4SHarish Mahendrakar       signature_len(0),
4095*103e46e4SHarish Mahendrakar       sig_key_id(NULL),
4096*103e46e4SHarish Mahendrakar       sig_key_id_len(0),
4097*103e46e4SHarish Mahendrakar       sig_algo(0),
4098*103e46e4SHarish Mahendrakar       sig_hash_algo(0) {}
4099*103e46e4SHarish Mahendrakar 
~ContentEncryption()4100*103e46e4SHarish Mahendrakar ContentEncoding::ContentEncryption::~ContentEncryption() {
4101*103e46e4SHarish Mahendrakar   delete[] key_id;
4102*103e46e4SHarish Mahendrakar   delete[] signature;
4103*103e46e4SHarish Mahendrakar   delete[] sig_key_id;
4104*103e46e4SHarish Mahendrakar }
4105*103e46e4SHarish Mahendrakar 
ContentEncoding()4106*103e46e4SHarish Mahendrakar ContentEncoding::ContentEncoding()
4107*103e46e4SHarish Mahendrakar     : compression_entries_(NULL),
4108*103e46e4SHarish Mahendrakar       compression_entries_end_(NULL),
4109*103e46e4SHarish Mahendrakar       encryption_entries_(NULL),
4110*103e46e4SHarish Mahendrakar       encryption_entries_end_(NULL),
4111*103e46e4SHarish Mahendrakar       encoding_order_(0),
4112*103e46e4SHarish Mahendrakar       encoding_scope_(1),
4113*103e46e4SHarish Mahendrakar       encoding_type_(0) {}
4114*103e46e4SHarish Mahendrakar 
~ContentEncoding()4115*103e46e4SHarish Mahendrakar ContentEncoding::~ContentEncoding() {
4116*103e46e4SHarish Mahendrakar   ContentCompression** comp_i = compression_entries_;
4117*103e46e4SHarish Mahendrakar   ContentCompression** const comp_j = compression_entries_end_;
4118*103e46e4SHarish Mahendrakar 
4119*103e46e4SHarish Mahendrakar   while (comp_i != comp_j) {
4120*103e46e4SHarish Mahendrakar     ContentCompression* const comp = *comp_i++;
4121*103e46e4SHarish Mahendrakar     delete comp;
4122*103e46e4SHarish Mahendrakar   }
4123*103e46e4SHarish Mahendrakar 
4124*103e46e4SHarish Mahendrakar   delete[] compression_entries_;
4125*103e46e4SHarish Mahendrakar 
4126*103e46e4SHarish Mahendrakar   ContentEncryption** enc_i = encryption_entries_;
4127*103e46e4SHarish Mahendrakar   ContentEncryption** const enc_j = encryption_entries_end_;
4128*103e46e4SHarish Mahendrakar 
4129*103e46e4SHarish Mahendrakar   while (enc_i != enc_j) {
4130*103e46e4SHarish Mahendrakar     ContentEncryption* const enc = *enc_i++;
4131*103e46e4SHarish Mahendrakar     delete enc;
4132*103e46e4SHarish Mahendrakar   }
4133*103e46e4SHarish Mahendrakar 
4134*103e46e4SHarish Mahendrakar   delete[] encryption_entries_;
4135*103e46e4SHarish Mahendrakar }
4136*103e46e4SHarish Mahendrakar 
4137*103e46e4SHarish Mahendrakar const ContentEncoding::ContentCompression*
GetCompressionByIndex(unsigned long idx) const4138*103e46e4SHarish Mahendrakar ContentEncoding::GetCompressionByIndex(unsigned long idx) const {
4139*103e46e4SHarish Mahendrakar   const ptrdiff_t count = compression_entries_end_ - compression_entries_;
4140*103e46e4SHarish Mahendrakar   assert(count >= 0);
4141*103e46e4SHarish Mahendrakar 
4142*103e46e4SHarish Mahendrakar   if (idx >= static_cast<unsigned long>(count))
4143*103e46e4SHarish Mahendrakar     return NULL;
4144*103e46e4SHarish Mahendrakar 
4145*103e46e4SHarish Mahendrakar   return compression_entries_[idx];
4146*103e46e4SHarish Mahendrakar }
4147*103e46e4SHarish Mahendrakar 
GetCompressionCount() const4148*103e46e4SHarish Mahendrakar unsigned long ContentEncoding::GetCompressionCount() const {
4149*103e46e4SHarish Mahendrakar   const ptrdiff_t count = compression_entries_end_ - compression_entries_;
4150*103e46e4SHarish Mahendrakar   assert(count >= 0);
4151*103e46e4SHarish Mahendrakar 
4152*103e46e4SHarish Mahendrakar   return static_cast<unsigned long>(count);
4153*103e46e4SHarish Mahendrakar }
4154*103e46e4SHarish Mahendrakar 
GetEncryptionByIndex(unsigned long idx) const4155*103e46e4SHarish Mahendrakar const ContentEncoding::ContentEncryption* ContentEncoding::GetEncryptionByIndex(
4156*103e46e4SHarish Mahendrakar     unsigned long idx) const {
4157*103e46e4SHarish Mahendrakar   const ptrdiff_t count = encryption_entries_end_ - encryption_entries_;
4158*103e46e4SHarish Mahendrakar   assert(count >= 0);
4159*103e46e4SHarish Mahendrakar 
4160*103e46e4SHarish Mahendrakar   if (idx >= static_cast<unsigned long>(count))
4161*103e46e4SHarish Mahendrakar     return NULL;
4162*103e46e4SHarish Mahendrakar 
4163*103e46e4SHarish Mahendrakar   return encryption_entries_[idx];
4164*103e46e4SHarish Mahendrakar }
4165*103e46e4SHarish Mahendrakar 
GetEncryptionCount() const4166*103e46e4SHarish Mahendrakar unsigned long ContentEncoding::GetEncryptionCount() const {
4167*103e46e4SHarish Mahendrakar   const ptrdiff_t count = encryption_entries_end_ - encryption_entries_;
4168*103e46e4SHarish Mahendrakar   assert(count >= 0);
4169*103e46e4SHarish Mahendrakar 
4170*103e46e4SHarish Mahendrakar   return static_cast<unsigned long>(count);
4171*103e46e4SHarish Mahendrakar }
4172*103e46e4SHarish Mahendrakar 
ParseContentEncAESSettingsEntry(long long start,long long size,IMkvReader * pReader,ContentEncAESSettings * aes)4173*103e46e4SHarish Mahendrakar long ContentEncoding::ParseContentEncAESSettingsEntry(
4174*103e46e4SHarish Mahendrakar     long long start, long long size, IMkvReader* pReader,
4175*103e46e4SHarish Mahendrakar     ContentEncAESSettings* aes) {
4176*103e46e4SHarish Mahendrakar   assert(pReader);
4177*103e46e4SHarish Mahendrakar   assert(aes);
4178*103e46e4SHarish Mahendrakar 
4179*103e46e4SHarish Mahendrakar   long long pos = start;
4180*103e46e4SHarish Mahendrakar   const long long stop = start + size;
4181*103e46e4SHarish Mahendrakar 
4182*103e46e4SHarish Mahendrakar   while (pos < stop) {
4183*103e46e4SHarish Mahendrakar     long long id, size;
4184*103e46e4SHarish Mahendrakar     const long status = ParseElementHeader(pReader, pos, stop, id, size);
4185*103e46e4SHarish Mahendrakar     if (status < 0)  // error
4186*103e46e4SHarish Mahendrakar       return status;
4187*103e46e4SHarish Mahendrakar 
4188*103e46e4SHarish Mahendrakar     if (id == libwebm::kMkvAESSettingsCipherMode) {
4189*103e46e4SHarish Mahendrakar       aes->cipher_mode = UnserializeUInt(pReader, pos, size);
4190*103e46e4SHarish Mahendrakar       if (aes->cipher_mode != 1)
4191*103e46e4SHarish Mahendrakar         return E_FILE_FORMAT_INVALID;
4192*103e46e4SHarish Mahendrakar     }
4193*103e46e4SHarish Mahendrakar 
4194*103e46e4SHarish Mahendrakar     pos += size;  // consume payload
4195*103e46e4SHarish Mahendrakar     if (pos > stop)
4196*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
4197*103e46e4SHarish Mahendrakar   }
4198*103e46e4SHarish Mahendrakar 
4199*103e46e4SHarish Mahendrakar   return 0;
4200*103e46e4SHarish Mahendrakar }
4201*103e46e4SHarish Mahendrakar 
ParseContentEncodingEntry(long long start,long long size,IMkvReader * pReader)4202*103e46e4SHarish Mahendrakar long ContentEncoding::ParseContentEncodingEntry(long long start, long long size,
4203*103e46e4SHarish Mahendrakar                                                 IMkvReader* pReader) {
4204*103e46e4SHarish Mahendrakar   assert(pReader);
4205*103e46e4SHarish Mahendrakar 
4206*103e46e4SHarish Mahendrakar   long long pos = start;
4207*103e46e4SHarish Mahendrakar   const long long stop = start + size;
4208*103e46e4SHarish Mahendrakar 
4209*103e46e4SHarish Mahendrakar   // Count ContentCompression and ContentEncryption elements.
4210*103e46e4SHarish Mahendrakar   long long compression_count = 0;
4211*103e46e4SHarish Mahendrakar   long long encryption_count = 0;
4212*103e46e4SHarish Mahendrakar 
4213*103e46e4SHarish Mahendrakar   while (pos < stop) {
4214*103e46e4SHarish Mahendrakar     long long id, size;
4215*103e46e4SHarish Mahendrakar     const long status = ParseElementHeader(pReader, pos, stop, id, size);
4216*103e46e4SHarish Mahendrakar     if (status < 0)  // error
4217*103e46e4SHarish Mahendrakar       return status;
4218*103e46e4SHarish Mahendrakar 
4219*103e46e4SHarish Mahendrakar     if (id == libwebm::kMkvContentCompression) {
4220*103e46e4SHarish Mahendrakar       ++compression_count;
4221*103e46e4SHarish Mahendrakar       if (compression_count > INT_MAX)
4222*103e46e4SHarish Mahendrakar         return E_PARSE_FAILED;
4223*103e46e4SHarish Mahendrakar     }
4224*103e46e4SHarish Mahendrakar 
4225*103e46e4SHarish Mahendrakar     if (id == libwebm::kMkvContentEncryption) {
4226*103e46e4SHarish Mahendrakar       ++encryption_count;
4227*103e46e4SHarish Mahendrakar       if (encryption_count > INT_MAX)
4228*103e46e4SHarish Mahendrakar         return E_PARSE_FAILED;
4229*103e46e4SHarish Mahendrakar     }
4230*103e46e4SHarish Mahendrakar 
4231*103e46e4SHarish Mahendrakar     pos += size;  // consume payload
4232*103e46e4SHarish Mahendrakar     if (pos > stop)
4233*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
4234*103e46e4SHarish Mahendrakar   }
4235*103e46e4SHarish Mahendrakar 
4236*103e46e4SHarish Mahendrakar   if (compression_count <= 0 && encryption_count <= 0)
4237*103e46e4SHarish Mahendrakar     return -1;
4238*103e46e4SHarish Mahendrakar 
4239*103e46e4SHarish Mahendrakar   if (compression_count > 0) {
4240*103e46e4SHarish Mahendrakar     compression_entries_ = new (std::nothrow)
4241*103e46e4SHarish Mahendrakar         ContentCompression*[static_cast<size_t>(compression_count)];
4242*103e46e4SHarish Mahendrakar     if (!compression_entries_)
4243*103e46e4SHarish Mahendrakar       return -1;
4244*103e46e4SHarish Mahendrakar     compression_entries_end_ = compression_entries_;
4245*103e46e4SHarish Mahendrakar   }
4246*103e46e4SHarish Mahendrakar 
4247*103e46e4SHarish Mahendrakar   if (encryption_count > 0) {
4248*103e46e4SHarish Mahendrakar     encryption_entries_ = new (std::nothrow)
4249*103e46e4SHarish Mahendrakar         ContentEncryption*[static_cast<size_t>(encryption_count)];
4250*103e46e4SHarish Mahendrakar     if (!encryption_entries_) {
4251*103e46e4SHarish Mahendrakar       delete[] compression_entries_;
4252*103e46e4SHarish Mahendrakar       compression_entries_ = NULL;
4253*103e46e4SHarish Mahendrakar       return -1;
4254*103e46e4SHarish Mahendrakar     }
4255*103e46e4SHarish Mahendrakar     encryption_entries_end_ = encryption_entries_;
4256*103e46e4SHarish Mahendrakar   }
4257*103e46e4SHarish Mahendrakar 
4258*103e46e4SHarish Mahendrakar   pos = start;
4259*103e46e4SHarish Mahendrakar   while (pos < stop) {
4260*103e46e4SHarish Mahendrakar     long long id, size;
4261*103e46e4SHarish Mahendrakar     long status = ParseElementHeader(pReader, pos, stop, id, size);
4262*103e46e4SHarish Mahendrakar     if (status < 0)  // error
4263*103e46e4SHarish Mahendrakar       return status;
4264*103e46e4SHarish Mahendrakar 
4265*103e46e4SHarish Mahendrakar     if (id == libwebm::kMkvContentEncodingOrder) {
4266*103e46e4SHarish Mahendrakar       encoding_order_ = UnserializeUInt(pReader, pos, size);
4267*103e46e4SHarish Mahendrakar     } else if (id == libwebm::kMkvContentEncodingScope) {
4268*103e46e4SHarish Mahendrakar       encoding_scope_ = UnserializeUInt(pReader, pos, size);
4269*103e46e4SHarish Mahendrakar       if (encoding_scope_ < 1)
4270*103e46e4SHarish Mahendrakar         return -1;
4271*103e46e4SHarish Mahendrakar     } else if (id == libwebm::kMkvContentEncodingType) {
4272*103e46e4SHarish Mahendrakar       encoding_type_ = UnserializeUInt(pReader, pos, size);
4273*103e46e4SHarish Mahendrakar     } else if (id == libwebm::kMkvContentCompression) {
4274*103e46e4SHarish Mahendrakar       ContentCompression* const compression =
4275*103e46e4SHarish Mahendrakar           new (std::nothrow) ContentCompression();
4276*103e46e4SHarish Mahendrakar       if (!compression)
4277*103e46e4SHarish Mahendrakar         return -1;
4278*103e46e4SHarish Mahendrakar 
4279*103e46e4SHarish Mahendrakar       status = ParseCompressionEntry(pos, size, pReader, compression);
4280*103e46e4SHarish Mahendrakar       if (status) {
4281*103e46e4SHarish Mahendrakar         delete compression;
4282*103e46e4SHarish Mahendrakar         return status;
4283*103e46e4SHarish Mahendrakar       }
4284*103e46e4SHarish Mahendrakar       assert(compression_count > 0);
4285*103e46e4SHarish Mahendrakar       *compression_entries_end_++ = compression;
4286*103e46e4SHarish Mahendrakar     } else if (id == libwebm::kMkvContentEncryption) {
4287*103e46e4SHarish Mahendrakar       ContentEncryption* const encryption =
4288*103e46e4SHarish Mahendrakar           new (std::nothrow) ContentEncryption();
4289*103e46e4SHarish Mahendrakar       if (!encryption)
4290*103e46e4SHarish Mahendrakar         return -1;
4291*103e46e4SHarish Mahendrakar 
4292*103e46e4SHarish Mahendrakar       status = ParseEncryptionEntry(pos, size, pReader, encryption);
4293*103e46e4SHarish Mahendrakar       if (status) {
4294*103e46e4SHarish Mahendrakar         delete encryption;
4295*103e46e4SHarish Mahendrakar         return status;
4296*103e46e4SHarish Mahendrakar       }
4297*103e46e4SHarish Mahendrakar       assert(encryption_count > 0);
4298*103e46e4SHarish Mahendrakar       *encryption_entries_end_++ = encryption;
4299*103e46e4SHarish Mahendrakar     }
4300*103e46e4SHarish Mahendrakar 
4301*103e46e4SHarish Mahendrakar     pos += size;  // consume payload
4302*103e46e4SHarish Mahendrakar     if (pos > stop)
4303*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
4304*103e46e4SHarish Mahendrakar   }
4305*103e46e4SHarish Mahendrakar 
4306*103e46e4SHarish Mahendrakar   if (pos != stop)
4307*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
4308*103e46e4SHarish Mahendrakar   return 0;
4309*103e46e4SHarish Mahendrakar }
4310*103e46e4SHarish Mahendrakar 
ParseCompressionEntry(long long start,long long size,IMkvReader * pReader,ContentCompression * compression)4311*103e46e4SHarish Mahendrakar long ContentEncoding::ParseCompressionEntry(long long start, long long size,
4312*103e46e4SHarish Mahendrakar                                             IMkvReader* pReader,
4313*103e46e4SHarish Mahendrakar                                             ContentCompression* compression) {
4314*103e46e4SHarish Mahendrakar   assert(pReader);
4315*103e46e4SHarish Mahendrakar   assert(compression);
4316*103e46e4SHarish Mahendrakar 
4317*103e46e4SHarish Mahendrakar   long long pos = start;
4318*103e46e4SHarish Mahendrakar   const long long stop = start + size;
4319*103e46e4SHarish Mahendrakar 
4320*103e46e4SHarish Mahendrakar   bool valid = false;
4321*103e46e4SHarish Mahendrakar 
4322*103e46e4SHarish Mahendrakar   while (pos < stop) {
4323*103e46e4SHarish Mahendrakar     long long id, size;
4324*103e46e4SHarish Mahendrakar     const long status = ParseElementHeader(pReader, pos, stop, id, size);
4325*103e46e4SHarish Mahendrakar     if (status < 0)  // error
4326*103e46e4SHarish Mahendrakar       return status;
4327*103e46e4SHarish Mahendrakar 
4328*103e46e4SHarish Mahendrakar     if (id == libwebm::kMkvContentCompAlgo) {
4329*103e46e4SHarish Mahendrakar       long long algo = UnserializeUInt(pReader, pos, size);
4330*103e46e4SHarish Mahendrakar       if (algo < 0)
4331*103e46e4SHarish Mahendrakar         return E_FILE_FORMAT_INVALID;
4332*103e46e4SHarish Mahendrakar       compression->algo = algo;
4333*103e46e4SHarish Mahendrakar       valid = true;
4334*103e46e4SHarish Mahendrakar     } else if (id == libwebm::kMkvContentCompSettings) {
4335*103e46e4SHarish Mahendrakar       if (size <= 0)
4336*103e46e4SHarish Mahendrakar         return E_FILE_FORMAT_INVALID;
4337*103e46e4SHarish Mahendrakar 
4338*103e46e4SHarish Mahendrakar       const size_t buflen = static_cast<size_t>(size);
4339*103e46e4SHarish Mahendrakar       unsigned char* buf = SafeArrayAlloc<unsigned char>(1, buflen);
4340*103e46e4SHarish Mahendrakar       if (buf == NULL)
4341*103e46e4SHarish Mahendrakar         return -1;
4342*103e46e4SHarish Mahendrakar 
4343*103e46e4SHarish Mahendrakar       const int read_status =
4344*103e46e4SHarish Mahendrakar           pReader->Read(pos, static_cast<long>(buflen), buf);
4345*103e46e4SHarish Mahendrakar       if (read_status) {
4346*103e46e4SHarish Mahendrakar         delete[] buf;
4347*103e46e4SHarish Mahendrakar         return status;
4348*103e46e4SHarish Mahendrakar       }
4349*103e46e4SHarish Mahendrakar 
4350*103e46e4SHarish Mahendrakar       // There should be only one settings element per content compression.
4351*103e46e4SHarish Mahendrakar       if (compression->settings != NULL) {
4352*103e46e4SHarish Mahendrakar         delete[] buf;
4353*103e46e4SHarish Mahendrakar         return E_FILE_FORMAT_INVALID;
4354*103e46e4SHarish Mahendrakar       }
4355*103e46e4SHarish Mahendrakar 
4356*103e46e4SHarish Mahendrakar       compression->settings = buf;
4357*103e46e4SHarish Mahendrakar       compression->settings_len = buflen;
4358*103e46e4SHarish Mahendrakar     }
4359*103e46e4SHarish Mahendrakar 
4360*103e46e4SHarish Mahendrakar     pos += size;  // consume payload
4361*103e46e4SHarish Mahendrakar     if (pos > stop)
4362*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
4363*103e46e4SHarish Mahendrakar   }
4364*103e46e4SHarish Mahendrakar 
4365*103e46e4SHarish Mahendrakar   // ContentCompAlgo is mandatory
4366*103e46e4SHarish Mahendrakar   if (!valid)
4367*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
4368*103e46e4SHarish Mahendrakar 
4369*103e46e4SHarish Mahendrakar   return 0;
4370*103e46e4SHarish Mahendrakar }
4371*103e46e4SHarish Mahendrakar 
ParseEncryptionEntry(long long start,long long size,IMkvReader * pReader,ContentEncryption * encryption)4372*103e46e4SHarish Mahendrakar long ContentEncoding::ParseEncryptionEntry(long long start, long long size,
4373*103e46e4SHarish Mahendrakar                                            IMkvReader* pReader,
4374*103e46e4SHarish Mahendrakar                                            ContentEncryption* encryption) {
4375*103e46e4SHarish Mahendrakar   assert(pReader);
4376*103e46e4SHarish Mahendrakar   assert(encryption);
4377*103e46e4SHarish Mahendrakar 
4378*103e46e4SHarish Mahendrakar   long long pos = start;
4379*103e46e4SHarish Mahendrakar   const long long stop = start + size;
4380*103e46e4SHarish Mahendrakar 
4381*103e46e4SHarish Mahendrakar   while (pos < stop) {
4382*103e46e4SHarish Mahendrakar     long long id, size;
4383*103e46e4SHarish Mahendrakar     const long status = ParseElementHeader(pReader, pos, stop, id, size);
4384*103e46e4SHarish Mahendrakar     if (status < 0)  // error
4385*103e46e4SHarish Mahendrakar       return status;
4386*103e46e4SHarish Mahendrakar 
4387*103e46e4SHarish Mahendrakar     if (id == libwebm::kMkvContentEncAlgo) {
4388*103e46e4SHarish Mahendrakar       encryption->algo = UnserializeUInt(pReader, pos, size);
4389*103e46e4SHarish Mahendrakar       if (encryption->algo != 5)
4390*103e46e4SHarish Mahendrakar         return E_FILE_FORMAT_INVALID;
4391*103e46e4SHarish Mahendrakar     } else if (id == libwebm::kMkvContentEncKeyID) {
4392*103e46e4SHarish Mahendrakar       delete[] encryption->key_id;
4393*103e46e4SHarish Mahendrakar       encryption->key_id = NULL;
4394*103e46e4SHarish Mahendrakar       encryption->key_id_len = 0;
4395*103e46e4SHarish Mahendrakar 
4396*103e46e4SHarish Mahendrakar       if (size <= 0)
4397*103e46e4SHarish Mahendrakar         return E_FILE_FORMAT_INVALID;
4398*103e46e4SHarish Mahendrakar 
4399*103e46e4SHarish Mahendrakar       const size_t buflen = static_cast<size_t>(size);
4400*103e46e4SHarish Mahendrakar       unsigned char* buf = SafeArrayAlloc<unsigned char>(1, buflen);
4401*103e46e4SHarish Mahendrakar       if (buf == NULL)
4402*103e46e4SHarish Mahendrakar         return -1;
4403*103e46e4SHarish Mahendrakar 
4404*103e46e4SHarish Mahendrakar       const int read_status =
4405*103e46e4SHarish Mahendrakar           pReader->Read(pos, static_cast<long>(buflen), buf);
4406*103e46e4SHarish Mahendrakar       if (read_status) {
4407*103e46e4SHarish Mahendrakar         delete[] buf;
4408*103e46e4SHarish Mahendrakar         return status;
4409*103e46e4SHarish Mahendrakar       }
4410*103e46e4SHarish Mahendrakar 
4411*103e46e4SHarish Mahendrakar       encryption->key_id = buf;
4412*103e46e4SHarish Mahendrakar       encryption->key_id_len = buflen;
4413*103e46e4SHarish Mahendrakar     } else if (id == libwebm::kMkvContentSignature) {
4414*103e46e4SHarish Mahendrakar       delete[] encryption->signature;
4415*103e46e4SHarish Mahendrakar       encryption->signature = NULL;
4416*103e46e4SHarish Mahendrakar       encryption->signature_len = 0;
4417*103e46e4SHarish Mahendrakar 
4418*103e46e4SHarish Mahendrakar       if (size <= 0)
4419*103e46e4SHarish Mahendrakar         return E_FILE_FORMAT_INVALID;
4420*103e46e4SHarish Mahendrakar 
4421*103e46e4SHarish Mahendrakar       const size_t buflen = static_cast<size_t>(size);
4422*103e46e4SHarish Mahendrakar       unsigned char* buf = SafeArrayAlloc<unsigned char>(1, buflen);
4423*103e46e4SHarish Mahendrakar       if (buf == NULL)
4424*103e46e4SHarish Mahendrakar         return -1;
4425*103e46e4SHarish Mahendrakar 
4426*103e46e4SHarish Mahendrakar       const int read_status =
4427*103e46e4SHarish Mahendrakar           pReader->Read(pos, static_cast<long>(buflen), buf);
4428*103e46e4SHarish Mahendrakar       if (read_status) {
4429*103e46e4SHarish Mahendrakar         delete[] buf;
4430*103e46e4SHarish Mahendrakar         return status;
4431*103e46e4SHarish Mahendrakar       }
4432*103e46e4SHarish Mahendrakar 
4433*103e46e4SHarish Mahendrakar       encryption->signature = buf;
4434*103e46e4SHarish Mahendrakar       encryption->signature_len = buflen;
4435*103e46e4SHarish Mahendrakar     } else if (id == libwebm::kMkvContentSigKeyID) {
4436*103e46e4SHarish Mahendrakar       delete[] encryption->sig_key_id;
4437*103e46e4SHarish Mahendrakar       encryption->sig_key_id = NULL;
4438*103e46e4SHarish Mahendrakar       encryption->sig_key_id_len = 0;
4439*103e46e4SHarish Mahendrakar 
4440*103e46e4SHarish Mahendrakar       if (size <= 0)
4441*103e46e4SHarish Mahendrakar         return E_FILE_FORMAT_INVALID;
4442*103e46e4SHarish Mahendrakar 
4443*103e46e4SHarish Mahendrakar       const size_t buflen = static_cast<size_t>(size);
4444*103e46e4SHarish Mahendrakar       unsigned char* buf = SafeArrayAlloc<unsigned char>(1, buflen);
4445*103e46e4SHarish Mahendrakar       if (buf == NULL)
4446*103e46e4SHarish Mahendrakar         return -1;
4447*103e46e4SHarish Mahendrakar 
4448*103e46e4SHarish Mahendrakar       const int read_status =
4449*103e46e4SHarish Mahendrakar           pReader->Read(pos, static_cast<long>(buflen), buf);
4450*103e46e4SHarish Mahendrakar       if (read_status) {
4451*103e46e4SHarish Mahendrakar         delete[] buf;
4452*103e46e4SHarish Mahendrakar         return status;
4453*103e46e4SHarish Mahendrakar       }
4454*103e46e4SHarish Mahendrakar 
4455*103e46e4SHarish Mahendrakar       encryption->sig_key_id = buf;
4456*103e46e4SHarish Mahendrakar       encryption->sig_key_id_len = buflen;
4457*103e46e4SHarish Mahendrakar     } else if (id == libwebm::kMkvContentSigAlgo) {
4458*103e46e4SHarish Mahendrakar       encryption->sig_algo = UnserializeUInt(pReader, pos, size);
4459*103e46e4SHarish Mahendrakar     } else if (id == libwebm::kMkvContentSigHashAlgo) {
4460*103e46e4SHarish Mahendrakar       encryption->sig_hash_algo = UnserializeUInt(pReader, pos, size);
4461*103e46e4SHarish Mahendrakar     } else if (id == libwebm::kMkvContentEncAESSettings) {
4462*103e46e4SHarish Mahendrakar       const long status = ParseContentEncAESSettingsEntry(
4463*103e46e4SHarish Mahendrakar           pos, size, pReader, &encryption->aes_settings);
4464*103e46e4SHarish Mahendrakar       if (status)
4465*103e46e4SHarish Mahendrakar         return status;
4466*103e46e4SHarish Mahendrakar     }
4467*103e46e4SHarish Mahendrakar 
4468*103e46e4SHarish Mahendrakar     pos += size;  // consume payload
4469*103e46e4SHarish Mahendrakar     if (pos > stop)
4470*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
4471*103e46e4SHarish Mahendrakar   }
4472*103e46e4SHarish Mahendrakar 
4473*103e46e4SHarish Mahendrakar   return 0;
4474*103e46e4SHarish Mahendrakar }
4475*103e46e4SHarish Mahendrakar 
Track(Segment * pSegment,long long element_start,long long element_size)4476*103e46e4SHarish Mahendrakar Track::Track(Segment* pSegment, long long element_start, long long element_size)
4477*103e46e4SHarish Mahendrakar     : m_pSegment(pSegment),
4478*103e46e4SHarish Mahendrakar       m_element_start(element_start),
4479*103e46e4SHarish Mahendrakar       m_element_size(element_size),
4480*103e46e4SHarish Mahendrakar       content_encoding_entries_(NULL),
4481*103e46e4SHarish Mahendrakar       content_encoding_entries_end_(NULL) {}
4482*103e46e4SHarish Mahendrakar 
~Track()4483*103e46e4SHarish Mahendrakar Track::~Track() {
4484*103e46e4SHarish Mahendrakar   Info& info = const_cast<Info&>(m_info);
4485*103e46e4SHarish Mahendrakar   info.Clear();
4486*103e46e4SHarish Mahendrakar 
4487*103e46e4SHarish Mahendrakar   ContentEncoding** i = content_encoding_entries_;
4488*103e46e4SHarish Mahendrakar   ContentEncoding** const j = content_encoding_entries_end_;
4489*103e46e4SHarish Mahendrakar 
4490*103e46e4SHarish Mahendrakar   while (i != j) {
4491*103e46e4SHarish Mahendrakar     ContentEncoding* const encoding = *i++;
4492*103e46e4SHarish Mahendrakar     delete encoding;
4493*103e46e4SHarish Mahendrakar   }
4494*103e46e4SHarish Mahendrakar 
4495*103e46e4SHarish Mahendrakar   delete[] content_encoding_entries_;
4496*103e46e4SHarish Mahendrakar }
4497*103e46e4SHarish Mahendrakar 
Create(Segment * pSegment,const Info & info,long long element_start,long long element_size,Track * & pResult)4498*103e46e4SHarish Mahendrakar long Track::Create(Segment* pSegment, const Info& info, long long element_start,
4499*103e46e4SHarish Mahendrakar                    long long element_size, Track*& pResult) {
4500*103e46e4SHarish Mahendrakar   if (pResult)
4501*103e46e4SHarish Mahendrakar     return -1;
4502*103e46e4SHarish Mahendrakar 
4503*103e46e4SHarish Mahendrakar   Track* const pTrack =
4504*103e46e4SHarish Mahendrakar       new (std::nothrow) Track(pSegment, element_start, element_size);
4505*103e46e4SHarish Mahendrakar 
4506*103e46e4SHarish Mahendrakar   if (pTrack == NULL)
4507*103e46e4SHarish Mahendrakar     return -1;  // generic error
4508*103e46e4SHarish Mahendrakar 
4509*103e46e4SHarish Mahendrakar   const int status = info.Copy(pTrack->m_info);
4510*103e46e4SHarish Mahendrakar 
4511*103e46e4SHarish Mahendrakar   if (status) {  // error
4512*103e46e4SHarish Mahendrakar     delete pTrack;
4513*103e46e4SHarish Mahendrakar     return status;
4514*103e46e4SHarish Mahendrakar   }
4515*103e46e4SHarish Mahendrakar 
4516*103e46e4SHarish Mahendrakar   pResult = pTrack;
4517*103e46e4SHarish Mahendrakar   return 0;  // success
4518*103e46e4SHarish Mahendrakar }
4519*103e46e4SHarish Mahendrakar 
Info()4520*103e46e4SHarish Mahendrakar Track::Info::Info()
4521*103e46e4SHarish Mahendrakar     : uid(0),
4522*103e46e4SHarish Mahendrakar       defaultDuration(0),
4523*103e46e4SHarish Mahendrakar       codecDelay(0),
4524*103e46e4SHarish Mahendrakar       seekPreRoll(0),
4525*103e46e4SHarish Mahendrakar       nameAsUTF8(NULL),
4526*103e46e4SHarish Mahendrakar       language(NULL),
4527*103e46e4SHarish Mahendrakar       codecId(NULL),
4528*103e46e4SHarish Mahendrakar       codecNameAsUTF8(NULL),
4529*103e46e4SHarish Mahendrakar       codecPrivate(NULL),
4530*103e46e4SHarish Mahendrakar       codecPrivateSize(0),
4531*103e46e4SHarish Mahendrakar       lacing(false) {}
4532*103e46e4SHarish Mahendrakar 
~Info()4533*103e46e4SHarish Mahendrakar Track::Info::~Info() { Clear(); }
4534*103e46e4SHarish Mahendrakar 
Clear()4535*103e46e4SHarish Mahendrakar void Track::Info::Clear() {
4536*103e46e4SHarish Mahendrakar   delete[] nameAsUTF8;
4537*103e46e4SHarish Mahendrakar   nameAsUTF8 = NULL;
4538*103e46e4SHarish Mahendrakar 
4539*103e46e4SHarish Mahendrakar   delete[] language;
4540*103e46e4SHarish Mahendrakar   language = NULL;
4541*103e46e4SHarish Mahendrakar 
4542*103e46e4SHarish Mahendrakar   delete[] codecId;
4543*103e46e4SHarish Mahendrakar   codecId = NULL;
4544*103e46e4SHarish Mahendrakar 
4545*103e46e4SHarish Mahendrakar   delete[] codecPrivate;
4546*103e46e4SHarish Mahendrakar   codecPrivate = NULL;
4547*103e46e4SHarish Mahendrakar   codecPrivateSize = 0;
4548*103e46e4SHarish Mahendrakar 
4549*103e46e4SHarish Mahendrakar   delete[] codecNameAsUTF8;
4550*103e46e4SHarish Mahendrakar   codecNameAsUTF8 = NULL;
4551*103e46e4SHarish Mahendrakar }
4552*103e46e4SHarish Mahendrakar 
CopyStr(char * Info::* str,Info & dst_) const4553*103e46e4SHarish Mahendrakar int Track::Info::CopyStr(char* Info::*str, Info& dst_) const {
4554*103e46e4SHarish Mahendrakar   if (str == static_cast<char * Info::*>(NULL))
4555*103e46e4SHarish Mahendrakar     return -1;
4556*103e46e4SHarish Mahendrakar 
4557*103e46e4SHarish Mahendrakar   char*& dst = dst_.*str;
4558*103e46e4SHarish Mahendrakar 
4559*103e46e4SHarish Mahendrakar   if (dst)  // should be NULL already
4560*103e46e4SHarish Mahendrakar     return -1;
4561*103e46e4SHarish Mahendrakar 
4562*103e46e4SHarish Mahendrakar   const char* const src = this->*str;
4563*103e46e4SHarish Mahendrakar 
4564*103e46e4SHarish Mahendrakar   if (src == NULL)
4565*103e46e4SHarish Mahendrakar     return 0;
4566*103e46e4SHarish Mahendrakar 
4567*103e46e4SHarish Mahendrakar   const size_t len = strlen(src);
4568*103e46e4SHarish Mahendrakar 
4569*103e46e4SHarish Mahendrakar   dst = SafeArrayAlloc<char>(1, len + 1);
4570*103e46e4SHarish Mahendrakar 
4571*103e46e4SHarish Mahendrakar   if (dst == NULL)
4572*103e46e4SHarish Mahendrakar     return -1;
4573*103e46e4SHarish Mahendrakar 
4574*103e46e4SHarish Mahendrakar   memcpy(dst, src, len);
4575*103e46e4SHarish Mahendrakar   dst[len] = '\0';
4576*103e46e4SHarish Mahendrakar 
4577*103e46e4SHarish Mahendrakar   return 0;
4578*103e46e4SHarish Mahendrakar }
4579*103e46e4SHarish Mahendrakar 
Copy(Info & dst) const4580*103e46e4SHarish Mahendrakar int Track::Info::Copy(Info& dst) const {
4581*103e46e4SHarish Mahendrakar   if (&dst == this)
4582*103e46e4SHarish Mahendrakar     return 0;
4583*103e46e4SHarish Mahendrakar 
4584*103e46e4SHarish Mahendrakar   dst.type = type;
4585*103e46e4SHarish Mahendrakar   dst.number = number;
4586*103e46e4SHarish Mahendrakar   dst.defaultDuration = defaultDuration;
4587*103e46e4SHarish Mahendrakar   dst.codecDelay = codecDelay;
4588*103e46e4SHarish Mahendrakar   dst.seekPreRoll = seekPreRoll;
4589*103e46e4SHarish Mahendrakar   dst.uid = uid;
4590*103e46e4SHarish Mahendrakar   dst.lacing = lacing;
4591*103e46e4SHarish Mahendrakar   dst.settings = settings;
4592*103e46e4SHarish Mahendrakar 
4593*103e46e4SHarish Mahendrakar   // We now copy the string member variables from src to dst.
4594*103e46e4SHarish Mahendrakar   // This involves memory allocation so in principle the operation
4595*103e46e4SHarish Mahendrakar   // can fail (indeed, that's why we have Info::Copy), so we must
4596*103e46e4SHarish Mahendrakar   // report this to the caller.  An error return from this function
4597*103e46e4SHarish Mahendrakar   // therefore implies that the copy was only partially successful.
4598*103e46e4SHarish Mahendrakar 
4599*103e46e4SHarish Mahendrakar   if (int status = CopyStr(&Info::nameAsUTF8, dst))
4600*103e46e4SHarish Mahendrakar     return status;
4601*103e46e4SHarish Mahendrakar 
4602*103e46e4SHarish Mahendrakar   if (int status = CopyStr(&Info::language, dst))
4603*103e46e4SHarish Mahendrakar     return status;
4604*103e46e4SHarish Mahendrakar 
4605*103e46e4SHarish Mahendrakar   if (int status = CopyStr(&Info::codecId, dst))
4606*103e46e4SHarish Mahendrakar     return status;
4607*103e46e4SHarish Mahendrakar 
4608*103e46e4SHarish Mahendrakar   if (int status = CopyStr(&Info::codecNameAsUTF8, dst))
4609*103e46e4SHarish Mahendrakar     return status;
4610*103e46e4SHarish Mahendrakar 
4611*103e46e4SHarish Mahendrakar   if (codecPrivateSize > 0) {
4612*103e46e4SHarish Mahendrakar     if (codecPrivate == NULL)
4613*103e46e4SHarish Mahendrakar       return -1;
4614*103e46e4SHarish Mahendrakar 
4615*103e46e4SHarish Mahendrakar     if (dst.codecPrivate)
4616*103e46e4SHarish Mahendrakar       return -1;
4617*103e46e4SHarish Mahendrakar 
4618*103e46e4SHarish Mahendrakar     if (dst.codecPrivateSize != 0)
4619*103e46e4SHarish Mahendrakar       return -1;
4620*103e46e4SHarish Mahendrakar 
4621*103e46e4SHarish Mahendrakar     dst.codecPrivate = SafeArrayAlloc<unsigned char>(1, codecPrivateSize);
4622*103e46e4SHarish Mahendrakar 
4623*103e46e4SHarish Mahendrakar     if (dst.codecPrivate == NULL)
4624*103e46e4SHarish Mahendrakar       return -1;
4625*103e46e4SHarish Mahendrakar 
4626*103e46e4SHarish Mahendrakar     memcpy(dst.codecPrivate, codecPrivate, codecPrivateSize);
4627*103e46e4SHarish Mahendrakar     dst.codecPrivateSize = codecPrivateSize;
4628*103e46e4SHarish Mahendrakar   }
4629*103e46e4SHarish Mahendrakar 
4630*103e46e4SHarish Mahendrakar   return 0;
4631*103e46e4SHarish Mahendrakar }
4632*103e46e4SHarish Mahendrakar 
GetEOS() const4633*103e46e4SHarish Mahendrakar const BlockEntry* Track::GetEOS() const { return &m_eos; }
4634*103e46e4SHarish Mahendrakar 
GetType() const4635*103e46e4SHarish Mahendrakar long Track::GetType() const { return m_info.type; }
4636*103e46e4SHarish Mahendrakar 
GetNumber() const4637*103e46e4SHarish Mahendrakar long Track::GetNumber() const { return m_info.number; }
4638*103e46e4SHarish Mahendrakar 
GetUid() const4639*103e46e4SHarish Mahendrakar unsigned long long Track::GetUid() const { return m_info.uid; }
4640*103e46e4SHarish Mahendrakar 
GetNameAsUTF8() const4641*103e46e4SHarish Mahendrakar const char* Track::GetNameAsUTF8() const { return m_info.nameAsUTF8; }
4642*103e46e4SHarish Mahendrakar 
GetLanguage() const4643*103e46e4SHarish Mahendrakar const char* Track::GetLanguage() const { return m_info.language; }
4644*103e46e4SHarish Mahendrakar 
GetCodecNameAsUTF8() const4645*103e46e4SHarish Mahendrakar const char* Track::GetCodecNameAsUTF8() const { return m_info.codecNameAsUTF8; }
4646*103e46e4SHarish Mahendrakar 
GetCodecId() const4647*103e46e4SHarish Mahendrakar const char* Track::GetCodecId() const { return m_info.codecId; }
4648*103e46e4SHarish Mahendrakar 
GetCodecPrivate(size_t & size) const4649*103e46e4SHarish Mahendrakar const unsigned char* Track::GetCodecPrivate(size_t& size) const {
4650*103e46e4SHarish Mahendrakar   size = m_info.codecPrivateSize;
4651*103e46e4SHarish Mahendrakar   return m_info.codecPrivate;
4652*103e46e4SHarish Mahendrakar }
4653*103e46e4SHarish Mahendrakar 
GetLacing() const4654*103e46e4SHarish Mahendrakar bool Track::GetLacing() const { return m_info.lacing; }
4655*103e46e4SHarish Mahendrakar 
GetDefaultDuration() const4656*103e46e4SHarish Mahendrakar unsigned long long Track::GetDefaultDuration() const {
4657*103e46e4SHarish Mahendrakar   return m_info.defaultDuration;
4658*103e46e4SHarish Mahendrakar }
4659*103e46e4SHarish Mahendrakar 
GetCodecDelay() const4660*103e46e4SHarish Mahendrakar unsigned long long Track::GetCodecDelay() const { return m_info.codecDelay; }
4661*103e46e4SHarish Mahendrakar 
GetSeekPreRoll() const4662*103e46e4SHarish Mahendrakar unsigned long long Track::GetSeekPreRoll() const { return m_info.seekPreRoll; }
4663*103e46e4SHarish Mahendrakar 
GetFirst(const BlockEntry * & pBlockEntry) const4664*103e46e4SHarish Mahendrakar long Track::GetFirst(const BlockEntry*& pBlockEntry) const {
4665*103e46e4SHarish Mahendrakar   const Cluster* pCluster = m_pSegment->GetFirst();
4666*103e46e4SHarish Mahendrakar 
4667*103e46e4SHarish Mahendrakar   for (int i = 0;;) {
4668*103e46e4SHarish Mahendrakar     if (pCluster == NULL) {
4669*103e46e4SHarish Mahendrakar       pBlockEntry = GetEOS();
4670*103e46e4SHarish Mahendrakar       return 1;
4671*103e46e4SHarish Mahendrakar     }
4672*103e46e4SHarish Mahendrakar 
4673*103e46e4SHarish Mahendrakar     if (pCluster->EOS()) {
4674*103e46e4SHarish Mahendrakar       if (m_pSegment->DoneParsing()) {
4675*103e46e4SHarish Mahendrakar         pBlockEntry = GetEOS();
4676*103e46e4SHarish Mahendrakar         return 1;
4677*103e46e4SHarish Mahendrakar       }
4678*103e46e4SHarish Mahendrakar 
4679*103e46e4SHarish Mahendrakar       pBlockEntry = 0;
4680*103e46e4SHarish Mahendrakar       return E_BUFFER_NOT_FULL;
4681*103e46e4SHarish Mahendrakar     }
4682*103e46e4SHarish Mahendrakar 
4683*103e46e4SHarish Mahendrakar     long status = pCluster->GetFirst(pBlockEntry);
4684*103e46e4SHarish Mahendrakar 
4685*103e46e4SHarish Mahendrakar     if (status < 0)  // error
4686*103e46e4SHarish Mahendrakar       return status;
4687*103e46e4SHarish Mahendrakar 
4688*103e46e4SHarish Mahendrakar     if (pBlockEntry == 0) {  // empty cluster
4689*103e46e4SHarish Mahendrakar       pCluster = m_pSegment->GetNext(pCluster);
4690*103e46e4SHarish Mahendrakar       continue;
4691*103e46e4SHarish Mahendrakar     }
4692*103e46e4SHarish Mahendrakar 
4693*103e46e4SHarish Mahendrakar     for (;;) {
4694*103e46e4SHarish Mahendrakar       const Block* const pBlock = pBlockEntry->GetBlock();
4695*103e46e4SHarish Mahendrakar       assert(pBlock);
4696*103e46e4SHarish Mahendrakar 
4697*103e46e4SHarish Mahendrakar       const long long tn = pBlock->GetTrackNumber();
4698*103e46e4SHarish Mahendrakar 
4699*103e46e4SHarish Mahendrakar       if ((tn == m_info.number) && VetEntry(pBlockEntry))
4700*103e46e4SHarish Mahendrakar         return 0;
4701*103e46e4SHarish Mahendrakar 
4702*103e46e4SHarish Mahendrakar       const BlockEntry* pNextEntry;
4703*103e46e4SHarish Mahendrakar 
4704*103e46e4SHarish Mahendrakar       status = pCluster->GetNext(pBlockEntry, pNextEntry);
4705*103e46e4SHarish Mahendrakar 
4706*103e46e4SHarish Mahendrakar       if (status < 0)  // error
4707*103e46e4SHarish Mahendrakar         return status;
4708*103e46e4SHarish Mahendrakar 
4709*103e46e4SHarish Mahendrakar       if (pNextEntry == 0)
4710*103e46e4SHarish Mahendrakar         break;
4711*103e46e4SHarish Mahendrakar 
4712*103e46e4SHarish Mahendrakar       pBlockEntry = pNextEntry;
4713*103e46e4SHarish Mahendrakar     }
4714*103e46e4SHarish Mahendrakar 
4715*103e46e4SHarish Mahendrakar     ++i;
4716*103e46e4SHarish Mahendrakar 
4717*103e46e4SHarish Mahendrakar     if (i >= 100)
4718*103e46e4SHarish Mahendrakar       break;
4719*103e46e4SHarish Mahendrakar 
4720*103e46e4SHarish Mahendrakar     pCluster = m_pSegment->GetNext(pCluster);
4721*103e46e4SHarish Mahendrakar   }
4722*103e46e4SHarish Mahendrakar 
4723*103e46e4SHarish Mahendrakar   // NOTE: if we get here, it means that we didn't find a block with
4724*103e46e4SHarish Mahendrakar   // a matching track number.  We interpret that as an error (which
4725*103e46e4SHarish Mahendrakar   // might be too conservative).
4726*103e46e4SHarish Mahendrakar 
4727*103e46e4SHarish Mahendrakar   pBlockEntry = GetEOS();  // so we can return a non-NULL value
4728*103e46e4SHarish Mahendrakar   return 1;
4729*103e46e4SHarish Mahendrakar }
4730*103e46e4SHarish Mahendrakar 
GetNext(const BlockEntry * pCurrEntry,const BlockEntry * & pNextEntry) const4731*103e46e4SHarish Mahendrakar long Track::GetNext(const BlockEntry* pCurrEntry,
4732*103e46e4SHarish Mahendrakar                     const BlockEntry*& pNextEntry) const {
4733*103e46e4SHarish Mahendrakar   assert(pCurrEntry);
4734*103e46e4SHarish Mahendrakar   assert(!pCurrEntry->EOS());  //?
4735*103e46e4SHarish Mahendrakar 
4736*103e46e4SHarish Mahendrakar   const Block* const pCurrBlock = pCurrEntry->GetBlock();
4737*103e46e4SHarish Mahendrakar   assert(pCurrBlock && pCurrBlock->GetTrackNumber() == m_info.number);
4738*103e46e4SHarish Mahendrakar   if (!pCurrBlock || pCurrBlock->GetTrackNumber() != m_info.number)
4739*103e46e4SHarish Mahendrakar     return -1;
4740*103e46e4SHarish Mahendrakar 
4741*103e46e4SHarish Mahendrakar   const Cluster* pCluster = pCurrEntry->GetCluster();
4742*103e46e4SHarish Mahendrakar   assert(pCluster);
4743*103e46e4SHarish Mahendrakar   assert(!pCluster->EOS());
4744*103e46e4SHarish Mahendrakar 
4745*103e46e4SHarish Mahendrakar   long status = pCluster->GetNext(pCurrEntry, pNextEntry);
4746*103e46e4SHarish Mahendrakar 
4747*103e46e4SHarish Mahendrakar   if (status < 0)  // error
4748*103e46e4SHarish Mahendrakar     return status;
4749*103e46e4SHarish Mahendrakar 
4750*103e46e4SHarish Mahendrakar   for (int i = 0;;) {
4751*103e46e4SHarish Mahendrakar     while (pNextEntry) {
4752*103e46e4SHarish Mahendrakar       const Block* const pNextBlock = pNextEntry->GetBlock();
4753*103e46e4SHarish Mahendrakar       assert(pNextBlock);
4754*103e46e4SHarish Mahendrakar 
4755*103e46e4SHarish Mahendrakar       if (pNextBlock->GetTrackNumber() == m_info.number)
4756*103e46e4SHarish Mahendrakar         return 0;
4757*103e46e4SHarish Mahendrakar 
4758*103e46e4SHarish Mahendrakar       pCurrEntry = pNextEntry;
4759*103e46e4SHarish Mahendrakar 
4760*103e46e4SHarish Mahendrakar       status = pCluster->GetNext(pCurrEntry, pNextEntry);
4761*103e46e4SHarish Mahendrakar 
4762*103e46e4SHarish Mahendrakar       if (status < 0)  // error
4763*103e46e4SHarish Mahendrakar         return status;
4764*103e46e4SHarish Mahendrakar     }
4765*103e46e4SHarish Mahendrakar 
4766*103e46e4SHarish Mahendrakar     pCluster = m_pSegment->GetNext(pCluster);
4767*103e46e4SHarish Mahendrakar 
4768*103e46e4SHarish Mahendrakar     if (pCluster == NULL) {
4769*103e46e4SHarish Mahendrakar       pNextEntry = GetEOS();
4770*103e46e4SHarish Mahendrakar       return 1;
4771*103e46e4SHarish Mahendrakar     }
4772*103e46e4SHarish Mahendrakar 
4773*103e46e4SHarish Mahendrakar     if (pCluster->EOS()) {
4774*103e46e4SHarish Mahendrakar       if (m_pSegment->DoneParsing()) {
4775*103e46e4SHarish Mahendrakar         pNextEntry = GetEOS();
4776*103e46e4SHarish Mahendrakar         return 1;
4777*103e46e4SHarish Mahendrakar       }
4778*103e46e4SHarish Mahendrakar 
4779*103e46e4SHarish Mahendrakar       // TODO: there is a potential O(n^2) problem here: we tell the
4780*103e46e4SHarish Mahendrakar       // caller to (pre)load another cluster, which he does, but then he
4781*103e46e4SHarish Mahendrakar       // calls GetNext again, which repeats the same search.  This is
4782*103e46e4SHarish Mahendrakar       // a pathological case, since the only way it can happen is if
4783*103e46e4SHarish Mahendrakar       // there exists a long sequence of clusters none of which contain a
4784*103e46e4SHarish Mahendrakar       // block from this track.  One way around this problem is for the
4785*103e46e4SHarish Mahendrakar       // caller to be smarter when he loads another cluster: don't call
4786*103e46e4SHarish Mahendrakar       // us back until you have a cluster that contains a block from this
4787*103e46e4SHarish Mahendrakar       // track. (Of course, that's not cheap either, since our caller
4788*103e46e4SHarish Mahendrakar       // would have to scan the each cluster as it's loaded, so that
4789*103e46e4SHarish Mahendrakar       // would just push back the problem.)
4790*103e46e4SHarish Mahendrakar 
4791*103e46e4SHarish Mahendrakar       pNextEntry = NULL;
4792*103e46e4SHarish Mahendrakar       return E_BUFFER_NOT_FULL;
4793*103e46e4SHarish Mahendrakar     }
4794*103e46e4SHarish Mahendrakar 
4795*103e46e4SHarish Mahendrakar     status = pCluster->GetFirst(pNextEntry);
4796*103e46e4SHarish Mahendrakar 
4797*103e46e4SHarish Mahendrakar     if (status < 0)  // error
4798*103e46e4SHarish Mahendrakar       return status;
4799*103e46e4SHarish Mahendrakar 
4800*103e46e4SHarish Mahendrakar     if (pNextEntry == NULL)  // empty cluster
4801*103e46e4SHarish Mahendrakar       continue;
4802*103e46e4SHarish Mahendrakar 
4803*103e46e4SHarish Mahendrakar     ++i;
4804*103e46e4SHarish Mahendrakar 
4805*103e46e4SHarish Mahendrakar     if (i >= 100)
4806*103e46e4SHarish Mahendrakar       break;
4807*103e46e4SHarish Mahendrakar   }
4808*103e46e4SHarish Mahendrakar 
4809*103e46e4SHarish Mahendrakar   // NOTE: if we get here, it means that we didn't find a block with
4810*103e46e4SHarish Mahendrakar   // a matching track number after lots of searching, so we give
4811*103e46e4SHarish Mahendrakar   // up trying.
4812*103e46e4SHarish Mahendrakar 
4813*103e46e4SHarish Mahendrakar   pNextEntry = GetEOS();  // so we can return a non-NULL value
4814*103e46e4SHarish Mahendrakar   return 1;
4815*103e46e4SHarish Mahendrakar }
4816*103e46e4SHarish Mahendrakar 
VetEntry(const BlockEntry * pBlockEntry) const4817*103e46e4SHarish Mahendrakar bool Track::VetEntry(const BlockEntry* pBlockEntry) const {
4818*103e46e4SHarish Mahendrakar   assert(pBlockEntry);
4819*103e46e4SHarish Mahendrakar   const Block* const pBlock = pBlockEntry->GetBlock();
4820*103e46e4SHarish Mahendrakar   assert(pBlock);
4821*103e46e4SHarish Mahendrakar   assert(pBlock->GetTrackNumber() == m_info.number);
4822*103e46e4SHarish Mahendrakar   if (!pBlock || pBlock->GetTrackNumber() != m_info.number)
4823*103e46e4SHarish Mahendrakar     return false;
4824*103e46e4SHarish Mahendrakar 
4825*103e46e4SHarish Mahendrakar   // This function is used during a seek to determine whether the
4826*103e46e4SHarish Mahendrakar   // frame is a valid seek target.  This default function simply
4827*103e46e4SHarish Mahendrakar   // returns true, which means all frames are valid seek targets.
4828*103e46e4SHarish Mahendrakar   // It gets overridden by the VideoTrack class, because only video
4829*103e46e4SHarish Mahendrakar   // keyframes can be used as seek target.
4830*103e46e4SHarish Mahendrakar 
4831*103e46e4SHarish Mahendrakar   return true;
4832*103e46e4SHarish Mahendrakar }
4833*103e46e4SHarish Mahendrakar 
Seek(long long time_ns,const BlockEntry * & pResult) const4834*103e46e4SHarish Mahendrakar long Track::Seek(long long time_ns, const BlockEntry*& pResult) const {
4835*103e46e4SHarish Mahendrakar   const long status = GetFirst(pResult);
4836*103e46e4SHarish Mahendrakar 
4837*103e46e4SHarish Mahendrakar   if (status < 0)  // buffer underflow, etc
4838*103e46e4SHarish Mahendrakar     return status;
4839*103e46e4SHarish Mahendrakar 
4840*103e46e4SHarish Mahendrakar   assert(pResult);
4841*103e46e4SHarish Mahendrakar 
4842*103e46e4SHarish Mahendrakar   if (pResult->EOS())
4843*103e46e4SHarish Mahendrakar     return 0;
4844*103e46e4SHarish Mahendrakar 
4845*103e46e4SHarish Mahendrakar   const Cluster* pCluster = pResult->GetCluster();
4846*103e46e4SHarish Mahendrakar   assert(pCluster);
4847*103e46e4SHarish Mahendrakar   assert(pCluster->GetIndex() >= 0);
4848*103e46e4SHarish Mahendrakar 
4849*103e46e4SHarish Mahendrakar   if (time_ns <= pResult->GetBlock()->GetTime(pCluster))
4850*103e46e4SHarish Mahendrakar     return 0;
4851*103e46e4SHarish Mahendrakar 
4852*103e46e4SHarish Mahendrakar   Cluster** const clusters = m_pSegment->m_clusters;
4853*103e46e4SHarish Mahendrakar   assert(clusters);
4854*103e46e4SHarish Mahendrakar 
4855*103e46e4SHarish Mahendrakar   const long count = m_pSegment->GetCount();  // loaded only, not preloaded
4856*103e46e4SHarish Mahendrakar   assert(count > 0);
4857*103e46e4SHarish Mahendrakar 
4858*103e46e4SHarish Mahendrakar   Cluster** const i = clusters + pCluster->GetIndex();
4859*103e46e4SHarish Mahendrakar   assert(i);
4860*103e46e4SHarish Mahendrakar   assert(*i == pCluster);
4861*103e46e4SHarish Mahendrakar   assert(pCluster->GetTime() <= time_ns);
4862*103e46e4SHarish Mahendrakar 
4863*103e46e4SHarish Mahendrakar   Cluster** const j = clusters + count;
4864*103e46e4SHarish Mahendrakar 
4865*103e46e4SHarish Mahendrakar   Cluster** lo = i;
4866*103e46e4SHarish Mahendrakar   Cluster** hi = j;
4867*103e46e4SHarish Mahendrakar 
4868*103e46e4SHarish Mahendrakar   while (lo < hi) {
4869*103e46e4SHarish Mahendrakar     // INVARIANT:
4870*103e46e4SHarish Mahendrakar     //[i, lo) <= time_ns
4871*103e46e4SHarish Mahendrakar     //[lo, hi) ?
4872*103e46e4SHarish Mahendrakar     //[hi, j)  > time_ns
4873*103e46e4SHarish Mahendrakar 
4874*103e46e4SHarish Mahendrakar     Cluster** const mid = lo + (hi - lo) / 2;
4875*103e46e4SHarish Mahendrakar     assert(mid < hi);
4876*103e46e4SHarish Mahendrakar 
4877*103e46e4SHarish Mahendrakar     pCluster = *mid;
4878*103e46e4SHarish Mahendrakar     assert(pCluster);
4879*103e46e4SHarish Mahendrakar     assert(pCluster->GetIndex() >= 0);
4880*103e46e4SHarish Mahendrakar     assert(pCluster->GetIndex() == long(mid - m_pSegment->m_clusters));
4881*103e46e4SHarish Mahendrakar 
4882*103e46e4SHarish Mahendrakar     const long long t = pCluster->GetTime();
4883*103e46e4SHarish Mahendrakar 
4884*103e46e4SHarish Mahendrakar     if (t <= time_ns)
4885*103e46e4SHarish Mahendrakar       lo = mid + 1;
4886*103e46e4SHarish Mahendrakar     else
4887*103e46e4SHarish Mahendrakar       hi = mid;
4888*103e46e4SHarish Mahendrakar 
4889*103e46e4SHarish Mahendrakar     assert(lo <= hi);
4890*103e46e4SHarish Mahendrakar   }
4891*103e46e4SHarish Mahendrakar 
4892*103e46e4SHarish Mahendrakar   assert(lo == hi);
4893*103e46e4SHarish Mahendrakar   assert(lo > i);
4894*103e46e4SHarish Mahendrakar   assert(lo <= j);
4895*103e46e4SHarish Mahendrakar 
4896*103e46e4SHarish Mahendrakar   while (lo > i) {
4897*103e46e4SHarish Mahendrakar     pCluster = *--lo;
4898*103e46e4SHarish Mahendrakar     assert(pCluster);
4899*103e46e4SHarish Mahendrakar     assert(pCluster->GetTime() <= time_ns);
4900*103e46e4SHarish Mahendrakar 
4901*103e46e4SHarish Mahendrakar     pResult = pCluster->GetEntry(this);
4902*103e46e4SHarish Mahendrakar 
4903*103e46e4SHarish Mahendrakar     if ((pResult != 0) && !pResult->EOS())
4904*103e46e4SHarish Mahendrakar       return 0;
4905*103e46e4SHarish Mahendrakar 
4906*103e46e4SHarish Mahendrakar     // landed on empty cluster (no entries)
4907*103e46e4SHarish Mahendrakar   }
4908*103e46e4SHarish Mahendrakar 
4909*103e46e4SHarish Mahendrakar   pResult = GetEOS();  // weird
4910*103e46e4SHarish Mahendrakar   return 0;
4911*103e46e4SHarish Mahendrakar }
4912*103e46e4SHarish Mahendrakar 
GetContentEncodingByIndex(unsigned long idx) const4913*103e46e4SHarish Mahendrakar const ContentEncoding* Track::GetContentEncodingByIndex(
4914*103e46e4SHarish Mahendrakar     unsigned long idx) const {
4915*103e46e4SHarish Mahendrakar   const ptrdiff_t count =
4916*103e46e4SHarish Mahendrakar       content_encoding_entries_end_ - content_encoding_entries_;
4917*103e46e4SHarish Mahendrakar   assert(count >= 0);
4918*103e46e4SHarish Mahendrakar 
4919*103e46e4SHarish Mahendrakar   if (idx >= static_cast<unsigned long>(count))
4920*103e46e4SHarish Mahendrakar     return NULL;
4921*103e46e4SHarish Mahendrakar 
4922*103e46e4SHarish Mahendrakar   return content_encoding_entries_[idx];
4923*103e46e4SHarish Mahendrakar }
4924*103e46e4SHarish Mahendrakar 
GetContentEncodingCount() const4925*103e46e4SHarish Mahendrakar unsigned long Track::GetContentEncodingCount() const {
4926*103e46e4SHarish Mahendrakar   const ptrdiff_t count =
4927*103e46e4SHarish Mahendrakar       content_encoding_entries_end_ - content_encoding_entries_;
4928*103e46e4SHarish Mahendrakar   assert(count >= 0);
4929*103e46e4SHarish Mahendrakar 
4930*103e46e4SHarish Mahendrakar   return static_cast<unsigned long>(count);
4931*103e46e4SHarish Mahendrakar }
4932*103e46e4SHarish Mahendrakar 
ParseContentEncodingsEntry(long long start,long long size)4933*103e46e4SHarish Mahendrakar long Track::ParseContentEncodingsEntry(long long start, long long size) {
4934*103e46e4SHarish Mahendrakar   IMkvReader* const pReader = m_pSegment->m_pReader;
4935*103e46e4SHarish Mahendrakar   assert(pReader);
4936*103e46e4SHarish Mahendrakar 
4937*103e46e4SHarish Mahendrakar   long long pos = start;
4938*103e46e4SHarish Mahendrakar   const long long stop = start + size;
4939*103e46e4SHarish Mahendrakar 
4940*103e46e4SHarish Mahendrakar   // Count ContentEncoding elements.
4941*103e46e4SHarish Mahendrakar   long long count = 0;
4942*103e46e4SHarish Mahendrakar   while (pos < stop) {
4943*103e46e4SHarish Mahendrakar     long long id, size;
4944*103e46e4SHarish Mahendrakar     const long status = ParseElementHeader(pReader, pos, stop, id, size);
4945*103e46e4SHarish Mahendrakar     if (status < 0)  // error
4946*103e46e4SHarish Mahendrakar       return status;
4947*103e46e4SHarish Mahendrakar 
4948*103e46e4SHarish Mahendrakar     // pos now designates start of element
4949*103e46e4SHarish Mahendrakar     if (id == libwebm::kMkvContentEncoding) {
4950*103e46e4SHarish Mahendrakar       ++count;
4951*103e46e4SHarish Mahendrakar       if (count > INT_MAX)
4952*103e46e4SHarish Mahendrakar         return E_PARSE_FAILED;
4953*103e46e4SHarish Mahendrakar     }
4954*103e46e4SHarish Mahendrakar 
4955*103e46e4SHarish Mahendrakar     pos += size;  // consume payload
4956*103e46e4SHarish Mahendrakar     if (pos > stop)
4957*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
4958*103e46e4SHarish Mahendrakar   }
4959*103e46e4SHarish Mahendrakar 
4960*103e46e4SHarish Mahendrakar   if (count <= 0)
4961*103e46e4SHarish Mahendrakar     return -1;
4962*103e46e4SHarish Mahendrakar 
4963*103e46e4SHarish Mahendrakar   content_encoding_entries_ =
4964*103e46e4SHarish Mahendrakar       new (std::nothrow) ContentEncoding*[static_cast<size_t>(count)];
4965*103e46e4SHarish Mahendrakar   if (!content_encoding_entries_)
4966*103e46e4SHarish Mahendrakar     return -1;
4967*103e46e4SHarish Mahendrakar 
4968*103e46e4SHarish Mahendrakar   content_encoding_entries_end_ = content_encoding_entries_;
4969*103e46e4SHarish Mahendrakar 
4970*103e46e4SHarish Mahendrakar   pos = start;
4971*103e46e4SHarish Mahendrakar   while (pos < stop) {
4972*103e46e4SHarish Mahendrakar     long long id, size;
4973*103e46e4SHarish Mahendrakar     long status = ParseElementHeader(pReader, pos, stop, id, size);
4974*103e46e4SHarish Mahendrakar     if (status < 0)  // error
4975*103e46e4SHarish Mahendrakar       return status;
4976*103e46e4SHarish Mahendrakar 
4977*103e46e4SHarish Mahendrakar     // pos now designates start of element
4978*103e46e4SHarish Mahendrakar     if (id == libwebm::kMkvContentEncoding) {
4979*103e46e4SHarish Mahendrakar       ContentEncoding* const content_encoding =
4980*103e46e4SHarish Mahendrakar           new (std::nothrow) ContentEncoding();
4981*103e46e4SHarish Mahendrakar       if (!content_encoding)
4982*103e46e4SHarish Mahendrakar         return -1;
4983*103e46e4SHarish Mahendrakar 
4984*103e46e4SHarish Mahendrakar       status = content_encoding->ParseContentEncodingEntry(pos, size, pReader);
4985*103e46e4SHarish Mahendrakar       if (status) {
4986*103e46e4SHarish Mahendrakar         delete content_encoding;
4987*103e46e4SHarish Mahendrakar         return status;
4988*103e46e4SHarish Mahendrakar       }
4989*103e46e4SHarish Mahendrakar 
4990*103e46e4SHarish Mahendrakar       *content_encoding_entries_end_++ = content_encoding;
4991*103e46e4SHarish Mahendrakar     }
4992*103e46e4SHarish Mahendrakar 
4993*103e46e4SHarish Mahendrakar     pos += size;  // consume payload
4994*103e46e4SHarish Mahendrakar     if (pos > stop)
4995*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
4996*103e46e4SHarish Mahendrakar   }
4997*103e46e4SHarish Mahendrakar 
4998*103e46e4SHarish Mahendrakar   if (pos != stop)
4999*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
5000*103e46e4SHarish Mahendrakar 
5001*103e46e4SHarish Mahendrakar   return 0;
5002*103e46e4SHarish Mahendrakar }
5003*103e46e4SHarish Mahendrakar 
EOSBlock()5004*103e46e4SHarish Mahendrakar Track::EOSBlock::EOSBlock() : BlockEntry(NULL, LONG_MIN) {}
5005*103e46e4SHarish Mahendrakar 
GetKind() const5006*103e46e4SHarish Mahendrakar BlockEntry::Kind Track::EOSBlock::GetKind() const { return kBlockEOS; }
5007*103e46e4SHarish Mahendrakar 
GetBlock() const5008*103e46e4SHarish Mahendrakar const Block* Track::EOSBlock::GetBlock() const { return NULL; }
5009*103e46e4SHarish Mahendrakar 
Parse(IMkvReader * reader,long long read_pos,long long value_size,bool is_x,PrimaryChromaticity ** chromaticity)5010*103e46e4SHarish Mahendrakar bool PrimaryChromaticity::Parse(IMkvReader* reader, long long read_pos,
5011*103e46e4SHarish Mahendrakar                                 long long value_size, bool is_x,
5012*103e46e4SHarish Mahendrakar                                 PrimaryChromaticity** chromaticity) {
5013*103e46e4SHarish Mahendrakar   if (!reader)
5014*103e46e4SHarish Mahendrakar     return false;
5015*103e46e4SHarish Mahendrakar 
5016*103e46e4SHarish Mahendrakar   if (!*chromaticity)
5017*103e46e4SHarish Mahendrakar     *chromaticity = new PrimaryChromaticity();
5018*103e46e4SHarish Mahendrakar 
5019*103e46e4SHarish Mahendrakar   if (!*chromaticity)
5020*103e46e4SHarish Mahendrakar     return false;
5021*103e46e4SHarish Mahendrakar 
5022*103e46e4SHarish Mahendrakar   PrimaryChromaticity* pc = *chromaticity;
5023*103e46e4SHarish Mahendrakar   float* value = is_x ? &pc->x : &pc->y;
5024*103e46e4SHarish Mahendrakar 
5025*103e46e4SHarish Mahendrakar   double parser_value = 0;
5026*103e46e4SHarish Mahendrakar   const long long parse_status =
5027*103e46e4SHarish Mahendrakar       UnserializeFloat(reader, read_pos, value_size, parser_value);
5028*103e46e4SHarish Mahendrakar 
5029*103e46e4SHarish Mahendrakar   // Valid range is [0, 1]. Make sure the double is representable as a float
5030*103e46e4SHarish Mahendrakar   // before casting.
5031*103e46e4SHarish Mahendrakar   if (parse_status < 0 || parser_value < 0.0 || parser_value > 1.0 ||
5032*103e46e4SHarish Mahendrakar       (parser_value > 0.0 && parser_value < FLT_MIN))
5033*103e46e4SHarish Mahendrakar     return false;
5034*103e46e4SHarish Mahendrakar 
5035*103e46e4SHarish Mahendrakar   *value = static_cast<float>(parser_value);
5036*103e46e4SHarish Mahendrakar 
5037*103e46e4SHarish Mahendrakar   return true;
5038*103e46e4SHarish Mahendrakar }
5039*103e46e4SHarish Mahendrakar 
Parse(IMkvReader * reader,long long mm_start,long long mm_size,MasteringMetadata ** mm)5040*103e46e4SHarish Mahendrakar bool MasteringMetadata::Parse(IMkvReader* reader, long long mm_start,
5041*103e46e4SHarish Mahendrakar                               long long mm_size, MasteringMetadata** mm) {
5042*103e46e4SHarish Mahendrakar   if (!reader || *mm)
5043*103e46e4SHarish Mahendrakar     return false;
5044*103e46e4SHarish Mahendrakar 
5045*103e46e4SHarish Mahendrakar   std::unique_ptr<MasteringMetadata> mm_ptr(new MasteringMetadata());
5046*103e46e4SHarish Mahendrakar   if (!mm_ptr.get())
5047*103e46e4SHarish Mahendrakar     return false;
5048*103e46e4SHarish Mahendrakar 
5049*103e46e4SHarish Mahendrakar   const long long mm_end = mm_start + mm_size;
5050*103e46e4SHarish Mahendrakar   long long read_pos = mm_start;
5051*103e46e4SHarish Mahendrakar 
5052*103e46e4SHarish Mahendrakar   while (read_pos < mm_end) {
5053*103e46e4SHarish Mahendrakar     long long child_id = 0;
5054*103e46e4SHarish Mahendrakar     long long child_size = 0;
5055*103e46e4SHarish Mahendrakar 
5056*103e46e4SHarish Mahendrakar     const long long status =
5057*103e46e4SHarish Mahendrakar         ParseElementHeader(reader, read_pos, mm_end, child_id, child_size);
5058*103e46e4SHarish Mahendrakar     if (status < 0)
5059*103e46e4SHarish Mahendrakar       return false;
5060*103e46e4SHarish Mahendrakar 
5061*103e46e4SHarish Mahendrakar     if (child_id == libwebm::kMkvLuminanceMax) {
5062*103e46e4SHarish Mahendrakar       double value = 0;
5063*103e46e4SHarish Mahendrakar       const long long value_parse_status =
5064*103e46e4SHarish Mahendrakar           UnserializeFloat(reader, read_pos, child_size, value);
5065*103e46e4SHarish Mahendrakar       if (value < -FLT_MAX || value > FLT_MAX ||
5066*103e46e4SHarish Mahendrakar           (value > 0.0 && value < FLT_MIN)) {
5067*103e46e4SHarish Mahendrakar         return false;
5068*103e46e4SHarish Mahendrakar       }
5069*103e46e4SHarish Mahendrakar       mm_ptr->luminance_max = static_cast<float>(value);
5070*103e46e4SHarish Mahendrakar       if (value_parse_status < 0 || mm_ptr->luminance_max < 0.0 ||
5071*103e46e4SHarish Mahendrakar           mm_ptr->luminance_max > 9999.99) {
5072*103e46e4SHarish Mahendrakar         return false;
5073*103e46e4SHarish Mahendrakar       }
5074*103e46e4SHarish Mahendrakar     } else if (child_id == libwebm::kMkvLuminanceMin) {
5075*103e46e4SHarish Mahendrakar       double value = 0;
5076*103e46e4SHarish Mahendrakar       const long long value_parse_status =
5077*103e46e4SHarish Mahendrakar           UnserializeFloat(reader, read_pos, child_size, value);
5078*103e46e4SHarish Mahendrakar       if (value < -FLT_MAX || value > FLT_MAX ||
5079*103e46e4SHarish Mahendrakar           (value > 0.0 && value < FLT_MIN)) {
5080*103e46e4SHarish Mahendrakar         return false;
5081*103e46e4SHarish Mahendrakar       }
5082*103e46e4SHarish Mahendrakar       mm_ptr->luminance_min = static_cast<float>(value);
5083*103e46e4SHarish Mahendrakar       if (value_parse_status < 0 || mm_ptr->luminance_min < 0.0 ||
5084*103e46e4SHarish Mahendrakar           mm_ptr->luminance_min > 999.9999) {
5085*103e46e4SHarish Mahendrakar         return false;
5086*103e46e4SHarish Mahendrakar       }
5087*103e46e4SHarish Mahendrakar     } else {
5088*103e46e4SHarish Mahendrakar       bool is_x = false;
5089*103e46e4SHarish Mahendrakar       PrimaryChromaticity** chromaticity;
5090*103e46e4SHarish Mahendrakar       switch (child_id) {
5091*103e46e4SHarish Mahendrakar         case libwebm::kMkvPrimaryRChromaticityX:
5092*103e46e4SHarish Mahendrakar         case libwebm::kMkvPrimaryRChromaticityY:
5093*103e46e4SHarish Mahendrakar           is_x = child_id == libwebm::kMkvPrimaryRChromaticityX;
5094*103e46e4SHarish Mahendrakar           chromaticity = &mm_ptr->r;
5095*103e46e4SHarish Mahendrakar           break;
5096*103e46e4SHarish Mahendrakar         case libwebm::kMkvPrimaryGChromaticityX:
5097*103e46e4SHarish Mahendrakar         case libwebm::kMkvPrimaryGChromaticityY:
5098*103e46e4SHarish Mahendrakar           is_x = child_id == libwebm::kMkvPrimaryGChromaticityX;
5099*103e46e4SHarish Mahendrakar           chromaticity = &mm_ptr->g;
5100*103e46e4SHarish Mahendrakar           break;
5101*103e46e4SHarish Mahendrakar         case libwebm::kMkvPrimaryBChromaticityX:
5102*103e46e4SHarish Mahendrakar         case libwebm::kMkvPrimaryBChromaticityY:
5103*103e46e4SHarish Mahendrakar           is_x = child_id == libwebm::kMkvPrimaryBChromaticityX;
5104*103e46e4SHarish Mahendrakar           chromaticity = &mm_ptr->b;
5105*103e46e4SHarish Mahendrakar           break;
5106*103e46e4SHarish Mahendrakar         case libwebm::kMkvWhitePointChromaticityX:
5107*103e46e4SHarish Mahendrakar         case libwebm::kMkvWhitePointChromaticityY:
5108*103e46e4SHarish Mahendrakar           is_x = child_id == libwebm::kMkvWhitePointChromaticityX;
5109*103e46e4SHarish Mahendrakar           chromaticity = &mm_ptr->white_point;
5110*103e46e4SHarish Mahendrakar           break;
5111*103e46e4SHarish Mahendrakar         default:
5112*103e46e4SHarish Mahendrakar           return false;
5113*103e46e4SHarish Mahendrakar       }
5114*103e46e4SHarish Mahendrakar       const bool value_parse_status = PrimaryChromaticity::Parse(
5115*103e46e4SHarish Mahendrakar           reader, read_pos, child_size, is_x, chromaticity);
5116*103e46e4SHarish Mahendrakar       if (!value_parse_status)
5117*103e46e4SHarish Mahendrakar         return false;
5118*103e46e4SHarish Mahendrakar     }
5119*103e46e4SHarish Mahendrakar 
5120*103e46e4SHarish Mahendrakar     read_pos += child_size;
5121*103e46e4SHarish Mahendrakar     if (read_pos > mm_end)
5122*103e46e4SHarish Mahendrakar       return false;
5123*103e46e4SHarish Mahendrakar   }
5124*103e46e4SHarish Mahendrakar 
5125*103e46e4SHarish Mahendrakar   *mm = mm_ptr.release();
5126*103e46e4SHarish Mahendrakar   return true;
5127*103e46e4SHarish Mahendrakar }
5128*103e46e4SHarish Mahendrakar 
Parse(IMkvReader * reader,long long colour_start,long long colour_size,Colour ** colour)5129*103e46e4SHarish Mahendrakar bool Colour::Parse(IMkvReader* reader, long long colour_start,
5130*103e46e4SHarish Mahendrakar                    long long colour_size, Colour** colour) {
5131*103e46e4SHarish Mahendrakar   if (!reader || *colour)
5132*103e46e4SHarish Mahendrakar     return false;
5133*103e46e4SHarish Mahendrakar 
5134*103e46e4SHarish Mahendrakar   std::unique_ptr<Colour> colour_ptr(new Colour());
5135*103e46e4SHarish Mahendrakar   if (!colour_ptr.get())
5136*103e46e4SHarish Mahendrakar     return false;
5137*103e46e4SHarish Mahendrakar 
5138*103e46e4SHarish Mahendrakar   const long long colour_end = colour_start + colour_size;
5139*103e46e4SHarish Mahendrakar   long long read_pos = colour_start;
5140*103e46e4SHarish Mahendrakar 
5141*103e46e4SHarish Mahendrakar   while (read_pos < colour_end) {
5142*103e46e4SHarish Mahendrakar     long long child_id = 0;
5143*103e46e4SHarish Mahendrakar     long long child_size = 0;
5144*103e46e4SHarish Mahendrakar 
5145*103e46e4SHarish Mahendrakar     const long status =
5146*103e46e4SHarish Mahendrakar         ParseElementHeader(reader, read_pos, colour_end, child_id, child_size);
5147*103e46e4SHarish Mahendrakar     if (status < 0)
5148*103e46e4SHarish Mahendrakar       return false;
5149*103e46e4SHarish Mahendrakar 
5150*103e46e4SHarish Mahendrakar     if (child_id == libwebm::kMkvMatrixCoefficients) {
5151*103e46e4SHarish Mahendrakar       colour_ptr->matrix_coefficients =
5152*103e46e4SHarish Mahendrakar           UnserializeUInt(reader, read_pos, child_size);
5153*103e46e4SHarish Mahendrakar       if (colour_ptr->matrix_coefficients < 0)
5154*103e46e4SHarish Mahendrakar         return false;
5155*103e46e4SHarish Mahendrakar     } else if (child_id == libwebm::kMkvBitsPerChannel) {
5156*103e46e4SHarish Mahendrakar       colour_ptr->bits_per_channel =
5157*103e46e4SHarish Mahendrakar           UnserializeUInt(reader, read_pos, child_size);
5158*103e46e4SHarish Mahendrakar       if (colour_ptr->bits_per_channel < 0)
5159*103e46e4SHarish Mahendrakar         return false;
5160*103e46e4SHarish Mahendrakar     } else if (child_id == libwebm::kMkvChromaSubsamplingHorz) {
5161*103e46e4SHarish Mahendrakar       colour_ptr->chroma_subsampling_horz =
5162*103e46e4SHarish Mahendrakar           UnserializeUInt(reader, read_pos, child_size);
5163*103e46e4SHarish Mahendrakar       if (colour_ptr->chroma_subsampling_horz < 0)
5164*103e46e4SHarish Mahendrakar         return false;
5165*103e46e4SHarish Mahendrakar     } else if (child_id == libwebm::kMkvChromaSubsamplingVert) {
5166*103e46e4SHarish Mahendrakar       colour_ptr->chroma_subsampling_vert =
5167*103e46e4SHarish Mahendrakar           UnserializeUInt(reader, read_pos, child_size);
5168*103e46e4SHarish Mahendrakar       if (colour_ptr->chroma_subsampling_vert < 0)
5169*103e46e4SHarish Mahendrakar         return false;
5170*103e46e4SHarish Mahendrakar     } else if (child_id == libwebm::kMkvCbSubsamplingHorz) {
5171*103e46e4SHarish Mahendrakar       colour_ptr->cb_subsampling_horz =
5172*103e46e4SHarish Mahendrakar           UnserializeUInt(reader, read_pos, child_size);
5173*103e46e4SHarish Mahendrakar       if (colour_ptr->cb_subsampling_horz < 0)
5174*103e46e4SHarish Mahendrakar         return false;
5175*103e46e4SHarish Mahendrakar     } else if (child_id == libwebm::kMkvCbSubsamplingVert) {
5176*103e46e4SHarish Mahendrakar       colour_ptr->cb_subsampling_vert =
5177*103e46e4SHarish Mahendrakar           UnserializeUInt(reader, read_pos, child_size);
5178*103e46e4SHarish Mahendrakar       if (colour_ptr->cb_subsampling_vert < 0)
5179*103e46e4SHarish Mahendrakar         return false;
5180*103e46e4SHarish Mahendrakar     } else if (child_id == libwebm::kMkvChromaSitingHorz) {
5181*103e46e4SHarish Mahendrakar       colour_ptr->chroma_siting_horz =
5182*103e46e4SHarish Mahendrakar           UnserializeUInt(reader, read_pos, child_size);
5183*103e46e4SHarish Mahendrakar       if (colour_ptr->chroma_siting_horz < 0)
5184*103e46e4SHarish Mahendrakar         return false;
5185*103e46e4SHarish Mahendrakar     } else if (child_id == libwebm::kMkvChromaSitingVert) {
5186*103e46e4SHarish Mahendrakar       colour_ptr->chroma_siting_vert =
5187*103e46e4SHarish Mahendrakar           UnserializeUInt(reader, read_pos, child_size);
5188*103e46e4SHarish Mahendrakar       if (colour_ptr->chroma_siting_vert < 0)
5189*103e46e4SHarish Mahendrakar         return false;
5190*103e46e4SHarish Mahendrakar     } else if (child_id == libwebm::kMkvRange) {
5191*103e46e4SHarish Mahendrakar       colour_ptr->range = UnserializeUInt(reader, read_pos, child_size);
5192*103e46e4SHarish Mahendrakar       if (colour_ptr->range < 0)
5193*103e46e4SHarish Mahendrakar         return false;
5194*103e46e4SHarish Mahendrakar     } else if (child_id == libwebm::kMkvTransferCharacteristics) {
5195*103e46e4SHarish Mahendrakar       colour_ptr->transfer_characteristics =
5196*103e46e4SHarish Mahendrakar           UnserializeUInt(reader, read_pos, child_size);
5197*103e46e4SHarish Mahendrakar       if (colour_ptr->transfer_characteristics < 0)
5198*103e46e4SHarish Mahendrakar         return false;
5199*103e46e4SHarish Mahendrakar     } else if (child_id == libwebm::kMkvPrimaries) {
5200*103e46e4SHarish Mahendrakar       colour_ptr->primaries = UnserializeUInt(reader, read_pos, child_size);
5201*103e46e4SHarish Mahendrakar       if (colour_ptr->primaries < 0)
5202*103e46e4SHarish Mahendrakar         return false;
5203*103e46e4SHarish Mahendrakar     } else if (child_id == libwebm::kMkvMaxCLL) {
5204*103e46e4SHarish Mahendrakar       colour_ptr->max_cll = UnserializeUInt(reader, read_pos, child_size);
5205*103e46e4SHarish Mahendrakar       if (colour_ptr->max_cll < 0)
5206*103e46e4SHarish Mahendrakar         return false;
5207*103e46e4SHarish Mahendrakar     } else if (child_id == libwebm::kMkvMaxFALL) {
5208*103e46e4SHarish Mahendrakar       colour_ptr->max_fall = UnserializeUInt(reader, read_pos, child_size);
5209*103e46e4SHarish Mahendrakar       if (colour_ptr->max_fall < 0)
5210*103e46e4SHarish Mahendrakar         return false;
5211*103e46e4SHarish Mahendrakar     } else if (child_id == libwebm::kMkvMasteringMetadata) {
5212*103e46e4SHarish Mahendrakar       if (!MasteringMetadata::Parse(reader, read_pos, child_size,
5213*103e46e4SHarish Mahendrakar                                     &colour_ptr->mastering_metadata))
5214*103e46e4SHarish Mahendrakar         return false;
5215*103e46e4SHarish Mahendrakar     } else {
5216*103e46e4SHarish Mahendrakar       return false;
5217*103e46e4SHarish Mahendrakar     }
5218*103e46e4SHarish Mahendrakar 
5219*103e46e4SHarish Mahendrakar     read_pos += child_size;
5220*103e46e4SHarish Mahendrakar     if (read_pos > colour_end)
5221*103e46e4SHarish Mahendrakar       return false;
5222*103e46e4SHarish Mahendrakar   }
5223*103e46e4SHarish Mahendrakar   *colour = colour_ptr.release();
5224*103e46e4SHarish Mahendrakar   return true;
5225*103e46e4SHarish Mahendrakar }
5226*103e46e4SHarish Mahendrakar 
Parse(IMkvReader * reader,long long start,long long size,Projection ** projection)5227*103e46e4SHarish Mahendrakar bool Projection::Parse(IMkvReader* reader, long long start, long long size,
5228*103e46e4SHarish Mahendrakar                        Projection** projection) {
5229*103e46e4SHarish Mahendrakar   if (!reader || *projection)
5230*103e46e4SHarish Mahendrakar     return false;
5231*103e46e4SHarish Mahendrakar 
5232*103e46e4SHarish Mahendrakar   std::unique_ptr<Projection> projection_ptr(new Projection());
5233*103e46e4SHarish Mahendrakar   if (!projection_ptr.get())
5234*103e46e4SHarish Mahendrakar     return false;
5235*103e46e4SHarish Mahendrakar 
5236*103e46e4SHarish Mahendrakar   const long long end = start + size;
5237*103e46e4SHarish Mahendrakar   long long read_pos = start;
5238*103e46e4SHarish Mahendrakar 
5239*103e46e4SHarish Mahendrakar   while (read_pos < end) {
5240*103e46e4SHarish Mahendrakar     long long child_id = 0;
5241*103e46e4SHarish Mahendrakar     long long child_size = 0;
5242*103e46e4SHarish Mahendrakar 
5243*103e46e4SHarish Mahendrakar     const long long status =
5244*103e46e4SHarish Mahendrakar         ParseElementHeader(reader, read_pos, end, child_id, child_size);
5245*103e46e4SHarish Mahendrakar     if (status < 0)
5246*103e46e4SHarish Mahendrakar       return false;
5247*103e46e4SHarish Mahendrakar 
5248*103e46e4SHarish Mahendrakar     if (child_id == libwebm::kMkvProjectionType) {
5249*103e46e4SHarish Mahendrakar       long long projection_type = kTypeNotPresent;
5250*103e46e4SHarish Mahendrakar       projection_type = UnserializeUInt(reader, read_pos, child_size);
5251*103e46e4SHarish Mahendrakar       if (projection_type < 0)
5252*103e46e4SHarish Mahendrakar         return false;
5253*103e46e4SHarish Mahendrakar 
5254*103e46e4SHarish Mahendrakar       projection_ptr->type = static_cast<ProjectionType>(projection_type);
5255*103e46e4SHarish Mahendrakar     } else if (child_id == libwebm::kMkvProjectionPrivate) {
5256*103e46e4SHarish Mahendrakar       if (projection_ptr->private_data != NULL)
5257*103e46e4SHarish Mahendrakar         return false;
5258*103e46e4SHarish Mahendrakar       unsigned char* data = SafeArrayAlloc<unsigned char>(1, child_size);
5259*103e46e4SHarish Mahendrakar 
5260*103e46e4SHarish Mahendrakar       if (data == NULL)
5261*103e46e4SHarish Mahendrakar         return false;
5262*103e46e4SHarish Mahendrakar 
5263*103e46e4SHarish Mahendrakar       const int status =
5264*103e46e4SHarish Mahendrakar           reader->Read(read_pos, static_cast<long>(child_size), data);
5265*103e46e4SHarish Mahendrakar 
5266*103e46e4SHarish Mahendrakar       if (status) {
5267*103e46e4SHarish Mahendrakar         delete[] data;
5268*103e46e4SHarish Mahendrakar         return false;
5269*103e46e4SHarish Mahendrakar       }
5270*103e46e4SHarish Mahendrakar 
5271*103e46e4SHarish Mahendrakar       projection_ptr->private_data = data;
5272*103e46e4SHarish Mahendrakar       projection_ptr->private_data_length = static_cast<size_t>(child_size);
5273*103e46e4SHarish Mahendrakar     } else {
5274*103e46e4SHarish Mahendrakar       double value = 0;
5275*103e46e4SHarish Mahendrakar       const long long value_parse_status =
5276*103e46e4SHarish Mahendrakar           UnserializeFloat(reader, read_pos, child_size, value);
5277*103e46e4SHarish Mahendrakar       // Make sure value is representable as a float before casting.
5278*103e46e4SHarish Mahendrakar       if (value_parse_status < 0 || value < -FLT_MAX || value > FLT_MAX ||
5279*103e46e4SHarish Mahendrakar           (value > 0.0 && value < FLT_MIN)) {
5280*103e46e4SHarish Mahendrakar         return false;
5281*103e46e4SHarish Mahendrakar       }
5282*103e46e4SHarish Mahendrakar 
5283*103e46e4SHarish Mahendrakar       switch (child_id) {
5284*103e46e4SHarish Mahendrakar         case libwebm::kMkvProjectionPoseYaw:
5285*103e46e4SHarish Mahendrakar           projection_ptr->pose_yaw = static_cast<float>(value);
5286*103e46e4SHarish Mahendrakar           break;
5287*103e46e4SHarish Mahendrakar         case libwebm::kMkvProjectionPosePitch:
5288*103e46e4SHarish Mahendrakar           projection_ptr->pose_pitch = static_cast<float>(value);
5289*103e46e4SHarish Mahendrakar           break;
5290*103e46e4SHarish Mahendrakar         case libwebm::kMkvProjectionPoseRoll:
5291*103e46e4SHarish Mahendrakar           projection_ptr->pose_roll = static_cast<float>(value);
5292*103e46e4SHarish Mahendrakar           break;
5293*103e46e4SHarish Mahendrakar         default:
5294*103e46e4SHarish Mahendrakar           return false;
5295*103e46e4SHarish Mahendrakar       }
5296*103e46e4SHarish Mahendrakar     }
5297*103e46e4SHarish Mahendrakar 
5298*103e46e4SHarish Mahendrakar     read_pos += child_size;
5299*103e46e4SHarish Mahendrakar     if (read_pos > end)
5300*103e46e4SHarish Mahendrakar       return false;
5301*103e46e4SHarish Mahendrakar   }
5302*103e46e4SHarish Mahendrakar 
5303*103e46e4SHarish Mahendrakar   *projection = projection_ptr.release();
5304*103e46e4SHarish Mahendrakar   return true;
5305*103e46e4SHarish Mahendrakar }
5306*103e46e4SHarish Mahendrakar 
VideoTrack(Segment * pSegment,long long element_start,long long element_size)5307*103e46e4SHarish Mahendrakar VideoTrack::VideoTrack(Segment* pSegment, long long element_start,
5308*103e46e4SHarish Mahendrakar                        long long element_size)
5309*103e46e4SHarish Mahendrakar     : Track(pSegment, element_start, element_size),
5310*103e46e4SHarish Mahendrakar       m_colour_space(NULL),
5311*103e46e4SHarish Mahendrakar       m_colour(NULL),
5312*103e46e4SHarish Mahendrakar       m_projection(NULL) {}
5313*103e46e4SHarish Mahendrakar 
~VideoTrack()5314*103e46e4SHarish Mahendrakar VideoTrack::~VideoTrack() {
5315*103e46e4SHarish Mahendrakar   delete[] m_colour_space;
5316*103e46e4SHarish Mahendrakar   delete m_colour;
5317*103e46e4SHarish Mahendrakar   delete m_projection;
5318*103e46e4SHarish Mahendrakar }
5319*103e46e4SHarish Mahendrakar 
Parse(Segment * pSegment,const Info & info,long long element_start,long long element_size,VideoTrack * & pResult)5320*103e46e4SHarish Mahendrakar long VideoTrack::Parse(Segment* pSegment, const Info& info,
5321*103e46e4SHarish Mahendrakar                        long long element_start, long long element_size,
5322*103e46e4SHarish Mahendrakar                        VideoTrack*& pResult) {
5323*103e46e4SHarish Mahendrakar   if (pResult)
5324*103e46e4SHarish Mahendrakar     return -1;
5325*103e46e4SHarish Mahendrakar 
5326*103e46e4SHarish Mahendrakar   if (info.type != Track::kVideo)
5327*103e46e4SHarish Mahendrakar     return -1;
5328*103e46e4SHarish Mahendrakar 
5329*103e46e4SHarish Mahendrakar   long long width = 0;
5330*103e46e4SHarish Mahendrakar   long long height = 0;
5331*103e46e4SHarish Mahendrakar   long long display_width = 0;
5332*103e46e4SHarish Mahendrakar   long long display_height = 0;
5333*103e46e4SHarish Mahendrakar   long long display_unit = 0;
5334*103e46e4SHarish Mahendrakar   long long stereo_mode = 0;
5335*103e46e4SHarish Mahendrakar 
5336*103e46e4SHarish Mahendrakar   double rate = 0.0;
5337*103e46e4SHarish Mahendrakar   std::unique_ptr<char[]> colour_space_ptr;
5338*103e46e4SHarish Mahendrakar 
5339*103e46e4SHarish Mahendrakar   IMkvReader* const pReader = pSegment->m_pReader;
5340*103e46e4SHarish Mahendrakar 
5341*103e46e4SHarish Mahendrakar   const Settings& s = info.settings;
5342*103e46e4SHarish Mahendrakar   assert(s.start >= 0);
5343*103e46e4SHarish Mahendrakar   assert(s.size >= 0);
5344*103e46e4SHarish Mahendrakar 
5345*103e46e4SHarish Mahendrakar   long long pos = s.start;
5346*103e46e4SHarish Mahendrakar   assert(pos >= 0);
5347*103e46e4SHarish Mahendrakar 
5348*103e46e4SHarish Mahendrakar   const long long stop = pos + s.size;
5349*103e46e4SHarish Mahendrakar 
5350*103e46e4SHarish Mahendrakar   std::unique_ptr<Colour> colour_ptr;
5351*103e46e4SHarish Mahendrakar   std::unique_ptr<Projection> projection_ptr;
5352*103e46e4SHarish Mahendrakar 
5353*103e46e4SHarish Mahendrakar   while (pos < stop) {
5354*103e46e4SHarish Mahendrakar     long long id, size;
5355*103e46e4SHarish Mahendrakar 
5356*103e46e4SHarish Mahendrakar     const long status = ParseElementHeader(pReader, pos, stop, id, size);
5357*103e46e4SHarish Mahendrakar 
5358*103e46e4SHarish Mahendrakar     if (status < 0)  // error
5359*103e46e4SHarish Mahendrakar       return status;
5360*103e46e4SHarish Mahendrakar 
5361*103e46e4SHarish Mahendrakar     if (id == libwebm::kMkvPixelWidth) {
5362*103e46e4SHarish Mahendrakar       width = UnserializeUInt(pReader, pos, size);
5363*103e46e4SHarish Mahendrakar 
5364*103e46e4SHarish Mahendrakar       if (width <= 0)
5365*103e46e4SHarish Mahendrakar         return E_FILE_FORMAT_INVALID;
5366*103e46e4SHarish Mahendrakar     } else if (id == libwebm::kMkvPixelHeight) {
5367*103e46e4SHarish Mahendrakar       height = UnserializeUInt(pReader, pos, size);
5368*103e46e4SHarish Mahendrakar 
5369*103e46e4SHarish Mahendrakar       if (height <= 0)
5370*103e46e4SHarish Mahendrakar         return E_FILE_FORMAT_INVALID;
5371*103e46e4SHarish Mahendrakar     } else if (id == libwebm::kMkvDisplayWidth) {
5372*103e46e4SHarish Mahendrakar       display_width = UnserializeUInt(pReader, pos, size);
5373*103e46e4SHarish Mahendrakar 
5374*103e46e4SHarish Mahendrakar       if (display_width <= 0)
5375*103e46e4SHarish Mahendrakar         return E_FILE_FORMAT_INVALID;
5376*103e46e4SHarish Mahendrakar     } else if (id == libwebm::kMkvDisplayHeight) {
5377*103e46e4SHarish Mahendrakar       display_height = UnserializeUInt(pReader, pos, size);
5378*103e46e4SHarish Mahendrakar 
5379*103e46e4SHarish Mahendrakar       if (display_height <= 0)
5380*103e46e4SHarish Mahendrakar         return E_FILE_FORMAT_INVALID;
5381*103e46e4SHarish Mahendrakar     } else if (id == libwebm::kMkvDisplayUnit) {
5382*103e46e4SHarish Mahendrakar       display_unit = UnserializeUInt(pReader, pos, size);
5383*103e46e4SHarish Mahendrakar 
5384*103e46e4SHarish Mahendrakar       if (display_unit < 0)
5385*103e46e4SHarish Mahendrakar         return E_FILE_FORMAT_INVALID;
5386*103e46e4SHarish Mahendrakar     } else if (id == libwebm::kMkvStereoMode) {
5387*103e46e4SHarish Mahendrakar       stereo_mode = UnserializeUInt(pReader, pos, size);
5388*103e46e4SHarish Mahendrakar 
5389*103e46e4SHarish Mahendrakar       if (stereo_mode < 0)
5390*103e46e4SHarish Mahendrakar         return E_FILE_FORMAT_INVALID;
5391*103e46e4SHarish Mahendrakar     } else if (id == libwebm::kMkvFrameRate) {
5392*103e46e4SHarish Mahendrakar       const long status = UnserializeFloat(pReader, pos, size, rate);
5393*103e46e4SHarish Mahendrakar 
5394*103e46e4SHarish Mahendrakar       if (status < 0)
5395*103e46e4SHarish Mahendrakar         return status;
5396*103e46e4SHarish Mahendrakar 
5397*103e46e4SHarish Mahendrakar       if (rate <= 0)
5398*103e46e4SHarish Mahendrakar         return E_FILE_FORMAT_INVALID;
5399*103e46e4SHarish Mahendrakar     } else if (id == libwebm::kMkvColour) {
5400*103e46e4SHarish Mahendrakar       Colour* colour = NULL;
5401*103e46e4SHarish Mahendrakar       if (!Colour::Parse(pReader, pos, size, &colour)) {
5402*103e46e4SHarish Mahendrakar         return E_FILE_FORMAT_INVALID;
5403*103e46e4SHarish Mahendrakar       } else {
5404*103e46e4SHarish Mahendrakar         colour_ptr.reset(colour);
5405*103e46e4SHarish Mahendrakar       }
5406*103e46e4SHarish Mahendrakar     } else if (id == libwebm::kMkvProjection) {
5407*103e46e4SHarish Mahendrakar       Projection* projection = NULL;
5408*103e46e4SHarish Mahendrakar       if (!Projection::Parse(pReader, pos, size, &projection)) {
5409*103e46e4SHarish Mahendrakar         return E_FILE_FORMAT_INVALID;
5410*103e46e4SHarish Mahendrakar       } else {
5411*103e46e4SHarish Mahendrakar         projection_ptr.reset(projection);
5412*103e46e4SHarish Mahendrakar       }
5413*103e46e4SHarish Mahendrakar     } else if (id == libwebm::kMkvColourSpace) {
5414*103e46e4SHarish Mahendrakar       char* colour_space = NULL;
5415*103e46e4SHarish Mahendrakar       const long status = UnserializeString(pReader, pos, size, colour_space);
5416*103e46e4SHarish Mahendrakar       if (status < 0)
5417*103e46e4SHarish Mahendrakar         return status;
5418*103e46e4SHarish Mahendrakar       colour_space_ptr.reset(colour_space);
5419*103e46e4SHarish Mahendrakar     }
5420*103e46e4SHarish Mahendrakar 
5421*103e46e4SHarish Mahendrakar     pos += size;  // consume payload
5422*103e46e4SHarish Mahendrakar     if (pos > stop)
5423*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
5424*103e46e4SHarish Mahendrakar   }
5425*103e46e4SHarish Mahendrakar 
5426*103e46e4SHarish Mahendrakar   if (pos != stop)
5427*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
5428*103e46e4SHarish Mahendrakar 
5429*103e46e4SHarish Mahendrakar   VideoTrack* const pTrack =
5430*103e46e4SHarish Mahendrakar       new (std::nothrow) VideoTrack(pSegment, element_start, element_size);
5431*103e46e4SHarish Mahendrakar 
5432*103e46e4SHarish Mahendrakar   if (pTrack == NULL)
5433*103e46e4SHarish Mahendrakar     return -1;  // generic error
5434*103e46e4SHarish Mahendrakar 
5435*103e46e4SHarish Mahendrakar   const int status = info.Copy(pTrack->m_info);
5436*103e46e4SHarish Mahendrakar 
5437*103e46e4SHarish Mahendrakar   if (status) {  // error
5438*103e46e4SHarish Mahendrakar     delete pTrack;
5439*103e46e4SHarish Mahendrakar     return status;
5440*103e46e4SHarish Mahendrakar   }
5441*103e46e4SHarish Mahendrakar 
5442*103e46e4SHarish Mahendrakar   pTrack->m_width = width;
5443*103e46e4SHarish Mahendrakar   pTrack->m_height = height;
5444*103e46e4SHarish Mahendrakar   pTrack->m_display_width = display_width;
5445*103e46e4SHarish Mahendrakar   pTrack->m_display_height = display_height;
5446*103e46e4SHarish Mahendrakar   pTrack->m_display_unit = display_unit;
5447*103e46e4SHarish Mahendrakar   pTrack->m_stereo_mode = stereo_mode;
5448*103e46e4SHarish Mahendrakar   pTrack->m_rate = rate;
5449*103e46e4SHarish Mahendrakar   pTrack->m_colour = colour_ptr.release();
5450*103e46e4SHarish Mahendrakar   pTrack->m_colour_space = colour_space_ptr.release();
5451*103e46e4SHarish Mahendrakar   pTrack->m_projection = projection_ptr.release();
5452*103e46e4SHarish Mahendrakar 
5453*103e46e4SHarish Mahendrakar   pResult = pTrack;
5454*103e46e4SHarish Mahendrakar   return 0;  // success
5455*103e46e4SHarish Mahendrakar }
5456*103e46e4SHarish Mahendrakar 
VetEntry(const BlockEntry * pBlockEntry) const5457*103e46e4SHarish Mahendrakar bool VideoTrack::VetEntry(const BlockEntry* pBlockEntry) const {
5458*103e46e4SHarish Mahendrakar   return Track::VetEntry(pBlockEntry) && pBlockEntry->GetBlock()->IsKey();
5459*103e46e4SHarish Mahendrakar }
5460*103e46e4SHarish Mahendrakar 
Seek(long long time_ns,const BlockEntry * & pResult) const5461*103e46e4SHarish Mahendrakar long VideoTrack::Seek(long long time_ns, const BlockEntry*& pResult) const {
5462*103e46e4SHarish Mahendrakar   const long status = GetFirst(pResult);
5463*103e46e4SHarish Mahendrakar 
5464*103e46e4SHarish Mahendrakar   if (status < 0)  // buffer underflow, etc
5465*103e46e4SHarish Mahendrakar     return status;
5466*103e46e4SHarish Mahendrakar 
5467*103e46e4SHarish Mahendrakar   assert(pResult);
5468*103e46e4SHarish Mahendrakar 
5469*103e46e4SHarish Mahendrakar   if (pResult->EOS())
5470*103e46e4SHarish Mahendrakar     return 0;
5471*103e46e4SHarish Mahendrakar 
5472*103e46e4SHarish Mahendrakar   const Cluster* pCluster = pResult->GetCluster();
5473*103e46e4SHarish Mahendrakar   assert(pCluster);
5474*103e46e4SHarish Mahendrakar   assert(pCluster->GetIndex() >= 0);
5475*103e46e4SHarish Mahendrakar 
5476*103e46e4SHarish Mahendrakar   if (time_ns <= pResult->GetBlock()->GetTime(pCluster))
5477*103e46e4SHarish Mahendrakar     return 0;
5478*103e46e4SHarish Mahendrakar 
5479*103e46e4SHarish Mahendrakar   Cluster** const clusters = m_pSegment->m_clusters;
5480*103e46e4SHarish Mahendrakar   assert(clusters);
5481*103e46e4SHarish Mahendrakar 
5482*103e46e4SHarish Mahendrakar   const long count = m_pSegment->GetCount();  // loaded only, not pre-loaded
5483*103e46e4SHarish Mahendrakar   assert(count > 0);
5484*103e46e4SHarish Mahendrakar 
5485*103e46e4SHarish Mahendrakar   Cluster** const i = clusters + pCluster->GetIndex();
5486*103e46e4SHarish Mahendrakar   assert(i);
5487*103e46e4SHarish Mahendrakar   assert(*i == pCluster);
5488*103e46e4SHarish Mahendrakar   assert(pCluster->GetTime() <= time_ns);
5489*103e46e4SHarish Mahendrakar 
5490*103e46e4SHarish Mahendrakar   Cluster** const j = clusters + count;
5491*103e46e4SHarish Mahendrakar 
5492*103e46e4SHarish Mahendrakar   Cluster** lo = i;
5493*103e46e4SHarish Mahendrakar   Cluster** hi = j;
5494*103e46e4SHarish Mahendrakar 
5495*103e46e4SHarish Mahendrakar   while (lo < hi) {
5496*103e46e4SHarish Mahendrakar     // INVARIANT:
5497*103e46e4SHarish Mahendrakar     //[i, lo) <= time_ns
5498*103e46e4SHarish Mahendrakar     //[lo, hi) ?
5499*103e46e4SHarish Mahendrakar     //[hi, j)  > time_ns
5500*103e46e4SHarish Mahendrakar 
5501*103e46e4SHarish Mahendrakar     Cluster** const mid = lo + (hi - lo) / 2;
5502*103e46e4SHarish Mahendrakar     assert(mid < hi);
5503*103e46e4SHarish Mahendrakar 
5504*103e46e4SHarish Mahendrakar     pCluster = *mid;
5505*103e46e4SHarish Mahendrakar     assert(pCluster);
5506*103e46e4SHarish Mahendrakar     assert(pCluster->GetIndex() >= 0);
5507*103e46e4SHarish Mahendrakar     assert(pCluster->GetIndex() == long(mid - m_pSegment->m_clusters));
5508*103e46e4SHarish Mahendrakar 
5509*103e46e4SHarish Mahendrakar     const long long t = pCluster->GetTime();
5510*103e46e4SHarish Mahendrakar 
5511*103e46e4SHarish Mahendrakar     if (t <= time_ns)
5512*103e46e4SHarish Mahendrakar       lo = mid + 1;
5513*103e46e4SHarish Mahendrakar     else
5514*103e46e4SHarish Mahendrakar       hi = mid;
5515*103e46e4SHarish Mahendrakar 
5516*103e46e4SHarish Mahendrakar     assert(lo <= hi);
5517*103e46e4SHarish Mahendrakar   }
5518*103e46e4SHarish Mahendrakar 
5519*103e46e4SHarish Mahendrakar   assert(lo == hi);
5520*103e46e4SHarish Mahendrakar   assert(lo > i);
5521*103e46e4SHarish Mahendrakar   assert(lo <= j);
5522*103e46e4SHarish Mahendrakar 
5523*103e46e4SHarish Mahendrakar   pCluster = *--lo;
5524*103e46e4SHarish Mahendrakar   assert(pCluster);
5525*103e46e4SHarish Mahendrakar   assert(pCluster->GetTime() <= time_ns);
5526*103e46e4SHarish Mahendrakar 
5527*103e46e4SHarish Mahendrakar   pResult = pCluster->GetEntry(this, time_ns);
5528*103e46e4SHarish Mahendrakar 
5529*103e46e4SHarish Mahendrakar   if ((pResult != 0) && !pResult->EOS())  // found a keyframe
5530*103e46e4SHarish Mahendrakar     return 0;
5531*103e46e4SHarish Mahendrakar 
5532*103e46e4SHarish Mahendrakar   while (lo != i) {
5533*103e46e4SHarish Mahendrakar     pCluster = *--lo;
5534*103e46e4SHarish Mahendrakar     assert(pCluster);
5535*103e46e4SHarish Mahendrakar     assert(pCluster->GetTime() <= time_ns);
5536*103e46e4SHarish Mahendrakar 
5537*103e46e4SHarish Mahendrakar     pResult = pCluster->GetEntry(this, time_ns);
5538*103e46e4SHarish Mahendrakar 
5539*103e46e4SHarish Mahendrakar     if ((pResult != 0) && !pResult->EOS())
5540*103e46e4SHarish Mahendrakar       return 0;
5541*103e46e4SHarish Mahendrakar   }
5542*103e46e4SHarish Mahendrakar 
5543*103e46e4SHarish Mahendrakar   // weird: we're on the first cluster, but no keyframe found
5544*103e46e4SHarish Mahendrakar   // should never happen but we must return something anyway
5545*103e46e4SHarish Mahendrakar 
5546*103e46e4SHarish Mahendrakar   pResult = GetEOS();
5547*103e46e4SHarish Mahendrakar   return 0;
5548*103e46e4SHarish Mahendrakar }
5549*103e46e4SHarish Mahendrakar 
GetColour() const5550*103e46e4SHarish Mahendrakar Colour* VideoTrack::GetColour() const { return m_colour; }
5551*103e46e4SHarish Mahendrakar 
GetProjection() const5552*103e46e4SHarish Mahendrakar Projection* VideoTrack::GetProjection() const { return m_projection; }
5553*103e46e4SHarish Mahendrakar 
GetWidth() const5554*103e46e4SHarish Mahendrakar long long VideoTrack::GetWidth() const { return m_width; }
5555*103e46e4SHarish Mahendrakar 
GetHeight() const5556*103e46e4SHarish Mahendrakar long long VideoTrack::GetHeight() const { return m_height; }
5557*103e46e4SHarish Mahendrakar 
GetDisplayWidth() const5558*103e46e4SHarish Mahendrakar long long VideoTrack::GetDisplayWidth() const {
5559*103e46e4SHarish Mahendrakar   return m_display_width > 0 ? m_display_width : GetWidth();
5560*103e46e4SHarish Mahendrakar }
5561*103e46e4SHarish Mahendrakar 
GetDisplayHeight() const5562*103e46e4SHarish Mahendrakar long long VideoTrack::GetDisplayHeight() const {
5563*103e46e4SHarish Mahendrakar   return m_display_height > 0 ? m_display_height : GetHeight();
5564*103e46e4SHarish Mahendrakar }
5565*103e46e4SHarish Mahendrakar 
GetDisplayUnit() const5566*103e46e4SHarish Mahendrakar long long VideoTrack::GetDisplayUnit() const { return m_display_unit; }
5567*103e46e4SHarish Mahendrakar 
GetStereoMode() const5568*103e46e4SHarish Mahendrakar long long VideoTrack::GetStereoMode() const { return m_stereo_mode; }
5569*103e46e4SHarish Mahendrakar 
GetFrameRate() const5570*103e46e4SHarish Mahendrakar double VideoTrack::GetFrameRate() const { return m_rate; }
5571*103e46e4SHarish Mahendrakar 
AudioTrack(Segment * pSegment,long long element_start,long long element_size)5572*103e46e4SHarish Mahendrakar AudioTrack::AudioTrack(Segment* pSegment, long long element_start,
5573*103e46e4SHarish Mahendrakar                        long long element_size)
5574*103e46e4SHarish Mahendrakar     : Track(pSegment, element_start, element_size) {}
5575*103e46e4SHarish Mahendrakar 
Parse(Segment * pSegment,const Info & info,long long element_start,long long element_size,AudioTrack * & pResult)5576*103e46e4SHarish Mahendrakar long AudioTrack::Parse(Segment* pSegment, const Info& info,
5577*103e46e4SHarish Mahendrakar                        long long element_start, long long element_size,
5578*103e46e4SHarish Mahendrakar                        AudioTrack*& pResult) {
5579*103e46e4SHarish Mahendrakar   if (pResult)
5580*103e46e4SHarish Mahendrakar     return -1;
5581*103e46e4SHarish Mahendrakar 
5582*103e46e4SHarish Mahendrakar   if (info.type != Track::kAudio)
5583*103e46e4SHarish Mahendrakar     return -1;
5584*103e46e4SHarish Mahendrakar 
5585*103e46e4SHarish Mahendrakar   IMkvReader* const pReader = pSegment->m_pReader;
5586*103e46e4SHarish Mahendrakar 
5587*103e46e4SHarish Mahendrakar   const Settings& s = info.settings;
5588*103e46e4SHarish Mahendrakar   assert(s.start >= 0);
5589*103e46e4SHarish Mahendrakar   assert(s.size >= 0);
5590*103e46e4SHarish Mahendrakar 
5591*103e46e4SHarish Mahendrakar   long long pos = s.start;
5592*103e46e4SHarish Mahendrakar   assert(pos >= 0);
5593*103e46e4SHarish Mahendrakar 
5594*103e46e4SHarish Mahendrakar   const long long stop = pos + s.size;
5595*103e46e4SHarish Mahendrakar 
5596*103e46e4SHarish Mahendrakar   double rate = 8000.0;  // MKV default
5597*103e46e4SHarish Mahendrakar   long long channels = 1;
5598*103e46e4SHarish Mahendrakar   long long bit_depth = 0;
5599*103e46e4SHarish Mahendrakar 
5600*103e46e4SHarish Mahendrakar   while (pos < stop) {
5601*103e46e4SHarish Mahendrakar     long long id, size;
5602*103e46e4SHarish Mahendrakar 
5603*103e46e4SHarish Mahendrakar     long status = ParseElementHeader(pReader, pos, stop, id, size);
5604*103e46e4SHarish Mahendrakar 
5605*103e46e4SHarish Mahendrakar     if (status < 0)  // error
5606*103e46e4SHarish Mahendrakar       return status;
5607*103e46e4SHarish Mahendrakar 
5608*103e46e4SHarish Mahendrakar     if (id == libwebm::kMkvSamplingFrequency) {
5609*103e46e4SHarish Mahendrakar       status = UnserializeFloat(pReader, pos, size, rate);
5610*103e46e4SHarish Mahendrakar 
5611*103e46e4SHarish Mahendrakar       if (status < 0)
5612*103e46e4SHarish Mahendrakar         return status;
5613*103e46e4SHarish Mahendrakar 
5614*103e46e4SHarish Mahendrakar       if (rate <= 0)
5615*103e46e4SHarish Mahendrakar         return E_FILE_FORMAT_INVALID;
5616*103e46e4SHarish Mahendrakar     } else if (id == libwebm::kMkvChannels) {
5617*103e46e4SHarish Mahendrakar       channels = UnserializeUInt(pReader, pos, size);
5618*103e46e4SHarish Mahendrakar 
5619*103e46e4SHarish Mahendrakar       if (channels <= 0)
5620*103e46e4SHarish Mahendrakar         return E_FILE_FORMAT_INVALID;
5621*103e46e4SHarish Mahendrakar     } else if (id == libwebm::kMkvBitDepth) {
5622*103e46e4SHarish Mahendrakar       bit_depth = UnserializeUInt(pReader, pos, size);
5623*103e46e4SHarish Mahendrakar 
5624*103e46e4SHarish Mahendrakar       if (bit_depth <= 0)
5625*103e46e4SHarish Mahendrakar         return E_FILE_FORMAT_INVALID;
5626*103e46e4SHarish Mahendrakar     }
5627*103e46e4SHarish Mahendrakar 
5628*103e46e4SHarish Mahendrakar     pos += size;  // consume payload
5629*103e46e4SHarish Mahendrakar     if (pos > stop)
5630*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
5631*103e46e4SHarish Mahendrakar   }
5632*103e46e4SHarish Mahendrakar 
5633*103e46e4SHarish Mahendrakar   if (pos != stop)
5634*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
5635*103e46e4SHarish Mahendrakar 
5636*103e46e4SHarish Mahendrakar   AudioTrack* const pTrack =
5637*103e46e4SHarish Mahendrakar       new (std::nothrow) AudioTrack(pSegment, element_start, element_size);
5638*103e46e4SHarish Mahendrakar 
5639*103e46e4SHarish Mahendrakar   if (pTrack == NULL)
5640*103e46e4SHarish Mahendrakar     return -1;  // generic error
5641*103e46e4SHarish Mahendrakar 
5642*103e46e4SHarish Mahendrakar   const int status = info.Copy(pTrack->m_info);
5643*103e46e4SHarish Mahendrakar 
5644*103e46e4SHarish Mahendrakar   if (status) {
5645*103e46e4SHarish Mahendrakar     delete pTrack;
5646*103e46e4SHarish Mahendrakar     return status;
5647*103e46e4SHarish Mahendrakar   }
5648*103e46e4SHarish Mahendrakar 
5649*103e46e4SHarish Mahendrakar   pTrack->m_rate = rate;
5650*103e46e4SHarish Mahendrakar   pTrack->m_channels = channels;
5651*103e46e4SHarish Mahendrakar   pTrack->m_bitDepth = bit_depth;
5652*103e46e4SHarish Mahendrakar 
5653*103e46e4SHarish Mahendrakar   pResult = pTrack;
5654*103e46e4SHarish Mahendrakar   return 0;  // success
5655*103e46e4SHarish Mahendrakar }
5656*103e46e4SHarish Mahendrakar 
GetSamplingRate() const5657*103e46e4SHarish Mahendrakar double AudioTrack::GetSamplingRate() const { return m_rate; }
5658*103e46e4SHarish Mahendrakar 
GetChannels() const5659*103e46e4SHarish Mahendrakar long long AudioTrack::GetChannels() const { return m_channels; }
5660*103e46e4SHarish Mahendrakar 
GetBitDepth() const5661*103e46e4SHarish Mahendrakar long long AudioTrack::GetBitDepth() const { return m_bitDepth; }
5662*103e46e4SHarish Mahendrakar 
Tracks(Segment * pSegment,long long start,long long size_,long long element_start,long long element_size)5663*103e46e4SHarish Mahendrakar Tracks::Tracks(Segment* pSegment, long long start, long long size_,
5664*103e46e4SHarish Mahendrakar                long long element_start, long long element_size)
5665*103e46e4SHarish Mahendrakar     : m_pSegment(pSegment),
5666*103e46e4SHarish Mahendrakar       m_start(start),
5667*103e46e4SHarish Mahendrakar       m_size(size_),
5668*103e46e4SHarish Mahendrakar       m_element_start(element_start),
5669*103e46e4SHarish Mahendrakar       m_element_size(element_size),
5670*103e46e4SHarish Mahendrakar       m_trackEntries(NULL),
5671*103e46e4SHarish Mahendrakar       m_trackEntriesEnd(NULL) {}
5672*103e46e4SHarish Mahendrakar 
Parse()5673*103e46e4SHarish Mahendrakar long Tracks::Parse() {
5674*103e46e4SHarish Mahendrakar   assert(m_trackEntries == NULL);
5675*103e46e4SHarish Mahendrakar   assert(m_trackEntriesEnd == NULL);
5676*103e46e4SHarish Mahendrakar 
5677*103e46e4SHarish Mahendrakar   const long long stop = m_start + m_size;
5678*103e46e4SHarish Mahendrakar   IMkvReader* const pReader = m_pSegment->m_pReader;
5679*103e46e4SHarish Mahendrakar 
5680*103e46e4SHarish Mahendrakar   long long count = 0;
5681*103e46e4SHarish Mahendrakar   long long pos = m_start;
5682*103e46e4SHarish Mahendrakar 
5683*103e46e4SHarish Mahendrakar   while (pos < stop) {
5684*103e46e4SHarish Mahendrakar     long long id, size;
5685*103e46e4SHarish Mahendrakar 
5686*103e46e4SHarish Mahendrakar     const long status = ParseElementHeader(pReader, pos, stop, id, size);
5687*103e46e4SHarish Mahendrakar 
5688*103e46e4SHarish Mahendrakar     if (status < 0)  // error
5689*103e46e4SHarish Mahendrakar       return status;
5690*103e46e4SHarish Mahendrakar 
5691*103e46e4SHarish Mahendrakar     if (size == 0)  // weird
5692*103e46e4SHarish Mahendrakar       continue;
5693*103e46e4SHarish Mahendrakar 
5694*103e46e4SHarish Mahendrakar     if (id == libwebm::kMkvTrackEntry) {
5695*103e46e4SHarish Mahendrakar       ++count;
5696*103e46e4SHarish Mahendrakar       if (count > INT_MAX)
5697*103e46e4SHarish Mahendrakar         return E_PARSE_FAILED;
5698*103e46e4SHarish Mahendrakar     }
5699*103e46e4SHarish Mahendrakar 
5700*103e46e4SHarish Mahendrakar     pos += size;  // consume payload
5701*103e46e4SHarish Mahendrakar     if (pos > stop)
5702*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
5703*103e46e4SHarish Mahendrakar   }
5704*103e46e4SHarish Mahendrakar 
5705*103e46e4SHarish Mahendrakar   if (pos != stop)
5706*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
5707*103e46e4SHarish Mahendrakar 
5708*103e46e4SHarish Mahendrakar   if (count <= 0)
5709*103e46e4SHarish Mahendrakar     return 0;  // success
5710*103e46e4SHarish Mahendrakar 
5711*103e46e4SHarish Mahendrakar   m_trackEntries = new (std::nothrow) Track*[static_cast<size_t>(count)];
5712*103e46e4SHarish Mahendrakar 
5713*103e46e4SHarish Mahendrakar   if (m_trackEntries == NULL)
5714*103e46e4SHarish Mahendrakar     return -1;
5715*103e46e4SHarish Mahendrakar 
5716*103e46e4SHarish Mahendrakar   m_trackEntriesEnd = m_trackEntries;
5717*103e46e4SHarish Mahendrakar 
5718*103e46e4SHarish Mahendrakar   pos = m_start;
5719*103e46e4SHarish Mahendrakar 
5720*103e46e4SHarish Mahendrakar   while (pos < stop) {
5721*103e46e4SHarish Mahendrakar     const long long element_start = pos;
5722*103e46e4SHarish Mahendrakar 
5723*103e46e4SHarish Mahendrakar     long long id, payload_size;
5724*103e46e4SHarish Mahendrakar 
5725*103e46e4SHarish Mahendrakar     const long status =
5726*103e46e4SHarish Mahendrakar         ParseElementHeader(pReader, pos, stop, id, payload_size);
5727*103e46e4SHarish Mahendrakar 
5728*103e46e4SHarish Mahendrakar     if (status < 0)  // error
5729*103e46e4SHarish Mahendrakar       return status;
5730*103e46e4SHarish Mahendrakar 
5731*103e46e4SHarish Mahendrakar     if (payload_size == 0)  // weird
5732*103e46e4SHarish Mahendrakar       continue;
5733*103e46e4SHarish Mahendrakar 
5734*103e46e4SHarish Mahendrakar     const long long payload_stop = pos + payload_size;
5735*103e46e4SHarish Mahendrakar     assert(payload_stop <= stop);  // checked in ParseElement
5736*103e46e4SHarish Mahendrakar 
5737*103e46e4SHarish Mahendrakar     const long long element_size = payload_stop - element_start;
5738*103e46e4SHarish Mahendrakar 
5739*103e46e4SHarish Mahendrakar     if (id == libwebm::kMkvTrackEntry) {
5740*103e46e4SHarish Mahendrakar       Track*& pTrack = *m_trackEntriesEnd;
5741*103e46e4SHarish Mahendrakar       pTrack = NULL;
5742*103e46e4SHarish Mahendrakar 
5743*103e46e4SHarish Mahendrakar       const long status = ParseTrackEntry(pos, payload_size, element_start,
5744*103e46e4SHarish Mahendrakar                                           element_size, pTrack);
5745*103e46e4SHarish Mahendrakar       if (status)
5746*103e46e4SHarish Mahendrakar         return status;
5747*103e46e4SHarish Mahendrakar 
5748*103e46e4SHarish Mahendrakar       if (pTrack)
5749*103e46e4SHarish Mahendrakar         ++m_trackEntriesEnd;
5750*103e46e4SHarish Mahendrakar     }
5751*103e46e4SHarish Mahendrakar 
5752*103e46e4SHarish Mahendrakar     pos = payload_stop;
5753*103e46e4SHarish Mahendrakar     if (pos > stop)
5754*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
5755*103e46e4SHarish Mahendrakar   }
5756*103e46e4SHarish Mahendrakar 
5757*103e46e4SHarish Mahendrakar   if (pos != stop)
5758*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
5759*103e46e4SHarish Mahendrakar 
5760*103e46e4SHarish Mahendrakar   return 0;  // success
5761*103e46e4SHarish Mahendrakar }
5762*103e46e4SHarish Mahendrakar 
GetTracksCount() const5763*103e46e4SHarish Mahendrakar unsigned long Tracks::GetTracksCount() const {
5764*103e46e4SHarish Mahendrakar   const ptrdiff_t result = m_trackEntriesEnd - m_trackEntries;
5765*103e46e4SHarish Mahendrakar   assert(result >= 0);
5766*103e46e4SHarish Mahendrakar 
5767*103e46e4SHarish Mahendrakar   return static_cast<unsigned long>(result);
5768*103e46e4SHarish Mahendrakar }
5769*103e46e4SHarish Mahendrakar 
ParseTrackEntry(long long track_start,long long track_size,long long element_start,long long element_size,Track * & pResult) const5770*103e46e4SHarish Mahendrakar long Tracks::ParseTrackEntry(long long track_start, long long track_size,
5771*103e46e4SHarish Mahendrakar                              long long element_start, long long element_size,
5772*103e46e4SHarish Mahendrakar                              Track*& pResult) const {
5773*103e46e4SHarish Mahendrakar   if (pResult)
5774*103e46e4SHarish Mahendrakar     return -1;
5775*103e46e4SHarish Mahendrakar 
5776*103e46e4SHarish Mahendrakar   IMkvReader* const pReader = m_pSegment->m_pReader;
5777*103e46e4SHarish Mahendrakar 
5778*103e46e4SHarish Mahendrakar   long long pos = track_start;
5779*103e46e4SHarish Mahendrakar   const long long track_stop = track_start + track_size;
5780*103e46e4SHarish Mahendrakar 
5781*103e46e4SHarish Mahendrakar   Track::Info info;
5782*103e46e4SHarish Mahendrakar 
5783*103e46e4SHarish Mahendrakar   info.type = 0;
5784*103e46e4SHarish Mahendrakar   info.number = 0;
5785*103e46e4SHarish Mahendrakar   info.uid = 0;
5786*103e46e4SHarish Mahendrakar   info.defaultDuration = 0;
5787*103e46e4SHarish Mahendrakar 
5788*103e46e4SHarish Mahendrakar   Track::Settings v;
5789*103e46e4SHarish Mahendrakar   v.start = -1;
5790*103e46e4SHarish Mahendrakar   v.size = -1;
5791*103e46e4SHarish Mahendrakar 
5792*103e46e4SHarish Mahendrakar   Track::Settings a;
5793*103e46e4SHarish Mahendrakar   a.start = -1;
5794*103e46e4SHarish Mahendrakar   a.size = -1;
5795*103e46e4SHarish Mahendrakar 
5796*103e46e4SHarish Mahendrakar   Track::Settings e;  // content_encodings_settings;
5797*103e46e4SHarish Mahendrakar   e.start = -1;
5798*103e46e4SHarish Mahendrakar   e.size = -1;
5799*103e46e4SHarish Mahendrakar 
5800*103e46e4SHarish Mahendrakar   long long lacing = 1;  // default is true
5801*103e46e4SHarish Mahendrakar 
5802*103e46e4SHarish Mahendrakar   while (pos < track_stop) {
5803*103e46e4SHarish Mahendrakar     long long id, size;
5804*103e46e4SHarish Mahendrakar 
5805*103e46e4SHarish Mahendrakar     const long status = ParseElementHeader(pReader, pos, track_stop, id, size);
5806*103e46e4SHarish Mahendrakar 
5807*103e46e4SHarish Mahendrakar     if (status < 0)  // error
5808*103e46e4SHarish Mahendrakar       return status;
5809*103e46e4SHarish Mahendrakar 
5810*103e46e4SHarish Mahendrakar     if (size < 0)
5811*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
5812*103e46e4SHarish Mahendrakar 
5813*103e46e4SHarish Mahendrakar     const long long start = pos;
5814*103e46e4SHarish Mahendrakar 
5815*103e46e4SHarish Mahendrakar     if (id == libwebm::kMkvVideo) {
5816*103e46e4SHarish Mahendrakar       v.start = start;
5817*103e46e4SHarish Mahendrakar       v.size = size;
5818*103e46e4SHarish Mahendrakar     } else if (id == libwebm::kMkvAudio) {
5819*103e46e4SHarish Mahendrakar       a.start = start;
5820*103e46e4SHarish Mahendrakar       a.size = size;
5821*103e46e4SHarish Mahendrakar     } else if (id == libwebm::kMkvContentEncodings) {
5822*103e46e4SHarish Mahendrakar       e.start = start;
5823*103e46e4SHarish Mahendrakar       e.size = size;
5824*103e46e4SHarish Mahendrakar     } else if (id == libwebm::kMkvTrackUID) {
5825*103e46e4SHarish Mahendrakar       if (size > 8)
5826*103e46e4SHarish Mahendrakar         return E_FILE_FORMAT_INVALID;
5827*103e46e4SHarish Mahendrakar 
5828*103e46e4SHarish Mahendrakar       info.uid = 0;
5829*103e46e4SHarish Mahendrakar 
5830*103e46e4SHarish Mahendrakar       long long pos_ = start;
5831*103e46e4SHarish Mahendrakar       const long long pos_end = start + size;
5832*103e46e4SHarish Mahendrakar 
5833*103e46e4SHarish Mahendrakar       while (pos_ != pos_end) {
5834*103e46e4SHarish Mahendrakar         unsigned char b;
5835*103e46e4SHarish Mahendrakar 
5836*103e46e4SHarish Mahendrakar         const int status = pReader->Read(pos_, 1, &b);
5837*103e46e4SHarish Mahendrakar 
5838*103e46e4SHarish Mahendrakar         if (status)
5839*103e46e4SHarish Mahendrakar           return status;
5840*103e46e4SHarish Mahendrakar 
5841*103e46e4SHarish Mahendrakar         info.uid <<= 8;
5842*103e46e4SHarish Mahendrakar         info.uid |= b;
5843*103e46e4SHarish Mahendrakar 
5844*103e46e4SHarish Mahendrakar         ++pos_;
5845*103e46e4SHarish Mahendrakar       }
5846*103e46e4SHarish Mahendrakar     } else if (id == libwebm::kMkvTrackNumber) {
5847*103e46e4SHarish Mahendrakar       const long long num = UnserializeUInt(pReader, pos, size);
5848*103e46e4SHarish Mahendrakar 
5849*103e46e4SHarish Mahendrakar       if ((num <= 0) || (num > 127))
5850*103e46e4SHarish Mahendrakar         return E_FILE_FORMAT_INVALID;
5851*103e46e4SHarish Mahendrakar 
5852*103e46e4SHarish Mahendrakar       info.number = static_cast<long>(num);
5853*103e46e4SHarish Mahendrakar     } else if (id == libwebm::kMkvTrackType) {
5854*103e46e4SHarish Mahendrakar       const long long type = UnserializeUInt(pReader, pos, size);
5855*103e46e4SHarish Mahendrakar 
5856*103e46e4SHarish Mahendrakar       if ((type <= 0) || (type > 254))
5857*103e46e4SHarish Mahendrakar         return E_FILE_FORMAT_INVALID;
5858*103e46e4SHarish Mahendrakar 
5859*103e46e4SHarish Mahendrakar       info.type = static_cast<long>(type);
5860*103e46e4SHarish Mahendrakar     } else if (id == libwebm::kMkvName) {
5861*103e46e4SHarish Mahendrakar       const long status =
5862*103e46e4SHarish Mahendrakar           UnserializeString(pReader, pos, size, info.nameAsUTF8);
5863*103e46e4SHarish Mahendrakar 
5864*103e46e4SHarish Mahendrakar       if (status)
5865*103e46e4SHarish Mahendrakar         return status;
5866*103e46e4SHarish Mahendrakar     } else if (id == libwebm::kMkvLanguage) {
5867*103e46e4SHarish Mahendrakar       const long status = UnserializeString(pReader, pos, size, info.language);
5868*103e46e4SHarish Mahendrakar 
5869*103e46e4SHarish Mahendrakar       if (status)
5870*103e46e4SHarish Mahendrakar         return status;
5871*103e46e4SHarish Mahendrakar     } else if (id == libwebm::kMkvDefaultDuration) {
5872*103e46e4SHarish Mahendrakar       const long long duration = UnserializeUInt(pReader, pos, size);
5873*103e46e4SHarish Mahendrakar 
5874*103e46e4SHarish Mahendrakar       if (duration < 0)
5875*103e46e4SHarish Mahendrakar         return E_FILE_FORMAT_INVALID;
5876*103e46e4SHarish Mahendrakar 
5877*103e46e4SHarish Mahendrakar       info.defaultDuration = static_cast<unsigned long long>(duration);
5878*103e46e4SHarish Mahendrakar     } else if (id == libwebm::kMkvCodecID) {
5879*103e46e4SHarish Mahendrakar       const long status = UnserializeString(pReader, pos, size, info.codecId);
5880*103e46e4SHarish Mahendrakar 
5881*103e46e4SHarish Mahendrakar       if (status)
5882*103e46e4SHarish Mahendrakar         return status;
5883*103e46e4SHarish Mahendrakar     } else if (id == libwebm::kMkvFlagLacing) {
5884*103e46e4SHarish Mahendrakar       lacing = UnserializeUInt(pReader, pos, size);
5885*103e46e4SHarish Mahendrakar 
5886*103e46e4SHarish Mahendrakar       if ((lacing < 0) || (lacing > 1))
5887*103e46e4SHarish Mahendrakar         return E_FILE_FORMAT_INVALID;
5888*103e46e4SHarish Mahendrakar     } else if (id == libwebm::kMkvCodecPrivate) {
5889*103e46e4SHarish Mahendrakar       delete[] info.codecPrivate;
5890*103e46e4SHarish Mahendrakar       info.codecPrivate = NULL;
5891*103e46e4SHarish Mahendrakar       info.codecPrivateSize = 0;
5892*103e46e4SHarish Mahendrakar 
5893*103e46e4SHarish Mahendrakar       const size_t buflen = static_cast<size_t>(size);
5894*103e46e4SHarish Mahendrakar 
5895*103e46e4SHarish Mahendrakar       if (buflen) {
5896*103e46e4SHarish Mahendrakar         unsigned char* buf = SafeArrayAlloc<unsigned char>(1, buflen);
5897*103e46e4SHarish Mahendrakar 
5898*103e46e4SHarish Mahendrakar         if (buf == NULL)
5899*103e46e4SHarish Mahendrakar           return -1;
5900*103e46e4SHarish Mahendrakar 
5901*103e46e4SHarish Mahendrakar         const int status = pReader->Read(pos, static_cast<long>(buflen), buf);
5902*103e46e4SHarish Mahendrakar 
5903*103e46e4SHarish Mahendrakar         if (status) {
5904*103e46e4SHarish Mahendrakar           delete[] buf;
5905*103e46e4SHarish Mahendrakar           return status;
5906*103e46e4SHarish Mahendrakar         }
5907*103e46e4SHarish Mahendrakar 
5908*103e46e4SHarish Mahendrakar         info.codecPrivate = buf;
5909*103e46e4SHarish Mahendrakar         info.codecPrivateSize = buflen;
5910*103e46e4SHarish Mahendrakar       }
5911*103e46e4SHarish Mahendrakar     } else if (id == libwebm::kMkvCodecName) {
5912*103e46e4SHarish Mahendrakar       const long status =
5913*103e46e4SHarish Mahendrakar           UnserializeString(pReader, pos, size, info.codecNameAsUTF8);
5914*103e46e4SHarish Mahendrakar 
5915*103e46e4SHarish Mahendrakar       if (status)
5916*103e46e4SHarish Mahendrakar         return status;
5917*103e46e4SHarish Mahendrakar     } else if (id == libwebm::kMkvCodecDelay) {
5918*103e46e4SHarish Mahendrakar       info.codecDelay = UnserializeUInt(pReader, pos, size);
5919*103e46e4SHarish Mahendrakar     } else if (id == libwebm::kMkvSeekPreRoll) {
5920*103e46e4SHarish Mahendrakar       info.seekPreRoll = UnserializeUInt(pReader, pos, size);
5921*103e46e4SHarish Mahendrakar     }
5922*103e46e4SHarish Mahendrakar 
5923*103e46e4SHarish Mahendrakar     pos += size;  // consume payload
5924*103e46e4SHarish Mahendrakar     if (pos > track_stop)
5925*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
5926*103e46e4SHarish Mahendrakar   }
5927*103e46e4SHarish Mahendrakar 
5928*103e46e4SHarish Mahendrakar   if (pos != track_stop)
5929*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
5930*103e46e4SHarish Mahendrakar 
5931*103e46e4SHarish Mahendrakar   if (info.number <= 0)  // not specified
5932*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
5933*103e46e4SHarish Mahendrakar 
5934*103e46e4SHarish Mahendrakar   if (GetTrackByNumber(info.number))
5935*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
5936*103e46e4SHarish Mahendrakar 
5937*103e46e4SHarish Mahendrakar   if (info.type <= 0)  // not specified
5938*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
5939*103e46e4SHarish Mahendrakar 
5940*103e46e4SHarish Mahendrakar   info.lacing = (lacing > 0) ? true : false;
5941*103e46e4SHarish Mahendrakar 
5942*103e46e4SHarish Mahendrakar   if (info.type == Track::kVideo) {
5943*103e46e4SHarish Mahendrakar     if (v.start < 0)
5944*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
5945*103e46e4SHarish Mahendrakar 
5946*103e46e4SHarish Mahendrakar     if (a.start >= 0)
5947*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
5948*103e46e4SHarish Mahendrakar 
5949*103e46e4SHarish Mahendrakar     info.settings = v;
5950*103e46e4SHarish Mahendrakar 
5951*103e46e4SHarish Mahendrakar     VideoTrack* pTrack = NULL;
5952*103e46e4SHarish Mahendrakar 
5953*103e46e4SHarish Mahendrakar     const long status = VideoTrack::Parse(m_pSegment, info, element_start,
5954*103e46e4SHarish Mahendrakar                                           element_size, pTrack);
5955*103e46e4SHarish Mahendrakar 
5956*103e46e4SHarish Mahendrakar     if (status)
5957*103e46e4SHarish Mahendrakar       return status;
5958*103e46e4SHarish Mahendrakar 
5959*103e46e4SHarish Mahendrakar     pResult = pTrack;
5960*103e46e4SHarish Mahendrakar     assert(pResult);
5961*103e46e4SHarish Mahendrakar 
5962*103e46e4SHarish Mahendrakar     if (e.start >= 0)
5963*103e46e4SHarish Mahendrakar       pResult->ParseContentEncodingsEntry(e.start, e.size);
5964*103e46e4SHarish Mahendrakar   } else if (info.type == Track::kAudio) {
5965*103e46e4SHarish Mahendrakar     if (a.start < 0)
5966*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
5967*103e46e4SHarish Mahendrakar 
5968*103e46e4SHarish Mahendrakar     if (v.start >= 0)
5969*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
5970*103e46e4SHarish Mahendrakar 
5971*103e46e4SHarish Mahendrakar     info.settings = a;
5972*103e46e4SHarish Mahendrakar 
5973*103e46e4SHarish Mahendrakar     AudioTrack* pTrack = NULL;
5974*103e46e4SHarish Mahendrakar 
5975*103e46e4SHarish Mahendrakar     const long status = AudioTrack::Parse(m_pSegment, info, element_start,
5976*103e46e4SHarish Mahendrakar                                           element_size, pTrack);
5977*103e46e4SHarish Mahendrakar 
5978*103e46e4SHarish Mahendrakar     if (status)
5979*103e46e4SHarish Mahendrakar       return status;
5980*103e46e4SHarish Mahendrakar 
5981*103e46e4SHarish Mahendrakar     pResult = pTrack;
5982*103e46e4SHarish Mahendrakar     assert(pResult);
5983*103e46e4SHarish Mahendrakar 
5984*103e46e4SHarish Mahendrakar     if (e.start >= 0)
5985*103e46e4SHarish Mahendrakar       pResult->ParseContentEncodingsEntry(e.start, e.size);
5986*103e46e4SHarish Mahendrakar   } else {
5987*103e46e4SHarish Mahendrakar     // neither video nor audio - probably metadata or subtitles
5988*103e46e4SHarish Mahendrakar 
5989*103e46e4SHarish Mahendrakar     if (a.start >= 0)
5990*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
5991*103e46e4SHarish Mahendrakar 
5992*103e46e4SHarish Mahendrakar     if (v.start >= 0)
5993*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
5994*103e46e4SHarish Mahendrakar 
5995*103e46e4SHarish Mahendrakar     if (info.type == Track::kMetadata && e.start >= 0)
5996*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
5997*103e46e4SHarish Mahendrakar 
5998*103e46e4SHarish Mahendrakar     info.settings.start = -1;
5999*103e46e4SHarish Mahendrakar     info.settings.size = 0;
6000*103e46e4SHarish Mahendrakar 
6001*103e46e4SHarish Mahendrakar     Track* pTrack = NULL;
6002*103e46e4SHarish Mahendrakar 
6003*103e46e4SHarish Mahendrakar     const long status =
6004*103e46e4SHarish Mahendrakar         Track::Create(m_pSegment, info, element_start, element_size, pTrack);
6005*103e46e4SHarish Mahendrakar 
6006*103e46e4SHarish Mahendrakar     if (status)
6007*103e46e4SHarish Mahendrakar       return status;
6008*103e46e4SHarish Mahendrakar 
6009*103e46e4SHarish Mahendrakar     pResult = pTrack;
6010*103e46e4SHarish Mahendrakar     assert(pResult);
6011*103e46e4SHarish Mahendrakar   }
6012*103e46e4SHarish Mahendrakar 
6013*103e46e4SHarish Mahendrakar   return 0;  // success
6014*103e46e4SHarish Mahendrakar }
6015*103e46e4SHarish Mahendrakar 
~Tracks()6016*103e46e4SHarish Mahendrakar Tracks::~Tracks() {
6017*103e46e4SHarish Mahendrakar   Track** i = m_trackEntries;
6018*103e46e4SHarish Mahendrakar   Track** const j = m_trackEntriesEnd;
6019*103e46e4SHarish Mahendrakar 
6020*103e46e4SHarish Mahendrakar   while (i != j) {
6021*103e46e4SHarish Mahendrakar     Track* const pTrack = *i++;
6022*103e46e4SHarish Mahendrakar     delete pTrack;
6023*103e46e4SHarish Mahendrakar   }
6024*103e46e4SHarish Mahendrakar 
6025*103e46e4SHarish Mahendrakar   delete[] m_trackEntries;
6026*103e46e4SHarish Mahendrakar }
6027*103e46e4SHarish Mahendrakar 
GetTrackByNumber(long tn) const6028*103e46e4SHarish Mahendrakar const Track* Tracks::GetTrackByNumber(long tn) const {
6029*103e46e4SHarish Mahendrakar   if (tn < 0)
6030*103e46e4SHarish Mahendrakar     return NULL;
6031*103e46e4SHarish Mahendrakar 
6032*103e46e4SHarish Mahendrakar   Track** i = m_trackEntries;
6033*103e46e4SHarish Mahendrakar   Track** const j = m_trackEntriesEnd;
6034*103e46e4SHarish Mahendrakar 
6035*103e46e4SHarish Mahendrakar   while (i != j) {
6036*103e46e4SHarish Mahendrakar     Track* const pTrack = *i++;
6037*103e46e4SHarish Mahendrakar 
6038*103e46e4SHarish Mahendrakar     if (pTrack == NULL)
6039*103e46e4SHarish Mahendrakar       continue;
6040*103e46e4SHarish Mahendrakar 
6041*103e46e4SHarish Mahendrakar     if (tn == pTrack->GetNumber())
6042*103e46e4SHarish Mahendrakar       return pTrack;
6043*103e46e4SHarish Mahendrakar   }
6044*103e46e4SHarish Mahendrakar 
6045*103e46e4SHarish Mahendrakar   return NULL;  // not found
6046*103e46e4SHarish Mahendrakar }
6047*103e46e4SHarish Mahendrakar 
GetTrackByIndex(unsigned long idx) const6048*103e46e4SHarish Mahendrakar const Track* Tracks::GetTrackByIndex(unsigned long idx) const {
6049*103e46e4SHarish Mahendrakar   const ptrdiff_t count = m_trackEntriesEnd - m_trackEntries;
6050*103e46e4SHarish Mahendrakar 
6051*103e46e4SHarish Mahendrakar   if (idx >= static_cast<unsigned long>(count))
6052*103e46e4SHarish Mahendrakar     return NULL;
6053*103e46e4SHarish Mahendrakar 
6054*103e46e4SHarish Mahendrakar   return m_trackEntries[idx];
6055*103e46e4SHarish Mahendrakar }
6056*103e46e4SHarish Mahendrakar 
Load(long long & pos,long & len) const6057*103e46e4SHarish Mahendrakar long Cluster::Load(long long& pos, long& len) const {
6058*103e46e4SHarish Mahendrakar   if (m_pSegment == NULL)
6059*103e46e4SHarish Mahendrakar     return E_PARSE_FAILED;
6060*103e46e4SHarish Mahendrakar 
6061*103e46e4SHarish Mahendrakar   if (m_timecode >= 0)  // at least partially loaded
6062*103e46e4SHarish Mahendrakar     return 0;
6063*103e46e4SHarish Mahendrakar 
6064*103e46e4SHarish Mahendrakar   if (m_pos != m_element_start || m_element_size >= 0)
6065*103e46e4SHarish Mahendrakar     return E_PARSE_FAILED;
6066*103e46e4SHarish Mahendrakar 
6067*103e46e4SHarish Mahendrakar   IMkvReader* const pReader = m_pSegment->m_pReader;
6068*103e46e4SHarish Mahendrakar   long long total, avail;
6069*103e46e4SHarish Mahendrakar   const int status = pReader->Length(&total, &avail);
6070*103e46e4SHarish Mahendrakar 
6071*103e46e4SHarish Mahendrakar   if (status < 0)  // error
6072*103e46e4SHarish Mahendrakar     return status;
6073*103e46e4SHarish Mahendrakar 
6074*103e46e4SHarish Mahendrakar   if (total >= 0 && (avail > total || m_pos > total))
6075*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
6076*103e46e4SHarish Mahendrakar 
6077*103e46e4SHarish Mahendrakar   pos = m_pos;
6078*103e46e4SHarish Mahendrakar 
6079*103e46e4SHarish Mahendrakar   long long cluster_size = -1;
6080*103e46e4SHarish Mahendrakar 
6081*103e46e4SHarish Mahendrakar   if ((pos + 1) > avail) {
6082*103e46e4SHarish Mahendrakar     len = 1;
6083*103e46e4SHarish Mahendrakar     return E_BUFFER_NOT_FULL;
6084*103e46e4SHarish Mahendrakar   }
6085*103e46e4SHarish Mahendrakar 
6086*103e46e4SHarish Mahendrakar   long long result = GetUIntLength(pReader, pos, len);
6087*103e46e4SHarish Mahendrakar 
6088*103e46e4SHarish Mahendrakar   if (result < 0)  // error or underflow
6089*103e46e4SHarish Mahendrakar     return static_cast<long>(result);
6090*103e46e4SHarish Mahendrakar 
6091*103e46e4SHarish Mahendrakar   if (result > 0)
6092*103e46e4SHarish Mahendrakar     return E_BUFFER_NOT_FULL;
6093*103e46e4SHarish Mahendrakar 
6094*103e46e4SHarish Mahendrakar   if ((pos + len) > avail)
6095*103e46e4SHarish Mahendrakar     return E_BUFFER_NOT_FULL;
6096*103e46e4SHarish Mahendrakar 
6097*103e46e4SHarish Mahendrakar   const long long id_ = ReadID(pReader, pos, len);
6098*103e46e4SHarish Mahendrakar 
6099*103e46e4SHarish Mahendrakar   if (id_ < 0)  // error
6100*103e46e4SHarish Mahendrakar     return static_cast<long>(id_);
6101*103e46e4SHarish Mahendrakar 
6102*103e46e4SHarish Mahendrakar   if (id_ != libwebm::kMkvCluster)
6103*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
6104*103e46e4SHarish Mahendrakar 
6105*103e46e4SHarish Mahendrakar   pos += len;  // consume id
6106*103e46e4SHarish Mahendrakar 
6107*103e46e4SHarish Mahendrakar   // read cluster size
6108*103e46e4SHarish Mahendrakar 
6109*103e46e4SHarish Mahendrakar   if ((pos + 1) > avail) {
6110*103e46e4SHarish Mahendrakar     len = 1;
6111*103e46e4SHarish Mahendrakar     return E_BUFFER_NOT_FULL;
6112*103e46e4SHarish Mahendrakar   }
6113*103e46e4SHarish Mahendrakar 
6114*103e46e4SHarish Mahendrakar   result = GetUIntLength(pReader, pos, len);
6115*103e46e4SHarish Mahendrakar 
6116*103e46e4SHarish Mahendrakar   if (result < 0)  // error
6117*103e46e4SHarish Mahendrakar     return static_cast<long>(result);
6118*103e46e4SHarish Mahendrakar 
6119*103e46e4SHarish Mahendrakar   if (result > 0)
6120*103e46e4SHarish Mahendrakar     return E_BUFFER_NOT_FULL;
6121*103e46e4SHarish Mahendrakar 
6122*103e46e4SHarish Mahendrakar   if ((pos + len) > avail)
6123*103e46e4SHarish Mahendrakar     return E_BUFFER_NOT_FULL;
6124*103e46e4SHarish Mahendrakar 
6125*103e46e4SHarish Mahendrakar   const long long size = ReadUInt(pReader, pos, len);
6126*103e46e4SHarish Mahendrakar 
6127*103e46e4SHarish Mahendrakar   if (size < 0)  // error
6128*103e46e4SHarish Mahendrakar     return static_cast<long>(cluster_size);
6129*103e46e4SHarish Mahendrakar 
6130*103e46e4SHarish Mahendrakar   if (size == 0)
6131*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
6132*103e46e4SHarish Mahendrakar 
6133*103e46e4SHarish Mahendrakar   pos += len;  // consume length of size of element
6134*103e46e4SHarish Mahendrakar 
6135*103e46e4SHarish Mahendrakar   const long long unknown_size = (1LL << (7 * len)) - 1;
6136*103e46e4SHarish Mahendrakar 
6137*103e46e4SHarish Mahendrakar   if (size != unknown_size)
6138*103e46e4SHarish Mahendrakar     cluster_size = size;
6139*103e46e4SHarish Mahendrakar 
6140*103e46e4SHarish Mahendrakar   // pos points to start of payload
6141*103e46e4SHarish Mahendrakar   long long timecode = -1;
6142*103e46e4SHarish Mahendrakar   long long new_pos = -1;
6143*103e46e4SHarish Mahendrakar   bool bBlock = false;
6144*103e46e4SHarish Mahendrakar 
6145*103e46e4SHarish Mahendrakar   long long cluster_stop = (cluster_size < 0) ? -1 : pos + cluster_size;
6146*103e46e4SHarish Mahendrakar 
6147*103e46e4SHarish Mahendrakar   for (;;) {
6148*103e46e4SHarish Mahendrakar     if ((cluster_stop >= 0) && (pos >= cluster_stop))
6149*103e46e4SHarish Mahendrakar       break;
6150*103e46e4SHarish Mahendrakar 
6151*103e46e4SHarish Mahendrakar     // Parse ID
6152*103e46e4SHarish Mahendrakar 
6153*103e46e4SHarish Mahendrakar     if ((pos + 1) > avail) {
6154*103e46e4SHarish Mahendrakar       len = 1;
6155*103e46e4SHarish Mahendrakar       return E_BUFFER_NOT_FULL;
6156*103e46e4SHarish Mahendrakar     }
6157*103e46e4SHarish Mahendrakar 
6158*103e46e4SHarish Mahendrakar     long long result = GetUIntLength(pReader, pos, len);
6159*103e46e4SHarish Mahendrakar 
6160*103e46e4SHarish Mahendrakar     if (result < 0)  // error
6161*103e46e4SHarish Mahendrakar       return static_cast<long>(result);
6162*103e46e4SHarish Mahendrakar 
6163*103e46e4SHarish Mahendrakar     if (result > 0)
6164*103e46e4SHarish Mahendrakar       return E_BUFFER_NOT_FULL;
6165*103e46e4SHarish Mahendrakar 
6166*103e46e4SHarish Mahendrakar     if ((cluster_stop >= 0) && ((pos + len) > cluster_stop))
6167*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
6168*103e46e4SHarish Mahendrakar 
6169*103e46e4SHarish Mahendrakar     if ((pos + len) > avail)
6170*103e46e4SHarish Mahendrakar       return E_BUFFER_NOT_FULL;
6171*103e46e4SHarish Mahendrakar 
6172*103e46e4SHarish Mahendrakar     const long long id = ReadID(pReader, pos, len);
6173*103e46e4SHarish Mahendrakar 
6174*103e46e4SHarish Mahendrakar     if (id < 0)  // error
6175*103e46e4SHarish Mahendrakar       return static_cast<long>(id);
6176*103e46e4SHarish Mahendrakar 
6177*103e46e4SHarish Mahendrakar     if (id == 0)
6178*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
6179*103e46e4SHarish Mahendrakar 
6180*103e46e4SHarish Mahendrakar     // This is the distinguished set of ID's we use to determine
6181*103e46e4SHarish Mahendrakar     // that we have exhausted the sub-element's inside the cluster
6182*103e46e4SHarish Mahendrakar     // whose ID we parsed earlier.
6183*103e46e4SHarish Mahendrakar 
6184*103e46e4SHarish Mahendrakar     if (id == libwebm::kMkvCluster)
6185*103e46e4SHarish Mahendrakar       break;
6186*103e46e4SHarish Mahendrakar 
6187*103e46e4SHarish Mahendrakar     if (id == libwebm::kMkvCues)
6188*103e46e4SHarish Mahendrakar       break;
6189*103e46e4SHarish Mahendrakar 
6190*103e46e4SHarish Mahendrakar     pos += len;  // consume ID field
6191*103e46e4SHarish Mahendrakar 
6192*103e46e4SHarish Mahendrakar     // Parse Size
6193*103e46e4SHarish Mahendrakar 
6194*103e46e4SHarish Mahendrakar     if ((pos + 1) > avail) {
6195*103e46e4SHarish Mahendrakar       len = 1;
6196*103e46e4SHarish Mahendrakar       return E_BUFFER_NOT_FULL;
6197*103e46e4SHarish Mahendrakar     }
6198*103e46e4SHarish Mahendrakar 
6199*103e46e4SHarish Mahendrakar     result = GetUIntLength(pReader, pos, len);
6200*103e46e4SHarish Mahendrakar 
6201*103e46e4SHarish Mahendrakar     if (result < 0)  // error
6202*103e46e4SHarish Mahendrakar       return static_cast<long>(result);
6203*103e46e4SHarish Mahendrakar 
6204*103e46e4SHarish Mahendrakar     if (result > 0)
6205*103e46e4SHarish Mahendrakar       return E_BUFFER_NOT_FULL;
6206*103e46e4SHarish Mahendrakar 
6207*103e46e4SHarish Mahendrakar     if ((cluster_stop >= 0) && ((pos + len) > cluster_stop))
6208*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
6209*103e46e4SHarish Mahendrakar 
6210*103e46e4SHarish Mahendrakar     if ((pos + len) > avail)
6211*103e46e4SHarish Mahendrakar       return E_BUFFER_NOT_FULL;
6212*103e46e4SHarish Mahendrakar 
6213*103e46e4SHarish Mahendrakar     const long long size = ReadUInt(pReader, pos, len);
6214*103e46e4SHarish Mahendrakar 
6215*103e46e4SHarish Mahendrakar     if (size < 0)  // error
6216*103e46e4SHarish Mahendrakar       return static_cast<long>(size);
6217*103e46e4SHarish Mahendrakar 
6218*103e46e4SHarish Mahendrakar     const long long unknown_size = (1LL << (7 * len)) - 1;
6219*103e46e4SHarish Mahendrakar 
6220*103e46e4SHarish Mahendrakar     if (size == unknown_size)
6221*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
6222*103e46e4SHarish Mahendrakar 
6223*103e46e4SHarish Mahendrakar     pos += len;  // consume size field
6224*103e46e4SHarish Mahendrakar 
6225*103e46e4SHarish Mahendrakar     if ((cluster_stop >= 0) && (pos > cluster_stop))
6226*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
6227*103e46e4SHarish Mahendrakar 
6228*103e46e4SHarish Mahendrakar     // pos now points to start of payload
6229*103e46e4SHarish Mahendrakar 
6230*103e46e4SHarish Mahendrakar     if (size == 0)
6231*103e46e4SHarish Mahendrakar       continue;
6232*103e46e4SHarish Mahendrakar 
6233*103e46e4SHarish Mahendrakar     if ((cluster_stop >= 0) && ((pos + size) > cluster_stop))
6234*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
6235*103e46e4SHarish Mahendrakar 
6236*103e46e4SHarish Mahendrakar     if (id == libwebm::kMkvTimecode) {
6237*103e46e4SHarish Mahendrakar       len = static_cast<long>(size);
6238*103e46e4SHarish Mahendrakar 
6239*103e46e4SHarish Mahendrakar       if ((pos + size) > avail)
6240*103e46e4SHarish Mahendrakar         return E_BUFFER_NOT_FULL;
6241*103e46e4SHarish Mahendrakar 
6242*103e46e4SHarish Mahendrakar       timecode = UnserializeUInt(pReader, pos, size);
6243*103e46e4SHarish Mahendrakar 
6244*103e46e4SHarish Mahendrakar       if (timecode < 0)  // error (or underflow)
6245*103e46e4SHarish Mahendrakar         return static_cast<long>(timecode);
6246*103e46e4SHarish Mahendrakar 
6247*103e46e4SHarish Mahendrakar       new_pos = pos + size;
6248*103e46e4SHarish Mahendrakar 
6249*103e46e4SHarish Mahendrakar       if (bBlock)
6250*103e46e4SHarish Mahendrakar         break;
6251*103e46e4SHarish Mahendrakar     } else if (id == libwebm::kMkvBlockGroup) {
6252*103e46e4SHarish Mahendrakar       bBlock = true;
6253*103e46e4SHarish Mahendrakar       break;
6254*103e46e4SHarish Mahendrakar     } else if (id == libwebm::kMkvSimpleBlock) {
6255*103e46e4SHarish Mahendrakar       bBlock = true;
6256*103e46e4SHarish Mahendrakar       break;
6257*103e46e4SHarish Mahendrakar     }
6258*103e46e4SHarish Mahendrakar 
6259*103e46e4SHarish Mahendrakar     pos += size;  // consume payload
6260*103e46e4SHarish Mahendrakar     if (cluster_stop >= 0 && pos > cluster_stop)
6261*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
6262*103e46e4SHarish Mahendrakar   }
6263*103e46e4SHarish Mahendrakar 
6264*103e46e4SHarish Mahendrakar   if (cluster_stop >= 0 && pos > cluster_stop)
6265*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
6266*103e46e4SHarish Mahendrakar 
6267*103e46e4SHarish Mahendrakar   if (timecode < 0)  // no timecode found
6268*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
6269*103e46e4SHarish Mahendrakar 
6270*103e46e4SHarish Mahendrakar   if (!bBlock)
6271*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
6272*103e46e4SHarish Mahendrakar 
6273*103e46e4SHarish Mahendrakar   m_pos = new_pos;  // designates position just beyond timecode payload
6274*103e46e4SHarish Mahendrakar   m_timecode = timecode;  // m_timecode >= 0 means we're partially loaded
6275*103e46e4SHarish Mahendrakar 
6276*103e46e4SHarish Mahendrakar   if (cluster_size >= 0)
6277*103e46e4SHarish Mahendrakar     m_element_size = cluster_stop - m_element_start;
6278*103e46e4SHarish Mahendrakar 
6279*103e46e4SHarish Mahendrakar   return 0;
6280*103e46e4SHarish Mahendrakar }
6281*103e46e4SHarish Mahendrakar 
Parse(long long & pos,long & len) const6282*103e46e4SHarish Mahendrakar long Cluster::Parse(long long& pos, long& len) const {
6283*103e46e4SHarish Mahendrakar   long status = Load(pos, len);
6284*103e46e4SHarish Mahendrakar 
6285*103e46e4SHarish Mahendrakar   if (status < 0)
6286*103e46e4SHarish Mahendrakar     return status;
6287*103e46e4SHarish Mahendrakar 
6288*103e46e4SHarish Mahendrakar   if (m_pos < m_element_start || m_timecode < 0)
6289*103e46e4SHarish Mahendrakar     return E_PARSE_FAILED;
6290*103e46e4SHarish Mahendrakar 
6291*103e46e4SHarish Mahendrakar   const long long cluster_stop =
6292*103e46e4SHarish Mahendrakar       (m_element_size < 0) ? -1 : m_element_start + m_element_size;
6293*103e46e4SHarish Mahendrakar 
6294*103e46e4SHarish Mahendrakar   if ((cluster_stop >= 0) && (m_pos >= cluster_stop))
6295*103e46e4SHarish Mahendrakar     return 1;  // nothing else to do
6296*103e46e4SHarish Mahendrakar 
6297*103e46e4SHarish Mahendrakar   IMkvReader* const pReader = m_pSegment->m_pReader;
6298*103e46e4SHarish Mahendrakar 
6299*103e46e4SHarish Mahendrakar   long long total, avail;
6300*103e46e4SHarish Mahendrakar 
6301*103e46e4SHarish Mahendrakar   status = pReader->Length(&total, &avail);
6302*103e46e4SHarish Mahendrakar 
6303*103e46e4SHarish Mahendrakar   if (status < 0)  // error
6304*103e46e4SHarish Mahendrakar     return status;
6305*103e46e4SHarish Mahendrakar 
6306*103e46e4SHarish Mahendrakar   if (total >= 0 && avail > total)
6307*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
6308*103e46e4SHarish Mahendrakar 
6309*103e46e4SHarish Mahendrakar   pos = m_pos;
6310*103e46e4SHarish Mahendrakar 
6311*103e46e4SHarish Mahendrakar   for (;;) {
6312*103e46e4SHarish Mahendrakar     if ((cluster_stop >= 0) && (pos >= cluster_stop))
6313*103e46e4SHarish Mahendrakar       break;
6314*103e46e4SHarish Mahendrakar 
6315*103e46e4SHarish Mahendrakar     if ((total >= 0) && (pos >= total)) {
6316*103e46e4SHarish Mahendrakar       if (m_element_size < 0)
6317*103e46e4SHarish Mahendrakar         m_element_size = pos - m_element_start;
6318*103e46e4SHarish Mahendrakar 
6319*103e46e4SHarish Mahendrakar       break;
6320*103e46e4SHarish Mahendrakar     }
6321*103e46e4SHarish Mahendrakar 
6322*103e46e4SHarish Mahendrakar     // Parse ID
6323*103e46e4SHarish Mahendrakar 
6324*103e46e4SHarish Mahendrakar     if ((pos + 1) > avail) {
6325*103e46e4SHarish Mahendrakar       len = 1;
6326*103e46e4SHarish Mahendrakar       return E_BUFFER_NOT_FULL;
6327*103e46e4SHarish Mahendrakar     }
6328*103e46e4SHarish Mahendrakar 
6329*103e46e4SHarish Mahendrakar     long long result = GetUIntLength(pReader, pos, len);
6330*103e46e4SHarish Mahendrakar 
6331*103e46e4SHarish Mahendrakar     if (result < 0)  // error
6332*103e46e4SHarish Mahendrakar       return static_cast<long>(result);
6333*103e46e4SHarish Mahendrakar 
6334*103e46e4SHarish Mahendrakar     if (result > 0)
6335*103e46e4SHarish Mahendrakar       return E_BUFFER_NOT_FULL;
6336*103e46e4SHarish Mahendrakar 
6337*103e46e4SHarish Mahendrakar     if ((cluster_stop >= 0) && ((pos + len) > cluster_stop))
6338*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
6339*103e46e4SHarish Mahendrakar 
6340*103e46e4SHarish Mahendrakar     if ((pos + len) > avail)
6341*103e46e4SHarish Mahendrakar       return E_BUFFER_NOT_FULL;
6342*103e46e4SHarish Mahendrakar 
6343*103e46e4SHarish Mahendrakar     const long long id = ReadID(pReader, pos, len);
6344*103e46e4SHarish Mahendrakar 
6345*103e46e4SHarish Mahendrakar     if (id < 0)
6346*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
6347*103e46e4SHarish Mahendrakar 
6348*103e46e4SHarish Mahendrakar     // This is the distinguished set of ID's we use to determine
6349*103e46e4SHarish Mahendrakar     // that we have exhausted the sub-element's inside the cluster
6350*103e46e4SHarish Mahendrakar     // whose ID we parsed earlier.
6351*103e46e4SHarish Mahendrakar 
6352*103e46e4SHarish Mahendrakar     if ((id == libwebm::kMkvCluster) || (id == libwebm::kMkvCues)) {
6353*103e46e4SHarish Mahendrakar       if (m_element_size < 0)
6354*103e46e4SHarish Mahendrakar         m_element_size = pos - m_element_start;
6355*103e46e4SHarish Mahendrakar 
6356*103e46e4SHarish Mahendrakar       break;
6357*103e46e4SHarish Mahendrakar     }
6358*103e46e4SHarish Mahendrakar 
6359*103e46e4SHarish Mahendrakar     pos += len;  // consume ID field
6360*103e46e4SHarish Mahendrakar 
6361*103e46e4SHarish Mahendrakar     // Parse Size
6362*103e46e4SHarish Mahendrakar 
6363*103e46e4SHarish Mahendrakar     if ((pos + 1) > avail) {
6364*103e46e4SHarish Mahendrakar       len = 1;
6365*103e46e4SHarish Mahendrakar       return E_BUFFER_NOT_FULL;
6366*103e46e4SHarish Mahendrakar     }
6367*103e46e4SHarish Mahendrakar 
6368*103e46e4SHarish Mahendrakar     result = GetUIntLength(pReader, pos, len);
6369*103e46e4SHarish Mahendrakar 
6370*103e46e4SHarish Mahendrakar     if (result < 0)  // error
6371*103e46e4SHarish Mahendrakar       return static_cast<long>(result);
6372*103e46e4SHarish Mahendrakar 
6373*103e46e4SHarish Mahendrakar     if (result > 0)
6374*103e46e4SHarish Mahendrakar       return E_BUFFER_NOT_FULL;
6375*103e46e4SHarish Mahendrakar 
6376*103e46e4SHarish Mahendrakar     if ((cluster_stop >= 0) && ((pos + len) > cluster_stop))
6377*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
6378*103e46e4SHarish Mahendrakar 
6379*103e46e4SHarish Mahendrakar     if ((pos + len) > avail)
6380*103e46e4SHarish Mahendrakar       return E_BUFFER_NOT_FULL;
6381*103e46e4SHarish Mahendrakar 
6382*103e46e4SHarish Mahendrakar     const long long size = ReadUInt(pReader, pos, len);
6383*103e46e4SHarish Mahendrakar 
6384*103e46e4SHarish Mahendrakar     if (size < 0)  // error
6385*103e46e4SHarish Mahendrakar       return static_cast<long>(size);
6386*103e46e4SHarish Mahendrakar 
6387*103e46e4SHarish Mahendrakar     const long long unknown_size = (1LL << (7 * len)) - 1;
6388*103e46e4SHarish Mahendrakar 
6389*103e46e4SHarish Mahendrakar     if (size == unknown_size)
6390*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
6391*103e46e4SHarish Mahendrakar 
6392*103e46e4SHarish Mahendrakar     pos += len;  // consume size field
6393*103e46e4SHarish Mahendrakar 
6394*103e46e4SHarish Mahendrakar     if ((cluster_stop >= 0) && (pos > cluster_stop))
6395*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
6396*103e46e4SHarish Mahendrakar 
6397*103e46e4SHarish Mahendrakar     // pos now points to start of payload
6398*103e46e4SHarish Mahendrakar 
6399*103e46e4SHarish Mahendrakar     if (size == 0)
6400*103e46e4SHarish Mahendrakar       continue;
6401*103e46e4SHarish Mahendrakar 
6402*103e46e4SHarish Mahendrakar     // const long long block_start = pos;
6403*103e46e4SHarish Mahendrakar     const long long block_stop = pos + size;
6404*103e46e4SHarish Mahendrakar 
6405*103e46e4SHarish Mahendrakar     if (cluster_stop >= 0) {
6406*103e46e4SHarish Mahendrakar       if (block_stop > cluster_stop) {
6407*103e46e4SHarish Mahendrakar         if (id == libwebm::kMkvBlockGroup || id == libwebm::kMkvSimpleBlock) {
6408*103e46e4SHarish Mahendrakar           return E_FILE_FORMAT_INVALID;
6409*103e46e4SHarish Mahendrakar         }
6410*103e46e4SHarish Mahendrakar 
6411*103e46e4SHarish Mahendrakar         pos = cluster_stop;
6412*103e46e4SHarish Mahendrakar         break;
6413*103e46e4SHarish Mahendrakar       }
6414*103e46e4SHarish Mahendrakar     } else if ((total >= 0) && (block_stop > total)) {
6415*103e46e4SHarish Mahendrakar       m_element_size = total - m_element_start;
6416*103e46e4SHarish Mahendrakar       pos = total;
6417*103e46e4SHarish Mahendrakar       break;
6418*103e46e4SHarish Mahendrakar     } else if (block_stop > avail) {
6419*103e46e4SHarish Mahendrakar       len = static_cast<long>(size);
6420*103e46e4SHarish Mahendrakar       return E_BUFFER_NOT_FULL;
6421*103e46e4SHarish Mahendrakar     }
6422*103e46e4SHarish Mahendrakar 
6423*103e46e4SHarish Mahendrakar     Cluster* const this_ = const_cast<Cluster*>(this);
6424*103e46e4SHarish Mahendrakar 
6425*103e46e4SHarish Mahendrakar     if (id == libwebm::kMkvBlockGroup)
6426*103e46e4SHarish Mahendrakar       return this_->ParseBlockGroup(size, pos, len);
6427*103e46e4SHarish Mahendrakar 
6428*103e46e4SHarish Mahendrakar     if (id == libwebm::kMkvSimpleBlock)
6429*103e46e4SHarish Mahendrakar       return this_->ParseSimpleBlock(size, pos, len);
6430*103e46e4SHarish Mahendrakar 
6431*103e46e4SHarish Mahendrakar     pos += size;  // consume payload
6432*103e46e4SHarish Mahendrakar     if (cluster_stop >= 0 && pos > cluster_stop)
6433*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
6434*103e46e4SHarish Mahendrakar   }
6435*103e46e4SHarish Mahendrakar 
6436*103e46e4SHarish Mahendrakar   if (m_element_size < 1)
6437*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
6438*103e46e4SHarish Mahendrakar 
6439*103e46e4SHarish Mahendrakar   m_pos = pos;
6440*103e46e4SHarish Mahendrakar   if (cluster_stop >= 0 && m_pos > cluster_stop)
6441*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
6442*103e46e4SHarish Mahendrakar 
6443*103e46e4SHarish Mahendrakar   if (m_entries_count > 0) {
6444*103e46e4SHarish Mahendrakar     const long idx = m_entries_count - 1;
6445*103e46e4SHarish Mahendrakar 
6446*103e46e4SHarish Mahendrakar     const BlockEntry* const pLast = m_entries[idx];
6447*103e46e4SHarish Mahendrakar     if (pLast == NULL)
6448*103e46e4SHarish Mahendrakar       return E_PARSE_FAILED;
6449*103e46e4SHarish Mahendrakar 
6450*103e46e4SHarish Mahendrakar     const Block* const pBlock = pLast->GetBlock();
6451*103e46e4SHarish Mahendrakar     if (pBlock == NULL)
6452*103e46e4SHarish Mahendrakar       return E_PARSE_FAILED;
6453*103e46e4SHarish Mahendrakar 
6454*103e46e4SHarish Mahendrakar     const long long start = pBlock->m_start;
6455*103e46e4SHarish Mahendrakar 
6456*103e46e4SHarish Mahendrakar     if ((total >= 0) && (start > total))
6457*103e46e4SHarish Mahendrakar       return E_PARSE_FAILED;  // defend against trucated stream
6458*103e46e4SHarish Mahendrakar 
6459*103e46e4SHarish Mahendrakar     const long long size = pBlock->m_size;
6460*103e46e4SHarish Mahendrakar 
6461*103e46e4SHarish Mahendrakar     const long long stop = start + size;
6462*103e46e4SHarish Mahendrakar     if (cluster_stop >= 0 && stop > cluster_stop)
6463*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
6464*103e46e4SHarish Mahendrakar 
6465*103e46e4SHarish Mahendrakar     if ((total >= 0) && (stop > total))
6466*103e46e4SHarish Mahendrakar       return E_PARSE_FAILED;  // defend against trucated stream
6467*103e46e4SHarish Mahendrakar   }
6468*103e46e4SHarish Mahendrakar 
6469*103e46e4SHarish Mahendrakar   return 1;  // no more entries
6470*103e46e4SHarish Mahendrakar }
6471*103e46e4SHarish Mahendrakar 
ParseSimpleBlock(long long block_size,long long & pos,long & len)6472*103e46e4SHarish Mahendrakar long Cluster::ParseSimpleBlock(long long block_size, long long& pos,
6473*103e46e4SHarish Mahendrakar                                long& len) {
6474*103e46e4SHarish Mahendrakar   const long long block_start = pos;
6475*103e46e4SHarish Mahendrakar   const long long block_stop = pos + block_size;
6476*103e46e4SHarish Mahendrakar 
6477*103e46e4SHarish Mahendrakar   IMkvReader* const pReader = m_pSegment->m_pReader;
6478*103e46e4SHarish Mahendrakar 
6479*103e46e4SHarish Mahendrakar   long long total, avail;
6480*103e46e4SHarish Mahendrakar 
6481*103e46e4SHarish Mahendrakar   long status = pReader->Length(&total, &avail);
6482*103e46e4SHarish Mahendrakar 
6483*103e46e4SHarish Mahendrakar   if (status < 0)  // error
6484*103e46e4SHarish Mahendrakar     return status;
6485*103e46e4SHarish Mahendrakar 
6486*103e46e4SHarish Mahendrakar   assert((total < 0) || (avail <= total));
6487*103e46e4SHarish Mahendrakar 
6488*103e46e4SHarish Mahendrakar   // parse track number
6489*103e46e4SHarish Mahendrakar 
6490*103e46e4SHarish Mahendrakar   if ((pos + 1) > avail) {
6491*103e46e4SHarish Mahendrakar     len = 1;
6492*103e46e4SHarish Mahendrakar     return E_BUFFER_NOT_FULL;
6493*103e46e4SHarish Mahendrakar   }
6494*103e46e4SHarish Mahendrakar 
6495*103e46e4SHarish Mahendrakar   long long result = GetUIntLength(pReader, pos, len);
6496*103e46e4SHarish Mahendrakar 
6497*103e46e4SHarish Mahendrakar   if (result < 0)  // error
6498*103e46e4SHarish Mahendrakar     return static_cast<long>(result);
6499*103e46e4SHarish Mahendrakar 
6500*103e46e4SHarish Mahendrakar   if (result > 0)  // weird
6501*103e46e4SHarish Mahendrakar     return E_BUFFER_NOT_FULL;
6502*103e46e4SHarish Mahendrakar 
6503*103e46e4SHarish Mahendrakar   if ((pos + len) > block_stop)
6504*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
6505*103e46e4SHarish Mahendrakar 
6506*103e46e4SHarish Mahendrakar   if ((pos + len) > avail)
6507*103e46e4SHarish Mahendrakar     return E_BUFFER_NOT_FULL;
6508*103e46e4SHarish Mahendrakar 
6509*103e46e4SHarish Mahendrakar   const long long track = ReadUInt(pReader, pos, len);
6510*103e46e4SHarish Mahendrakar 
6511*103e46e4SHarish Mahendrakar   if (track < 0)  // error
6512*103e46e4SHarish Mahendrakar     return static_cast<long>(track);
6513*103e46e4SHarish Mahendrakar 
6514*103e46e4SHarish Mahendrakar   if (track == 0)
6515*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
6516*103e46e4SHarish Mahendrakar 
6517*103e46e4SHarish Mahendrakar   pos += len;  // consume track number
6518*103e46e4SHarish Mahendrakar 
6519*103e46e4SHarish Mahendrakar   if ((pos + 2) > block_stop)
6520*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
6521*103e46e4SHarish Mahendrakar 
6522*103e46e4SHarish Mahendrakar   if ((pos + 2) > avail) {
6523*103e46e4SHarish Mahendrakar     len = 2;
6524*103e46e4SHarish Mahendrakar     return E_BUFFER_NOT_FULL;
6525*103e46e4SHarish Mahendrakar   }
6526*103e46e4SHarish Mahendrakar 
6527*103e46e4SHarish Mahendrakar   pos += 2;  // consume timecode
6528*103e46e4SHarish Mahendrakar 
6529*103e46e4SHarish Mahendrakar   if ((pos + 1) > block_stop)
6530*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
6531*103e46e4SHarish Mahendrakar 
6532*103e46e4SHarish Mahendrakar   if ((pos + 1) > avail) {
6533*103e46e4SHarish Mahendrakar     len = 1;
6534*103e46e4SHarish Mahendrakar     return E_BUFFER_NOT_FULL;
6535*103e46e4SHarish Mahendrakar   }
6536*103e46e4SHarish Mahendrakar 
6537*103e46e4SHarish Mahendrakar   unsigned char flags;
6538*103e46e4SHarish Mahendrakar 
6539*103e46e4SHarish Mahendrakar   status = pReader->Read(pos, 1, &flags);
6540*103e46e4SHarish Mahendrakar 
6541*103e46e4SHarish Mahendrakar   if (status < 0) {  // error or underflow
6542*103e46e4SHarish Mahendrakar     len = 1;
6543*103e46e4SHarish Mahendrakar     return status;
6544*103e46e4SHarish Mahendrakar   }
6545*103e46e4SHarish Mahendrakar 
6546*103e46e4SHarish Mahendrakar   ++pos;  // consume flags byte
6547*103e46e4SHarish Mahendrakar   assert(pos <= avail);
6548*103e46e4SHarish Mahendrakar 
6549*103e46e4SHarish Mahendrakar   if (pos >= block_stop)
6550*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
6551*103e46e4SHarish Mahendrakar 
6552*103e46e4SHarish Mahendrakar   const int lacing = int(flags & 0x06) >> 1;
6553*103e46e4SHarish Mahendrakar 
6554*103e46e4SHarish Mahendrakar   if ((lacing != 0) && (block_stop > avail)) {
6555*103e46e4SHarish Mahendrakar     len = static_cast<long>(block_stop - pos);
6556*103e46e4SHarish Mahendrakar     return E_BUFFER_NOT_FULL;
6557*103e46e4SHarish Mahendrakar   }
6558*103e46e4SHarish Mahendrakar 
6559*103e46e4SHarish Mahendrakar   status = CreateBlock(libwebm::kMkvSimpleBlock, block_start, block_size,
6560*103e46e4SHarish Mahendrakar                        0);  // DiscardPadding
6561*103e46e4SHarish Mahendrakar 
6562*103e46e4SHarish Mahendrakar   if (status != 0)
6563*103e46e4SHarish Mahendrakar     return status;
6564*103e46e4SHarish Mahendrakar 
6565*103e46e4SHarish Mahendrakar   m_pos = block_stop;
6566*103e46e4SHarish Mahendrakar 
6567*103e46e4SHarish Mahendrakar   return 0;  // success
6568*103e46e4SHarish Mahendrakar }
6569*103e46e4SHarish Mahendrakar 
ParseBlockGroup(long long payload_size,long long & pos,long & len)6570*103e46e4SHarish Mahendrakar long Cluster::ParseBlockGroup(long long payload_size, long long& pos,
6571*103e46e4SHarish Mahendrakar                               long& len) {
6572*103e46e4SHarish Mahendrakar   const long long payload_start = pos;
6573*103e46e4SHarish Mahendrakar   const long long payload_stop = pos + payload_size;
6574*103e46e4SHarish Mahendrakar 
6575*103e46e4SHarish Mahendrakar   IMkvReader* const pReader = m_pSegment->m_pReader;
6576*103e46e4SHarish Mahendrakar 
6577*103e46e4SHarish Mahendrakar   long long total, avail;
6578*103e46e4SHarish Mahendrakar 
6579*103e46e4SHarish Mahendrakar   long status = pReader->Length(&total, &avail);
6580*103e46e4SHarish Mahendrakar 
6581*103e46e4SHarish Mahendrakar   if (status < 0)  // error
6582*103e46e4SHarish Mahendrakar     return status;
6583*103e46e4SHarish Mahendrakar 
6584*103e46e4SHarish Mahendrakar   assert((total < 0) || (avail <= total));
6585*103e46e4SHarish Mahendrakar 
6586*103e46e4SHarish Mahendrakar   if ((total >= 0) && (payload_stop > total))
6587*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
6588*103e46e4SHarish Mahendrakar 
6589*103e46e4SHarish Mahendrakar   if (payload_stop > avail) {
6590*103e46e4SHarish Mahendrakar     len = static_cast<long>(payload_size);
6591*103e46e4SHarish Mahendrakar     return E_BUFFER_NOT_FULL;
6592*103e46e4SHarish Mahendrakar   }
6593*103e46e4SHarish Mahendrakar 
6594*103e46e4SHarish Mahendrakar   long long discard_padding = 0;
6595*103e46e4SHarish Mahendrakar 
6596*103e46e4SHarish Mahendrakar   while (pos < payload_stop) {
6597*103e46e4SHarish Mahendrakar     // parse sub-block element ID
6598*103e46e4SHarish Mahendrakar 
6599*103e46e4SHarish Mahendrakar     if ((pos + 1) > avail) {
6600*103e46e4SHarish Mahendrakar       len = 1;
6601*103e46e4SHarish Mahendrakar       return E_BUFFER_NOT_FULL;
6602*103e46e4SHarish Mahendrakar     }
6603*103e46e4SHarish Mahendrakar 
6604*103e46e4SHarish Mahendrakar     long long result = GetUIntLength(pReader, pos, len);
6605*103e46e4SHarish Mahendrakar 
6606*103e46e4SHarish Mahendrakar     if (result < 0)  // error
6607*103e46e4SHarish Mahendrakar       return static_cast<long>(result);
6608*103e46e4SHarish Mahendrakar 
6609*103e46e4SHarish Mahendrakar     if (result > 0)  // weird
6610*103e46e4SHarish Mahendrakar       return E_BUFFER_NOT_FULL;
6611*103e46e4SHarish Mahendrakar 
6612*103e46e4SHarish Mahendrakar     if ((pos + len) > payload_stop)
6613*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
6614*103e46e4SHarish Mahendrakar 
6615*103e46e4SHarish Mahendrakar     if ((pos + len) > avail)
6616*103e46e4SHarish Mahendrakar       return E_BUFFER_NOT_FULL;
6617*103e46e4SHarish Mahendrakar 
6618*103e46e4SHarish Mahendrakar     const long long id = ReadID(pReader, pos, len);
6619*103e46e4SHarish Mahendrakar 
6620*103e46e4SHarish Mahendrakar     if (id < 0)  // error
6621*103e46e4SHarish Mahendrakar       return static_cast<long>(id);
6622*103e46e4SHarish Mahendrakar 
6623*103e46e4SHarish Mahendrakar     if (id == 0)  // not a valid ID
6624*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
6625*103e46e4SHarish Mahendrakar 
6626*103e46e4SHarish Mahendrakar     pos += len;  // consume ID field
6627*103e46e4SHarish Mahendrakar 
6628*103e46e4SHarish Mahendrakar     // Parse Size
6629*103e46e4SHarish Mahendrakar 
6630*103e46e4SHarish Mahendrakar     if ((pos + 1) > avail) {
6631*103e46e4SHarish Mahendrakar       len = 1;
6632*103e46e4SHarish Mahendrakar       return E_BUFFER_NOT_FULL;
6633*103e46e4SHarish Mahendrakar     }
6634*103e46e4SHarish Mahendrakar 
6635*103e46e4SHarish Mahendrakar     result = GetUIntLength(pReader, pos, len);
6636*103e46e4SHarish Mahendrakar 
6637*103e46e4SHarish Mahendrakar     if (result < 0)  // error
6638*103e46e4SHarish Mahendrakar       return static_cast<long>(result);
6639*103e46e4SHarish Mahendrakar 
6640*103e46e4SHarish Mahendrakar     if (result > 0)  // weird
6641*103e46e4SHarish Mahendrakar       return E_BUFFER_NOT_FULL;
6642*103e46e4SHarish Mahendrakar 
6643*103e46e4SHarish Mahendrakar     if ((pos + len) > payload_stop)
6644*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
6645*103e46e4SHarish Mahendrakar 
6646*103e46e4SHarish Mahendrakar     if ((pos + len) > avail)
6647*103e46e4SHarish Mahendrakar       return E_BUFFER_NOT_FULL;
6648*103e46e4SHarish Mahendrakar 
6649*103e46e4SHarish Mahendrakar     const long long size = ReadUInt(pReader, pos, len);
6650*103e46e4SHarish Mahendrakar 
6651*103e46e4SHarish Mahendrakar     if (size < 0)  // error
6652*103e46e4SHarish Mahendrakar       return static_cast<long>(size);
6653*103e46e4SHarish Mahendrakar 
6654*103e46e4SHarish Mahendrakar     pos += len;  // consume size field
6655*103e46e4SHarish Mahendrakar 
6656*103e46e4SHarish Mahendrakar     // pos now points to start of sub-block group payload
6657*103e46e4SHarish Mahendrakar 
6658*103e46e4SHarish Mahendrakar     if (pos > payload_stop)
6659*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
6660*103e46e4SHarish Mahendrakar 
6661*103e46e4SHarish Mahendrakar     if (size == 0)  // weird
6662*103e46e4SHarish Mahendrakar       continue;
6663*103e46e4SHarish Mahendrakar 
6664*103e46e4SHarish Mahendrakar     const long long unknown_size = (1LL << (7 * len)) - 1;
6665*103e46e4SHarish Mahendrakar 
6666*103e46e4SHarish Mahendrakar     if (size == unknown_size)
6667*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
6668*103e46e4SHarish Mahendrakar 
6669*103e46e4SHarish Mahendrakar     if (id == libwebm::kMkvDiscardPadding) {
6670*103e46e4SHarish Mahendrakar       status = UnserializeInt(pReader, pos, size, discard_padding);
6671*103e46e4SHarish Mahendrakar 
6672*103e46e4SHarish Mahendrakar       if (status < 0)  // error
6673*103e46e4SHarish Mahendrakar         return status;
6674*103e46e4SHarish Mahendrakar     }
6675*103e46e4SHarish Mahendrakar 
6676*103e46e4SHarish Mahendrakar     if (id != libwebm::kMkvBlock) {
6677*103e46e4SHarish Mahendrakar       pos += size;  // consume sub-part of block group
6678*103e46e4SHarish Mahendrakar 
6679*103e46e4SHarish Mahendrakar       if (pos > payload_stop)
6680*103e46e4SHarish Mahendrakar         return E_FILE_FORMAT_INVALID;
6681*103e46e4SHarish Mahendrakar 
6682*103e46e4SHarish Mahendrakar       continue;
6683*103e46e4SHarish Mahendrakar     }
6684*103e46e4SHarish Mahendrakar 
6685*103e46e4SHarish Mahendrakar     const long long block_stop = pos + size;
6686*103e46e4SHarish Mahendrakar 
6687*103e46e4SHarish Mahendrakar     if (block_stop > payload_stop)
6688*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
6689*103e46e4SHarish Mahendrakar 
6690*103e46e4SHarish Mahendrakar     // parse track number
6691*103e46e4SHarish Mahendrakar 
6692*103e46e4SHarish Mahendrakar     if ((pos + 1) > avail) {
6693*103e46e4SHarish Mahendrakar       len = 1;
6694*103e46e4SHarish Mahendrakar       return E_BUFFER_NOT_FULL;
6695*103e46e4SHarish Mahendrakar     }
6696*103e46e4SHarish Mahendrakar 
6697*103e46e4SHarish Mahendrakar     result = GetUIntLength(pReader, pos, len);
6698*103e46e4SHarish Mahendrakar 
6699*103e46e4SHarish Mahendrakar     if (result < 0)  // error
6700*103e46e4SHarish Mahendrakar       return static_cast<long>(result);
6701*103e46e4SHarish Mahendrakar 
6702*103e46e4SHarish Mahendrakar     if (result > 0)  // weird
6703*103e46e4SHarish Mahendrakar       return E_BUFFER_NOT_FULL;
6704*103e46e4SHarish Mahendrakar 
6705*103e46e4SHarish Mahendrakar     if ((pos + len) > block_stop)
6706*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
6707*103e46e4SHarish Mahendrakar 
6708*103e46e4SHarish Mahendrakar     if ((pos + len) > avail)
6709*103e46e4SHarish Mahendrakar       return E_BUFFER_NOT_FULL;
6710*103e46e4SHarish Mahendrakar 
6711*103e46e4SHarish Mahendrakar     const long long track = ReadUInt(pReader, pos, len);
6712*103e46e4SHarish Mahendrakar 
6713*103e46e4SHarish Mahendrakar     if (track < 0)  // error
6714*103e46e4SHarish Mahendrakar       return static_cast<long>(track);
6715*103e46e4SHarish Mahendrakar 
6716*103e46e4SHarish Mahendrakar     if (track == 0)
6717*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
6718*103e46e4SHarish Mahendrakar 
6719*103e46e4SHarish Mahendrakar     pos += len;  // consume track number
6720*103e46e4SHarish Mahendrakar 
6721*103e46e4SHarish Mahendrakar     if ((pos + 2) > block_stop)
6722*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
6723*103e46e4SHarish Mahendrakar 
6724*103e46e4SHarish Mahendrakar     if ((pos + 2) > avail) {
6725*103e46e4SHarish Mahendrakar       len = 2;
6726*103e46e4SHarish Mahendrakar       return E_BUFFER_NOT_FULL;
6727*103e46e4SHarish Mahendrakar     }
6728*103e46e4SHarish Mahendrakar 
6729*103e46e4SHarish Mahendrakar     pos += 2;  // consume timecode
6730*103e46e4SHarish Mahendrakar 
6731*103e46e4SHarish Mahendrakar     if ((pos + 1) > block_stop)
6732*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
6733*103e46e4SHarish Mahendrakar 
6734*103e46e4SHarish Mahendrakar     if ((pos + 1) > avail) {
6735*103e46e4SHarish Mahendrakar       len = 1;
6736*103e46e4SHarish Mahendrakar       return E_BUFFER_NOT_FULL;
6737*103e46e4SHarish Mahendrakar     }
6738*103e46e4SHarish Mahendrakar 
6739*103e46e4SHarish Mahendrakar     unsigned char flags;
6740*103e46e4SHarish Mahendrakar 
6741*103e46e4SHarish Mahendrakar     status = pReader->Read(pos, 1, &flags);
6742*103e46e4SHarish Mahendrakar 
6743*103e46e4SHarish Mahendrakar     if (status < 0) {  // error or underflow
6744*103e46e4SHarish Mahendrakar       len = 1;
6745*103e46e4SHarish Mahendrakar       return status;
6746*103e46e4SHarish Mahendrakar     }
6747*103e46e4SHarish Mahendrakar 
6748*103e46e4SHarish Mahendrakar     ++pos;  // consume flags byte
6749*103e46e4SHarish Mahendrakar     assert(pos <= avail);
6750*103e46e4SHarish Mahendrakar 
6751*103e46e4SHarish Mahendrakar     if (pos >= block_stop)
6752*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
6753*103e46e4SHarish Mahendrakar 
6754*103e46e4SHarish Mahendrakar     const int lacing = int(flags & 0x06) >> 1;
6755*103e46e4SHarish Mahendrakar 
6756*103e46e4SHarish Mahendrakar     if ((lacing != 0) && (block_stop > avail)) {
6757*103e46e4SHarish Mahendrakar       len = static_cast<long>(block_stop - pos);
6758*103e46e4SHarish Mahendrakar       return E_BUFFER_NOT_FULL;
6759*103e46e4SHarish Mahendrakar     }
6760*103e46e4SHarish Mahendrakar 
6761*103e46e4SHarish Mahendrakar     pos = block_stop;  // consume block-part of block group
6762*103e46e4SHarish Mahendrakar     if (pos > payload_stop)
6763*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
6764*103e46e4SHarish Mahendrakar   }
6765*103e46e4SHarish Mahendrakar 
6766*103e46e4SHarish Mahendrakar   if (pos != payload_stop)
6767*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
6768*103e46e4SHarish Mahendrakar 
6769*103e46e4SHarish Mahendrakar   status = CreateBlock(libwebm::kMkvBlockGroup, payload_start, payload_size,
6770*103e46e4SHarish Mahendrakar                        discard_padding);
6771*103e46e4SHarish Mahendrakar   if (status != 0)
6772*103e46e4SHarish Mahendrakar     return status;
6773*103e46e4SHarish Mahendrakar 
6774*103e46e4SHarish Mahendrakar   m_pos = payload_stop;
6775*103e46e4SHarish Mahendrakar 
6776*103e46e4SHarish Mahendrakar   return 0;  // success
6777*103e46e4SHarish Mahendrakar }
6778*103e46e4SHarish Mahendrakar 
GetEntry(long index,const mkvparser::BlockEntry * & pEntry) const6779*103e46e4SHarish Mahendrakar long Cluster::GetEntry(long index, const mkvparser::BlockEntry*& pEntry) const {
6780*103e46e4SHarish Mahendrakar   assert(m_pos >= m_element_start);
6781*103e46e4SHarish Mahendrakar 
6782*103e46e4SHarish Mahendrakar   pEntry = NULL;
6783*103e46e4SHarish Mahendrakar 
6784*103e46e4SHarish Mahendrakar   if (index < 0)
6785*103e46e4SHarish Mahendrakar     return -1;  // generic error
6786*103e46e4SHarish Mahendrakar 
6787*103e46e4SHarish Mahendrakar   if (m_entries_count < 0)
6788*103e46e4SHarish Mahendrakar     return E_BUFFER_NOT_FULL;
6789*103e46e4SHarish Mahendrakar 
6790*103e46e4SHarish Mahendrakar   assert(m_entries);
6791*103e46e4SHarish Mahendrakar   assert(m_entries_size > 0);
6792*103e46e4SHarish Mahendrakar   assert(m_entries_count <= m_entries_size);
6793*103e46e4SHarish Mahendrakar 
6794*103e46e4SHarish Mahendrakar   if (index < m_entries_count) {
6795*103e46e4SHarish Mahendrakar     pEntry = m_entries[index];
6796*103e46e4SHarish Mahendrakar     assert(pEntry);
6797*103e46e4SHarish Mahendrakar 
6798*103e46e4SHarish Mahendrakar     return 1;  // found entry
6799*103e46e4SHarish Mahendrakar   }
6800*103e46e4SHarish Mahendrakar 
6801*103e46e4SHarish Mahendrakar   if (m_element_size < 0)  // we don't know cluster end yet
6802*103e46e4SHarish Mahendrakar     return E_BUFFER_NOT_FULL;  // underflow
6803*103e46e4SHarish Mahendrakar 
6804*103e46e4SHarish Mahendrakar   const long long element_stop = m_element_start + m_element_size;
6805*103e46e4SHarish Mahendrakar 
6806*103e46e4SHarish Mahendrakar   if (m_pos >= element_stop)
6807*103e46e4SHarish Mahendrakar     return 0;  // nothing left to parse
6808*103e46e4SHarish Mahendrakar 
6809*103e46e4SHarish Mahendrakar   return E_BUFFER_NOT_FULL;  // underflow, since more remains to be parsed
6810*103e46e4SHarish Mahendrakar }
6811*103e46e4SHarish Mahendrakar 
Create(Segment * pSegment,long idx,long long off)6812*103e46e4SHarish Mahendrakar Cluster* Cluster::Create(Segment* pSegment, long idx, long long off) {
6813*103e46e4SHarish Mahendrakar   if (!pSegment || off < 0)
6814*103e46e4SHarish Mahendrakar     return NULL;
6815*103e46e4SHarish Mahendrakar 
6816*103e46e4SHarish Mahendrakar   const long long element_start = pSegment->m_start + off;
6817*103e46e4SHarish Mahendrakar 
6818*103e46e4SHarish Mahendrakar   Cluster* const pCluster =
6819*103e46e4SHarish Mahendrakar       new (std::nothrow) Cluster(pSegment, idx, element_start);
6820*103e46e4SHarish Mahendrakar 
6821*103e46e4SHarish Mahendrakar   return pCluster;
6822*103e46e4SHarish Mahendrakar }
6823*103e46e4SHarish Mahendrakar 
Cluster()6824*103e46e4SHarish Mahendrakar Cluster::Cluster()
6825*103e46e4SHarish Mahendrakar     : m_pSegment(NULL),
6826*103e46e4SHarish Mahendrakar       m_element_start(0),
6827*103e46e4SHarish Mahendrakar       m_index(0),
6828*103e46e4SHarish Mahendrakar       m_pos(0),
6829*103e46e4SHarish Mahendrakar       m_element_size(0),
6830*103e46e4SHarish Mahendrakar       m_timecode(0),
6831*103e46e4SHarish Mahendrakar       m_entries(NULL),
6832*103e46e4SHarish Mahendrakar       m_entries_size(0),
6833*103e46e4SHarish Mahendrakar       m_entries_count(0)  // means "no entries"
6834*103e46e4SHarish Mahendrakar {}
6835*103e46e4SHarish Mahendrakar 
Cluster(Segment * pSegment,long idx,long long element_start)6836*103e46e4SHarish Mahendrakar Cluster::Cluster(Segment* pSegment, long idx, long long element_start
6837*103e46e4SHarish Mahendrakar                  /* long long element_size */)
6838*103e46e4SHarish Mahendrakar     : m_pSegment(pSegment),
6839*103e46e4SHarish Mahendrakar       m_element_start(element_start),
6840*103e46e4SHarish Mahendrakar       m_index(idx),
6841*103e46e4SHarish Mahendrakar       m_pos(element_start),
6842*103e46e4SHarish Mahendrakar       m_element_size(-1 /* element_size */),
6843*103e46e4SHarish Mahendrakar       m_timecode(-1),
6844*103e46e4SHarish Mahendrakar       m_entries(NULL),
6845*103e46e4SHarish Mahendrakar       m_entries_size(0),
6846*103e46e4SHarish Mahendrakar       m_entries_count(-1)  // means "has not been parsed yet"
6847*103e46e4SHarish Mahendrakar {}
6848*103e46e4SHarish Mahendrakar 
~Cluster()6849*103e46e4SHarish Mahendrakar Cluster::~Cluster() {
6850*103e46e4SHarish Mahendrakar   if (m_entries_count <= 0) {
6851*103e46e4SHarish Mahendrakar     delete[] m_entries;
6852*103e46e4SHarish Mahendrakar     return;
6853*103e46e4SHarish Mahendrakar   }
6854*103e46e4SHarish Mahendrakar 
6855*103e46e4SHarish Mahendrakar   BlockEntry** i = m_entries;
6856*103e46e4SHarish Mahendrakar   BlockEntry** const j = m_entries + m_entries_count;
6857*103e46e4SHarish Mahendrakar 
6858*103e46e4SHarish Mahendrakar   while (i != j) {
6859*103e46e4SHarish Mahendrakar     BlockEntry* p = *i++;
6860*103e46e4SHarish Mahendrakar     assert(p);
6861*103e46e4SHarish Mahendrakar 
6862*103e46e4SHarish Mahendrakar     delete p;
6863*103e46e4SHarish Mahendrakar   }
6864*103e46e4SHarish Mahendrakar 
6865*103e46e4SHarish Mahendrakar   delete[] m_entries;
6866*103e46e4SHarish Mahendrakar }
6867*103e46e4SHarish Mahendrakar 
EOS() const6868*103e46e4SHarish Mahendrakar bool Cluster::EOS() const { return (m_pSegment == NULL); }
6869*103e46e4SHarish Mahendrakar 
GetIndex() const6870*103e46e4SHarish Mahendrakar long Cluster::GetIndex() const { return m_index; }
6871*103e46e4SHarish Mahendrakar 
GetPosition() const6872*103e46e4SHarish Mahendrakar long long Cluster::GetPosition() const {
6873*103e46e4SHarish Mahendrakar   const long long pos = m_element_start - m_pSegment->m_start;
6874*103e46e4SHarish Mahendrakar   assert(pos >= 0);
6875*103e46e4SHarish Mahendrakar 
6876*103e46e4SHarish Mahendrakar   return pos;
6877*103e46e4SHarish Mahendrakar }
6878*103e46e4SHarish Mahendrakar 
GetElementSize() const6879*103e46e4SHarish Mahendrakar long long Cluster::GetElementSize() const { return m_element_size; }
6880*103e46e4SHarish Mahendrakar 
HasBlockEntries(const Segment * pSegment,long long off,long long & pos,long & len)6881*103e46e4SHarish Mahendrakar long Cluster::HasBlockEntries(
6882*103e46e4SHarish Mahendrakar     const Segment* pSegment,
6883*103e46e4SHarish Mahendrakar     long long off,  // relative to start of segment payload
6884*103e46e4SHarish Mahendrakar     long long& pos, long& len) {
6885*103e46e4SHarish Mahendrakar   assert(pSegment);
6886*103e46e4SHarish Mahendrakar   assert(off >= 0);  // relative to segment
6887*103e46e4SHarish Mahendrakar 
6888*103e46e4SHarish Mahendrakar   IMkvReader* const pReader = pSegment->m_pReader;
6889*103e46e4SHarish Mahendrakar 
6890*103e46e4SHarish Mahendrakar   long long total, avail;
6891*103e46e4SHarish Mahendrakar 
6892*103e46e4SHarish Mahendrakar   long status = pReader->Length(&total, &avail);
6893*103e46e4SHarish Mahendrakar 
6894*103e46e4SHarish Mahendrakar   if (status < 0)  // error
6895*103e46e4SHarish Mahendrakar     return status;
6896*103e46e4SHarish Mahendrakar 
6897*103e46e4SHarish Mahendrakar   assert((total < 0) || (avail <= total));
6898*103e46e4SHarish Mahendrakar 
6899*103e46e4SHarish Mahendrakar   pos = pSegment->m_start + off;  // absolute
6900*103e46e4SHarish Mahendrakar 
6901*103e46e4SHarish Mahendrakar   if ((total >= 0) && (pos >= total))
6902*103e46e4SHarish Mahendrakar     return 0;  // we don't even have a complete cluster
6903*103e46e4SHarish Mahendrakar 
6904*103e46e4SHarish Mahendrakar   const long long segment_stop =
6905*103e46e4SHarish Mahendrakar       (pSegment->m_size < 0) ? -1 : pSegment->m_start + pSegment->m_size;
6906*103e46e4SHarish Mahendrakar 
6907*103e46e4SHarish Mahendrakar   long long cluster_stop = -1;  // interpreted later to mean "unknown size"
6908*103e46e4SHarish Mahendrakar 
6909*103e46e4SHarish Mahendrakar   {
6910*103e46e4SHarish Mahendrakar     if ((pos + 1) > avail) {
6911*103e46e4SHarish Mahendrakar       len = 1;
6912*103e46e4SHarish Mahendrakar       return E_BUFFER_NOT_FULL;
6913*103e46e4SHarish Mahendrakar     }
6914*103e46e4SHarish Mahendrakar 
6915*103e46e4SHarish Mahendrakar     long long result = GetUIntLength(pReader, pos, len);
6916*103e46e4SHarish Mahendrakar 
6917*103e46e4SHarish Mahendrakar     if (result < 0)  // error
6918*103e46e4SHarish Mahendrakar       return static_cast<long>(result);
6919*103e46e4SHarish Mahendrakar 
6920*103e46e4SHarish Mahendrakar     if (result > 0)  // need more data
6921*103e46e4SHarish Mahendrakar       return E_BUFFER_NOT_FULL;
6922*103e46e4SHarish Mahendrakar 
6923*103e46e4SHarish Mahendrakar     if ((segment_stop >= 0) && ((pos + len) > segment_stop))
6924*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
6925*103e46e4SHarish Mahendrakar 
6926*103e46e4SHarish Mahendrakar     if ((total >= 0) && ((pos + len) > total))
6927*103e46e4SHarish Mahendrakar       return 0;
6928*103e46e4SHarish Mahendrakar 
6929*103e46e4SHarish Mahendrakar     if ((pos + len) > avail)
6930*103e46e4SHarish Mahendrakar       return E_BUFFER_NOT_FULL;
6931*103e46e4SHarish Mahendrakar 
6932*103e46e4SHarish Mahendrakar     const long long id = ReadID(pReader, pos, len);
6933*103e46e4SHarish Mahendrakar 
6934*103e46e4SHarish Mahendrakar     if (id < 0)  // error
6935*103e46e4SHarish Mahendrakar       return static_cast<long>(id);
6936*103e46e4SHarish Mahendrakar 
6937*103e46e4SHarish Mahendrakar     if (id != libwebm::kMkvCluster)
6938*103e46e4SHarish Mahendrakar       return E_PARSE_FAILED;
6939*103e46e4SHarish Mahendrakar 
6940*103e46e4SHarish Mahendrakar     pos += len;  // consume Cluster ID field
6941*103e46e4SHarish Mahendrakar 
6942*103e46e4SHarish Mahendrakar     // read size field
6943*103e46e4SHarish Mahendrakar 
6944*103e46e4SHarish Mahendrakar     if ((pos + 1) > avail) {
6945*103e46e4SHarish Mahendrakar       len = 1;
6946*103e46e4SHarish Mahendrakar       return E_BUFFER_NOT_FULL;
6947*103e46e4SHarish Mahendrakar     }
6948*103e46e4SHarish Mahendrakar 
6949*103e46e4SHarish Mahendrakar     result = GetUIntLength(pReader, pos, len);
6950*103e46e4SHarish Mahendrakar 
6951*103e46e4SHarish Mahendrakar     if (result < 0)  // error
6952*103e46e4SHarish Mahendrakar       return static_cast<long>(result);
6953*103e46e4SHarish Mahendrakar 
6954*103e46e4SHarish Mahendrakar     if (result > 0)  // weird
6955*103e46e4SHarish Mahendrakar       return E_BUFFER_NOT_FULL;
6956*103e46e4SHarish Mahendrakar 
6957*103e46e4SHarish Mahendrakar     if ((segment_stop >= 0) && ((pos + len) > segment_stop))
6958*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
6959*103e46e4SHarish Mahendrakar 
6960*103e46e4SHarish Mahendrakar     if ((total >= 0) && ((pos + len) > total))
6961*103e46e4SHarish Mahendrakar       return 0;
6962*103e46e4SHarish Mahendrakar 
6963*103e46e4SHarish Mahendrakar     if ((pos + len) > avail)
6964*103e46e4SHarish Mahendrakar       return E_BUFFER_NOT_FULL;
6965*103e46e4SHarish Mahendrakar 
6966*103e46e4SHarish Mahendrakar     const long long size = ReadUInt(pReader, pos, len);
6967*103e46e4SHarish Mahendrakar 
6968*103e46e4SHarish Mahendrakar     if (size < 0)  // error
6969*103e46e4SHarish Mahendrakar       return static_cast<long>(size);
6970*103e46e4SHarish Mahendrakar 
6971*103e46e4SHarish Mahendrakar     if (size == 0)
6972*103e46e4SHarish Mahendrakar       return 0;  // cluster does not have entries
6973*103e46e4SHarish Mahendrakar 
6974*103e46e4SHarish Mahendrakar     pos += len;  // consume size field
6975*103e46e4SHarish Mahendrakar 
6976*103e46e4SHarish Mahendrakar     // pos now points to start of payload
6977*103e46e4SHarish Mahendrakar 
6978*103e46e4SHarish Mahendrakar     const long long unknown_size = (1LL << (7 * len)) - 1;
6979*103e46e4SHarish Mahendrakar 
6980*103e46e4SHarish Mahendrakar     if (size != unknown_size) {
6981*103e46e4SHarish Mahendrakar       cluster_stop = pos + size;
6982*103e46e4SHarish Mahendrakar       assert(cluster_stop >= 0);
6983*103e46e4SHarish Mahendrakar 
6984*103e46e4SHarish Mahendrakar       if ((segment_stop >= 0) && (cluster_stop > segment_stop))
6985*103e46e4SHarish Mahendrakar         return E_FILE_FORMAT_INVALID;
6986*103e46e4SHarish Mahendrakar 
6987*103e46e4SHarish Mahendrakar       if ((total >= 0) && (cluster_stop > total))
6988*103e46e4SHarish Mahendrakar         // return E_FILE_FORMAT_INVALID;  //too conservative
6989*103e46e4SHarish Mahendrakar         return 0;  // cluster does not have any entries
6990*103e46e4SHarish Mahendrakar     }
6991*103e46e4SHarish Mahendrakar   }
6992*103e46e4SHarish Mahendrakar 
6993*103e46e4SHarish Mahendrakar   for (;;) {
6994*103e46e4SHarish Mahendrakar     if ((cluster_stop >= 0) && (pos >= cluster_stop))
6995*103e46e4SHarish Mahendrakar       return 0;  // no entries detected
6996*103e46e4SHarish Mahendrakar 
6997*103e46e4SHarish Mahendrakar     if ((pos + 1) > avail) {
6998*103e46e4SHarish Mahendrakar       len = 1;
6999*103e46e4SHarish Mahendrakar       return E_BUFFER_NOT_FULL;
7000*103e46e4SHarish Mahendrakar     }
7001*103e46e4SHarish Mahendrakar 
7002*103e46e4SHarish Mahendrakar     long long result = GetUIntLength(pReader, pos, len);
7003*103e46e4SHarish Mahendrakar 
7004*103e46e4SHarish Mahendrakar     if (result < 0)  // error
7005*103e46e4SHarish Mahendrakar       return static_cast<long>(result);
7006*103e46e4SHarish Mahendrakar 
7007*103e46e4SHarish Mahendrakar     if (result > 0)  // need more data
7008*103e46e4SHarish Mahendrakar       return E_BUFFER_NOT_FULL;
7009*103e46e4SHarish Mahendrakar 
7010*103e46e4SHarish Mahendrakar     if ((cluster_stop >= 0) && ((pos + len) > cluster_stop))
7011*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
7012*103e46e4SHarish Mahendrakar 
7013*103e46e4SHarish Mahendrakar     if ((pos + len) > avail)
7014*103e46e4SHarish Mahendrakar       return E_BUFFER_NOT_FULL;
7015*103e46e4SHarish Mahendrakar 
7016*103e46e4SHarish Mahendrakar     const long long id = ReadID(pReader, pos, len);
7017*103e46e4SHarish Mahendrakar 
7018*103e46e4SHarish Mahendrakar     if (id < 0)  // error
7019*103e46e4SHarish Mahendrakar       return static_cast<long>(id);
7020*103e46e4SHarish Mahendrakar 
7021*103e46e4SHarish Mahendrakar     // This is the distinguished set of ID's we use to determine
7022*103e46e4SHarish Mahendrakar     // that we have exhausted the sub-element's inside the cluster
7023*103e46e4SHarish Mahendrakar     // whose ID we parsed earlier.
7024*103e46e4SHarish Mahendrakar 
7025*103e46e4SHarish Mahendrakar     if (id == libwebm::kMkvCluster)
7026*103e46e4SHarish Mahendrakar       return 0;  // no entries found
7027*103e46e4SHarish Mahendrakar 
7028*103e46e4SHarish Mahendrakar     if (id == libwebm::kMkvCues)
7029*103e46e4SHarish Mahendrakar       return 0;  // no entries found
7030*103e46e4SHarish Mahendrakar 
7031*103e46e4SHarish Mahendrakar     pos += len;  // consume id field
7032*103e46e4SHarish Mahendrakar 
7033*103e46e4SHarish Mahendrakar     if ((cluster_stop >= 0) && (pos >= cluster_stop))
7034*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
7035*103e46e4SHarish Mahendrakar 
7036*103e46e4SHarish Mahendrakar     // read size field
7037*103e46e4SHarish Mahendrakar 
7038*103e46e4SHarish Mahendrakar     if ((pos + 1) > avail) {
7039*103e46e4SHarish Mahendrakar       len = 1;
7040*103e46e4SHarish Mahendrakar       return E_BUFFER_NOT_FULL;
7041*103e46e4SHarish Mahendrakar     }
7042*103e46e4SHarish Mahendrakar 
7043*103e46e4SHarish Mahendrakar     result = GetUIntLength(pReader, pos, len);
7044*103e46e4SHarish Mahendrakar 
7045*103e46e4SHarish Mahendrakar     if (result < 0)  // error
7046*103e46e4SHarish Mahendrakar       return static_cast<long>(result);
7047*103e46e4SHarish Mahendrakar 
7048*103e46e4SHarish Mahendrakar     if (result > 0)  // underflow
7049*103e46e4SHarish Mahendrakar       return E_BUFFER_NOT_FULL;
7050*103e46e4SHarish Mahendrakar 
7051*103e46e4SHarish Mahendrakar     if ((cluster_stop >= 0) && ((pos + len) > cluster_stop))
7052*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
7053*103e46e4SHarish Mahendrakar 
7054*103e46e4SHarish Mahendrakar     if ((pos + len) > avail)
7055*103e46e4SHarish Mahendrakar       return E_BUFFER_NOT_FULL;
7056*103e46e4SHarish Mahendrakar 
7057*103e46e4SHarish Mahendrakar     const long long size = ReadUInt(pReader, pos, len);
7058*103e46e4SHarish Mahendrakar 
7059*103e46e4SHarish Mahendrakar     if (size < 0)  // error
7060*103e46e4SHarish Mahendrakar       return static_cast<long>(size);
7061*103e46e4SHarish Mahendrakar 
7062*103e46e4SHarish Mahendrakar     pos += len;  // consume size field
7063*103e46e4SHarish Mahendrakar 
7064*103e46e4SHarish Mahendrakar     // pos now points to start of payload
7065*103e46e4SHarish Mahendrakar 
7066*103e46e4SHarish Mahendrakar     if ((cluster_stop >= 0) && (pos > cluster_stop))
7067*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
7068*103e46e4SHarish Mahendrakar 
7069*103e46e4SHarish Mahendrakar     if (size == 0)  // weird
7070*103e46e4SHarish Mahendrakar       continue;
7071*103e46e4SHarish Mahendrakar 
7072*103e46e4SHarish Mahendrakar     const long long unknown_size = (1LL << (7 * len)) - 1;
7073*103e46e4SHarish Mahendrakar 
7074*103e46e4SHarish Mahendrakar     if (size == unknown_size)
7075*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;  // not supported inside cluster
7076*103e46e4SHarish Mahendrakar 
7077*103e46e4SHarish Mahendrakar     if ((cluster_stop >= 0) && ((pos + size) > cluster_stop))
7078*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
7079*103e46e4SHarish Mahendrakar 
7080*103e46e4SHarish Mahendrakar     if (id == libwebm::kMkvBlockGroup)
7081*103e46e4SHarish Mahendrakar       return 1;  // have at least one entry
7082*103e46e4SHarish Mahendrakar 
7083*103e46e4SHarish Mahendrakar     if (id == libwebm::kMkvSimpleBlock)
7084*103e46e4SHarish Mahendrakar       return 1;  // have at least one entry
7085*103e46e4SHarish Mahendrakar 
7086*103e46e4SHarish Mahendrakar     pos += size;  // consume payload
7087*103e46e4SHarish Mahendrakar     if (cluster_stop >= 0 && pos > cluster_stop)
7088*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
7089*103e46e4SHarish Mahendrakar   }
7090*103e46e4SHarish Mahendrakar }
7091*103e46e4SHarish Mahendrakar 
GetTimeCode() const7092*103e46e4SHarish Mahendrakar long long Cluster::GetTimeCode() const {
7093*103e46e4SHarish Mahendrakar   long long pos;
7094*103e46e4SHarish Mahendrakar   long len;
7095*103e46e4SHarish Mahendrakar 
7096*103e46e4SHarish Mahendrakar   const long status = Load(pos, len);
7097*103e46e4SHarish Mahendrakar 
7098*103e46e4SHarish Mahendrakar   if (status < 0)  // error
7099*103e46e4SHarish Mahendrakar     return status;
7100*103e46e4SHarish Mahendrakar 
7101*103e46e4SHarish Mahendrakar   return m_timecode;
7102*103e46e4SHarish Mahendrakar }
7103*103e46e4SHarish Mahendrakar 
GetTime() const7104*103e46e4SHarish Mahendrakar long long Cluster::GetTime() const {
7105*103e46e4SHarish Mahendrakar   const long long tc = GetTimeCode();
7106*103e46e4SHarish Mahendrakar 
7107*103e46e4SHarish Mahendrakar   if (tc < 0)
7108*103e46e4SHarish Mahendrakar     return tc;
7109*103e46e4SHarish Mahendrakar 
7110*103e46e4SHarish Mahendrakar   const SegmentInfo* const pInfo = m_pSegment->GetInfo();
7111*103e46e4SHarish Mahendrakar   assert(pInfo);
7112*103e46e4SHarish Mahendrakar 
7113*103e46e4SHarish Mahendrakar   const long long scale = pInfo->GetTimeCodeScale();
7114*103e46e4SHarish Mahendrakar   assert(scale >= 1);
7115*103e46e4SHarish Mahendrakar 
7116*103e46e4SHarish Mahendrakar   const long long t = m_timecode * scale;
7117*103e46e4SHarish Mahendrakar 
7118*103e46e4SHarish Mahendrakar   return t;
7119*103e46e4SHarish Mahendrakar }
7120*103e46e4SHarish Mahendrakar 
GetFirstTime() const7121*103e46e4SHarish Mahendrakar long long Cluster::GetFirstTime() const {
7122*103e46e4SHarish Mahendrakar   const BlockEntry* pEntry;
7123*103e46e4SHarish Mahendrakar 
7124*103e46e4SHarish Mahendrakar   const long status = GetFirst(pEntry);
7125*103e46e4SHarish Mahendrakar 
7126*103e46e4SHarish Mahendrakar   if (status < 0)  // error
7127*103e46e4SHarish Mahendrakar     return status;
7128*103e46e4SHarish Mahendrakar 
7129*103e46e4SHarish Mahendrakar   if (pEntry == NULL)  // empty cluster
7130*103e46e4SHarish Mahendrakar     return GetTime();
7131*103e46e4SHarish Mahendrakar 
7132*103e46e4SHarish Mahendrakar   const Block* const pBlock = pEntry->GetBlock();
7133*103e46e4SHarish Mahendrakar   assert(pBlock);
7134*103e46e4SHarish Mahendrakar 
7135*103e46e4SHarish Mahendrakar   return pBlock->GetTime(this);
7136*103e46e4SHarish Mahendrakar }
7137*103e46e4SHarish Mahendrakar 
GetLastTime() const7138*103e46e4SHarish Mahendrakar long long Cluster::GetLastTime() const {
7139*103e46e4SHarish Mahendrakar   const BlockEntry* pEntry;
7140*103e46e4SHarish Mahendrakar 
7141*103e46e4SHarish Mahendrakar   const long status = GetLast(pEntry);
7142*103e46e4SHarish Mahendrakar 
7143*103e46e4SHarish Mahendrakar   if (status < 0)  // error
7144*103e46e4SHarish Mahendrakar     return status;
7145*103e46e4SHarish Mahendrakar 
7146*103e46e4SHarish Mahendrakar   if (pEntry == NULL)  // empty cluster
7147*103e46e4SHarish Mahendrakar     return GetTime();
7148*103e46e4SHarish Mahendrakar 
7149*103e46e4SHarish Mahendrakar   const Block* const pBlock = pEntry->GetBlock();
7150*103e46e4SHarish Mahendrakar   assert(pBlock);
7151*103e46e4SHarish Mahendrakar 
7152*103e46e4SHarish Mahendrakar   return pBlock->GetTime(this);
7153*103e46e4SHarish Mahendrakar }
7154*103e46e4SHarish Mahendrakar 
CreateBlock(long long id,long long pos,long long size,long long discard_padding)7155*103e46e4SHarish Mahendrakar long Cluster::CreateBlock(long long id,
7156*103e46e4SHarish Mahendrakar                           long long pos,  // absolute pos of payload
7157*103e46e4SHarish Mahendrakar                           long long size, long long discard_padding) {
7158*103e46e4SHarish Mahendrakar   if (id != libwebm::kMkvBlockGroup && id != libwebm::kMkvSimpleBlock)
7159*103e46e4SHarish Mahendrakar     return E_PARSE_FAILED;
7160*103e46e4SHarish Mahendrakar 
7161*103e46e4SHarish Mahendrakar   if (m_entries_count < 0) {  // haven't parsed anything yet
7162*103e46e4SHarish Mahendrakar     assert(m_entries == NULL);
7163*103e46e4SHarish Mahendrakar     assert(m_entries_size == 0);
7164*103e46e4SHarish Mahendrakar 
7165*103e46e4SHarish Mahendrakar     m_entries_size = 1024;
7166*103e46e4SHarish Mahendrakar     m_entries = new (std::nothrow) BlockEntry*[m_entries_size];
7167*103e46e4SHarish Mahendrakar     if (m_entries == NULL)
7168*103e46e4SHarish Mahendrakar       return -1;
7169*103e46e4SHarish Mahendrakar 
7170*103e46e4SHarish Mahendrakar     m_entries_count = 0;
7171*103e46e4SHarish Mahendrakar   } else {
7172*103e46e4SHarish Mahendrakar     assert(m_entries);
7173*103e46e4SHarish Mahendrakar     assert(m_entries_size > 0);
7174*103e46e4SHarish Mahendrakar     assert(m_entries_count <= m_entries_size);
7175*103e46e4SHarish Mahendrakar 
7176*103e46e4SHarish Mahendrakar     if (m_entries_count >= m_entries_size) {
7177*103e46e4SHarish Mahendrakar       const long entries_size = 2 * m_entries_size;
7178*103e46e4SHarish Mahendrakar 
7179*103e46e4SHarish Mahendrakar       BlockEntry** const entries = new (std::nothrow) BlockEntry*[entries_size];
7180*103e46e4SHarish Mahendrakar       if (entries == NULL)
7181*103e46e4SHarish Mahendrakar         return -1;
7182*103e46e4SHarish Mahendrakar 
7183*103e46e4SHarish Mahendrakar       BlockEntry** src = m_entries;
7184*103e46e4SHarish Mahendrakar       BlockEntry** const src_end = src + m_entries_count;
7185*103e46e4SHarish Mahendrakar 
7186*103e46e4SHarish Mahendrakar       BlockEntry** dst = entries;
7187*103e46e4SHarish Mahendrakar 
7188*103e46e4SHarish Mahendrakar       while (src != src_end)
7189*103e46e4SHarish Mahendrakar         *dst++ = *src++;
7190*103e46e4SHarish Mahendrakar 
7191*103e46e4SHarish Mahendrakar       delete[] m_entries;
7192*103e46e4SHarish Mahendrakar 
7193*103e46e4SHarish Mahendrakar       m_entries = entries;
7194*103e46e4SHarish Mahendrakar       m_entries_size = entries_size;
7195*103e46e4SHarish Mahendrakar     }
7196*103e46e4SHarish Mahendrakar   }
7197*103e46e4SHarish Mahendrakar 
7198*103e46e4SHarish Mahendrakar   if (id == libwebm::kMkvBlockGroup)
7199*103e46e4SHarish Mahendrakar     return CreateBlockGroup(pos, size, discard_padding);
7200*103e46e4SHarish Mahendrakar   else
7201*103e46e4SHarish Mahendrakar     return CreateSimpleBlock(pos, size);
7202*103e46e4SHarish Mahendrakar }
7203*103e46e4SHarish Mahendrakar 
CreateBlockGroup(long long start_offset,long long size,long long discard_padding)7204*103e46e4SHarish Mahendrakar long Cluster::CreateBlockGroup(long long start_offset, long long size,
7205*103e46e4SHarish Mahendrakar                                long long discard_padding) {
7206*103e46e4SHarish Mahendrakar   assert(m_entries);
7207*103e46e4SHarish Mahendrakar   assert(m_entries_size > 0);
7208*103e46e4SHarish Mahendrakar   assert(m_entries_count >= 0);
7209*103e46e4SHarish Mahendrakar   assert(m_entries_count < m_entries_size);
7210*103e46e4SHarish Mahendrakar 
7211*103e46e4SHarish Mahendrakar   IMkvReader* const pReader = m_pSegment->m_pReader;
7212*103e46e4SHarish Mahendrakar 
7213*103e46e4SHarish Mahendrakar   long long pos = start_offset;
7214*103e46e4SHarish Mahendrakar   const long long stop = start_offset + size;
7215*103e46e4SHarish Mahendrakar 
7216*103e46e4SHarish Mahendrakar   // For WebM files, there is a bias towards previous reference times
7217*103e46e4SHarish Mahendrakar   //(in order to support alt-ref frames, which refer back to the previous
7218*103e46e4SHarish Mahendrakar   // keyframe).  Normally a 0 value is not possible, but here we tenatively
7219*103e46e4SHarish Mahendrakar   // allow 0 as the value of a reference frame, with the interpretation
7220*103e46e4SHarish Mahendrakar   // that this is a "previous" reference time.
7221*103e46e4SHarish Mahendrakar 
7222*103e46e4SHarish Mahendrakar   long long prev = 1;  // nonce
7223*103e46e4SHarish Mahendrakar   long long next = 0;  // nonce
7224*103e46e4SHarish Mahendrakar   long long duration = -1;  // really, this is unsigned
7225*103e46e4SHarish Mahendrakar 
7226*103e46e4SHarish Mahendrakar   long long bpos = -1;
7227*103e46e4SHarish Mahendrakar   long long bsize = -1;
7228*103e46e4SHarish Mahendrakar 
7229*103e46e4SHarish Mahendrakar   while (pos < stop) {
7230*103e46e4SHarish Mahendrakar     long len;
7231*103e46e4SHarish Mahendrakar     const long long id = ReadID(pReader, pos, len);
7232*103e46e4SHarish Mahendrakar     if (id < 0 || (pos + len) > stop)
7233*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
7234*103e46e4SHarish Mahendrakar 
7235*103e46e4SHarish Mahendrakar     pos += len;  // consume ID
7236*103e46e4SHarish Mahendrakar 
7237*103e46e4SHarish Mahendrakar     const long long size = ReadUInt(pReader, pos, len);
7238*103e46e4SHarish Mahendrakar     assert(size >= 0);  // TODO
7239*103e46e4SHarish Mahendrakar     assert((pos + len) <= stop);
7240*103e46e4SHarish Mahendrakar 
7241*103e46e4SHarish Mahendrakar     pos += len;  // consume size
7242*103e46e4SHarish Mahendrakar 
7243*103e46e4SHarish Mahendrakar     if (id == libwebm::kMkvBlock) {
7244*103e46e4SHarish Mahendrakar       if (bpos < 0) {  // Block ID
7245*103e46e4SHarish Mahendrakar         bpos = pos;
7246*103e46e4SHarish Mahendrakar         bsize = size;
7247*103e46e4SHarish Mahendrakar       }
7248*103e46e4SHarish Mahendrakar     } else if (id == libwebm::kMkvBlockDuration) {
7249*103e46e4SHarish Mahendrakar       if (size > 8)
7250*103e46e4SHarish Mahendrakar         return E_FILE_FORMAT_INVALID;
7251*103e46e4SHarish Mahendrakar 
7252*103e46e4SHarish Mahendrakar       duration = UnserializeUInt(pReader, pos, size);
7253*103e46e4SHarish Mahendrakar 
7254*103e46e4SHarish Mahendrakar       if (duration < 0)
7255*103e46e4SHarish Mahendrakar         return E_FILE_FORMAT_INVALID;
7256*103e46e4SHarish Mahendrakar     } else if (id == libwebm::kMkvReferenceBlock) {
7257*103e46e4SHarish Mahendrakar       if (size > 8 || size <= 0)
7258*103e46e4SHarish Mahendrakar         return E_FILE_FORMAT_INVALID;
7259*103e46e4SHarish Mahendrakar       const long size_ = static_cast<long>(size);
7260*103e46e4SHarish Mahendrakar 
7261*103e46e4SHarish Mahendrakar       long long time;
7262*103e46e4SHarish Mahendrakar 
7263*103e46e4SHarish Mahendrakar       long status = UnserializeInt(pReader, pos, size_, time);
7264*103e46e4SHarish Mahendrakar       assert(status == 0);
7265*103e46e4SHarish Mahendrakar       if (status != 0)
7266*103e46e4SHarish Mahendrakar         return -1;
7267*103e46e4SHarish Mahendrakar 
7268*103e46e4SHarish Mahendrakar       if (time <= 0)  // see note above
7269*103e46e4SHarish Mahendrakar         prev = time;
7270*103e46e4SHarish Mahendrakar       else
7271*103e46e4SHarish Mahendrakar         next = time;
7272*103e46e4SHarish Mahendrakar     }
7273*103e46e4SHarish Mahendrakar 
7274*103e46e4SHarish Mahendrakar     pos += size;  // consume payload
7275*103e46e4SHarish Mahendrakar     if (pos > stop)
7276*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
7277*103e46e4SHarish Mahendrakar   }
7278*103e46e4SHarish Mahendrakar   if (bpos < 0)
7279*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
7280*103e46e4SHarish Mahendrakar 
7281*103e46e4SHarish Mahendrakar   if (pos != stop)
7282*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
7283*103e46e4SHarish Mahendrakar   assert(bsize >= 0);
7284*103e46e4SHarish Mahendrakar 
7285*103e46e4SHarish Mahendrakar   const long idx = m_entries_count;
7286*103e46e4SHarish Mahendrakar 
7287*103e46e4SHarish Mahendrakar   BlockEntry** const ppEntry = m_entries + idx;
7288*103e46e4SHarish Mahendrakar   BlockEntry*& pEntry = *ppEntry;
7289*103e46e4SHarish Mahendrakar 
7290*103e46e4SHarish Mahendrakar   pEntry = new (std::nothrow)
7291*103e46e4SHarish Mahendrakar       BlockGroup(this, idx, bpos, bsize, prev, next, duration, discard_padding);
7292*103e46e4SHarish Mahendrakar 
7293*103e46e4SHarish Mahendrakar   if (pEntry == NULL)
7294*103e46e4SHarish Mahendrakar     return -1;  // generic error
7295*103e46e4SHarish Mahendrakar 
7296*103e46e4SHarish Mahendrakar   BlockGroup* const p = static_cast<BlockGroup*>(pEntry);
7297*103e46e4SHarish Mahendrakar 
7298*103e46e4SHarish Mahendrakar   const long status = p->Parse();
7299*103e46e4SHarish Mahendrakar 
7300*103e46e4SHarish Mahendrakar   if (status == 0) {  // success
7301*103e46e4SHarish Mahendrakar     ++m_entries_count;
7302*103e46e4SHarish Mahendrakar     return 0;
7303*103e46e4SHarish Mahendrakar   }
7304*103e46e4SHarish Mahendrakar 
7305*103e46e4SHarish Mahendrakar   delete pEntry;
7306*103e46e4SHarish Mahendrakar   pEntry = 0;
7307*103e46e4SHarish Mahendrakar 
7308*103e46e4SHarish Mahendrakar   return status;
7309*103e46e4SHarish Mahendrakar }
7310*103e46e4SHarish Mahendrakar 
CreateSimpleBlock(long long st,long long sz)7311*103e46e4SHarish Mahendrakar long Cluster::CreateSimpleBlock(long long st, long long sz) {
7312*103e46e4SHarish Mahendrakar   assert(m_entries);
7313*103e46e4SHarish Mahendrakar   assert(m_entries_size > 0);
7314*103e46e4SHarish Mahendrakar   assert(m_entries_count >= 0);
7315*103e46e4SHarish Mahendrakar   assert(m_entries_count < m_entries_size);
7316*103e46e4SHarish Mahendrakar 
7317*103e46e4SHarish Mahendrakar   const long idx = m_entries_count;
7318*103e46e4SHarish Mahendrakar 
7319*103e46e4SHarish Mahendrakar   BlockEntry** const ppEntry = m_entries + idx;
7320*103e46e4SHarish Mahendrakar   BlockEntry*& pEntry = *ppEntry;
7321*103e46e4SHarish Mahendrakar 
7322*103e46e4SHarish Mahendrakar   pEntry = new (std::nothrow) SimpleBlock(this, idx, st, sz);
7323*103e46e4SHarish Mahendrakar 
7324*103e46e4SHarish Mahendrakar   if (pEntry == NULL)
7325*103e46e4SHarish Mahendrakar     return -1;  // generic error
7326*103e46e4SHarish Mahendrakar 
7327*103e46e4SHarish Mahendrakar   SimpleBlock* const p = static_cast<SimpleBlock*>(pEntry);
7328*103e46e4SHarish Mahendrakar 
7329*103e46e4SHarish Mahendrakar   const long status = p->Parse();
7330*103e46e4SHarish Mahendrakar 
7331*103e46e4SHarish Mahendrakar   if (status == 0) {
7332*103e46e4SHarish Mahendrakar     ++m_entries_count;
7333*103e46e4SHarish Mahendrakar     return 0;
7334*103e46e4SHarish Mahendrakar   }
7335*103e46e4SHarish Mahendrakar 
7336*103e46e4SHarish Mahendrakar   delete pEntry;
7337*103e46e4SHarish Mahendrakar   pEntry = 0;
7338*103e46e4SHarish Mahendrakar 
7339*103e46e4SHarish Mahendrakar   return status;
7340*103e46e4SHarish Mahendrakar }
7341*103e46e4SHarish Mahendrakar 
GetFirst(const BlockEntry * & pFirst) const7342*103e46e4SHarish Mahendrakar long Cluster::GetFirst(const BlockEntry*& pFirst) const {
7343*103e46e4SHarish Mahendrakar   if (m_entries_count <= 0) {
7344*103e46e4SHarish Mahendrakar     long long pos;
7345*103e46e4SHarish Mahendrakar     long len;
7346*103e46e4SHarish Mahendrakar 
7347*103e46e4SHarish Mahendrakar     const long status = Parse(pos, len);
7348*103e46e4SHarish Mahendrakar 
7349*103e46e4SHarish Mahendrakar     if (status < 0) {  // error
7350*103e46e4SHarish Mahendrakar       pFirst = NULL;
7351*103e46e4SHarish Mahendrakar       return status;
7352*103e46e4SHarish Mahendrakar     }
7353*103e46e4SHarish Mahendrakar 
7354*103e46e4SHarish Mahendrakar     if (m_entries_count <= 0) {  // empty cluster
7355*103e46e4SHarish Mahendrakar       pFirst = NULL;
7356*103e46e4SHarish Mahendrakar       return 0;
7357*103e46e4SHarish Mahendrakar     }
7358*103e46e4SHarish Mahendrakar   }
7359*103e46e4SHarish Mahendrakar 
7360*103e46e4SHarish Mahendrakar   assert(m_entries);
7361*103e46e4SHarish Mahendrakar 
7362*103e46e4SHarish Mahendrakar   pFirst = m_entries[0];
7363*103e46e4SHarish Mahendrakar   assert(pFirst);
7364*103e46e4SHarish Mahendrakar 
7365*103e46e4SHarish Mahendrakar   return 0;  // success
7366*103e46e4SHarish Mahendrakar }
7367*103e46e4SHarish Mahendrakar 
GetLast(const BlockEntry * & pLast) const7368*103e46e4SHarish Mahendrakar long Cluster::GetLast(const BlockEntry*& pLast) const {
7369*103e46e4SHarish Mahendrakar   for (;;) {
7370*103e46e4SHarish Mahendrakar     long long pos;
7371*103e46e4SHarish Mahendrakar     long len;
7372*103e46e4SHarish Mahendrakar 
7373*103e46e4SHarish Mahendrakar     const long status = Parse(pos, len);
7374*103e46e4SHarish Mahendrakar 
7375*103e46e4SHarish Mahendrakar     if (status < 0) {  // error
7376*103e46e4SHarish Mahendrakar       pLast = NULL;
7377*103e46e4SHarish Mahendrakar       return status;
7378*103e46e4SHarish Mahendrakar     }
7379*103e46e4SHarish Mahendrakar 
7380*103e46e4SHarish Mahendrakar     if (status > 0)  // no new block
7381*103e46e4SHarish Mahendrakar       break;
7382*103e46e4SHarish Mahendrakar   }
7383*103e46e4SHarish Mahendrakar 
7384*103e46e4SHarish Mahendrakar   if (m_entries_count <= 0) {
7385*103e46e4SHarish Mahendrakar     pLast = NULL;
7386*103e46e4SHarish Mahendrakar     return 0;
7387*103e46e4SHarish Mahendrakar   }
7388*103e46e4SHarish Mahendrakar 
7389*103e46e4SHarish Mahendrakar   assert(m_entries);
7390*103e46e4SHarish Mahendrakar 
7391*103e46e4SHarish Mahendrakar   const long idx = m_entries_count - 1;
7392*103e46e4SHarish Mahendrakar 
7393*103e46e4SHarish Mahendrakar   pLast = m_entries[idx];
7394*103e46e4SHarish Mahendrakar   assert(pLast);
7395*103e46e4SHarish Mahendrakar 
7396*103e46e4SHarish Mahendrakar   return 0;
7397*103e46e4SHarish Mahendrakar }
7398*103e46e4SHarish Mahendrakar 
GetNext(const BlockEntry * pCurr,const BlockEntry * & pNext) const7399*103e46e4SHarish Mahendrakar long Cluster::GetNext(const BlockEntry* pCurr, const BlockEntry*& pNext) const {
7400*103e46e4SHarish Mahendrakar   assert(pCurr);
7401*103e46e4SHarish Mahendrakar   assert(m_entries);
7402*103e46e4SHarish Mahendrakar   assert(m_entries_count > 0);
7403*103e46e4SHarish Mahendrakar 
7404*103e46e4SHarish Mahendrakar   size_t idx = pCurr->GetIndex();
7405*103e46e4SHarish Mahendrakar   assert(idx < size_t(m_entries_count));
7406*103e46e4SHarish Mahendrakar   assert(m_entries[idx] == pCurr);
7407*103e46e4SHarish Mahendrakar 
7408*103e46e4SHarish Mahendrakar   ++idx;
7409*103e46e4SHarish Mahendrakar 
7410*103e46e4SHarish Mahendrakar   if (idx >= size_t(m_entries_count)) {
7411*103e46e4SHarish Mahendrakar     long long pos;
7412*103e46e4SHarish Mahendrakar     long len;
7413*103e46e4SHarish Mahendrakar 
7414*103e46e4SHarish Mahendrakar     const long status = Parse(pos, len);
7415*103e46e4SHarish Mahendrakar 
7416*103e46e4SHarish Mahendrakar     if (status < 0) {  // error
7417*103e46e4SHarish Mahendrakar       pNext = NULL;
7418*103e46e4SHarish Mahendrakar       return status;
7419*103e46e4SHarish Mahendrakar     }
7420*103e46e4SHarish Mahendrakar 
7421*103e46e4SHarish Mahendrakar     if (status > 0) {
7422*103e46e4SHarish Mahendrakar       pNext = NULL;
7423*103e46e4SHarish Mahendrakar       return 0;
7424*103e46e4SHarish Mahendrakar     }
7425*103e46e4SHarish Mahendrakar 
7426*103e46e4SHarish Mahendrakar     assert(m_entries);
7427*103e46e4SHarish Mahendrakar     assert(m_entries_count > 0);
7428*103e46e4SHarish Mahendrakar     assert(idx < size_t(m_entries_count));
7429*103e46e4SHarish Mahendrakar   }
7430*103e46e4SHarish Mahendrakar 
7431*103e46e4SHarish Mahendrakar   pNext = m_entries[idx];
7432*103e46e4SHarish Mahendrakar   assert(pNext);
7433*103e46e4SHarish Mahendrakar 
7434*103e46e4SHarish Mahendrakar   return 0;
7435*103e46e4SHarish Mahendrakar }
7436*103e46e4SHarish Mahendrakar 
GetEntryCount() const7437*103e46e4SHarish Mahendrakar long Cluster::GetEntryCount() const { return m_entries_count; }
7438*103e46e4SHarish Mahendrakar 
GetEntry(const Track * pTrack,long long time_ns) const7439*103e46e4SHarish Mahendrakar const BlockEntry* Cluster::GetEntry(const Track* pTrack,
7440*103e46e4SHarish Mahendrakar                                     long long time_ns) const {
7441*103e46e4SHarish Mahendrakar   assert(pTrack);
7442*103e46e4SHarish Mahendrakar 
7443*103e46e4SHarish Mahendrakar   if (m_pSegment == NULL)  // this is the special EOS cluster
7444*103e46e4SHarish Mahendrakar     return pTrack->GetEOS();
7445*103e46e4SHarish Mahendrakar 
7446*103e46e4SHarish Mahendrakar   const BlockEntry* pResult = pTrack->GetEOS();
7447*103e46e4SHarish Mahendrakar 
7448*103e46e4SHarish Mahendrakar   long index = 0;
7449*103e46e4SHarish Mahendrakar 
7450*103e46e4SHarish Mahendrakar   for (;;) {
7451*103e46e4SHarish Mahendrakar     if (index >= m_entries_count) {
7452*103e46e4SHarish Mahendrakar       long long pos;
7453*103e46e4SHarish Mahendrakar       long len;
7454*103e46e4SHarish Mahendrakar 
7455*103e46e4SHarish Mahendrakar       const long status = Parse(pos, len);
7456*103e46e4SHarish Mahendrakar       assert(status >= 0);
7457*103e46e4SHarish Mahendrakar 
7458*103e46e4SHarish Mahendrakar       if (status > 0)  // completely parsed, and no more entries
7459*103e46e4SHarish Mahendrakar         return pResult;
7460*103e46e4SHarish Mahendrakar 
7461*103e46e4SHarish Mahendrakar       if (status < 0)  // should never happen
7462*103e46e4SHarish Mahendrakar         return 0;
7463*103e46e4SHarish Mahendrakar 
7464*103e46e4SHarish Mahendrakar       assert(m_entries);
7465*103e46e4SHarish Mahendrakar       assert(index < m_entries_count);
7466*103e46e4SHarish Mahendrakar     }
7467*103e46e4SHarish Mahendrakar 
7468*103e46e4SHarish Mahendrakar     const BlockEntry* const pEntry = m_entries[index];
7469*103e46e4SHarish Mahendrakar     assert(pEntry);
7470*103e46e4SHarish Mahendrakar     assert(!pEntry->EOS());
7471*103e46e4SHarish Mahendrakar 
7472*103e46e4SHarish Mahendrakar     const Block* const pBlock = pEntry->GetBlock();
7473*103e46e4SHarish Mahendrakar     assert(pBlock);
7474*103e46e4SHarish Mahendrakar 
7475*103e46e4SHarish Mahendrakar     if (pBlock->GetTrackNumber() != pTrack->GetNumber()) {
7476*103e46e4SHarish Mahendrakar       ++index;
7477*103e46e4SHarish Mahendrakar       continue;
7478*103e46e4SHarish Mahendrakar     }
7479*103e46e4SHarish Mahendrakar 
7480*103e46e4SHarish Mahendrakar     if (pTrack->VetEntry(pEntry)) {
7481*103e46e4SHarish Mahendrakar       if (time_ns < 0)  // just want first candidate block
7482*103e46e4SHarish Mahendrakar         return pEntry;
7483*103e46e4SHarish Mahendrakar 
7484*103e46e4SHarish Mahendrakar       const long long ns = pBlock->GetTime(this);
7485*103e46e4SHarish Mahendrakar 
7486*103e46e4SHarish Mahendrakar       if (ns > time_ns)
7487*103e46e4SHarish Mahendrakar         return pResult;
7488*103e46e4SHarish Mahendrakar 
7489*103e46e4SHarish Mahendrakar       pResult = pEntry;  // have a candidate
7490*103e46e4SHarish Mahendrakar     } else if (time_ns >= 0) {
7491*103e46e4SHarish Mahendrakar       const long long ns = pBlock->GetTime(this);
7492*103e46e4SHarish Mahendrakar 
7493*103e46e4SHarish Mahendrakar       if (ns > time_ns)
7494*103e46e4SHarish Mahendrakar         return pResult;
7495*103e46e4SHarish Mahendrakar     }
7496*103e46e4SHarish Mahendrakar 
7497*103e46e4SHarish Mahendrakar     ++index;
7498*103e46e4SHarish Mahendrakar   }
7499*103e46e4SHarish Mahendrakar }
7500*103e46e4SHarish Mahendrakar 
GetEntry(const CuePoint & cp,const CuePoint::TrackPosition & tp) const7501*103e46e4SHarish Mahendrakar const BlockEntry* Cluster::GetEntry(const CuePoint& cp,
7502*103e46e4SHarish Mahendrakar                                     const CuePoint::TrackPosition& tp) const {
7503*103e46e4SHarish Mahendrakar   assert(m_pSegment);
7504*103e46e4SHarish Mahendrakar   const long long tc = cp.GetTimeCode();
7505*103e46e4SHarish Mahendrakar 
7506*103e46e4SHarish Mahendrakar   if (tp.m_block > 0) {
7507*103e46e4SHarish Mahendrakar     const long block = static_cast<long>(tp.m_block);
7508*103e46e4SHarish Mahendrakar     const long index = block - 1;
7509*103e46e4SHarish Mahendrakar 
7510*103e46e4SHarish Mahendrakar     while (index >= m_entries_count) {
7511*103e46e4SHarish Mahendrakar       long long pos;
7512*103e46e4SHarish Mahendrakar       long len;
7513*103e46e4SHarish Mahendrakar 
7514*103e46e4SHarish Mahendrakar       const long status = Parse(pos, len);
7515*103e46e4SHarish Mahendrakar 
7516*103e46e4SHarish Mahendrakar       if (status < 0)  // TODO: can this happen?
7517*103e46e4SHarish Mahendrakar         return NULL;
7518*103e46e4SHarish Mahendrakar 
7519*103e46e4SHarish Mahendrakar       if (status > 0)  // nothing remains to be parsed
7520*103e46e4SHarish Mahendrakar         return NULL;
7521*103e46e4SHarish Mahendrakar     }
7522*103e46e4SHarish Mahendrakar 
7523*103e46e4SHarish Mahendrakar     const BlockEntry* const pEntry = m_entries[index];
7524*103e46e4SHarish Mahendrakar     assert(pEntry);
7525*103e46e4SHarish Mahendrakar     assert(!pEntry->EOS());
7526*103e46e4SHarish Mahendrakar 
7527*103e46e4SHarish Mahendrakar     const Block* const pBlock = pEntry->GetBlock();
7528*103e46e4SHarish Mahendrakar     assert(pBlock);
7529*103e46e4SHarish Mahendrakar 
7530*103e46e4SHarish Mahendrakar     if ((pBlock->GetTrackNumber() == tp.m_track) &&
7531*103e46e4SHarish Mahendrakar         (pBlock->GetTimeCode(this) == tc)) {
7532*103e46e4SHarish Mahendrakar       return pEntry;
7533*103e46e4SHarish Mahendrakar     }
7534*103e46e4SHarish Mahendrakar   }
7535*103e46e4SHarish Mahendrakar 
7536*103e46e4SHarish Mahendrakar   long index = 0;
7537*103e46e4SHarish Mahendrakar 
7538*103e46e4SHarish Mahendrakar   for (;;) {
7539*103e46e4SHarish Mahendrakar     if (index >= m_entries_count) {
7540*103e46e4SHarish Mahendrakar       long long pos;
7541*103e46e4SHarish Mahendrakar       long len;
7542*103e46e4SHarish Mahendrakar 
7543*103e46e4SHarish Mahendrakar       const long status = Parse(pos, len);
7544*103e46e4SHarish Mahendrakar 
7545*103e46e4SHarish Mahendrakar       if (status < 0)  // TODO: can this happen?
7546*103e46e4SHarish Mahendrakar         return NULL;
7547*103e46e4SHarish Mahendrakar 
7548*103e46e4SHarish Mahendrakar       if (status > 0)  // nothing remains to be parsed
7549*103e46e4SHarish Mahendrakar         return NULL;
7550*103e46e4SHarish Mahendrakar 
7551*103e46e4SHarish Mahendrakar       assert(m_entries);
7552*103e46e4SHarish Mahendrakar       assert(index < m_entries_count);
7553*103e46e4SHarish Mahendrakar     }
7554*103e46e4SHarish Mahendrakar 
7555*103e46e4SHarish Mahendrakar     const BlockEntry* const pEntry = m_entries[index];
7556*103e46e4SHarish Mahendrakar     assert(pEntry);
7557*103e46e4SHarish Mahendrakar     assert(!pEntry->EOS());
7558*103e46e4SHarish Mahendrakar 
7559*103e46e4SHarish Mahendrakar     const Block* const pBlock = pEntry->GetBlock();
7560*103e46e4SHarish Mahendrakar     assert(pBlock);
7561*103e46e4SHarish Mahendrakar 
7562*103e46e4SHarish Mahendrakar     if (pBlock->GetTrackNumber() != tp.m_track) {
7563*103e46e4SHarish Mahendrakar       ++index;
7564*103e46e4SHarish Mahendrakar       continue;
7565*103e46e4SHarish Mahendrakar     }
7566*103e46e4SHarish Mahendrakar 
7567*103e46e4SHarish Mahendrakar     const long long tc_ = pBlock->GetTimeCode(this);
7568*103e46e4SHarish Mahendrakar 
7569*103e46e4SHarish Mahendrakar     if (tc_ < tc) {
7570*103e46e4SHarish Mahendrakar       ++index;
7571*103e46e4SHarish Mahendrakar       continue;
7572*103e46e4SHarish Mahendrakar     }
7573*103e46e4SHarish Mahendrakar 
7574*103e46e4SHarish Mahendrakar     if (tc_ > tc)
7575*103e46e4SHarish Mahendrakar       return NULL;
7576*103e46e4SHarish Mahendrakar 
7577*103e46e4SHarish Mahendrakar     const Tracks* const pTracks = m_pSegment->GetTracks();
7578*103e46e4SHarish Mahendrakar     assert(pTracks);
7579*103e46e4SHarish Mahendrakar 
7580*103e46e4SHarish Mahendrakar     const long tn = static_cast<long>(tp.m_track);
7581*103e46e4SHarish Mahendrakar     const Track* const pTrack = pTracks->GetTrackByNumber(tn);
7582*103e46e4SHarish Mahendrakar 
7583*103e46e4SHarish Mahendrakar     if (pTrack == NULL)
7584*103e46e4SHarish Mahendrakar       return NULL;
7585*103e46e4SHarish Mahendrakar 
7586*103e46e4SHarish Mahendrakar     const long long type = pTrack->GetType();
7587*103e46e4SHarish Mahendrakar 
7588*103e46e4SHarish Mahendrakar     if (type == 2)  // audio
7589*103e46e4SHarish Mahendrakar       return pEntry;
7590*103e46e4SHarish Mahendrakar 
7591*103e46e4SHarish Mahendrakar     if (type != 1)  // not video
7592*103e46e4SHarish Mahendrakar       return NULL;
7593*103e46e4SHarish Mahendrakar 
7594*103e46e4SHarish Mahendrakar     if (!pBlock->IsKey())
7595*103e46e4SHarish Mahendrakar       return NULL;
7596*103e46e4SHarish Mahendrakar 
7597*103e46e4SHarish Mahendrakar     return pEntry;
7598*103e46e4SHarish Mahendrakar   }
7599*103e46e4SHarish Mahendrakar }
7600*103e46e4SHarish Mahendrakar 
BlockEntry(Cluster * p,long idx)7601*103e46e4SHarish Mahendrakar BlockEntry::BlockEntry(Cluster* p, long idx) : m_pCluster(p), m_index(idx) {}
~BlockEntry()7602*103e46e4SHarish Mahendrakar BlockEntry::~BlockEntry() {}
GetCluster() const7603*103e46e4SHarish Mahendrakar const Cluster* BlockEntry::GetCluster() const { return m_pCluster; }
GetIndex() const7604*103e46e4SHarish Mahendrakar long BlockEntry::GetIndex() const { return m_index; }
7605*103e46e4SHarish Mahendrakar 
SimpleBlock(Cluster * pCluster,long idx,long long start,long long size)7606*103e46e4SHarish Mahendrakar SimpleBlock::SimpleBlock(Cluster* pCluster, long idx, long long start,
7607*103e46e4SHarish Mahendrakar                          long long size)
7608*103e46e4SHarish Mahendrakar     : BlockEntry(pCluster, idx), m_block(start, size, 0) {}
7609*103e46e4SHarish Mahendrakar 
Parse()7610*103e46e4SHarish Mahendrakar long SimpleBlock::Parse() { return m_block.Parse(m_pCluster); }
GetKind() const7611*103e46e4SHarish Mahendrakar BlockEntry::Kind SimpleBlock::GetKind() const { return kBlockSimple; }
GetBlock() const7612*103e46e4SHarish Mahendrakar const Block* SimpleBlock::GetBlock() const { return &m_block; }
7613*103e46e4SHarish Mahendrakar 
BlockGroup(Cluster * pCluster,long idx,long long block_start,long long block_size,long long prev,long long next,long long duration,long long discard_padding)7614*103e46e4SHarish Mahendrakar BlockGroup::BlockGroup(Cluster* pCluster, long idx, long long block_start,
7615*103e46e4SHarish Mahendrakar                        long long block_size, long long prev, long long next,
7616*103e46e4SHarish Mahendrakar                        long long duration, long long discard_padding)
7617*103e46e4SHarish Mahendrakar     : BlockEntry(pCluster, idx),
7618*103e46e4SHarish Mahendrakar       m_block(block_start, block_size, discard_padding),
7619*103e46e4SHarish Mahendrakar       m_prev(prev),
7620*103e46e4SHarish Mahendrakar       m_next(next),
7621*103e46e4SHarish Mahendrakar       m_duration(duration) {}
7622*103e46e4SHarish Mahendrakar 
Parse()7623*103e46e4SHarish Mahendrakar long BlockGroup::Parse() {
7624*103e46e4SHarish Mahendrakar   const long status = m_block.Parse(m_pCluster);
7625*103e46e4SHarish Mahendrakar 
7626*103e46e4SHarish Mahendrakar   if (status)
7627*103e46e4SHarish Mahendrakar     return status;
7628*103e46e4SHarish Mahendrakar 
7629*103e46e4SHarish Mahendrakar   m_block.SetKey((m_prev > 0) && (m_next <= 0));
7630*103e46e4SHarish Mahendrakar 
7631*103e46e4SHarish Mahendrakar   return 0;
7632*103e46e4SHarish Mahendrakar }
7633*103e46e4SHarish Mahendrakar 
GetKind() const7634*103e46e4SHarish Mahendrakar BlockEntry::Kind BlockGroup::GetKind() const { return kBlockGroup; }
GetBlock() const7635*103e46e4SHarish Mahendrakar const Block* BlockGroup::GetBlock() const { return &m_block; }
GetPrevTimeCode() const7636*103e46e4SHarish Mahendrakar long long BlockGroup::GetPrevTimeCode() const { return m_prev; }
GetNextTimeCode() const7637*103e46e4SHarish Mahendrakar long long BlockGroup::GetNextTimeCode() const { return m_next; }
GetDurationTimeCode() const7638*103e46e4SHarish Mahendrakar long long BlockGroup::GetDurationTimeCode() const { return m_duration; }
7639*103e46e4SHarish Mahendrakar 
Block(long long start,long long size_,long long discard_padding)7640*103e46e4SHarish Mahendrakar Block::Block(long long start, long long size_, long long discard_padding)
7641*103e46e4SHarish Mahendrakar     : m_start(start),
7642*103e46e4SHarish Mahendrakar       m_size(size_),
7643*103e46e4SHarish Mahendrakar       m_track(0),
7644*103e46e4SHarish Mahendrakar       m_timecode(-1),
7645*103e46e4SHarish Mahendrakar       m_flags(0),
7646*103e46e4SHarish Mahendrakar       m_frames(NULL),
7647*103e46e4SHarish Mahendrakar       m_frame_count(-1),
7648*103e46e4SHarish Mahendrakar       m_discard_padding(discard_padding) {}
7649*103e46e4SHarish Mahendrakar 
~Block()7650*103e46e4SHarish Mahendrakar Block::~Block() { delete[] m_frames; }
7651*103e46e4SHarish Mahendrakar 
Parse(const Cluster * pCluster)7652*103e46e4SHarish Mahendrakar long Block::Parse(const Cluster* pCluster) {
7653*103e46e4SHarish Mahendrakar   if (pCluster == NULL)
7654*103e46e4SHarish Mahendrakar     return -1;
7655*103e46e4SHarish Mahendrakar 
7656*103e46e4SHarish Mahendrakar   if (pCluster->m_pSegment == NULL)
7657*103e46e4SHarish Mahendrakar     return -1;
7658*103e46e4SHarish Mahendrakar 
7659*103e46e4SHarish Mahendrakar   assert(m_start >= 0);
7660*103e46e4SHarish Mahendrakar   assert(m_size >= 0);
7661*103e46e4SHarish Mahendrakar   assert(m_track <= 0);
7662*103e46e4SHarish Mahendrakar   assert(m_frames == NULL);
7663*103e46e4SHarish Mahendrakar   assert(m_frame_count <= 0);
7664*103e46e4SHarish Mahendrakar 
7665*103e46e4SHarish Mahendrakar   long long pos = m_start;
7666*103e46e4SHarish Mahendrakar   const long long stop = m_start + m_size;
7667*103e46e4SHarish Mahendrakar 
7668*103e46e4SHarish Mahendrakar   long len;
7669*103e46e4SHarish Mahendrakar 
7670*103e46e4SHarish Mahendrakar   IMkvReader* const pReader = pCluster->m_pSegment->m_pReader;
7671*103e46e4SHarish Mahendrakar 
7672*103e46e4SHarish Mahendrakar   m_track = ReadUInt(pReader, pos, len);
7673*103e46e4SHarish Mahendrakar 
7674*103e46e4SHarish Mahendrakar   if (m_track <= 0)
7675*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
7676*103e46e4SHarish Mahendrakar 
7677*103e46e4SHarish Mahendrakar   if ((pos + len) > stop)
7678*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
7679*103e46e4SHarish Mahendrakar 
7680*103e46e4SHarish Mahendrakar   pos += len;  // consume track number
7681*103e46e4SHarish Mahendrakar 
7682*103e46e4SHarish Mahendrakar   if ((stop - pos) < 2)
7683*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
7684*103e46e4SHarish Mahendrakar 
7685*103e46e4SHarish Mahendrakar   long status;
7686*103e46e4SHarish Mahendrakar   long long value;
7687*103e46e4SHarish Mahendrakar 
7688*103e46e4SHarish Mahendrakar   status = UnserializeInt(pReader, pos, 2, value);
7689*103e46e4SHarish Mahendrakar 
7690*103e46e4SHarish Mahendrakar   if (status)
7691*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
7692*103e46e4SHarish Mahendrakar 
7693*103e46e4SHarish Mahendrakar   if (value < SHRT_MIN)
7694*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
7695*103e46e4SHarish Mahendrakar 
7696*103e46e4SHarish Mahendrakar   if (value > SHRT_MAX)
7697*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
7698*103e46e4SHarish Mahendrakar 
7699*103e46e4SHarish Mahendrakar   m_timecode = static_cast<short>(value);
7700*103e46e4SHarish Mahendrakar 
7701*103e46e4SHarish Mahendrakar   pos += 2;
7702*103e46e4SHarish Mahendrakar 
7703*103e46e4SHarish Mahendrakar   if ((stop - pos) <= 0)
7704*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
7705*103e46e4SHarish Mahendrakar 
7706*103e46e4SHarish Mahendrakar   status = pReader->Read(pos, 1, &m_flags);
7707*103e46e4SHarish Mahendrakar 
7708*103e46e4SHarish Mahendrakar   if (status)
7709*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
7710*103e46e4SHarish Mahendrakar 
7711*103e46e4SHarish Mahendrakar   const int lacing = int(m_flags & 0x06) >> 1;
7712*103e46e4SHarish Mahendrakar 
7713*103e46e4SHarish Mahendrakar   ++pos;  // consume flags byte
7714*103e46e4SHarish Mahendrakar 
7715*103e46e4SHarish Mahendrakar   if (lacing == 0) {  // no lacing
7716*103e46e4SHarish Mahendrakar     if (pos > stop)
7717*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
7718*103e46e4SHarish Mahendrakar 
7719*103e46e4SHarish Mahendrakar     m_frame_count = 1;
7720*103e46e4SHarish Mahendrakar     m_frames = new (std::nothrow) Frame[m_frame_count];
7721*103e46e4SHarish Mahendrakar     if (m_frames == NULL)
7722*103e46e4SHarish Mahendrakar       return -1;
7723*103e46e4SHarish Mahendrakar 
7724*103e46e4SHarish Mahendrakar     Frame& f = m_frames[0];
7725*103e46e4SHarish Mahendrakar     f.pos = pos;
7726*103e46e4SHarish Mahendrakar 
7727*103e46e4SHarish Mahendrakar     const long long frame_size = stop - pos;
7728*103e46e4SHarish Mahendrakar 
7729*103e46e4SHarish Mahendrakar     if (frame_size > LONG_MAX || frame_size <= 0)
7730*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
7731*103e46e4SHarish Mahendrakar 
7732*103e46e4SHarish Mahendrakar     f.len = static_cast<long>(frame_size);
7733*103e46e4SHarish Mahendrakar 
7734*103e46e4SHarish Mahendrakar     return 0;  // success
7735*103e46e4SHarish Mahendrakar   }
7736*103e46e4SHarish Mahendrakar 
7737*103e46e4SHarish Mahendrakar   if (pos >= stop)
7738*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
7739*103e46e4SHarish Mahendrakar 
7740*103e46e4SHarish Mahendrakar   unsigned char biased_count;
7741*103e46e4SHarish Mahendrakar 
7742*103e46e4SHarish Mahendrakar   status = pReader->Read(pos, 1, &biased_count);
7743*103e46e4SHarish Mahendrakar 
7744*103e46e4SHarish Mahendrakar   if (status)
7745*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
7746*103e46e4SHarish Mahendrakar 
7747*103e46e4SHarish Mahendrakar   ++pos;  // consume frame count
7748*103e46e4SHarish Mahendrakar   if (pos > stop)
7749*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
7750*103e46e4SHarish Mahendrakar 
7751*103e46e4SHarish Mahendrakar   m_frame_count = int(biased_count) + 1;
7752*103e46e4SHarish Mahendrakar 
7753*103e46e4SHarish Mahendrakar   m_frames = new (std::nothrow) Frame[m_frame_count];
7754*103e46e4SHarish Mahendrakar   if (m_frames == NULL)
7755*103e46e4SHarish Mahendrakar     return -1;
7756*103e46e4SHarish Mahendrakar 
7757*103e46e4SHarish Mahendrakar   if (!m_frames)
7758*103e46e4SHarish Mahendrakar     return E_FILE_FORMAT_INVALID;
7759*103e46e4SHarish Mahendrakar 
7760*103e46e4SHarish Mahendrakar   if (lacing == 1) {  // Xiph
7761*103e46e4SHarish Mahendrakar     Frame* pf = m_frames;
7762*103e46e4SHarish Mahendrakar     Frame* const pf_end = pf + m_frame_count;
7763*103e46e4SHarish Mahendrakar 
7764*103e46e4SHarish Mahendrakar     long long size = 0;
7765*103e46e4SHarish Mahendrakar     int frame_count = m_frame_count;
7766*103e46e4SHarish Mahendrakar 
7767*103e46e4SHarish Mahendrakar     while (frame_count > 1) {
7768*103e46e4SHarish Mahendrakar       long frame_size = 0;
7769*103e46e4SHarish Mahendrakar 
7770*103e46e4SHarish Mahendrakar       for (;;) {
7771*103e46e4SHarish Mahendrakar         unsigned char val;
7772*103e46e4SHarish Mahendrakar 
7773*103e46e4SHarish Mahendrakar         if (pos >= stop)
7774*103e46e4SHarish Mahendrakar           return E_FILE_FORMAT_INVALID;
7775*103e46e4SHarish Mahendrakar 
7776*103e46e4SHarish Mahendrakar         status = pReader->Read(pos, 1, &val);
7777*103e46e4SHarish Mahendrakar 
7778*103e46e4SHarish Mahendrakar         if (status)
7779*103e46e4SHarish Mahendrakar           return E_FILE_FORMAT_INVALID;
7780*103e46e4SHarish Mahendrakar 
7781*103e46e4SHarish Mahendrakar         ++pos;  // consume xiph size byte
7782*103e46e4SHarish Mahendrakar 
7783*103e46e4SHarish Mahendrakar         frame_size += val;
7784*103e46e4SHarish Mahendrakar 
7785*103e46e4SHarish Mahendrakar         if (val < 255)
7786*103e46e4SHarish Mahendrakar           break;
7787*103e46e4SHarish Mahendrakar       }
7788*103e46e4SHarish Mahendrakar 
7789*103e46e4SHarish Mahendrakar       Frame& f = *pf++;
7790*103e46e4SHarish Mahendrakar       assert(pf < pf_end);
7791*103e46e4SHarish Mahendrakar       if (pf >= pf_end)
7792*103e46e4SHarish Mahendrakar         return E_FILE_FORMAT_INVALID;
7793*103e46e4SHarish Mahendrakar 
7794*103e46e4SHarish Mahendrakar       f.pos = 0;  // patch later
7795*103e46e4SHarish Mahendrakar 
7796*103e46e4SHarish Mahendrakar       if (frame_size <= 0)
7797*103e46e4SHarish Mahendrakar         return E_FILE_FORMAT_INVALID;
7798*103e46e4SHarish Mahendrakar 
7799*103e46e4SHarish Mahendrakar       f.len = frame_size;
7800*103e46e4SHarish Mahendrakar       size += frame_size;  // contribution of this frame
7801*103e46e4SHarish Mahendrakar 
7802*103e46e4SHarish Mahendrakar       --frame_count;
7803*103e46e4SHarish Mahendrakar     }
7804*103e46e4SHarish Mahendrakar 
7805*103e46e4SHarish Mahendrakar     if (pf >= pf_end || pos > stop)
7806*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
7807*103e46e4SHarish Mahendrakar 
7808*103e46e4SHarish Mahendrakar     {
7809*103e46e4SHarish Mahendrakar       Frame& f = *pf++;
7810*103e46e4SHarish Mahendrakar 
7811*103e46e4SHarish Mahendrakar       if (pf != pf_end)
7812*103e46e4SHarish Mahendrakar         return E_FILE_FORMAT_INVALID;
7813*103e46e4SHarish Mahendrakar 
7814*103e46e4SHarish Mahendrakar       f.pos = 0;  // patch later
7815*103e46e4SHarish Mahendrakar 
7816*103e46e4SHarish Mahendrakar       const long long total_size = stop - pos;
7817*103e46e4SHarish Mahendrakar 
7818*103e46e4SHarish Mahendrakar       if (total_size < size)
7819*103e46e4SHarish Mahendrakar         return E_FILE_FORMAT_INVALID;
7820*103e46e4SHarish Mahendrakar 
7821*103e46e4SHarish Mahendrakar       const long long frame_size = total_size - size;
7822*103e46e4SHarish Mahendrakar 
7823*103e46e4SHarish Mahendrakar       if (frame_size > LONG_MAX || frame_size <= 0)
7824*103e46e4SHarish Mahendrakar         return E_FILE_FORMAT_INVALID;
7825*103e46e4SHarish Mahendrakar 
7826*103e46e4SHarish Mahendrakar       f.len = static_cast<long>(frame_size);
7827*103e46e4SHarish Mahendrakar     }
7828*103e46e4SHarish Mahendrakar 
7829*103e46e4SHarish Mahendrakar     pf = m_frames;
7830*103e46e4SHarish Mahendrakar     while (pf != pf_end) {
7831*103e46e4SHarish Mahendrakar       Frame& f = *pf++;
7832*103e46e4SHarish Mahendrakar       assert((pos + f.len) <= stop);
7833*103e46e4SHarish Mahendrakar 
7834*103e46e4SHarish Mahendrakar       if ((pos + f.len) > stop)
7835*103e46e4SHarish Mahendrakar         return E_FILE_FORMAT_INVALID;
7836*103e46e4SHarish Mahendrakar 
7837*103e46e4SHarish Mahendrakar       f.pos = pos;
7838*103e46e4SHarish Mahendrakar       pos += f.len;
7839*103e46e4SHarish Mahendrakar     }
7840*103e46e4SHarish Mahendrakar 
7841*103e46e4SHarish Mahendrakar     assert(pos == stop);
7842*103e46e4SHarish Mahendrakar     if (pos != stop)
7843*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
7844*103e46e4SHarish Mahendrakar 
7845*103e46e4SHarish Mahendrakar   } else if (lacing == 2) {  // fixed-size lacing
7846*103e46e4SHarish Mahendrakar     if (pos >= stop)
7847*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
7848*103e46e4SHarish Mahendrakar 
7849*103e46e4SHarish Mahendrakar     const long long total_size = stop - pos;
7850*103e46e4SHarish Mahendrakar 
7851*103e46e4SHarish Mahendrakar     if ((total_size % m_frame_count) != 0)
7852*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
7853*103e46e4SHarish Mahendrakar 
7854*103e46e4SHarish Mahendrakar     const long long frame_size = total_size / m_frame_count;
7855*103e46e4SHarish Mahendrakar 
7856*103e46e4SHarish Mahendrakar     if (frame_size > LONG_MAX || frame_size <= 0)
7857*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
7858*103e46e4SHarish Mahendrakar 
7859*103e46e4SHarish Mahendrakar     Frame* pf = m_frames;
7860*103e46e4SHarish Mahendrakar     Frame* const pf_end = pf + m_frame_count;
7861*103e46e4SHarish Mahendrakar 
7862*103e46e4SHarish Mahendrakar     while (pf != pf_end) {
7863*103e46e4SHarish Mahendrakar       assert((pos + frame_size) <= stop);
7864*103e46e4SHarish Mahendrakar       if ((pos + frame_size) > stop)
7865*103e46e4SHarish Mahendrakar         return E_FILE_FORMAT_INVALID;
7866*103e46e4SHarish Mahendrakar 
7867*103e46e4SHarish Mahendrakar       Frame& f = *pf++;
7868*103e46e4SHarish Mahendrakar 
7869*103e46e4SHarish Mahendrakar       f.pos = pos;
7870*103e46e4SHarish Mahendrakar       f.len = static_cast<long>(frame_size);
7871*103e46e4SHarish Mahendrakar 
7872*103e46e4SHarish Mahendrakar       pos += frame_size;
7873*103e46e4SHarish Mahendrakar     }
7874*103e46e4SHarish Mahendrakar 
7875*103e46e4SHarish Mahendrakar     assert(pos == stop);
7876*103e46e4SHarish Mahendrakar     if (pos != stop)
7877*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
7878*103e46e4SHarish Mahendrakar 
7879*103e46e4SHarish Mahendrakar   } else {
7880*103e46e4SHarish Mahendrakar     assert(lacing == 3);  // EBML lacing
7881*103e46e4SHarish Mahendrakar 
7882*103e46e4SHarish Mahendrakar     if (pos >= stop)
7883*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
7884*103e46e4SHarish Mahendrakar 
7885*103e46e4SHarish Mahendrakar     long long size = 0;
7886*103e46e4SHarish Mahendrakar     int frame_count = m_frame_count;
7887*103e46e4SHarish Mahendrakar 
7888*103e46e4SHarish Mahendrakar     long long frame_size = ReadUInt(pReader, pos, len);
7889*103e46e4SHarish Mahendrakar 
7890*103e46e4SHarish Mahendrakar     if (frame_size <= 0)
7891*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
7892*103e46e4SHarish Mahendrakar 
7893*103e46e4SHarish Mahendrakar     if (frame_size > LONG_MAX)
7894*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
7895*103e46e4SHarish Mahendrakar 
7896*103e46e4SHarish Mahendrakar     if ((pos + len) > stop)
7897*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
7898*103e46e4SHarish Mahendrakar 
7899*103e46e4SHarish Mahendrakar     pos += len;  // consume length of size of first frame
7900*103e46e4SHarish Mahendrakar 
7901*103e46e4SHarish Mahendrakar     if ((pos + frame_size) > stop)
7902*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
7903*103e46e4SHarish Mahendrakar 
7904*103e46e4SHarish Mahendrakar     Frame* pf = m_frames;
7905*103e46e4SHarish Mahendrakar     Frame* const pf_end = pf + m_frame_count;
7906*103e46e4SHarish Mahendrakar 
7907*103e46e4SHarish Mahendrakar     {
7908*103e46e4SHarish Mahendrakar       Frame& curr = *pf;
7909*103e46e4SHarish Mahendrakar 
7910*103e46e4SHarish Mahendrakar       curr.pos = 0;  // patch later
7911*103e46e4SHarish Mahendrakar 
7912*103e46e4SHarish Mahendrakar       curr.len = static_cast<long>(frame_size);
7913*103e46e4SHarish Mahendrakar       size += curr.len;  // contribution of this frame
7914*103e46e4SHarish Mahendrakar     }
7915*103e46e4SHarish Mahendrakar 
7916*103e46e4SHarish Mahendrakar     --frame_count;
7917*103e46e4SHarish Mahendrakar 
7918*103e46e4SHarish Mahendrakar     while (frame_count > 1) {
7919*103e46e4SHarish Mahendrakar       if (pos >= stop)
7920*103e46e4SHarish Mahendrakar         return E_FILE_FORMAT_INVALID;
7921*103e46e4SHarish Mahendrakar 
7922*103e46e4SHarish Mahendrakar       assert(pf < pf_end);
7923*103e46e4SHarish Mahendrakar       if (pf >= pf_end)
7924*103e46e4SHarish Mahendrakar         return E_FILE_FORMAT_INVALID;
7925*103e46e4SHarish Mahendrakar 
7926*103e46e4SHarish Mahendrakar       const Frame& prev = *pf++;
7927*103e46e4SHarish Mahendrakar       assert(prev.len == frame_size);
7928*103e46e4SHarish Mahendrakar       if (prev.len != frame_size)
7929*103e46e4SHarish Mahendrakar         return E_FILE_FORMAT_INVALID;
7930*103e46e4SHarish Mahendrakar 
7931*103e46e4SHarish Mahendrakar       assert(pf < pf_end);
7932*103e46e4SHarish Mahendrakar       if (pf >= pf_end)
7933*103e46e4SHarish Mahendrakar         return E_FILE_FORMAT_INVALID;
7934*103e46e4SHarish Mahendrakar 
7935*103e46e4SHarish Mahendrakar       Frame& curr = *pf;
7936*103e46e4SHarish Mahendrakar 
7937*103e46e4SHarish Mahendrakar       curr.pos = 0;  // patch later
7938*103e46e4SHarish Mahendrakar 
7939*103e46e4SHarish Mahendrakar       const long long delta_size_ = ReadUInt(pReader, pos, len);
7940*103e46e4SHarish Mahendrakar 
7941*103e46e4SHarish Mahendrakar       if (delta_size_ < 0)
7942*103e46e4SHarish Mahendrakar         return E_FILE_FORMAT_INVALID;
7943*103e46e4SHarish Mahendrakar 
7944*103e46e4SHarish Mahendrakar       if ((pos + len) > stop)
7945*103e46e4SHarish Mahendrakar         return E_FILE_FORMAT_INVALID;
7946*103e46e4SHarish Mahendrakar 
7947*103e46e4SHarish Mahendrakar       pos += len;  // consume length of (delta) size
7948*103e46e4SHarish Mahendrakar       if (pos > stop)
7949*103e46e4SHarish Mahendrakar         return E_FILE_FORMAT_INVALID;
7950*103e46e4SHarish Mahendrakar 
7951*103e46e4SHarish Mahendrakar       const long exp = 7 * len - 1;
7952*103e46e4SHarish Mahendrakar       const long long bias = (1LL << exp) - 1LL;
7953*103e46e4SHarish Mahendrakar       const long long delta_size = delta_size_ - bias;
7954*103e46e4SHarish Mahendrakar 
7955*103e46e4SHarish Mahendrakar       frame_size += delta_size;
7956*103e46e4SHarish Mahendrakar 
7957*103e46e4SHarish Mahendrakar       if (frame_size <= 0)
7958*103e46e4SHarish Mahendrakar         return E_FILE_FORMAT_INVALID;
7959*103e46e4SHarish Mahendrakar 
7960*103e46e4SHarish Mahendrakar       if (frame_size > LONG_MAX)
7961*103e46e4SHarish Mahendrakar         return E_FILE_FORMAT_INVALID;
7962*103e46e4SHarish Mahendrakar 
7963*103e46e4SHarish Mahendrakar       curr.len = static_cast<long>(frame_size);
7964*103e46e4SHarish Mahendrakar       // Check if size + curr.len could overflow.
7965*103e46e4SHarish Mahendrakar       if (size > LLONG_MAX - curr.len) {
7966*103e46e4SHarish Mahendrakar         return E_FILE_FORMAT_INVALID;
7967*103e46e4SHarish Mahendrakar       }
7968*103e46e4SHarish Mahendrakar       size += curr.len;  // contribution of this frame
7969*103e46e4SHarish Mahendrakar 
7970*103e46e4SHarish Mahendrakar       --frame_count;
7971*103e46e4SHarish Mahendrakar     }
7972*103e46e4SHarish Mahendrakar 
7973*103e46e4SHarish Mahendrakar     // parse last frame
7974*103e46e4SHarish Mahendrakar     if (frame_count > 0) {
7975*103e46e4SHarish Mahendrakar       if (pos > stop || pf >= pf_end)
7976*103e46e4SHarish Mahendrakar         return E_FILE_FORMAT_INVALID;
7977*103e46e4SHarish Mahendrakar 
7978*103e46e4SHarish Mahendrakar       const Frame& prev = *pf++;
7979*103e46e4SHarish Mahendrakar       assert(prev.len == frame_size);
7980*103e46e4SHarish Mahendrakar       if (prev.len != frame_size)
7981*103e46e4SHarish Mahendrakar         return E_FILE_FORMAT_INVALID;
7982*103e46e4SHarish Mahendrakar 
7983*103e46e4SHarish Mahendrakar       if (pf >= pf_end)
7984*103e46e4SHarish Mahendrakar         return E_FILE_FORMAT_INVALID;
7985*103e46e4SHarish Mahendrakar 
7986*103e46e4SHarish Mahendrakar       Frame& curr = *pf++;
7987*103e46e4SHarish Mahendrakar       if (pf != pf_end)
7988*103e46e4SHarish Mahendrakar         return E_FILE_FORMAT_INVALID;
7989*103e46e4SHarish Mahendrakar 
7990*103e46e4SHarish Mahendrakar       curr.pos = 0;  // patch later
7991*103e46e4SHarish Mahendrakar 
7992*103e46e4SHarish Mahendrakar       const long long total_size = stop - pos;
7993*103e46e4SHarish Mahendrakar 
7994*103e46e4SHarish Mahendrakar       if (total_size < size)
7995*103e46e4SHarish Mahendrakar         return E_FILE_FORMAT_INVALID;
7996*103e46e4SHarish Mahendrakar 
7997*103e46e4SHarish Mahendrakar       frame_size = total_size - size;
7998*103e46e4SHarish Mahendrakar 
7999*103e46e4SHarish Mahendrakar       if (frame_size > LONG_MAX || frame_size <= 0)
8000*103e46e4SHarish Mahendrakar         return E_FILE_FORMAT_INVALID;
8001*103e46e4SHarish Mahendrakar 
8002*103e46e4SHarish Mahendrakar       curr.len = static_cast<long>(frame_size);
8003*103e46e4SHarish Mahendrakar     }
8004*103e46e4SHarish Mahendrakar 
8005*103e46e4SHarish Mahendrakar     pf = m_frames;
8006*103e46e4SHarish Mahendrakar     while (pf != pf_end) {
8007*103e46e4SHarish Mahendrakar       Frame& f = *pf++;
8008*103e46e4SHarish Mahendrakar       if ((pos + f.len) > stop)
8009*103e46e4SHarish Mahendrakar         return E_FILE_FORMAT_INVALID;
8010*103e46e4SHarish Mahendrakar 
8011*103e46e4SHarish Mahendrakar       f.pos = pos;
8012*103e46e4SHarish Mahendrakar       pos += f.len;
8013*103e46e4SHarish Mahendrakar     }
8014*103e46e4SHarish Mahendrakar 
8015*103e46e4SHarish Mahendrakar     if (pos != stop)
8016*103e46e4SHarish Mahendrakar       return E_FILE_FORMAT_INVALID;
8017*103e46e4SHarish Mahendrakar   }
8018*103e46e4SHarish Mahendrakar 
8019*103e46e4SHarish Mahendrakar   return 0;  // success
8020*103e46e4SHarish Mahendrakar }
8021*103e46e4SHarish Mahendrakar 
GetTimeCode(const Cluster * pCluster) const8022*103e46e4SHarish Mahendrakar long long Block::GetTimeCode(const Cluster* pCluster) const {
8023*103e46e4SHarish Mahendrakar   if (pCluster == 0)
8024*103e46e4SHarish Mahendrakar     return m_timecode;
8025*103e46e4SHarish Mahendrakar 
8026*103e46e4SHarish Mahendrakar   const long long tc0 = pCluster->GetTimeCode();
8027*103e46e4SHarish Mahendrakar   assert(tc0 >= 0);
8028*103e46e4SHarish Mahendrakar 
8029*103e46e4SHarish Mahendrakar   // Check if tc0 + m_timecode would overflow.
8030*103e46e4SHarish Mahendrakar   if (tc0 < 0 || LLONG_MAX - tc0 < m_timecode) {
8031*103e46e4SHarish Mahendrakar     return -1;
8032*103e46e4SHarish Mahendrakar   }
8033*103e46e4SHarish Mahendrakar 
8034*103e46e4SHarish Mahendrakar   const long long tc = tc0 + m_timecode;
8035*103e46e4SHarish Mahendrakar 
8036*103e46e4SHarish Mahendrakar   return tc;  // unscaled timecode units
8037*103e46e4SHarish Mahendrakar }
8038*103e46e4SHarish Mahendrakar 
GetTime(const Cluster * pCluster) const8039*103e46e4SHarish Mahendrakar long long Block::GetTime(const Cluster* pCluster) const {
8040*103e46e4SHarish Mahendrakar   assert(pCluster);
8041*103e46e4SHarish Mahendrakar 
8042*103e46e4SHarish Mahendrakar   const long long tc = GetTimeCode(pCluster);
8043*103e46e4SHarish Mahendrakar 
8044*103e46e4SHarish Mahendrakar   const Segment* const pSegment = pCluster->m_pSegment;
8045*103e46e4SHarish Mahendrakar   const SegmentInfo* const pInfo = pSegment->GetInfo();
8046*103e46e4SHarish Mahendrakar   assert(pInfo);
8047*103e46e4SHarish Mahendrakar 
8048*103e46e4SHarish Mahendrakar   const long long scale = pInfo->GetTimeCodeScale();
8049*103e46e4SHarish Mahendrakar   assert(scale >= 1);
8050*103e46e4SHarish Mahendrakar 
8051*103e46e4SHarish Mahendrakar   // Check if tc * scale could overflow.
8052*103e46e4SHarish Mahendrakar   if (tc != 0 && scale > LLONG_MAX / tc) {
8053*103e46e4SHarish Mahendrakar     return -1;
8054*103e46e4SHarish Mahendrakar   }
8055*103e46e4SHarish Mahendrakar   const long long ns = tc * scale;
8056*103e46e4SHarish Mahendrakar 
8057*103e46e4SHarish Mahendrakar   return ns;
8058*103e46e4SHarish Mahendrakar }
8059*103e46e4SHarish Mahendrakar 
GetTrackNumber() const8060*103e46e4SHarish Mahendrakar long long Block::GetTrackNumber() const { return m_track; }
8061*103e46e4SHarish Mahendrakar 
IsKey() const8062*103e46e4SHarish Mahendrakar bool Block::IsKey() const {
8063*103e46e4SHarish Mahendrakar   return ((m_flags & static_cast<unsigned char>(1 << 7)) != 0);
8064*103e46e4SHarish Mahendrakar }
8065*103e46e4SHarish Mahendrakar 
SetKey(bool bKey)8066*103e46e4SHarish Mahendrakar void Block::SetKey(bool bKey) {
8067*103e46e4SHarish Mahendrakar   if (bKey)
8068*103e46e4SHarish Mahendrakar     m_flags |= static_cast<unsigned char>(1 << 7);
8069*103e46e4SHarish Mahendrakar   else
8070*103e46e4SHarish Mahendrakar     m_flags &= 0x7F;
8071*103e46e4SHarish Mahendrakar }
8072*103e46e4SHarish Mahendrakar 
IsInvisible() const8073*103e46e4SHarish Mahendrakar bool Block::IsInvisible() const { return bool(int(m_flags & 0x08) != 0); }
8074*103e46e4SHarish Mahendrakar 
GetLacing() const8075*103e46e4SHarish Mahendrakar Block::Lacing Block::GetLacing() const {
8076*103e46e4SHarish Mahendrakar   const int value = int(m_flags & 0x06) >> 1;
8077*103e46e4SHarish Mahendrakar   return static_cast<Lacing>(value);
8078*103e46e4SHarish Mahendrakar }
8079*103e46e4SHarish Mahendrakar 
GetFrameCount() const8080*103e46e4SHarish Mahendrakar int Block::GetFrameCount() const { return m_frame_count; }
8081*103e46e4SHarish Mahendrakar 
GetFrame(int idx) const8082*103e46e4SHarish Mahendrakar const Block::Frame& Block::GetFrame(int idx) const {
8083*103e46e4SHarish Mahendrakar   assert(idx >= 0);
8084*103e46e4SHarish Mahendrakar   assert(idx < m_frame_count);
8085*103e46e4SHarish Mahendrakar 
8086*103e46e4SHarish Mahendrakar   const Frame& f = m_frames[idx];
8087*103e46e4SHarish Mahendrakar   assert(f.pos > 0);
8088*103e46e4SHarish Mahendrakar   assert(f.len > 0);
8089*103e46e4SHarish Mahendrakar 
8090*103e46e4SHarish Mahendrakar   return f;
8091*103e46e4SHarish Mahendrakar }
8092*103e46e4SHarish Mahendrakar 
Read(IMkvReader * pReader,unsigned char * buf) const8093*103e46e4SHarish Mahendrakar long Block::Frame::Read(IMkvReader* pReader, unsigned char* buf) const {
8094*103e46e4SHarish Mahendrakar   assert(pReader);
8095*103e46e4SHarish Mahendrakar   assert(buf);
8096*103e46e4SHarish Mahendrakar 
8097*103e46e4SHarish Mahendrakar   const long status = pReader->Read(pos, len, buf);
8098*103e46e4SHarish Mahendrakar   return status;
8099*103e46e4SHarish Mahendrakar }
8100*103e46e4SHarish Mahendrakar 
GetDiscardPadding() const8101*103e46e4SHarish Mahendrakar long long Block::GetDiscardPadding() const { return m_discard_padding; }
8102*103e46e4SHarish Mahendrakar 
8103*103e46e4SHarish Mahendrakar }  // namespace mkvparser
8104