~ubuntu-branches/ubuntu/utopic/libjaudiotagger-java/utopic

« back to all changes in this revision

Viewing changes to org/jaudiotagger/tag/id3/ID3v24Tag.java

  • Committer: Bazaar Package Importer
  • Author(s): Varun Hiremath, Damien Raude-Morvan, Varun Hiremath
  • Date: 2009-04-01 19:17:56 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20090401191756-bygniim270guy7o1
Tags: 1.0.9-1
[ Damien Raude-Morvan ]
* New upstream release
* debian/watch: Use java.net repository (which contains new releases!)
* debian/control:
  - Build-Depends on default-jdk-builddep
  - Bump Standards-Version to 3.8.1 (no changes needed)
  - Change section to "java"
* debian/rules: use default-java as JAVA_HOME
* debina/orig-tar.{sh|excludes}: strip audio and others binary files from ZIP
* debian/build.xml:
  - compile with "nowarn" to keep build log readable
  - exclude LogFormatter from build (use com.sun classes)
* debian/ant.properties: new source directory is "src" in orig.tar.gz
* Add myself as Uploaders

[ Varun Hiremath ]
* Accept changes made by Damien Raude-Morvan (Closes: #522130)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 *  MusicTag Copyright (C)2003,2004
3
 
 *
4
 
 *  This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser
5
 
 *  General Public  License as published by the Free Software Foundation; either version 2.1 of the License,
6
 
 *  or (at your option) any later version.
7
 
 *
8
 
 *  This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
9
 
 *  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10
 
 *  See the GNU Lesser General Public License for more details.
11
 
 *
12
 
 *  You should have received a copy of the GNU Lesser General Public License along with this library; if not,
13
 
 *  you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software
14
 
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15
 
 */
16
 
package org.jaudiotagger.tag.id3;
17
 
 
18
 
import org.jaudiotagger.FileConstants;
19
 
import org.jaudiotagger.audio.mp3.MP3File;
20
 
import org.jaudiotagger.tag.*;
21
 
import org.jaudiotagger.tag.id3.framebody.*;
22
 
import org.jaudiotagger.tag.id3.valuepair.GenreTypes;
23
 
import org.jaudiotagger.tag.lyrics3.AbstractLyrics3;
24
 
import org.jaudiotagger.tag.lyrics3.Lyrics3v2;
25
 
import org.jaudiotagger.tag.lyrics3.Lyrics3v2Field;
26
 
 
27
 
import java.io.File;
28
 
import java.io.IOException;
29
 
import java.io.RandomAccessFile;
30
 
import java.io.UnsupportedEncodingException;
31
 
import java.nio.ByteBuffer;
32
 
import java.nio.channels.FileChannel;
33
 
import java.nio.channels.WritableByteChannel;
34
 
import java.util.*;
35
 
import java.util.logging.Level;
36
 
 
37
 
/**
38
 
 * Represents an ID3v2.4 tag.
39
 
 *
40
 
 * @author : Paul Taylor
41
 
 * @author : Eric Farng
42
 
 * @version $Id: ID3v24Tag.java,v 1.39 2007/12/03 13:28:04 paultaylor Exp $
43
 
 */
44
 
public class ID3v24Tag extends AbstractID3v2Tag
45
 
{
46
 
    protected static final String TYPE_FOOTER = "footer";
47
 
    protected static final String TYPE_IMAGEENCODINGRESTRICTION = "imageEncodingRestriction";
48
 
    protected static final String TYPE_IMAGESIZERESTRICTION = "imageSizeRestriction";
49
 
    protected static final String TYPE_TAGRESTRICTION = "tagRestriction";
50
 
    protected static final String TYPE_TAGSIZERESTRICTION = "tagSizeRestriction";
51
 
    protected static final String TYPE_TEXTENCODINGRESTRICTION = "textEncodingRestriction";
52
 
    protected static final String TYPE_TEXTFIELDSIZERESTRICTION = "textFieldSizeRestriction";
53
 
    protected static final String TYPE_UPDATETAG = "updateTag";
54
 
    protected static final String TYPE_CRCDATA = "crcdata";
55
 
    protected static final String TYPE_EXPERIMENTAL = "experimental";
56
 
    protected static final String TYPE_EXTENDED = "extended";
57
 
    protected static final String TYPE_PADDINGSIZE = "paddingsize";
58
 
    protected static final String TYPE_UNSYNCHRONISATION = "unsyncronisation";
59
 
 
60
 
 
61
 
    protected static int TAG_EXT_HEADER_LENGTH = 6;
62
 
    protected static int TAG_EXT_HEADER_UPDATE_LENGTH = 1;
63
 
    protected static int TAG_EXT_HEADER_CRC_LENGTH = 6;
64
 
    protected static int TAG_EXT_HEADER_RESTRICTION_LENGTH = 2;
65
 
    protected static int TAG_EXT_HEADER_CRC_DATA_LENGTH = 5;
66
 
    protected static int TAG_EXT_HEADER_RESTRICTION_DATA_LENGTH = 1;
67
 
    protected static int TAG_EXT_NUMBER_BYTES_DATA_LENGTH = 1;
68
 
 
69
 
    /**
70
 
     * ID3v2.4 Header bit mask
71
 
     */
72
 
    public static final int MASK_V24_UNSYNCHRONIZATION = FileConstants.BIT7;
73
 
 
74
 
    /**
75
 
     * ID3v2.4 Header bit mask
76
 
     */
77
 
    public static final int MASK_V24_EXTENDED_HEADER = FileConstants.BIT6;
78
 
 
79
 
    /**
80
 
     * ID3v2.4 Header bit mask
81
 
     */
82
 
    public static final int MASK_V24_EXPERIMENTAL = FileConstants.BIT5;
83
 
 
84
 
    /**
85
 
     * ID3v2.4 Header bit mask
86
 
     */
87
 
    public static final int MASK_V24_FOOTER_PRESENT = FileConstants.BIT4;
88
 
 
89
 
    /**
90
 
     * ID3v2.4 Extended header bit mask
91
 
     */
92
 
    public static final int MASK_V24_TAG_UPDATE = FileConstants.BIT6;
93
 
 
94
 
    /**
95
 
     * ID3v2.4 Extended header bit mask
96
 
     */
97
 
    public static final int MASK_V24_CRC_DATA_PRESENT = FileConstants.BIT5;
98
 
 
99
 
    /**
100
 
     * ID3v2.4 Extended header bit mask
101
 
     */
102
 
    public static final int MASK_V24_TAG_RESTRICTIONS = FileConstants.BIT4;
103
 
 
104
 
    /**
105
 
     * ID3v2.4 Extended header bit mask
106
 
     */
107
 
    public static final int MASK_V24_TAG_SIZE_RESTRICTIONS = (byte) FileConstants.BIT7 | FileConstants.BIT6;
108
 
 
109
 
    /**
110
 
     * ID3v2.4 Extended header bit mask
111
 
     */
112
 
    public static final int MASK_V24_TEXT_ENCODING_RESTRICTIONS = FileConstants.BIT5;
113
 
 
114
 
    /**
115
 
     * ID3v2.4 Extended header bit mask
116
 
     */
117
 
    public static final int MASK_V24_TEXT_FIELD_SIZE_RESTRICTIONS = FileConstants.BIT4 | FileConstants.BIT3;
118
 
 
119
 
    /**
120
 
     * ID3v2.4 Extended header bit mask
121
 
     */
122
 
    public static final int MASK_V24_IMAGE_ENCODING = FileConstants.BIT2;
123
 
 
124
 
    /**
125
 
     * ID3v2.4 Extended header bit mask
126
 
     */
127
 
    public static final int MASK_V24_IMAGE_SIZE_RESTRICTIONS = FileConstants.BIT2 | FileConstants.BIT1;
128
 
 
129
 
    /**
130
 
     * ID3v2.4 Header Footer are the same as the header flags. WHY?!?! move the
131
 
     * flags from thier position in 2.3??????????
132
 
     */
133
 
    /**
134
 
     * ID3v2.4 Header Footer bit mask
135
 
     */
136
 
    public static final int MASK_V24_TAG_ALTER_PRESERVATION = FileConstants.BIT6;
137
 
 
138
 
    /**
139
 
     * ID3v2.4 Header Footer bit mask
140
 
     */
141
 
    public static final int MASK_V24_FILE_ALTER_PRESERVATION = FileConstants.BIT5;
142
 
 
143
 
    /**
144
 
     * ID3v2.4 Header Footer bit mask
145
 
     */
146
 
    public static final int MASK_V24_READ_ONLY = FileConstants.BIT4;
147
 
 
148
 
    /**
149
 
     * ID3v2.4 Header Footer bit mask
150
 
     */
151
 
    public static final int MASK_V24_GROUPING_IDENTITY = FileConstants.BIT6;
152
 
 
153
 
    /**
154
 
     * ID3v2.4 Header Footer bit mask
155
 
     */
156
 
    public static final int MASK_V24_COMPRESSION = FileConstants.BIT4;
157
 
 
158
 
    /**
159
 
     * ID3v2.4 Header Footer bit mask
160
 
     */
161
 
    public static final int MASK_V24_ENCRYPTION = FileConstants.BIT3;
162
 
 
163
 
    /**
164
 
     * ID3v2.4 Header Footer bit mask
165
 
     */
166
 
    public static final int MASK_V24_FRAME_UNSYNCHRONIZATION = FileConstants.BIT2;
167
 
 
168
 
    /**
169
 
     * ID3v2.4 Header Footer bit mask
170
 
     */
171
 
    public static final int MASK_V24_DATA_LENGTH_INDICATOR = FileConstants.BIT1;
172
 
 
173
 
    /**
174
 
     * CRC Checksum calculated
175
 
     */
176
 
    protected boolean crcDataFlag = false;
177
 
 
178
 
    /**
179
 
     * Experiemntal tag
180
 
     */
181
 
    protected boolean experimental = false;
182
 
 
183
 
    /**
184
 
     * Contains extended header
185
 
     */
186
 
    protected boolean extended = false;
187
 
 
188
 
    /**
189
 
     * All frames in the tag uses unsynchronisation
190
 
     */
191
 
    protected boolean unsynchronization = false;
192
 
 
193
 
    /**
194
 
     * CRC Checksum
195
 
     */
196
 
    protected int crcData = 0;
197
 
 
198
 
 
199
 
    /**
200
 
     * Contains a footer
201
 
     */
202
 
    protected boolean footer = false;
203
 
 
204
 
    /**
205
 
     * Tag is an update
206
 
     */
207
 
    protected boolean updateTag = false;
208
 
 
209
 
    /**
210
 
     * Tag has restrictions
211
 
     */
212
 
    protected boolean tagRestriction = false;
213
 
 
214
 
    /**
215
 
     *
216
 
     */
217
 
    protected byte imageEncodingRestriction = 0;
218
 
 
219
 
    /**
220
 
     *
221
 
     */
222
 
    protected byte imageSizeRestriction = 0;
223
 
 
224
 
    /**
225
 
     *
226
 
     */
227
 
    protected byte tagSizeRestriction = 0;
228
 
 
229
 
    /**
230
 
     *
231
 
     */
232
 
    protected byte textEncodingRestriction = 0;
233
 
 
234
 
    /**
235
 
     * Tag padding
236
 
     */
237
 
    protected int paddingSize = 0;
238
 
 
239
 
 
240
 
    /**
241
 
     *
242
 
     */
243
 
    protected byte textFieldSizeRestriction = 0;
244
 
 
245
 
    public static final byte RELEASE = 2;
246
 
    public static final byte MAJOR_VERSION = 4;
247
 
    public static final byte REVISION = 0;
248
 
 
249
 
    /**
250
 
     * Retrieve the Release
251
 
     */
252
 
    public byte getRelease()
253
 
    {
254
 
        return RELEASE;
255
 
    }
256
 
 
257
 
    /**
258
 
     * Retrieve the Major Version
259
 
     */
260
 
    public byte getMajorVersion()
261
 
    {
262
 
        return MAJOR_VERSION;
263
 
    }
264
 
 
265
 
    /**
266
 
     * Retrieve the Revision
267
 
     */
268
 
    public byte getRevision()
269
 
    {
270
 
        return REVISION;
271
 
    }
272
 
 
273
 
 
274
 
    /**
275
 
     * Creates a new empty ID3v2_4 datatype.
276
 
     */
277
 
    public ID3v24Tag()
278
 
    {
279
 
        frameMap = new LinkedHashMap();
280
 
    }
281
 
 
282
 
    /**
283
 
     * Copy primitives applicable to v2.4, this is used when cloning a v2.4 datatype
284
 
     * and other objects such as v2.3 so need to check instanceof
285
 
     */
286
 
    protected void copyPrimitives(AbstractID3v2Tag copyObj)
287
 
    {
288
 
        logger.info("Copying primitives");
289
 
        super.copyPrimitives(copyObj);
290
 
 
291
 
        if (copyObj instanceof ID3v24Tag)
292
 
        {
293
 
            ID3v24Tag copyObject = (ID3v24Tag) copyObj;
294
 
            this.footer = copyObject.footer;
295
 
            this.tagRestriction = copyObject.tagRestriction;
296
 
            this.updateTag = copyObject.updateTag;
297
 
            this.imageEncodingRestriction = copyObject.imageEncodingRestriction;
298
 
            this.imageSizeRestriction = copyObject.imageSizeRestriction;
299
 
            this.tagSizeRestriction = copyObject.tagSizeRestriction;
300
 
            this.textEncodingRestriction = copyObject.textEncodingRestriction;
301
 
            this.textFieldSizeRestriction = copyObject.textFieldSizeRestriction;
302
 
        }
303
 
    }
304
 
 
305
 
    /**
306
 
     * Copy frames from one tag into a v2.4 tag
307
 
     */
308
 
    protected void copyFrames(AbstractID3v2Tag copyObject)
309
 
    {
310
 
        logger.info("Copying Frames,there are:" + copyObject.frameMap.keySet().size() + " different types");
311
 
        frameMap = new LinkedHashMap();
312
 
        //Copy Frames that are a valid 2.4 type
313
 
        Iterator iterator = copyObject.frameMap.keySet().iterator();
314
 
        AbstractID3v2Frame frame;
315
 
        ID3v24Frame newFrame = null;
316
 
        while (iterator.hasNext())
317
 
        {
318
 
            String id = (String) iterator.next();
319
 
            Object o = copyObject.frameMap.get(id);
320
 
            //SingleFrames
321
 
            if (o instanceof AbstractID3v2Frame)
322
 
            {
323
 
                frame = (AbstractID3v2Frame) o;
324
 
                try
325
 
                {
326
 
                    newFrame = new ID3v24Frame(frame);
327
 
                    logger.info("Adding Frame:" + newFrame.getIdentifier());
328
 
                    copyFrameIntoMap(newFrame.getIdentifier(), newFrame);
329
 
                }
330
 
                catch (InvalidFrameException ife)
331
 
                {
332
 
                    logger.log(Level.SEVERE, "Unable to convert frame:" + frame.getIdentifier(), ife);
333
 
                }
334
 
            }
335
 
            //MultiFrames
336
 
            else if (o instanceof ArrayList)
337
 
            {
338
 
                ArrayList multiFrame = new ArrayList();
339
 
                for (ListIterator li = ((ArrayList) o).listIterator(); li.hasNext();)
340
 
                {
341
 
                    frame = (AbstractID3v2Frame) li.next();
342
 
                    try
343
 
                    {
344
 
                        newFrame = new ID3v24Frame(frame);
345
 
                        multiFrame.add(newFrame);
346
 
                    }
347
 
                    catch (InvalidFrameException ife)
348
 
                    {
349
 
                        logger.log(Level.SEVERE, "Unable to convert frame:" + frame.getIdentifier());
350
 
                    }
351
 
                }
352
 
                if (newFrame != null)
353
 
                {
354
 
                    logger.finest("Adding multi frame list to map:" + newFrame.getIdentifier());
355
 
                    frameMap.put(newFrame.getIdentifier(), multiFrame);
356
 
                }
357
 
            }
358
 
        }
359
 
    }
360
 
 
361
 
    /**
362
 
     * Copy Constructor, creates a new ID3v2_4 Tag based on another ID3v2_4 Tag
363
 
     */
364
 
    public ID3v24Tag(ID3v24Tag copyObject)
365
 
    {
366
 
        logger.info("Creating tag from another tag of same type");
367
 
        copyPrimitives(copyObject);
368
 
        copyFrames(copyObject);
369
 
    }
370
 
 
371
 
    /**
372
 
     * Creates a new ID3v2_4 datatype based on another (non 2.4) tag
373
 
     *
374
 
     * @param mp3tag
375
 
     */
376
 
    public ID3v24Tag(AbstractTag mp3tag)
377
 
    {
378
 
        logger.info("Creating tag from a tag of a different version");
379
 
        frameMap = new LinkedHashMap();
380
 
        if (mp3tag != null)
381
 
        {
382
 
            //Should use simpler copy constructor
383
 
            if ((mp3tag instanceof ID3v24Tag == true))
384
 
            {
385
 
                throw new UnsupportedOperationException("Copy Constructor not called. Please type cast the argument");
386
 
            }
387
 
            /* If we get a tag, we want to convert to id3v2_4
388
 
             * both id3v1 and lyrics3 convert to this type
389
 
             * id3v1 needs to convert to id3v2_4 before converting to lyrics3
390
 
             */
391
 
            else if (mp3tag instanceof AbstractID3v2Tag)
392
 
            {
393
 
                copyPrimitives((AbstractID3v2Tag) mp3tag);
394
 
                copyFrames((AbstractID3v2Tag) mp3tag);
395
 
            }
396
 
            //IDv1
397
 
            else if (mp3tag instanceof ID3v1Tag)
398
 
            {
399
 
                // convert id3v1 tags.
400
 
                ID3v1Tag id3tag = (ID3v1Tag) mp3tag;
401
 
                ID3v24Frame newFrame;
402
 
                AbstractID3v2FrameBody newBody;
403
 
                if (id3tag.title.length() > 0)
404
 
                {
405
 
                    newBody = new FrameBodyTIT2((byte) 0, id3tag.title);
406
 
                    newFrame = new ID3v24Frame(ID3v24Frames.FRAME_ID_TITLE);
407
 
                    newFrame.setBody(newBody);
408
 
                    frameMap.put(newFrame.getIdentifier(), newFrame);
409
 
                }
410
 
                if (id3tag.artist.length() > 0)
411
 
                {
412
 
                    newBody = new FrameBodyTPE1((byte) 0, id3tag.artist);
413
 
                    newFrame = new ID3v24Frame(ID3v24Frames.FRAME_ID_ARTIST);
414
 
                    newFrame.setBody(newBody);
415
 
                    frameMap.put(newFrame.getIdentifier(), newFrame);
416
 
                }
417
 
                if (id3tag.album.length() > 0)
418
 
                {
419
 
                    newBody = new FrameBodyTALB((byte) 0, id3tag.album);
420
 
                    newFrame = new ID3v24Frame(ID3v24Frames.FRAME_ID_ALBUM);
421
 
                    newFrame.setBody(newBody);
422
 
                    frameMap.put(newFrame.getIdentifier(), newFrame);
423
 
                }
424
 
                if (id3tag.year.length() > 0)
425
 
                {
426
 
                    newBody = new FrameBodyTDRC((byte) 0, id3tag.year);
427
 
                    newFrame = new ID3v24Frame(ID3v24Frames.FRAME_ID_YEAR);
428
 
                    newFrame.setBody(newBody);
429
 
                    frameMap.put(newFrame.getIdentifier(), newFrame);
430
 
                }
431
 
                if (id3tag.comment.length() > 0)
432
 
                {
433
 
                    newBody = new FrameBodyCOMM((byte) 0, "ENG", "", id3tag.comment);
434
 
                    newFrame = new ID3v24Frame(ID3v24Frames.FRAME_ID_COMMENT);
435
 
                    newFrame.setBody(newBody);
436
 
                    frameMap.put(newFrame.getIdentifier(), newFrame);
437
 
                }
438
 
                if (((id3tag.genre & ID3v1Tag.BYTE_TO_UNSIGNED) >= 0) && ((id3tag.genre & ID3v1Tag.BYTE_TO_UNSIGNED) != ID3v1Tag.BYTE_TO_UNSIGNED))
439
 
                {
440
 
                    Integer genreId = id3tag.genre & ID3v1Tag.BYTE_TO_UNSIGNED;
441
 
                    String genre = "(" + genreId + ") " + GenreTypes.getInstanceOf().getValueForId(genreId);
442
 
 
443
 
                    newBody = new FrameBodyTCON((byte) 0, genre);
444
 
                    newFrame = new ID3v24Frame(ID3v24Frames.FRAME_ID_GENRE);
445
 
                    newFrame.setBody(newBody);
446
 
                    frameMap.put(newFrame.getIdentifier(), newFrame);
447
 
                }
448
 
                if (mp3tag instanceof ID3v11Tag)
449
 
                {
450
 
                    ID3v11Tag id3tag2 = (ID3v11Tag) mp3tag;
451
 
                    if (id3tag2.track > 0)
452
 
                    {
453
 
                        newBody = new FrameBodyTRCK((byte) 0, Byte.toString(id3tag2.track));
454
 
                        newFrame = new ID3v24Frame(ID3v24Frames.FRAME_ID_TRACK);
455
 
                        newFrame.setBody(newBody);
456
 
                        frameMap.put(newFrame.getIdentifier(), newFrame);
457
 
                    }
458
 
                }
459
 
            }
460
 
            //Lyrics 3
461
 
            else if (mp3tag instanceof AbstractLyrics3)
462
 
            {
463
 
                //Put the conversion stuff in the individual frame code.
464
 
                Lyrics3v2 lyric;
465
 
                if (mp3tag instanceof Lyrics3v2)
466
 
                {
467
 
                    lyric = new Lyrics3v2((Lyrics3v2) mp3tag);
468
 
                }
469
 
                else
470
 
                {
471
 
                    lyric = new Lyrics3v2(mp3tag);
472
 
                }
473
 
                Iterator iterator = lyric.iterator();
474
 
                Lyrics3v2Field field;
475
 
                ID3v24Frame newFrame;
476
 
                while (iterator.hasNext())
477
 
                {
478
 
                    try
479
 
                    {
480
 
                        field = (Lyrics3v2Field) iterator.next();
481
 
                        newFrame = new ID3v24Frame(field);
482
 
                        frameMap.put(newFrame.getIdentifier(), newFrame);
483
 
                    }
484
 
                    catch (InvalidTagException ex)
485
 
                    {
486
 
                        logger.warning("Unable to convert Lyrics3 to v24 Frame:Frame Identifier");
487
 
                    }
488
 
                }
489
 
            }
490
 
        }
491
 
    }
492
 
 
493
 
    /**
494
 
     * Creates a new ID3v2_4 datatype.
495
 
     *
496
 
     * @param buffer
497
 
     * @param loggingFilename
498
 
     * @throws TagException
499
 
     */
500
 
    public ID3v24Tag(ByteBuffer buffer, String loggingFilename) throws TagException
501
 
    {
502
 
        frameMap = new LinkedHashMap();
503
 
        setLoggingFilename(loggingFilename);
504
 
        this.read(buffer);
505
 
    }
506
 
 
507
 
 
508
 
    /**
509
 
     * Creates a new ID3v2_4 datatype.
510
 
     *
511
 
     * @param buffer
512
 
     * @throws TagException
513
 
     * @deprecated use {@link #ID3v24Tag(ByteBuffer,String)} instead
514
 
     */
515
 
    public ID3v24Tag(ByteBuffer buffer) throws TagException
516
 
    {
517
 
        this(buffer, "");
518
 
    }
519
 
 
520
 
    /**
521
 
     * @return identifier
522
 
     */
523
 
    public String getIdentifier()
524
 
    {
525
 
        return "ID3v2.40";
526
 
    }
527
 
 
528
 
    /**
529
 
     * Return tag size based upon the sizes of the frames rather than the physical
530
 
     * no of bytes between start of ID3Tag and start of Audio Data.
531
 
     *
532
 
     * @return size
533
 
     */
534
 
    public int getSize()
535
 
    {
536
 
        int size = TAG_HEADER_LENGTH;
537
 
        if (extended)
538
 
        {
539
 
            size += this.TAG_EXT_HEADER_LENGTH;
540
 
            if (updateTag)
541
 
            {
542
 
                size += this.TAG_EXT_HEADER_UPDATE_LENGTH;
543
 
            }
544
 
            if (crcDataFlag)
545
 
            {
546
 
                size += this.TAG_EXT_HEADER_CRC_LENGTH;
547
 
            }
548
 
            if (tagRestriction)
549
 
            {
550
 
                size += this.TAG_EXT_HEADER_RESTRICTION_LENGTH;
551
 
            }
552
 
        }
553
 
        size += super.getSize();
554
 
        logger.finer("Tag Size is" + size);
555
 
        return size;
556
 
    }
557
 
 
558
 
    /**
559
 
     * @param obj
560
 
     * @return equality
561
 
     */
562
 
    public boolean equals(Object obj)
563
 
    {
564
 
        if ((obj instanceof ID3v24Tag) == false)
565
 
        {
566
 
            return false;
567
 
        }
568
 
        ID3v24Tag object = (ID3v24Tag) obj;
569
 
        if (this.footer != object.footer)
570
 
        {
571
 
            return false;
572
 
        }
573
 
        if (this.imageEncodingRestriction != object.imageEncodingRestriction)
574
 
        {
575
 
            return false;
576
 
        }
577
 
        if (this.imageSizeRestriction != object.imageSizeRestriction)
578
 
        {
579
 
            return false;
580
 
        }
581
 
        if (this.tagRestriction != object.tagRestriction)
582
 
        {
583
 
            return false;
584
 
        }
585
 
        if (this.tagSizeRestriction != object.tagSizeRestriction)
586
 
        {
587
 
            return false;
588
 
        }
589
 
        if (this.textEncodingRestriction != object.textEncodingRestriction)
590
 
        {
591
 
            return false;
592
 
        }
593
 
        if (this.textFieldSizeRestriction != object.textFieldSizeRestriction)
594
 
        {
595
 
            return false;
596
 
        }
597
 
        if (this.updateTag != object.updateTag)
598
 
        {
599
 
            return false;
600
 
        }
601
 
        return super.equals(obj);
602
 
    }
603
 
 
604
 
    /**
605
 
     * Read Tag from Specified file.
606
 
     * Read tag header, delegate reading of frames to readFrames()
607
 
     *
608
 
     * @param byteBuffer to read the tag from
609
 
     * @throws TagException
610
 
     * @throws TagNotFoundException
611
 
     * @throws InvalidTagException
612
 
     */
613
 
    public void read(ByteBuffer byteBuffer) throws TagException
614
 
    {
615
 
        int size;
616
 
        byte[] buffer;
617
 
        if (seek(byteBuffer) == false)
618
 
        {
619
 
            throw new TagNotFoundException(getLoggingFilename() + ":" + getIdentifier() + " tag not found");
620
 
        }
621
 
        //Flags
622
 
        byte flags = byteBuffer.get();
623
 
        unsynchronization = (flags & MASK_V24_UNSYNCHRONIZATION) != 0;
624
 
        extended = (flags & MASK_V24_EXTENDED_HEADER) != 0;
625
 
        experimental = (flags & MASK_V24_EXPERIMENTAL) != 0;
626
 
        footer = (flags & MASK_V24_FOOTER_PRESENT) != 0;
627
 
 
628
 
        if (isUnsynchronization())
629
 
        {
630
 
            logger.warning(getLoggingFilename() + ":" + "ID3v24 Tag is unsynchronized");
631
 
        }
632
 
 
633
 
        if (extended)
634
 
        {
635
 
            logger.warning(getLoggingFilename() + ":" + "ID3v24 Tag is extended");
636
 
        }
637
 
 
638
 
        if (experimental)
639
 
        {
640
 
            logger.warning(getLoggingFilename() + ":" + "ID3v24 Tag is experimental");
641
 
        }
642
 
 
643
 
        if (footer)
644
 
        {
645
 
            logger.warning(getLoggingFilename() + ":" + "ID3v24 Tag has footer");
646
 
        }
647
 
 
648
 
        // Read the size, this is size of tag apart from tag header
649
 
        size = ID3SyncSafeInteger.bufferToValue(byteBuffer);
650
 
        logger.info(getLoggingFilename() + ":" + "Reading tag from file size set in header is" + size);
651
 
        if (extended)
652
 
        {
653
 
            // int is 4 bytes.
654
 
            int extendedHeaderSize = byteBuffer.getInt();
655
 
            // the extended header must be atleast 6 bytes
656
 
            if (extendedHeaderSize <= TAG_EXT_HEADER_LENGTH)
657
 
            {
658
 
                throw new InvalidTagException(getLoggingFilename() + ":" + "Invalid Extended Header Size.");
659
 
            }
660
 
            //Number of bytes
661
 
            byteBuffer.get();
662
 
            // Read the extended flag bytes
663
 
            byte extFlag = byteBuffer.get();
664
 
            updateTag = (extFlag & MASK_V24_TAG_UPDATE) != 0;
665
 
            crcDataFlag = (extFlag & MASK_V24_CRC_DATA_PRESENT) != 0;
666
 
            tagRestriction = (extFlag & MASK_V24_TAG_RESTRICTIONS) != 0;
667
 
            // read the length byte if the flag is set
668
 
            // this tag should always be zero but just in case
669
 
            // read this information.
670
 
            if (updateTag == true)
671
 
            {
672
 
                byteBuffer.get();
673
 
            }
674
 
            if (crcDataFlag == true)
675
 
            {
676
 
                // the CRC has a variable length
677
 
                byteBuffer.get();
678
 
                buffer = new byte[TAG_EXT_HEADER_CRC_DATA_LENGTH];
679
 
                byteBuffer.get(buffer, 0, TAG_EXT_HEADER_CRC_DATA_LENGTH);
680
 
                crcData = 0;
681
 
                for (int i = 0; i < TAG_EXT_HEADER_CRC_DATA_LENGTH; i++)
682
 
                {
683
 
                    crcData <<= 8;
684
 
                    crcData += buffer[i];
685
 
                }
686
 
            }
687
 
            if (tagRestriction == true)
688
 
            {
689
 
                byteBuffer.get();
690
 
                buffer = new byte[1];
691
 
                byteBuffer.get(buffer, 0, 1);
692
 
                tagSizeRestriction = (byte) ((buffer[0] & MASK_V24_TAG_SIZE_RESTRICTIONS) >> 6);
693
 
                textEncodingRestriction = (byte) ((buffer[0] & MASK_V24_TEXT_ENCODING_RESTRICTIONS) >> 5);
694
 
                textFieldSizeRestriction = (byte) ((buffer[0] & MASK_V24_TEXT_FIELD_SIZE_RESTRICTIONS) >> 3);
695
 
                imageEncodingRestriction = (byte) ((buffer[0] & MASK_V24_IMAGE_ENCODING) >> 2);
696
 
                imageSizeRestriction = (byte) (buffer[0] & MASK_V24_IMAGE_SIZE_RESTRICTIONS);
697
 
            }
698
 
        }
699
 
        //Note if there was an extended header the size value has padding taken
700
 
        //off so we dont search it.
701
 
        readFrames(byteBuffer, size);
702
 
 
703
 
    }
704
 
 
705
 
    /**
706
 
     * Read frames from tag
707
 
     */
708
 
    protected void readFrames(ByteBuffer byteBuffer, int size)
709
 
    {
710
 
        logger.finest(getLoggingFilename() + ":" + "Start of frame body at" + byteBuffer.position());
711
 
        //Now start looking for frames
712
 
        ID3v24Frame next;
713
 
        frameMap = new LinkedHashMap();
714
 
        //Read the size from the Tag Header
715
 
        this.fileReadSize = size;
716
 
        // Read the frames until got to upto the size as specified in header
717
 
        logger.finest(getLoggingFilename() + ":" + "Start of frame body at:" + byteBuffer.position() + ",frames data size is:" + size);
718
 
        while (byteBuffer.position() <= size)
719
 
        {
720
 
            String id;
721
 
            try
722
 
            {
723
 
                //Read Frame
724
 
                logger.finest(getLoggingFilename() + ":" + "looking for next frame at:" + byteBuffer.position());
725
 
                next = new ID3v24Frame(byteBuffer, getLoggingFilename());
726
 
                id = next.getIdentifier();
727
 
                loadFrameIntoMap(id, next);
728
 
            }
729
 
            //Found Empty Frame
730
 
            catch (EmptyFrameException ex)
731
 
            {
732
 
                logger.warning(getLoggingFilename() + ":" + "Empty Frame:" + ex.getMessage());
733
 
                this.emptyFrameBytes += TAG_HEADER_LENGTH;
734
 
            }
735
 
            catch (InvalidFrameIdentifierException ifie)
736
 
            {
737
 
                logger.info(getLoggingFilename() + ":" + "Invalid Frame Identifier:" + ifie.getMessage());
738
 
                this.invalidFrameBytes++;
739
 
                //Dont try and find any more frames
740
 
                break;
741
 
            }
742
 
            //Problem trying to find frame
743
 
            catch (InvalidFrameException ife)
744
 
            {
745
 
                logger.warning(getLoggingFilename() + ":" + "Invalid Frame:" + ife.getMessage());
746
 
                this.invalidFrameBytes++;
747
 
                //Dont try and find any more frames
748
 
                break;
749
 
            }
750
 
        }
751
 
    }
752
 
 
753
 
    /**
754
 
     * Write the ID3 header to the ByteBuffer.
755
 
     * <p/>
756
 
     * TODO Calculate the CYC Data Check
757
 
     * TODO Reintroduce Extended Header
758
 
     *
759
 
     * @param padding is the size of the padding
760
 
     * @param size    is the size of the body data
761
 
     * @return ByteBuffer
762
 
     * @throws IOException
763
 
     */
764
 
    private ByteBuffer writeHeaderToBuffer(int padding, int size) throws IOException
765
 
    {
766
 
        //This would only be set if every frame in tag has been unsynchronized, I only unsychronize frames
767
 
        //that need it, in any case I have been advised not to set it even then.
768
 
        unsynchronization = false;
769
 
 
770
 
        // Flags,currently we never calculate the CRC
771
 
        // and if we dont calculate them cant keep orig values. Tags are not
772
 
        // experimental and we never create extended header to keep things simple.
773
 
        extended = false;
774
 
        experimental = false;
775
 
        footer = false;
776
 
 
777
 
        // Create Header Buffer,allocate maximum possible size for the header
778
 
        ByteBuffer headerBuffer = ByteBuffer.allocate(TAG_HEADER_LENGTH);
779
 
        //TAGID
780
 
        headerBuffer.put(TAG_ID);
781
 
 
782
 
        //Major Version
783
 
        headerBuffer.put(getMajorVersion());
784
 
 
785
 
        //Minor Version
786
 
        headerBuffer.put(getRevision());
787
 
 
788
 
        //Flags
789
 
        byte flagsByte = 0;
790
 
        if (isUnsynchronization() == true)
791
 
        {
792
 
            flagsByte |= MASK_V24_UNSYNCHRONIZATION;
793
 
        }
794
 
        if (extended == true)
795
 
        {
796
 
            flagsByte |= MASK_V24_EXTENDED_HEADER;
797
 
        }
798
 
        if (experimental == true)
799
 
        {
800
 
            flagsByte |= MASK_V24_EXPERIMENTAL;
801
 
        }
802
 
        if (footer == true)
803
 
        {
804
 
            flagsByte |= MASK_V24_FOOTER_PRESENT;
805
 
        }
806
 
        headerBuffer.put(flagsByte);
807
 
 
808
 
        //Size As Recorded in Header, don't include the main header length
809
 
        //Additional Header Size,(for completeness we never actually write the extended header, or footer)
810
 
        int additionalHeaderSize = 0;
811
 
        if (extended)
812
 
        {
813
 
            additionalHeaderSize += this.TAG_EXT_HEADER_LENGTH;
814
 
            if (updateTag)
815
 
            {
816
 
                additionalHeaderSize += this.TAG_EXT_HEADER_UPDATE_LENGTH;
817
 
            }
818
 
            if (crcDataFlag)
819
 
            {
820
 
                additionalHeaderSize += this.TAG_EXT_HEADER_CRC_LENGTH;
821
 
            }
822
 
            if (tagRestriction)
823
 
            {
824
 
                additionalHeaderSize += this.TAG_EXT_HEADER_RESTRICTION_LENGTH;
825
 
            }
826
 
        }
827
 
 
828
 
        //Size As Recorded in Header, don't include the main header length
829
 
        headerBuffer.put(ID3SyncSafeInteger.valueToBuffer(padding + size + additionalHeaderSize));
830
 
 
831
 
        //Write Extended Header
832
 
        ByteBuffer extHeaderBuffer = null;
833
 
        if (extended == true)
834
 
        {
835
 
            //Write Extended Header Size
836
 
            int extendedSize = TAG_EXT_HEADER_LENGTH;
837
 
            if (updateTag == true)
838
 
            {
839
 
                extendedSize += TAG_EXT_HEADER_UPDATE_LENGTH;
840
 
            }
841
 
            if (crcDataFlag == true)
842
 
            {
843
 
                extendedSize += TAG_EXT_HEADER_CRC_LENGTH;
844
 
            }
845
 
            if (tagRestriction == true)
846
 
            {
847
 
                extendedSize += TAG_EXT_HEADER_RESTRICTION_LENGTH;
848
 
            }
849
 
            extHeaderBuffer = ByteBuffer.allocate(extendedSize);
850
 
            extHeaderBuffer.putInt(extendedSize);
851
 
            //Write Number of flags Byte
852
 
            extHeaderBuffer.put((byte) TAG_EXT_NUMBER_BYTES_DATA_LENGTH);
853
 
            //Write Extended Flags
854
 
            byte extFlag = 0;
855
 
            if (updateTag)
856
 
            {
857
 
                extFlag |= MASK_V24_TAG_UPDATE;
858
 
            }
859
 
            if (crcDataFlag)
860
 
            {
861
 
                extFlag |= MASK_V24_CRC_DATA_PRESENT;
862
 
            }
863
 
            if (tagRestriction)
864
 
            {
865
 
                extFlag |= MASK_V24_TAG_RESTRICTIONS;
866
 
            }
867
 
            extHeaderBuffer.put(extFlag);
868
 
            //Write Update Data
869
 
            if (updateTag)
870
 
            {
871
 
                extHeaderBuffer.put((byte) 0);
872
 
            }
873
 
            //Write CRC Data
874
 
            if (crcDataFlag)
875
 
            {
876
 
                extHeaderBuffer.put((byte) TAG_EXT_HEADER_CRC_DATA_LENGTH);
877
 
                extHeaderBuffer.put((byte) 0);
878
 
                extHeaderBuffer.putInt(crcData);
879
 
            }
880
 
            //Write Tag Restriction
881
 
            if (tagRestriction)
882
 
            {
883
 
                extHeaderBuffer.put((byte) TAG_EXT_HEADER_RESTRICTION_DATA_LENGTH);
884
 
                //todo not currently setting restrictions
885
 
                extHeaderBuffer.put((byte) 0);
886
 
            }
887
 
        }
888
 
 
889
 
        if (extHeaderBuffer != null)
890
 
        {
891
 
            extHeaderBuffer.flip();
892
 
            headerBuffer.put(extHeaderBuffer);
893
 
        }
894
 
 
895
 
        headerBuffer.flip();
896
 
        return headerBuffer;
897
 
    }
898
 
 
899
 
    /**
900
 
     * Write this tag to file.
901
 
     *
902
 
     * @param file
903
 
     * @throws IOException
904
 
     */
905
 
    public void write(File file, long audioStartLocation) throws IOException
906
 
    {
907
 
        logger.info("Writing tag to file");
908
 
 
909
 
        //Write Body Buffer
910
 
        byte[] bodyByteBuffer = writeFramesToBuffer().toByteArray();
911
 
 
912
 
        //Calculate Tag Size including Padding
913
 
        int sizeIncPadding = calculateTagSize(bodyByteBuffer.length + TAG_HEADER_LENGTH, (int) audioStartLocation);
914
 
 
915
 
        //Calculate padding bytes required
916
 
        int padding = sizeIncPadding - (bodyByteBuffer.length + TAG_HEADER_LENGTH);
917
 
 
918
 
        ByteBuffer headerBuffer = writeHeaderToBuffer(padding, bodyByteBuffer.length);
919
 
 
920
 
        //We need to adjust location of audio File
921
 
        if (sizeIncPadding > audioStartLocation)
922
 
        {
923
 
            logger.finest("Adjusting Padding");
924
 
            adjustPadding(file, sizeIncPadding, audioStartLocation);
925
 
        }
926
 
 
927
 
        //Write changes to file
928
 
        FileChannel fc = null;
929
 
        try
930
 
        {
931
 
            fc = new RandomAccessFile(file, "rw").getChannel();
932
 
            fc.write(headerBuffer);
933
 
            fc.write(ByteBuffer.wrap(bodyByteBuffer));
934
 
            fc.write(ByteBuffer.wrap(new byte[padding]));
935
 
        }
936
 
        finally
937
 
        {
938
 
            if (fc != null)
939
 
            {
940
 
                fc.close();
941
 
            }
942
 
        }
943
 
    }
944
 
 
945
 
    /**
946
 
     * Write tag to channel
947
 
     *
948
 
     * @param channel
949
 
     * @throws IOException
950
 
     */
951
 
    public void write(WritableByteChannel channel) throws IOException
952
 
    {
953
 
        logger.info("Writing tag to channel");
954
 
 
955
 
        byte[] bodyByteBuffer = writeFramesToBuffer().toByteArray();
956
 
        ByteBuffer headerBuffer = writeHeaderToBuffer(0, bodyByteBuffer.length);
957
 
 
958
 
        channel.write(headerBuffer);
959
 
        channel.write(ByteBuffer.wrap(bodyByteBuffer));
960
 
    }
961
 
 
962
 
    /**
963
 
     * Display the tag in an XMLFormat
964
 
     */
965
 
    public void createStructure()
966
 
    {
967
 
        MP3File.getStructureFormatter().openHeadingElement(TYPE_TAG, getIdentifier());
968
 
 
969
 
        super.createStructureHeader();
970
 
 
971
 
        //Header
972
 
        MP3File.getStructureFormatter().openHeadingElement(TYPE_HEADER, "");
973
 
        MP3File.getStructureFormatter().addElement(TYPE_UNSYNCHRONISATION, this.isUnsynchronization());
974
 
        MP3File.getStructureFormatter().addElement(TYPE_CRCDATA, this.crcData);
975
 
        MP3File.getStructureFormatter().addElement(TYPE_EXPERIMENTAL, this.experimental);
976
 
        MP3File.getStructureFormatter().addElement(TYPE_EXTENDED, this.extended);
977
 
        MP3File.getStructureFormatter().addElement(TYPE_PADDINGSIZE, this.paddingSize);
978
 
        MP3File.getStructureFormatter().addElement(TYPE_FOOTER, this.footer);
979
 
        MP3File.getStructureFormatter().addElement(TYPE_IMAGEENCODINGRESTRICTION, this.paddingSize);
980
 
        MP3File.getStructureFormatter().addElement(TYPE_IMAGESIZERESTRICTION, (int) this.imageSizeRestriction);
981
 
        MP3File.getStructureFormatter().addElement(TYPE_TAGRESTRICTION, this.tagRestriction);
982
 
        MP3File.getStructureFormatter().addElement(TYPE_TAGSIZERESTRICTION, (int) this.tagSizeRestriction);
983
 
        MP3File.getStructureFormatter().addElement(TYPE_TEXTFIELDSIZERESTRICTION, (int) this.textFieldSizeRestriction);
984
 
        MP3File.getStructureFormatter().addElement(TYPE_TEXTENCODINGRESTRICTION, (int) this.textEncodingRestriction);
985
 
        MP3File.getStructureFormatter().addElement(TYPE_UPDATETAG, this.updateTag);
986
 
        MP3File.getStructureFormatter().closeHeadingElement(TYPE_HEADER);
987
 
 
988
 
        //Body
989
 
        super.createStructureBody();
990
 
 
991
 
        MP3File.getStructureFormatter().closeHeadingElement(TYPE_TAG);
992
 
    }
993
 
 
994
 
    /**
995
 
     * Are all frame swithin this tag unsynchronized
996
 
     * <p/>
997
 
     * <p>Because synchronization occurs at the frame level it is not normally desirable to unsynchronize all frames
998
 
     * and hence this flag is not normally set.
999
 
     *
1000
 
     * @return are all frames within the tag unsynchronized
1001
 
     */
1002
 
    public boolean isUnsynchronization()
1003
 
    {
1004
 
        return unsynchronization;
1005
 
    }
1006
 
 
1007
 
    protected String getArtistId()
1008
 
    {
1009
 
        return ID3v24Frames.FRAME_ID_ARTIST;
1010
 
    }
1011
 
 
1012
 
    protected String getAlbumId()
1013
 
    {
1014
 
        return ID3v24Frames.FRAME_ID_ALBUM;
1015
 
    }
1016
 
 
1017
 
    protected String getTitleId()
1018
 
    {
1019
 
        return ID3v24Frames.FRAME_ID_TITLE;
1020
 
    }
1021
 
 
1022
 
    protected String getTrackId()
1023
 
    {
1024
 
        return ID3v24Frames.FRAME_ID_TRACK;
1025
 
    }
1026
 
 
1027
 
    protected String getYearId()
1028
 
    {
1029
 
        return ID3v24Frames.FRAME_ID_YEAR;
1030
 
    }
1031
 
 
1032
 
    protected String getCommentId()
1033
 
    {
1034
 
        return ID3v24Frames.FRAME_ID_COMMENT;
1035
 
    }
1036
 
 
1037
 
    protected String getGenreId()
1038
 
    {
1039
 
        return ID3v24Frames.FRAME_ID_GENRE;
1040
 
    }
1041
 
 
1042
 
    /**
1043
 
     * Create a new frame with the specified frameid
1044
 
     *
1045
 
     * @param id
1046
 
     * @return
1047
 
     */
1048
 
    public ID3v24Frame createFrame(String id)
1049
 
    {
1050
 
        return new ID3v24Frame(id);
1051
 
    }
1052
 
 
1053
 
 
1054
 
 
1055
 
    /**
1056
 
     * Create Frame for Id3 Key
1057
 
     * <p/>
1058
 
     * Only textual data supported at the moment, should only be used with frames that
1059
 
     * support a simple string argument.
1060
 
     *
1061
 
     * @param id3Key
1062
 
     * @param value
1063
 
     * @return
1064
 
     * @throws KeyNotFoundException
1065
 
     * @throws FieldDataInvalidException
1066
 
     */
1067
 
    public TagField createTagField(ID3v24FieldKey id3Key, String value)
1068
 
            throws KeyNotFoundException, FieldDataInvalidException
1069
 
    {
1070
 
        if (id3Key == null)
1071
 
        {
1072
 
            throw new KeyNotFoundException();
1073
 
        }
1074
 
         return super.doCreateTagField(new FrameAndSubId(id3Key.getFrameId(),id3Key.getSubId()),value);
1075
 
    }
1076
 
 
1077
 
    /**
1078
 
     * Retrieve the first value that exists for this id3v24key
1079
 
     *
1080
 
     * @param id3v24FieldKey
1081
 
     * @return
1082
 
     */
1083
 
    public String getFirst(ID3v24FieldKey id3v24FieldKey) throws KeyNotFoundException
1084
 
    {
1085
 
        if (id3v24FieldKey == null)
1086
 
        {
1087
 
            throw new KeyNotFoundException();
1088
 
        }
1089
 
        return super.doGetFirst(new FrameAndSubId(id3v24FieldKey.getFrameId(),id3v24FieldKey.getSubId()));
1090
 
    }
1091
 
 
1092
 
    
1093
 
 
1094
 
    /**
1095
 
     * Delete fields with this id3v24FieldKey
1096
 
     *
1097
 
     * @param id3v24FieldKey
1098
 
     */
1099
 
    public void deleteTagField
1100
 
            (ID3v24FieldKey
1101
 
                    id3v24FieldKey) throws KeyNotFoundException
1102
 
    {
1103
 
        if (id3v24FieldKey == null)
1104
 
        {
1105
 
            throw new KeyNotFoundException();
1106
 
        }
1107
 
        super.doDeleteTagField(new FrameAndSubId(id3v24FieldKey.getFrameId(),id3v24FieldKey.getSubId()));
1108
 
    }
1109
 
 
1110
 
 
1111
 
    protected FrameAndSubId getFrameAndSubIdFromGenericKey(TagFieldKey genericKey)
1112
 
    {
1113
 
        ID3v24FieldKey id3v24FieldKey = ID3v24Frames.getInstanceOf().getId3KeyFromGenericKey(genericKey);
1114
 
        if (id3v24FieldKey == null)
1115
 
        {
1116
 
            throw new KeyNotFoundException();
1117
 
        }
1118
 
        return new FrameAndSubId(id3v24FieldKey.getFrameId(),id3v24FieldKey.getSubId());
1119
 
    }
1120
 
 
1121
 
    protected ID3Frames getID3Frames()
1122
 
    {
1123
 
        return ID3v24Frames.getInstanceOf();
1124
 
    }
1125
 
}