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 ***************************************************************************/
32 #include <tbytevectorlist.h>
36 #include "asfproperties.h"
38 using namespace TagLib;
40 class ASF::File::FilePrivate
47 contentDescriptionObject(0),
48 extendedContentDescriptionObject(0),
49 headerExtensionObject(0),
51 metadataLibraryObject(0) {}
52 unsigned long long size;
54 ASF::Properties *properties;
55 List<ASF::File::BaseObject *> objects;
56 ASF::File::ContentDescriptionObject *contentDescriptionObject;
57 ASF::File::ExtendedContentDescriptionObject *extendedContentDescriptionObject;
58 ASF::File::HeaderExtensionObject *headerExtensionObject;
59 ASF::File::MetadataObject *metadataObject;
60 ASF::File::MetadataLibraryObject *metadataLibraryObject;
63 static ByteVector headerGuid("\x30\x26\xB2\x75\x8E\x66\xCF\x11\xA6\xD9\x00\xAA\x00\x62\xCE\x6C", 16);
64 static ByteVector filePropertiesGuid("\xA1\xDC\xAB\x8C\x47\xA9\xCF\x11\x8E\xE4\x00\xC0\x0C\x20\x53\x65", 16);
65 static ByteVector streamPropertiesGuid("\x91\x07\xDC\xB7\xB7\xA9\xCF\x11\x8E\xE6\x00\xC0\x0C\x20\x53\x65", 16);
66 static ByteVector contentDescriptionGuid("\x33\x26\xB2\x75\x8E\x66\xCF\x11\xA6\xD9\x00\xAA\x00\x62\xCE\x6C", 16);
67 static ByteVector extendedContentDescriptionGuid("\x40\xA4\xD0\xD2\x07\xE3\xD2\x11\x97\xF0\x00\xA0\xC9\x5E\xA8\x50", 16);
68 static ByteVector headerExtensionGuid("\xb5\x03\xbf_.\xa9\xcf\x11\x8e\xe3\x00\xc0\x0c Se", 16);
69 static ByteVector metadataGuid("\xEA\xCB\xF8\xC5\xAF[wH\204g\xAA\214D\xFAL\xCA", 16);
70 static ByteVector metadataLibraryGuid("\224\034#D\230\224\321I\241A\x1d\x13NEpT", 16);
72 class ASF::File::BaseObject
76 virtual ~BaseObject() {}
77 virtual ByteVector guid() = 0;
78 virtual void parse(ASF::File *file, unsigned int size);
79 virtual ByteVector render(ASF::File *file);
82 class ASF::File::UnknownObject : public ASF::File::BaseObject
86 UnknownObject(const ByteVector &guid);
90 class ASF::File::FilePropertiesObject : public ASF::File::BaseObject
94 void parse(ASF::File *file, uint size);
97 class ASF::File::StreamPropertiesObject : public ASF::File::BaseObject
101 void parse(ASF::File *file, uint size);
104 class ASF::File::ContentDescriptionObject : public ASF::File::BaseObject
108 void parse(ASF::File *file, uint size);
109 ByteVector render(ASF::File *file);
112 class ASF::File::ExtendedContentDescriptionObject : public ASF::File::BaseObject
115 ByteVectorList attributeData;
117 void parse(ASF::File *file, uint size);
118 ByteVector render(ASF::File *file);
121 class ASF::File::MetadataObject : public ASF::File::BaseObject
124 ByteVectorList attributeData;
126 void parse(ASF::File *file, uint size);
127 ByteVector render(ASF::File *file);
130 class ASF::File::MetadataLibraryObject : public ASF::File::BaseObject
133 ByteVectorList attributeData;
135 void parse(ASF::File *file, uint size);
136 ByteVector render(ASF::File *file);
139 class ASF::File::HeaderExtensionObject : public ASF::File::BaseObject
142 List<ASF::File::BaseObject *> objects;
144 void parse(ASF::File *file, uint size);
145 ByteVector render(ASF::File *file);
149 ASF::File::BaseObject::parse(ASF::File *file, unsigned int size)
151 data = file->readBlock(size - 24);
155 ASF::File::BaseObject::render(ASF::File * /*file*/)
157 return guid() + ByteVector::fromLongLong(data.size() + 24, false) + data;
160 ASF::File::UnknownObject::UnknownObject(const ByteVector &guid) : myGuid(guid)
165 ASF::File::UnknownObject::guid()
171 ASF::File::FilePropertiesObject::guid()
173 return filePropertiesGuid;
177 ASF::File::FilePropertiesObject::parse(ASF::File *file, uint size)
179 BaseObject::parse(file, size);
180 file->d->properties->setLength((int)(data.mid(40, 8).toLongLong(false) / 10000000L - data.mid(56, 8).toLongLong(false) / 1000L));
184 ASF::File::StreamPropertiesObject::guid()
186 return streamPropertiesGuid;
190 ASF::File::StreamPropertiesObject::parse(ASF::File *file, uint size)
192 BaseObject::parse(file, size);
193 file->d->properties->setChannels(data.mid(56, 2).toShort(false));
194 file->d->properties->setSampleRate(data.mid(58, 4).toUInt(false));
195 file->d->properties->setBitrate(data.mid(62, 4).toUInt(false) * 8 / 1000);
199 ASF::File::ContentDescriptionObject::guid()
201 return contentDescriptionGuid;
205 ASF::File::ContentDescriptionObject::parse(ASF::File *file, uint /*size*/)
207 file->d->contentDescriptionObject = this;
208 int titleLength = file->readWORD();
209 int artistLength = file->readWORD();
210 int copyrightLength = file->readWORD();
211 int commentLength = file->readWORD();
212 int ratingLength = file->readWORD();
213 file->d->tag->setTitle(file->readString(titleLength));
214 file->d->tag->setArtist(file->readString(artistLength));
215 file->d->tag->setCopyright(file->readString(copyrightLength));
216 file->d->tag->setComment(file->readString(commentLength));
217 file->d->tag->setRating(file->readString(ratingLength));
221 ASF::File::ContentDescriptionObject::render(ASF::File *file)
223 ByteVector v1 = file->renderString(file->d->tag->title());
224 ByteVector v2 = file->renderString(file->d->tag->artist());
225 ByteVector v3 = file->renderString(file->d->tag->copyright());
226 ByteVector v4 = file->renderString(file->d->tag->comment());
227 ByteVector v5 = file->renderString(file->d->tag->rating());
229 data.append(ByteVector::fromShort(v1.size(), false));
230 data.append(ByteVector::fromShort(v2.size(), false));
231 data.append(ByteVector::fromShort(v3.size(), false));
232 data.append(ByteVector::fromShort(v4.size(), false));
233 data.append(ByteVector::fromShort(v5.size(), false));
239 return BaseObject::render(file);
243 ASF::File::ExtendedContentDescriptionObject::guid()
245 return extendedContentDescriptionGuid;
249 ASF::File::ExtendedContentDescriptionObject::parse(ASF::File *file, uint /*size*/)
251 file->d->extendedContentDescriptionObject = this;
252 int count = file->readWORD();
254 ASF::Attribute attribute;
255 String name = attribute.parse(*file);
256 file->d->tag->addAttribute(name, attribute);
261 ASF::File::ExtendedContentDescriptionObject::render(ASF::File *file)
264 data.append(ByteVector::fromShort(attributeData.size(), false));
265 data.append(attributeData.toByteVector(ByteVector::null));
266 return BaseObject::render(file);
270 ASF::File::MetadataObject::guid()
276 ASF::File::MetadataObject::parse(ASF::File *file, uint /*size*/)
278 file->d->metadataObject = this;
279 int count = file->readWORD();
281 ASF::Attribute attribute;
282 String name = attribute.parse(*file, 1);
283 file->d->tag->addAttribute(name, attribute);
288 ASF::File::MetadataObject::render(ASF::File *file)
291 data.append(ByteVector::fromShort(attributeData.size(), false));
292 data.append(attributeData.toByteVector(ByteVector::null));
293 return BaseObject::render(file);
297 ASF::File::MetadataLibraryObject::guid()
299 return metadataLibraryGuid;
303 ASF::File::MetadataLibraryObject::parse(ASF::File *file, uint /*size*/)
305 file->d->metadataLibraryObject = this;
306 int count = file->readWORD();
308 ASF::Attribute attribute;
309 String name = attribute.parse(*file, 2);
310 file->d->tag->addAttribute(name, attribute);
315 ASF::File::MetadataLibraryObject::render(ASF::File *file)
318 data.append(ByteVector::fromShort(attributeData.size(), false));
319 data.append(attributeData.toByteVector(ByteVector::null));
320 return BaseObject::render(file);
324 ASF::File::HeaderExtensionObject::guid()
326 return headerExtensionGuid;
330 ASF::File::HeaderExtensionObject::parse(ASF::File *file, uint /*size*/)
332 file->d->headerExtensionObject = this;
333 file->seek(18, File::Current);
334 long long dataSize = file->readDWORD();
335 long long dataPos = 0;
336 while(dataPos < dataSize) {
337 ByteVector guid = file->readBlock(16);
338 long long size = file->readQWORD();
340 if(guid == metadataGuid) {
341 obj = new MetadataObject();
343 else if(guid == metadataLibraryGuid) {
344 obj = new MetadataLibraryObject();
347 obj = new UnknownObject(guid);
349 obj->parse(file, size);
356 ASF::File::HeaderExtensionObject::render(ASF::File *file)
359 for(unsigned int i = 0; i < objects.size(); i++) {
360 data.append(objects[i]->render(file));
362 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;
363 return BaseObject::render(file);
366 ////////////////////////////////////////////////////////////////////////////////
368 ////////////////////////////////////////////////////////////////////////////////
370 ASF::File::File(FileName file, bool readProperties, Properties::ReadStyle propertiesStyle)
374 read(readProperties, propertiesStyle);
379 for(unsigned int i = 0; i < d->objects.size(); i++) {
380 delete d->objects[i];
386 delete d->properties;
391 ASF::Tag *ASF::File::tag() const
396 ASF::Properties *ASF::File::audioProperties() const
398 return d->properties;
401 void ASF::File::read(bool /*readProperties*/, Properties::ReadStyle /*propertiesStyle*/)
406 ByteVector guid = readBlock(16);
407 if(guid != headerGuid) {
408 debug("ASF: Not an ASF file.");
412 d->tag = new ASF::Tag();
413 d->properties = new ASF::Properties();
415 d->size = readQWORD();
416 int numObjects = readDWORD();
419 for(int i = 0; i < numObjects; i++) {
420 ByteVector guid = readBlock(16);
421 long size = (long)readQWORD();
423 if(guid == filePropertiesGuid) {
424 obj = new FilePropertiesObject();
426 else if(guid == streamPropertiesGuid) {
427 obj = new StreamPropertiesObject();
429 else if(guid == contentDescriptionGuid) {
430 obj = new ContentDescriptionObject();
432 else if(guid == extendedContentDescriptionGuid) {
433 obj = new ExtendedContentDescriptionObject();
435 else if(guid == headerExtensionGuid) {
436 obj = new HeaderExtensionObject();
439 obj = new UnknownObject(guid);
441 obj->parse(this, size);
442 d->objects.append(obj);
446 bool ASF::File::save()
449 debug("ASF: File is read-only.");
453 if(!d->contentDescriptionObject) {
454 d->contentDescriptionObject = new ContentDescriptionObject();
455 d->objects.append(d->contentDescriptionObject);
457 if(!d->extendedContentDescriptionObject) {
458 d->extendedContentDescriptionObject = new ExtendedContentDescriptionObject();
459 d->objects.append(d->extendedContentDescriptionObject);
461 if(!d->headerExtensionObject) {
462 d->headerExtensionObject = new HeaderExtensionObject();
463 d->objects.append(d->headerExtensionObject);
465 if(!d->metadataObject) {
466 d->metadataObject = new MetadataObject();
467 d->headerExtensionObject->objects.append(d->metadataObject);
469 if(!d->metadataLibraryObject) {
470 d->metadataLibraryObject = new MetadataLibraryObject();
471 d->headerExtensionObject->objects.append(d->metadataLibraryObject);
474 ASF::AttributeListMap::ConstIterator it = d->tag->attributeListMap().begin();
475 for(; it != d->tag->attributeListMap().end(); it++) {
476 const String &name = it->first;
477 const AttributeList &attributes = it->second;
478 bool inExtendedContentDescriptionObject = false;
479 bool inMetadataObject = false;
480 for(unsigned int j = 0; j < attributes.size(); j++) {
481 const Attribute &attribute = attributes[j];
482 bool largeValue = attribute.dataSize() > 65535;
483 if(!inExtendedContentDescriptionObject && !largeValue && attribute.language() == 0 && attribute.stream() == 0) {
484 d->extendedContentDescriptionObject->attributeData.append(attribute.render(name));
485 inExtendedContentDescriptionObject = true;
487 else if(!inMetadataObject && !largeValue && attribute.language() == 0 && attribute.stream() != 0) {
488 d->metadataObject->attributeData.append(attribute.render(name, 1));
489 inMetadataObject = true;
492 d->metadataLibraryObject->attributeData.append(attribute.render(name, 2));
498 for(unsigned int i = 0; i < d->objects.size(); i++) {
499 data.append(d->objects[i]->render(this));
501 data = headerGuid + ByteVector::fromLongLong(data.size() + 30, false) + ByteVector::fromUInt(d->objects.size(), false) + ByteVector("\x01\x02", 2) + data;
502 insert(data, 0, d->size);
507 ////////////////////////////////////////////////////////////////////////////////
509 ////////////////////////////////////////////////////////////////////////////////
511 int ASF::File::readBYTE()
513 ByteVector v = readBlock(1);
517 int ASF::File::readWORD()
519 ByteVector v = readBlock(2);
520 return v.toShort(false);
523 unsigned int ASF::File::readDWORD()
525 ByteVector v = readBlock(4);
526 return v.toUInt(false);
529 long long ASF::File::readQWORD()
531 ByteVector v = readBlock(8);
532 return v.toLongLong(false);
536 ASF::File::readString(int length)
538 ByteVector data = readBlock(length);
539 unsigned int size = data.size();
541 if(data[size - 1] != '\0' || data[size - 2] != '\0') {
546 if(size != data.size()) {
549 return String(data, String::UTF16LE);
553 ASF::File::renderString(const String &str, bool includeLength)
555 ByteVector data = str.data(String::UTF16LE) + ByteVector::fromShort(0, false);
557 data = ByteVector::fromShort(data.size(), false) + data;