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

COVERAGE SUMMARY FOR SOURCE FILE [ID3v1_1.java]

nameclass, %method, %block, %line, %
ID3v1_1.java100% (1/1)79%  (15/19)64%  (546/856)70%  (125.1/179)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class ID3v1_1100% (1/1)79%  (15/19)64%  (546/856)70%  (125.1/179)
append (AbstractMP3Tag): void 0%   (0/1)0%   (0/39)0%   (0/10)
getIdentifier (): String 0%   (0/1)0%   (0/2)0%   (0/1)
toString (): String 0%   (0/1)0%   (0/115)0%   (0/9)
write (AbstractMP3Tag): void 0%   (0/1)0%   (0/26)0%   (0/9)
write (RandomAccessFile): void 100% (1/1)72%  (111/155)83%  (27.3/33)
ID3v1_1 (AbstractMP3Tag): void 100% (1/1)73%  (171/235)75%  (39/52)
overwrite (AbstractMP3Tag): void 100% (1/1)76%  (29/38)80%  (8.8/11)
equals (Object): boolean 100% (1/1)79%  (15/19)67%  (4/6)
read (RandomAccessFile): void 100% (1/1)96%  (120/125)95%  (19/20)
seek (RandomAccessFile): boolean 100% (1/1)96%  (48/50)91%  (10/11)
ID3v1_1 (): void 100% (1/1)100% (6/6)100% (3/3)
ID3v1_1 (ID3v1_1): void 100% (1/1)100% (11/11)100% (4/4)
ID3v1_1 (RandomAccessFile): void 100% (1/1)100% (9/9)100% (4/4)
getComment (): String 100% (1/1)100% (3/3)100% (1/1)
getTrack (): byte 100% (1/1)100% (3/3)100% (1/1)
getTrackNumberOnAlbum (): String 100% (1/1)100% (4/4)100% (1/1)
setComment (String): void 100% (1/1)100% (6/6)100% (2/2)
setTrack (byte): void 100% (1/1)100% (4/4)100% (2/2)
setTrackNumberOnAlbum (String): void 100% (1/1)100% (6/6)100% (2/2)

1package org.farng.mp3.id3;
2 
3import org.farng.mp3.AbstractMP3Tag;
4import org.farng.mp3.TagException;
5import org.farng.mp3.TagNotFoundException;
6import org.farng.mp3.TagOptionSingleton;
7import org.farng.mp3.TagUtility;
8 
9import java.io.IOException;
10import java.io.RandomAccessFile;
11import java.util.Iterator;
12 
13/**
14 * <TABLE border=0> <TBODY> <TR> <TD class=h2>What is ID3v1.1?</TD></TR></TBODY></TABLE> <TABLE border=0> <TBODY> <TR
15 * vAlign=top> <TD> <P>ID3v1 may well be easy to implement for programmers, but it sure is frustrating for those with
16 * their own, creative ideas. Since the ID3v1 tag had a fixed size and no space marked "Reserved for future use", there
17 * isn't really room for that much improvement, if you want to maintain compatibility with existing software.</P>
18 * <p/>
19 * <P>One who found a way out was Michael Mutschler who made a quite clever improvement on ID3v1. Since all non-filled
20 * fields must be padded with zeroed bytes its a good assumption that all ID3v1 readers will stop reading the field when
21 * they encounter a zeroed byte. If the second last byte of a field is zeroed and the last one isn't we have an extra
22 * byte to fill with information. As the comments field is to short to write anything useful in the ID3v1.1 standard
23 * declares that this field should be 28 characters, that the next byte always should be zero and that the last byte
24 * before the genre byte should contain which track on the CD this music comes from.</P></TD> </TR></TBODY></TABLE>
25 *
26 * @author Eric Farng
27 * @version $Revision: 1.7 $
28 */
29public class ID3v1_1 extends ID3v1 {
30 
31    protected byte track = -1;
32 
33    /**
34     * Creates a new ID3v1_1 object.
35     */
36    public ID3v1_1() {
37        super();
38    }
39 
40    /**
41     * Creates a new ID3v1_1 object.
42     */
43    public ID3v1_1(final ID3v1_1 copyObject) {
44        super(copyObject);
45        this.track = copyObject.track;
46    }
47 
48    /**
49     * Creates a new ID3v1_1 object.
50     */
51    public ID3v1_1(final AbstractMP3Tag mp3tag) {
52        if (mp3tag != null) {
53            if (mp3tag instanceof ID3v1) {
54                if (mp3tag instanceof ID3v1_1) {
55                    throw new UnsupportedOperationException("Copy Constructor not called. Please type cast the argument");
56                }
57 
58                // id3v1_1 objects are also id3v1 objects
59                final ID3v1 id3old = (ID3v1) mp3tag;
60                this.title = new String(id3old.title.trim());
61                this.artist = new String(id3old.artist.trim());
62                this.album = new String(id3old.album.trim());
63                this.comment = new String(id3old.comment.trim());
64                this.year = new String(id3old.year.trim());
65                this.genre = id3old.genre;
66            } else {
67                // first change the tag to ID3v2_4 tag.
68                // id3v2_4 can take any tag.
69                final ID3v2_4 id3tag;
70                id3tag = new ID3v2_4(mp3tag);
71                ID3v2_4Frame frame;
72                String text;
73                if (id3tag.hasFrame("TIT2")) {
74                    frame = (ID3v2_4Frame) id3tag.getFrame("TIT2");
75                    text = ((FrameBodyTIT2) frame.getBody()).getText();
76                    this.title = TagUtility.truncate(text, 30);
77                }
78                if (id3tag.hasFrame("TPE1")) {
79                    frame = (ID3v2_4Frame) id3tag.getFrame("TPE1");
80                    text = ((FrameBodyTPE1) frame.getBody()).getText();
81                    this.artist = TagUtility.truncate(text, 30);
82                }
83                if (id3tag.hasFrame("TALB")) {
84                    frame = (ID3v2_4Frame) id3tag.getFrame("TALB");
85                    text = ((FrameBodyTALB) frame.getBody()).getText();
86                    this.album = TagUtility.truncate(text, 30);
87                }
88                if (id3tag.hasFrame("TDRC")) {
89                    frame = (ID3v2_4Frame) id3tag.getFrame("TDRC");
90                    text = ((FrameBodyTDRC) frame.getBody()).getText();
91                    this.year = TagUtility.truncate(text, 4);
92                }
93                if (id3tag.hasFrameOfType("COMM")) {
94                    final Iterator iterator = id3tag.getFrameOfType("COMM");
95                    text = "";
96                    while (iterator.hasNext()) {
97                        frame = (ID3v2_4Frame) iterator.next();
98                        text += (((FrameBodyCOMM) frame.getBody()).getText() + " ");
99                    }
100                    this.comment = TagUtility.truncate(text, 28);
101                }
102                if (id3tag.hasFrame("TCON")) {
103                    frame = (ID3v2_4Frame) id3tag.getFrame("TCON");
104                    text = ((FrameBodyTCON) frame.getBody()).getText();
105                    try {
106                        this.genre = (byte) TagUtility.findNumber(text);
107                    } catch (TagException ex) {
108                        this.genre = 0;
109                    }
110                }
111                if (id3tag.hasFrame("TRCK")) {
112                    frame = (ID3v2_4Frame) id3tag.getFrame("TRCK");
113                    text = ((FrameBodyTRCK) frame.getBody()).getText();
114                    try {
115                        this.track = (byte) TagUtility.findNumber(text);
116                    } catch (TagException ex) {
117                        this.track = 0;
118                    }
119                }
120            }
121        }
122    }
123 
124    /**
125     * Creates a new ID3v1_1 object.
126     */
127    public ID3v1_1(final RandomAccessFile file) throws TagNotFoundException, IOException {
128        this.read(file);
129    }
130 
131    public void setComment(final String comment) {
132        this.comment = TagUtility.truncate(comment, 28);
133    }
134 
135    public String getComment() {
136        return this.comment;
137    }
138 
139    public String getIdentifier() {
140        return "ID3v1_1.10";
141    }
142 
143    public void setTrack(final byte track) {
144        this.track = track;
145    }
146 
147    public byte getTrack() {
148        return this.track;
149    }
150 
151    public void append(final AbstractMP3Tag tag) {
152        final ID3v1_1 oldTag = this;
153        final ID3v1_1 newTag;
154        if (tag != null) {
155            if (tag instanceof ID3v1_1) {
156                newTag = (ID3v1_1) tag;
157            } else {
158                newTag = new ID3v1_1(tag);
159            }
160            if (tag instanceof org.farng.mp3.lyrics3.AbstractLyrics3) {
161                TagOptionSingleton.getInstance().setId3v1SaveTrack(false);
162            }
163            oldTag.track = (TagOptionSingleton.getInstance().isId3v1SaveTrack() && (oldTag.track <= 0)) ?
164                           newTag.track :
165                           oldTag.track;
166 
167            // we don't need to reset the tag options because
168            // we want to save all fields (default)
169        }
170 
171        // we can't send newTag here because we need to keep the lyrics3
172        // class type ... check super.append and you'll see what i mean.
173        super.append(tag);
174    }
175 
176    public boolean equals(final Object obj) {
177        if ((obj instanceof ID3v1_1) == false) {
178            return false;
179        }
180        final ID3v1_1 id3v1_1 = (ID3v1_1) obj;
181        if (this.track != id3v1_1.track) {
182            return false;
183        }
184        return super.equals(obj);
185    }
186 
187    public void overwrite(final AbstractMP3Tag tag) {
188        final ID3v1_1 oldTag = this;
189        ID3v1_1 newTag = null;
190        if (tag != null) {
191            if (tag instanceof ID3v1_1) {
192                newTag = (ID3v1_1) tag;
193            } else {
194                newTag = new ID3v1_1(tag);
195            }
196            if (tag instanceof org.farng.mp3.lyrics3.AbstractLyrics3) {
197                TagOptionSingleton.getInstance().setId3v1SaveTrack(false);
198            }
199            oldTag.track = TagOptionSingleton.getInstance().isId3v1SaveTrack() ? newTag.track : oldTag.track;
200 
201            // we don't need to reset the tag options because
202            // we want to save all fields (default)
203        }
204        super.overwrite(newTag);
205    }
206 
207    public void read(final RandomAccessFile file) throws TagNotFoundException, IOException {
208        final byte[] buffer = new byte[30];
209        if (this.seek(file) == false) {
210            throw new TagNotFoundException("ID3v1.1 tag not found");
211        }
212        file.read(buffer, 0, 30);
213        this.title = new String(buffer, 0, 30, "ISO-8859-1").trim();
214        file.read(buffer, 0, 30);
215        this.artist = new String(buffer, 0, 30, "ISO-8859-1").trim();
216        file.read(buffer, 0, 30);
217        this.album = new String(buffer, 0, 30, "ISO-8859-1").trim();
218        file.read(buffer, 0, 4);
219        this.year = new String(buffer, 0, 4, "ISO-8859-1").trim();
220        file.read(buffer, 0, 28);
221        this.comment = new String(buffer, 0, 28, "ISO-8859-1").trim();
222 
223        // if this value is zero, then check the next value
224        // to see if it's the track number. ID3v1.1
225        file.read(buffer, 0, 2);
226        if (buffer[0] == 0) {
227            this.track = buffer[1];
228        } else {
229            throw new TagNotFoundException("ID3v1.1 Tag Not found");
230        }
231        file.read(buffer, 0, 1);
232        this.genre = buffer[0];
233    }
234 
235    public boolean seek(final RandomAccessFile file) throws IOException {
236        final byte[] buffer = new byte[3];
237        if (file.length() < 128) {
238            return false;
239        }
240 
241        // Check for the empty byte before the TRACK
242        file.seek(file.length() - 3);
243        buffer[0] = file.readByte();
244        if (buffer[0] != 0) {
245            return false;
246        }
247 
248        // If there's a tag, it's 128 bytes long and we'll find the tag
249        file.seek(file.length() - 128);
250 
251        // read the TAG value
252        file.read(buffer, 0, 3);
253        final String tag = new String(buffer, 0, 3);
254        return tag.equals("TAG");
255    }
256 
257    public String toString() {
258        String str = getIdentifier() + " " + this.getSize() + "\n";
259        str += ("Title = " + this.title + "\n");
260        str += ("Artist = " + this.artist + "\n");
261        str += ("Album = " + this.album + "\n");
262        str += ("Comment = " + this.comment + "\n");
263        str += ("Year = " + this.year + "\n");
264        str += ("Genre = " + this.genre + "\n");
265        str += ("Track = " + this.track + "\n");
266        return str;
267    }
268 
269    public void write(final AbstractMP3Tag tag) {
270        final ID3v1_1 oldTag = this;
271        ID3v1_1 newTag = null;
272        if (tag != null) {
273            if (tag instanceof ID3v1_1) {
274                newTag = (ID3v1_1) tag;
275            } else {
276                newTag = new ID3v1_1(tag);
277            }
278            oldTag.track = newTag.track;
279        }
280        super.write(newTag);
281    }
282 
283    public void write(final RandomAccessFile file) throws IOException {
284        final byte[] buffer = new byte[128];
285        int i;
286        int offset = 3;
287        String str;
288        delete(file);
289        file.seek(file.length());
290        buffer[0] = (byte) 'T';
291        buffer[1] = (byte) 'A';
292        buffer[2] = (byte) 'G';
293        str = TagUtility.truncate(this.title, 30);
294        for (i = 0; i < str.length(); i++) {
295            buffer[i + offset] = (byte) str.charAt(i);
296        }
297        offset += 30;
298        str = TagUtility.truncate(this.artist, 30);
299        for (i = 0; i < str.length(); i++) {
300            buffer[i + offset] = (byte) str.charAt(i);
301        }
302        offset += 30;
303        str = TagUtility.truncate(this.album, 30);
304        for (i = 0; i < str.length(); i++) {
305            buffer[i + offset] = (byte) str.charAt(i);
306        }
307        offset += 30;
308        str = TagUtility.truncate(this.year, 4);
309        for (i = 0; i < str.length(); i++) {
310            buffer[i + offset] = (byte) str.charAt(i);
311        }
312        offset += 4;
313        str = TagUtility.truncate(this.comment, 28);
314        for (i = 0; i < str.length(); i++) {
315            buffer[i + offset] = (byte) str.charAt(i);
316        }
317        offset += 28;
318        offset++;
319        buffer[offset] = this.track; // skip one byte extra blank for 1.1
320 
321        // definition
322        offset++;
323        buffer[offset] = this.genre;
324        file.write(buffer);
325    }
326 
327    public String getTrackNumberOnAlbum() {
328        return Integer.toString(getTrack());
329    }
330 
331    public void setTrackNumberOnAlbum(String trackNumberOnAlbum) {
332        setTrack(Byte.parseByte(trackNumberOnAlbum.trim()));
333    }
334}

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