1 /**************************************************************************
2 copyright : (C) 2005-2007 by Lukáš Lalinský
3 email : lalinsky@gmail.com
4 **************************************************************************/
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. *
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. *
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
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 ***************************************************************************/
33 #include <tbytevectorlist.h>
37 #include "asfproperties.h"
39 using namespace TagLib;
41 class ASF::File::FilePrivate
48 contentDescriptionObject(0),
49 extendedContentDescriptionObject(0),
50 headerExtensionObject(0),
52 metadataLibraryObject(0) {}
53 unsigned long long size;
55 ASF::Properties *properties;
56 List<ASF::File::BaseObject *> objects;
57 ASF::File::ContentDescriptionObject *contentDescriptionObject;
58 ASF::File::ExtendedContentDescriptionObject *extendedContentDescriptionObject;
59 ASF::File::HeaderExtensionObject *headerExtensionObject;
60 ASF::File::MetadataObject *metadataObject;
61 ASF::File::MetadataLibraryObject *metadataLibraryObject;
64 static ByteVector headerGuid("\x30\x26\xB2\x75\x8E\x66\xCF\x11\xA6\xD9\x00\xAA\x00\x62\xCE\x6C", 16);
65 static ByteVector filePropertiesGuid("\xA1\xDC\xAB\x8C\x47\xA9\xCF\x11\x8E\xE4\x00\xC0\x0C\x20\x53\x65", 16);
66 static ByteVector streamPropertiesGuid("\x91\x07\xDC\xB7\xB7\xA9\xCF\x11\x8E\xE6\x00\xC0\x0C\x20\x53\x65", 16);
67 static ByteVector contentDescriptionGuid("\x33\x26\xB2\x75\x8E\x66\xCF\x11\xA6\xD9\x00\xAA\x00\x62\xCE\x6C", 16);
68 static ByteVector extendedContentDescriptionGuid("\x40\xA4\xD0\xD2\x07\xE3\xD2\x11\x97\xF0\x00\xA0\xC9\x5E\xA8\x50", 16);
69 static ByteVector headerExtensionGuid("\xb5\x03\xbf_.\xa9\xcf\x11\x8e\xe3\x00\xc0\x0c Se", 16);
70 static ByteVector metadataGuid("\xEA\xCB\xF8\xC5\xAF[wH\204g\xAA\214D\xFAL\xCA", 16);
71 static ByteVector metadataLibraryGuid("\224\034#D\230\224\321I\241A\x1d\x13NEpT", 16);
73 class ASF::File::BaseObject
77 virtual ~BaseObject() {}
78 virtual ByteVector guid() = 0;
79 virtual void parse(ASF::File *file, unsigned int size);
80 virtual ByteVector render(ASF::File *file);
83 class ASF::File::UnknownObject : public ASF::File::BaseObject
87 UnknownObject(const ByteVector &guid);
91 class ASF::File::FilePropertiesObject : public ASF::File::BaseObject
95 void parse(ASF::File *file, uint size);
98 class ASF::File::StreamPropertiesObject : public ASF::File::BaseObject
102 void parse(ASF::File *file, uint size);
105 class ASF::File::ContentDescriptionObject : public ASF::File::BaseObject
109 void parse(ASF::File *file, uint size);
110 ByteVector render(ASF::File *file);
113 class ASF::File::ExtendedContentDescriptionObject : public ASF::File::BaseObject
116 ByteVectorList attributeData;
118 void parse(ASF::File *file, uint size);
119 ByteVector render(ASF::File *file);
122 class ASF::File::MetadataObject : public ASF::File::BaseObject
125 ByteVectorList attributeData;
127 void parse(ASF::File *file, uint size);
128 ByteVector render(ASF::File *file);
131 class ASF::File::MetadataLibraryObject : public ASF::File::BaseObject
134 ByteVectorList attributeData;
136 void parse(ASF::File *file, uint size);
137 ByteVector render(ASF::File *file);
140 class ASF::File::HeaderExtensionObject : public ASF::File::BaseObject
143 List<ASF::File::BaseObject *> objects;
145 void parse(ASF::File *file, uint size);
146 ByteVector render(ASF::File *file);
150 ASF::File::BaseObject::parse(ASF::File *file, unsigned int size)
152 data = file->readBlock(size - 24);
156 ASF::File::BaseObject::render(ASF::File * /*file*/)
158 return guid() + ByteVector::fromLongLong(data.size() + 24, false) + data;
161 ASF::File::UnknownObject::UnknownObject(const ByteVector &guid) : myGuid(guid)
166 ASF::File::UnknownObject::guid()
172 ASF::File::FilePropertiesObject::guid()
174 return filePropertiesGuid;
178 ASF::File::FilePropertiesObject::parse(ASF::File *file, uint size)
180 BaseObject::parse(file, size);
181 file->d->properties->setLength((int)(data.mid(40, 8).toLongLong(false) / 10000000L - data.mid(56, 8).toLongLong(false) / 1000L));
185 ASF::File::StreamPropertiesObject::guid()
187 return streamPropertiesGuid;
191 ASF::File::StreamPropertiesObject::parse(ASF::File *file, uint size)
193 BaseObject::parse(file, size);
194 file->d->properties->setChannels(data.mid(56, 2).toShort(false));
195 file->d->properties->setSampleRate(data.mid(58, 4).toUInt(false));
196 file->d->properties->setBitrate(data.mid(62, 4).toUInt(false) * 8 / 1000);
200 ASF::File::ContentDescriptionObject::guid()
202 return contentDescriptionGuid;
206 ASF::File::ContentDescriptionObject::parse(ASF::File *file, uint /*size*/)
208 file->d->contentDescriptionObject = this;
209 int titleLength = file->readWORD();
210 int artistLength = file->readWORD();
211 int copyrightLength = file->readWORD();
212 int commentLength = file->readWORD();
213 int ratingLength = file->readWORD();
214 file->d->tag->setTitle(file->readString(titleLength));
215 file->d->tag->setArtist(file->readString(artistLength));
216 file->d->tag->setCopyright(file->readString(copyrightLength));
217 file->d->tag->setComment(file->readString(commentLength));
218 file->d->tag->setRating(file->readString(ratingLength));
222 ASF::File::ContentDescriptionObject::render(ASF::File *file)
224 ByteVector v1 = file->renderString(file->d->tag->title());
225 ByteVector v2 = file->renderString(file->d->tag->artist());
226 ByteVector v3 = file->renderString(file->d->tag->copyright());
227 ByteVector v4 = file->renderString(file->d->tag->comment());
228 ByteVector v5 = file->renderString(file->d->tag->rating());
230 data.append(ByteVector::fromShort(v1.size(), false));
231 data.append(ByteVector::fromShort(v2.size(), false));
232 data.append(ByteVector::fromShort(v3.size(), false));
233 data.append(ByteVector::fromShort(v4.size(), false));
234 data.append(ByteVector::fromShort(v5.size(), false));
240 return BaseObject::render(file);
244 ASF::File::ExtendedContentDescriptionObject::guid()
246 return extendedContentDescriptionGuid;
250 ASF::File::ExtendedContentDescriptionObject::parse(ASF::File *file, uint /*size*/)
252 file->d->extendedContentDescriptionObject = this;
253 int count = file->readWORD();
255 ASF::Attribute attribute;
256 String name = attribute.parse(*file);
257 file->d->tag->addAttribute(name, attribute);
262 ASF::File::ExtendedContentDescriptionObject::render(ASF::File *file)
265 data.append(ByteVector::fromShort(attributeData.size(), false));
266 data.append(attributeData.toByteVector(ByteVector::null));
267 return BaseObject::render(file);
271 ASF::File::MetadataObject::guid()
277 ASF::File::MetadataObject::parse(ASF::File *file, uint /*size*/)
279 file->d->metadataObject = this;
280 int count = file->readWORD();
282 ASF::Attribute attribute;
283 String name = attribute.parse(*file, 1);
284 file->d->tag->addAttribute(name, attribute);
289 ASF::File::MetadataObject::render(ASF::File *file)
292 data.append(ByteVector::fromShort(attributeData.size(), false));
293 data.append(attributeData.toByteVector(ByteVector::null));
294 return BaseObject::render(file);
298 ASF::File::MetadataLibraryObject::guid()
300 return metadataLibraryGuid;
304 ASF::File::MetadataLibraryObject::parse(ASF::File *file, uint /*size*/)
306 file->d->metadataLibraryObject = this;
307 int count = file->readWORD();
309 ASF::Attribute attribute;
310 String name = attribute.parse(*file, 2);
311 file->d->tag->addAttribute(name, attribute);
316 ASF::File::MetadataLibraryObject::render(ASF::File *file)
319 data.append(ByteVector::fromShort(attributeData.size(), false));
320 data.append(attributeData.toByteVector(ByteVector::null));
321 return BaseObject::render(file);
325 ASF::File::HeaderExtensionObject::guid()
327 return headerExtensionGuid;
331 ASF::File::HeaderExtensionObject::parse(ASF::File *file, uint /*size*/)
333 file->d->headerExtensionObject = this;
334 file->seek(18, File::Current);
335 long long dataSize = file->readDWORD();
336 long long dataPos = 0;
337 while(dataPos < dataSize) {
338 ByteVector guid = file->readBlock(16);
339 long long size = file->readQWORD();
341 if(guid == metadataGuid) {
342 obj = new MetadataObject();
344 else if(guid == metadataLibraryGuid) {
345 obj = new MetadataLibraryObject();
348 obj = new UnknownObject(guid);
350 obj->parse(file, size);
357 ASF::File::HeaderExtensionObject::render(ASF::File *file)
360 for(unsigned int i = 0; i < objects.size(); i++) {
361 data.append(objects[i]->render(file));
363 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;
364 return BaseObject::render(file);
367 ////////////////////////////////////////////////////////////////////////////////
369 ////////////////////////////////////////////////////////////////////////////////
371 ASF::File::File(FileName file, bool readProperties, Properties::ReadStyle propertiesStyle)
375 read(readProperties, propertiesStyle);
380 for(unsigned int i = 0; i < d->objects.size(); i++) {
381 delete d->objects[i];
387 delete d->properties;
392 ASF::Tag *ASF::File::tag() const
397 ASF::Properties *ASF::File::audioProperties() const
399 return d->properties;
402 void ASF::File::read(bool /*readProperties*/, Properties::ReadStyle /*propertiesStyle*/)
407 ByteVector guid = readBlock(16);
408 if(guid != headerGuid) {
409 debug("ASF: Not an ASF file.");
413 d->tag = new ASF::Tag();
414 d->properties = new ASF::Properties();
416 d->size = readQWORD();
417 int numObjects = readDWORD();
420 for(int i = 0; i < numObjects; i++) {
421 ByteVector guid = readBlock(16);
422 long size = (long)readQWORD();
424 if(guid == filePropertiesGuid) {
425 obj = new FilePropertiesObject();
427 else if(guid == streamPropertiesGuid) {
428 obj = new StreamPropertiesObject();
430 else if(guid == contentDescriptionGuid) {
431 obj = new ContentDescriptionObject();
433 else if(guid == extendedContentDescriptionGuid) {
434 obj = new ExtendedContentDescriptionObject();
436 else if(guid == headerExtensionGuid) {
437 obj = new HeaderExtensionObject();
440 obj = new UnknownObject(guid);
442 obj->parse(this, size);
443 d->objects.append(obj);
447 bool ASF::File::save()
450 debug("ASF: File is read-only.");
454 if(!d->contentDescriptionObject) {
455 d->contentDescriptionObject = new ContentDescriptionObject();
456 d->objects.append(d->contentDescriptionObject);
458 if(!d->extendedContentDescriptionObject) {
459 d->extendedContentDescriptionObject = new ExtendedContentDescriptionObject();
460 d->objects.append(d->extendedContentDescriptionObject);
462 if(!d->headerExtensionObject) {
463 d->headerExtensionObject = new HeaderExtensionObject();
464 d->objects.append(d->headerExtensionObject);
466 if(!d->metadataObject) {
467 d->metadataObject = new MetadataObject();
468 d->headerExtensionObject->objects.append(d->metadataObject);
470 if(!d->metadataLibraryObject) {
471 d->metadataLibraryObject = new MetadataLibraryObject();
472 d->headerExtensionObject->objects.append(d->metadataLibraryObject);
475 ASF::AttributeListMap::ConstIterator it = d->tag->attributeListMap().begin();
476 for(; it != d->tag->attributeListMap().end(); it++) {
477 const String &name = it->first;
478 const AttributeList &attributes = it->second;
479 bool inExtendedContentDescriptionObject = false;
480 bool inMetadataObject = false;
481 for(unsigned int j = 0; j < attributes.size(); j++) {
482 const Attribute &attribute = attributes[j];
483 bool largeValue = attribute.dataSize() > 65535;
484 if(!inExtendedContentDescriptionObject && !largeValue && attribute.language() == 0 && attribute.stream() == 0) {
485 d->extendedContentDescriptionObject->attributeData.append(attribute.render(name));
486 inExtendedContentDescriptionObject = true;
488 else if(!inMetadataObject && !largeValue && attribute.language() == 0 && attribute.stream() != 0) {
489 d->metadataObject->attributeData.append(attribute.render(name, 1));
490 inMetadataObject = true;
493 d->metadataLibraryObject->attributeData.append(attribute.render(name, 2));
499 for(unsigned int i = 0; i < d->objects.size(); i++) {
500 data.append(d->objects[i]->render(this));
502 data = headerGuid + ByteVector::fromLongLong(data.size() + 30, false) + ByteVector::fromUInt(d->objects.size(), false) + ByteVector("\x01\x02", 2) + data;
503 insert(data, 0, d->size);
508 ////////////////////////////////////////////////////////////////////////////////
510 ////////////////////////////////////////////////////////////////////////////////
512 int ASF::File::readBYTE()
514 ByteVector v = readBlock(1);
518 int ASF::File::readWORD()
520 ByteVector v = readBlock(2);
521 return v.toShort(false);
524 unsigned int ASF::File::readDWORD()
526 ByteVector v = readBlock(4);
527 return v.toUInt(false);
530 long long ASF::File::readQWORD()
532 ByteVector v = readBlock(8);
533 return v.toLongLong(false);
537 ASF::File::readString(int length)
539 ByteVector data = readBlock(length);
540 unsigned int size = data.size();
542 if(data[size - 1] != '\0' || data[size - 2] != '\0') {
547 if(size != data.size()) {
550 return String(data, String::UTF16LE);
554 ASF::File::renderString(const String &str, bool includeLength)
556 ByteVector data = str.data(String::UTF16LE) + ByteVector::fromShort(0, false);
558 data = ByteVector::fromShort(data.size(), false) + data;