1 /***************************************************************************
2 copyright : (C) 2002 - 2008 by Scott Wheeler
3 email : wheeler@kde.org
4
5 copyright : (C) 2006 by Urs Fleisch
6 email : ufleisch@users.sourceforge.net
7 ***************************************************************************/
8
9 /***************************************************************************
10 * This library is free software; you can redistribute it and/or modify *
11 * it under the terms of the GNU Lesser General Public License version *
12 * 2.1 as published by the Free Software Foundation. *
13 * *
14 * This library is distributed in the hope that it will be useful, but *
15 * WITHOUT ANY WARRANTY; without even the implied warranty of *
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
17 * Lesser General Public License for more details. *
18 * *
19 * You should have received a copy of the GNU Lesser General Public *
20 * License along with this library; if not, write to the Free Software *
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
22 * 02110-1301 USA *
23 * *
24 * Alternatively, this file is available under the Mozilla Public *
25 * License Version 1.1. You may obtain a copy of the License at *
26 * http://www.mozilla.org/MPL/ *
27 ***************************************************************************/
28
29 #include "unsynchronizedlyricsframe.h"
30 #include <tbytevectorlist.h>
31 #include <id3v2tag.h>
32 #include <tdebug.h>
33 #include <tpropertymap.h>
34
35 using namespace TagLib;
36 using namespace ID3v2;
37
38 class UnsynchronizedLyricsFrame::UnsynchronizedLyricsFramePrivate
39 {
40 public:
UnsynchronizedLyricsFramePrivate()41 UnsynchronizedLyricsFramePrivate() : textEncoding(String::Latin1) {}
42 String::Type textEncoding;
43 ByteVector language;
44 String description;
45 String text;
46 };
47
48 ////////////////////////////////////////////////////////////////////////////////
49 // public members
50 ////////////////////////////////////////////////////////////////////////////////
51
UnsynchronizedLyricsFrame(String::Type encoding)52 UnsynchronizedLyricsFrame::UnsynchronizedLyricsFrame(String::Type encoding) :
53 Frame("USLT"),
54 d(new UnsynchronizedLyricsFramePrivate())
55 {
56 d->textEncoding = encoding;
57 }
58
UnsynchronizedLyricsFrame(const ByteVector & data)59 UnsynchronizedLyricsFrame::UnsynchronizedLyricsFrame(const ByteVector &data) :
60 Frame(data),
61 d(new UnsynchronizedLyricsFramePrivate())
62 {
63 setData(data);
64 }
65
~UnsynchronizedLyricsFrame()66 UnsynchronizedLyricsFrame::~UnsynchronizedLyricsFrame()
67 {
68 delete d;
69 }
70
toString() const71 String UnsynchronizedLyricsFrame::toString() const
72 {
73 return d->text;
74 }
75
language() const76 ByteVector UnsynchronizedLyricsFrame::language() const
77 {
78 return d->language;
79 }
80
description() const81 String UnsynchronizedLyricsFrame::description() const
82 {
83 return d->description;
84 }
85
text() const86 String UnsynchronizedLyricsFrame::text() const
87 {
88 return d->text;
89 }
90
setLanguage(const ByteVector & languageEncoding)91 void UnsynchronizedLyricsFrame::setLanguage(const ByteVector &languageEncoding)
92 {
93 d->language = languageEncoding.mid(0, 3);
94 }
95
setDescription(const String & s)96 void UnsynchronizedLyricsFrame::setDescription(const String &s)
97 {
98 d->description = s;
99 }
100
setText(const String & s)101 void UnsynchronizedLyricsFrame::setText(const String &s)
102 {
103 d->text = s;
104 }
105
106
textEncoding() const107 String::Type UnsynchronizedLyricsFrame::textEncoding() const
108 {
109 return d->textEncoding;
110 }
111
setTextEncoding(String::Type encoding)112 void UnsynchronizedLyricsFrame::setTextEncoding(String::Type encoding)
113 {
114 d->textEncoding = encoding;
115 }
116
asProperties() const117 PropertyMap UnsynchronizedLyricsFrame::asProperties() const
118 {
119 PropertyMap map;
120 String key = description().upper();
121 if(key.isEmpty() || key == "LYRICS")
122 map.insert("LYRICS", text());
123 else
124 map.insert("LYRICS:" + key, text());
125 return map;
126 }
127
findByDescription(const ID3v2::Tag * tag,const String & d)128 UnsynchronizedLyricsFrame *UnsynchronizedLyricsFrame::findByDescription(const ID3v2::Tag *tag, const String &d) // static
129 {
130 ID3v2::FrameList lyrics = tag->frameList("USLT");
131
132 for(ID3v2::FrameList::ConstIterator it = lyrics.begin(); it != lyrics.end(); ++it){
133 UnsynchronizedLyricsFrame *frame = dynamic_cast<UnsynchronizedLyricsFrame *>(*it);
134 if(frame && frame->description() == d)
135 return frame;
136 }
137 return 0;
138 }
139 ////////////////////////////////////////////////////////////////////////////////
140 // protected members
141 ////////////////////////////////////////////////////////////////////////////////
142
parseFields(const ByteVector & data)143 void UnsynchronizedLyricsFrame::parseFields(const ByteVector &data)
144 {
145 if(data.size() < 5) {
146 debug("An unsynchronized lyrics frame must contain at least 5 bytes.");
147 return;
148 }
149
150 d->textEncoding = String::Type(data[0]);
151 d->language = data.mid(1, 3);
152
153 int byteAlign
154 = d->textEncoding == String::Latin1 || d->textEncoding == String::UTF8 ? 1 : 2;
155
156 ByteVectorList l =
157 ByteVectorList::split(data.mid(4), textDelimiter(d->textEncoding), byteAlign, 2);
158
159 if(l.size() == 2) {
160 if(d->textEncoding == String::Latin1) {
161 d->description = Tag::latin1StringHandler()->parse(l.front());
162 d->text = Tag::latin1StringHandler()->parse(l.back());
163 } else {
164 d->description = String(l.front(), d->textEncoding);
165 d->text = String(l.back(), d->textEncoding);
166 }
167 }
168 }
169
renderFields() const170 ByteVector UnsynchronizedLyricsFrame::renderFields() const
171 {
172 StringList sl;
173 sl.append(d->description);
174 sl.append(d->text);
175
176 const String::Type encoding = checkTextEncoding(sl, d->textEncoding);
177
178 ByteVector v;
179
180 v.append(char(encoding));
181 v.append(d->language.size() == 3 ? d->language : "XXX");
182 v.append(d->description.data(encoding));
183 v.append(textDelimiter(encoding));
184 v.append(d->text.data(encoding));
185
186 return v;
187 }
188
189 ////////////////////////////////////////////////////////////////////////////////
190 // private members
191 ////////////////////////////////////////////////////////////////////////////////
192
UnsynchronizedLyricsFrame(const ByteVector & data,Header * h)193 UnsynchronizedLyricsFrame::UnsynchronizedLyricsFrame(const ByteVector &data, Header *h) :
194 Frame(h),
195 d(new UnsynchronizedLyricsFramePrivate())
196 {
197 parseFields(fieldData(data));
198 }
199