Coverage Report

Created: 2026-08-14 07:16

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/vlc/contrib/contrib-build/ebml/src/EbmlElement.cpp
Line
Count
Source
1
/****************************************************************************
2
** libebml : parse EBML files, see http://embl.sourceforge.net/
3
**
4
** <file/class description>
5
**
6
** Copyright (C) 2002-2010 Steve Lhomme.  All rights reserved.
7
**
8
** This library is free software; you can redistribute it and/or
9
** modify it under the terms of the GNU Lesser General Public
10
** License as published by the Free Software Foundation; either
11
** version 2.1 of the License, or (at your option) any later version.
12
**
13
** This library is distributed in the hope that it will be useful,
14
** but WITHOUT ANY WARRANTY; without even the implied warranty of
15
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16
** Lesser General Public License for more details.
17
**
18
** You should have received a copy of the GNU Lesser General Public
19
** License along with this library; if not, write to the Free Software
20
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
21
**
22
** See http://www.gnu.org/licenses/lgpl-2.1.html for LGPL licensing information.
23
**
24
** Contact license@matroska.org if any conditions of this licensing are
25
** not clear to you.
26
**
27
**********************************************************************/
28
29
/*!
30
  \file
31
  \version \$Id$
32
  \author Steve Lhomme     <robux4 @ users.sf.net>
33
*/
34
35
#include <cassert>
36
#include <cstdlib>
37
#include <cstring>
38
#include <iostream>
39
#include <new>
40
#include <stdexcept>
41
#include <sstream>
42
43
#include "ebml/EbmlElement.h"
44
#include "ebml/EbmlMaster.h"
45
#include "ebml/EbmlStream.h"
46
#include "ebml/EbmlVoid.h"
47
#include "ebml/EbmlDummy.h"
48
#include "ebml/EbmlContexts.h"
49
50
namespace libebml {
51
52
/*!
53
  \todo handle more than CodedSize of 5
54
*/
55
int CodedSizeLength(uint64 Length, unsigned int SizeLength, bool bSizeIsFinite)
56
2.82M
{
57
2.82M
  unsigned int CodedSize;
58
2.82M
  if (bSizeIsFinite) {
59
    // prepare the head of the size (000...01xxxxxx)
60
    // optimal size
61
2.82M
    if (Length < 127) // 2^7 - 1
62
1.54M
      CodedSize = 1;
63
1.28M
    else if (Length < 16383) // 2^14 - 1
64
897k
      CodedSize = 2;
65
385k
    else if (Length < 2097151L) // 2^21 - 1
66
284k
      CodedSize = 3;
67
101k
    else if (Length < 268435455L) // 2^28 - 1
68
93.9k
      CodedSize = 4;
69
7.56k
    else CodedSize = 5;
70
2.82M
  } else {
71
603
    if (Length <= 127) // 2^7 - 1
72
597
      CodedSize = 1;
73
6
    else if (Length <= 16383) // 2^14 - 1
74
0
      CodedSize = 2;
75
6
    else if (Length <= 2097151L) // 2^21 - 1
76
0
      CodedSize = 3;
77
6
    else if (Length <= 268435455L) // 2^28 - 1
78
0
      CodedSize = 4;
79
6
    else CodedSize = 5;
80
603
  }
81
82
2.82M
  if (SizeLength > 0 && CodedSize < SizeLength) {
83
    // defined size
84
496k
    CodedSize = SizeLength;
85
496k
  }
86
87
2.82M
  return CodedSize;
88
2.82M
}
89
90
/*!
91
  \todo handle more than CodedSize of 5
92
*/
93
int CodedSizeLengthSigned(int64 Length, unsigned int SizeLength)
94
0
{
95
0
  unsigned int CodedSize;
96
  // prepare the head of the size (000...01xxxxxx)
97
  // optimal size
98
0
  if (Length > -64 && Length < 64) // 2^6
99
0
    CodedSize = 1;
100
0
  else if (Length > -8192 && Length < 8192) // 2^13
101
0
    CodedSize = 2;
102
0
  else if (Length > -1048576L && Length < 1048576L) // 2^20
103
0
    CodedSize = 3;
104
0
  else if (Length > -134217728L && Length < 134217728L) // 2^27
105
0
    CodedSize = 4;
106
0
  else CodedSize = 5;
107
108
0
  if (SizeLength > 0 && CodedSize < SizeLength) {
109
    // defined size
110
0
    CodedSize = SizeLength;
111
0
  }
112
113
0
  return CodedSize;
114
0
}
115
116
int CodedValueLength(uint64 Length, int CodedSize, binary * OutBuffer)
117
0
{
118
0
  int _SizeMask = 0xFF;
119
0
  OutBuffer[0] = 1 << (8 - CodedSize);
120
0
  for (int i=1; i<CodedSize; i++) {
121
0
    OutBuffer[CodedSize-i] = Length & 0xFF;
122
0
    Length >>= 8;
123
0
    _SizeMask >>= 1;
124
0
  }
125
  // first one use a OR with the "EBML size head"
126
0
  OutBuffer[0] |= Length & 0xFF & _SizeMask;
127
0
  return CodedSize;
128
0
}
129
130
int CodedValueLengthSigned(int64 Length, int CodedSize, binary * OutBuffer)
131
0
{
132
0
  if (Length > -64 && Length < 64) // 2^6
133
0
    Length += 63;
134
0
  else if (Length > -8192 && Length < 8192) // 2^13
135
0
    Length += 8191;
136
0
  else if (Length > -1048576L && Length < 1048576L) // 2^20
137
0
    Length += 1048575L;
138
0
  else if (Length > -134217728L && Length < 134217728L) // 2^27
139
0
    Length += 134217727L;
140
141
0
  return CodedValueLength(Length, CodedSize, OutBuffer);
142
0
}
143
144
uint64 ReadCodedSizeValue(const binary * InBuffer, uint32 & BufferSize, uint64 & SizeUnknown)
145
15.5M
{
146
15.5M
  binary SizeBitMask = 1 << 7;
147
15.5M
  uint64 Result = 0x7F;
148
15.5M
  unsigned int SizeIdx, PossibleSizeLength = 0;
149
15.5M
  binary PossibleSize[8];
150
15.5M
  memset(PossibleSize, 0, 8);
151
152
15.5M
  SizeUnknown = 0x7F; // the last bit is discarded when computing the size
153
41.4M
  for (SizeIdx = 0; SizeIdx < BufferSize && SizeIdx < 8; SizeIdx++) {
154
33.0M
    if (InBuffer[0] & (SizeBitMask >> SizeIdx)) {
155
      // ID found
156
7.13M
      PossibleSizeLength = SizeIdx + 1;
157
7.13M
      SizeBitMask >>= SizeIdx;
158
159
      // Guard against invalid memory accesses with incomplete IDs.
160
7.13M
      if (PossibleSizeLength > BufferSize)
161
0
        break;
162
163
21.5M
      for (SizeIdx = 0; SizeIdx < PossibleSizeLength; SizeIdx++) {
164
14.4M
        PossibleSize[SizeIdx] = InBuffer[SizeIdx];
165
14.4M
      }
166
14.4M
      for (SizeIdx = 0; SizeIdx < PossibleSizeLength - 1; SizeIdx++) {
167
7.26M
        Result <<= 7;
168
7.26M
        Result |= 0xFF;
169
7.26M
      }
170
171
7.13M
      Result = 0;
172
7.13M
      Result |= PossibleSize[0] & ~SizeBitMask;
173
14.4M
      for (unsigned int i = 1; i<PossibleSizeLength; i++) {
174
7.26M
        Result <<= 8;
175
7.26M
        Result |= PossibleSize[i];
176
7.26M
      }
177
178
7.13M
      BufferSize = PossibleSizeLength;
179
180
7.13M
      return Result;
181
7.13M
    }
182
25.8M
    SizeUnknown <<= 7;
183
25.8M
    SizeUnknown |= 0xFF;
184
25.8M
  }
185
186
8.41M
  BufferSize = 0;
187
8.41M
  return 0;
188
15.5M
}
189
190
int64 ReadCodedSizeSignedValue(const binary * InBuffer, uint32 & BufferSize, uint64 & SizeUnknown)
191
29.7k
{
192
29.7k
  int64 Result = ReadCodedSizeValue(InBuffer, BufferSize, SizeUnknown);
193
194
29.7k
  if (BufferSize != 0) {
195
29.5k
    switch (BufferSize) {
196
27.2k
      case 1:
197
27.2k
        Result -= 63;
198
27.2k
        break;
199
2.25k
      case 2:
200
2.25k
        Result -= 8191;
201
2.25k
        break;
202
17
      case 3:
203
17
        Result -= 1048575L;
204
17
        break;
205
0
      case 4:
206
0
        Result -= 134217727L;
207
0
        break;
208
29.5k
    }
209
29.5k
  }
210
211
29.7k
  return Result;
212
29.7k
}
213
214
215
EbmlCallbacks::EbmlCallbacks(EbmlElement & (*Creator)(), const EbmlId & aGlobalId, const char * aDebugName, const EbmlSemanticContext & aContext)
216
23.2k
  :Create(Creator)
217
23.2k
  ,GlobalId(aGlobalId)
218
23.2k
  ,DebugName(aDebugName)
219
23.2k
  ,Context(aContext)
220
23.2k
{
221
23.2k
  assert((Create!=nullptr) || !strcmp(aDebugName, "DummyElement"));
222
23.2k
}
223
224
const EbmlSemantic & EbmlSemanticContext::GetSemantic(size_t i) const
225
0
{
226
0
  assert(i<Size);
227
0
  if (i<Size)
228
0
    return MyTable[i];
229
230
0
  std::stringstream ss;
231
0
  ss << "EbmlSemanticContext::GetSemantic: programming error: index i outside of table size (" << i << " >= " << Size << ")";
232
0
  throw std::logic_error(ss.str());
233
0
}
234
235
236
EbmlElement::EbmlElement(uint64 aDefaultSize, bool bValueSet)
237
1.87M
  :DefaultSize(aDefaultSize)
238
1.87M
  ,SizeLength(0) ///< write optimal size by default
239
1.87M
  ,bSizeIsFinite(true)
240
1.87M
  ,ElementPosition(0)
241
1.87M
  ,SizePosition(0)
242
1.87M
  ,bValueIsSet(bValueSet)
243
1.87M
  ,DefaultIsSet(false)
244
1.87M
  ,bLocked(false)
245
1.87M
{
246
1.87M
  Size = DefaultSize;
247
1.87M
}
248
249
EbmlElement::~EbmlElement()
250
1.87M
{
251
1.87M
  assert(!bLocked);
252
1.87M
}
253
254
/*!
255
  \todo this method is deprecated and should be called FindThisID
256
  \todo replace the new RawElement with the appropriate class (when known)
257
*/
258
EbmlElement * EbmlElement::FindNextID(IOCallback & DataStream, const EbmlCallbacks & ClassInfos, uint64 MaxDataSize)
259
8.92k
{
260
8.92k
  binary PossibleId[4];
261
8.92k
  int PossibleID_Length = 0;
262
8.92k
  binary PossibleSize[8]; // we don't support size stored in more than 64 bits
263
8.92k
  uint32 PossibleSizeLength = 0;
264
8.92k
  uint64 SizeUnknown = 0;
265
8.92k
  uint64 SizeFound = 0;
266
8.92k
  bool bElementFound = false;
267
268
8.92k
  binary BitMask;
269
8.92k
  uint64 aElementPosition = 0, aSizePosition = 0;
270
15.0k
  while (!bElementFound) {
271
    // read ID
272
8.92k
    aElementPosition = DataStream.getFilePointer();
273
8.92k
    uint32 ReadSize = 0;
274
8.92k
    BitMask = 1 << 7;
275
27.2k
    while (PossibleID_Length < 4) {
276
27.0k
      if (!DataStream.read(&PossibleId[PossibleID_Length], 1))
277
2.61k
        return nullptr;            // no more data
278
279
24.4k
      ++ReadSize;
280
24.4k
      ++PossibleID_Length;
281
282
24.4k
      if (PossibleId[0] & BitMask) {
283
        // this is the last octet of the ID
284
        // check wether that's the one we're looking for
285
/*      if (PossibleID == EBML_INFO_ID(ClassInfos)) {
286
          break;
287
        } else {
288
          /// \todo This element should be skipped (use a context ?)
289
        }*/
290
6.10k
        bElementFound = true; /// \todo not exactly the one we're looking for
291
6.10k
        break;
292
6.10k
      }
293
18.3k
      BitMask >>= 1;
294
18.3k
    }
295
296
6.31k
    if (!bElementFound)
297
211
      return nullptr;
298
299
    // read the data size
300
6.10k
    aSizePosition = DataStream.getFilePointer();
301
6.10k
    uint32 _SizeLength;
302
21.6k
    do {
303
21.6k
      if (PossibleSizeLength >= 8)
304
        // Size is larger than 8 bytes
305
6
        return nullptr;
306
307
21.6k
      ReadSize += DataStream.read(&PossibleSize[PossibleSizeLength++], 1);
308
21.6k
      _SizeLength = PossibleSizeLength;
309
21.6k
      SizeFound = ReadCodedSizeValue(&PossibleSize[0], _SizeLength, SizeUnknown);
310
21.6k
    } while (_SizeLength == 0);
311
6.10k
  }
312
313
6.09k
  EbmlElement *Result = nullptr;
314
6.09k
  EbmlId PossibleID(PossibleId, PossibleID_Length);
315
6.09k
  if (PossibleID == EBML_INFO_ID(ClassInfos)) {
316
    // the element is the one expected
317
5.70k
    Result = &EBML_INFO_CREATE(ClassInfos);
318
5.70k
  } else {
319
    /// \todo find the element in the context
320
392
    Result = new (std::nothrow) EbmlDummy(PossibleID);
321
392
    if(Result == nullptr)
322
0
      return nullptr;
323
392
  }
324
325
6.09k
  Result->SetSizeLength(PossibleSizeLength);
326
327
6.09k
  Result->Size = SizeFound;
328
329
6.09k
  if (!Result->ValidateSize() || (SizeFound != SizeUnknown && MaxDataSize < Result->Size)) {
330
45
    delete Result;
331
45
    return nullptr;
332
45
  }
333
334
  // check if the size is not all 1s
335
6.05k
  if (SizeFound == SizeUnknown) {
336
    // Size of this element is unknown
337
    // only possible for Master elements
338
582
    if (!Result->SetSizeInfinite()) {
339
      /// \todo the element is not allowed to be infinite
340
3
      delete Result;
341
3
      return nullptr;
342
3
    }
343
5.47k
  } else Result->SetSizeInfinite(false);
344
6.05k
  Result->ElementPosition = aElementPosition;
345
6.05k
  Result->SizePosition = aSizePosition;
346
347
6.05k
  return Result;
348
6.05k
}
349
350
351
/*!
352
  \todo replace the new RawElement with the appropriate class (when known)
353
  \todo skip data for Dummy elements when they are not allowed
354
  \todo better check of the size checking for upper elements (using a list of size for each level)
355
  \param LowLevel Will be returned with the level of the element found compared to the context given
356
*/
357
EbmlElement * EbmlElement::FindNextElement(IOCallback & DataStream, const EbmlSemanticContext & Context, int & UpperLevel,
358
                                           uint64 MaxDataSize, bool AllowDummyElt, unsigned int MaxLowerLevel)
359
651k
{
360
651k
  int PossibleID_Length = 0;
361
651k
  binary PossibleIdNSize[16];
362
651k
  int PossibleSizeLength;
363
651k
  uint64 SizeUnknown;
364
651k
  int ReadIndex = 0; // trick for the algo, start index at 0
365
651k
  uint32 ReadSize = 0, IdStart = 0;
366
651k
  uint64 SizeFound;
367
651k
  int SizeIdx;
368
651k
  bool bFound;
369
651k
  int UpperLevel_original = UpperLevel;
370
651k
  uint64 ParseStart = DataStream.getFilePointer();
371
372
7.53M
  do {
373
    // read a potential ID
374
15.4M
    do {
375
15.4M
      assert(ReadIndex < 16);
376
      // build the ID with the current Read Buffer
377
15.4M
      bFound = false;
378
15.4M
      binary IdBitMask = 1 << 7;
379
49.1M
      for (SizeIdx = 0; SizeIdx < ReadIndex && SizeIdx < 4; SizeIdx++) {
380
41.2M
        if (PossibleIdNSize[0] & (IdBitMask >> SizeIdx)) {
381
          // ID found
382
7.51M
          PossibleID_Length = SizeIdx + 1;
383
7.51M
          IdBitMask >>= SizeIdx;
384
7.51M
          bFound = true;
385
7.51M
          break;
386
7.51M
        }
387
41.2M
      }
388
15.4M
      if (bFound) {
389
7.51M
        break;
390
7.51M
      }
391
392
7.94M
      if (ReadIndex >= 4) {
393
        // ID not found
394
        // shift left the read octets
395
6.69M
        memmove(&PossibleIdNSize[0],&PossibleIdNSize[1], --ReadIndex);
396
6.69M
        IdStart++;
397
6.69M
      }
398
399
7.94M
      if (MaxDataSize <= ReadSize)
400
19.4k
        break;
401
7.92M
      if (DataStream.read(&PossibleIdNSize[ReadIndex++], 1) == 0) {
402
4.82k
        return nullptr; // no more data ?
403
4.82k
      }
404
7.92M
      ReadSize++;
405
406
7.92M
    } while (!bFound);
407
408
7.53M
    if (!bFound)
409
      // we reached the maximum we could read without a proper ID
410
19.4k
      return nullptr;
411
412
7.51M
    SizeIdx = ReadIndex;
413
7.51M
    ReadIndex -= PossibleID_Length;
414
415
    // read the data size
416
7.51M
    uint32 _SizeLength;
417
7.51M
    PossibleSizeLength = ReadIndex;
418
15.4M
    while (true) {
419
15.4M
      _SizeLength = PossibleSizeLength;
420
15.4M
      SizeFound = ReadCodedSizeValue(&PossibleIdNSize[PossibleID_Length], _SizeLength, SizeUnknown);
421
15.4M
      if (_SizeLength != 0) {
422
7.09M
        bFound = true;
423
7.09M
        break;
424
7.09M
      }
425
8.40M
      if (PossibleSizeLength >= 8) {
426
395k
        bFound = false;
427
395k
        break;
428
395k
      }
429
8.00M
      if (MaxDataSize <= ReadSize) {
430
21.9k
        bFound = false;
431
21.9k
        break;
432
21.9k
      }
433
7.98M
      if( DataStream.read( &PossibleIdNSize[SizeIdx++], 1 ) == 0 ) {
434
77
        return nullptr; // no more data ?
435
77
      }
436
7.98M
      ReadSize++;
437
7.98M
      PossibleSizeLength++;
438
7.98M
    }
439
440
7.51M
    if (bFound) {
441
      // find the element in the context and use the correct creator
442
7.09M
      EbmlId PossibleID(PossibleIdNSize, PossibleID_Length);
443
7.09M
      EbmlElement * Result = CreateElementUsingContext(PossibleID, Context, UpperLevel, false, AllowDummyElt, MaxLowerLevel);
444
      ///< \todo continue is misplaced
445
7.09M
      if (Result != nullptr) {
446
1.41M
        if (AllowDummyElt || !Result->IsDummy()) {
447
1.41M
          Result->SetSizeLength(_SizeLength);
448
449
1.41M
          Result->Size = SizeFound;
450
          // UpperLevel values
451
          // -1 : global element
452
          //  0 : child
453
          //  1 : same level
454
          //  + : further parent
455
1.41M
          if (Result->ValidateSize() && (SizeFound == SizeUnknown || UpperLevel > 0 || MaxDataSize == 0 ||
456
1.19M
                                         MaxDataSize >= (IdStart + PossibleID_Length + _SizeLength + SizeFound))) {
457
743k
            if (SizeFound != SizeUnknown || Result->SetSizeInfinite()) {
458
626k
              Result->ElementPosition = ParseStart + IdStart;
459
626k
              Result->SizePosition = Result->ElementPosition + PossibleID_Length;
460
              // place the file at the beggining of the data
461
626k
              DataStream.setFilePointer(Result->SizePosition + _SizeLength);
462
626k
              return Result;
463
626k
            }
464
743k
          }
465
1.41M
        }
466
787k
        delete Result;
467
787k
      }
468
7.09M
    }
469
470
    // recover all the data in the buffer minus one byte
471
6.88M
    ReadIndex = SizeIdx - 1;
472
6.88M
    memmove(&PossibleIdNSize[0], &PossibleIdNSize[1], ReadIndex);
473
6.88M
    IdStart++;
474
6.88M
    UpperLevel = UpperLevel_original;
475
6.88M
  } while ( MaxDataSize >= ReadSize );
476
477
0
  return nullptr;
478
651k
}
479
480
/*!
481
  \todo what happens if we are in a upper element with a known size ?
482
*/
483
EbmlElement * EbmlElement::SkipData(EbmlStream & DataStream, const EbmlSemanticContext & Context, EbmlElement * TestReadElt, bool AllowDummyElt)
484
534k
{
485
534k
  EbmlElement * Result = nullptr;
486
534k
  if (bSizeIsFinite) {
487
534k
    assert(TestReadElt == nullptr);
488
534k
    assert(ElementPosition < SizePosition);
489
534k
    DataStream.I_O().setFilePointer(SizePosition + CodedSizeLength(Size, SizeLength, bSizeIsFinite) + Size, seek_beginning);
490
    //    DataStream.I_O().setFilePointer(Size, seek_current);
491
534k
  } else {
492
    /////////////////////////////////////////////////
493
    // read elements until an upper element is found
494
    /////////////////////////////////////////////////
495
0
    bool bEndFound = false;
496
0
    while (!bEndFound && Result == nullptr) {
497
      // read an element
498
      /// \todo 0xFF... and true should be configurable
499
      //      EbmlElement * NewElt;
500
0
      if (TestReadElt == nullptr) {
501
0
        int bUpperElement = 0; // trick to call FindNextID correctly
502
0
        Result = DataStream.FindNextElement(Context, bUpperElement, 0xFFFFFFFFL, AllowDummyElt);
503
0
      } else {
504
0
        Result = TestReadElt;
505
0
        TestReadElt = nullptr;
506
0
      }
507
508
0
      if (Result != nullptr) {
509
0
        unsigned int EltIndex;
510
        // data known in this Master's context
511
0
        for (EltIndex = 0; EltIndex < EBML_CTX_SIZE(Context); EltIndex++) {
512
0
          if (EbmlId(*Result) == EBML_CTX_IDX_ID(Context,EltIndex)) {
513
            // skip the data with its own context
514
0
            Result = Result->SkipData(DataStream, EBML_SEM_CONTEXT(EBML_CTX_IDX(Context,EltIndex)), nullptr);
515
0
            break; // let's go to the next ID
516
0
          }
517
0
        }
518
519
0
        if (EltIndex >= EBML_CTX_SIZE(Context)) {
520
0
          if (EBML_CTX_PARENT(Context) != nullptr) {
521
0
            Result = SkipData(DataStream, *EBML_CTX_PARENT(Context), Result);
522
0
          } else {
523
0
            assert(Context.GetGlobalContext != nullptr);
524
0
            if (Context != Context.GetGlobalContext()) {
525
0
              Result = SkipData(DataStream, Context.GetGlobalContext(), Result);
526
0
            } else {
527
0
              bEndFound = true;
528
0
            }
529
0
          }
530
0
        }
531
0
      } else {
532
0
        bEndFound = true;
533
0
      }
534
0
    }
535
0
  }
536
534k
  return Result;
537
534k
}
538
539
EbmlElement *EbmlElement::CreateElementUsingContext(const EbmlId & aID, const EbmlSemanticContext & Context,
540
                                                    int & LowLevel, bool IsGlobalContext, bool bAllowDummy, unsigned int MaxLowerLevel)
541
15.9M
{
542
15.9M
  unsigned int ContextIndex;
543
15.9M
  EbmlElement *Result = nullptr;
544
545
  // elements at the current level
546
95.4M
  for (ContextIndex = 0; ContextIndex < EBML_CTX_SIZE(Context); ContextIndex++) {
547
79.9M
    if (aID == EBML_CTX_IDX_ID(Context,ContextIndex)) {
548
397k
      return &EBML_SEM_CREATE(EBML_CTX_IDX(Context,ContextIndex));
549
397k
    }
550
79.9M
  }
551
552
  // global elements
553
15.9M
  assert(Context.GetGlobalContext != nullptr); // global should always exist, at least the EBML ones
554
15.5M
  const EbmlSemanticContext & tstContext = Context.GetGlobalContext();
555
15.5M
  if (tstContext != Context) {
556
7.81M
    LowLevel--;
557
7.81M
    MaxLowerLevel--;
558
    // recursive is good, but be carefull...
559
7.81M
    Result = CreateElementUsingContext(aID, tstContext, LowLevel, true, bAllowDummy, MaxLowerLevel);
560
7.81M
    if (Result != nullptr) {
561
24.7k
      return Result;
562
24.7k
    }
563
7.78M
    LowLevel++;
564
7.78M
    MaxLowerLevel++;
565
7.78M
  } else {
566
7.78M
    return nullptr;
567
7.78M
  }
568
569
  // parent elements
570
7.78M
  if (EBML_CTX_MASTER(Context) != nullptr && aID == EBML_INFO_ID(*EBML_CTX_MASTER(Context))) {
571
50.6k
    LowLevel++; // already one level up (same as context)
572
50.6k
    return &EBML_INFO_CREATE(*EBML_CTX_MASTER(Context));
573
50.6k
  }
574
575
  // check wether it's not part of an upper context
576
7.73M
  if (EBML_CTX_PARENT(Context) != nullptr) {
577
1.09M
    LowLevel++;
578
1.09M
    MaxLowerLevel++;
579
1.09M
    return CreateElementUsingContext(aID, *EBML_CTX_PARENT(Context), LowLevel, IsGlobalContext, bAllowDummy, MaxLowerLevel);
580
1.09M
  }
581
582
6.64M
  if (!IsGlobalContext && bAllowDummy) {
583
965k
    LowLevel = 0;
584
965k
    Result = new (std::nothrow) EbmlDummy(aID);
585
965k
  }
586
587
6.64M
  return Result;
588
7.73M
}
589
590
/*!
591
  \todo verify that the size written is the same as the data written
592
*/
593
filepos_t EbmlElement::Render(IOCallback & output, bool bWithDefault, bool bKeepPosition, bool bForceRender)
594
0
{
595
0
  assert(bValueIsSet || (bWithDefault && DefaultISset())); // an element is been rendered without a value set !!!
596
  // it may be a mandatory element without a default value
597
0
  if (!bWithDefault && IsDefaultValue()) {
598
0
    return 0;
599
0
  }
600
#if defined(LIBEBML_DEBUG)
601
  uint64 SupposedSize = UpdateSize(bWithDefault, bForceRender);
602
#endif // LIBEBML_DEBUG
603
0
  filepos_t result = RenderHead(output, bForceRender, bWithDefault, bKeepPosition);
604
0
  uint64 WrittenSize = RenderData(output, bForceRender, bWithDefault);
605
#if defined(LIBEBML_DEBUG)
606
  if (static_cast<int64>(SupposedSize) != (0-1))
607
    assert(WrittenSize == SupposedSize);
608
#endif // LIBEBML_DEBUG
609
0
  result += WrittenSize;
610
0
  return result;
611
0
}
612
613
/*!
614
  \todo store the position of the Size writing for elements with unknown size
615
  \todo handle exceptions on errors
616
  \todo handle CodeSize bigger than 5 bytes
617
*/
618
filepos_t EbmlElement::RenderHead(IOCallback & output, bool bForceRender, bool bWithDefault, bool bKeepPosition)
619
0
{
620
0
  if (EBML_ID_LENGTH((const EbmlId&)*this) <= 0 || EBML_ID_LENGTH((const EbmlId&)*this) > 4)
621
0
    return 0;
622
623
0
  UpdateSize(bWithDefault, bForceRender);
624
625
0
  return MakeRenderHead(output, bKeepPosition);
626
0
}
627
628
filepos_t EbmlElement::MakeRenderHead(IOCallback & output, bool bKeepPosition)
629
0
{
630
0
  binary FinalHead[4+8]; // Class D + 64 bits coded size
631
0
  unsigned int FinalHeadSize;
632
633
0
  FinalHeadSize = EBML_ID_LENGTH((const EbmlId&)*this);
634
0
  EbmlId(*this).Fill(FinalHead);
635
636
0
  int CodedSize = CodedSizeLength(Size, SizeLength, bSizeIsFinite);
637
0
  CodedValueLength(Size, CodedSize, &FinalHead[FinalHeadSize]);
638
0
  FinalHeadSize += CodedSize;
639
640
0
  output.writeFully(FinalHead, FinalHeadSize);
641
0
  if (!bKeepPosition) {
642
0
    ElementPosition = output.getFilePointer() - FinalHeadSize;
643
0
    SizePosition = ElementPosition + EBML_ID_LENGTH((const EbmlId&)*this);
644
0
  }
645
646
0
  return FinalHeadSize;
647
0
}
648
649
uint64 EbmlElement::ElementSize(bool bWithDefault) const
650
0
{
651
0
  if (!bWithDefault && IsDefaultValue())
652
0
    return 0; // won't be saved
653
0
  return Size + EBML_ID_LENGTH((const EbmlId&)*this) + CodedSizeLength(Size, SizeLength, bSizeIsFinite);
654
0
}
655
656
bool EbmlElement::IsSmallerThan(const EbmlElement *Cmp) const
657
0
{
658
0
  return EbmlId(*this) == EbmlId(*Cmp);
659
0
}
660
661
bool EbmlElement::CompareElements(const EbmlElement *A, const EbmlElement *B)
662
0
{
663
0
  if (EbmlId(*A) == EbmlId(*B))
664
0
    return A->IsSmallerThan(B);
665
666
0
  return false;
667
0
}
668
669
void EbmlElement::Read(EbmlStream & inDataStream, const EbmlSemanticContext & /* Context */, int & /* UpperEltFound */, EbmlElement * & /* FoundElt */, bool /* AllowDummyElt */, ScopeMode ReadFully)
670
124k
{
671
124k
  ReadData(inDataStream.I_O(), ReadFully);
672
124k
}
673
674
bool EbmlElement::ForceSize(uint64 NewSize)
675
0
{
676
0
  if (bSizeIsFinite) {
677
0
    return false;
678
0
  }
679
680
0
  int OldSizeLen = CodedSizeLength(Size, SizeLength, bSizeIsFinite);
681
0
  uint64 OldSize = Size;
682
683
0
  Size = NewSize;
684
685
0
  if (CodedSizeLength(Size, SizeLength, bSizeIsFinite) == OldSizeLen) {
686
0
    bSizeIsFinite = true;
687
0
    return true;
688
0
  }
689
0
  Size = OldSize;
690
691
0
  return false;
692
0
}
693
694
filepos_t EbmlElement::OverwriteHead(IOCallback & output, bool bKeepPosition)
695
0
{
696
0
  if (ElementPosition == 0) {
697
0
    return 0; // the element has not been written
698
0
  }
699
700
0
  uint64 CurrentPosition = output.getFilePointer();
701
0
  output.setFilePointer(GetElementPosition());
702
0
  filepos_t Result = MakeRenderHead(output, bKeepPosition);
703
0
  output.setFilePointer(CurrentPosition);
704
0
  return Result;
705
0
}
706
707
filepos_t EbmlElement::OverwriteData(IOCallback & output, bool bKeepPosition)
708
0
{
709
0
  if (ElementPosition == 0) {
710
0
    return 0; // the element has not been written
711
0
  }
712
713
0
  auto HeaderSize = EbmlId(*this).GetLength() + CodedSizeLength(Size, SizeLength, bSizeIsFinite);
714
#if !defined(NDEBUG)
715
  auto DataSize   = GetSize();
716
#endif
717
718
0
  auto CurrentPosition = output.getFilePointer();
719
0
  output.setFilePointer(GetElementPosition() + HeaderSize);
720
0
  auto Result = RenderData(output, true, bKeepPosition);
721
0
  output.setFilePointer(CurrentPosition);
722
0
  assert(Result == DataSize);
723
0
  return Result;
724
0
}
725
726
727
uint64 EbmlElement::VoidMe(IOCallback & output, bool bWithDefault)
728
0
{
729
0
  if (ElementPosition == 0) {
730
0
    return 0; // the element has not been written
731
0
  }
732
733
0
  EbmlVoid Dummy;
734
0
  return Dummy.Overwrite(*this, output, true, bWithDefault);
735
0
}
736
737
} // namespace libebml