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