EMMA Coverage Report (generated Tue Mar 14 21:50:42 EST 2006)
[all classes][org.farng.mp3.id3]

COVERAGE SUMMARY FOR SOURCE FILE [ID3v2_4Frame.java]

nameclass, %method, %block, %line, %
ID3v2_4Frame.java100% (1/1)100% (11/11)86%  (582/679)90%  (127.2/141)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class ID3v2_4Frame100% (1/1)100% (11/11)86%  (582/679)90%  (127.2/141)
write (RandomAccessFile): void 100% (1/1)62%  (91/147)77%  (23/30)
equals (Object): boolean 100% (1/1)77%  (20/26)62%  (5/8)
ID3v2_4Frame (Lyrics3v2Field): void 100% (1/1)88%  (166/189)92%  (36/39)
read (RandomAccessFile): void 100% (1/1)93%  (149/160)98%  (25.4/26)
ID3v2_4Frame (AbstractID3v2Frame): void 100% (1/1)99%  (69/70)99%  (19.8/20)
ID3v2_4Frame (): void 100% (1/1)100% (9/9)100% (4/4)
ID3v2_4Frame (AbstractID3v2FrameBody): void 100% (1/1)100% (10/10)100% (4/4)
ID3v2_4Frame (ID3v2_4Frame): void 100% (1/1)100% (18/18)100% (6/6)
ID3v2_4Frame (RandomAccessFile): void 100% (1/1)100% (12/12)100% (5/5)
ID3v2_4Frame (boolean, boolean, boolean, boolean, boolean, boolean, AbstractI... 100% (1/1)100% (28/28)100% (10/10)
getSize (): int 100% (1/1)100% (10/10)100% (1/1)

1package org.farng.mp3.id3;
2 
3import org.farng.mp3.InvalidTagException;
4import org.farng.mp3.TagConstant;
5import org.farng.mp3.TagUtility;
6import org.farng.mp3.lyrics3.FieldBodyAUT;
7import org.farng.mp3.lyrics3.FieldBodyEAL;
8import org.farng.mp3.lyrics3.FieldBodyEAR;
9import org.farng.mp3.lyrics3.FieldBodyETT;
10import org.farng.mp3.lyrics3.FieldBodyINF;
11import org.farng.mp3.lyrics3.FieldBodyLYR;
12import org.farng.mp3.lyrics3.Lyrics3v2Field;
13import org.farng.mp3.object.ObjectLyrics3Line;
14 
15import java.io.IOException;
16import java.io.RandomAccessFile;
17import java.util.Iterator;
18 
19/**
20 * <p>&nbsp;&nbsp; All ID3v2 frames consists of one frame header followed by one or more<br> &nbsp;&nbsp; fields
21 * containing the actual information. The header is always 10<br> &nbsp;&nbsp; bytes and laid out as follows:</p>
22 * <p/>
23 * <p>&nbsp;&nbsp;&nbsp;&nbsp; Frame ID&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $xx xx xx xx&nbsp; (four characters)<br>
24 * &nbsp;&nbsp;&nbsp;&nbsp; Size&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4 * %0xxxxxxx<br> &nbsp;&nbsp;&nbsp;&nbsp;
25 * Flags&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $xx xx</p>
26 * <p/>
27 * <p>&nbsp;&nbsp; The frame ID is made out of the characters capital A-Z and 0-9.<br> &nbsp;&nbsp; Identifiers
28 * beginning with &quot;X&quot;, &quot;Y&quot; and &quot;Z&quot; are for experimental<br> &nbsp;&nbsp; frames and free
29 * for everyone to use, without the need to set the<br> &nbsp;&nbsp; experimental bit in the tag header. Bear in mind
30 * that someone else<br> &nbsp;&nbsp; might have used the same identifier as you. All other identifiers are<br>
31 * &nbsp;&nbsp; either used or reserved for future use.</p>
32 * <p/>
33 * <p>&nbsp;&nbsp; The frame ID is followed by a size descriptor containing the size of<br> &nbsp;&nbsp; the data in the
34 * final frame, after encryption, compression and<br> &nbsp;&nbsp; unsynchronisation. The size is excluding the frame
35 * header ('total<br> &nbsp;&nbsp; frame size' - 10 bytes) and stored as a 32 bit synchsafe integer.</p>
36 * <p/>
37 * <p>&nbsp;&nbsp; In the frame header the size descriptor is followed by two flag<br> &nbsp;&nbsp; bytes. These flags
38 * are described in section 4.1.</p>
39 * <p/>
40 * <p>&nbsp;&nbsp; There is no fixed order of the frames' appearance in the tag,<br> &nbsp;&nbsp; although it is desired
41 * that the frames are arranged in order of<br> &nbsp;&nbsp; significance concerning the recognition of the file. An
42 * example of<br> &nbsp;&nbsp; such order: UFID, TIT2, MCDI, TRCK ...</p>
43 * <p/>
44 * <p>&nbsp;&nbsp; A tag MUST contain at least one frame. A frame must be at least 1<br> &nbsp;&nbsp; byte big,
45 * excluding the header.</p>
46 * <p/>
47 * <p>&nbsp;&nbsp; If nothing else is said, strings, including numeric strings and URLs<br> &nbsp;&nbsp; [URL], are
48 * represented as ISO-8859-1 [ISO-8859-1] characters in the<br> &nbsp;&nbsp; range $20 - $FF. Such strings are
49 * represented in frame descriptions<br> &nbsp;&nbsp; as &lt;text string&gt;, or &lt;full text string&gt; if newlines
50 * are allowed. If<br> &nbsp;&nbsp; nothing else is said newline character is forbidden. In ISO-8859-1 a<br>
51 * &nbsp;&nbsp; newline is represented, when allowed, with $0A only.</p>
52 * <p/>
53 * <p>&nbsp;&nbsp; Frames that allow different types of text encoding contains a text<br> &nbsp;&nbsp; encoding
54 * description byte. Possible encodings:</p>
55 * <p/>
56 * <p>&nbsp;&nbsp;&nbsp;&nbsp; $00&nbsp;&nbsp; ISO-8859-1 [ISO-8859-1]. Terminated with $00.<br>
57 * &nbsp;&nbsp;&nbsp;&nbsp; $01&nbsp;&nbsp; UTF-16 [UTF-16] encoded Unicode [UNICODE] with BOM. All<br>
58 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; strings in the same frame SHALL have the same
59 * byteorder.<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Terminated with $00 00.<br>
60 * &nbsp;&nbsp;&nbsp;&nbsp; $02&nbsp;&nbsp; UTF-16BE [UTF-16] encoded Unicode [UNICODE] without BOM.<br>
61 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Terminated with $00 00.<br> &nbsp;&nbsp;&nbsp;&nbsp;
62 * $03&nbsp;&nbsp; UTF-8 [UTF-8] encoded Unicode [UNICODE]. Terminated with $00.</p>
63 * <p/>
64 * <p>&nbsp;&nbsp; Strings dependent on encoding are represented in frame descriptions<br> &nbsp;&nbsp; as &lt;text
65 * string according to encoding&gt;, or &lt;full text string<br> &nbsp;&nbsp; according to encoding&gt; if newlines are
66 * allowed. Any empty strings of<br> &nbsp;&nbsp; type $01 which are NULL-terminated may have the Unicode BOM
67 * followed<br> &nbsp;&nbsp; by a Unicode NULL ($FF FE 00 00 or $FE FF 00 00).</p>
68 * <p/>
69 * <p>&nbsp;&nbsp; The timestamp fields are based on a subset of ISO 8601. When being as<br> &nbsp;&nbsp; precise as
70 * possible the format of a time string is<br> &nbsp;&nbsp; yyyy-MM-ddTHH:mm:ss (year, &quot;-&quot;, month,
71 * &quot;-&quot;, day, &quot;T&quot;, hour (out of<br> &nbsp;&nbsp; 24), &quot;:&quot;, minutes, &quot;:&quot;,
72 * seconds), but the precision may be reduced by<br> &nbsp;&nbsp; removing as many time indicators as wanted. Hence
73 * valid timestamps<br> &nbsp;&nbsp; are<br> &nbsp;&nbsp; yyyy, yyyy-MM, yyyy-MM-dd, yyyy-MM-ddTHH, yyyy-MM-ddTHH:mm
74 * and<br> &nbsp;&nbsp; yyyy-MM-ddTHH:mm:ss. All time stamps are UTC. For durations, use<br> &nbsp;&nbsp; the slash
75 * character as described in 8601, and for multiple non-<br> &nbsp;&nbsp; contiguous dates, use multiple strings, if
76 * allowed by the frame<br> &nbsp;&nbsp; definition.</p>
77 * <p/>
78 * <p>&nbsp;&nbsp; The three byte language field, present in several frames, is used to<br> &nbsp;&nbsp; describe the
79 * language of the frame's content, according to ISO-639-2<br> &nbsp;&nbsp; [ISO-639-2]. The language should be
80 * represented in lower case. If the<br> &nbsp;&nbsp; language is not known the string &quot;XXX&quot; should be
81 * used.</p>
82 * <p/>
83 * <p>&nbsp;&nbsp; All URLs [URL] MAY be relative, e.g. &quot;picture.png&quot;, &quot;../doc.txt&quot;.</p>
84 * <p/>
85 * <p>&nbsp;&nbsp; If a frame is longer than it should be, e.g. having more fields than<br> &nbsp;&nbsp; specified in
86 * this document, that indicates that additions to the<br> &nbsp;&nbsp; frame have been made in a later version of the
87 * ID3v2 standard. This<br> &nbsp;&nbsp; is reflected by the revision number in the header of the tag.<br> </p> <a
88 * name="sec4.1"></a>
89 * <p/>
90 * <h3>4.1.&nbsp;&nbsp; Frame header flags</h3>
91 * <p/>
92 * <p>&nbsp;&nbsp; In the frame header the size descriptor is followed by two flag<br> &nbsp;&nbsp; bytes. All unused
93 * flags MUST be cleared. The first byte is for<br> &nbsp;&nbsp; 'status messages' and the second byte is a format
94 * description. If an<br> &nbsp;&nbsp; unknown flag is set in the first byte the frame MUST NOT be changed<br>
95 * &nbsp;&nbsp; without that bit cleared. If an unknown flag is set in the second<br> &nbsp;&nbsp; byte the frame is
96 * likely to not be readable. Some flags in the second<br> &nbsp;&nbsp; byte indicates that extra information is added
97 * to the header. These<br> &nbsp;&nbsp; fields of extra information is ordered as the flags that indicates<br>
98 * &nbsp;&nbsp; them. The flags field is defined as follows (l and o left out because<br> &nbsp;&nbsp; ther resemblence
99 * to one and zero):</p>
100 * <p/>
101 * <p>&nbsp;&nbsp;&nbsp;&nbsp; %0abc0000 %0h00kmnp</p>
102 * <p/>
103 * <p>&nbsp;&nbsp; Some frame format flags indicate that additional information fields<br> &nbsp;&nbsp; are added to the
104 * frame. This information is added after the frame<br> &nbsp;&nbsp; header and before the frame data in the same order
105 * as the flags that<br> &nbsp;&nbsp; indicates them. I.e. the four bytes of decompressed size will precede<br>
106 * &nbsp;&nbsp; the encryption method byte. These additions affects the 'frame size'<br> &nbsp;&nbsp; field, but are not
107 * subject to encryption or compression.<br> &nbsp;&nbsp; </p>
108 * <p/>
109 * <p>&nbsp;&nbsp; The default status flags setting for a frame is, unless stated<br> &nbsp;&nbsp; otherwise, 'preserved
110 * if tag is altered' and 'preserved if file is<br> &nbsp;&nbsp; altered', i.e. %00000000.<br> </p> <a
111 * name="sec4.1.1"></a>
112 * <p/>
113 * <h3>4.1.1. Frame status flags</h3>
114 * <p/>
115 * <p>&nbsp;&nbsp; a - Tag alter preservation</p>
116 * <p/>
117 * <p>&nbsp;&nbsp;&nbsp;&nbsp; This flag tells the tag parser what to do with this frame if it is<br>
118 * &nbsp;&nbsp;&nbsp;&nbsp; unknown and the tag is altered in any way. This applies to all<br> &nbsp;&nbsp;&nbsp;&nbsp;
119 * kinds of alterations, including adding more padding and reordering<br> &nbsp;&nbsp;&nbsp;&nbsp; the frames.</p>
120 * <p/>
121 * <p>&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp; Frame should be preserved.<br> &nbsp;&nbsp;&nbsp;&nbsp;
122 * 1&nbsp;&nbsp;&nbsp;&nbsp; Frame should be discarded.<br> </p>
123 * <p/>
124 * <p>&nbsp;&nbsp; b - File alter preservation</p>
125 * <p/>
126 * <p>&nbsp;&nbsp;&nbsp;&nbsp; This flag tells the tag parser what to do with this frame if it is<br>
127 * &nbsp;&nbsp;&nbsp;&nbsp; unknown and the file, excluding the tag, is altered. This does not<br>
128 * &nbsp;&nbsp;&nbsp;&nbsp; apply when the audio is completely replaced with other audio data.</p>
129 * <p/>
130 * <p>&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp; Frame should be preserved.<br> &nbsp;&nbsp;&nbsp;&nbsp;
131 * 1&nbsp;&nbsp;&nbsp;&nbsp; Frame should be discarded.<br> </p>
132 * <p/>
133 * <p>&nbsp;&nbsp; c - Read only</p>
134 * <p/>
135 * <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; This flag, if set, tells the software that the contents of this<br>
136 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; frame are intended to be read only. Changing the contents might<br>
137 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break something, e.g. a signature. If the contents are changed,<br>
138 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; without knowledge of why the frame was flagged read only and<br>
139 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; without taking the proper means to compensate, e.g. recalculating<br>
140 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; the signature, the bit MUST be cleared.<br> </p> <a name="sec4.1.2"></a>
141 * <p/>
142 * <h3>4.1.2. Frame format flags</h3>
143 * <p/>
144 * <p>&nbsp;&nbsp; h - Grouping identity</p>
145 * <p/>
146 * <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; This flag indicates whether or not this frame belongs in a group<br>
147 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; with other frames. If set, a group identifier byte is added to the<br>
148 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; frame. Every frame with the same group identifier belongs to the<br>
149 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; same group.</p>
150 * <p/>
151 * <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp; Frame does not contain group information<br>
152 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp;&nbsp; Frame contains group information<br> </p>
153 * <p/>
154 * <p>&nbsp;&nbsp; k - Compression</p>
155 * <p/>
156 * <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; This flag indicates whether or not the frame is compressed.<br>
157 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; A 'Data Length Indicator' byte MUST be included in the frame.</p>
158 * <p/>
159 * <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp; Frame is not compressed.<br>
160 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp;&nbsp; Frame is compressed using zlib [zlib] deflate method.<br>
161 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; If set, this requires the 'Data Length Indicator'
162 * bit<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; to be set as well.<br> </p>
163 * <p/>
164 * <p>&nbsp;&nbsp; m - Encryption<br> &nbsp;&nbsp; </p>
165 * <p/>
166 * <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; This flag indicates whether or not the frame is encrypted. If set,<br>
167 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; one byte indicating with which method it was encrypted will be<br>
168 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; added to the frame. See description of the ENCR frame for more<br>
169 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; information about encryption method registration. Encryption<br>
170 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; should be done after compression. Whether or not setting this flag<br>
171 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; requires the presence of a 'Data Length Indicator' depends on the<br>
172 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; specific algorithm used.</p>
173 * <p/>
174 * <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp; Frame is not encrypted.<br>
175 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp;&nbsp; Frame is encrypted.</p>
176 * <p/>
177 * <p>&nbsp;&nbsp; n - Unsynchronisation</p>
178 * <p/>
179 * <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; This flag indicates whether or not unsynchronisation was applied<br>
180 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; to this frame. See section 6 for details on unsynchronisation.<br>
181 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; If this flag is set all data from the end of this header to the<br>
182 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; end of this frame has been unsynchronised. Although desirable, the<br>
183 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; presence of a 'Data Length Indicator' is not made mandatory by<br>
184 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsynchronisation.</p>
185 * <p/>
186 * <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp; Frame has not been unsynchronised.<br>
187 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp;&nbsp; Frame has been unsyrchronised.</p>
188 * <p/>
189 * <p>&nbsp;&nbsp; p - Data length indicator</p>
190 * <p/>
191 * <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; This flag indicates that a data length indicator has been added to<br>
192 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; the frame. The data length indicator is the value one would write<br>
193 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; as the 'Frame length' if all of the frame format flags were<br>
194 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; zeroed, represented as a 32 bit synchsafe integer.</p>
195 * <p/>
196 * <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; There is no Data Length Indicator.<br>
197 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; A data length Indicator has been added to the
198 * frame.<br> </p>
199 *
200 * @author Eric Farng
201 * @version $Revision: 1.6 $
202 */
203public class ID3v2_4Frame extends ID3v2_3Frame {
204 
205    protected boolean dataLengthIndicator = false;
206    protected boolean unsynchronization = false;
207 
208    /**
209     * Creates a new ID3v2_4Frame object.
210     */
211    public ID3v2_4Frame() {
212        // base empty constructor
213    }
214 
215    /**
216     * Creates a new ID3v2_4Frame object.
217     */
218    public ID3v2_4Frame(final ID3v2_4Frame copyObject) {
219        super(copyObject);
220        this.dataLengthIndicator = copyObject.dataLengthIndicator;
221        this.unsynchronization = copyObject.unsynchronization;
222    }
223 
224    /**
225     * Creates a new ID3v2_4Frame object.
226     */
227    public ID3v2_4Frame(final AbstractID3v2FrameBody body) {
228        super(body);
229    }
230 
231    /**
232     * Creates a new ID3v2_4Frame object.
233     */
234    public ID3v2_4Frame(final AbstractID3v2Frame frame) {
235        if (frame instanceof ID3v2_4Frame) {
236            final ID3v2_4Frame f = (ID3v2_4Frame) frame;
237            this.unsynchronization = f.unsynchronization;
238            this.dataLengthIndicator = f.dataLengthIndicator;
239        }
240        if (frame instanceof ID3v2_3Frame) {
241            // a id3v2_4 frame is of type id3v2_3 frame also ...
242            final ID3v2_3Frame f = (ID3v2_3Frame) frame;
243            this.tagAlterPreservation = f.tagAlterPreservation;
244            this.fileAlterPreservation = f.fileAlterPreservation;
245            this.readOnly = f.readOnly;
246            this.groupingIdentity = f.groupingIdentity;
247            this.compression = f.compression;
248            this.encryption = f.encryption;
249        }
250        if (frame instanceof ID3v2_2Frame) {
251            // no variables yet
252        }
253        if (frame.getBody() == null) {
254            // do nothing
255        } else if (TagUtility.isID3v2_4FrameIdentifier(frame.getIdentifier())) {
256            this.setBody((AbstractID3v2FrameBody) TagUtility.copyObject(frame.getBody()));
257//        } else if (TagUtility.isID3v2_3FrameIdentifier(frame.getIdentifier())) {
258//            // @TODO correctly convert tags
259//            this.setBody((AbstractID3v2FrameBody) TagUtility.copyObject(frame.getBody()));
260//        } else if (TagUtility.isID3v2_2FrameIdentifier(frame.getIdentifier())) {
261//            // @TODO correctly convert tags
262//            this.setBody((AbstractID3v2FrameBody) TagUtility.copyObject(frame.getBody()));
263        }
264    }
265 
266    /**
267     * Creates a new ID3v2_4Frame object.
268     */
269    public ID3v2_4Frame(final boolean readOnly,
270                        final boolean groupingIdentity,
271                        final boolean compression,
272                        final boolean encryption,
273                        final boolean unsynchronization,
274                        final boolean dataLengthIndicator,
275                        final AbstractID3v2FrameBody body) {
276        super(body);
277        this.readOnly = readOnly;
278        this.groupingIdentity = groupingIdentity;
279        this.compression = compression;
280        this.encryption = encryption;
281        this.unsynchronization = unsynchronization;
282        this.dataLengthIndicator = dataLengthIndicator;
283    }
284 
285    /**
286     * Creates a new ID3v2_4Frame object.
287     */
288    public ID3v2_4Frame(final Lyrics3v2Field field) throws InvalidTagException {
289        final String id = field.getIdentifier();
290        final String value;
291        if (id.equals("IND")) {
292            throw new InvalidTagException("Cannot create ID3v2.40 frame from Lyrics3 indications field.");
293        } else if (id.equals("LYR")) {
294            final FieldBodyLYR lyric = (FieldBodyLYR) field.getBody();
295            ObjectLyrics3Line line;
296            final Iterator iterator = lyric.iterator();
297            final FrameBodySYLT sync;
298            final FrameBodyUSLT unsync;
299            final boolean hasTimeStamp = lyric.hasTimeStamp();
300 
301            // we'll create only one frame here.
302            // if there is any timestamp at all, we will create a sync'ed frame.
303            sync = new FrameBodySYLT((byte) 0, "ENG", (byte) 2, (byte) 1, "");
304            unsync = new FrameBodyUSLT((byte) 0, "ENG", "", "");
305            while (iterator.hasNext()) {
306                line = (ObjectLyrics3Line) iterator.next();
307                if (hasTimeStamp) {
308                    sync.addLyric(line);
309                } else {
310                    unsync.addLyric(line);
311                }
312            }
313            if (hasTimeStamp) {
314                this.setBody(sync);
315            } else {
316                this.setBody(unsync);
317            }
318        } else if (id.equals("INF")) {
319            value = ((FieldBodyINF) field.getBody()).getAdditionalInformation();
320            this.setBody(new FrameBodyCOMM((byte) 0, "ENG", "", value));
321        } else if (id.equals("AUT")) {
322            value = ((FieldBodyAUT) field.getBody()).getAuthor();
323            this.setBody(new FrameBodyTCOM((byte) 0, value));
324        } else if (id.equals("EAL")) {
325            value = ((FieldBodyEAL) field.getBody()).getAlbum();
326            this.setBody(new FrameBodyTALB((byte) 0, value));
327        } else if (id.equals("EAR")) {
328            value = ((FieldBodyEAR) field.getBody()).getArtist();
329            this.setBody(new FrameBodyTPE1((byte) 0, value));
330        } else if (id.equals("ETT")) {
331            value = ((FieldBodyETT) field.getBody()).getTitle();
332            this.setBody(new FrameBodyTIT2((byte) 0, value));
333        } else if (id.equals("IMG")) {
334            throw new InvalidTagException("Cannot create ID3v2.40 frame from Lyrics3 image field.");
335        } else {
336            throw new InvalidTagException("Cannot caret ID3v2.40 frame from " + id + " Lyrics3 field");
337        }
338    }
339 
340    /**
341     * Creates a new ID3v2_4Frame object.
342     */
343    public ID3v2_4Frame(final RandomAccessFile file) throws IOException, InvalidTagException {
344        this.read(file);
345    }
346 
347    public int getSize() {
348        return this.getBody().getSize() + 4 + 2 + 4;
349    }
350 
351    public boolean equals(final Object obj) {
352        if ((obj instanceof ID3v2_4Frame) == false) {
353            return false;
354        }
355        final ID3v2_4Frame id3v2_4Frame = (ID3v2_4Frame) obj;
356        if (this.unsynchronization != id3v2_4Frame.unsynchronization) {
357            return false;
358        }
359        if (this.dataLengthIndicator != id3v2_4Frame.dataLengthIndicator) {
360            return false;
361        }
362        return super.equals(obj);
363    }
364 
365    public void read(final RandomAccessFile file) throws IOException, InvalidTagException {
366        long filePointer;
367        final byte[] buffer = new byte[4];
368        byte b;
369 
370        // lets scan for a non-zero byte;
371        do {
372            filePointer = file.getFilePointer();
373            b = file.readByte();
374            org.farng.mp3.id3.AbstractID3v2.incrementPaddingCounter();
375        } while (b == 0);
376        file.seek(filePointer);
377        org.farng.mp3.id3.AbstractID3v2.decrementPaddingCounter();
378 
379        // read the four character identifier
380        file.read(buffer, 0, 4);
381        final String identifier = new String(buffer, 0, 4);
382 
383        // is this a valid identifier?
384        if (isValidID3v2FrameIdentifier(identifier) == false) {
385            file.seek(file.getFilePointer() - 3);
386            throw new InvalidTagException(identifier + " is not a valid ID3v2.40 frame");
387        }
388        filePointer = file.getFilePointer();
389 
390        // skip the 4 byte size
391        file.skipBytes(4);
392 
393        // read the flag bytes
394        file.read(buffer, 0, 2);
395        this.tagAlterPreservation = (buffer[0] & TagConstant.MASK_V24_TAG_ALTER_PRESERVATION) != 0;
396        this.fileAlterPreservation = (buffer[0] & TagConstant.MASK_V24_FILE_ALTER_PRESERVATION) != 0;
397        this.readOnly = (buffer[0] & TagConstant.MASK_V24_READ_ONLY) != 0;
398        this.groupingIdentity = (buffer[1] & TagConstant.MASK_V24_GROUPING_IDENTITY) != 0;
399        this.compression = (buffer[1] & TagConstant.MASK_V24_COMPRESSION) != 0;
400        this.encryption = (buffer[1] & TagConstant.MASK_V24_ENCRYPTION) != 0;
401        this.unsynchronization = (buffer[1] & TagConstant.MASK_V24_FRAME_UNSYNCHRONIZATION) != 0;
402        this.dataLengthIndicator = (buffer[1] & TagConstant.MASK_V24_DATA_LENGTH_INDICATOR) != 0;
403        file.seek(filePointer);
404        this.setBody(readBody(identifier, file));
405    }
406 
407    public void write(final RandomAccessFile file) throws IOException {
408        final byte[] buffer = new byte[4];
409        final long filePointer;
410        final String str = TagUtility.truncate(getIdentifier(), 4);
411        for (int i = 0; i < str.length(); i++) {
412            buffer[i] = (byte) str.charAt(i);
413        }
414        file.write(buffer, 0, str.length());
415        filePointer = file.getFilePointer();
416 
417        // skip the size bytes
418        file.skipBytes(4);
419        setAlterPreservation();
420        buffer[0] = 0;
421        buffer[1] = 0;
422        if (this.tagAlterPreservation) {
423            buffer[0] |= TagConstant.MASK_V24_TAG_ALTER_PRESERVATION;
424        }
425        if (this.fileAlterPreservation) {
426            buffer[0] |= TagConstant.MASK_V24_FILE_ALTER_PRESERVATION;
427        }
428        if (this.readOnly) {
429            buffer[0] |= TagConstant.MASK_V24_READ_ONLY;
430        }
431        if (this.groupingIdentity) {
432            buffer[1] |= TagConstant.MASK_V24_GROUPING_IDENTITY;
433        }
434        if (this.compression) {
435            buffer[1] |= TagConstant.MASK_V24_COMPRESSION;
436        }
437        if (this.encryption) {
438            buffer[1] |= TagConstant.MASK_V24_ENCRYPTION;
439        }
440        if (this.unsynchronization) {
441            buffer[1] |= TagConstant.MASK_V24_FRAME_UNSYNCHRONIZATION;
442        }
443        if (this.dataLengthIndicator) {
444            buffer[1] |= TagConstant.MASK_V24_DATA_LENGTH_INDICATOR;
445        }
446        file.write(buffer, 0, 2);
447        file.seek(filePointer);
448        this.getBody().write(file);
449    }
450}

[all classes][org.farng.mp3.id3]
EMMA 2.0.5312 (C) Vladimir Roubtsov