Added TagLib (with AUTORS and COPYING files)
[someplayer] / src / taglib / ape / apeitem.cpp
1 /***************************************************************************
2     copyright            : (C) 2004 by Allan Sandfeld Jensen
3     email                : kde@carewolf.com
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 <tbytevectorlist.h>
27 #include <tdebug.h>
28
29 #include "apeitem.h"
30
31 using namespace TagLib;
32 using namespace APE;
33
34 class APE::Item::ItemPrivate
35 {
36 public:
37   ItemPrivate() : type(Text), readOnly(false) {}
38
39   Item::ItemTypes type;
40   String key;
41   ByteVector value;
42   StringList text;
43   bool readOnly;
44 };
45
46 APE::Item::Item()
47 {
48   d = new ItemPrivate;
49 }
50
51 APE::Item::Item(const String &key, const String &value)
52 {
53   d = new ItemPrivate;
54   d->key = key;
55   d->text.append(value);
56 }
57
58 APE::Item::Item(const String &key, const StringList &values)
59 {
60   d = new ItemPrivate;
61   d->key = key;
62   d->text = values;
63 }
64
65 APE::Item::Item(const Item &item)
66 {
67   d = new ItemPrivate(*item.d);
68 }
69
70 APE::Item::~Item()
71 {
72   delete d;
73 }
74
75 Item &APE::Item::operator=(const Item &item)
76 {
77   delete d;
78   d = new ItemPrivate(*item.d);
79   return *this;
80 }
81
82 void APE::Item::setReadOnly(bool readOnly)
83 {
84   d->readOnly = readOnly;
85 }
86
87 bool APE::Item::isReadOnly() const
88 {
89   return d->readOnly;
90 }
91
92 void APE::Item::setType(APE::Item::ItemTypes val)
93 {
94   d->type = val;
95 }
96
97 APE::Item::ItemTypes APE::Item::type() const
98 {
99   return d->type;
100 }
101
102 String APE::Item::key() const
103 {
104   return d->key;
105 }
106
107 ByteVector APE::Item::value() const
108 {
109   // This seems incorrect as it won't be actually rendering the value to keep it
110   // up to date.
111
112   return d->value;
113 }
114
115 void APE::Item::setKey(const String &key)
116 {
117     d->key = key;
118 }
119
120 void APE::Item::setValue(const String &value)
121 {
122     d->text = value;
123 }
124
125 void APE::Item::setValues(const StringList &value)
126 {
127     d->text = value;
128 }
129
130 void APE::Item::appendValue(const String &value)
131 {
132     d->text.append(value);
133 }
134
135 void APE::Item::appendValues(const StringList &values)
136 {
137     d->text.append(values);
138 }
139
140 int APE::Item::size() const
141 {
142   return 8 + d->key.size() + 1 + d->value.size();
143 }
144
145 StringList APE::Item::toStringList() const
146 {
147   return d->text;
148 }
149
150 StringList APE::Item::values() const
151 {
152   return d->text;
153 }
154
155 String APE::Item::toString() const
156 {
157   return isEmpty() ? String::null : d->text.front();
158 }
159
160 bool APE::Item::isEmpty() const
161 {
162   switch(d->type) {
163     case Text:
164     case Binary:
165       if(d->text.isEmpty())
166         return true;
167       if(d->text.size() == 1 && d->text.front().isEmpty())
168         return true;
169       return false;
170     case Locator:
171       return d->value.isEmpty();
172     default:
173       return false;
174   }
175 }
176
177 void APE::Item::parse(const ByteVector &data)
178 {
179   // 11 bytes is the minimum size for an APE item
180
181   if(data.size() < 11) {
182     debug("APE::Item::parse() -- no data in item");
183     return;
184   }
185
186   uint valueLength  = data.mid(0, 4).toUInt(false);
187   uint flags        = data.mid(4, 4).toUInt(false);
188
189   d->key = String(data.mid(8), String::UTF8);
190
191   d->value = data.mid(8 + d->key.size() + 1, valueLength);
192
193   setReadOnly(flags & 1);
194   setType(ItemTypes((flags >> 1) & 3));
195
196   if(int(d->type) < 2)
197     d->text = StringList(ByteVectorList::split(d->value, '\0'), String::UTF8);
198 }
199
200 ByteVector APE::Item::render() const
201 {
202   ByteVector data;
203   TagLib::uint flags = ((d->readOnly) ? 1 : 0) | (d->type << 1);
204   ByteVector value;
205
206   if(isEmpty())
207     return data;
208
209   if(d->type == Text) {
210     StringList::ConstIterator it = d->text.begin();
211
212     value.append(it->data(String::UTF8));
213     it++;
214     for(; it != d->text.end(); ++it) {
215       value.append('\0');
216       value.append(it->data(String::UTF8));
217     }
218     d->value = value;
219   }
220   else
221     value.append(d->value);
222
223   data.append(ByteVector::fromUInt(value.size(), false));
224   data.append(ByteVector::fromUInt(flags, false));
225   data.append(d->key.data(String::UTF8));
226   data.append(ByteVector('\0'));
227   data.append(value);
228
229   return data;
230 }