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 "urllinkframe.h"
30 #include "id3v2tag.h"
31 #include <tdebug.h>
32 #include <tstringlist.h>
33 #include <tpropertymap.h>
34
35 using namespace TagLib;
36 using namespace ID3v2;
37
38 class UrlLinkFrame::UrlLinkFramePrivate
39 {
40 public:
41 String url;
42 };
43
44 class UserUrlLinkFrame::UserUrlLinkFramePrivate
45 {
46 public:
UserUrlLinkFramePrivate()47 UserUrlLinkFramePrivate() : textEncoding(String::Latin1) {}
48 String::Type textEncoding;
49 String description;
50 };
51
52 ////////////////////////////////////////////////////////////////////////////////
53 // UrlLinkFrame public members
54 ////////////////////////////////////////////////////////////////////////////////
55
UrlLinkFrame(const ByteVector & data)56 UrlLinkFrame::UrlLinkFrame(const ByteVector &data) :
57 Frame(data),
58 d(new UrlLinkFramePrivate())
59 {
60 setData(data);
61 }
62
~UrlLinkFrame()63 UrlLinkFrame::~UrlLinkFrame()
64 {
65 delete d;
66 }
67
setUrl(const String & s)68 void UrlLinkFrame::setUrl(const String &s)
69 {
70 d->url = s;
71 }
72
url() const73 String UrlLinkFrame::url() const
74 {
75 return d->url;
76 }
77
setText(const String & s)78 void UrlLinkFrame::setText(const String &s)
79 {
80 setUrl(s);
81 }
82
toString() const83 String UrlLinkFrame::toString() const
84 {
85 return url();
86 }
87
asProperties() const88 PropertyMap UrlLinkFrame::asProperties() const
89 {
90 String key = frameIDToKey(frameID());
91 PropertyMap map;
92 if(key.isEmpty())
93 // unknown W*** frame - this normally shouldn't happen
94 map.unsupportedData().append(frameID());
95 else
96 map.insert(key, url());
97 return map;
98 }
99
100 ////////////////////////////////////////////////////////////////////////////////
101 // UrlLinkFrame protected members
102 ////////////////////////////////////////////////////////////////////////////////
103
parseFields(const ByteVector & data)104 void UrlLinkFrame::parseFields(const ByteVector &data)
105 {
106 d->url = String(data);
107 }
108
renderFields() const109 ByteVector UrlLinkFrame::renderFields() const
110 {
111 return d->url.data(String::Latin1);
112 }
113
UrlLinkFrame(const ByteVector & data,Header * h)114 UrlLinkFrame::UrlLinkFrame(const ByteVector &data, Header *h) :
115 Frame(h),
116 d(new UrlLinkFramePrivate())
117 {
118 parseFields(fieldData(data));
119 }
120
121 ////////////////////////////////////////////////////////////////////////////////
122 // UserUrlLinkFrame public members
123 ////////////////////////////////////////////////////////////////////////////////
124
UserUrlLinkFrame(String::Type encoding)125 UserUrlLinkFrame::UserUrlLinkFrame(String::Type encoding) :
126 UrlLinkFrame("WXXX"),
127 d(new UserUrlLinkFramePrivate())
128 {
129 d->textEncoding = encoding;
130 }
131
UserUrlLinkFrame(const ByteVector & data)132 UserUrlLinkFrame::UserUrlLinkFrame(const ByteVector &data) :
133 UrlLinkFrame(data),
134 d(new UserUrlLinkFramePrivate())
135 {
136 setData(data);
137 }
138
~UserUrlLinkFrame()139 UserUrlLinkFrame::~UserUrlLinkFrame()
140 {
141 delete d;
142 }
143
toString() const144 String UserUrlLinkFrame::toString() const
145 {
146 return "[" + description() + "] " + url();
147 }
148
textEncoding() const149 String::Type UserUrlLinkFrame::textEncoding() const
150 {
151 return d->textEncoding;
152 }
153
setTextEncoding(String::Type encoding)154 void UserUrlLinkFrame::setTextEncoding(String::Type encoding)
155 {
156 d->textEncoding = encoding;
157 }
158
description() const159 String UserUrlLinkFrame::description() const
160 {
161 return d->description;
162 }
163
setDescription(const String & s)164 void UserUrlLinkFrame::setDescription(const String &s)
165 {
166 d->description = s;
167 }
168
asProperties() const169 PropertyMap UserUrlLinkFrame::asProperties() const
170 {
171 PropertyMap map;
172 String key = description().upper();
173 if(key.isEmpty() || key == "URL")
174 map.insert("URL", url());
175 else
176 map.insert("URL:" + key, url());
177 return map;
178 }
179
find(ID3v2::Tag * tag,const String & description)180 UserUrlLinkFrame *UserUrlLinkFrame::find(ID3v2::Tag *tag, const String &description) // static
181 {
182 FrameList l = tag->frameList("WXXX");
183 for(FrameList::ConstIterator it = l.begin(); it != l.end(); ++it) {
184 UserUrlLinkFrame *f = dynamic_cast<UserUrlLinkFrame *>(*it);
185 if(f && f->description() == description)
186 return f;
187 }
188 return 0;
189 }
190
191 ////////////////////////////////////////////////////////////////////////////////
192 // UserUrlLinkFrame protected members
193 ////////////////////////////////////////////////////////////////////////////////
194
parseFields(const ByteVector & data)195 void UserUrlLinkFrame::parseFields(const ByteVector &data)
196 {
197 if(data.size() < 2) {
198 debug("A user URL link frame must contain at least 2 bytes.");
199 return;
200 }
201
202 int pos = 0;
203
204 d->textEncoding = String::Type(data[0]);
205 pos += 1;
206
207 if(d->textEncoding == String::Latin1 || d->textEncoding == String::UTF8) {
208 int offset = data.find(textDelimiter(d->textEncoding), pos);
209 if(offset < pos)
210 return;
211
212 d->description = String(data.mid(pos, offset - pos), d->textEncoding);
213 pos = offset + 1;
214 }
215 else {
216 int len = data.mid(pos).find(textDelimiter(d->textEncoding), 0, 2);
217 if(len < 0)
218 return;
219
220 d->description = String(data.mid(pos, len), d->textEncoding);
221 pos += len + 2;
222 }
223
224 setUrl(String(data.mid(pos)));
225 }
226
renderFields() const227 ByteVector UserUrlLinkFrame::renderFields() const
228 {
229 ByteVector v;
230
231 String::Type encoding = checkTextEncoding(d->description, d->textEncoding);
232
233 v.append(char(encoding));
234 v.append(d->description.data(encoding));
235 v.append(textDelimiter(encoding));
236 v.append(url().data(String::Latin1));
237
238 return v;
239 }
240
UserUrlLinkFrame(const ByteVector & data,Header * h)241 UserUrlLinkFrame::UserUrlLinkFrame(const ByteVector &data, Header *h) :
242 UrlLinkFrame(data, h),
243 d(new UserUrlLinkFramePrivate())
244 {
245 parseFields(fieldData(data));
246 }
247