Added TagLib (with AUTORS and COPYING files)
[someplayer] / src / taglib / mpeg / id3v2 / frames / textidentificationframe.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 <tbytevectorlist.h>
27 #include <id3v2tag.h>
28
29 #include "textidentificationframe.h"
30
31 using namespace TagLib;
32 using namespace ID3v2;
33
34 class TextIdentificationFrame::TextIdentificationFramePrivate
35 {
36 public:
37   TextIdentificationFramePrivate() : textEncoding(String::Latin1) {}
38   String::Type textEncoding;
39   StringList fieldList;
40 };
41
42 ////////////////////////////////////////////////////////////////////////////////
43 // TextIdentificationFrame public members
44 ////////////////////////////////////////////////////////////////////////////////
45
46 TextIdentificationFrame::TextIdentificationFrame(const ByteVector &type, String::Type encoding) :
47   Frame(type)
48 {
49   d = new TextIdentificationFramePrivate;
50   d->textEncoding = encoding;
51 }
52
53 TextIdentificationFrame::TextIdentificationFrame(const ByteVector &data) :
54   Frame(data)
55 {
56   d = new TextIdentificationFramePrivate;
57   setData(data);
58 }
59
60 TextIdentificationFrame::~TextIdentificationFrame()
61 {
62   delete d;
63 }
64
65 void TextIdentificationFrame::setText(const StringList &l)
66 {
67   d->fieldList = l;
68 }
69
70 void TextIdentificationFrame::setText(const String &s)
71 {
72   d->fieldList = s;
73 }
74
75 String TextIdentificationFrame::toString() const
76 {
77   return d->fieldList.toString();
78 }
79
80 StringList TextIdentificationFrame::fieldList() const
81 {
82   return d->fieldList;
83 }
84
85 String::Type TextIdentificationFrame::textEncoding() const
86 {
87   return d->textEncoding;
88 }
89
90 void TextIdentificationFrame::setTextEncoding(String::Type encoding)
91 {
92   d->textEncoding = encoding;
93 }
94
95 ////////////////////////////////////////////////////////////////////////////////
96 // TextIdentificationFrame protected members
97 ////////////////////////////////////////////////////////////////////////////////
98
99 void TextIdentificationFrame::parseFields(const ByteVector &data)
100 {
101   // Don't try to parse invalid frames
102
103   if(data.size() < 2)
104     return;
105
106   // read the string data type (the first byte of the field data)
107
108   d->textEncoding = String::Type(data[0]);
109
110   // split the byte array into chunks based on the string type (two byte delimiter
111   // for unicode encodings)
112
113   int byteAlign = d->textEncoding == String::Latin1 || d->textEncoding == String::UTF8 ? 1 : 2;
114
115   // build a small counter to strip nulls off the end of the field
116
117   int dataLength = data.size() - 1;
118
119   while(dataLength > 0 && data[dataLength] == 0)
120     dataLength--;
121
122   while(dataLength % byteAlign != 0)
123     dataLength++;
124
125   ByteVectorList l = ByteVectorList::split(data.mid(1, dataLength), textDelimiter(d->textEncoding), byteAlign);
126
127   d->fieldList.clear();
128
129   // append those split values to the list and make sure that the new string's
130   // type is the same specified for this frame
131
132   for(ByteVectorList::Iterator it = l.begin(); it != l.end(); it++) {
133     if(!(*it).isEmpty()) {
134       String s(*it, d->textEncoding);
135       d->fieldList.append(s);
136     }
137   }
138 }
139
140 ByteVector TextIdentificationFrame::renderFields() const
141 {
142   String::Type encoding = checkEncoding(d->fieldList, d->textEncoding);
143
144   ByteVector v;
145
146   v.append(char(encoding));
147
148   for(StringList::ConstIterator it = d->fieldList.begin(); it != d->fieldList.end(); it++) {
149
150     // Since the field list is null delimited, if this is not the first
151     // element in the list, append the appropriate delimiter for this
152     // encoding.
153
154     if(it != d->fieldList.begin())
155       v.append(textDelimiter(encoding));
156
157     v.append((*it).data(encoding));
158   }
159
160   return v;
161 }
162
163 ////////////////////////////////////////////////////////////////////////////////
164 // TextIdentificationFrame private members
165 ////////////////////////////////////////////////////////////////////////////////
166
167 TextIdentificationFrame::TextIdentificationFrame(const ByteVector &data, Header *h) : Frame(h)
168 {
169   d = new TextIdentificationFramePrivate;
170   parseFields(fieldData(data));
171 }
172
173 ////////////////////////////////////////////////////////////////////////////////
174 // UserTextIdentificationFrame public members
175 ////////////////////////////////////////////////////////////////////////////////
176
177 UserTextIdentificationFrame::UserTextIdentificationFrame(String::Type encoding) :
178   TextIdentificationFrame("TXXX", encoding),
179   d(0)
180 {
181   StringList l;
182   l.append(String::null);
183   l.append(String::null);
184   setText(l);
185 }
186
187
188 UserTextIdentificationFrame::UserTextIdentificationFrame(const ByteVector &data) :
189   TextIdentificationFrame(data)
190 {
191   checkFields();
192 }
193
194 String UserTextIdentificationFrame::toString() const
195 {
196   return "[" + description() + "] " + fieldList().toString();
197 }
198
199 String UserTextIdentificationFrame::description() const
200 {
201   return !TextIdentificationFrame::fieldList().isEmpty()
202     ? TextIdentificationFrame::fieldList().front()
203     : String::null;
204 }
205
206 StringList UserTextIdentificationFrame::fieldList() const
207 {
208   // TODO: remove this function
209
210   return TextIdentificationFrame::fieldList();
211 }
212
213 void UserTextIdentificationFrame::setText(const String &text)
214 {
215   if(description().isEmpty())
216     setDescription(String::null);
217
218   TextIdentificationFrame::setText(StringList(description()).append(text));
219 }
220
221 void UserTextIdentificationFrame::setText(const StringList &fields)
222 {
223   if(description().isEmpty())
224     setDescription(String::null);
225
226   TextIdentificationFrame::setText(StringList(description()).append(fields));
227 }
228
229 void UserTextIdentificationFrame::setDescription(const String &s)
230 {
231   StringList l = fieldList();
232
233   if(l.isEmpty())
234     l.append(s);
235   else
236     l[0] = s;
237
238   TextIdentificationFrame::setText(l);
239 }
240
241 UserTextIdentificationFrame *UserTextIdentificationFrame::find(
242   ID3v2::Tag *tag, const String &description) // static
243 {
244   FrameList l = tag->frameList("TXXX");
245   for(FrameList::Iterator it = l.begin(); it != l.end(); ++it) {
246     UserTextIdentificationFrame *f = dynamic_cast<UserTextIdentificationFrame *>(*it);
247     if(f && f->description() == description)
248       return f;
249   }
250   return 0;
251 }
252
253 ////////////////////////////////////////////////////////////////////////////////
254 // UserTextIdentificationFrame private members
255 ////////////////////////////////////////////////////////////////////////////////
256
257 UserTextIdentificationFrame::UserTextIdentificationFrame(const ByteVector &data, Header *h) :
258   TextIdentificationFrame(data, h)
259 {
260   checkFields();
261 }
262
263 void UserTextIdentificationFrame::checkFields()
264 {
265   int fields = fieldList().size();
266
267   if(fields == 0)
268     setDescription(String::null);
269   if(fields <= 1)
270     setText(String::null);
271 }