Added TagLib (with AUTORS and COPYING files)
[someplayer] / src / taglib / asf / asffile.cpp
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *
19  *   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 #ifdef HAVE_CONFIG_H
27 #include <config.h>
28 #endif
29
30 #ifdef WITH_ASF
31
32 #include <tdebug.h>
33 #include <tbytevectorlist.h>
34 #include <tstring.h>
35 #include "asffile.h"
36 #include "asftag.h"
37 #include "asfproperties.h"
38
39 using namespace TagLib;
40
41 class ASF::File::FilePrivate
42 {
43 public:
44   FilePrivate():
45     size(0),
46     tag(0),
47     properties(0),
48     contentDescriptionObject(0),
49     extendedContentDescriptionObject(0),
50     headerExtensionObject(0),
51     metadataObject(0),
52     metadataLibraryObject(0) {}
53   unsigned long long size;
54   ASF::Tag *tag;
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;
62 };
63
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);
72
73 class ASF::File::BaseObject
74 {
75 public:
76   ByteVector data;
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);
81 };
82
83 class ASF::File::UnknownObject : public ASF::File::BaseObject
84 {
85   ByteVector myGuid;
86 public:
87   UnknownObject(const ByteVector &guid);
88   ByteVector guid();
89 };
90
91 class ASF::File::FilePropertiesObject : public ASF::File::BaseObject
92 {
93 public:
94   ByteVector guid();
95   void parse(ASF::File *file, uint size);
96 };
97
98 class ASF::File::StreamPropertiesObject : public ASF::File::BaseObject
99 {
100 public:
101   ByteVector guid();
102   void parse(ASF::File *file, uint size);
103 };
104
105 class ASF::File::ContentDescriptionObject : public ASF::File::BaseObject
106 {
107 public:
108   ByteVector guid();
109   void parse(ASF::File *file, uint size);
110   ByteVector render(ASF::File *file);
111 };
112
113 class ASF::File::ExtendedContentDescriptionObject : public ASF::File::BaseObject
114 {
115 public:
116   ByteVectorList attributeData;
117   ByteVector guid();
118   void parse(ASF::File *file, uint size);
119   ByteVector render(ASF::File *file);
120 };
121
122 class ASF::File::MetadataObject : public ASF::File::BaseObject
123 {
124 public:
125   ByteVectorList attributeData;
126   ByteVector guid();
127   void parse(ASF::File *file, uint size);
128   ByteVector render(ASF::File *file);
129 };
130
131 class ASF::File::MetadataLibraryObject : public ASF::File::BaseObject
132 {
133 public:
134   ByteVectorList attributeData;
135   ByteVector guid();
136   void parse(ASF::File *file, uint size);
137   ByteVector render(ASF::File *file);
138 };
139
140 class ASF::File::HeaderExtensionObject : public ASF::File::BaseObject
141 {
142 public:
143   List<ASF::File::BaseObject *> objects;
144   ByteVector guid();
145   void parse(ASF::File *file, uint size);
146   ByteVector render(ASF::File *file);
147 };
148
149 void
150 ASF::File::BaseObject::parse(ASF::File *file, unsigned int size)
151 {
152   data = file->readBlock(size - 24);
153 }
154
155 ByteVector
156 ASF::File::BaseObject::render(ASF::File * /*file*/)
157 {
158   return guid() + ByteVector::fromLongLong(data.size() + 24, false) + data;
159 }
160
161 ASF::File::UnknownObject::UnknownObject(const ByteVector &guid) : myGuid(guid)
162 {
163 }
164
165 ByteVector
166 ASF::File::UnknownObject::guid()
167 {
168   return myGuid;
169 }
170
171 ByteVector
172 ASF::File::FilePropertiesObject::guid()
173 {
174   return filePropertiesGuid;
175 }
176
177 void
178 ASF::File::FilePropertiesObject::parse(ASF::File *file, uint size)
179 {
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));
182 }
183
184 ByteVector
185 ASF::File::StreamPropertiesObject::guid()
186 {
187   return streamPropertiesGuid;
188 }
189
190 void
191 ASF::File::StreamPropertiesObject::parse(ASF::File *file, uint size)
192 {
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);
197 }
198
199 ByteVector
200 ASF::File::ContentDescriptionObject::guid()
201 {
202   return contentDescriptionGuid;
203 }
204
205 void
206 ASF::File::ContentDescriptionObject::parse(ASF::File *file, uint /*size*/)
207 {
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));
219 }
220
221 ByteVector
222 ASF::File::ContentDescriptionObject::render(ASF::File *file)
223 {
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());
229   data.clear();
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));
235   data.append(v1);
236   data.append(v2);
237   data.append(v3);
238   data.append(v4);
239   data.append(v5);
240   return BaseObject::render(file);
241 }
242
243 ByteVector
244 ASF::File::ExtendedContentDescriptionObject::guid()
245 {
246   return extendedContentDescriptionGuid;
247 }
248
249 void
250 ASF::File::ExtendedContentDescriptionObject::parse(ASF::File *file, uint /*size*/)
251 {
252   file->d->extendedContentDescriptionObject = this;
253   int count = file->readWORD();
254   while(count--) {
255     ASF::Attribute attribute;
256     String name = attribute.parse(*file);
257     file->d->tag->addAttribute(name, attribute);
258   }
259 }
260
261 ByteVector
262 ASF::File::ExtendedContentDescriptionObject::render(ASF::File *file)
263 {
264   data.clear();
265   data.append(ByteVector::fromShort(attributeData.size(), false));
266   data.append(attributeData.toByteVector(ByteVector::null));
267   return BaseObject::render(file);
268 }
269
270 ByteVector
271 ASF::File::MetadataObject::guid()
272 {
273   return metadataGuid;
274 }
275
276 void
277 ASF::File::MetadataObject::parse(ASF::File *file, uint /*size*/)
278 {
279   file->d->metadataObject = this;
280   int count = file->readWORD();
281   while(count--) {
282     ASF::Attribute attribute;
283     String name = attribute.parse(*file, 1);
284     file->d->tag->addAttribute(name, attribute);
285   }
286 }
287
288 ByteVector
289 ASF::File::MetadataObject::render(ASF::File *file)
290 {
291   data.clear();
292   data.append(ByteVector::fromShort(attributeData.size(), false));
293   data.append(attributeData.toByteVector(ByteVector::null));
294   return BaseObject::render(file);
295 }
296
297 ByteVector
298 ASF::File::MetadataLibraryObject::guid()
299 {
300   return metadataLibraryGuid;
301 }
302
303 void
304 ASF::File::MetadataLibraryObject::parse(ASF::File *file, uint /*size*/)
305 {
306   file->d->metadataLibraryObject = this;
307   int count = file->readWORD();
308   while(count--) {
309     ASF::Attribute attribute;
310     String name = attribute.parse(*file, 2);
311     file->d->tag->addAttribute(name, attribute);
312   }
313 }
314
315 ByteVector
316 ASF::File::MetadataLibraryObject::render(ASF::File *file)
317 {
318   data.clear();
319   data.append(ByteVector::fromShort(attributeData.size(), false));
320   data.append(attributeData.toByteVector(ByteVector::null));
321   return BaseObject::render(file);
322 }
323
324 ByteVector
325 ASF::File::HeaderExtensionObject::guid()
326 {
327   return headerExtensionGuid;
328 }
329
330 void
331 ASF::File::HeaderExtensionObject::parse(ASF::File *file, uint /*size*/)
332 {
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();
340     BaseObject *obj;
341     if(guid == metadataGuid) {
342       obj = new MetadataObject();
343     }
344     else if(guid == metadataLibraryGuid) {
345       obj = new MetadataLibraryObject();
346     }
347     else {
348       obj = new UnknownObject(guid);
349     }
350     obj->parse(file, size);
351     objects.append(obj);
352     dataPos += size;
353   }
354 }
355
356 ByteVector
357 ASF::File::HeaderExtensionObject::render(ASF::File *file)
358 {
359   data.clear();
360   for(unsigned int i = 0; i < objects.size(); i++) {
361     data.append(objects[i]->render(file));
362   }
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);
365 }
366
367 ////////////////////////////////////////////////////////////////////////////////
368 // public members
369 ////////////////////////////////////////////////////////////////////////////////
370
371 ASF::File::File(FileName file, bool readProperties, Properties::ReadStyle propertiesStyle) 
372   : TagLib::File(file)
373 {
374   d = new FilePrivate;
375   read(readProperties, propertiesStyle);
376 }
377
378 ASF::File::~File()
379 {
380   for(unsigned int i = 0; i < d->objects.size(); i++) {
381     delete d->objects[i];
382   }
383   if(d->tag) {
384     delete d->tag;
385   }
386   if(d->properties) {
387     delete d->properties;
388   }
389   delete d;
390 }
391
392 ASF::Tag *ASF::File::tag() const
393 {
394   return d->tag;
395 }
396
397 ASF::Properties *ASF::File::audioProperties() const
398 {
399   return d->properties;
400 }
401
402 void ASF::File::read(bool /*readProperties*/, Properties::ReadStyle /*propertiesStyle*/)
403 {
404   if(!isValid())
405     return;
406
407   ByteVector guid = readBlock(16);
408   if(guid != headerGuid) {
409     debug("ASF: Not an ASF file.");
410     return;
411   }
412
413   d->tag = new ASF::Tag();
414   d->properties = new ASF::Properties();
415
416   d->size = readQWORD();
417   int numObjects = readDWORD();
418   seek(2, Current);
419
420   for(int i = 0; i < numObjects; i++) {
421     ByteVector guid = readBlock(16);
422     long size = (long)readQWORD();
423     BaseObject *obj;
424     if(guid == filePropertiesGuid) {
425       obj = new FilePropertiesObject();
426     }
427     else if(guid == streamPropertiesGuid) {
428       obj = new StreamPropertiesObject();
429     }
430     else if(guid == contentDescriptionGuid) {
431       obj = new ContentDescriptionObject();
432     }
433     else if(guid == extendedContentDescriptionGuid) {
434       obj = new ExtendedContentDescriptionObject();
435     }
436     else if(guid == headerExtensionGuid) {
437       obj = new HeaderExtensionObject();
438     }
439     else {
440       obj = new UnknownObject(guid);
441     }
442     obj->parse(this, size);
443     d->objects.append(obj);
444   }
445 }
446
447 bool ASF::File::save()
448 {
449   if(readOnly()) {
450     debug("ASF: File is read-only.");
451     return false;
452   }
453
454   if(!d->contentDescriptionObject) {
455     d->contentDescriptionObject = new ContentDescriptionObject();
456     d->objects.append(d->contentDescriptionObject);
457   }
458   if(!d->extendedContentDescriptionObject) {
459     d->extendedContentDescriptionObject = new ExtendedContentDescriptionObject();
460     d->objects.append(d->extendedContentDescriptionObject);
461   }
462   if(!d->headerExtensionObject) {
463     d->headerExtensionObject = new HeaderExtensionObject();
464     d->objects.append(d->headerExtensionObject);
465   }
466   if(!d->metadataObject) {
467     d->metadataObject = new MetadataObject();
468     d->headerExtensionObject->objects.append(d->metadataObject);
469   }
470   if(!d->metadataLibraryObject) {
471     d->metadataLibraryObject = new MetadataLibraryObject();
472     d->headerExtensionObject->objects.append(d->metadataLibraryObject);
473   }
474
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;
487       }
488       else if(!inMetadataObject && !largeValue && attribute.language() == 0 && attribute.stream() != 0) {
489         d->metadataObject->attributeData.append(attribute.render(name, 1));
490         inMetadataObject = true;
491       }
492       else {
493         d->metadataLibraryObject->attributeData.append(attribute.render(name, 2));
494       }
495     }
496   }
497
498   ByteVector data;
499   for(unsigned int i = 0; i < d->objects.size(); i++) {
500     data.append(d->objects[i]->render(this));
501   }
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);
504
505   return true;
506 }
507
508 ////////////////////////////////////////////////////////////////////////////////
509 // protected members
510 ////////////////////////////////////////////////////////////////////////////////
511
512 int ASF::File::readBYTE()
513 {
514   ByteVector v = readBlock(1);
515   return v[0];
516 }
517
518 int ASF::File::readWORD()
519 {
520   ByteVector v = readBlock(2);
521   return v.toShort(false);
522 }
523
524 unsigned int ASF::File::readDWORD()
525 {
526   ByteVector v = readBlock(4);
527   return v.toUInt(false);
528 }
529
530 long long ASF::File::readQWORD()
531 {
532   ByteVector v = readBlock(8);
533   return v.toLongLong(false);
534 }
535
536 String
537 ASF::File::readString(int length)
538 {
539   ByteVector data = readBlock(length);
540   unsigned int size = data.size();
541   while (size >= 2) {
542     if(data[size - 1] != '\0' || data[size - 2] != '\0') {
543       break;
544     }
545     size -= 2;
546   }
547   if(size != data.size()) {
548     data.resize(size);
549   }
550   return String(data, String::UTF16LE);
551 }
552
553 ByteVector
554 ASF::File::renderString(const String &str, bool includeLength)
555 {
556   ByteVector data = str.data(String::UTF16LE) + ByteVector::fromShort(0, false);
557   if(includeLength) {
558     data = ByteVector::fromShort(data.size(), false) + data;
559   }
560   return data;
561 }
562
563 #endif