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