Added TagLib (with AUTORS and COPYING files)
[someplayer] / src / taglib / mpeg / id3v1 / id3v1tag.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 <tdebug.h>
27 #include <tfile.h>
28
29 #include "id3v1tag.h"
30 #include "id3v1genres.h"
31
32 using namespace TagLib;
33 using namespace ID3v1;
34
35 class ID3v1::Tag::TagPrivate
36 {
37 public:
38   TagPrivate() : file(0), tagOffset(-1), track(0), genre(255) {}
39
40   File *file;
41   long tagOffset;
42
43   String title;
44   String artist;
45   String album;
46   String year;
47   String comment;
48   uchar track;
49   uchar genre;
50
51   static const StringHandler *stringHandler;
52 };
53
54 const ID3v1::StringHandler *ID3v1::Tag::TagPrivate::stringHandler = new StringHandler;
55
56 ////////////////////////////////////////////////////////////////////////////////
57 // StringHandler implementation
58 ////////////////////////////////////////////////////////////////////////////////
59
60 String ID3v1::StringHandler::parse(const ByteVector &data) const
61 {
62   return String(data, String::Latin1).stripWhiteSpace();
63 }
64
65 ByteVector ID3v1::StringHandler::render(const String &s) const
66 {
67   if(!s.isLatin1())
68   {
69     return ByteVector();
70   }
71
72   return s.data(String::Latin1);
73 }
74
75 ////////////////////////////////////////////////////////////////////////////////
76 // public methods
77 ////////////////////////////////////////////////////////////////////////////////
78
79 ID3v1::Tag::Tag() : TagLib::Tag()
80 {
81   d = new TagPrivate;
82 }
83
84 ID3v1::Tag::Tag(File *file, long tagOffset) : TagLib::Tag()
85 {
86   d = new TagPrivate;
87   d->file = file;
88   d->tagOffset = tagOffset;
89
90   read();
91 }
92
93 ID3v1::Tag::~Tag()
94 {
95   delete d;
96 }
97
98 ByteVector ID3v1::Tag::render() const
99 {
100   ByteVector data;
101
102   data.append(fileIdentifier());
103   data.append(TagPrivate::stringHandler->render(d->title).resize(30));
104   data.append(TagPrivate::stringHandler->render(d->artist).resize(30));
105   data.append(TagPrivate::stringHandler->render(d->album).resize(30));
106   data.append(TagPrivate::stringHandler->render(d->year).resize(4));
107   data.append(TagPrivate::stringHandler->render(d->comment).resize(28));
108   data.append(char(0));
109   data.append(char(d->track));
110   data.append(char(d->genre));
111
112   return data;
113 }
114
115 ByteVector ID3v1::Tag::fileIdentifier()
116 {
117   return ByteVector::fromCString("TAG");
118 }
119
120 String ID3v1::Tag::title() const
121 {
122   return d->title;
123 }
124
125 String ID3v1::Tag::artist() const
126 {
127   return d->artist;
128 }
129
130 String ID3v1::Tag::album() const
131 {
132   return d->album;
133 }
134
135 String ID3v1::Tag::comment() const
136 {
137   return d->comment;
138 }
139
140 String ID3v1::Tag::genre() const
141 {
142   return ID3v1::genre(d->genre);
143 }
144
145 TagLib::uint ID3v1::Tag::year() const
146 {
147   return d->year.toInt();
148 }
149
150 TagLib::uint ID3v1::Tag::track() const
151 {
152   return d->track;
153 }
154
155 void ID3v1::Tag::setTitle(const String &s)
156 {
157   d->title = s;
158 }
159
160 void ID3v1::Tag::setArtist(const String &s)
161 {
162   d->artist = s;
163 }
164
165 void ID3v1::Tag::setAlbum(const String &s)
166 {
167   d->album = s;
168 }
169
170 void ID3v1::Tag::setComment(const String &s)
171 {
172   d->comment = s;
173 }
174
175 void ID3v1::Tag::setGenre(const String &s)
176 {
177   d->genre = ID3v1::genreIndex(s);
178 }
179
180 void ID3v1::Tag::setYear(uint i)
181 {
182   d->year = i > 0 ? String::number(i) : String::null;
183 }
184
185 void ID3v1::Tag::setTrack(uint i)
186 {
187   d->track = i < 256 ? i : 0;
188 }
189
190 void ID3v1::Tag::setStringHandler(const StringHandler *handler)
191 {
192   delete TagPrivate::stringHandler;
193   TagPrivate::stringHandler = handler;
194 }
195
196 ////////////////////////////////////////////////////////////////////////////////
197 // protected methods
198 ////////////////////////////////////////////////////////////////////////////////
199
200 void ID3v1::Tag::read()
201 {
202   if(d->file && d->file->isValid()) {
203     d->file->seek(d->tagOffset);
204     // read the tag -- always 128 bytes
205     ByteVector data = d->file->readBlock(128);
206
207     // some initial sanity checking
208     if(data.size() == 128 && data.startsWith("TAG"))
209       parse(data);
210     else
211       debug("ID3v1 tag is not valid or could not be read at the specified offset.");
212   }
213 }
214
215 void ID3v1::Tag::parse(const ByteVector &data)
216 {
217   int offset = 3;
218
219   d->title = TagPrivate::stringHandler->parse(data.mid(offset, 30));
220   offset += 30;
221
222   d->artist = TagPrivate::stringHandler->parse(data.mid(offset, 30));
223   offset += 30;
224
225   d->album = TagPrivate::stringHandler->parse(data.mid(offset, 30));
226   offset += 30;
227
228   d->year = TagPrivate::stringHandler->parse(data.mid(offset, 4));
229   offset += 4;
230
231   // Check for ID3v1.1 -- Note that ID3v1 *does not* support "track zero" -- this
232   // is not a bug in TagLib.  Since a zeroed byte is what we would expect to
233   // indicate the end of a C-String, specifically the comment string, a value of
234   // zero must be assumed to be just that.
235
236   if(data[offset + 28] == 0 && data[offset + 29] != 0) {
237     // ID3v1.1 detected
238
239     d->comment = TagPrivate::stringHandler->parse(data.mid(offset, 28));
240     d->track = uchar(data[offset + 29]);
241   }
242   else
243     d->comment = data.mid(offset, 30);
244
245   offset += 30;
246
247   d->genre = uchar(data[offset]);
248 }