Added TagLib (with AUTORS and COPYING files)
[someplayer] / src / taglib / mpeg / id3v2 / id3v2header.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 #include <iostream>
27 #include <bitset>
28
29 #include <tstring.h>
30 #include <tdebug.h>
31
32 #include "id3v2header.h"
33 #include "id3v2footer.h"
34 #include "id3v2synchdata.h"
35
36 using namespace TagLib;
37 using namespace ID3v2;
38
39 class Header::HeaderPrivate
40 {
41 public:
42   HeaderPrivate() : majorVersion(4),
43                     revisionNumber(0),
44                     unsynchronisation(false),
45                     extendedHeader(false),
46                     experimentalIndicator(false),
47                     footerPresent(false),
48                     tagSize(0) {}
49
50   ~HeaderPrivate() {}
51
52   uint majorVersion;
53   uint revisionNumber;
54
55   bool unsynchronisation;
56   bool extendedHeader;
57   bool experimentalIndicator;
58   bool footerPresent;
59
60   uint tagSize;
61
62   static const uint size = 10;
63 };
64
65 ////////////////////////////////////////////////////////////////////////////////
66 // static members
67 ////////////////////////////////////////////////////////////////////////////////
68
69 TagLib::uint Header::size()
70 {
71   return HeaderPrivate::size;
72 }
73
74 ByteVector Header::fileIdentifier()
75 {
76   return ByteVector::fromCString("ID3");
77 }
78
79 ////////////////////////////////////////////////////////////////////////////////
80 // public members
81 ////////////////////////////////////////////////////////////////////////////////
82
83 Header::Header()
84 {
85   d = new HeaderPrivate;
86 }
87
88 Header::Header(const ByteVector &data)
89 {
90   d = new HeaderPrivate;
91   parse(data);
92 }
93
94 Header::~Header()
95 {
96   delete d;
97 }
98
99 TagLib::uint Header::majorVersion() const
100 {
101   return d->majorVersion;
102 }
103
104 void Header::setMajorVersion(TagLib::uint version)
105 {
106   d->majorVersion = version;
107 }
108
109 TagLib::uint Header::revisionNumber() const
110 {
111   return d->revisionNumber;
112 }
113
114 bool Header::unsynchronisation() const
115 {
116   return d->unsynchronisation;
117 }
118
119 bool Header::extendedHeader() const
120 {
121   return d->extendedHeader;
122 }
123
124 bool Header::experimentalIndicator() const
125 {
126   return d->experimentalIndicator;
127 }
128
129 bool Header::footerPresent() const
130 {
131   return d->footerPresent;
132 }
133
134 TagLib::uint Header::tagSize() const
135 {
136   return d->tagSize;
137 }
138
139 TagLib::uint Header::completeTagSize() const
140 {
141   if(d->footerPresent)
142     return d->tagSize + d->size + Footer::size();
143   else
144     return d->tagSize + d->size;
145 }
146
147 void Header::setTagSize(uint s)
148 {
149   d->tagSize = s;
150 }
151
152 void Header::setData(const ByteVector &data)
153 {
154   parse(data);
155 }
156
157 ByteVector Header::render() const
158 {
159   ByteVector v;
160
161   // add the file identifier -- "ID3"
162   v.append(fileIdentifier());
163
164   // add the version number -- we always render a 2.4.0 tag regardless of what
165   // the tag originally was.
166
167   v.append(char(4));
168   v.append(char(0));
169
170   // Currently we don't actually support writing extended headers, footers or
171   // unsynchronized tags, make sure that the flags are set accordingly.
172
173   d->extendedHeader = false;
174   d->footerPresent = false;
175   d->unsynchronisation = false;
176
177   // render and add the flags
178   std::bitset<8> flags;
179
180   flags[7] = d->unsynchronisation;
181   flags[6] = d->extendedHeader;
182   flags[5] = d->experimentalIndicator;
183   flags[4] = d->footerPresent;
184
185   v.append(char(flags.to_ulong()));
186
187   // add the size
188   v.append(SynchData::fromUInt(d->tagSize));
189
190   return v;
191 }
192
193 ////////////////////////////////////////////////////////////////////////////////
194 // protected members
195 ////////////////////////////////////////////////////////////////////////////////
196
197 void Header::parse(const ByteVector &data)
198 {
199   if(data.size() < size())
200     return;
201
202
203   // do some sanity checking -- even in ID3v2.3.0 and less the tag size is a
204   // synch-safe integer, so all bytes must be less than 128.  If this is not
205   // true then this is an invalid tag.
206
207   // note that we're doing things a little out of order here -- the size is
208   // later in the bytestream than the version
209
210   ByteVector sizeData = data.mid(6, 4);
211
212   if(sizeData.size() != 4) {
213     d->tagSize = 0;
214     debug("TagLib::ID3v2::Header::parse() - The tag size as read was 0 bytes!");
215     return;
216   }
217
218   for(ByteVector::Iterator it = sizeData.begin(); it != sizeData.end(); it++) {
219     if(uchar(*it) >= 128) {
220       d->tagSize = 0;
221       debug("TagLib::ID3v2::Header::parse() - One of the size bytes in the id3v2 header was greater than the allowed 128.");
222       return;
223     }
224   }
225
226   // The first three bytes, data[0..2], are the File Identifier, "ID3". (structure 3.1 "file identifier")
227
228   // Read the version number from the fourth and fifth bytes.
229   d->majorVersion = data[3];   // (structure 3.1 "major version")
230   d->revisionNumber = data[4]; // (structure 3.1 "revision number")
231
232   // Read the flags, the first four bits of the sixth byte.
233   std::bitset<8> flags(data[5]);
234
235   d->unsynchronisation     = flags[7]; // (structure 3.1.a)
236   d->extendedHeader        = flags[6]; // (structure 3.1.b)
237   d->experimentalIndicator = flags[5]; // (structure 3.1.c)
238   d->footerPresent         = flags[4]; // (structure 3.1.d)
239
240   // Get the size from the remaining four bytes (read above)
241
242   d->tagSize = SynchData::toUInt(sizeData); // (structure 3.1 "size")
243 }