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
***************************************************************************/
26
#include <tbytevectorlist.h>
30
#include "asfproperties.h"
32
using namespace TagLib;
34
class ASF::File::FilePrivate
41
contentDescriptionObject(0),
42
extendedContentDescriptionObject(0),
43
headerExtensionObject(0),
45
metadataLibraryObject(0) {}
46
unsigned long long size;
48
ASF::Properties *properties;
49
List<ASF::File::BaseObject *> objects;
50
ASF::File::ContentDescriptionObject *contentDescriptionObject;
51
ASF::File::ExtendedContentDescriptionObject *extendedContentDescriptionObject;
52
ASF::File::HeaderExtensionObject *headerExtensionObject;
53
ASF::File::MetadataObject *metadataObject;
54
ASF::File::MetadataLibraryObject *metadataLibraryObject;
57
static ByteVector headerGuid("\x30\x26\xB2\x75\x8E\x66\xCF\x11\xA6\xD9\x00\xAA\x00\x62\xCE\x6C", 16);
58
static ByteVector filePropertiesGuid("\xA1\xDC\xAB\x8C\x47\xA9\xCF\x11\x8E\xE4\x00\xC0\x0C\x20\x53\x65", 16);
59
static ByteVector streamPropertiesGuid("\x91\x07\xDC\xB7\xB7\xA9\xCF\x11\x8E\xE6\x00\xC0\x0C\x20\x53\x65", 16);
60
static ByteVector contentDescriptionGuid("\x33\x26\xB2\x75\x8E\x66\xCF\x11\xA6\xD9\x00\xAA\x00\x62\xCE\x6C", 16);
61
static ByteVector extendedContentDescriptionGuid("\x40\xA4\xD0\xD2\x07\xE3\xD2\x11\x97\xF0\x00\xA0\xC9\x5E\xA8\x50", 16);
62
static ByteVector headerExtensionGuid("\xb5\x03\xbf_.\xa9\xcf\x11\x8e\xe3\x00\xc0\x0c Se", 16);
63
static ByteVector metadataGuid("\xEA\xCB\xF8\xC5\xAF[wH\204g\xAA\214D\xFAL\xCA", 16);
64
static ByteVector metadataLibraryGuid("\224\034#D\230\224\321I\241A\x1d\x13NEpT", 16);
66
class ASF::File::BaseObject
70
virtual ~BaseObject() {}
71
virtual ByteVector guid() = 0;
72
virtual void parse(ASF::File *file, unsigned int size);
73
virtual ByteVector render(ASF::File *file);
76
class ASF::File::UnknownObject : public ASF::File::BaseObject
80
UnknownObject(const ByteVector &guid);
84
class ASF::File::FilePropertiesObject : public ASF::File::BaseObject
88
void parse(ASF::File *file, uint size);
91
class ASF::File::StreamPropertiesObject : public ASF::File::BaseObject
95
void parse(ASF::File *file, uint size);
98
class ASF::File::ContentDescriptionObject : public ASF::File::BaseObject
102
void parse(ASF::File *file, uint size);
103
ByteVector render(ASF::File *file);
106
class ASF::File::ExtendedContentDescriptionObject : public ASF::File::BaseObject
109
ByteVectorList attributeData;
111
void parse(ASF::File *file, uint size);
112
ByteVector render(ASF::File *file);
115
class ASF::File::MetadataObject : public ASF::File::BaseObject
118
ByteVectorList attributeData;
120
void parse(ASF::File *file, uint size);
121
ByteVector render(ASF::File *file);
124
class ASF::File::MetadataLibraryObject : public ASF::File::BaseObject
127
ByteVectorList attributeData;
129
void parse(ASF::File *file, uint size);
130
ByteVector render(ASF::File *file);
133
class ASF::File::HeaderExtensionObject : public ASF::File::BaseObject
136
List<ASF::File::BaseObject *> objects;
138
void parse(ASF::File *file, uint size);
139
ByteVector render(ASF::File *file);
143
ASF::File::BaseObject::parse(ASF::File *file, unsigned int size)
145
data = file->readBlock(size - 24);
149
ASF::File::BaseObject::render(ASF::File * /*file*/)
151
return guid() + ByteVector::fromLongLong(data.size() + 24, false) + data;
154
ASF::File::UnknownObject::UnknownObject(const ByteVector &guid) : myGuid(guid)
159
ASF::File::UnknownObject::guid()
165
ASF::File::FilePropertiesObject::guid()
167
return filePropertiesGuid;
171
ASF::File::FilePropertiesObject::parse(ASF::File *file, uint size)
173
BaseObject::parse(file, size);
174
file->d->properties->setLength((int)(data.mid(40, 8).toLongLong(false) / 10000000L - data.mid(56, 8).toLongLong(false) / 1000L));
178
ASF::File::StreamPropertiesObject::guid()
180
return streamPropertiesGuid;
184
ASF::File::StreamPropertiesObject::parse(ASF::File *file, uint size)
186
BaseObject::parse(file, size);
187
file->d->properties->setChannels(data.mid(56, 2).toShort(false));
188
file->d->properties->setSampleRate(data.mid(58, 4).toUInt(false));
189
file->d->properties->setBitrate(data.mid(62, 4).toUInt(false) * 8 / 1000);
193
ASF::File::ContentDescriptionObject::guid()
195
return contentDescriptionGuid;
199
ASF::File::ContentDescriptionObject::parse(ASF::File *file, uint /*size*/)
201
file->d->contentDescriptionObject = this;
202
int titleLength = file->readWORD();
203
int artistLength = file->readWORD();
204
int copyrightLength = file->readWORD();
205
int commentLength = file->readWORD();
206
int ratingLength = file->readWORD();
207
file->d->tag->setTitle(file->readString(titleLength));
208
file->d->tag->setArtist(file->readString(artistLength));
209
file->d->tag->setCopyright(file->readString(copyrightLength));
210
file->d->tag->setComment(file->readString(commentLength));
211
file->d->tag->setRating(file->readString(ratingLength));
215
ASF::File::ContentDescriptionObject::render(ASF::File *file)
217
ByteVector v1 = file->renderString(file->d->tag->title());
218
ByteVector v2 = file->renderString(file->d->tag->artist());
219
ByteVector v3 = file->renderString(file->d->tag->copyright());
220
ByteVector v4 = file->renderString(file->d->tag->comment());
221
ByteVector v5 = file->renderString(file->d->tag->rating());
223
data.append(ByteVector::fromShort(v1.size(), false));
224
data.append(ByteVector::fromShort(v2.size(), false));
225
data.append(ByteVector::fromShort(v3.size(), false));
226
data.append(ByteVector::fromShort(v4.size(), false));
227
data.append(ByteVector::fromShort(v5.size(), false));
233
return BaseObject::render(file);
237
ASF::File::ExtendedContentDescriptionObject::guid()
239
return extendedContentDescriptionGuid;
243
ASF::File::ExtendedContentDescriptionObject::parse(ASF::File *file, uint /*size*/)
245
file->d->extendedContentDescriptionObject = this;
246
int count = file->readWORD();
248
ASF::Attribute attribute;
249
String name = attribute.parse(*file);
250
file->d->tag->addAttribute(name, attribute);
255
ASF::File::ExtendedContentDescriptionObject::render(ASF::File *file)
258
data.append(ByteVector::fromShort(attributeData.size(), false));
259
data.append(attributeData.toByteVector(ByteVector::null));
260
return BaseObject::render(file);
264
ASF::File::MetadataObject::guid()
270
ASF::File::MetadataObject::parse(ASF::File *file, uint /*size*/)
272
file->d->metadataObject = this;
273
int count = file->readWORD();
275
ASF::Attribute attribute;
276
String name = attribute.parse(*file, 1);
277
file->d->tag->addAttribute(name, attribute);
282
ASF::File::MetadataObject::render(ASF::File *file)
285
data.append(ByteVector::fromShort(attributeData.size(), false));
286
data.append(attributeData.toByteVector(ByteVector::null));
287
return BaseObject::render(file);
291
ASF::File::MetadataLibraryObject::guid()
293
return metadataLibraryGuid;
297
ASF::File::MetadataLibraryObject::parse(ASF::File *file, uint /*size*/)
299
file->d->metadataLibraryObject = this;
300
int count = file->readWORD();
302
ASF::Attribute attribute;
303
String name = attribute.parse(*file, 2);
304
file->d->tag->addAttribute(name, attribute);
309
ASF::File::MetadataLibraryObject::render(ASF::File *file)
312
data.append(ByteVector::fromShort(attributeData.size(), false));
313
data.append(attributeData.toByteVector(ByteVector::null));
314
return BaseObject::render(file);
318
ASF::File::HeaderExtensionObject::guid()
320
return headerExtensionGuid;
324
ASF::File::HeaderExtensionObject::parse(ASF::File *file, uint /*size*/)
326
file->d->headerExtensionObject = this;
327
file->seek(18, File::Current);
328
long long dataSize = file->readDWORD();
329
long long dataPos = 0;
330
while(dataPos < dataSize) {
331
ByteVector guid = file->readBlock(16);
332
long long size = file->readQWORD();
334
if(guid == metadataGuid) {
335
obj = new MetadataObject();
337
else if(guid == metadataLibraryGuid) {
338
obj = new MetadataLibraryObject();
341
obj = new UnknownObject(guid);
343
obj->parse(file, size);
350
ASF::File::HeaderExtensionObject::render(ASF::File *file)
353
for(unsigned int i = 0; i < objects.size(); i++) {
354
data.append(objects[i]->render(file));
356
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;
357
return BaseObject::render(file);
360
////////////////////////////////////////////////////////////////////////////////
362
////////////////////////////////////////////////////////////////////////////////
364
ASF::File::File(FileName file, bool readProperties, Properties::ReadStyle propertiesStyle)
368
read(readProperties, propertiesStyle);
373
for(unsigned int i = 0; i < d->objects.size(); i++) {
374
delete d->objects[i];
380
delete d->properties;
385
ASF::Tag *ASF::File::tag() const
390
ASF::Properties *ASF::File::audioProperties() const
392
return d->properties;
395
void ASF::File::read(bool /*readProperties*/, Properties::ReadStyle /*propertiesStyle*/)
400
ByteVector guid = readBlock(16);
401
if(guid != headerGuid) {
405
d->tag = new ASF::Tag();
406
d->properties = new ASF::Properties();
408
d->size = readQWORD();
409
int numObjects = readDWORD();
412
for(int i = 0; i < numObjects; i++) {
413
ByteVector guid = readBlock(16);
414
long size = (long)readQWORD();
416
if(guid == filePropertiesGuid) {
417
obj = new FilePropertiesObject();
419
else if(guid == streamPropertiesGuid) {
420
obj = new StreamPropertiesObject();
422
else if(guid == contentDescriptionGuid) {
423
obj = new ContentDescriptionObject();
425
else if(guid == extendedContentDescriptionGuid) {
426
obj = new ExtendedContentDescriptionObject();
428
else if(guid == headerExtensionGuid) {
429
obj = new HeaderExtensionObject();
432
obj = new UnknownObject(guid);
434
obj->parse(this, size);
435
d->objects.append(obj);
439
bool ASF::File::save()
445
if(!d->contentDescriptionObject) {
446
d->contentDescriptionObject = new ContentDescriptionObject();
447
d->objects.append(d->contentDescriptionObject);
449
if(!d->extendedContentDescriptionObject) {
450
d->extendedContentDescriptionObject = new ExtendedContentDescriptionObject();
451
d->objects.append(d->extendedContentDescriptionObject);
453
if(!d->headerExtensionObject) {
454
d->headerExtensionObject = new HeaderExtensionObject();
455
d->objects.append(d->headerExtensionObject);
457
if(!d->metadataObject) {
458
d->metadataObject = new MetadataObject();
459
d->headerExtensionObject->objects.append(d->metadataObject);
461
if(!d->metadataLibraryObject) {
462
d->metadataLibraryObject = new MetadataLibraryObject();
463
d->headerExtensionObject->objects.append(d->metadataLibraryObject);
466
ASF::AttributeListMap::ConstIterator it = d->tag->attributeListMap().begin();
467
for(; it != d->tag->attributeListMap().end(); it++) {
468
const String &name = it->first;
469
const AttributeList &attributes = it->second;
470
bool inExtendedContentDescriptionObject = false;
471
bool inMetadataObject = false;
472
for(unsigned int j = 0; j < attributes.size(); j++) {
473
const Attribute &attribute = attributes[j];
474
if(!inExtendedContentDescriptionObject && attribute.language() == 0 && attribute.stream() == 0) {
475
d->extendedContentDescriptionObject->attributeData.append(attribute.render(name));
476
inExtendedContentDescriptionObject = true;
478
else if(!inMetadataObject && attribute.language() == 0 && attribute.stream() != 0) {
479
d->metadataObject->attributeData.append(attribute.render(name, 1));
480
inMetadataObject = true;
483
d->metadataLibraryObject->attributeData.append(attribute.render(name, 2));
489
for(unsigned int i = 0; i < d->objects.size(); i++) {
490
data.append(d->objects[i]->render(this));
492
data = headerGuid + ByteVector::fromLongLong(data.size() + 30, false) + ByteVector::fromUInt(d->objects.size(), false) + ByteVector("\x01\x02", 2) + data;
493
insert(data, 0, d->size);
498
////////////////////////////////////////////////////////////////////////////////
500
////////////////////////////////////////////////////////////////////////////////
502
int ASF::File::readBYTE()
504
ByteVector v = readBlock(1);
508
int ASF::File::readWORD()
510
ByteVector v = readBlock(2);
511
return v.toShort(false);
514
unsigned int ASF::File::readDWORD()
516
ByteVector v = readBlock(4);
517
return v.toUInt(false);
520
long long ASF::File::readQWORD()
522
ByteVector v = readBlock(8);
523
return v.toLongLong(false);
527
ASF::File::readString(int length)
529
ByteVector data = readBlock(length);
530
unsigned int size = data.size();
532
if(data[size - 1] != '\0' || data[size - 2] != '\0') {
537
if(size != data.size()) {
540
return String(data, String::UTF16LE);
544
ASF::File::renderString(const String &str, bool includeLength)
546
ByteVector data = str.data(String::UTF16LE) + ByteVector::fromShort(0, false);
548
data = ByteVector::fromShort(data.size(), false) + data;