~njh-aelius/maxosx/musicbrainz-tags

« back to all changes in this revision

Viewing changes to Frameworks/taglib/taglib/taglib/mpc/mpcfile.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) 2004 by Allan Sandfeld Jensen
 
3
    email                : kde@carewolf.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 <tstring.h>
 
28
#include <tagunion.h>
 
29
#include <tdebug.h>
 
30
 
 
31
#include "mpcfile.h"
 
32
#include "id3v1tag.h"
 
33
#include "id3v2header.h"
 
34
#include "apetag.h"
 
35
#include "apefooter.h"
 
36
 
 
37
using namespace TagLib;
 
38
 
 
39
namespace
 
40
{
 
41
  enum { APEIndex, ID3v1Index };
 
42
}
 
43
 
 
44
class MPC::File::FilePrivate
 
45
{
 
46
public:
 
47
  FilePrivate() :
 
48
    APELocation(-1),
 
49
    APESize(0),
 
50
    ID3v1Location(-1),
 
51
    ID3v2Header(0),
 
52
    ID3v2Location(-1),
 
53
    ID3v2Size(0),
 
54
    properties(0),
 
55
    scanned(false),
 
56
    hasAPE(false),
 
57
    hasID3v1(false),
 
58
    hasID3v2(false) {}
 
59
 
 
60
  ~FilePrivate()
 
61
  {
 
62
    delete ID3v2Header;
 
63
    delete properties;
 
64
  }
 
65
 
 
66
  long APELocation;
 
67
  uint APESize;
 
68
 
 
69
  long ID3v1Location;
 
70
 
 
71
  ID3v2::Header *ID3v2Header;
 
72
  long ID3v2Location;
 
73
  uint ID3v2Size;
 
74
 
 
75
  TagUnion tag;
 
76
 
 
77
  Properties *properties;
 
78
  bool scanned;
 
79
 
 
80
  // These indicate whether the file *on disk* has these tags, not if
 
81
  // this data structure does.  This is used in computing offsets.
 
82
 
 
83
  bool hasAPE;
 
84
  bool hasID3v1;
 
85
  bool hasID3v2;
 
86
};
 
87
 
 
88
////////////////////////////////////////////////////////////////////////////////
 
89
// public members
 
90
////////////////////////////////////////////////////////////////////////////////
 
91
 
 
92
MPC::File::File(FileName file, bool readProperties,
 
93
                Properties::ReadStyle propertiesStyle) : TagLib::File(file)
 
94
{
 
95
  d = new FilePrivate;
 
96
  read(readProperties, propertiesStyle);
 
97
}
 
98
 
 
99
MPC::File::~File()
 
100
{
 
101
  delete d;
 
102
}
 
103
 
 
104
TagLib::Tag *MPC::File::tag() const
 
105
{
 
106
  return &d->tag;
 
107
}
 
108
 
 
109
MPC::Properties *MPC::File::audioProperties() const
 
110
{
 
111
  return d->properties;
 
112
}
 
113
 
 
114
bool MPC::File::save()
 
115
{
 
116
  if(readOnly()) {
 
117
    debug("MPC::File::save() -- File is read only.");
 
118
    return false;
 
119
  }
 
120
 
 
121
  // Possibly strip ID3v2 tag
 
122
 
 
123
  if(d->hasID3v2 && !d->ID3v2Header) {
 
124
    removeBlock(d->ID3v2Location, d->ID3v2Size);
 
125
    d->hasID3v2 = false;
 
126
    if(d->hasID3v1)
 
127
      d->ID3v1Location -= d->ID3v2Size;
 
128
    if(d->hasAPE)
 
129
      d->APELocation -= d->ID3v2Size;
 
130
  }
 
131
 
 
132
  // Update ID3v1 tag
 
133
 
 
134
  if(ID3v1Tag()) {
 
135
    if(d->hasID3v1) {
 
136
      seek(d->ID3v1Location);
 
137
      writeBlock(ID3v1Tag()->render());
 
138
    }
 
139
    else {
 
140
      seek(0, End);
 
141
      d->ID3v1Location = tell();
 
142
      writeBlock(ID3v1Tag()->render());
 
143
      d->hasID3v1 = true;
 
144
    }
 
145
  } else
 
146
    if(d->hasID3v1) {
 
147
      removeBlock(d->ID3v1Location, 128);
 
148
      d->hasID3v1 = false;
 
149
      if(d->hasAPE) {
 
150
        if(d->APELocation > d->ID3v1Location)
 
151
          d->APELocation -= 128;
 
152
      }
 
153
    }
 
154
 
 
155
  // Update APE tag
 
156
 
 
157
  if(APETag()) {
 
158
    if(d->hasAPE)
 
159
      insert(APETag()->render(), d->APELocation, d->APESize);
 
160
    else {
 
161
      if(d->hasID3v1)  {
 
162
        insert(APETag()->render(), d->ID3v1Location, 0);
 
163
        d->APESize = APETag()->footer()->completeTagSize();
 
164
        d->hasAPE = true;
 
165
        d->APELocation = d->ID3v1Location;
 
166
        d->ID3v1Location += d->APESize;
 
167
      }
 
168
      else {
 
169
        seek(0, End);
 
170
        d->APELocation = tell();
 
171
        writeBlock(APETag()->render());
 
172
        d->APESize = APETag()->footer()->completeTagSize();
 
173
        d->hasAPE = true;
 
174
      }
 
175
    }
 
176
  }
 
177
  else
 
178
    if(d->hasAPE) {
 
179
      removeBlock(d->APELocation, d->APESize);
 
180
      d->hasAPE = false;
 
181
      if(d->hasID3v1) {
 
182
        if(d->ID3v1Location > d->APELocation)
 
183
          d->ID3v1Location -= d->APESize;
 
184
      }
 
185
    }
 
186
 
 
187
  return true;
 
188
}
 
189
 
 
190
ID3v1::Tag *MPC::File::ID3v1Tag(bool create)
 
191
{
 
192
  return d->tag.access<ID3v1::Tag>(ID3v1Index, create);
 
193
}
 
194
 
 
195
APE::Tag *MPC::File::APETag(bool create)
 
196
{
 
197
  return d->tag.access<APE::Tag>(APEIndex, create);
 
198
}
 
199
 
 
200
void MPC::File::strip(int tags)
 
201
{
 
202
  if(tags & ID3v1) {
 
203
    d->tag.set(ID3v1Index, 0);
 
204
    APETag(true);
 
205
  }
 
206
 
 
207
  if(tags & ID3v2) {
 
208
    delete d->ID3v2Header;
 
209
    d->ID3v2Header = 0;
 
210
  }
 
211
 
 
212
  if(tags & APE) {
 
213
    d->tag.set(APEIndex, 0);
 
214
 
 
215
    if(!ID3v1Tag())
 
216
      APETag(true);
 
217
  }
 
218
}
 
219
 
 
220
void MPC::File::remove(int tags)
 
221
{
 
222
  strip(tags);
 
223
}
 
224
 
 
225
 
 
226
////////////////////////////////////////////////////////////////////////////////
 
227
// private members
 
228
////////////////////////////////////////////////////////////////////////////////
 
229
 
 
230
void MPC::File::read(bool readProperties, Properties::ReadStyle /* propertiesStyle */)
 
231
{
 
232
  // Look for an ID3v1 tag
 
233
 
 
234
  d->ID3v1Location = findID3v1();
 
235
 
 
236
  if(d->ID3v1Location >= 0) {
 
237
    d->tag.set(ID3v1Index, new ID3v1::Tag(this, d->ID3v1Location));
 
238
    d->hasID3v1 = true;
 
239
  }
 
240
 
 
241
  // Look for an APE tag
 
242
 
 
243
  findAPE();
 
244
 
 
245
  d->APELocation = findAPE();
 
246
 
 
247
  if(d->APELocation >= 0) {
 
248
    d->tag.set(APEIndex, new APE::Tag(this, d->APELocation));
 
249
 
 
250
    d->APESize = APETag()->footer()->completeTagSize();
 
251
    d->APELocation = d->APELocation + APETag()->footer()->size() - d->APESize;
 
252
    d->hasAPE = true;
 
253
  }
 
254
 
 
255
  if(!d->hasID3v1)
 
256
    APETag(true);
 
257
 
 
258
  // Look for and skip an ID3v2 tag
 
259
 
 
260
  d->ID3v2Location = findID3v2();
 
261
 
 
262
  if(d->ID3v2Location >= 0) {
 
263
    seek(d->ID3v2Location);
 
264
    d->ID3v2Header = new ID3v2::Header(readBlock(ID3v2::Header::size()));
 
265
    d->ID3v2Size = d->ID3v2Header->completeTagSize();
 
266
    d->hasID3v2 = true;
 
267
  }
 
268
 
 
269
  if(d->hasID3v2)
 
270
    seek(d->ID3v2Location + d->ID3v2Size);
 
271
  else
 
272
    seek(0);
 
273
 
 
274
  // Look for MPC metadata
 
275
 
 
276
  if(readProperties) {
 
277
    d->properties = new Properties(readBlock(MPC::HeaderSize),
 
278
                                   length() - d->ID3v2Size - d->APESize);
 
279
  }
 
280
}
 
281
 
 
282
long MPC::File::findAPE()
 
283
{
 
284
  if(!isValid())
 
285
    return -1;
 
286
 
 
287
  if(d->hasID3v1)
 
288
    seek(-160, End);
 
289
  else
 
290
    seek(-32, End);
 
291
 
 
292
  long p = tell();
 
293
 
 
294
  if(readBlock(8) == APE::Tag::fileIdentifier())
 
295
    return p;
 
296
 
 
297
  return -1;
 
298
}
 
299
 
 
300
long MPC::File::findID3v1()
 
301
{
 
302
  if(!isValid())
 
303
    return -1;
 
304
 
 
305
  seek(-128, End);
 
306
  long p = tell();
 
307
 
 
308
  if(readBlock(3) == ID3v1::Tag::fileIdentifier())
 
309
    return p;
 
310
 
 
311
  return -1;
 
312
}
 
313
 
 
314
long MPC::File::findID3v2()
 
315
{
 
316
  if(!isValid())
 
317
    return -1;
 
318
 
 
319
  seek(0);
 
320
 
 
321
  if(readBlock(3) == ID3v2::Header::fileIdentifier())
 
322
    return 0;
 
323
 
 
324
  return -1;
 
325
}