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