1 /**************************************************************************
2 copyright : (C) 2005-2007 by Lukáš Lalinský
3 email : lalinsky@gmail.com
4 **************************************************************************/
5
6 /***************************************************************************
7 * This library is free software; you can redistribute it and/or modify *
8 * it under the terms of the GNU Lesser General Public License version *
9 * 2.1 as published by the Free Software Foundation. *
10 * *
11 * This library is distributed in the hope that it will be useful, but *
12 * WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
14 * Lesser General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU Lesser General Public *
17 * License along with this library; if not, write to the Free Software *
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
19 * 02110-1301 USA *
20 * *
21 * Alternatively, this file is available under the Mozilla Public *
22 * License Version 1.1. You may obtain a copy of the License at *
23 * http://www.mozilla.org/MPL/ *
24 ***************************************************************************/
25
26 #include <tdebug.h>
27 #include <tbytevectorlist.h>
28 #include <tpropertymap.h>
29 #include <tstring.h>
30 #include <tagutils.h>
31
32 #include "asffile.h"
33 #include "asftag.h"
34 #include "asfproperties.h"
35 #include "asfutils.h"
36
37 using namespace TagLib;
38
39 class ASF::File::FilePrivate
40 {
41 public:
42 class BaseObject;
43 class UnknownObject;
44 class FilePropertiesObject;
45 class StreamPropertiesObject;
46 class ContentDescriptionObject;
47 class ExtendedContentDescriptionObject;
48 class HeaderExtensionObject;
49 class CodecListObject;
50 class MetadataObject;
51 class MetadataLibraryObject;
52
FilePrivate()53 FilePrivate():
54 headerSize(0),
55 tag(0),
56 properties(0),
57 contentDescriptionObject(0),
58 extendedContentDescriptionObject(0),
59 headerExtensionObject(0),
60 metadataObject(0),
61 metadataLibraryObject(0)
62 {
63 objects.setAutoDelete(true);
64 }
65
~FilePrivate()66 ~FilePrivate()
67 {
68 delete tag;
69 delete properties;
70 }
71
72 unsigned long long headerSize;
73
74 ASF::Tag *tag;
75 ASF::Properties *properties;
76
77 List<BaseObject *> objects;
78
79 ContentDescriptionObject *contentDescriptionObject;
80 ExtendedContentDescriptionObject *extendedContentDescriptionObject;
81 HeaderExtensionObject *headerExtensionObject;
82 MetadataObject *metadataObject;
83 MetadataLibraryObject *metadataLibraryObject;
84 };
85
86 namespace
87 {
88 const ByteVector headerGuid("\x30\x26\xB2\x75\x8E\x66\xCF\x11\xA6\xD9\x00\xAA\x00\x62\xCE\x6C", 16);
89 const ByteVector filePropertiesGuid("\xA1\xDC\xAB\x8C\x47\xA9\xCF\x11\x8E\xE4\x00\xC0\x0C\x20\x53\x65", 16);
90 const ByteVector streamPropertiesGuid("\x91\x07\xDC\xB7\xB7\xA9\xCF\x11\x8E\xE6\x00\xC0\x0C\x20\x53\x65", 16);
91 const ByteVector contentDescriptionGuid("\x33\x26\xB2\x75\x8E\x66\xCF\x11\xA6\xD9\x00\xAA\x00\x62\xCE\x6C", 16);
92 const ByteVector extendedContentDescriptionGuid("\x40\xA4\xD0\xD2\x07\xE3\xD2\x11\x97\xF0\x00\xA0\xC9\x5E\xA8\x50", 16);
93 const ByteVector headerExtensionGuid("\xb5\x03\xbf_.\xa9\xcf\x11\x8e\xe3\x00\xc0\x0c Se", 16);
94 const ByteVector metadataGuid("\xEA\xCB\xF8\xC5\xAF[wH\204g\xAA\214D\xFAL\xCA", 16);
95 const ByteVector metadataLibraryGuid("\224\034#D\230\224\321I\241A\x1d\x13NEpT", 16);
96 const ByteVector codecListGuid("\x40\x52\xd1\x86\x1d\x31\xd0\x11\xa3\xa4\x00\xa0\xc9\x03\x48\xf6", 16);
97 const ByteVector contentEncryptionGuid("\xFB\xB3\x11\x22\x23\xBD\xD2\x11\xB4\xB7\x00\xA0\xC9\x55\xFC\x6E", 16);
98 const ByteVector extendedContentEncryptionGuid("\x14\xE6\x8A\x29\x22\x26 \x17\x4C\xB9\x35\xDA\xE0\x7E\xE9\x28\x9C", 16);
99 const ByteVector advancedContentEncryptionGuid("\xB6\x9B\x07\x7A\xA4\xDA\x12\x4E\xA5\xCA\x91\xD3\x8D\xC1\x1A\x8D", 16);
100 }
101
102 class ASF::File::FilePrivate::BaseObject
103 {
104 public:
105 ByteVector data;
~BaseObject()106 virtual ~BaseObject() {}
107 virtual ByteVector guid() const = 0;
108 virtual void parse(ASF::File *file, unsigned int size);
109 virtual ByteVector render(ASF::File *file);
110 };
111
112 class ASF::File::FilePrivate::UnknownObject : public ASF::File::FilePrivate::BaseObject
113 {
114 ByteVector myGuid;
115 public:
116 UnknownObject(const ByteVector &guid);
117 ByteVector guid() const;
118 };
119
120 class ASF::File::FilePrivate::FilePropertiesObject : public ASF::File::FilePrivate::BaseObject
121 {
122 public:
123 ByteVector guid() const;
124 void parse(ASF::File *file, unsigned int size);
125 };
126
127 class ASF::File::FilePrivate::StreamPropertiesObject : public ASF::File::FilePrivate::BaseObject
128 {
129 public:
130 ByteVector guid() const;
131 void parse(ASF::File *file, unsigned int size);
132 };
133
134 class ASF::File::FilePrivate::ContentDescriptionObject : public ASF::File::FilePrivate::BaseObject
135 {
136 public:
137 ByteVector guid() const;
138 void parse(ASF::File *file, unsigned int size);
139 ByteVector render(ASF::File *file);
140 };
141
142 class ASF::File::FilePrivate::ExtendedContentDescriptionObject : public ASF::File::FilePrivate::BaseObject
143 {
144 public:
145 ByteVectorList attributeData;
146 ByteVector guid() const;
147 void parse(ASF::File *file, unsigned int size);
148 ByteVector render(ASF::File *file);
149 };
150
151 class ASF::File::FilePrivate::MetadataObject : public ASF::File::FilePrivate::BaseObject
152 {
153 public:
154 ByteVectorList attributeData;
155 ByteVector guid() const;
156 void parse(ASF::File *file, unsigned int size);
157 ByteVector render(ASF::File *file);
158 };
159
160 class ASF::File::FilePrivate::MetadataLibraryObject : public ASF::File::FilePrivate::BaseObject
161 {
162 public:
163 ByteVectorList attributeData;
164 ByteVector guid() const;
165 void parse(ASF::File *file, unsigned int size);
166 ByteVector render(ASF::File *file);
167 };
168
169 class ASF::File::FilePrivate::HeaderExtensionObject : public ASF::File::FilePrivate::BaseObject
170 {
171 public:
172 List<ASF::File::FilePrivate::BaseObject *> objects;
173 HeaderExtensionObject();
174 ByteVector guid() const;
175 void parse(ASF::File *file, unsigned int size);
176 ByteVector render(ASF::File *file);
177 };
178
179 class ASF::File::FilePrivate::CodecListObject : public ASF::File::FilePrivate::BaseObject
180 {
181 public:
182 ByteVector guid() const;
183 void parse(ASF::File *file, unsigned int size);
184
185 private:
186 enum CodecType
187 {
188 Video = 0x0001,
189 Audio = 0x0002,
190 Unknown = 0xFFFF
191 };
192 };
193
parse(ASF::File * file,unsigned int size)194 void ASF::File::FilePrivate::BaseObject::parse(ASF::File *file, unsigned int size)
195 {
196 data.clear();
197 if(size > 24 && size <= (unsigned int)(file->length()))
198 data = file->readBlock(size - 24);
199 else
200 data = ByteVector();
201 }
202
render(ASF::File *)203 ByteVector ASF::File::FilePrivate::BaseObject::render(ASF::File * /*file*/)
204 {
205 return guid() + ByteVector::fromLongLong(data.size() + 24, false) + data;
206 }
207
UnknownObject(const ByteVector & guid)208 ASF::File::FilePrivate::UnknownObject::UnknownObject(const ByteVector &guid) : myGuid(guid)
209 {
210 }
211
guid() const212 ByteVector ASF::File::FilePrivate::UnknownObject::guid() const
213 {
214 return myGuid;
215 }
216
guid() const217 ByteVector ASF::File::FilePrivate::FilePropertiesObject::guid() const
218 {
219 return filePropertiesGuid;
220 }
221
parse(ASF::File * file,unsigned int size)222 void ASF::File::FilePrivate::FilePropertiesObject::parse(ASF::File *file, unsigned int size)
223 {
224 BaseObject::parse(file, size);
225 if(data.size() < 64) {
226 debug("ASF::File::FilePrivate::FilePropertiesObject::parse() -- data is too short.");
227 return;
228 }
229
230 const long long duration = data.toLongLong(40, false);
231 const long long preroll = data.toLongLong(56, false);
232 file->d->properties->setLengthInMilliseconds(static_cast<int>(duration / 10000.0 - preroll + 0.5));
233 }
234
guid() const235 ByteVector ASF::File::FilePrivate::StreamPropertiesObject::guid() const
236 {
237 return streamPropertiesGuid;
238 }
239
parse(ASF::File * file,unsigned int size)240 void ASF::File::FilePrivate::StreamPropertiesObject::parse(ASF::File *file, unsigned int size)
241 {
242 BaseObject::parse(file, size);
243 if(data.size() < 70) {
244 debug("ASF::File::FilePrivate::StreamPropertiesObject::parse() -- data is too short.");
245 return;
246 }
247
248 file->d->properties->setCodec(data.toUShort(54, false));
249 file->d->properties->setChannels(data.toUShort(56, false));
250 file->d->properties->setSampleRate(data.toUInt(58, false));
251 file->d->properties->setBitrate(static_cast<int>(data.toUInt(62, false) * 8.0 / 1000.0 + 0.5));
252 file->d->properties->setBitsPerSample(data.toUShort(68, false));
253 }
254
guid() const255 ByteVector ASF::File::FilePrivate::ContentDescriptionObject::guid() const
256 {
257 return contentDescriptionGuid;
258 }
259
parse(ASF::File * file,unsigned int)260 void ASF::File::FilePrivate::ContentDescriptionObject::parse(ASF::File *file, unsigned int /*size*/)
261 {
262 const int titleLength = readWORD(file);
263 const int artistLength = readWORD(file);
264 const int copyrightLength = readWORD(file);
265 const int commentLength = readWORD(file);
266 const int ratingLength = readWORD(file);
267 file->d->tag->setTitle(readString(file,titleLength));
268 file->d->tag->setArtist(readString(file,artistLength));
269 file->d->tag->setCopyright(readString(file,copyrightLength));
270 file->d->tag->setComment(readString(file,commentLength));
271 file->d->tag->setRating(readString(file,ratingLength));
272 }
273
render(ASF::File * file)274 ByteVector ASF::File::FilePrivate::ContentDescriptionObject::render(ASF::File *file)
275 {
276 const ByteVector v1 = renderString(file->d->tag->title());
277 const ByteVector v2 = renderString(file->d->tag->artist());
278 const ByteVector v3 = renderString(file->d->tag->copyright());
279 const ByteVector v4 = renderString(file->d->tag->comment());
280 const ByteVector v5 = renderString(file->d->tag->rating());
281 data.clear();
282 data.append(ByteVector::fromShort(v1.size(), false));
283 data.append(ByteVector::fromShort(v2.size(), false));
284 data.append(ByteVector::fromShort(v3.size(), false));
285 data.append(ByteVector::fromShort(v4.size(), false));
286 data.append(ByteVector::fromShort(v5.size(), false));
287 data.append(v1);
288 data.append(v2);
289 data.append(v3);
290 data.append(v4);
291 data.append(v5);
292 return BaseObject::render(file);
293 }
294
guid() const295 ByteVector ASF::File::FilePrivate::ExtendedContentDescriptionObject::guid() const
296 {
297 return extendedContentDescriptionGuid;
298 }
299
parse(ASF::File * file,unsigned int)300 void ASF::File::FilePrivate::ExtendedContentDescriptionObject::parse(ASF::File *file, unsigned int /*size*/)
301 {
302 int count = readWORD(file);
303 while(count--) {
304 ASF::Attribute attribute;
305 String name = attribute.parse(*file);
306 file->d->tag->addAttribute(name, attribute);
307 }
308 }
309
render(ASF::File * file)310 ByteVector ASF::File::FilePrivate::ExtendedContentDescriptionObject::render(ASF::File *file)
311 {
312 data.clear();
313 data.append(ByteVector::fromShort(attributeData.size(), false));
314 data.append(attributeData.toByteVector(""));
315 return BaseObject::render(file);
316 }
317
guid() const318 ByteVector ASF::File::FilePrivate::MetadataObject::guid() const
319 {
320 return metadataGuid;
321 }
322
parse(ASF::File * file,unsigned int)323 void ASF::File::FilePrivate::MetadataObject::parse(ASF::File *file, unsigned int /*size*/)
324 {
325 int count = readWORD(file);
326 while(count--) {
327 ASF::Attribute attribute;
328 String name = attribute.parse(*file, 1);
329 file->d->tag->addAttribute(name, attribute);
330 }
331 }
332
render(ASF::File * file)333 ByteVector ASF::File::FilePrivate::MetadataObject::render(ASF::File *file)
334 {
335 data.clear();
336 data.append(ByteVector::fromShort(attributeData.size(), false));
337 data.append(attributeData.toByteVector(""));
338 return BaseObject::render(file);
339 }
340
guid() const341 ByteVector ASF::File::FilePrivate::MetadataLibraryObject::guid() const
342 {
343 return metadataLibraryGuid;
344 }
345
parse(ASF::File * file,unsigned int)346 void ASF::File::FilePrivate::MetadataLibraryObject::parse(ASF::File *file, unsigned int /*size*/)
347 {
348 int count = readWORD(file);
349 while(count--) {
350 ASF::Attribute attribute;
351 String name = attribute.parse(*file, 2);
352 file->d->tag->addAttribute(name, attribute);
353 }
354 }
355
render(ASF::File * file)356 ByteVector ASF::File::FilePrivate::MetadataLibraryObject::render(ASF::File *file)
357 {
358 data.clear();
359 data.append(ByteVector::fromShort(attributeData.size(), false));
360 data.append(attributeData.toByteVector(""));
361 return BaseObject::render(file);
362 }
363
HeaderExtensionObject()364 ASF::File::FilePrivate::HeaderExtensionObject::HeaderExtensionObject()
365 {
366 objects.setAutoDelete(true);
367 }
368
guid() const369 ByteVector ASF::File::FilePrivate::HeaderExtensionObject::guid() const
370 {
371 return headerExtensionGuid;
372 }
373
parse(ASF::File * file,unsigned int)374 void ASF::File::FilePrivate::HeaderExtensionObject::parse(ASF::File *file, unsigned int /*size*/)
375 {
376 file->seek(18, File::Current);
377 long long dataSize = readDWORD(file);
378 long long dataPos = 0;
379 while(dataPos < dataSize) {
380 ByteVector guid = file->readBlock(16);
381 if(guid.size() != 16) {
382 file->setValid(false);
383 break;
384 }
385 bool ok;
386 long long size = readQWORD(file, &ok);
387 if(!ok) {
388 file->setValid(false);
389 break;
390 }
391 BaseObject *obj;
392 if(guid == metadataGuid) {
393 file->d->metadataObject = new MetadataObject();
394 obj = file->d->metadataObject;
395 }
396 else if(guid == metadataLibraryGuid) {
397 file->d->metadataLibraryObject = new MetadataLibraryObject();
398 obj = file->d->metadataLibraryObject;
399 }
400 else {
401 obj = new UnknownObject(guid);
402 }
403 obj->parse(file, (unsigned int)size);
404 objects.append(obj);
405 dataPos += size;
406 }
407 }
408
render(ASF::File * file)409 ByteVector ASF::File::FilePrivate::HeaderExtensionObject::render(ASF::File *file)
410 {
411 data.clear();
412 for(List<BaseObject *>::ConstIterator it = objects.begin(); it != objects.end(); ++it) {
413 data.append((*it)->render(file));
414 }
415 data = ByteVector("\x11\xD2\xD3\xAB\xBA\xA9\xcf\x11\x8E\xE6\x00\xC0\x0C\x20\x53\x65\x06\x00", 18) + ByteVector::fromUInt(data.size(), false) + data;
416 return BaseObject::render(file);
417 }
418
guid() const419 ByteVector ASF::File::FilePrivate::CodecListObject::guid() const
420 {
421 return codecListGuid;
422 }
423
parse(ASF::File * file,unsigned int size)424 void ASF::File::FilePrivate::CodecListObject::parse(ASF::File *file, unsigned int size)
425 {
426 BaseObject::parse(file, size);
427 if(data.size() <= 20) {
428 debug("ASF::File::FilePrivate::CodecListObject::parse() -- data is too short.");
429 return;
430 }
431
432 unsigned int pos = 16;
433
434 const int count = data.toUInt(pos, false);
435 pos += 4;
436
437 for(int i = 0; i < count; ++i) {
438
439 if(pos >= data.size())
440 break;
441
442 const CodecType type = static_cast<CodecType>(data.toUShort(pos, false));
443 pos += 2;
444
445 int nameLength = data.toUShort(pos, false);
446 pos += 2;
447
448 const unsigned int namePos = pos;
449 pos += nameLength * 2;
450
451 const int descLength = data.toUShort(pos, false);
452 pos += 2;
453
454 const unsigned int descPos = pos;
455 pos += descLength * 2;
456
457 const int infoLength = data.toUShort(pos, false);
458 pos += 2 + infoLength * 2;
459
460 if(type == CodecListObject::Audio) {
461 // First audio codec found.
462
463 const String name(data.mid(namePos, nameLength * 2), String::UTF16LE);
464 file->d->properties->setCodecName(name.stripWhiteSpace());
465
466 const String desc(data.mid(descPos, descLength * 2), String::UTF16LE);
467 file->d->properties->setCodecDescription(desc.stripWhiteSpace());
468
469 break;
470 }
471 }
472 }
473
474 ////////////////////////////////////////////////////////////////////////////////
475 // static members
476 ////////////////////////////////////////////////////////////////////////////////
477
isSupported(IOStream * stream)478 bool ASF::File::isSupported(IOStream *stream)
479 {
480 // An ASF file has to start with the designated GUID.
481
482 const ByteVector id = Utils::readHeader(stream, 16, false);
483 return (id == headerGuid);
484 }
485
486 ////////////////////////////////////////////////////////////////////////////////
487 // public members
488 ////////////////////////////////////////////////////////////////////////////////
489
File(FileName file,bool,Properties::ReadStyle)490 ASF::File::File(FileName file, bool, Properties::ReadStyle) :
491 TagLib::File(file),
492 d(new FilePrivate())
493 {
494 if(isOpen())
495 read();
496 }
497
File(IOStream * stream,bool,Properties::ReadStyle)498 ASF::File::File(IOStream *stream, bool, Properties::ReadStyle) :
499 TagLib::File(stream),
500 d(new FilePrivate())
501 {
502 if(isOpen())
503 read();
504 }
505
~File()506 ASF::File::~File()
507 {
508 delete d;
509 }
510
tag() const511 ASF::Tag *ASF::File::tag() const
512 {
513 return d->tag;
514 }
515
properties() const516 PropertyMap ASF::File::properties() const
517 {
518 return d->tag->properties();
519 }
520
removeUnsupportedProperties(const StringList & properties)521 void ASF::File::removeUnsupportedProperties(const StringList &properties)
522 {
523 d->tag->removeUnsupportedProperties(properties);
524 }
525
setProperties(const PropertyMap & properties)526 PropertyMap ASF::File::setProperties(const PropertyMap &properties)
527 {
528 return d->tag->setProperties(properties);
529 }
530
audioProperties() const531 ASF::Properties *ASF::File::audioProperties() const
532 {
533 return d->properties;
534 }
535
save()536 bool ASF::File::save()
537 {
538 if(readOnly()) {
539 debug("ASF::File::save() -- File is read only.");
540 return false;
541 }
542
543 if(!isValid()) {
544 debug("ASF::File::save() -- Trying to save invalid file.");
545 return false;
546 }
547
548 if(!d->contentDescriptionObject) {
549 d->contentDescriptionObject = new FilePrivate::ContentDescriptionObject();
550 d->objects.append(d->contentDescriptionObject);
551 }
552 if(!d->extendedContentDescriptionObject) {
553 d->extendedContentDescriptionObject = new FilePrivate::ExtendedContentDescriptionObject();
554 d->objects.append(d->extendedContentDescriptionObject);
555 }
556 if(!d->headerExtensionObject) {
557 d->headerExtensionObject = new FilePrivate::HeaderExtensionObject();
558 d->objects.append(d->headerExtensionObject);
559 }
560 if(!d->metadataObject) {
561 d->metadataObject = new FilePrivate::MetadataObject();
562 d->headerExtensionObject->objects.append(d->metadataObject);
563 }
564 if(!d->metadataLibraryObject) {
565 d->metadataLibraryObject = new FilePrivate::MetadataLibraryObject();
566 d->headerExtensionObject->objects.append(d->metadataLibraryObject);
567 }
568
569 d->extendedContentDescriptionObject->attributeData.clear();
570 d->metadataObject->attributeData.clear();
571 d->metadataLibraryObject->attributeData.clear();
572
573 const AttributeListMap allAttributes = d->tag->attributeListMap();
574
575 for(AttributeListMap::ConstIterator it = allAttributes.begin(); it != allAttributes.end(); ++it) {
576
577 const String &name = it->first;
578 const AttributeList &attributes = it->second;
579
580 bool inExtendedContentDescriptionObject = false;
581 bool inMetadataObject = false;
582
583 for(AttributeList::ConstIterator jt = attributes.begin(); jt != attributes.end(); ++jt) {
584
585 const Attribute &attribute = *jt;
586 const bool largeValue = (attribute.dataSize() > 65535);
587 const bool guid = (attribute.type() == Attribute::GuidType);
588
589 if(!inExtendedContentDescriptionObject && !guid && !largeValue && attribute.language() == 0 && attribute.stream() == 0) {
590 d->extendedContentDescriptionObject->attributeData.append(attribute.render(name));
591 inExtendedContentDescriptionObject = true;
592 }
593 else if(!inMetadataObject && !guid && !largeValue && attribute.language() == 0 && attribute.stream() != 0) {
594 d->metadataObject->attributeData.append(attribute.render(name, 1));
595 inMetadataObject = true;
596 }
597 else {
598 d->metadataLibraryObject->attributeData.append(attribute.render(name, 2));
599 }
600 }
601 }
602
603 ByteVector data;
604 for(List<FilePrivate::BaseObject *>::ConstIterator it = d->objects.begin(); it != d->objects.end(); ++it) {
605 data.append((*it)->render(this));
606 }
607
608 seek(16);
609 writeBlock(ByteVector::fromLongLong(data.size() + 30, false));
610 writeBlock(ByteVector::fromUInt(d->objects.size(), false));
611 writeBlock(ByteVector("\x01\x02", 2));
612
613 insert(data, 30, static_cast<unsigned long>(d->headerSize - 30));
614
615 d->headerSize = data.size() + 30;
616
617 return true;
618 }
619
620 ////////////////////////////////////////////////////////////////////////////////
621 // private members
622 ////////////////////////////////////////////////////////////////////////////////
623
read()624 void ASF::File::read()
625 {
626 if(!isValid())
627 return;
628
629 if(readBlock(16) != headerGuid) {
630 debug("ASF::File::read(): Not an ASF file.");
631 setValid(false);
632 return;
633 }
634
635 d->tag = new ASF::Tag();
636 d->properties = new ASF::Properties();
637
638 bool ok;
639 d->headerSize = readQWORD(this, &ok);
640 if(!ok) {
641 setValid(false);
642 return;
643 }
644 int numObjects = readDWORD(this, &ok);
645 if(!ok) {
646 setValid(false);
647 return;
648 }
649 seek(2, Current);
650
651 FilePrivate::FilePropertiesObject *filePropertiesObject = 0;
652 FilePrivate::StreamPropertiesObject *streamPropertiesObject = 0;
653 for(int i = 0; i < numObjects; i++) {
654 const ByteVector guid = readBlock(16);
655 if(guid.size() != 16) {
656 setValid(false);
657 break;
658 }
659 long size = (long)readQWORD(this, &ok);
660 if(!ok) {
661 setValid(false);
662 break;
663 }
664 FilePrivate::BaseObject *obj;
665 if(guid == filePropertiesGuid) {
666 filePropertiesObject = new FilePrivate::FilePropertiesObject();
667 obj = filePropertiesObject;
668 }
669 else if(guid == streamPropertiesGuid) {
670 streamPropertiesObject = new FilePrivate::StreamPropertiesObject();
671 obj = streamPropertiesObject;
672 }
673 else if(guid == contentDescriptionGuid) {
674 d->contentDescriptionObject = new FilePrivate::ContentDescriptionObject();
675 obj = d->contentDescriptionObject;
676 }
677 else if(guid == extendedContentDescriptionGuid) {
678 d->extendedContentDescriptionObject = new FilePrivate::ExtendedContentDescriptionObject();
679 obj = d->extendedContentDescriptionObject;
680 }
681 else if(guid == headerExtensionGuid) {
682 d->headerExtensionObject = new FilePrivate::HeaderExtensionObject();
683 obj = d->headerExtensionObject;
684 }
685 else if(guid == codecListGuid) {
686 obj = new FilePrivate::CodecListObject();
687 }
688 else {
689 if(guid == contentEncryptionGuid ||
690 guid == extendedContentEncryptionGuid ||
691 guid == advancedContentEncryptionGuid) {
692 d->properties->setEncrypted(true);
693 }
694 obj = new FilePrivate::UnknownObject(guid);
695 }
696 obj->parse(this, size);
697 d->objects.append(obj);
698 }
699
700 if(!filePropertiesObject || !streamPropertiesObject) {
701 debug("ASF::File::read(): Missing mandatory header objects.");
702 setValid(false);
703 return;
704 }
705 }
706