~ubuntu-branches/ubuntu/karmic/taglib-extras/karmic

« back to all changes in this revision

Viewing changes to taglib-extras/asf/asffile.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jonathan Riddell
  • Date: 2009-04-01 15:35:05 UTC
  • Revision ID: james.westby@ubuntu.com-20090401153505-vwi459v8y2c1xnbr
Tags: upstream-0.1.1
Import upstream version 0.1.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
#include <tbytevectorlist.h>
 
27
#include <tstring.h>
 
28
#include "asffile.h"
 
29
#include "asftag.h"
 
30
#include "asfproperties.h"
 
31
 
 
32
using namespace TagLib;
 
33
 
 
34
class ASF::File::FilePrivate
 
35
{
 
36
public:
 
37
  FilePrivate():
 
38
    size(0),
 
39
    tag(0),
 
40
    properties(0),
 
41
    contentDescriptionObject(0),
 
42
    extendedContentDescriptionObject(0),
 
43
    headerExtensionObject(0),
 
44
    metadataObject(0),
 
45
    metadataLibraryObject(0) {}
 
46
  unsigned long long size;
 
47
  ASF::Tag *tag;
 
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;
 
55
};
 
56
 
 
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);
 
65
 
 
66
class ASF::File::BaseObject
 
67
{
 
68
public:
 
69
  ByteVector data;
 
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);
 
74
};
 
75
 
 
76
class ASF::File::UnknownObject : public ASF::File::BaseObject
 
77
{
 
78
  ByteVector myGuid;
 
79
public:
 
80
  UnknownObject(const ByteVector &guid);
 
81
  ByteVector guid();
 
82
};
 
83
 
 
84
class ASF::File::FilePropertiesObject : public ASF::File::BaseObject
 
85
{
 
86
public:
 
87
  ByteVector guid();
 
88
  void parse(ASF::File *file, uint size);
 
89
};
 
90
 
 
91
class ASF::File::StreamPropertiesObject : public ASF::File::BaseObject
 
92
{
 
93
public:
 
94
  ByteVector guid();
 
95
  void parse(ASF::File *file, uint size);
 
96
};
 
97
 
 
98
class ASF::File::ContentDescriptionObject : public ASF::File::BaseObject
 
99
{
 
100
public:
 
101
  ByteVector guid();
 
102
  void parse(ASF::File *file, uint size);
 
103
  ByteVector render(ASF::File *file);
 
104
};
 
105
 
 
106
class ASF::File::ExtendedContentDescriptionObject : public ASF::File::BaseObject
 
107
{
 
108
public:
 
109
  ByteVectorList attributeData;
 
110
  ByteVector guid();
 
111
  void parse(ASF::File *file, uint size);
 
112
  ByteVector render(ASF::File *file);
 
113
};
 
114
 
 
115
class ASF::File::MetadataObject : public ASF::File::BaseObject
 
116
{
 
117
public:
 
118
  ByteVectorList attributeData;
 
119
  ByteVector guid();
 
120
  void parse(ASF::File *file, uint size);
 
121
  ByteVector render(ASF::File *file);
 
122
};
 
123
 
 
124
class ASF::File::MetadataLibraryObject : public ASF::File::BaseObject
 
125
{
 
126
public:
 
127
  ByteVectorList attributeData;
 
128
  ByteVector guid();
 
129
  void parse(ASF::File *file, uint size);
 
130
  ByteVector render(ASF::File *file);
 
131
};
 
132
 
 
133
class ASF::File::HeaderExtensionObject : public ASF::File::BaseObject
 
134
{
 
135
public:
 
136
  List<ASF::File::BaseObject *> objects;
 
137
  ByteVector guid();
 
138
  void parse(ASF::File *file, uint size);
 
139
  ByteVector render(ASF::File *file);
 
140
};
 
141
 
 
142
void
 
143
ASF::File::BaseObject::parse(ASF::File *file, unsigned int size)
 
144
{
 
145
  data = file->readBlock(size - 24);
 
146
}
 
147
 
 
148
ByteVector
 
149
ASF::File::BaseObject::render(ASF::File * /*file*/)
 
150
{
 
151
  return guid() + ByteVector::fromLongLong(data.size() + 24, false) + data;
 
152
}
 
153
 
 
154
ASF::File::UnknownObject::UnknownObject(const ByteVector &guid) : myGuid(guid)
 
155
{
 
156
}
 
157
 
 
158
ByteVector
 
159
ASF::File::UnknownObject::guid()
 
160
{
 
161
  return myGuid;
 
162
}
 
163
 
 
164
ByteVector
 
165
ASF::File::FilePropertiesObject::guid()
 
166
{
 
167
  return filePropertiesGuid;
 
168
}
 
169
 
 
170
void
 
171
ASF::File::FilePropertiesObject::parse(ASF::File *file, uint size)
 
172
{
 
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));
 
175
}
 
176
 
 
177
ByteVector
 
178
ASF::File::StreamPropertiesObject::guid()
 
179
{
 
180
  return streamPropertiesGuid;
 
181
}
 
182
 
 
183
void
 
184
ASF::File::StreamPropertiesObject::parse(ASF::File *file, uint size)
 
185
{
 
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);
 
190
}
 
191
 
 
192
ByteVector
 
193
ASF::File::ContentDescriptionObject::guid()
 
194
{
 
195
  return contentDescriptionGuid;
 
196
}
 
197
 
 
198
void
 
199
ASF::File::ContentDescriptionObject::parse(ASF::File *file, uint /*size*/)
 
200
{
 
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));
 
212
}
 
213
 
 
214
ByteVector
 
215
ASF::File::ContentDescriptionObject::render(ASF::File *file)
 
216
{
 
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());
 
222
  data.clear();
 
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));
 
228
  data.append(v1);
 
229
  data.append(v2);
 
230
  data.append(v3);
 
231
  data.append(v4);
 
232
  data.append(v5);
 
233
  return BaseObject::render(file);
 
234
}
 
235
 
 
236
ByteVector
 
237
ASF::File::ExtendedContentDescriptionObject::guid()
 
238
{
 
239
  return extendedContentDescriptionGuid;
 
240
}
 
241
 
 
242
void
 
243
ASF::File::ExtendedContentDescriptionObject::parse(ASF::File *file, uint /*size*/)
 
244
{
 
245
  file->d->extendedContentDescriptionObject = this;
 
246
  int count = file->readWORD();
 
247
  while(count--) {
 
248
    ASF::Attribute attribute;
 
249
    String name = attribute.parse(*file);
 
250
    file->d->tag->addAttribute(name, attribute);
 
251
  }
 
252
}
 
253
 
 
254
ByteVector
 
255
ASF::File::ExtendedContentDescriptionObject::render(ASF::File *file)
 
256
{
 
257
  data.clear();
 
258
  data.append(ByteVector::fromShort(attributeData.size(), false));
 
259
  data.append(attributeData.toByteVector(ByteVector::null));
 
260
  return BaseObject::render(file);
 
261
}
 
262
 
 
263
ByteVector
 
264
ASF::File::MetadataObject::guid()
 
265
{
 
266
  return metadataGuid;
 
267
}
 
268
 
 
269
void
 
270
ASF::File::MetadataObject::parse(ASF::File *file, uint /*size*/)
 
271
{
 
272
  file->d->metadataObject = this;
 
273
  int count = file->readWORD();
 
274
  while(count--) {
 
275
    ASF::Attribute attribute;
 
276
    String name = attribute.parse(*file, 1);
 
277
    file->d->tag->addAttribute(name, attribute);
 
278
  }
 
279
}
 
280
 
 
281
ByteVector
 
282
ASF::File::MetadataObject::render(ASF::File *file)
 
283
{
 
284
  data.clear();
 
285
  data.append(ByteVector::fromShort(attributeData.size(), false));
 
286
  data.append(attributeData.toByteVector(ByteVector::null));
 
287
  return BaseObject::render(file);
 
288
}
 
289
 
 
290
ByteVector
 
291
ASF::File::MetadataLibraryObject::guid()
 
292
{
 
293
  return metadataLibraryGuid;
 
294
}
 
295
 
 
296
void
 
297
ASF::File::MetadataLibraryObject::parse(ASF::File *file, uint /*size*/)
 
298
{
 
299
  file->d->metadataLibraryObject = this;
 
300
  int count = file->readWORD();
 
301
  while(count--) {
 
302
    ASF::Attribute attribute;
 
303
    String name = attribute.parse(*file, 2);
 
304
    file->d->tag->addAttribute(name, attribute);
 
305
  }
 
306
}
 
307
 
 
308
ByteVector
 
309
ASF::File::MetadataLibraryObject::render(ASF::File *file)
 
310
{
 
311
  data.clear();
 
312
  data.append(ByteVector::fromShort(attributeData.size(), false));
 
313
  data.append(attributeData.toByteVector(ByteVector::null));
 
314
  return BaseObject::render(file);
 
315
}
 
316
 
 
317
ByteVector
 
318
ASF::File::HeaderExtensionObject::guid()
 
319
{
 
320
  return headerExtensionGuid;
 
321
}
 
322
 
 
323
void
 
324
ASF::File::HeaderExtensionObject::parse(ASF::File *file, uint /*size*/)
 
325
{
 
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();
 
333
    BaseObject *obj;
 
334
    if(guid == metadataGuid) {
 
335
      obj = new MetadataObject();
 
336
    }
 
337
    else if(guid == metadataLibraryGuid) {
 
338
      obj = new MetadataLibraryObject();
 
339
    }
 
340
    else {
 
341
      obj = new UnknownObject(guid);
 
342
    }
 
343
    obj->parse(file, size);
 
344
    objects.append(obj);
 
345
    dataPos += size;
 
346
  }
 
347
}
 
348
 
 
349
ByteVector
 
350
ASF::File::HeaderExtensionObject::render(ASF::File *file)
 
351
{
 
352
  data.clear();
 
353
  for(unsigned int i = 0; i < objects.size(); i++) {
 
354
    data.append(objects[i]->render(file));
 
355
  }
 
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);
 
358
}
 
359
 
 
360
////////////////////////////////////////////////////////////////////////////////
 
361
// public members
 
362
////////////////////////////////////////////////////////////////////////////////
 
363
 
 
364
ASF::File::File(FileName file, bool readProperties, Properties::ReadStyle propertiesStyle) 
 
365
  : TagLib::File(file)
 
366
{
 
367
  d = new FilePrivate;
 
368
  read(readProperties, propertiesStyle);
 
369
}
 
370
 
 
371
ASF::File::~File()
 
372
{
 
373
  for(unsigned int i = 0; i < d->objects.size(); i++) {
 
374
    delete d->objects[i];
 
375
  }
 
376
  if(d->tag) {
 
377
    delete d->tag;
 
378
  }
 
379
  if(d->properties) {
 
380
    delete d->properties;
 
381
  }
 
382
  delete d;
 
383
}
 
384
 
 
385
ASF::Tag *ASF::File::tag() const
 
386
{
 
387
  return d->tag;
 
388
}
 
389
 
 
390
ASF::Properties *ASF::File::audioProperties() const
 
391
{
 
392
  return d->properties;
 
393
}
 
394
 
 
395
void ASF::File::read(bool /*readProperties*/, Properties::ReadStyle /*propertiesStyle*/)
 
396
{
 
397
  if(!isValid())
 
398
    return;
 
399
 
 
400
  ByteVector guid = readBlock(16);
 
401
  if(guid != headerGuid) {
 
402
    return;
 
403
  }
 
404
 
 
405
  d->tag = new ASF::Tag();
 
406
  d->properties = new ASF::Properties();
 
407
 
 
408
  d->size = readQWORD();
 
409
  int numObjects = readDWORD();
 
410
  seek(2, Current);
 
411
 
 
412
  for(int i = 0; i < numObjects; i++) {
 
413
    ByteVector guid = readBlock(16);
 
414
    long size = (long)readQWORD();
 
415
    BaseObject *obj;
 
416
    if(guid == filePropertiesGuid) {
 
417
      obj = new FilePropertiesObject();
 
418
    }
 
419
    else if(guid == streamPropertiesGuid) {
 
420
      obj = new StreamPropertiesObject();
 
421
    }
 
422
    else if(guid == contentDescriptionGuid) {
 
423
      obj = new ContentDescriptionObject();
 
424
    }
 
425
    else if(guid == extendedContentDescriptionGuid) {
 
426
      obj = new ExtendedContentDescriptionObject();
 
427
    }
 
428
    else if(guid == headerExtensionGuid) {
 
429
      obj = new HeaderExtensionObject();
 
430
    }
 
431
    else {
 
432
      obj = new UnknownObject(guid);
 
433
    }
 
434
    obj->parse(this, size);
 
435
    d->objects.append(obj);
 
436
  }
 
437
}
 
438
 
 
439
bool ASF::File::save()
 
440
{
 
441
  if(readOnly()) {
 
442
    return false;
 
443
  }
 
444
 
 
445
  if(!d->contentDescriptionObject) {
 
446
    d->contentDescriptionObject = new ContentDescriptionObject();
 
447
    d->objects.append(d->contentDescriptionObject);
 
448
  }
 
449
  if(!d->extendedContentDescriptionObject) {
 
450
    d->extendedContentDescriptionObject = new ExtendedContentDescriptionObject();
 
451
    d->objects.append(d->extendedContentDescriptionObject);
 
452
  }
 
453
  if(!d->headerExtensionObject) {
 
454
    d->headerExtensionObject = new HeaderExtensionObject();
 
455
    d->objects.append(d->headerExtensionObject);
 
456
  }
 
457
  if(!d->metadataObject) {
 
458
    d->metadataObject = new MetadataObject();
 
459
    d->headerExtensionObject->objects.append(d->metadataObject);
 
460
  }
 
461
  if(!d->metadataLibraryObject) {
 
462
    d->metadataLibraryObject = new MetadataLibraryObject();
 
463
    d->headerExtensionObject->objects.append(d->metadataLibraryObject);
 
464
  }
 
465
 
 
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;
 
477
      }
 
478
      else if(!inMetadataObject && attribute.language() == 0 && attribute.stream() != 0) {
 
479
        d->metadataObject->attributeData.append(attribute.render(name, 1));
 
480
        inMetadataObject = true;
 
481
      }
 
482
      else {
 
483
        d->metadataLibraryObject->attributeData.append(attribute.render(name, 2));
 
484
      }
 
485
    }
 
486
  }
 
487
 
 
488
  ByteVector data;
 
489
  for(unsigned int i = 0; i < d->objects.size(); i++) {
 
490
    data.append(d->objects[i]->render(this));
 
491
  }
 
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);
 
494
 
 
495
  return true;
 
496
}
 
497
 
 
498
////////////////////////////////////////////////////////////////////////////////
 
499
// protected members
 
500
////////////////////////////////////////////////////////////////////////////////
 
501
 
 
502
int ASF::File::readBYTE()
 
503
{
 
504
  ByteVector v = readBlock(1);
 
505
  return v[0];
 
506
}
 
507
 
 
508
int ASF::File::readWORD()
 
509
{
 
510
  ByteVector v = readBlock(2);
 
511
  return v.toShort(false);
 
512
}
 
513
 
 
514
unsigned int ASF::File::readDWORD()
 
515
{
 
516
  ByteVector v = readBlock(4);
 
517
  return v.toUInt(false);
 
518
}
 
519
 
 
520
long long ASF::File::readQWORD()
 
521
{
 
522
  ByteVector v = readBlock(8);
 
523
  return v.toLongLong(false);
 
524
}
 
525
 
 
526
String
 
527
ASF::File::readString(int length)
 
528
{
 
529
  ByteVector data = readBlock(length);
 
530
  unsigned int size = data.size();
 
531
  while (size >= 2) {
 
532
    if(data[size - 1] != '\0' || data[size - 2] != '\0') {
 
533
      break;
 
534
    }
 
535
    size -= 2;
 
536
  }
 
537
  if(size != data.size()) {
 
538
    data.resize(size);
 
539
  }
 
540
  return String(data, String::UTF16LE);
 
541
}
 
542
 
 
543
ByteVector
 
544
ASF::File::renderString(const String &str, bool includeLength)
 
545
{
 
546
  ByteVector data = str.data(String::UTF16LE) + ByteVector::fromShort(0, false);
 
547
  if(includeLength) {
 
548
    data = ByteVector::fromShort(data.size(), false) + data;
 
549
  }
 
550
  return data;
 
551
}
 
552