1 /****************************************************************************
2 ** libebml : parse EBML files, see http://embl.sourceforge.net/
4 ** <file/class description>
6 ** Copyright (C) 2002-2005 Steve Lhomme. All rights reserved.
8 ** This file is part of libebml.
10 ** This library is free software; you can redistribute it and/or
11 ** modify it under the terms of the GNU Lesser General Public
12 ** License as published by the Free Software Foundation; either
13 ** version 2.1 of the License, or (at your option) any later version.
15 ** This library is distributed in the hope that it will be useful,
16 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 ** Lesser General Public License for more details.
20 ** You should have received a copy of the GNU Lesser General Public
21 ** License along with this library; if not, write to the Free Software
22 ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 ** See http://www.matroska.org/license/lgpl/ for LGPL licensing information.
26 ** Contact license@matroska.org if any conditions of this licensing are
29 **********************************************************************/
33 \version \$Id: EbmlMaster.cpp 1178 2005-05-19 15:47:11Z robux4 $
34 \author Steve Lhomme <robux4 @ users.sf.net>
40 #include "ebml/EbmlMaster.h"
41 #include "ebml/EbmlStream.h"
42 #include "ebml/EbmlContexts.h"
43 #include "ebml/MemIOCallback.h"
45 START_LIBEBML_NAMESPACE
47 EbmlMaster::EbmlMaster(const EbmlSemanticContext
& aContext
, const bool bSizeIsknown
)
48 :EbmlElement(0), Context(aContext
), bChecksumUsed(bChecksumUsedByDefault
)
50 bSizeIsFinite
= bSizeIsknown
;
55 EbmlMaster::EbmlMaster(const EbmlMaster
& ElementToClone
)
56 :EbmlElement(ElementToClone
)
57 ,ElementList(ElementToClone
.ListSize())
58 ,Context(ElementToClone
.Context
)
59 ,bChecksumUsed(ElementToClone
.bChecksumUsed
)
60 ,Checksum(ElementToClone
.Checksum
)
62 // add a clone of the list
63 std::vector
<EbmlElement
*>::const_iterator Itr
= ElementToClone
.ElementList
.begin();
64 std::vector
<EbmlElement
*>::iterator myItr
= ElementList
.begin();
65 while (Itr
!= ElementToClone
.ElementList
.end())
67 *myItr
= (*Itr
)->Clone();
73 EbmlMaster::~EbmlMaster()
75 assert(!bLocked
); // you're trying to delete a locked element !!!
79 for (Index
= 0; Index
< ElementList
.size(); Index
++) {
80 if (!(*ElementList
[Index
]).IsLocked()) {
81 delete ElementList
[Index
];
87 \todo handle exception on errors
88 \todo write all the Mandatory elements in the Context, otherwise assert
90 uint32
EbmlMaster::RenderData(IOCallback
& output
, bool bForceRender
, bool bKeepIntact
)
96 assert(CheckMandatory());
99 if (!bChecksumUsed
) { // old school
100 for (Index
= 0; Index
< ElementList
.size(); Index
++) {
101 if (!bKeepIntact
&& (ElementList
[Index
])->IsDefaultValue())
103 Result
+= (ElementList
[Index
])->Render(output
, bKeepIntact
, false ,bForceRender
);
105 } else { // new school
106 MemIOCallback
TmpBuf(Size
- 6);
107 for (Index
= 0; Index
< ElementList
.size(); Index
++) {
108 if (!bKeepIntact
&& (ElementList
[Index
])->IsDefaultValue())
110 (ElementList
[Index
])->Render(TmpBuf
, bKeepIntact
, false ,bForceRender
);
112 Checksum
.FillCRC32(TmpBuf
.GetDataBuffer(), TmpBuf
.GetDataBufferSize());
113 Result
+= Checksum
.Render(output
, true, false ,bForceRender
);
114 output
.writeFully(TmpBuf
.GetDataBuffer(), TmpBuf
.GetDataBufferSize());
115 Result
+= TmpBuf
.GetDataBufferSize();
122 \todo We might be able to forbid elements that don't exist in the context
124 bool EbmlMaster::PushElement(EbmlElement
& element
)
126 ElementList
.push_back(&element
);
130 uint64
EbmlMaster::UpdateSize(bool bKeepIntact
, bool bForceRender
)
138 assert(CheckMandatory());
143 for (Index
= 0; Index
< ElementList
.size(); Index
++) {
144 if (!bKeepIntact
&& (ElementList
[Index
])->IsDefaultValue())
146 (ElementList
[Index
])->UpdateSize(bKeepIntact
, bForceRender
);
147 uint64 SizeToAdd
= (ElementList
[Index
])->ElementSize(bKeepIntact
);
148 #if defined(_DEBUG) || defined(DEBUG)
149 if (SizeToAdd
== (0-1))
155 Size
+= Checksum
.ElementSize();
161 uint32
EbmlMaster::WriteHead(IOCallback
& output
, int nSizeLength
, bool bKeepIntact
)
163 SetSizeLength(nSizeLength
);
164 return RenderHead(output
, false, bKeepIntact
);
168 \todo this code is very suspicious !
170 uint64
EbmlMaster::ReadData(IOCallback
& input
, ScopeMode ReadFully
)
172 input
.setFilePointer(Size
, seek_current
);
177 \note Hopefully no global element is mandatory
178 \todo should be called for ALL EbmlMaster element on construction
180 bool EbmlMaster::ProcessMandatory()
182 if (Context
.Size
== 0)
187 assert(Context
.MyTable
!= NULL
);
190 for (EltIdx
= 0; EltIdx
< Context
.Size
; EltIdx
++) {
191 if (Context
.MyTable
[EltIdx
].Mandatory
&& Context
.MyTable
[EltIdx
].Unique
) {
192 assert(Context
.MyTable
[EltIdx
].GetCallbacks
.Create
!= NULL
);
193 PushElement(Context
.MyTable
[EltIdx
].GetCallbacks
.Create());
199 bool EbmlMaster::CheckMandatory() const
201 assert(Context
.MyTable
!= NULL
);
204 for (EltIdx
= 0; EltIdx
< Context
.Size
; EltIdx
++) {
205 if (Context
.MyTable
[EltIdx
].Mandatory
) {
206 if (FindElt(Context
.MyTable
[EltIdx
].GetCallbacks
) == NULL
) {
207 #if defined(_DEBUG) || defined(DEBUG)
208 // you are missing this Mandatory element
209 // const char * MissingName = Context.MyTable[EltIdx].GetCallbacks.DebugName;
219 std::vector
<std::string
> EbmlMaster::FindAllMissingElements()
221 assert(Context
.MyTable
!= NULL
);
223 std::vector
<std::string
> missingElements
;
225 for (size_t ChildElementNo
= 0; ChildElementNo
< ElementList
.size(); ChildElementNo
++) {
226 EbmlElement
*childElement
= ElementList
[ChildElementNo
];
227 if (!childElement
->ValueIsSet()) {
228 std::string missingValue
;
229 missingValue
= "The Child Element \"";
230 missingValue
.append(childElement
->Generic().DebugName
);
231 missingValue
.append("\" of EbmlMaster \"");
232 missingValue
.append(this->Generic().DebugName
);
233 missingValue
.append("\", does not have a value set.");
234 missingElements
.push_back(missingValue
);
237 if (childElement
->IsMaster()) {
238 EbmlMaster
*childMaster
= (EbmlMaster
*)childElement
;
240 std::vector
<std::string
> childMissingElements
= childMaster
->FindAllMissingElements();
241 for (size_t s
= 0; s
< childMissingElements
.size(); s
++)
242 missingElements
.push_back(childMissingElements
[s
]);
246 for (EltIdx
= 0; EltIdx
< Context
.Size
; EltIdx
++) {
247 if (Context
.MyTable
[EltIdx
].Mandatory
) {
248 if (FindElt(Context
.MyTable
[EltIdx
].GetCallbacks
) == NULL
) {
249 std::string missingElement
;
250 missingElement
= "Missing element \"";
251 missingElement
.append(Context
.MyTable
[EltIdx
].GetCallbacks
.DebugName
);
252 missingElement
.append("\" in EbmlMaster \"");
253 missingElement
.append(Context
.MasterElt
->DebugName
);
254 missingElement
.append("\"");
255 missingElements
.push_back(missingElement
);
260 return missingElements
;
263 EbmlElement
*EbmlMaster::FindElt(const EbmlCallbacks
& Callbacks
) const
267 for (Index
= 0; Index
< ElementList
.size(); Index
++) {
268 EbmlElement
* tmp
= ElementList
[Index
];
269 if (EbmlId(*tmp
) == Callbacks
.GlobalId
)
276 EbmlElement
*EbmlMaster::FindFirstElt(const EbmlCallbacks
& Callbacks
, const bool bCreateIfNull
)
280 for (Index
= 0; Index
< ElementList
.size(); Index
++) {
281 if (EbmlId(*(ElementList
[Index
])) == Callbacks
.GlobalId
)
282 return ElementList
[Index
];
285 if (bCreateIfNull
&& Callbacks
.Create
!= NULL
) {
287 EbmlElement
*NewElt
= &(Callbacks
.Create());
291 if (!PushElement(*NewElt
)) {
301 EbmlElement
*EbmlMaster::FindFirstElt(const EbmlCallbacks
& Callbacks
) const
305 for (Index
= 0; Index
< ElementList
.size(); Index
++) {
306 if (EbmlId(*(ElementList
[Index
])) == Callbacks
.GlobalId
)
307 return ElementList
[Index
];
314 \todo only return elements that are from the same type !
315 \todo the element might be the unique in the context !
317 EbmlElement
*EbmlMaster::FindNextElt(const EbmlElement
& PastElt
, const bool bCreateIfNull
)
321 for (Index
= 0; Index
< ElementList
.size(); Index
++) {
322 if ((ElementList
[Index
]) == &PastElt
) {
323 // found past element, new one is :
329 while (Index
< ElementList
.size()) {
330 if (PastElt
.Generic().GlobalId
== ElementList
[Index
]->Generic().GlobalId
)
335 if (Index
!= ElementList
.size())
336 return ElementList
[Index
];
338 if (bCreateIfNull
&& PastElt
.Generic().Create
!= NULL
) {
340 EbmlElement
*NewElt
= &(PastElt
.Generic().Create());
344 if (!PushElement(*NewElt
)) {
354 EbmlElement
*EbmlMaster::FindNextElt(const EbmlElement
& PastElt
) const
358 for (Index
= 0; Index
< ElementList
.size(); Index
++) {
359 if ((ElementList
[Index
]) == &PastElt
) {
360 // found past element, new one is :
366 while (Index
< ElementList
.size()) {
367 if (PastElt
.Generic().GlobalId
== ElementList
[Index
]->Generic().GlobalId
)
368 return ElementList
[Index
];
375 EbmlElement
*EbmlMaster::AddNewElt(const EbmlCallbacks
& Callbacks
)
378 EbmlElement
*NewElt
= &(Callbacks
.Create());
382 if (!PushElement(*NewElt
)) {
389 void EbmlMaster::Sort()
391 std::sort(ElementList
.begin(), ElementList
.end(), EbmlElement::CompareElements
);
395 \brief Method to help reading a Master element and all subsequent children quickly
396 \todo add an option to discard even unknown elements
397 \todo handle when a mandatory element is not found
399 void EbmlMaster::Read(EbmlStream
& inDataStream
, const EbmlSemanticContext
& sContext
, int & UpperEltFound
, EbmlElement
* & FoundElt
, bool AllowDummyElt
, ScopeMode ReadFully
)
401 if (ReadFully
!= SCOPE_NO_DATA
)
403 EbmlElement
* ElementLevelA
;
404 // remove all existing elements, including the mandatory ones...
406 for (Index
=0; Index
<ElementList
.size(); Index
++) {
407 if (!(*ElementList
[Index
]).IsLocked()) {
408 delete ElementList
[Index
];
412 uint64 MaxSizeToRead
= Size
;
414 // read blocks and discard the ones we don't care about
415 if (MaxSizeToRead
> 0) {
416 inDataStream
.I_O().setFilePointer(SizePosition
+ SizeLength
, seek_beginning
);
417 ElementLevelA
= inDataStream
.FindNextElement(sContext
, UpperEltFound
, MaxSizeToRead
, AllowDummyElt
);
418 while (ElementLevelA
!= NULL
&& MaxSizeToRead
> 0 && UpperEltFound
<= 0) {
419 MaxSizeToRead
= GetEndPosition() - ElementLevelA
->GetEndPosition(); // even if it's the default value
420 if (!AllowDummyElt
&& ElementLevelA
->IsDummy()) {
421 ElementLevelA
->SkipData(inDataStream
, sContext
);
422 delete ElementLevelA
; // forget this unknown element
424 // more logical to do it afterward
425 ElementList
.push_back(ElementLevelA
);
427 ElementLevelA
->Read(inDataStream
, ElementLevelA
->Generic().Context
, UpperEltFound
, FoundElt
, AllowDummyElt
, ReadFully
);
430 ElementLevelA
->SkipData(inDataStream
, ElementLevelA
->Generic().Context
);
433 if (UpperEltFound
> 0) {
435 if (UpperEltFound
> 0 || MaxSizeToRead
<= 0)
437 ElementLevelA
= FoundElt
;
441 if (UpperEltFound
< 0) {
443 if (UpperEltFound
< 0)
447 if (MaxSizeToRead
<= 0) {
448 goto processCrc
;// this level is finished
451 ElementLevelA
= inDataStream
.FindNextElement(sContext
, UpperEltFound
, MaxSizeToRead
, AllowDummyElt
);
453 if (UpperEltFound
> 0) {
454 FoundElt
= ElementLevelA
;
458 for (Index
=0; Index
<ElementList
.size(); Index
++) {
459 if (ElementList
[Index
]->Generic().GlobalId
== EbmlCrc32::ClassInfos
.GlobalId
) {
460 bChecksumUsed
= true;
461 // remove the element
462 Checksum
= *(static_cast<EbmlCrc32
*>(ElementList
[Index
]));
463 delete ElementList
[Index
];
471 void EbmlMaster::Remove(size_t Index
)
473 if (Index
< ElementList
.size()) {
474 std::vector
<EbmlElement
*>::iterator Itr
= ElementList
.begin();
475 while (Index
-- > 0) {
479 ElementList
.erase(Itr
);
483 bool EbmlMaster::VerifyChecksum() const
489 /// \todo remove the Checksum if it's in the list
490 /// \todo find another way when not all default values are saved or (unknown from the reader !!!)
491 MemIOCallback
TmpBuf(Size
- 6);
492 for (size_t Index
= 0; Index
< ElementList
.size(); Index
++) {
493 (ElementList
[Index
])->Render(TmpBuf
, true, false, true);
495 aChecksum
.FillCRC32(TmpBuf
.GetDataBuffer(), TmpBuf
.GetDataBufferSize());
496 return (aChecksum
.GetCrc32() == Checksum
.GetCrc32());
499 bool EbmlMaster::InsertElement(EbmlElement
& element
, size_t position
)
501 std::vector
<EbmlElement
*>::iterator Itr
= ElementList
.begin();
502 while (Itr
!= ElementList
.end() && position
--)
506 if ((Itr
== ElementList
.end()) && position
)
509 ElementList
.insert(Itr
, &element
);
513 bool EbmlMaster::InsertElement(EbmlElement
& element
, const EbmlElement
& before
)
515 std::vector
<EbmlElement
*>::iterator Itr
= ElementList
.begin();
516 while (Itr
!= ElementList
.end() && *Itr
!= &before
)
520 if (Itr
== ElementList
.end())
523 ElementList
.insert(Itr
, &element
);
528 END_LIBEBML_NAMESPACE