~njh-aelius/maxosx/musicbrainz-tags

« back to all changes in this revision

Viewing changes to Frameworks/taglib/taglib/taglib/ogg/xiphcomment.cpp

  • Committer: stephen_booth
  • Date: 2008-04-30 02:09:12 UTC
  • Revision ID: svn-v4:6b6cea13-1402-0410-9567-a7afb52bf336:trunk:1372
Update to latest taglib SVN

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 <tbytevector.h>
 
27
#include <tdebug.h>
 
28
 
 
29
#include <xiphcomment.h>
 
30
 
 
31
using namespace TagLib;
 
32
 
 
33
class Ogg::XiphComment::XiphCommentPrivate
 
34
{
 
35
public:
 
36
  FieldListMap fieldListMap;
 
37
  String vendorID;
 
38
  String commentField;
 
39
};
 
40
 
 
41
////////////////////////////////////////////////////////////////////////////////
 
42
// public members
 
43
////////////////////////////////////////////////////////////////////////////////
 
44
 
 
45
Ogg::XiphComment::XiphComment() : TagLib::Tag()
 
46
{
 
47
  d = new XiphCommentPrivate;
 
48
}
 
49
 
 
50
Ogg::XiphComment::XiphComment(const ByteVector &data) : TagLib::Tag()
 
51
{
 
52
  d = new XiphCommentPrivate;
 
53
  parse(data);
 
54
}
 
55
 
 
56
Ogg::XiphComment::~XiphComment()
 
57
{
 
58
  delete d;
 
59
}
 
60
 
 
61
String Ogg::XiphComment::title() const
 
62
{
 
63
  if(d->fieldListMap["TITLE"].isEmpty())
 
64
    return String::null;
 
65
  return d->fieldListMap["TITLE"].front();
 
66
}
 
67
 
 
68
String Ogg::XiphComment::artist() const
 
69
{
 
70
  if(d->fieldListMap["ARTIST"].isEmpty())
 
71
    return String::null;
 
72
  return d->fieldListMap["ARTIST"].front();
 
73
}
 
74
 
 
75
String Ogg::XiphComment::album() const
 
76
{
 
77
  if(d->fieldListMap["ALBUM"].isEmpty())
 
78
    return String::null;
 
79
  return d->fieldListMap["ALBUM"].front();
 
80
}
 
81
 
 
82
String Ogg::XiphComment::comment() const
 
83
{
 
84
  if(!d->fieldListMap["DESCRIPTION"].isEmpty()) {
 
85
    d->commentField = "DESCRIPTION";
 
86
    return d->fieldListMap["DESCRIPTION"].front();
 
87
  }
 
88
 
 
89
  if(!d->fieldListMap["COMMENT"].isEmpty()) {
 
90
    d->commentField = "COMMENT";
 
91
    return d->fieldListMap["COMMENT"].front();
 
92
  }
 
93
 
 
94
  return String::null;
 
95
}
 
96
 
 
97
String Ogg::XiphComment::genre() const
 
98
{
 
99
  if(d->fieldListMap["GENRE"].isEmpty())
 
100
    return String::null;
 
101
  return d->fieldListMap["GENRE"].front();
 
102
}
 
103
 
 
104
TagLib::uint Ogg::XiphComment::year() const
 
105
{
 
106
  if(d->fieldListMap["DATE"].isEmpty())
 
107
    return 0;
 
108
  return d->fieldListMap["DATE"].front().toInt();
 
109
}
 
110
 
 
111
TagLib::uint Ogg::XiphComment::track() const
 
112
{
 
113
  if(d->fieldListMap["TRACKNUMBER"].isEmpty())
 
114
    return 0;
 
115
  return d->fieldListMap["TRACKNUMBER"].front().toInt();
 
116
}
 
117
 
 
118
void Ogg::XiphComment::setTitle(const String &s)
 
119
{
 
120
  addField("TITLE", s);
 
121
}
 
122
 
 
123
void Ogg::XiphComment::setArtist(const String &s)
 
124
{
 
125
  addField("ARTIST", s);
 
126
}
 
127
 
 
128
void Ogg::XiphComment::setAlbum(const String &s)
 
129
{
 
130
  addField("ALBUM", s);
 
131
}
 
132
 
 
133
void Ogg::XiphComment::setComment(const String &s)
 
134
{
 
135
  addField(d->commentField.isEmpty() ? "DESCRIPTION" : d->commentField, s);
 
136
}
 
137
 
 
138
void Ogg::XiphComment::setGenre(const String &s)
 
139
{
 
140
  addField("GENRE", s);
 
141
}
 
142
 
 
143
void Ogg::XiphComment::setYear(uint i)
 
144
{
 
145
  if(i == 0)
 
146
    removeField("DATE");
 
147
  else
 
148
    addField("DATE", String::number(i));
 
149
}
 
150
 
 
151
void Ogg::XiphComment::setTrack(uint i)
 
152
{
 
153
  if(i == 0)
 
154
    removeField("TRACKNUMBER");
 
155
  else
 
156
    addField("TRACKNUMBER", String::number(i));
 
157
}
 
158
 
 
159
bool Ogg::XiphComment::isEmpty() const
 
160
{
 
161
  FieldListMap::ConstIterator it = d->fieldListMap.begin();
 
162
  for(; it != d->fieldListMap.end(); ++it)
 
163
    if(!(*it).second.isEmpty())
 
164
      return false;
 
165
 
 
166
  return true;
 
167
}
 
168
 
 
169
TagLib::uint Ogg::XiphComment::fieldCount() const
 
170
{
 
171
  uint count = 0;
 
172
 
 
173
  FieldListMap::ConstIterator it = d->fieldListMap.begin();
 
174
  for(; it != d->fieldListMap.end(); ++it)
 
175
    count += (*it).second.size();
 
176
 
 
177
  return count;
 
178
}
 
179
 
 
180
const Ogg::FieldListMap &Ogg::XiphComment::fieldListMap() const
 
181
{
 
182
  return d->fieldListMap;
 
183
}
 
184
 
 
185
String Ogg::XiphComment::vendorID() const
 
186
{
 
187
  return d->vendorID;
 
188
}
 
189
 
 
190
void Ogg::XiphComment::addField(const String &key, const String &value, bool replace)
 
191
{
 
192
  if(replace)
 
193
    removeField(key.upper());
 
194
 
 
195
  if(!key.isEmpty() && !value.isEmpty())
 
196
    d->fieldListMap[key.upper()].append(value);
 
197
}
 
198
 
 
199
void Ogg::XiphComment::removeField(const String &key, const String &value)
 
200
{
 
201
  if(!value.isNull()) {
 
202
    StringList::Iterator it = d->fieldListMap[key].begin();
 
203
    while(it != d->fieldListMap[key].end()) {
 
204
      if(value == *it)
 
205
        it = d->fieldListMap[key].erase(it);
 
206
      else
 
207
        it++;
 
208
    }
 
209
  }
 
210
  else
 
211
    d->fieldListMap.erase(key);
 
212
}
 
213
 
 
214
bool Ogg::XiphComment::contains(const String &key) const
 
215
{
 
216
  return d->fieldListMap.contains(key) && !d->fieldListMap[key].isEmpty();
 
217
}
 
218
 
 
219
ByteVector Ogg::XiphComment::render() const
 
220
{
 
221
  return render(true);
 
222
}
 
223
 
 
224
ByteVector Ogg::XiphComment::render(bool addFramingBit) const
 
225
{
 
226
  ByteVector data;
 
227
 
 
228
  // Add the vendor ID length and the vendor ID.  It's important to use the
 
229
  // length of the data(String::UTF8) rather than the length of the the string
 
230
  // since this is UTF8 text and there may be more characters in the data than
 
231
  // in the UTF16 string.
 
232
 
 
233
  ByteVector vendorData = d->vendorID.data(String::UTF8);
 
234
 
 
235
  data.append(ByteVector::fromUInt(vendorData.size(), false));
 
236
  data.append(vendorData);
 
237
 
 
238
  // Add the number of fields.
 
239
 
 
240
  data.append(ByteVector::fromUInt(fieldCount(), false));
 
241
 
 
242
  // Iterate over the the field lists.  Our iterator returns a
 
243
  // std::pair<String, StringList> where the first String is the field name and
 
244
  // the StringList is the values associated with that field.
 
245
 
 
246
  FieldListMap::ConstIterator it = d->fieldListMap.begin();
 
247
  for(; it != d->fieldListMap.end(); ++it) {
 
248
 
 
249
    // And now iterate over the values of the current list.
 
250
 
 
251
    String fieldName = (*it).first;
 
252
    StringList values = (*it).second;
 
253
 
 
254
    StringList::ConstIterator valuesIt = values.begin();
 
255
    for(; valuesIt != values.end(); ++valuesIt) {
 
256
      ByteVector fieldData = fieldName.data(String::UTF8);
 
257
      fieldData.append('=');
 
258
      fieldData.append((*valuesIt).data(String::UTF8));
 
259
 
 
260
      data.append(ByteVector::fromUInt(fieldData.size(), false));
 
261
      data.append(fieldData);
 
262
    }
 
263
  }
 
264
 
 
265
  // Append the "framing bit".
 
266
 
 
267
  if(addFramingBit)
 
268
    data.append(char(1));
 
269
 
 
270
  return data;
 
271
}
 
272
 
 
273
////////////////////////////////////////////////////////////////////////////////
 
274
// protected members
 
275
////////////////////////////////////////////////////////////////////////////////
 
276
 
 
277
void Ogg::XiphComment::parse(const ByteVector &data)
 
278
{
 
279
  // The first thing in the comment data is the vendor ID length, followed by a
 
280
  // UTF8 string with the vendor ID.
 
281
 
 
282
  int pos = 0;
 
283
 
 
284
  int vendorLength = data.mid(0, 4).toUInt(false);
 
285
  pos += 4;
 
286
 
 
287
  d->vendorID = String(data.mid(pos, vendorLength), String::UTF8);
 
288
  pos += vendorLength;
 
289
 
 
290
  // Next the number of fields in the comment vector.
 
291
 
 
292
  int commentFields = data.mid(pos, 4).toUInt(false);
 
293
  pos += 4;
 
294
 
 
295
  for(int i = 0; i < commentFields; i++) {
 
296
 
 
297
    // Each comment field is in the format "KEY=value" in a UTF8 string and has
 
298
    // 4 bytes before the text starts that gives the length.
 
299
 
 
300
    int commentLength = data.mid(pos, 4).toUInt(false);
 
301
    pos += 4;
 
302
 
 
303
    String comment = String(data.mid(pos, commentLength), String::UTF8);
 
304
    pos += commentLength;
 
305
 
 
306
    int commentSeparatorPosition = comment.find("=");
 
307
 
 
308
    String key = comment.substr(0, commentSeparatorPosition);
 
309
    String value = comment.substr(commentSeparatorPosition + 1);
 
310
 
 
311
    addField(key, value, false);
 
312
  }
 
313
}