Added TagLib (with AUTORS and COPYING files)
[someplayer] / src / taglib / mpeg / id3v2 / id3v2frame.cpp
1 /***************************************************************************
2     copyright            : (C) 2002 - 2008 by Scott Wheeler
3     email                : wheeler@kde.org
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 #define HAVE_ZLIB 0
27
28 #ifndef HAVE_ZLIB
29 #include <config.h>
30 #endif
31
32 #if HAVE_ZLIB
33 #include <zlib.h>
34 #endif
35
36 #include <bitset>
37
38 #include <tdebug.h>
39 #include <tstringlist.h>
40
41 #include "id3v2frame.h"
42 #include "id3v2synchdata.h"
43
44 using namespace TagLib;
45 using namespace ID3v2;
46
47 class Frame::FramePrivate
48 {
49 public:
50   FramePrivate() :
51     header(0)
52     {}
53
54   ~FramePrivate()
55   {
56     delete header;
57   }
58
59   Frame::Header *header;
60 };
61
62 namespace
63 {
64   bool isValidFrameID(const ByteVector &frameID)
65   {
66     if(frameID.size() != 4)
67       return false;
68
69     for(ByteVector::ConstIterator it = frameID.begin(); it != frameID.end(); it++) {
70       if( (*it < 'A' || *it > 'Z') && (*it < '1' || *it > '9') ) {
71         return false;
72       }
73     }
74     return true;
75   }
76 }
77
78 ////////////////////////////////////////////////////////////////////////////////
79 // static methods
80 ////////////////////////////////////////////////////////////////////////////////
81
82 TagLib::uint Frame::headerSize()
83 {
84   return Header::size();
85 }
86
87 TagLib::uint Frame::headerSize(uint version)
88 {
89   return Header::size(version);
90 }
91
92 ByteVector Frame::textDelimiter(String::Type t)
93 {
94   ByteVector d = char(0);
95   if(t == String::UTF16 || t == String::UTF16BE || t == String::UTF16LE)
96     d.append(char(0));
97   return d;
98 }
99
100 ////////////////////////////////////////////////////////////////////////////////
101 // public members
102 ////////////////////////////////////////////////////////////////////////////////
103
104 Frame::~Frame()
105 {
106   delete d;
107 }
108
109 ByteVector Frame::frameID() const
110 {
111   if(d->header)
112     return d->header->frameID();
113   else
114     return ByteVector::null;
115 }
116
117 TagLib::uint Frame::size() const
118 {
119   if(d->header)
120     return d->header->frameSize();
121   else
122     return 0;
123 }
124
125 void Frame::setData(const ByteVector &data)
126 {
127   parse(data);
128 }
129
130 void Frame::setText(const String &)
131 {
132
133 }
134
135 ByteVector Frame::render() const
136 {
137   ByteVector fieldData = renderFields();
138   d->header->setFrameSize(fieldData.size());
139   ByteVector headerData = d->header->render();
140
141   return headerData + fieldData;
142 }
143
144 ////////////////////////////////////////////////////////////////////////////////
145 // protected members
146 ////////////////////////////////////////////////////////////////////////////////
147
148 Frame::Frame(const ByteVector &data)
149 {
150   d = new FramePrivate;
151   d->header = new Header(data);
152 }
153
154 Frame::Frame(Header *h)
155 {
156   d = new FramePrivate;
157   d->header = h;
158 }
159
160 Frame::Header *Frame::header() const
161 {
162   return d->header;
163 }
164
165 void Frame::setHeader(Header *h, bool deleteCurrent)
166 {
167   if(deleteCurrent)
168     delete d->header;
169
170   d->header = h;
171 }
172
173 void Frame::parse(const ByteVector &data)
174 {
175   if(d->header)
176     d->header->setData(data);
177   else
178     d->header = new Header(data);
179
180   parseFields(fieldData(data));
181 }
182
183 ByteVector Frame::fieldData(const ByteVector &frameData) const
184 {
185   uint headerSize = Header::size(d->header->version());
186
187   uint frameDataOffset = headerSize;
188   uint frameDataLength = size();
189
190   if(d->header->compression() || d->header->dataLengthIndicator()) {
191     frameDataLength = SynchData::toUInt(frameData.mid(headerSize, 4));
192     frameDataOffset += 4;
193   }
194
195 #if HAVE_ZLIB
196   if(d->header->compression() &&
197      !d->header->encryption())
198   {
199     ByteVector data(frameDataLength);
200     uLongf uLongTmp = frameDataLength;
201     ::uncompress((Bytef *) data.data(),
202                  (uLongf *) &uLongTmp,
203                  (Bytef *) frameData.data() + frameDataOffset,
204                  size());
205     return data;
206   }
207   else
208 #endif
209     return frameData.mid(frameDataOffset, frameDataLength);
210 }
211
212 String Frame::readStringField(const ByteVector &data, String::Type encoding, int *position)
213 {
214   int start = 0;
215
216   if(!position)
217     position = &start;
218
219   ByteVector delimiter = textDelimiter(encoding);
220
221   int end = data.find(delimiter, *position, delimiter.size());
222
223   if(end < *position)
224     return String::null;
225
226   String str = String(data.mid(*position, end - *position), encoding);
227
228   *position = end + delimiter.size();
229
230   return str;
231 }
232
233 String::Type Frame::checkEncoding(const StringList &fields, String::Type encoding) // static
234 {
235   if(encoding != String::Latin1)
236     return encoding;
237
238   for(StringList::ConstIterator it = fields.begin(); it != fields.end(); ++it) {
239     if(!(*it).isLatin1()) {
240       debug("Frame::checkEncoding() -- Rendering using UTF8.");
241       return String::UTF8;
242     }
243   }
244
245   return String::Latin1;
246 }
247
248 ////////////////////////////////////////////////////////////////////////////////
249 // Frame::Header class
250 ////////////////////////////////////////////////////////////////////////////////
251
252 class Frame::Header::HeaderPrivate
253 {
254 public:
255   HeaderPrivate() :
256     frameSize(0),
257     version(4),
258     tagAlterPreservation(false),
259     fileAlterPreservation(false),
260     readOnly(false),
261     groupingIdentity(false),
262     compression(false),
263     encryption(false),
264     unsynchronisation(false),
265     dataLengthIndicator(false)
266     {}
267
268   ByteVector frameID;
269   uint frameSize;
270   uint version;
271
272   // flags
273
274   bool tagAlterPreservation;
275   bool fileAlterPreservation;
276   bool readOnly;
277   bool groupingIdentity;
278   bool compression;
279   bool encryption;
280   bool unsynchronisation;
281   bool dataLengthIndicator;
282 };
283
284 ////////////////////////////////////////////////////////////////////////////////
285 // static members (Frame::Header)
286 ////////////////////////////////////////////////////////////////////////////////
287
288 TagLib::uint Frame::Header::size()
289 {
290   return size(4);
291 }
292
293 TagLib::uint Frame::Header::size(uint version)
294 {
295   switch(version) {
296   case 0:
297   case 1:
298   case 2:
299     return 6;
300   case 3:
301   case 4:
302   default:
303     return 10;
304   }
305 }
306
307 ////////////////////////////////////////////////////////////////////////////////
308 // public members (Frame::Header)
309 ////////////////////////////////////////////////////////////////////////////////
310
311 Frame::Header::Header(const ByteVector &data, bool synchSafeInts)
312 {
313   d = new HeaderPrivate;
314   setData(data, synchSafeInts);
315 }
316
317 Frame::Header::Header(const ByteVector &data, uint version)
318 {
319   d = new HeaderPrivate;
320   setData(data, version);
321 }
322
323 Frame::Header::~Header()
324 {
325   delete d;
326 }
327
328 void Frame::Header::setData(const ByteVector &data, bool synchSafeInts)
329 {
330   setData(data, uint(synchSafeInts ? 4 : 3));
331 }
332
333 void Frame::Header::setData(const ByteVector &data, uint version)
334 {
335   d->version = version;
336
337   switch(version) {
338   case 0:
339   case 1:
340   case 2:
341   {
342     // ID3v2.2
343
344     if(data.size() < 3) {
345       debug("You must at least specify a frame ID.");
346       return;
347     }
348
349     // Set the frame ID -- the first three bytes
350
351     d->frameID = data.mid(0, 3);
352
353     // If the full header information was not passed in, do not continue to the
354     // steps to parse the frame size and flags.
355
356     if(data.size() < 6) {
357       d->frameSize = 0;
358       return;
359     }
360
361     d->frameSize = data.mid(3, 3).toUInt();
362
363     break;
364   }
365   case 3:
366   {
367     // ID3v2.3
368
369     if(data.size() < 4) {
370       debug("You must at least specify a frame ID.");
371       return;
372     }
373
374     // Set the frame ID -- the first four bytes
375
376     d->frameID = data.mid(0, 4);
377
378     // If the full header information was not passed in, do not continue to the
379     // steps to parse the frame size and flags.
380
381     if(data.size() < 10) {
382       d->frameSize = 0;
383       return;
384     }
385
386     // Set the size -- the frame size is the four bytes starting at byte four in
387     // the frame header (structure 4)
388
389     d->frameSize = data.mid(4, 4).toUInt();
390
391     { // read the first byte of flags
392       std::bitset<8> flags(data[8]);
393       d->tagAlterPreservation  = flags[7]; // (structure 3.3.1.a)
394       d->fileAlterPreservation = flags[6]; // (structure 3.3.1.b)
395       d->readOnly              = flags[5]; // (structure 3.3.1.c)
396     }
397
398     { // read the second byte of flags
399       std::bitset<8> flags(data[9]);
400       d->compression         = flags[7]; // (structure 3.3.1.i)
401       d->encryption          = flags[6]; // (structure 3.3.1.j)
402       d->groupingIdentity    = flags[5]; // (structure 3.3.1.k)
403     }
404     break;
405   }
406   case 4:
407   default:
408   {
409     // ID3v2.4
410
411     if(data.size() < 4) {
412       debug("You must at least specify a frame ID.");
413       return;
414     }
415
416     // Set the frame ID -- the first four bytes
417
418     d->frameID = data.mid(0, 4);
419
420     // If the full header information was not passed in, do not continue to the
421     // steps to parse the frame size and flags.
422
423     if(data.size() < 10) {
424       d->frameSize = 0;
425       return;
426     }
427
428     // Set the size -- the frame size is the four bytes starting at byte four in
429     // the frame header (structure 4)
430
431     d->frameSize = SynchData::toUInt(data.mid(4, 4));
432 #ifndef NO_ITUNES_HACKS
433     // iTunes writes v2.4 tags with v2.3-like frame sizes
434     if(d->frameSize > 127) {
435       if(!isValidFrameID(data.mid(d->frameSize + 10, 4))) {
436         unsigned int uintSize = data.mid(4, 4).toUInt();
437         if(isValidFrameID(data.mid(uintSize + 10, 4))) {
438           d->frameSize = uintSize;
439         }
440       }
441     }
442 #endif
443
444     { // read the first byte of flags
445       std::bitset<8> flags(data[8]);
446       d->tagAlterPreservation  = flags[6]; // (structure 4.1.1.a)
447       d->fileAlterPreservation = flags[5]; // (structure 4.1.1.b)
448       d->readOnly              = flags[4]; // (structure 4.1.1.c)
449     }
450
451     { // read the second byte of flags
452       std::bitset<8> flags(data[9]);
453       d->groupingIdentity    = flags[6]; // (structure 4.1.2.h)
454       d->compression         = flags[3]; // (structure 4.1.2.k)
455       d->encryption          = flags[2]; // (structure 4.1.2.m)
456       d->unsynchronisation   = flags[1]; // (structure 4.1.2.n)
457       d->dataLengthIndicator = flags[0]; // (structure 4.1.2.p)
458     }
459     break;
460   }
461   }
462 }
463
464 ByteVector Frame::Header::frameID() const
465 {
466   return d->frameID;
467 }
468
469 void Frame::Header::setFrameID(const ByteVector &id)
470 {
471   d->frameID = id.mid(0, 4);
472 }
473
474 TagLib::uint Frame::Header::frameSize() const
475 {
476   return d->frameSize;
477 }
478
479 void Frame::Header::setFrameSize(uint size)
480 {
481   d->frameSize = size;
482 }
483
484 TagLib::uint Frame::Header::version() const
485 {
486   return d->version;
487 }
488
489 bool Frame::Header::tagAlterPreservation() const
490 {
491   return d->tagAlterPreservation;
492 }
493
494 void Frame::Header::setTagAlterPreservation(bool preserve)
495 {
496   d->tagAlterPreservation = preserve;
497 }
498
499 bool Frame::Header::fileAlterPreservation() const
500 {
501   return d->fileAlterPreservation;
502 }
503
504 bool Frame::Header::readOnly() const
505 {
506   return d->readOnly;
507 }
508
509 bool Frame::Header::groupingIdentity() const
510 {
511   return d->groupingIdentity;
512 }
513
514 bool Frame::Header::compression() const
515 {
516   return d->compression;
517 }
518
519 bool Frame::Header::encryption() const
520 {
521   return d->encryption;
522 }
523
524 bool Frame::Header::unsycronisation() const
525 {
526   return unsynchronisation();
527 }
528
529 bool Frame::Header::unsynchronisation() const
530 {
531   return d->unsynchronisation;
532 }
533
534 bool Frame::Header::dataLengthIndicator() const
535 {
536   return d->dataLengthIndicator;
537 }
538
539 ByteVector Frame::Header::render() const
540 {
541   ByteVector flags(2, char(0)); // just blank for the moment
542
543   ByteVector v = d->frameID + SynchData::fromUInt(d->frameSize) + flags;
544
545   return v;
546 }
547
548 bool Frame::Header::frameAlterPreservation() const
549 {
550   return fileAlterPreservation();
551 }