1 /****************************************************************************
2 ** libmatroska : parse Matroska files, see http://www.matroska.org/
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 ** Contact license@matroska.org if any conditions of this licensing are
24 ** not clear to you.
25 **
26 **********************************************************************/
27 
28 /*!
29   \file
30   \version \$Id: KaxBlock.cpp 1265 2007-01-14 17:20:35Z mosu $
31   \author Steve Lhomme     <robux4 @ users.sf.net>
32   \author Julien Coloos    <suiryc @ users.sf.net>
33   \author Moritz Bunkus <moritz@bunkus.org>
34 */
35 #include <cassert>
36 
37 //#include <streams.h>
38 
39 #include "ebml/MemReadIOCallback.h"
40 #include "ebml/SafeReadIOCallback.h"
41 #include "matroska/KaxBlock.h"
42 #include "matroska/KaxContexts.h"
43 #include "matroska/KaxBlockData.h"
44 #include "matroska/KaxCluster.h"
45 #include "matroska/KaxDefines.h"
46 
47 START_LIBMATROSKA_NAMESPACE
48 
Clone()49 DataBuffer * DataBuffer::Clone()
50 {
51   auto ClonedData = static_cast<binary *>(malloc(mySize * sizeof(binary)));
52   assert(ClonedData != nullptr);
53   memcpy(ClonedData, myBuffer ,mySize );
54 
55   auto result = new SimpleDataBuffer(ClonedData, mySize, 0);
56   result->bValidValue = bValidValue;
57   return result;
58 }
59 
SimpleDataBuffer(const SimpleDataBuffer & ToClone)60 SimpleDataBuffer::SimpleDataBuffer(const SimpleDataBuffer & ToClone)
61   :DataBuffer(static_cast<binary *>(malloc(ToClone.mySize * sizeof(binary))), ToClone.mySize, myFreeBuffer)
62 {
63   assert(myBuffer != nullptr);
64   memcpy(myBuffer, ToClone.myBuffer ,mySize );
65   bValidValue = ToClone.bValidValue;
66 }
67 
ValidateSize() const68 bool KaxInternalBlock::ValidateSize() const
69 {
70   return (GetSize() >= 4); /// for the moment
71 }
72 
~KaxInternalBlock()73 KaxInternalBlock::~KaxInternalBlock()
74 {
75   ReleaseFrames();
76 }
77 
KaxInternalBlock(const KaxInternalBlock & ElementToClone)78 KaxInternalBlock::KaxInternalBlock(const KaxInternalBlock & ElementToClone)
79   :EbmlBinary(ElementToClone)
80   ,myBuffers(ElementToClone.myBuffers.size())
81   ,Timecode(ElementToClone.Timecode)
82   ,LocalTimecode(ElementToClone.LocalTimecode)
83   ,bLocalTimecodeUsed(ElementToClone.bLocalTimecodeUsed)
84   ,TrackNumber(ElementToClone.TrackNumber)
85   ,ParentCluster(ElementToClone.ParentCluster) ///< \todo not exactly
86 {
87   // add a clone of the list
88   auto Itr = ElementToClone.myBuffers.begin();
89   auto myItr = myBuffers.begin();
90   while (Itr != ElementToClone.myBuffers.end()) {
91     *myItr = (*Itr)->Clone();
92     ++Itr; ++myItr;
93   }
94 }
95 
96 
97 /* KaxBlockGroup::~KaxBlockGroup()
98 {
99   //NOTE("KaxBlockGroup::~KaxBlockGroup");
100 } */
101 
KaxBlockGroup(EBML_EXTRA_DEF)102 KaxBlockGroup::KaxBlockGroup(EBML_EXTRA_DEF)
103   :EbmlMaster(EBML_CLASS_SEMCONTEXT(KaxBlockGroup) EBML_DEF_SEP EBML_EXTRA_CALL)
104   ,ParentCluster(nullptr)
105   ,ParentTrack(nullptr)
106 {}
107 
108 /*!
109   \todo handle flags
110   \todo hardcoded limit of the number of frames in a lace should be a parameter
111   \return true if more frames can be added to this Block
112 */
AddFrame(const KaxTrackEntry & track,uint64 timecode,DataBuffer & buffer,LacingType lacing,bool invisible)113 bool KaxInternalBlock::AddFrame(const KaxTrackEntry & track, uint64 timecode, DataBuffer & buffer, LacingType lacing, bool invisible)
114 {
115   SetValueIsSet();
116   if (myBuffers.empty()) {
117     // first frame
118     Timecode = timecode;
119     TrackNumber = track.TrackNumber();
120     mInvisible = invisible;
121     mLacing = lacing;
122   }
123   myBuffers.push_back(&buffer);
124 
125   // we don't allow more than 8 frames in a Block because the overhead improvement is minimal
126   if (myBuffers.size() >= 8 || lacing == LACING_NONE)
127     return false;
128 
129   if (lacing == LACING_XIPH)
130     // decide wether a new frame can be added or not
131     // a frame in a lace is not efficient when the place necessary to code it in a lace is bigger
132     // than the size of a simple Block. That means more than 6 bytes (4 in struct + 2 for EBML) to code the size
133     return (buffer.Size() < 6*0xFF);
134 
135   return true;
136 }
137 
138 /*!
139   \return Returns the lacing type that produces the smallest footprint.
140 */
GetBestLacingType() const141 LacingType KaxInternalBlock::GetBestLacingType() const {
142   int XiphLacingSize, EbmlLacingSize, i;
143   bool SameSize = true;
144 
145   if (myBuffers.size() <= 1)
146     return LACING_NONE;
147 
148   XiphLacingSize = 1; // Number of laces is stored in 1 byte.
149   EbmlLacingSize = 1;
150   for (i = 0; i < static_cast<int>(myBuffers.size()) - 1; i++) {
151     if (myBuffers[i]->Size() != myBuffers[i + 1]->Size())
152       SameSize = false;
153     XiphLacingSize += myBuffers[i]->Size() / 255 + 1;
154   }
155   EbmlLacingSize += CodedSizeLength(myBuffers[0]->Size(), 0, IsFiniteSize());
156   for (i = 1; i < static_cast<int>(myBuffers.size()) - 1; i++)
157     EbmlLacingSize += CodedSizeLengthSigned(int64(myBuffers[i]->Size()) - int64(myBuffers[i - 1]->Size()), 0);
158   if (SameSize)
159     return LACING_FIXED;
160   if (XiphLacingSize < EbmlLacingSize)
161     return LACING_XIPH;
162 
163   return LACING_EBML;
164 }
165 
UpdateSize(bool,bool)166 filepos_t KaxInternalBlock::UpdateSize(bool /* bSaveDefault */, bool /* bForceRender */)
167 {
168   LacingType LacingHere;
169   assert(EbmlBinary::GetBuffer() == nullptr); // Data is not used for KaxInternalBlock
170   assert(TrackNumber < 0x4000); // no more allowed for the moment
171   unsigned int i;
172 
173   // compute the final size of the data
174   switch (myBuffers.size()) {
175     case 0:
176       SetSize_(0);
177       break;
178     case 1:
179       SetSize_(4 + myBuffers[0]->Size());
180       break;
181     default:
182       SetSize_(4 + 1); // 1 for the lacing head
183       if (mLacing == LACING_AUTO)
184         LacingHere = GetBestLacingType();
185       else
186         LacingHere = mLacing;
187       switch (LacingHere) {
188         case LACING_XIPH:
189           for (i=0; i<myBuffers.size()-1; i++) {
190             SetSize_(GetSize() + myBuffers[i]->Size() + (myBuffers[i]->Size() / 0xFF + 1));
191           }
192           break;
193         case LACING_EBML:
194           SetSize_(GetSize() + myBuffers[0]->Size() + CodedSizeLength(myBuffers[0]->Size(), 0, IsFiniteSize()));
195           for (i=1; i<myBuffers.size()-1; i++) {
196             SetSize_(GetSize() + myBuffers[i]->Size() + CodedSizeLengthSigned(int64(myBuffers[i]->Size()) - int64(myBuffers[i-1]->Size()), 0));
197           }
198           break;
199         case LACING_FIXED:
200           for (i=0; i<myBuffers.size()-1; i++) {
201             SetSize_(GetSize() + myBuffers[i]->Size());
202           }
203           break;
204         default:
205           i = 0;
206           assert(0);
207       }
208       // Size of the last frame (not in lace)
209       SetSize_(GetSize() + myBuffers[i]->Size());
210       break;
211   }
212 
213   if (TrackNumber >= 0x80)
214     SetSize_(GetSize() + 1); // the size will be coded with one more octet
215 
216   return GetSize();
217 }
218 
KaxBlockVirtual(const KaxBlockVirtual & ElementToClone)219 KaxBlockVirtual::KaxBlockVirtual(const KaxBlockVirtual & ElementToClone)
220   :EbmlBinary(ElementToClone)
221   ,Timecode(ElementToClone.Timecode)
222   ,TrackNumber(ElementToClone.TrackNumber)
223   ,ParentCluster(ElementToClone.ParentCluster) ///< \todo not exactly
224 {
225   SetBuffer(DataBlock,sizeof(DataBlock));
226   SetValueIsSet(false);
227 }
228 
KaxBlockVirtual(EBML_EXTRA_DEF)229 KaxBlockVirtual::KaxBlockVirtual(EBML_EXTRA_DEF)
230   :EBML_DEF_BINARY(KaxBlockVirtual)EBML_DEF_SEP ParentCluster(nullptr)
231 {
232   SetBuffer(DataBlock,sizeof(DataBlock));
233   SetValueIsSet(false);
234 }
235 
~KaxBlockVirtual()236 KaxBlockVirtual::~KaxBlockVirtual()
237 {
238   if(GetBuffer() == DataBlock)
239     SetBuffer( nullptr, 0 );
240 }
241 
UpdateSize(bool,bool)242 filepos_t KaxBlockVirtual::UpdateSize(bool /* bSaveDefault */, bool /* bForceRender */)
243 {
244   assert(TrackNumber < 0x4000);
245   binary *cursor = EbmlBinary::GetBuffer();
246   // fill data
247   if (TrackNumber < 0x80) {
248     assert(GetSize() >= 4);
249     *cursor++ = TrackNumber | 0x80; // set the first bit to 1
250   } else {
251     assert(GetSize() >= 5);
252     *cursor++ = (TrackNumber >> 8) | 0x40; // set the second bit to 1
253     *cursor++ = TrackNumber & 0xFF;
254   }
255 
256   assert(ParentCluster != nullptr);
257   int16 ActualTimecode = ParentCluster->GetBlockLocalTimecode(Timecode);
258   big_int16 b16(ActualTimecode);
259   b16.Fill(cursor);
260   cursor += 2;
261 
262   *cursor++ = 0; // flags
263 
264   return GetSize();
265 }
266 
267 /*!
268   \todo more optimisation is possible (render the Block head and don't copy the buffer in memory, care should be taken with the allocation of Data)
269   \todo the actual timecode to write should be retrieved from the Cluster from here
270 */
RenderData(IOCallback & output,bool,bool)271 filepos_t KaxInternalBlock::RenderData(IOCallback & output, bool /* bForceRender */, bool /* bSaveDefault */)
272 {
273   if (myBuffers.empty()) {
274     return 0;
275   } else {
276     assert(TrackNumber < 0x4000);
277     binary BlockHead[5], *cursor = BlockHead;
278     unsigned int i;
279 
280     if (myBuffers.size() == 1) {
281       SetSize_(4);
282       mLacing = LACING_NONE;
283     } else {
284       if (mLacing == LACING_NONE)
285         mLacing = LACING_EBML; // supposedly the best of all
286       SetSize_(4 + 1); // 1 for the lacing head (number of laced elements)
287     }
288     if (TrackNumber >= 0x80)
289       SetSize_(GetSize() + 1);
290 
291     // write Block Head
292     if (TrackNumber < 0x80) {
293       *cursor++ = TrackNumber | 0x80; // set the first bit to 1
294     } else {
295       *cursor++ = (TrackNumber >> 8) | 0x40; // set the second bit to 1
296       *cursor++ = TrackNumber & 0xFF;
297     }
298 
299     assert(ParentCluster != nullptr);
300     int16 ActualTimecode = ParentCluster->GetBlockLocalTimecode(Timecode);
301     big_int16 b16(ActualTimecode);
302     b16.Fill(cursor);
303     cursor += 2;
304 
305     *cursor = 0; // flags
306 
307     if (mLacing == LACING_AUTO) {
308       mLacing = GetBestLacingType();
309     }
310 
311     // invisible flag
312     if (mInvisible)
313       *cursor = 0x08;
314 
315     if (bIsSimple) {
316       if (bIsKeyframe)
317         *cursor |= 0x80;
318       if (bIsDiscardable)
319         *cursor |= 0x01;
320     }
321 
322     // lacing flag
323     switch (mLacing) {
324       case LACING_XIPH:
325         *cursor++ |= 0x02;
326         break;
327       case LACING_EBML:
328         *cursor++ |= 0x06;
329         break;
330       case LACING_FIXED:
331         *cursor++ |= 0x04;
332         break;
333       case LACING_NONE:
334         break;
335       default:
336         assert(0);
337     }
338 
339     output.writeFully(BlockHead, 4 + ((TrackNumber >= 0x80) ? 1 : 0));
340 
341     binary tmpValue;
342     switch (mLacing) {
343       case LACING_XIPH:
344         // number of laces
345         tmpValue = myBuffers.size()-1;
346         output.writeFully(&tmpValue, 1);
347 
348         // set the size of each member in the lace
349         for (i=0; i<myBuffers.size()-1; i++) {
350           tmpValue = 0xFF;
351           uint16 tmpSize = myBuffers[i]->Size();
352           while (tmpSize >= 0xFF) {
353             output.writeFully(&tmpValue, 1);
354             SetSize_(GetSize() + 1);
355             tmpSize -= 0xFF;
356           }
357           tmpValue = binary(tmpSize);
358           output.writeFully(&tmpValue, 1);
359           SetSize_(GetSize() + 1);
360         }
361         break;
362       case LACING_EBML:
363         // number of laces
364         tmpValue = myBuffers.size()-1;
365         output.writeFully(&tmpValue, 1);
366         {
367           int64 _Size;
368           int _CodedSize;
369           binary _FinalHead[8]; // 64 bits max coded size
370 
371           _Size = myBuffers[0]->Size();
372 
373           _CodedSize = CodedSizeLength(_Size, 0, IsFiniteSize());
374 
375           // first size in the lace is not a signed
376           CodedValueLength(_Size, _CodedSize, _FinalHead);
377           output.writeFully(_FinalHead, _CodedSize);
378           SetSize_(GetSize() + _CodedSize);
379 
380           // set the size of each member in the lace
381           for (i=1; i<myBuffers.size()-1; i++) {
382             _Size = int64(myBuffers[i]->Size()) - int64(myBuffers[i-1]->Size());
383             _CodedSize = CodedSizeLengthSigned(_Size, 0);
384             CodedValueLengthSigned(_Size, _CodedSize, _FinalHead);
385             output.writeFully(_FinalHead, _CodedSize);
386             SetSize_(GetSize() + _CodedSize);
387           }
388         }
389         break;
390       case LACING_FIXED:
391         // number of laces
392         tmpValue = myBuffers.size()-1;
393         output.writeFully(&tmpValue, 1);
394         break;
395       case LACING_NONE:
396         break;
397       default:
398         assert(0);
399     }
400 
401     // put the data of each frame
402     for (i=0; i<myBuffers.size(); i++) {
403       output.writeFully(myBuffers[i]->Buffer(), myBuffers[i]->Size());
404       SetSize_(GetSize() + myBuffers[i]->Size());
405     }
406   }
407 
408   return GetSize();
409 }
410 
ReadInternalHead(IOCallback & input)411 uint64 KaxInternalBlock::ReadInternalHead(IOCallback & input)
412 {
413   binary Buffer[5], *cursor = Buffer;
414   uint64 Result = input.read(cursor, 4);
415   if (Result != 4)
416     return Result;
417 
418   // update internal values
419   TrackNumber = *cursor++;
420   if ((TrackNumber & 0x80) == 0) {
421     // there is extra data
422     if ((TrackNumber & 0x40) == 0) {
423       // We don't support track numbers that large !
424       return Result;
425     }
426     Result += input.read(&Buffer[4], 1);
427     TrackNumber = (TrackNumber & 0x3F) << 8;
428     TrackNumber += *cursor++;
429   } else {
430     TrackNumber &= 0x7F;
431   }
432 
433 
434   big_int16 b16;
435   b16.Eval(cursor);
436   assert(ParentCluster != nullptr);
437   Timecode = ParentCluster->GetBlockGlobalTimecode(int16(b16));
438   bLocalTimecodeUsed = false;
439   cursor += 2;
440 
441   return Result;
442 }
443 
444 /*!
445   \todo better zero copy handling
446 */
ReadData(IOCallback & input,ScopeMode ReadFully)447 filepos_t KaxInternalBlock::ReadData(IOCallback & input, ScopeMode ReadFully)
448 {
449   filepos_t Result;
450 
451   FirstFrameLocation = input.getFilePointer(); // will be updated accordingly below
452 
453   SetValueIsSet(false);
454 
455   try {
456     if (ReadFully == SCOPE_ALL_DATA) {
457       Result = EbmlBinary::ReadData(input, ReadFully);
458       if (Result != GetSize())
459         throw SafeReadIOCallback::EndOfStreamX(GetSize() - Result);
460 
461       binary *BufferStart = EbmlBinary::GetBuffer();
462 
463       SafeReadIOCallback Mem(*this);
464       uint8 BlockHeadSize = 4;
465 
466       // update internal values
467       TrackNumber = Mem.GetUInt8();
468       if ((TrackNumber & 0x80) == 0) {
469         // there is extra data
470         if ((TrackNumber & 0x40) == 0) {
471           // We don't support track numbers that large !
472           throw SafeReadIOCallback::EndOfStreamX(0);
473         }
474         TrackNumber = (TrackNumber & 0x3F) << 8;
475         TrackNumber += Mem.GetUInt8();
476         BlockHeadSize++;
477       } else {
478         TrackNumber &= 0x7F;
479       }
480 
481       LocalTimecode = int16(Mem.GetUInt16BE());
482       bLocalTimecodeUsed = true;
483 
484       uint8 Flags = Mem.GetUInt8();
485       if (EbmlId(*this) == EBML_ID(KaxSimpleBlock)) {
486         bIsKeyframe = (Flags & 0x80) != 0;
487         bIsDiscardable = (Flags & 0x01) != 0;
488       }
489       mInvisible = (Flags & 0x08) >> 3;
490       mLacing = LacingType((Flags & 0x06) >> 1);
491 
492       // put all Frames in the list
493       if (mLacing == LACING_NONE) {
494         FirstFrameLocation += Mem.GetPosition();
495         auto soloFrame = new DataBuffer(BufferStart + Mem.GetPosition(), GetSize() - BlockHeadSize);
496         myBuffers.push_back(soloFrame);
497         SizeList.resize(1);
498         SizeList[0] = GetSize() - BlockHeadSize;
499       } else {
500         // read the number of frames in the lace
501         uint32 LastBufferSize = GetSize() - BlockHeadSize - 1; // 1 for number of frame
502         uint8 FrameNum = Mem.GetUInt8(); // number of frames in the lace - 1
503         // read the list of frame sizes
504         uint8 Index;
505         int32 FrameSize;
506         uint32 SizeRead;
507         uint64 SizeUnknown;
508 
509         SizeList.resize(FrameNum + 1);
510 
511         switch (mLacing) {
512           case LACING_XIPH:
513             for (Index=0; Index<FrameNum; Index++) {
514               // get the size of the frame
515               FrameSize = 0;
516               uint8 Value;
517               do {
518                 Value = Mem.GetUInt8();
519                 FrameSize += Value;
520                 LastBufferSize--;
521               } while (Value == 0xFF);
522               SizeList[Index] = FrameSize;
523               LastBufferSize -= FrameSize;
524             }
525             SizeList[Index] = LastBufferSize;
526             break;
527           case LACING_EBML:
528             SizeRead = LastBufferSize;
529             FrameSize = ReadCodedSizeValue(BufferStart + Mem.GetPosition(), SizeRead, SizeUnknown);
530             if (!FrameSize || (static_cast<uint32>(FrameSize + SizeRead) > LastBufferSize))
531               throw SafeReadIOCallback::EndOfStreamX(SizeRead);
532             SizeList[0] = FrameSize;
533             Mem.Skip(SizeRead);
534             LastBufferSize -= FrameSize + SizeRead;
535 
536             for (Index=1; Index<FrameNum; Index++) {
537               // get the size of the frame
538               SizeRead = LastBufferSize;
539               FrameSize += ReadCodedSizeSignedValue(BufferStart + Mem.GetPosition(), SizeRead, SizeUnknown);
540               if (!FrameSize || (static_cast<uint32>(FrameSize + SizeRead) > LastBufferSize))
541                 throw SafeReadIOCallback::EndOfStreamX(SizeRead);
542               SizeList[Index] = FrameSize;
543               Mem.Skip(SizeRead);
544               LastBufferSize -= FrameSize + SizeRead;
545             }
546             if (Index <= FrameNum) // Safety check if FrameNum == 0
547               SizeList[Index] = LastBufferSize;
548             break;
549           case LACING_FIXED:
550             for (Index=0; Index<=FrameNum; Index++) {
551               // get the size of the frame
552               SizeList[Index] = LastBufferSize / (FrameNum + 1);
553             }
554             break;
555           default: // other lacing not supported
556             assert(0);
557         }
558 
559         FirstFrameLocation += Mem.GetPosition();
560 
561         for (Index=0; Index<=FrameNum; Index++) {
562           auto lacedFrame = new DataBuffer(BufferStart + Mem.GetPosition(), SizeList[Index]);
563           myBuffers.push_back(lacedFrame);
564           Mem.Skip(SizeList[Index]);
565         }
566       }
567 
568       binary *BufferEnd = BufferStart + GetSize();
569       size_t NumFrames  = myBuffers.size();
570 
571       // Sanity checks for frame pointers and boundaries.
572       for (size_t Index = 0; Index < NumFrames; ++Index) {
573         binary *FrameStart  = myBuffers[Index]->Buffer();
574         binary *FrameEnd    = FrameStart + myBuffers[Index]->Size();
575         binary *ExpectedEnd = (Index + 1) < NumFrames ? myBuffers[Index + 1]->Buffer() : BufferEnd;
576 
577         if ((FrameStart < BufferStart) || (FrameEnd > BufferEnd) || (FrameEnd != ExpectedEnd))
578           throw SafeReadIOCallback::EndOfStreamX(0);
579       }
580 
581       SetValueIsSet();
582     } else if (ReadFully == SCOPE_PARTIAL_DATA) {
583       binary _TempHead[5];
584       Result = input.read(_TempHead, 5);
585       if (Result != 5)
586         throw SafeReadIOCallback::EndOfStreamX(0);
587       binary *cursor = _TempHead;
588       binary *_tmpBuf;
589       uint8 BlockHeadSize = 4;
590 
591       // update internal values
592       TrackNumber = *cursor++;
593       if ((TrackNumber & 0x80) == 0) {
594         // there is extra data
595         if ((TrackNumber & 0x40) == 0) {
596           // We don't support track numbers that large !
597           return Result;
598         }
599         TrackNumber = (TrackNumber & 0x3F) << 8;
600         TrackNumber += *cursor++;
601         BlockHeadSize++;
602       } else {
603         TrackNumber &= 0x7F;
604       }
605 
606       big_int16 b16;
607       b16.Eval(cursor);
608       LocalTimecode = int16(b16);
609       bLocalTimecodeUsed = true;
610       cursor += 2;
611 
612       if (EbmlId(*this) == EBML_ID(KaxSimpleBlock)) {
613         bIsKeyframe = (*cursor & 0x80) != 0;
614         bIsDiscardable = (*cursor & 0x01) != 0;
615       }
616       mInvisible = (*cursor & 0x08) >> 3;
617       mLacing = LacingType((*cursor++ & 0x06) >> 1);
618       if (cursor == &_TempHead[4]) {
619         _TempHead[0] = _TempHead[4];
620       } else {
621         Result += input.read(_TempHead, 1);
622       }
623 
624       FirstFrameLocation += cursor - _TempHead;
625 
626       // put all Frames in the list
627       if (mLacing != LACING_NONE) {
628         // read the number of frames in the lace
629         const uint32 TotalLacedSize = GetSize() - BlockHeadSize - 1; // 1 for number of frame
630         uint32 LastBufferSize = TotalLacedSize;
631         uint8 FrameNum = _TempHead[0]; // number of frames in the lace - 1
632         // read the list of frame sizes
633         uint8 Index;
634         uint32 FrameSize;
635         uint32 SizeRead;
636         uint64 SizeUnknown;
637 
638         SizeList.resize(FrameNum + 1);
639 
640         switch (mLacing) {
641           case LACING_XIPH:
642             for (Index=0; Index<FrameNum; Index++) {
643               // get the size of the frame
644               FrameSize = 0;
645               do {
646                 Result += input.read(_TempHead, 1);
647                 FrameSize += uint8(_TempHead[0]);
648                 if (FrameSize > TotalLacedSize)
649                   throw SafeReadIOCallback::EndOfStreamX(0);
650                 LastBufferSize--;
651 
652                 FirstFrameLocation++;
653               } while (_TempHead[0] == 0xFF);
654 
655               FirstFrameLocation++;
656               SizeList[Index] = FrameSize;
657               LastBufferSize -= FrameSize;
658             }
659             SizeList[Index] = LastBufferSize;
660             break;
661           case LACING_EBML:
662             SizeRead = LastBufferSize;
663             cursor = _tmpBuf = new binary[FrameNum*4]; /// \warning assume the mean size will be coded in less than 4 bytes
664             Result += input.read(cursor, FrameNum*4);
665             FrameSize = ReadCodedSizeValue(cursor, SizeRead, SizeUnknown);
666             if (FrameSize > TotalLacedSize)
667               throw SafeReadIOCallback::EndOfStreamX(0);
668             SizeList[0] = FrameSize;
669             cursor += SizeRead;
670             LastBufferSize -= FrameSize + SizeRead;
671 
672             for (Index=1; Index<FrameNum; Index++) {
673               // get the size of the frame
674               SizeRead = LastBufferSize;
675               FrameSize += ReadCodedSizeSignedValue(cursor, SizeRead, SizeUnknown);
676               if (FrameSize > TotalLacedSize)
677                 throw SafeReadIOCallback::EndOfStreamX(0);
678               SizeList[Index] = FrameSize;
679               cursor += SizeRead;
680               LastBufferSize -= FrameSize + SizeRead;
681             }
682 
683             FirstFrameLocation += cursor - _tmpBuf;
684 
685             SizeList[Index] = LastBufferSize;
686             delete [] _tmpBuf;
687             break;
688           case LACING_FIXED:
689             for (Index=0; Index<=FrameNum; Index++) {
690               // get the size of the frame
691               SizeList[Index] = LastBufferSize / (FrameNum + 1);
692             }
693             break;
694           default: // other lacing not supported
695             assert(0);
696         }
697       } else {
698         SizeList.resize(1);
699         SizeList[0] = GetSize() - BlockHeadSize;
700       }
701       SetValueIsSet(false);
702       Result = GetSize();
703     } else {
704       SetValueIsSet(false);
705       Result = GetSize();
706     }
707 
708   } catch (SafeReadIOCallback::EndOfStreamX &) {
709     SetValueIsSet(false);
710 
711     myBuffers.clear();
712     SizeList.clear();
713     Timecode           = 0;
714     LocalTimecode      = 0;
715     TrackNumber        = 0;
716     bLocalTimecodeUsed = false;
717     FirstFrameLocation = 0;
718 
719     return 0;
720   }
721 
722   return Result;
723 }
724 
AddFrame(const KaxTrackEntry & track,uint64 timecode,DataBuffer & buffer,LacingType lacing)725 bool KaxBlockGroup::AddFrame(const KaxTrackEntry & track, uint64 timecode, DataBuffer & buffer, LacingType lacing)
726 {
727   auto & theBlock = GetChild<KaxBlock>(*this);
728   assert(ParentCluster != nullptr);
729   theBlock.SetParent(*ParentCluster);
730   ParentTrack = &track;
731   return theBlock.AddFrame(track, timecode, buffer, lacing);
732 }
733 
AddFrame(const KaxTrackEntry & track,uint64 timecode,DataBuffer & buffer,const KaxBlockGroup & PastBlock,LacingType lacing)734 bool KaxBlockGroup::AddFrame(const KaxTrackEntry & track, uint64 timecode, DataBuffer & buffer, const KaxBlockGroup & PastBlock, LacingType lacing)
735 {
736   //  assert(past_timecode < 0);
737 
738   auto & theBlock = GetChild<KaxBlock>(*this);
739   assert(ParentCluster != nullptr);
740   theBlock.SetParent(*ParentCluster);
741   ParentTrack = &track;
742   bool bRes = theBlock.AddFrame(track, timecode, buffer, lacing);
743 
744   auto & thePastRef = GetChild<KaxReferenceBlock>(*this);
745   thePastRef.SetReferencedBlock(PastBlock);
746   thePastRef.SetParentBlock(*this);
747 
748   return bRes;
749 }
750 
AddFrame(const KaxTrackEntry & track,uint64 timecode,DataBuffer & buffer,const KaxBlockGroup & PastBlock,const KaxBlockGroup & ForwBlock,LacingType lacing)751 bool KaxBlockGroup::AddFrame(const KaxTrackEntry & track, uint64 timecode, DataBuffer & buffer, const KaxBlockGroup & PastBlock, const KaxBlockGroup & ForwBlock, LacingType lacing)
752 {
753   //  assert(past_timecode < 0);
754 
755   //  assert(forw_timecode > 0);
756 
757   auto & theBlock = GetChild<KaxBlock>(*this);
758   assert(ParentCluster != nullptr);
759   theBlock.SetParent(*ParentCluster);
760   ParentTrack = &track;
761   bool bRes = theBlock.AddFrame(track, timecode, buffer, lacing);
762 
763   auto & thePastRef = GetChild<KaxReferenceBlock>(*this);
764   thePastRef.SetReferencedBlock(PastBlock);
765   thePastRef.SetParentBlock(*this);
766 
767   auto & theFutureRef = AddNewChild<KaxReferenceBlock>(*this);
768   theFutureRef.SetReferencedBlock(ForwBlock);
769   theFutureRef.SetParentBlock(*this);
770 
771   return bRes;
772 }
773 
AddFrame(const KaxTrackEntry & track,uint64 timecode,DataBuffer & buffer,const KaxBlockBlob * PastBlock,const KaxBlockBlob * ForwBlock,LacingType lacing)774 bool KaxBlockGroup::AddFrame(const KaxTrackEntry & track, uint64 timecode, DataBuffer & buffer, const KaxBlockBlob * PastBlock, const KaxBlockBlob * ForwBlock, LacingType lacing)
775 {
776   auto & theBlock = GetChild<KaxBlock>(*this);
777   assert(ParentCluster != nullptr);
778   theBlock.SetParent(*ParentCluster);
779   ParentTrack = &track;
780   bool bRes = theBlock.AddFrame(track, timecode, buffer, lacing);
781 
782   if (PastBlock != nullptr) {
783     auto & thePastRef = GetChild<KaxReferenceBlock>(*this);
784     thePastRef.SetReferencedBlock(PastBlock);
785     thePastRef.SetParentBlock(*this);
786   }
787 
788   if (ForwBlock != nullptr) {
789     auto & theFutureRef = AddNewChild<KaxReferenceBlock>(*this);
790     theFutureRef.SetReferencedBlock(ForwBlock);
791     theFutureRef.SetParentBlock(*this);
792   }
793 
794   return bRes;
795 }
796 
797 /*!
798   \todo we may cache the reference to the timecode block
799 */
GlobalTimecode() const800 uint64 KaxBlockGroup::GlobalTimecode() const
801 {
802   assert(ParentCluster != nullptr); // impossible otherwise
803   KaxInternalBlock & MyBlock = *static_cast<KaxBlock *>(this->FindElt(EBML_INFO(KaxBlock)));
804   return MyBlock.GlobalTimecode();
805 
806 }
807 
TrackNumber() const808 uint16 KaxBlockGroup::TrackNumber() const
809 {
810   KaxInternalBlock & MyBlock = *static_cast<KaxBlock *>(this->FindElt(EBML_INFO(KaxBlock)));
811   return MyBlock.TrackNum();
812 }
813 
ClusterPosition() const814 uint64 KaxBlockGroup::ClusterPosition() const
815 {
816   assert(ParentCluster != nullptr); // impossible otherwise
817   return ParentCluster->GetPosition();
818 }
819 
ClusterPosition() const820 uint64 KaxInternalBlock::ClusterPosition() const
821 {
822   assert(ParentCluster != nullptr); // impossible otherwise
823   return ParentCluster->GetPosition();
824 }
825 
ReferenceCount() const826 unsigned int KaxBlockGroup::ReferenceCount() const
827 {
828   unsigned int Result = 0;
829   auto MyBlockAdds = static_cast<KaxReferenceBlock *>(FindFirstElt(EBML_INFO(KaxReferenceBlock)));
830   if (MyBlockAdds != nullptr) {
831     Result++;
832     while ((MyBlockAdds = static_cast<KaxReferenceBlock *>(FindNextElt(*MyBlockAdds))) != nullptr) {
833       Result++;
834     }
835   }
836   return Result;
837 }
838 
Reference(unsigned int Index) const839 const KaxReferenceBlock & KaxBlockGroup::Reference(unsigned int Index) const
840 {
841   auto MyBlockAdds = static_cast<KaxReferenceBlock *>(FindFirstElt(EBML_INFO(KaxReferenceBlock)));
842   assert(MyBlockAdds != nullptr); // call of a non existing reference
843 
844   while (Index != 0) {
845     MyBlockAdds = static_cast<KaxReferenceBlock *>(FindNextElt(*MyBlockAdds));
846     assert(MyBlockAdds != nullptr);
847     Index--;
848   }
849   return *MyBlockAdds;
850 }
851 
ReleaseFrames()852 void KaxBlockGroup::ReleaseFrames()
853 {
854   KaxInternalBlock & MyBlock = *static_cast<KaxBlock *>(this->FindElt(EBML_INFO(KaxBlock)));
855   MyBlock.ReleaseFrames();
856 }
857 
ReleaseFrames()858 void KaxInternalBlock::ReleaseFrames()
859 {
860   // free the allocated Frames
861   int i;
862   for (i=myBuffers.size()-1; i>=0; i--) {
863     if (myBuffers[i] != nullptr) {
864       myBuffers[i]->FreeBuffer(*myBuffers[i]);
865       delete myBuffers[i];
866       myBuffers[i] = nullptr;
867     }
868   }
869 }
870 
SetBlockDuration(uint64 TimeLength)871 void KaxBlockGroup::SetBlockDuration(uint64 TimeLength)
872 {
873   assert(ParentTrack != nullptr);
874   int64 scale = ParentTrack->GlobalTimecodeScale();
875   KaxBlockDuration & myDuration = *static_cast<KaxBlockDuration *>(FindFirstElt(EBML_INFO(KaxBlockDuration), true));
876   *(static_cast<EbmlUInteger *>(&myDuration)) = TimeLength / uint64(scale);
877 }
878 
GetBlockDuration(uint64 & TheTimecode) const879 bool KaxBlockGroup::GetBlockDuration(uint64 &TheTimecode) const
880 {
881   auto myDuration = static_cast<KaxBlockDuration *>(FindElt(EBML_INFO(KaxBlockDuration)));
882   if (myDuration == nullptr) {
883     return false;
884   }
885 
886   assert(ParentTrack != nullptr);
887   TheTimecode = uint64(*myDuration) * ParentTrack->GlobalTimecodeScale();
888   return true;
889 }
890 
operator KaxInternalBlock&()891 KaxBlockGroup::operator KaxInternalBlock &() {
892   auto & theBlock = GetChild<KaxBlock>(*this);
893   return theBlock;
894 }
895 
SetParent(KaxCluster & aParentCluster)896 void KaxBlockGroup::SetParent(KaxCluster & aParentCluster) {
897   ParentCluster = &aParentCluster;
898   auto & theBlock = GetChild<KaxBlock>(*this);
899   theBlock.SetParent( aParentCluster );
900 }
901 
SetParent(KaxCluster & aParentCluster)902 void KaxSimpleBlock::SetParent(KaxCluster & aParentCluster) {
903   KaxInternalBlock::SetParent( aParentCluster );
904 }
905 
SetParent(KaxCluster & aParentCluster)906 void KaxInternalBlock::SetParent(KaxCluster & aParentCluster)
907 {
908   ParentCluster = &aParentCluster;
909   if (bLocalTimecodeUsed) {
910     Timecode = aParentCluster.GetBlockGlobalTimecode(LocalTimecode);
911     bLocalTimecodeUsed = false;
912   }
913 }
914 
GetDataPosition(size_t FrameNumber)915 int64 KaxInternalBlock::GetDataPosition(size_t FrameNumber)
916 {
917   int64 _Result = -1;
918 
919   if (ValueIsSet() && FrameNumber < SizeList.size()) {
920     _Result = FirstFrameLocation;
921 
922     size_t _Idx = 0;
923     while(FrameNumber--) {
924       _Result += SizeList[_Idx++];
925     }
926   }
927 
928   return _Result;
929 }
930 
GetFrameSize(size_t FrameNumber)931 int64 KaxInternalBlock::GetFrameSize(size_t FrameNumber)
932 {
933   int64 _Result = -1;
934 
935   if (/*bValueIsSet &&*/ FrameNumber < SizeList.size()) {
936     _Result = SizeList[FrameNumber];
937   }
938 
939   return _Result;
940 }
941 
operator KaxBlockGroup&()942 KaxBlockBlob::operator KaxBlockGroup &()
943 {
944   assert(!bUseSimpleBlock);
945   assert(Block.group);
946   return *Block.group;
947 }
948 
operator const KaxBlockGroup&() const949 KaxBlockBlob::operator const KaxBlockGroup &() const
950 {
951   assert(!bUseSimpleBlock);
952   assert(Block.group);
953   return *Block.group;
954 }
955 
operator KaxInternalBlock&()956 KaxBlockBlob::operator KaxInternalBlock &()
957 {
958   assert(Block.group);
959   if (bUseSimpleBlock)
960     return *Block.simpleblock;
961   return *Block.group;
962 }
963 
operator const KaxInternalBlock&() const964 KaxBlockBlob::operator const KaxInternalBlock &() const
965 {
966   assert(Block.group);
967   if (bUseSimpleBlock)
968     return *Block.simpleblock;
969   return *Block.group;
970 }
971 
operator KaxSimpleBlock&()972 KaxBlockBlob::operator KaxSimpleBlock &()
973 {
974   assert(bUseSimpleBlock);
975   assert(Block.simpleblock);
976   return *Block.simpleblock;
977 }
978 
AddFrameAuto(const KaxTrackEntry & track,uint64 timecode,DataBuffer & buffer,LacingType lacing,const KaxBlockBlob * PastBlock,const KaxBlockBlob * ForwBlock)979 bool KaxBlockBlob::AddFrameAuto(const KaxTrackEntry & track, uint64 timecode, DataBuffer & buffer, LacingType lacing, const KaxBlockBlob * PastBlock, const KaxBlockBlob * ForwBlock)
980 {
981   bool bResult = false;
982   if ((SimpleBlockMode == BLOCK_BLOB_ALWAYS_SIMPLE) || (SimpleBlockMode == BLOCK_BLOB_SIMPLE_AUTO && PastBlock == nullptr && ForwBlock == nullptr)) {
983     assert(bUseSimpleBlock == true);
984     if (Block.simpleblock == nullptr) {
985       Block.simpleblock = new KaxSimpleBlock();
986       Block.simpleblock->SetParent(*ParentCluster);
987     }
988 
989     bResult = Block.simpleblock->AddFrame(track, timecode, buffer, lacing);
990     if (PastBlock == nullptr && ForwBlock == nullptr) {
991       Block.simpleblock->SetKeyframe(true);
992       Block.simpleblock->SetDiscardable(false);
993     } else {
994       Block.simpleblock->SetKeyframe(false);
995       if ((ForwBlock == nullptr || ((const KaxInternalBlock &)*ForwBlock).GlobalTimecode() <= timecode) &&
996           (PastBlock == nullptr || ((const KaxInternalBlock &)*PastBlock).GlobalTimecode() <= timecode))
997         Block.simpleblock->SetDiscardable(false);
998       else
999         Block.simpleblock->SetDiscardable(true);
1000     }
1001   }
1002   else
1003     if (ReplaceSimpleByGroup())
1004       bResult = Block.group->AddFrame(track, timecode, buffer, PastBlock, ForwBlock, lacing);
1005 
1006   return bResult;
1007 }
1008 
SetParent(KaxCluster & aParentCluster)1009 void KaxBlockBlob::SetParent(KaxCluster & aParentCluster)
1010 {
1011   ParentCluster = &aParentCluster;
1012 }
1013 
SetBlockDuration(uint64 TimeLength)1014 void KaxBlockBlob::SetBlockDuration(uint64 TimeLength)
1015 {
1016   if (ReplaceSimpleByGroup())
1017     Block.group->SetBlockDuration(TimeLength);
1018 }
1019 
ReplaceSimpleByGroup()1020 bool KaxBlockBlob::ReplaceSimpleByGroup()
1021 {
1022   if (SimpleBlockMode== BLOCK_BLOB_ALWAYS_SIMPLE)
1023     return false;
1024 
1025   if (!bUseSimpleBlock) {
1026     if (Block.group == nullptr) {
1027       Block.group = new KaxBlockGroup();
1028     }
1029   }
1030   else {
1031 
1032     if (Block.simpleblock != nullptr) {
1033       KaxSimpleBlock *old_simpleblock = Block.simpleblock;
1034       Block.group = new KaxBlockGroup();
1035       // _TODO_ : move all the data to the blockgroup
1036       assert(false);
1037       // -> while(frame) AddFrame(myBuffer)
1038       delete old_simpleblock;
1039     } else {
1040       Block.group = new KaxBlockGroup();
1041     }
1042   }
1043   if (ParentCluster != nullptr)
1044     Block.group->SetParent(*ParentCluster);
1045 
1046   bUseSimpleBlock = false;
1047   return true;
1048 }
1049 
SetBlockGroup(KaxBlockGroup & BlockRef)1050 void KaxBlockBlob::SetBlockGroup( KaxBlockGroup &BlockRef )
1051 {
1052   assert(!bUseSimpleBlock);
1053   Block.group = &BlockRef;
1054 }
1055 
ReadData(IOCallback & input,ScopeMode)1056 filepos_t KaxBlockVirtual::ReadData(IOCallback & input, ScopeMode /* ReadFully */)
1057 {
1058   input.setFilePointer(SizePosition + CodedSizeLength(Size, SizeLength, bSizeIsFinite) + Size, seek_beginning);
1059   return GetSize();
1060 }
1061 
1062 END_LIBMATROSKA_NAMESPACE
1063