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