libjaudiotagger-java-2.0.3/0000755000175000017500000000000011556363446015500 5ustar drazzibdrazziblibjaudiotagger-java-2.0.3/ReadTest.bat0000644000175000017500000000015010414415065017662 0ustar drazzibdrazzibset classpath=%classpath%;.\classes;\dist\jaudiotagger.jar java org.jaudiotagger.test.TestAudioTagger %1libjaudiotagger-java-2.0.3/jaudiotagger.iws0000644000175000017500000032261311470746136020674 0ustar drazzibdrazzib Inspections Visibility issues Inspections Class metrics libjaudiotagger-java-2.0.3/jaudiotagger.ipr0000644000175000017500000012655511470746136020673 0ustar drazzibdrazzib libjaudiotagger-java-2.0.3/Fix202.bat0000644000175000017500000000013610757305272017135 0ustar drazzibdrazzibset classpath=%classpath%;.\classes;\dist\jaudiotagger.jar java org.jaudiotagger.fix.Fix202 %1libjaudiotagger-java-2.0.3/pom.xml0000644000175000017500000001656211470746136017023 0ustar drazzibdrazzib 4.0.0 org jaudiotagger 2.0.3 jar jaudiotagger The aim of this project is to provide a world class Java library for editing tag information in audio files. Most existing solutions are not java based inhibiting the use of java applications with digital files. maven2-repository.dev.java.net Java.net Repository for Maven http://download.java.net/maven/2/ https://jaudiotagger.dev.java.net/ 2005 scm:svn:https://jaudiotagger.dev.java.net/svn/jaudiotagger/trunk https://jaudiotagger.dev.java.net/svn/jaudiotagger/trunk https://jaudiotagger.dev.java.net/issues java.net http://www.java.net/ Development mailing list dev@jaudiotagger.dev.java.net https://jaudiotagger.dev.java.net/servlets/SummarizeList?listName=dev Issues mailing list issues@jaudiotagger.dev.java.net https://jaudiotagger.dev.java.net/servlets/SummarizeList?listName=issues paultaylor Paul Taylor paultaylor@dev.java.net jthink http://www.jthink.net/jaudiotagger Project Manager Java Developer LGPL http://www.gnu.org/copyleft/lesser.html junit junit 3.8.1 test jthink scp://www.jthink.net//home/jthink/jakarta-tomcat/webapps/jaudiotagger/maven false java.net-maven2-repository java-net:/maven2-repository/trunk/repository/ org.jvnet.wagon-svn wagon-svn 1.8 org.apache.maven.plugins maven-compiler-plugin UTF-8 1.5 1.5 org.apache.maven.plugins maven-surefire-plugin -Dfile.encoding=UTF-8 org.apache.maven.plugins maven-source-plugin attach-sources jar org.apache.maven.plugins maven-javadoc-plugin attach-javadocs jar src srctest org.apache.maven.plugins maven-javadoc-plugin 2.6.1 private false org.apache.maven.plugins maven-project-info-reports-plugin org.apache.maven.plugins maven-surefire-report-plugin org.codehaus.mojo cobertura-maven-plugin html xml org.apache.maven.plugins maven-pmd-plugin 1.5 libjaudiotagger-java-2.0.3/build.xml0000644000175000017500000002375311470746136017327 0ustar drazzibdrazzib Jaudiotagger User API ${build.release}]]> Jaudiotagger Developer API ${build.release}]]> libjaudiotagger-java-2.0.3/srctest/0000755000175000017500000000000011556363176017167 5ustar drazzibdrazziblibjaudiotagger-java-2.0.3/srctest/org/0000755000175000017500000000000011556363176017756 5ustar drazzibdrazziblibjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/0000755000175000017500000000000011556363177022424 5ustar drazzibdrazziblibjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/0000755000175000017500000000000011556363201023163 5ustar drazzibdrazziblibjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/wav/0000755000175000017500000000000011556363201023760 5ustar drazzibdrazziblibjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/wav/WavSimpleTest.java0000644000175000017500000000703411276777123027411 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.wav; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.audio.generic.GenericTag; import org.jaudiotagger.audio.wav.WavTag; import org.jaudiotagger.tag.FieldKey; import java.io.File; /** * User: paul * Date: 07-Dec-2007 */ public class WavSimpleTest extends AbstractTestCase { public void testReadFile() { Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test.wav"); AudioFile f = AudioFileIO.read(testFile); assertEquals("176", f.getAudioHeader().getBitRate()); assertEquals("WAV-RIFF 8 bits", f.getAudioHeader().getEncodingType()); assertEquals("1", f.getAudioHeader().getChannels()); assertEquals("22050", f.getAudioHeader().getSampleRate()); assertTrue(f.getTag() instanceof GenericTag); //TODO Flawed concept should be asftag WavTag tag = (WavTag) f.getTag(); //Ease of use methods for common fields assertEquals("", tag.getFirst(FieldKey.ARTIST)); assertEquals("", tag.getFirst(FieldKey.ALBUM)); assertEquals("", tag.getFirst(FieldKey.TITLE)); assertEquals("", tag.getFirst(FieldKey.COMMENT)); assertEquals("", tag.getFirst(FieldKey.YEAR)); assertEquals("", tag.getFirst(FieldKey.TRACK)); assertEquals("", tag.getFirst(FieldKey.GENRE)); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /* Doesnt support writing currently public void testWriteFile() { Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test.wav",new File("testwrite1.wav")); AudioFile f = AudioFileIO.read(testFile); assertEquals("176",f.getAudioHeader().getBitRate()); assertEquals("WAV-RIFF 8 bits",f.getAudioHeader().getEncodingType()); assertEquals("1",f.getAudioHeader().getChannels()); assertEquals("22050",f.getAudioHeader().getSampleRate()); assertTrue(f.getTag() instanceof GenericTag); //TODO Flawed concept hould be wavtag GenericTag tag = (GenericTag)f.getTag(); //Write some new values and save tag.setField(FieldKey.ARTIST,("artist2"); tag.setField(FieldKey.ALBUM,"album2"); tag.setField(FieldKey.TITLE,"tracktitle2"); tag.setField(FieldKey.COMMENT,"comments2"); tag.setField(FieldKey.YEAR,"1972"); tag.setField(FieldKey.GENRE,("genre2"); tag.setField(FieldKey.TRACK,"4"); f.commit(); f = AudioFileIO.read(testFile); tag = (GenericTag)f.getTag(); assertEquals("artist2", tag.getFirst(FieldKey.ARTIST)); assertEquals("album2", tag.getFirst(FieldKey.ALBUM)); assertEquals("tracktitle2", tag.getFirst(FieldKey.TITLE)); assertEquals("comments2", tag.getFirstComment()); assertEquals("1972", tag.getFirst(FieldKey.YEAR)); assertEquals("4", tag.getFirst(FieldKey.TRACK)); assertEquals("genre2", tag.getFirst(FieldKey.GENRE)); } catch(Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } */ } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/id3/0000755000175000017500000000000011556363200023641 5ustar drazzibdrazziblibjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/id3/FrameTSOPTest.java0000644000175000017500000002625511247705415027123 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.mp3.MP3File; import org.jaudiotagger.tag.id3.framebody.FrameBodyTSOP; import org.jaudiotagger.tag.id3.framebody.FrameBodyTSOPTest; import org.jaudiotagger.tag.id3.framebody.FrameBodyXSOP; import org.jaudiotagger.tag.id3.framebody.FrameBodyXSOPTest; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; import java.io.File; /** * Test TSOP and XSOP (Title Sort) Frame */ public class FrameTSOPTest extends AbstractTestCase { public static ID3v24Frame getInitialisedFrame() { ID3v24Frame frame = new ID3v24Frame(ID3v24Frames.FRAME_ID_ARTIST_SORT_ORDER); FrameBodyTSOP fb = FrameBodyTSOPTest.getInitialisedBody(); frame.setBody(fb); return frame; } public static ID3v23Frame getV23InitialisedFrame() { ID3v23Frame frame = new ID3v23Frame(ID3v23Frames.FRAME_ID_V3_ARTIST_SORT_ORDER_MUSICBRAINZ); FrameBodyXSOP fb = FrameBodyXSOPTest.getInitialisedBody(); frame.setBody(fb); return frame; } public void testCreateID3v24Frame() { Exception exceptionCaught = null; ID3v24Frame frame = null; FrameBodyTSOP fb = null; try { frame = new ID3v24Frame(ID3v24Frames.FRAME_ID_ARTIST_SORT_ORDER); fb = FrameBodyTSOPTest.getInitialisedBody(); frame.setBody(fb); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v24Frames.FRAME_ID_ARTIST_SORT_ORDER, frame.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, fb.getTextEncoding()); assertFalse(ID3v24Frames.getInstanceOf().isExtensionFrames(frame.getIdentifier())); assertTrue(ID3v24Frames.getInstanceOf().isSupportedFrames(frame.getIdentifier())); assertEquals(FrameBodyTSOPTest.ARTIST_SORT, fb.getText()); } public void testCreateID3v23ITunesFrame() { Exception exceptionCaught = null; ID3v23Frame frame = null; FrameBodyTSOP fb = null; try { frame = new ID3v23Frame(ID3v23Frames.FRAME_ID_V3_ARTIST_SORT_ORDER_ITUNES); fb = FrameBodyTSOPTest.getInitialisedBody(); frame.setBody(fb); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v23Frames.FRAME_ID_V3_ARTIST_SORT_ORDER_ITUNES, frame.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, fb.getTextEncoding()); assertTrue(ID3v23Frames.getInstanceOf().isExtensionFrames(frame.getIdentifier())); assertFalse(ID3v23Frames.getInstanceOf().isSupportedFrames(frame.getIdentifier())); assertEquals(FrameBodyTSOPTest.ARTIST_SORT, fb.getText()); } public void testCreateID3v23MusicBrainzFrame() { Exception exceptionCaught = null; ID3v23Frame frame = null; FrameBodyXSOP fb = null; try { frame = new ID3v23Frame(ID3v23Frames.FRAME_ID_V3_ARTIST_SORT_ORDER_MUSICBRAINZ); fb = FrameBodyXSOPTest.getInitialisedBody(); frame.setBody(fb); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v23Frames.FRAME_ID_V3_ARTIST_SORT_ORDER_MUSICBRAINZ, frame.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, fb.getTextEncoding()); assertTrue(ID3v23Frames.getInstanceOf().isExtensionFrames(frame.getIdentifier())); assertFalse(ID3v23Frames.getInstanceOf().isSupportedFrames(frame.getIdentifier())); assertEquals(FrameBodyTSOPTest.ARTIST_SORT, fb.getText()); } public void testCreateID3v22Frame() { Exception exceptionCaught = null; ID3v22Frame frame = null; FrameBodyTSOP fb = null; try { frame = new ID3v22Frame(ID3v22Frames.FRAME_ID_V2_ARTIST_SORT_ORDER_ITUNES); fb = FrameBodyTSOPTest.getInitialisedBody(); frame.setBody(fb); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v22Frames.FRAME_ID_V2_ARTIST_SORT_ORDER_ITUNES, frame.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, fb.getTextEncoding()); assertTrue(ID3v22Frames.getInstanceOf().isExtensionFrames(frame.getIdentifier())); assertFalse(ID3v22Frames.getInstanceOf().isSupportedFrames(frame.getIdentifier())); assertEquals(FrameBodyTSOPTest.ARTIST_SORT, fb.getText()); } public void testSaveToFile() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3",new File("test1016.mp3")); MP3File mp3File = new MP3File(testFile); //Create and Save ID3v24Tag tag = new ID3v24Tag(); tag.setFrame(FrameTSOPTest.getInitialisedFrame()); mp3File.setID3v2Tag(tag); mp3File.save(); //Reload mp3File = new MP3File(testFile); ID3v24Frame frame = (ID3v24Frame) mp3File.getID3v2Tag().getFrame(ID3v24Frames.FRAME_ID_ARTIST_SORT_ORDER); FrameBodyTSOP body = (FrameBodyTSOP) frame.getBody(); assertEquals(TextEncoding.ISO_8859_1, body.getTextEncoding()); } public void testSaveEmptyFrameToFile() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3",new File("test1004.mp3")); MP3File mp3File = new MP3File(testFile); ID3v24Frame frame = new ID3v24Frame(ID3v24Frames.FRAME_ID_ARTIST_SORT_ORDER); frame.setBody(new FrameBodyTSOP()); //Create and Save ID3v24Tag tag = new ID3v24Tag(); tag.setFrame(frame); mp3File.setID3v2Tag(tag); mp3File.save(); //Reload mp3File = new MP3File(testFile); frame = (ID3v24Frame) mp3File.getID3v2Tag().getFrame(ID3v24Frames.FRAME_ID_ARTIST_SORT_ORDER); FrameBodyTSOP body = (FrameBodyTSOP) frame.getBody(); assertEquals(TextEncoding.ISO_8859_1, body.getTextEncoding()); } public void testConvertV24ToV23() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3",new File("test1005.mp3")); MP3File mp3File = new MP3File(testFile); //Create and Save ID3v24Tag tag = new ID3v24Tag(); tag.setFrame(FrameTSOPTest.getInitialisedFrame()); mp3File.setID3v2Tag(tag); mp3File.save(); //Reload and convert to v23 and save mp3File = new MP3File(testFile); mp3File.setID3v2TagOnly(new ID3v23Tag(mp3File.getID3v2TagAsv24())); mp3File.save(); //Reload mp3File = new MP3File(testFile); ID3v23Frame frame = (ID3v23Frame) mp3File.getID3v2Tag().getFrame(ID3v23Frames.FRAME_ID_V3_ARTIST_SORT_ORDER_ITUNES); FrameBodyTSOP body = (FrameBodyTSOP) frame.getBody(); assertEquals(TextEncoding.ISO_8859_1, body.getTextEncoding()); assertEquals(FrameBodyTSOPTest.ARTIST_SORT, body.getText()); } public void testConvertV24ToV22() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3",new File("test1006.mp3")); MP3File mp3File = new MP3File(testFile); //Create and Save ID3v24Tag tag = new ID3v24Tag(); tag.setFrame(FrameTSOPTest.getInitialisedFrame()); mp3File.setID3v2Tag(tag); mp3File.save(); //Reload and convert to v22 and save mp3File = new MP3File(testFile); mp3File.setID3v2TagOnly(new ID3v22Tag(mp3File.getID3v2TagAsv24())); mp3File.save(); //Reload mp3File = new MP3File(testFile); ID3v22Frame frame = (ID3v22Frame) mp3File.getID3v2Tag().getFrame(ID3v22Frames.FRAME_ID_V2_ARTIST_SORT_ORDER_ITUNES); FrameBodyTSOP body = (FrameBodyTSOP) frame.getBody(); assertEquals(TextEncoding.ISO_8859_1, body.getTextEncoding()); assertEquals(FrameBodyTSOPTest.ARTIST_SORT, body.getText()); } public void testConvertV23ITunesToV22() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3",new File("test1007.mp3")); MP3File mp3File = new MP3File(testFile); //Create and Save ID3v23Tag tag = new ID3v23Tag(); tag.setFrame(FrameTSOPTest.getInitialisedFrame()); mp3File.setID3v2TagOnly((ID3v23Tag) tag); mp3File.save(); //Reload and convert from v23 to v22 and save mp3File = new MP3File(testFile); mp3File.setID3v2TagOnly(new ID3v22Tag(mp3File.getID3v2Tag())); mp3File.save(); //Reload mp3File = new MP3File(testFile); ID3v22Frame frame = (ID3v22Frame) mp3File.getID3v2Tag().getFrame(ID3v22Frames.FRAME_ID_V2_ARTIST_SORT_ORDER_ITUNES); FrameBodyTSOP body = (FrameBodyTSOP) frame.getBody(); assertEquals(TextEncoding.ISO_8859_1, body.getTextEncoding()); assertEquals(FrameBodyTSOPTest.ARTIST_SORT, body.getText()); } public void testConvertV23MusicBrainzToV22() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3",new File("test1008.mp3")); MP3File mp3File = new MP3File(testFile); //Create and Save ID3v23Tag tag = new ID3v23Tag(); tag.setFrame(FrameTSOPTest.getV23InitialisedFrame()); mp3File.setID3v2TagOnly((ID3v23Tag) tag); mp3File.save(); //Reload and convert from v23 to v22 and save mp3File = new MP3File(testFile); mp3File.setID3v2TagOnly(new ID3v22Tag(mp3File.getID3v2Tag())); mp3File.save(); //Reload will be converted to same TST version for v22 mp3File = new MP3File(testFile); ID3v22Frame frame = (ID3v22Frame) mp3File.getID3v2Tag().getFrame(ID3v22Frames.FRAME_ID_V2_ARTIST_SORT_ORDER_ITUNES); FrameBodyTSOP body = (FrameBodyTSOP) frame.getBody(); assertEquals(TextEncoding.ISO_8859_1, body.getTextEncoding()); assertEquals(FrameBodyTSOPTest.ARTIST_SORT, body.getText()); } public void testConvertV22ToV24() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3",new File("test1009.mp3")); MP3File mp3File = new MP3File(testFile); //Create and Save ID3v22Tag tag = new ID3v22Tag(); //..Notes (uses v22Frame but frame body will be the v23/24 version) ID3v22Frame id3v22frame = new ID3v22Frame(ID3v22Frames.FRAME_ID_V2_ARTIST_SORT_ORDER_ITUNES); ((FrameBodyTSOP) id3v22frame.getBody()).setText(FrameBodyTSOPTest.ARTIST_SORT); tag.setFrame(id3v22frame); mp3File.setID3v2TagOnly((ID3v22Tag) tag); mp3File.save(); //Reload and convert from v22 to v24 and save mp3File = new MP3File(testFile); mp3File.setID3v2TagOnly(new ID3v24Tag(mp3File.getID3v2Tag())); mp3File.save(); //Reload mp3File = new MP3File(testFile); ID3v24Frame frame = (ID3v24Frame) mp3File.getID3v2Tag().getFrame(ID3v24Frames.FRAME_ID_ARTIST_SORT_ORDER); FrameBodyTSOP body = (FrameBodyTSOP) frame.getBody(); assertEquals(TextEncoding.ISO_8859_1, body.getTextEncoding()); assertEquals(FrameBodyTSOPTest.ARTIST_SORT, body.getText()); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/id3/UnsynchronizationTest.java0000644000175000017500000002356511305717447031133 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.audio.mp3.MP3File; import org.jaudiotagger.logging.Hex; import org.jaudiotagger.tag.Tag; import org.jaudiotagger.tag.TagOptionSingleton; import org.jaudiotagger.tag.datatype.Artwork; import org.jaudiotagger.tag.id3.framebody.FrameBodyAPIC; import javax.imageio.ImageIO; import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.io.File; /** * Test Itunes problems */ public class UnsynchronizationTest extends AbstractTestCase { private static final int FRAME_SIZE = 2049; /** * This tests unsynchronizing frame in v24 * * @throws Exception */ public void testv24TagCreateFrameUnsynced() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("Issue1.id3", "testV1.mp3"); //Read file as currently stands MP3File mp3File = new MP3File(testFile); ID3v24Tag v24tag = (ID3v24Tag) mp3File.getID3v2Tag(); assertFalse(v24tag.isUnsynchronization()); ID3v24Frame v24TitleFrame = (ID3v24Frame) v24tag.getFrame(ID3v24Frames.FRAME_ID_TITLE); assertNotNull(v24TitleFrame); assertFalse(((ID3v24Frame.EncodingFlags) v24TitleFrame.getEncodingFlags()).isUnsynchronised()); ID3v24Frame v24Imageframe = (ID3v24Frame) v24tag.getFrame(ID3v24Frames.FRAME_ID_ATTACHED_PICTURE); assertNotNull(v24Imageframe); assertTrue(((ID3v24Frame.EncodingFlags) v24Imageframe.getEncodingFlags()).isUnsynchronised()); FrameBodyAPIC fb = (FrameBodyAPIC) v24Imageframe.getBody(); //Write mp3 back to file , TagOptionSingleton.getInstance().setUnsyncTags(false); mp3File.save(); mp3File = new MP3File(testFile); v24tag = (ID3v24Tag) mp3File.getID3v2Tag(); assertFalse(v24tag.isUnsynchronization()); assertEquals(AbstractID3v2Tag.getV2TagSizeIfExists(testFile), mp3File.getMP3AudioHeader().getMp3StartByte()); v24TitleFrame = (ID3v24Frame) v24tag.getFrame(ID3v24Frames.FRAME_ID_TITLE); assertNotNull(v24TitleFrame); assertFalse(((ID3v24Frame.EncodingFlags) v24TitleFrame.getEncodingFlags()).isUnsynchronised()); v24Imageframe = (ID3v24Frame) v24tag.getFrame(ID3v24Frames.FRAME_ID_ATTACHED_PICTURE); assertNotNull(v24Imageframe); fb = (FrameBodyAPIC) v24Imageframe.getBody(); assertFalse(((ID3v24Frame.EncodingFlags) v24Imageframe.getEncodingFlags()).isUnsynchronised()); //Enable unsynchronization and write mp3 back to file , only APIC requires unsynchronization TagOptionSingleton.getInstance().setUnsyncTags(true); mp3File.save(); mp3File = new MP3File(testFile); v24tag = (ID3v24Tag) mp3File.getID3v2Tag(); assertFalse(v24tag.isUnsynchronization()); assertEquals(AbstractID3v2Tag.getV2TagSizeIfExists(testFile), mp3File.getMP3AudioHeader().getMp3StartByte()); //this does not need unsynchronizing, even though now enabled v24TitleFrame = (ID3v24Frame) v24tag.getFrame(ID3v24Frames.FRAME_ID_TITLE); assertNotNull(v24TitleFrame); assertFalse(((ID3v24Frame.EncodingFlags) v24TitleFrame.getEncodingFlags()).isUnsynchronised()); v24Imageframe = (ID3v24Frame) v24tag.getFrame(ID3v24Frames.FRAME_ID_ATTACHED_PICTURE); assertNotNull(v24Imageframe); fb = (FrameBodyAPIC) v24Imageframe.getBody(); assertTrue(((ID3v24Frame.EncodingFlags) v24Imageframe.getEncodingFlags()).isUnsynchronised()); } /** * This tests unsynchronizing tags in v23 * * @throws Exception */ public void testv23TagCreateTagUnsynced() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("Issue1.id3", "testV1.mp3"); //Read file as currently stands MP3File mp3File = new MP3File(testFile); ID3v24Tag v24tag = (ID3v24Tag) mp3File.getID3v2Tag(); assertFalse(v24tag.isUnsynchronization()); //Convert to v23 ID3v23Tag v23tag = new ID3v23Tag((AbstractTag) v24tag); mp3File.setID3v2Tag(v23tag); //Write mp3 back to file TagOptionSingleton.getInstance().setUnsyncTags(false); mp3File.save(); mp3File = new MP3File(testFile); v23tag = (ID3v23Tag) mp3File.getID3v2Tag(); assertFalse(v23tag.isUnsynchronization()); assertEquals(AbstractID3v2Tag.getV2TagSizeIfExists(testFile), mp3File.getMP3AudioHeader().getMp3StartByte()); //Enable unsynchronization and write mp3 back to file, only APIC requires unsynchronization TagOptionSingleton.getInstance().setUnsyncTags(true); mp3File.save(); mp3File = new MP3File(testFile); v23tag = (ID3v23Tag) mp3File.getID3v2Tag(); assertTrue(v23tag.isUnsynchronization()); assertEquals(AbstractID3v2Tag.getV2TagSizeIfExists(testFile), mp3File.getMP3AudioHeader().getMp3StartByte()); } /** * This tests unsynchronizing tags in v22 * * @throws Exception */ public void testv22TagCreateTagUnsynced() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("Issue1.id3", "testV1.mp3"); //Read file as currently stands MP3File mp3File = new MP3File(testFile); ID3v24Tag v24tag = (ID3v24Tag) mp3File.getID3v2Tag(); assertFalse(v24tag.isUnsynchronization()); //Convert to v22 ID3v22Tag v22tag = new ID3v22Tag((AbstractTag) v24tag); mp3File.setID3v2Tag(v22tag); //Write mp3 back to file TagOptionSingleton.getInstance().setUnsyncTags(false); mp3File.save(); mp3File = new MP3File(testFile); v22tag = (ID3v22Tag) mp3File.getID3v2Tag(); assertFalse(v22tag.isUnsynchronization()); assertEquals(AbstractID3v2Tag.getV2TagSizeIfExists(testFile), mp3File.getMP3AudioHeader().getMp3StartByte()); //Enable unsynchronization and write mp3 back to file , only APIC requires unsynchronization TagOptionSingleton.getInstance().setUnsyncTags(true); mp3File.save(); mp3File = new MP3File(testFile); v22tag = (ID3v22Tag) mp3File.getID3v2Tag(); assertTrue(v22tag.isUnsynchronization()); assertEquals(AbstractID3v2Tag.getV2TagSizeIfExists(testFile), mp3File.getMP3AudioHeader().getMp3StartByte()); } /** * Test writing Artwork to Mp3 ID3v23 compares not synchronized to unsynchronised */ public void testWriteLargeunsynchronizedFields() { File testFile = null; File testFile2 = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); testFile2 = AbstractTestCase.copyAudioToTmp("testV1.mp3",new File("testV1-nonsynced.mp3")); //Save Unsynced TagOptionSingleton.getInstance().setUnsyncTags(true); AudioFile af = AudioFileIO.read(testFile); af.setTag(new ID3v23Tag()); ID3v23Tag v23TagUnsynced = (ID3v23Tag)af.getTag(); assertFalse(v23TagUnsynced.isUnsynchronization()); Tag unsyncedTag = af.getTag(); Artwork artworkUnsynced = Artwork.createArtworkFromFile(new File("testdata/coverart_large.jpg")); unsyncedTag.setField(artworkUnsynced); af.commit(); //Save Notsynced TagOptionSingleton.getInstance().setUnsyncTags(false); af = AudioFileIO.read(testFile2); af.setTag(new ID3v23Tag()); ID3v23Tag v23TagNotsynced = (ID3v23Tag)af.getTag(); assertFalse(v23TagNotsynced.isUnsynchronization()); Tag notSyncedTag = af.getTag(); Artwork artworkNotsynced = Artwork.createArtworkFromFile(new File("testdata/coverart_large.jpg")); notSyncedTag.setField(artworkNotsynced); af.commit(); //Now read back ok long start = System.nanoTime(); af = AudioFileIO.read(testFile2); long time = System.nanoTime() - start; System.out.printf("NOTSYNCED Took %6.3f ms \n", time/1e6); notSyncedTag = af.getTag(); v23TagNotsynced = (ID3v23Tag)notSyncedTag; assertEquals(1,notSyncedTag.getArtworkList().size()); artworkNotsynced = notSyncedTag.getArtworkList().get(0); //Now read back ok start = System.nanoTime(); af = AudioFileIO.read(testFile); time = System.nanoTime() - start; System.out.printf("UNSYCNCED Took %6.3f ms \n", time/1e6); unsyncedTag = af.getTag(); v23TagUnsynced = (ID3v23Tag)unsyncedTag; assertTrue(v23TagUnsynced.isUnsynchronization()); assertEquals(1,unsyncedTag.getArtworkList().size()); artworkUnsynced = unsyncedTag.getArtworkList().get(0); int count=0; assertEquals(114425, artworkUnsynced.getBinaryData().length); assertEquals(114425, artworkNotsynced.getBinaryData().length); boolean matches = true; for(int i=0;i< artworkUnsynced.getBinaryData().length;i++) { if((artworkUnsynced.getBinaryData()[i])!=(artworkNotsynced.getBinaryData()[i])) { System.out.println(i+":"+ Hex.asHex(artworkNotsynced.getBinaryData()[i])+":"+Hex.asHex(artworkUnsynced.getBinaryData()[i])); matches=false; break; } } assertTrue(matches); BufferedImage bi = ImageIO.read(new ByteArrayInputStream(artworkNotsynced.getBinaryData())); bi = ImageIO.read(new ByteArrayInputStream(artworkUnsynced.getBinaryData())); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/id3/FramePICAndAPICTest.java0000644000175000017500000001746611041064726030030 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.mp3.MP3File; import org.jaudiotagger.tag.id3.framebody.FrameBodyAPIC; import org.jaudiotagger.tag.id3.framebody.FrameBodyAPICTest; import org.jaudiotagger.tag.id3.framebody.FrameBodyPIC; import org.jaudiotagger.tag.id3.framebody.FrameBodyPICTest; import java.io.File; /** * Test PIC (v22) and APIC (v23,v24) frames */ public class FramePICAndAPICTest extends AbstractTestCase { public static String cmp(byte[] a, byte[] b) { if (a.length != b.length) { return "length of byte arrays differ (" + a.length + "!=" + b.length + ")"; } for (int i = 0; i < a.length; i++) { if (a[i] != b[i]) { return "byte arrays differ at offset " + i + " (" + a[i] + "!=" + b[i] + ")"; } } return null; } public static ID3v24Frame getV24InitialisedFrame() { ID3v24Frame frame = new ID3v24Frame(ID3v24Frames.FRAME_ID_ATTACHED_PICTURE); FrameBodyAPIC fb = FrameBodyAPICTest.getInitialisedBody(); frame.setBody(fb); return frame; } public static ID3v23Frame getV23InitialisedFrame() { ID3v23Frame frame = new ID3v23Frame(ID3v23Frames.FRAME_ID_V3_ATTACHED_PICTURE); FrameBodyAPIC fb = FrameBodyAPICTest.getInitialisedBody(); frame.setBody(fb); return frame; } public static ID3v22Frame getV22InitialisedFrame() { ID3v22Frame frame = new ID3v22Frame(ID3v22Frames.FRAME_ID_V2_ATTACHED_PICTURE); FrameBodyPIC fb = FrameBodyPICTest.getInitialisedBody(); frame.setBody(fb); return frame; } public void testCreateID3v24Frame() { Exception exceptionCaught = null; ID3v24Frame frame = null; FrameBodyAPIC fb = null; try { frame = new ID3v24Frame(ID3v24Frames.FRAME_ID_ATTACHED_PICTURE); fb = FrameBodyAPICTest.getInitialisedBody(); frame.setBody(fb); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v24Frames.FRAME_ID_ATTACHED_PICTURE, frame.getIdentifier()); assertFalse(ID3v24Frames.getInstanceOf().isExtensionFrames(frame.getIdentifier())); assertTrue(ID3v24Frames.getInstanceOf().isSupportedFrames(frame.getIdentifier())); assertEquals(FrameBodyAPICTest.DESCRIPTION, fb.getDescription()); } public void testCreateID3v23Frame() { Exception exceptionCaught = null; ID3v23Frame frame = null; FrameBodyAPIC fb = null; try { frame = new ID3v23Frame(ID3v23Frames.FRAME_ID_V3_ATTACHED_PICTURE); fb = FrameBodyAPICTest.getInitialisedBody(); frame.setBody(fb); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v23Frames.FRAME_ID_V3_ATTACHED_PICTURE, frame.getIdentifier()); assertFalse(ID3v23Frames.getInstanceOf().isExtensionFrames(frame.getIdentifier())); assertTrue(ID3v23Frames.getInstanceOf().isSupportedFrames(frame.getIdentifier())); assertEquals(FrameBodyAPICTest.DESCRIPTION, fb.getDescription()); } public void testCreateID3v22Frame() { Exception exceptionCaught = null; ID3v22Frame frame = null; FrameBodyPIC fb = null; try { frame = new ID3v22Frame(ID3v22Frames.FRAME_ID_V2_ATTACHED_PICTURE); fb = FrameBodyPICTest.getInitialisedBody(); frame.setBody(fb); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v22Frames.FRAME_ID_V2_ATTACHED_PICTURE, frame.getIdentifier()); assertFalse(ID3v22Frames.getInstanceOf().isExtensionFrames(frame.getIdentifier())); assertTrue(ID3v22Frames.getInstanceOf().isSupportedFrames(frame.getIdentifier())); assertEquals(FrameBodyPICTest.DESCRIPTION, fb.getDescription()); } public void testSaveToFile() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); MP3File mp3File = new MP3File(testFile); //Create and Save ID3v24Tag tag = new ID3v24Tag(); tag.setFrame(FramePICAndAPICTest.getV24InitialisedFrame()); mp3File.setID3v2Tag(tag); mp3File.save(); //Reload mp3File = new MP3File(testFile); ID3v24Frame frame = (ID3v24Frame) mp3File.getID3v2Tag().getFrame(ID3v24Frames.FRAME_ID_ATTACHED_PICTURE); assertTrue(frame != null); FrameBodyAPIC body = (FrameBodyAPIC) frame.getBody(); assertTrue(body instanceof FrameBodyAPIC); assertEquals(FrameBodyAPICTest.DESCRIPTION, body.getDescription()); } public void testConvertV24ToV23() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); MP3File mp3File = new MP3File(testFile); //Create and Save ID3v24Tag tag = new ID3v24Tag(); tag.setFrame(FramePICAndAPICTest.getV24InitialisedFrame()); mp3File.setID3v2Tag(tag); mp3File.save(); //Reload and convert to v23 and save mp3File = new MP3File(testFile); mp3File.setID3v2TagOnly(new ID3v23Tag(mp3File.getID3v2TagAsv24())); mp3File.save(); //Reload mp3File = new MP3File(testFile); ID3v23Frame frame = (ID3v23Frame) mp3File.getID3v2Tag().getFrame(ID3v23Frames.FRAME_ID_V3_ATTACHED_PICTURE); assertTrue(frame != null); FrameBodyAPIC body = (FrameBodyAPIC) frame.getBody(); assertTrue(body instanceof FrameBodyAPIC); assertEquals(FrameBodyAPICTest.DESCRIPTION, body.getDescription()); } public void testConvertV24ToV22() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); MP3File mp3File = new MP3File(testFile); //Create and Save ID3v24Tag tag = new ID3v24Tag(); tag.setFrame(FramePICAndAPICTest.getV24InitialisedFrame()); mp3File.setID3v2Tag(tag); mp3File.save(); //Reload and convert to v22 and save mp3File = new MP3File(testFile); mp3File.setID3v2TagOnly(new ID3v22Tag(mp3File.getID3v2TagAsv24())); mp3File.save(); //Reload mp3File = new MP3File(testFile); ID3v22Frame frame = (ID3v22Frame) mp3File.getID3v2Tag().getFrame(ID3v22Frames.FRAME_ID_V2_ATTACHED_PICTURE); assertTrue(frame != null); FrameBodyPIC body = (FrameBodyPIC) frame.getBody(); assertTrue(body instanceof FrameBodyPIC); assertEquals(FrameBodyAPICTest.DESCRIPTION, body.getDescription()); } public void testConvertV22ToV24() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); MP3File mp3File = new MP3File(testFile); //Create and Save ID3v22Tag tag = new ID3v22Tag(); //..Notes (uses v22Frame but frame body will be the v23/24 version) tag.setFrame(FramePICAndAPICTest.getV22InitialisedFrame()); mp3File.setID3v2TagOnly((ID3v22Tag) tag); mp3File.save(); //Reload and convert from v22 to v24 and save mp3File = new MP3File(testFile); mp3File.setID3v2TagOnly(new ID3v24Tag(mp3File.getID3v2Tag())); mp3File.save(); //Reload mp3File = new MP3File(testFile); ID3v24Frame frame = (ID3v24Frame) mp3File.getID3v2Tag().getFrame(ID3v24Frames.FRAME_ID_ATTACHED_PICTURE); assertTrue(frame != null); FrameBodyAPIC body = (FrameBodyAPIC) frame.getBody(); assertTrue(body instanceof FrameBodyAPIC); assertEquals(FrameBodyPICTest.DESCRIPTION, body.getDescription()); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/id3/FrameTPOSTest.java0000644000175000017500000000353011470746136027115 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.audio.mp3.MP3File; import org.jaudiotagger.tag.FieldKey; import org.jaudiotagger.tag.Tag; import org.jaudiotagger.tag.TagField; import org.jaudiotagger.tag.id3.framebody.FrameBodyTRCK; import org.jaudiotagger.tag.id3.framebody.FrameBodyTRCKTest; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; import java.io.File; import java.util.Iterator; /** * Test TPOSFrame */ public class FrameTPOSTest extends AbstractTestCase { public void testMergingMultipleFrames() throws Exception { ID3v24Tag tag = new ID3v24Tag(); tag.setField(tag.createField(FieldKey.DISC_NO,"1")); tag.setField(tag.createField(FieldKey.DISC_TOTAL,"10")); assertEquals("1",tag.getFirst(FieldKey.DISC_NO)); assertEquals("10",tag.getFirst(FieldKey.DISC_TOTAL)); assertTrue(tag.getFrame("TPOS") instanceof AbstractID3v2Frame); } public void testDiscNo() { Exception exceptionCaught=null; File orig = new File("testdata", "test82.mp3"); if (!orig.isFile()) { System.err.println("Unable to test file - not available"); return; } try { AudioFile af = AudioFileIO.read(orig); Tag newTags = (Tag)af.getTag(); Iterator i = newTags.getFields(); while(i.hasNext()) { System.out.println(i.next().getId()); } //Integer discNo = Integer.parseInt(newTags.get("Disc Number")); //tag.setField(FieldKey.DISC_NO,discNo.toString()) } catch(Exception e) { exceptionCaught=e; } assertNull(exceptionCaught); } }libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/id3/FrameTPUBTest.java0000644000175000017500000000730011331770237027074 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.tag.FieldKey; import org.jaudiotagger.tag.Tag; import org.jaudiotagger.tag.id3.framebody.FrameBodyTPE3; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; /** */ public class FrameTPUBTest extends AbstractTestCase { public void testGenericv22() throws Exception { Exception e=null; try { Tag tag = new ID3v22Tag(); tag.addField(FieldKey.RECORD_LABEL,"testrecordlabel"); assertEquals("testrecordlabel",tag.getFirst(FieldKey.RECORD_LABEL)); assertEquals("testrecordlabel",tag.getFirst("TPB")); } catch(Exception ex) { e=ex; ex.printStackTrace(); } assertNull(e); } public void testID3Specificv22() throws Exception { Exception e=null; try { ID3v22Tag tag = new ID3v22Tag(); ID3v22Frame frame = new ID3v22Frame("TPB"); frame.setBody(new FrameBodyTPE3(TextEncoding.ISO_8859_1,"testrecordlabel")); tag.addFrame(frame); assertEquals("testrecordlabel",tag.getFirst(FieldKey.RECORD_LABEL)); assertEquals("testrecordlabel",tag.getFirst("TPB")); } catch(Exception ex) { e=ex; ex.printStackTrace(); } assertNull(e); } public void testGenericv23() throws Exception { Exception e=null; try { Tag tag = new ID3v23Tag(); tag.addField(FieldKey.RECORD_LABEL,"testrecordlabel"); assertEquals("testrecordlabel",tag.getFirst(FieldKey.RECORD_LABEL)); assertEquals("testrecordlabel",tag.getFirst("TPUB")); } catch(Exception ex) { e=ex; ex.printStackTrace(); } assertNull(e); } public void testID3Specificv23() throws Exception { Exception e=null; try { ID3v23Tag tag = new ID3v23Tag(); ID3v23Frame frame = new ID3v23Frame("TPUB"); frame.setBody(new FrameBodyTPE3(TextEncoding.ISO_8859_1,"testrecordlabel")); tag.addFrame(frame); assertEquals("testrecordlabel",tag.getFirst(FieldKey.RECORD_LABEL)); assertEquals("testrecordlabel",tag.getFirst("TPUB")); } catch(Exception ex) { e=ex; ex.printStackTrace(); } assertNull(e); } public void testGenericv24() throws Exception { Exception e=null; try { Tag tag = new ID3v24Tag(); tag.addField(FieldKey.RECORD_LABEL,"testrecordlabel"); assertEquals("testrecordlabel",tag.getFirst(FieldKey.RECORD_LABEL)); assertEquals("testrecordlabel",tag.getFirst("TPUB")); } catch(Exception ex) { e=ex; ex.printStackTrace(); } assertNull(e); } public void testID3Specificv24() throws Exception { Exception e=null; try { ID3v24Tag tag = new ID3v24Tag(); ID3v24Frame frame = new ID3v24Frame("TPUB"); frame.setBody(new FrameBodyTPE3(TextEncoding.ISO_8859_1,"testrecordlabel")); tag.addFrame(frame); assertEquals("testrecordlabel",tag.getFirst(FieldKey.RECORD_LABEL)); assertEquals("testrecordlabel",tag.getFirst("TPUB")); } catch(Exception ex) { e=ex; ex.printStackTrace(); } assertNull(e); } }libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/id3/Unicode24TagTest.java0000644000175000017500000004102011276777123027545 0ustar drazzibdrazzib/* * Jaudiotagger Copyright (C)2004,2005 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can getFields a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.mp3.MP3File; import org.jaudiotagger.tag.TagOptionSingleton; import org.jaudiotagger.tag.id3.framebody.FrameBodyTPE1; import org.jaudiotagger.tag.id3.framebody.FrameBodyTPE1Test; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; import java.io.File; /** * */ public class Unicode24TagTest extends TestCase { /** * Constructor * * @param arg0 */ public Unicode24TagTest(String arg0) { super(arg0); } /** * Command line entrance. * * @param args */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } ///////////////////////////////////////////////////////////////////////// // TestCase classes to override ///////////////////////////////////////////////////////////////////////// /** * */ protected void setUp() { TagOptionSingleton.getInstance().setToDefault(); } /** * */ protected void tearDown() { } /** * */ // protected void runTest() // { // } /** * Builds the Test Suite. * * @return the Test Suite. */ public static Test suite() { return new TestSuite(Unicode24TagTest.class); } /** * Create a String that only contains text within IS8859 charset so should be * as ISO_88859 * * @throws Exception */ public void testCreateISO8859EncodedSizeTerminatedString() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3", new File("testISO8859.mp3")); MP3File mp3File = new MP3File(testFile); ID3v24Frame frame = new ID3v24Frame(ID3v24Frames.FRAME_ID_ARTIST); Exception exceptionCaught = null; FrameBodyTPE1 fb = null; try { fb = FrameBodyTPE1Test.getInitialisedBody(); frame.setBody(fb); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v24Frames.FRAME_ID_ARTIST, fb.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, fb.getTextEncoding()); assertEquals(FrameBodyTPE1Test.TPE1_TEST_STRING, fb.getText()); //Create and Save ID3v24Tag tag = new ID3v24Tag(); tag.setFrame(frame); mp3File.setID3v2Tag(tag); mp3File.save(); //Reload, should be written as UTF16 because of the text mp3File = new MP3File(testFile); frame = (ID3v24Frame) mp3File.getID3v2Tag().getFrame(ID3v24Frames.FRAME_ID_ARTIST); FrameBodyTPE1 body = (FrameBodyTPE1) frame.getBody(); assertEquals(ID3v24Frames.FRAME_ID_ARTIST, fb.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, fb.getTextEncoding()); assertEquals(FrameBodyTPE1Test.TPE1_TEST_STRING, fb.getText()); } /** * Can explicitly uses UTF-16 even if not required * as UTf16 by default * * @throws Exception */ public void testCreateUTF16EncodedSizeTerminatedString() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3", new File("testutf16.mp3")); MP3File mp3File = new MP3File(testFile); ID3v24Frame frame = new ID3v24Frame(ID3v24Frames.FRAME_ID_ARTIST); Exception exceptionCaught = null; FrameBodyTPE1 fb = null; try { fb = FrameBodyTPE1Test.getInitialisedBody(); fb.setTextEncoding(TextEncoding.UTF_16); frame.setBody(fb); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v24Frames.FRAME_ID_ARTIST, fb.getIdentifier()); assertEquals(TextEncoding.UTF_16, fb.getTextEncoding()); assertEquals(FrameBodyTPE1Test.TPE1_TEST_STRING, fb.getText()); //Create and Save ID3v24Tag tag = new ID3v24Tag(); tag.setFrame(frame); mp3File.setID3v2Tag(tag); mp3File.save(); //Reload, should be written as UTF16 because of the text mp3File = new MP3File(testFile); frame = (ID3v24Frame) mp3File.getID3v2Tag().getFrame(ID3v24Frames.FRAME_ID_ARTIST); FrameBodyTPE1 body = (FrameBodyTPE1) frame.getBody(); assertEquals(ID3v24Frames.FRAME_ID_ARTIST, body.getIdentifier()); assertEquals(TextEncoding.UTF_16, body.getTextEncoding()); assertEquals(FrameBodyTPE1Test.TPE1_TEST_STRING, body.getText()); } /** * Create a String that contains text outside of the IS8859 charset should be written * as UTf16 by default * * @throws Exception */ public void testCreateUTF16AutoEncodedSizeTerminatedString() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3", new File("testutf16-2.mp3")); MP3File mp3File = new MP3File(testFile); ID3v24Frame frame = new ID3v24Frame(ID3v24Frames.FRAME_ID_ARTIST); Exception exceptionCaught = null; FrameBodyTPE1 fb = null; try { fb = FrameBodyTPE1Test.getUnicodeRequiredInitialisedBody(); frame.setBody(fb); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v24Frames.FRAME_ID_ARTIST, fb.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, fb.getTextEncoding()); assertEquals(FrameBodyTPE1Test.TPE1_UNICODE_REQUIRED_TEST_STRING, fb.getText()); //Create and Save ID3v24Tag tag = new ID3v24Tag(); tag.setFrame(frame); mp3File.setID3v2Tag(tag); mp3File.save(); //Reload, should be written as UTF16 because of the text mp3File = new MP3File(testFile); frame = (ID3v24Frame) mp3File.getID3v2Tag().getFrame(ID3v24Frames.FRAME_ID_ARTIST); FrameBodyTPE1 body = (FrameBodyTPE1) frame.getBody(); assertEquals(ID3v24Frames.FRAME_ID_ARTIST, body.getIdentifier()); assertEquals(TextEncoding.UTF_16, body.getTextEncoding()); assertEquals(FrameBodyTPE1Test.TPE1_UNICODE_REQUIRED_TEST_STRING, body.getText()); } /** * Create a String that contains text outside of the IS8859 charset should be written * as UTf8 because overridden default * * @throws Exception */ public void testCreateUTF8AutoEncodedSizeTerminatedString() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3", new File("testutf8.mp3")); MP3File mp3File = new MP3File(testFile); ID3v24Frame frame = new ID3v24Frame(ID3v24Frames.FRAME_ID_ARTIST); Exception exceptionCaught = null; FrameBodyTPE1 fb = null; try { fb = FrameBodyTPE1Test.getUnicodeRequiredInitialisedBody(); frame.setBody(fb); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v24Frames.FRAME_ID_ARTIST, fb.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, fb.getTextEncoding()); assertEquals(FrameBodyTPE1Test.TPE1_UNICODE_REQUIRED_TEST_STRING, fb.getText()); //Modify tag options TagOptionSingleton.getInstance().setId3v24UnicodeTextEncoding(TextEncoding.UTF_8); //Create and Save ID3v24Tag tag = new ID3v24Tag(); tag.setFrame(frame); mp3File.setID3v2Tag(tag); mp3File.save(); //Reload, should be written as UTF16 because of the text mp3File = new MP3File(testFile); frame = (ID3v24Frame) mp3File.getID3v2Tag().getFrame(ID3v24Frames.FRAME_ID_ARTIST); FrameBodyTPE1 body = (FrameBodyTPE1) frame.getBody(); assertEquals(ID3v24Frames.FRAME_ID_ARTIST, body.getIdentifier()); assertEquals(TextEncoding.UTF_8, body.getTextEncoding()); assertEquals(FrameBodyTPE1Test.TPE1_UNICODE_REQUIRED_TEST_STRING, body.getText()); } /** * Strings can bbe written to UTF16BE if text encoding explicitly set * * @throws Exception */ public void testCreateUTF16BEEncodedSizeTerminatedString() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3", new File("testutf16be.mp3")); MP3File mp3File = new MP3File(testFile); ID3v24Frame frame = new ID3v24Frame(ID3v24Frames.FRAME_ID_ARTIST); Exception exceptionCaught = null; FrameBodyTPE1 fb = null; try { fb = FrameBodyTPE1Test.getUnicodeRequiredInitialisedBody(); fb.setTextEncoding(TextEncoding.UTF_16BE); frame.setBody(fb); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v24Frames.FRAME_ID_ARTIST, fb.getIdentifier()); assertEquals(TextEncoding.UTF_16BE, fb.getTextEncoding()); assertEquals(FrameBodyTPE1Test.TPE1_UNICODE_REQUIRED_TEST_STRING, fb.getText()); //Create and Save ID3v24Tag tag = new ID3v24Tag(); tag.setFrame(frame); mp3File.setID3v2Tag(tag); mp3File.save(); //Reload, should be written as UTF16BE mp3File = new MP3File(testFile); frame = (ID3v24Frame) mp3File.getID3v2Tag().getFrame(ID3v24Frames.FRAME_ID_ARTIST); FrameBodyTPE1 body = (FrameBodyTPE1) frame.getBody(); assertEquals(ID3v24Frames.FRAME_ID_ARTIST, body.getIdentifier()); assertEquals(TextEncoding.UTF_16BE, body.getTextEncoding()); assertEquals(FrameBodyTPE1Test.TPE1_UNICODE_REQUIRED_TEST_STRING, body.getText()); } /** * Strings can bbe written to UTF8 if text encoding explicitly set * * @throws Exception */ public void testCreateUTF8EncodedSizeTerminatedString() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3", new File("testutf8enc.mp3")); MP3File mp3File = new MP3File(testFile); ID3v24Frame frame = new ID3v24Frame(ID3v24Frames.FRAME_ID_ARTIST); Exception exceptionCaught = null; FrameBodyTPE1 fb = null; try { fb = FrameBodyTPE1Test.getUnicodeRequiredInitialisedBody(); fb.setTextEncoding(TextEncoding.UTF_8); frame.setBody(fb); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v24Frames.FRAME_ID_ARTIST, fb.getIdentifier()); assertEquals(TextEncoding.UTF_8, fb.getTextEncoding()); assertEquals(FrameBodyTPE1Test.TPE1_UNICODE_REQUIRED_TEST_STRING, fb.getText()); //Create and Save ID3v24Tag tag = new ID3v24Tag(); tag.setFrame(frame); mp3File.setID3v2Tag(tag); mp3File.save(); //Reload, should be written as UTF8 mp3File = new MP3File(testFile); frame = (ID3v24Frame) mp3File.getID3v2Tag().getFrame(ID3v24Frames.FRAME_ID_ARTIST); FrameBodyTPE1 body = (FrameBodyTPE1) frame.getBody(); assertEquals(ID3v24Frames.FRAME_ID_ARTIST, body.getIdentifier()); assertEquals(TextEncoding.UTF_8, body.getTextEncoding()); assertEquals(FrameBodyTPE1Test.TPE1_UNICODE_REQUIRED_TEST_STRING, body.getText()); } public void testv24TagsWithUTF8EncodingMaintainedOnSave() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("issue109-2.id3", "testV1.mp3"); //Read file as currently stands MP3File mp3File = new MP3File(testFile); ID3v24Tag v24tag = (ID3v24Tag) mp3File.getID3v2Tag(); //Currently contains tags with utf8 textencodings ID3v24Frame artistFrame = (ID3v24Frame) v24tag.getFrame(ID3v24Frames.FRAME_ID_ARTIST); FrameBodyTPE1 body = (FrameBodyTPE1) artistFrame.getBody(); assertEquals(ID3v23Frames.FRAME_ID_V3_ARTIST, body.getIdentifier()); assertEquals(TextEncoding.UTF_8, body.getTextEncoding()); //Save mp3File.save(); //Read file after save mp3File = new MP3File(testFile); v24tag = (ID3v24Tag) mp3File.getID3v2Tag(); artistFrame = (ID3v24Frame) v24tag.getFrame(ID3v24Frames.FRAME_ID_ARTIST); body = (FrameBodyTPE1) artistFrame.getBody(); assertEquals(ID3v24Frames.FRAME_ID_ARTIST, body.getIdentifier()); //Text Encoding has been corrected ( note the text could use ISO_8859 but because the user has selected //a Unicode text encoding the default behaviour is to just conver to a valid text encoding for this id3 version assertEquals(TextEncoding.UTF_8, body.getTextEncoding()); } public void testv24TagsWithUTF8OverriddenByDefaultOnSave() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("issue109-2.id3", "testV1.mp3"); //Read file as currently stands MP3File mp3File = new MP3File(testFile); ID3v24Tag v24tag = (ID3v24Tag) mp3File.getID3v2Tag(); //Currently contains tags with utf8 textencodings ID3v24Frame artistFrame = (ID3v24Frame) v24tag.getFrame(ID3v24Frames.FRAME_ID_ARTIST); FrameBodyTPE1 body = (FrameBodyTPE1) artistFrame.getBody(); assertEquals(ID3v23Frames.FRAME_ID_V3_ARTIST, body.getIdentifier()); assertEquals(TextEncoding.UTF_8, body.getTextEncoding()); //Modify tag options //So will default to default on save (default is ISO8859) TagOptionSingleton.getInstance().setResetTextEncodingForExistingFrames(true); //Save mp3File.save(); //Read file after save mp3File = new MP3File(testFile); v24tag = (ID3v24Tag) mp3File.getID3v2Tag(); artistFrame = (ID3v24Frame) v24tag.getFrame(ID3v24Frames.FRAME_ID_ARTIST); body = (FrameBodyTPE1) artistFrame.getBody(); assertEquals(ID3v24Frames.FRAME_ID_ARTIST, body.getIdentifier()); //Text Encoding has been corrected ( note the text could use ISO_8859 but because the user has selected //a Unicode text encoding the default behaviour is to just conver to a valid text encoding for this id3 version assertEquals(TextEncoding.ISO_8859_1, body.getTextEncoding()); } public void testv24TagsWithUTF8OverriddenByDefaultsOnSave() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("issue109-2.id3", "testV1.mp3"); //Read file as currently stands MP3File mp3File = new MP3File(testFile); ID3v24Tag v24tag = (ID3v24Tag) mp3File.getID3v2Tag(); //Currently contains tags with utf8 textencodings ID3v24Frame artistFrame = (ID3v24Frame) v24tag.getFrame(ID3v24Frames.FRAME_ID_ARTIST); FrameBodyTPE1 body = (FrameBodyTPE1) artistFrame.getBody(); assertEquals(ID3v23Frames.FRAME_ID_V3_ARTIST, body.getIdentifier()); assertEquals(TextEncoding.UTF_8, body.getTextEncoding()); //Modify tag options //So will default to default on save (default is ISO8859) TagOptionSingleton.getInstance().setResetTextEncodingForExistingFrames(true); TagOptionSingleton.getInstance().setId3v24DefaultTextEncoding(TextEncoding.UTF_16); //Save mp3File.save(); //Read file after save mp3File = new MP3File(testFile); v24tag = (ID3v24Tag) mp3File.getID3v2Tag(); artistFrame = (ID3v24Frame) v24tag.getFrame(ID3v24Frames.FRAME_ID_ARTIST); body = (FrameBodyTPE1) artistFrame.getBody(); assertEquals(ID3v24Frames.FRAME_ID_ARTIST, body.getIdentifier()); //Text Encoding has been defaulted by tagoption - no unicode required assertEquals(TextEncoding.UTF_16, body.getTextEncoding()); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/id3/FrameTIT1Test.java0000644000175000017500000000156511331564261027050 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.tag.FieldKey; import org.jaudiotagger.tag.Tag; import org.jaudiotagger.tag.id3.framebody.FrameBodyTPE1; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; /** */ public class FrameTIT1Test extends AbstractTestCase { public void testID3Specific() throws Exception { Exception e=null; try { ID3v23Tag tag = new ID3v23Tag(); ID3v23Frame frame = new ID3v23Frame("TIT1"); frame.setBody(new FrameBodyTPE1(TextEncoding.ISO_8859_1,"testgrouping")); tag.addFrame(frame); assertEquals("testgrouping",tag.getFirst("TIT1")); } catch(Exception ex) { e=ex; ex.printStackTrace(); } assertNull(e); } }libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/id3/framebody/0000755000175000017500000000000011556363200025611 5ustar drazzibdrazziblibjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/id3/framebody/FrameBodyTPOSTest.java0000644000175000017500000001245611276777123031716 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.tag.TagOptionSingleton; import org.jaudiotagger.tag.id3.ID3v24Frames; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; /** * Test TPOSFrameBody */ public class FrameBodyTPOSTest extends AbstractTestCase { public static FrameBodyTPOS getInitialisedBody() { FrameBodyTPOS fb = new FrameBodyTPOS(); fb.setDiscNo(1); fb.setDiscTotal(11); return fb; } public void testCreateFrameBodyStringConstructor() { TagOptionSingleton.getInstance().setPadNumbers(false); Exception exceptionCaught = null; FrameBodyTPOS fb = null; try { fb = new FrameBodyTPOS(TextEncoding.ISO_8859_1, "1/11"); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v24Frames.FRAME_ID_SET, fb.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, fb.getTextEncoding()); assertEquals(1,fb.getDiscNo().intValue()); assertEquals(11,fb.getDiscTotal().intValue()); assertEquals("1/11", fb.getText()); } public void testCreateFrameBodyIntegerConstructor() { TagOptionSingleton.getInstance().setPadNumbers(false); Exception exceptionCaught = null; FrameBodyTPOS fb = null; try { fb = new FrameBodyTPOS(TextEncoding.ISO_8859_1, 1,11); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v24Frames.FRAME_ID_SET, fb.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, fb.getTextEncoding()); assertEquals(1,fb.getDiscNo().intValue()); assertEquals(11,fb.getDiscTotal().intValue()); assertEquals("1/11", fb.getText()); } public void testCreateFrameBodyEmptyConstructor() { TagOptionSingleton.getInstance().setPadNumbers(false); Exception exceptionCaught = null; FrameBodyTPOS fb = null; try { fb = new FrameBodyTPOS(); fb.setDiscNo(1); fb.setDiscTotal(11); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v24Frames.FRAME_ID_SET, fb.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, fb.getTextEncoding()); assertEquals("1/11", fb.getText()); assertEquals(1,fb.getDiscNo().intValue()); assertEquals(11,fb.getDiscTotal().intValue()); } public void testCreateFrameBodyDiscOnly() { TagOptionSingleton.getInstance().setPadNumbers(false); Exception exceptionCaught = null; FrameBodyTPOS fb = null; try { fb = new FrameBodyTPOS(); fb.setDiscNo(1); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v24Frames.FRAME_ID_SET, fb.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, fb.getTextEncoding()); assertEquals("1", fb.getText()); assertEquals(1,fb.getDiscNo().intValue()); assertNull(fb.getDiscTotal()); } public void testCreateFrameBodyTotalOnly() { Exception exceptionCaught = null; FrameBodyTPOS fb = null; try { fb = new FrameBodyTPOS(); fb.setDiscTotal(11); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v24Frames.FRAME_ID_SET, fb.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, fb.getTextEncoding()); assertEquals("0/11", fb.getText()); assertNull(fb.getDiscNo()); assertEquals(11,fb.getDiscTotal().intValue()); } public void testCreateFrameBodyWithPadding() { TagOptionSingleton.getInstance().setPadNumbers(true); Exception exceptionCaught = null; FrameBodyTPOS fb = null; try { fb = new FrameBodyTPOS(TextEncoding.ISO_8859_1, 1,11); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v24Frames.FRAME_ID_SET, fb.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, fb.getTextEncoding()); assertEquals(1,fb.getDiscNo().intValue()); assertEquals(11,fb.getDiscTotal().intValue()); assertEquals("01/11", fb.getText()); } public void testCreateFrameBodyWithPaddingTwo() { TagOptionSingleton.getInstance().setPadNumbers(true); Exception exceptionCaught = null; FrameBodyTPOS fb = null; try { fb = new FrameBodyTPOS(TextEncoding.ISO_8859_1, 3,7); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v24Frames.FRAME_ID_SET, fb.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, fb.getTextEncoding()); assertEquals(3,fb.getDiscNo().intValue()); assertEquals(7,fb.getDiscTotal().intValue()); assertEquals("03/07", fb.getText()); } }libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/id3/framebody/FrameBodyXSOTTest.java0000644000175000017500000000331511041064726031704 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.tag.id3.ID3v23Frames; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; /** * Test TSOTFrameBody */ public class FrameBodyXSOTTest extends AbstractTestCase { public static final String TITLE_SORT = "titlesort"; public static FrameBodyXSOT getInitialisedBody() { FrameBodyXSOT fb = new FrameBodyXSOT(); fb.setText(FrameBodyXSOTTest.TITLE_SORT); return fb; } public void testCreateFrameBody() { Exception exceptionCaught = null; FrameBodyXSOT fb = null; try { fb = new FrameBodyXSOT(TextEncoding.ISO_8859_1, FrameBodyXSOTTest.TITLE_SORT); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v23Frames.FRAME_ID_V3_TITLE_SORT_ORDER_MUSICBRAINZ, fb.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, fb.getTextEncoding()); assertEquals(FrameBodyXSOTTest.TITLE_SORT, fb.getText()); } public void testCreateFrameBodyEmptyConstructor() { Exception exceptionCaught = null; FrameBodyXSOT fb = null; try { fb = new FrameBodyXSOT(); fb.setText(FrameBodyXSOTTest.TITLE_SORT); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v23Frames.FRAME_ID_V3_TITLE_SORT_ORDER_MUSICBRAINZ, fb.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, fb.getTextEncoding()); assertEquals(FrameBodyXSOTTest.TITLE_SORT, fb.getText()); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/id3/framebody/FrameBodyUSLTTest.java0000644000175000017500000000320411041064726031673 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; import java.io.ByteArrayOutputStream; import java.io.FileOutputStream; import java.io.IOException; /** */ public class FrameBodyUSLTTest extends AbstractTestCase { public static final String UTF16_REQUIRED = "\u2026"; public void testWriteUnicodeBody() throws IOException { FrameBodyUSLT fb = new FrameBodyUSLT(TextEncoding.UTF_16, "eng", "", UTF16_REQUIRED); ByteArrayOutputStream baos = new ByteArrayOutputStream(); fb.write(baos); FileOutputStream fos = new FileOutputStream("TEST.TXT"); fos.write(baos.toByteArray()); byte[] frameBody = baos.toByteArray(); byte[] correctBits = makeByteArray(new int[]{0x01, 'e', 'n', 'g', 0xff, 0xfe, 0x00, 0x00, 0xff, 0xfe, 0x26, 0x20}); String s = cmp(correctBits, frameBody); if (s != null) { fail(s); } } private String cmp(byte[] a, byte[] b) { if (a.length != b.length) { return "length of byte arrays differ (" + a.length + "!=" + b.length + ")"; } for (int i = 0; i < a.length; i++) { if (a[i] != b[i]) { return "byte arrays differ at offset " + i + " (" + a[i] + "!=" + b[i] + ")"; } } return null; } private byte[] makeByteArray(int[] ints) { byte[] bs = new byte[ints.length]; for (int i = 0; i < ints.length; i++) { bs[i] = (byte) ints[i]; } return bs; } }libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/id3/framebody/FrameBodyRVADTest.java0000644000175000017500000000342011041064726031640 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.tag.datatype.DataTypes; import org.jaudiotagger.tag.id3.ID3v23Frames; /** * Test RVADFrameBody */ public class FrameBodyRVADTest extends AbstractTestCase { public static byte[] TEST_BYTES; static { TEST_BYTES = FrameBodyRVADTest.makeByteArray(new int[]{0x03, 0x04}); } public static FrameBodyRVAD getInitialisedBody() { FrameBodyRVAD fb = new FrameBodyRVAD(); fb.setObjectValue(DataTypes.OBJ_DATA, TEST_BYTES); return fb; } private static byte[] makeByteArray(int[] ints) { byte[] bs = new byte[ints.length]; for (int i = 0; i < ints.length; i++) { bs[i] = (byte) ints[i]; } return bs; } public void testCreateFrameBody() { Exception exceptionCaught = null; FrameBodyRVAD fb = null; try { fb = new FrameBodyRVAD(); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v23Frames.FRAME_ID_V3_RELATIVE_VOLUME_ADJUSTMENT, fb.getIdentifier()); } public void testCreateFrameBodyEmptyConstructor() { Exception exceptionCaught = null; FrameBodyRVAD fb = null; try { fb = new FrameBodyRVAD(); fb.setObjectValue(DataTypes.OBJ_DATA, TEST_BYTES); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v23Frames.FRAME_ID_V3_RELATIVE_VOLUME_ADJUSTMENT, fb.getIdentifier()); assertEquals(TEST_BYTES, fb.getObjectValue(DataTypes.OBJ_DATA)); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/id3/framebody/FrameBodyPCNTTest.java0000644000175000017500000000320211041064726031646 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.tag.id3.ID3v24Frames; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; /** * Test PCNTFrameBody */ public class FrameBodyPCNTTest extends AbstractTestCase { public static final long PCNT_COUNTER = 1000; public static FrameBodyPCNT getInitialisedBody() { FrameBodyPCNT fb = new FrameBodyPCNT(FrameBodyPCNTTest.PCNT_COUNTER); return fb; } public void testCreateFrameBody() { Exception exceptionCaught = null; FrameBodyPCNT fb = null; try { fb = new FrameBodyPCNT(FrameBodyPCNTTest.PCNT_COUNTER); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v24Frames.FRAME_ID_PLAY_COUNTER, fb.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, fb.getTextEncoding()); assertEquals(FrameBodyPCNTTest.PCNT_COUNTER, fb.getCounter()); } public void testCreateFrameBodyEmptyConstructor() { Exception exceptionCaught = null; FrameBodyPCNT fb = null; try { fb = new FrameBodyPCNT(); fb.setCounter(FrameBodyPCNTTest.PCNT_COUNTER); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v24Frames.FRAME_ID_PLAY_COUNTER, fb.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, fb.getTextEncoding()); assertEquals(FrameBodyPCNTTest.PCNT_COUNTER, fb.getCounter()); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/id3/framebody/FrameBodyTMOOTest.java0000644000175000017500000000315711271612232031665 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.tag.id3.ID3v24Frames; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; /** * Test TMOOFrameBody */ public class FrameBodyTMOOTest extends AbstractTestCase { public static final String MOOD = "mellow"; public static FrameBodyTMOO getInitialisedBody() { FrameBodyTMOO fb = new FrameBodyTMOO(); fb.setText(FrameBodyTMOOTest.MOOD); return fb; } public void testCreateFrameBody() { Exception exceptionCaught = null; FrameBodyTMOO fb = null; try { fb = new FrameBodyTMOO(TextEncoding.ISO_8859_1, FrameBodyTMOOTest.MOOD); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v24Frames.FRAME_ID_MOOD, fb.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, fb.getTextEncoding()); assertEquals(FrameBodyTMOOTest.MOOD, fb.getText()); } public void testCreateFrameBodyEmptyConstructor() { Exception exceptionCaught = null; FrameBodyTMOO fb = null; try { fb = new FrameBodyTMOO(); fb.setText(FrameBodyTMOOTest.MOOD); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v24Frames.FRAME_ID_MOOD, fb.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, fb.getTextEncoding()); assertEquals(FrameBodyTMOOTest.MOOD, fb.getText()); } }libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/id3/framebody/FrameBodyTIPLTest.java0000644000175000017500000000753011470746136031672 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.tag.id3.ID3v23Frames; import org.jaudiotagger.tag.id3.ID3v24Frames; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; /** * Test TIPL */ public class FrameBodyTIPLTest extends AbstractTestCase { public static final String INVOLVED_PEOPLE = "producer\0eno,lanois"; public static final String INVOLVED_PEOPLE_ODD = "producer\0eno,lanois\0engineer"; public static FrameBodyTIPL getInitialisedBodyOdd() { FrameBodyTIPL fb = new FrameBodyTIPL(); fb.setText(FrameBodyTIPLTest.INVOLVED_PEOPLE_ODD); return fb; } public static FrameBodyTIPL getInitialisedBody() { FrameBodyTIPL fb = new FrameBodyTIPL(); fb.setText(FrameBodyTIPLTest.INVOLVED_PEOPLE); return fb; } public void testCreateFrameBody() { Exception exceptionCaught = null; FrameBodyTIPL fb = null; try { fb = new FrameBodyTIPL(); fb.setText(FrameBodyTIPLTest.INVOLVED_PEOPLE); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v24Frames.FRAME_ID_INVOLVED_PEOPLE, fb.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, fb.getTextEncoding()); assertEquals(FrameBodyTIPLTest.INVOLVED_PEOPLE, fb.getText()); //assertEquals(2,fb.getNumberOfValues()); //assertEquals("producer",fb.getNumberOfPairs()); assertEquals("producer",fb.getKeyAtIndex(0)); assertEquals("eno,lanois",fb.getValueAtIndex(0)); } public void testCreateFrameBodyodd() { Exception exceptionCaught = null; FrameBodyTIPL fb = null; try { fb = new FrameBodyTIPL(); fb.setText(FrameBodyTIPLTest.INVOLVED_PEOPLE_ODD); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v24Frames.FRAME_ID_INVOLVED_PEOPLE, fb.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, fb.getTextEncoding()); assertEquals(FrameBodyTIPLTest.INVOLVED_PEOPLE, fb.getText()); //assertEquals(2,fb.getNumberOfValues()); //assertEquals("producer",fb.getNumberOfPairs()); assertEquals("producer",fb.getKeyAtIndex(0)); assertEquals("eno,lanois",fb.getValueAtIndex(0)); } public void testCreateFrameBodyEmptyConstructor() { Exception exceptionCaught = null; FrameBodyTIPL fb = null; try { fb = new FrameBodyTIPL(); fb.setText(FrameBodyTIPLTest.INVOLVED_PEOPLE); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v24Frames.FRAME_ID_INVOLVED_PEOPLE, fb.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, fb.getTextEncoding()); assertEquals(FrameBodyTIPLTest.INVOLVED_PEOPLE, fb.getText()); } public void testCreateFromIPLS() { Exception exceptionCaught = null; FrameBodyIPLS fbv3 = FrameBodyIPLSTest.getInitialisedBody(); FrameBodyTIPL fb = null; try { fb = new FrameBodyTIPL(fbv3); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v24Frames.FRAME_ID_INVOLVED_PEOPLE, fb.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, fb.getTextEncoding()); assertEquals("*"+fb.getText()+"*","*"+FrameBodyIPLSTest.INVOLVED_PEOPLE+"*"); assertEquals(2,fb.getNumberOfPairs()); assertEquals("producer",fb.getKeyAtIndex(0)); assertEquals("eno,lanois",fb.getValueAtIndex(0)); } }libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/id3/framebody/FrameBodyTRCKTest.java0000644000175000017500000001235111276536055031663 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.tag.id3.ID3v24Frames; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; import org.jaudiotagger.tag.TagOptionSingleton; /** * Test TRCKFrameBody */ public class FrameBodyTRCKTest extends AbstractTestCase { public static FrameBodyTRCK getInitialisedBody() { TagOptionSingleton.getInstance().setPadNumbers(false); FrameBodyTRCK fb = new FrameBodyTRCK(); fb.setTrackNo(1); fb.setTrackTotal(11); return fb; } public void testCreateFrameBodyStringConstructor() { TagOptionSingleton.getInstance().setPadNumbers(false); Exception exceptionCaught = null; FrameBodyTRCK fb = null; try { fb = new FrameBodyTRCK(TextEncoding.ISO_8859_1, "1/11"); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v24Frames.FRAME_ID_TRACK, fb.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, fb.getTextEncoding()); assertEquals(1,fb.getTrackNo().intValue()); assertEquals(11,fb.getTrackTotal().intValue()); assertEquals("1/11", fb.getText()); } public void testCreateFrameBodyIntegerConstructor() { TagOptionSingleton.getInstance().setPadNumbers(false); Exception exceptionCaught = null; FrameBodyTRCK fb = null; try { fb = new FrameBodyTRCK(TextEncoding.ISO_8859_1, 1,11); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v24Frames.FRAME_ID_TRACK, fb.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, fb.getTextEncoding()); assertEquals(1,fb.getTrackNo().intValue()); assertEquals(11,fb.getTrackTotal().intValue()); assertEquals("1/11", fb.getText()); } public void testCreateFrameBodyEmptyConstructor() { Exception exceptionCaught = null; FrameBodyTRCK fb = null; try { fb = new FrameBodyTRCK(); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v24Frames.FRAME_ID_TRACK, fb.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, fb.getTextEncoding()); assertEquals("", fb.getText()); assertNull(fb.getTrackNo()); assertNull(fb.getTrackTotal()); } public void testCreateFrameBodyTrackOnly() { TagOptionSingleton.getInstance().setPadNumbers(false); Exception exceptionCaught = null; FrameBodyTRCK fb = null; try { fb = new FrameBodyTRCK(); fb.setTrackNo(1); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v24Frames.FRAME_ID_TRACK, fb.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, fb.getTextEncoding()); assertEquals("1", fb.getText()); assertEquals(1,fb.getTrackNo().intValue()); assertNull(fb.getTrackTotal()); } public void testCreateFrameBodyTotalOnly() { Exception exceptionCaught = null; FrameBodyTRCK fb = null; try { fb = new FrameBodyTRCK(); fb.setTrackTotal(11); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v24Frames.FRAME_ID_TRACK, fb.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, fb.getTextEncoding()); assertEquals("0/11", fb.getText()); assertNull(fb.getTrackNo()); assertEquals(11,fb.getTrackTotal().intValue()); } public void testCreateFrameBodyWithPadding() { TagOptionSingleton.getInstance().setPadNumbers(true); Exception exceptionCaught = null; FrameBodyTRCK fb = null; try { fb = new FrameBodyTRCK(TextEncoding.ISO_8859_1, 1,11); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v24Frames.FRAME_ID_TRACK, fb.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, fb.getTextEncoding()); assertEquals(1,fb.getTrackNo().intValue()); assertEquals(11,fb.getTrackTotal().intValue()); assertEquals("01/11", fb.getText()); } public void testCreateFrameBodyWithPaddingTwo() { TagOptionSingleton.getInstance().setPadNumbers(true); Exception exceptionCaught = null; FrameBodyTRCK fb = null; try { fb = new FrameBodyTRCK(TextEncoding.ISO_8859_1, 3,7); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v24Frames.FRAME_ID_TRACK, fb.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, fb.getTextEncoding()); assertEquals(3,fb.getTrackNo().intValue()); assertEquals(7,fb.getTrackTotal().intValue()); assertEquals("03/07", fb.getText()); } }libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/id3/framebody/FrameBodyPOPMTest.java0000644000175000017500000000566711041064726031676 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.tag.id3.ID3v24Frames; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; /** * Test POPMFrameBody */ public class FrameBodyPOPMTest extends AbstractTestCase { public static final String POPM_EMAIL = "paul@jaudiotagger.dev.net"; public static final long POPM_RATING = 167; public static final long POPM_COUNTER = 1000; public static FrameBodyPOPM getInitialisedBody() { FrameBodyPOPM fb = new FrameBodyPOPM(POPM_EMAIL, POPM_RATING, POPM_COUNTER); return fb; } public void testCreateFrameBody() { Exception exceptionCaught = null; FrameBodyPOPM fb = null; try { fb = new FrameBodyPOPM(POPM_EMAIL, POPM_RATING, POPM_COUNTER); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v24Frames.FRAME_ID_POPULARIMETER, fb.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, fb.getTextEncoding()); assertEquals(FrameBodyPOPMTest.POPM_EMAIL, fb.getEmailToUser()); assertEquals(FrameBodyPOPMTest.POPM_RATING, fb.getRating()); assertEquals(FrameBodyPOPMTest.POPM_COUNTER, fb.getCounter()); } public void testCreateFrameBodyEmptyConstructor() { Exception exceptionCaught = null; FrameBodyPOPM fb = null; try { fb = new FrameBodyPOPM(); fb.setEmailToUser(FrameBodyPOPMTest.POPM_EMAIL); fb.setRating(FrameBodyPOPMTest.POPM_RATING); fb.setCounter(FrameBodyPOPMTest.POPM_COUNTER); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v24Frames.FRAME_ID_POPULARIMETER, fb.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, fb.getTextEncoding()); assertEquals(FrameBodyPOPMTest.POPM_EMAIL, fb.getEmailToUser()); assertEquals(FrameBodyPOPMTest.POPM_RATING, fb.getRating()); assertEquals(FrameBodyPOPMTest.POPM_COUNTER, fb.getCounter()); } public void testCreateFrameBodyEmptyConstructorWithoutCounter() { Exception exceptionCaught = null; FrameBodyPOPM fb = null; try { fb = new FrameBodyPOPM(); fb.setEmailToUser(FrameBodyPOPMTest.POPM_EMAIL); fb.setRating(FrameBodyPOPMTest.POPM_RATING); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v24Frames.FRAME_ID_POPULARIMETER, fb.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, fb.getTextEncoding()); assertEquals(FrameBodyPOPMTest.POPM_EMAIL, fb.getEmailToUser()); assertEquals(FrameBodyPOPMTest.POPM_RATING, fb.getRating()); assertEquals(0, fb.getCounter()); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/id3/framebody/FrameBodyTSOCTest.java0000644000175000017500000000336411041064726031663 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.tag.id3.ID3v24Frames; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; /** * Test TSOCFrameBody (Composer Sort iTunes Only) */ public class FrameBodyTSOCTest extends AbstractTestCase { public static final String COMPOSER_SORT = "composersort"; public static FrameBodyTSOC getInitialisedBody() { FrameBodyTSOC fb = new FrameBodyTSOC(); fb.setText(FrameBodyTSOCTest.COMPOSER_SORT); return fb; } public void testCreateFrameBody() { Exception exceptionCaught = null; FrameBodyTSOC fb = null; try { fb = new FrameBodyTSOC(TextEncoding.ISO_8859_1, FrameBodyTSOCTest.COMPOSER_SORT); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v24Frames.FRAME_ID_COMPOSER_SORT_ORDER_ITUNES, fb.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, fb.getTextEncoding()); assertEquals(FrameBodyTSOCTest.COMPOSER_SORT, fb.getText()); } public void testCreateFrameBodyEmptyConstructor() { Exception exceptionCaught = null; FrameBodyTSOC fb = null; try { fb = new FrameBodyTSOC(); fb.setText(FrameBodyTSOCTest.COMPOSER_SORT); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v24Frames.FRAME_ID_COMPOSER_SORT_ORDER_ITUNES, fb.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, fb.getTextEncoding()); assertEquals(FrameBodyTSOCTest.COMPOSER_SORT, fb.getText()); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/id3/framebody/FrameBodyTCMPTest.java0000644000175000017500000000333311041064726031652 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.tag.id3.ID3v24Frames; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; /** * Test TCMPFrameBody */ public class FrameBodyTCMPTest extends AbstractTestCase { public static final String COMPILATION_TRUE = "1"; public static FrameBodyTCMP getInitialisedBody() { FrameBodyTCMP fb = new FrameBodyTCMP(); return fb; } public void testCreateFrameBody() { Exception exceptionCaught = null; FrameBodyTCMP fb = null; try { fb = new FrameBodyTCMP(); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v24Frames.FRAME_ID_IS_COMPILATION, fb.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, fb.getTextEncoding()); assertTrue(fb.isCompilation()); assertEquals(FrameBodyTCMP.IS_COMPILATION, fb.getText()); assertEquals(COMPILATION_TRUE, fb.getFirstTextValue()); } public void testCreateFrameBodyEmptyConstructor() { Exception exceptionCaught = null; FrameBodyTCMP fb = null; try { fb = new FrameBodyTCMP(); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v24Frames.FRAME_ID_IS_COMPILATION, fb.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, fb.getTextEncoding()); assertTrue(fb.isCompilation()); assertEquals(FrameBodyTCMP.IS_COMPILATION, fb.getText()); assertEquals(COMPILATION_TRUE, fb.getFirstTextValue()); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/id3/framebody/FrameBodyIPLSTest.java0000644000175000017500000000610311470746136031664 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.tag.id3.ID3v23Frames; import org.jaudiotagger.tag.id3.ID3v24Frames; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; /** * Test IPLS */ public class FrameBodyIPLSTest extends AbstractTestCase { public static final String INVOLVED_PEOPLE = "producer\0eno,lanois\0engineer\0lillywhite"; public static FrameBodyIPLS getInitialisedBody() { FrameBodyIPLS fb = new FrameBodyIPLS(); fb.setText(FrameBodyIPLSTest.INVOLVED_PEOPLE); return fb; } public void testCreateFrameBody() { Exception exceptionCaught = null; FrameBodyIPLS fb = null; try { fb = new FrameBodyIPLS(TextEncoding.ISO_8859_1, FrameBodyIPLSTest.INVOLVED_PEOPLE); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v23Frames.FRAME_ID_V3_IPLS, fb.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, fb.getTextEncoding()); assertEquals("*"+FrameBodyIPLSTest.INVOLVED_PEOPLE+"*", "*"+fb.getText()+"*"); assertEquals(2,fb.getNumberOfPairs()); assertEquals("producer",fb.getKeyAtIndex(0)); assertEquals("eno,lanois",fb.getValueAtIndex(0)); assertEquals("engineer",fb.getKeyAtIndex(1)); assertEquals("lillywhite",fb.getValueAtIndex(1)); } public void testCreateFrameBodyEmptyConstructor() { Exception exceptionCaught = null; FrameBodyIPLS fb = null; try { fb = new FrameBodyIPLS(); fb.setText(FrameBodyIPLSTest.INVOLVED_PEOPLE); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v23Frames.FRAME_ID_V3_IPLS, fb.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, fb.getTextEncoding()); assertEquals("*"+FrameBodyIPLSTest.INVOLVED_PEOPLE+"*", "*"+fb.getText()+"*"); assertEquals(2,fb.getNumberOfPairs()); assertEquals("producer",fb.getKeyAtIndex(0)); assertEquals("eno,lanois",fb.getValueAtIndex(0)); assertEquals("engineer",fb.getKeyAtIndex(1)); assertEquals("lillywhite",fb.getValueAtIndex(1)); } public void testCreateFromTIPL() { Exception exceptionCaught = null; FrameBodyTIPL fbv4 = FrameBodyTIPLTest.getInitialisedBody(); FrameBodyIPLS fb = null; try { fb = new FrameBodyIPLS(fbv4); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v23Frames.FRAME_ID_V3_IPLS, fb.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, fb.getTextEncoding()); assertEquals("*"+fb.getText()+"*","*"+FrameBodyTIPLTest.INVOLVED_PEOPLE+"*"); assertEquals(1,fb.getNumberOfPairs()); assertEquals("producer",fb.getKeyAtIndex(0)); assertEquals("eno,lanois",fb.getValueAtIndex(0)); } }libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/id3/framebody/FrameBodyTSOATest.java0000644000175000017500000000325711041064726031662 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.tag.id3.ID3v24Frames; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; /** * Test TSOAFrameBody */ public class FrameBodyTSOATest extends AbstractTestCase { public static final String ALBUM_SORT = "albumsort"; public static FrameBodyTSOA getInitialisedBody() { FrameBodyTSOA fb = new FrameBodyTSOA(); fb.setText(FrameBodyTSOATest.ALBUM_SORT); return fb; } public void testCreateFrameBody() { Exception exceptionCaught = null; FrameBodyTSOA fb = null; try { fb = new FrameBodyTSOA(TextEncoding.ISO_8859_1, FrameBodyTSOATest.ALBUM_SORT); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v24Frames.FRAME_ID_ALBUM_SORT_ORDER, fb.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, fb.getTextEncoding()); assertEquals(FrameBodyTSOATest.ALBUM_SORT, fb.getText()); } public void testCreateFrameBodyEmptyConstructor() { Exception exceptionCaught = null; FrameBodyTSOA fb = null; try { fb = new FrameBodyTSOA(); fb.setText(FrameBodyTSOATest.ALBUM_SORT); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v24Frames.FRAME_ID_ALBUM_SORT_ORDER, fb.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, fb.getTextEncoding()); assertEquals(FrameBodyTSOATest.ALBUM_SORT, fb.getText()); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/id3/framebody/FrameBodyRVA2Test.java0000644000175000017500000000326011041064726031620 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.tag.datatype.DataTypes; import org.jaudiotagger.tag.id3.ID3v24Frames; /** * Test RVA2FrameBody */ public class FrameBodyRVA2Test extends AbstractTestCase { public static byte[] TEST_BYTES; static { TEST_BYTES = FrameBodyRVA2Test.makeByteArray(new int[]{0x01, 0x2}); } public static FrameBodyRVA2 getInitialisedBody() { FrameBodyRVA2 fb = new FrameBodyRVA2(); fb.setObjectValue(DataTypes.OBJ_DATA, TEST_BYTES); return fb; } private static byte[] makeByteArray(int[] ints) { byte[] bs = new byte[ints.length]; for (int i = 0; i < ints.length; i++) { bs[i] = (byte) ints[i]; } return bs; } public void testCreateFrameBody() { Exception exceptionCaught = null; FrameBodyRVA2 fb = null; try { fb = new FrameBodyRVA2(); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); } public void testCreateFrameBodyEmptyConstructor() { Exception exceptionCaught = null; FrameBodyRVA2 fb = null; try { fb = new FrameBodyRVA2(); fb.setObjectValue(DataTypes.OBJ_DATA, TEST_BYTES); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v24Frames.FRAME_ID_RELATIVE_VOLUME_ADJUSTMENT2, fb.getIdentifier()); assertEquals(TEST_BYTES, fb.getObjectValue(DataTypes.OBJ_DATA)); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/id3/framebody/FrameBodyWXXXTest.java0000644000175000017500000000327711041064726031734 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.tag.id3.ID3v24Frames; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; /** * Test WXXXFrameBody (Artist) */ public class FrameBodyWXXXTest extends AbstractTestCase { public static final String WXXX_TEST_URL = "http://test.url.com"; public static final String WXXX_TEST_STRING = "simple url"; public static final String WXXX_UNICODE_REQUIRED_TEST_STRING = "\u01ff\u01ffcomplex url"; public static FrameBodyWXXX getInitialisedBody() { //Text Encoding doesnt matter until written to file FrameBodyWXXX fb = new FrameBodyWXXX(TextEncoding.ISO_8859_1, WXXX_TEST_STRING, WXXX_TEST_URL); return fb; } public static FrameBodyWXXX getUnicodeRequiredInitialisedBody() { //Text Encoding doesnt matter until written to file FrameBodyWXXX fb = new FrameBodyWXXX(TextEncoding.ISO_8859_1, WXXX_UNICODE_REQUIRED_TEST_STRING, WXXX_TEST_URL); return fb; } public void testCreateFrameBody() { Exception exceptionCaught = null; FrameBodyWXXX fb = null; try { fb = new FrameBodyWXXX(TextEncoding.ISO_8859_1, WXXX_TEST_STRING, WXXX_TEST_URL); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v24Frames.FRAME_ID_USER_DEFINED_URL, fb.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, fb.getTextEncoding()); assertEquals(FrameBodyWXXXTest.WXXX_TEST_STRING, fb.getDescription()); assertEquals(FrameBodyWXXXTest.WXXX_TEST_URL, fb.getUrlLink()); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/id3/framebody/FrameBodyTSOPTest.java0000644000175000017500000000327011041064726031674 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.tag.id3.ID3v24Frames; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; /** * Test TSOTFrameBody */ public class FrameBodyTSOPTest extends AbstractTestCase { public static final String ARTIST_SORT = "artistsort"; public static FrameBodyTSOP getInitialisedBody() { FrameBodyTSOP fb = new FrameBodyTSOP(); fb.setText(FrameBodyTSOPTest.ARTIST_SORT); return fb; } public void testCreateFrameBody() { Exception exceptionCaught = null; FrameBodyTSOP fb = null; try { fb = new FrameBodyTSOP(TextEncoding.ISO_8859_1, FrameBodyTSOPTest.ARTIST_SORT); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v24Frames.FRAME_ID_ARTIST_SORT_ORDER, fb.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, fb.getTextEncoding()); assertEquals(FrameBodyTSOPTest.ARTIST_SORT, fb.getText()); } public void testCreateFrameBodyEmptyConstructor() { Exception exceptionCaught = null; FrameBodyTSOP fb = null; try { fb = new FrameBodyTSOP(); fb.setText(FrameBodyTSOPTest.ARTIST_SORT); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v24Frames.FRAME_ID_ARTIST_SORT_ORDER, fb.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, fb.getTextEncoding()); assertEquals(FrameBodyTSOPTest.ARTIST_SORT, fb.getText()); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/id3/framebody/FrameBodyAPICTest.java0000644000175000017500000000260711041064726031626 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.tag.id3.ID3v24Frames; /** * Test APICFrameBody */ public class FrameBodyAPICTest extends AbstractTestCase { public static String DESCRIPTION = "ImageTest"; public static FrameBodyAPIC getInitialisedBody() { FrameBodyAPIC fb = new FrameBodyAPIC(); fb.setDescription(DESCRIPTION); return fb; } public void testCreateFrameBody() { Exception exceptionCaught = null; FrameBodyAPIC fb = null; try { fb = new FrameBodyAPIC(); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v24Frames.FRAME_ID_ATTACHED_PICTURE, fb.getIdentifier()); assertTrue(fb.getDescription() == null); } public void testCreateFrameBodyEmptyConstructor() { Exception exceptionCaught = null; FrameBodyAPIC fb = null; try { fb = new FrameBodyAPIC(); fb.setDescription(DESCRIPTION); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v24Frames.FRAME_ID_ATTACHED_PICTURE, fb.getIdentifier()); assertEquals(DESCRIPTION, fb.getDescription()); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/id3/framebody/FrameBodyPICTest.java0000644000175000017500000000267211041064726031527 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.tag.id3.ID3v22Frames; /** * Test PICFrameBody */ public class FrameBodyPICTest extends AbstractTestCase { public static String DESCRIPTION = "ImageTestv22"; public static FrameBodyPIC getInitialisedBody() { FrameBodyPIC fb = new FrameBodyPIC(); fb.setDescription(FrameBodyPICTest.DESCRIPTION); return fb; } public void testCreateFrameBody() { Exception exceptionCaught = null; FrameBodyPIC fb = null; try { fb = new FrameBodyPIC(); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v22Frames.FRAME_ID_V2_ATTACHED_PICTURE, fb.getIdentifier()); assertTrue(fb.getDescription() == null); } public void testCreateFrameBodyEmptyConstructor() { Exception exceptionCaught = null; FrameBodyPIC fb = null; try { fb = new FrameBodyPIC(); fb.setDescription(FrameBodyPICTest.DESCRIPTION); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v22Frames.FRAME_ID_V2_ATTACHED_PICTURE, fb.getIdentifier()); assertEquals(FrameBodyPICTest.DESCRIPTION, fb.getDescription()); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/id3/framebody/FrameBodyTDRCTest.java0000644000175000017500000000161111041064726031640 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.tag.id3.ID3v24Frames; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; /** * Test Unique File Identifier FrameBody */ public class FrameBodyTDRCTest extends AbstractTestCase { public static final String TEST_YEAR = "2002"; public void testCreateFrameBody() { Exception exceptionCaught = null; FrameBodyTDRC fb = null; try { fb = new FrameBodyTDRC(); fb.setDate(TEST_YEAR); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v24Frames.FRAME_ID_YEAR, fb.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, fb.getTextEncoding()); assertEquals(FrameBodyTDRCTest.TEST_YEAR, fb.getDate()); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/id3/framebody/FrameBodyTPE1Test.java0000644000175000017500000000300011041064726031607 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.tag.id3.ID3v24Frames; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; /** * Test TPE1FrameBody (Artist) */ public class FrameBodyTPE1Test extends AbstractTestCase { public static final String TPE1_TEST_STRING = "beck"; public static final String TPE1_UNICODE_REQUIRED_TEST_STRING = "\u01ff\u01ffbeck"; public static FrameBodyTPE1 getInitialisedBody() { //Text Encoding doesnt matter until written to file FrameBodyTPE1 fb = new FrameBodyTPE1(TextEncoding.ISO_8859_1, TPE1_TEST_STRING); return fb; } public static FrameBodyTPE1 getUnicodeRequiredInitialisedBody() { //Text Encoding doesnt matter until written to file FrameBodyTPE1 fb = new FrameBodyTPE1(TextEncoding.ISO_8859_1, TPE1_UNICODE_REQUIRED_TEST_STRING); return fb; } public void testCreateFrameBody() { Exception exceptionCaught = null; FrameBodyTPE1 fb = null; try { fb = new FrameBodyTPE1(TextEncoding.UTF_16, TPE1_UNICODE_REQUIRED_TEST_STRING); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v24Frames.FRAME_ID_ARTIST, fb.getIdentifier()); assertEquals(TextEncoding.UTF_16, fb.getTextEncoding()); assertEquals(FrameBodyTPE1Test.TPE1_UNICODE_REQUIRED_TEST_STRING, fb.getText()); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/id3/framebody/FrameBodyTSO2Test.java0000644000175000017500000000343311041064726031637 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.tag.id3.ID3v24Frames; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; /** * Test TSO2FrameBody (Album Artist Sort iTunes Only) */ public class FrameBodyTSO2Test extends AbstractTestCase { public static final String ALBUM_ARTIST_SORT = "albumartistsort"; public static FrameBodyTSO2 getInitialisedBody() { FrameBodyTSO2 fb = new FrameBodyTSO2(); fb.setText(FrameBodyTSO2Test.ALBUM_ARTIST_SORT); return fb; } public void testCreateFrameBody() { Exception exceptionCaught = null; FrameBodyTSO2 fb = null; try { fb = new FrameBodyTSO2(TextEncoding.ISO_8859_1, FrameBodyTSO2Test.ALBUM_ARTIST_SORT); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v24Frames.FRAME_ID_ALBUM_ARTIST_SORT_ORDER_ITUNES, fb.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, fb.getTextEncoding()); assertEquals(FrameBodyTSO2Test.ALBUM_ARTIST_SORT, fb.getText()); } public void testCreateFrameBodyEmptyConstructor() { Exception exceptionCaught = null; FrameBodyTSO2 fb = null; try { fb = new FrameBodyTSO2(); fb.setText(FrameBodyTSO2Test.ALBUM_ARTIST_SORT); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v24Frames.FRAME_ID_ALBUM_ARTIST_SORT_ORDER_ITUNES, fb.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, fb.getTextEncoding()); assertEquals(FrameBodyTSO2Test.ALBUM_ARTIST_SORT, fb.getText()); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/id3/framebody/FrameBodyTSOTTest.java0000644000175000017500000000312511041064726031677 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.tag.id3.ID3v24Frames; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; /** * Test TSOTFrameBody */ public class FrameBodyTSOTTest extends AbstractTestCase { public static final String TITLE_SORT = "titlesort"; public static FrameBodyTSOT getInitialisedBody() { FrameBodyTSOT fb = new FrameBodyTSOT(); fb.setText(TITLE_SORT); return fb; } public void testCreateFrameBody() { Exception exceptionCaught = null; FrameBodyTSOT fb = null; try { fb = new FrameBodyTSOT(TextEncoding.ISO_8859_1, TITLE_SORT); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v24Frames.FRAME_ID_TITLE_SORT_ORDER, fb.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, fb.getTextEncoding()); assertEquals(TITLE_SORT, fb.getText()); } public void testCreateFrameBodyEmptyConstructor() { Exception exceptionCaught = null; FrameBodyTSOT fb = null; try { fb = new FrameBodyTSOT(); fb.setText(TITLE_SORT); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v24Frames.FRAME_ID_TITLE_SORT_ORDER, fb.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, fb.getTextEncoding()); assertEquals(TITLE_SORT, fb.getText()); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/id3/framebody/FrameBodyUFIDTest.java0000644000175000017500000000232511041064726031636 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.tag.datatype.DataTypes; import org.jaudiotagger.tag.id3.ID3v24Frames; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; /** * Test Unique File Identifier FrameBody */ public class FrameBodyUFIDTest extends AbstractTestCase { public static final String TEST_OWNER = FrameBodyUFID.UFID_MUSICBRAINZ; public static final byte[] TEST_OBJECT_DATA = new byte[2]; public void testCreateFrameBody() { Exception exceptionCaught = null; FrameBodyUFID fb = null; try { fb = new FrameBodyUFID(); fb.setOwner(TEST_OWNER); fb.setUniqueIdentifier(TEST_OBJECT_DATA); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v24Frames.FRAME_ID_UNIQUE_FILE_ID, fb.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, fb.getTextEncoding()); assertEquals(TEST_OWNER, fb.getOwner()); assertEquals(TEST_OBJECT_DATA, fb.getObjectValue(DataTypes.OBJ_DATA)); assertEquals(TEST_OBJECT_DATA, fb.getUniqueIdentifier()); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/id3/framebody/FrameBodyXSOATest.java0000644000175000017500000000331511041064726031661 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.tag.id3.ID3v23Frames; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; /** * Test TSOAFrameBody */ public class FrameBodyXSOATest extends AbstractTestCase { public static final String ALBUM_SORT = "albumsort"; public static FrameBodyXSOA getInitialisedBody() { FrameBodyXSOA fb = new FrameBodyXSOA(); fb.setText(FrameBodyXSOATest.ALBUM_SORT); return fb; } public void testCreateFrameBody() { Exception exceptionCaught = null; FrameBodyXSOA fb = null; try { fb = new FrameBodyXSOA(TextEncoding.ISO_8859_1, FrameBodyXSOATest.ALBUM_SORT); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v23Frames.FRAME_ID_V3_ALBUM_SORT_ORDER_MUSICBRAINZ, fb.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, fb.getTextEncoding()); assertEquals(FrameBodyXSOATest.ALBUM_SORT, fb.getText()); } public void testCreateFrameBodyEmptyConstructor() { Exception exceptionCaught = null; FrameBodyXSOA fb = null; try { fb = new FrameBodyXSOA(); fb.setText(FrameBodyXSOATest.ALBUM_SORT); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v23Frames.FRAME_ID_V3_ALBUM_SORT_ORDER_MUSICBRAINZ, fb.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, fb.getTextEncoding()); assertEquals(FrameBodyXSOATest.ALBUM_SORT, fb.getText()); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/id3/framebody/FrameBodyTXXXTest.java0000644000175000017500000000313411271612232031715 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.tag.id3.ID3v24Frames; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; /** * Test WXXXFrameBody (Artist) */ public class FrameBodyTXXXTest extends AbstractTestCase { public static final String TXXX_TEST_DESC = FrameBodyTXXX.BARCODE; public static final String TXXX_TEST_STRING = "0123456789"; public static FrameBodyTXXX getInitialisedBody() { //Text Encoding doesnt matter until written to file FrameBodyTXXX fb = new FrameBodyTXXX(TextEncoding.ISO_8859_1, TXXX_TEST_STRING, TXXX_TEST_DESC); return fb; } public static FrameBodyTXXX getUnicodeRequiredInitialisedBody() { //Text Encoding doesnt matter until written to file FrameBodyTXXX fb = new FrameBodyTXXX(TextEncoding.ISO_8859_1, TXXX_TEST_STRING, TXXX_TEST_DESC); return fb; } public void testCreateFrameBody() { Exception exceptionCaught = null; FrameBodyTXXX fb = null; try { fb = new FrameBodyTXXX(TextEncoding.ISO_8859_1, TXXX_TEST_STRING, TXXX_TEST_DESC); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v24Frames.FRAME_ID_USER_DEFINED_INFO, fb.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, fb.getTextEncoding()); assertEquals(FrameBodyTXXXTest.TXXX_TEST_STRING, fb.getDescription()); assertEquals(FrameBodyTXXXTest.TXXX_TEST_DESC, fb.getFirstTextValue()); } }libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/id3/framebody/FrameBodyDeprecatedTest.java0000644000175000017500000000142111041064726033143 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.tag.id3.ID3v24Frames; /** * Test DeprecatedFrameBody */ public class FrameBodyDeprecatedTest extends AbstractTestCase { public void testCreateFrameBody() { Exception exceptionCaught = null; FrameBodyDeprecated fb = null; try { fb = new FrameBodyDeprecated(FrameBodyTPE1Test.getInitialisedBody()); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v24Frames.FRAME_ID_ARTIST, fb.getIdentifier()); assertEquals(FrameBodyTPE1Test.getInitialisedBody().getBriefDescription(), fb.getBriefDescription()); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/id3/framebody/FrameBodyXSOPTest.java0000644000175000017500000000332611041064726031702 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.tag.id3.ID3v23Frames; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; /** * Test TSOTFrameBody */ public class FrameBodyXSOPTest extends AbstractTestCase { public static final String ARTIST_SORT = "artistsort"; public static FrameBodyXSOP getInitialisedBody() { FrameBodyXSOP fb = new FrameBodyXSOP(); fb.setText(FrameBodyXSOPTest.ARTIST_SORT); return fb; } public void testCreateFrameBody() { Exception exceptionCaught = null; FrameBodyXSOP fb = null; try { fb = new FrameBodyXSOP(TextEncoding.ISO_8859_1, FrameBodyXSOPTest.ARTIST_SORT); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v23Frames.FRAME_ID_V3_ARTIST_SORT_ORDER_MUSICBRAINZ, fb.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, fb.getTextEncoding()); assertEquals(FrameBodyXSOPTest.ARTIST_SORT, fb.getText()); } public void testCreateFrameBodyEmptyConstructor() { Exception exceptionCaught = null; FrameBodyXSOP fb = null; try { fb = new FrameBodyXSOP(); fb.setText(FrameBodyXSOPTest.ARTIST_SORT); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v23Frames.FRAME_ID_V3_ARTIST_SORT_ORDER_MUSICBRAINZ, fb.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, fb.getTextEncoding()); assertEquals(FrameBodyXSOPTest.ARTIST_SORT, fb.getText()); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/id3/FrameTPE4Test.java0000644000175000017500000000731011331770237027037 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.tag.FieldKey; import org.jaudiotagger.tag.Tag; import org.jaudiotagger.tag.id3.framebody.FrameBodyTPE3; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; /** */ public class FrameTPE4Test extends AbstractTestCase { public void testGenericv22() throws Exception { Exception e=null; try { Tag tag = new ID3v22Tag(); tag.addField(FieldKey.REMIXER,"testREMIXER"); assertEquals("testREMIXER",tag.getFirst(FieldKey.REMIXER)); assertEquals("testREMIXER",tag.getFirst("TP4")); } catch(Exception ex) { e=ex; ex.printStackTrace(); } assertNull(e); } public void testID3Specificv22() throws Exception { Exception e=null; try { ID3v22Tag tag = new ID3v22Tag(); ID3v22Frame frame = new ID3v22Frame("TP4"); frame.setBody(new FrameBodyTPE3(TextEncoding.ISO_8859_1,"testRemixer")); tag.addFrame(frame); assertEquals("testRemixer",tag.getFirst(FieldKey.REMIXER)); assertEquals("testRemixer",tag.getFirst("TP4")); } catch(Exception ex) { e=ex; ex.printStackTrace(); } assertNull(e); } public void testGenericv23() throws Exception { Exception e=null; try { Tag tag = new ID3v23Tag(); tag.addField(FieldKey.REMIXER,"testRemixer"); assertEquals("testRemixer",tag.getFirst(FieldKey.REMIXER)); assertEquals("testRemixer",tag.getFirst("TPE4")); } catch(Exception ex) { e=ex; ex.printStackTrace(); } assertNull(e); } public void testID3Specificv23() throws Exception { Exception e=null; try { ID3v23Tag tag = new ID3v23Tag(); ID3v23Frame frame = new ID3v23Frame("TPE4"); frame.setBody(new FrameBodyTPE3(TextEncoding.ISO_8859_1,"testRemixer")); tag.addFrame(frame); assertEquals("testRemixer",tag.getFirst(FieldKey.REMIXER)); assertEquals("testRemixer",tag.getFirst("TPE4")); } catch(Exception ex) { e=ex; ex.printStackTrace(); } assertNull(e); } public void testGenericv24() throws Exception { Exception e=null; try { Tag tag = new ID3v24Tag(); tag.addField(FieldKey.REMIXER,"testRemixer"); assertEquals("testRemixer",tag.getFirst(FieldKey.REMIXER)); assertEquals("testRemixer",tag.getFirst("TPE4")); } catch(Exception ex) { e=ex; ex.printStackTrace(); } assertNull(e); } public void testID3Specificv24() throws Exception { Exception e=null; try { ID3v24Tag tag = new ID3v24Tag(); ID3v24Frame frame = new ID3v24Frame("TPE4"); frame.setBody(new FrameBodyTPE3(TextEncoding.ISO_8859_1,"testRemixer")); tag.addFrame(frame); assertEquals("testRemixer",tag.getFirst(FieldKey.REMIXER)); assertEquals("testRemixer",tag.getFirst("TPE4")); } catch(Exception ex) { e=ex; ex.printStackTrace(); } assertNull(e); } }libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/id3/FrameTMOOTest.java0000644000175000017500000002327211470746136027113 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.mp3.MP3File; import org.jaudiotagger.tag.id3.framebody.*; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; import java.io.File; import java.util.Iterator; import java.util.ArrayList; import java.util.List; /** * Test TSOP and XSOP (Title Sort) Frame */ public class FrameTMOOTest extends AbstractTestCase { public static ID3v24Frame getInitialisedFrame() { ID3v24Frame frame = new ID3v24Frame(ID3v24Frames.FRAME_ID_MOOD); FrameBodyTMOO fb = FrameBodyTMOOTest.getInitialisedBody(); frame.setBody(fb); return frame; } /*public static ID3v23Frame getV23InitialisedFrame() { ID3v23Frame frame = new ID3v23Frame(ID3v23Frames.FRAME_ID_V3_USER_DEFINED_INFO); FrameBodyXSOP fb = FrameBodyXSOPTest.getInitialisedBody(); frame.setBody(fb); return frame; } */ public void testCreateID3v24Frame() { Exception exceptionCaught = null; ID3v24Frame frame = null; FrameBodyTMOO fb = null; try { frame = new ID3v24Frame(ID3v24Frames.FRAME_ID_MOOD); fb = FrameBodyTMOOTest.getInitialisedBody(); frame.setBody(fb); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v24Frames.FRAME_ID_MOOD, frame.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, fb.getTextEncoding()); assertFalse(ID3v24Frames.getInstanceOf().isExtensionFrames(frame.getIdentifier())); assertTrue(ID3v24Frames.getInstanceOf().isSupportedFrames(frame.getIdentifier())); assertEquals(FrameBodyTMOOTest.MOOD, fb.getText()); } /* public void testCreateID3v23Frame() { Exception exceptionCaught = null; ID3v23Frame frame = null; FrameBodyXSOP fb = null; try { frame = new ID3v23Frame(ID3v23Frames.FRAME_ID_V3_ARTIST_SORT_ORDER_MUSICBRAINZ); fb = FrameBodyXSOPTest.getInitialisedBody(); frame.setBody(fb); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v23Frames.FRAME_ID_V3_ARTIST_SORT_ORDER_MUSICBRAINZ, frame.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, fb.getTextEncoding()); assertTrue(ID3v23Frames.getInstanceOf().isExtensionFrames(frame.getIdentifier())); assertFalse(ID3v23Frames.getInstanceOf().isSupportedFrames(frame.getIdentifier())); assertEquals(FrameBodyTSOPTest.ARTIST_SORT, fb.getText()); } */ /* public void testCreateID3v22Frame() { Exception exceptionCaught = null; ID3v22Frame frame = null; FrameBodyTSOP fb = null; try { frame = new ID3v22Frame(ID3v22Frames.FRAME_ID_V2_ARTIST_SORT_ORDER_ITUNES); fb = FrameBodyTSOPTest.getInitialisedBody(); frame.setBody(fb); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v22Frames.FRAME_ID_V2_ARTIST_SORT_ORDER_ITUNES, frame.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, fb.getTextEncoding()); assertTrue(ID3v22Frames.getInstanceOf().isExtensionFrames(frame.getIdentifier())); assertFalse(ID3v22Frames.getInstanceOf().isSupportedFrames(frame.getIdentifier())); assertEquals(FrameBodyTSOPTest.ARTIST_SORT, fb.getText()); } */ public void testSaveToFile() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3", new File("test1016.mp3")); MP3File mp3File = new MP3File(testFile); //Create and Save ID3v24Tag tag = new ID3v24Tag(); tag.setFrame(FrameTMOOTest.getInitialisedFrame()); mp3File.setID3v2Tag(tag); mp3File.save(); //Reload mp3File = new MP3File(testFile); ID3v24Frame frame = (ID3v24Frame) mp3File.getID3v2Tag().getFrame(ID3v24Frames.FRAME_ID_MOOD); FrameBodyTMOO body = (FrameBodyTMOO) frame.getBody(); assertEquals(TextEncoding.ISO_8859_1, body.getTextEncoding()); } public void testSaveEmptyFrameToFile() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3", new File("test1004.mp3")); MP3File mp3File = new MP3File(testFile); ID3v24Frame frame = new ID3v24Frame(ID3v24Frames.FRAME_ID_MOOD); frame.setBody(new FrameBodyTMOO()); //Create and Save ID3v24Tag tag = new ID3v24Tag(); tag.setFrame(frame); mp3File.setID3v2Tag(tag); mp3File.save(); //Reload mp3File = new MP3File(testFile); frame = (ID3v24Frame) mp3File.getID3v2Tag().getFrame(ID3v24Frames.FRAME_ID_MOOD); FrameBodyTMOO body = (FrameBodyTMOO) frame.getBody(); assertEquals(TextEncoding.ISO_8859_1, body.getTextEncoding()); } /** * Testing not only conversion of MOOD but also what hapens when have two frame of different types (TMOO and TXXX) that * become the same type TXXX * * @throws Exception */ public void testConvertV24ToV23() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3", new File("test1005.mp3")); MP3File mp3File = new MP3File(testFile); //Create and Save ID3v24Tag tag = new ID3v24Tag(); tag.setFrame(FrameTMOOTest.getInitialisedFrame()); tag.setFrame(FrameTXXXTest.getV24InitialisedFrame()); mp3File.setID3v2Tag(tag); mp3File.save(); //Reload and convert to v23 and save mp3File = new MP3File(testFile); ID3v23Tag v23Tag = new ID3v23Tag(mp3File.getID3v2TagAsv24()); assertEquals(2, v23Tag.getFields("TXXX").size()); mp3File.setID3v2TagOnly(v23Tag); Iterator i = v23Tag.getFields(); while (i.hasNext()) { System.out.println(((ID3v23Frame) i.next()).getIdentifier()); } mp3File.save(); //Reload mp3File = new MP3File(testFile); ID3v23Frame frame = (ID3v23Frame) ((List) mp3File.getID3v2Tag().getFrame(ID3v23Frames.FRAME_ID_V3_USER_DEFINED_INFO)).get(0); FrameBodyTXXX body = (FrameBodyTXXX) frame.getBody(); assertEquals(TextEncoding.ISO_8859_1, body.getTextEncoding()); assertEquals(FrameBodyTXXXTest.TXXX_TEST_DESC, body.getText()); frame = (ID3v23Frame) ((List) mp3File.getID3v2Tag().getFrame(ID3v23Frames.FRAME_ID_V3_USER_DEFINED_INFO)).get(1); body = (FrameBodyTXXX) frame.getBody(); assertEquals(TextEncoding.ISO_8859_1, body.getTextEncoding()); assertEquals(FrameBodyTMOOTest.MOOD, body.getText()); } /** * Testing not only conversion of MOOD but also what happens when have two frame of different types (TMOO and TXXX) that * become the same type TXXX * * @throws Exception */ public void testConvertV23ToV24() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3", new File("test1005.mp3")); MP3File mp3File = new MP3File(testFile); //Create and Save ID3v23Tag tag = new ID3v23Tag(); FrameBodyTXXX frameBody = new FrameBodyTXXX(); frameBody.setDescription(FrameBodyTXXX.MOOD); frameBody.setText("Tranquil"); ID3v23Frame frame = new ID3v23Frame(ID3v23Frames.FRAME_ID_V3_USER_DEFINED_INFO); frame.setBody(frameBody); tag.setFrame(frame); mp3File.setID3v2Tag(tag); mp3File.save(); //Reload and convert to v23 and save mp3File = new MP3File(testFile); ID3v24Tag v24Tag = new ID3v24Tag(mp3File.getID3v2Tag()); Iterator i = v24Tag.getFields(); while (i.hasNext()) { System.out.println("kkk" + ((ID3v24Frame) i.next()).getIdentifier()); } assertEquals(1, v24Tag.getFieldCount()); ID3v24Frame v24frame = (ID3v24Frame)v24Tag.getFrame("TMOO"); assertTrue(v24frame.getBody() instanceof FrameBodyTMOO); FrameBodyTMOO v24framebody = (FrameBodyTMOO)v24frame.getBody(); assertEquals("Tranquil",v24framebody.getText()); } public void testConvertMultiV23ToV24() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3", new File("test1005.mp3")); MP3File mp3File = new MP3File(testFile); //Create and Save ID3v23Tag tag = new ID3v23Tag(); ArrayList frames= new ArrayList(); { FrameBodyTXXX frameBody = new FrameBodyTXXX(); frameBody.setDescription(FrameBodyTXXX.MOOD); frameBody.setText("Tranquil"); ID3v23Frame frame = new ID3v23Frame(ID3v23Frames.FRAME_ID_V3_USER_DEFINED_INFO); frame.setBody(frameBody); frames.add(frame); } { FrameBodyTXXX frameBody = new FrameBodyTXXX(); frameBody.setDescription(FrameBodyTXXX.BARCODE); frameBody.setText("0123456789"); ID3v23Frame frame = new ID3v23Frame(ID3v23Frames.FRAME_ID_V3_USER_DEFINED_INFO); frame.setBody(frameBody); frames.add(frame); } tag.setFrame("TXXX",frames); mp3File.setID3v2Tag(tag); mp3File.save(); //Reload and convert to v23 and save mp3File = new MP3File(testFile); ID3v24Tag v24Tag = new ID3v24Tag(mp3File.getID3v2Tag()); Iterator i = v24Tag.getFields(); while (i.hasNext()) { System.out.println("kkk" + ((ID3v24Frame) i.next()).getIdentifier()); } assertEquals(2, v24Tag.getFieldCount()); ID3v24Frame v24frame = (ID3v24Frame)v24Tag.getFrame("TMOO"); assertNotNull(v24frame); assertTrue(v24frame.getBody() instanceof FrameBodyTMOO); FrameBodyTMOO v24framebody = (FrameBodyTMOO)v24frame.getBody(); assertEquals("Tranquil",v24framebody.getText()); } }libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/id3/FrameWXXXTest.java0000644000175000017500000001633511302721504027137 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.mp3.MP3File; import org.jaudiotagger.tag.id3.framebody.FrameBodyWXXX; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; import org.jaudiotagger.tag.TagOptionSingleton; import java.io.File; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; /** * Test WXXX Frame */ public class FrameWXXXTest extends AbstractTestCase { public static final String NORMAL_LINK = "http:www.btinternet.com/~birdpoo/kots.htm"; //Note cant put Japanese chars directly into code because the source code is not a UTF8 file public static final String UNICODE_LINK_START = "http://ja.wikipedia.org/wiki/"; public static final String UNICODE_LINK_END = "\u5742\u672c\u4e5d"; public static final String UNICODE_ENCODED = "http://ja.wikipedia.org/wiki/%E5%9D%82%E6%9C%AC%E4%B9%9D"; public static final String UNICODE_LINK = "http://ja.wikipedia.org/wiki/\u5742\u672c\u4e5d"; /** * */ protected void tearDown() { } public static ID3v24Frame getInitialisedFrame() { ID3v24Frame frame = new ID3v24Frame(ID3v24Frames.FRAME_ID_USER_DEFINED_URL); FrameBodyWXXX fb = new FrameBodyWXXX(); fb.setUrlLink(NORMAL_LINK); frame.setBody(fb); return frame; } public static ID3v24Frame getInitialisedUnicodeFrame() throws Exception { ID3v24Frame frame = new ID3v24Frame(ID3v24Frames.FRAME_ID_USER_DEFINED_URL); FrameBodyWXXX fb = new FrameBodyWXXX(); fb.setUrlLink(UNICODE_LINK_START + URLEncoder.encode(UNICODE_LINK_END, "utf8")); frame.setBody(fb); return frame; } public static ID3v24Frame getRawUnicodeFrame() throws Exception { ID3v24Frame frame = new ID3v24Frame(ID3v24Frames.FRAME_ID_USER_DEFINED_URL); FrameBodyWXXX fb = new FrameBodyWXXX(); fb.setUrlLink(UNICODE_LINK); frame.setBody(fb); return frame; } public void testCreateID3v24Frame() { Exception exceptionCaught = null; ID3v24Frame frame = null; try { frame = getInitialisedFrame(); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertTrue(frame.getBody() instanceof FrameBodyWXXX); assertEquals(ID3v24Frames.FRAME_ID_USER_DEFINED_URL, frame.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, frame.getBody().getTextEncoding()); assertFalse(ID3v24Frames.getInstanceOf().isExtensionFrames(frame.getIdentifier())); assertTrue(ID3v24Frames.getInstanceOf().isSupportedFrames(frame.getIdentifier())); assertEquals(NORMAL_LINK, ((FrameBodyWXXX) frame.getBody()).getUrlLink()); } public void testSaveToFile() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); MP3File mp3File = new MP3File(testFile); //Create and Save ID3v24Tag tag = new ID3v24Tag(); tag.setFrame(getInitialisedFrame()); mp3File.setID3v2Tag(tag); mp3File.save(); //Reload mp3File = new MP3File(testFile); ID3v24Frame frame = (ID3v24Frame) mp3File.getID3v2Tag().getFrame(ID3v24Frames.FRAME_ID_USER_DEFINED_URL); assertTrue(frame.getBody() instanceof FrameBodyWXXX); assertEquals(ID3v24Frames.FRAME_ID_USER_DEFINED_URL, frame.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, frame.getBody().getTextEncoding()); assertFalse(ID3v24Frames.getInstanceOf().isExtensionFrames(frame.getIdentifier())); assertTrue(ID3v24Frames.getInstanceOf().isSupportedFrames(frame.getIdentifier())); assertEquals(NORMAL_LINK, ((FrameBodyWXXX) frame.getBody()).getUrlLink()); } public void testCreateID3v24UnicodeFrame() { Exception exceptionCaught = null; ID3v24Frame frame = null; try { frame = getInitialisedUnicodeFrame(); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertTrue(frame.getBody() instanceof FrameBodyWXXX); assertEquals(ID3v24Frames.FRAME_ID_USER_DEFINED_URL, frame.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, frame.getBody().getTextEncoding()); assertFalse(ID3v24Frames.getInstanceOf().isExtensionFrames(frame.getIdentifier())); assertTrue(ID3v24Frames.getInstanceOf().isSupportedFrames(frame.getIdentifier())); assertEquals(UNICODE_ENCODED, ((FrameBodyWXXX) frame.getBody()).getUrlLink()); } /** * Encoding already done * * @throws Exception */ public void testSaveUnicodeToFile() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); MP3File mp3File = new MP3File(testFile); //Create and Save ID3v24Tag tag = new ID3v24Tag(); tag.setFrame(getInitialisedUnicodeFrame()); mp3File.setID3v2Tag(tag); mp3File.save(); //Reload mp3File = new MP3File(testFile); ID3v24Frame frame = (ID3v24Frame) mp3File.getID3v2Tag().getFrame(ID3v24Frames.FRAME_ID_USER_DEFINED_URL); assertTrue(frame.getBody() instanceof FrameBodyWXXX); assertEquals(ID3v24Frames.FRAME_ID_USER_DEFINED_URL, frame.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, frame.getBody().getTextEncoding()); assertFalse(ID3v24Frames.getInstanceOf().isExtensionFrames(frame.getIdentifier())); assertTrue(ID3v24Frames.getInstanceOf().isSupportedFrames(frame.getIdentifier())); assertEquals(UNICODE_ENCODED, ((FrameBodyWXXX) frame.getBody()).getUrlLink()); } /** * Encoding done by jaudiotagger itself * * @throws Exception */ public void testSaveUnicodeToFile2() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); MP3File mp3File = new MP3File(testFile); //Create and Save ID3v24Tag tag = new ID3v24Tag(); tag.setFrame(getRawUnicodeFrame()); mp3File.setID3v2Tag(tag); mp3File.save(); //Reload mp3File = new MP3File(testFile); ID3v24Frame frame = (ID3v24Frame) mp3File.getID3v2Tag().getFrame(ID3v24Frames.FRAME_ID_USER_DEFINED_URL); assertTrue(frame.getBody() instanceof FrameBodyWXXX); assertEquals(ID3v24Frames.FRAME_ID_USER_DEFINED_URL, frame.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, frame.getBody().getTextEncoding()); assertFalse(ID3v24Frames.getInstanceOf().isExtensionFrames(frame.getIdentifier())); assertTrue(ID3v24Frames.getInstanceOf().isSupportedFrames(frame.getIdentifier())); assertEquals(UNICODE_ENCODED, ((FrameBodyWXXX) frame.getBody()).getUrlLink()); } public void testEncodeURL() throws UnsupportedEncodingException { String url = UNICODE_LINK; final String[] splitURL = url.split("(? tagFields = f.getTag().getFields(FieldKey.ALBUM_ARTIST_SORT); assertEquals(0,tagFields.size()); //Add album artist sort field f.getTag().addField(FieldKey.ALBUM_ARTIST_SORT,"artist1"); //Add another, jaudiotagger silently adds second value to the same frame because only one frame of this type //allowed, but text frames allow multiple values within them - I this is the correct (albeit confusing) behaviour f.getTag().addField(FieldKey.ALBUM_ARTIST_SORT,"artist2"); //because added to the same frame, the number of fields is only one assertEquals(1,f.getTag().getFields(FieldKey.ALBUM_ARTIST_SORT).size()); assertEquals(1,f.getTag().getFieldCount()); //but the field count includng subvalues takes this into account and shows 2 assertEquals(2,f.getTag().getFieldCountIncludingSubValues()); //And if we get the value back we see the whole value (both values) //TODO is this what we want ? assertEquals("artist1\u0000artist2",f.getTag().getFirst(FieldKey.ALBUM_ARTIST_SORT)); assertEquals("artist1\u0000artist2",f.getTag().getValue(FieldKey.ALBUM_ARTIST_SORT,0)); //As can be seen from the longhand method ID3v24Frame frame = (ID3v24Frame)f.getTag().getFirstField(FieldKey.ALBUM_ARTIST_SORT); assertEquals("artist1\u0000artist2",((AbstractFrameBodyTextInfo)frame.frameBody).getText()); //We can get individual values back using longhand as well assertEquals("artist1",((AbstractFrameBodyTextInfo)frame.frameBody).getValueAtIndex(0)); assertEquals("artist2",((AbstractFrameBodyTextInfo)frame.frameBody).getValueAtIndex(1)); //TODO .. but we need a neater generic method assertEquals(1,((AbstractID3v2Tag)f.getTag()).getFieldCount()); tagFields = f.getTag().getFields(FieldKey.ALBUM_ARTIST_SORT); assertEquals(1,tagFields.size()); f.commit(); f = AudioFileIO.read(testFile); assertEquals(1,f.getTag().getFields(FieldKey.ALBUM_ARTIST_SORT).size()); assertEquals("artist1\u0000artist2",f.getTag().getFirst(FieldKey.ALBUM_ARTIST_SORT)); assertEquals(1,f.getTag().getFieldCount()); assertEquals(2,f.getTag().getFieldCountIncludingSubValues()); assertEquals(1,((AbstractID3v2Tag)f.getTag()).getFieldCount()); tagFields = f.getTag().getFields(FieldKey.ALBUM_ARTIST_SORT); assertEquals(1,tagFields.size()); } /** TXXX frames are not treated as text frames regarding nul serpretd strings, only allowed one string */ public void testWriteMultipleTextTXXXFields() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3", new File("testWriteMultipleTextTXXX.mp3")); AudioFile f = AudioFileIO.read(testFile); assertNull(f.getTag()); f.setTag(new ID3v24Tag()); List tagFields = f.getTag().getFields(FieldKey.BARCODE); assertEquals(0,tagFields.size()); f.getTag().addField(FieldKey.BARCODE,"xxxxxxxxxxxxxx"); f.getTag().addField(FieldKey.BARCODE,"yyyyyyyyyyyyyy"); assertEquals(2,f.getTag().getFields(FieldKey.BARCODE).size()); assertEquals(2,f.getTag().getFieldCount()); tagFields = f.getTag().getFields(FieldKey.BARCODE); assertEquals(2,tagFields.size()); f.commit(); f = AudioFileIO.read(testFile); assertEquals(2,f.getTag().getFields(FieldKey.BARCODE).size()); assertEquals(2,f.getTag().getFieldCount()); tagFields = f.getTag().getFields(FieldKey.BARCODE); assertEquals(2,tagFields.size()); } /** TXXX frames are not treated as text frames regarding nul serpretd strings, only allowed one string */ public void testWriteMultipleDifferentTextTXXXFields() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3", new File("testWriteMultipleTextTXXX.mp3")); AudioFile f = AudioFileIO.read(testFile); assertNull(f.getTag()); f.setTag(new ID3v24Tag()); List tagFields = f.getTag().getFields(FieldKey.BARCODE); assertEquals(0,tagFields.size()); f.getTag().addField(FieldKey.BARCODE,"xxxxxxxxxxxxxx"); f.getTag().addField(FieldKey.MUSICBRAINZ_DISC_ID,"yyyyyyyyyyyyyy"); assertEquals(1,f.getTag().getFields(FieldKey.BARCODE).size()); assertEquals(1,f.getTag().getFields(FieldKey.MUSICBRAINZ_DISC_ID).size()); assertEquals(2,f.getTag().getFieldCount()); tagFields = f.getTag().getFields(FieldKey.BARCODE); assertEquals(1,tagFields.size()); f.commit(); f = AudioFileIO.read(testFile); assertEquals(1,f.getTag().getFields(FieldKey.BARCODE).size()); assertEquals(1,f.getTag().getFields(FieldKey.MUSICBRAINZ_DISC_ID).size()); assertEquals(2,f.getTag().getFieldCount()); tagFields = f.getTag().getFields(FieldKey.BARCODE); assertEquals(1,tagFields.size()); } public void testWriteMultipleFields() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3", new File("testWriteMultiple.mp3")); AudioFile f = AudioFileIO.read(testFile); assertNull(f.getTag()); f.setTag(new ID3v24Tag()); List tagFields = f.getTag().getFields(FieldKey.ALBUM_ARTIST_SORT); assertEquals(0,tagFields.size()); f.getTag().addField(FieldKey.URL_OFFICIAL_RELEASE_SITE,"http://www,test.org"); f.getTag().addField(FieldKey.URL_OFFICIAL_RELEASE_SITE,"http://www,test.org"); assertEquals(2,f.getTag().getFields(FieldKey.URL_OFFICIAL_RELEASE_SITE).size()); assertEquals(2,f.getTag().getFieldCount()); assertEquals(2,((AbstractID3v2Tag)f.getTag()).getFieldCount()); tagFields = f.getTag().getFields(FieldKey.URL_OFFICIAL_RELEASE_SITE); //assertEquals(1,tagFields.size()); f.commit(); f = AudioFileIO.read(testFile); assertEquals(2,f.getTag().getFields(FieldKey.URL_OFFICIAL_RELEASE_SITE).size()); assertEquals(2,f.getTag().getFieldCount()); assertEquals(2,((AbstractID3v2Tag)f.getTag()).getFieldCount()); tagFields = f.getTag().getFields(FieldKey.URL_OFFICIAL_RELEASE_SITE); assertEquals(2,tagFields.size()); } public void testDeleteFields() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); MP3File mp3File = new MP3File(testFile); ID3v23Tag v2Tag = new ID3v23Tag(); mp3File.setID3v2Tag(v2Tag); mp3File.save(); //Delete using generic key AudioFile f = AudioFileIO.read(testFile); List tagFields = f.getTag().getFields(FieldKey.ALBUM_ARTIST_SORT); assertEquals(0,tagFields.size()); f.getTag().addField(FieldKey.ALBUM_ARTIST_SORT,"artist1"); tagFields = f.getTag().getFields(FieldKey.ALBUM_ARTIST_SORT); assertEquals(1,tagFields.size()); f.getTag().deleteField(FieldKey.ALBUM_ARTIST_SORT); f.commit(); //Delete using flac id f = AudioFileIO.read(testFile); tagFields = f.getTag().getFields(FieldKey.ALBUM_ARTIST_SORT); assertEquals(0,tagFields.size()); f.getTag().addField(FieldKey.ALBUM_ARTIST_SORT,"artist1"); tagFields = f.getTag().getFields(FieldKey.ALBUM_ARTIST_SORT); assertEquals(1,tagFields.size()); f.getTag().deleteField("TSO2"); tagFields = f.getTag().getFields(FieldKey.ALBUM_ARTIST_SORT); assertEquals(0,tagFields.size()); f.commit(); f = AudioFileIO.read(testFile); tagFields = f.getTag().getFields(FieldKey.ALBUM_ARTIST_SORT); assertEquals(0,tagFields.size()); } /** Test Deleting tag and that deletion of tag is represented startight away * * @throws Exception */ public void testDeleteTag() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("test70.mp3"); MP3File audioFile = new MP3File(testFile); ID3v1Tag v1tag = audioFile.getID3v1Tag(); assertTrue(audioFile.hasID3v1Tag()); audioFile.delete(v1tag); assertFalse(audioFile.hasID3v1Tag()); AbstractID3v2Tag tag = audioFile.getID3v2Tag(); assertTrue(audioFile.hasID3v2Tag()); audioFile.delete(tag); assertFalse(audioFile.hasID3v2Tag()); audioFile = new MP3File(testFile); assertFalse(audioFile.hasID3v2Tag()); assertFalse(audioFile.hasID3v1Tag()); } public void testWriteTagUsingAudioIOMethod() { Exception exceptionCaught=null; try { File testFile = AbstractTestCase.copyAudioToTmp("test70.mp3"); MP3File audioFile = new MP3File(testFile); AudioFileIO.write(audioFile); } catch(Exception e) { exceptionCaught=e; } assertNull(exceptionCaught); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/id3/FrameTSOCTest.java0000644000175000017500000002026411041064726027073 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.mp3.MP3File; import org.jaudiotagger.tag.id3.framebody.FrameBodyTSOC; import org.jaudiotagger.tag.id3.framebody.FrameBodyTSOCTest; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; import java.io.File; /** * Test TSOC Frame */ public class FrameTSOCTest extends AbstractTestCase { public static ID3v24Frame getV24InitialisedFrame() { ID3v24Frame frame = new ID3v24Frame(ID3v24Frames.FRAME_ID_COMPOSER_SORT_ORDER_ITUNES); FrameBodyTSOC fb = FrameBodyTSOCTest.getInitialisedBody(); frame.setBody(fb); return frame; } public static ID3v23Frame getV23InitialisedFrame() { ID3v23Frame frame = new ID3v23Frame(ID3v23Frames.FRAME_ID_V3_COMPOSER_SORT_ORDER_ITUNES); FrameBodyTSOC fb = FrameBodyTSOCTest.getInitialisedBody(); frame.setBody(fb); return frame; } public static ID3v22Frame getV22InitialisedFrame() { ID3v22Frame frame = new ID3v22Frame(ID3v22Frames.FRAME_ID_V2_COMPOSER_SORT_ORDER_ITUNES); FrameBodyTSOC fb = FrameBodyTSOCTest.getInitialisedBody(); frame.setBody(fb); return frame; } public void testCreateID3v24Frame() { Exception exceptionCaught = null; ID3v24Frame frame = null; try { frame = getV24InitialisedFrame(); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v24Frames.FRAME_ID_COMPOSER_SORT_ORDER_ITUNES, frame.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, frame.getBody().getTextEncoding()); assertTrue(ID3v24Frames.getInstanceOf().isExtensionFrames(frame.getIdentifier())); assertFalse(ID3v24Frames.getInstanceOf().isSupportedFrames(frame.getIdentifier())); assertEquals(FrameBodyTSOCTest.COMPOSER_SORT, ((FrameBodyTSOC) frame.getBody()).getText()); } public void testCreateID3v23Frame() { Exception exceptionCaught = null; ID3v23Frame frame = null; try { frame = getV23InitialisedFrame(); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v23Frames.FRAME_ID_V3_COMPOSER_SORT_ORDER_ITUNES, frame.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, frame.getBody().getTextEncoding()); assertTrue(ID3v23Frames.getInstanceOf().isExtensionFrames(frame.getIdentifier())); assertFalse(ID3v23Frames.getInstanceOf().isSupportedFrames(frame.getIdentifier())); assertEquals(FrameBodyTSOCTest.COMPOSER_SORT, ((FrameBodyTSOC) frame.getBody()).getText()); } public void testCreateID3v22Frame() { Exception exceptionCaught = null; ID3v22Frame frame = null; try { frame = getV22InitialisedFrame(); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v22Frames.FRAME_ID_V2_COMPOSER_SORT_ORDER_ITUNES, frame.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, frame.getBody().getTextEncoding()); assertTrue(ID3v22Frames.getInstanceOf().isExtensionFrames(frame.getIdentifier())); assertFalse(ID3v22Frames.getInstanceOf().isSupportedFrames(frame.getIdentifier())); assertEquals(FrameBodyTSOCTest.COMPOSER_SORT, ((FrameBodyTSOC) frame.getBody()).getText()); } public void testSaveToFile() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); MP3File mp3File = new MP3File(testFile); //Create and Save ID3v24Tag tag = new ID3v24Tag(); tag.setFrame(getV24InitialisedFrame()); mp3File.setID3v2Tag(tag); mp3File.save(); //Reload mp3File = new MP3File(testFile); ID3v24Frame frame = (ID3v24Frame) mp3File.getID3v2Tag().getFrame(ID3v24Frames.FRAME_ID_COMPOSER_SORT_ORDER_ITUNES); FrameBodyTSOC body = (FrameBodyTSOC) frame.getBody(); assertEquals(TextEncoding.ISO_8859_1, body.getTextEncoding()); } public void testConvertV24ToV23() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); MP3File mp3File = new MP3File(testFile); //Create and Save ID3v24Tag tag = new ID3v24Tag(); tag.setFrame(getV24InitialisedFrame()); mp3File.setID3v2Tag(tag); mp3File.save(); //Reload and convert to v23 and save mp3File = new MP3File(testFile); mp3File.setID3v2TagOnly(new ID3v23Tag(mp3File.getID3v2TagAsv24())); mp3File.save(); //Reload mp3File = new MP3File(testFile); ID3v23Frame frame = (ID3v23Frame) mp3File.getID3v2Tag().getFrame(ID3v23Frames.FRAME_ID_V3_COMPOSER_SORT_ORDER_ITUNES); FrameBodyTSOC body = (FrameBodyTSOC) frame.getBody(); assertEquals(TextEncoding.ISO_8859_1, body.getTextEncoding()); assertEquals(FrameBodyTSOCTest.COMPOSER_SORT, body.getText()); } public void testConvertV24ToV22() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); MP3File mp3File = new MP3File(testFile); //Create and Save ID3v24Tag tag = new ID3v24Tag(); tag.setFrame(FrameTSOCTest.getV24InitialisedFrame()); mp3File.setID3v2Tag(tag); mp3File.save(); //Reload and convert to v22 and save mp3File = new MP3File(testFile); mp3File.setID3v2TagOnly(new ID3v22Tag(mp3File.getID3v2TagAsv24())); mp3File.save(); //Reload mp3File = new MP3File(testFile); ID3v22Frame frame = (ID3v22Frame) mp3File.getID3v2Tag().getFrame(ID3v22Frames.FRAME_ID_V2_COMPOSER_SORT_ORDER_ITUNES); FrameBodyTSOC body = (FrameBodyTSOC) frame.getBody(); assertEquals(TextEncoding.ISO_8859_1, body.getTextEncoding()); assertEquals(FrameBodyTSOCTest.COMPOSER_SORT, body.getText()); } public void testConvertV23ToV22() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); MP3File mp3File = new MP3File(testFile); //Create and Save ID3v23Tag tag = new ID3v23Tag(); tag.setFrame(FrameTSOCTest.getV23InitialisedFrame()); mp3File.setID3v2TagOnly((ID3v23Tag) tag); mp3File.save(); //Reload and convert from v23 to v22 and save mp3File = new MP3File(testFile); mp3File.setID3v2TagOnly(new ID3v22Tag(mp3File.getID3v2Tag())); mp3File.save(); //Reload mp3File = new MP3File(testFile); ID3v22Frame frame = (ID3v22Frame) mp3File.getID3v2Tag().getFrame(ID3v22Frames.FRAME_ID_V2_COMPOSER_SORT_ORDER_ITUNES); FrameBodyTSOC body = (FrameBodyTSOC) frame.getBody(); assertEquals(TextEncoding.ISO_8859_1, body.getTextEncoding()); assertEquals(FrameBodyTSOCTest.COMPOSER_SORT, body.getText()); } public void testConvertV22ToV24() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); MP3File mp3File = new MP3File(testFile); //Create and Save ID3v22Tag tag = new ID3v22Tag(); //..Notes (uses v22Frame but frame body will be the v23/24 version) ID3v22Frame id3v22frame = new ID3v22Frame(ID3v22Frames.FRAME_ID_V2_COMPOSER_SORT_ORDER_ITUNES); ((FrameBodyTSOC) id3v22frame.getBody()).setText(FrameBodyTSOCTest.COMPOSER_SORT); tag.setFrame(id3v22frame); mp3File.setID3v2TagOnly((ID3v22Tag) tag); mp3File.save(); //Reload and convert from v22 to v24 and save mp3File = new MP3File(testFile); mp3File.setID3v2TagOnly(new ID3v24Tag(mp3File.getID3v2Tag())); mp3File.save(); //Reload mp3File = new MP3File(testFile); ID3v24Frame frame = (ID3v24Frame) mp3File.getID3v2Tag().getFrame(ID3v24Frames.FRAME_ID_COMPOSER_SORT_ORDER_ITUNES); FrameBodyTSOC body = (FrameBodyTSOC) frame.getBody(); assertEquals(TextEncoding.ISO_8859_1, body.getTextEncoding()); assertEquals(FrameBodyTSOCTest.COMPOSER_SORT, body.getText()); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/id3/FrameTDLYTest.java0000644000175000017500000000152011331564261027072 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.tag.id3.framebody.FrameBodyTDLY; import org.jaudiotagger.tag.id3.framebody.FrameBodyTDTG; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; public class FrameTDLYTest extends AbstractTestCase { public void testID3Specific() throws Exception { Exception e=null; try { ID3v24Tag tag = new ID3v24Tag(); ID3v24Frame frame = new ID3v24Frame("TDLY"); frame.setBody(new FrameBodyTDLY(TextEncoding.ISO_8859_1,"11:10")); tag.addFrame(frame); assertEquals("11:10",tag.getFirst("TDLY")); } catch(Exception ex) { e=ex; ex.printStackTrace(); } assertNull(e); } }libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/id3/FrameTDRCTest.java0000644000175000017500000000123711041064726027056 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.mp3.MP3File; import java.io.File; /** * Test TDRCFrame */ public class FrameTDRCTest extends AbstractTestCase { public void testReadFileContainingTDRCAndTYERFrames() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("Issue73.id3", "testV1.mp3"); MP3File mp3File = new MP3File(testFile); ID3v23Frame v23frame = (ID3v23Frame) mp3File.getID3v2Tag().getFrame(ID3v23Frames.FRAME_ID_V3_TYER); ID3v24Frame v24frame = (ID3v24Frame) mp3File.getID3v2TagAsv24().getFrame(ID3v23Frames.FRAME_ID_V3_TYER); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/id3/FrameTDENTest.java0000644000175000017500000000153011331564261027051 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.tag.id3.framebody.FrameBodyTDEN; import org.jaudiotagger.tag.id3.framebody.FrameBodyTDTG; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; /** */ public class FrameTDENTest extends AbstractTestCase { public void testID3Specific() throws Exception { Exception e=null; try { ID3v24Tag tag = new ID3v24Tag(); ID3v24Frame frame = new ID3v24Frame("TDEN"); frame.setBody(new FrameBodyTDEN(TextEncoding.ISO_8859_1,"11:10")); tag.addFrame(frame); assertEquals("11:10",tag.getFirst("TDEN")); } catch(Exception ex) { e=ex; ex.printStackTrace(); } assertNull(e); } }libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/id3/FrameTXXXTest.java0000644000175000017500000001763211330522400027130 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.mp3.MP3File; import org.jaudiotagger.tag.id3.framebody.FrameBodyTSOC; import org.jaudiotagger.tag.id3.framebody.FrameBodyTSOCTest; import org.jaudiotagger.tag.id3.framebody.FrameBodyTXXX; import org.jaudiotagger.tag.id3.framebody.FrameBodyTXXXTest; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; import java.io.File; /** * Test TXXX Frame */ public class FrameTXXXTest extends AbstractTestCase { public static ID3v24Frame getV24InitialisedFrame() { ID3v24Frame frame = new ID3v24Frame(ID3v24Frames.FRAME_ID_USER_DEFINED_INFO); FrameBodyTXXX fb = FrameBodyTXXXTest.getInitialisedBody(); frame.setBody(fb); return frame; } public static ID3v23Frame getV23InitialisedFrame() { ID3v23Frame frame = new ID3v23Frame(ID3v23Frames.FRAME_ID_V3_USER_DEFINED_INFO); FrameBodyTXXX fb = FrameBodyTXXXTest.getInitialisedBody(); frame.setBody(fb); return frame; } public static ID3v22Frame getV22InitialisedFrame() { ID3v22Frame frame = new ID3v22Frame(ID3v22Frames.FRAME_ID_V2_USER_DEFINED_INFO); FrameBodyTXXX fb = FrameBodyTXXXTest.getInitialisedBody(); frame.setBody(fb); return frame; } public void testCreateID3v24Frame() { Exception exceptionCaught = null; ID3v24Frame frame = null; try { frame = getV24InitialisedFrame(); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v24Frames.FRAME_ID_USER_DEFINED_INFO, frame.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, frame.getBody().getTextEncoding()); assertFalse(ID3v24Frames.getInstanceOf().isExtensionFrames(frame.getIdentifier())); assertTrue(ID3v24Frames.getInstanceOf().isSupportedFrames(frame.getIdentifier())); } public void testCreateID3v23Frame() { Exception exceptionCaught = null; ID3v23Frame frame = null; try { frame = getV23InitialisedFrame(); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v23Frames.FRAME_ID_V3_USER_DEFINED_INFO, frame.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, frame.getBody().getTextEncoding()); assertFalse(ID3v23Frames.getInstanceOf().isExtensionFrames(frame.getIdentifier())); assertTrue(ID3v23Frames.getInstanceOf().isSupportedFrames(frame.getIdentifier())); } public void testCreateID3v22Frame() { Exception exceptionCaught = null; ID3v22Frame frame = null; try { frame = getV22InitialisedFrame(); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v22Frames.FRAME_ID_V2_USER_DEFINED_INFO, frame.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, frame.getBody().getTextEncoding()); assertFalse(ID3v22Frames.getInstanceOf().isExtensionFrames(frame.getIdentifier())); assertTrue(ID3v22Frames.getInstanceOf().isSupportedFrames(frame.getIdentifier())); } public void testSaveToFile() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); MP3File mp3File = new MP3File(testFile); //Create and Save ID3v24Tag tag = new ID3v24Tag(); tag.setFrame(getV24InitialisedFrame()); mp3File.setID3v2Tag(tag); mp3File.save(); //Reload mp3File = new MP3File(testFile); ID3v24Frame frame = (ID3v24Frame) mp3File.getID3v2Tag().getFrame(ID3v24Frames.FRAME_ID_USER_DEFINED_INFO); FrameBodyTXXX body = (FrameBodyTXXX) frame.getBody(); assertEquals(TextEncoding.ISO_8859_1, body.getTextEncoding()); } public void testConvertV24ToV23() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); MP3File mp3File = new MP3File(testFile); //Create and Save ID3v24Tag tag = new ID3v24Tag(); tag.setFrame(getV24InitialisedFrame()); mp3File.setID3v2Tag(tag); mp3File.save(); //Reload and convert to v23 and save mp3File = new MP3File(testFile); mp3File.setID3v2TagOnly(new ID3v23Tag(mp3File.getID3v2TagAsv24())); mp3File.save(); //Reload mp3File = new MP3File(testFile); ID3v23Frame frame = (ID3v23Frame) mp3File.getID3v2Tag().getFrame(ID3v23Frames.FRAME_ID_V3_USER_DEFINED_INFO); FrameBodyTXXX body = (FrameBodyTXXX) frame.getBody(); assertEquals(TextEncoding.ISO_8859_1, body.getTextEncoding()); assertEquals(FrameBodyTXXXTest.TXXX_TEST_DESC, body.getText()); } public void testConvertV24ToV22() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); MP3File mp3File = new MP3File(testFile); //Create and Save ID3v24Tag tag = new ID3v24Tag(); tag.setFrame(FrameTXXXTest.getV24InitialisedFrame()); mp3File.setID3v2Tag(tag); mp3File.save(); //Reload and convert to v22 and save mp3File = new MP3File(testFile); mp3File.setID3v2TagOnly(new ID3v22Tag(mp3File.getID3v2TagAsv24())); mp3File.save(); //Reload mp3File = new MP3File(testFile); ID3v22Frame frame = (ID3v22Frame) mp3File.getID3v2Tag().getFrame(ID3v22Frames.FRAME_ID_V2_USER_DEFINED_INFO); FrameBodyTXXX body = (FrameBodyTXXX) frame.getBody(); assertEquals(TextEncoding.ISO_8859_1, body.getTextEncoding()); assertEquals(FrameBodyTXXXTest.TXXX_TEST_DESC, body.getText()); } public void testConvertV23ToV22() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); MP3File mp3File = new MP3File(testFile); //Create and Save ID3v23Tag tag = new ID3v23Tag(); tag.setFrame(FrameTXXXTest.getV23InitialisedFrame()); mp3File.setID3v2TagOnly((ID3v23Tag) tag); mp3File.save(); //Reload and convert from v23 to v22 and save mp3File = new MP3File(testFile); mp3File.setID3v2TagOnly(new ID3v22Tag(mp3File.getID3v2Tag())); mp3File.save(); //Reload mp3File = new MP3File(testFile); ID3v22Frame frame = (ID3v22Frame) mp3File.getID3v2Tag().getFrame(ID3v22Frames.FRAME_ID_V2_USER_DEFINED_INFO); FrameBodyTXXX body = (FrameBodyTXXX) frame.getBody(); assertEquals(TextEncoding.ISO_8859_1, body.getTextEncoding()); assertEquals(FrameBodyTXXXTest.TXXX_TEST_DESC, body.getText()); } public void testConvertV22ToV24() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); MP3File mp3File = new MP3File(testFile); //Create and Save ID3v22Tag tag = new ID3v22Tag(); //..Notes (uses v22Frame but frame body will be the v23/24 version) ID3v22Frame id3v22frame = new ID3v22Frame(ID3v22Frames.FRAME_ID_V2_USER_DEFINED_INFO); ((FrameBodyTXXX) id3v22frame.getBody()).setText(FrameBodyTXXXTest.TXXX_TEST_STRING); tag.setFrame(id3v22frame); mp3File.setID3v2TagOnly((ID3v22Tag) tag); mp3File.save(); //Reload and convert from v22 to v24 and save mp3File = new MP3File(testFile); mp3File.setID3v2TagOnly(new ID3v24Tag(mp3File.getID3v2Tag())); mp3File.save(); //Reload mp3File = new MP3File(testFile); ID3v24Frame frame = (ID3v24Frame) mp3File.getID3v2Tag().getFrame(ID3v24Frames.FRAME_ID_USER_DEFINED_INFO); FrameBodyTXXX body = (FrameBodyTXXX) frame.getBody(); assertEquals(TextEncoding.ISO_8859_1, body.getTextEncoding()); assertEquals(FrameBodyTXXXTest.TXXX_TEST_STRING, body.getText()); } }libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/id3/FileClosingTest.java0000644000175000017500000000430411276777123027557 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.mp3.MP3File; import java.io.File; /** * testing of reading compressed frames */ public class FileClosingTest extends AbstractTestCase { /** * This tests checks files are closed after reading attempt */ public void testClosingFileAfterFailedRead() { Exception exception = null; File testFile = AbstractTestCase.copyAudioToTmp("corrupt.mp3"); //Try and Read try { MP3File mp3File = new MP3File(testFile); } catch (Exception e) { exception = e; } //Error Should have occured assertTrue(exception != null); //Should be able to deleteField boolean deleted = testFile.delete(); assertTrue(deleted); } /** * This tests checks files are closed after succesful reading attempt */ public void testClosingFileAfterSuccessfulRead() { Exception exception = null; File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); //Try and Read try { MP3File mp3File = new MP3File(testFile); } catch (Exception e) { exception = e; } //No Error Should have occured assertTrue(exception == null); //Should be able to deleteField boolean deleted = testFile.delete(); assertTrue(deleted); } /** * This tests checks files are closed after failed reading attempt (read only) */ public void testClosingFileAfterFailedReadOnly() { Exception exception = null; File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); boolean readonly = testFile.setReadOnly(); assertTrue(readonly); //Try and Read try { MP3File mp3File = new MP3File(testFile); } catch (Exception e) { exception = e; } //Error Should have occured assertTrue(exception != null); //Should be able to deleteField boolean deleted = testFile.delete(); assertTrue(deleted); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/id3/FrameTIMETest.java0000644000175000017500000000143611331564261027062 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.tag.id3.framebody.FrameBodyTPE1; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; /** */ public class FrameTIMETest extends AbstractTestCase { public void testID3Specific() throws Exception { Exception e=null; try { ID3v23Tag tag = new ID3v23Tag(); ID3v23Frame frame = new ID3v23Frame("TIME"); frame.setBody(new FrameBodyTPE1(TextEncoding.ISO_8859_1,"11:10")); tag.addFrame(frame); assertEquals("11:10",tag.getFirst("TIME")); } catch(Exception ex) { e=ex; ex.printStackTrace(); } assertNull(e); } }libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/id3/FrameTLANTest.java0000644000175000017500000000072211041064726027056 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.mp3.MP3File; import java.io.File; /** * Test TLANFrame */ public class FrameTLANTest extends AbstractTestCase { public void testWriteFileContainingTLANFrame() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("Issue116.id3", "testV1.mp3"); MP3File mp3File = new MP3File(testFile); mp3File.save(); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/id3/EmptyFrameTest.java0000644000175000017500000001060111470746136027423 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3; import junit.framework.TestCase; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.mp3.MP3File; import org.jaudiotagger.tag.id3.framebody.FrameBodyWOAF; import org.jaudiotagger.tag.id3.framebody.FrameBodyWORS; import java.io.File; /** * Issue #183:Tests that tags containiing empty frames (which are not really allowed by ID3 spec, but do exist) dont * prevent subsequent framesthat contain data from being read. * Date: 01-Jan-2008 */ public class EmptyFrameTest extends TestCase { public void testWriteID3v23TagWithEmptyFrameFirst() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1Cbr128ID3v2.mp3"); MP3File mp3File = null; mp3File = new MP3File(testFile); assertTrue(mp3File.hasID3v2Tag()); assertEquals(8, mp3File.getID3v2Tag().getFieldCount()); ID3v23Frame emptyFrame = new ID3v23Frame(ID3v23Frames.FRAME_ID_V3_URL_FILE_WEB); ((FrameBodyWOAF) emptyFrame.getBody()).setUrlLink(""); ID3v23Frame nonemptyFrame = new ID3v23Frame(ID3v23Frames.FRAME_ID_V3_URL_OFFICIAL_RADIO); ((FrameBodyWORS) nonemptyFrame.getBody()).setUrlLink("something"); mp3File.getID3v2Tag().setFrame(emptyFrame); mp3File.getID3v2Tag().setFrame(nonemptyFrame); mp3File.save(); mp3File = new MP3File(testFile); assertTrue(mp3File.hasID3v2Tag()); //Empty frame is disregarded, but doesnt prevent retrievel of valid WORS frame, so count of frame increased by //one assertEquals(9, mp3File.getID3v2Tag().getFieldCount()); assertEquals(0, mp3File.getID3v2Tag().getFields("WOAF").size()); assertEquals(1, mp3File.getID3v2Tag().getFields("WORS").size()); } public void testWriteID3v24TagWithEmptyFrameFirst() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1Cbr128ID3v2.mp3"); MP3File mp3File = null; mp3File = new MP3File(testFile); //Convert to v24 mp3File.setID3v2Tag(new ID3v24Tag(mp3File.getID3v2Tag())); mp3File.save(); assertTrue(mp3File.hasID3v2Tag()); assertEquals(8, mp3File.getID3v2Tag().getFieldCount()); ID3v24Frame emptyFrame = new ID3v24Frame(ID3v24Frames.FRAME_ID_URL_FILE_WEB); ((FrameBodyWOAF) emptyFrame.getBody()).setUrlLink(""); ID3v24Frame nonemptyFrame = new ID3v24Frame(ID3v24Frames.FRAME_ID_URL_OFFICIAL_RADIO); ((FrameBodyWORS) nonemptyFrame.getBody()).setUrlLink("something"); mp3File.getID3v2Tag().setFrame(emptyFrame); mp3File.getID3v2Tag().setFrame(nonemptyFrame); mp3File.save(); mp3File = new MP3File(testFile); assertTrue(mp3File.hasID3v2Tag()); //Empty frame is disregarded, but doesnt prevent retrievel of valid WORS frame, so count of frame increased by //one assertEquals(9, mp3File.getID3v2Tag().getFieldCount()); assertEquals(0, mp3File.getID3v2Tag().getFields("WOAF").size()); assertEquals(1, mp3File.getID3v2Tag().getFields("WORS").size()); } public void testWriteID3v22TagWithEmptyFrameFirst() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1Cbr128ID3v2.mp3"); MP3File mp3File = null; mp3File = new MP3File(testFile); //Convert to v24 mp3File.setID3v2Tag(new ID3v22Tag(mp3File.getID3v2Tag())); mp3File.save(); assertTrue(mp3File.hasID3v2Tag()); assertEquals(8, mp3File.getID3v2Tag().getFieldCount()); ID3v22Frame emptyFrame = new ID3v22Frame(ID3v22Frames.FRAME_ID_V2_URL_FILE_WEB); ((FrameBodyWOAF) emptyFrame.getBody()).setUrlLink(""); ID3v22Frame nonemptyFrame = new ID3v22Frame(ID3v22Frames.FRAME_ID_V2_URL_OFFICIAL_RADIO); ((FrameBodyWORS) nonemptyFrame.getBody()).setUrlLink("something"); mp3File.getID3v2Tag().setFrame(emptyFrame); mp3File.getID3v2Tag().setFrame(nonemptyFrame); mp3File.save(); mp3File = new MP3File(testFile); assertTrue(mp3File.hasID3v2Tag()); //Empty frame is disregarded, but doesnt prevent retrievel of valid WORS frame, so count of frame increased by //one assertEquals(9, mp3File.getID3v2Tag().getFieldCount()); assertEquals(0, mp3File.getID3v2Tag().getFields("WAF").size()); assertEquals(1, mp3File.getID3v2Tag().getFields("WRS").size()); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/id3/ID3v11TagTest.java0000644000175000017500000002655211470746136026731 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.mp3.MP3File; import org.jaudiotagger.tag.FieldKey; import org.jaudiotagger.tag.TagOptionSingleton; import org.jaudiotagger.tag.TagTextField; import java.io.File; /** * */ public class ID3v11TagTest extends TestCase { public static final String ARTIST = "artist"; public static final String ALBUM = "album"; public static final String COMMENT = "comment"; public static final String TITLE = "title"; public static final String TRACK_VALUE = "10"; public static final String GENRE_VAL = "Country"; public static final String YEAR = "1971"; /** * Provides an initilised object to be used in other tests * to prevent code duplication * * @return ID3v11Tag */ public static ID3v11Tag getInitialisedTag() { ID3v11Tag v11Tag = new ID3v11Tag(); v11Tag.setArtist(ARTIST); v11Tag.setAlbum(ALBUM); v11Tag.setComment(COMMENT); v11Tag.setTitle(TITLE); v11Tag.setTrack(TRACK_VALUE); v11Tag.setGenre(GENRE_VAL); v11Tag.setYear(YEAR); return v11Tag; } /** * Constructor * * @param arg0 */ public ID3v11TagTest(String arg0) { super(arg0); } /** * Command line entrance. * * @param args */ public static void main(String[] args) { junit.textui.TestRunner.run(ID3v11TagTest.suite()); } ///////////////////////////////////////////////////////////////////////// // TestCase classes to override ///////////////////////////////////////////////////////////////////////// /** * */ protected void setUp() { TagOptionSingleton.getInstance().setToDefault(); } /** * */ protected void tearDown() { } /** * */ // protected void runTest() // { // } /** * Builds the Test Suite. * * @return the Test Suite. */ public static Test suite() { return new TestSuite(ID3v11TagTest.class); } ///////////////////////////////////////////////////////////////////////// // Tests ///////////////////////////////////////////////////////////////////////// public void testCreateID3v11Tag() throws Exception { ID3v11Tag v11Tag = new ID3v11Tag(); v11Tag.setArtist(ARTIST); v11Tag.setAlbum(ALBUM); v11Tag.setComment(COMMENT); v11Tag.setTitle(TITLE); v11Tag.setTrack(TRACK_VALUE); v11Tag.setGenre(GENRE_VAL); v11Tag.setYear(YEAR); assertEquals((byte) 1, v11Tag.getRelease()); assertEquals((byte) 1, v11Tag.getMajorVersion()); assertEquals((byte) 0, v11Tag.getRevision()); assertEquals(ARTIST, v11Tag.getFirst(FieldKey.ARTIST)); assertEquals(ALBUM, v11Tag.getFirst(FieldKey.ALBUM)); assertEquals(COMMENT, v11Tag.getFirstComment()); assertEquals(TITLE, v11Tag.getFirst(FieldKey.TITLE)); assertEquals(TRACK_VALUE, v11Tag.getFirst(FieldKey.TRACK)); assertEquals(GENRE_VAL, v11Tag.getFirst(FieldKey.GENRE)); assertEquals(YEAR, v11Tag.getFirst(FieldKey.YEAR)); //Check with entagged interface assertEquals(ID3v1TagTest.ARTIST, ((TagTextField) v11Tag.getArtist().get(0)).getContent()); assertEquals(ID3v1TagTest.ALBUM, ((TagTextField) v11Tag.getAlbum().get(0)).getContent()); assertEquals(ID3v1TagTest.COMMENT, ((TagTextField) v11Tag.getComment().get(0)).getContent()); assertEquals(ID3v1TagTest.TITLE, ((TagTextField) v11Tag.getTitle().get(0)).getContent()); assertEquals(ID3v1TagTest.GENRE_VAL, ((TagTextField) v11Tag.getGenre().get(0)).getContent()); assertEquals(ID3v1TagTest.TRACK_VALUE, ((TagTextField) v11Tag.getTrack().get(0)).getContent()); assertEquals(ID3v1TagTest.YEAR, ((TagTextField) v11Tag.getYear().get(0)).getContent()); v11Tag.setField(FieldKey.TRACK,"3"); assertEquals("3",v11Tag.getFirst(FieldKey.TRACK)); } public void testCreateID3v11FromID3v24() { ID3v24Tag v2Tag = new ID3v24Tag(); ID3v11Tag v1Tag = new ID3v11Tag(v2Tag); assertNotNull(v1Tag); assertEquals((byte) 1, v1Tag.getRelease()); assertEquals((byte) 1, v1Tag.getMajorVersion()); assertEquals((byte) 0, v1Tag.getRevision()); } public void testCreateID3v11FromID3v23() { ID3v23Tag v2Tag = new ID3v23Tag(); ID3v11Tag v1Tag = new ID3v11Tag(v2Tag); assertNotNull(v1Tag); assertEquals((byte) 1, v1Tag.getRelease()); assertEquals((byte) 1, v1Tag.getMajorVersion()); assertEquals((byte) 0, v1Tag.getRevision()); } public void testCreateID3v11FromID3v22() { ID3v22Tag v2Tag = new ID3v22Tag(); ID3v11Tag v1Tag = new ID3v11Tag(v2Tag); assertNotNull(v1Tag); assertEquals((byte) 1, v1Tag.getRelease()); assertEquals((byte) 1, v1Tag.getMajorVersion()); assertEquals((byte) 0, v1Tag.getRevision()); } public void testNewInterface() { Exception exceptionCaught = null; ID3v1Tag v1Tag = new ID3v11Tag(); assertTrue(v1Tag.isEmpty()); v1Tag.setField(new ID3v1TagField(FieldKey.ARTIST.name(), "artist")); assertEquals("artist", ((TagTextField) v1Tag.getFields(FieldKey.ARTIST).get(0)).getContent()); assertEquals("artist", v1Tag.getFirst(FieldKey.ARTIST)); assertEquals("artist", ((TagTextField) (v1Tag.getArtist().get(0))).getContent()); assertEquals("artist", ((TagTextField) v1Tag.getFirstField(FieldKey.ARTIST.name())).getContent()); assertEquals("artist", ((TagTextField) (v1Tag.getFields(FieldKey.ARTIST.name()).get(0))).getContent()); v1Tag.setField(new ID3v1TagField(FieldKey.ALBUM.name(), "album")); assertEquals("album", ((TagTextField) v1Tag.getFields(FieldKey.ALBUM).get(0)).getContent()); assertEquals("album", v1Tag.getFirst(FieldKey.ALBUM)); assertEquals("album", ((TagTextField) (v1Tag.getAlbum().get(0))).getContent()); assertEquals("album", ((TagTextField) v1Tag.getFirstField(FieldKey.ALBUM.name())).getContent()); v1Tag.setField(new ID3v1TagField(FieldKey.TITLE.name(), "title")); assertEquals("title", ((TagTextField) v1Tag.getFields(FieldKey.TITLE).get(0)).getContent()); assertEquals("title", v1Tag.getFirst(FieldKey.TITLE)); assertEquals("title", ((TagTextField) (v1Tag.getTitle().get(0))).getContent()); assertEquals("title", ((TagTextField) v1Tag.getFirstField(FieldKey.TITLE.name())).getContent()); v1Tag.setField(new ID3v1TagField(FieldKey.YEAR.name(), "year")); assertEquals("year", ((TagTextField) v1Tag.getFields(FieldKey.YEAR).get(0)).getContent()); assertEquals("year", v1Tag.getFirst(FieldKey.YEAR)); assertEquals("year", ((TagTextField) (v1Tag.getYear().get(0))).getContent()); assertEquals("year", ((TagTextField) v1Tag.getFirstField(FieldKey.YEAR.name())).getContent()); v1Tag.setField(new ID3v1TagField(FieldKey.GENRE.name(), "Country")); assertEquals("Country", ((TagTextField) v1Tag.getFields(FieldKey.GENRE).get(0)).getContent()); assertEquals("Country", v1Tag.getFirst(FieldKey.GENRE)); assertEquals("Country", ((TagTextField) (v1Tag.getGenre().get(0))).getContent()); assertEquals("Country", ((TagTextField) v1Tag.getFirstField(FieldKey.GENRE.name())).getContent()); v1Tag.setField(new ID3v1TagField(FieldKey.COMMENT.name(), "comment")); assertEquals("comment", ((TagTextField) v1Tag.getFields(FieldKey.COMMENT).get(0)).getContent()); assertEquals("comment", v1Tag.getFirstComment()); assertEquals("comment", ((TagTextField) (v1Tag.getFields(FieldKey.COMMENT).get(0))).getContent()); assertEquals("comment", ((TagTextField) v1Tag.getFirstField(FieldKey.COMMENT.name())).getContent()); v1Tag.setField(new ID3v1TagField(FieldKey.TRACK.name(), "5")); assertEquals("5", ((TagTextField) v1Tag.getFields(FieldKey.TRACK).get(0)).getContent()); assertEquals("5", v1Tag.getFirst(FieldKey.TRACK)); assertEquals("5", ((TagTextField) (v1Tag.getTrack().get(0))).getContent()); assertEquals("5", ((TagTextField) v1Tag.getFirstField(FieldKey.TRACK.name())).getContent()); //Check nothing been overwritten assertEquals("year", v1Tag.getFirst(FieldKey.YEAR)); assertEquals("Country", v1Tag.getFirst(FieldKey.GENRE)); assertEquals("title", v1Tag.getFirst(FieldKey.TITLE)); assertEquals("album", v1Tag.getFirst(FieldKey.ALBUM)); assertEquals("artist", v1Tag.getFirst(FieldKey.ARTIST)); //Delete artist field v1Tag.deleteField(FieldKey.ARTIST); assertEquals("", v1Tag.getFirst(FieldKey.ARTIST)); assertEquals("year", v1Tag.getFirst(FieldKey.YEAR)); assertEquals("Country", v1Tag.getFirst(FieldKey.GENRE)); assertEquals("title", v1Tag.getFirst(FieldKey.TITLE)); assertEquals("album", v1Tag.getFirst(FieldKey.ALBUM)); //Not Empty assertFalse(v1Tag.isEmpty()); v1Tag.deleteField(FieldKey.ALBUM); v1Tag.deleteField(FieldKey.YEAR); v1Tag.deleteField(FieldKey.GENRE); v1Tag.deleteField(FieldKey.TITLE); v1Tag.deleteField(FieldKey.COMMENT); v1Tag.setField(new ID3v1TagField(FieldKey.COMMENT.name(), "")); v1Tag.deleteField(FieldKey.TRACK); //Empty assertTrue(v1Tag.isEmpty()); //Null Handling try { v1Tag.setField(new ID3v1TagField(FieldKey.COMMENT.name(), null)); } catch (Exception e) { exceptionCaught = e; } assertTrue(exceptionCaught instanceof IllegalArgumentException); } public void testSaveID3v11TagToFile() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); MP3File mp3File = new MP3File(testFile); //Create v11 Tag ID3v11Tag tag = new ID3v11Tag(); tag.setArtist(ID3v11TagTest.ARTIST); tag.setAlbum(ID3v11TagTest.ALBUM); tag.setComment(ID3v11TagTest.COMMENT); tag.setTitle(ID3v11TagTest.TITLE); tag.setGenre(ID3v11TagTest.GENRE_VAL); tag.setYear(ID3v11TagTest.YEAR); tag.setTrack(ID3v11TagTest.TRACK_VALUE); //Save tag to file mp3File.setID3v1Tag(tag); mp3File.save(); //Reload mp3File = new MP3File(testFile); tag = (ID3v11Tag)mp3File.getID3v1Tag(); assertEquals(ID3v11TagTest.ARTIST, tag.getFirst(FieldKey.ARTIST)); assertEquals(ID3v11TagTest.ALBUM, tag.getFirst(FieldKey.ALBUM)); assertEquals(ID3v11TagTest.COMMENT, tag.getFirstComment()); assertEquals(ID3v11TagTest.TITLE, tag.getFirst(FieldKey.TITLE)); assertEquals(ID3v11TagTest.GENRE_VAL, tag.getFirst(FieldKey.GENRE)); assertEquals(ID3v11TagTest.YEAR, tag.getFirst(FieldKey.YEAR)); assertEquals(ID3v11TagTest.YEAR, tag.getFirst(FieldKey.YEAR)); assertEquals(ID3v11TagTest.TRACK_VALUE, tag.getFirst(FieldKey.TRACK)); tag.setField(FieldKey.TRACK,"3"); mp3File.save(); mp3File = new MP3File(testFile); tag = (ID3v11Tag)mp3File.getID3v1Tag(); assertEquals("3", tag.getFirst(FieldKey.TRACK )); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/id3/FrameTRCKTest.java0000644000175000017500000001023011470746136027066 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.mp3.MP3File; import org.jaudiotagger.tag.FieldKey; import org.jaudiotagger.tag.id3.framebody.FrameBodyTRCK; import org.jaudiotagger.tag.id3.framebody.FrameBodyTRCKTest; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; import java.io.File; /** * Test TRCKFrame */ public class FrameTRCKTest extends AbstractTestCase { public static ID3v24Frame getInitialisedFrame() { ID3v24Frame frame = new ID3v24Frame(ID3v24Frames.FRAME_ID_TRACK); FrameBodyTRCK fb = FrameBodyTRCKTest.getInitialisedBody(); frame.setBody(fb); return frame; } public void testCreateID3v24Frame() { Exception exceptionCaught = null; ID3v24Frame frame = null; FrameBodyTRCK fb = null; try { frame = new ID3v24Frame(ID3v24Frames.FRAME_ID_TRACK); fb = FrameBodyTRCKTest.getInitialisedBody(); frame.setBody(fb); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v24Frames.FRAME_ID_TRACK, frame.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, fb.getTextEncoding()); assertEquals("1/11", ((FrameBodyTRCK) frame.getBody()).getText()); assertFalse(ID3v24Frames.getInstanceOf().isExtensionFrames(frame.getIdentifier())); assertTrue(ID3v24Frames.getInstanceOf().isSupportedFrames(frame.getIdentifier())); } public void testCreateID3v23Frame() { Exception exceptionCaught = null; ID3v23Frame frame = null; FrameBodyTRCK fb = null; try { frame = new ID3v23Frame(ID3v23Frames.FRAME_ID_V3_TRACK); fb = FrameBodyTRCKTest.getInitialisedBody(); frame.setBody(fb); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v23Frames.FRAME_ID_V3_TRACK, frame.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, fb.getTextEncoding()); assertEquals("1/11", ((FrameBodyTRCK) frame.getBody()).getText()); } public void testSaveToFile() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); MP3File mp3File = new MP3File(testFile); //Create and Save ID3v24Tag tag = new ID3v24Tag(); tag.setFrame(FrameTRCKTest.getInitialisedFrame()); mp3File.setID3v2Tag(tag); mp3File.save(); //Reload mp3File = new MP3File(testFile); ID3v24Frame frame = (ID3v24Frame) mp3File.getID3v2Tag().getFrame(ID3v24Frames.FRAME_ID_TRACK); FrameBodyTRCK body = (FrameBodyTRCK) frame.getBody(); assertEquals(TextEncoding.ISO_8859_1, body.getTextEncoding()); assertEquals("1/11", ((FrameBodyTRCK) frame.getBody()).getText()); } public void testSaveEmptyFrameToFile() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); MP3File mp3File = new MP3File(testFile); ID3v24Frame frame = new ID3v24Frame(ID3v24Frames.FRAME_ID_TRACK); frame.setBody(new FrameBodyTRCK()); //Create and Save ID3v24Tag tag = new ID3v24Tag(); tag.setFrame(frame); mp3File.setID3v2Tag(tag); mp3File.save(); //Reload mp3File = new MP3File(testFile); frame = (ID3v24Frame) mp3File.getID3v2Tag().getFrame(ID3v24Frames.FRAME_ID_TRACK); FrameBodyTRCK body = (FrameBodyTRCK) frame.getBody(); assertEquals(TextEncoding.ISO_8859_1, body.getTextEncoding()); assertEquals("", ((FrameBodyTRCK) frame.getBody()).getText()); } public void testMergingMultipleTrackFrames() throws Exception { ID3v24Tag tag = new ID3v24Tag(); tag.setField(tag.createField(FieldKey.TRACK,"1")); tag.setField(tag.createField(FieldKey.TRACK_TOTAL,"10")); assertEquals("1",tag.getFirst(FieldKey.TRACK)); assertEquals("10",tag.getFirst(FieldKey.TRACK_TOTAL)); assertTrue(tag.getFrame("TRCK") instanceof AbstractID3v2Frame); } }libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/id3/FrameTPE1Test.java0000644000175000017500000000272711331564261027041 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.tag.FieldKey; import org.jaudiotagger.tag.Tag; import org.jaudiotagger.tag.id3.framebody.FrameBodyTPE1; import org.jaudiotagger.tag.id3.framebody.FrameBodyTPE3; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; /** */ public class FrameTPE1Test extends AbstractTestCase { public void testGeneric() throws Exception { Exception e=null; try { Tag tag = new ID3v23Tag(); tag.addField(FieldKey.ARTIST,"testartist"); assertEquals("testartist",tag.getFirst(FieldKey.ARTIST)); assertEquals("testartist",tag.getFirst("TPE1")); } catch(Exception ex) { e=ex; ex.printStackTrace(); } assertNull(e); } public void testID3Specific() throws Exception { Exception e=null; try { ID3v23Tag tag = new ID3v23Tag(); ID3v23Frame frame = new ID3v23Frame("TPE1"); frame.setBody(new FrameBodyTPE1(TextEncoding.ISO_8859_1,"testartist")); tag.addFrame(frame); assertEquals("testartist",tag.getFirst(FieldKey.ARTIST)); assertEquals("testartist",tag.getFirst("TPE1")); } catch(Exception ex) { e=ex; ex.printStackTrace(); } assertNull(e); } }libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/id3/FramePCNTTest.java0000644000175000017500000000742111041064726027067 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.mp3.MP3File; import org.jaudiotagger.tag.id3.framebody.FrameBodyPCNT; import org.jaudiotagger.tag.id3.framebody.FrameBodyPCNTTest; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; import java.io.File; /** * Test PCNTFrameBody */ public class FramePCNTTest extends AbstractTestCase { public static ID3v24Frame getInitialisedFrame() { ID3v24Frame frame = new ID3v24Frame(ID3v24Frames.FRAME_ID_PLAY_COUNTER); FrameBodyPCNT fb = FrameBodyPCNTTest.getInitialisedBody(); frame.setBody(fb); return frame; } public void testCreateID3v24Frame() { Exception exceptionCaught = null; ID3v24Frame frame = null; FrameBodyPCNT fb = null; try { frame = new ID3v24Frame(ID3v24Frames.FRAME_ID_PLAY_COUNTER); fb = FrameBodyPCNTTest.getInitialisedBody(); frame.setBody(fb); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v24Frames.FRAME_ID_PLAY_COUNTER, frame.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, fb.getTextEncoding()); assertEquals(FrameBodyPCNTTest.PCNT_COUNTER, ((FrameBodyPCNT) frame.getBody()).getCounter()); assertFalse(ID3v24Frames.getInstanceOf().isExtensionFrames(frame.getIdentifier())); assertTrue(ID3v24Frames.getInstanceOf().isSupportedFrames(frame.getIdentifier())); } public void testCreateID3v23Frame() { Exception exceptionCaught = null; ID3v23Frame frame = null; FrameBodyPCNT fb = null; try { frame = new ID3v23Frame(ID3v23Frames.FRAME_ID_V3_PLAY_COUNTER); fb = FrameBodyPCNTTest.getInitialisedBody(); frame.setBody(fb); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v23Frames.FRAME_ID_V3_PLAY_COUNTER, frame.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, fb.getTextEncoding()); assertEquals(FrameBodyPCNTTest.PCNT_COUNTER, ((FrameBodyPCNT) frame.getBody()).getCounter()); } public void testSaveToFile() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); MP3File mp3File = new MP3File(testFile); //Create and Save ID3v24Tag tag = new ID3v24Tag(); tag.setFrame(FramePCNTTest.getInitialisedFrame()); mp3File.setID3v2Tag(tag); mp3File.save(); //Reload mp3File = new MP3File(testFile); ID3v24Frame frame = (ID3v24Frame) mp3File.getID3v2Tag().getFrame(ID3v24Frames.FRAME_ID_PLAY_COUNTER); FrameBodyPCNT body = (FrameBodyPCNT) frame.getBody(); assertEquals(TextEncoding.ISO_8859_1, body.getTextEncoding()); assertEquals(FrameBodyPCNTTest.PCNT_COUNTER, body.getCounter()); } public void testSaveEmptyFrameToFile() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); MP3File mp3File = new MP3File(testFile); ID3v24Frame frame = new ID3v24Frame(ID3v24Frames.FRAME_ID_PLAY_COUNTER); frame.setBody(new FrameBodyPCNT()); //Create and Save ID3v24Tag tag = new ID3v24Tag(); tag.setFrame(frame); mp3File.setID3v2Tag(tag); mp3File.save(); //Reload mp3File = new MP3File(testFile); frame = (ID3v24Frame) mp3File.getID3v2Tag().getFrame(ID3v24Frames.FRAME_ID_PLAY_COUNTER); FrameBodyPCNT body = (FrameBodyPCNT) frame.getBody(); assertEquals(TextEncoding.ISO_8859_1, body.getTextEncoding()); assertEquals(0, body.getCounter()); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/id3/FrameTIPLTest.java0000644000175000017500000001415611470746136027106 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.mp3.MP3File; import org.jaudiotagger.tag.id3.framebody.*; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; import java.io.File; import java.util.Iterator; /** * Test TIPL Frame */ public class FrameTIPLTest extends AbstractTestCase { public static ID3v24Frame getInitialisedFrame() { ID3v24Frame frame = new ID3v24Frame(ID3v24Frames.FRAME_ID_INVOLVED_PEOPLE); FrameBodyTIPL fb = FrameBodyTIPLTest.getInitialisedBody(); frame.setBody(fb); return frame; } public static ID3v24Frame getInitialisedFrameOdd() { ID3v24Frame frame = new ID3v24Frame(ID3v24Frames.FRAME_ID_INVOLVED_PEOPLE); FrameBodyTIPL fb = FrameBodyTIPLTest.getInitialisedBodyOdd(); frame.setBody(fb); return frame; } public static ID3v23Frame getV23InitialisedFrame() { ID3v23Frame frame = new ID3v23Frame(ID3v23Frames.FRAME_ID_V3_IPLS); FrameBodyTIPL fb = FrameBodyTIPLTest.getInitialisedBody(); frame.setBody(fb); return frame; } public void testCreateID3v24Frame() { Exception exceptionCaught = null; ID3v24Frame frame = null; FrameBodyTIPL fb = null; try { frame = new ID3v24Frame(ID3v24Frames.FRAME_ID_INVOLVED_PEOPLE); fb = FrameBodyTIPLTest.getInitialisedBody(); frame.setBody(fb); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v24Frames.FRAME_ID_INVOLVED_PEOPLE, frame.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, fb.getTextEncoding()); assertFalse(ID3v24Frames.getInstanceOf().isExtensionFrames(frame.getIdentifier())); assertTrue(ID3v24Frames.getInstanceOf().isSupportedFrames(frame.getIdentifier())); assertEquals(FrameBodyTIPLTest.INVOLVED_PEOPLE, fb.getText()); } public void testCreateID3v23Frame() { Exception exceptionCaught = null; ID3v23Frame frame = null; FrameBodyTIPL fb = null; try { frame = new ID3v23Frame(ID3v23Frames.FRAME_ID_V3_IPLS); fb = FrameBodyTIPLTest.getInitialisedBody(); frame.setBody(fb); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v23Frames.FRAME_ID_V3_IPLS, frame.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, fb.getTextEncoding()); assertFalse(ID3v23Frames.getInstanceOf().isExtensionFrames(frame.getIdentifier())); assertTrue(ID3v23Frames.getInstanceOf().isSupportedFrames(frame.getIdentifier())); assertEquals(FrameBodyTIPLTest.INVOLVED_PEOPLE, fb.getText()); } public void testSaveToFile() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3",new File("test1016.mp3")); MP3File mp3File = new MP3File(testFile); //Create and Save ID3v24Tag tag = new ID3v24Tag(); tag.setFrame(FrameTIPLTest.getInitialisedFrame()); mp3File.setID3v2Tag(tag); mp3File.save(); //Reload mp3File = new MP3File(testFile); ID3v24Frame frame = (ID3v24Frame) mp3File.getID3v2Tag().getFrame(ID3v24Frames.FRAME_ID_INVOLVED_PEOPLE); FrameBodyTIPL body = (FrameBodyTIPL) frame.getBody(); assertEquals(TextEncoding.ISO_8859_1, body.getTextEncoding()); } public void testSaveToFileOdd() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3",new File("test1016.mp3")); MP3File mp3File = new MP3File(testFile); //Create and Save ID3v24Tag tag = new ID3v24Tag(); tag.setFrame(FrameTIPLTest.getInitialisedFrameOdd()); mp3File.setID3v2Tag(tag); mp3File.save(); //Reload mp3File = new MP3File(testFile); ID3v24Frame frame = (ID3v24Frame) mp3File.getID3v2Tag().getFrame(ID3v24Frames.FRAME_ID_INVOLVED_PEOPLE); FrameBodyTIPL body = (FrameBodyTIPL) frame.getBody(); assertEquals(TextEncoding.ISO_8859_1, body.getTextEncoding()); } public void testSaveEmptyFrameToFile() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3",new File("test1004.mp3")); MP3File mp3File = new MP3File(testFile); ID3v24Frame frame = new ID3v24Frame(ID3v24Frames.FRAME_ID_INVOLVED_PEOPLE); frame.setBody(new FrameBodyTIPL()); //Create and Save ID3v24Tag tag = new ID3v24Tag(); tag.setFrame(frame); mp3File.setID3v2Tag(tag); mp3File.save(); //Reload mp3File = new MP3File(testFile); frame = (ID3v24Frame) mp3File.getID3v2Tag().getFrame(ID3v24Frames.FRAME_ID_INVOLVED_PEOPLE); FrameBodyTIPL body = (FrameBodyTIPL) frame.getBody(); assertEquals(TextEncoding.ISO_8859_1, body.getTextEncoding()); } public void testConvertV24ToV23() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3",new File("test1005.mp3")); MP3File mp3File = new MP3File(testFile); //Create and Save ID3v24Tag tag = new ID3v24Tag(); tag.setFrame(FrameTIPLTest.getInitialisedFrame()); mp3File.setID3v2Tag(tag); mp3File.save(); //Reload and convert to v23 and save mp3File = new MP3File(testFile); ID3v23Tag v23Tag = new ID3v23Tag(mp3File.getID3v2TagAsv24()); mp3File.setID3v2TagOnly(v23Tag); assertTrue(v23Tag.hasFrame("IPLS")); mp3File.save(); //Reload mp3File = new MP3File(testFile); ID3v23Frame frame = (ID3v23Frame) mp3File.getID3v2Tag().getFrame(ID3v23Frames.FRAME_ID_V3_IPLS); FrameBodyIPLS body = (FrameBodyIPLS) frame.getBody(); assertEquals(TextEncoding.ISO_8859_1, body.getTextEncoding()); assertEquals(FrameBodyTIPLTest.INVOLVED_PEOPLE, body.getText()); assertEquals("producer", body.getKeyAtIndex(0)); assertEquals("eno,lanois", body.getValueAtIndex(0)); } }libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/id3/Unicode23TagTest.java0000644000175000017500000005621611470746136027555 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.mp3.MP3File; import org.jaudiotagger.tag.TagOptionSingleton; import org.jaudiotagger.tag.datatype.DataTypes; import org.jaudiotagger.tag.id3.framebody.FrameBodyTPE1; import org.jaudiotagger.tag.id3.framebody.FrameBodyTPE1Test; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; import java.io.File; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; /** * */ public class Unicode23TagTest extends TestCase { /** * Constructor * * @param arg0 */ public Unicode23TagTest(String arg0) { super(arg0); } /** * Command line entrance. * * @param args */ public static void main(String[] args) { junit.textui.TestRunner.run(Unicode23TagTest.suite()); } ///////////////////////////////////////////////////////////////////////// // TestCase classes to override ///////////////////////////////////////////////////////////////////////// /** * */ protected void setUp() { TagOptionSingleton.getInstance().setToDefault(); } /** * */ protected void tearDown() { } /** * */ // protected void runTest() // { // } /** * Builds the Test Suite. * * @return the Test Suite. */ public static Test suite() { return new TestSuite(Unicode23TagTest.class); } /** * Create a String that only contains text within IS8859 charset so should be * as ISO_88859 * * @throws Exception */ public void testCreateISO8859EncodedSizeTerminatedString() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); MP3File mp3File = new MP3File(testFile); ID3v23Frame frame = new ID3v23Frame(ID3v23Frames.FRAME_ID_V3_ARTIST); Exception exceptionCaught = null; FrameBodyTPE1 fb = null; try { fb = FrameBodyTPE1Test.getInitialisedBody(); frame.setBody(fb); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v23Frames.FRAME_ID_V3_ARTIST, fb.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, fb.getTextEncoding()); assertEquals(FrameBodyTPE1Test.TPE1_TEST_STRING, fb.getText()); //Create and Save ID3v23Tag tag = new ID3v23Tag(); tag.setFrame(frame); mp3File.setID3v2Tag(tag); mp3File.save(); //Reload, should be written as UTF16 because of the text mp3File = new MP3File(testFile); frame = (ID3v23Frame) mp3File.getID3v2Tag().getFrame(ID3v23Frames.FRAME_ID_V3_ARTIST); FrameBodyTPE1 body = (FrameBodyTPE1) frame.getBody(); assertEquals(ID3v23Frames.FRAME_ID_V3_ARTIST, body.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, body.getTextEncoding()); assertEquals(FrameBodyTPE1Test.TPE1_TEST_STRING, body.getText()); } /** * Can explictly uses UTF-16 even if not required * as UTf16 by default * * @throws Exception */ public void testCreateUTF16EncodedSizeTerminatedString() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); MP3File mp3File = new MP3File(testFile); ID3v23Frame frame = new ID3v23Frame(ID3v23Frames.FRAME_ID_V3_ARTIST); Exception exceptionCaught = null; FrameBodyTPE1 fb = null; try { fb = FrameBodyTPE1Test.getInitialisedBody(); fb.setTextEncoding(TextEncoding.UTF_16); frame.setBody(fb); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v23Frames.FRAME_ID_V3_ARTIST, fb.getIdentifier()); assertEquals(TextEncoding.UTF_16, fb.getTextEncoding()); assertEquals(FrameBodyTPE1Test.TPE1_TEST_STRING, fb.getText()); //Create and Save ID3v23Tag tag = new ID3v23Tag(); tag.setFrame(frame); mp3File.setID3v2Tag(tag); mp3File.save(); //Reload, should be written as UTF16 because of the text mp3File = new MP3File(testFile); frame = (ID3v23Frame) mp3File.getID3v2Tag().getFrame(ID3v23Frames.FRAME_ID_V3_ARTIST); FrameBodyTPE1 body = (FrameBodyTPE1) frame.getBody(); assertEquals(ID3v23Frames.FRAME_ID_V3_ARTIST, body.getIdentifier()); assertEquals(TextEncoding.UTF_16, body.getTextEncoding()); assertEquals(FrameBodyTPE1Test.TPE1_TEST_STRING, body.getText()); } /** * Create a String that contains text outside of the IS8859 charset should be written * as UTf16 by default * * @throws Exception */ public void testCreateUTF16AutoEncodedSizeTerminatedString() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); MP3File mp3File = new MP3File(testFile); ID3v23Frame frame = new ID3v23Frame(ID3v23Frames.FRAME_ID_V3_ARTIST); Exception exceptionCaught = null; FrameBodyTPE1 fb = null; try { fb = FrameBodyTPE1Test.getUnicodeRequiredInitialisedBody(); frame.setBody(fb); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v23Frames.FRAME_ID_V3_ARTIST, fb.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, fb.getTextEncoding()); assertEquals(FrameBodyTPE1Test.TPE1_UNICODE_REQUIRED_TEST_STRING, fb.getText()); //Create and Save ID3v23Tag tag = new ID3v23Tag(); tag.setFrame(frame); mp3File.setID3v2Tag(tag); mp3File.save(); //Reload, should be written as UTF16 because of the text mp3File = new MP3File(testFile); frame = (ID3v23Frame) mp3File.getID3v2Tag().getFrame(ID3v23Frames.FRAME_ID_V3_ARTIST); FrameBodyTPE1 body = (FrameBodyTPE1) frame.getBody(); assertEquals(ID3v23Frames.FRAME_ID_V3_ARTIST, body.getIdentifier()); assertEquals(TextEncoding.UTF_16, body.getTextEncoding()); assertEquals(FrameBodyTPE1Test.TPE1_UNICODE_REQUIRED_TEST_STRING, body.getText()); } /** * Strings cannot be written to UTF16BE even if text encoding explicitly set * * @throws Exception */ public void testCreateUTF16BEEncodedSizeTerminatedString() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); MP3File mp3File = new MP3File(testFile); ID3v23Frame frame = new ID3v23Frame(ID3v23Frames.FRAME_ID_V3_ARTIST); Exception exceptionCaught = null; FrameBodyTPE1 fb = null; try { fb = FrameBodyTPE1Test.getUnicodeRequiredInitialisedBody(); fb.setTextEncoding(TextEncoding.UTF_16BE); frame.setBody(fb); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v23Frames.FRAME_ID_V3_ARTIST, fb.getIdentifier()); assertEquals(TextEncoding.UTF_16BE, fb.getTextEncoding()); assertEquals(FrameBodyTPE1Test.TPE1_UNICODE_REQUIRED_TEST_STRING, fb.getText()); //Create and Save ID3v23Tag tag = new ID3v23Tag(); tag.setFrame(frame); mp3File.setID3v2Tag(tag); mp3File.save(); //Reload, should be written as UTF16BE mp3File = new MP3File(testFile); frame = (ID3v23Frame) mp3File.getID3v2Tag().getFrame(ID3v23Frames.FRAME_ID_V3_ARTIST); FrameBodyTPE1 body = (FrameBodyTPE1) frame.getBody(); assertEquals(ID3v23Frames.FRAME_ID_V3_ARTIST, body.getIdentifier()); assertEquals(TextEncoding.UTF_16, body.getTextEncoding()); assertEquals(FrameBodyTPE1Test.TPE1_UNICODE_REQUIRED_TEST_STRING, body.getText()); } /** * Strings cannot be written to UTF8 even if text encoding explicitly set, because invalid for v23 * * @throws Exception */ public void testCreateUTF8EncodedSizeTerminatedString() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); MP3File mp3File = new MP3File(testFile); ID3v23Frame frame = new ID3v23Frame(ID3v23Frames.FRAME_ID_V3_ARTIST); Exception exceptionCaught = null; FrameBodyTPE1 fb = null; try { fb = FrameBodyTPE1Test.getUnicodeRequiredInitialisedBody(); fb.setTextEncoding(TextEncoding.UTF_8); frame.setBody(fb); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v23Frames.FRAME_ID_V3_ARTIST, fb.getIdentifier()); assertEquals(TextEncoding.UTF_8, fb.getTextEncoding()); assertEquals(FrameBodyTPE1Test.TPE1_UNICODE_REQUIRED_TEST_STRING, fb.getText()); //Create and Save ID3v23Tag tag = new ID3v23Tag(); tag.setFrame(frame); mp3File.setID3v2Tag(tag); mp3File.save(); //Reload, should be written as UTF8 mp3File = new MP3File(testFile); frame = (ID3v23Frame) mp3File.getID3v2Tag().getFrame(ID3v23Frames.FRAME_ID_V3_ARTIST); FrameBodyTPE1 body = (FrameBodyTPE1) frame.getBody(); assertEquals(ID3v23Frames.FRAME_ID_V3_ARTIST, body.getIdentifier()); assertEquals(TextEncoding.UTF_16, body.getTextEncoding()); assertEquals(FrameBodyTPE1Test.TPE1_UNICODE_REQUIRED_TEST_STRING, body.getText()); } public void testFixv23TagsWithInvalidEncoding() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("Issue109.id3", "testV1.mp3"); //Read file as currently stands MP3File mp3File = new MP3File(testFile); ID3v23Tag v23tag = (ID3v23Tag) mp3File.getID3v2Tag(); //Currently contains tags with invalid textencodings ID3v23Frame artistFrame = (ID3v23Frame) v23tag.getFrame(ID3v23Frames.FRAME_ID_V3_ARTIST); FrameBodyTPE1 body = (FrameBodyTPE1) artistFrame.getBody(); assertEquals(ID3v23Frames.FRAME_ID_V3_ARTIST, body.getIdentifier()); assertEquals(TextEncoding.UTF_8, body.getTextEncoding()); //Save mp3File.save(); //Read file after save mp3File = new MP3File(testFile); v23tag = (ID3v23Tag) mp3File.getID3v2Tag(); //Currently contains tags with invalid textencodings artistFrame = (ID3v23Frame) v23tag.getFrame(ID3v23Frames.FRAME_ID_V3_ARTIST); body = (FrameBodyTPE1) artistFrame.getBody(); assertEquals(ID3v23Frames.FRAME_ID_V3_ARTIST, body.getIdentifier()); //Text Encoding has been corrected assertEquals(TextEncoding.ISO_8859_1, body.getTextEncoding()); } public void testFixv23TagsWithInvalidEncodingAndDefaultOverridden() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("Issue109.id3", "testV1.mp3"); //Read file as currently stands MP3File mp3File = new MP3File(testFile); ID3v23Tag v23tag = (ID3v23Tag) mp3File.getID3v2Tag(); //Currently contains tags with invalid textencodings ID3v23Frame artistFrame = (ID3v23Frame) v23tag.getFrame(ID3v23Frames.FRAME_ID_V3_ARTIST); FrameBodyTPE1 body = (FrameBodyTPE1) artistFrame.getBody(); assertEquals(ID3v23Frames.FRAME_ID_V3_ARTIST, body.getIdentifier()); assertEquals(TextEncoding.UTF_8, body.getTextEncoding()); //Modify tag options //So will default to default on save (default is ISO8859) TagOptionSingleton.getInstance().setResetTextEncodingForExistingFrames(true); //Save mp3File.save(); //Read file after save mp3File = new MP3File(testFile); v23tag = (ID3v23Tag) mp3File.getID3v2Tag(); //Currently contains tags with invalid textencodings artistFrame = (ID3v23Frame) v23tag.getFrame(ID3v23Frames.FRAME_ID_V3_ARTIST); body = (FrameBodyTPE1) artistFrame.getBody(); assertEquals(ID3v23Frames.FRAME_ID_V3_ARTIST, body.getIdentifier()); //Text Encoding has been corrected ( note the text could use ISO_8859 but because the user has selected //a Unicode text encoding the default behaviour is to just conver to a valid text encoding for this id3 version assertEquals(TextEncoding.ISO_8859_1, body.getTextEncoding()); } /** * @throws Exception */ public void testCreateUTF16EvenIfNotNeededIfDefaultSetEncodedSizeTerminatedString() throws Exception { //Modify tag options //So will default to default on save (default is ISO8859) has to be done before the frame is created TagOptionSingleton.getInstance().setId3v23DefaultTextEncoding(TextEncoding.UTF_16); File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); MP3File mp3File = new MP3File(testFile); ID3v23Frame frame = new ID3v23Frame(ID3v23Frames.FRAME_ID_V3_ARTIST); Exception exceptionCaught = null; try { frame.getBody().setObjectValue(DataTypes.OBJ_TEXT, FrameBodyTPE1Test.TPE1_TEST_STRING); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); //Create and Save ID3v23Tag tag = new ID3v23Tag(); tag.setFrame(frame); mp3File.setID3v2Tag(tag); mp3File.save(); //Reload, should be written as UTF16 because setField in tag options mp3File = new MP3File(testFile); frame = (ID3v23Frame) mp3File.getID3v2Tag().getFrame(ID3v23Frames.FRAME_ID_V3_ARTIST); FrameBodyTPE1 body = (FrameBodyTPE1) frame.getBody(); assertEquals(ID3v23Frames.FRAME_ID_V3_ARTIST, body.getIdentifier()); assertEquals(TextEncoding.UTF_16, body.getTextEncoding()); assertEquals(FrameBodyTPE1Test.TPE1_TEST_STRING, body.getText()); //Check Bytes FileChannel fc = new RandomAccessFile(testFile, "r").getChannel(); ByteBuffer buffer = ByteBuffer.allocate(100); int count = fc.read(buffer); fc.close(); //Frame Header assertTrue((buffer.get(10) & 0xff) == 'T'); assertTrue((buffer.get(11) & 0xff) == 'P'); assertTrue((buffer.get(12) & 0xff) == 'E'); assertTrue((buffer.get(13) & 0xff) == '1'); //Charset assertTrue((buffer.get(20) & 0xff) == 0x01); //BOM assertTrue((buffer.get(21) & 0xff) == 0xFF); assertTrue((buffer.get(22) & 0xff) == 0xFE); //Data, least significant byte (which contaisn the data is first in each pair) assertTrue((buffer.get(23) & 0xff) == 'b'); assertTrue((buffer.get(24) & 0xff) == 0x00); assertTrue((buffer.get(25) & 0xff) == 'e'); assertTrue((buffer.get(26) & 0xff) == 0x00); assertTrue((buffer.get(27) & 0xff) == 'c'); assertTrue((buffer.get(28) & 0xff) == 0x00); assertTrue((buffer.get(29) & 0xff) == 'k'); assertTrue((buffer.get(28) & 0xff) == 0x00); } /** * @throws Exception */ public void testCreateUTF16AndResetEvenIfNotNeededIfDefaultSetEncodedSizeTerminatedString() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); MP3File mp3File = new MP3File(testFile); ID3v23Frame frame = new ID3v23Frame(ID3v23Frames.FRAME_ID_V3_ARTIST); Exception exceptionCaught = null; try { frame.getBody().setObjectValue(DataTypes.OBJ_TEXT, FrameBodyTPE1Test.TPE1_TEST_STRING); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); //Modify tag options so rewrites all frames even if already created //So will default to default on save (default is ISO8859) has to be done before the frame is created TagOptionSingleton.getInstance().setId3v23DefaultTextEncoding(TextEncoding.UTF_16); TagOptionSingleton.getInstance().setResetTextEncodingForExistingFrames(true); //Create and Save ID3v23Tag tag = new ID3v23Tag(); tag.setFrame(frame); mp3File.setID3v2Tag(tag); mp3File.save(); //Reload, should be written as UTF16 because setField in tag options mp3File = new MP3File(testFile); frame = (ID3v23Frame) mp3File.getID3v2Tag().getFrame(ID3v23Frames.FRAME_ID_V3_ARTIST); FrameBodyTPE1 body = (FrameBodyTPE1) frame.getBody(); assertEquals(ID3v23Frames.FRAME_ID_V3_ARTIST, body.getIdentifier()); assertEquals(TextEncoding.UTF_16, body.getTextEncoding()); assertEquals(FrameBodyTPE1Test.TPE1_TEST_STRING, body.getText()); //Check Bytes FileChannel fc = new RandomAccessFile(testFile, "r").getChannel(); ByteBuffer buffer = ByteBuffer.allocate(100); int count = fc.read(buffer); fc.close(); //Frame Header assertTrue((buffer.get(10) & 0xff) == 'T'); assertTrue((buffer.get(11) & 0xff) == 'P'); assertTrue((buffer.get(12) & 0xff) == 'E'); assertTrue((buffer.get(13) & 0xff) == '1'); //Charset assertTrue((buffer.get(20) & 0xff) == 0x01); //BOM assertTrue((buffer.get(21) & 0xff) == 0xFF); assertTrue((buffer.get(22) & 0xff) == 0xFE); //Data, least significant byte (which contaisn the data is first in each pair) assertTrue((buffer.get(23) & 0xff) == 'b'); assertTrue((buffer.get(24) & 0xff) == 0x00); assertTrue((buffer.get(25) & 0xff) == 'e'); assertTrue((buffer.get(26) & 0xff) == 0x00); assertTrue((buffer.get(27) & 0xff) == 'c'); assertTrue((buffer.get(28) & 0xff) == 0x00); assertTrue((buffer.get(29) & 0xff) == 'k'); assertTrue((buffer.get(28) & 0xff) == 0x00); } /** * @throws Exception */ public void testCreateUTF16AndResetEvenIfNotNeededIfDefaultSetEncodedSizeTerminatedStringUnsnced() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); MP3File mp3File = new MP3File(testFile); ID3v23Frame frame = new ID3v23Frame(ID3v23Frames.FRAME_ID_V3_ARTIST); Exception exceptionCaught = null; try { frame.getBody().setObjectValue(DataTypes.OBJ_TEXT, FrameBodyTPE1Test.TPE1_TEST_STRING); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); //Modify tag options so rewrites all frames even if already created //So will default to default on save (default is ISO8859) has to be done before the frame is created TagOptionSingleton.getInstance().setId3v23DefaultTextEncoding(TextEncoding.UTF_16); TagOptionSingleton.getInstance().setResetTextEncodingForExistingFrames(true); TagOptionSingleton.getInstance().setUnsyncTags(true); //Create and Save ID3v23Tag tag = new ID3v23Tag(); tag.setFrame(frame); mp3File.setID3v2Tag(tag); mp3File.save(); //Reload, should be written as UTF16 because setField in tag options mp3File = new MP3File(testFile); frame = (ID3v23Frame) mp3File.getID3v2Tag().getFrame(ID3v23Frames.FRAME_ID_V3_ARTIST); FrameBodyTPE1 body = (FrameBodyTPE1) frame.getBody(); assertEquals(ID3v23Frames.FRAME_ID_V3_ARTIST, body.getIdentifier()); assertEquals(TextEncoding.UTF_16, body.getTextEncoding()); assertEquals(FrameBodyTPE1Test.TPE1_TEST_STRING, body.getText()); //Check Bytes FileChannel fc = new RandomAccessFile(testFile, "r").getChannel(); ByteBuffer buffer = ByteBuffer.allocate(100); int count = fc.read(buffer); fc.close(); //Frame Header assertTrue((buffer.get(10) & 0xff) == 'T'); assertTrue((buffer.get(11) & 0xff) == 'P'); assertTrue((buffer.get(12) & 0xff) == 'E'); assertTrue((buffer.get(13) & 0xff) == '1'); //Charset assertTrue((buffer.get(20) & 0xff) == 0x01); //BOM assertTrue((buffer.get(21) & 0xff) == 0xFF); assertTrue((buffer.get(22) & 0xff) == 0x00); //Unsync applied assertTrue((buffer.get(23) & 0xff) == 0xFE); //Data, least significant byte (which contaisn the data is first in each pair) assertTrue((buffer.get(24) & 0xff) == 'b'); assertTrue((buffer.get(25) & 0xff) == 0x00); assertTrue((buffer.get(26) & 0xff) == 'e'); assertTrue((buffer.get(27) & 0xff) == 0x00); assertTrue((buffer.get(28) & 0xff) == 'c'); assertTrue((buffer.get(29) & 0xff) == 0x00); assertTrue((buffer.get(30) & 0xff) == 'k'); assertTrue((buffer.get(31) & 0xff) == 0x00); } /** * @throws Exception */ public void testDoesntCreateUTF16IfDefaultSetEncodedSizeTerminatedStringifOverriddenUsingSetBody() throws Exception { //Modify tag options //So will default to default on save (default is ISO8859) TagOptionSingleton.getInstance().setId3v23DefaultTextEncoding(TextEncoding.UTF_16); File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); MP3File mp3File = new MP3File(testFile); ID3v23Frame frame = new ID3v23Frame(ID3v23Frames.FRAME_ID_V3_ARTIST); Exception exceptionCaught = null; FrameBodyTPE1 fb = null; try { fb = FrameBodyTPE1Test.getInitialisedBody(); frame.setBody(fb); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v23Frames.FRAME_ID_V3_ARTIST, fb.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, fb.getTextEncoding()); assertEquals(FrameBodyTPE1Test.TPE1_TEST_STRING, fb.getText()); //Create and Save ID3v23Tag tag = new ID3v23Tag(); tag.setFrame(frame); mp3File.setID3v2Tag(tag); mp3File.save(); //Reload, still ISO8859-1 mp3File = new MP3File(testFile); frame = (ID3v23Frame) mp3File.getID3v2Tag().getFrame(ID3v23Frames.FRAME_ID_V3_ARTIST); FrameBodyTPE1 body = (FrameBodyTPE1) frame.getBody(); assertEquals(ID3v23Frames.FRAME_ID_V3_ARTIST, body.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, body.getTextEncoding()); assertEquals(FrameBodyTPE1Test.TPE1_TEST_STRING, body.getText()); //Check Bytes FileChannel fc = new RandomAccessFile(testFile, "r").getChannel(); ByteBuffer buffer = ByteBuffer.allocate(100); int count = fc.read(buffer); fc.close(); //Frame Header assertTrue((buffer.get(10) & 0xff) == 'T'); assertTrue((buffer.get(11) & 0xff) == 'P'); assertTrue((buffer.get(12) & 0xff) == 'E'); assertTrue((buffer.get(13) & 0xff) == '1'); //Charset ISO8859 assertTrue((buffer.get(20) & 0xff) == 0x00); //Data assertTrue((buffer.get(21) & 0xff) == 'b'); assertTrue((buffer.get(22) & 0xff) == 'e'); assertTrue((buffer.get(23) & 0xff) == 'c'); assertTrue((buffer.get(24) & 0xff) == 'k'); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/id3/FrameTDORTest.java0000644000175000017500000000143611331564261027074 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.tag.id3.framebody.FrameBodyTDTG; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; /** */ public class FrameTDORTest extends AbstractTestCase { public void testID3Specific() throws Exception { Exception e=null; try { ID3v24Tag tag = new ID3v24Tag(); ID3v24Frame frame = new ID3v24Frame("TDOR"); frame.setBody(new FrameBodyTDTG(TextEncoding.ISO_8859_1,"11:10")); tag.addFrame(frame); assertEquals("11:10",tag.getFirst("TDOR")); } catch(Exception ex) { e=ex; ex.printStackTrace(); } assertNull(e); } }libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/id3/NewInterfaceTest.java0000644000175000017500000016741611470746136027745 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.audio.mp3.MP3File; import org.jaudiotagger.tag.FieldKey; import org.jaudiotagger.tag.TagField; import org.jaudiotagger.tag.TagOptionSingleton; import org.jaudiotagger.tag.TagTextField; import org.jaudiotagger.tag.datatype.DataTypes; import org.jaudiotagger.tag.id3.framebody.*; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; import javax.imageio.ImageIO; import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.io.File; import java.io.RandomAccessFile; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.NoSuchElementException; /** * Testing retrofitting of entagged interfaces */ public class NewInterfaceTest extends TestCase { private static final String V1_ARTIST = "V1ARTIST"; public static final String ALBUM_TEST_STRING = "mellow gold"; public static final String ALBUM_TEST_STRING2 = "odelay"; /** * */ protected void setUp() { TagOptionSingleton.getInstance().setToDefault(); } /** * */ protected void tearDown() { } /** * Constructor * * @param arg0 */ public NewInterfaceTest(String arg0) { super(arg0); } /** * Command line entrance. * * @param args */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Builds the Test Suite. * * @return the Test Suite. */ public static Test suite() { return new TestSuite(NewInterfaceTest.class); } public void testBasicWrite() { Exception ex = null; try { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3", new File("testBasicWrite.mp3")); org.jaudiotagger.audio.AudioFile audioFile = org.jaudiotagger.audio.AudioFileIO.read(testFile); org.jaudiotagger.tag.Tag newTag = audioFile.getTag(); if (audioFile.getTag() == null) { audioFile.setTag(new ID3v23Tag()); newTag = audioFile.getTag(); } newTag.setField(FieldKey.ALBUM,"album"); newTag.setField(FieldKey.ARTIST,"artist"); newTag.setField(FieldKey.COMMENT,"comment"); newTag.setField(FieldKey.GENRE,"Rock"); newTag.setField(FieldKey.TITLE,"title"); newTag.setField(FieldKey.YEAR,"year"); newTag.setField(FieldKey.TRACK,Integer.toString(1)); assertEquals("album", newTag.getFirst(FieldKey.ALBUM)); assertEquals("artist", newTag.getFirst(FieldKey.ARTIST)); assertEquals("comment", newTag.getFirst(FieldKey.COMMENT)); assertEquals("Rock", newTag.getFirst(FieldKey.GENRE)); assertEquals("title", newTag.getFirst(FieldKey.TITLE)); assertEquals("year", newTag.getFirst(FieldKey.YEAR)); assertEquals("1", newTag.getFirst(FieldKey.TRACK)); audioFile.commit(); audioFile = org.jaudiotagger.audio.AudioFileIO.read(testFile); newTag = audioFile.getTag(); assertEquals("album", newTag.getFirst(FieldKey.ALBUM)); assertEquals("artist", newTag.getFirst(FieldKey.ARTIST)); assertEquals("comment", newTag.getFirst(FieldKey.COMMENT)); assertEquals("Rock", newTag.getFirst(FieldKey.GENRE)); assertEquals("title", newTag.getFirst(FieldKey.TITLE)); assertEquals("year", newTag.getFirst(FieldKey.YEAR)); assertEquals("1", newTag.getFirst(FieldKey.TRACK)); AbstractTagFrameBody body = (((ID3v23Frame) newTag.getFirstField(ID3v23FieldKey.ALBUM.getFrameId())).getBody()); assertEquals(TextEncoding.ISO_8859_1, body.getTextEncoding()); TagOptionSingleton.getInstance().setId3v23DefaultTextEncoding(TextEncoding.UTF_16); TagOptionSingleton.getInstance().setResetTextEncodingForExistingFrames(true); audioFile.commit(); audioFile = org.jaudiotagger.audio.AudioFileIO.read(testFile); newTag = audioFile.getTag(); assertEquals("album", newTag.getFirst(FieldKey.ALBUM)); assertEquals("artist", newTag.getFirst(FieldKey.ARTIST)); assertEquals("comment", newTag.getFirst(FieldKey.COMMENT)); assertEquals("Rock", newTag.getFirst(FieldKey.GENRE)); assertEquals("title", newTag.getFirst(FieldKey.TITLE)); assertEquals("year", newTag.getFirst(FieldKey.YEAR)); assertEquals("1", newTag.getFirst(FieldKey.TRACK)); body = (((ID3v23Frame) newTag.getFirstField(ID3v23FieldKey.ALBUM.getFrameId())).getBody()); assertEquals(TextEncoding.UTF_16, body.getTextEncoding()); TagOptionSingleton.getInstance().setId3v23DefaultTextEncoding(TextEncoding.ISO_8859_1); TagOptionSingleton.getInstance().setResetTextEncodingForExistingFrames(true); audioFile.commit(); audioFile = org.jaudiotagger.audio.AudioFileIO.read(testFile); newTag = audioFile.getTag(); body = (((ID3v23Frame) newTag.getFirstField(ID3v23FieldKey.ALBUM.getFrameId())).getBody()); assertEquals(TextEncoding.ISO_8859_1, body.getTextEncoding()); TagOptionSingleton.getInstance().setResetTextEncodingForExistingFrames(false); } catch (Exception e) { ex = e; ex.printStackTrace(); } assertNull(ex); } public void testNewInterfaceBasicReadandWriteID3v1() throws Exception { Exception e = null; File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3", new File("testnewIntId3v1.mp3")); MP3File mp3File = new MP3File(testFile); //Has no tag at this point assertFalse(mp3File.hasID3v1Tag()); assertFalse(mp3File.hasID3v2Tag()); //Create v1 tag (old method) ID3v11Tag v1tag = new ID3v11Tag(); v1tag.setField(FieldKey.ARTIST,V1_ARTIST); v1tag.setField(FieldKey.ALBUM,"V1ALBUM" + "\u01ff"); //Note always convert to single byte so will be written as FF v1tag.setField(v1tag.createField(FieldKey.TITLE, "title")); v1tag.setField(FieldKey.GENRE,"Rock"); v1tag.setField(v1tag.createField(FieldKey.TRACK, "12")); mp3File.setID3v1Tag(v1tag); mp3File.save(); //Has only v1 tag assertTrue(mp3File.hasID3v1Tag()); assertFalse(mp3File.hasID3v2Tag()); //Read fields AudioFile af = AudioFileIO.read(testFile); assertEquals(V1_ARTIST, af.getTag().getFirst(FieldKey.ARTIST)); assertEquals(V1_ARTIST, af.getTag().getFirst(FieldKey.ARTIST)); assertEquals(V1_ARTIST, af.getTag().getFirst(FieldKey.ARTIST)); assertEquals("V1ALBUM" + "\u00ff", af.getTag().getFirst(FieldKey.ALBUM)); //Lost the 00, is that what we want assertEquals("title", af.getTag().getFirst(FieldKey.TITLE)); assertEquals("title", af.getTag().getFirst(FieldKey.TITLE)); assertEquals("Rock", af.getTag().getFirst(FieldKey.GENRE)); assertEquals("12", af.getTag().getFirst(FieldKey.TRACK)); assertEquals("12", af.getTag().getFirst(FieldKey.TRACK)); //Delete some fields (just sets string to empty String) af.getTag().deleteField(FieldKey.TITLE); assertEquals("", af.getTag().getFirst(FieldKey.TITLE)); //Modify a value af.getTag().setField(FieldKey.TITLE,"newtitle"); assertEquals("newtitle", af.getTag().getFirst(FieldKey.TITLE)); //Adding just replaces current value af.getTag().addField(FieldKey.TITLE,"newtitle2"); assertEquals("newtitle2", af.getTag().getFirst(FieldKey.TITLE)); } public void testNewInterfaceBasicReadandWriteID3v24() throws Exception { Exception e = null; File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3", new File("testnewIntId3v24.mp3")); MP3File mp3File = new MP3File(testFile); //Has no tag at this point assertFalse(mp3File.hasID3v1Tag()); assertFalse(mp3File.hasID3v2Tag()); //Create v1 tag (old method) ID3v11Tag v1tag = new ID3v11Tag(); v1tag.setField(FieldKey.ARTIST,V1_ARTIST); v1tag.setField(FieldKey.ALBUM,"V1ALBUM"); mp3File.setID3v1Tag(v1tag); mp3File.save(); //Has only v1 tag at this point assertTrue(mp3File.hasID3v1Tag()); assertFalse(mp3File.hasID3v2Tag()); //Read back artist (new method ,v1) AudioFile af = AudioFileIO.read(testFile); assertEquals(V1_ARTIST, af.getTag().getFirst(FieldKey.ARTIST)); assertEquals(V1_ARTIST, af.getTag().getFirst(FieldKey.ARTIST)); assertEquals(V1_ARTIST, af.getTag().getFirst(FieldKey.ARTIST)); //Add artist frame (old method) ID3v24Tag tag = new ID3v24Tag(); ID3v24Frame frame = new ID3v24Frame(ID3v24Frames.FRAME_ID_ARTIST); ((FrameBodyTPE1) frame.getBody()).setText(FrameBodyTPE1Test.TPE1_TEST_STRING); tag.setFrame(frame); mp3File.setID3v2TagOnly(tag); mp3File.save(); //Has v1 and v2 tag at this point assertTrue(mp3File.hasID3v1Tag()); assertTrue(mp3File.hasID3v2Tag()); //Read back artist (new method ,v1 value overridden by v2 method) af = AudioFileIO.read(testFile); assertEquals(FrameBodyTPE1Test.TPE1_TEST_STRING, af.getTag().getFirst(FieldKey.ARTIST)); assertEquals(FrameBodyTPE1Test.TPE1_TEST_STRING, af.getTag().getFirst(FieldKey.ARTIST)); assertEquals(FrameBodyTPE1Test.TPE1_TEST_STRING, ((ID3v24Tag) af.getTag()).getFirst(ID3v24FieldKey.ARTIST)); assertEquals(FrameBodyTPE1Test.TPE1_TEST_STRING,((TagTextField)af.getTag().getFirstField(FieldKey.ARTIST)).getContent()); //.... but v1 value is still there assertEquals(V1_ARTIST, ((MP3File) af).getID3v1Tag().getFirst(FieldKey.ARTIST)); //Write album ( new method) af.getTag().setField(FieldKey.ALBUM,ALBUM_TEST_STRING); af.commit(); //Read back album (new method) af = AudioFileIO.read(testFile); assertEquals(ALBUM_TEST_STRING, af.getTag().getFirst(FieldKey.ALBUM)); assertEquals(ALBUM_TEST_STRING, af.getTag().getFirst(FieldKey.ALBUM)); assertEquals(ALBUM_TEST_STRING, ((ID3v24Tag) af.getTag()).getFirst(ID3v24FieldKey.ALBUM)); assertEquals(ALBUM_TEST_STRING,((TagTextField)af.getTag().getFirstField(FieldKey.ALBUM)).getContent()); assertEquals(1, af.getTag().getFields(FieldKey.ALBUM).size()); //Read back album (old method) AbstractID3v2Frame checkframe = (AbstractID3v2Frame) ((MP3File) af).getID3v2Tag().getFrame(ID3v24Frames.FRAME_ID_ALBUM); assertEquals(ALBUM_TEST_STRING, ((FrameBodyTALB) checkframe.getBody()).getText()); //If addField again, the value gets appended using the null char sperator system af.getTag().addField(FieldKey.ALBUM,ALBUM_TEST_STRING2); af.commit(); af = AudioFileIO.read(testFile); assertEquals(ALBUM_TEST_STRING + "\u0000" + ALBUM_TEST_STRING2, af.getTag().getFirst(FieldKey.ALBUM)); assertEquals(ALBUM_TEST_STRING + "\u0000" + ALBUM_TEST_STRING2, af.getTag().getValue(FieldKey.ALBUM,0)); assertEquals(ALBUM_TEST_STRING, af.getTag().getSubValue(FieldKey.ALBUM,0,0)); assertEquals(ALBUM_TEST_STRING2, af.getTag().getSubValue(FieldKey.ALBUM,0,1)); assertEquals(ALBUM_TEST_STRING + "\u0000" + ALBUM_TEST_STRING2, ((ID3v24Tag) af.getTag()).getFirst(ID3v24FieldKey.ALBUM)); assertEquals(ALBUM_TEST_STRING + "\u0000" + ALBUM_TEST_STRING2,((TagTextField)af.getTag().getFirstField(FieldKey.ALBUM)).getContent()); assertEquals(1, af.getTag().getFields(FieldKey.ALBUM).size()); //And can replace existing value af.getTag().setField(FieldKey.ALBUM,ALBUM_TEST_STRING2); af.commit(); af = AudioFileIO.read(testFile); assertEquals(ALBUM_TEST_STRING2, af.getTag().getFirst(FieldKey.ALBUM)); assertEquals(ALBUM_TEST_STRING2, af.getTag().getFirst(FieldKey.ALBUM)); assertEquals(ALBUM_TEST_STRING2, ((ID3v24Tag) af.getTag()).getFirst(ID3v24FieldKey.ALBUM)); assertEquals(1, af.getTag().getFields(FieldKey.ALBUM).size()); //and deleteField it af.getTag().deleteField(FieldKey.ALBUM); af.commit(); af = AudioFileIO.read(testFile); assertEquals("", af.getTag().getFirst(FieldKey.ALBUM)); assertEquals("", af.getTag().getFirst(FieldKey.ALBUM)); assertEquals("", ((ID3v24Tag) af.getTag()).getFirst(ID3v24FieldKey.ALBUM)); assertEquals(0, af.getTag().getFields(FieldKey.ALBUM).size()); //Test out the other basic fields //Year af.getTag().setField(FieldKey.YEAR,"1991"); af.commit(); af = AudioFileIO.read(testFile); assertEquals("1991", af.getTag().getFirst(FieldKey.YEAR)); assertEquals("1991", af.getTag().getFirst(FieldKey.YEAR)); assertEquals("1991", ((ID3v24Tag) af.getTag()).getFirst(ID3v24FieldKey.YEAR)); assertEquals("1991",((TagTextField)af.getTag().getFirstField(FieldKey.YEAR)).getContent()); assertEquals(1, af.getTag().getFields(FieldKey.YEAR).size()); assertEquals(2, af.getTag().getFieldCount()); //Title af.getTag().setField(FieldKey.TITLE,"Title"); af.commit(); af = AudioFileIO.read(testFile); assertEquals("Title", af.getTag().getFirst(FieldKey.TITLE)); assertEquals("Title", af.getTag().getFirst(FieldKey.TITLE)); assertEquals("Title", ((ID3v24Tag) af.getTag()).getFirst(ID3v24FieldKey.TITLE)); assertEquals("Title",((TagTextField)af.getTag().getFirstField(FieldKey.TITLE)).getContent()); assertEquals(1, af.getTag().getFields(FieldKey.TITLE).size()); assertEquals(3, af.getTag().getFieldCount()); //Comment, trickier because uses different framebody subclass to the ones above af.getTag().setField(FieldKey.COMMENT,"Comment"); af.commit(); af = AudioFileIO.read(testFile); assertEquals("Comment", af.getTag().getFirst(FieldKey.COMMENT)); assertEquals("Comment", ((ID3v24Tag) af.getTag()).getFirst(ID3v24FieldKey.COMMENT)); //By default comments are created with empty description because this is what expected //by plyers such as iTunes. ID3v24Frame commentFrame = (ID3v24Frame) ((ID3v24Tag) af.getTag()).getFrame("COMM"); FrameBodyCOMM fb = (FrameBodyCOMM) commentFrame.getBody(); assertEquals("", fb.getDescription()); assertEquals("Comment", fb.getText()); //Change description, cant do this with common interface fb.setDescription("test"); //Because has different description the following setField will addField another comment rather than overwriting the first one af.getTag().setField(FieldKey.COMMENT,"Comment2"); assertEquals(2, af.getTag().getFields(FieldKey.COMMENT).size()); //Add third Comment List comments = af.getTag().getFields(FieldKey.COMMENT); ((FrameBodyCOMM) ((ID3v24Frame) comments.get(1)).getBody()).setDescription("test2"); af.getTag().setField(FieldKey.COMMENT,"Comment3"); af.commit(); af = AudioFileIO.read(testFile); assertEquals(3, af.getTag().getFields(FieldKey.COMMENT).size()); //Add fourth Comment (but duplicate key - so overwrites 3rd comment) af.getTag().setField(FieldKey.COMMENT,"Comment4"); af.commit(); af = AudioFileIO.read(testFile); assertEquals(3, af.getTag().getFields(FieldKey.COMMENT).size()); //Remove all Comment tags af.getTag().deleteField(FieldKey.COMMENT); assertEquals(0, af.getTag().getFields(FieldKey.COMMENT).size()); //Add first one back in af.getTag().setField(FieldKey.COMMENT,"Comment"); af.commit(); af = AudioFileIO.read(testFile); assertEquals(1, af.getTag().getFields(FieldKey.COMMENT).size()); assertEquals(4, af.getTag().getFieldCount()); //Genre //TODO only one genre frame allowed, but that can contain multiple GENRE values, currently //must parse as one genre e.g 34 67 af.getTag().setField(FieldKey.GENRE,"CustomGenre"); af.commit(); af = AudioFileIO.read(testFile); assertEquals("CustomGenre", af.getTag().getFirst(FieldKey.GENRE)); assertEquals("CustomGenre", af.getTag().getFirst(FieldKey.GENRE)); assertEquals("CustomGenre", ((ID3v24Tag) af.getTag()).getFirst(ID3v24FieldKey.GENRE)); assertEquals(1, af.getTag().getFields(FieldKey.GENRE).size()); assertEquals(5, af.getTag().getFieldCount()); //Track af.getTag().setField(FieldKey.TRACK,"7"); af.getTag().setField(af.getTag().createField(FieldKey.TRACK_TOTAL, "11")); assertEquals("7",af.getTag().getFirst(FieldKey.TRACK)); assertEquals("11",af.getTag().getFirst(FieldKey.TRACK_TOTAL)); af.commit(); af = AudioFileIO.read(testFile); assertEquals("7", af.getTag().getFirst(FieldKey.TRACK)); assertEquals("7", af.getTag().getFirst(FieldKey.TRACK)); assertEquals("7", ((ID3v24Tag) af.getTag()).getFirst(ID3v24FieldKey.TRACK)); assertEquals("11",af.getTag().getFirst(FieldKey.TRACK_TOTAL)); assertEquals(1, af.getTag().getFields(FieldKey.TRACK).size()); assertEquals(6, af.getTag().getFieldCount()); //AmazonId //This is one of many fields that uses the TXXX frame, the logic is more complicated af.getTag().setField(af.getTag().createField(FieldKey.AMAZON_ID, "asin123456" + "\u01ff")); af.commit(); af = AudioFileIO.read(testFile); //Mood af.getTag().setField(af.getTag().createField(FieldKey.MOOD, "mood")); af.commit(); af = AudioFileIO.read(testFile); assertEquals("asin123456" + "\u01ff", af.getTag().getFirst(FieldKey.AMAZON_ID)); assertEquals("asin123456" + "\u01ff", ((ID3v24Tag) af.getTag()).getFirst(ID3v24FieldKey.AMAZON_ID)); assertEquals(1, af.getTag().getFields(FieldKey.AMAZON_ID).size()); assertEquals(8, af.getTag().getFieldCount()); //Now addField another different field that also uses a TXXX frame af.getTag().setField(af.getTag().createField(FieldKey.MUSICIP_ID, "musicip_id")); af.commit(); af = AudioFileIO.read(testFile); assertEquals(2, ((List) ((ID3v24Tag) af.getTag()).getFrame("TXXX")).size()); assertEquals("musicip_id", af.getTag().getFirst(FieldKey.MUSICIP_ID)); assertEquals("musicip_id", ((ID3v24Tag) af.getTag()).getFirst(ID3v24FieldKey.MUSICIP_ID)); assertEquals(1, af.getTag().getFields(FieldKey.MUSICIP_ID).size()); assertEquals("asin123456" + "\u01ff", af.getTag().getFirst(FieldKey.AMAZON_ID)); assertEquals(9, af.getTag().getFieldCount()); //Now addField yet another different field that also uses a TXXX frame af.getTag().setField(af.getTag().createField(FieldKey.MUSICBRAINZ_RELEASEID, "releaseid")); af.commit(); af = AudioFileIO.read(testFile); assertEquals(3, ((List) ((ID3v24Tag) af.getTag()).getFrame("TXXX")).size()); assertEquals("musicip_id", af.getTag().getFirst(FieldKey.MUSICIP_ID)); assertEquals("releaseid", af.getTag().getFirst(FieldKey.MUSICBRAINZ_RELEASEID)); assertEquals("releaseid",((TagTextField)af.getTag().getFirstField(FieldKey.MUSICBRAINZ_RELEASEID)).getContent()); assertEquals("asin123456" + "\u01ff", af.getTag().getFirst(FieldKey.AMAZON_ID)); assertEquals(1, af.getTag().getFields(FieldKey.MUSICIP_ID).size()); assertEquals(1, af.getTag().getFields(FieldKey.AMAZON_ID).size()); assertEquals(1, af.getTag().getFields(FieldKey.MUSICBRAINZ_RELEASEID).size()); assertEquals(10, af.getTag().getFieldCount()); //Now deleteField field af.getTag().deleteField(FieldKey.MUSICBRAINZ_RELEASEID); af.commit(); af = AudioFileIO.read(testFile); assertEquals(2, ((List) ((ID3v24Tag) af.getTag()).getFrame("TXXX")).size()); assertEquals(1, af.getTag().getFields(FieldKey.MUSICIP_ID).size()); assertEquals(1, af.getTag().getFields(FieldKey.AMAZON_ID).size()); assertEquals(9, af.getTag().getFieldCount()); //Cover Art:invalid way to do it try { af.getTag().setField(af.getTag().createField(FieldKey.COVER_ART, "coverart")); } catch (java.lang.UnsupportedOperationException uoe) { e = uoe; } assertTrue(e instanceof UnsupportedOperationException); //Add new image correctly RandomAccessFile imageFile = new RandomAccessFile(new File("testdata", "coverart.png"), "r"); byte[] imagedata = new byte[(int) imageFile.length()]; imageFile.read(imagedata); af.getTag().addField(tag.createArtworkField(imagedata, "image/png")); af.commit(); af = AudioFileIO.read(testFile); assertEquals(1, ((ID3v24Tag) af.getTag()).getFields(FieldKey.COVER_ART).size()); assertEquals(1, ((ID3v24Tag) af.getTag()).getFields(ID3v24FieldKey.COVER_ART.getFieldName()).size()); //TODO This isnt very user friendly TagField tagField = af.getTag().getFirstField(ID3v24FieldKey.COVER_ART.getFieldName()); assertEquals("image/png::18545",((TagTextField)af.getTag().getFirstField(FieldKey.COVER_ART)).getContent()); assertTrue(tagField instanceof ID3v24Frame); ID3v24Frame apicFrame = (ID3v24Frame) tagField; assertTrue(apicFrame.getBody() instanceof FrameBodyAPIC); FrameBodyAPIC apicframebody = (FrameBodyAPIC) apicFrame.getBody(); assertFalse(apicframebody.isImageUrl()); assertEquals(10, af.getTag().getFieldCount()); //Add another image correctly imageFile = new RandomAccessFile(new File("testdata", "coverart_small.png"), "r"); imagedata = new byte[(int) imageFile.length()]; imageFile.read(imagedata); af.getTag().addField(tag.createArtworkField(imagedata, "image/png")); af.commit(); af = AudioFileIO.read(testFile); assertEquals(2, af.getTag().getFields(FieldKey.COVER_ART).size()); assertEquals(11, af.getTag().getFieldCount()); //Actually createField the image from the read data BufferedImage bi = null; TagField imageField = af.getTag().getFields(FieldKey.COVER_ART).get(0); if (imageField instanceof AbstractID3v2Frame) { FrameBodyAPIC imageFrameBody = (FrameBodyAPIC) ((AbstractID3v2Frame) imageField).getBody(); if (!imageFrameBody.isImageUrl()) { byte[] imageRawData = (byte[]) imageFrameBody.getObjectValue(DataTypes.OBJ_PICTURE_DATA); bi = ImageIO.read(new ByteArrayInputStream(imageRawData)); } } assertNotNull(bi); //Add a linked Image af.getTag().addField(tag.createLinkedArtworkField("../testdata/coverart.jpg")); af.commit(); af = AudioFileIO.read(testFile); assertEquals(3, af.getTag().getFields(FieldKey.COVER_ART).size()); assertEquals(12, af.getTag().getFieldCount()); List imageFields = af.getTag().getFields(FieldKey.COVER_ART); tagField = imageFields.get(2); apicFrame = (ID3v24Frame) tagField; assertTrue(apicFrame.getBody() instanceof FrameBodyAPIC); apicframebody = (FrameBodyAPIC) apicFrame.getBody(); assertTrue(apicframebody.isImageUrl()); assertEquals("../testdata/coverart.jpg", apicframebody.getImageUrl()); } /* public void testReadUrlImage() throws Exception { Exception ex = null; try { File testFile = AbstractTestCase.copyAudioToTmp("testV1withurlimage.mp3"); org.jaudiotagger.audio.AudioFile audioFile = org.jaudiotagger.audio.AudioFileIO.read(testFile); ID3v23Tag newTag = (ID3v23Tag)audioFile.getTag(); assertEquals(1, newTag.getFields(FieldKey.COVER_ART).size()); TagField tagField = newTag.getFirstField(ID3v23FieldKey.COVER_ART.getFieldName()); assertTrue(tagField instanceof ID3v23Frame); ID3v23Frame apicFrame = (ID3v23Frame)tagField; assertTrue(apicFrame.getBody() instanceof FrameBodyAPIC); FrameBodyAPIC apicframebody = (FrameBodyAPIC)apicFrame.getBody(); assertFalse(apicframebody.isImageUrl()); } catch(Exception e) { ex=e; ex.printStackTrace(); } assertNull(ex); } */ public void testNewInterfaceBasicReadandWriteID3v23() throws Exception { Exception e = null; File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3", new File("testnewIntId3v23.mp3")); MP3File mp3File = new MP3File(testFile); //Has no tag at this point assertFalse(mp3File.hasID3v1Tag()); assertFalse(mp3File.hasID3v2Tag()); //Create v1 tag (old method) ID3v11Tag v1tag = new ID3v11Tag(); v1tag.setField(FieldKey.ARTIST,V1_ARTIST); v1tag.setField(FieldKey.ALBUM,"V1ALBUM"); mp3File.setID3v1Tag(v1tag); mp3File.save(); //Has only v1 tag at this point assertTrue(mp3File.hasID3v1Tag()); assertFalse(mp3File.hasID3v2Tag()); //Read back artist (new method ,v1) AudioFile af = AudioFileIO.read(testFile); assertEquals(V1_ARTIST, af.getTag().getFirst(FieldKey.ARTIST)); assertEquals(V1_ARTIST, af.getTag().getFirst(FieldKey.ARTIST)); assertEquals(V1_ARTIST, af.getTag().getFirst(FieldKey.ARTIST)); //Add artist frame (old method) ID3v23Tag tag = new ID3v23Tag(); ID3v23Frame frame = new ID3v23Frame(ID3v23Frames.FRAME_ID_V3_ARTIST); ((FrameBodyTPE1) frame.getBody()).setText(FrameBodyTPE1Test.TPE1_TEST_STRING); tag.setFrame(frame); mp3File.setID3v2TagOnly(tag); mp3File.save(); //Has v1 and v2 tag at this point assertTrue(mp3File.hasID3v1Tag()); assertTrue(mp3File.hasID3v2Tag()); //Read back artist (new method ,v1 value overrriden by v2 method) af = AudioFileIO.read(testFile); assertEquals(FrameBodyTPE1Test.TPE1_TEST_STRING, af.getTag().getFirst(FieldKey.ARTIST)); assertEquals(FrameBodyTPE1Test.TPE1_TEST_STRING, af.getTag().getFirst(FieldKey.ARTIST)); assertEquals(FrameBodyTPE1Test.TPE1_TEST_STRING, ((ID3v23Tag) af.getTag()).getFirst(ID3v23FieldKey.ARTIST)); //.... but v1 value is still there assertEquals(V1_ARTIST, ((MP3File) af).getID3v1Tag().getFirst(FieldKey.ARTIST)); //Write album ( new method) af.getTag().setField(FieldKey.ALBUM,ALBUM_TEST_STRING); af.commit(); //Read back album (new method) af = AudioFileIO.read(testFile); assertEquals(ALBUM_TEST_STRING, af.getTag().getFirst(FieldKey.ALBUM)); assertEquals(ALBUM_TEST_STRING, af.getTag().getFirst(FieldKey.ALBUM)); assertEquals(ALBUM_TEST_STRING, ((ID3v23Tag) af.getTag()).getFirst(ID3v23FieldKey.ALBUM)); assertEquals(1, af.getTag().getFields(FieldKey.ALBUM).size()); //Read back album (old method) AbstractID3v2Frame checkframe = (AbstractID3v2Frame) ((MP3File) af).getID3v2Tag().getFrame(ID3v23Frames.FRAME_ID_V3_ALBUM); assertEquals(ALBUM_TEST_STRING, ((FrameBodyTALB) checkframe.getBody()).getText()); //If add smae field again appended to existiong frame af.getTag().addField(FieldKey.ALBUM,ALBUM_TEST_STRING2); af.commit(); af = AudioFileIO.read(testFile); assertEquals(ALBUM_TEST_STRING + "\u0000" + ALBUM_TEST_STRING2, af.getTag().getFirst(FieldKey.ALBUM)); assertEquals(ALBUM_TEST_STRING + "\u0000" + ALBUM_TEST_STRING2, af.getTag().getFirst(FieldKey.ALBUM)); assertEquals(ALBUM_TEST_STRING, af.getTag().getSubValue(FieldKey.ALBUM,0,0)); assertEquals(ALBUM_TEST_STRING2, af.getTag().getSubValue(FieldKey.ALBUM,0,1)); assertEquals(ALBUM_TEST_STRING + "\u0000" + ALBUM_TEST_STRING2, ((ID3v23Tag) af.getTag()).getFirst(ID3v23FieldKey.ALBUM)); assertEquals(1, af.getTag().getFields(FieldKey.ALBUM).size()); //But can replace existing value af.getTag().setField(FieldKey.ALBUM,ALBUM_TEST_STRING2); af.commit(); af = AudioFileIO.read(testFile); assertEquals(ALBUM_TEST_STRING2, af.getTag().getFirst(FieldKey.ALBUM)); assertEquals(ALBUM_TEST_STRING2, af.getTag().getFirst(FieldKey.ALBUM)); assertEquals(ALBUM_TEST_STRING2, ((ID3v23Tag) af.getTag()).getFirst(ID3v23FieldKey.ALBUM)); assertEquals(1, af.getTag().getFields(FieldKey.ALBUM).size()); //and deleteField it af.getTag().deleteField(FieldKey.ALBUM); af.commit(); af = AudioFileIO.read(testFile); assertEquals("", af.getTag().getFirst(FieldKey.ALBUM)); assertEquals("", af.getTag().getFirst(FieldKey.ALBUM)); assertEquals("", ((ID3v23Tag) af.getTag()).getFirst(ID3v23FieldKey.ALBUM)); assertEquals(0, af.getTag().getFields(FieldKey.ALBUM).size()); //Test out the other basic fields //Year af.getTag().setField(FieldKey.YEAR,"1991"); af.commit(); af = AudioFileIO.read(testFile); assertEquals("1991", af.getTag().getFirst(FieldKey.YEAR)); assertEquals("1991", af.getTag().getFirst(FieldKey.YEAR)); assertEquals("1991", ((ID3v23Tag) af.getTag()).getFirst(ID3v23FieldKey.YEAR)); assertEquals(1, af.getTag().getFields(FieldKey.YEAR).size()); assertEquals(2, af.getTag().getFieldCount()); //Title af.getTag().setField(FieldKey.TITLE,"Title"); af.commit(); af = AudioFileIO.read(testFile); assertEquals("Title", af.getTag().getFirst(FieldKey.TITLE)); assertEquals("Title", af.getTag().getFirst(FieldKey.TITLE)); assertEquals("Title", ((ID3v23Tag) af.getTag()).getFirst(ID3v23FieldKey.TITLE)); assertEquals(1, af.getTag().getFields(FieldKey.TITLE).size()); assertEquals(3, af.getTag().getFieldCount()); //Comment, trickier because uses different framebody subclass to the ones above af.getTag().setField(FieldKey.COMMENT,"Comment"); af.commit(); af = AudioFileIO.read(testFile); assertEquals("Comment", af.getTag().getFirst(FieldKey.COMMENT)); assertEquals("Comment", ((ID3v23Tag) af.getTag()).getFirst(ID3v23FieldKey.COMMENT)); assertEquals(1, af.getTag().getFields(FieldKey.COMMENT).size()); assertEquals(4, af.getTag().getFieldCount()); //Genre //TODO only one genre frame allowed, but that can contain multiple GENRE values, currently //must parse as one genre e.g 34 67 af.getTag().setField(FieldKey.GENRE,"CustomGenre"); af.commit(); af = AudioFileIO.read(testFile); assertEquals("CustomGenre", af.getTag().getFirst(FieldKey.GENRE)); assertEquals("CustomGenre", ((ID3v23Tag) af.getTag()).getFirst(ID3v23FieldKey.GENRE)); assertEquals(1, af.getTag().getFields(FieldKey.GENRE).size()); assertEquals(5, af.getTag().getFieldCount()); //Track af.getTag().setField(FieldKey.TRACK,"7"); af.getTag().setField(af.getTag().createField(FieldKey.TRACK_TOTAL, "11")); assertEquals("7",af.getTag().getFirst(FieldKey.TRACK)); assertEquals("11",af.getTag().getFirst(FieldKey.TRACK_TOTAL)); af.commit(); af = AudioFileIO.read(testFile); assertEquals("7", af.getTag().getFirst(FieldKey.TRACK)); assertEquals("7", af.getTag().getFirst(FieldKey.TRACK)); assertEquals("7", ((ID3v23Tag) af.getTag()).getFirst(ID3v23FieldKey.TRACK)); assertEquals(1, af.getTag().getFields(FieldKey.TRACK).size()); assertEquals(6, af.getTag().getFieldCount()); assertEquals("7",af.getTag().getFirst(FieldKey.TRACK)); //AmazonId also testing utf encoding here //This is one of many fields that uses the TXXX frame, the logic is more complicated af.getTag().setField(af.getTag().createField(FieldKey.AMAZON_ID, "asin123456" + "\u01ff")); af.commit(); af = AudioFileIO.read(testFile); assertEquals("asin123456" + "\u01ff", af.getTag().getFirst(FieldKey.AMAZON_ID)); assertEquals("asin123456" + "\u01ff", ((ID3v23Tag) af.getTag()).getFirst(ID3v23FieldKey.AMAZON_ID)); assertEquals(1, af.getTag().getFields(FieldKey.AMAZON_ID).size()); assertEquals(7, af.getTag().getFieldCount()); //Mood af.getTag().setField(af.getTag().createField(FieldKey.MOOD, "mood")); af.commit(); af = AudioFileIO.read(testFile); assertEquals("mood", af.getTag().getFirst(FieldKey.MOOD)); //Now deleteField field af.getTag().deleteField(FieldKey.MOOD); af.commit(); af = AudioFileIO.read(testFile); assertEquals("7",af.getTag().getFirst(FieldKey.TRACK)); //Track Total af.getTag().setField(af.getTag().createField(FieldKey.TRACK_TOTAL, "11")); assertEquals("11",af.getTag().getFirst(FieldKey.TRACK_TOTAL)); //Now addField another different field that also uses a TXXX frame af.getTag().setField(af.getTag().createField(FieldKey.MUSICIP_ID, "musicip_id")); af.commit(); af = AudioFileIO.read(testFile); assertEquals(2, ((List) ((ID3v23Tag) af.getTag()).getFrame("TXXX")).size()); assertEquals("musicip_id", af.getTag().getFirst(FieldKey.MUSICIP_ID)); assertEquals("musicip_id", ((ID3v23Tag) af.getTag()).getFirst(ID3v23FieldKey.MUSICIP_ID)); assertEquals(1, af.getTag().getFields(FieldKey.MUSICIP_ID).size()); assertEquals("asin123456" + "\u01ff", af.getTag().getFirst(FieldKey.AMAZON_ID)); assertEquals("7",af.getTag().getFirst(FieldKey.TRACK)); assertEquals(8, af.getTag().getFieldCount()); assertEquals("11",af.getTag().getFirst(FieldKey.TRACK_TOTAL)); assertEquals("7",((ID3v23Tag)af.getTag()).getFirst(ID3v23FieldKey.TRACK)); assertEquals("11",((ID3v23Tag)af.getTag()).getFirst(ID3v23FieldKey.TRACK_TOTAL)); //Now addField yet another different field that also uses a TXXX frame af.getTag().setField(af.getTag().createField(FieldKey.MUSICBRAINZ_RELEASEID, "releaseid")); af.commit(); af = AudioFileIO.read(testFile); assertEquals(3, ((List) ((ID3v23Tag) af.getTag()).getFrame("TXXX")).size()); assertEquals("musicip_id", af.getTag().getFirst(FieldKey.MUSICIP_ID)); assertEquals("releaseid", af.getTag().getFirst(FieldKey.MUSICBRAINZ_RELEASEID)); assertEquals("asin123456" + "\u01ff", af.getTag().getFirst(FieldKey.AMAZON_ID)); assertEquals(1, af.getTag().getFields(FieldKey.MUSICIP_ID).size()); assertEquals(1, af.getTag().getFields(FieldKey.AMAZON_ID).size()); assertEquals(1, af.getTag().getFields(FieldKey.MUSICBRAINZ_RELEASEID).size()); assertEquals(9, af.getTag().getFieldCount()); //Now deleteField field af.getTag().deleteField(FieldKey.MUSICBRAINZ_RELEASEID); af.commit(); af = AudioFileIO.read(testFile); assertEquals(2, ((List) ((ID3v23Tag) af.getTag()).getFrame("TXXX")).size()); assertEquals(1, af.getTag().getFields(FieldKey.MUSICIP_ID).size()); assertEquals(1, af.getTag().getFields(FieldKey.AMAZON_ID).size()); assertEquals(8, af.getTag().getFieldCount()); //Cover Art:invalid way to do it try { af.getTag().setField(af.getTag().createField(FieldKey.COVER_ART, "coverart")); } catch (java.lang.UnsupportedOperationException uoe) { e = uoe; } assertTrue(e instanceof UnsupportedOperationException); //Add new image correctly RandomAccessFile imageFile = new RandomAccessFile(new File("testdata", "coverart.png"), "r"); byte[] imagedata = new byte[(int) imageFile.length()]; imageFile.read(imagedata); af.getTag().addField(tag.createArtworkField(imagedata, "image/png")); af.commit(); af = AudioFileIO.read(testFile); assertEquals(1, af.getTag().getFields(FieldKey.COVER_ART).size()); assertEquals(9, af.getTag().getFieldCount()); //Add another image correctly imageFile = new RandomAccessFile(new File("testdata", "coverart_small.png"), "r"); imagedata = new byte[(int) imageFile.length()]; imageFile.read(imagedata); af.getTag().addField(tag.createArtworkField(imagedata, "image/png")); af.commit(); af = AudioFileIO.read(testFile); assertEquals(2, af.getTag().getFields(FieldKey.COVER_ART).size()); assertEquals(10, af.getTag().getFieldCount()); } public void testNewInterfaceBasicReadandWriteID3v22() throws Exception { Exception e = null; File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3", new File("testnewIntId3v22.mp3")); MP3File mp3File = new MP3File(testFile); //Has no tag at this point assertFalse(mp3File.hasID3v1Tag()); assertFalse(mp3File.hasID3v2Tag()); //Create v1 tag (old method) ID3v11Tag v1tag = new ID3v11Tag(); v1tag.setField(FieldKey.ARTIST,V1_ARTIST); v1tag.setField(FieldKey.ALBUM,"V1ALBUM"); mp3File.setID3v1Tag(v1tag); mp3File.save(); //Has only v1 tag at this point assertTrue(mp3File.hasID3v1Tag()); assertFalse(mp3File.hasID3v2Tag()); //Read back artist (new method ,v1) AudioFile af = AudioFileIO.read(testFile); assertEquals(V1_ARTIST, af.getTag().getFirst(FieldKey.ARTIST)); assertEquals(V1_ARTIST, af.getTag().getFirst(FieldKey.ARTIST)); assertEquals(V1_ARTIST, af.getTag().getFirst(FieldKey.ARTIST)); //Add artist frame (old method) ID3v22Tag tag = new ID3v22Tag(); ID3v22Frame frame = new ID3v22Frame(ID3v22Frames.FRAME_ID_V2_ARTIST); ((FrameBodyTPE1) frame.getBody()).setText(FrameBodyTPE1Test.TPE1_TEST_STRING); tag.setFrame(frame); mp3File.setID3v2TagOnly(tag); mp3File.save(); //Has v1 and v2 tag at this point assertTrue(mp3File.hasID3v1Tag()); assertTrue(mp3File.hasID3v2Tag()); //Read back artist (new method ,v1 value overrriden by v2 method) af = AudioFileIO.read(testFile); assertEquals(FrameBodyTPE1Test.TPE1_TEST_STRING, af.getTag().getFirst(FieldKey.ARTIST)); assertEquals(FrameBodyTPE1Test.TPE1_TEST_STRING, af.getTag().getFirst(FieldKey.ARTIST)); assertEquals(FrameBodyTPE1Test.TPE1_TEST_STRING, ((ID3v22Tag) af.getTag()).getFirst(ID3v22FieldKey.ARTIST)); //.... but v1 value is still there assertEquals(V1_ARTIST, ((MP3File) af).getID3v1Tag().getFirst(FieldKey.ARTIST)); //Write album ( new method) af.getTag().setField(FieldKey.ALBUM,ALBUM_TEST_STRING); assertEquals(ALBUM_TEST_STRING, af.getTag().getFirst(FieldKey.ALBUM)); assertEquals(1, af.getTag().getFields(FieldKey.ALBUM).size()); af.commit(); //Read back album (new method) af = AudioFileIO.read(testFile); assertEquals(ALBUM_TEST_STRING, af.getTag().getFirst(FieldKey.ALBUM)); assertEquals(ALBUM_TEST_STRING, af.getTag().getFirst(FieldKey.ALBUM)); assertEquals(ALBUM_TEST_STRING, ((ID3v22Tag) af.getTag()).getFirst(ID3v22FieldKey.ALBUM)); assertEquals(1, af.getTag().getFields(FieldKey.ALBUM).size()); //Read back album (old method) AbstractID3v2Frame checkframe = (AbstractID3v2Frame) ((MP3File) af).getID3v2Tag().getFrame(ID3v22Frames.FRAME_ID_V2_ALBUM); assertEquals(ALBUM_TEST_STRING, ((FrameBodyTALB) checkframe.getBody()).getText()); //If add extra text field its appended to existing frame af.getTag().addField(FieldKey.ALBUM,ALBUM_TEST_STRING2); af.commit(); af = AudioFileIO.read(testFile); assertEquals(ALBUM_TEST_STRING + "\u0000" + ALBUM_TEST_STRING2, af.getTag().getFirst(FieldKey.ALBUM)); assertEquals(ALBUM_TEST_STRING + "\u0000" + ALBUM_TEST_STRING2, af.getTag().getFirst(FieldKey.ALBUM)); assertEquals(ALBUM_TEST_STRING, af.getTag().getSubValue(FieldKey.ALBUM,0,0)); assertEquals(ALBUM_TEST_STRING2, af.getTag().getSubValue(FieldKey.ALBUM,0,1)); assertEquals(ALBUM_TEST_STRING + "\u0000" + ALBUM_TEST_STRING2, ((ID3v22Tag) af.getTag()).getFirst(ID3v22FieldKey.ALBUM)); assertEquals(1, af.getTag().getFields(FieldKey.ALBUM).size()); //But can replace existing value af.getTag().setField(FieldKey.ALBUM,ALBUM_TEST_STRING2); af.commit(); af = AudioFileIO.read(testFile); assertEquals(ALBUM_TEST_STRING2, af.getTag().getFirst(FieldKey.ALBUM)); assertEquals(ALBUM_TEST_STRING2, af.getTag().getFirst(FieldKey.ALBUM)); assertEquals(ALBUM_TEST_STRING2, ((ID3v22Tag) af.getTag()).getFirst(ID3v22FieldKey.ALBUM)); assertEquals(1,af.getTag().getFields(FieldKey.ALBUM).size()); //and deleteField it af.getTag().deleteField(FieldKey.ALBUM); af.commit(); af = AudioFileIO.read(testFile); assertEquals("", af.getTag().getFirst(FieldKey.ALBUM)); assertEquals("", af.getTag().getFirst(FieldKey.ALBUM)); assertEquals("", ((ID3v22Tag) af.getTag()).getFirst(ID3v22FieldKey.ALBUM)); assertEquals(0, af.getTag().getFields(FieldKey.ALBUM).size()); //Test out the other basic fields //Year af.getTag().setField(FieldKey.YEAR,"1991"); af.commit(); af = AudioFileIO.read(testFile); assertEquals("1991", af.getTag().getFirst(FieldKey.YEAR)); assertEquals("1991", af.getTag().getFirst(FieldKey.YEAR)); assertEquals("1991", ((ID3v22Tag) af.getTag()).getFirst(ID3v22FieldKey.YEAR)); assertEquals(1, af.getTag().getFields(FieldKey.YEAR).size()); assertEquals(2, af.getTag().getFieldCount()); //Title af.getTag().setField(FieldKey.TITLE,"Title"); af.commit(); af = AudioFileIO.read(testFile); assertEquals("Title", af.getTag().getFirst(FieldKey.TITLE)); assertEquals("Title", af.getTag().getFirst(FieldKey.TITLE)); assertEquals("Title", ((ID3v22Tag) af.getTag()).getFirst(ID3v22FieldKey.TITLE)); assertEquals(1, af.getTag().getFields(FieldKey.TITLE).size()); assertEquals(3, af.getTag().getFieldCount()); //Comment, trickier because uses different framebody subclass to the ones above af.getTag().setField(FieldKey.COMMENT,"Comment"); af.commit(); af = AudioFileIO.read(testFile); assertEquals("Comment", af.getTag().getFirst(FieldKey.COMMENT)); assertEquals("Comment", af.getTag().getFirst(FieldKey.COMMENT)); assertEquals("Comment", ((ID3v22Tag) af.getTag()).getFirst(ID3v22FieldKey.COMMENT)); assertEquals(1, af.getTag().getFields(FieldKey.COMMENT).size()); assertEquals(4, af.getTag().getFieldCount()); //Genre //TODO only one genre frame allowed, but that can contain multiple GENRE values, currently //must parse as one genre e.g 34 67 af.getTag().setField(FieldKey.GENRE,"CustomGenre"); af.commit(); af = AudioFileIO.read(testFile); assertEquals("CustomGenre", af.getTag().getFirst(FieldKey.GENRE)); assertEquals("CustomGenre", af.getTag().getFirst(FieldKey.GENRE)); assertEquals("CustomGenre", ((ID3v22Tag) af.getTag()).getFirst(ID3v22FieldKey.GENRE)); assertEquals(1, af.getTag().getFields(FieldKey.GENRE).size()); assertEquals(5, af.getTag().getFieldCount()); //Track af.getTag().setField(FieldKey.TRACK,"7"); af.getTag().setField(af.getTag().createField(FieldKey.TRACK_TOTAL, "11")); assertEquals("7",af.getTag().getFirst(FieldKey.TRACK)); assertEquals("11",af.getTag().getFirst(FieldKey.TRACK_TOTAL)); af.commit(); af = AudioFileIO.read(testFile); assertEquals("7", af.getTag().getFirst(FieldKey.TRACK)); assertEquals("7", af.getTag().getFirst(FieldKey.TRACK)); assertEquals("7", ((ID3v22Tag) af.getTag()).getFirst(ID3v22FieldKey.TRACK)); assertEquals("11",af.getTag().getFirst(FieldKey.TRACK_TOTAL)); assertEquals(1, af.getTag().getFields(FieldKey.TRACK).size()); assertEquals(1, af.getTag().getFields(FieldKey.TRACK).size()); assertEquals(6, af.getTag().getFieldCount()); //AmazonId //This is one of many fields that uses the TXXX frame, the logic is more complicated af.getTag().setField(af.getTag().createField(FieldKey.AMAZON_ID, "asin123456" + "\u01ff")); af.commit(); af = AudioFileIO.read(testFile); //Mood af.getTag().setField(af.getTag().createField(FieldKey.MOOD, "mood")); af.commit(); af = AudioFileIO.read(testFile); assertEquals("mood", af.getTag().getFirst(FieldKey.MOOD)); //Now deleteField field af.getTag().deleteField(FieldKey.MOOD); af.commit(); af = AudioFileIO.read(testFile); assertEquals("asin123456" + "\u01ff", af.getTag().getFirst(FieldKey.AMAZON_ID)); assertEquals("asin123456" + "\u01ff", ((ID3v22Tag) af.getTag()).getFirst(ID3v22FieldKey.AMAZON_ID)); assertEquals(1, af.getTag().getFields(FieldKey.AMAZON_ID).size()); assertEquals(7, af.getTag().getFieldCount()); //Now addField another different field that also uses a TXX frame af.getTag().setField(af.getTag().createField(FieldKey.MUSICIP_ID, "musicip_id")); af.commit(); af = AudioFileIO.read(testFile); assertEquals(2, ((List) ((ID3v22Tag) af.getTag()).getFrame("TXX")).size()); assertEquals("musicip_id", af.getTag().getFirst(FieldKey.MUSICIP_ID)); assertEquals("musicip_id", ((ID3v22Tag) af.getTag()).getFirst(ID3v22FieldKey.MUSICIP_ID)); assertEquals(1, af.getTag().getFields(FieldKey.MUSICIP_ID).size()); assertEquals("asin123456" + "\u01ff", af.getTag().getFirst(FieldKey.AMAZON_ID)); assertEquals(8, af.getTag().getFieldCount()); //Now addField yet another different field that also uses a TXX frame af.getTag().setField(af.getTag().createField(FieldKey.MUSICBRAINZ_RELEASEID, "releaseid")); af.commit(); af = AudioFileIO.read(testFile); assertEquals(3, ((List) ((ID3v22Tag) af.getTag()).getFrame("TXX")).size()); assertEquals("musicip_id", af.getTag().getFirst(FieldKey.MUSICIP_ID)); assertEquals("releaseid", af.getTag().getFirst(FieldKey.MUSICBRAINZ_RELEASEID)); assertEquals("asin123456" + "\u01ff", af.getTag().getFirst(FieldKey.AMAZON_ID)); assertEquals(1, af.getTag().getFields(FieldKey.MUSICIP_ID).size()); assertEquals(1, af.getTag().getFields(FieldKey.AMAZON_ID).size()); assertEquals(1, af.getTag().getFields(FieldKey.MUSICBRAINZ_RELEASEID).size()); assertEquals(9, af.getTag().getFieldCount()); //Now deleteField field af.getTag().deleteField(FieldKey.MUSICBRAINZ_RELEASEID); af.commit(); af = AudioFileIO.read(testFile); assertEquals(2, ((List) ((ID3v22Tag) af.getTag()).getFrame("TXX")).size()); assertEquals(1, af.getTag().getFields(FieldKey.MUSICIP_ID).size()); assertEquals(1, af.getTag().getFields(FieldKey.AMAZON_ID).size()); assertEquals(8, af.getTag().getFieldCount()); //Cover Art:invalid way to do it try { af.getTag().setField(af.getTag().createField(FieldKey.COVER_ART, "coverart")); } catch (java.lang.UnsupportedOperationException uoe) { e = uoe; } assertTrue(e instanceof UnsupportedOperationException); //Add new image correctly RandomAccessFile imageFile = new RandomAccessFile(new File("testdata", "coverart.png"), "r"); byte[] imagedata = new byte[(int) imageFile.length()]; imageFile.read(imagedata); af.getTag().addField(tag.createArtworkField(imagedata, "image/png")); af.commit(); af = AudioFileIO.read(testFile); assertEquals(1, af.getTag().getFields(FieldKey.COVER_ART).size()); assertEquals(9, af.getTag().getFieldCount()); //Add another image correctly imageFile = new RandomAccessFile(new File("testdata", "coverart_small.png"), "r"); imagedata = new byte[(int) imageFile.length()]; imageFile.read(imagedata); af.getTag().addField(tag.createArtworkField(imagedata, "image/png")); af.commit(); af = AudioFileIO.read(testFile); assertEquals(2, af.getTag().getFields(FieldKey.COVER_ART).size()); assertEquals(10, af.getTag().getFieldCount()); } /** * Test how adding multiple frameswith new interface of same type is is handled * * @throws Exception */ public void testSettingMultipleFramesofSameType() throws Exception { Exception e = null; File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3", new File("testSetMultiple.mp3")); AudioFile af = AudioFileIO.read(testFile); MP3File mp3File = (MP3File) af; ID3v24Tag tag = new ID3v24Tag(); ID3v24Frame frame = new ID3v24Frame(ID3v24Frames.FRAME_ID_COMMENT); ((FrameBodyCOMM) frame.getBody()).setText("Comment"); tag.setFrame(frame); mp3File.setID3v2TagOnly(tag); mp3File.save(); af = AudioFileIO.read(testFile); mp3File = (MP3File) af; //COMM { ID3v24Frame commentFrame = (ID3v24Frame) ((ID3v24Tag) af.getTag()).getFrame("COMM"); FrameBodyCOMM fb = (FrameBodyCOMM) commentFrame.getBody(); assertEquals("", fb.getDescription()); assertEquals("Comment", fb.getText()); //Change description, cant do this with common interface fb.setDescription("test"); //Because has different description the following setField will addField another comment rather than overwriting the first one af.getTag().setField(FieldKey.COMMENT,"Comment2"); assertEquals(2, af.getTag().getFields(FieldKey.COMMENT).size()); //Add third Comment List comments = af.getTag().getFields(FieldKey.COMMENT); ((FrameBodyCOMM) ((ID3v24Frame) comments.get(1)).getBody()).setDescription("test2"); af.getTag().setField(FieldKey.COMMENT,"Comment3"); af.commit(); af = AudioFileIO.read(testFile); assertEquals(3, af.getTag().getFields(FieldKey.COMMENT).size()); //Add fourth Comment (but duplicate key - so overwrites 3rd comment) af.getTag().setField(FieldKey.COMMENT,"Comment4"); af.commit(); af = AudioFileIO.read(testFile); assertEquals(3, af.getTag().getFields(FieldKey.COMMENT).size()); //Add comment using generic call af.getTag().setField(af.getTag().createField(FieldKey.COMMENT, "abcdef-ghijklmn")); //Remove all Comment tags af.getTag().deleteField(FieldKey.COMMENT); assertEquals(0, af.getTag().getFields(FieldKey.COMMENT).size()); //Add first one back in af.getTag().setField(FieldKey.COMMENT,"Comment"); af.commit(); af = AudioFileIO.read(testFile); assertEquals(1, af.getTag().getFields(FieldKey.COMMENT).size()); assertEquals(1, af.getTag().getFieldCount()); } //TXXX { tag = (ID3v24Tag) af.getTag(); frame = new ID3v24Frame(ID3v24Frames.FRAME_ID_USER_DEFINED_INFO); ((FrameBodyTXXX) frame.getBody()).setText("UserDefined"); tag.setFrame(frame); ID3v24Frame txxxFrame = (ID3v24Frame) tag.getFrame("TXXX"); FrameBodyTXXX fb = (FrameBodyTXXX) txxxFrame.getBody(); assertEquals("", fb.getDescription()); assertEquals("UserDefined", fb.getText()); //Change description, cant do this with common interface fb.setDescription("test"); //Because has different description the following setField will addField another txxx rather than overwriting the first one af.getTag().setField(af.getTag().createField(FieldKey.MUSICBRAINZ_ARTISTID, "abcdef-ghijklmn")); assertEquals(2, ((List) tag.getFrame("TXXX")).size()); //Now adding TXXX with same id so gets overwritten af.getTag().setField(af.getTag().createField(FieldKey.MUSICBRAINZ_ARTISTID, "abcfffff")); assertEquals(2, ((List) tag.getFrame("TXXX")).size()); //Try deleting some of these tag.removeFrameOfType("TXXX"); assertNull(tag.getFrame("TXXX")); af.getTag().setField(af.getTag().createField(FieldKey.MUSICBRAINZ_ARTISTID, "abcdef-ghijklmn")); ((ID3v24Tag) af.getTag()).deleteField(FieldKey.MUSICBRAINZ_ARTISTID); assertNull(tag.getFrame("TXXX")); } //UFID { tag = (ID3v24Tag) af.getTag(); frame = new ID3v24Frame(ID3v24Frames.FRAME_ID_UNIQUE_FILE_ID); ((FrameBodyUFID) frame.getBody()).setOwner("owner"); tag.setFrame(frame); ID3v24Frame ufidFrame = (ID3v24Frame) tag.getFrame("UFID"); FrameBodyUFID fb = (FrameBodyUFID) ufidFrame.getBody(); assertEquals("owner", fb.getOwner()); //Because has different owner the following setField will addField another ufid rather than overwriting the first one af.getTag().setField(af.getTag().createField(FieldKey.MUSICBRAINZ_TRACK_ID, "abcdef-ghijklmn")); assertEquals(2, ((List) tag.getFrame("UFID")).size()); //Now adding UFID with same owner so gets overwritten af.getTag().setField(af.getTag().createField(FieldKey.MUSICBRAINZ_TRACK_ID, "abcfffff")); assertEquals(2, ((List) tag.getFrame("UFID")).size()); //Try deleting some of these tag.removeFrame("UFID"); assertNull(tag.getFrame("UFID")); } //ULST { tag = (ID3v24Tag) af.getTag(); frame = new ID3v24Frame(ID3v24Frames.FRAME_ID_UNSYNC_LYRICS); ((FrameBodyUSLT) frame.getBody()).setDescription("lyrics1"); tag.setFrame(frame); ID3v24Frame usltFrame = (ID3v24Frame) tag.getFrame("USLT"); FrameBodyUSLT fb = (FrameBodyUSLT) usltFrame.getBody(); assertEquals("lyrics1", fb.getDescription()); //Because has different desc the following setField will addField another uslt rather than overwriting the first one af.getTag().setField(af.getTag().createField(FieldKey.LYRICS, "abcdef-ghijklmn")); assertEquals(2, ((List) tag.getFrame("USLT")).size()); assertEquals(2, af.getTag().getFields(FieldKey.LYRICS).size()); frame = (ID3v24Frame) ((List) tag.getFrame("USLT")).get(1); assertEquals("", ((FrameBodyUSLT) frame.getBody()).getDescription()); //Now adding USLT with same description so gets overwritten af.getTag().setField(af.getTag().createField(FieldKey.LYRICS, "abcfffff")); assertEquals(2, ((List) tag.getFrame("USLT")).size()); assertEquals(2, af.getTag().getFields(FieldKey.LYRICS).size()); } //POPM TODO not a supported FieldKey yet { tag = (ID3v24Tag) af.getTag(); frame = new ID3v24Frame(ID3v24Frames.FRAME_ID_POPULARIMETER); ((FrameBodyPOPM) frame.getBody()).setEmailToUser("paultaylor@jthink.net"); tag.setFrame(frame); ID3v24Frame popmFrame = (ID3v24Frame) tag.getFrame("POPM"); FrameBodyPOPM fb = (FrameBodyPOPM) popmFrame.getBody(); assertEquals("paultaylor@jthink.net", fb.getEmailToUser()); } } public void testIterator() throws Exception { File orig = new File("testdata", "test26.mp3"); if (!orig.isFile()) { return; } Exception e = null; File testFile = AbstractTestCase.copyAudioToTmp("test26.mp3"); MP3File mp3File = new MP3File(testFile); assertEquals(0, mp3File.getID3v2Tag().getFieldCount()); Iterator i = mp3File.getID3v2Tag().getFields(); assertFalse(i.hasNext()); try { i.next(); } catch(Exception ex) { e=ex; } assertTrue(e instanceof NoSuchElementException); mp3File.getID3v2Tag().addField(FieldKey.ALBUM,"album"); assertEquals(1, mp3File.getID3v2Tag().getFieldCount()); i = mp3File.getID3v2Tag().getFields(); //Should be able to iterate without actually having to call isNext() first i.next(); //Should be able to call hasNext() without it having any effect i = mp3File.getID3v2Tag().getFields(); assertTrue(i.hasNext()); Object o = i.next(); assertTrue( o instanceof ID3v23Frame); assertEquals("album",((AbstractFrameBodyTextInfo)(((ID3v23Frame)o).getBody())).getFirstTextValue()); try { i.next(); } catch(Exception ex) { e=ex; } assertTrue(e instanceof NoSuchElementException); assertFalse(i.hasNext()); //Empty frame map and force adding of empty list mp3File.getID3v2Tag().frameMap.clear(); mp3File.getID3v2Tag().frameMap.put("TXXX",new ArrayList()); assertEquals(0,mp3File.getID3v2Tag().getFieldCount()); //Issue #236 //i = mp3File.getID3v2Tag().getFields(); //assertFalse(i.hasNext()); } /** * Currently genres are written to and from v2 tag as is, the decoding from genre number to string has to be done manually */ public void testGenres() { Exception ex = null; try { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3", new File("testBasicWrite.mp3")); org.jaudiotagger.audio.AudioFile audioFile = org.jaudiotagger.audio.AudioFileIO.read(testFile); org.jaudiotagger.tag.Tag newTag = audioFile.getTag(); assertTrue(newTag == null); if (audioFile.getTag() == null) { audioFile.setTag(new ID3v23Tag()); newTag = audioFile.getTag(); } //Write literal String newTag.setField(FieldKey.GENRE,"Rock"); audioFile.commit(); audioFile = org.jaudiotagger.audio.AudioFileIO.read(testFile); newTag = audioFile.getTag(); //..and read back assertEquals("Rock", newTag.getFirst(FieldKey.GENRE)); //Write Code newTag.setField(FieldKey.GENRE,"(17)"); audioFile.commit(); audioFile = org.jaudiotagger.audio.AudioFileIO.read(testFile); newTag = audioFile.getTag(); //..and read back assertEquals("(17)", newTag.getFirst(FieldKey.GENRE)); } catch (Exception e) { ex = e; ex.printStackTrace(); } assertNull(ex); } public void testRemoveFrameOfType() { File orig = new File("testdata", "test30.mp3"); if (!orig.isFile()) { return; } Exception exceptionCaught = null; File testFile = AbstractTestCase.copyAudioToTmp("test30.mp3"); MP3File mp3file = null; try { mp3file = new MP3File(testFile); //deleteField multiple frames starting make change to file ((ID3v24Tag) mp3file.getID3v2Tag()).removeFrameOfType("PRIV"); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/id3/DuplicateFrameTest.java0000644000175000017500000000266511470746136030252 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.audio.mp3.MP3File; import org.jaudiotagger.tag.Tag; import java.io.File; /** * Test if read a tag with a corrupt frame that in certain circumstances continue to read the other frames * regardless. */ public class DuplicateFrameTest extends AbstractTestCase { public void testReadingFileWithCorruptFirstFrame() throws Exception { File orig = new File("testdata", "test78.mp3"); if (!orig.isFile()) { System.err.println("Unable to test file - not available"); return; } File testFile = AbstractTestCase.copyAudioToTmp("test78.mp3"); MP3File f = (MP3File)AudioFileIO.read(testFile); Tag tag = f.getTag(); assertTrue(f.getTag() instanceof ID3v23Tag); ID3v23Tag id3v23tag = (ID3v23Tag)tag; //Frame contains two TYER frames assertEquals(21,id3v23tag.getDuplicateBytes()); assertEquals("*TYER*","*"+id3v23tag.getDuplicateFrameId()+"*"); f.commit(); f = (MP3File)AudioFileIO.read(testFile); tag = f.getTag(); id3v23tag = (ID3v23Tag)tag; //After save the duplicate frame has been discarded assertEquals(0,id3v23tag.getDuplicateBytes()); assertEquals("",id3v23tag.getDuplicateFrameId()); } }libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/id3/ID3v1TagTest.java0000644000175000017500000002616711470746136026652 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.audio.mp3.MP3File; import org.jaudiotagger.tag.FieldKey; import org.jaudiotagger.tag.Tag; import org.jaudiotagger.tag.TagOptionSingleton; import org.jaudiotagger.tag.TagTextField; import java.io.File; /** * */ public class ID3v1TagTest extends TestCase { public static final String ARTIST = "artist"; public static final String ALBUM = "album"; public static final String COMMENT = "comment"; public static final String TITLE = "title"; public static final String TRACK_VALUE = "10"; public static final String GENRE_VAL = "Country"; public static final String YEAR = "1971"; /** * Provides an initialised object to be used in other tests * to prevent code duplication * * @return ID3v1Tag */ public static ID3v1Tag getInitialisedTag() { ID3v1Tag v1Tag = new ID3v1Tag(); v1Tag.setArtist(ID3v1TagTest.ARTIST); v1Tag.setAlbum(ID3v1TagTest.ALBUM); v1Tag.setComment(ID3v1TagTest.COMMENT); v1Tag.setTitle(ID3v1TagTest.TITLE); v1Tag.setGenre(ID3v1TagTest.GENRE_VAL); v1Tag.setYear(ID3v1TagTest.YEAR); return v1Tag; } /** * Constructor * * @param arg0 */ public ID3v1TagTest(String arg0) { super(arg0); } /** * Command line entrance. * * @param args */ public static void main(String[] args) { junit.textui.TestRunner.run(ID3v1TagTest.suite()); } ///////////////////////////////////////////////////////////////////////// // TestCase classes to override ///////////////////////////////////////////////////////////////////////// /** * */ protected void setUp() { TagOptionSingleton.getInstance().setToDefault(); } /** * */ protected void tearDown() { } /** * */ // protected void runTest() // { // } /** * Builds the Test Suite. * * @return the Test Suite. */ public static Test suite() { return new TestSuite(ID3v1TagTest.class); } ///////////////////////////////////////////////////////////////////////// // Tests ///////////////////////////////////////////////////////////////////////// public void testCreateID3v1Tag() { ID3v1Tag v1Tag = new ID3v1Tag(); v1Tag.setArtist(ID3v1TagTest.ARTIST); v1Tag.setAlbum(ID3v1TagTest.ALBUM); v1Tag.setComment(ID3v1TagTest.COMMENT); v1Tag.setTitle(ID3v1TagTest.TITLE); v1Tag.setGenre(ID3v1TagTest.GENRE_VAL); v1Tag.setYear(ID3v1TagTest.YEAR); assertEquals((byte) 1, v1Tag.getRelease()); assertEquals((byte) 0, v1Tag.getMajorVersion()); assertEquals((byte) 0, v1Tag.getRevision()); //Check with old interface assertEquals(ID3v1TagTest.ARTIST, v1Tag.getFirst(FieldKey.ARTIST)); assertEquals(ID3v1TagTest.ALBUM, v1Tag.getFirst(FieldKey.ALBUM)); assertEquals(ID3v1TagTest.COMMENT, v1Tag.getFirstComment()); assertEquals(ID3v1TagTest.TITLE, v1Tag.getFirst(FieldKey.TITLE)); assertEquals(ID3v1TagTest.GENRE_VAL, v1Tag.getFirst(FieldKey.GENRE)); assertEquals(ID3v1TagTest.YEAR, v1Tag.getFirst(FieldKey.YEAR)); //Check with entagged interface assertEquals(ID3v1TagTest.ARTIST, ((TagTextField) v1Tag.getArtist().get(0)).getContent()); assertEquals(ID3v1TagTest.ALBUM, ((TagTextField) v1Tag.getAlbum().get(0)).getContent()); assertEquals(ID3v1TagTest.COMMENT, ((TagTextField) v1Tag.getComment().get(0)).getContent()); assertEquals(ID3v1TagTest.TITLE, ((TagTextField) v1Tag.getTitle().get(0)).getContent()); assertEquals(ID3v1TagTest.GENRE_VAL, ((TagTextField) v1Tag.getGenre().get(0)).getContent()); assertEquals(ID3v1TagTest.YEAR, ((TagTextField) v1Tag.getYear().get(0)).getContent()); } public void testSaveID3v1TagToFile() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); MP3File mp3File = new MP3File(testFile); //Create v1 Tag ID3v1Tag tag = new ID3v1Tag(); tag.setArtist(ID3v1TagTest.ARTIST); tag.setAlbum(ID3v1TagTest.ALBUM); tag.setComment(ID3v1TagTest.COMMENT); tag.setTitle(ID3v1TagTest.TITLE); tag.setGenre(ID3v1TagTest.GENRE_VAL); tag.setYear(ID3v1TagTest.YEAR); //Save tag to file mp3File.setID3v1Tag(tag); mp3File.save(); //Reload mp3File = new MP3File(testFile); tag = mp3File.getID3v1Tag(); assertEquals(ID3v1TagTest.ARTIST, tag.getFirst(FieldKey.ARTIST)); assertEquals(ID3v1TagTest.ALBUM, tag.getFirst(FieldKey.ALBUM)); assertEquals(ID3v1TagTest.COMMENT, tag.getFirstComment()); assertEquals(ID3v1TagTest.TITLE, tag.getFirst(FieldKey.TITLE)); assertEquals(ID3v1TagTest.GENRE_VAL, tag.getFirst(FieldKey.GENRE)); assertEquals(ID3v1TagTest.YEAR, tag.getFirst(FieldKey.YEAR)); tag.setField(FieldKey.TRACK,"3"); mp3File.save(); mp3File = new MP3File(testFile); tag = mp3File.getID3v1Tag(); assertEquals("", tag.getFirst(FieldKey.TRACK)); } public void testSaveID3v1TagToFileUsingTagInterface() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); AudioFile file = AudioFileIO.read(testFile); //Create v1 Tag Tag tag = file.getTag(); if (tag == null) { file.setTag(new ID3v1Tag()); tag = file.getTag(); } tag.setField(FieldKey.ARTIST,ID3v1TagTest.ARTIST); tag.setField(FieldKey.ALBUM,ID3v1TagTest.ALBUM); tag.setField(FieldKey.COMMENT,ID3v1TagTest.COMMENT); tag.setField(FieldKey.TITLE,ID3v1TagTest.TITLE); tag.setField(FieldKey.GENRE,ID3v1TagTest.GENRE_VAL); tag.setField(FieldKey.YEAR,ID3v1TagTest.YEAR); //Save tag changes to file file.setTag(tag); file.commit(); //Reload file = AudioFileIO.read(testFile); tag = file.getTag(); assertEquals(ID3v1TagTest.ARTIST, tag.getFirst(FieldKey.ARTIST)); assertEquals(ID3v1TagTest.ALBUM, tag.getFirst(FieldKey.ALBUM)); assertEquals(ID3v1TagTest.COMMENT, tag.getFirst(FieldKey.COMMENT)); assertEquals(ID3v1TagTest.TITLE, tag.getFirst(FieldKey.TITLE)); assertEquals(ID3v1TagTest.GENRE_VAL, tag.getFirst(FieldKey.GENRE)); assertEquals(ID3v1TagTest.YEAR, tag.getFirst(FieldKey.YEAR)); } public void testCreateID3v1FromID3v24() { ID3v24Tag v2Tag = new ID3v24Tag(); ID3v1Tag v1Tag = new ID3v1Tag(v2Tag); assertNotNull(v1Tag); assertEquals((byte) 1, v1Tag.getRelease()); assertEquals((byte) 0, v1Tag.getMajorVersion()); assertEquals((byte) 0, v1Tag.getRevision()); } public void testCreateID3v1FromID3v23() { ID3v23Tag v2Tag = new ID3v23Tag(); ID3v1Tag v1Tag = new ID3v1Tag(v2Tag); assertNotNull(v1Tag); assertEquals((byte) 1, v1Tag.getRelease()); assertEquals((byte) 0, v1Tag.getMajorVersion()); assertEquals((byte) 0, v1Tag.getRevision()); } public void testCreateID3v1FromID3v22() { ID3v22Tag v2Tag = new ID3v22Tag(); ID3v1Tag v1Tag = new ID3v1Tag(v2Tag); assertNotNull(v1Tag); assertEquals((byte) 1, v1Tag.getRelease()); assertEquals((byte) 0, v1Tag.getMajorVersion()); assertEquals((byte) 0, v1Tag.getRevision()); } public void testNewInterface() { Exception exceptionCaught = null; ID3v1Tag v1Tag = new ID3v1Tag(); assertTrue(v1Tag.isEmpty()); v1Tag.setField(new ID3v1TagField(FieldKey.ARTIST.name(), "artist")); assertEquals("artist", ((TagTextField) v1Tag.getFields(FieldKey.ARTIST).get(0)).getContent()); assertEquals("artist", ((TagTextField) v1Tag.getFirstField(FieldKey.ARTIST.name())).getContent()); assertEquals("artist", ((TagTextField) (v1Tag.getFields(FieldKey.ARTIST.name()).get(0))).getContent()); v1Tag.setField(new ID3v1TagField(FieldKey.ALBUM.name(), "album")); assertEquals("album", ((TagTextField) v1Tag.getFields(FieldKey.ALBUM).get(0)).getContent()); assertEquals("album", ((TagTextField) v1Tag.getFirstField(FieldKey.ALBUM.name())).getContent()); v1Tag.setField(new ID3v1TagField(FieldKey.TITLE.name(), "title")); assertEquals("title", ((TagTextField) v1Tag.getFields(FieldKey.TITLE).get(0)).getContent()); assertEquals("title", ((TagTextField) v1Tag.getFirstField(FieldKey.TITLE.name())).getContent()); v1Tag.setField(new ID3v1TagField(FieldKey.YEAR.name(), "year")); assertEquals("year", ((TagTextField) v1Tag.getFields(FieldKey.YEAR).get(0)).getContent()); assertEquals("year", ((TagTextField) v1Tag.getFirstField(FieldKey.YEAR.name())).getContent()); v1Tag.setField(new ID3v1TagField(FieldKey.GENRE.name(), "Country")); assertEquals("Country", ((TagTextField) v1Tag.getFields(FieldKey.GENRE).get(0)).getContent()); assertEquals("Country", ((TagTextField) v1Tag.getFirstField(FieldKey.GENRE.name())).getContent()); v1Tag.setField(new ID3v1TagField(FieldKey.COMMENT.name(), "comment")); assertEquals("comment", ((TagTextField) v1Tag.getFields(FieldKey.COMMENT).get(0)).getContent()); assertEquals("comment", ((TagTextField) v1Tag.getFirstField(FieldKey.COMMENT.name())).getContent()); //Check nothing been overwritten assertEquals("year", v1Tag.getFirst(FieldKey.YEAR)); assertEquals("Country", v1Tag.getFirst(FieldKey.GENRE)); assertEquals("title", v1Tag.getFirst(FieldKey.TITLE)); assertEquals("album", v1Tag.getFirst(FieldKey.ALBUM)); assertEquals("artist", v1Tag.getFirst(FieldKey.ARTIST)); //Delete artist field v1Tag.deleteField(FieldKey.ARTIST); assertEquals("", v1Tag.getFirst(FieldKey.ARTIST)); assertEquals("year", v1Tag.getFirst(FieldKey.YEAR)); assertEquals("Country", v1Tag.getFirst(FieldKey.GENRE)); assertEquals("title", v1Tag.getFirst(FieldKey.TITLE)); assertEquals("album", v1Tag.getFirst(FieldKey.ALBUM)); //Not Empty assertFalse(v1Tag.isEmpty()); v1Tag.deleteField(FieldKey.ALBUM); v1Tag.deleteField(FieldKey.YEAR); v1Tag.deleteField(FieldKey.GENRE); v1Tag.deleteField(FieldKey.TITLE); v1Tag.deleteField(FieldKey.COMMENT); v1Tag.setField(new ID3v1TagField(FieldKey.COMMENT.name(), "")); //Empty assertTrue(v1Tag.isEmpty()); //Null Handling try { v1Tag.setField(new ID3v1TagField(FieldKey.COMMENT.name(), null)); } catch (Exception e) { exceptionCaught = e; } assertTrue(exceptionCaught instanceof IllegalArgumentException); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/id3/SyncSafeIntegerTest.java0000644000175000017500000000173111041064726030377 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.mp3.MP3File; import java.io.File; /** * Test SyncSafe integers read correctly */ public class SyncSafeIntegerTest extends AbstractTestCase { /** * Ensure bytes contian value >128 are read as a postive integer rather than a negative integer */ public void testReadFileContainingLargeSyncSizedFrame() throws Exception { Exception e = null; try { File testFile = AbstractTestCase.copyAudioToTmp("issue158.id3", "testV1.mp3"); MP3File mp3File = new MP3File(testFile); //Read frame that contains the byte>128 value assertTrue(mp3File.getID3v2Tag().hasFrame("USLT")); //managed to read last value assertTrue(mp3File.getID3v2Tag().hasFrame("TCON")); } catch (Exception ie) { e = ie; } assertNull(e); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/id3/DeprecatedFrameTest.java0000644000175000017500000000714011271612232030355 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.mp3.MP3File; import org.jaudiotagger.tag.id3.framebody.FrameBodyDeprecated; import org.jaudiotagger.tag.id3.framebody.FrameBodyTDAT; import org.jaudiotagger.tag.id3.framebody.FrameBodyTIME; import org.jaudiotagger.tag.id3.framebody.FrameBodyTYER; import java.io.File; import java.util.List; /** * Test DeprecatedFrames */ public class DeprecatedFrameTest extends AbstractTestCase { public void testv24TagWithDeprecatedFrameShouldCreateAsDeprecated() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("Issue88.id3", "testV1.mp3"); MP3File mp3File = new MP3File(testFile); ID3v24Frame v24frame = (ID3v24Frame) mp3File.getID3v2Tag().getFrame(ID3v23Frames.FRAME_ID_V3_TYER); assertNotNull(v24frame); assertTrue(v24frame.getBody() instanceof FrameBodyDeprecated); } public void testConvertTagWithDeprecatedFrameToTagWhereFrameShouldNoLongerBeDeprecated() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("Issue88.id3", "testV1.mp3"); MP3File mp3File = new MP3File(testFile); ID3v23Tag v23Tag = new ID3v23Tag(mp3File.getID3v2Tag()); ID3v23Frame v23frame = (ID3v23Frame) ((List)v23Tag.getFrame(ID3v23Frames.FRAME_ID_V3_TYER)).get(0); assertTrue(v23frame.getBody() instanceof FrameBodyTYER); v23frame = (ID3v23Frame) ((List)v23Tag.getFrame(ID3v23Frames.FRAME_ID_V3_TYER)).get(1); assertTrue(v23frame.getBody() instanceof FrameBodyTYER); mp3File.setID3v2Tag(v23Tag); mp3File.save(); mp3File = new MP3File(testFile); v23Tag = (ID3v23Tag) mp3File.getID3v2Tag(); v23frame = (ID3v23Frame) v23Tag.getFrame(ID3v23Frames.FRAME_ID_V3_TYER); assertTrue(v23frame.getBody() instanceof FrameBodyTYER); } public void testSavingV24DeprecatedTIMETagToV23() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("Issue122-1.id3", "testV1.mp3"); MP3File mp3File = new MP3File(testFile); ID3v24Tag v24Tag = (ID3v24Tag) mp3File.getID3v2Tag(); ID3v24Frame v24frame = (ID3v24Frame) v24Tag.getFrame(ID3v23Frames.FRAME_ID_V3_TIME); assertNotNull(v24frame); assertTrue(v24frame.getBody() instanceof FrameBodyDeprecated); //Save as V23 ID3v23Tag v23Tag = new ID3v23Tag((AbstractID3v2Tag) v24Tag); mp3File.setID3v2Tag(v23Tag); mp3File.save(); mp3File = new MP3File(testFile); v23Tag = (ID3v23Tag) mp3File.getID3v2Tag(); ID3v23Frame v23frame = (ID3v23Frame) v23Tag.getFrame(ID3v23Frames.FRAME_ID_V3_TIME); assertTrue(v23frame.getBody() instanceof FrameBodyTIME); } public void testSavingV24DeprecatedTDATTagToV23() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("Issue122-2.id3", "testV1.mp3"); MP3File mp3File = new MP3File(testFile); ID3v24Tag v24Tag = (ID3v24Tag) mp3File.getID3v2Tag(); ID3v24Frame v24frame = (ID3v24Frame) v24Tag.getFrame(ID3v23Frames.FRAME_ID_V3_TDAT); assertNotNull(v24frame); assertTrue(v24frame.getBody() instanceof FrameBodyDeprecated); //Save as V23 ID3v23Tag v23Tag = new ID3v23Tag((AbstractID3v2Tag) v24Tag); mp3File.setID3v2Tag(v23Tag); mp3File.save(); mp3File = new MP3File(testFile); v23Tag = (ID3v23Tag) mp3File.getID3v2Tag(); ID3v23Frame v23frame = (ID3v23Frame) v23Tag.getFrame(ID3v23Frames.FRAME_ID_V3_TDAT); assertTrue(v23frame.getBody() instanceof FrameBodyTDAT); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/id3/FramePOPMTest.java0000644000175000017500000001240411041064726027073 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.mp3.MP3File; import org.jaudiotagger.tag.id3.framebody.FrameBodyPOPM; import org.jaudiotagger.tag.id3.framebody.FrameBodyPOPMTest; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; import java.io.File; /** * Test POPMFrameBody */ public class FramePOPMTest extends AbstractTestCase { private static final String ISSUE_72_TEST_EMAIL = "Windows Media Player 9 Series"; private static final int ISSUE_72_TEST_RATING = 255; private static final int ISSUE_72_TEST_COUNTER = 0; public static ID3v24Frame getInitialisedFrame() { ID3v24Frame frame = new ID3v24Frame(ID3v24Frames.FRAME_ID_POPULARIMETER); FrameBodyPOPM fb = FrameBodyPOPMTest.getInitialisedBody(); frame.setBody(fb); return frame; } public void testCreateID3v24Frame() { Exception exceptionCaught = null; ID3v24Frame frame = null; FrameBodyPOPM fb = null; try { frame = new ID3v24Frame(ID3v24Frames.FRAME_ID_POPULARIMETER); fb = FrameBodyPOPMTest.getInitialisedBody(); frame.setBody(fb); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v24Frames.FRAME_ID_POPULARIMETER, frame.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, fb.getTextEncoding()); assertEquals(FrameBodyPOPMTest.POPM_EMAIL, ((FrameBodyPOPM) frame.getBody()).getEmailToUser()); assertEquals(FrameBodyPOPMTest.POPM_RATING, ((FrameBodyPOPM) frame.getBody()).getRating()); assertEquals(FrameBodyPOPMTest.POPM_COUNTER, ((FrameBodyPOPM) frame.getBody()).getCounter()); assertFalse(ID3v24Frames.getInstanceOf().isExtensionFrames(frame.getIdentifier())); assertTrue(ID3v24Frames.getInstanceOf().isSupportedFrames(frame.getIdentifier())); } public void testCreateID3v23Frame() { Exception exceptionCaught = null; ID3v23Frame frame = null; FrameBodyPOPM fb = null; try { frame = new ID3v23Frame(ID3v23Frames.FRAME_ID_V3_POPULARIMETER); fb = FrameBodyPOPMTest.getInitialisedBody(); frame.setBody(fb); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v23Frames.FRAME_ID_V3_POPULARIMETER, frame.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, fb.getTextEncoding()); assertEquals(FrameBodyPOPMTest.POPM_EMAIL, ((FrameBodyPOPM) frame.getBody()).getEmailToUser()); assertEquals(FrameBodyPOPMTest.POPM_RATING, ((FrameBodyPOPM) frame.getBody()).getRating()); assertEquals(FrameBodyPOPMTest.POPM_COUNTER, ((FrameBodyPOPM) frame.getBody()).getCounter()); } public void testSaveToFile() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); MP3File mp3File = new MP3File(testFile); //Create and Save ID3v24Tag tag = new ID3v24Tag(); tag.setFrame(FramePOPMTest.getInitialisedFrame()); mp3File.setID3v2Tag(tag); mp3File.save(); //Reload mp3File = new MP3File(testFile); ID3v24Frame frame = (ID3v24Frame) mp3File.getID3v2Tag().getFrame(ID3v24Frames.FRAME_ID_POPULARIMETER); FrameBodyPOPM body = (FrameBodyPOPM) frame.getBody(); assertEquals(TextEncoding.ISO_8859_1, body.getTextEncoding()); assertEquals(FrameBodyPOPMTest.POPM_EMAIL, body.getEmailToUser()); assertEquals(FrameBodyPOPMTest.POPM_RATING, body.getRating()); assertEquals(FrameBodyPOPMTest.POPM_COUNTER, body.getCounter()); } public void testSaveEmptyFrameToFile() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); MP3File mp3File = new MP3File(testFile); ID3v24Frame frame = new ID3v24Frame(ID3v24Frames.FRAME_ID_POPULARIMETER); frame.setBody(new FrameBodyPOPM()); //Create and Save ID3v24Tag tag = new ID3v24Tag(); tag.setFrame(frame); mp3File.setID3v2Tag(tag); mp3File.save(); //Reload mp3File = new MP3File(testFile); frame = (ID3v24Frame) mp3File.getID3v2Tag().getFrame(ID3v24Frames.FRAME_ID_POPULARIMETER); FrameBodyPOPM body = (FrameBodyPOPM) frame.getBody(); assertEquals(TextEncoding.ISO_8859_1, body.getTextEncoding()); assertEquals("", body.getEmailToUser()); assertEquals(0, body.getRating()); assertEquals(0, body.getCounter()); } public void testReadFileContainingPOMFrameWithoutCounter() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("Issue72.id3", "testV1.mp3"); MP3File mp3File = new MP3File(testFile); ID3v23Frame frame = (ID3v23Frame) mp3File.getID3v2Tag().getFrame(ID3v24Frames.FRAME_ID_POPULARIMETER); FrameBodyPOPM body = (FrameBodyPOPM) frame.getBody(); assertEquals(TextEncoding.ISO_8859_1, body.getTextEncoding()); assertEquals(ISSUE_72_TEST_EMAIL, body.getEmailToUser()); assertEquals(ISSUE_72_TEST_RATING, body.getRating()); assertEquals(ISSUE_72_TEST_COUNTER, body.getCounter()); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/id3/FrameCOMMTest.java0000644000175000017500000001043711041064726027057 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.mp3.MP3File; import org.jaudiotagger.tag.id3.framebody.FrameBodyCOMM; import java.io.File; /** * Test POPMFrameBody */ public class FrameCOMMTest extends AbstractTestCase { /** * Should run without throwing Runtime excception, although COMMFrame wont be loaded and will * throwe invalid size exception */ public void testReadFileContainingInvalidSizeCOMMFrame() throws Exception { Exception e = null; try { File testFile = AbstractTestCase.copyAudioToTmp("Issue77.id3", "testV1.mp3"); MP3File mp3File = new MP3File(testFile); } catch (Exception ie) { e = ie; } assertNull(e); } /** * Should run without throwing Runtime excception, although COMMFrame wont be loaded and will * throwe invalid datatype exception */ public void testReadFileContainingInvalidTextEncodingCOMMFrame() throws Exception { Exception e = null; try { File testFile = AbstractTestCase.copyAudioToTmp("Issue80.id3", "testV1.mp3"); MP3File mp3File = new MP3File(testFile); } catch (Exception ie) { e = ie; } assertNull(e); } /** * Can read file containing a language code that does not actually map to a code , and write it back * In this real example the language code has been held as three space characters */ public void testreadFrameContainingInvalidlanguageCodeCOMMFrame() throws Exception { final String INVALID_LANG_CODE = " "; Exception e = null; try { File testFile = AbstractTestCase.copyAudioToTmp("Issue108.id3", "testV1.mp3"); MP3File mp3File = new MP3File(testFile); assertTrue(mp3File.getID3v2Tag().hasFrame("COMM")); ID3v24Frame commFrame = (ID3v24Frame) mp3File.getID3v2Tag().getFrame("COMM"); FrameBodyCOMM frameBody = (FrameBodyCOMM) commFrame.getBody(); assertEquals(INVALID_LANG_CODE, frameBody.getLanguage()); } catch (Exception ie) { ie.printStackTrace(); e = ie; } assertNull(e); } /** * Can write file containing a COMM Frame with null language code */ public void testsaveFileContainingNullLanguageCodeCOMMFrame() throws Exception { final String SAFE_LANG_CODE = " "; final String SAFE_LONGER_LANG_CODE = "aa "; final String SAFE_SHORTER_LANG_CODE = "aaa"; Exception e = null; try { //Read tag File testFile = AbstractTestCase.copyAudioToTmp("Issue108.id3", "testV1.mp3"); MP3File mp3File = new MP3File(testFile); ID3v24Frame commFrame = (ID3v24Frame) mp3File.getID3v2Tag().getFrame("COMM"); FrameBodyCOMM frameBody = (FrameBodyCOMM) commFrame.getBody(); //Set language to null, this is common problem for new frames might null lang codes frameBody.setLanguage(null); mp3File.save(); mp3File = new MP3File(testFile); commFrame = (ID3v24Frame) mp3File.getID3v2Tag().getFrame("COMM"); frameBody = (FrameBodyCOMM) commFrame.getBody(); assertEquals(SAFE_LANG_CODE, frameBody.getLanguage()); //Set language to too short a value frameBody.setLanguage("aa"); mp3File.save(); mp3File = new MP3File(testFile); commFrame = (ID3v24Frame) mp3File.getID3v2Tag().getFrame("COMM"); frameBody = (FrameBodyCOMM) commFrame.getBody(); assertEquals(SAFE_LONGER_LANG_CODE, frameBody.getLanguage()); //Set language to too long a value frameBody.setLanguage("aaaaaaa"); mp3File.save(); mp3File = new MP3File(testFile); commFrame = (ID3v24Frame) mp3File.getID3v2Tag().getFrame("COMM"); frameBody = (FrameBodyCOMM) commFrame.getBody(); assertEquals(SAFE_SHORTER_LANG_CODE, frameBody.getLanguage()); } catch (Exception ie) { ie.printStackTrace(); e = ie; } assertNull(e); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/id3/FrameWOARTest.java0000644000175000017500000001542011041064726027071 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.mp3.MP3File; import org.jaudiotagger.tag.id3.framebody.FrameBodyWOAR; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; import java.io.File; import java.net.URLEncoder; /** * Test WOAR Frame */ public class FrameWOARTest extends AbstractTestCase { public static final String NORMAL_LINK = "http:www.btinternet.com/~birdpoo/kots.htm"; //Note cant put Japanese chars directly into code because the source code is not a UTF8 file public static final String UNICODE_LINK_START = "http://ja.wikipedia.org/wiki/"; public static final String UNICODE_LINK_END = "\u5742\u672c\u4e5d"; public static final String UNICODE_ENCODED = "http://ja.wikipedia.org/wiki/%E5%9D%82%E6%9C%AC%E4%B9%9D"; public static final String UNICODE_LINK = "http://ja.wikipedia.org/wiki/\u5742\u672c\u4e5d"; //http://ja.wikipedia.org/wiki/%E5%9D%82%E6%9C%AC%E4%B9%9D public static ID3v24Frame getInitialisedFrame() { ID3v24Frame frame = new ID3v24Frame(ID3v24Frames.FRAME_ID_URL_ARTIST_WEB); FrameBodyWOAR fb = new FrameBodyWOAR(); fb.setUrlLink(NORMAL_LINK); frame.setBody(fb); return frame; } public static ID3v24Frame getInitialisedUnicodeFrame() throws Exception { ID3v24Frame frame = new ID3v24Frame(ID3v24Frames.FRAME_ID_URL_ARTIST_WEB); FrameBodyWOAR fb = new FrameBodyWOAR(); fb.setUrlLink(UNICODE_LINK_START + URLEncoder.encode(UNICODE_LINK_END, "utf8")); //fb.setUrlLink(URLEncoder.encode(UNICODE_LINK_START+UNICODE_LINK_END,"utf8")); frame.setBody(fb); return frame; } public static ID3v24Frame getRawUnicodeFrame() throws Exception { ID3v24Frame frame = new ID3v24Frame(ID3v24Frames.FRAME_ID_URL_ARTIST_WEB); FrameBodyWOAR fb = new FrameBodyWOAR(); fb.setUrlLink(UNICODE_LINK); frame.setBody(fb); return frame; } public void testCreateID3v24Frame() { Exception exceptionCaught = null; ID3v24Frame frame = null; try { frame = getInitialisedFrame(); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertTrue(frame.getBody() instanceof FrameBodyWOAR); assertEquals(ID3v24Frames.FRAME_ID_URL_ARTIST_WEB, frame.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, frame.getBody().getTextEncoding()); assertFalse(ID3v24Frames.getInstanceOf().isExtensionFrames(frame.getIdentifier())); assertTrue(ID3v24Frames.getInstanceOf().isSupportedFrames(frame.getIdentifier())); assertEquals(FrameWOARTest.NORMAL_LINK, ((FrameBodyWOAR) frame.getBody()).getUrlLink()); } public void testSaveToFile() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); MP3File mp3File = new MP3File(testFile); //Create and Save ID3v24Tag tag = new ID3v24Tag(); tag.setFrame(getInitialisedFrame()); mp3File.setID3v2Tag(tag); mp3File.save(); //Reload mp3File = new MP3File(testFile); ID3v24Frame frame = (ID3v24Frame) mp3File.getID3v2Tag().getFrame(ID3v24Frames.FRAME_ID_URL_ARTIST_WEB); assertTrue(frame.getBody() instanceof FrameBodyWOAR); assertEquals(ID3v24Frames.FRAME_ID_URL_ARTIST_WEB, frame.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, frame.getBody().getTextEncoding()); assertFalse(ID3v24Frames.getInstanceOf().isExtensionFrames(frame.getIdentifier())); assertTrue(ID3v24Frames.getInstanceOf().isSupportedFrames(frame.getIdentifier())); assertEquals(FrameWOARTest.NORMAL_LINK, ((FrameBodyWOAR) frame.getBody()).getUrlLink()); } public void testCreateID3v24UnicodeFrame() { Exception exceptionCaught = null; ID3v24Frame frame = null; try { frame = getInitialisedUnicodeFrame(); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertTrue(frame.getBody() instanceof FrameBodyWOAR); assertEquals(ID3v24Frames.FRAME_ID_URL_ARTIST_WEB, frame.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, frame.getBody().getTextEncoding()); assertFalse(ID3v24Frames.getInstanceOf().isExtensionFrames(frame.getIdentifier())); assertTrue(ID3v24Frames.getInstanceOf().isSupportedFrames(frame.getIdentifier())); assertEquals(FrameWOARTest.UNICODE_ENCODED, ((FrameBodyWOAR) frame.getBody()).getUrlLink()); } //This fails beccause cant save Unicode to WOAR fields public void testSaveUnicodeToFile() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); MP3File mp3File = new MP3File(testFile); //Create and Save ID3v24Tag tag = new ID3v24Tag(); tag.setFrame(getInitialisedUnicodeFrame()); mp3File.setID3v2Tag(tag); mp3File.save(); //Reload mp3File = new MP3File(testFile); ID3v24Frame frame = (ID3v24Frame) mp3File.getID3v2Tag().getFrame(ID3v24Frames.FRAME_ID_URL_ARTIST_WEB); assertTrue(frame.getBody() instanceof FrameBodyWOAR); assertEquals(ID3v24Frames.FRAME_ID_URL_ARTIST_WEB, frame.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, frame.getBody().getTextEncoding()); assertFalse(ID3v24Frames.getInstanceOf().isExtensionFrames(frame.getIdentifier())); assertTrue(ID3v24Frames.getInstanceOf().isSupportedFrames(frame.getIdentifier())); assertEquals(FrameWOARTest.UNICODE_ENCODED, ((FrameBodyWOAR) frame.getBody()).getUrlLink()); } //This fails beccause cant save Unicode to WOAR fields public void testSaveUnicodeToFile2() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); MP3File mp3File = new MP3File(testFile); //Create and Save ID3v24Tag tag = new ID3v24Tag(); tag.setFrame(getRawUnicodeFrame()); mp3File.setID3v2Tag(tag); mp3File.save(); //Reload mp3File = new MP3File(testFile); ID3v24Frame frame = (ID3v24Frame) mp3File.getID3v2Tag().getFrame(ID3v24Frames.FRAME_ID_URL_ARTIST_WEB); assertTrue(frame.getBody() instanceof FrameBodyWOAR); assertEquals(ID3v24Frames.FRAME_ID_URL_ARTIST_WEB, frame.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, frame.getBody().getTextEncoding()); assertFalse(ID3v24Frames.getInstanceOf().isExtensionFrames(frame.getIdentifier())); assertTrue(ID3v24Frames.getInstanceOf().isSupportedFrames(frame.getIdentifier())); assertEquals(FrameWOARTest.UNICODE_ENCODED, ((FrameBodyWOAR) frame.getBody()).getUrlLink()); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/id3/FrameULSTTest.java0000644000175000017500000002327011470746136027122 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.audio.mp3.MP3File; import org.jaudiotagger.tag.FieldKey; import org.jaudiotagger.tag.id3.framebody.FrameBodyUSLT; import org.jaudiotagger.tag.reference.Languages; import java.io.File; /** * Test ULSTFrame */ public class FrameULSTTest extends AbstractTestCase { public void testReadULST() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("test23.mp3"); MP3File mp3File = new MP3File(testFile); ID3v24Frame v24frame = (ID3v24Frame) mp3File.getID3v2Tag().getFrame(ID3v24Frames.FRAME_ID_UNSYNC_LYRICS); //Old method FrameBodyUSLT lyricsBody = (FrameBodyUSLT) v24frame.getBody(); assertEquals(589, lyricsBody.getFirstTextValue().length()); assertEquals("", lyricsBody.getDescription()); assertEquals(" ", lyricsBody.getLanguage()); //New Method should be same length AudioFile file = AudioFileIO.read(testFile); assertEquals(589, file.getTag().getFirst(FieldKey.LYRICS).length()); } public void testWriteULSTID3v24() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("test23.mp3"); MP3File mp3File = new MP3File(testFile); ID3v24Frame v24frame = (ID3v24Frame) mp3File.getID3v2Tag().getFrame(ID3v24Frames.FRAME_ID_UNSYNC_LYRICS); //Get lyrics frame and modify FrameBodyUSLT lyricsBody = (FrameBodyUSLT) v24frame.getBody(); assertEquals(589, lyricsBody.getFirstTextValue().length()); assertEquals(1, lyricsBody.getTextEncoding()); lyricsBody.setLanguage(Languages.DEFAULT_ID); lyricsBody.setDescription("description"); lyricsBody.setLyric("lyric1"); mp3File.save(); //Check normal values mp3File = new MP3File(testFile); v24frame = (ID3v24Frame) mp3File.getID3v2Tag().getFrame(ID3v24Frames.FRAME_ID_UNSYNC_LYRICS); lyricsBody = (FrameBodyUSLT) v24frame.getBody(); assertEquals(Languages.DEFAULT_ID, lyricsBody.getLanguage()); assertEquals("description", lyricsBody.getDescription()); assertEquals("lyric1", lyricsBody.getLyric()); assertEquals(1, lyricsBody.getTextEncoding()); //Now force to UTF-16 lyricsBody.setLyric("lyric\u111F"); mp3File.save(); mp3File = new MP3File(testFile); v24frame = (ID3v24Frame) mp3File.getID3v2Tag().getFrame(ID3v24Frames.FRAME_ID_UNSYNC_LYRICS); lyricsBody = (FrameBodyUSLT) v24frame.getBody(); assertEquals(Languages.DEFAULT_ID, lyricsBody.getLanguage()); assertEquals("description", lyricsBody.getDescription()); assertEquals("lyric\u111F", lyricsBody.getLyric()); assertEquals(1, lyricsBody.getTextEncoding()); //Now check UTf16 with empty description lyricsBody.setDescription(""); mp3File.save(); mp3File = new MP3File(testFile); v24frame = (ID3v24Frame) mp3File.getID3v2Tag().getFrame(ID3v24Frames.FRAME_ID_UNSYNC_LYRICS); lyricsBody = (FrameBodyUSLT) v24frame.getBody(); mp3File.save(); assertEquals("", lyricsBody.getDescription()); assertEquals(1, lyricsBody.getTextEncoding()); } public void testWriteULSTID3v23() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); MP3File mp3File = new MP3File(testFile); ID3v23Tag tag = new ID3v23Tag(); mp3File.setID3v2TagOnly(tag); //Create lyrics frame and modify FrameBodyUSLT lyricsBody = new FrameBodyUSLT(); lyricsBody.setLanguage(Languages.DEFAULT_ID); lyricsBody.setDescription("description"); lyricsBody.setLyric("lyric1"); ID3v23Frame v23frame = new ID3v23Frame(ID3v23Frames.FRAME_ID_V3_UNSYNC_LYRICS); v23frame.setBody(lyricsBody); tag.setFrame(v23frame); mp3File.save(); //Check normal values mp3File = new MP3File(testFile); v23frame = (ID3v23Frame) mp3File.getID3v2Tag().getFrame(ID3v23Frames.FRAME_ID_V3_UNSYNC_LYRICS); lyricsBody = (FrameBodyUSLT) v23frame.getBody(); assertEquals(Languages.DEFAULT_ID, lyricsBody.getLanguage()); assertEquals("description", lyricsBody.getDescription()); assertEquals("lyric1", lyricsBody.getLyric()); assertEquals(0, lyricsBody.getTextEncoding()); //Change to another ISO8859value lyricsBody.setLyric("lyric"); mp3File.save(); mp3File = new MP3File(testFile); v23frame = (ID3v23Frame) mp3File.getID3v2Tag().getFrame(ID3v23Frames.FRAME_ID_V3_UNSYNC_LYRICS); lyricsBody = (FrameBodyUSLT) v23frame.getBody(); assertEquals("lyric", lyricsBody.getLyric()); assertEquals(0, lyricsBody.getTextEncoding()); //Now force to UTF-16 lyricsBody.setLyric("lyric\u111F"); mp3File.save(); mp3File = new MP3File(testFile); v23frame = (ID3v23Frame) mp3File.getID3v2Tag().getFrame(ID3v23Frames.FRAME_ID_V3_UNSYNC_LYRICS); lyricsBody = (FrameBodyUSLT) v23frame.getBody(); assertEquals(Languages.DEFAULT_ID, lyricsBody.getLanguage()); assertEquals("description", lyricsBody.getDescription()); assertEquals("lyric\u111F", lyricsBody.getLyric()); assertEquals(1, lyricsBody.getTextEncoding()); //Now check UTf16 with empty description lyricsBody.setDescription(""); mp3File.save(); mp3File = new MP3File(testFile); v23frame = (ID3v23Frame) mp3File.getID3v2Tag().getFrame(ID3v23Frames.FRAME_ID_V3_UNSYNC_LYRICS); lyricsBody = (FrameBodyUSLT) v23frame.getBody(); mp3File.save(); assertEquals("", lyricsBody.getDescription()); assertEquals(1, lyricsBody.getTextEncoding()); } public void testWriteULSTID3v23Test2() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); MP3File mp3File = new MP3File(testFile); ID3v23Tag tag = new ID3v23Tag(); mp3File.setID3v2TagOnly(tag); //Create lyrics frame and modify FrameBodyUSLT lyricsBody = new FrameBodyUSLT(); lyricsBody.setLanguage(Languages.DEFAULT_ID); lyricsBody.setDescription(""); lyricsBody.setLyric("lyric1\u111f"); ID3v23Frame v23frame = new ID3v23Frame(ID3v23Frames.FRAME_ID_V3_UNSYNC_LYRICS); v23frame.setBody(lyricsBody); tag.setFrame(v23frame); mp3File.save(); //Check normal values mp3File = new MP3File(testFile); v23frame = (ID3v23Frame) mp3File.getID3v2Tag().getFrame(ID3v23Frames.FRAME_ID_V3_UNSYNC_LYRICS); lyricsBody = (FrameBodyUSLT) v23frame.getBody(); assertEquals(Languages.DEFAULT_ID, lyricsBody.getLanguage()); assertEquals("", lyricsBody.getDescription()); assertEquals("lyric1\u111f", lyricsBody.getLyric()); assertEquals(1, lyricsBody.getTextEncoding()); } /** * V23 tag created as v24 * * @throws Exception */ public void testWriteULSTID3v23Test3() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); MP3File mp3File = new MP3File(testFile); ID3v23Tag tag = new ID3v23Tag(); mp3File.setID3v2Tag(tag); //Create lyrics frame and modify FrameBodyUSLT lyricsBody = new FrameBodyUSLT(); lyricsBody.setLanguage(Languages.DEFAULT_ID); lyricsBody.setDescription(""); lyricsBody.setLyric("lyric1\u111f"); ID3v24Frame v24frame = new ID3v24Frame(ID3v24Frames.FRAME_ID_UNSYNC_LYRICS); v24frame.setBody(lyricsBody); tag.setFrame(v24frame); mp3File.save(); //Check normal values mp3File = new MP3File(testFile); ID3v23Frame v23frame = (ID3v23Frame) mp3File.getID3v2Tag().getFrame(ID3v23Frames.FRAME_ID_V3_UNSYNC_LYRICS); lyricsBody = (FrameBodyUSLT) v23frame.getBody(); assertEquals(Languages.DEFAULT_ID, lyricsBody.getLanguage()); assertEquals("", lyricsBody.getDescription()); assertEquals("lyric1\u111f", lyricsBody.getLyric()); assertEquals(1, lyricsBody.getTextEncoding()); } /** * V23 tag created as v24 * * @throws Exception */ public void testWriteULSTID3v23Test4() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); MP3File mp3File = new MP3File(testFile); ID3v23Tag tag = new ID3v23Tag(); mp3File.setID3v2Tag(tag); //Create lyrics frame and modify FrameBodyUSLT lyricsBody = new FrameBodyUSLT(); lyricsBody.setLanguage(Languages.DEFAULT_ID); lyricsBody.setDescription(""); lyricsBody.setLyric("lyric1"); ID3v24Frame v24frame = new ID3v24Frame(ID3v24Frames.FRAME_ID_UNSYNC_LYRICS); v24frame.setBody(lyricsBody); tag.setFrame(v24frame); mp3File.save(); //Check normal values mp3File = new MP3File(testFile); ID3v23Frame v23frame = (ID3v23Frame) mp3File.getID3v2Tag().getFrame(ID3v23Frames.FRAME_ID_V3_UNSYNC_LYRICS); lyricsBody = (FrameBodyUSLT) v23frame.getBody(); assertEquals(Languages.DEFAULT_ID, lyricsBody.getLanguage()); assertEquals("", lyricsBody.getDescription()); assertEquals("lyric1", lyricsBody.getLyric()); assertEquals(0, lyricsBody.getTextEncoding()); //Change Encoding lyricsBody.setTextEncoding((byte)1); mp3File.save(); mp3File = new MP3File(testFile); v23frame = (ID3v23Frame) mp3File.getID3v2Tag().getFrame(ID3v23Frames.FRAME_ID_V3_UNSYNC_LYRICS); assertEquals(1, lyricsBody.getTextEncoding()); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/id3/FrameTIT3Test.java0000644000175000017500000000145411331564261027047 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.tag.id3.framebody.FrameBodyTPE1; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; /** */ public class FrameTIT3Test extends AbstractTestCase { public void testID3Specific() throws Exception { Exception e=null; try { ID3v23Tag tag = new ID3v23Tag(); ID3v23Frame frame = new ID3v23Frame("TIT3"); frame.setBody(new FrameBodyTPE1(TextEncoding.ISO_8859_1,"testsubtitle")); tag.addFrame(frame); assertEquals("testsubtitle",tag.getFirst("TIT3")); } catch(Exception ex) { e=ex; ex.printStackTrace(); } assertNull(e); } }libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/id3/FrameTPE2Test.java0000644000175000017500000000155511331564261027040 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.tag.FieldKey; import org.jaudiotagger.tag.Tag; import org.jaudiotagger.tag.id3.framebody.FrameBodyTPE1; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; /** */ public class FrameTPE2Test extends AbstractTestCase { public void testID3Specific() throws Exception { Exception e=null; try { ID3v23Tag tag = new ID3v23Tag(); ID3v23Frame frame = new ID3v23Frame("TPE2"); frame.setBody(new FrameBodyTPE1(TextEncoding.ISO_8859_1,"testband")); tag.addFrame(frame); assertEquals("testband",tag.getFirst("TPE2")); } catch(Exception ex) { e=ex; ex.printStackTrace(); } assertNull(e); } }libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/id3/FrameTIT2Test.java0000644000175000017500000000262411331564261027046 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.tag.FieldKey; import org.jaudiotagger.tag.Tag; import org.jaudiotagger.tag.id3.framebody.FrameBodyTPE1; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; /** */ public class FrameTIT2Test extends AbstractTestCase { public void testGeneric() throws Exception { Exception e=null; try { Tag tag = new ID3v23Tag(); tag.addField(FieldKey.TITLE,"testtitle"); assertEquals("testtitle",tag.getFirst(FieldKey.TITLE)); assertEquals("testtitle",tag.getFirst("TIT2")); } catch(Exception ex) { e=ex; ex.printStackTrace(); } assertNull(e); } public void testID3Specific() throws Exception { Exception e=null; try { ID3v23Tag tag = new ID3v23Tag(); ID3v23Frame frame = new ID3v23Frame("TIT2"); frame.setBody(new FrameBodyTPE1(TextEncoding.ISO_8859_1,"testtitle")); tag.addFrame(frame); assertEquals("testtitle",tag.getFirst(FieldKey.TITLE)); assertEquals("testtitle",tag.getFirst("TIT2")); } catch(Exception ex) { e=ex; ex.printStackTrace(); } assertNull(e); } }libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/id3/FrameTPE3Test.java0000644000175000017500000000275211331564261027041 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.mp3.MP3File; import org.jaudiotagger.tag.FieldKey; import org.jaudiotagger.tag.Tag; import org.jaudiotagger.tag.id3.*; import org.jaudiotagger.tag.id3.framebody.FrameBodyTPE3; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; import java.io.File; /** */ public class FrameTPE3Test extends AbstractTestCase { public void testGeneric() throws Exception { Exception e=null; try { Tag tag = new ID3v23Tag(); tag.addField(FieldKey.CONDUCTOR,"testconductor"); assertEquals("testconductor",tag.getFirst(FieldKey.CONDUCTOR)); assertEquals("testconductor",tag.getFirst("TPE3")); } catch(Exception ex) { e=ex; ex.printStackTrace(); } assertNull(e); } public void testID3Specific() throws Exception { Exception e=null; try { ID3v23Tag tag = new ID3v23Tag(); ID3v23Frame frame = new ID3v23Frame("TPE3"); frame.setBody(new FrameBodyTPE3(TextEncoding.ISO_8859_1,"testconductor")); tag.addFrame(frame); assertEquals("testconductor",tag.getFirst(FieldKey.CONDUCTOR)); assertEquals("testconductor",tag.getFirst("TPE3")); } catch(Exception ex) { e=ex; ex.printStackTrace(); } assertNull(e); } }libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/id3/ID3v23TagTest.java0000644000175000017500000004003211470746136026721 0ustar drazzibdrazzib/* * Jaudiotagger Copyright (C)2004,2005 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can getFields a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.audio.mp3.MP3File; import org.jaudiotagger.tag.FieldKey; import org.jaudiotagger.tag.TagField; import org.jaudiotagger.tag.TagOptionSingleton; import org.jaudiotagger.tag.datatype.DataTypes; import org.jaudiotagger.tag.id3.framebody.*; import java.io.File; import java.util.List; /** * */ public class ID3v23TagTest extends TestCase { /** * Constructor * * @param arg0 */ public ID3v23TagTest(String arg0) { super(arg0); } /** * Command line entrance. * * @param args */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } ///////////////////////////////////////////////////////////////////////// // TestCase classes to override ///////////////////////////////////////////////////////////////////////// /** * */ protected void setUp() { TagOptionSingleton.getInstance().setToDefault(); } /** * */ protected void tearDown() { } /** * */ // protected void runTest() // { // } /** * Builds the Test Suite. * * @return the Test Suite. */ public static Test suite() { return new TestSuite(ID3v23TagTest.class); } ///////////////////////////////////////////////////////////////////////// // Tests ///////////////////////////////////////////////////////////////////////// public void testReadID3v1ID3v23Tag() { Exception exceptionCaught = null; File testFile = AbstractTestCase.copyAudioToTmp("testV1Cbr128ID3v1v2.mp3"); MP3File mp3File = null; try { mp3File = new MP3File(testFile); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); assertNotNull(mp3File.getID3v1Tag()); assertNotNull(mp3File.getID3v2Tag()); } public void testReadID3v23Tag() { Exception exceptionCaught = null; File testFile = AbstractTestCase.copyAudioToTmp("testV1Cbr128ID3v2.mp3"); MP3File mp3File = null; try { mp3File = new MP3File(testFile); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); assertNull(mp3File.getID3v1Tag()); assertNotNull(mp3File.getID3v2Tag()); } public void testReadPaddedID3v23Tag() { Exception exceptionCaught = null; File testFile = AbstractTestCase.copyAudioToTmp("testV1Cbr128ID3v2pad.mp3"); MP3File mp3File = null; try { mp3File = new MP3File(testFile); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertNull(mp3File.getID3v1Tag()); assertNotNull(mp3File.getID3v2Tag()); } public void testDeleteID3v23Tag() { Exception exceptionCaught = null; File testFile = AbstractTestCase.copyAudioToTmp("testV1Cbr128ID3v1v2.mp3"); MP3File mp3File = null; try { mp3File = new MP3File(testFile); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertNotNull(mp3File.getID3v1Tag()); assertNotNull(mp3File.getID3v2Tag()); mp3File.setID3v1Tag(null); mp3File.setID3v2Tag(null); try { mp3File.save(); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertNull(mp3File.getID3v1Tag()); assertNull(mp3File.getID3v2Tag()); } public void testCreateIDv23Tag() { ID3v23Tag v2Tag = new ID3v23Tag(); assertEquals((byte) 2, v2Tag.getRelease()); assertEquals((byte) 3, v2Tag.getMajorVersion()); assertEquals((byte) 0, v2Tag.getRevision()); } public void testCreateID3v23FromID3v11() { ID3v11Tag v11Tag = ID3v11TagTest.getInitialisedTag(); ID3v23Tag v2Tag = new ID3v23Tag(v11Tag); assertNotNull(v11Tag); assertNotNull(v2Tag); assertEquals(ID3v11TagTest.ARTIST, ((FrameBodyTPE1) ((ID3v23Frame) v2Tag.getFrame(ID3v23Frames.FRAME_ID_V3_ARTIST)).getBody()).getText()); assertEquals(ID3v11TagTest.ALBUM, ((FrameBodyTALB) ((ID3v23Frame) v2Tag.getFrame(ID3v23Frames.FRAME_ID_V3_ALBUM)).getBody()).getText()); assertEquals(ID3v11TagTest.COMMENT, ((FrameBodyCOMM) ((ID3v23Frame) v2Tag.getFrame(ID3v23Frames.FRAME_ID_V3_COMMENT)).getBody()).getText()); assertEquals(ID3v11TagTest.TITLE, ((FrameBodyTIT2) ((ID3v23Frame) v2Tag.getFrame(ID3v23Frames.FRAME_ID_V3_TITLE)).getBody()).getText()); assertEquals(ID3v11TagTest.TRACK_VALUE, String.valueOf(((FrameBodyTRCK) ((ID3v23Frame) v2Tag.getFrame(ID3v23Frames.FRAME_ID_V3_TRACK)).getBody()).getTrackNo())); assertTrue(((FrameBodyTCON) ((ID3v23Frame) v2Tag.getFrame(ID3v23Frames.FRAME_ID_V3_GENRE)).getBody()).getText().endsWith(ID3v11TagTest.GENRE_VAL)); assertEquals(ID3v11TagTest.YEAR, ((FrameBodyTYER) ((ID3v23Frame) v2Tag.getFrame(ID3v23Frames.FRAME_ID_V3_TYER)).getBody()).getText()); assertEquals((byte) 2, v2Tag.getRelease()); assertEquals((byte) 3, v2Tag.getMajorVersion()); assertEquals((byte) 0, v2Tag.getRevision()); } /** * Test converting a v24 tag to a v23 tag, the v24 tag contains: *

* A frame which is known in v24 and v23 * * @throws Exception */ public void testCreateID3v23FromID3v24knownInV3() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); MP3File mp3File = null; mp3File = new MP3File(testFile); //Add v24 tag to mp3 with single tdrl frame (which is only supported in v24) ID3v24Tag tag = new ID3v24Tag(); FrameBodyTIT2 framebodyTdrl = new FrameBodyTIT2(); framebodyTdrl.setText("title"); ID3v24Frame tdrlFrame = new ID3v24Frame("TIT2"); tdrlFrame.setBody(framebodyTdrl); tag.setFrame(tdrlFrame); mp3File.setID3v2Tag(tag); mp3File.save(); //Reread from File mp3File = new MP3File(testFile); //Convert to v23 ,frame converted and marked as unsupported ID3v23Tag v23tag = new ID3v23Tag(mp3File.getID3v2TagAsv24()); ID3v23Frame v23frame = (ID3v23Frame) v23tag.getFrame("TIT2"); assertNotNull(v23frame); assertTrue(v23frame.getBody() instanceof FrameBodyTIT2); //Save as v23 tag (side effect convert v23 to v24 tag as well) mp3File.setID3v2Tag(v23tag); mp3File.save(); //Reread from File mp3File = new MP3File(testFile); //Convert to v23 ,frame should still exist v23tag = (ID3v23Tag) mp3File.getID3v2Tag(); v23frame = (ID3v23Frame) v23tag.getFrame("TIT2"); assertNotNull(v23frame); assertTrue(v23frame.getBody() instanceof FrameBodyTIT2); //Save as v23 tag (side effect convert v23 to v24 tag as well) mp3File.setID3v2Tag(v23tag); mp3File.save(); //Check when converted to v24 has value been maintained assertEquals("title", ((FrameBodyTIT2) ((ID3v24Frame) mp3File.getID3v2TagAsv24().getFrame("TIT2")).getBody()).getText()); } /** * Test converting a v24 tag to a v23 tag, the v24 tag contains: *

* A frame which is known in v24 but not v23 * * @throws Exception */ public void testCreateID3v23FromID3v24UnknownInV3() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); MP3File mp3File = null; mp3File = new MP3File(testFile); //Add v24 tag to mp3 with single tdrl frame (which is only supported in v24) ID3v24Tag tag = new ID3v24Tag(); FrameBodyTDRL framebodyTdrl = new FrameBodyTDRL(); framebodyTdrl.setText("2008"); ID3v24Frame tdrlFrame = new ID3v24Frame("TDRL"); tdrlFrame.setBody(framebodyTdrl); tag.setFrame(tdrlFrame); mp3File.setID3v2Tag(tag); mp3File.save(); //Reread from File mp3File = new MP3File(testFile); //Convert to v23 ,frame converted and marked as unsupported ID3v23Tag v23tag = new ID3v23Tag(mp3File.getID3v2TagAsv24()); ID3v23Frame v23frame = (ID3v23Frame) v23tag.getFrame("TDRL"); assertNotNull(v23frame); assertTrue(v23frame.getBody() instanceof FrameBodyUnsupported); //Save as v23 tag (side effect convert v23 to v24 tag as well) mp3File.setID3v2Tag(v23tag); mp3File.save(); //Reread from File mp3File = new MP3File(testFile); //Convert to v23 ,frame should still exist v23tag = (ID3v23Tag) mp3File.getID3v2Tag(); v23frame = (ID3v23Frame) v23tag.getFrame("TDRL"); assertNotNull(v23frame); assertTrue(v23frame.getBody() instanceof FrameBodyUnsupported); //Save as v23 tag (side effect convert v23 to v24 tag as well) mp3File.setID3v2Tag(v23tag); mp3File.save(); //Check value maintained, can only see as bytes FrameBodyUnsupported v23FrameBody = (FrameBodyUnsupported) v23frame.getBody(); assertEquals((byte) '2', ((byte[]) v23FrameBody.getObjectValue(DataTypes.OBJ_DATA))[1]); assertEquals((byte) '0', ((byte[]) v23FrameBody.getObjectValue(DataTypes.OBJ_DATA))[2]); assertEquals((byte) '0', ((byte[]) v23FrameBody.getObjectValue(DataTypes.OBJ_DATA))[3]); assertEquals((byte) '8', ((byte[]) v23FrameBody.getObjectValue(DataTypes.OBJ_DATA))[4]); //Reread from File mp3File = new MP3File(testFile); v23tag = (ID3v23Tag) mp3File.getID3v2Tag(); v23frame = (ID3v23Frame) v23tag.getFrame("TDRL"); assertNotNull(v23frame); assertTrue(v23frame.getBody() instanceof FrameBodyUnsupported); //Check value maintained, can only see as bytes v23FrameBody = (FrameBodyUnsupported) v23frame.getBody(); assertEquals((byte) '2', ((byte[]) v23FrameBody.getObjectValue(DataTypes.OBJ_DATA))[1]); assertEquals((byte) '0', ((byte[]) v23FrameBody.getObjectValue(DataTypes.OBJ_DATA))[2]); assertEquals((byte) '0', ((byte[]) v23FrameBody.getObjectValue(DataTypes.OBJ_DATA))[3]); assertEquals((byte) '8', ((byte[]) v23FrameBody.getObjectValue(DataTypes.OBJ_DATA))[4]); //Convert V24 representation to V23, and then save this v23tag = new ID3v23Tag(mp3File.getID3v2TagAsv24()); mp3File.setID3v2TagOnly(v23tag); mp3File.setID3v2Tag(v23tag); mp3File.save(); //Reread from File mp3File = new MP3File(testFile); v23tag = (ID3v23Tag) mp3File.getID3v2Tag(); v23frame = (ID3v23Frame) v23tag.getFrame("TDRL"); assertNotNull(v23frame); assertTrue(v23frame.getBody() instanceof FrameBodyUnsupported); //Check value maintained, can only see as bytes v23FrameBody = (FrameBodyUnsupported) v23frame.getBody(); assertEquals((byte) '2', ((byte[]) v23FrameBody.getObjectValue(DataTypes.OBJ_DATA))[1]); assertEquals((byte) '0', ((byte[]) v23FrameBody.getObjectValue(DataTypes.OBJ_DATA))[2]); assertEquals((byte) '0', ((byte[]) v23FrameBody.getObjectValue(DataTypes.OBJ_DATA))[3]); assertEquals((byte) '8', ((byte[]) v23FrameBody.getObjectValue(DataTypes.OBJ_DATA))[4]); } /** * Test converting a v24 tag to a v23 tag, the v24 tag contains: * * A frame which is unknown in v24 and v23 * * @throws Exception */ /* public void testCreateID3v23FromID3v24UnknownInV3AndV4()throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); MP3File mp3File = null; mp3File = new MP3File(testFile); //Add v24 tag to mp3 with single user defined frame byte[] byteData = new byte[1]; byteData[0] = 'X'; ID3v24Tag tag = new ID3v24Tag(); FrameBodyUnsupported framebodyUnsupported = new FrameBodyUnsupported("FREW",byteData); ID3v24Frame frame = new ID3v24Frame(); frame.setBody(framebodyUnsupported); tag.setFrame(frame); mp3File.setID3v2Tag(tag); mp3File.save(); //Reread from File mp3File = new MP3File(testFile); //Convert to v23 ,frame converted and marked as unsupported ID3v23Tag v23tag = new ID3v23Tag(mp3File.getID3v2TagAsv24()); ID3v23Frame v23frame = (ID3v23Frame)v23tag.getFrame("FREW"); assertNotNull(v23frame); assertTrue(v23frame.getBody() instanceof FrameBodyUnsupported); //Save as v23 tag (side effect convert v23 to v24 tag as well) mp3File.setID3v2Tag(v23tag); mp3File.save(); //Reread from File mp3File = new MP3File(testFile); //Convert to v23 ,frame should still exist v23tag = (ID3v23Tag) mp3File.getID3v2Tag(); v23frame = (ID3v23Frame)v23tag.getFrame("FREW"); assertNotNull(v23frame); assertTrue(v23frame.getBody() instanceof FrameBodyUnsupported); //Save as v23 tag (side effect convert v23 to v24 tag as well) mp3File.setID3v2Tag(v23tag); mp3File.save(); //Check value maintained, can only see as bytes FrameBodyUnsupported v23FrameBody = (FrameBodyUnsupported)v23frame.getBody(); assertEquals((byte)'X',((byte[])v23FrameBody.getObjectValue(DataTypes.OBJ_DATA))[0]); } */ public void testDeleteFields() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); MP3File mp3File = new MP3File(testFile); ID3v23Tag v2Tag = new ID3v23Tag(); mp3File.setID3v2Tag(v2Tag); mp3File.save(); //Delete using generic key AudioFile f = AudioFileIO.read(testFile); List tagFields = f.getTag().getFields(FieldKey.ALBUM_ARTIST_SORT); assertEquals(0,tagFields.size()); f.getTag().addField(FieldKey.ALBUM_ARTIST_SORT,"artist1"); tagFields = f.getTag().getFields(FieldKey.ALBUM_ARTIST_SORT); assertEquals(1,tagFields.size()); f.getTag().deleteField(FieldKey.ALBUM_ARTIST_SORT); f.commit(); //Delete using flac id f = AudioFileIO.read(testFile); tagFields = f.getTag().getFields(FieldKey.ALBUM_ARTIST_SORT); assertEquals(0,tagFields.size()); f.getTag().addField(FieldKey.ALBUM_ARTIST_SORT,"artist1"); tagFields = f.getTag().getFields(FieldKey.ALBUM_ARTIST_SORT); assertEquals(1,tagFields.size()); f.getTag().deleteField("TSO2"); tagFields = f.getTag().getFields(FieldKey.ALBUM_ARTIST_SORT); assertEquals(0,tagFields.size()); f.commit(); f = AudioFileIO.read(testFile); tagFields = f.getTag().getFields(FieldKey.ALBUM_ARTIST_SORT); assertEquals(0,tagFields.size()); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/id3/FrameTCMPTest.java0000644000175000017500000001446211247705415027076 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.mp3.MP3File; import org.jaudiotagger.tag.id3.framebody.FrameBodyTCMP; import org.jaudiotagger.tag.id3.framebody.FrameBodyTCMPTest; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; import java.io.File; /** * Test TCMP Frame */ public class FrameTCMPTest extends AbstractTestCase { public static ID3v24Frame getInitialisedFrame() { ID3v24Frame frame = new ID3v24Frame(ID3v24Frames.FRAME_ID_IS_COMPILATION); FrameBodyTCMP fb = FrameBodyTCMPTest.getInitialisedBody(); frame.setBody(fb); return frame; } public void testCreateID3v24Frame() { Exception exceptionCaught = null; ID3v24Frame frame = null; FrameBodyTCMP fb = null; try { frame = new ID3v24Frame(ID3v24Frames.FRAME_ID_IS_COMPILATION); fb = FrameBodyTCMPTest.getInitialisedBody(); frame.setBody(fb); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v24Frames.FRAME_ID_IS_COMPILATION, frame.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, fb.getTextEncoding()); assertTrue(ID3v24Frames.getInstanceOf().isExtensionFrames(frame.getIdentifier())); assertFalse(ID3v24Frames.getInstanceOf().isSupportedFrames(frame.getIdentifier())); } public void testCreateID3v23Frame() { Exception exceptionCaught = null; ID3v23Frame frame = null; FrameBodyTCMP fb = null; try { frame = new ID3v23Frame(ID3v23Frames.FRAME_ID_V3_IS_COMPILATION); fb = FrameBodyTCMPTest.getInitialisedBody(); frame.setBody(fb); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v23Frames.FRAME_ID_V3_IS_COMPILATION, frame.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, fb.getTextEncoding()); assertTrue(ID3v23Frames.getInstanceOf().isExtensionFrames(frame.getIdentifier())); assertFalse(ID3v23Frames.getInstanceOf().isSupportedFrames(frame.getIdentifier())); } public void testCreateID3v22Frame() { Exception exceptionCaught = null; ID3v22Frame frame = null; FrameBodyTCMP fb = null; try { frame = new ID3v22Frame(ID3v22Frames.FRAME_ID_V2_IS_COMPILATION); fb = FrameBodyTCMPTest.getInitialisedBody(); frame.setBody(fb); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v22Frames.FRAME_ID_V2_IS_COMPILATION, frame.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, fb.getTextEncoding()); assertTrue(ID3v22Frames.getInstanceOf().isExtensionFrames(frame.getIdentifier())); assertFalse(ID3v22Frames.getInstanceOf().isSupportedFrames(frame.getIdentifier())); } public void testSaveToFile() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3",new File("test1000.mp3")); MP3File mp3File = new MP3File(testFile); //Create and Save ID3v24Tag tag = new ID3v24Tag(); tag.setFrame(FrameTCMPTest.getInitialisedFrame()); mp3File.setID3v2Tag(tag); mp3File.save(); //Reload mp3File = new MP3File(testFile); ID3v24Frame frame = (ID3v24Frame) mp3File.getID3v2Tag().getFrame(ID3v24Frames.FRAME_ID_IS_COMPILATION); FrameBodyTCMP body = (FrameBodyTCMP) frame.getBody(); assertEquals(TextEncoding.ISO_8859_1, body.getTextEncoding()); } public void testSaveEmptyFrameToFile() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3",new File("test1001.mp3")); MP3File mp3File = new MP3File(testFile); ID3v24Frame frame = new ID3v24Frame(ID3v24Frames.FRAME_ID_IS_COMPILATION); frame.setBody(new FrameBodyTCMP()); //Create and Save ID3v24Tag tag = new ID3v24Tag(); tag.setFrame(frame); mp3File.setID3v2Tag(tag); mp3File.save(); //Reload mp3File = new MP3File(testFile); frame = (ID3v24Frame) mp3File.getID3v2Tag().getFrame(ID3v24Frames.FRAME_ID_IS_COMPILATION); FrameBodyTCMP body = (FrameBodyTCMP) frame.getBody(); assertEquals(TextEncoding.ISO_8859_1, body.getTextEncoding()); } public void testConvertV24ToV23() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3",new File("test1002.mp3")); MP3File mp3File = new MP3File(testFile); //Create and Save ID3v24Tag tag = new ID3v24Tag(); tag.setFrame(FrameTCMPTest.getInitialisedFrame()); mp3File.setID3v2Tag(tag); mp3File.save(); //Reload and convert to v23 and save mp3File = new MP3File(testFile); mp3File.setID3v2TagOnly(new ID3v23Tag(mp3File.getID3v2TagAsv24())); mp3File.save(); //Reload mp3File = new MP3File(testFile); ID3v23Frame frame = (ID3v23Frame) mp3File.getID3v2Tag().getFrame(ID3v23Frames.FRAME_ID_V3_IS_COMPILATION); FrameBodyTCMP body = (FrameBodyTCMP) frame.getBody(); assertEquals(TextEncoding.ISO_8859_1, body.getTextEncoding()); } public void testConvertV22ToV24() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3",new File("test1003.mp3")); MP3File mp3File = new MP3File(testFile); //Create and Save ID3v22Tag tag = new ID3v22Tag(); ID3v22Frame id3v22frame = new ID3v22Frame(ID3v22Frames.FRAME_ID_V2_IS_COMPILATION); tag.setFrame(id3v22frame); mp3File.setID3v2TagOnly(tag); mp3File.save(); //Reload and convert to v23 and save mp3File = new MP3File(testFile); mp3File.setID3v2TagOnly(new ID3v24Tag(mp3File.getID3v2Tag())); mp3File.save(); //Reload mp3File = new MP3File(testFile); ID3v24Frame frame = (ID3v24Frame) mp3File.getID3v2Tag().getFrame(ID3v24Frames.FRAME_ID_IS_COMPILATION); FrameBodyTCMP body = (FrameBodyTCMP) frame.getBody(); assertEquals(TextEncoding.ISO_8859_1, body.getTextEncoding()); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/id3/ID3v22TagTest.java0000644000175000017500000002367411470746136026735 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.audio.mp3.MP3File; import org.jaudiotagger.tag.FieldKey; import org.jaudiotagger.tag.TagField; import org.jaudiotagger.tag.TagOptionSingleton; import org.jaudiotagger.tag.id3.framebody.*; import java.io.File; import java.util.List; /** * */ public class ID3v22TagTest extends TestCase { /** * Constructor * * @param arg0 */ public ID3v22TagTest(String arg0) { super(arg0); } /** * Command line entrance. * * @param args */ public static void main(String[] args) { junit.textui.TestRunner.run(ID3v22TagTest.suite()); } ///////////////////////////////////////////////////////////////////////// // TestCase classes to override ///////////////////////////////////////////////////////////////////////// /** * */ protected void setUp() { TagOptionSingleton.getInstance().setToDefault(); } /** * */ protected void tearDown() { } /** * */ // protected void runTest() // { // } /** * Builds the Test Suite. * * @return the Test Suite. */ public static Test suite() { return new TestSuite(ID3v22TagTest.class); } ///////////////////////////////////////////////////////////////////////// // Tests ///////////////////////////////////////////////////////////////////////// public void testCreateIDv22Tag() { ID3v22Tag v2Tag = new ID3v22Tag(); assertEquals((byte) 2, v2Tag.getRelease()); assertEquals((byte) 2, v2Tag.getMajorVersion()); assertEquals((byte) 0, v2Tag.getRevision()); } public void testCreateID3v22FromID3v11() { ID3v11Tag v11Tag = ID3v11TagTest.getInitialisedTag(); ID3v22Tag v2Tag = new ID3v22Tag(v11Tag); assertNotNull(v11Tag); assertNotNull(v2Tag); assertEquals(ID3v11TagTest.ARTIST, ((FrameBodyTPE1) ((ID3v22Frame) v2Tag.getFrame(ID3v22Frames.FRAME_ID_V2_ARTIST)).getBody()).getText()); assertEquals(ID3v11TagTest.ALBUM, ((FrameBodyTALB) ((ID3v22Frame) v2Tag.getFrame(ID3v22Frames.FRAME_ID_V2_ALBUM)).getBody()).getText()); assertEquals(ID3v11TagTest.COMMENT, ((FrameBodyCOMM) ((ID3v22Frame) v2Tag.getFrame(ID3v22Frames.FRAME_ID_V2_COMMENT)).getBody()).getText()); assertEquals(ID3v11TagTest.TITLE, ((FrameBodyTIT2) ((ID3v22Frame) v2Tag.getFrame(ID3v22Frames.FRAME_ID_V2_TITLE)).getBody()).getText()); assertEquals(ID3v11TagTest.TRACK_VALUE, String.valueOf(((FrameBodyTRCK) ((ID3v22Frame) v2Tag.getFrame(ID3v22Frames.FRAME_ID_V2_TRACK)).getBody()).getTrackNo())); assertTrue(((FrameBodyTCON) ((ID3v22Frame) v2Tag.getFrame(ID3v22Frames.FRAME_ID_V2_GENRE)).getBody()).getText().endsWith(ID3v11TagTest.GENRE_VAL)); //TODO:Note confusingly V22 YEAR Frame shave v2 identifier but use TDRC behind the scenes, is confusing assertEquals(ID3v11TagTest.YEAR, ((FrameBodyTDRC) ((ID3v22Frame) v2Tag.getFrame(ID3v22Frames.FRAME_ID_V2_TYER)).getBody()).getText()); assertEquals((byte) 2, v2Tag.getRelease()); assertEquals((byte) 2, v2Tag.getMajorVersion()); assertEquals((byte) 0, v2Tag.getRevision()); } public void testCreateIDv22TagAndSave() { Exception exception = null; try { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); MP3File mp3File = new MP3File(testFile); ID3v22Tag v2Tag = new ID3v22Tag(); v2Tag.setField(FieldKey.TITLE,"fred"); v2Tag.setField(FieldKey.ARTIST,"artist"); v2Tag.setField(FieldKey.ALBUM,"album"); assertEquals((byte) 2, v2Tag.getRelease()); assertEquals((byte) 2, v2Tag.getMajorVersion()); assertEquals((byte) 0, v2Tag.getRevision()); mp3File.setID3v2Tag(v2Tag); mp3File.save(); //Read using new Interface AudioFile v22File = AudioFileIO.read(testFile); assertEquals("fred", v22File.getTag().getFirst(FieldKey.TITLE)); assertEquals("artist", v22File.getTag().getFirst(FieldKey.ARTIST)); assertEquals("album", v22File.getTag().getFirst(FieldKey.ALBUM)); //Read using old Interface mp3File = new MP3File(testFile); v2Tag = (ID3v22Tag) mp3File.getID3v2Tag(); ID3v22Frame frame = (ID3v22Frame) v2Tag.getFrame(ID3v22Frames.FRAME_ID_V2_TITLE); assertEquals("fred", ((AbstractFrameBodyTextInfo) frame.getBody()).getText()); } catch (Exception e) { exception = e; } assertNull(exception); } public void testv22TagWithUnneccessaryTrailingNulls() { File orig = new File("testdata", "test24.mp3"); if (!orig.isFile()) { return; } Exception exception = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test24.mp3"); AudioFile af = AudioFileIO.read(testFile); MP3File m = (MP3File) af; //Read using new Interface getFirst method with key assertEquals("*Listen to images:*", "*"+af.getTag().getFirst(FieldKey.TITLE) + ":*"); assertEquals("Clean:", af.getTag().getFirst(FieldKey.ALBUM) + ":"); assertEquals("Cosmo Vitelli:", af.getTag().getFirst(FieldKey.ARTIST) + ":"); assertEquals("Electronica/Dance:", af.getTag().getFirst(FieldKey.GENRE) + ":"); assertEquals("2003:", af.getTag().getFirst(FieldKey.YEAR) + ":"); assertEquals("1:", af.getTag().getFirst(FieldKey.TRACK) + ":"); assertEquals("11:", af.getTag().getFirst(FieldKey.TRACK_TOTAL) + ":"); //Read using new Interface getFirst method with String assertEquals("Listen to images:", af.getTag().getFirst(ID3v22Frames.FRAME_ID_V2_TITLE) + ":"); assertEquals("Clean:", af.getTag().getFirst(ID3v22Frames.FRAME_ID_V2_ALBUM) + ":"); assertEquals("Cosmo Vitelli:", af.getTag().getFirst(ID3v22Frames.FRAME_ID_V2_ARTIST) + ":"); assertEquals("Electronica/Dance:", af.getTag().getFirst(ID3v22Frames.FRAME_ID_V2_GENRE) + ":"); assertEquals("2003:", af.getTag().getFirst(ID3v22Frames.FRAME_ID_V2_TYER) + ":"); assertEquals("1:", af.getTag().getFirst(ID3v22Frames.FRAME_ID_V2_TRACK) + ":"); //Read using new Interface getFirst methods for common fields assertEquals("Listen to images:", af.getTag().getFirst(FieldKey.TITLE) + ":"); assertEquals("Cosmo Vitelli:", af.getTag().getFirst(FieldKey.ARTIST) + ":"); assertEquals("Clean:", af.getTag().getFirst(FieldKey.ALBUM) + ":"); assertEquals("Electronica/Dance:", af.getTag().getFirst(FieldKey.GENRE) + ":"); assertEquals("2003:", af.getTag().getFirst(FieldKey.YEAR) + ":"); assertEquals("1:", af.getTag().getFirst(FieldKey.TRACK) + ":"); //Read using old Interface ID3v22Tag v2Tag = (ID3v22Tag) m.getID3v2Tag(); ID3v22Frame frame = (ID3v22Frame) v2Tag.getFrame(ID3v22Frames.FRAME_ID_V2_TITLE); assertEquals("Listen to images\0:", ((AbstractFrameBodyTextInfo) frame.getBody()).getText() + ":"); frame = (ID3v22Frame) v2Tag.getFrame(ID3v22Frames.FRAME_ID_V2_ARTIST); assertEquals("Cosmo Vitelli\0:", ((AbstractFrameBodyTextInfo) frame.getBody()).getText() + ":"); frame = (ID3v22Frame) v2Tag.getFrame(ID3v22Frames.FRAME_ID_V2_ALBUM); assertEquals("Clean\0:", ((AbstractFrameBodyTextInfo) frame.getBody()).getText() + ":"); frame = (ID3v22Frame) v2Tag.getFrame(ID3v22Frames.FRAME_ID_V2_GENRE); assertEquals("Electronica/Dance\0:", ((AbstractFrameBodyTextInfo) frame.getBody()).getText() + ":"); frame = (ID3v22Frame) v2Tag.getFrame(ID3v22Frames.FRAME_ID_V2_TYER); assertEquals("2003\0:", ((AbstractFrameBodyTextInfo) frame.getBody()).getText() + ":"); frame = (ID3v22Frame) v2Tag.getFrame(ID3v22Frames.FRAME_ID_V2_TRACK); assertEquals("1/11\0:", ((FrameBodyTRCK) frame.getBody()).getText() + ":"); } catch (Exception e) { e.printStackTrace(); exception = e; } assertNull(exception); } public void testDeleteFields() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); MP3File mp3File = new MP3File(testFile); ID3v22Tag v2Tag = new ID3v22Tag(); mp3File.setID3v2Tag(v2Tag); mp3File.save(); //Delete using generic key AudioFile f = AudioFileIO.read(testFile); List tagFields = f.getTag().getFields(FieldKey.ALBUM_ARTIST_SORT); assertEquals(0,tagFields.size()); f.getTag().addField(FieldKey.ALBUM_ARTIST_SORT,"artist1"); tagFields = f.getTag().getFields(FieldKey.ALBUM_ARTIST_SORT); assertEquals(1,tagFields.size()); f.getTag().deleteField(FieldKey.ALBUM_ARTIST_SORT); f.commit(); //Delete using flac id f = AudioFileIO.read(testFile); tagFields = f.getTag().getFields(FieldKey.ALBUM_ARTIST_SORT); assertEquals(0,tagFields.size()); f.getTag().addField(FieldKey.ALBUM_ARTIST_SORT,"artist1"); tagFields = f.getTag().getFields(FieldKey.ALBUM_ARTIST_SORT); assertEquals(1,tagFields.size()); f.getTag().deleteField("TS2"); tagFields = f.getTag().getFields(FieldKey.ALBUM_ARTIST_SORT); assertEquals(0,tagFields.size()); f.commit(); f = AudioFileIO.read(testFile); tagFields = f.getTag().getFields(FieldKey.ALBUM_ARTIST_SORT); assertEquals(0,tagFields.size()); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/id3/FrameRVADAndRVA2Test.java0000644000175000017500000002013111041064726030126 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.mp3.MP3File; import org.jaudiotagger.tag.datatype.DataTypes; import org.jaudiotagger.tag.id3.framebody.FrameBodyRVA2; import org.jaudiotagger.tag.id3.framebody.FrameBodyRVA2Test; import org.jaudiotagger.tag.id3.framebody.FrameBodyRVAD; import org.jaudiotagger.tag.id3.framebody.FrameBodyRVADTest; import java.io.File; /** * Test RVAD (v23) and RVA2 (V24) frames */ public class FrameRVADAndRVA2Test extends AbstractTestCase { public static String cmp(byte[] a, byte[] b) { if (a.length != b.length) { return "length of byte arrays differ (" + a.length + "!=" + b.length + ")"; } for (int i = 0; i < a.length; i++) { if (a[i] != b[i]) { return "byte arrays differ at offset " + i + " (" + a[i] + "!=" + b[i] + ")"; } } return null; } public static ID3v24Frame getInitialisedFrame() { ID3v24Frame frame = new ID3v24Frame(ID3v24Frames.FRAME_ID_RELATIVE_VOLUME_ADJUSTMENT2); FrameBodyRVA2 fb = FrameBodyRVA2Test.getInitialisedBody(); frame.setBody(fb); return frame; } public static ID3v23Frame getV23InitialisedFrame() { ID3v23Frame frame = new ID3v23Frame(ID3v23Frames.FRAME_ID_V3_RELATIVE_VOLUME_ADJUSTMENT); FrameBodyRVAD fb = FrameBodyRVADTest.getInitialisedBody(); frame.setBody(fb); return frame; } public static ID3v22Frame getV22InitialisedFrame() { ID3v22Frame frame = new ID3v22Frame(ID3v22Frames.FRAME_ID_V2_RELATIVE_VOLUME_ADJUSTMENT); FrameBodyRVAD fb = FrameBodyRVADTest.getInitialisedBody(); frame.setBody(fb); return frame; } public void testCreateID3v24Frame() { Exception exceptionCaught = null; ID3v24Frame frame = null; FrameBodyRVA2 fb = null; try { frame = new ID3v24Frame(ID3v24Frames.FRAME_ID_RELATIVE_VOLUME_ADJUSTMENT2); fb = FrameBodyRVA2Test.getInitialisedBody(); frame.setBody(fb); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v24Frames.FRAME_ID_RELATIVE_VOLUME_ADJUSTMENT2, frame.getIdentifier()); assertFalse(ID3v24Frames.getInstanceOf().isExtensionFrames(frame.getIdentifier())); assertTrue(ID3v24Frames.getInstanceOf().isSupportedFrames(frame.getIdentifier())); assertEquals(FrameBodyRVA2Test.TEST_BYTES, frame.getBody().getObjectValue(DataTypes.OBJ_DATA)); } public void testCreateID3v23Frame() { Exception exceptionCaught = null; ID3v23Frame frame = null; FrameBodyRVAD fb = null; try { frame = new ID3v23Frame(ID3v23Frames.FRAME_ID_V3_RELATIVE_VOLUME_ADJUSTMENT); fb = FrameBodyRVADTest.getInitialisedBody(); frame.setBody(fb); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v23Frames.FRAME_ID_V3_RELATIVE_VOLUME_ADJUSTMENT, frame.getIdentifier()); assertFalse(ID3v23Frames.getInstanceOf().isExtensionFrames(frame.getIdentifier())); assertTrue(ID3v23Frames.getInstanceOf().isSupportedFrames(frame.getIdentifier())); assertEquals(FrameBodyRVADTest.TEST_BYTES, frame.getBody().getObjectValue(DataTypes.OBJ_DATA)); } public void testCreateID3v22Frame() { Exception exceptionCaught = null; ID3v22Frame frame = null; FrameBodyRVAD fb = null; try { frame = new ID3v22Frame(ID3v22Frames.FRAME_ID_V2_RELATIVE_VOLUME_ADJUSTMENT); fb = FrameBodyRVADTest.getInitialisedBody(); frame.setBody(fb); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v22Frames.FRAME_ID_V2_RELATIVE_VOLUME_ADJUSTMENT, frame.getIdentifier()); assertFalse(ID3v22Frames.getInstanceOf().isExtensionFrames(frame.getIdentifier())); assertTrue(ID3v22Frames.getInstanceOf().isSupportedFrames(frame.getIdentifier())); assertEquals(FrameBodyRVADTest.TEST_BYTES, frame.getBody().getObjectValue(DataTypes.OBJ_DATA)); } public void testSaveToFile() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); MP3File mp3File = new MP3File(testFile); //Create and Save ID3v24Tag tag = new ID3v24Tag(); tag.setFrame(FrameRVADAndRVA2Test.getInitialisedFrame()); mp3File.setID3v2Tag(tag); mp3File.save(); //Reload mp3File = new MP3File(testFile); ID3v24Frame frame = (ID3v24Frame) mp3File.getID3v2Tag().getFrame(ID3v24Frames.FRAME_ID_RELATIVE_VOLUME_ADJUSTMENT2); assertTrue(frame != null); FrameBodyRVA2 body = (FrameBodyRVA2) frame.getBody(); assertTrue(body instanceof FrameBodyRVA2); assertTrue(cmp(FrameBodyRVA2Test.TEST_BYTES, (byte[]) body.getObjectValue(DataTypes.OBJ_DATA)) == null); } public void testConvertV24ToV23() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); MP3File mp3File = new MP3File(testFile); //Create and Save ID3v24Tag tag = new ID3v24Tag(); tag.setFrame(FrameRVADAndRVA2Test.getInitialisedFrame()); mp3File.setID3v2Tag(tag); mp3File.save(); //Reload and convert to v23 and save mp3File = new MP3File(testFile); mp3File.setID3v2TagOnly(new ID3v23Tag(mp3File.getID3v2TagAsv24())); mp3File.save(); //Reload mp3File = new MP3File(testFile); ID3v23Frame frame = (ID3v23Frame) mp3File.getID3v2Tag().getFrame(ID3v23Frames.FRAME_ID_V3_RELATIVE_VOLUME_ADJUSTMENT); assertTrue(frame != null); FrameBodyRVAD body = (FrameBodyRVAD) frame.getBody(); assertTrue(body instanceof FrameBodyRVAD); assertTrue(cmp(FrameBodyRVA2Test.TEST_BYTES, (byte[]) body.getObjectValue(DataTypes.OBJ_DATA)) == null); } public void testConvertV24ToV22() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); MP3File mp3File = new MP3File(testFile); //Create and Save ID3v24Tag tag = new ID3v24Tag(); tag.setFrame(FrameRVADAndRVA2Test.getInitialisedFrame()); mp3File.setID3v2Tag(tag); mp3File.save(); //Reload and convert to v22 and save mp3File = new MP3File(testFile); mp3File.setID3v2TagOnly(new ID3v22Tag(mp3File.getID3v2TagAsv24())); mp3File.save(); //Reload mp3File = new MP3File(testFile); ID3v22Frame frame = (ID3v22Frame) mp3File.getID3v2Tag().getFrame(ID3v22Frames.FRAME_ID_V2_RELATIVE_VOLUME_ADJUSTMENT); assertTrue(frame != null); FrameBodyRVAD body = (FrameBodyRVAD) frame.getBody(); assertTrue(body instanceof FrameBodyRVAD); } public void testConvertV22ToV24() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); MP3File mp3File = new MP3File(testFile); //Create and Save ID3v22Tag tag = new ID3v22Tag(); //..Notes (uses v22Frame but frame body will be the v23/24 version) tag.setFrame(getV22InitialisedFrame()); mp3File.setID3v2TagOnly((ID3v22Tag) tag); mp3File.save(); //Reload and convert from v22 to v24 and save mp3File = new MP3File(testFile); mp3File.setID3v2TagOnly(new ID3v24Tag(mp3File.getID3v2Tag())); mp3File.save(); //Reload mp3File = new MP3File(testFile); ID3v24Frame frame = (ID3v24Frame) mp3File.getID3v2Tag().getFrame(ID3v24Frames.FRAME_ID_RELATIVE_VOLUME_ADJUSTMENT2); assertTrue(frame != null); FrameBodyRVA2 body = (FrameBodyRVA2) frame.getBody(); assertTrue(body instanceof FrameBodyRVA2); assertTrue(cmp(FrameBodyRVADTest.TEST_BYTES, (byte[]) body.getObjectValue(DataTypes.OBJ_DATA)) == null); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/id3/ItunesTest.java0000644000175000017500000002014411470746136026624 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.mp3.MP3File; import org.jaudiotagger.tag.TagOptionSingleton; import org.jaudiotagger.tag.id3.framebody.FrameBodyAPIC; import org.jaudiotagger.tag.id3.framebody.FrameBodyCOMM; import org.jaudiotagger.tag.id3.framebody.FrameBodyTPE1; import java.io.File; import java.util.Iterator; import java.util.List; /** * Test Itunes problems */ public class ItunesTest extends AbstractTestCase { private static final int FRAME_SIZE = 2049; private static final int FRAME_SIZE2 = 765450; private static final int STRING_LENGTH_WITH_NULL = 12; private static final int STRING_LENGTH_WITHOUT_NULL = 11; private static final int TERMINATOR_LENGTH = 1; private static final String SECOND_VALUE = "test"; private static final String EMPTY_VALUE = ""; /** * */ protected void tearDown() { } /** * This tests that we work out that the frame is not unsynced and read the frame size as a normal integer * using an integral algorithm * * @throws Exception */ public void testv24TagWithNonSyncSafeFrame() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("Issue96-1.id3", "testV1.mp3"); MP3File mp3File = new MP3File(testFile); ID3v24Frame v24frame = (ID3v24Frame) mp3File.getID3v2Tag().getFrame(ID3v24Frames.FRAME_ID_ATTACHED_PICTURE); assertNotNull(v24frame); FrameBodyAPIC fb = (FrameBodyAPIC) v24frame.getBody(); assertEquals(FRAME_SIZE, fb.getSize()); } /** * This tests that we work out that the frame is not unsynced because its highest order bit size is set * and read the frame size as a normal integer using an integral algorithm * * @throws Exception */ public void testv24TagWithNonSyncSafeFrame2() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("Issue96-3.id3", "testV1.mp3"); MP3File mp3File = new MP3File(testFile); ID3v24Frame v24frame = (ID3v24Frame) mp3File.getID3v2Tag().getFrame(ID3v24Frames.FRAME_ID_ATTACHED_PICTURE); assertNotNull(v24frame); FrameBodyAPIC fb = (FrameBodyAPIC) v24frame.getBody(); assertEquals(FRAME_SIZE2, fb.getSize()); } /** * This tests that we work out that the frame is not unsynced because frame only matches to next frame identifier * when not unsynced ( it is the USLT frame that is bering tested in this case, we only get to APIC if read * USLT frame ok) * * @throws Exception */ public void testv24TagWithNonSyncSafeFrame3() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("Issue96-4.id3", "testV1.mp3"); MP3File mp3File = new MP3File(testFile); ID3v24Frame v24frame = (ID3v24Frame) mp3File.getID3v2Tag().getFrame(ID3v24Frames.FRAME_ID_ATTACHED_PICTURE); assertNotNull(v24frame); FrameBodyAPIC fb = (FrameBodyAPIC) v24frame.getBody(); } /** * This tests that we work out that the frame is unsynced and read the frame size correctly and convert to intger * this is what most (non-itunes applications do) * * @throws Exception */ public void testv24TagWithSyncSafeFrame() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("Issue96-2.id3", "testV1.mp3"); MP3File mp3File = new MP3File(testFile); ID3v24Frame v24frame = (ID3v24Frame) mp3File.getID3v2Tag().getFrame(ID3v24Frames.FRAME_ID_ATTACHED_PICTURE); assertNotNull(v24frame); FrameBodyAPIC fb = (FrameBodyAPIC) v24frame.getBody(); assertEquals(FRAME_SIZE, fb.getSize()); } /** * test can read string with spurious null at end, and can retrieve string without this if we want * to. Can then write to file without null if options set correctly, can add multiple values * * @throws Exception */ public void testCanIgnoreSpuriousNullCharacters() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("Issue92.id3", "testV1.mp3"); MP3File mp3File = new MP3File(testFile); ID3v24Frame v24frame = (ID3v24Frame) mp3File.getID3v2Tag().getFrame(ID3v24Frames.FRAME_ID_ARTIST); assertNotNull(v24frame); FrameBodyTPE1 fb = (FrameBodyTPE1) v24frame.getBody(); assertEquals(STRING_LENGTH_WITH_NULL, fb.getText().length()); assertEquals(STRING_LENGTH_WITHOUT_NULL, fb.getFirstTextValue().length()); //Null remains TagOptionSingleton.getInstance().setRemoveTrailingTerminatorOnWrite(false); mp3File.save(); mp3File = new MP3File(testFile); v24frame = (ID3v24Frame) mp3File.getID3v2Tag().getFrame(ID3v24Frames.FRAME_ID_ARTIST); fb = (FrameBodyTPE1) v24frame.getBody(); assertEquals(STRING_LENGTH_WITH_NULL, fb.getText().length()); assertEquals(STRING_LENGTH_WITHOUT_NULL, fb.getFirstTextValue().length()); //Null removed TagOptionSingleton.getInstance().setRemoveTrailingTerminatorOnWrite(true); mp3File.save(); mp3File = new MP3File(testFile); v24frame = (ID3v24Frame) mp3File.getID3v2Tag().getFrame(ID3v24Frames.FRAME_ID_ARTIST); fb = (FrameBodyTPE1) v24frame.getBody(); assertEquals(STRING_LENGTH_WITHOUT_NULL, fb.getText().length()); assertEquals(STRING_LENGTH_WITHOUT_NULL, fb.getFirstTextValue().length()); assertEquals(1, fb.getNumberOfValues()); //Adding additional values fb.addTextValue(SECOND_VALUE); assertEquals(2, fb.getNumberOfValues()); assertEquals(SECOND_VALUE, fb.getValueAtIndex(1)); mp3File.save(); mp3File = new MP3File(testFile); v24frame = (ID3v24Frame) mp3File.getID3v2Tag().getFrame(ID3v24Frames.FRAME_ID_ARTIST); fb = (FrameBodyTPE1) v24frame.getBody(); assertEquals(2, fb.getNumberOfValues()); assertEquals(STRING_LENGTH_WITHOUT_NULL + TERMINATOR_LENGTH + SECOND_VALUE.length(), fb.getText().length()); assertEquals(STRING_LENGTH_WITHOUT_NULL, fb.getFirstTextValue().length()); assertEquals(SECOND_VALUE, fb.getValueAtIndex(1)); } /** * Check can handle empty value when splitting strings into a list */ public void testCanReadEmptyString() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("Issue92-2.id3", "testV1.mp3"); MP3File mp3File = new MP3File(testFile); ID3v23Frame v23frame = (ID3v23Frame) mp3File.getID3v2Tag().getFrame(ID3v23Frames.FRAME_ID_V3_COMMENT); assertNotNull(v23frame); FrameBodyCOMM fb = (FrameBodyCOMM) v23frame.getBody(); assertEquals(EMPTY_VALUE, fb.getText()); } /** * Check skips over tag to read mp3 audio */ public void testCanFindStartOfMp3AudioWithinUTF16LETag() throws Exception { long START_OF_AUDIO_LOCATION = 2048; int FRAME_COUNT = 11; File testFile = AbstractTestCase.copyAudioToTmp("Issue104-1.id3", "testV1.mp3"); MP3File mp3File = new MP3File(testFile); //Should find mp3 in same location whether start search from start or after ID3tag assertEquals(START_OF_AUDIO_LOCATION, mp3File.getMP3AudioHeader().getMp3StartByte()); assertEquals(FRAME_COUNT, mp3File.getID3v2Tag().getFieldCountIncludingSubValues()); assertEquals(FRAME_COUNT, mp3File.getID3v2Tag().getFieldCount()); } /** * Because last frame is large it has to check that size is unsynced, because no padding * code have to be careful not to have buffer underflow exception * * @throws Exception */ public void testv24TagWithlargeSyncSafeFrameAndNoPadding() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("issue115.id3", "testV1.mp3"); MP3File mp3File = new MP3File(testFile); List apicFrames = (List) mp3File.getID3v2Tag().getFrame(ID3v24Frames.FRAME_ID_ATTACHED_PICTURE); ID3v24Frame v24frame = (ID3v24Frame) apicFrames.get(0); assertNotNull(v24frame); v24frame = (ID3v24Frame) apicFrames.get(1); assertNotNull(v24frame); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/id3/FrameTSOTTest.java0000644000175000017500000002622111247705415027120 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.mp3.MP3File; import org.jaudiotagger.tag.id3.framebody.FrameBodyTSOT; import org.jaudiotagger.tag.id3.framebody.FrameBodyTSOTTest; import org.jaudiotagger.tag.id3.framebody.FrameBodyXSOT; import org.jaudiotagger.tag.id3.framebody.FrameBodyXSOTTest; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; import java.io.File; /** * Test TSOT and XSOT (Title Sort) Frame */ public class FrameTSOTTest extends AbstractTestCase { public static ID3v24Frame getInitialisedFrame() { ID3v24Frame frame = new ID3v24Frame(ID3v24Frames.FRAME_ID_TITLE_SORT_ORDER); FrameBodyTSOT fb = FrameBodyTSOTTest.getInitialisedBody(); frame.setBody(fb); return frame; } public static ID3v23Frame getV23InitialisedFrame() { ID3v23Frame frame = new ID3v23Frame(ID3v23Frames.FRAME_ID_V3_TITLE_SORT_ORDER_MUSICBRAINZ); FrameBodyXSOT fb = FrameBodyXSOTTest.getInitialisedBody(); frame.setBody(fb); return frame; } public void testCreateID3v24Frame() { Exception exceptionCaught = null; ID3v24Frame frame = null; FrameBodyTSOT fb = null; try { frame = new ID3v24Frame(ID3v24Frames.FRAME_ID_TITLE_SORT_ORDER); fb = FrameBodyTSOTTest.getInitialisedBody(); frame.setBody(fb); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v24Frames.FRAME_ID_TITLE_SORT_ORDER, frame.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, fb.getTextEncoding()); assertFalse(ID3v24Frames.getInstanceOf().isExtensionFrames(frame.getIdentifier())); assertTrue(ID3v24Frames.getInstanceOf().isSupportedFrames(frame.getIdentifier())); assertEquals(FrameBodyTSOTTest.TITLE_SORT, fb.getText()); } public void testCreateID3v23ITunesFrame() { Exception exceptionCaught = null; ID3v23Frame frame = null; FrameBodyTSOT fb = null; try { frame = new ID3v23Frame(ID3v23Frames.FRAME_ID_V3_TITLE_SORT_ORDER_ITUNES); fb = FrameBodyTSOTTest.getInitialisedBody(); frame.setBody(fb); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v23Frames.FRAME_ID_V3_TITLE_SORT_ORDER_ITUNES, frame.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, fb.getTextEncoding()); assertTrue(ID3v23Frames.getInstanceOf().isExtensionFrames(frame.getIdentifier())); assertFalse(ID3v23Frames.getInstanceOf().isSupportedFrames(frame.getIdentifier())); assertEquals(FrameBodyTSOTTest.TITLE_SORT, fb.getText()); } public void testCreateID3v23MusicBrainzFrame() { Exception exceptionCaught = null; ID3v23Frame frame = null; FrameBodyXSOT fb = null; try { frame = new ID3v23Frame(ID3v23Frames.FRAME_ID_V3_TITLE_SORT_ORDER_MUSICBRAINZ); fb = FrameBodyXSOTTest.getInitialisedBody(); frame.setBody(fb); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v23Frames.FRAME_ID_V3_TITLE_SORT_ORDER_MUSICBRAINZ, frame.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, fb.getTextEncoding()); assertTrue(ID3v23Frames.getInstanceOf().isExtensionFrames(frame.getIdentifier())); assertFalse(ID3v23Frames.getInstanceOf().isSupportedFrames(frame.getIdentifier())); assertEquals(FrameBodyTSOTTest.TITLE_SORT, fb.getText()); } public void testCreateID3v22Frame() { Exception exceptionCaught = null; ID3v22Frame frame = null; FrameBodyTSOT fb = null; try { frame = new ID3v22Frame(ID3v22Frames.FRAME_ID_V2_TITLE_SORT_ORDER_ITUNES); fb = FrameBodyTSOTTest.getInitialisedBody(); frame.setBody(fb); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(ID3v22Frames.FRAME_ID_V2_TITLE_SORT_ORDER_ITUNES, frame.getIdentifier()); assertEquals(TextEncoding.ISO_8859_1, fb.getTextEncoding()); assertTrue(ID3v22Frames.getInstanceOf().isExtensionFrames(frame.getIdentifier())); assertFalse(ID3v22Frames.getInstanceOf().isSupportedFrames(frame.getIdentifier())); assertEquals(FrameBodyTSOTTest.TITLE_SORT, fb.getText()); } public void testSaveToFile() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3",new File("test1010.mp3")); MP3File mp3File = new MP3File(testFile); //Create and Save ID3v24Tag tag = new ID3v24Tag(); tag.setFrame(FrameTSOTTest.getInitialisedFrame()); mp3File.setID3v2Tag(tag); mp3File.save(); //Reload mp3File = new MP3File(testFile); ID3v24Frame frame = (ID3v24Frame) mp3File.getID3v2Tag().getFrame(ID3v24Frames.FRAME_ID_TITLE_SORT_ORDER); FrameBodyTSOT body = (FrameBodyTSOT) frame.getBody(); assertEquals(TextEncoding.ISO_8859_1, body.getTextEncoding()); } public void testSaveEmptyFrameToFile() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3",new File("test1011.mp3")); MP3File mp3File = new MP3File(testFile); ID3v24Frame frame = new ID3v24Frame(ID3v24Frames.FRAME_ID_TITLE_SORT_ORDER); frame.setBody(new FrameBodyTSOT()); //Create and Save ID3v24Tag tag = new ID3v24Tag(); tag.setFrame(frame); mp3File.setID3v2Tag(tag); mp3File.save(); //Reload mp3File = new MP3File(testFile); frame = (ID3v24Frame) mp3File.getID3v2Tag().getFrame(ID3v24Frames.FRAME_ID_TITLE_SORT_ORDER); FrameBodyTSOT body = (FrameBodyTSOT) frame.getBody(); assertEquals(TextEncoding.ISO_8859_1, body.getTextEncoding()); } public void testConvertV24ToV23() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3",new File("test1012.mp3")); MP3File mp3File = new MP3File(testFile); //Create and Save ID3v24Tag tag = new ID3v24Tag(); tag.setFrame(FrameTSOTTest.getInitialisedFrame()); mp3File.setID3v2Tag(tag); mp3File.save(); //Reload and convert to v23 and save mp3File = new MP3File(testFile); mp3File.setID3v2TagOnly(new ID3v23Tag(mp3File.getID3v2TagAsv24())); mp3File.save(); //Reload mp3File = new MP3File(testFile); ID3v23Frame frame = (ID3v23Frame) mp3File.getID3v2Tag().getFrame(ID3v23Frames.FRAME_ID_V3_TITLE_SORT_ORDER_ITUNES); FrameBodyTSOT body = (FrameBodyTSOT) frame.getBody(); assertEquals(TextEncoding.ISO_8859_1, body.getTextEncoding()); assertEquals(FrameBodyTSOTTest.TITLE_SORT, body.getText()); } public void testConvertV24ToV22() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3",new File("test1013.mp3")); MP3File mp3File = new MP3File(testFile); //Create and Save ID3v24Tag tag = new ID3v24Tag(); tag.setFrame(FrameTSOTTest.getInitialisedFrame()); mp3File.setID3v2Tag(tag); mp3File.save(); //Reload and convert to v22 and save mp3File = new MP3File(testFile); mp3File.setID3v2TagOnly(new ID3v22Tag(mp3File.getID3v2TagAsv24())); mp3File.save(); //Reload mp3File = new MP3File(testFile); ID3v22Frame frame = (ID3v22Frame) mp3File.getID3v2Tag().getFrame(ID3v22Frames.FRAME_ID_V2_TITLE_SORT_ORDER_ITUNES); FrameBodyTSOT body = (FrameBodyTSOT) frame.getBody(); assertEquals(TextEncoding.ISO_8859_1, body.getTextEncoding()); assertEquals(FrameBodyTSOTTest.TITLE_SORT, body.getText()); } public void testConvertV23ITunesToV22() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3",new File("test1014.mp3")); MP3File mp3File = new MP3File(testFile); //Create and Save ID3v23Tag tag = new ID3v23Tag(); tag.setFrame(FrameTSOTTest.getInitialisedFrame()); mp3File.setID3v2TagOnly((ID3v23Tag) tag); mp3File.save(); //Reload and convert from v23 to v22 and save mp3File = new MP3File(testFile); mp3File.setID3v2TagOnly(new ID3v22Tag(mp3File.getID3v2Tag())); mp3File.save(); //Reload mp3File = new MP3File(testFile); ID3v22Frame frame = (ID3v22Frame) mp3File.getID3v2Tag().getFrame(ID3v22Frames.FRAME_ID_V2_TITLE_SORT_ORDER_ITUNES); FrameBodyTSOT body = (FrameBodyTSOT) frame.getBody(); assertEquals(TextEncoding.ISO_8859_1, body.getTextEncoding()); assertEquals(FrameBodyTSOTTest.TITLE_SORT, body.getText()); } public void testConvertV23MusicBrainzToV22() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3", new File("test1015.mp3")); MP3File mp3File = new MP3File(testFile); //Create and Save ID3v23Tag tag = new ID3v23Tag(); tag.setFrame(FrameTSOTTest.getV23InitialisedFrame()); mp3File.setID3v2TagOnly((ID3v23Tag) tag); mp3File.save(); //Reload and convert from v23 to v22 and save mp3File = new MP3File(testFile); mp3File.setID3v2TagOnly(new ID3v22Tag(mp3File.getID3v2Tag())); mp3File.save(); //Reload will be converted to same TST version for v22 mp3File = new MP3File(testFile); ID3v22Frame frame = (ID3v22Frame) mp3File.getID3v2Tag().getFrame(ID3v22Frames.FRAME_ID_V2_TITLE_SORT_ORDER_ITUNES); FrameBodyTSOT body = (FrameBodyTSOT) frame.getBody(); assertEquals(TextEncoding.ISO_8859_1, body.getTextEncoding()); assertEquals(FrameBodyTSOTTest.TITLE_SORT, body.getText()); } public void testConvertV22ToV24() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3",new File("test1016.mp3")); MP3File mp3File = new MP3File(testFile); //Create and Save ID3v22Tag tag = new ID3v22Tag(); //..Notes (uses v22Frame but frame body will be the v23/24 version) ID3v22Frame id3v22frame = new ID3v22Frame(ID3v22Frames.FRAME_ID_V2_TITLE_SORT_ORDER_ITUNES); ((FrameBodyTSOT) id3v22frame.getBody()).setText(FrameBodyTSOTTest.TITLE_SORT); tag.setFrame(id3v22frame); mp3File.setID3v2TagOnly((ID3v22Tag) tag); mp3File.save(); //Reload and convert from v22 to v24 and save mp3File = new MP3File(testFile); mp3File.setID3v2TagOnly(new ID3v24Tag(mp3File.getID3v2Tag())); mp3File.save(); //Reload mp3File = new MP3File(testFile); ID3v24Frame frame = (ID3v24Frame) mp3File.getID3v2Tag().getFrame(ID3v24Frames.FRAME_ID_TITLE_SORT_ORDER); FrameBodyTSOT body = (FrameBodyTSOT) frame.getBody(); assertEquals(TextEncoding.ISO_8859_1, body.getTextEncoding()); assertEquals(FrameBodyTSOTTest.TITLE_SORT, body.getText()); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/mp4/0000755000175000017500000000000011556363200023662 5ustar drazzibdrazziblibjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/mp4/M4aReadDrmTagTest.java0000644000175000017500000000613311277014227027706 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.mp4; import junit.framework.TestCase; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.audio.mp4.EncoderType; import org.jaudiotagger.audio.mp4.Mp4AudioHeader; import org.jaudiotagger.audio.mp4.atom.Mp4EsdsBox; import org.jaudiotagger.tag.FieldKey; import org.jaudiotagger.tag.Tag; import java.io.File; import java.util.List; /** */ public class M4aReadDrmTagTest extends TestCase { /** * Test to read all metadata from an Apple iTunes encoded mp4 file, note also uses fixed genre rather than * custom genre */ public void testReadFile() { Exception exceptionCaught = null; try { File orig = new File("testdata", "test9.m4p"); if (!orig.isFile()) { return; } File testFile = AbstractTestCase.copyAudioToTmp("test9.m4p"); AudioFile f = AudioFileIO.read(testFile); Tag tag = f.getTag(); System.out.println(f.getAudioHeader()); System.out.println(tag); //AudioInfo //Time in seconds assertEquals(329, f.getAudioHeader().getTrackLength()); assertEquals(44100, f.getAudioHeader().getSampleRateAsNumber()); assertEquals(new String("2"), f.getAudioHeader().getChannels()); assertEquals(128, f.getAudioHeader().getBitRateAsNumber()); assertEquals(EncoderType.DRM_AAC.getDescription(), f.getAudioHeader().getEncodingType()); //MPEG Specific Mp4AudioHeader audioheader = (Mp4AudioHeader) f.getAudioHeader(); assertEquals(Mp4EsdsBox.Kind.MPEG4_AUDIO, audioheader.getKind()); assertEquals(Mp4EsdsBox.AudioProfile.LOW_COMPLEXITY, audioheader.getProfile()); //Ease of use methods for common fields assertEquals("The King Of The Slums", tag.getFirst(FieldKey.ARTIST)); assertEquals("Barbarous English Fayre", tag.getFirst(FieldKey.ALBUM)); assertEquals("Simpering Blonde Bombshell", tag.getFirst(FieldKey.TITLE)); assertEquals("1990-01-01T08:00:00Z", tag.getFirst(FieldKey.YEAR)); assertEquals("1", tag.getFirst(FieldKey.TRACK)); assertEquals("12", tag.getFirst(FieldKey.TRACK_TOTAL)); assertEquals("Rock", tag.getFirst(FieldKey.GENRE)); //Cast to format specific tag Mp4Tag mp4tag = (Mp4Tag) tag; //Lookup by mp4 key assertEquals("The King Of The Slums", mp4tag.getFirst(Mp4FieldKey.ARTIST)); assertEquals("Barbarous English Fayre", mp4tag.getFirst(Mp4FieldKey.ALBUM)); assertEquals("Simpering Blonde Bombshell", mp4tag.getFirst(Mp4FieldKey.TITLE)); List coverart = mp4tag.get(Mp4FieldKey.ARTWORK); //Should be one image assertEquals(1, coverart.size()); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/mp4/M4aWriteDataBeforeMoovTagTest.java0000644000175000017500000003340711276777123032256 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.mp4; import junit.framework.TestCase; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.audio.mp4.Mp4AtomTree; import org.jaudiotagger.tag.FieldKey; import org.jaudiotagger.tag.Tag; import java.io.File; import java.io.RandomAccessFile; /** * Write tags for a file which contains MDAT before MOOV, (not normal case) */ public class M4aWriteDataBeforeMoovTagTest extends TestCase { /** * Test to write file that has MDAT at start BEFORE MOOV atom, this is what Facc 1.25 does *

*/ public void testWriteFileOption1SameSize() { Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test15.m4a", new File("testWriteWhenMDatAtStart1.m4a")); //First lets just createField tree Mp4AtomTree atomTree = new Mp4AtomTree(new RandomAccessFile(testFile, "r")); atomTree.printAtomTree(); //Now we try to make some changes AudioFile f = AudioFileIO.read(testFile); Tag tag = f.getTag(); System.out.println(tag); //Change values and Save changes and reread from disk tag.setField(FieldKey.ARTIST,"AUTHOR"); f.commit(); f = AudioFileIO.read(testFile); tag = f.getTag(); System.out.println(tag); //See tree again atomTree = new Mp4AtomTree(new RandomAccessFile(testFile, "r")); atomTree.printAtomTree(); //Ease of use methods for common fields assertEquals("AUTHOR", tag.getFirst(FieldKey.ARTIST)); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * Test to write file that has MDAT at start BEFORE MOOV atom, this is what Facc 1.25 does *

*/ public void testWriteFileOption3SmallerSizeCreateFree() { Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test15.m4a", new File("testWriteWhenMDatAtStart2.m4a")); //First lets just createField tree Mp4AtomTree atomTree = new Mp4AtomTree(new RandomAccessFile(testFile, "r")); atomTree.printAtomTree(); //Now we try to make some changes AudioFile f = AudioFileIO.read(testFile); Tag tag = f.getTag(); System.out.println(tag); //Change values and Save changes and reread from disk tag.setField(FieldKey.ARTIST,"AR"); tag.setField(FieldKey.ALBUM,"AL"); tag.setField(FieldKey.TITLE,"T"); f.commit(); f = AudioFileIO.read(testFile); tag = f.getTag(); System.out.println(tag); //See tree again atomTree = new Mp4AtomTree(new RandomAccessFile(testFile, "r")); atomTree.printAtomTree(); //Ease of use methods for common fields assertEquals("AR", tag.getFirst(FieldKey.ARTIST)); assertEquals("AL", tag.getFirst(FieldKey.ALBUM)); assertEquals("T", tag.getFirst(FieldKey.TITLE)); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * Test to write file that has MDAT at start BEFORE MOOV atom, this is what Facc 1.25 does *

*/ public void testWriteFileOption4SmallerSizeNoFree() { Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test15.m4a", new File("testWriteWhenMDatAtStart3.m4a")); //First lets just createField tree Mp4AtomTree atomTree = new Mp4AtomTree(new RandomAccessFile(testFile, "r")); atomTree.printAtomTree(); //Now we try to make some changes AudioFile f = AudioFileIO.read(testFile); Tag tag = f.getTag(); System.out.println(tag); //Change values and Save changes and reread from disk tag.setField(FieldKey.ARTIST,"AR"); f.commit(); f = AudioFileIO.read(testFile); tag = f.getTag(); System.out.println(tag); //See tree again atomTree = new Mp4AtomTree(new RandomAccessFile(testFile, "r")); atomTree.printAtomTree(); //Ease of use methods for common fields assertEquals("AR", tag.getFirst(FieldKey.ARTIST)); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * Test to write all fields to check all can be written, just use simple file as starting point *

* TODO:Test incomplete */ public void testWriteFileOption8CannoutUseTopLevelFree() { Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test15.m4a", new File("testWriteWhenMDatAtStart8.m4a")); AudioFile f = AudioFileIO.read(testFile); Tag tag = f.getTag(); //Change values tag.setField(FieldKey.ARTIST,"VERYLONGARTISTNAME"); tag.setField(FieldKey.ALBUM,"VERYLONGALBUMTNAME"); tag.setField(tag.createField(FieldKey.ALBUM_ARTIST, "A1")); tag.setField(tag.createField(FieldKey.ALBUM_ARTIST_SORT, "A2")); tag.setField(tag.createField(FieldKey.ALBUM_SORT, "A3")); tag.setField(tag.createField(FieldKey.AMAZON_ID, "A4")); tag.setField(tag.createField(FieldKey.ARTIST_SORT, "A5")); tag.setField(tag.createField(FieldKey.BPM, "200")); tag.setField(tag.createField(FieldKey.COMMENT, "C1")); tag.setField(tag.createField(FieldKey.COMPOSER, "C2")); tag.setField(tag.createField(FieldKey.COMPOSER_SORT, "C3")); tag.setField(tag.createField(FieldKey.DISC_NO, "1")); tag.setField(tag.createField(FieldKey.MUSICBRAINZ_ARTISTID, "1")); tag.setField(tag.createField(FieldKey.MUSICBRAINZ_RELEASEID, "2")); tag.setField(tag.createField(FieldKey.MUSICBRAINZ_TRACK_ID, "3")); tag.setField(tag.createField(FieldKey.MUSICBRAINZ_DISC_ID, "4")); tag.setField(tag.createField(FieldKey.MUSICBRAINZ_RELEASE_COUNTRY, "5")); tag.setField(tag.createField(FieldKey.MUSICBRAINZ_RELEASE_STATUS, "6")); tag.setField(tag.createField(FieldKey.MUSICBRAINZ_RELEASE_TYPE, "7")); tag.setField(tag.createField(FieldKey.MUSICBRAINZ_RELEASEARTISTID, "8")); tag.setField(tag.createField(FieldKey.MUSICIP_ID, "9")); tag.setField(tag.createField(FieldKey.GENRE, "2")); //key for classic rock tag.setField(tag.createField(FieldKey.ENCODER, "encoder")); //Save changes and reread from disk f.commit(); f = AudioFileIO.read(testFile); tag = f.getTag(); System.out.println(f.getAudioHeader()); System.out.println(tag); //AudioInfo //Time in seconds assertEquals(30, f.getAudioHeader().getTrackLength()); assertEquals(44100, f.getAudioHeader().getSampleRateAsNumber()); //Stereo thing doesnt work //assertEquals(new String("2"),f.getAudioHeader().getChannels()); //Ease of use methods for common fields assertEquals("VERYLONGARTISTNAME", tag.getFirst(FieldKey.ARTIST)); assertEquals("VERYLONGALBUMTNAME", tag.getFirst(FieldKey.ALBUM)); assertEquals("A1", tag.getFirst(FieldKey.ALBUM_ARTIST)); assertEquals("A2", tag.getFirst(FieldKey.ALBUM_ARTIST_SORT)); assertEquals("A3", tag.getFirst(FieldKey.ALBUM_SORT)); assertEquals("A4", tag.getFirst(FieldKey.AMAZON_ID)); assertEquals("A5", tag.getFirst(FieldKey.ARTIST_SORT)); assertEquals("200", tag.getFirst(FieldKey.BPM)); assertEquals("C1", tag.getFirst(FieldKey.COMMENT)); assertEquals("C2", tag.getFirst(FieldKey.COMPOSER)); assertEquals("C3", tag.getFirst(FieldKey.COMPOSER_SORT)); assertEquals("1", tag.getFirst(FieldKey.DISC_NO)); assertEquals("1", tag.getFirst(FieldKey.MUSICBRAINZ_ARTISTID)); assertEquals("2", tag.getFirst(FieldKey.MUSICBRAINZ_RELEASEID)); assertEquals("3", tag.getFirst(FieldKey.MUSICBRAINZ_TRACK_ID)); assertEquals("4", tag.getFirst(FieldKey.MUSICBRAINZ_DISC_ID)); assertEquals("5", tag.getFirst(FieldKey.MUSICBRAINZ_RELEASE_COUNTRY)); assertEquals("6", tag.getFirst(FieldKey.MUSICBRAINZ_RELEASE_STATUS)); assertEquals("7", tag.getFirst(FieldKey.MUSICBRAINZ_RELEASE_TYPE)); assertEquals("8", tag.getFirst(FieldKey.MUSICBRAINZ_RELEASEARTISTID)); assertEquals("9", tag.getFirst(FieldKey.MUSICIP_ID)); assertEquals("Classic Rock", tag.getFirst(FieldKey.GENRE)); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * Test to write file that has MDAT at start BEFORE MOOV atom, this is what Facc 1.25 does *

*/ public void testWriteFileOption9CannoutUseTopLevelFree() { Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test19.m4a", new File("testWriteWhenMDatAtStart9.m4a")); AudioFile f = AudioFileIO.read(testFile); Tag tag = f.getTag(); //Change values tag.setField(FieldKey.ARTIST,"VERYLONGARTISTNAME"); tag.setField(FieldKey.ALBUM,"VERYLONGALBUMTNAME"); tag.setField(tag.createField(FieldKey.ALBUM_ARTIST, "A1")); tag.setField(tag.createField(FieldKey.ALBUM_ARTIST_SORT, "A2")); tag.setField(tag.createField(FieldKey.ALBUM_SORT, "A3")); tag.setField(tag.createField(FieldKey.AMAZON_ID, "A4")); tag.setField(tag.createField(FieldKey.ARTIST_SORT, "A5")); tag.setField(tag.createField(FieldKey.BPM, "200")); tag.setField(tag.createField(FieldKey.COMMENT, "C1")); tag.setField(tag.createField(FieldKey.COMPOSER, "C2")); tag.setField(tag.createField(FieldKey.COMPOSER_SORT, "C3")); tag.setField(tag.createField(FieldKey.DISC_NO, "1")); tag.setField(tag.createField(FieldKey.MUSICBRAINZ_ARTISTID, "1")); tag.setField(tag.createField(FieldKey.MUSICBRAINZ_RELEASEID, "2")); tag.setField(tag.createField(FieldKey.MUSICBRAINZ_TRACK_ID, "3")); tag.setField(tag.createField(FieldKey.MUSICBRAINZ_DISC_ID, "4")); tag.setField(tag.createField(FieldKey.MUSICBRAINZ_RELEASE_COUNTRY, "5")); tag.setField(tag.createField(FieldKey.MUSICBRAINZ_RELEASE_STATUS, "6")); tag.setField(tag.createField(FieldKey.MUSICBRAINZ_RELEASE_TYPE, "7")); tag.setField(tag.createField(FieldKey.MUSICBRAINZ_RELEASEARTISTID, "8")); tag.setField(tag.createField(FieldKey.MUSICIP_ID, "9")); tag.setField(tag.createField(FieldKey.GENRE, "2")); //key for classic rock tag.setField(tag.createField(FieldKey.ENCODER, "encoder")); //Save changes and reread from disk f.commit(); f = AudioFileIO.read(testFile); tag = f.getTag(); System.out.println(f.getAudioHeader()); System.out.println(tag); //AudioInfo //Time in seconds assertEquals(30, f.getAudioHeader().getTrackLength()); assertEquals(44100, f.getAudioHeader().getSampleRateAsNumber()); //Stereo thing doesnt work //assertEquals(new String("2"),f.getAudioHeader().getChannels()); //Ease of use methods for common fields assertEquals("VERYLONGARTISTNAME", tag.getFirst(FieldKey.ARTIST)); assertEquals("VERYLONGALBUMTNAME", tag.getFirst(FieldKey.ALBUM)); assertEquals("A1", tag.getFirst(FieldKey.ALBUM_ARTIST)); assertEquals("A2", tag.getFirst(FieldKey.ALBUM_ARTIST_SORT)); assertEquals("A3", tag.getFirst(FieldKey.ALBUM_SORT)); assertEquals("A4", tag.getFirst(FieldKey.AMAZON_ID)); assertEquals("A5", tag.getFirst(FieldKey.ARTIST_SORT)); assertEquals("200", tag.getFirst(FieldKey.BPM)); assertEquals("C1", tag.getFirst(FieldKey.COMMENT)); assertEquals("C2", tag.getFirst(FieldKey.COMPOSER)); assertEquals("C3", tag.getFirst(FieldKey.COMPOSER_SORT)); assertEquals("1", tag.getFirst(FieldKey.DISC_NO)); assertEquals("1", tag.getFirst(FieldKey.MUSICBRAINZ_ARTISTID)); assertEquals("2", tag.getFirst(FieldKey.MUSICBRAINZ_RELEASEID)); assertEquals("3", tag.getFirst(FieldKey.MUSICBRAINZ_TRACK_ID)); assertEquals("4", tag.getFirst(FieldKey.MUSICBRAINZ_DISC_ID)); assertEquals("5", tag.getFirst(FieldKey.MUSICBRAINZ_RELEASE_COUNTRY)); assertEquals("6", tag.getFirst(FieldKey.MUSICBRAINZ_RELEASE_STATUS)); assertEquals("7", tag.getFirst(FieldKey.MUSICBRAINZ_RELEASE_TYPE)); assertEquals("8", tag.getFirst(FieldKey.MUSICBRAINZ_RELEASEARTISTID)); assertEquals("9", tag.getFirst(FieldKey.MUSICIP_ID)); assertEquals("Classic Rock", tag.getFirst(FieldKey.GENRE)); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/mp4/M4aWriteTagTest.java0000644000175000017500000037744711470746136027513 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.mp4; import junit.framework.TestCase; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.audio.mp3.MP3File; import org.jaudiotagger.tag.FieldKey; import org.jaudiotagger.tag.Tag; import org.jaudiotagger.tag.TagField; import org.jaudiotagger.tag.id3.ID3v23Tag; import org.jaudiotagger.tag.mp4.atom.Mp4ContentTypeValue; import org.jaudiotagger.tag.mp4.atom.Mp4RatingValue; import org.jaudiotagger.tag.mp4.field.*; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; import java.util.List; /** */ public class M4aWriteTagTest extends TestCase { private static int TEST_FILE1_SIZE = 3883555; private static int TEST_FILE2_SIZE = 3882440; private static int TEST_FILE5_SIZE = 119472; /** * Test to write tagt data, new tagdata identical size to existing data */ public void testWriteFileSameSize() { Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test.m4a", new File("testWriteFileSameSize.m4a")); AudioFile f = AudioFileIO.read(testFile); Tag tag = f.getTag(); //Change values to different value (but same no of characters, this is the easiest mod to make tag.setField(FieldKey.ARTIST,"AUTHOR"); tag.setField(FieldKey.ALBUM,"ALBUM"); //tag.setField(FieldKey.TRACK,"2"); tag.setField(tag.createField(FieldKey.TRACK, "2")); tag.setField(tag.createField(FieldKey.TRACK_TOTAL, "12")); assertEquals("2",tag.getFirst(FieldKey.TRACK)); //tag.setField(tag.createField(FieldKey.DISC_NO,"4/15")); tag.setField(new Mp4DiscNoField(4, 15)); tag.setField(tag.createField(FieldKey.MUSICBRAINZ_TRACK_ID, "e785f700-c1aa-4943-bcee-87dd316a2c31")); tag.setField(tag.createField(FieldKey.BPM, "300")); //Save changes and reread from disk f.commit(); f = AudioFileIO.read(testFile); tag = f.getTag(); //Total FileSize should not have changed assertEquals(TEST_FILE1_SIZE, testFile.length()); //AudioInfo //Time in seconds assertEquals(241, f.getAudioHeader().getTrackLength()); assertEquals(44100, f.getAudioHeader().getSampleRateAsNumber()); //Ease of use methods for common fields assertEquals("AUTHOR", tag.getFirst(FieldKey.ARTIST)); assertEquals("ALBUM", tag.getFirst(FieldKey.ALBUM)); assertEquals("title", tag.getFirst(FieldKey.TITLE)); assertEquals("comments", tag.getFirst(FieldKey.COMMENT)); assertEquals("1971", tag.getFirst(FieldKey.YEAR)); assertEquals("2", tag.getFirst(FieldKey.TRACK)); assertEquals("12", tag.getFirst(FieldKey.TRACK_TOTAL)); assertEquals("4", tag.getFirst(FieldKey.DISC_NO)); assertEquals("composer", tag.getFirst(FieldKey.COMPOSER)); assertEquals("Sortartist", tag.getFirst(FieldKey.ARTIST_SORT)); assertEquals("lyrics", tag.getFirst(FieldKey.LYRICS)); assertEquals("300", tag.getFirst(FieldKey.BPM)); assertEquals("Albumartist", tag.getFirst(FieldKey.ALBUM_ARTIST)); assertEquals("Sortalbumartist", tag.getFirst(FieldKey.ALBUM_ARTIST_SORT)); assertEquals("Sortalbum", tag.getFirst(FieldKey.ALBUM_SORT)); assertEquals("GROUping", tag.getFirst(FieldKey.GROUPING)); assertEquals("Sortcomposer", tag.getFirst(FieldKey.COMPOSER_SORT)); assertEquals("sorttitle", tag.getFirst(FieldKey.TITLE_SORT)); assertEquals("1", tag.getFirst(FieldKey.IS_COMPILATION)); assertEquals("66027994-edcf-9d89-bec8-0d30077d888c", tag.getFirst(FieldKey.MUSICIP_ID)); assertEquals("e785f700-c1aa-4943-bcee-87dd316a2c31", tag.getFirst(FieldKey.MUSICBRAINZ_TRACK_ID)); assertEquals("989a13f6-b58c-4559-b09e-76ae0adb94ed", tag.getFirst(FieldKey.MUSICBRAINZ_ARTISTID)); assertEquals("989a13f6-b58c-4559-b09e-76ae0adb94ed", tag.getFirst(FieldKey.MUSICBRAINZ_RELEASEARTISTID)); assertEquals("19c6f0f6-3d6d-4b02-88c7-ffb559d52be6", tag.getFirst(FieldKey.MUSICBRAINZ_RELEASEID)); //Cast to format specific tag Mp4Tag mp4tag = (Mp4Tag) tag; //Lookup by mp4 key assertEquals("AUTHOR", mp4tag.getFirst(Mp4FieldKey.ARTIST)); assertEquals("ALBUM", mp4tag.getFirst(Mp4FieldKey.ALBUM)); assertEquals("title", mp4tag.getFirst(Mp4FieldKey.TITLE)); assertEquals("comments", mp4tag.getFirst(Mp4FieldKey.COMMENT)); assertEquals("1971", mp4tag.getFirst(Mp4FieldKey.DAY)); //Not sure why there are 4 values, only understand 2nd and third assertEquals("2/12", mp4tag.getFirst(Mp4FieldKey.TRACK)); assertEquals("2/12", ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getContent()); assertEquals(new Short("0"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getNumbers().get(0)); assertEquals(new Short("2"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getNumbers().get(1)); assertEquals(new Short("12"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getNumbers().get(2)); assertEquals(new Short("0"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getNumbers().get(3)); //Not sure why there are 4 values, only understand 2nd and third assertEquals("4/15", mp4tag.getFirst(Mp4FieldKey.DISCNUMBER)); assertEquals("4/15", ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.DISCNUMBER).get(0)).getContent()); assertEquals(new Short("0"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.DISCNUMBER).get(0)).getNumbers().get(0)); assertEquals(new Short("4"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.DISCNUMBER).get(0)).getNumbers().get(1)); assertEquals(new Short("15"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.DISCNUMBER).get(0)).getNumbers().get(2)); assertEquals("composer", mp4tag.getFirst(Mp4FieldKey.COMPOSER)); assertEquals("Sortartist", mp4tag.getFirst(Mp4FieldKey.ARTIST_SORT)); assertEquals("lyrics", mp4tag.getFirst(Mp4FieldKey.LYRICS)); assertEquals("300", mp4tag.getFirst(Mp4FieldKey.BPM)); assertEquals("Albumartist", mp4tag.getFirst(Mp4FieldKey.ALBUM_ARTIST)); assertEquals("Sortalbumartist", mp4tag.getFirst(Mp4FieldKey.ALBUM_ARTIST_SORT)); assertEquals("Sortalbum", mp4tag.getFirst(Mp4FieldKey.ALBUM_SORT)); assertEquals("GROUping", mp4tag.getFirst(Mp4FieldKey.GROUPING)); assertEquals("Sortcomposer", mp4tag.getFirst(Mp4FieldKey.COMPOSER_SORT)); assertEquals("sorttitle", mp4tag.getFirst(Mp4FieldKey.TITLE_SORT)); assertEquals("1", mp4tag.getFirst(Mp4FieldKey.COMPILATION)); assertEquals("66027994-edcf-9d89-bec8-0d30077d888c", mp4tag.getFirst(Mp4FieldKey.MUSICIP_PUID)); assertEquals("e785f700-c1aa-4943-bcee-87dd316a2c31", mp4tag.getFirst(Mp4FieldKey.MUSICBRAINZ_TRACKID)); assertEquals("989a13f6-b58c-4559-b09e-76ae0adb94ed", mp4tag.getFirst(Mp4FieldKey.MUSICBRAINZ_ARTISTID)); assertEquals("989a13f6-b58c-4559-b09e-76ae0adb94ed", mp4tag.getFirst(Mp4FieldKey.MUSICBRAINZ_ALBUMARTISTID)); assertEquals("19c6f0f6-3d6d-4b02-88c7-ffb559d52be6", mp4tag.getFirst(Mp4FieldKey.MUSICBRAINZ_ALBUMID)); Mp4TagReverseDnsField rvs = (Mp4TagReverseDnsField) mp4tag.getFirstField(Mp4FieldKey.MUSICBRAINZ_ALBUMID); assertEquals("com.apple.iTunes", rvs.getIssuer()); assertEquals("MusicBrainz Album Id", rvs.getDescriptor()); assertEquals("19c6f0f6-3d6d-4b02-88c7-ffb559d52be6", rvs.getContent()); //Lookup by mp4key (no generic key mapping for these yet) assertEquals(" 000002C0 00000298 00004210 00002FD5 0001CB31 0001CB48 0000750D 00007C4A 000291A8 00029191", mp4tag.getFirst(Mp4FieldKey.ITUNES_NORM)); assertEquals(" 00000000 00000840 000000E4 0000000000A29EDC 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000", mp4tag.getFirst(Mp4FieldKey.ITUNES_SMPB)); assertEquals("0", mp4tag.getFirst(Mp4FieldKey.PART_OF_GAPLESS_ALBUM)); assertEquals("iTunes v7.4.3.1, QuickTime 7.2", mp4tag.getFirst(Mp4FieldKey.ENCODER)); assertEquals("sortshow", mp4tag.getFirst(Mp4FieldKey.SHOW_SORT)); assertEquals("show", mp4tag.getFirst(Mp4FieldKey.SHOW)); assertEquals("Genre", mp4tag.getFirst(Mp4FieldKey.GENRE_CUSTOM)); assertEquals(String.valueOf(Mp4RatingValue.EXPLICIT.getId()), mp4tag.getFirst(Mp4FieldKey.RATING)); assertEquals(String.valueOf(Mp4ContentTypeValue.BOOKLET.getId()), mp4tag.getFirst(Mp4FieldKey.CONTENT_TYPE)); List coverart = mp4tag.get(Mp4FieldKey.ARTWORK); //Should be one image assertEquals(1, coverart.size()); Mp4TagCoverField coverArtField = (Mp4TagCoverField) coverart.get(0); //Check type jpeg assertEquals(Mp4FieldType.COVERART_JPEG, coverArtField.getFieldType()); //Just check jpeg signature assertEquals(0xff, coverArtField.getData()[0] & 0xff); assertEquals(0xd8, coverArtField.getData()[1] & 0xff); assertEquals(0xff, coverArtField.getData()[2] & 0xff); assertEquals(0xe0, coverArtField.getData()[3] & 0xff); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * * Test to write tag data, new tagdata is smaller size than existing data */ public void testWriteFileSmallerSize() { Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test.m4a", new File("testWriteFileSmallerSize.m4a")); AudioFile f = AudioFileIO.read(testFile); Tag tag = f.getTag(); //Change album to different value (but same no of characters, this is the easiest mod to make tag.setField(FieldKey.ARTIST,"AR"); tag.setField(FieldKey.ALBUM,"AL"); //Save changes and reread from disk AudioFileIO.write(f); f = AudioFileIO.read(testFile); tag = f.getTag(); //Total FileSize should not have changed assertEquals(TEST_FILE1_SIZE, testFile.length()); //AudioInfo //Time in seconds assertEquals(241, f.getAudioHeader().getTrackLength()); assertEquals(44100, f.getAudioHeader().getSampleRateAsNumber()); //Ease of use methods for common fields assertEquals("AR", tag.getFirst(FieldKey.ARTIST)); assertEquals("AL", tag.getFirst(FieldKey.ALBUM)); assertEquals("title", tag.getFirst(FieldKey.TITLE)); assertEquals("comments", tag.getFirst(FieldKey.COMMENT)); assertEquals("1971", tag.getFirst(FieldKey.YEAR)); assertEquals("1", tag.getFirst(FieldKey.TRACK)); assertEquals("1", tag.getFirst(FieldKey.DISC_NO)); assertEquals("10", tag.getFirst(FieldKey.TRACK_TOTAL)); assertEquals("10", tag.getFirst(FieldKey.DISC_TOTAL)); assertEquals("composer", tag.getFirst(FieldKey.COMPOSER)); assertEquals("Sortartist", tag.getFirst(FieldKey.ARTIST_SORT)); assertEquals("lyrics", tag.getFirst(FieldKey.LYRICS)); assertEquals("199", tag.getFirst(FieldKey.BPM)); assertEquals("Albumartist", tag.getFirst(FieldKey.ALBUM_ARTIST)); assertEquals("Sortalbumartist", tag.getFirst(FieldKey.ALBUM_ARTIST_SORT)); assertEquals("Sortalbum", tag.getFirst(FieldKey.ALBUM_SORT)); assertEquals("GROUping", tag.getFirst(FieldKey.GROUPING)); assertEquals("Sortcomposer", tag.getFirst(FieldKey.COMPOSER_SORT)); assertEquals("sorttitle", tag.getFirst(FieldKey.TITLE_SORT)); assertEquals("1", tag.getFirst(FieldKey.IS_COMPILATION)); assertEquals("66027994-edcf-9d89-bec8-0d30077d888c", tag.getFirst(FieldKey.MUSICIP_ID)); assertEquals("e785f700-c1aa-4943-bcee-87dd316a2c30", tag.getFirst(FieldKey.MUSICBRAINZ_TRACK_ID)); assertEquals("989a13f6-b58c-4559-b09e-76ae0adb94ed", tag.getFirst(FieldKey.MUSICBRAINZ_ARTISTID)); assertEquals("989a13f6-b58c-4559-b09e-76ae0adb94ed", tag.getFirst(FieldKey.MUSICBRAINZ_RELEASEARTISTID)); assertEquals("19c6f0f6-3d6d-4b02-88c7-ffb559d52be6", tag.getFirst(FieldKey.MUSICBRAINZ_RELEASEID)); //Cast to format specific tag Mp4Tag mp4tag = (Mp4Tag) tag; //Lookup by mp4 key assertEquals("AR", mp4tag.getFirst(Mp4FieldKey.ARTIST)); assertEquals("AL", mp4tag.getFirst(Mp4FieldKey.ALBUM)); assertEquals("title", mp4tag.getFirst(Mp4FieldKey.TITLE)); assertEquals("comments", mp4tag.getFirst(Mp4FieldKey.COMMENT)); assertEquals("1971", mp4tag.getFirst(Mp4FieldKey.DAY)); //Not sure why there are 4 values, only understand 2nd and third assertEquals("1/10", mp4tag.getFirst(Mp4FieldKey.TRACK)); assertEquals("1/10", ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getContent()); assertEquals(new Short("0"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getNumbers().get(0)); assertEquals(new Short("1"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getNumbers().get(1)); assertEquals(new Short("10"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getNumbers().get(2)); assertEquals(new Short("0"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getNumbers().get(3)); //Not sure why there are 4 values, only understand 2nd and third assertEquals("1/10", mp4tag.getFirst(Mp4FieldKey.DISCNUMBER)); assertEquals("1/10", ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.DISCNUMBER).get(0)).getContent()); assertEquals(new Short("0"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.DISCNUMBER).get(0)).getNumbers().get(0)); assertEquals(new Short("1"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.DISCNUMBER).get(0)).getNumbers().get(1)); assertEquals(new Short("10"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.DISCNUMBER).get(0)).getNumbers().get(2)); assertEquals("composer", mp4tag.getFirst(Mp4FieldKey.COMPOSER)); assertEquals("Sortartist", mp4tag.getFirst(Mp4FieldKey.ARTIST_SORT)); assertEquals("lyrics", mp4tag.getFirst(Mp4FieldKey.LYRICS)); assertEquals("199", mp4tag.getFirst(Mp4FieldKey.BPM)); assertEquals("Albumartist", mp4tag.getFirst(Mp4FieldKey.ALBUM_ARTIST)); assertEquals("Sortalbumartist", mp4tag.getFirst(Mp4FieldKey.ALBUM_ARTIST_SORT)); assertEquals("Sortalbum", mp4tag.getFirst(Mp4FieldKey.ALBUM_SORT)); assertEquals("GROUping", mp4tag.getFirst(Mp4FieldKey.GROUPING)); assertEquals("Sortcomposer", mp4tag.getFirst(Mp4FieldKey.COMPOSER_SORT)); assertEquals("sorttitle", mp4tag.getFirst(Mp4FieldKey.TITLE_SORT)); assertEquals("1", mp4tag.getFirst(Mp4FieldKey.COMPILATION)); assertEquals("66027994-edcf-9d89-bec8-0d30077d888c", mp4tag.getFirst(Mp4FieldKey.MUSICIP_PUID)); assertEquals("e785f700-c1aa-4943-bcee-87dd316a2c30", mp4tag.getFirst(Mp4FieldKey.MUSICBRAINZ_TRACKID)); assertEquals("989a13f6-b58c-4559-b09e-76ae0adb94ed", mp4tag.getFirst(Mp4FieldKey.MUSICBRAINZ_ARTISTID)); assertEquals("989a13f6-b58c-4559-b09e-76ae0adb94ed", mp4tag.getFirst(Mp4FieldKey.MUSICBRAINZ_ALBUMARTISTID)); assertEquals("19c6f0f6-3d6d-4b02-88c7-ffb559d52be6", mp4tag.getFirst(Mp4FieldKey.MUSICBRAINZ_ALBUMID)); Mp4TagReverseDnsField rvs = (Mp4TagReverseDnsField) mp4tag.getFirstField(Mp4FieldKey.MUSICBRAINZ_ALBUMID); assertEquals("com.apple.iTunes", rvs.getIssuer()); assertEquals("MusicBrainz Album Id", rvs.getDescriptor()); assertEquals("19c6f0f6-3d6d-4b02-88c7-ffb559d52be6", rvs.getContent()); //Lookup by mp4key (no generic key mapping for these yet) assertEquals(" 000002C0 00000298 00004210 00002FD5 0001CB31 0001CB48 0000750D 00007C4A 000291A8 00029191", mp4tag.getFirst(Mp4FieldKey.ITUNES_NORM)); assertEquals(" 00000000 00000840 000000E4 0000000000A29EDC 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000", mp4tag.getFirst(Mp4FieldKey.ITUNES_SMPB)); assertEquals("0", mp4tag.getFirst(Mp4FieldKey.PART_OF_GAPLESS_ALBUM)); assertEquals("iTunes v7.4.3.1, QuickTime 7.2", mp4tag.getFirst(Mp4FieldKey.ENCODER)); assertEquals("sortshow", mp4tag.getFirst(Mp4FieldKey.SHOW_SORT)); assertEquals("show", mp4tag.getFirst(Mp4FieldKey.SHOW)); assertEquals("Genre", mp4tag.getFirst(Mp4FieldKey.GENRE_CUSTOM)); assertEquals(String.valueOf(Mp4RatingValue.EXPLICIT.getId()), mp4tag.getFirst(Mp4FieldKey.RATING)); assertEquals(String.valueOf(Mp4ContentTypeValue.BOOKLET.getId()), mp4tag.getFirst(Mp4FieldKey.CONTENT_TYPE)); List coverart = mp4tag.get(Mp4FieldKey.ARTWORK); //Should be one image assertEquals(1, coverart.size()); Mp4TagCoverField coverArtField = (Mp4TagCoverField) coverart.get(0); //Check type jpeg assertEquals(Mp4FieldType.COVERART_JPEG, coverArtField.getFieldType()); //Just check jpeg signature assertEquals(0xff, coverArtField.getData()[0] & 0xff); assertEquals(0xd8, coverArtField.getData()[1] & 0xff); assertEquals(0xff, coverArtField.getData()[2] & 0xff); assertEquals(0xe0, coverArtField.getData()[3] & 0xff); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * Test to write tag data, new tagdata is alrger size than existing data, but not so large * that it cant fit into the sapce already allocated to meta (ilst + free atom) */ public void testWriteFileLargerSize() { Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test.m4a", new File("testWriteFileLargerSize.m4a")); AudioFile f = AudioFileIO.read(testFile); Tag tag = f.getTag(); //Change album to different value (but same no of characters, this is the easiest mod to make tag.setField(FieldKey.ARTIST,"VERYLONGARTISTNAME"); tag.setField(FieldKey.ALBUM,"VERYLONGALBUMTNAME"); //Save changes and reread from disk f.commit(); f = AudioFileIO.read(testFile); tag = f.getTag(); //Total FileSize should not have changed assertEquals(TEST_FILE1_SIZE, testFile.length()); //AudioInfo //Time in seconds assertEquals(241, f.getAudioHeader().getTrackLength()); assertEquals(44100, f.getAudioHeader().getSampleRateAsNumber()); //Ease of use methods for common fields assertEquals("VERYLONGARTISTNAME", tag.getFirst(FieldKey.ARTIST)); assertEquals("VERYLONGALBUMTNAME", tag.getFirst(FieldKey.ALBUM)); assertEquals("title", tag.getFirst(FieldKey.TITLE)); assertEquals("comments", tag.getFirst(FieldKey.COMMENT)); assertEquals("1971", tag.getFirst(FieldKey.YEAR)); assertEquals("1", tag.getFirst(FieldKey.TRACK)); assertEquals("1", tag.getFirst(FieldKey.DISC_NO)); assertEquals("10", tag.getFirst(FieldKey.TRACK_TOTAL)); assertEquals("10", tag.getFirst(FieldKey.DISC_TOTAL)); assertEquals("composer", tag.getFirst(FieldKey.COMPOSER)); assertEquals("Sortartist", tag.getFirst(FieldKey.ARTIST_SORT)); assertEquals("lyrics", tag.getFirst(FieldKey.LYRICS)); assertEquals("199", tag.getFirst(FieldKey.BPM)); assertEquals("Albumartist", tag.getFirst(FieldKey.ALBUM_ARTIST)); assertEquals("Sortalbumartist", tag.getFirst(FieldKey.ALBUM_ARTIST_SORT)); assertEquals("Sortalbum", tag.getFirst(FieldKey.ALBUM_SORT)); assertEquals("GROUping", tag.getFirst(FieldKey.GROUPING)); assertEquals("Sortcomposer", tag.getFirst(FieldKey.COMPOSER_SORT)); assertEquals("sorttitle", tag.getFirst(FieldKey.TITLE_SORT)); assertEquals("1", tag.getFirst(FieldKey.IS_COMPILATION)); assertEquals("66027994-edcf-9d89-bec8-0d30077d888c", tag.getFirst(FieldKey.MUSICIP_ID)); assertEquals("e785f700-c1aa-4943-bcee-87dd316a2c30", tag.getFirst(FieldKey.MUSICBRAINZ_TRACK_ID)); assertEquals("989a13f6-b58c-4559-b09e-76ae0adb94ed", tag.getFirst(FieldKey.MUSICBRAINZ_ARTISTID)); assertEquals("989a13f6-b58c-4559-b09e-76ae0adb94ed", tag.getFirst(FieldKey.MUSICBRAINZ_RELEASEARTISTID)); assertEquals("19c6f0f6-3d6d-4b02-88c7-ffb559d52be6", tag.getFirst(FieldKey.MUSICBRAINZ_RELEASEID)); //Cast to format specific tag Mp4Tag mp4tag = (Mp4Tag) tag; //Lookup by mp4 key assertEquals("VERYLONGARTISTNAME", mp4tag.getFirst(Mp4FieldKey.ARTIST)); assertEquals("VERYLONGALBUMTNAME", mp4tag.getFirst(Mp4FieldKey.ALBUM)); assertEquals("title", mp4tag.getFirst(Mp4FieldKey.TITLE)); assertEquals("comments", mp4tag.getFirst(Mp4FieldKey.COMMENT)); assertEquals("1971", mp4tag.getFirst(Mp4FieldKey.DAY)); //Not sure why there are 4 values, only understand 2nd and third assertEquals("1/10", mp4tag.getFirst(Mp4FieldKey.TRACK)); assertEquals("1/10", ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getContent()); assertEquals(new Short("0"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getNumbers().get(0)); assertEquals(new Short("1"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getNumbers().get(1)); assertEquals(new Short("10"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getNumbers().get(2)); assertEquals(new Short("0"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getNumbers().get(3)); //Not sure why there are 4 values, only understand 2nd and third assertEquals("1/10", mp4tag.getFirst(Mp4FieldKey.DISCNUMBER)); assertEquals("1/10", ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.DISCNUMBER).get(0)).getContent()); assertEquals(new Short("0"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.DISCNUMBER).get(0)).getNumbers().get(0)); assertEquals(new Short("1"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.DISCNUMBER).get(0)).getNumbers().get(1)); assertEquals(new Short("10"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.DISCNUMBER).get(0)).getNumbers().get(2)); assertEquals("composer", mp4tag.getFirst(Mp4FieldKey.COMPOSER)); assertEquals("Sortartist", mp4tag.getFirst(Mp4FieldKey.ARTIST_SORT)); assertEquals("lyrics", mp4tag.getFirst(Mp4FieldKey.LYRICS)); assertEquals("199", mp4tag.getFirst(Mp4FieldKey.BPM)); assertEquals("Albumartist", mp4tag.getFirst(Mp4FieldKey.ALBUM_ARTIST)); assertEquals("Sortalbumartist", mp4tag.getFirst(Mp4FieldKey.ALBUM_ARTIST_SORT)); assertEquals("Sortalbum", mp4tag.getFirst(Mp4FieldKey.ALBUM_SORT)); assertEquals("GROUping", mp4tag.getFirst(Mp4FieldKey.GROUPING)); assertEquals("Sortcomposer", mp4tag.getFirst(Mp4FieldKey.COMPOSER_SORT)); assertEquals("sorttitle", mp4tag.getFirst(Mp4FieldKey.TITLE_SORT)); assertEquals("1", mp4tag.getFirst(Mp4FieldKey.COMPILATION)); assertEquals("66027994-edcf-9d89-bec8-0d30077d888c", mp4tag.getFirst(Mp4FieldKey.MUSICIP_PUID)); assertEquals("e785f700-c1aa-4943-bcee-87dd316a2c30", mp4tag.getFirst(Mp4FieldKey.MUSICBRAINZ_TRACKID)); assertEquals("989a13f6-b58c-4559-b09e-76ae0adb94ed", mp4tag.getFirst(Mp4FieldKey.MUSICBRAINZ_ARTISTID)); assertEquals("989a13f6-b58c-4559-b09e-76ae0adb94ed", mp4tag.getFirst(Mp4FieldKey.MUSICBRAINZ_ALBUMARTISTID)); assertEquals("19c6f0f6-3d6d-4b02-88c7-ffb559d52be6", mp4tag.getFirst(Mp4FieldKey.MUSICBRAINZ_ALBUMID)); Mp4TagReverseDnsField rvs = (Mp4TagReverseDnsField) mp4tag.getFirstField(Mp4FieldKey.MUSICBRAINZ_ALBUMID); assertEquals("com.apple.iTunes", rvs.getIssuer()); assertEquals("MusicBrainz Album Id", rvs.getDescriptor()); assertEquals("19c6f0f6-3d6d-4b02-88c7-ffb559d52be6", rvs.getContent()); //Lookup by mp4key (no generic key mapping for these yet) assertEquals(" 000002C0 00000298 00004210 00002FD5 0001CB31 0001CB48 0000750D 00007C4A 000291A8 00029191", mp4tag.getFirst(Mp4FieldKey.ITUNES_NORM)); assertEquals(" 00000000 00000840 000000E4 0000000000A29EDC 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000", mp4tag.getFirst(Mp4FieldKey.ITUNES_SMPB)); assertEquals("0", mp4tag.getFirst(Mp4FieldKey.PART_OF_GAPLESS_ALBUM)); assertEquals("iTunes v7.4.3.1, QuickTime 7.2", mp4tag.getFirst(Mp4FieldKey.ENCODER)); assertEquals("sortshow", mp4tag.getFirst(Mp4FieldKey.SHOW_SORT)); assertEquals("show", mp4tag.getFirst(Mp4FieldKey.SHOW)); assertEquals("Genre", mp4tag.getFirst(Mp4FieldKey.GENRE_CUSTOM)); assertEquals(String.valueOf(Mp4RatingValue.EXPLICIT.getId()), mp4tag.getFirst(Mp4FieldKey.RATING)); assertEquals(String.valueOf(Mp4ContentTypeValue.BOOKLET.getId()), mp4tag.getFirst(Mp4FieldKey.CONTENT_TYPE)); List coverart = mp4tag.get(Mp4FieldKey.ARTWORK); //Should be one image assertEquals(1, coverart.size()); Mp4TagCoverField coverArtField = (Mp4TagCoverField) coverart.get(0); //Check type jpeg assertEquals(Mp4FieldType.COVERART_JPEG, coverArtField.getFieldType()); //Just check jpeg signature assertEquals(0xff, coverArtField.getData()[0] & 0xff); assertEquals(0xd8, coverArtField.getData()[1] & 0xff); assertEquals(0xff, coverArtField.getData()[2] & 0xff); assertEquals(0xe0, coverArtField.getData()[3] & 0xff); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * Test to write tag data, new tagdata is a larger size than existing data, and too * large to fit into the space already allocated to meta (ilst + free atom) but can fit into * the second free atom */ public void testWriteFileAlotLargerSize() { Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test.m4a", new File("testWriteFileAlot.m4a")); //Starting filesize assertEquals(TEST_FILE1_SIZE, testFile.length()); AudioFile f = AudioFileIO.read(testFile); Mp4Tag tag = (Mp4Tag) f.getTag(); //Add new image RandomAccessFile imageFile = new RandomAccessFile(new File("testdata", "coverart_small.png"), "r"); byte[] imagedata = new byte[(int) imageFile.length()]; imageFile.read(imagedata); tag.addField(((Mp4Tag) tag).createArtworkField(imagedata)); //Save changes and reread from disk f.commit(); f = AudioFileIO.read(testFile); tag = (Mp4Tag) f.getTag(); //Total FileSize should not be be any larger because we used the free atoms assertEquals(3883555, testFile.length()); //AudioInfo //Time in seconds assertEquals(241, f.getAudioHeader().getTrackLength()); assertEquals(44100, f.getAudioHeader().getSampleRateAsNumber()); //Ease of use methods for common fields assertEquals("Artist", tag.getFirst(FieldKey.ARTIST)); assertEquals("Album", tag.getFirst(FieldKey.ALBUM)); assertEquals("title", tag.getFirst(FieldKey.TITLE)); assertEquals("comments", tag.getFirst(FieldKey.COMMENT)); assertEquals("1971", tag.getFirst(FieldKey.YEAR)); assertEquals("1", tag.getFirst(FieldKey.TRACK)); assertEquals("1", tag.getFirst(FieldKey.DISC_NO)); assertEquals("10", tag.getFirst(FieldKey.TRACK_TOTAL)); assertEquals("10", tag.getFirst(FieldKey.DISC_TOTAL)); assertEquals("composer", tag.getFirst(FieldKey.COMPOSER)); assertEquals("Sortartist", tag.getFirst(FieldKey.ARTIST_SORT)); assertEquals("lyrics", tag.getFirst(FieldKey.LYRICS)); assertEquals("199", tag.getFirst(FieldKey.BPM)); assertEquals("Albumartist", tag.getFirst(FieldKey.ALBUM_ARTIST)); assertEquals("Sortalbumartist", tag.getFirst(FieldKey.ALBUM_ARTIST_SORT)); assertEquals("Sortalbum", tag.getFirst(FieldKey.ALBUM_SORT)); assertEquals("GROUping", tag.getFirst(FieldKey.GROUPING)); assertEquals("Sortcomposer", tag.getFirst(FieldKey.COMPOSER_SORT)); assertEquals("sorttitle", tag.getFirst(FieldKey.TITLE_SORT)); assertEquals("1", tag.getFirst(FieldKey.IS_COMPILATION)); assertEquals("66027994-edcf-9d89-bec8-0d30077d888c", tag.getFirst(FieldKey.MUSICIP_ID)); assertEquals("e785f700-c1aa-4943-bcee-87dd316a2c30", tag.getFirst(FieldKey.MUSICBRAINZ_TRACK_ID)); assertEquals("989a13f6-b58c-4559-b09e-76ae0adb94ed", tag.getFirst(FieldKey.MUSICBRAINZ_ARTISTID)); assertEquals("989a13f6-b58c-4559-b09e-76ae0adb94ed", tag.getFirst(FieldKey.MUSICBRAINZ_RELEASEARTISTID)); assertEquals("19c6f0f6-3d6d-4b02-88c7-ffb559d52be6", tag.getFirst(FieldKey.MUSICBRAINZ_RELEASEID)); //Cast to format specific tag Mp4Tag mp4tag = (Mp4Tag) tag; //Lookup by mp4 key assertEquals("Artist", mp4tag.getFirst(Mp4FieldKey.ARTIST)); assertEquals("Album", mp4tag.getFirst(Mp4FieldKey.ALBUM)); assertEquals("title", mp4tag.getFirst(Mp4FieldKey.TITLE)); assertEquals("comments", mp4tag.getFirst(Mp4FieldKey.COMMENT)); assertEquals("1971", mp4tag.getFirst(Mp4FieldKey.DAY)); //Not sure why there are 4 values, only understand 2nd and third assertEquals("1/10", mp4tag.getFirst(Mp4FieldKey.TRACK)); assertEquals("1/10", ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getContent()); assertEquals(new Short("0"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getNumbers().get(0)); assertEquals(new Short("1"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getNumbers().get(1)); assertEquals(new Short("10"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getNumbers().get(2)); assertEquals(new Short("0"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getNumbers().get(3)); //Not sure why there are 4 values, only understand 2nd and third assertEquals("1/10", mp4tag.getFirst(Mp4FieldKey.DISCNUMBER)); assertEquals("1/10", ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.DISCNUMBER).get(0)).getContent()); assertEquals(new Short("0"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.DISCNUMBER).get(0)).getNumbers().get(0)); assertEquals(new Short("1"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.DISCNUMBER).get(0)).getNumbers().get(1)); assertEquals(new Short("10"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.DISCNUMBER).get(0)).getNumbers().get(2)); assertEquals("composer", mp4tag.getFirst(Mp4FieldKey.COMPOSER)); assertEquals("Sortartist", mp4tag.getFirst(Mp4FieldKey.ARTIST_SORT)); assertEquals("lyrics", mp4tag.getFirst(Mp4FieldKey.LYRICS)); assertEquals("199", mp4tag.getFirst(Mp4FieldKey.BPM)); assertEquals("Albumartist", mp4tag.getFirst(Mp4FieldKey.ALBUM_ARTIST)); assertEquals("Sortalbumartist", mp4tag.getFirst(Mp4FieldKey.ALBUM_ARTIST_SORT)); assertEquals("Sortalbum", mp4tag.getFirst(Mp4FieldKey.ALBUM_SORT)); assertEquals("GROUping", mp4tag.getFirst(Mp4FieldKey.GROUPING)); assertEquals("Sortcomposer", mp4tag.getFirst(Mp4FieldKey.COMPOSER_SORT)); assertEquals("sorttitle", mp4tag.getFirst(Mp4FieldKey.TITLE_SORT)); assertEquals("1", mp4tag.getFirst(Mp4FieldKey.COMPILATION)); assertEquals("66027994-edcf-9d89-bec8-0d30077d888c", mp4tag.getFirst(Mp4FieldKey.MUSICIP_PUID)); assertEquals("e785f700-c1aa-4943-bcee-87dd316a2c30", mp4tag.getFirst(Mp4FieldKey.MUSICBRAINZ_TRACKID)); assertEquals("989a13f6-b58c-4559-b09e-76ae0adb94ed", mp4tag.getFirst(Mp4FieldKey.MUSICBRAINZ_ARTISTID)); assertEquals("989a13f6-b58c-4559-b09e-76ae0adb94ed", mp4tag.getFirst(Mp4FieldKey.MUSICBRAINZ_ALBUMARTISTID)); assertEquals("19c6f0f6-3d6d-4b02-88c7-ffb559d52be6", mp4tag.getFirst(Mp4FieldKey.MUSICBRAINZ_ALBUMID)); Mp4TagReverseDnsField rvs = (Mp4TagReverseDnsField) mp4tag.getFirstField(Mp4FieldKey.MUSICBRAINZ_ALBUMID); assertEquals("com.apple.iTunes", rvs.getIssuer()); assertEquals("MusicBrainz Album Id", rvs.getDescriptor()); assertEquals("19c6f0f6-3d6d-4b02-88c7-ffb559d52be6", rvs.getContent()); //Lookup by mp4key (no generic key mapping for these yet) assertEquals(" 000002C0 00000298 00004210 00002FD5 0001CB31 0001CB48 0000750D 00007C4A 000291A8 00029191", mp4tag.getFirst(Mp4FieldKey.ITUNES_NORM)); assertEquals(" 00000000 00000840 000000E4 0000000000A29EDC 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000", mp4tag.getFirst(Mp4FieldKey.ITUNES_SMPB)); assertEquals("0", mp4tag.getFirst(Mp4FieldKey.PART_OF_GAPLESS_ALBUM)); assertEquals("iTunes v7.4.3.1, QuickTime 7.2", mp4tag.getFirst(Mp4FieldKey.ENCODER)); assertEquals("sortshow", mp4tag.getFirst(Mp4FieldKey.SHOW_SORT)); assertEquals("show", mp4tag.getFirst(Mp4FieldKey.SHOW)); assertEquals("Genre", mp4tag.getFirst(Mp4FieldKey.GENRE_CUSTOM)); assertEquals(String.valueOf(Mp4RatingValue.EXPLICIT.getId()), mp4tag.getFirst(Mp4FieldKey.RATING)); assertEquals(String.valueOf(Mp4ContentTypeValue.BOOKLET.getId()), mp4tag.getFirst(Mp4FieldKey.CONTENT_TYPE)); List coverart = mp4tag.get(Mp4FieldKey.ARTWORK); //Should be one image assertEquals(2, coverart.size()); Mp4TagCoverField coverArtField = (Mp4TagCoverField) coverart.get(0); //Check type png assertEquals(Mp4FieldType.COVERART_JPEG, coverArtField.getFieldType()); //Just check png signature assertEquals(0xff, coverArtField.getData()[0] & 0xff); assertEquals(0xd8, coverArtField.getData()[1] & 0xff); assertEquals(0xff, coverArtField.getData()[2] & 0xff); assertEquals(0xe0, coverArtField.getData()[3] & 0xff); coverArtField = (Mp4TagCoverField) coverart.get(1); //Check type png assertEquals(Mp4FieldType.COVERART_PNG, coverArtField.getFieldType()); //Just check png signature assertEquals(0x89, coverArtField.getData()[0] & 0xff); assertEquals(0x50, coverArtField.getData()[1] & 0xff); assertEquals(0x4e, coverArtField.getData()[2] & 0xff); assertEquals(0x47, coverArtField.getData()[3] & 0xff); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * Test to write tag data, new tagdata is a larger size than existing data, and too * large to fit into the space already allocated to meta (ilst + free atom) and is even too large to fit * into the second free atom, so mdat data gets moved */ public void testWriteFileMuchLargerSize() { Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test.m4a", new File("testWriteFileMuchLargerSize.m4a")); //Starting filesize assertEquals(TEST_FILE1_SIZE, testFile.length()); AudioFile f = AudioFileIO.read(testFile); Mp4Tag tag = (Mp4Tag) f.getTag(); //Add new image RandomAccessFile imageFile = new RandomAccessFile(new File("testdata", "coverart.png"), "r"); byte[] imagedata = new byte[(int) imageFile.length()]; imageFile.read(imagedata); tag.addField(((Mp4Tag) tag).createArtworkField(imagedata)); //Save changes and reread from disk f.commit(); f = AudioFileIO.read(testFile); tag = (Mp4Tag) f.getTag(); //Total FileSize should now be larger assertEquals(3901001, testFile.length()); //AudioInfo //Time in seconds assertEquals(241, f.getAudioHeader().getTrackLength()); assertEquals(44100, f.getAudioHeader().getSampleRateAsNumber()); //Ease of use methods for common fields assertEquals("Artist", tag.getFirst(FieldKey.ARTIST)); assertEquals("Album", tag.getFirst(FieldKey.ALBUM)); assertEquals("title", tag.getFirst(FieldKey.TITLE)); assertEquals("comments", tag.getFirst(FieldKey.COMMENT)); assertEquals("1971", tag.getFirst(FieldKey.YEAR)); assertEquals("1", tag.getFirst(FieldKey.TRACK)); assertEquals("1", tag.getFirst(FieldKey.DISC_NO)); assertEquals("10", tag.getFirst(FieldKey.TRACK_TOTAL)); assertEquals("10", tag.getFirst(FieldKey.DISC_TOTAL)); assertEquals("composer", tag.getFirst(FieldKey.COMPOSER)); assertEquals("Sortartist", tag.getFirst(FieldKey.ARTIST_SORT)); assertEquals("lyrics", tag.getFirst(FieldKey.LYRICS)); assertEquals("199", tag.getFirst(FieldKey.BPM)); assertEquals("Albumartist", tag.getFirst(FieldKey.ALBUM_ARTIST)); assertEquals("Sortalbumartist", tag.getFirst(FieldKey.ALBUM_ARTIST_SORT)); assertEquals("Sortalbum", tag.getFirst(FieldKey.ALBUM_SORT)); assertEquals("GROUping", tag.getFirst(FieldKey.GROUPING)); assertEquals("Sortcomposer", tag.getFirst(FieldKey.COMPOSER_SORT)); assertEquals("sorttitle", tag.getFirst(FieldKey.TITLE_SORT)); assertEquals("1", tag.getFirst(FieldKey.IS_COMPILATION)); assertEquals("66027994-edcf-9d89-bec8-0d30077d888c", tag.getFirst(FieldKey.MUSICIP_ID)); assertEquals("e785f700-c1aa-4943-bcee-87dd316a2c30", tag.getFirst(FieldKey.MUSICBRAINZ_TRACK_ID)); assertEquals("989a13f6-b58c-4559-b09e-76ae0adb94ed", tag.getFirst(FieldKey.MUSICBRAINZ_ARTISTID)); assertEquals("989a13f6-b58c-4559-b09e-76ae0adb94ed", tag.getFirst(FieldKey.MUSICBRAINZ_RELEASEARTISTID)); assertEquals("19c6f0f6-3d6d-4b02-88c7-ffb559d52be6", tag.getFirst(FieldKey.MUSICBRAINZ_RELEASEID)); //Cast to format specific tag Mp4Tag mp4tag = (Mp4Tag) tag; //Lookup by mp4 key assertEquals("Artist", mp4tag.getFirst(Mp4FieldKey.ARTIST)); assertEquals("Album", mp4tag.getFirst(Mp4FieldKey.ALBUM)); assertEquals("title", mp4tag.getFirst(Mp4FieldKey.TITLE)); assertEquals("comments", mp4tag.getFirst(Mp4FieldKey.COMMENT)); assertEquals("1971", mp4tag.getFirst(Mp4FieldKey.DAY)); //Not sure why there are 4 values, only understand 2nd and third assertEquals("1/10", mp4tag.getFirst(Mp4FieldKey.TRACK)); assertEquals("1/10", ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getContent()); assertEquals(new Short("0"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getNumbers().get(0)); assertEquals(new Short("1"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getNumbers().get(1)); assertEquals(new Short("10"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getNumbers().get(2)); assertEquals(new Short("0"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getNumbers().get(3)); //Not sure why there are 4 values, only understand 2nd and third assertEquals("1/10", mp4tag.getFirst(Mp4FieldKey.DISCNUMBER)); assertEquals("1/10", ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.DISCNUMBER).get(0)).getContent()); assertEquals(new Short("0"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.DISCNUMBER).get(0)).getNumbers().get(0)); assertEquals(new Short("1"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.DISCNUMBER).get(0)).getNumbers().get(1)); assertEquals(new Short("10"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.DISCNUMBER).get(0)).getNumbers().get(2)); assertEquals("composer", mp4tag.getFirst(Mp4FieldKey.COMPOSER)); assertEquals("Sortartist", mp4tag.getFirst(Mp4FieldKey.ARTIST_SORT)); assertEquals("lyrics", mp4tag.getFirst(Mp4FieldKey.LYRICS)); assertEquals("199", mp4tag.getFirst(Mp4FieldKey.BPM)); assertEquals("Albumartist", mp4tag.getFirst(Mp4FieldKey.ALBUM_ARTIST)); assertEquals("Sortalbumartist", mp4tag.getFirst(Mp4FieldKey.ALBUM_ARTIST_SORT)); assertEquals("Sortalbum", mp4tag.getFirst(Mp4FieldKey.ALBUM_SORT)); assertEquals("GROUping", mp4tag.getFirst(Mp4FieldKey.GROUPING)); assertEquals("Sortcomposer", mp4tag.getFirst(Mp4FieldKey.COMPOSER_SORT)); assertEquals("sorttitle", mp4tag.getFirst(Mp4FieldKey.TITLE_SORT)); assertEquals("1", mp4tag.getFirst(Mp4FieldKey.COMPILATION)); assertEquals("66027994-edcf-9d89-bec8-0d30077d888c", mp4tag.getFirst(Mp4FieldKey.MUSICIP_PUID)); assertEquals("e785f700-c1aa-4943-bcee-87dd316a2c30", mp4tag.getFirst(Mp4FieldKey.MUSICBRAINZ_TRACKID)); assertEquals("989a13f6-b58c-4559-b09e-76ae0adb94ed", mp4tag.getFirst(Mp4FieldKey.MUSICBRAINZ_ARTISTID)); assertEquals("989a13f6-b58c-4559-b09e-76ae0adb94ed", mp4tag.getFirst(Mp4FieldKey.MUSICBRAINZ_ALBUMARTISTID)); assertEquals("19c6f0f6-3d6d-4b02-88c7-ffb559d52be6", mp4tag.getFirst(Mp4FieldKey.MUSICBRAINZ_ALBUMID)); Mp4TagReverseDnsField rvs = (Mp4TagReverseDnsField) mp4tag.getFirstField(Mp4FieldKey.MUSICBRAINZ_ALBUMID); assertEquals("com.apple.iTunes", rvs.getIssuer()); assertEquals("MusicBrainz Album Id", rvs.getDescriptor()); assertEquals("19c6f0f6-3d6d-4b02-88c7-ffb559d52be6", rvs.getContent()); //Lookup by mp4key (no generic key mapping for these yet) assertEquals(" 000002C0 00000298 00004210 00002FD5 0001CB31 0001CB48 0000750D 00007C4A 000291A8 00029191", mp4tag.getFirst(Mp4FieldKey.ITUNES_NORM)); assertEquals(" 00000000 00000840 000000E4 0000000000A29EDC 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000", mp4tag.getFirst(Mp4FieldKey.ITUNES_SMPB)); assertEquals("0", mp4tag.getFirst(Mp4FieldKey.PART_OF_GAPLESS_ALBUM)); assertEquals("iTunes v7.4.3.1, QuickTime 7.2", mp4tag.getFirst(Mp4FieldKey.ENCODER)); assertEquals("sortshow", mp4tag.getFirst(Mp4FieldKey.SHOW_SORT)); assertEquals("show", mp4tag.getFirst(Mp4FieldKey.SHOW)); assertEquals("Genre", mp4tag.getFirst(Mp4FieldKey.GENRE_CUSTOM)); assertEquals(String.valueOf(Mp4RatingValue.EXPLICIT.getId()), mp4tag.getFirst(Mp4FieldKey.RATING)); assertEquals(String.valueOf(Mp4ContentTypeValue.BOOKLET.getId()), mp4tag.getFirst(Mp4FieldKey.CONTENT_TYPE)); List coverart = mp4tag.get(Mp4FieldKey.ARTWORK); //Should be one image assertEquals(2, coverart.size()); Mp4TagCoverField coverArtField = (Mp4TagCoverField) coverart.get(0); //Check type png assertEquals(Mp4FieldType.COVERART_JPEG, coverArtField.getFieldType()); //Just check png signature assertEquals(0xff, coverArtField.getData()[0] & 0xff); assertEquals(0xd8, coverArtField.getData()[1] & 0xff); assertEquals(0xff, coverArtField.getData()[2] & 0xff); assertEquals(0xe0, coverArtField.getData()[3] & 0xff); coverArtField = (Mp4TagCoverField) coverart.get(1); //Check type png assertEquals(Mp4FieldType.COVERART_PNG, coverArtField.getFieldType()); //Just check png signature assertEquals(0x89, coverArtField.getData()[0] & 0xff); assertEquals(0x50, coverArtField.getData()[1] & 0xff); assertEquals(0x4e, coverArtField.getData()[2] & 0xff); assertEquals(0x47, coverArtField.getData()[3] & 0xff); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * Test removing the tag from the file */ public void testDeleteTag() { Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test.m4a", new File("testDeleteMeta.m4a")); AudioFile f = AudioFileIO.read(testFile); AudioFileIO.delete(f); //Check all Tags Deleted f = AudioFileIO.read(testFile); System.out.println(f.getTag()); assertEquals(0, f.getTag().getFieldCount()); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * Test removing the tag from the file which does not have a free atom */ public void testDeleteTag2() { Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test3.m4a", new File("testDeleteMeta2.m4a")); AudioFile f = AudioFileIO.read(testFile); AudioFileIO.delete(f); //Check all Tags Deleted f = AudioFileIO.read(testFile); System.out.println(f.getTag()); assertEquals(0, f.getTag().getFieldCount()); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * Test to write tag data, new tagdata identical size to existing data, but no meta free atom */ public void testWriteFileSameSizeNoMetaFreeAtom() { Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test3.m4a", new File("testWriteFileSameSizeNoMetaFree.m4a")); AudioFile f = AudioFileIO.read(testFile); Tag tag = f.getTag(); //Change values to different value (but same no of characters, this is the easiest mod to make tag.setField(FieldKey.ARTIST,"AUTHOR"); tag.setField(FieldKey.ALBUM,"ALBUM"); tag.setField(new Mp4TrackField(2, 12)); tag.setField(new Mp4DiscNoField(4, 15)); tag.setField(tag.createField(FieldKey.MUSICBRAINZ_TRACK_ID, "e785f700-c1aa-4943-bcee-87dd316a2c31")); tag.setField(tag.createField(FieldKey.BPM, "300")); //Save changes and reread from disk f.commit(); f = AudioFileIO.read(testFile); tag = f.getTag(); //Total FileSize should not have changed assertEquals(TEST_FILE2_SIZE, testFile.length()); //AudioInfo //Time in seconds assertEquals(241, f.getAudioHeader().getTrackLength()); assertEquals(44100, f.getAudioHeader().getSampleRateAsNumber()); //Ease of use methods for common fields assertEquals("AUTHOR", tag.getFirst(FieldKey.ARTIST)); assertEquals("ALBUM", tag.getFirst(FieldKey.ALBUM)); assertEquals("title", tag.getFirst(FieldKey.TITLE)); assertEquals("comments", tag.getFirst(FieldKey.COMMENT)); assertEquals("1971", tag.getFirst(FieldKey.YEAR)); assertEquals("2", tag.getFirst(FieldKey.TRACK)); assertEquals("4", tag.getFirst(FieldKey.DISC_NO)); assertEquals("composer", tag.getFirst(FieldKey.COMPOSER)); assertEquals("Sortartist", tag.getFirst(FieldKey.ARTIST_SORT)); assertEquals("lyrics", tag.getFirst(FieldKey.LYRICS)); assertEquals("300", tag.getFirst(FieldKey.BPM)); assertEquals("Albumartist", tag.getFirst(FieldKey.ALBUM_ARTIST)); assertEquals("Sortalbumartist", tag.getFirst(FieldKey.ALBUM_ARTIST_SORT)); assertEquals("Sortalbum", tag.getFirst(FieldKey.ALBUM_SORT)); assertEquals("GROUping", tag.getFirst(FieldKey.GROUPING)); assertEquals("Sortcomposer", tag.getFirst(FieldKey.COMPOSER_SORT)); assertEquals("sorttitle", tag.getFirst(FieldKey.TITLE_SORT)); assertEquals("1", tag.getFirst(FieldKey.IS_COMPILATION)); assertEquals("66027994-edcf-9d89-bec8-0d30077d888c", tag.getFirst(FieldKey.MUSICIP_ID)); assertEquals("e785f700-c1aa-4943-bcee-87dd316a2c31", tag.getFirst(FieldKey.MUSICBRAINZ_TRACK_ID)); assertEquals("989a13f6-b58c-4559-b09e-76ae0adb94ed", tag.getFirst(FieldKey.MUSICBRAINZ_ARTISTID)); assertEquals("989a13f6-b58c-4559-b09e-76ae0adb94ed", tag.getFirst(FieldKey.MUSICBRAINZ_RELEASEARTISTID)); assertEquals("19c6f0f6-3d6d-4b02-88c7-ffb559d52be6", tag.getFirst(FieldKey.MUSICBRAINZ_RELEASEID)); //Cast to format specific tag Mp4Tag mp4tag = (Mp4Tag) tag; //Lookup by mp4 key assertEquals("AUTHOR", mp4tag.getFirst(Mp4FieldKey.ARTIST)); assertEquals("ALBUM", mp4tag.getFirst(Mp4FieldKey.ALBUM)); assertEquals("title", mp4tag.getFirst(Mp4FieldKey.TITLE)); assertEquals("comments", mp4tag.getFirst(Mp4FieldKey.COMMENT)); assertEquals("1971", mp4tag.getFirst(Mp4FieldKey.DAY)); //Not sure why there are 4 values, only understand 2nd and third assertEquals("2/12", mp4tag.getFirst(Mp4FieldKey.TRACK)); assertEquals("2/12", ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getContent()); assertEquals(new Short("0"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getNumbers().get(0)); assertEquals(new Short("2"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getNumbers().get(1)); assertEquals(new Short("12"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getNumbers().get(2)); assertEquals(new Short("0"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getNumbers().get(3)); //Not sure why there are 4 values, only understand 2nd and third assertEquals("4/15", mp4tag.getFirst(Mp4FieldKey.DISCNUMBER)); assertEquals("4/15", ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.DISCNUMBER).get(0)).getContent()); assertEquals(new Short("0"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.DISCNUMBER).get(0)).getNumbers().get(0)); assertEquals(new Short("4"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.DISCNUMBER).get(0)).getNumbers().get(1)); assertEquals(new Short("15"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.DISCNUMBER).get(0)).getNumbers().get(2)); assertEquals("composer", mp4tag.getFirst(Mp4FieldKey.COMPOSER)); assertEquals("Sortartist", mp4tag.getFirst(Mp4FieldKey.ARTIST_SORT)); assertEquals("lyrics", mp4tag.getFirst(Mp4FieldKey.LYRICS)); assertEquals("300", mp4tag.getFirst(Mp4FieldKey.BPM)); assertEquals("Albumartist", mp4tag.getFirst(Mp4FieldKey.ALBUM_ARTIST)); assertEquals("Sortalbumartist", mp4tag.getFirst(Mp4FieldKey.ALBUM_ARTIST_SORT)); assertEquals("Sortalbum", mp4tag.getFirst(Mp4FieldKey.ALBUM_SORT)); assertEquals("GROUping", mp4tag.getFirst(Mp4FieldKey.GROUPING)); assertEquals("Sortcomposer", mp4tag.getFirst(Mp4FieldKey.COMPOSER_SORT)); assertEquals("sorttitle", mp4tag.getFirst(Mp4FieldKey.TITLE_SORT)); assertEquals("1", mp4tag.getFirst(Mp4FieldKey.COMPILATION)); assertEquals("66027994-edcf-9d89-bec8-0d30077d888c", mp4tag.getFirst(Mp4FieldKey.MUSICIP_PUID)); assertEquals("e785f700-c1aa-4943-bcee-87dd316a2c31", mp4tag.getFirst(Mp4FieldKey.MUSICBRAINZ_TRACKID)); assertEquals("989a13f6-b58c-4559-b09e-76ae0adb94ed", mp4tag.getFirst(Mp4FieldKey.MUSICBRAINZ_ARTISTID)); assertEquals("989a13f6-b58c-4559-b09e-76ae0adb94ed", mp4tag.getFirst(Mp4FieldKey.MUSICBRAINZ_ALBUMARTISTID)); assertEquals("19c6f0f6-3d6d-4b02-88c7-ffb559d52be6", mp4tag.getFirst(Mp4FieldKey.MUSICBRAINZ_ALBUMID)); Mp4TagReverseDnsField rvs = (Mp4TagReverseDnsField) mp4tag.getFirstField(Mp4FieldKey.MUSICBRAINZ_ALBUMID); assertEquals("com.apple.iTunes", rvs.getIssuer()); assertEquals("MusicBrainz Album Id", rvs.getDescriptor()); assertEquals("19c6f0f6-3d6d-4b02-88c7-ffb559d52be6", rvs.getContent()); //Lookup by mp4key (no generic key mapping for these yet) assertEquals(" 000002C0 00000298 00004210 00002FD5 0001CB31 0001CB48 0000750D 00007C4A 000291A8 00029191", mp4tag.getFirst(Mp4FieldKey.ITUNES_NORM)); assertEquals(" 00000000 00000840 000000E4 0000000000A29EDC 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000", mp4tag.getFirst(Mp4FieldKey.ITUNES_SMPB)); assertEquals("0", mp4tag.getFirst(Mp4FieldKey.PART_OF_GAPLESS_ALBUM)); assertEquals("iTunes v7.4.3.1, QuickTime 7.2", mp4tag.getFirst(Mp4FieldKey.ENCODER)); assertEquals("sortshow", mp4tag.getFirst(Mp4FieldKey.SHOW_SORT)); assertEquals("show", mp4tag.getFirst(Mp4FieldKey.SHOW)); assertEquals("Genre", mp4tag.getFirst(Mp4FieldKey.GENRE_CUSTOM)); assertEquals(String.valueOf(Mp4RatingValue.EXPLICIT.getId()), mp4tag.getFirst(Mp4FieldKey.RATING)); assertEquals(String.valueOf(Mp4ContentTypeValue.BOOKLET.getId()), mp4tag.getFirst(Mp4FieldKey.CONTENT_TYPE)); List coverart = mp4tag.get(Mp4FieldKey.ARTWORK); //Should be one image assertEquals(1, coverart.size()); Mp4TagCoverField coverArtField = (Mp4TagCoverField) coverart.get(0); //Check type jpeg assertEquals(Mp4FieldType.COVERART_JPEG, coverArtField.getFieldType()); //Just check jpeg signature assertEquals(0xff, coverArtField.getData()[0] & 0xff); assertEquals(0xd8, coverArtField.getData()[1] & 0xff); assertEquals(0xff, coverArtField.getData()[2] & 0xff); assertEquals(0xe0, coverArtField.getData()[3] & 0xff); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * * Test to write tag data, new tagdata is smaller size than existing data */ public void testWriteFileSmallerSizeMoreThanEightBytesSmallerNoMetaFreeAtom() { Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test3.m4a", new File("testWriteFileSmallerSizeNoMetaFreeMoreThanEight.m4a")); AudioFile f = AudioFileIO.read(testFile); Tag tag = f.getTag(); //Change album to different value (but same no of characters, this is the easiest mod to make tag.setField(FieldKey.ARTIST,"AR"); tag.setField(FieldKey.ALBUM,"AL"); tag.setField(FieldKey.COMMENT,"C"); tag.setField(FieldKey.TITLE,"t"); //Save changes and reread from disk AudioFileIO.write(f); f = AudioFileIO.read(testFile); tag = f.getTag(); //Total FileSize should not have changed assertEquals(TEST_FILE2_SIZE, testFile.length()); //AudioInfo //Time in seconds assertEquals(241, f.getAudioHeader().getTrackLength()); assertEquals(44100, f.getAudioHeader().getSampleRateAsNumber()); //Ease of use methods for common fields assertEquals("AR", tag.getFirst(FieldKey.ARTIST)); assertEquals("AL", tag.getFirst(FieldKey.ALBUM)); assertEquals("t", tag.getFirst(FieldKey.TITLE)); assertEquals("C", tag.getFirst(FieldKey.COMMENT)); assertEquals("1971", tag.getFirst(FieldKey.YEAR)); assertEquals("1", tag.getFirst(FieldKey.TRACK)); assertEquals("1", tag.getFirst(FieldKey.DISC_NO)); assertEquals("composer", tag.getFirst(FieldKey.COMPOSER)); assertEquals("Sortartist", tag.getFirst(FieldKey.ARTIST_SORT)); assertEquals("lyrics", tag.getFirst(FieldKey.LYRICS)); assertEquals("199", tag.getFirst(FieldKey.BPM)); assertEquals("Albumartist", tag.getFirst(FieldKey.ALBUM_ARTIST)); assertEquals("Sortalbumartist", tag.getFirst(FieldKey.ALBUM_ARTIST_SORT)); assertEquals("Sortalbum", tag.getFirst(FieldKey.ALBUM_SORT)); assertEquals("GROUping", tag.getFirst(FieldKey.GROUPING)); assertEquals("Sortcomposer", tag.getFirst(FieldKey.COMPOSER_SORT)); assertEquals("sorttitle", tag.getFirst(FieldKey.TITLE_SORT)); assertEquals("1", tag.getFirst(FieldKey.IS_COMPILATION)); assertEquals("66027994-edcf-9d89-bec8-0d30077d888c", tag.getFirst(FieldKey.MUSICIP_ID)); assertEquals("e785f700-c1aa-4943-bcee-87dd316a2c30", tag.getFirst(FieldKey.MUSICBRAINZ_TRACK_ID)); assertEquals("989a13f6-b58c-4559-b09e-76ae0adb94ed", tag.getFirst(FieldKey.MUSICBRAINZ_ARTISTID)); assertEquals("989a13f6-b58c-4559-b09e-76ae0adb94ed", tag.getFirst(FieldKey.MUSICBRAINZ_RELEASEARTISTID)); assertEquals("19c6f0f6-3d6d-4b02-88c7-ffb559d52be6", tag.getFirst(FieldKey.MUSICBRAINZ_RELEASEID)); //Cast to format specific tag Mp4Tag mp4tag = (Mp4Tag) tag; //Lookup by mp4 key assertEquals("AR", mp4tag.getFirst(Mp4FieldKey.ARTIST)); assertEquals("AL", mp4tag.getFirst(Mp4FieldKey.ALBUM)); assertEquals("t", mp4tag.getFirst(Mp4FieldKey.TITLE)); assertEquals("C", mp4tag.getFirst(Mp4FieldKey.COMMENT)); assertEquals("1971", mp4tag.getFirst(Mp4FieldKey.DAY)); //Not sure why there are 4 values, only understand 2nd and third assertEquals("1/10", mp4tag.getFirst(Mp4FieldKey.TRACK)); assertEquals("1/10", ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getContent()); assertEquals(new Short("0"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getNumbers().get(0)); assertEquals(new Short("1"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getNumbers().get(1)); assertEquals(new Short("10"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getNumbers().get(2)); assertEquals(new Short("0"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getNumbers().get(3)); //Not sure why there are 4 values, only understand 2nd and third assertEquals("1/10", mp4tag.getFirst(Mp4FieldKey.DISCNUMBER)); assertEquals("1/10", ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.DISCNUMBER).get(0)).getContent()); assertEquals(new Short("0"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.DISCNUMBER).get(0)).getNumbers().get(0)); assertEquals(new Short("1"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.DISCNUMBER).get(0)).getNumbers().get(1)); assertEquals(new Short("10"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.DISCNUMBER).get(0)).getNumbers().get(2)); assertEquals("composer", mp4tag.getFirst(Mp4FieldKey.COMPOSER)); assertEquals("Sortartist", mp4tag.getFirst(Mp4FieldKey.ARTIST_SORT)); assertEquals("lyrics", mp4tag.getFirst(Mp4FieldKey.LYRICS)); assertEquals("199", mp4tag.getFirst(Mp4FieldKey.BPM)); assertEquals("Albumartist", mp4tag.getFirst(Mp4FieldKey.ALBUM_ARTIST)); assertEquals("Sortalbumartist", mp4tag.getFirst(Mp4FieldKey.ALBUM_ARTIST_SORT)); assertEquals("Sortalbum", mp4tag.getFirst(Mp4FieldKey.ALBUM_SORT)); assertEquals("GROUping", mp4tag.getFirst(Mp4FieldKey.GROUPING)); assertEquals("Sortcomposer", mp4tag.getFirst(Mp4FieldKey.COMPOSER_SORT)); assertEquals("sorttitle", mp4tag.getFirst(Mp4FieldKey.TITLE_SORT)); assertEquals("1", mp4tag.getFirst(Mp4FieldKey.COMPILATION)); assertEquals("66027994-edcf-9d89-bec8-0d30077d888c", mp4tag.getFirst(Mp4FieldKey.MUSICIP_PUID)); assertEquals("e785f700-c1aa-4943-bcee-87dd316a2c30", mp4tag.getFirst(Mp4FieldKey.MUSICBRAINZ_TRACKID)); assertEquals("989a13f6-b58c-4559-b09e-76ae0adb94ed", mp4tag.getFirst(Mp4FieldKey.MUSICBRAINZ_ARTISTID)); assertEquals("989a13f6-b58c-4559-b09e-76ae0adb94ed", mp4tag.getFirst(Mp4FieldKey.MUSICBRAINZ_ALBUMARTISTID)); assertEquals("19c6f0f6-3d6d-4b02-88c7-ffb559d52be6", mp4tag.getFirst(Mp4FieldKey.MUSICBRAINZ_ALBUMID)); Mp4TagReverseDnsField rvs = (Mp4TagReverseDnsField) mp4tag.getFirstField(Mp4FieldKey.MUSICBRAINZ_ALBUMID); assertEquals("com.apple.iTunes", rvs.getIssuer()); assertEquals("MusicBrainz Album Id", rvs.getDescriptor()); assertEquals("19c6f0f6-3d6d-4b02-88c7-ffb559d52be6", rvs.getContent()); //Lookup by mp4key (no generic key mapping for these yet) assertEquals(" 000002C0 00000298 00004210 00002FD5 0001CB31 0001CB48 0000750D 00007C4A 000291A8 00029191", mp4tag.getFirst(Mp4FieldKey.ITUNES_NORM)); assertEquals(" 00000000 00000840 000000E4 0000000000A29EDC 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000", mp4tag.getFirst(Mp4FieldKey.ITUNES_SMPB)); assertEquals("0", mp4tag.getFirst(Mp4FieldKey.PART_OF_GAPLESS_ALBUM)); assertEquals("iTunes v7.4.3.1, QuickTime 7.2", mp4tag.getFirst(Mp4FieldKey.ENCODER)); assertEquals("sortshow", mp4tag.getFirst(Mp4FieldKey.SHOW_SORT)); assertEquals("show", mp4tag.getFirst(Mp4FieldKey.SHOW)); assertEquals("Genre", mp4tag.getFirst(Mp4FieldKey.GENRE_CUSTOM)); assertEquals(String.valueOf(Mp4RatingValue.EXPLICIT.getId()), mp4tag.getFirst(Mp4FieldKey.RATING)); assertEquals(String.valueOf(Mp4ContentTypeValue.BOOKLET.getId()), mp4tag.getFirst(Mp4FieldKey.CONTENT_TYPE)); List coverart = mp4tag.get(Mp4FieldKey.ARTWORK); //Should be one image assertEquals(1, coverart.size()); Mp4TagCoverField coverArtField = (Mp4TagCoverField) coverart.get(0); //Check type jpeg assertEquals(Mp4FieldType.COVERART_JPEG, coverArtField.getFieldType()); //Just check jpeg signature assertEquals(0xff, coverArtField.getData()[0] & 0xff); assertEquals(0xd8, coverArtField.getData()[1] & 0xff); assertEquals(0xff, coverArtField.getData()[2] & 0xff); assertEquals(0xe0, coverArtField.getData()[3] & 0xff); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * Test to write tag data, new tagdata is smaller size than existing data, and there is no metadata atom to allow * for adjustments, but there is a toplevel free atom */ public void testWriteFileSmallerSizeLessThanEightBytesNoMetaFreeAtom() { Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test3.m4a", new File("testWriteFileLessThanEight2.m4a")); AudioFile f = AudioFileIO.read(testFile); Tag tag = f.getTag(); //Change values to slightly smaller than values (but less than 8 chras diff in total) tag.setField(FieldKey.ARTIST,"AR"); tag.setField(FieldKey.ALBUM,"AL"); //Save changes and reread from disk AudioFileIO.write(f); f = AudioFileIO.read(testFile); tag = f.getTag(); //Total FileSize should not have changed assertEquals(TEST_FILE2_SIZE - 7, testFile.length()); //AudioInfo //Time in seconds assertEquals(241, f.getAudioHeader().getTrackLength()); assertEquals(44100, f.getAudioHeader().getSampleRateAsNumber()); //Ease of use methods for common fields assertEquals("AR", tag.getFirst(FieldKey.ARTIST)); assertEquals("AL", tag.getFirst(FieldKey.ALBUM)); assertEquals("title", tag.getFirst(FieldKey.TITLE)); assertEquals("comments", tag.getFirst(FieldKey.COMMENT)); assertEquals("1971", tag.getFirst(FieldKey.YEAR)); assertEquals("1", tag.getFirst(FieldKey.TRACK)); assertEquals("1", tag.getFirst(FieldKey.DISC_NO)); assertEquals("composer", tag.getFirst(FieldKey.COMPOSER)); assertEquals("Sortartist", tag.getFirst(FieldKey.ARTIST_SORT)); assertEquals("lyrics", tag.getFirst(FieldKey.LYRICS)); assertEquals("199", tag.getFirst(FieldKey.BPM)); assertEquals("Albumartist", tag.getFirst(FieldKey.ALBUM_ARTIST)); assertEquals("Sortalbumartist", tag.getFirst(FieldKey.ALBUM_ARTIST_SORT)); assertEquals("Sortalbum", tag.getFirst(FieldKey.ALBUM_SORT)); assertEquals("GROUping", tag.getFirst(FieldKey.GROUPING)); assertEquals("Sortcomposer", tag.getFirst(FieldKey.COMPOSER_SORT)); assertEquals("sorttitle", tag.getFirst(FieldKey.TITLE_SORT)); assertEquals("1", tag.getFirst(FieldKey.IS_COMPILATION)); assertEquals("66027994-edcf-9d89-bec8-0d30077d888c", tag.getFirst(FieldKey.MUSICIP_ID)); assertEquals("e785f700-c1aa-4943-bcee-87dd316a2c30", tag.getFirst(FieldKey.MUSICBRAINZ_TRACK_ID)); assertEquals("989a13f6-b58c-4559-b09e-76ae0adb94ed", tag.getFirst(FieldKey.MUSICBRAINZ_ARTISTID)); assertEquals("989a13f6-b58c-4559-b09e-76ae0adb94ed", tag.getFirst(FieldKey.MUSICBRAINZ_RELEASEARTISTID)); assertEquals("19c6f0f6-3d6d-4b02-88c7-ffb559d52be6", tag.getFirst(FieldKey.MUSICBRAINZ_RELEASEID)); //Cast to format specific tag Mp4Tag mp4tag = (Mp4Tag) tag; //Lookup by mp4 key assertEquals("AR", mp4tag.getFirst(Mp4FieldKey.ARTIST)); assertEquals("AL", mp4tag.getFirst(Mp4FieldKey.ALBUM)); assertEquals("title", mp4tag.getFirst(Mp4FieldKey.TITLE)); assertEquals("comments", mp4tag.getFirst(Mp4FieldKey.COMMENT)); assertEquals("1971", mp4tag.getFirst(Mp4FieldKey.DAY)); //Not sure why there are 4 values, only understand 2nd and third assertEquals("1/10", mp4tag.getFirst(Mp4FieldKey.TRACK)); assertEquals("1/10", ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getContent()); assertEquals(new Short("0"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getNumbers().get(0)); assertEquals(new Short("1"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getNumbers().get(1)); assertEquals(new Short("10"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getNumbers().get(2)); assertEquals(new Short("0"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getNumbers().get(3)); //Not sure why there are 4 values, only understand 2nd and third assertEquals("1/10", mp4tag.getFirst(Mp4FieldKey.DISCNUMBER)); assertEquals("1/10", ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.DISCNUMBER).get(0)).getContent()); assertEquals(new Short("0"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.DISCNUMBER).get(0)).getNumbers().get(0)); assertEquals(new Short("1"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.DISCNUMBER).get(0)).getNumbers().get(1)); assertEquals(new Short("10"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.DISCNUMBER).get(0)).getNumbers().get(2)); assertEquals("composer", mp4tag.getFirst(Mp4FieldKey.COMPOSER)); assertEquals("Sortartist", mp4tag.getFirst(Mp4FieldKey.ARTIST_SORT)); assertEquals("lyrics", mp4tag.getFirst(Mp4FieldKey.LYRICS)); assertEquals("199", mp4tag.getFirst(Mp4FieldKey.BPM)); assertEquals("Albumartist", mp4tag.getFirst(Mp4FieldKey.ALBUM_ARTIST)); assertEquals("Sortalbumartist", mp4tag.getFirst(Mp4FieldKey.ALBUM_ARTIST_SORT)); assertEquals("Sortalbum", mp4tag.getFirst(Mp4FieldKey.ALBUM_SORT)); assertEquals("GROUping", mp4tag.getFirst(Mp4FieldKey.GROUPING)); assertEquals("Sortcomposer", mp4tag.getFirst(Mp4FieldKey.COMPOSER_SORT)); assertEquals("sorttitle", mp4tag.getFirst(Mp4FieldKey.TITLE_SORT)); assertEquals("1", mp4tag.getFirst(Mp4FieldKey.COMPILATION)); assertEquals("66027994-edcf-9d89-bec8-0d30077d888c", mp4tag.getFirst(Mp4FieldKey.MUSICIP_PUID)); assertEquals("e785f700-c1aa-4943-bcee-87dd316a2c30", mp4tag.getFirst(Mp4FieldKey.MUSICBRAINZ_TRACKID)); assertEquals("989a13f6-b58c-4559-b09e-76ae0adb94ed", mp4tag.getFirst(Mp4FieldKey.MUSICBRAINZ_ARTISTID)); assertEquals("989a13f6-b58c-4559-b09e-76ae0adb94ed", mp4tag.getFirst(Mp4FieldKey.MUSICBRAINZ_ALBUMARTISTID)); assertEquals("19c6f0f6-3d6d-4b02-88c7-ffb559d52be6", mp4tag.getFirst(Mp4FieldKey.MUSICBRAINZ_ALBUMID)); Mp4TagReverseDnsField rvs = (Mp4TagReverseDnsField) mp4tag.getFirstField(Mp4FieldKey.MUSICBRAINZ_ALBUMID); assertEquals("com.apple.iTunes", rvs.getIssuer()); assertEquals("MusicBrainz Album Id", rvs.getDescriptor()); assertEquals("19c6f0f6-3d6d-4b02-88c7-ffb559d52be6", rvs.getContent()); //Lookup by mp4key (no generic key mapping for these yet) assertEquals(" 000002C0 00000298 00004210 00002FD5 0001CB31 0001CB48 0000750D 00007C4A 000291A8 00029191", mp4tag.getFirst(Mp4FieldKey.ITUNES_NORM)); assertEquals(" 00000000 00000840 000000E4 0000000000A29EDC 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000", mp4tag.getFirst(Mp4FieldKey.ITUNES_SMPB)); assertEquals("0", mp4tag.getFirst(Mp4FieldKey.PART_OF_GAPLESS_ALBUM)); assertEquals("iTunes v7.4.3.1, QuickTime 7.2", mp4tag.getFirst(Mp4FieldKey.ENCODER)); assertEquals("sortshow", mp4tag.getFirst(Mp4FieldKey.SHOW_SORT)); assertEquals("show", mp4tag.getFirst(Mp4FieldKey.SHOW)); assertEquals("Genre", mp4tag.getFirst(Mp4FieldKey.GENRE_CUSTOM)); assertEquals(String.valueOf(Mp4RatingValue.EXPLICIT.getId()), mp4tag.getFirst(Mp4FieldKey.RATING)); assertEquals(String.valueOf(Mp4ContentTypeValue.BOOKLET.getId()), mp4tag.getFirst(Mp4FieldKey.CONTENT_TYPE)); List coverart = mp4tag.get(Mp4FieldKey.ARTWORK); //Should be one image assertEquals(1, coverart.size()); Mp4TagCoverField coverArtField = (Mp4TagCoverField) coverart.get(0); //Check type jpeg assertEquals(Mp4FieldType.COVERART_JPEG, coverArtField.getFieldType()); //Just check jpeg signature assertEquals(0xff, coverArtField.getData()[0] & 0xff); assertEquals(0xd8, coverArtField.getData()[1] & 0xff); assertEquals(0xff, coverArtField.getData()[2] & 0xff); assertEquals(0xe0, coverArtField.getData()[3] & 0xff); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * Test to write tag data, new tagdata is smaller size than existing data, and there is no metadata or top level * free atom */ public void testWriteFileSmallerSizeLessThanEightBytesNoFreeAtoms() { Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test8.m4a", new File("testWriteFileLessThanEight3.m4a")); AudioFile f = AudioFileIO.read(testFile); Tag tag = f.getTag(); //Change values to slightly smaller than values (but less than 8 chars diff in total) tag.setField(FieldKey.ARTIST,"AR"); tag.setField(FieldKey.ALBUM,"AL"); //Save changes and reread from disk AudioFileIO.write(f); f = AudioFileIO.read(testFile); tag = f.getTag(); //Total FileSize should not have changed assertEquals(TEST_FILE2_SIZE - 7, testFile.length()); //AudioInfo //Time in seconds assertEquals(241, f.getAudioHeader().getTrackLength()); assertEquals(44100, f.getAudioHeader().getSampleRateAsNumber()); //Ease of use methods for common fields assertEquals("AR", tag.getFirst(FieldKey.ARTIST)); assertEquals("AL", tag.getFirst(FieldKey.ALBUM)); assertEquals("title", tag.getFirst(FieldKey.TITLE)); assertEquals("comments", tag.getFirst(FieldKey.COMMENT)); assertEquals("1971", tag.getFirst(FieldKey.YEAR)); assertEquals("1", tag.getFirst(FieldKey.TRACK)); assertEquals("1", tag.getFirst(FieldKey.DISC_NO)); assertEquals("composer", tag.getFirst(FieldKey.COMPOSER)); assertEquals("Sortartist", tag.getFirst(FieldKey.ARTIST_SORT)); assertEquals("lyrics", tag.getFirst(FieldKey.LYRICS)); assertEquals("199", tag.getFirst(FieldKey.BPM)); assertEquals("Albumartist", tag.getFirst(FieldKey.ALBUM_ARTIST)); assertEquals("Sortalbumartist", tag.getFirst(FieldKey.ALBUM_ARTIST_SORT)); assertEquals("Sortalbum", tag.getFirst(FieldKey.ALBUM_SORT)); assertEquals("GROUping", tag.getFirst(FieldKey.GROUPING)); assertEquals("Sortcomposer", tag.getFirst(FieldKey.COMPOSER_SORT)); assertEquals("sorttitle", tag.getFirst(FieldKey.TITLE_SORT)); assertEquals("1", tag.getFirst(FieldKey.IS_COMPILATION)); assertEquals("66027994-edcf-9d89-bec8-0d30077d888c", tag.getFirst(FieldKey.MUSICIP_ID)); assertEquals("e785f700-c1aa-4943-bcee-87dd316a2c30", tag.getFirst(FieldKey.MUSICBRAINZ_TRACK_ID)); assertEquals("989a13f6-b58c-4559-b09e-76ae0adb94ed", tag.getFirst(FieldKey.MUSICBRAINZ_ARTISTID)); assertEquals("989a13f6-b58c-4559-b09e-76ae0adb94ed", tag.getFirst(FieldKey.MUSICBRAINZ_RELEASEARTISTID)); assertEquals("19c6f0f6-3d6d-4b02-88c7-ffb559d52be6", tag.getFirst(FieldKey.MUSICBRAINZ_RELEASEID)); //Cast to format specific tag Mp4Tag mp4tag = (Mp4Tag) tag; //Lookup by mp4 key assertEquals("AR", mp4tag.getFirst(Mp4FieldKey.ARTIST)); assertEquals("AL", mp4tag.getFirst(Mp4FieldKey.ALBUM)); assertEquals("title", mp4tag.getFirst(Mp4FieldKey.TITLE)); assertEquals("comments", mp4tag.getFirst(Mp4FieldKey.COMMENT)); assertEquals("1971", mp4tag.getFirst(Mp4FieldKey.DAY)); //Not sure why there are 4 values, only understand 2nd and third assertEquals("1/10", mp4tag.getFirst(Mp4FieldKey.TRACK)); assertEquals("1/10", ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getContent()); assertEquals(new Short("0"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getNumbers().get(0)); assertEquals(new Short("1"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getNumbers().get(1)); assertEquals(new Short("10"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getNumbers().get(2)); assertEquals(new Short("0"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getNumbers().get(3)); //Not sure why there are 4 values, only understand 2nd and third assertEquals("1/10", mp4tag.getFirst(Mp4FieldKey.DISCNUMBER)); assertEquals("1/10", ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.DISCNUMBER).get(0)).getContent()); assertEquals(new Short("0"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.DISCNUMBER).get(0)).getNumbers().get(0)); assertEquals(new Short("1"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.DISCNUMBER).get(0)).getNumbers().get(1)); assertEquals(new Short("10"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.DISCNUMBER).get(0)).getNumbers().get(2)); assertEquals("composer", mp4tag.getFirst(Mp4FieldKey.COMPOSER)); assertEquals("Sortartist", mp4tag.getFirst(Mp4FieldKey.ARTIST_SORT)); assertEquals("lyrics", mp4tag.getFirst(Mp4FieldKey.LYRICS)); assertEquals("199", mp4tag.getFirst(Mp4FieldKey.BPM)); assertEquals("Albumartist", mp4tag.getFirst(Mp4FieldKey.ALBUM_ARTIST)); assertEquals("Sortalbumartist", mp4tag.getFirst(Mp4FieldKey.ALBUM_ARTIST_SORT)); assertEquals("Sortalbum", mp4tag.getFirst(Mp4FieldKey.ALBUM_SORT)); assertEquals("GROUping", mp4tag.getFirst(Mp4FieldKey.GROUPING)); assertEquals("Sortcomposer", mp4tag.getFirst(Mp4FieldKey.COMPOSER_SORT)); assertEquals("sorttitle", mp4tag.getFirst(Mp4FieldKey.TITLE_SORT)); assertEquals("1", mp4tag.getFirst(Mp4FieldKey.COMPILATION)); assertEquals("66027994-edcf-9d89-bec8-0d30077d888c", mp4tag.getFirst(Mp4FieldKey.MUSICIP_PUID)); assertEquals("e785f700-c1aa-4943-bcee-87dd316a2c30", mp4tag.getFirst(Mp4FieldKey.MUSICBRAINZ_TRACKID)); assertEquals("989a13f6-b58c-4559-b09e-76ae0adb94ed", mp4tag.getFirst(Mp4FieldKey.MUSICBRAINZ_ARTISTID)); assertEquals("989a13f6-b58c-4559-b09e-76ae0adb94ed", mp4tag.getFirst(Mp4FieldKey.MUSICBRAINZ_ALBUMARTISTID)); assertEquals("19c6f0f6-3d6d-4b02-88c7-ffb559d52be6", mp4tag.getFirst(Mp4FieldKey.MUSICBRAINZ_ALBUMID)); Mp4TagReverseDnsField rvs = (Mp4TagReverseDnsField) mp4tag.getFirstField(Mp4FieldKey.MUSICBRAINZ_ALBUMID); assertEquals("com.apple.iTunes", rvs.getIssuer()); assertEquals("MusicBrainz Album Id", rvs.getDescriptor()); assertEquals("19c6f0f6-3d6d-4b02-88c7-ffb559d52be6", rvs.getContent()); //Lookup by mp4key (no generic key mapping for these yet) assertEquals(" 000002C0 00000298 00004210 00002FD5 0001CB31 0001CB48 0000750D 00007C4A 000291A8 00029191", mp4tag.getFirst(Mp4FieldKey.ITUNES_NORM)); assertEquals(" 00000000 00000840 000000E4 0000000000A29EDC 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000", mp4tag.getFirst(Mp4FieldKey.ITUNES_SMPB)); assertEquals("0", mp4tag.getFirst(Mp4FieldKey.PART_OF_GAPLESS_ALBUM)); assertEquals("iTunes v7.4.3.1, QuickTime 7.2", mp4tag.getFirst(Mp4FieldKey.ENCODER)); assertEquals("sortshow", mp4tag.getFirst(Mp4FieldKey.SHOW_SORT)); assertEquals("show", mp4tag.getFirst(Mp4FieldKey.SHOW)); assertEquals("Genre", mp4tag.getFirst(Mp4FieldKey.GENRE_CUSTOM)); assertEquals(String.valueOf(Mp4RatingValue.EXPLICIT.getId()), mp4tag.getFirst(Mp4FieldKey.RATING)); assertEquals(String.valueOf(Mp4ContentTypeValue.BOOKLET.getId()), mp4tag.getFirst(Mp4FieldKey.CONTENT_TYPE)); List coverart = mp4tag.get(Mp4FieldKey.ARTWORK); //Should be one image assertEquals(2, coverart.size()); Mp4TagCoverField coverArtField = (Mp4TagCoverField) coverart.get(0); //Check type jpeg assertEquals(Mp4FieldType.COVERART_JPEG, coverArtField.getFieldType()); //Just check jpeg signature assertEquals(0xff, coverArtField.getData()[0] & 0xff); assertEquals(0xd8, coverArtField.getData()[1] & 0xff); assertEquals(0xff, coverArtField.getData()[2] & 0xff); assertEquals(0xe0, coverArtField.getData()[3] & 0xff); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * Test to write tag data, new tagdata is smaller size than existing data, and there is no metadata or top level * free atom */ public void testWriteFileSmallerNoFreeAtoms() { Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test8.m4a", new File("testWriteFileNoFreeAtom2.m4a")); AudioFile f = AudioFileIO.read(testFile); Tag tag = f.getTag(); //Change values to slightly smaller than values (but less than 8 chras diff in total) tag.setField(FieldKey.ARTIST,"AR"); tag.setField(FieldKey.ALBUM,"AL"); tag.setField(FieldKey.COMMENT,"C"); //Save changes and reread from disk AudioFileIO.write(f); f = AudioFileIO.read(testFile); tag = f.getTag(); //Total FileSize should not have changed assertEquals(TEST_FILE2_SIZE, testFile.length()); //AudioInfo //Time in seconds assertEquals(241, f.getAudioHeader().getTrackLength()); assertEquals(44100, f.getAudioHeader().getSampleRateAsNumber()); //Ease of use methods for common fields assertEquals("AR", tag.getFirst(FieldKey.ARTIST)); assertEquals("AL", tag.getFirst(FieldKey.ALBUM)); assertEquals("title", tag.getFirst(FieldKey.TITLE)); assertEquals("C", tag.getFirst(FieldKey.COMMENT)); assertEquals("1971", tag.getFirst(FieldKey.YEAR)); assertEquals("1", tag.getFirst(FieldKey.TRACK)); assertEquals("1", tag.getFirst(FieldKey.DISC_NO)); assertEquals("composer", tag.getFirst(FieldKey.COMPOSER)); assertEquals("Sortartist", tag.getFirst(FieldKey.ARTIST_SORT)); assertEquals("lyrics", tag.getFirst(FieldKey.LYRICS)); assertEquals("199", tag.getFirst(FieldKey.BPM)); assertEquals("Albumartist", tag.getFirst(FieldKey.ALBUM_ARTIST)); assertEquals("Sortalbumartist", tag.getFirst(FieldKey.ALBUM_ARTIST_SORT)); assertEquals("Sortalbum", tag.getFirst(FieldKey.ALBUM_SORT)); assertEquals("GROUping", tag.getFirst(FieldKey.GROUPING)); assertEquals("Sortcomposer", tag.getFirst(FieldKey.COMPOSER_SORT)); assertEquals("sorttitle", tag.getFirst(FieldKey.TITLE_SORT)); assertEquals("1", tag.getFirst(FieldKey.IS_COMPILATION)); assertEquals("66027994-edcf-9d89-bec8-0d30077d888c", tag.getFirst(FieldKey.MUSICIP_ID)); assertEquals("e785f700-c1aa-4943-bcee-87dd316a2c30", tag.getFirst(FieldKey.MUSICBRAINZ_TRACK_ID)); assertEquals("989a13f6-b58c-4559-b09e-76ae0adb94ed", tag.getFirst(FieldKey.MUSICBRAINZ_ARTISTID)); assertEquals("989a13f6-b58c-4559-b09e-76ae0adb94ed", tag.getFirst(FieldKey.MUSICBRAINZ_RELEASEARTISTID)); assertEquals("19c6f0f6-3d6d-4b02-88c7-ffb559d52be6", tag.getFirst(FieldKey.MUSICBRAINZ_RELEASEID)); //Cast to format specific tag Mp4Tag mp4tag = (Mp4Tag) tag; //Lookup by mp4 key assertEquals("AR", mp4tag.getFirst(Mp4FieldKey.ARTIST)); assertEquals("AL", mp4tag.getFirst(Mp4FieldKey.ALBUM)); assertEquals("title", mp4tag.getFirst(Mp4FieldKey.TITLE)); assertEquals("C", mp4tag.getFirst(Mp4FieldKey.COMMENT)); assertEquals("1971", mp4tag.getFirst(Mp4FieldKey.DAY)); //Not sure why there are 4 values, only understand 2nd and third assertEquals("1/10", mp4tag.getFirst(Mp4FieldKey.TRACK)); assertEquals("1/10", ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getContent()); assertEquals(new Short("0"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getNumbers().get(0)); assertEquals(new Short("1"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getNumbers().get(1)); assertEquals(new Short("10"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getNumbers().get(2)); assertEquals(new Short("0"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getNumbers().get(3)); //Not sure why there are 4 values, only understand 2nd and third assertEquals("1/10", mp4tag.getFirst(Mp4FieldKey.DISCNUMBER)); assertEquals("1/10", ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.DISCNUMBER).get(0)).getContent()); assertEquals(new Short("0"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.DISCNUMBER).get(0)).getNumbers().get(0)); assertEquals(new Short("1"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.DISCNUMBER).get(0)).getNumbers().get(1)); assertEquals(new Short("10"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.DISCNUMBER).get(0)).getNumbers().get(2)); assertEquals("composer", mp4tag.getFirst(Mp4FieldKey.COMPOSER)); assertEquals("Sortartist", mp4tag.getFirst(Mp4FieldKey.ARTIST_SORT)); assertEquals("lyrics", mp4tag.getFirst(Mp4FieldKey.LYRICS)); assertEquals("199", mp4tag.getFirst(Mp4FieldKey.BPM)); assertEquals("Albumartist", mp4tag.getFirst(Mp4FieldKey.ALBUM_ARTIST)); assertEquals("Sortalbumartist", mp4tag.getFirst(Mp4FieldKey.ALBUM_ARTIST_SORT)); assertEquals("Sortalbum", mp4tag.getFirst(Mp4FieldKey.ALBUM_SORT)); assertEquals("GROUping", mp4tag.getFirst(Mp4FieldKey.GROUPING)); assertEquals("Sortcomposer", mp4tag.getFirst(Mp4FieldKey.COMPOSER_SORT)); assertEquals("sorttitle", mp4tag.getFirst(Mp4FieldKey.TITLE_SORT)); assertEquals("1", mp4tag.getFirst(Mp4FieldKey.COMPILATION)); assertEquals("66027994-edcf-9d89-bec8-0d30077d888c", mp4tag.getFirst(Mp4FieldKey.MUSICIP_PUID)); assertEquals("e785f700-c1aa-4943-bcee-87dd316a2c30", mp4tag.getFirst(Mp4FieldKey.MUSICBRAINZ_TRACKID)); assertEquals("989a13f6-b58c-4559-b09e-76ae0adb94ed", mp4tag.getFirst(Mp4FieldKey.MUSICBRAINZ_ARTISTID)); assertEquals("989a13f6-b58c-4559-b09e-76ae0adb94ed", mp4tag.getFirst(Mp4FieldKey.MUSICBRAINZ_ALBUMARTISTID)); assertEquals("19c6f0f6-3d6d-4b02-88c7-ffb559d52be6", mp4tag.getFirst(Mp4FieldKey.MUSICBRAINZ_ALBUMID)); Mp4TagReverseDnsField rvs = (Mp4TagReverseDnsField) mp4tag.getFirstField(Mp4FieldKey.MUSICBRAINZ_ALBUMID); assertEquals("com.apple.iTunes", rvs.getIssuer()); assertEquals("MusicBrainz Album Id", rvs.getDescriptor()); assertEquals("19c6f0f6-3d6d-4b02-88c7-ffb559d52be6", rvs.getContent()); //Lookup by mp4key (no generic key mapping for these yet) assertEquals(" 000002C0 00000298 00004210 00002FD5 0001CB31 0001CB48 0000750D 00007C4A 000291A8 00029191", mp4tag.getFirst(Mp4FieldKey.ITUNES_NORM)); assertEquals(" 00000000 00000840 000000E4 0000000000A29EDC 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000", mp4tag.getFirst(Mp4FieldKey.ITUNES_SMPB)); assertEquals("0", mp4tag.getFirst(Mp4FieldKey.PART_OF_GAPLESS_ALBUM)); assertEquals("iTunes v7.4.3.1, QuickTime 7.2", mp4tag.getFirst(Mp4FieldKey.ENCODER)); assertEquals("sortshow", mp4tag.getFirst(Mp4FieldKey.SHOW_SORT)); assertEquals("show", mp4tag.getFirst(Mp4FieldKey.SHOW)); assertEquals("Genre", mp4tag.getFirst(Mp4FieldKey.GENRE_CUSTOM)); assertEquals(String.valueOf(Mp4RatingValue.EXPLICIT.getId()), mp4tag.getFirst(Mp4FieldKey.RATING)); assertEquals(String.valueOf(Mp4ContentTypeValue.BOOKLET.getId()), mp4tag.getFirst(Mp4FieldKey.CONTENT_TYPE)); List coverart = mp4tag.get(Mp4FieldKey.ARTWORK); //Should be one image assertEquals(2, coverart.size()); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * Test to write tag data, new tagdata is alrger size than existing data, but not so large * that it cant fit into the sapce already allocated to meta (ilst + free atom) */ public void testWriteFileLargerSizeNoMetaFreeAtom() { Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test3.m4a", new File("testWriteFileLargerSizeNoMetaFree.m4a")); AudioFile f = AudioFileIO.read(testFile); Tag tag = f.getTag(); //Change album to different value (but same no of characters, this is the easiest mod to make tag.setField(FieldKey.ARTIST,"VERYLONGARTISTNAME"); tag.setField(FieldKey.ALBUM,"VERYLONGALBUMTNAME"); //Save changes and reread from disk f.commit(); f = AudioFileIO.read(testFile); tag = f.getTag(); //Total FileSize should not have changed assertEquals(TEST_FILE2_SIZE, testFile.length()); //AudioInfo //Time in seconds assertEquals(241, f.getAudioHeader().getTrackLength()); assertEquals(44100, f.getAudioHeader().getSampleRateAsNumber()); //Ease of use methods for common fields assertEquals("VERYLONGARTISTNAME", tag.getFirst(FieldKey.ARTIST)); assertEquals("VERYLONGALBUMTNAME", tag.getFirst(FieldKey.ALBUM)); assertEquals("title", tag.getFirst(FieldKey.TITLE)); assertEquals("comments", tag.getFirst(FieldKey.COMMENT)); assertEquals("1971", tag.getFirst(FieldKey.YEAR)); assertEquals("1", tag.getFirst(FieldKey.TRACK)); assertEquals("1", tag.getFirst(FieldKey.DISC_NO)); assertEquals("composer", tag.getFirst(FieldKey.COMPOSER)); assertEquals("Sortartist", tag.getFirst(FieldKey.ARTIST_SORT)); assertEquals("lyrics", tag.getFirst(FieldKey.LYRICS)); assertEquals("199", tag.getFirst(FieldKey.BPM)); assertEquals("Albumartist", tag.getFirst(FieldKey.ALBUM_ARTIST)); assertEquals("Sortalbumartist", tag.getFirst(FieldKey.ALBUM_ARTIST_SORT)); assertEquals("Sortalbum", tag.getFirst(FieldKey.ALBUM_SORT)); assertEquals("GROUping", tag.getFirst(FieldKey.GROUPING)); assertEquals("Sortcomposer", tag.getFirst(FieldKey.COMPOSER_SORT)); assertEquals("sorttitle", tag.getFirst(FieldKey.TITLE_SORT)); assertEquals("1", tag.getFirst(FieldKey.IS_COMPILATION)); assertEquals("66027994-edcf-9d89-bec8-0d30077d888c", tag.getFirst(FieldKey.MUSICIP_ID)); assertEquals("e785f700-c1aa-4943-bcee-87dd316a2c30", tag.getFirst(FieldKey.MUSICBRAINZ_TRACK_ID)); assertEquals("989a13f6-b58c-4559-b09e-76ae0adb94ed", tag.getFirst(FieldKey.MUSICBRAINZ_ARTISTID)); assertEquals("989a13f6-b58c-4559-b09e-76ae0adb94ed", tag.getFirst(FieldKey.MUSICBRAINZ_RELEASEARTISTID)); assertEquals("19c6f0f6-3d6d-4b02-88c7-ffb559d52be6", tag.getFirst(FieldKey.MUSICBRAINZ_RELEASEID)); //Cast to format specific tag Mp4Tag mp4tag = (Mp4Tag) tag; //Lookup by mp4 key assertEquals("VERYLONGARTISTNAME", mp4tag.getFirst(Mp4FieldKey.ARTIST)); assertEquals("VERYLONGALBUMTNAME", mp4tag.getFirst(Mp4FieldKey.ALBUM)); assertEquals("title", mp4tag.getFirst(Mp4FieldKey.TITLE)); assertEquals("comments", mp4tag.getFirst(Mp4FieldKey.COMMENT)); assertEquals("1971", mp4tag.getFirst(Mp4FieldKey.DAY)); //Not sure why there are 4 values, only understand 2nd and third assertEquals("1/10", mp4tag.getFirst(Mp4FieldKey.TRACK)); assertEquals("1/10", ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getContent()); assertEquals(new Short("0"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getNumbers().get(0)); assertEquals(new Short("1"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getNumbers().get(1)); assertEquals(new Short("10"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getNumbers().get(2)); assertEquals(new Short("0"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getNumbers().get(3)); //Not sure why there are 4 values, only understand 2nd and third assertEquals("1/10", mp4tag.getFirst(Mp4FieldKey.DISCNUMBER)); assertEquals("1/10", ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.DISCNUMBER).get(0)).getContent()); assertEquals(new Short("0"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.DISCNUMBER).get(0)).getNumbers().get(0)); assertEquals(new Short("1"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.DISCNUMBER).get(0)).getNumbers().get(1)); assertEquals(new Short("10"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.DISCNUMBER).get(0)).getNumbers().get(2)); assertEquals("composer", mp4tag.getFirst(Mp4FieldKey.COMPOSER)); assertEquals("Sortartist", mp4tag.getFirst(Mp4FieldKey.ARTIST_SORT)); assertEquals("lyrics", mp4tag.getFirst(Mp4FieldKey.LYRICS)); assertEquals("199", mp4tag.getFirst(Mp4FieldKey.BPM)); assertEquals("Albumartist", mp4tag.getFirst(Mp4FieldKey.ALBUM_ARTIST)); assertEquals("Sortalbumartist", mp4tag.getFirst(Mp4FieldKey.ALBUM_ARTIST_SORT)); assertEquals("Sortalbum", mp4tag.getFirst(Mp4FieldKey.ALBUM_SORT)); assertEquals("GROUping", mp4tag.getFirst(Mp4FieldKey.GROUPING)); assertEquals("Sortcomposer", mp4tag.getFirst(Mp4FieldKey.COMPOSER_SORT)); assertEquals("sorttitle", mp4tag.getFirst(Mp4FieldKey.TITLE_SORT)); assertEquals("1", mp4tag.getFirst(Mp4FieldKey.COMPILATION)); assertEquals("66027994-edcf-9d89-bec8-0d30077d888c", mp4tag.getFirst(Mp4FieldKey.MUSICIP_PUID)); assertEquals("e785f700-c1aa-4943-bcee-87dd316a2c30", mp4tag.getFirst(Mp4FieldKey.MUSICBRAINZ_TRACKID)); assertEquals("989a13f6-b58c-4559-b09e-76ae0adb94ed", mp4tag.getFirst(Mp4FieldKey.MUSICBRAINZ_ARTISTID)); assertEquals("989a13f6-b58c-4559-b09e-76ae0adb94ed", mp4tag.getFirst(Mp4FieldKey.MUSICBRAINZ_ALBUMARTISTID)); assertEquals("19c6f0f6-3d6d-4b02-88c7-ffb559d52be6", mp4tag.getFirst(Mp4FieldKey.MUSICBRAINZ_ALBUMID)); Mp4TagReverseDnsField rvs = (Mp4TagReverseDnsField) mp4tag.getFirstField(Mp4FieldKey.MUSICBRAINZ_ALBUMID); assertEquals("com.apple.iTunes", rvs.getIssuer()); assertEquals("MusicBrainz Album Id", rvs.getDescriptor()); assertEquals("19c6f0f6-3d6d-4b02-88c7-ffb559d52be6", rvs.getContent()); //Lookup by mp4key (no generic key mapping for these yet) assertEquals(" 000002C0 00000298 00004210 00002FD5 0001CB31 0001CB48 0000750D 00007C4A 000291A8 00029191", mp4tag.getFirst(Mp4FieldKey.ITUNES_NORM)); assertEquals(" 00000000 00000840 000000E4 0000000000A29EDC 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000", mp4tag.getFirst(Mp4FieldKey.ITUNES_SMPB)); assertEquals("0", mp4tag.getFirst(Mp4FieldKey.PART_OF_GAPLESS_ALBUM)); assertEquals("iTunes v7.4.3.1, QuickTime 7.2", mp4tag.getFirst(Mp4FieldKey.ENCODER)); assertEquals("sortshow", mp4tag.getFirst(Mp4FieldKey.SHOW_SORT)); assertEquals("show", mp4tag.getFirst(Mp4FieldKey.SHOW)); assertEquals("Genre", mp4tag.getFirst(Mp4FieldKey.GENRE_CUSTOM)); assertEquals(String.valueOf(Mp4RatingValue.EXPLICIT.getId()), mp4tag.getFirst(Mp4FieldKey.RATING)); assertEquals(String.valueOf(Mp4ContentTypeValue.BOOKLET.getId()), mp4tag.getFirst(Mp4FieldKey.CONTENT_TYPE)); List coverart = mp4tag.get(Mp4FieldKey.ARTWORK); //Should be one image assertEquals(1, coverart.size()); Mp4TagCoverField coverArtField = (Mp4TagCoverField) coverart.get(0); //Check type jpeg assertEquals(Mp4FieldType.COVERART_JPEG, coverArtField.getFieldType()); //Just check jpeg signature assertEquals(0xff, coverArtField.getData()[0] & 0xff); assertEquals(0xd8, coverArtField.getData()[1] & 0xff); assertEquals(0xff, coverArtField.getData()[2] & 0xff); assertEquals(0xe0, coverArtField.getData()[3] & 0xff); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * * Test to write tag data,no tagdata currently exists in the file */ public void testWriteFileWhichDoesntHaveAMetadataAtom() { Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test4.m4a", new File("testWriteNewMetadata.m4a")); AudioFile f = AudioFileIO.read(testFile); Tag tag = f.getTag(); //Change album to different value (but same no of characters, this is the easiest mod to make tag.setField(FieldKey.ARTIST,"AR"); tag.setField(FieldKey.ALBUM,"AL"); //Add new image RandomAccessFile imageFile = new RandomAccessFile(new File("testdata", "coverart.png"), "r"); byte[] imagedata = new byte[(int) imageFile.length()]; imageFile.read(imagedata); tag.addField(((Mp4Tag) tag).createArtworkField(imagedata)); //Add second image imageFile = new RandomAccessFile(new File("testdata", "coverart_small.png"), "r"); imagedata = new byte[(int) imageFile.length()]; imageFile.read(imagedata); tag.addField(((Mp4Tag) tag).createArtworkField(imagedata)); //Save changes and reread from disk AudioFileIO.write(f); f = AudioFileIO.read(testFile); tag = f.getTag(); //AudioInfo //Time in seconds assertEquals(241, f.getAudioHeader().getTrackLength()); assertEquals(44100, f.getAudioHeader().getSampleRateAsNumber()); //Ease of use methods for common fields assertEquals("AR", tag.getFirst(FieldKey.ARTIST)); assertEquals("AL", tag.getFirst(FieldKey.ALBUM)); //Should be two images List coverart = tag.getFields(FieldKey.COVER_ART); assertEquals(2, coverart.size()); Mp4TagCoverField coverArtField = (Mp4TagCoverField) coverart.get(0); //Check type png assertEquals(Mp4FieldType.COVERART_PNG, coverArtField.getFieldType()); //Just check png signature assertEquals(0x89, coverArtField.getData()[0] & 0xff); assertEquals(0x50, coverArtField.getData()[1] & 0xff); assertEquals(0x4e, coverArtField.getData()[2] & 0xff); assertEquals(0x47, coverArtField.getData()[3] & 0xff); coverArtField = (Mp4TagCoverField) coverart.get(1); //Check type png assertEquals(Mp4FieldType.COVERART_PNG, coverArtField.getFieldType()); //Just check png signature assertEquals(0x89, coverArtField.getData()[0] & 0xff); assertEquals(0x50, coverArtField.getData()[1] & 0xff); assertEquals(0x4e, coverArtField.getData()[2] & 0xff); assertEquals(0x47, coverArtField.getData()[3] & 0xff); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * Test to write tag data, there is no top level free atom (there is a meta free atom) */ public void testWriteFileLargerSizeNoTopLevelFreeAtom() { File orig = new File("testdata", "test6.m4p"); if (!orig.isFile()) { return; } Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test6.m4a", new File("testWriteNoTopFree.m4a")); AudioFile f = AudioFileIO.read(testFile); Tag tag = f.getTag(); //Change album to different value (but same no of characters, this is the easiest mod to make tag.setField(FieldKey.ARTIST,"VERYLONGARTISTNAME"); tag.setField(FieldKey.ALBUM,"VERYLONGALBUMTNAME"); tag.setField(tag.createField(FieldKey.MUSICBRAINZ_ARTISTID, "989a13f6-b58c-4559-b09e-76ae0adb94ed")); //Save changes and reread from disk f.commit(); f = AudioFileIO.read(testFile); tag = f.getTag(); //Total FileSize should not have changed assertEquals(5208679, testFile.length()); //AudioInfo //Time in seconds assertEquals(321, f.getAudioHeader().getTrackLength()); assertEquals(44100, f.getAudioHeader().getSampleRateAsNumber()); //Ease of use methods for common fields assertEquals("VERYLONGARTISTNAME", tag.getFirst(FieldKey.ARTIST)); assertEquals("VERYLONGALBUMTNAME", tag.getFirst(FieldKey.ALBUM)); assertEquals("989a13f6-b58c-4559-b09e-76ae0adb94ed", tag.getFirst(FieldKey.MUSICBRAINZ_ARTISTID)); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * Test to write tag data, new tagdata is smaller size than existing data, and there is no metadata atom to allow * for adjustments, but there is a toplevel free atom */ public void testWriteFileLargerSizeEqualToTopLevelFreeSpace() { Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test3.m4a", new File("testWriteFileEqualToFreeSpace.m4a")); AudioFile f = AudioFileIO.read(testFile); Tag tag = f.getTag(); //Frig adding pretend image which will require exactly the same size as space available in top level atom , (there is //no meta atom) in test3.m4a byte[] imagedata = new byte[2032]; imagedata[0] = (byte) 0x89; imagedata[1] = (byte) 0x50; imagedata[2] = (byte) 0x4E; imagedata[3] = (byte) 0x47; tag.addField(((Mp4Tag) tag).createArtworkField(imagedata)); //Save changes and reread from disk AudioFileIO.write(f); f = AudioFileIO.read(testFile); tag = f.getTag(); //AudioInfo //Time in seconds assertEquals(241, f.getAudioHeader().getTrackLength()); assertEquals(44100, f.getAudioHeader().getSampleRateAsNumber()); //Ease of use methods for common fields assertEquals("Artist", tag.getFirst(FieldKey.ARTIST)); assertEquals("Album", tag.getFirst(FieldKey.ALBUM)); assertEquals("title", tag.getFirst(FieldKey.TITLE)); assertEquals("comments", tag.getFirst(FieldKey.COMMENT)); assertEquals("1971", tag.getFirst(FieldKey.YEAR)); assertEquals("1", tag.getFirst(FieldKey.TRACK)); assertEquals("10", tag.getFirst(FieldKey.TRACK_TOTAL)); assertEquals("1", tag.getFirst(FieldKey.DISC_NO)); assertEquals("10", tag.getFirst(FieldKey.DISC_TOTAL)); assertEquals("composer", tag.getFirst(FieldKey.COMPOSER)); assertEquals("Sortartist", tag.getFirst(FieldKey.ARTIST_SORT)); assertEquals("lyrics", tag.getFirst(FieldKey.LYRICS)); assertEquals("199", tag.getFirst(FieldKey.BPM)); assertEquals("Albumartist", tag.getFirst(FieldKey.ALBUM_ARTIST)); assertEquals("Sortalbumartist", tag.getFirst(FieldKey.ALBUM_ARTIST_SORT)); assertEquals("Sortalbum", tag.getFirst(FieldKey.ALBUM_SORT)); assertEquals("GROUping", tag.getFirst(FieldKey.GROUPING)); assertEquals("Sortcomposer", tag.getFirst(FieldKey.COMPOSER_SORT)); assertEquals("sorttitle", tag.getFirst(FieldKey.TITLE_SORT)); assertEquals("1", tag.getFirst(FieldKey.IS_COMPILATION)); assertEquals("66027994-edcf-9d89-bec8-0d30077d888c", tag.getFirst(FieldKey.MUSICIP_ID)); assertEquals("e785f700-c1aa-4943-bcee-87dd316a2c30", tag.getFirst(FieldKey.MUSICBRAINZ_TRACK_ID)); assertEquals("989a13f6-b58c-4559-b09e-76ae0adb94ed", tag.getFirst(FieldKey.MUSICBRAINZ_ARTISTID)); assertEquals("989a13f6-b58c-4559-b09e-76ae0adb94ed", tag.getFirst(FieldKey.MUSICBRAINZ_RELEASEARTISTID)); assertEquals("19c6f0f6-3d6d-4b02-88c7-ffb559d52be6", tag.getFirst(FieldKey.MUSICBRAINZ_RELEASEID)); //Cast to format specific tag Mp4Tag mp4tag = (Mp4Tag) tag; //Lookup by mp4 key assertEquals("Artist", mp4tag.getFirst(Mp4FieldKey.ARTIST)); assertEquals("Album", mp4tag.getFirst(Mp4FieldKey.ALBUM)); assertEquals("title", mp4tag.getFirst(Mp4FieldKey.TITLE)); assertEquals("comments", mp4tag.getFirst(Mp4FieldKey.COMMENT)); assertEquals("1971", mp4tag.getFirst(Mp4FieldKey.DAY)); //Not sure why there are 4 values, only understand 2nd and third assertEquals("1/10", mp4tag.getFirst(Mp4FieldKey.TRACK)); assertEquals("1/10", ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getContent()); assertEquals(new Short("0"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getNumbers().get(0)); assertEquals(new Short("1"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getNumbers().get(1)); assertEquals(new Short("10"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getNumbers().get(2)); assertEquals(new Short("0"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getNumbers().get(3)); //Not sure why there are 4 values, only understand 2nd and third assertEquals("1/10", mp4tag.getFirst(Mp4FieldKey.DISCNUMBER)); assertEquals("1/10", ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.DISCNUMBER).get(0)).getContent()); assertEquals(new Short("0"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.DISCNUMBER).get(0)).getNumbers().get(0)); assertEquals(new Short("1"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.DISCNUMBER).get(0)).getNumbers().get(1)); assertEquals(new Short("10"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.DISCNUMBER).get(0)).getNumbers().get(2)); assertEquals("composer", mp4tag.getFirst(Mp4FieldKey.COMPOSER)); assertEquals("Sortartist", mp4tag.getFirst(Mp4FieldKey.ARTIST_SORT)); assertEquals("lyrics", mp4tag.getFirst(Mp4FieldKey.LYRICS)); assertEquals("199", mp4tag.getFirst(Mp4FieldKey.BPM)); assertEquals("Albumartist", mp4tag.getFirst(Mp4FieldKey.ALBUM_ARTIST)); assertEquals("Sortalbumartist", mp4tag.getFirst(Mp4FieldKey.ALBUM_ARTIST_SORT)); assertEquals("Sortalbum", mp4tag.getFirst(Mp4FieldKey.ALBUM_SORT)); assertEquals("GROUping", mp4tag.getFirst(Mp4FieldKey.GROUPING)); assertEquals("Sortcomposer", mp4tag.getFirst(Mp4FieldKey.COMPOSER_SORT)); assertEquals("sorttitle", mp4tag.getFirst(Mp4FieldKey.TITLE_SORT)); assertEquals("1", mp4tag.getFirst(Mp4FieldKey.COMPILATION)); assertEquals("66027994-edcf-9d89-bec8-0d30077d888c", mp4tag.getFirst(Mp4FieldKey.MUSICIP_PUID)); assertEquals("e785f700-c1aa-4943-bcee-87dd316a2c30", mp4tag.getFirst(Mp4FieldKey.MUSICBRAINZ_TRACKID)); assertEquals("989a13f6-b58c-4559-b09e-76ae0adb94ed", mp4tag.getFirst(Mp4FieldKey.MUSICBRAINZ_ARTISTID)); assertEquals("989a13f6-b58c-4559-b09e-76ae0adb94ed", mp4tag.getFirst(Mp4FieldKey.MUSICBRAINZ_ALBUMARTISTID)); assertEquals("19c6f0f6-3d6d-4b02-88c7-ffb559d52be6", mp4tag.getFirst(Mp4FieldKey.MUSICBRAINZ_ALBUMID)); Mp4TagReverseDnsField rvs = (Mp4TagReverseDnsField) mp4tag.getFirstField(Mp4FieldKey.MUSICBRAINZ_ALBUMID); assertEquals("com.apple.iTunes", rvs.getIssuer()); assertEquals("MusicBrainz Album Id", rvs.getDescriptor()); assertEquals("19c6f0f6-3d6d-4b02-88c7-ffb559d52be6", rvs.getContent()); //Lookup by mp4key (no generic key mapping for these yet) assertEquals(" 000002C0 00000298 00004210 00002FD5 0001CB31 0001CB48 0000750D 00007C4A 000291A8 00029191", mp4tag.getFirst(Mp4FieldKey.ITUNES_NORM)); assertEquals(" 00000000 00000840 000000E4 0000000000A29EDC 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000", mp4tag.getFirst(Mp4FieldKey.ITUNES_SMPB)); assertEquals("0", mp4tag.getFirst(Mp4FieldKey.PART_OF_GAPLESS_ALBUM)); assertEquals("iTunes v7.4.3.1, QuickTime 7.2", mp4tag.getFirst(Mp4FieldKey.ENCODER)); assertEquals("sortshow", mp4tag.getFirst(Mp4FieldKey.SHOW_SORT)); assertEquals("show", mp4tag.getFirst(Mp4FieldKey.SHOW)); assertEquals("Genre", mp4tag.getFirst(Mp4FieldKey.GENRE_CUSTOM)); assertEquals(String.valueOf(Mp4RatingValue.EXPLICIT.getId()), mp4tag.getFirst(Mp4FieldKey.RATING)); assertEquals(String.valueOf(Mp4ContentTypeValue.BOOKLET.getId()), mp4tag.getFirst(Mp4FieldKey.CONTENT_TYPE)); List coverart = mp4tag.get(Mp4FieldKey.ARTWORK); //Should be one image assertEquals(2, coverart.size()); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * Test to write all fields to check all can be written, just use simple file as starting point *

* TODO:Test incomplete */ public void testWriteAllFields() { Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test5.m4a", new File("testWriteAllFields.m4a")); AudioFile f = AudioFileIO.read(testFile); Tag tag = f.getTag(); assertEquals(TEST_FILE5_SIZE, testFile.length()); //Change values tag.setField(FieldKey.ARTIST,"VERYLONGARTISTNAME"); tag.setField(FieldKey.ALBUM,"VERYLONGALBUMTNAME"); tag.setField(FieldKey.ALBUM_ARTIST, "A1"); tag.setField(FieldKey.ALBUM_ARTIST_SORT, "A2"); tag.setField(FieldKey.ALBUM_SORT, "A3"); tag.setField(FieldKey.AMAZON_ID, "A4"); tag.setField(FieldKey.ARTIST_SORT, "A5"); tag.setField(FieldKey.BPM, "200"); tag.setField(FieldKey.COMMENT, "C1"); tag.setField(FieldKey.COMPOSER, "C2"); tag.setField(FieldKey.COMPOSER_SORT, "C3"); tag.setField(FieldKey.DISC_NO, "1"); tag.setField(FieldKey.TRACK, "1"); assertEquals("1",tag.getFirst(FieldKey.TRACK)); tag.setField(FieldKey.MUSICBRAINZ_ARTISTID, "1"); tag.setField(FieldKey.MUSICBRAINZ_RELEASEID, "2"); tag.setField(FieldKey.MUSICBRAINZ_TRACK_ID, "3"); tag.setField(FieldKey.MUSICBRAINZ_DISC_ID, "4"); tag.setField(FieldKey.MUSICBRAINZ_RELEASE_COUNTRY, "5"); tag.setField(FieldKey.MUSICBRAINZ_RELEASE_STATUS, "6"); tag.setField(FieldKey.MUSICBRAINZ_RELEASE_TYPE, "7"); tag.setField(FieldKey.MUSICBRAINZ_RELEASEARTISTID, "8"); tag.setField(FieldKey.MUSICIP_ID, "9"); tag.setField(FieldKey.GENRE, "2"); //key for classic rock tag.setField(FieldKey.ENCODER, "encoder"); tag.setField(FieldKey.URL_LYRICS_SITE,"http://www.lyrics.fly.com"); tag.setField(FieldKey.URL_DISCOGS_ARTIST_SITE,"http://www.discogs1.com"); tag.setField(FieldKey.URL_DISCOGS_RELEASE_SITE,"http://www.discogs2.com"); tag.setField(FieldKey.URL_OFFICIAL_ARTIST_SITE,"http://www.discogs3.com"); tag.setField(FieldKey.URL_OFFICIAL_RELEASE_SITE,"http://www.discogs4.com"); tag.setField(FieldKey.URL_WIKIPEDIA_ARTIST_SITE,"http://www.discogs5.com"); tag.setField(FieldKey.URL_WIKIPEDIA_RELEASE_SITE,"http://www.discogs6.com"); assertEquals("1",tag.getFirst(FieldKey.TRACK)); assertEquals("",tag.getFirst(FieldKey.TRACK_TOTAL)); tag.setField(FieldKey.TRACK_TOTAL,"11"); tag.setField(FieldKey.DISC_TOTAL,"3"); //error content not updated when just setField field //They share Field assertEquals(1,tag.getFields(FieldKey.TRACK_TOTAL).size()); assertEquals(1,tag.getFields(FieldKey.TRACK).size()); //They share Field assertEquals(1,tag.getFields(FieldKey.DISC_NO).size()); assertEquals(1,tag.getFields(FieldKey.DISC_TOTAL).size()); assertEquals(1,tag.getFields("trkn").size()); assertEquals(1,tag.getFields("disk").size()); assertEquals("1",tag.getFirst(FieldKey.TRACK)); assertEquals("11",tag.getFirst(FieldKey.TRACK_TOTAL)); assertEquals("1",tag.getFirst(FieldKey.DISC_NO)); assertEquals("3",tag.getFirst(FieldKey.DISC_TOTAL)); //Save changes and reread from disk f.commit(); f = AudioFileIO.read(testFile); tag = f.getTag(); System.out.println(f.getAudioHeader()); System.out.println(tag); //AudioInfo //Time in seconds assertEquals(14, f.getAudioHeader().getTrackLength()); assertEquals(44100, f.getAudioHeader().getSampleRateAsNumber()); //Stereo thing doesnt work //assertEquals(new String("2"),f.getAudioHeader().getChannels()); //Ease of use methods for common fields assertEquals("VERYLONGARTISTNAME", tag.getFirst(FieldKey.ARTIST)); assertEquals("VERYLONGALBUMTNAME", tag.getFirst(FieldKey.ALBUM)); assertEquals("A1", tag.getFirst(FieldKey.ALBUM_ARTIST)); assertEquals("A2", tag.getFirst(FieldKey.ALBUM_ARTIST_SORT)); assertEquals("A3", tag.getFirst(FieldKey.ALBUM_SORT)); assertEquals("A4", tag.getFirst(FieldKey.AMAZON_ID)); assertEquals("A5", tag.getFirst(FieldKey.ARTIST_SORT)); assertEquals("200", tag.getFirst(FieldKey.BPM)); assertEquals("C1", tag.getFirst(FieldKey.COMMENT)); assertEquals("C2", tag.getFirst(FieldKey.COMPOSER)); assertEquals("C3", tag.getFirst(FieldKey.COMPOSER_SORT)); assertEquals("1", tag.getFirst(FieldKey.TRACK)); assertEquals("1", tag.getFirst(FieldKey.DISC_NO)); assertEquals("11", tag.getFirst(FieldKey.TRACK_TOTAL)); assertEquals("3", tag.getFirst(FieldKey.DISC_TOTAL)); assertEquals("1", tag.getFirst(FieldKey.MUSICBRAINZ_ARTISTID)); assertEquals("2", tag.getFirst(FieldKey.MUSICBRAINZ_RELEASEID)); assertEquals("3", tag.getFirst(FieldKey.MUSICBRAINZ_TRACK_ID)); assertEquals("4", tag.getFirst(FieldKey.MUSICBRAINZ_DISC_ID)); assertEquals("5", tag.getFirst(FieldKey.MUSICBRAINZ_RELEASE_COUNTRY)); assertEquals("6", tag.getFirst(FieldKey.MUSICBRAINZ_RELEASE_STATUS)); assertEquals("7", tag.getFirst(FieldKey.MUSICBRAINZ_RELEASE_TYPE)); assertEquals("8", tag.getFirst(FieldKey.MUSICBRAINZ_RELEASEARTISTID)); assertEquals("9", tag.getFirst(FieldKey.MUSICIP_ID)); assertEquals("Classic Rock", tag.getFirst(FieldKey.GENRE)); assertEquals("http://www.lyrics.fly.com",tag.getFirst(FieldKey.URL_LYRICS_SITE)); assertEquals("http://www.discogs1.com",tag.getFirst(FieldKey.URL_DISCOGS_ARTIST_SITE)); assertEquals("http://www.discogs2.com",tag.getFirst(FieldKey.URL_DISCOGS_RELEASE_SITE)); assertEquals("http://www.discogs3.com",tag.getFirst(FieldKey.URL_OFFICIAL_ARTIST_SITE)); assertEquals("http://www.discogs4.com",tag.getFirst(FieldKey.URL_OFFICIAL_RELEASE_SITE)); assertEquals("http://www.discogs5.com",tag.getFirst(FieldKey.URL_WIKIPEDIA_ARTIST_SITE)); assertEquals("http://www.discogs6.com",tag.getFirst(FieldKey.URL_WIKIPEDIA_RELEASE_SITE)); assertEquals("11",tag.getFirst(FieldKey.TRACK_TOTAL)); assertEquals("3",tag.getFirst(FieldKey.DISC_TOTAL)); assertEquals("1/11",tag.getFirst("trkn")); assertEquals("1/3",tag.getFirst("disk")); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * Testing to ensure can only have genre or custom genre not both */ public void testWriteGenres() { Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test5.m4a", new File("testWriteGenres.m4a")); AudioFile f = AudioFileIO.read(testFile); Mp4Tag tag = (Mp4Tag) f.getTag(); assertEquals(TEST_FILE5_SIZE, testFile.length()); //Change value using key tag.setField(tag.createField(FieldKey.GENRE, "2")); //key for classic rock f.commit(); f = AudioFileIO.read(testFile); tag = (Mp4Tag) f.getTag(); assertEquals("Classic Rock", tag.getFirst(FieldKey.GENRE)); assertEquals("Classic Rock", tag.getFirst(Mp4FieldKey.GENRE)); assertEquals("", tag.getFirst(Mp4FieldKey.GENRE_CUSTOM)); //coz doesnt exist //Change value using string tag.setField(tag.createField(FieldKey.GENRE, "Tango")); //key for classic rock f.commit(); f = AudioFileIO.read(testFile); tag = (Mp4Tag) f.getTag(); assertEquals("Tango", tag.getFirst(FieldKey.GENRE)); assertEquals("Tango", tag.getFirst(Mp4FieldKey.GENRE)); assertEquals("", tag.getFirst(Mp4FieldKey.GENRE_CUSTOM)); //coz doesnt exist //Change value using string which is ok for ID3 but because extended winamp is ot ok for mp4 //so has to use custom tag.setField(tag.createField(FieldKey.GENRE, "SynthPop")); f.commit(); f = AudioFileIO.read(testFile); tag = (Mp4Tag) f.getTag(); //TODO really want this value to didsappear automtically but unfortunately have to manully do it //at moment 9 see next) assertEquals("Tango", tag.getFirst(FieldKey.GENRE)); assertEquals("Tango", tag.getFirst(Mp4FieldKey.GENRE)); assertEquals("SynthPop", tag.getFirst(Mp4FieldKey.GENRE_CUSTOM)); //Delete fields and let lib decide what to do (has to use custom) tag.deleteField(Mp4FieldKey.GENRE); tag.deleteField(Mp4FieldKey.GENRE_CUSTOM); tag.setField(tag.createField(FieldKey.GENRE, "SynthPop")); assertEquals("SynthPop", tag.getFirst(FieldKey.GENRE)); assertEquals("", tag.getFirst(Mp4FieldKey.GENRE)); assertEquals("SynthPop", tag.getFirst(Mp4FieldKey.GENRE_CUSTOM)); f.commit(); f = AudioFileIO.read(testFile); tag = (Mp4Tag) f.getTag(); //Delete fields and let lib decide what to do (can use list) tag.deleteField(Mp4FieldKey.GENRE); tag.deleteField(Mp4FieldKey.GENRE_CUSTOM); tag.setField(tag.createField(FieldKey.GENRE, "Tango")); assertEquals("Tango", tag.getFirst(FieldKey.GENRE)); assertEquals("Tango", tag.getFirst(Mp4FieldKey.GENRE)); assertEquals("", tag.getFirst(Mp4FieldKey.GENRE_CUSTOM)); f.commit(); f = AudioFileIO.read(testFile); tag = (Mp4Tag) f.getTag(); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * Test saving to file that contains a mdat atom and then a free atom at the end of file, normally it is the other * way round or there is no free atom. */ public void testWriteWhenFreeisAfterMdat() { Exception exceptionCaught = null; try { File orig = new File("testdata", "unable_to_write.m4p"); if (!orig.isFile()) { return; } File testFile = AbstractTestCase.copyAudioToTmp("unable_to_write.m4p"); AudioFile f = AudioFileIO.read(testFile); Tag tag = f.getTag(); tag.setField(FieldKey.TITLE,"tit2"); f.commit(); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } public void testWriteMuchLargerWhenFreeIsAfterMdat() { Exception exceptionCaught = null; try { File orig = new File("testdata", "unable_to_write.m4p"); if (!orig.isFile()) { return; } File testFile = AbstractTestCase.copyAudioToTmp("unable_to_write.m4p"); AudioFile f = AudioFileIO.read(testFile); Tag tag = f.getTag(); RandomAccessFile imageFile = new RandomAccessFile(new File("testdata", "coverart.png"), "r"); byte[] imagedata = new byte[(int) imageFile.length()]; imageFile.read(imagedata); tag.addField(((Mp4Tag) tag).createArtworkField(imagedata)); f.commit(); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } public void testWriteFileLargerSizeLessThanTopLevelFreeWhenFreeAafterMdat() { Exception exceptionCaught = null; try { File orig = new File("testdata", "unable_to_write.m4p"); if (!orig.isFile()) { return; } File testFile = AbstractTestCase.copyAudioToTmp("unable_to_write.m4p"); AudioFile f = AudioFileIO.read(testFile); Tag tag = f.getTag(); //Frig adding pretend image which will require exactly the same size as space available in the two //free atoms byte[] imagedata = new byte[1340]; imagedata[0] = (byte) 0x89; imagedata[1] = (byte) 0x50; imagedata[2] = (byte) 0x4E; imagedata[3] = (byte) 0x47; tag.addField(((Mp4Tag) tag).createArtworkField(imagedata)); f.commit(); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } public void testWriteFileLargerSizeEqualToTopLevelFreeWhenFreeAafterMdat() { Exception exceptionCaught = null; try { File orig = new File("testdata", "unable_to_write.m4p"); if (!orig.isFile()) { return; } File testFile = AbstractTestCase.copyAudioToTmp("unable_to_write.m4p"); AudioFile f = AudioFileIO.read(testFile); Tag tag = f.getTag(); //Frig adding pretend image which will require exactly the same size as space available in the two //free atoms byte[] imagedata = new byte[1349]; imagedata[0] = (byte) 0x89; imagedata[1] = (byte) 0x50; imagedata[2] = (byte) 0x4E; imagedata[3] = (byte) 0x47; tag.addField(((Mp4Tag) tag).createArtworkField(imagedata)); f.commit(); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * Test Wrting mp4 file * * @throws Exception */ public void testWritingIssue198() throws Exception { File orig = new File("testdata", "test27.m4a"); if (!orig.isFile()) { return; } Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test27.m4a", new File("rvdnswithoutdata.m4a")); AudioFile f = AudioFileIO.read(testFile); Mp4Tag tag = (Mp4Tag) f.getTag(); tag.setField(FieldKey.TITLE,"Title"); tag.setField(FieldKey.ALBUM,"Album"); tag.setField(tag.createField(Mp4FieldKey.CDDB_TRACKNUMBER, "1")); f.commit(); //Reread changes f = AudioFileIO.read(testFile); tag = (Mp4Tag) f.getTag(); assertEquals("Title", tag.getFirst(FieldKey.TITLE)); assertEquals("Album", tag.getFirst(FieldKey.ALBUM)); assertEquals("Buddy Holly & the Crickets", tag.getFirst(FieldKey.ARTIST)); assertEquals(1, tag.get(Mp4FieldKey.ITUNES_NORM).size()); assertEquals(0, tag.get(Mp4FieldKey.ITUNES_SMPB).size()); assertEquals(1, tag.get(Mp4FieldKey.CDDB_1).size()); assertEquals(1, tag.get(Mp4FieldKey.CDDB_TRACKNUMBER).size()); assertEquals(1, tag.get(Mp4FieldKey.CDDB_IDS).size()); System.out.println(f.getAudioHeader()); System.out.println(tag); } catch (IOException e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } public void testWriteMultipleFields() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("test.m4a", new File("testWriteMultiple.m4a")); AudioFile f = AudioFileIO.read(testFile); List tagFields = f.getTag().getFields(FieldKey.ALBUM_ARTIST_SORT); assertEquals(tagFields.size(),1); f.getTag().addField(FieldKey.ALBUM_ARTIST_SORT,"artist1"); f.getTag().addField(FieldKey.ALBUM_ARTIST_SORT,"artist2"); f.commit(); f = AudioFileIO.read(testFile); tagFields = f.getTag().getFields(FieldKey.ALBUM_ARTIST_SORT); assertEquals(tagFields.size(),3); } public void testDeleteFields() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("test.m4a"); //Delete using generic key AudioFile f = AudioFileIO.read(testFile); List tagFields = f.getTag().getFields(FieldKey.ALBUM_ARTIST_SORT); assertEquals(1,tagFields.size()); tagFields = f.getTag().getFields(FieldKey.ALBUM_ARTIST_SORT); assertEquals(1,tagFields.size()); f.getTag().deleteField(FieldKey.ALBUM_ARTIST_SORT); f.commit(); //Delete using mp4key f = AudioFileIO.read(testFile); tagFields = f.getTag().getFields(FieldKey.ALBUM_ARTIST_SORT); assertEquals(0,tagFields.size()); f.getTag().addField(FieldKey.ALBUM_ARTIST_SORT,"artist1"); tagFields = f.getTag().getFields(FieldKey.ALBUM_ARTIST_SORT); assertEquals(1,tagFields.size()); f.getTag().deleteField("soaa"); tagFields = f.getTag().getFields(FieldKey.ALBUM_ARTIST_SORT); assertEquals(0,tagFields.size()); f.commit(); f = AudioFileIO.read(testFile); tagFields = f.getTag().getFields(FieldKey.ALBUM_ARTIST_SORT); assertEquals(0,tagFields.size()); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/mp4/M4aReadTagTest.java0000644000175000017500000016712211470746136027257 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.mp4; import junit.framework.TestCase; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.audio.exceptions.CannotReadVideoException; import org.jaudiotagger.audio.mp4.EncoderType; import org.jaudiotagger.audio.mp4.Mp4AudioHeader; import org.jaudiotagger.audio.mp4.Mp4TagReader; import org.jaudiotagger.audio.mp4.atom.Mp4EsdsBox; import org.jaudiotagger.tag.FieldKey; import org.jaudiotagger.tag.Tag; import org.jaudiotagger.tag.mp4.atom.Mp4ContentTypeValue; import org.jaudiotagger.tag.mp4.atom.Mp4RatingValue; import org.jaudiotagger.tag.mp4.field.*; import org.jaudiotagger.tag.reference.GenreTypes; import javax.imageio.ImageIO; import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.nio.charset.Charset; import java.util.List; /** */ public class M4aReadTagTest extends TestCase { /** * Test to read all metadata from an Apple iTunes encoded m4a file */ public void testReadFile() { Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test.m4a"); AudioFile f = AudioFileIO.read(testFile); Tag tag = f.getTag(); System.out.println(f.getAudioHeader()); System.out.println(tag); //AudioInfo //Time in seconds assertEquals(241, f.getAudioHeader().getTrackLength()); assertEquals(44100, f.getAudioHeader().getSampleRateAsNumber()); assertEquals(new String("2"), f.getAudioHeader().getChannels()); assertEquals(128, f.getAudioHeader().getBitRateAsNumber()); //MPEG Specific Mp4AudioHeader audioheader = (Mp4AudioHeader) f.getAudioHeader(); assertEquals(Mp4EsdsBox.Kind.MPEG4_AUDIO, audioheader.getKind()); assertEquals(Mp4EsdsBox.AudioProfile.LOW_COMPLEXITY, audioheader.getProfile()); //Ease of use methods for common fields assertEquals("Artist", tag.getFirst(FieldKey.ARTIST)); assertEquals("Album", tag.getFirst(FieldKey.ALBUM)); assertEquals("title", tag.getFirst(FieldKey.TITLE)); assertEquals("comments", tag.getFirst(FieldKey.COMMENT)); assertEquals("1971", tag.getFirst(FieldKey.YEAR)); assertEquals("1", tag.getFirst(FieldKey.TRACK)); //Although using custom genre this call works this out and gets correct value assertEquals("Genre", tag.getFirst(FieldKey.GENRE)); //Lookup by generickey assertEquals("Artist", tag.getFirst(FieldKey.ARTIST)); assertEquals("Album", tag.getFirst(FieldKey.ALBUM)); assertEquals("title", tag.getFirst(FieldKey.TITLE)); assertEquals("comments", tag.getFirst(FieldKey.COMMENT)); assertEquals("1971", tag.getFirst(FieldKey.YEAR)); assertEquals("1", tag.getFirst(FieldKey.TRACK)); assertEquals("10", tag.getFirst(FieldKey.TRACK_TOTAL)); assertEquals("1", tag.getFirst(FieldKey.DISC_NO)); assertEquals("10", tag.getFirst(FieldKey.DISC_TOTAL)); assertEquals("composer", tag.getFirst(FieldKey.COMPOSER)); assertEquals("Sortartist", tag.getFirst(FieldKey.ARTIST_SORT)); assertEquals("lyrics", tag.getFirst(FieldKey.LYRICS)); assertEquals("199", tag.getFirst(FieldKey.BPM)); assertEquals("Albumartist", tag.getFirst(FieldKey.ALBUM_ARTIST)); assertEquals("Sortalbumartist", tag.getFirst(FieldKey.ALBUM_ARTIST_SORT)); assertEquals("Sortalbum", tag.getFirst(FieldKey.ALBUM_SORT)); assertEquals("GROUping", tag.getFirst(FieldKey.GROUPING)); assertEquals("Sortcomposer", tag.getFirst(FieldKey.COMPOSER_SORT)); assertEquals("sorttitle", tag.getFirst(FieldKey.TITLE_SORT)); assertEquals("1", tag.getFirst(FieldKey.IS_COMPILATION)); assertEquals("iTunes v7.4.3.1, QuickTime 7.2", tag.getFirst(FieldKey.ENCODER)); assertEquals("66027994-edcf-9d89-bec8-0d30077d888c", tag.getFirst(FieldKey.MUSICIP_ID)); assertEquals("e785f700-c1aa-4943-bcee-87dd316a2c30", tag.getFirst(FieldKey.MUSICBRAINZ_TRACK_ID)); assertEquals("989a13f6-b58c-4559-b09e-76ae0adb94ed", tag.getFirst(FieldKey.MUSICBRAINZ_ARTISTID)); assertEquals("989a13f6-b58c-4559-b09e-76ae0adb94ed", tag.getFirst(FieldKey.MUSICBRAINZ_RELEASEARTISTID)); assertEquals("19c6f0f6-3d6d-4b02-88c7-ffb559d52be6", tag.getFirst(FieldKey.MUSICBRAINZ_RELEASEID)); //Cast to format specific tag Mp4Tag mp4tag = (Mp4Tag) tag; //Lookup by mp4 key assertEquals("Artist", mp4tag.getFirst(Mp4FieldKey.ARTIST)); assertEquals("Album", mp4tag.getFirst(Mp4FieldKey.ALBUM)); assertEquals("title", mp4tag.getFirst(Mp4FieldKey.TITLE)); assertEquals("comments", mp4tag.getFirst(Mp4FieldKey.COMMENT)); assertEquals("1971", mp4tag.getFirst(Mp4FieldKey.DAY)); //Not sure why there are 4 values, only understand 2nd and third assertEquals("1/10", mp4tag.getFirst(Mp4FieldKey.TRACK)); assertEquals("1/10", ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getContent()); assertEquals(new Short("0"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getNumbers().get(0)); assertEquals(new Short("1"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getNumbers().get(1)); assertEquals(new Short("10"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getNumbers().get(2)); assertEquals(new Short("0"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getNumbers().get(3)); assertEquals(new Short("1"), ((Mp4TrackField) mp4tag.getFirstField(Mp4FieldKey.TRACK)).getTrackNo()); assertEquals(new Short("10"), ((Mp4TrackField) mp4tag.getFirstField(Mp4FieldKey.TRACK)).getTrackTotal()); //Not sure why there are 4 values, only understand 2nd and third assertEquals("1/10", mp4tag.getFirst(Mp4FieldKey.DISCNUMBER)); assertEquals("1/10", ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.DISCNUMBER).get(0)).getContent()); assertEquals(new Short("0"), ((Mp4TagTextNumberField) mp4tag.getFirstField(Mp4FieldKey.DISCNUMBER)).getNumbers().get(0)); assertEquals(new Short("1"), ((Mp4TagTextNumberField) mp4tag.getFirstField(Mp4FieldKey.DISCNUMBER)).getNumbers().get(1)); assertEquals(new Short("10"), ((Mp4TagTextNumberField) mp4tag.getFirstField(Mp4FieldKey.DISCNUMBER)).getNumbers().get(2)); assertEquals(new Short("1"), ((Mp4DiscNoField) mp4tag.getFirstField(Mp4FieldKey.DISCNUMBER)).getDiscNo()); assertEquals(new Short("10"), ((Mp4DiscNoField) mp4tag.getFirstField(Mp4FieldKey.DISCNUMBER)).getDiscTotal()); assertEquals("composer", mp4tag.getFirst(Mp4FieldKey.COMPOSER)); assertEquals("Sortartist", mp4tag.getFirst(Mp4FieldKey.ARTIST_SORT)); assertEquals("lyrics", mp4tag.getFirst(Mp4FieldKey.LYRICS)); assertEquals("199", mp4tag.getFirst(Mp4FieldKey.BPM)); assertEquals("Albumartist", mp4tag.getFirst(Mp4FieldKey.ALBUM_ARTIST)); assertEquals("Sortalbumartist", mp4tag.getFirst(Mp4FieldKey.ALBUM_ARTIST_SORT)); assertEquals("Sortalbum", mp4tag.getFirst(Mp4FieldKey.ALBUM_SORT)); assertEquals("GROUping", mp4tag.getFirst(Mp4FieldKey.GROUPING)); assertEquals("Sortcomposer", mp4tag.getFirst(Mp4FieldKey.COMPOSER_SORT)); assertEquals("sorttitle", mp4tag.getFirst(Mp4FieldKey.TITLE_SORT)); assertEquals("1", mp4tag.getFirst(Mp4FieldKey.COMPILATION)); assertEquals("66027994-edcf-9d89-bec8-0d30077d888c", mp4tag.getFirst(Mp4FieldKey.MUSICIP_PUID)); assertEquals("e785f700-c1aa-4943-bcee-87dd316a2c30", mp4tag.getFirst(Mp4FieldKey.MUSICBRAINZ_TRACKID)); assertEquals("989a13f6-b58c-4559-b09e-76ae0adb94ed", mp4tag.getFirst(Mp4FieldKey.MUSICBRAINZ_ARTISTID)); assertEquals("989a13f6-b58c-4559-b09e-76ae0adb94ed", mp4tag.getFirst(Mp4FieldKey.MUSICBRAINZ_ALBUMARTISTID)); assertEquals("19c6f0f6-3d6d-4b02-88c7-ffb559d52be6", mp4tag.getFirst(Mp4FieldKey.MUSICBRAINZ_ALBUMID)); Mp4TagReverseDnsField rvs = (Mp4TagReverseDnsField) mp4tag.getFirstField(Mp4FieldKey.MUSICBRAINZ_ALBUMID); assertEquals("com.apple.iTunes", rvs.getIssuer()); assertEquals("MusicBrainz Album Id", rvs.getDescriptor()); assertEquals("19c6f0f6-3d6d-4b02-88c7-ffb559d52be6", rvs.getContent()); //Lookup by mp4key (no generic key mapping for these yet) assertEquals(" 000002C0 00000298 00004210 00002FD5 0001CB31 0001CB48 0000750D 00007C4A 000291A8 00029191", mp4tag.getFirst(Mp4FieldKey.ITUNES_NORM)); assertEquals(" 00000000 00000840 000000E4 0000000000A29EDC 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000", mp4tag.getFirst(Mp4FieldKey.ITUNES_SMPB)); assertEquals("0", mp4tag.getFirst(Mp4FieldKey.PART_OF_GAPLESS_ALBUM)); assertEquals("iTunes v7.4.3.1, QuickTime 7.2", mp4tag.getFirst(Mp4FieldKey.ENCODER)); assertEquals("sortshow", mp4tag.getFirst(Mp4FieldKey.SHOW_SORT)); assertEquals("show", mp4tag.getFirst(Mp4FieldKey.SHOW)); assertEquals("Genre", mp4tag.getFirst(Mp4FieldKey.GENRE_CUSTOM)); assertEquals(String.valueOf(Mp4RatingValue.EXPLICIT.getId()), mp4tag.getFirst(Mp4FieldKey.RATING)); assertEquals(String.valueOf(Mp4ContentTypeValue.BOOKLET.getId()), mp4tag.getFirst(Mp4FieldKey.CONTENT_TYPE)); List coverart = mp4tag.get(Mp4FieldKey.ARTWORK); //Should be one image assertEquals(1, coverart.size()); Mp4TagCoverField coverArtField = (Mp4TagCoverField) coverart.get(0); //Check type jpeg assertEquals(Mp4FieldType.COVERART_JPEG, coverArtField.getFieldType()); //Just check jpeg signature assertEquals(0xff, coverArtField.getData()[0] & 0xff); assertEquals(0xd8, coverArtField.getData()[1] & 0xff); assertEquals(0xff, coverArtField.getData()[2] & 0xff); assertEquals(0xe0, coverArtField.getData()[3] & 0xff); //Recreate the image BufferedImage bi = ImageIO.read(ImageIO .createImageInputStream(new ByteArrayInputStream(coverArtField.getData()))); assertNotNull(bi); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * Test to check comptaibility with latest verison of media Monkey */ public void testReadFileFromMediaMonkey306() { File orig = new File("testdata", "test38.m4a"); if (!orig.isFile()) { System.err.println("Unable to test file - not available"); return; } Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test38.m4a"); AudioFile f = AudioFileIO.read(testFile); Tag tag = f.getTag(); System.out.println(f.getAudioHeader()); System.out.println(tag); //AudioInfo //Time in seconds assertEquals(241, f.getAudioHeader().getTrackLength()); assertEquals(44100, f.getAudioHeader().getSampleRateAsNumber()); assertEquals(new String("2"), f.getAudioHeader().getChannels()); assertEquals(128, f.getAudioHeader().getBitRateAsNumber()); //MPEG Specific Mp4AudioHeader audioheader = (Mp4AudioHeader) f.getAudioHeader(); assertEquals(Mp4EsdsBox.Kind.MPEG4_AUDIO, audioheader.getKind()); assertEquals(Mp4EsdsBox.AudioProfile.LOW_COMPLEXITY, audioheader.getProfile()); //Lookup by generickey assertEquals("artistname", tag.getFirst(FieldKey.ARTIST)); assertEquals("Album", tag.getFirst(FieldKey.ALBUM)); assertEquals("title", tag.getFirst(FieldKey.TITLE)); assertEquals("comments", tag.getFirst(FieldKey.COMMENT)); assertEquals("1971", tag.getFirst(FieldKey.YEAR)); assertEquals("1", tag.getFirst(FieldKey.TRACK)); assertEquals("10", tag.getFirst(FieldKey.TRACK_TOTAL)); assertEquals("1", tag.getFirst(FieldKey.DISC_NO)); assertEquals("10", tag.getFirst(FieldKey.DISC_TOTAL)); assertEquals("composer", tag.getFirst(FieldKey.COMPOSER)); assertEquals("Sortartist", tag.getFirst(FieldKey.ARTIST_SORT)); assertEquals("lyrics", tag.getFirst(FieldKey.LYRICS)); assertEquals("199", tag.getFirst(FieldKey.BPM)); assertEquals("Albumartist", tag.getFirst(FieldKey.ALBUM_ARTIST)); assertEquals("Sortalbumartist", tag.getFirst(FieldKey.ALBUM_ARTIST_SORT)); assertEquals("Sortalbum", tag.getFirst(FieldKey.ALBUM_SORT)); assertEquals("grouping", tag.getFirst(FieldKey.GROUPING)); assertEquals("Sortcomposer", tag.getFirst(FieldKey.COMPOSER_SORT)); assertEquals("sorttitle", tag.getFirst(FieldKey.TITLE_SORT)); assertEquals("1", tag.getFirst(FieldKey.IS_COMPILATION)); assertEquals("iTunes v7.4.3.1, QuickTime 7.2", tag.getFirst(FieldKey.ENCODER)); assertEquals("66027994-edcf-9d89-bec8-0d30077d888c", tag.getFirst(FieldKey.MUSICIP_ID)); assertEquals("e785f700-c1aa-4943-bcee-87dd316a2c30", tag.getFirst(FieldKey.MUSICBRAINZ_TRACK_ID)); assertEquals("989a13f6-b58c-4559-b09e-76ae0adb94ed", tag.getFirst(FieldKey.MUSICBRAINZ_ARTISTID)); assertEquals("989a13f6-b58c-4559-b09e-76ae0adb94ed", tag.getFirst(FieldKey.MUSICBRAINZ_RELEASEARTISTID)); assertEquals("19c6f0f6-3d6d-4b02-88c7-ffb559d52be6", tag.getFirst(FieldKey.MUSICBRAINZ_RELEASEID)); //Cast to format specific tag Mp4Tag mp4tag = (Mp4Tag) tag; //Lookup by mp4 key assertEquals("artistname", mp4tag.getFirst(Mp4FieldKey.ARTIST)); assertEquals("Album", mp4tag.getFirst(Mp4FieldKey.ALBUM)); assertEquals("title", mp4tag.getFirst(Mp4FieldKey.TITLE)); assertEquals("comments", mp4tag.getFirst(Mp4FieldKey.COMMENT)); assertEquals("1971", mp4tag.getFirst(Mp4FieldKey.DAY)); //Not sure why there are 4 values, only understand 2nd and third assertEquals("1/10", mp4tag.getFirst(Mp4FieldKey.TRACK)); assertEquals("1/10", ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getContent()); assertEquals(new Short("0"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getNumbers().get(0)); assertEquals(new Short("1"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getNumbers().get(1)); assertEquals(new Short("10"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getNumbers().get(2)); assertEquals(new Short("0"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getNumbers().get(3)); assertEquals(new Short("1"), ((Mp4TrackField) mp4tag.getFirstField(Mp4FieldKey.TRACK)).getTrackNo()); assertEquals(new Short("10"), ((Mp4TrackField) mp4tag.getFirstField(Mp4FieldKey.TRACK)).getTrackTotal()); //Not sure why there are 4 values, only understand 2nd and third assertEquals("1/10", mp4tag.getFirst(Mp4FieldKey.DISCNUMBER)); assertEquals("1/10", ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.DISCNUMBER).get(0)).getContent()); assertEquals(new Short("0"), ((Mp4TagTextNumberField) mp4tag.getFirstField(Mp4FieldKey.DISCNUMBER)).getNumbers().get(0)); assertEquals(new Short("1"), ((Mp4TagTextNumberField) mp4tag.getFirstField(Mp4FieldKey.DISCNUMBER)).getNumbers().get(1)); assertEquals(new Short("10"), ((Mp4TagTextNumberField) mp4tag.getFirstField(Mp4FieldKey.DISCNUMBER)).getNumbers().get(2)); assertEquals(new Short("1"), ((Mp4DiscNoField) mp4tag.getFirstField(Mp4FieldKey.DISCNUMBER)).getDiscNo()); assertEquals(new Short("10"), ((Mp4DiscNoField) mp4tag.getFirstField(Mp4FieldKey.DISCNUMBER)).getDiscTotal()); assertEquals("composer", mp4tag.getFirst(Mp4FieldKey.COMPOSER)); assertEquals("Sortartist", mp4tag.getFirst(Mp4FieldKey.ARTIST_SORT)); assertEquals("lyrics", mp4tag.getFirst(Mp4FieldKey.LYRICS)); assertEquals("199", mp4tag.getFirst(Mp4FieldKey.BPM)); assertEquals("Albumartist", mp4tag.getFirst(Mp4FieldKey.ALBUM_ARTIST)); assertEquals("Sortalbumartist", mp4tag.getFirst(Mp4FieldKey.ALBUM_ARTIST_SORT)); assertEquals("Sortalbum", mp4tag.getFirst(Mp4FieldKey.ALBUM_SORT)); assertEquals("grouping", mp4tag.getFirst(Mp4FieldKey.GROUPING)); assertEquals("Sortcomposer", mp4tag.getFirst(Mp4FieldKey.COMPOSER_SORT)); assertEquals("sorttitle", mp4tag.getFirst(Mp4FieldKey.TITLE_SORT)); assertEquals("1", mp4tag.getFirst(Mp4FieldKey.COMPILATION)); assertEquals("66027994-edcf-9d89-bec8-0d30077d888c", mp4tag.getFirst(Mp4FieldKey.MUSICIP_PUID)); assertEquals("e785f700-c1aa-4943-bcee-87dd316a2c30", mp4tag.getFirst(Mp4FieldKey.MUSICBRAINZ_TRACKID)); assertEquals("989a13f6-b58c-4559-b09e-76ae0adb94ed", mp4tag.getFirst(Mp4FieldKey.MUSICBRAINZ_ARTISTID)); assertEquals("989a13f6-b58c-4559-b09e-76ae0adb94ed", mp4tag.getFirst(Mp4FieldKey.MUSICBRAINZ_ALBUMARTISTID)); assertEquals("19c6f0f6-3d6d-4b02-88c7-ffb559d52be6", mp4tag.getFirst(Mp4FieldKey.MUSICBRAINZ_ALBUMID)); Mp4TagReverseDnsField rvs = (Mp4TagReverseDnsField) mp4tag.getFirstField(Mp4FieldKey.MUSICBRAINZ_ALBUMID); assertEquals("com.apple.iTunes", rvs.getIssuer()); assertEquals("MusicBrainz Album Id", rvs.getDescriptor()); assertEquals("19c6f0f6-3d6d-4b02-88c7-ffb559d52be6", rvs.getContent()); //Lookup by mp4key (no generic key mapping for these yet) assertEquals(" 000002C0 00000298 00004210 00002FD5 0001CB31 0001CB48 0000750D 00007C4A 000291A8 00029191", mp4tag.getFirst(Mp4FieldKey.ITUNES_NORM)); assertEquals(" 00000000 00000840 000000E4 0000000000A29EDC 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000", mp4tag.getFirst(Mp4FieldKey.ITUNES_SMPB)); assertEquals("1", mp4tag.getFirst(Mp4FieldKey.PART_OF_GAPLESS_ALBUM)); assertEquals("iTunes v7.4.3.1, QuickTime 7.2", mp4tag.getFirst(Mp4FieldKey.ENCODER)); assertEquals("sortshow", mp4tag.getFirst(Mp4FieldKey.SHOW_SORT)); assertEquals("show", mp4tag.getFirst(Mp4FieldKey.SHOW)); assertEquals("genre", mp4tag.getFirst(Mp4FieldKey.GENRE_CUSTOM)); List coverart = mp4tag.get(Mp4FieldKey.ARTWORK); //Should be three image assertEquals(3, coverart.size()); Mp4TagCoverField coverArtField = (Mp4TagCoverField) coverart.get(0); //Check type png assertEquals(Mp4FieldType.COVERART_PNG, coverArtField.getFieldType()); //Recreate the image BufferedImage bi = ImageIO.read(ImageIO .createImageInputStream(new ByteArrayInputStream(coverArtField.getData()))); assertNotNull(bi); //These fields seemed to have changed in Media Monkey 3.0.6 assertEquals("custom1", mp4tag.getFirst(Mp4FieldKey.MM_CUSTOM_1)); assertEquals("custom2", mp4tag.getFirst(Mp4FieldKey.MM_CUSTOM_2)); assertEquals("custom3", mp4tag.getFirst(Mp4FieldKey.MM_CUSTOM_3)); assertEquals("custom4", mp4tag.getFirst(Mp4FieldKey.MM_CUSTOM_4)); assertEquals("custom5", mp4tag.getFirst(Mp4FieldKey.MM_CUSTOM_5)); assertEquals("publisher", mp4tag.getFirst(Mp4FieldKey.MM_PUBLISHER)); assertEquals("originalartist", mp4tag.getFirst(Mp4FieldKey.MM_ORIGINAL_ARTIST)); assertEquals("originalalbumtitle", mp4tag.getFirst(Mp4FieldKey.MM_ORIGINAL_ALBUM_TITLE)); assertEquals("involvedpeople", mp4tag.getFirst(Mp4FieldKey.MM_INVOLVED_PEOPLE)); assertEquals("2001", mp4tag.getFirst(Mp4FieldKey.MM_ORIGINAL_YEAR)); assertEquals("Slow", mp4tag.getFirst(Mp4FieldKey.MM_TEMPO)); assertEquals("Dinner", mp4tag.getFirst(Mp4FieldKey.MM_OCCASION)); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * Test to check comptaibility with latest verison of media Monkey */ public void testReadFileFromWinamp5531() { File orig = new File("testdata", "test39.m4a"); if (!orig.isFile()) { System.err.println("Unable to test file - not available"); return; } Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test39.m4a"); AudioFile f = AudioFileIO.read(testFile); Tag tag = f.getTag(); System.out.println(f.getAudioHeader()); System.out.println(tag); //AudioInfo //Time in seconds assertEquals(241, f.getAudioHeader().getTrackLength()); assertEquals(44100, f.getAudioHeader().getSampleRateAsNumber()); assertEquals(new String("2"), f.getAudioHeader().getChannels()); assertEquals(126, f.getAudioHeader().getBitRateAsNumber()); //MPEG Specific Mp4AudioHeader audioheader = (Mp4AudioHeader) f.getAudioHeader(); assertEquals(Mp4EsdsBox.Kind.MPEG4_AUDIO, audioheader.getKind()); assertEquals(Mp4EsdsBox.AudioProfile.LOW_COMPLEXITY, audioheader.getProfile()); //Lookup by generickey assertEquals("artistname", tag.getFirst(FieldKey.ARTIST)); assertEquals("Album", tag.getFirst(FieldKey.ALBUM)); assertEquals("title", tag.getFirst(FieldKey.TITLE)); assertEquals("comments", tag.getFirst(FieldKey.COMMENT)); assertEquals("1971", tag.getFirst(FieldKey.YEAR)); assertEquals("1", tag.getFirst(FieldKey.TRACK)); assertEquals("1", tag.getFirst(FieldKey.DISC_NO)); assertEquals("composer", tag.getFirst(FieldKey.COMPOSER)); assertEquals("Sortartist", tag.getFirst(FieldKey.ARTIST_SORT)); assertEquals("lyrics", tag.getFirst(FieldKey.LYRICS)); assertEquals("199", tag.getFirst(FieldKey.BPM)); assertEquals("Albumartist", tag.getFirst(FieldKey.ALBUM_ARTIST)); //Cast to format specific tag Mp4Tag mp4tag = (Mp4Tag) tag; //Lookup by mp4 key assertEquals("artistname", mp4tag.getFirst(Mp4FieldKey.ARTIST)); assertEquals("Album", mp4tag.getFirst(Mp4FieldKey.ALBUM)); assertEquals("title", mp4tag.getFirst(Mp4FieldKey.TITLE)); assertEquals("comments", mp4tag.getFirst(Mp4FieldKey.COMMENT)); assertEquals("1971", mp4tag.getFirst(Mp4FieldKey.DAY)); //These fields added by winamp assertEquals("publisher", mp4tag.getFirst(Mp4FieldKey.WINAMP_PUBLISHER)); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * Test to read all metadata from an Apple iTunes encoded m4a file , this tests a few items that could not * be tested with first test. Namely genre picked from list, and png item instead of jpg *

* TODO:Although selected genre from a list still seems to be using a custom genre */ public void testReadFile2() { Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test2.m4a"); AudioFile f = AudioFileIO.read(testFile); Tag tag = f.getTag(); System.out.println(f.getAudioHeader()); System.out.println(tag); //AudioInfo //Time in seconds assertEquals(241, f.getAudioHeader().getTrackLength()); assertEquals(44100, f.getAudioHeader().getSampleRateAsNumber()); //MPEG Specific Mp4AudioHeader audioheader = (Mp4AudioHeader) f.getAudioHeader(); assertEquals(Mp4EsdsBox.Kind.MPEG4_AUDIO, audioheader.getKind()); assertEquals(Mp4EsdsBox.AudioProfile.LOW_COMPLEXITY, audioheader.getProfile()); //Ease of use methods for common fields assertEquals("Artist\u01fft", tag.getFirst(FieldKey.ARTIST)); assertEquals("Album", tag.getFirst(FieldKey.ALBUM)); assertEquals("title", tag.getFirst(FieldKey.TITLE)); assertEquals("comments", tag.getFirst(FieldKey.COMMENT)); assertEquals("1971", tag.getFirst(FieldKey.YEAR)); assertEquals("1", tag.getFirst(FieldKey.TRACK)); //Althjough using cusotm genre this call works this out and gets correct value assertEquals("Religious", tag.getFirst(FieldKey.GENRE)); //Lookup by generickey assertEquals("Artist\u01fft", tag.getFirst(FieldKey.ARTIST)); assertEquals("Album", tag.getFirst(FieldKey.ALBUM)); assertEquals("title", tag.getFirst(FieldKey.TITLE)); assertEquals("comments", tag.getFirst(FieldKey.COMMENT)); assertEquals("1971", tag.getFirst(FieldKey.YEAR)); assertEquals("1", tag.getFirst(FieldKey.TRACK)); assertEquals("10", tag.getFirst(FieldKey.TRACK_TOTAL)); assertEquals("1", tag.getFirst(FieldKey.DISC_NO)); assertEquals("10", tag.getFirst(FieldKey.DISC_TOTAL)); assertEquals("composer", tag.getFirst(FieldKey.COMPOSER)); assertEquals("Sortartist", tag.getFirst(FieldKey.ARTIST_SORT)); assertEquals("lyrics", tag.getFirst(FieldKey.LYRICS)); assertEquals("199", tag.getFirst(FieldKey.BPM)); assertEquals("Albumartist", tag.getFirst(FieldKey.ALBUM_ARTIST)); assertEquals("Sortalbumartist", tag.getFirst(FieldKey.ALBUM_ARTIST_SORT)); assertEquals("Sortalbum", tag.getFirst(FieldKey.ALBUM_SORT)); assertEquals("GROUping", tag.getFirst(FieldKey.GROUPING)); assertEquals("Sortcomposer", tag.getFirst(FieldKey.COMPOSER_SORT)); assertEquals("sorttitle", tag.getFirst(FieldKey.TITLE_SORT)); assertEquals("1", tag.getFirst(FieldKey.IS_COMPILATION)); assertEquals("66027994-edcf-9d89-bec8-0d30077d888c", tag.getFirst(FieldKey.MUSICIP_ID)); assertEquals("e785f700-c1aa-4943-bcee-87dd316a2c30", tag.getFirst(FieldKey.MUSICBRAINZ_TRACK_ID)); assertEquals("989a13f6-b58c-4559-b09e-76ae0adb94ed", tag.getFirst(FieldKey.MUSICBRAINZ_ARTISTID)); assertEquals("989a13f6-b58c-4559-b09e-76ae0adb94ed", tag.getFirst(FieldKey.MUSICBRAINZ_RELEASEARTISTID)); assertEquals("19c6f0f6-3d6d-4b02-88c7-ffb559d52be6", tag.getFirst(FieldKey.MUSICBRAINZ_RELEASEID)); //Cast to format specific tag Mp4Tag mp4tag = (Mp4Tag) tag; //Lookup by mp4 key assertEquals("Artist\u01fft", mp4tag.getFirst(Mp4FieldKey.ARTIST)); assertEquals("Album", mp4tag.getFirst(Mp4FieldKey.ALBUM)); assertEquals("title", mp4tag.getFirst(Mp4FieldKey.TITLE)); assertEquals("comments", mp4tag.getFirst(Mp4FieldKey.COMMENT)); assertEquals("1971", mp4tag.getFirst(Mp4FieldKey.DAY)); //Not sure why there are 4 values, only understand 2nd and third assertEquals("1/10", mp4tag.getFirst(Mp4FieldKey.TRACK)); assertEquals("1/10", ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getContent()); assertEquals(new Short("0"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getNumbers().get(0)); assertEquals(new Short("1"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getNumbers().get(1)); assertEquals(new Short("10"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getNumbers().get(2)); assertEquals(new Short("0"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getNumbers().get(3)); //Not sure why there are 4 values, only understand 2nd and third assertEquals("1/10", mp4tag.getFirst(Mp4FieldKey.DISCNUMBER)); assertEquals("1/10", ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.DISCNUMBER).get(0)).getContent()); assertEquals(new Short("0"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.DISCNUMBER).get(0)).getNumbers().get(0)); assertEquals(new Short("1"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.DISCNUMBER).get(0)).getNumbers().get(1)); assertEquals(new Short("10"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.DISCNUMBER).get(0)).getNumbers().get(2)); assertEquals("composer", mp4tag.getFirst(Mp4FieldKey.COMPOSER)); assertEquals("Sortartist", mp4tag.getFirst(Mp4FieldKey.ARTIST_SORT)); assertEquals("lyrics", mp4tag.getFirst(Mp4FieldKey.LYRICS)); assertEquals("199", mp4tag.getFirst(Mp4FieldKey.BPM)); assertEquals("Albumartist", mp4tag.getFirst(Mp4FieldKey.ALBUM_ARTIST)); assertEquals("Sortalbumartist", mp4tag.getFirst(Mp4FieldKey.ALBUM_ARTIST_SORT)); assertEquals("Sortalbum", mp4tag.getFirst(Mp4FieldKey.ALBUM_SORT)); assertEquals("GROUping", mp4tag.getFirst(Mp4FieldKey.GROUPING)); assertEquals("Sortcomposer", mp4tag.getFirst(Mp4FieldKey.COMPOSER_SORT)); assertEquals("sorttitle", mp4tag.getFirst(Mp4FieldKey.TITLE_SORT)); assertEquals("1", mp4tag.getFirst(Mp4FieldKey.COMPILATION)); assertEquals("66027994-edcf-9d89-bec8-0d30077d888c", mp4tag.getFirst(Mp4FieldKey.MUSICIP_PUID)); assertEquals("e785f700-c1aa-4943-bcee-87dd316a2c30", mp4tag.getFirst(Mp4FieldKey.MUSICBRAINZ_TRACKID)); assertEquals("989a13f6-b58c-4559-b09e-76ae0adb94ed", mp4tag.getFirst(Mp4FieldKey.MUSICBRAINZ_ARTISTID)); assertEquals("989a13f6-b58c-4559-b09e-76ae0adb94ed", mp4tag.getFirst(Mp4FieldKey.MUSICBRAINZ_ALBUMARTISTID)); assertEquals("19c6f0f6-3d6d-4b02-88c7-ffb559d52be6", mp4tag.getFirst(Mp4FieldKey.MUSICBRAINZ_ALBUMID)); //Lookup by mp4key (no generic key mapping for these yet) assertEquals("iTunes v7.4.3.1, QuickTime 7.2", mp4tag.getFirst(Mp4FieldKey.ENCODER)); assertEquals("sortshow", mp4tag.getFirst(Mp4FieldKey.SHOW_SORT)); assertEquals("show", mp4tag.getFirst(Mp4FieldKey.SHOW)); assertEquals("Religious", mp4tag.getFirst(Mp4FieldKey.GENRE_CUSTOM)); assertEquals("1", mp4tag.getFirst(Mp4FieldKey.PART_OF_GAPLESS_ALBUM)); assertEquals(" 000002C0 00000298 00004210 00002FD5 0001CB31 0001CB48 0000750D 00007C4A 000291A8 00029191", mp4tag.getFirst(Mp4FieldKey.ITUNES_NORM)); assertEquals(" 00000000 00000840 000000E4 0000000000A29EDC 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000", mp4tag.getFirst(Mp4FieldKey.ITUNES_SMPB)); List coverart = mp4tag.get(Mp4FieldKey.ARTWORK); //Should be one image assertEquals(3, coverart.size()); //Check 1st field Mp4TagCoverField coverArtField = (Mp4TagCoverField) coverart.get(0); //Check type png assertEquals(Mp4FieldType.COVERART_PNG, coverArtField.getFieldType()); //Just check png signature assertEquals(0x89, coverArtField.getData()[0] & 0xff); assertEquals(0x50, coverArtField.getData()[1] & 0xff); assertEquals(0x4E, coverArtField.getData()[2] & 0xff); assertEquals(0x47, coverArtField.getData()[3] & 0xff); //Recreate the image BufferedImage bi = ImageIO.read(ImageIO .createImageInputStream(new ByteArrayInputStream(coverArtField.getData()))); assertNotNull(bi); //Check 2nd field coverArtField = (Mp4TagCoverField) coverart.get(1); //Check type png assertEquals(Mp4FieldType.COVERART_PNG, coverArtField.getFieldType()); //Just check png signature assertEquals(0x89, coverArtField.getData()[0] & 0xff); assertEquals(0x50, coverArtField.getData()[1] & 0xff); assertEquals(0x4E, coverArtField.getData()[2] & 0xff); assertEquals(0x47, coverArtField.getData()[3] & 0xff); //Recreate the image bi = ImageIO.read(ImageIO .createImageInputStream(new ByteArrayInputStream(coverArtField.getData()))); assertNotNull(bi); //Check 3rd Field coverArtField = (Mp4TagCoverField) coverart.get(2); //Check type jpeg System.out.println("FieldType:"+coverArtField.getFieldType()); assertEquals(Mp4FieldType.COVERART_JPEG, coverArtField.getFieldType()); //Just check jpeg signature assertEquals(0xff, coverArtField.getData()[0] & 0xff); assertEquals(0xd8, coverArtField.getData()[1] & 0xff); assertEquals(0xff, coverArtField.getData()[2] & 0xff); assertEquals(0xe0, coverArtField.getData()[3] & 0xff); //Recreate the image bi = ImageIO.read(ImageIO .createImageInputStream(new ByteArrayInputStream(coverArtField.getData()))); assertNotNull(bi); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * Test to read all metadata from an Apple iTunes encoded m4a file which doesnt have a meta free atom */ public void testReadFileWithNoMetaFreeAtom() { Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test3.m4a"); AudioFile f = AudioFileIO.read(testFile); Tag tag = f.getTag(); System.out.println(f.getAudioHeader()); System.out.println(tag); //AudioInfo //Time in seconds assertEquals(241, f.getAudioHeader().getTrackLength()); assertEquals(44100, f.getAudioHeader().getSampleRateAsNumber()); //MPEG Specific Mp4AudioHeader audioheader = (Mp4AudioHeader) f.getAudioHeader(); assertEquals(Mp4EsdsBox.Kind.MPEG4_AUDIO, audioheader.getKind()); assertEquals(Mp4EsdsBox.AudioProfile.LOW_COMPLEXITY, audioheader.getProfile()); //Ease of use methods for common fields assertEquals("Artist", tag.getFirst(FieldKey.ARTIST)); assertEquals("Album", tag.getFirst(FieldKey.ALBUM)); assertEquals("title", tag.getFirst(FieldKey.TITLE)); assertEquals("comments", tag.getFirst(FieldKey.COMMENT)); assertEquals("1971", tag.getFirst(FieldKey.YEAR)); assertEquals("1", tag.getFirst(FieldKey.TRACK)); //Althjough using cusotm genre this call works this out and gets correct value assertEquals("Genre", tag.getFirst(FieldKey.GENRE)); //Lookup by generickey assertEquals("Artist", tag.getFirst(FieldKey.ARTIST)); assertEquals("Album", tag.getFirst(FieldKey.ALBUM)); assertEquals("title", tag.getFirst(FieldKey.TITLE)); assertEquals("comments", tag.getFirst(FieldKey.COMMENT)); assertEquals("1971", tag.getFirst(FieldKey.YEAR)); assertEquals("1", tag.getFirst(FieldKey.TRACK)); assertEquals("1", tag.getFirst(FieldKey.DISC_NO)); assertEquals("10", tag.getFirst(FieldKey.TRACK_TOTAL)); assertEquals("10", tag.getFirst(FieldKey.DISC_TOTAL)); assertEquals("composer", tag.getFirst(FieldKey.COMPOSER)); assertEquals("Sortartist", tag.getFirst(FieldKey.ARTIST_SORT)); assertEquals("lyrics", tag.getFirst(FieldKey.LYRICS)); assertEquals("199", tag.getFirst(FieldKey.BPM)); assertEquals("Albumartist", tag.getFirst(FieldKey.ALBUM_ARTIST)); assertEquals("Sortalbumartist", tag.getFirst(FieldKey.ALBUM_ARTIST_SORT)); assertEquals("Sortalbum", tag.getFirst(FieldKey.ALBUM_SORT)); assertEquals("GROUping", tag.getFirst(FieldKey.GROUPING)); assertEquals("Sortcomposer", tag.getFirst(FieldKey.COMPOSER_SORT)); assertEquals("sorttitle", tag.getFirst(FieldKey.TITLE_SORT)); assertEquals("1", tag.getFirst(FieldKey.IS_COMPILATION)); assertEquals("66027994-edcf-9d89-bec8-0d30077d888c", tag.getFirst(FieldKey.MUSICIP_ID)); assertEquals("e785f700-c1aa-4943-bcee-87dd316a2c30", tag.getFirst(FieldKey.MUSICBRAINZ_TRACK_ID)); assertEquals("989a13f6-b58c-4559-b09e-76ae0adb94ed", tag.getFirst(FieldKey.MUSICBRAINZ_ARTISTID)); assertEquals("989a13f6-b58c-4559-b09e-76ae0adb94ed", tag.getFirst(FieldKey.MUSICBRAINZ_RELEASEARTISTID)); assertEquals("19c6f0f6-3d6d-4b02-88c7-ffb559d52be6", tag.getFirst(FieldKey.MUSICBRAINZ_RELEASEID)); //Cast to format specific tag Mp4Tag mp4tag = (Mp4Tag) tag; //Lookup by mp4 key assertEquals("Artist", mp4tag.getFirst(Mp4FieldKey.ARTIST)); assertEquals("Album", mp4tag.getFirst(Mp4FieldKey.ALBUM)); assertEquals("title", mp4tag.getFirst(Mp4FieldKey.TITLE)); assertEquals("comments", mp4tag.getFirst(Mp4FieldKey.COMMENT)); assertEquals("1971", mp4tag.getFirst(Mp4FieldKey.DAY)); //Not sure why there are 4 values, only understand 2nd and third assertEquals("1/10", mp4tag.getFirst(Mp4FieldKey.TRACK)); assertEquals("1/10", ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getContent()); assertEquals(new Short("0"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getNumbers().get(0)); assertEquals(new Short("1"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getNumbers().get(1)); assertEquals(new Short("10"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getNumbers().get(2)); assertEquals(new Short("0"), ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.TRACK).get(0)).getNumbers().get(3)); assertEquals(new Short("1"), ((Mp4TrackField) mp4tag.getFirstField(Mp4FieldKey.TRACK)).getTrackNo()); assertEquals(new Short("10"), ((Mp4TrackField) mp4tag.getFirstField(Mp4FieldKey.TRACK)).getTrackTotal()); //Not sure why there are 4 values, only understand 2nd and third assertEquals("1/10", mp4tag.getFirst(Mp4FieldKey.DISCNUMBER)); assertEquals("1/10", ((Mp4TagTextNumberField) mp4tag.get(Mp4FieldKey.DISCNUMBER).get(0)).getContent()); assertEquals(new Short("0"), ((Mp4TagTextNumberField) mp4tag.getFirstField(Mp4FieldKey.DISCNUMBER)).getNumbers().get(0)); assertEquals(new Short("1"), ((Mp4TagTextNumberField) mp4tag.getFirstField(Mp4FieldKey.DISCNUMBER)).getNumbers().get(1)); assertEquals(new Short("10"), ((Mp4TagTextNumberField) mp4tag.getFirstField(Mp4FieldKey.DISCNUMBER)).getNumbers().get(2)); assertEquals(new Short("1"), ((Mp4DiscNoField) mp4tag.getFirstField(Mp4FieldKey.DISCNUMBER)).getDiscNo()); assertEquals(new Short("10"), ((Mp4DiscNoField) mp4tag.getFirstField(Mp4FieldKey.DISCNUMBER)).getDiscTotal()); assertEquals("composer", mp4tag.getFirst(Mp4FieldKey.COMPOSER)); assertEquals("Sortartist", mp4tag.getFirst(Mp4FieldKey.ARTIST_SORT)); assertEquals("lyrics", mp4tag.getFirst(Mp4FieldKey.LYRICS)); assertEquals("199", mp4tag.getFirst(Mp4FieldKey.BPM)); assertEquals("Albumartist", mp4tag.getFirst(Mp4FieldKey.ALBUM_ARTIST)); assertEquals("Sortalbumartist", mp4tag.getFirst(Mp4FieldKey.ALBUM_ARTIST_SORT)); assertEquals("Sortalbum", mp4tag.getFirst(Mp4FieldKey.ALBUM_SORT)); assertEquals("GROUping", mp4tag.getFirst(Mp4FieldKey.GROUPING)); assertEquals("Sortcomposer", mp4tag.getFirst(Mp4FieldKey.COMPOSER_SORT)); assertEquals("sorttitle", mp4tag.getFirst(Mp4FieldKey.TITLE_SORT)); assertEquals("1", mp4tag.getFirst(Mp4FieldKey.COMPILATION)); assertEquals("66027994-edcf-9d89-bec8-0d30077d888c", mp4tag.getFirst(Mp4FieldKey.MUSICIP_PUID)); assertEquals("e785f700-c1aa-4943-bcee-87dd316a2c30", mp4tag.getFirst(Mp4FieldKey.MUSICBRAINZ_TRACKID)); assertEquals("989a13f6-b58c-4559-b09e-76ae0adb94ed", mp4tag.getFirst(Mp4FieldKey.MUSICBRAINZ_ARTISTID)); assertEquals("989a13f6-b58c-4559-b09e-76ae0adb94ed", mp4tag.getFirst(Mp4FieldKey.MUSICBRAINZ_ALBUMARTISTID)); assertEquals("19c6f0f6-3d6d-4b02-88c7-ffb559d52be6", mp4tag.getFirst(Mp4FieldKey.MUSICBRAINZ_ALBUMID)); Mp4TagReverseDnsField rvs = (Mp4TagReverseDnsField) mp4tag.getFirstField(Mp4FieldKey.MUSICBRAINZ_ALBUMID); assertEquals("com.apple.iTunes", rvs.getIssuer()); assertEquals("MusicBrainz Album Id", rvs.getDescriptor()); assertEquals("19c6f0f6-3d6d-4b02-88c7-ffb559d52be6", rvs.getContent()); //Lookup by mp4key (no generic key mapping for these yet) assertEquals(" 000002C0 00000298 00004210 00002FD5 0001CB31 0001CB48 0000750D 00007C4A 000291A8 00029191", mp4tag.getFirst(Mp4FieldKey.ITUNES_NORM)); assertEquals(" 00000000 00000840 000000E4 0000000000A29EDC 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000", mp4tag.getFirst(Mp4FieldKey.ITUNES_SMPB)); assertEquals("0", mp4tag.getFirst(Mp4FieldKey.PART_OF_GAPLESS_ALBUM)); assertEquals("iTunes v7.4.3.1, QuickTime 7.2", mp4tag.getFirst(Mp4FieldKey.ENCODER)); assertEquals("sortshow", mp4tag.getFirst(Mp4FieldKey.SHOW_SORT)); assertEquals("show", mp4tag.getFirst(Mp4FieldKey.SHOW)); assertEquals("Genre", mp4tag.getFirst(Mp4FieldKey.GENRE_CUSTOM)); assertEquals(String.valueOf(Mp4RatingValue.EXPLICIT.getId()), mp4tag.getFirst(Mp4FieldKey.RATING)); assertEquals(String.valueOf(Mp4ContentTypeValue.BOOKLET.getId()), mp4tag.getFirst(Mp4FieldKey.CONTENT_TYPE)); List coverart = mp4tag.get(Mp4FieldKey.ARTWORK); //Should be one image assertEquals(1, coverart.size()); Mp4TagCoverField coverArtField = (Mp4TagCoverField) coverart.get(0); //Check type jpeg assertEquals(Mp4FieldType.COVERART_JPEG, coverArtField.getFieldType()); //Just check jpeg signature assertEquals(0xff, coverArtField.getData()[0] & 0xff); assertEquals(0xd8, coverArtField.getData()[1] & 0xff); assertEquals(0xff, coverArtField.getData()[2] & 0xff); assertEquals(0xe0, coverArtField.getData()[3] & 0xff); //Recreate the image BufferedImage bi = ImageIO.read(ImageIO .createImageInputStream(new ByteArrayInputStream(coverArtField.getData()))); assertNotNull(bi); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } public void testDetectVideo() { File orig = new File("testdata", "test7.mp4"); if (!orig.isFile()) { return; } Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test7.mp4"); AudioFile f = AudioFileIO.read(testFile); } catch (Exception e) { e.printStackTrace(System.err); exceptionCaught = e; } assertNotNull(exceptionCaught); assertTrue(exceptionCaught instanceof CannotReadVideoException); } /** * testing reading of header with low bit rate and mono channels */ public void testMonoLowbitRateReadFile() { Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test5.m4a"); AudioFile f = AudioFileIO.read(testFile); Tag tag = f.getTag(); System.out.println(f.getAudioHeader()); System.out.println(tag); //AudioInfo //Time in seconds assertEquals(14, f.getAudioHeader().getTrackLength()); assertEquals(44100, f.getAudioHeader().getSampleRateAsNumber()); assertEquals(new String("1"), f.getAudioHeader().getChannels()); assertEquals(64, f.getAudioHeader().getBitRateAsNumber()); //MPEG Specific Mp4AudioHeader audioheader = (Mp4AudioHeader) f.getAudioHeader(); assertEquals(Mp4EsdsBox.Kind.MPEG4_AUDIO, audioheader.getKind()); assertEquals(Mp4EsdsBox.AudioProfile.LOW_COMPLEXITY, audioheader.getProfile()); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * Test Issue #156:Handling of known fields with invalid fieldtypes * * @throws Exception */ public void testIssue156() throws Exception { Exception exceptionCaught = null; try { File orig = new File("testdata", "test13.m4a"); if (!orig.isFile()) { return; } File testFile = AbstractTestCase.copyAudioToTmp("test13.m4a"); AudioFile f = AudioFileIO.read(testFile); Tag tag = f.getTag(); System.out.println(f.getAudioHeader()); System.out.println(tag); //AudioInfo //Time in seconds assertEquals(219, f.getAudioHeader().getTrackLength()); assertEquals(44100, f.getAudioHeader().getSampleRateAsNumber()); //MPEG Specific Mp4AudioHeader audioheader = (Mp4AudioHeader) f.getAudioHeader(); assertEquals(Mp4EsdsBox.Kind.MPEG4_AUDIO, audioheader.getKind()); assertEquals(Mp4EsdsBox.AudioProfile.LOW_COMPLEXITY, audioheader.getProfile()); //These shouldn't be any values for these. because they have invalid fieldtype of 15 instead of 21 assertEquals("", tag.getFirst(FieldKey.BPM)); assertEquals("", tag.getFirst(FieldKey.IS_COMPILATION)); } catch (IOException e) { e.printStackTrace(); exceptionCaught = e; } try { File testFile = AbstractTestCase.copyAudioToTmp("test3.m4a", new File("testIssue156.m4a")); AudioFile f = AudioFileIO.read(testFile); Tag tag = f.getTag(); System.out.println(f.getAudioHeader()); System.out.println(tag); //Allow calling getFirst() on binary fields, although value actually currently makes not much sense assertEquals("COVERART_JPEG:8445bytes", tag.getFirst(FieldKey.COVER_ART)); } catch (IOException e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } public void testIssue163() { Exception exceptionCaught = null; try { //Charset Testing UTf8 String copyright_symbol = "\u00A9"; ByteBuffer bb = Charset.forName("UTF-8").encode(copyright_symbol); bb.rewind(); System.out.println("utf8 bb size is:" + bb.limit()); { System.out.println("utf8 byte value is " + (bb.get(0) & 0xFF)); System.out.println("utf8 byte value is " + (bb.get(1) & 0xFF)); } bb = Charset.forName("ISO-8859-1").encode(copyright_symbol); bb.rewind(); System.out.println("ISO-8859-1 bb size is:" + bb.limit()); { System.out.println("ISO-8859-1 byte value is " + (bb.get(0) & 0xFF)); } File orig = new File("testdata", "unable_to_read.m4a"); if (!orig.isFile()) { return; } File testFile = AbstractTestCase.copyAudioToTmp("unable_to_read.m4a"); AudioFile f = AudioFileIO.read(testFile); Tag tag = f.getTag(); tag.getFirst(FieldKey.ALBUM); tag.getFirst(FieldKey.ARTIST); tag.getFirst(FieldKey.COMMENT); tag.getFirst(FieldKey.GENRE); tag.getFirst(FieldKey.TITLE); tag.getFirst(FieldKey.TRACK); tag.getFirst(FieldKey.YEAR); System.out.println(tag); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } public void testGenre() { Exception exceptionCaught = null; try { assertNull(GenreTypes.getInstanceOf().getIdForValue("fred")); Mp4GenreField.isValidGenre("fred"); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * Test reading filers tagged with monkeymedia, which has custom image tags and additiona mm tags * * @throws Exception */ public void testIssue168() throws Exception { Exception exceptionCaught = null; try { File orig = new File("testdata", "test14.m4a"); if (!orig.isFile()) { return; } File testFile = AbstractTestCase.copyAudioToTmp("test14.m4a"); AudioFile f = AudioFileIO.read(testFile); Mp4Tag tag = (Mp4Tag) f.getTag(); System.out.println(f.getAudioHeader()); System.out.println(tag); //AudioInfo //Time in seconds assertEquals(241, f.getAudioHeader().getTrackLength()); assertEquals(44100, f.getAudioHeader().getSampleRateAsNumber()); //MPEG Specific Mp4AudioHeader audioheader = (Mp4AudioHeader) f.getAudioHeader(); assertEquals(Mp4EsdsBox.Kind.MPEG4_AUDIO, audioheader.getKind()); assertEquals(Mp4EsdsBox.AudioProfile.LOW_COMPLEXITY, audioheader.getProfile()); assertEquals(1, tag.getFields(Mp4NonStandardFieldKey.AAPR.getFieldName()).size()); assertNotNull(tag.getFirst(Mp4NonStandardFieldKey.AAPR.getFieldName())); assertEquals("AApr", tag.getFirstField(Mp4NonStandardFieldKey.AAPR.getFieldName()).getId()); //Make a change and save tag.setField(FieldKey.TITLE,"NEWTITLE\u00A9\u01ff"); //test UTF8 encoding tag.setField(tag.createField(Mp4FieldKey.CONTENT_TYPE, Mp4ContentTypeValue.TV_SHOW.getIdAsString())); f.commit(); f = AudioFileIO.read(testFile); tag = (Mp4Tag) f.getTag(); assertEquals("AApr", tag.getFirstField(Mp4NonStandardFieldKey.AAPR.getFieldName()).getId()); assertEquals("NEWTITLE\u00A9\u01ff", tag.getFirst(FieldKey.TITLE)); assertEquals(Mp4ContentTypeValue.TV_SHOW.getIdAsString(), tag.getFirst(Mp4FieldKey.CONTENT_TYPE)); assertEquals(1, tag.getFields(Mp4NonStandardFieldKey.AAPR.getFieldName()).size()); assertNotNull(tag.getFirst(Mp4NonStandardFieldKey.AAPR.getFieldName())); //Can we read all the other customfields (that do follow convention) System.out.println(tag.toString()); assertEquals("lyricist", tag.getFirst(Mp4FieldKey.LYRICIST_MM3BETA)); assertEquals("70", tag.getFirst(Mp4FieldKey.SCORE)); assertEquals("conductor", tag.getFirst(Mp4FieldKey.CONDUCTOR_MM3BETA)); assertEquals("original artist", tag.getFirst(Mp4FieldKey.ORIGINAL_ARTIST)); assertEquals("original album title", tag.getFirst(Mp4FieldKey.ORIGINAL_ALBUM_TITLE)); assertEquals("involved people", tag.getFirst(Mp4FieldKey.INVOLVED_PEOPLE)); assertEquals("Slow", tag.getFirst(Mp4FieldKey.TEMPO)); assertEquals("Mellow", tag.getFirst(Mp4FieldKey.MOOD_MM3BETA)); assertEquals("Dinner", tag.getFirst(Mp4FieldKey.OCCASION)); assertEquals("Very good copy", tag.getFirst(Mp4FieldKey.QUALITY)); assertEquals("custom1", tag.getFirst(Mp4FieldKey.CUSTOM_1)); assertEquals("custom2", tag.getFirst(Mp4FieldKey.CUSTOM_2)); assertEquals("custom3", tag.getFirst(Mp4FieldKey.CUSTOM_3)); assertEquals("custom4", tag.getFirst(Mp4FieldKey.CUSTOM_4)); assertEquals("custom5", tag.getFirst(Mp4FieldKey.CUSTOM_5)); } catch (IOException e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * Tests reading of winamp encoded files, that contain additional scene tracks */ public void testIssue182() throws Exception { Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test16.m4a"); AudioFile f = AudioFileIO.read(testFile); Mp4Tag tag = (Mp4Tag) f.getTag(); System.out.println(f.getAudioHeader()); System.out.println(tag); assertEquals("Suerte", tag.getFirst(FieldKey.ARTIST)); assertEquals("Kogani", tag.getFirst(FieldKey.TITLE)); } catch (IOException e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * Test reading mp4 file * * @throws Exception */ public void testIssue198() throws Exception { File orig = new File("testdata", "test27.m4a"); if (!orig.isFile()) { return; } Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test27.m4a"); AudioFile f = AudioFileIO.read(testFile); Mp4Tag tag = (Mp4Tag) f.getTag(); System.out.println(f.getAudioHeader()); System.out.println(tag); assertEquals("The Best Of Buddy Holly", tag.getFirst(FieldKey.ALBUM)); assertEquals("Buddy Holly & the Crickets", tag.getFirst(FieldKey.ARTIST)); assertEquals(1, tag.get(Mp4FieldKey.ITUNES_NORM).size()); assertEquals(0, tag.get(Mp4FieldKey.ITUNES_SMPB).size()); assertEquals(1, tag.get(Mp4FieldKey.CDDB_1).size()); assertEquals(1, tag.get(Mp4FieldKey.CDDB_TRACKNUMBER).size()); assertEquals(1, tag.get(Mp4FieldKey.CDDB_IDS).size()); } catch (IOException e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * Test reading mp4 file with Covr Art that includes a data AND a name field * * @throws Exception */ public void testIssue227() throws Exception { File orig = new File("testdata", "test31.m4a"); if (!orig.isFile()) { return; } Exception exceptionCaught = null; try { //Read Image File testFile = AbstractTestCase.copyAudioToTmp("test31.m4a"); AudioFile f = AudioFileIO.read(testFile); Mp4Tag tag = (Mp4Tag) f.getTag(); System.out.println(f.getAudioHeader()); System.out.println(tag); assertEquals("Es Wird Morgen", tag.getFirst(FieldKey.ALBUM)); assertEquals("2raumwohnung", tag.getFirst(FieldKey.ARTIST)); List pictures = tag.get(Mp4FieldKey.ARTWORK); assertEquals(1, pictures.size()); Mp4TagCoverField artwork = (Mp4TagCoverField) pictures.get(0); assertEquals(Mp4FieldType.COVERART_PNG, artwork.getFieldType()); //Add another field and save tag.setField(tag.createField(FieldKey.COMPOSER_SORT, "C3")); f.commit(); //Reget tag = (Mp4Tag) f.getTag(); System.out.println(f.getAudioHeader()); System.out.println(tag); assertEquals("Es Wird Morgen", tag.getFirst(FieldKey.ALBUM)); assertEquals("2raumwohnung", tag.getFirst(FieldKey.ARTIST)); pictures = tag.get(Mp4FieldKey.ARTWORK); assertEquals(1, pictures.size()); artwork = (Mp4TagCoverField) pictures.get(0); assertEquals(Mp4FieldType.COVERART_PNG, artwork.getFieldType()); assertEquals("C3", tag.getFirst(FieldKey.COMPOSER_SORT)); } catch (IOException e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * Test properly identified as Apple Lossless * * @throws Exception */ public void testIssue226Mono() throws Exception { Exception exceptionCaught = null; try { //Read Image File testFile = AbstractTestCase.copyAudioToTmp("test32.m4a"); AudioFile f = AudioFileIO.read(testFile); Mp4Tag tag = (Mp4Tag) f.getTag(); System.out.println(f.getAudioHeader()); System.out.println(tag); assertEquals("344", f.getAudioHeader().getBitRate()); assertEquals("1", f.getAudioHeader().getChannels()); assertEquals("44100", f.getAudioHeader().getSampleRate()); assertEquals(EncoderType.APPLE_LOSSLESS.getDescription(), f.getAudioHeader().getEncodingType()); } catch (IOException e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } public void testIssue226Stereo() throws Exception { Exception exceptionCaught = null; try { //Read Image File testFile = AbstractTestCase.copyAudioToTmp("test33.m4a"); AudioFile f = AudioFileIO.read(testFile); Mp4Tag tag = (Mp4Tag) f.getTag(); System.out.println(f.getAudioHeader()); System.out.println(tag); assertEquals("2", f.getAudioHeader().getChannels()); assertEquals("188", f.getAudioHeader().getBitRate()); assertEquals("44100", f.getAudioHeader().getSampleRate()); assertEquals(EncoderType.APPLE_LOSSLESS.getDescription(), f.getAudioHeader().getEncodingType()); } catch (IOException e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } public void testNumericGenres() throws Exception { Exception exceptionCaught = null; try { assertTrue(Mp4GenreField.isValidGenre("Rock")); //Read Image File testFile = AbstractTestCase.copyAudioToTmp("test75.m4a"); RandomAccessFile raf = new RandomAccessFile(testFile,"r"); Mp4Tag tagReader = new Mp4TagReader().read(raf); assertEquals("Rock",tagReader.getFirst(FieldKey.GENRE)); } catch (IOException e) { e.printStackTrace(); exceptionCaught = e; } } }libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/mp4/M4aWriteDatatoMultTrackAudioTest.java0000644000175000017500000004512411276777123033011 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.mp4; import junit.framework.TestCase; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.audio.mp4.Mp4AtomTree; import org.jaudiotagger.tag.FieldKey; import org.jaudiotagger.tag.Tag; import java.io.File; import java.io.RandomAccessFile; /** * Write tags for a file which contains multiple tracks such as winamp encoder */ public class M4aWriteDatatoMultTrackAudioTest extends TestCase { /** * Test to write file that has multiple tracks such as winamp encoder *

*/ public void testWriteFileOption1SameSize() { Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test16.m4a", new File("testWriteMultiTrack1.m4a")); //First lets just createField tree Mp4AtomTree atomTree = new Mp4AtomTree(new RandomAccessFile(testFile, "r")); atomTree.printAtomTree(); //Now we try to make some changes AudioFile f = AudioFileIO.read(testFile); Tag tag = f.getTag(); System.out.println(tag); //Change values and Save changes and reread from disk tag.setField(FieldKey.ARTIST,"AUTHOR"); f.commit(); f = AudioFileIO.read(testFile); tag = f.getTag(); System.out.println(tag); //See tree again atomTree = new Mp4AtomTree(new RandomAccessFile(testFile, "r")); atomTree.printAtomTree(); //Ease of use methods for common fields assertEquals("AUTHOR", tag.getFirst(FieldKey.ARTIST)); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * Test to write file that has MDAT at start BEFORE MOOV atom, this is what Facc 1.25 does *

*/ public void testWriteFileOption3SmallerSizeCreateFree() { Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test16.m4a", new File("testWriteMultiTrack3.m4a")); //First lets just createField tree Mp4AtomTree atomTree = new Mp4AtomTree(new RandomAccessFile(testFile, "r")); atomTree.printAtomTree(); //Now we try to make some changes AudioFile f = AudioFileIO.read(testFile); Tag tag = f.getTag(); System.out.println(tag); //Change values and Save changes and reread from disk tag.setField(FieldKey.ARTIST,"A"); tag.setField(FieldKey.TITLE,"T"); f.commit(); f = AudioFileIO.read(testFile); tag = f.getTag(); System.out.println(tag); //See tree again atomTree = new Mp4AtomTree(new RandomAccessFile(testFile, "r")); atomTree.printAtomTree(); //Ease of use methods for common fields assertEquals("A", tag.getFirst(FieldKey.ARTIST)); assertEquals("T", tag.getFirst(FieldKey.TITLE)); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * Test to write file that has MDAT at start BEFORE MOOV atom, this is what Facc 1.25 does *

*/ public void testWriteFileOption4SmallerSizeNoFree() { Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test16.m4a", new File("testWriteMultiTrack4.m4a")); //First lets just createField tree Mp4AtomTree atomTree = new Mp4AtomTree(new RandomAccessFile(testFile, "r")); atomTree.printAtomTree(); //Now we try to make some changes AudioFile f = AudioFileIO.read(testFile); Tag tag = f.getTag(); System.out.println(tag); //Change values and Save changes and reread from disk tag.setField(FieldKey.ARTIST,"AR"); f.commit(); f = AudioFileIO.read(testFile); tag = f.getTag(); System.out.println(tag); //See tree again atomTree = new Mp4AtomTree(new RandomAccessFile(testFile, "r")); atomTree.printAtomTree(); //Ease of use methods for common fields assertEquals("AR", tag.getFirst(FieldKey.ARTIST)); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * Test to write all fields to check all can be written, just use simple file as starting point *

* TODO:Test incomplete */ public void testWriteFileOption8CannoutUseTopLevelFree() { Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test16.m4a", new File("testWriteMultiTrack8.m4a")); AudioFile f = AudioFileIO.read(testFile); Tag tag = f.getTag(); //Change values tag.setField(FieldKey.ARTIST,"VERYLONGARTISTNAME"); tag.setField(FieldKey.ALBUM,"VERYLONGALBUMTNAME"); tag.setField(tag.createField(FieldKey.ALBUM_ARTIST, "A1")); tag.setField(tag.createField(FieldKey.ALBUM_ARTIST_SORT, "A2")); tag.setField(tag.createField(FieldKey.ALBUM_SORT, "A3")); tag.setField(tag.createField(FieldKey.AMAZON_ID, "A4")); tag.setField(tag.createField(FieldKey.ARTIST_SORT, "A5")); tag.setField(tag.createField(FieldKey.BPM, "200")); tag.setField(tag.createField(FieldKey.COMMENT, "C1")); tag.setField(tag.createField(FieldKey.COMPOSER, "C2")); tag.setField(tag.createField(FieldKey.COMPOSER_SORT, "C3")); tag.setField(tag.createField(FieldKey.DISC_NO, "1")); tag.setField(tag.createField(FieldKey.MUSICBRAINZ_ARTISTID, "1")); tag.setField(tag.createField(FieldKey.MUSICBRAINZ_RELEASEID, "2")); tag.setField(tag.createField(FieldKey.MUSICBRAINZ_TRACK_ID, "3")); tag.setField(tag.createField(FieldKey.MUSICBRAINZ_DISC_ID, "4")); tag.setField(tag.createField(FieldKey.MUSICBRAINZ_RELEASE_COUNTRY, "5")); tag.setField(tag.createField(FieldKey.MUSICBRAINZ_RELEASE_STATUS, "6")); tag.setField(tag.createField(FieldKey.MUSICBRAINZ_RELEASE_TYPE, "7")); tag.setField(tag.createField(FieldKey.MUSICBRAINZ_RELEASEARTISTID, "8")); tag.setField(tag.createField(FieldKey.MUSICIP_ID, "9")); tag.setField(tag.createField(FieldKey.GENRE, "2")); //key for classic rock tag.setField(tag.createField(FieldKey.ENCODER, "encoder")); //Save changes and reread from disk f.commit(); f = AudioFileIO.read(testFile); tag = f.getTag(); System.out.println(f.getAudioHeader()); System.out.println(tag); //AudioInfo //Time in seconds assertEquals(30, f.getAudioHeader().getTrackLength()); assertEquals(44100, f.getAudioHeader().getSampleRateAsNumber()); //Stereo thing doesnt work //assertEquals(new String("2"),f.getAudioHeader().getChannels()); //Ease of use methods for common fields assertEquals("VERYLONGARTISTNAME", tag.getFirst(FieldKey.ARTIST)); assertEquals("VERYLONGALBUMTNAME", tag.getFirst(FieldKey.ALBUM)); assertEquals("A1", tag.getFirst(FieldKey.ALBUM_ARTIST)); assertEquals("A2", tag.getFirst(FieldKey.ALBUM_ARTIST_SORT)); assertEquals("A3", tag.getFirst(FieldKey.ALBUM_SORT)); assertEquals("A4", tag.getFirst(FieldKey.AMAZON_ID)); assertEquals("A5", tag.getFirst(FieldKey.ARTIST_SORT)); assertEquals("200", tag.getFirst(FieldKey.BPM)); assertEquals("C1", tag.getFirst(FieldKey.COMMENT)); assertEquals("C2", tag.getFirst(FieldKey.COMPOSER)); assertEquals("C3", tag.getFirst(FieldKey.COMPOSER_SORT)); assertEquals("1", tag.getFirst(FieldKey.DISC_NO)); assertEquals("1", tag.getFirst(FieldKey.MUSICBRAINZ_ARTISTID)); assertEquals("2", tag.getFirst(FieldKey.MUSICBRAINZ_RELEASEID)); assertEquals("3", tag.getFirst(FieldKey.MUSICBRAINZ_TRACK_ID)); assertEquals("4", tag.getFirst(FieldKey.MUSICBRAINZ_DISC_ID)); assertEquals("5", tag.getFirst(FieldKey.MUSICBRAINZ_RELEASE_COUNTRY)); assertEquals("6", tag.getFirst(FieldKey.MUSICBRAINZ_RELEASE_STATUS)); assertEquals("7", tag.getFirst(FieldKey.MUSICBRAINZ_RELEASE_TYPE)); assertEquals("8", tag.getFirst(FieldKey.MUSICBRAINZ_RELEASEARTISTID)); assertEquals("9", tag.getFirst(FieldKey.MUSICIP_ID)); assertEquals("Classic Rock", tag.getFirst(FieldKey.GENRE)); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * Larger Size can use top free atom */ public void testWriteFileOption6LargerCanUseTopLevelFree() { Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test21.m4a", new File("testWriteMultiTrack6.m4a")); AudioFile f = AudioFileIO.read(testFile); Tag tag = f.getTag(); //Change values tag.setField(FieldKey.ARTIST,"VERYLONGARTISTNAME"); tag.setField(FieldKey.ALBUM,"VERYLONGALBUMTNAME"); tag.setField(tag.createField(FieldKey.ALBUM_ARTIST, "A1")); tag.setField(tag.createField(FieldKey.ALBUM_ARTIST_SORT, "A2")); tag.setField(tag.createField(FieldKey.ALBUM_SORT, "A3")); tag.setField(tag.createField(FieldKey.AMAZON_ID, "A4")); tag.setField(tag.createField(FieldKey.ARTIST_SORT, "A5")); tag.setField(tag.createField(FieldKey.BPM, "200")); tag.setField(tag.createField(FieldKey.COMMENT, "C1")); tag.setField(tag.createField(FieldKey.COMPOSER, "C2")); tag.setField(tag.createField(FieldKey.COMPOSER_SORT, "C3")); tag.setField(tag.createField(FieldKey.DISC_NO, "1")); tag.setField(tag.createField(FieldKey.MUSICBRAINZ_ARTISTID, "1")); tag.setField(tag.createField(FieldKey.MUSICBRAINZ_RELEASEID, "2")); tag.setField(tag.createField(FieldKey.MUSICBRAINZ_TRACK_ID, "3")); tag.setField(tag.createField(FieldKey.MUSICBRAINZ_DISC_ID, "4")); tag.setField(tag.createField(FieldKey.MUSICBRAINZ_RELEASE_COUNTRY, "5")); tag.setField(tag.createField(FieldKey.MUSICBRAINZ_RELEASE_STATUS, "6")); tag.setField(tag.createField(FieldKey.MUSICBRAINZ_RELEASE_TYPE, "7")); tag.setField(tag.createField(FieldKey.MUSICBRAINZ_RELEASEARTISTID, "8")); tag.setField(tag.createField(FieldKey.MUSICIP_ID, "9")); tag.setField(tag.createField(FieldKey.GENRE, "2")); //key for classic rock tag.setField(tag.createField(FieldKey.ENCODER, "encoder")); //Save changes and reread from disk f.commit(); f = AudioFileIO.read(testFile); tag = f.getTag(); System.out.println(f.getAudioHeader()); System.out.println(tag); //AudioInfo //Time in seconds assertEquals(30, f.getAudioHeader().getTrackLength()); assertEquals(44100, f.getAudioHeader().getSampleRateAsNumber()); //Stereo thing doesnt work //assertEquals(new String("2"),f.getAudioHeader().getChannels()); //Ease of use methods for common fields assertEquals("VERYLONGARTISTNAME", tag.getFirst(FieldKey.ARTIST)); assertEquals("VERYLONGALBUMTNAME", tag.getFirst(FieldKey.ALBUM)); assertEquals("A1", tag.getFirst(FieldKey.ALBUM_ARTIST)); assertEquals("A2", tag.getFirst(FieldKey.ALBUM_ARTIST_SORT)); assertEquals("A3", tag.getFirst(FieldKey.ALBUM_SORT)); assertEquals("A4", tag.getFirst(FieldKey.AMAZON_ID)); assertEquals("A5", tag.getFirst(FieldKey.ARTIST_SORT)); assertEquals("200", tag.getFirst(FieldKey.BPM)); assertEquals("C1", tag.getFirst(FieldKey.COMMENT)); assertEquals("C2", tag.getFirst(FieldKey.COMPOSER)); assertEquals("C3", tag.getFirst(FieldKey.COMPOSER_SORT)); assertEquals("1", tag.getFirst(FieldKey.DISC_NO)); assertEquals("1", tag.getFirst(FieldKey.MUSICBRAINZ_ARTISTID)); assertEquals("2", tag.getFirst(FieldKey.MUSICBRAINZ_RELEASEID)); assertEquals("3", tag.getFirst(FieldKey.MUSICBRAINZ_TRACK_ID)); assertEquals("4", tag.getFirst(FieldKey.MUSICBRAINZ_DISC_ID)); assertEquals("5", tag.getFirst(FieldKey.MUSICBRAINZ_RELEASE_COUNTRY)); assertEquals("6", tag.getFirst(FieldKey.MUSICBRAINZ_RELEASE_STATUS)); assertEquals("7", tag.getFirst(FieldKey.MUSICBRAINZ_RELEASE_TYPE)); assertEquals("8", tag.getFirst(FieldKey.MUSICBRAINZ_RELEASEARTISTID)); assertEquals("9", tag.getFirst(FieldKey.MUSICIP_ID)); assertEquals("Classic Rock", tag.getFirst(FieldKey.GENRE)); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * Larger Size can use top free atom */ public void testWriteFileOption7LargerCanUseTopLevelFree() { Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test21.m4a", new File("testWriteMultiTrack7.m4a")); AudioFile f = AudioFileIO.read(testFile); Tag tag = f.getTag(); //Change values tag.setField(FieldKey.ARTIST,"VERYLONGARTISTNAME"); tag.setField(FieldKey.ALBUM,"VERYLONGALBUMTNAME"); tag.setField(tag.createField(FieldKey.ALBUM_ARTIST, "A1")); tag.setField(tag.createField(FieldKey.ALBUM_ARTIST_SORT, "A2")); tag.setField(tag.createField(FieldKey.ALBUM_SORT, "A3")); tag.setField(tag.createField(FieldKey.AMAZON_ID, "A4")); tag.setField(tag.createField(FieldKey.ARTIST_SORT, "A5")); tag.setField(tag.createField(FieldKey.BPM, "200")); tag.setField(tag.createField(FieldKey.COMMENT, "C1")); tag.setField(tag.createField(FieldKey.COMPOSER, "C2")); tag.setField(tag.createField(FieldKey.COMPOSER_SORT, "C3")); tag.setField(tag.createField(FieldKey.DISC_NO, "1")); tag.setField(tag.createField(FieldKey.MUSICBRAINZ_ARTISTID, "1")); tag.setField(tag.createField(FieldKey.MUSICBRAINZ_RELEASEID, "2")); tag.setField(tag.createField(FieldKey.MUSICBRAINZ_TRACK_ID, "3")); tag.setField(tag.createField(FieldKey.MUSICBRAINZ_DISC_ID, "4")); tag.setField(tag.createField(FieldKey.MUSICBRAINZ_RELEASE_COUNTRY, "5")); tag.setField(tag.createField(FieldKey.MUSICBRAINZ_RELEASE_STATUS, "6")); tag.setField(tag.createField(FieldKey.MUSICBRAINZ_RELEASE_TYPE, "7")); tag.setField(tag.createField(FieldKey.MUSICBRAINZ_RELEASEARTISTID, "8")); tag.setField(tag.createField(FieldKey.MUSICIP_ID, "9")); tag.setField(tag.createField(FieldKey.GENRE, "2")); //key for classic rock tag.setField(tag.createField(FieldKey.ENCODER, "encoder")); //Frig adding pretend image which will require exactly the same size as space available in the //free atom byte[] imagedata = new byte[822]; imagedata[0] = (byte) 0x89; imagedata[1] = (byte) 0x50; imagedata[2] = (byte) 0x4E; imagedata[3] = (byte) 0x47; tag.addField(((Mp4Tag) tag).createArtworkField(imagedata)); //Save changes and reread from disk f.commit(); f = AudioFileIO.read(testFile); tag = f.getTag(); System.out.println(f.getAudioHeader()); System.out.println(tag); //AudioInfo //Time in seconds assertEquals(30, f.getAudioHeader().getTrackLength()); assertEquals(44100, f.getAudioHeader().getSampleRateAsNumber()); //Stereo thing doesnt work //assertEquals(new String("2"),f.getAudioHeader().getChannels()); //Ease of use methods for common fields assertEquals("VERYLONGARTISTNAME", tag.getFirst(FieldKey.ARTIST)); assertEquals("VERYLONGALBUMTNAME", tag.getFirst(FieldKey.ALBUM)); assertEquals("A1", tag.getFirst(FieldKey.ALBUM_ARTIST)); assertEquals("A2", tag.getFirst(FieldKey.ALBUM_ARTIST_SORT)); assertEquals("A3", tag.getFirst(FieldKey.ALBUM_SORT)); assertEquals("A4", tag.getFirst(FieldKey.AMAZON_ID)); assertEquals("A5", tag.getFirst(FieldKey.ARTIST_SORT)); assertEquals("200", tag.getFirst(FieldKey.BPM)); assertEquals("C1", tag.getFirst(FieldKey.COMMENT)); assertEquals("C2", tag.getFirst(FieldKey.COMPOSER)); assertEquals("C3", tag.getFirst(FieldKey.COMPOSER_SORT)); assertEquals("1", tag.getFirst(FieldKey.DISC_NO)); assertEquals("1", tag.getFirst(FieldKey.MUSICBRAINZ_ARTISTID)); assertEquals("2", tag.getFirst(FieldKey.MUSICBRAINZ_RELEASEID)); assertEquals("3", tag.getFirst(FieldKey.MUSICBRAINZ_TRACK_ID)); assertEquals("4", tag.getFirst(FieldKey.MUSICBRAINZ_DISC_ID)); assertEquals("5", tag.getFirst(FieldKey.MUSICBRAINZ_RELEASE_COUNTRY)); assertEquals("6", tag.getFirst(FieldKey.MUSICBRAINZ_RELEASE_STATUS)); assertEquals("7", tag.getFirst(FieldKey.MUSICBRAINZ_RELEASE_TYPE)); assertEquals("8", tag.getFirst(FieldKey.MUSICBRAINZ_RELEASEARTISTID)); assertEquals("9", tag.getFirst(FieldKey.MUSICIP_ID)); assertEquals("Classic Rock", tag.getFirst(FieldKey.GENRE)); //Visual check of atom tree testFile = new File("testdatatmp", "testWriteMultiTrack7.m4a"); Mp4AtomTree atomTree = new Mp4AtomTree(new RandomAccessFile(testFile, "r")); atomTree.printAtomTree(); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/mp4/M4aWriteDrmTagTest.java0000644000175000017500000000743611277014227030134 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.mp4; import junit.framework.TestCase; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.audio.mp4.Mp4AudioHeader; import org.jaudiotagger.audio.mp4.atom.Mp4EsdsBox; import org.jaudiotagger.audio.mp4.atom.Mp4StcoBox; import org.jaudiotagger.tag.FieldKey; import org.jaudiotagger.tag.Tag; import java.io.File; import java.io.RandomAccessFile; import java.util.List; /** * Write drms files, we can modify the metadata without breaking the drm file itself */ public class M4aWriteDrmTagTest extends TestCase { /** * Example code of how to show stco table * * @throws Exception */ public void testShowStco() throws Exception { File orig = new File("testdata", "test9.m4p"); if (!orig.isFile()) { return; } File testFile = AbstractTestCase.copyAudioToTmp("test9.m4p", new File("WriteDrmFile1.m4p")); //Stco test RandomAccessFile raf = new RandomAccessFile(testFile, "r"); Mp4StcoBox.debugShowStcoInfo(raf); raf.close(); } /** * Test to write all metadata from an Apple iTunes encoded mp4 file, note also uses fixed genre rather than * custom genre */ public void testWriteFile() { File orig = new File("testdata", "test9.m4p"); if (!orig.isFile()) { return; } Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test9.m4p", new File("WriteDrmFile1.m4p")); AudioFile f = AudioFileIO.read(testFile); Tag tag = f.getTag(); tag.setField(FieldKey.ARTIST,"AUTHOR"); tag.setField(FieldKey.ALBUM,"ALBUM"); f.commit(); f = AudioFileIO.read(testFile); tag = f.getTag(); System.out.println(f.getAudioHeader()); System.out.println(tag); //AudioInfo //Time in seconds assertEquals(329, f.getAudioHeader().getTrackLength()); assertEquals(44100, f.getAudioHeader().getSampleRateAsNumber()); assertEquals(new String("2"), f.getAudioHeader().getChannels()); assertEquals(128, f.getAudioHeader().getBitRateAsNumber()); //MPEG Specific Mp4AudioHeader audioheader = (Mp4AudioHeader) f.getAudioHeader(); assertEquals(Mp4EsdsBox.Kind.MPEG4_AUDIO, audioheader.getKind()); assertEquals(Mp4EsdsBox.AudioProfile.LOW_COMPLEXITY, audioheader.getProfile()); //Ease of use methods for common fields assertEquals("AUTHOR", tag.getFirst(FieldKey.ARTIST)); assertEquals("ALBUM", tag.getFirst(FieldKey.ALBUM)); assertEquals("Simpering Blonde Bombshell", tag.getFirst(FieldKey.TITLE)); assertEquals("1990-01-01T08:00:00Z", tag.getFirst(FieldKey.YEAR)); assertEquals("1", tag.getFirst(FieldKey.TRACK)); assertEquals("12", tag.getFirst(FieldKey.TRACK_TOTAL)); assertEquals("Rock", tag.getFirst(FieldKey.GENRE)); //Cast to format specific tag Mp4Tag mp4tag = (Mp4Tag) tag; //Lookup by mp4 key assertEquals("AUTHOR", mp4tag.getFirst(Mp4FieldKey.ARTIST)); assertEquals("ALBUM", mp4tag.getFirst(Mp4FieldKey.ALBUM)); assertEquals("Simpering Blonde Bombshell", mp4tag.getFirst(Mp4FieldKey.TITLE)); List coverart = mp4tag.get(Mp4FieldKey.ARTWORK); //Should be one image assertEquals(1, coverart.size()); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/flac/0000755000175000017500000000000011556363201024070 5ustar drazzibdrazziblibjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/flac/FlacReadTest.java0000644000175000017500000001003611066755200027234 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.flac; import junit.framework.TestCase; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.audio.exceptions.CannotReadException; import org.jaudiotagger.audio.flac.FlacInfoReader; import java.io.File; /** * basic Flac tests */ public class FlacReadTest extends TestCase { /** * Read Flac File */ public void testReadTwoChannelFile() { Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test2.flac", new File("test2read.flac")); AudioFile f = AudioFileIO.read(testFile); assertEquals("192", f.getAudioHeader().getBitRate()); assertEquals("FLAC 16 bits", f.getAudioHeader().getEncodingType()); assertEquals("2", f.getAudioHeader().getChannels()); assertEquals("44100", f.getAudioHeader().getSampleRate()); assertEquals(5, f.getAudioHeader().getTrackLength()); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * Read Flac File */ public void testReadSingleChannelFile() { Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test3.flac", new File("test3read.flac")); AudioFile f = AudioFileIO.read(testFile); assertEquals("FLAC 8 bits", f.getAudioHeader().getEncodingType()); assertEquals("1", f.getAudioHeader().getChannels()); assertEquals("16000", f.getAudioHeader().getSampleRate()); assertEquals(0, f.getAudioHeader().getTrackLength()); assertEquals("47", f.getAudioHeader().getBitRate()); //is this correct value } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * Test can identify file that isnt flac */ public void testNotFlac() { Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3", new File("testV1noFlac.flac")); AudioFile f = AudioFileIO.read(testFile); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertTrue(exceptionCaught instanceof CannotReadException); } /** * Reading file that contains cuesheet */ public void testReadCueSheet() { Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test3.flac"); AudioFile f = AudioFileIO.read(testFile); FlacInfoReader infoReader = new FlacInfoReader(); assertEquals(5, infoReader.countMetaBlocks(f.getFile())); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * test read flac file with preceding ID3 header */ public void testReadFileWithId3Header() { Exception exceptionCaught = null; try { File orig = new File("testdata", "test22.flac"); if (!orig.isFile()) { System.out.println("Test cannot be run because test file not available"); return; } File testFile = AbstractTestCase.copyAudioToTmp("test22.flac", new File("testreadFlacWithId3.flac")); AudioFile f = AudioFileIO.read(testFile); FlacInfoReader infoReader = new FlacInfoReader(); assertEquals(4, infoReader.countMetaBlocks(f.getFile())); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/flac/FlacWriteTest.java0000644000175000017500000004125711470746136027473 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.flac; import junit.framework.TestCase; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.audio.flac.FlacInfoReader; import org.jaudiotagger.audio.flac.metadatablock.MetadataBlockDataPicture; import org.jaudiotagger.tag.FieldKey; import org.jaudiotagger.tag.TagField; import org.jaudiotagger.tag.id3.valuepair.ImageFormats; import org.jaudiotagger.tag.reference.PictureTypes; import javax.imageio.ImageIO; import javax.imageio.stream.ImageInputStream; import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.io.File; import java.io.RandomAccessFile; import java.util.List; /** * basic Flac tests */ public class FlacWriteTest extends TestCase { /** * Write flac info to file */ public void testWriteAllFieldsToFile() { Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test2.flac", new File("test2write.flac")); AudioFile f = AudioFileIO.read(testFile); assertEquals("192", f.getAudioHeader().getBitRate()); assertEquals("FLAC 16 bits", f.getAudioHeader().getEncodingType()); assertEquals("2", f.getAudioHeader().getChannels()); assertEquals("44100", f.getAudioHeader().getSampleRate()); assertTrue(f.getTag() instanceof FlacTag); FlacTag tag = (FlacTag) f.getTag(); assertEquals("reference libFLAC 1.1.4 20070213", tag.getFirst(FieldKey.ENCODER)); assertEquals("reference libFLAC 1.1.4 20070213", tag.getVorbisCommentTag().getVendor()); //No Images assertEquals(0, tag.getImages().size()); FlacInfoReader infoReader = new FlacInfoReader(); assertEquals(4, infoReader.countMetaBlocks(f.getFile())); tag.addField(FieldKey.ARTIST,"artist\u01ff"); tag.addField(FieldKey.ALBUM,"album"); tag.addField(FieldKey.TITLE,"title"); assertEquals(1, tag.getFields(FieldKey.TITLE.name()).size()); tag.addField(FieldKey.YEAR,"1971"); assertEquals(1, tag.getFields(FieldKey.YEAR).size()); tag.addField(FieldKey.TRACK,"2"); tag.addField(FieldKey.GENRE,"Rock"); tag.setField(tag.createField(FieldKey.BPM, "123")); tag.setField(tag.createField(FieldKey.URL_LYRICS_SITE,"http://www.lyrics.fly.com")); tag.setField(tag.createField(FieldKey.URL_DISCOGS_ARTIST_SITE,"http://www.discogs1.com")); tag.setField(tag.createField(FieldKey.URL_DISCOGS_RELEASE_SITE,"http://www.discogs2.com")); tag.setField(tag.createField(FieldKey.URL_OFFICIAL_ARTIST_SITE,"http://www.discogs3.com")); tag.setField(tag.createField(FieldKey.URL_OFFICIAL_RELEASE_SITE,"http://www.discogs4.com")); tag.setField(tag.createField(FieldKey.URL_WIKIPEDIA_ARTIST_SITE,"http://www.discogs5.com")); tag.setField(tag.createField(FieldKey.URL_WIKIPEDIA_RELEASE_SITE,"http://www.discogs6.com")); tag.setField(tag.createField(FieldKey.TRACK_TOTAL,"11")); tag.setField(tag.createField(FieldKey.DISC_TOTAL,"3")); //key not known to jaudiotagger tag.setField("VIOLINIST", "Sarah Curtis"); //Add new image RandomAccessFile imageFile = new RandomAccessFile(new File("testdata", "coverart.png"), "r"); byte[] imagedata = new byte[(int) imageFile.length()]; imageFile.read(imagedata); tag.setField(tag.createArtworkField(imagedata, PictureTypes.DEFAULT_ID, ImageFormats.MIME_TYPE_PNG, "test", 200, 200, 24, 0)); assertEquals("11",tag.getFirst(FieldKey.TRACK_TOTAL)); assertEquals("3",tag.getFirst(FieldKey.DISC_TOTAL)); f.commit(); f = AudioFileIO.read(testFile); assertEquals(5, infoReader.countMetaBlocks(f.getFile())); assertTrue(f.getTag() instanceof FlacTag); assertEquals("reference libFLAC 1.1.4 20070213", tag.getFirst(FieldKey.ENCODER)); assertEquals("reference libFLAC 1.1.4 20070213", tag.getVorbisCommentTag().getVendor()); tag.addField(tag.createField(FieldKey.ENCODER, "encoder")); assertEquals("encoder", tag.getFirst(FieldKey.ENCODER)); tag = (FlacTag) f.getTag(); assertEquals("artist\u01ff", tag.getFirst(FieldKey.ARTIST)); assertEquals("album", tag.getFirst(FieldKey.ALBUM)); assertEquals("title", tag.getFirst(FieldKey.TITLE)); assertEquals("123", tag.getFirst(FieldKey.BPM)); assertEquals("1971", tag.getFirst(FieldKey.YEAR)); assertEquals("2", tag.getFirst(FieldKey.TRACK)); assertEquals("Rock", tag.getFirst(FieldKey.GENRE)); assertEquals(1, tag.getFields(FieldKey.GENRE).size()); assertEquals(1, tag.getFields(FieldKey.ARTIST).size()); assertEquals(1, tag.getFields(FieldKey.ALBUM).size()); assertEquals(1, tag.getFields(FieldKey.TITLE).size()); assertEquals(1, tag.getFields(FieldKey.BPM).size()); assertEquals(1, tag.getFields(FieldKey.YEAR).size()); assertEquals(1, tag.getFields(FieldKey.TRACK).size()); //One Image assertEquals(1, tag.getFields(FieldKey.COVER_ART.name()).size()); assertEquals(1, tag.getImages().size()); MetadataBlockDataPicture pic = tag.getImages().get(0); assertEquals((int) PictureTypes.DEFAULT_ID, pic.getPictureType()); assertEquals(ImageFormats.MIME_TYPE_PNG, pic.getMimeType()); assertEquals("test", pic.getDescription()); assertEquals(200, pic.getWidth()); assertEquals(200, pic.getHeight()); assertEquals(24, pic.getColourDepth()); assertEquals(0, pic.getIndexedColourCount()); assertEquals("http://www.lyrics.fly.com",tag.getFirst(FieldKey.URL_LYRICS_SITE)); assertEquals("http://www.discogs1.com",tag.getFirst(FieldKey.URL_DISCOGS_ARTIST_SITE)); assertEquals("http://www.discogs2.com",tag.getFirst(FieldKey.URL_DISCOGS_RELEASE_SITE)); assertEquals("http://www.discogs3.com",tag.getFirst(FieldKey.URL_OFFICIAL_ARTIST_SITE)); assertEquals("http://www.discogs4.com",tag.getFirst(FieldKey.URL_OFFICIAL_RELEASE_SITE)); assertEquals("http://www.discogs5.com",tag.getFirst(FieldKey.URL_WIKIPEDIA_ARTIST_SITE)); assertEquals("http://www.discogs6.com",tag.getFirst(FieldKey.URL_WIKIPEDIA_RELEASE_SITE)); assertEquals("11",tag.getFirst(FieldKey.TRACK_TOTAL)); assertEquals("3",tag.getFirst(FieldKey.DISC_TOTAL)); assertEquals("Sarah Curtis",tag.getFirst("VIOLINIST")); ImageInputStream stream = ImageIO.createImageInputStream(new ByteArrayInputStream(pic.getImageData())); BufferedImage bi = ImageIO.read(stream); assertEquals(200, bi.getWidth()); assertEquals(200, bi.getHeight()); //Add image using alternative tag.addField(tag.createArtworkField(bi, PictureTypes.DEFAULT_ID, ImageFormats.MIME_TYPE_PNG, "test", 24, 0)); f.commit(); //Two Images assertEquals(2, tag.getFields(FieldKey.COVER_ART.name()).size()); assertEquals(2, tag.getImages().size()); pic = tag.getImages().get(1); assertEquals((int) PictureTypes.DEFAULT_ID, pic.getPictureType()); assertEquals(ImageFormats.MIME_TYPE_PNG, pic.getMimeType()); assertEquals("test", pic.getDescription()); assertEquals(200, pic.getWidth()); assertEquals(200, pic.getHeight()); assertEquals(24, pic.getColourDepth()); assertEquals(0, pic.getIndexedColourCount()); stream = ImageIO.createImageInputStream(new ByteArrayInputStream(pic.getImageData())); bi = ImageIO.read(stream); assertEquals(200, bi.getWidth()); assertEquals(200, bi.getHeight()); assertEquals(6, infoReader.countMetaBlocks(f.getFile())); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * Test deleting tag file */ public void testDeleteTagFile() { Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test.flac", new File("testdeletetag.flac")); AudioFile f = AudioFileIO.read(testFile); assertEquals("192", f.getAudioHeader().getBitRate()); assertEquals("FLAC 16 bits", f.getAudioHeader().getEncodingType()); assertEquals("2", f.getAudioHeader().getChannels()); assertEquals("44100", f.getAudioHeader().getSampleRate()); assertEquals(2, ((FlacTag) f.getTag()).getImages().size()); assertTrue(f.getTag() instanceof FlacTag); assertFalse(f.getTag().isEmpty()); AudioFileIO.delete(f); f = AudioFileIO.read(testFile); assertTrue(f.getTag().isEmpty()); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * Test Writing file that contains cuesheet */ public void testWriteFileWithCueSheet() { Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test3.flac", new File("testWriteWithCueSheet.flac")); AudioFile f = AudioFileIO.read(testFile); FlacInfoReader infoReader = new FlacInfoReader(); assertEquals(5, infoReader.countMetaBlocks(f.getFile())); f.getTag().setField(FieldKey.ALBUM,"BLOCK"); f.commit(); f = AudioFileIO.read(testFile); infoReader = new FlacInfoReader(); assertEquals("BLOCK", f.getTag().getFirst(FieldKey.ALBUM)); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * Test writing to file that contains an ID3 header */ public void testWriteFileWithId3Header() { Exception exceptionCaught = null; try { File orig = new File("testdata", "test22.flac"); if (!orig.isFile()) { System.out.println("Test cannot be run because test file not available"); return; } File testFile = AbstractTestCase.copyAudioToTmp("test22.flac", new File("testWriteFlacWithId3.flac")); AudioFile f = AudioFileIO.read(testFile); FlacInfoReader infoReader = new FlacInfoReader(); assertEquals(4, infoReader.countMetaBlocks(f.getFile())); f.getTag().setField(FieldKey.ALBUM,"BLOCK"); f.commit(); f = AudioFileIO.read(testFile); infoReader = new FlacInfoReader(); assertEquals(4, infoReader.countMetaBlocks(f.getFile())); assertEquals("BLOCK", f.getTag().getFirst(FieldKey.ALBUM)); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * Metadata size has increased so that shift required */ public void testWriteFileWithId3HeaderAudioShifted() { Exception exceptionCaught = null; try { File orig = new File("testdata", "test22.flac"); if (!orig.isFile()) { System.out.println("Test cannot be run because test file not available"); return; } File testFile = AbstractTestCase.copyAudioToTmp("test22.flac", new File("testWriteFlacWithId3Shifted.flac")); AudioFile f = AudioFileIO.read(testFile); assertEquals("825", f.getAudioHeader().getBitRate()); assertEquals("FLAC 16 bits", f.getAudioHeader().getEncodingType()); assertEquals("2", f.getAudioHeader().getChannels()); assertEquals("44100", f.getAudioHeader().getSampleRate()); assertTrue(f.getTag() instanceof FlacTag); FlacTag tag = (FlacTag) f.getTag(); assertEquals("reference libFLAC 1.1.4 20070213", tag.getFirst(FieldKey.ENCODER)); assertEquals("reference libFLAC 1.1.4 20070213", tag.getVorbisCommentTag().getVendor()); //No Images assertEquals(0, tag.getImages().size()); FlacInfoReader infoReader = new FlacInfoReader(); assertEquals(4, infoReader.countMetaBlocks(f.getFile())); tag.setField(FieldKey.ARTIST,"BLOCK"); tag.addField(FieldKey.ALBUM,"album"); tag.addField(FieldKey.TITLE,"title"); tag.addField(FieldKey.YEAR,"1971"); tag.addField(FieldKey.TRACK,"2"); tag.addField(FieldKey.GENRE,"Rock"); tag.setField(tag.createField(FieldKey.BPM, "123")); //Add new image RandomAccessFile imageFile = new RandomAccessFile(new File("testdata", "coverart.png"), "r"); byte[] imagedata = new byte[(int) imageFile.length()]; imageFile.read(imagedata); tag.setField(tag.createArtworkField(imagedata, PictureTypes.DEFAULT_ID, ImageFormats.MIME_TYPE_PNG, "test", 200, 200, 24, 0)); f.commit(); f = AudioFileIO.read(testFile); assertEquals(5, infoReader.countMetaBlocks(f.getFile())); assertTrue(f.getTag() instanceof FlacTag); assertEquals("reference libFLAC 1.1.4 20070213", tag.getFirst(FieldKey.ENCODER)); assertEquals("reference libFLAC 1.1.4 20070213", tag.getVorbisCommentTag().getVendor()); tag = (FlacTag) f.getTag(); assertEquals("BLOCK", tag.getFirst(FieldKey.ARTIST)); assertEquals(1,tag.getArtworkList().size()); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } public void testDeleteTag() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("test2.flac", new File("testDelete.flac")); AudioFile f = AudioFileIO.read(testFile); AudioFileIO.delete(f); f = AudioFileIO.read(testFile); assertTrue(f.getTag().isEmpty()); } public void testWriteMultipleFields() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("test.flac", new File("testWriteMultiple.flac")); AudioFile f = AudioFileIO.read(testFile); List tagFields = f.getTag().getFields(FieldKey.ALBUM_ARTIST_SORT); assertEquals(0,tagFields.size()); f.getTag().addField(FieldKey.ALBUM_ARTIST_SORT,"artist1"); f.getTag().addField(FieldKey.ALBUM_ARTIST_SORT,"artist2"); tagFields = f.getTag().getFields(FieldKey.ALBUM_ARTIST_SORT); assertEquals(2,tagFields.size()); f.commit(); f = AudioFileIO.read(testFile); tagFields = f.getTag().getFields(FieldKey.ALBUM_ARTIST_SORT); assertEquals(2,tagFields.size()); } public void testDeleteFields() throws Exception { //Delete using generic key File testFile = AbstractTestCase.copyAudioToTmp("test.flac", new File("testWriteMultiple.flac")); AudioFile f = AudioFileIO.read(testFile); List tagFields = f.getTag().getFields(FieldKey.ALBUM_ARTIST_SORT); assertEquals(0,tagFields.size()); f.getTag().addField(FieldKey.ALBUM_ARTIST_SORT,"artist1"); f.getTag().addField(FieldKey.ALBUM_ARTIST_SORT,"artist2"); tagFields = f.getTag().getFields(FieldKey.ALBUM_ARTIST_SORT); assertEquals(2,tagFields.size()); f.getTag().deleteField(FieldKey.ALBUM_ARTIST_SORT); f.commit(); //Delete using flac id f = AudioFileIO.read(testFile); tagFields = f.getTag().getFields(FieldKey.ALBUM_ARTIST_SORT); assertEquals(0,tagFields.size()); f.getTag().addField(FieldKey.ALBUM_ARTIST_SORT,"artist1"); f.getTag().addField(FieldKey.ALBUM_ARTIST_SORT,"artist2"); tagFields = f.getTag().getFields(FieldKey.ALBUM_ARTIST_SORT); assertEquals(2,tagFields.size()); f.getTag().deleteField("ALBUMARTISTSORT"); tagFields = f.getTag().getFields(FieldKey.ALBUM_ARTIST_SORT); assertEquals(0,tagFields.size()); f.commit(); f = AudioFileIO.read(testFile); tagFields = f.getTag().getFields(FieldKey.ALBUM_ARTIST_SORT); assertEquals(0,tagFields.size()); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/real/0000755000175000017500000000000011556363200024105 5ustar drazzibdrazziblibjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/real/RealReadTagTest.java0000644000175000017500000001020711276777123027737 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.real; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.audio.exceptions.CannotReadException; import org.jaudiotagger.audio.exceptions.InvalidAudioFrameException; import org.jaudiotagger.audio.exceptions.ReadOnlyFileException; import org.jaudiotagger.tag.FieldKey; import org.jaudiotagger.tag.Tag; import org.jaudiotagger.tag.TagException; import java.io.File; import java.io.IOException; public class RealReadTagTest extends AbstractTestCase { public void test01() throws InvalidAudioFrameException, IOException, ReadOnlyFileException, TagException, CannotReadException { checkRealTag("test01.ra", "Temptation Rag", "Prince's Military Band", "1910 [Columbia A854]"); } public void test02() throws InvalidAudioFrameException, IOException, ReadOnlyFileException, TagException, CannotReadException { checkRealTag("test02.ra", "Dixieland Jass Band One Step", "Original Dixieland 'Jass' Band", "1917 [Victor 18255-A]"); } public void test03() throws InvalidAudioFrameException, IOException, ReadOnlyFileException, TagException, CannotReadException { checkRealTag("test03.ra", "Here Comes My Daddy Now", "Collins and Harlan", "1913 [Oxford 38528]"); } public void test04() throws InvalidAudioFrameException, IOException, ReadOnlyFileException, TagException, CannotReadException { checkRealTag("test04.ra", "A Cat-Astrophe", "Columbia Orchestra", "1919 [Columbia A2855]"); } public void test05ra() throws InvalidAudioFrameException, IOException, ReadOnlyFileException, TagException, CannotReadException { checkRealTag("test05.ra", "It Makes My Love Come Down", "Bessie Smith, vocal; James P. Johnson, piano", "1929 (Columbia 14464-D mx148904)"); } public void test05rm() throws InvalidAudioFrameException, IOException, ReadOnlyFileException, TagException, CannotReadException { checkRealTag("test05.rm", "It Makes My Love Come Down", "Bessie Smith, vocal; James P. Johnson, piano", "1929 (Columbia 14464-D mx148904)"); } public void test06() throws InvalidAudioFrameException, IOException, ReadOnlyFileException, TagException, CannotReadException { checkRealTag("test06.rm", "No Trouble But You", "Ben Bernie & His Hotel Roosevelt Orchestra", "1926 (Brunswick 3171-A)"); } public void test07() throws InvalidAudioFrameException, IOException, ReadOnlyFileException, TagException, CannotReadException { checkRealTag("test07.rm", "Is There A Place Up There For Me?", "Paul Tremaine & His Orchestra", "circa 1931 (Columbia Tele-Focal Radio Series 91957)"); } public void test08() throws InvalidAudioFrameException, IOException, ReadOnlyFileException, TagException, CannotReadException { checkRealTag("test08.rm", "Let's Say Good Night Till The Morning", " Jack Buchanan and Elsie Randolph", "1926 (Columbia (British) 9147)"); } public void test09() throws InvalidAudioFrameException, IOException, ReadOnlyFileException, TagException, CannotReadException { checkRealTag("test09.rm", "Until Today", "Fletcher Henderson and his Orchestra", "1936 (Victor 25373-B)"); } public void test10() throws InvalidAudioFrameException, IOException, ReadOnlyFileException, TagException, CannotReadException { checkRealTag("test10.rm", "Nobody Cares If I'm Blue", "Annette Hanshaw", "1930 (Harmony 1196-H)"); } public void checkRealTag(String filename, String title, String artist, String comment) throws InvalidAudioFrameException, IOException, ReadOnlyFileException, TagException, CannotReadException { File testFile = AbstractTestCase.copyAudioToTmp(filename); AudioFile f = AudioFileIO.read(testFile); Tag tag = f.getTag(); assertEquals(3, tag.getFieldCount()); // If this line fails we need to update our test as the RealMedia tag parser has been augmented assertEquals(title, tag.getFirst(FieldKey.TITLE)); assertEquals(artist, tag.getFirst(FieldKey.ARTIST)); assertEquals(comment, tag.getFirst(FieldKey.COMMENT)); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/vorbiscomment/0000755000175000017500000000000011556363201026052 5ustar drazzibdrazziblibjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/vorbiscomment/VorbisWriteTagTest.java0000644000175000017500000010433311470746136032503 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.vorbiscomment; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.audio.ogg.OggFileReader; import org.jaudiotagger.audio.ogg.util.OggPageHeader; import org.jaudiotagger.tag.FieldKey; import org.jaudiotagger.tag.TagField; import org.jaudiotagger.tag.vorbiscomment.util.Base64Coder; import javax.imageio.ImageIO; import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.io.File; import java.io.RandomAccessFile; import java.util.List; /** * Vorbis Write tsgs */ public class VorbisWriteTagTest extends AbstractTestCase { /** * Can summarize file */ public void testSummarizeFile() { Exception exceptionCaught = null; try { //Can summarize file File testFile = AbstractTestCase.copyAudioToTmp("test.ogg", new File("testSummarizeFile.ogg")); RandomAccessFile raf = new RandomAccessFile(testFile, "r"); OggFileReader oggFileReader = new OggFileReader(); oggFileReader.summarizeOggPageHeaders(testFile); raf.close(); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * Testing of writing various fields */ public void testWriteTagToFile() { Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test.ogg", new File("testWriteTagTest.ogg")); AudioFile f = AudioFileIO.read(testFile); assertTrue(f.getTag() instanceof VorbisCommentTag); VorbisCommentTag tag = (VorbisCommentTag) f.getTag(); assertEquals("jaudiotagger", tag.getVendor()); //These have methods coz common over all formats tag.setField(FieldKey.ARTIST,"AUTHOR"); tag.setField(FieldKey.ALBUM,"ALBUM"); tag.setField(FieldKey.TITLE,"title"); tag.setField(FieldKey.COMMENT,"comments"); tag.setField(FieldKey.YEAR,"1971"); tag.setField(FieldKey.TRACK,"2"); tag.setField(FieldKey.GENRE,"Genre"); //Common keys tag.setField(tag.createField(FieldKey.DISC_NO, "1")); tag.setField(tag.createField(FieldKey.COMPOSER, "composer\u00A9")); tag.setField(tag.createField(FieldKey.ARTIST_SORT, "Sortartist\u01ff")); tag.setField(FieldKey.LYRICS, "lyrics"); tag.setField(FieldKey.BPM, "200"); tag.setField(FieldKey.ALBUM_ARTIST, "Albumartist"); tag.setField(tag.createField(FieldKey.ALBUM_ARTIST_SORT, "Sortalbumartist")); tag.setField(tag.createField(FieldKey.ALBUM_SORT, "Sortalbum")); tag.setField(tag.createField(FieldKey.GROUPING, "GROUping")); tag.setField(tag.createField(FieldKey.COMPOSER_SORT, "Sortcomposer")); tag.setField(tag.createField(FieldKey.TITLE_SORT, "sorttitle")); tag.setField(tag.createField(FieldKey.IS_COMPILATION, "1")); tag.setField(tag.createField(FieldKey.MUSICIP_ID, "66027994-edcf-9d89-bec8-0d30077d888c")); tag.setField(tag.createField(FieldKey.MUSICBRAINZ_TRACK_ID, "e785f700-c1aa-4943-bcee-87dd316a2c31")); tag.setField(tag.createField(FieldKey.MUSICBRAINZ_ARTISTID, "989a13f6-b58c-4559-b09e-76ae0adb94ed")); tag.setField(tag.createField(FieldKey.MUSICBRAINZ_RELEASEARTISTID, "989a13f6-b58c-4559-b09e-76ae0adb94ed")); tag.setField(tag.createField(FieldKey.MUSICBRAINZ_RELEASEID, "19c6f0f6-3d6d-4b02-88c7-ffb559d52be6")); tag.setField(tag.createField(FieldKey.URL_LYRICS_SITE,"http://www.lyrics.fly.com")); tag.setField(tag.createField(FieldKey.URL_DISCOGS_ARTIST_SITE,"http://www.discogs1.com")); tag.setField(tag.createField(FieldKey.URL_DISCOGS_RELEASE_SITE,"http://www.discogs2.com")); tag.setField(tag.createField(FieldKey.URL_OFFICIAL_ARTIST_SITE,"http://www.discogs3.com")); tag.setField(tag.createField(FieldKey.URL_OFFICIAL_RELEASE_SITE,"http://www.discogs4.com")); tag.setField(tag.createField(FieldKey.URL_WIKIPEDIA_ARTIST_SITE,"http://www.discogs5.com")); tag.setField(tag.createField(FieldKey.URL_WIKIPEDIA_RELEASE_SITE,"http://www.discogs6.com")); tag.setField(tag.createField(FieldKey.TRACK_TOTAL,"11")); tag.setField(tag.createField(FieldKey.DISC_TOTAL,"3")); //Vorbis Only keys tag.setField(((VorbisCommentTag) tag).createField(VorbisCommentFieldKey.DESCRIPTION, "description")); //tag.setField(tag.createField(FieldKey.ENCODER,"encoder")); tag.setVendor("encoder"); assertEquals("encoder", tag.getVendor()); //Add new image, requires two fields in oggVorbis with data in base64 encoded form RandomAccessFile imageFile = new RandomAccessFile(new File("testdata", "coverart.png"), "r"); byte[] imagedata = new byte[(int) imageFile.length()]; imageFile.read(imagedata); char[] testdata = Base64Coder.encode(imagedata); String base64image = new String(testdata); tag.setField(tag.createField(VorbisCommentFieldKey.COVERART, base64image)); tag.setField(tag.createField(VorbisCommentFieldKey.COVERARTMIME, "image/png")); //key not known to jaudiotagger tag.setField("VOLINIST", "Sarah Curtis"); assertEquals("image/png", tag.getFirst(VorbisCommentFieldKey.COVERARTMIME)); f.commit(); f = AudioFileIO.read(testFile); tag = (VorbisCommentTag) f.getTag(); assertTrue(tag instanceof VorbisCommentTag); assertEquals("AUTHOR", tag.getFirst(FieldKey.ARTIST)); assertEquals("ALBUM", tag.getFirst(FieldKey.ALBUM)); assertEquals("title", tag.getFirst(FieldKey.TITLE)); assertEquals("comments", tag.getFirst(FieldKey.COMMENT)); assertEquals("1971", tag.getFirst(FieldKey.YEAR)); assertEquals("2", tag.getFirst(FieldKey.TRACK)); assertEquals("Genre", tag.getFirst(FieldKey.GENRE)); assertEquals("AUTHOR", tag.getFirst(FieldKey.ARTIST)); assertEquals("ALBUM", tag.getFirst(FieldKey.ALBUM)); assertEquals("title", tag.getFirst(FieldKey.TITLE)); assertEquals("comments", tag.getFirst(FieldKey.COMMENT)); assertEquals("1971", tag.getFirst(FieldKey.YEAR)); assertEquals("2", tag.getFirst(FieldKey.TRACK)); assertEquals("1", tag.getFirst(FieldKey.DISC_NO)); assertEquals("composer\u00A9", tag.getFirst(FieldKey.COMPOSER)); assertEquals("Sortartist\u01ff", tag.getFirst(FieldKey.ARTIST_SORT)); assertEquals("lyrics", tag.getFirst(FieldKey.LYRICS)); assertEquals("200", tag.getFirst(FieldKey.BPM)); assertEquals("Albumartist", tag.getFirst(FieldKey.ALBUM_ARTIST)); assertEquals("Sortalbumartist", tag.getFirst(FieldKey.ALBUM_ARTIST_SORT)); assertEquals("Sortalbum", tag.getFirst(FieldKey.ALBUM_SORT)); assertEquals("GROUping", tag.getFirst(FieldKey.GROUPING)); assertEquals("Sortcomposer", tag.getFirst(FieldKey.COMPOSER_SORT)); assertEquals("sorttitle", tag.getFirst(FieldKey.TITLE_SORT)); assertEquals("1", tag.getFirst(FieldKey.IS_COMPILATION)); assertEquals("66027994-edcf-9d89-bec8-0d30077d888c", tag.getFirst(FieldKey.MUSICIP_ID)); assertEquals("e785f700-c1aa-4943-bcee-87dd316a2c31", tag.getFirst(FieldKey.MUSICBRAINZ_TRACK_ID)); assertEquals("989a13f6-b58c-4559-b09e-76ae0adb94ed", tag.getFirst(FieldKey.MUSICBRAINZ_ARTISTID)); assertEquals("989a13f6-b58c-4559-b09e-76ae0adb94ed", tag.getFirst(FieldKey.MUSICBRAINZ_RELEASEARTISTID)); assertEquals("19c6f0f6-3d6d-4b02-88c7-ffb559d52be6", tag.getFirst(FieldKey.MUSICBRAINZ_RELEASEID)); assertEquals("11", tag.getFirst(FieldKey.TRACK_TOTAL)); assertEquals("3", tag.getFirst(FieldKey.DISC_TOTAL)); //Cast to format specific tag VorbisCommentTag vorbisTag = (VorbisCommentTag) tag; //Lookup by vorbis comment key assertEquals("AUTHOR", vorbisTag.getFirst(VorbisCommentFieldKey.ARTIST)); assertEquals("ALBUM", vorbisTag.getFirst(VorbisCommentFieldKey.ALBUM)); assertEquals("title", vorbisTag.getFirst(VorbisCommentFieldKey.TITLE)); assertEquals("comments", vorbisTag.getFirst(VorbisCommentFieldKey.COMMENT)); assertEquals("1971", vorbisTag.getFirst(VorbisCommentFieldKey.DATE)); assertEquals("2", vorbisTag.getFirst(VorbisCommentFieldKey.TRACKNUMBER)); assertEquals("1", vorbisTag.getFirst(VorbisCommentFieldKey.DISCNUMBER)); assertEquals("composer\u00A9", vorbisTag.getFirst(VorbisCommentFieldKey.COMPOSER)); assertEquals("Sortartist\u01ff", vorbisTag.getFirst(VorbisCommentFieldKey.ARTISTSORT)); assertEquals("lyrics", vorbisTag.getFirst(VorbisCommentFieldKey.LYRICS)); assertEquals("200", vorbisTag.getFirst(VorbisCommentFieldKey.BPM)); assertEquals("Albumartist", vorbisTag.getFirst(VorbisCommentFieldKey.ALBUMARTIST)); assertEquals("Sortalbumartist", vorbisTag.getFirst(VorbisCommentFieldKey.ALBUMARTISTSORT)); assertEquals("Sortalbum", vorbisTag.getFirst(VorbisCommentFieldKey.ALBUMSORT)); assertEquals("GROUping", vorbisTag.getFirst(VorbisCommentFieldKey.GROUPING)); assertEquals("Sortcomposer", vorbisTag.getFirst(VorbisCommentFieldKey.COMPOSERSORT)); assertEquals("sorttitle", vorbisTag.getFirst(VorbisCommentFieldKey.TITLESORT)); assertEquals("1", vorbisTag.getFirst(VorbisCommentFieldKey.COMPILATION)); assertEquals("66027994-edcf-9d89-bec8-0d30077d888c", vorbisTag.getFirst(VorbisCommentFieldKey.MUSICIP_PUID)); assertEquals("e785f700-c1aa-4943-bcee-87dd316a2c31", vorbisTag.getFirst(VorbisCommentFieldKey.MUSICBRAINZ_TRACKID)); assertEquals("989a13f6-b58c-4559-b09e-76ae0adb94ed", vorbisTag.getFirst(VorbisCommentFieldKey.MUSICBRAINZ_ARTISTID)); assertEquals("989a13f6-b58c-4559-b09e-76ae0adb94ed", vorbisTag.getFirst(VorbisCommentFieldKey.MUSICBRAINZ_ALBUMARTISTID)); assertEquals("19c6f0f6-3d6d-4b02-88c7-ffb559d52be6", vorbisTag.getFirst(VorbisCommentFieldKey.MUSICBRAINZ_ALBUMID)); assertEquals("http://www.lyrics.fly.com",tag.getFirst(VorbisCommentFieldKey.URL_LYRICS_SITE)); assertEquals("http://www.discogs1.com",tag.getFirst(VorbisCommentFieldKey.URL_DISCOGS_ARTIST_SITE)); assertEquals("http://www.discogs2.com",tag.getFirst(VorbisCommentFieldKey.URL_DISCOGS_RELEASE_SITE)); assertEquals("http://www.discogs3.com",tag.getFirst(VorbisCommentFieldKey.URL_OFFICIAL_ARTIST_SITE)); assertEquals("http://www.discogs4.com",tag.getFirst(VorbisCommentFieldKey.URL_OFFICIAL_RELEASE_SITE)); assertEquals("http://www.discogs5.com",tag.getFirst(VorbisCommentFieldKey.URL_WIKIPEDIA_ARTIST_SITE)); assertEquals("http://www.discogs6.com",tag.getFirst(VorbisCommentFieldKey.URL_WIKIPEDIA_RELEASE_SITE)); assertEquals("11", tag.getFirst(VorbisCommentFieldKey.TRACKTOTAL)); assertEquals("3", tag.getFirst(VorbisCommentFieldKey.DISCTOTAL)); assertEquals("Sarah Curtis", vorbisTag.getFirst("VOLINIST")); assertEquals("encoder", vorbisTag.getVendor()); //List methods List list = tag.getFields(FieldKey.ARTIST); assertEquals(1, list.size()); for (TagField field : list) { assertEquals("AUTHOR", field.toString()); } //Vorbis keys that have no mapping to generic key assertEquals("description", vorbisTag.getFirst(VorbisCommentFieldKey.DESCRIPTION)); //VorbisImage base64 image, and reconstruct assertEquals("image/png", vorbisTag.getFirst(VorbisCommentFieldKey.COVERARTMIME)); assertEquals(base64image, vorbisTag.getFirst(VorbisCommentFieldKey.COVERART)); BufferedImage bi = ImageIO.read(ImageIO .createImageInputStream(new ByteArrayInputStream(Base64Coder. decode(vorbisTag.getFirst(VorbisCommentFieldKey.COVERART).toCharArray())))); assertNotNull(bi); OggFileReader ofr = new OggFileReader(); OggPageHeader oph = ofr.readOggPageHeader(new RandomAccessFile(testFile, "r"), 0); assertEquals(30, oph.getPageLength()); assertEquals(0, oph.getPageSequence()); assertEquals(559748870, oph.getSerialNumber()); assertEquals(-2111591604, oph.getCheckSum()); assertEquals(2, oph.getHeaderType()); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * Test writing to file, comments too large to fit on single page anymore */ public void testWriteToFileMuchLarger() { File orig = new File("testdata", "test.ogg"); if (!orig.isFile()) { return; } Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test.ogg", new File("testWriteTagTestRequiresTwoPages.ogg")); AudioFile f = AudioFileIO.read(testFile); assertTrue(f.getTag() instanceof VorbisCommentTag); VorbisCommentTag tag = (VorbisCommentTag) f.getTag(); //Add new image, requires two fields in oggVorbis with data in base64 encoded form RandomAccessFile imageFile = new RandomAccessFile(new File("testdata", "coverart.bmp"), "r"); byte[] imagedata = new byte[(int) imageFile.length()]; imageFile.read(imagedata); char[] testdata = Base64Coder.encode(imagedata); String base64image = new String(testdata); tag.setField(tag.createField(VorbisCommentFieldKey.COVERART, base64image)); tag.setField(tag.createField(VorbisCommentFieldKey.COVERARTMIME, "image/png")); //Save f.commit(); //Reread f = AudioFileIO.read(testFile); tag = (VorbisCommentTag) f.getTag(); //Check changes assertEquals(1, tag.get(VorbisCommentFieldKey.COVERART).size()); assertEquals(1, tag.get(VorbisCommentFieldKey.COVERARTMIME).size()); RandomAccessFile raf = new RandomAccessFile(testFile, "r"); OggFileReader oggFileReader = new OggFileReader(); System.out.println(oggFileReader.readOggPageHeader(raf, 0)); raf.seek(0); System.out.println(oggFileReader.readOggPageHeader(raf, 1)); raf.seek(0); System.out.println(oggFileReader.readOggPageHeader(raf, 2)); raf.close(); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * Test writing to file, comments too large to fit on single page anymore, and also setup header gets split */ public void testWriteToFileMuchLargerSetupHeaderSplit() { File orig = new File("testdata", "test.ogg"); if (!orig.isFile()) { return; } Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test.ogg", new File("testWriteTagTestRequiresTwoPagesHeaderSplit.ogg")); AudioFile f = AudioFileIO.read(testFile); assertTrue(f.getTag() instanceof VorbisCommentTag); VorbisCommentTag tag = (VorbisCommentTag) f.getTag(); //Add new pretend image to force split of setup header StringBuffer sb = new StringBuffer(); for (int i = 0; i < 128000; i++) { sb.append("a"); } tag.setField(tag.createField(VorbisCommentFieldKey.COVERART, sb.toString())); tag.setField(tag.createField(VorbisCommentFieldKey.COVERARTMIME, "image/png")); //Save f.commit(); //Reread f = AudioFileIO.read(testFile); tag = (VorbisCommentTag) f.getTag(); //Check changes assertEquals(1, tag.get(VorbisCommentFieldKey.COVERART).size()); assertEquals(1, tag.get(VorbisCommentFieldKey.COVERARTMIME).size()); RandomAccessFile raf = new RandomAccessFile(testFile, "r"); OggFileReader oggFileReader = new OggFileReader(); System.out.println(oggFileReader.readOggPageHeader(raf, 0)); raf.seek(0); System.out.println(oggFileReader.readOggPageHeader(raf, 1)); raf.seek(0); System.out.println(oggFileReader.readOggPageHeader(raf, 2)); raf.seek(0); System.out.println(oggFileReader.readOggPageHeader(raf, 3)); raf.close(); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * Issue 197, test writing to file when audio packet come straight after setup packet on same oggPage, edit so * comment data is changed but size of comment header is same length */ public void testWriteToFileWithExtraPacketsOnSamePageAsSetupHeader() { File orig = new File("testdata", "test2.ogg"); if (!orig.isFile()) { return; } Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test2.ogg", new File("testWriteTagWithExtraPacketsHeaderSameSize.ogg")); OggFileReader oggFileReader = new OggFileReader(); RandomAccessFile raf = new RandomAccessFile(testFile, "r"); OggPageHeader pageHeader = oggFileReader.readOggPageHeader(raf, 1); int packetsInSecondPageCount = pageHeader.getPacketList().size(); pageHeader = null; raf.close(); AudioFile f = AudioFileIO.read(testFile); assertTrue(f.getTag() instanceof VorbisCommentTag); VorbisCommentTag tag = (VorbisCommentTag) f.getTag(); //These have methods coz common over all formats tag.setField(FieldKey.ARTIST,"AUTHOR"); //Save f.commit(); //Reread f = AudioFileIO.read(testFile); tag = (VorbisCommentTag) f.getTag(); //Check changes assertEquals("AUTHOR", tag.getFirst(FieldKey.ARTIST)); //Check 2nd page has same number of packets, this is only the case for this specific test, so check //in test not code itself. raf = new RandomAccessFile(testFile, "r"); pageHeader = oggFileReader.readOggPageHeader(raf, 1); raf.close(); assertEquals(packetsInSecondPageCount, pageHeader.getPacketList().size()); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * Issue 197, test writing to file when audio packet come straight after setup packet on same oggPage, edit enough * so that comment is larger, but the comment, header and extra packets can still all fit on page 2 */ public void testWriteToFileWithExtraPacketsOnSamePageAsSetupHeaderLarger() { File orig = new File("testdata", "test2.ogg"); if (!orig.isFile()) { return; } Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test2.ogg", new File("testWriteTagWithExtraPacketsHeaderLargerSize.ogg")); OggFileReader oggFileReader = new OggFileReader(); RandomAccessFile raf = new RandomAccessFile(testFile, "r"); OggPageHeader pageHeader = oggFileReader.readOggPageHeader(raf, 1); int packetsInSecondPageCount = pageHeader.getPacketList().size(); pageHeader = null; raf.close(); AudioFile f = AudioFileIO.read(testFile); assertTrue(f.getTag() instanceof VorbisCommentTag); VorbisCommentTag tag = (VorbisCommentTag) f.getTag(); //These have methods coz common over all formats tag.setField(FieldKey.ARTIST,"ARTISTIC"); //Save f.commit(); //Reread f = AudioFileIO.read(testFile); tag = (VorbisCommentTag) f.getTag(); //Check changes assertEquals("ARTISTIC", tag.getFirst(FieldKey.ARTIST)); //Check 2nd page has same number of packets, this is only the case for this specific test, so check //in test not code itself. raf = new RandomAccessFile(testFile, "r"); pageHeader = oggFileReader.readOggPageHeader(raf, 1); raf.close(); assertEquals(packetsInSecondPageCount, pageHeader.getPacketList().size()); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * Issue 197, test writing to file when audio packet come straight after setup packet on same oggPage, edit enough * so that comment is much larger, so that comment, header and extra packets can no longer fit on page 2 */ public void testWriteToFileWithExtraPacketsOnSamePageAsSetupHeaderMuchLarger() { File orig = new File("testdata", "test2.ogg"); if (!orig.isFile()) { return; } Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test.ogg", new File("testWriteTagWithExtraPacketsHeaderMuchLargerSize.ogg")); AudioFile f = AudioFileIO.read(testFile); assertTrue(f.getTag() instanceof VorbisCommentTag); VorbisCommentTag tag = (VorbisCommentTag) f.getTag(); //Add new image, requires two fields in oggVorbis with data in base64 encoded form RandomAccessFile imageFile = new RandomAccessFile(new File("testdata", "coverart.bmp"), "r"); byte[] imagedata = new byte[(int) imageFile.length()]; imageFile.read(imagedata); char[] testdata = Base64Coder.encode(imagedata); String base64image = new String(testdata); tag.setField(tag.createField(VorbisCommentFieldKey.COVERART, base64image)); tag.setField(tag.createField(VorbisCommentFieldKey.COVERARTMIME, "image/png")); //Save f.commit(); //Reread f = AudioFileIO.read(testFile); tag = (VorbisCommentTag) f.getTag(); //Check changes assertEquals(1, tag.get(VorbisCommentFieldKey.COVERART).size()); assertEquals(1, tag.get(VorbisCommentFieldKey.COVERARTMIME).size()); RandomAccessFile raf = new RandomAccessFile(testFile, "r"); OggFileReader oggFileReader = new OggFileReader(); System.out.println(oggFileReader.readOggPageHeader(raf, 0)); raf.seek(0); System.out.println("Page 2" + oggFileReader.readOggPageHeader(raf, 1)); //System.out.println("Page 3"+oggFileReader.readOggPageHeader(raf,2)); //oggFileReader.readOggPageHeader(raf,4); raf.close(); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * Issue 197, test writing to file when audio packet come straight after setup packet on same oggPage, edit enough * so that comment is much larger, so that comment, header and extra packets can no longer fit on page 2 AND * setup header is also split over two */ public void testWriteToFileWithExtraPacketsOnSamePageAsSetupHeaderMuchLargerAndSplit() { File orig = new File("testdata", "test2.ogg"); if (!orig.isFile()) { return; } Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test2.ogg", new File("testWriteTagWithExtraPacketsHeaderMuchLargerSizeAndSplit.ogg")); AudioFile f = AudioFileIO.read(testFile); assertTrue(f.getTag() instanceof VorbisCommentTag); VorbisCommentTag tag = (VorbisCommentTag) f.getTag(); //Add new pretend image to force split of setup header StringBuffer sb = new StringBuffer(); for (int i = 0; i < 128000; i++) { sb.append("a"); } tag.setField(tag.createField(VorbisCommentFieldKey.COVERART, sb.toString())); tag.setField(tag.createField(VorbisCommentFieldKey.COVERARTMIME, "image/png")); //Save f.commit(); //Reread f = AudioFileIO.read(testFile); RandomAccessFile raf = new RandomAccessFile(testFile, "r"); OggFileReader oggFileReader = new OggFileReader(); System.out.println(oggFileReader.readOggPageHeader(raf, 0)); raf.seek(0); System.out.println(oggFileReader.readOggPageHeader(raf, 1)); raf.seek(0); System.out.println(oggFileReader.readOggPageHeader(raf, 2)); raf.seek(0); System.out.println(oggFileReader.readOggPageHeader(raf, 3)); raf.close(); //tag = (VorbisCommentTag)f.getTag(); //Check changes //assertEquals(1,tag.getFields(VorbisCommentFieldKey.COVERART).size()); //assertEquals(1,tag.getFields(VorbisCommentFieldKey.COVERARTMIME).size()); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * Test writing to file, comments was too large for one page but not anymore */ public void testWriteToFileNoLongerRequiresTwoPages() { File orig = new File("testdata", "test3.ogg"); if (!orig.isFile()) { return; } Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test3.ogg", new File("testWriteTagTestNoLongerRequiresTwoPages.ogg")); AudioFile f = AudioFileIO.read(testFile); assertTrue(f.getTag() instanceof VorbisCommentTag); VorbisCommentTag tag = (VorbisCommentTag) f.getTag(); //Delete Large Image tag.deleteField(VorbisCommentFieldKey.COVERART); tag.deleteField(VorbisCommentFieldKey.COVERARTMIME); //Save f.commit(); //Reread f = AudioFileIO.read(testFile); tag = (VorbisCommentTag) f.getTag(); //Check changes assertEquals(0, tag.get(VorbisCommentFieldKey.COVERART).size()); assertEquals(0, tag.get(VorbisCommentFieldKey.COVERARTMIME).size()); RandomAccessFile raf = new RandomAccessFile(testFile, "r"); OggFileReader oggFileReader = new OggFileReader(); System.out.println(oggFileReader.readOggPageHeader(raf, 0)); raf.seek(0); System.out.println(oggFileReader.readOggPageHeader(raf, 1)); raf.seek(0); System.out.println(oggFileReader.readOggPageHeader(raf, 2)); raf.close(); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * Test writing to file, comments was too large for one page and setup header split but not anymore */ public void testWriteToFileNoLongerRequiresTwoPagesNorSplit() { File orig = new File("testdata", "test5.ogg"); if (!orig.isFile()) { return; } Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test5.ogg", new File("testWriteTagTestNoLongerRequiresTwoPagesNorSplit.ogg")); AudioFile f = AudioFileIO.read(testFile); assertTrue(f.getTag() instanceof VorbisCommentTag); VorbisCommentTag tag = (VorbisCommentTag) f.getTag(); //Delete Large Image tag.deleteField(VorbisCommentFieldKey.COVERART); tag.deleteField(VorbisCommentFieldKey.COVERARTMIME); //Save f.commit(); //Reread f = AudioFileIO.read(testFile); tag = (VorbisCommentTag) f.getTag(); //Check changes assertEquals(0, tag.get(VorbisCommentFieldKey.COVERART).size()); assertEquals(0, tag.get(VorbisCommentFieldKey.COVERARTMIME).size()); RandomAccessFile raf = new RandomAccessFile(testFile, "r"); OggFileReader oggFileReader = new OggFileReader(); System.out.println(oggFileReader.readOggPageHeader(raf, 0)); raf.seek(0); System.out.println(oggFileReader.readOggPageHeader(raf, 1)); raf.seek(0); System.out.println(oggFileReader.readOggPageHeader(raf, 2)); raf.close(); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * Test writing to file, comments was too large for one page but not anymore */ public void testWriteToFileWriteToFileWithExtraPacketsNoLongerRequiresTwoPages() { File orig = new File("testdata", "test4.ogg"); if (!orig.isFile()) { return; } Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test4.ogg", new File("testWriteTagTestWithPacketsNoLongerRequiresTwoPages.ogg")); AudioFile f = AudioFileIO.read(testFile); assertTrue(f.getTag() instanceof VorbisCommentTag); VorbisCommentTag tag = (VorbisCommentTag) f.getTag(); //Delete Large Image tag.deleteField(VorbisCommentFieldKey.ARTIST); tag.deleteField(VorbisCommentFieldKey.COVERART); tag.deleteField(VorbisCommentFieldKey.COVERARTMIME); //Save f.commit(); //Reread f = AudioFileIO.read(testFile); tag = (VorbisCommentTag) f.getTag(); //Check changes assertEquals(0, tag.get(VorbisCommentFieldKey.ARTIST).size()); assertEquals(0, tag.get(VorbisCommentFieldKey.COVERART).size()); assertEquals(0, tag.get(VorbisCommentFieldKey.COVERARTMIME).size()); RandomAccessFile raf = new RandomAccessFile(testFile, "r"); OggFileReader oggFileReader = new OggFileReader(); System.out.println(oggFileReader.readOggPageHeader(raf, 0)); raf.seek(0); System.out.println(oggFileReader.readOggPageHeader(raf, 1)); raf.seek(0); System.out.println(oggFileReader.readOggPageHeader(raf, 2)); raf.close(); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } public void testDeleteTag() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("test.ogg", new File("testDelete.ogg")); AudioFile f = AudioFileIO.read(testFile); f.setTag(VorbisCommentTag.createNewTag()); f.commit(); f = AudioFileIO.read(testFile); assertTrue(f.getTag().isEmpty()); assertEquals("jaudiotagger", ((VorbisCommentTag) f.getTag()).getVendor()); } public void testDeleteTag2() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("test.ogg", new File("testDelete2.ogg")); AudioFile f = AudioFileIO.read(testFile); AudioFileIO.delete(f); f = AudioFileIO.read(testFile); assertTrue(f.getTag().isEmpty()); assertEquals("jaudiotagger", ((VorbisCommentTag) f.getTag()).getVendor()); } public void testWriteMultipleFields() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("test.ogg", new File("testWriteMultiple.ogg")); AudioFile f = AudioFileIO.read(testFile); f.getTag().addField(FieldKey.ALBUM_ARTIST,"artist1"); f.getTag().addField(FieldKey.ALBUM_ARTIST,"artist2"); f.commit(); f = AudioFileIO.read(testFile); List tagFields = f.getTag().getFields(FieldKey.ALBUM_ARTIST); assertEquals(tagFields.size(),2); } public void testDeleteFields() throws Exception { //Delete using generic key File testFile = AbstractTestCase.copyAudioToTmp("test.ogg", new File("testDeleteFields.ogg")); AudioFile f = AudioFileIO.read(testFile); List tagFields = f.getTag().getFields(FieldKey.ALBUM_ARTIST_SORT); assertEquals(0,tagFields.size()); f.getTag().addField(FieldKey.ALBUM_ARTIST_SORT,"artist1"); f.getTag().addField(FieldKey.ALBUM_ARTIST_SORT,"artist2"); tagFields = f.getTag().getFields(FieldKey.ALBUM_ARTIST_SORT); assertEquals(2,tagFields.size()); f.getTag().deleteField(FieldKey.ALBUM_ARTIST_SORT); f.commit(); //Delete using flac id f = AudioFileIO.read(testFile); tagFields = f.getTag().getFields(FieldKey.ALBUM_ARTIST_SORT); assertEquals(0,tagFields.size()); f.getTag().addField(FieldKey.ALBUM_ARTIST_SORT,"artist1"); f.getTag().addField(FieldKey.ALBUM_ARTIST_SORT,"artist2"); tagFields = f.getTag().getFields(FieldKey.ALBUM_ARTIST_SORT); assertEquals(2,tagFields.size()); f.getTag().deleteField("ALBUMARTISTSORT"); tagFields = f.getTag().getFields(FieldKey.ALBUM_ARTIST_SORT); assertEquals(0,tagFields.size()); f.commit(); f = AudioFileIO.read(testFile); tagFields = f.getTag().getFields(FieldKey.ALBUM_ARTIST_SORT); assertEquals(0,tagFields.size()); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/vorbiscomment/VorbisReadTagTest.java0000644000175000017500000000760311276777123032272 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.vorbiscomment; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.audio.exceptions.CannotReadException; import org.jaudiotagger.audio.ogg.OggFileReader; import org.jaudiotagger.fix.Fix; import org.jaudiotagger.tag.FieldKey; import java.io.File; import java.io.RandomAccessFile; /** * User: paul * Date: 21-Feb-2008 */ public class VorbisReadTagTest extends AbstractTestCase { /** * Test reading a file with corrupt vorbis comment tag, however the ogg paging is actually correct * so no error found in this test. */ public void testReadCorruptOgg() { File orig = new File("testdata", "test6.ogg"); if (!orig.isFile()) { return; } Exception exceptionCaught = null; try { //Can summarize file File testFile = AbstractTestCase.copyAudioToTmp("test6.ogg"); RandomAccessFile raf = new RandomAccessFile(testFile, "r"); OggFileReader oggFileReader = new OggFileReader(); oggFileReader.summarizeOggPageHeaders(testFile); raf.close(); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * Test reading corrupt file, because vorbis comment has an error (says no of comments is 5 but actually there * are 6 it should throw appropriate error */ public void testReadCorruptOgg2() { File orig = new File("testdata", "test6.ogg"); if (!orig.isFile()) { return; } Exception exceptionCaught = null; try { //Can summarize file File testFile = AbstractTestCase.copyAudioToTmp("test6.ogg"); AudioFileIO.read(testFile); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertTrue(exceptionCaught instanceof CannotReadException); } /** * Create Value with empty value and then read back, then try and create another field * Was expecting to fail but works ok */ public void testCreateCorruptFile() { Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test.ogg", new File("testWithEmptyField.ogg")); AudioFile file = AudioFileIO.read(testFile); file.getTag().setField(FieldKey.YEAR,""); file.commit(); file = AudioFileIO.read(testFile); file.getTag().setField(FieldKey.TITLE,"testtitle"); file.commit(); file = AudioFileIO.read(testFile); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); } /** * Fixes an issue whereby a file contained a user comment with no value (DATE=) and the number * of comments was one less than it should be. */ public void testFix202CorruptFile() { File orig = new File("testdata", "test6.ogg"); if (!orig.isFile()) { return; } Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test6.ogg", new File("FixedCorruptedFile.ogg")); OggFileReader fileReader = new OggFileReader(Fix.FIX_OGG_VORBIS_COMMENT_NOT_COUNTING_EMPTY_COLUMNS); AudioFile audioFile = fileReader.read(testFile); audioFile.commit(); fileReader = new OggFileReader(); audioFile = fileReader.read(testFile); audioFile.commit(); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/vorbiscomment/VorbisImageTest.java0000644000175000017500000001564711277264361032010 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.vorbiscomment; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.tag.vorbiscomment.util.Base64Coder; import javax.imageio.ImageIO; import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.io.File; import java.io.RandomAccessFile; /** */ public class VorbisImageTest extends AbstractTestCase { /** * Test can read file with base64 encoded image from ogg *

* Works */ public void testReadFileWithSmallImageTag() { Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("testsmallimage.ogg"); AudioFile f = AudioFileIO.read(testFile); String mimeType = ((VorbisCommentTag) f.getTag()).getFirst(VorbisCommentFieldKey.COVERARTMIME); assertEquals("image/jpeg", mimeType); if (mimeType != null & mimeType.length() > 0) { String imageRawData = ((VorbisCommentTag) f.getTag()).getFirst(VorbisCommentFieldKey.COVERART); assertEquals(22972, imageRawData.length()); } } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); } /** * Test can read file with base64 encoded image thats spans multiple ogg pages *

* Fails:Doesnt give error but doesnt read image */ public void testReadFileWithLargeImageTag() { Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("testlargeimage.ogg"); AudioFile f = AudioFileIO.read(testFile); String mimeType = ((VorbisCommentTag) f.getTag()).getFirst(VorbisCommentFieldKey.COVERARTMIME); assertEquals("image/jpeg", mimeType); if (mimeType != null & mimeType.length() > 0) { String imageRawData = ((VorbisCommentTag) f.getTag()).getFirst(VorbisCommentFieldKey.COVERART); assertEquals(1013576, imageRawData.length()); } } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * Write and read image using lowest level methods */ public void testWriteImage1() { try { File testFile = AbstractTestCase.copyAudioToTmp("test.ogg", new File("testWriteImage1.ogg")); AudioFile f = AudioFileIO.read(testFile); VorbisCommentTag tag = (VorbisCommentTag) f.getTag(); //Add new image, requires two fields in oggVorbis with data in base64 encoded form RandomAccessFile imageFile = new RandomAccessFile(new File("testdata", "coverart.png"), "r"); byte[] imagedata = new byte[(int) imageFile.length()]; imageFile.read(imagedata); char[] testdata = Base64Coder.encode(imagedata); String base64image = new String(testdata); tag.setField(tag.createField(VorbisCommentFieldKey.COVERART, base64image)); tag.setField(tag.createField(VorbisCommentFieldKey.COVERARTMIME, "image/png")); f.commit(); f = AudioFileIO.read(testFile); tag = (VorbisCommentTag) f.getTag(); //VorbisImage base64 image, and reconstruct assertEquals(base64image, tag.getFirst(VorbisCommentFieldKey.COVERART)); assertEquals("image/png", tag.getFirst(VorbisCommentFieldKey.COVERARTMIME)); BufferedImage bi = ImageIO.read(ImageIO .createImageInputStream(new ByteArrayInputStream(Base64Coder. decode(tag.getFirst(VorbisCommentFieldKey.COVERART).toCharArray())))); assertNotNull(bi); } catch (Exception e) { e.printStackTrace(); } } /** * Write Image using new method, read using lowlevel */ public void testWriteImage2() { try { File testFile = AbstractTestCase.copyAudioToTmp("test.ogg", new File("testWriteImage2.ogg")); AudioFile f = AudioFileIO.read(testFile); VorbisCommentTag tag = (VorbisCommentTag) f.getTag(); //Add new image using purpose built method RandomAccessFile imageFile = new RandomAccessFile(new File("testdata", "coverart.png"), "r"); byte[] imagedata = new byte[(int) imageFile.length()]; imageFile.read(imagedata); tag.setArtworkField(imagedata, "image/png"); f.commit(); f = AudioFileIO.read(testFile); tag = (VorbisCommentTag) f.getTag(); //VorbisImage base64 image, and reconstruct char[] testdata = Base64Coder.encode(imagedata); String base64image = new String(testdata); assertEquals(base64image, tag.getFirst(VorbisCommentFieldKey.COVERART)); assertEquals("image/png", tag.getFirst(VorbisCommentFieldKey.COVERARTMIME)); BufferedImage bi = ImageIO.read(ImageIO .createImageInputStream(new ByteArrayInputStream(Base64Coder. decode(tag.getFirst(VorbisCommentFieldKey.COVERART).toCharArray())))); assertNotNull(bi); } catch (Exception e) { e.printStackTrace(); } } /** * Write Image using lowlevel , read using new method */ public void testWriteImage3() { try { File testFile = AbstractTestCase.copyAudioToTmp("test.ogg", new File("testWriteImage3.ogg")); AudioFile f = AudioFileIO.read(testFile); VorbisCommentTag tag = (VorbisCommentTag) f.getTag(); //Add new image, requires two fields in oggVorbis with data in base64 encoded form RandomAccessFile imageFile = new RandomAccessFile(new File("testdata", "coverart.png"), "r"); byte[] imagedata = new byte[(int) imageFile.length()]; imageFile.read(imagedata); char[] testdata = Base64Coder.encode(imagedata); String base64image = new String(testdata); tag.setField(tag.createField(VorbisCommentFieldKey.COVERART, base64image)); tag.setField(tag.createField(VorbisCommentFieldKey.COVERARTMIME, "image/png")); f.commit(); f = AudioFileIO.read(testFile); tag = (VorbisCommentTag) f.getTag(); //VorbisImage base64 image, and reconstruct assertEquals("image/png", tag.getArtworkMimeType()); byte[] newImageData = tag.getArtworkBinaryData(); BufferedImage bi = ImageIO.read(ImageIO .createImageInputStream(new ByteArrayInputStream(newImageData))); assertNotNull(bi); } catch (Exception e) { e.printStackTrace(); } } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/wma/0000755000175000017500000000000011556363200023746 5ustar drazzibdrazziblibjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/wma/WmaSimpleTest.java0000644000175000017500000011562211470746136027366 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.wma; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.tag.asf.AsfFieldKey; import org.jaudiotagger.tag.asf.AsfTag; import org.jaudiotagger.tag.asf.AsfTagCoverField; import org.jaudiotagger.tag.asf.AsfTagTextField; import org.jaudiotagger.tag.FieldKey; import org.jaudiotagger.tag.Tag; import org.jaudiotagger.tag.TagField; import org.jaudiotagger.tag.TagTextField; import org.jaudiotagger.tag.reference.PictureTypes; import javax.imageio.ImageIO; import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.io.File; import java.io.RandomAccessFile; import java.util.List; /** * User: paul * Date: 07-Dec-2007 */ public class WmaSimpleTest extends AbstractTestCase { public void testReadFileFromPicardQtInvalidHeaderSizeException() { File orig = new File("testdata", "test2.wma"); if (!orig.isFile()) { System.err.println("Unable to test file - not available"); return; } Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test2.wma"); AudioFile f = AudioFileIO.read(testFile); //Now } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * File metadata was set with Media Monkey 3 *

* Checking our fields match the fields used by media Monkey 3 (Defacto Standard) by ensuring we can read fields written * in Media Monkey */ public void testReadFileFromMediaMonkey3() { Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test1.wma"); AudioFile f = AudioFileIO.read(testFile); assertEquals("32", f.getAudioHeader().getBitRate()); assertEquals("ASF (audio): 0x0161 (Windows Media Audio (ver 7,8,9))", f.getAudioHeader().getEncodingType()); assertEquals("2", f.getAudioHeader().getChannels()); assertEquals("32000", f.getAudioHeader().getSampleRate()); assertFalse(f.getAudioHeader().isVariableBitRate()); assertTrue(f.getTag() instanceof AsfTag); AsfTag tag = (AsfTag) f.getTag(); System.out.println(tag); //Ease of use methods for common fields assertEquals("artist", tag.getFirst(FieldKey.ARTIST)); assertEquals("album", tag.getFirst(FieldKey.ALBUM)); assertEquals("tracktitle", tag.getFirst(FieldKey.TITLE)); assertEquals("comments", tag.getFirst(FieldKey.COMMENT)); assertEquals("1971", tag.getFirst(FieldKey.YEAR)); assertEquals("3", tag.getFirst(FieldKey.TRACK)); assertEquals("genre", tag.getFirst(FieldKey.GENRE)); assertEquals("artist", tag.getFirst(FieldKey.ARTIST)); assertEquals("artist", tag.getFirst(AsfFieldKey.AUTHOR.getFieldName())); assertEquals("album", tag.getFirst(FieldKey.ALBUM)); assertEquals("album", tag.getFirst(AsfFieldKey.ALBUM.getFieldName())); assertEquals("tracktitle", tag.getFirst(FieldKey.TITLE)); assertEquals("tracktitle", tag.getFirst(AsfFieldKey.TITLE.getFieldName())); assertEquals("genre", tag.getFirst(FieldKey.GENRE)); assertEquals("genre", tag.getFirst(AsfFieldKey.GENRE.getFieldName())); assertEquals("3", tag.getFirst(FieldKey.TRACK)); assertEquals("1971", tag.getFirst(FieldKey.YEAR)); assertEquals("genre", tag.getFirst(FieldKey.GENRE)); assertEquals("comments", tag.getFirst(FieldKey.COMMENT)); assertEquals("albumartist", tag.getFirst(FieldKey.ALBUM_ARTIST)); assertEquals("composer", tag.getFirst(FieldKey.COMPOSER)); assertEquals("grouping", tag.getFirst(FieldKey.GROUPING)); assertEquals("2", tag.getFirst(FieldKey.DISC_NO)); assertEquals("lyrics for song", tag.getFirst(FieldKey.LYRICS)); assertEquals("encoder", tag.getFirst(FieldKey.ENCODER)); assertEquals("isrc", tag.getFirst(FieldKey.ISRC)); assertEquals("publisher", tag.getFirst(FieldKey.RECORD_LABEL)); assertEquals("Lyricist", tag.getFirst(FieldKey.LYRICIST)); assertEquals("conductor", tag.getFirst(FieldKey.CONDUCTOR)); assertEquals("Mellow", tag.getFirst(FieldKey.MOOD)); //Media Monkey does not currently support these fields ... //assertEquals("is_compilation", tag.getFirst(FieldKey.IS_COMPILATION)); //assertEquals("artist_sort", tag.getFirst(FieldKey.ARTIST_SORT)); //assertEquals("album_artist_sort", tag.getFirst(FieldKey.ALBUM_ARTIST_SORT)); //assertEquals("album_sort", tag.getFirst(FieldKey.ALBUM_SORT)); //assertEquals("title_sort", tag.getFirst(FieldKey.TITLE_SORT)); //assertEquals("barcode", tag.getFirst(FieldKey.BARCODE)); //assertEquals("catalogno", tag.getFirst(FieldKey.CATALOG_NO)); //assertEquals("media", tag.getFirst(FieldKey.MEDIA)); //assertEquals("remixer", tag.getFirst(FieldKey.REMIXER)); //Now } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * File metadata was set with PicardQt *

* Checking our fields match the fields used by picard Qt3 (Defacto Standard for Musicbrainz fields) by ensuring we can read fields written * in Picard Qt */ public void testReadFileFromPicardQt() { File orig = new File("testdata", "test2.wma"); if (!orig.isFile()) { System.err.println("Unable to test file - not available"); return; } Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test2.wma"); AudioFile f = AudioFileIO.read(testFile); assertEquals("128", f.getAudioHeader().getBitRate()); assertEquals("ASF (audio): 0x0162 (Windows Media Audio 9 series (Professional))", f.getAudioHeader().getEncodingType()); assertEquals("2", f.getAudioHeader().getChannels()); assertEquals("44100", f.getAudioHeader().getSampleRate()); assertFalse(f.getAudioHeader().isVariableBitRate()); assertTrue(f.getTag() instanceof AsfTag); AsfTag tag = (AsfTag) f.getTag(); System.out.println(tag); //Ease of use methods for common fields assertEquals("Sonic Youth", tag.getFirst(FieldKey.ARTIST)); assertEquals("Sister", tag.getFirst(FieldKey.ALBUM)); assertEquals("(I Got a) Catholic Block", tag.getFirst(FieldKey.TITLE)); assertEquals("1987", tag.getFirst(FieldKey.YEAR)); assertEquals("2", tag.getFirst(FieldKey.TRACK)); //NOTE:track can have seroes or not assertEquals("no wave", tag.getFirst(FieldKey.GENRE)); assertEquals("Sonic Youth", tag.getFirst(FieldKey.ARTIST)); assertEquals("Sonic Youth", tag.getFirst(AsfFieldKey.AUTHOR.getFieldName())); assertEquals("Sister", tag.getFirst(FieldKey.ALBUM)); assertEquals("Sister", tag.getFirst(AsfFieldKey.ALBUM.getFieldName())); assertEquals("(I Got a) Catholic Block", tag.getFirst(FieldKey.TITLE)); assertEquals("(I Got a) Catholic Block", tag.getFirst(AsfFieldKey.TITLE.getFieldName())); assertEquals("no wave", tag.getFirst(FieldKey.GENRE)); assertEquals("no wave", tag.getFirst(AsfFieldKey.GENRE.getFieldName())); assertEquals("2", tag.getFirst(FieldKey.TRACK)); assertEquals("2", tag.getFirst(AsfFieldKey.TRACK.getFieldName())); assertEquals("1987", tag.getFirst(FieldKey.YEAR)); assertEquals("1987", tag.getFirst(AsfFieldKey.YEAR.getFieldName())); assertEquals("Sonic Youth", tag.getFirst(FieldKey.ALBUM_ARTIST)); assertEquals("Sonic Youth", tag.getFirst(AsfFieldKey.ALBUM_ARTIST.getFieldName())); assertEquals("Blast First", tag.getFirst(FieldKey.RECORD_LABEL)); assertEquals("Blast First", tag.getFirst(AsfFieldKey.RECORD_LABEL.getFieldName())); assertEquals("Sonic Youth", tag.getFirst(FieldKey.ARTIST_SORT)); assertEquals("Sonic Youth", tag.getFirst(AsfFieldKey.ARTIST_SORT.getFieldName())); assertEquals("Sonic Youth", tag.getFirst(FieldKey.ARTIST_SORT)); assertEquals("Sonic Youth", tag.getFirst(AsfFieldKey.ARTIST_SORT.getFieldName())); assertEquals("Sonic Youth", tag.getFirst(FieldKey.ALBUM_ARTIST_SORT)); assertEquals("Sonic Youth", tag.getFirst(AsfFieldKey.ALBUM_ARTIST_SORT.getFieldName())); assertEquals("official", tag.getFirst(FieldKey.MUSICBRAINZ_RELEASE_STATUS)); assertEquals("official", tag.getFirst(AsfFieldKey.MUSICBRAINZ_RELEASE_STATUS.getFieldName())); assertEquals("album", tag.getFirst(FieldKey.MUSICBRAINZ_RELEASE_TYPE)); assertEquals("album", tag.getFirst(AsfFieldKey.MUSICBRAINZ_RELEASE_TYPE.getFieldName())); assertEquals("GB", tag.getFirst(FieldKey.MUSICBRAINZ_RELEASE_COUNTRY)); assertEquals("GB", tag.getFirst(AsfFieldKey.MUSICBRAINZ_RELEASE_COUNTRY.getFieldName())); assertEquals("5cbef01b-cc35-4f52-af7b-d0df0c4f61b9", tag.getFirst(FieldKey.MUSICBRAINZ_RELEASEARTISTID)); assertEquals("5cbef01b-cc35-4f52-af7b-d0df0c4f61b9", tag.getFirst(AsfFieldKey.MUSICBRAINZ_RELEASEARTISTID.getFieldName())); assertEquals("f8ece8ad-0ef1-45c0-9d20-a58a10052d5c", tag.getFirst(FieldKey.MUSICBRAINZ_TRACK_ID)); assertEquals("f8ece8ad-0ef1-45c0-9d20-a58a10052d5c", tag.getFirst(AsfFieldKey.MUSICBRAINZ_TRACK_ID.getFieldName())); assertEquals("ca16e36d-fa43-4b49-8c71-d98bd70b341f", tag.getFirst(FieldKey.MUSICBRAINZ_RELEASEID)); assertEquals("ca16e36d-fa43-4b49-8c71-d98bd70b341f", tag.getFirst(AsfFieldKey.MUSICBRAINZ_RELEASEID.getFieldName())); assertEquals("5cbef01b-cc35-4f52-af7b-d0df0c4f61b9", tag.getFirst(FieldKey.MUSICBRAINZ_ARTISTID)); assertEquals("5cbef01b-cc35-4f52-af7b-d0df0c4f61b9", tag.getFirst(AsfFieldKey.MUSICBRAINZ_ARTISTID.getFieldName())); //This example doesnt populate these fields //assertEquals("Sonic Youth", tag.getFirst(FieldKey.COMPOSER)); //assertEquals("grouping", tag.getFirst(FieldKey.GROUPING)); //assertEquals("2", tag.getFirst(FieldKey.DISC_NO)); //assertEquals("lyrics for song", tag.getFirst(FieldKey.LYRICS)); //assertEquals("encoder", tag.getFirst(FieldKey.ENCODER)); //assertEquals("isrc", tag.getFirst(FieldKey.ISRC)); //assertEquals("Lyricist", tag.getFirst(FieldKey.LYRICIST)); //assertEquals("conductor", tag.getFirst(FieldKey.CONDUCTOR)); //assertEquals("Mellow", tag.getFirst(FieldKey.INVOLVED_PEOPLE)); //assertEquals("5cbef01b-cc35-4f52-af7b-d0df0c4f61b9", tag.getFirst(FieldKey.MUSICIP_ID)); //Picard Qt does not currently support these fields ... //assertEquals("is_compilation", tag.getFirst(FieldKey.IS_COMPILATION)); //assertEquals("album_sort", tag.getFirst(FieldKey.ALBUM_SORT)); //assertEquals("title_sort", tag.getFirst(FieldKey.TITLE_SORT)); //assertEquals("barcode", tag.getFirst(FieldKey.BARCODE)); //assertEquals("catalogno", tag.getFirst(FieldKey.CATALOG_NO)); //assertEquals("media", tag.getFirst(FieldKey.MEDIA)); //assertEquals("remixer", tag.getFirst(FieldKey.REMIXER)); //Now } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } public void testWriteFile() { Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test1.wma", new File("testwrite1.wma")); AudioFile f = AudioFileIO.read(testFile); assertEquals("32", f.getAudioHeader().getBitRate()); assertEquals("ASF (audio): 0x0161 (Windows Media Audio (ver 7,8,9))", f.getAudioHeader().getEncodingType()); assertEquals("2", f.getAudioHeader().getChannels()); assertEquals("32000", f.getAudioHeader().getSampleRate()); assertFalse(f.getAudioHeader().isVariableBitRate()); assertTrue(f.getTag() instanceof AsfTag); AsfTag tag = (AsfTag) f.getTag(); //Write some new values and save tag.setField(FieldKey.ARTIST,"artist2"); tag.setField(FieldKey.ALBUM,"album2"); tag.setField(FieldKey.TITLE,"tracktitle2"); tag.setField(FieldKey.COMMENT,"comments2"); tag.addField(FieldKey.YEAR,"1972"); tag.setField(FieldKey.GENRE,"genre2"); tag.setField(FieldKey.TRACK,"4"); tag.setCopyright("copyright"); tag.setRating("rating"); tag.setField(tag.createField(FieldKey.URL_LYRICS_SITE,"http://www.lyrics.fly.com")); tag.setField(tag.createField(FieldKey.URL_DISCOGS_ARTIST_SITE,"http://www.discogs1.com")); tag.setField(tag.createField(FieldKey.URL_DISCOGS_RELEASE_SITE,"http://www.discogs2.com")); tag.setField(tag.createField(FieldKey.URL_OFFICIAL_ARTIST_SITE,"http://www.discogs3.com")); tag.setField(tag.createField(FieldKey.URL_OFFICIAL_RELEASE_SITE,"http://www.discogs4.com")); tag.addField(tag.createField(FieldKey.URL_WIKIPEDIA_ARTIST_SITE,"http://www.discogs5.com")); tag.addField(tag.createField(FieldKey.URL_WIKIPEDIA_RELEASE_SITE,"http://www.discogs6.com")); tag.setField(tag.createField(FieldKey.DISC_TOTAL,"3")); tag.setField(tag.createField(FieldKey.TRACK_TOTAL,"11")); // setField the IsVbr value (can be modified for now) tag.setField(tag.createField(AsfFieldKey.ISVBR, Boolean.TRUE.toString())); f.commit(); f = AudioFileIO.read(testFile); tag = (AsfTag) f.getTag(); assertTrue(f.getAudioHeader().isVariableBitRate()); assertEquals("artist2", tag.getFirst(FieldKey.ARTIST)); assertEquals("album2", tag.getFirst(FieldKey.ALBUM)); assertEquals("tracktitle2", tag.getFirst(FieldKey.TITLE)); assertEquals("comments2", tag.getFirst(FieldKey.COMMENT)); assertEquals("1972", tag.getFirst(FieldKey.YEAR)); assertEquals("4", tag.getFirst(FieldKey.TRACK)); assertEquals("genre2", tag.getFirst(FieldKey.GENRE)); assertEquals("copyright", tag.getFirstCopyright()); assertEquals("rating", tag.getFirstRating()); assertEquals("http://www.lyrics.fly.com",tag.getFirst(FieldKey.URL_LYRICS_SITE)); assertEquals("http://www.discogs1.com",tag.getFirst(FieldKey.URL_DISCOGS_ARTIST_SITE)); assertEquals("http://www.discogs2.com",tag.getFirst(FieldKey.URL_DISCOGS_RELEASE_SITE)); assertEquals("http://www.discogs3.com",tag.getFirst(FieldKey.URL_OFFICIAL_ARTIST_SITE)); assertEquals("http://www.discogs4.com",tag.getFirst(FieldKey.URL_OFFICIAL_RELEASE_SITE)); assertEquals("http://www.discogs5.com",tag.getFirst(FieldKey.URL_WIKIPEDIA_ARTIST_SITE)); assertEquals("http://www.discogs6.com",tag.getFirst(FieldKey.URL_WIKIPEDIA_RELEASE_SITE)); assertEquals("3",tag.getFirst(FieldKey.DISC_TOTAL)); assertEquals("11",tag.getFirst(FieldKey.TRACK_TOTAL)); AudioFileIO.delete(f); f = AudioFileIO.read(testFile); tag = (AsfTag) f.getTag(); assertFalse(f.getAudioHeader().isVariableBitRate()); assertTrue(tag.isEmpty()); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * Just create fields for all the tag field keys defined, se if we hit any problems */ public void testTagFieldKeyWrite() { Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test1.wma", new File("testwrite1.wma")); AudioFile f = AudioFileIO.read(testFile); AudioFileIO.delete(f); // Tests multiple iterations on same file for (int i = 0; i < 2; i++) { f = AudioFileIO.read(testFile); Tag tag = f.getTag(); for (FieldKey key : FieldKey.values()) { if (!(key == FieldKey.COVER_ART)) { tag.setField(tag.createField(key, key.name() + "_value_" + i)); } } f.commit(); f = AudioFileIO.read(testFile); tag = f.getTag(); for (FieldKey key : FieldKey.values()) { /* * Test value retrieval, using multiple access methods. */ if (!(key == FieldKey.COVER_ART)) { String value = key.name() + "_value_" + i; System.out.println("Value is:" + value); assertEquals(value, tag.getFirst(key)); AsfTagTextField atf = (AsfTagTextField) tag.getFields(key).get(0); assertEquals(value, atf.getContent()); atf = (AsfTagTextField) tag.getFields(key).get(0); assertEquals(value, atf.getContent()); } } } } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * Lets now check the value explicity are what we expect */ public void testTagFieldKeyWrite2() { Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test1.wma", new File("testwrite1.wma")); AudioFile f = AudioFileIO.read(testFile); AudioFileIO.delete(f); //test fields are written with correct ids f = AudioFileIO.read(testFile); Tag tag = f.getTag(); for (FieldKey key : FieldKey.values()) { if (!(key == FieldKey.COVER_ART)) { tag.addField(tag.createField(key, key.name() + "_value")); } } f.commit(); //Reread File f = AudioFileIO.read(testFile); tag = f.getTag(); TagField tf = tag.getFirstField(AsfFieldKey.ALBUM.getFieldName()); assertEquals("WM/AlbumTitle", tf.getId()); assertEquals("ALBUM_value", ((TagTextField) tf).getContent()); assertEquals("UTF-16LE", ((TagTextField) tf).getEncoding()); tf = tag.getFirstField(AsfFieldKey.ALBUM_ARTIST.getFieldName()); assertEquals("WM/AlbumArtist", tf.getId()); assertEquals("ALBUM_ARTIST_value", ((TagTextField) tf).getContent()); assertEquals("UTF-16LE", ((TagTextField) tf).getEncoding()); tf = tag.getFirstField(AsfFieldKey.AMAZON_ID.getFieldName()); assertEquals("ASIN", tf.getId()); assertEquals("AMAZON_ID_value", ((TagTextField) tf).getContent()); assertEquals("UTF-16LE", ((TagTextField) tf).getEncoding()); tf = tag.getFirstField(AsfFieldKey.TITLE.getFieldName()); assertEquals("TITLE", tf.getId()); assertEquals("TITLE_value", ((TagTextField) tf).getContent()); assertEquals("UTF-16LE", ((TagTextField) tf).getEncoding()); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } public void testIsMultiValues() { assertFalse(AsfFieldKey.isMultiValued(AsfFieldKey.ALBUM.getFieldName())); } /** * Shouldnt fail just ecause header size doesnt match file size because file plays ok in winamp */ public void testReadFileWithHeaderSizeDoesntMatchFileSize() { File orig = new File("testdata", "test3.wma"); if (!orig.isFile()) { System.err.println("Unable to test file - not available"); return; } Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test3.wma"); AudioFile f = AudioFileIO.read(testFile); assertEquals("Glass", f.getTag().getFirst(FieldKey.TITLE)); //Now } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } public void testReadFileWithGifArtwork() { File orig = new File("testdata", "test1.wma"); if (!orig.isFile()) { System.err.println("Unable to test file - not available"); return; } Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test1.wma"); AudioFile f = AudioFileIO.read(testFile); Tag tag = f.getTag(); assertEquals(1, tag.getFields(FieldKey.COVER_ART).size()); TagField tagField = tag.getFields(FieldKey.COVER_ART).get(0); assertEquals("WM/Picture", tagField.getId()); assertEquals(14550, tagField.getRawContent().length); //Should have been loaded as special field to make things easier assertTrue(tagField instanceof AsfTagCoverField); AsfTagCoverField coverartField = (AsfTagCoverField) tagField; assertEquals("image/gif", coverartField.getMimeType()); assertEquals("coverart", coverartField.getDescription()); assertEquals(200, coverartField.getImage().getWidth()); assertEquals(200, coverartField.getImage().getHeight()); assertEquals(3, coverartField.getPictureType()); assertEquals(BufferedImage.TYPE_BYTE_INDEXED, coverartField.getImage().getType()); /***** TO SOME MANUAL CHECKING *****************/ //First byte of data is immediatley after the 2 byte Descriptor value assertEquals(0x03, tagField.getRawContent()[0]); //Raw Data consists of Unknown/MimeType/Name and Actual Image, null seperated (two bytes) //Skip first three unknown bytes plus two byte nulls int count = 5; String mimeType = null; String name = null; int endOfMimeType = 0; int endOfName = 0; while (count < tagField.getRawContent().length - 1) { if (tagField.getRawContent()[count] == 0 && tagField.getRawContent()[count + 1] == 0) { if (mimeType == null) { mimeType = new String(tagField.getRawContent(), 5, (count) - 5, "UTF-16LE"); endOfMimeType = count + 2; } else if (name == null) { name = new String(tagField.getRawContent(), endOfMimeType, count - endOfMimeType, "UTF-16LE"); endOfName = count + 2; break; } count += 2; } count += 2; //keep on two byte word boundary } assertEquals("image/gif", mimeType); assertEquals("coverart", name); BufferedImage bi = ImageIO.read(ImageIO .createImageInputStream(new ByteArrayInputStream(tagField.getRawContent(), endOfName, tagField.getRawContent().length - endOfName))); assertNotNull(bi); assertEquals(200, bi.getWidth()); assertEquals(200, bi.getHeight()); assertEquals(BufferedImage.TYPE_BYTE_INDEXED, bi.getType()); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * Contains image field, but only has image type and image, it doesnt have a label */ public void testReadFileWithGifArtworkNoDescription() { File orig = new File("testdata", "test4.wma"); if (!orig.isFile()) { System.err.println("Unable to test file - not available"); return; } Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test4.wma"); AudioFile f = AudioFileIO.read(testFile); Tag tag = f.getTag(); assertEquals(1, tag.getFields(FieldKey.COVER_ART).size()); TagField tagField = tag.getFields(FieldKey.COVER_ART).get(0); assertEquals("WM/Picture", tagField.getId()); assertEquals(14534, tagField.getRawContent().length); //Should have been loaded as special field to make things easier assertTrue(tagField instanceof AsfTagCoverField); AsfTagCoverField coverartField = (AsfTagCoverField) tagField; assertEquals("image/gif", coverartField.getMimeType()); assertEquals("", coverartField.getDescription()); assertEquals(200, coverartField.getImage().getWidth()); assertEquals(200, coverartField.getImage().getHeight()); assertEquals(12, coverartField.getPictureType()); assertEquals(BufferedImage.TYPE_BYTE_INDEXED, coverartField.getImage().getType()); //First byte of data is immediatley after the 2 byte Descriptor value assertEquals(12, tagField.getRawContent()[0]); //Raw Data consists of Unknown/MimeType/Name and Actual Image, null seperated (two bytes) //Skip first three unknown bytes plus two byte nulls int count = 5; String mimeType = null; String name = null; int endOfMimeType = 0; int endOfName = 0; while (count < tagField.getRawContent().length - 1) { if (tagField.getRawContent()[count] == 0 && tagField.getRawContent()[count + 1] == 0) { if (mimeType == null) { mimeType = new String(tagField.getRawContent(), 5, (count) - 5, "UTF-16LE"); endOfMimeType = count + 2; } else if (name == null) { name = new String(tagField.getRawContent(), endOfMimeType, count - endOfMimeType, "UTF-16LE"); endOfName = count + 2; break; } } count += 2; //keep on two byte word boundary } assertEquals("image/gif", mimeType); assertEquals("", name); BufferedImage bi = ImageIO.read(ImageIO .createImageInputStream(new ByteArrayInputStream(tagField.getRawContent(), endOfName, tagField.getRawContent().length - endOfName))); assertNotNull(bi); assertEquals(200, bi.getWidth()); assertEquals(200, bi.getHeight()); assertEquals(BufferedImage.TYPE_BYTE_INDEXED, bi.getType()); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } public void testReadFileWithPngArtwork() { File orig = new File("testdata", "test5.wma"); if (!orig.isFile()) { System.err.println("Unable to test file - not available"); return; } Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test5.wma"); AudioFile f = AudioFileIO.read(testFile); Tag tag = f.getTag(); assertEquals(1, tag.getFields(FieldKey.COVER_ART).size()); TagField tagField = tag.getFields(FieldKey.COVER_ART).get(0); assertEquals("WM/Picture", tagField.getId()); assertEquals(18590, tagField.getRawContent().length); //Should have been loaded as special field to make things easier assertTrue(tagField instanceof AsfTagCoverField); AsfTagCoverField coverartField = (AsfTagCoverField) tagField; assertEquals("image/png", coverartField.getMimeType()); assertEquals(3, coverartField.getPictureType()); assertEquals("coveerart", coverartField.getDescription()); assertEquals(200, coverartField.getImage().getWidth()); assertEquals(200, coverartField.getImage().getHeight()); assertEquals(BufferedImage.TYPE_CUSTOM, coverartField.getImage().getType()); /***** TO SOME MANUAL CHECKING *****************/ //First byte of data is immediatley after the 2 byte Descriptor value assertEquals(0x03, tagField.getRawContent()[0]); //Raw Data consists of Unknown/MimeType/Name and Actual Image, null seperated (two bytes) //Skip first three unknown bytes plus two byte nulls int count = 5; String mimeType = null; String name = null; int endOfMimeType = 0; int endOfName = 0; while (count < tagField.getRawContent().length - 1) { if (tagField.getRawContent()[count] == 0 && tagField.getRawContent()[count + 1] == 0) { if (mimeType == null) { mimeType = new String(tagField.getRawContent(), 5, (count) - 5, "UTF-16LE"); endOfMimeType = count + 2; } else if (name == null) { name = new String(tagField.getRawContent(), endOfMimeType, count - endOfMimeType, "UTF-16LE"); endOfName = count + 2; break; } count += 2; } count += 2; //keep on two byte word boundary } assertEquals("image/png", mimeType); assertEquals("coveerart", name); BufferedImage bi = ImageIO.read(ImageIO .createImageInputStream(new ByteArrayInputStream(tagField.getRawContent(), endOfName, tagField.getRawContent().length - endOfName))); assertNotNull(bi); assertEquals(200, bi.getWidth()); assertEquals(200, bi.getHeight()); assertEquals(BufferedImage.TYPE_CUSTOM, bi.getType()); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } public void testReadFileWithJpgArtwork() { File orig = new File("testdata", "test6.wma"); if (!orig.isFile()) { System.err.println("Unable to test file - not available"); return; } Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test6.wma"); AudioFile f = AudioFileIO.read(testFile); Tag tag = f.getTag(); assertEquals(1, tag.getFields(FieldKey.COVER_ART).size()); TagField tagField = tag.getFields(FieldKey.COVER_ART).get(0); assertEquals("WM/Picture", tagField.getId()); assertEquals(5093, tagField.getRawContent().length); //Should have been loaded as special field to make things easier assertTrue(tagField instanceof AsfTagCoverField); AsfTagCoverField coverartField = (AsfTagCoverField) tagField; assertEquals("image/jpeg", coverartField.getMimeType()); assertEquals("coveerart", coverartField.getDescription()); assertEquals(3, coverartField.getPictureType()); assertEquals(200, coverartField.getImage().getWidth()); assertEquals(200, coverartField.getImage().getHeight()); assertEquals(5093, coverartField.getRawContent().length); assertEquals(5046, coverartField.getRawImageData().length); assertEquals(5046, coverartField.getImageDataSize()); assertEquals(coverartField.getRawImageData().length, coverartField.getImageDataSize()); assertEquals(BufferedImage.TYPE_3BYTE_BGR, coverartField.getImage().getType()); /***** TO SOME MANUAL CHECKING *****************/ //First byte of data is immediatley after the 2 byte Descriptor value assertEquals(0x03, tagField.getRawContent()[0]); //Raw Data consists of Unknown/MimeType/Name and Actual Image, null seperated (two bytes) //Skip first three unknown bytes plus two byte nulls int count = 5; String mimeType = null; String name = null; int endOfMimeType = 0; int endOfName = 0; while (count < tagField.getRawContent().length - 1) { if (tagField.getRawContent()[count] == 0 && tagField.getRawContent()[count + 1] == 0) { if (mimeType == null) { mimeType = new String(tagField.getRawContent(), 5, (count) - 5, "UTF-16LE"); endOfMimeType = count + 2; } else if (name == null) { name = new String(tagField.getRawContent(), endOfMimeType, count - endOfMimeType, "UTF-16LE"); endOfName = count + 2; break; } count += 2; } count += 2; //keep on two byte word boundary } assertEquals("image/jpeg", mimeType); assertEquals("coveerart", name); BufferedImage bi = ImageIO.read(ImageIO .createImageInputStream(new ByteArrayInputStream(tagField.getRawContent(), endOfName, tagField.getRawContent().length - endOfName))); assertNotNull(bi); assertEquals(200, bi.getWidth()); assertEquals(200, bi.getHeight()); assertEquals(BufferedImage.TYPE_3BYTE_BGR, bi.getType()); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * Write png , old method */ public void testWritePngArtworkToFile() { File orig = new File("testdata", "test7.wma"); if (!orig.isFile()) { System.err.println("Unable to test file - not available"); return; } Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test7.wma"); AudioFile f = AudioFileIO.read(testFile); Tag tag = f.getTag(); assertEquals(0, tag.getFields(FieldKey.COVER_ART).size()); //Now createField artwork field RandomAccessFile imageFile = new RandomAccessFile(new File("testdata", "coverart.png"), "r"); byte[] imagedata = new byte[(int) imageFile.length()]; imageFile.read(imagedata); AsfTag asftag = (AsfTag) tag; asftag.setField(asftag.createArtworkField(imagedata)); f.commit(); f = AudioFileIO.read(testFile); tag = f.getTag(); assertEquals(1, tag.getFields(FieldKey.COVER_ART).size()); TagField tagField = tag.getFields(FieldKey.COVER_ART).get(0); AsfTagCoverField coverartField = (AsfTagCoverField) tagField; assertEquals("WM/Picture", tagField.getId()); assertEquals((Integer) PictureTypes.DEFAULT_ID, (Integer) coverartField.getPictureType()); assertEquals(18572, tagField.getRawContent().length); assertEquals(18545, coverartField.getRawImageData().length); assertEquals(coverartField.getImageDataSize(), coverartField.getRawImageData().length); assertEquals(200, coverartField.getImage().getWidth()); assertEquals(200, coverartField.getImage().getHeight()); assertEquals(BufferedImage.TYPE_CUSTOM, coverartField.getImage().getType()); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /* TODO multiple fields for WMA public void testWriteMultipleFields() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("test1.wma", new File("testWriteMultiple.wma")); AudioFile f = AudioFileIO.read(testFile); List tagFields = f.getTag().getFields(FieldKey.ALBUM_ARTIST_SORT); assertEquals(tagFields.size(),0); f.getTag().addField(FieldKey.ALBUM_ARTIST_SORT,"artist1"); f.getTag().addField(FieldKey.ALBUM_ARTIST_SORT,"artist2"); f.commit(); f = AudioFileIO.read(testFile); tagFields = f.getTag().getFields(FieldKey.ALBUM_ARTIST_SORT); assertEquals(2,tagFields.size()); } */ public void testDeleteFields() throws Exception { //Delete using generic key File testFile = AbstractTestCase.copyAudioToTmp("test1.wma", new File("testDeleteFields.wma")); AudioFile f = AudioFileIO.read(testFile); List tagFields = f.getTag().getFields(FieldKey.ALBUM_ARTIST_SORT); assertEquals(0,tagFields.size()); f.getTag().addField(FieldKey.ALBUM_ARTIST_SORT,"artist1"); tagFields = f.getTag().getFields(FieldKey.ALBUM_ARTIST_SORT); assertEquals(1,tagFields.size()); f.getTag().deleteField(FieldKey.ALBUM_ARTIST_SORT); f.commit(); //Delete using flac id f = AudioFileIO.read(testFile); tagFields = f.getTag().getFields(FieldKey.ALBUM_ARTIST_SORT); assertEquals(0,tagFields.size()); f.getTag().addField(FieldKey.ALBUM_ARTIST_SORT,"artist1"); tagFields = f.getTag().getFields(FieldKey.ALBUM_ARTIST_SORT); assertEquals(1,tagFields.size()); f.getTag().deleteField("WM/AlbumArtistSortOrder"); tagFields = f.getTag().getFields(FieldKey.ALBUM_ARTIST_SORT); assertEquals(0,tagFields.size()); f.commit(); f = AudioFileIO.read(testFile); tagFields = f.getTag().getFields(FieldKey.ALBUM_ARTIST_SORT); assertEquals(0,tagFields.size()); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/wma/WmaDescriptionLocationTest.java0000644000175000017500000001403711277264361032107 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.wma; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.audio.asf.data.AsfHeader; import org.jaudiotagger.audio.asf.data.MetadataContainer; import org.jaudiotagger.audio.asf.io.*; import org.jaudiotagger.tag.asf.AsfFieldKey; import org.jaudiotagger.tag.asf.AsfTag; import org.jaudiotagger.audio.asf.util.TagConverter; import org.jaudiotagger.tag.FieldKey; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.util.ArrayList; import java.util.List; /** * This testcase tests the ability to read the content description and extended content description * from the ASF header object and the ASF header extension object. * * @author Christian Laireiter */ public class WmaDescriptionLocationTest extends WmaTestCase { /** * Test file to use as source. */ public final static String TEST_FILE = "test1.wma"; //$NON-NLS-1$ /** * Will hold a tag instance for writing some values. */ private final AsfTag testTag; /** * Creates an instance. */ public WmaDescriptionLocationTest() throws Exception { super(TEST_FILE); this.testTag = new AsfTag(true); this.testTag.setField(FieldKey.ARTIST,"TheArtist"); this.testTag.setField(this.testTag.createField(AsfFieldKey.ISVBR, Boolean.TRUE.toString())); } /** * Applies {@link #testTag} to the given audio file, and allows to specify at which location the * content description and extended content description are to be added.
* @param testFile The file to work with. * @param hcd true if the content description should be placed into the header object. if false * it will be placed in the header extension object. * @param hecd true if the extended content description should be placed into the header object. if false * it will be placed in the header extension object. * @throws Exception on I/O Errors. */ private void applyTag(File testFile, boolean hcd, boolean hecd) throws Exception { // getFields an audio file instance AudioFile read = AudioFileIO.read(testFile); // deleteField all managed data AudioFileIO.delete(read); // Create chunks MetadataContainer[] distributeMetadata = TagConverter.distributeMetadata(this.testTag); // createField creator for the content description object (chunk) WriteableChunkModifer cdCreator = new WriteableChunkModifer(distributeMetadata[0]); MetadataContainer ecd = distributeMetadata[2]; // createField creator for the extended content description object (chunk) WriteableChunkModifer ecdCreator = new WriteableChunkModifer(ecd); // createField the modifier lists List headerMods = new ArrayList(); List extHeaderMods = new ArrayList(); if (hcd) { headerMods.add(cdCreator); } else { extHeaderMods.add(cdCreator); } if (hecd) { headerMods.add(ecdCreator); } else { extHeaderMods.add(ecdCreator); } headerMods.add(new AsfExtHeaderModifier(extHeaderMods)); File destination = prepareTestFile("chunkloc.wma"); new AsfStreamer() .createModifiedCopy(new FileInputStream(testFile), new FileOutputStream(destination), headerMods); checkExcpectations(destination, hcd, hecd, !hcd, !hecd); } /** * Tests whether the audio file contains artist and variable bitrate as specified in the * {@linkplain #WmaDescriptionLocationTest() constructor}, and if a content description object as well * as an extended content description is available. * @param testFile file to test * @param hcd true if a content description is expected in the ASF header. * @param hecd true if an extended content description is expected in the ASF header. * @param ehcd true if a content description is expected in the ASF header extension. * @param ehecd true if an extended content description is expected in the ASF header extension. * @throws Exception on I/O Errors */ private void checkExcpectations(File testFile, boolean hcd, boolean hecd, boolean ehcd, boolean ehecd) throws Exception { AudioFile read = AudioFileIO.read(testFile); assertTrue(read.getAudioHeader().isVariableBitRate()); assertEquals("TheArtist", read.getTag().getFirst(FieldKey.ARTIST)); AsfHeader readHeader = AsfHeaderReader.readHeader(testFile); assertNotNull(readHeader.findContentDescription()); assertNotNull(readHeader.findExtendedContentDescription()); assertEquals(hcd, readHeader.getContentDescription() != null); assertEquals(hecd, readHeader.getExtendedContentDescription() != null); assertEquals(ehcd, readHeader.getExtendedHeader() != null && readHeader.getExtendedHeader() .getContentDescription() != null); assertEquals(ehecd, readHeader.getExtendedHeader() != null && readHeader.getExtendedHeader() .getExtendedContentDescription() != null); } /** * Tests the locations of the metadata descriptor object and the extended metadata descriptor object, upon * some deep ASF manipulations. * * @throws Exception On I/O Errors */ public void testChunkLocations() throws Exception { File testFile = prepareTestFile(null); AudioFile read = AudioFileIO.read(testFile); AudioFileIO.delete(read); read.setTag(testTag); read.commit(); checkExcpectations(testFile, true, true, false, false); applyTag(testFile, false, false); applyTag(testFile, false, true); applyTag(testFile, true, false); applyTag(testFile, true, true); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/wma/WmaTestCase.java0000644000175000017500000000607411276777123027014 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.wma; import junit.framework.TestCase; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.audio.asf.util.Utils; import org.jaudiotagger.tag.Tag; import java.io.File; /** * Base class for WMA test cases.
* * @author Christian Laireiter */ public abstract class WmaTestCase extends TestCase { /** * Stores the audio file instance of {@link #testFile}.
*/ private AudioFile audioFile; /** * The file name of the source file, from which a copy will be created. */ private String sourceTestFile; /** * The file on which tests should be performed.
*/ private File testFile; /** * Creates an instance, that would perform tests on the given sourceFile. * @param sourceFile The filename of the file to perform tests on. ({@linkplain AbstractTestCase#copyAudioToTmp(String) copy} will be created) */ public WmaTestCase(final String sourceFile) { this.sourceTestFile = sourceFile; } /** * Creates an instance, that would perform tests on the given sourceFile. * @param sourceFile The filename of the file to perform tests on. ({@linkplain AbstractTestCase#copyAudioToTmp(String) copy} will be created) * @param name name of the test. */ public WmaTestCase(final String sourceFile, final String name) { super(name); this.sourceTestFile = sourceFile; } /** * Returns the audio file to perform the tests on.
* @return audio file to perform the tests on.
* @throws Exception Upon IO errors, or ASF parsing faults. */ public AudioFile getAudioFile() throws Exception { if (this.audioFile == null) { this.audioFile = AudioFileIO.read(this.testFile); } return this.audioFile; } /** * Returns the tag of the {@linkplain #audioFile}.
* @return the tag of the {@linkplain #audioFile}.
* @throws Exception from call of {@link #getAudioFile()}. */ public Tag getTag() throws Exception { return getAudioFile().getTag(); } /** * Returns a file for testing purposes. * @return file for testing. */ public File prepareTestFile(String fileName) { assertNotNull(sourceTestFile); File result = null; if (!Utils.isBlank(fileName)) { result = AbstractTestCase.copyAudioToTmp(sourceTestFile, new File(fileName)); } else { result = AbstractTestCase.copyAudioToTmp(sourceTestFile); } return result; } /** * Creates the file copy. */ protected void setUp() throws Exception { super.setUp(); assertNotNull(sourceTestFile); this.testFile = prepareTestFile(null); } /** * Deletes the copy. */ protected void tearDown() throws Exception { super.tearDown(); // this.testFile.deleteField(); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/wma/TagConverterTest.java0000644000175000017500000000341011277264361030062 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.wma; import org.jaudiotagger.audio.asf.data.AsfHeader; import org.jaudiotagger.audio.asf.data.ContainerType; import org.jaudiotagger.audio.asf.data.MetadataContainer; import org.jaudiotagger.audio.asf.data.MetadataContainerUtils; import org.jaudiotagger.audio.asf.io.AsfHeaderReader; import org.jaudiotagger.tag.asf.AsfTag; import org.jaudiotagger.audio.asf.util.TagConverter; import java.io.IOException; /** * @author Christian Laireiter * */ public class TagConverterTest extends WmaTestCase { public final static String TEST_FILE = "test6.wma"; /** * @param name */ public TagConverterTest(String name) { super(TEST_FILE, name); } /** * {@inheritDoc} */ protected void setUp() throws Exception { super.setUp(); } /** * Test method for * {@link org.jaudiotagger.audio.asf.util.TagConverter#distributeMetadata(org.jaudiotagger.tag.asf.AsfTag)} * . */ public void testDistributeMetadata() throws IOException { AsfHeader header = AsfHeaderReader.readHeader(prepareTestFile(null)); MetadataContainer contentDesc = header .findMetadataContainer(ContainerType.CONTENT_DESCRIPTION); assertNotNull(contentDesc); MetadataContainer extContentDesc = header .findMetadataContainer(ContainerType.EXTENDED_CONTENT); assertNotNull(extContentDesc); AsfTag createTagOf = TagConverter.createTagOf(header); MetadataContainer[] distributeMetadata = TagConverter .distributeMetadata(createTagOf); assertTrue(MetadataContainerUtils.equals(contentDesc, distributeMetadata[0])); assertTrue(MetadataContainerUtils.equals(extContentDesc, distributeMetadata[2])); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/wma/WmaContainerTest.java0000644000175000017500000000512011222471043030031 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.wma; import org.jaudiotagger.audio.asf.data.Chunk; import org.jaudiotagger.audio.asf.data.MetadataContainer; import org.jaudiotagger.audio.asf.data.MetadataContainerUtils; import org.jaudiotagger.audio.asf.io.MetadataReader; import org.jaudiotagger.audio.asf.util.Utils; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.audio.asf.data.GUID; import org.jaudiotagger.audio.asf.io.AsfHeaderUtils; import java.io.*; import java.util.Arrays; /** * @author Christian Laireiter * */ public class WmaContainerTest extends WmaTestCase { public final static String TEST_FILE = "test6.wma"; public WmaContainerTest() { super(TEST_FILE); } public void testExtContentAfterWrite() throws Exception { File prepareTestFile = prepareTestFile(null); AudioFile read = AudioFileIO.read(prepareTestFile); read.commit(); // Normalize Text file byte[] ext = AsfHeaderUtils.getFirstChunk(read.getFile(), GUID.GUID_EXTENDED_CONTENT_DESCRIPTION); read.commit(); byte[] ext2 = AsfHeaderUtils.getFirstChunk(read.getFile(), GUID.GUID_EXTENDED_CONTENT_DESCRIPTION); assertTrue(Arrays.equals(ext, ext2)); // assertEquals(ext, ext2); } public void testReadWriteEquality() throws IOException { File prepareTestFile = prepareTestFile(null); byte[] tmp = AsfHeaderUtils.getFirstChunk(prepareTestFile, GUID.GUID_EXTENDED_CONTENT_DESCRIPTION); MetadataReader reader = new MetadataReader(); ByteArrayInputStream bis = new ByteArrayInputStream(tmp); GUID readGUID = Utils.readGUID(bis); assertEquals(GUID.GUID_EXTENDED_CONTENT_DESCRIPTION, readGUID); Chunk read1 = reader.read(GUID.GUID_EXTENDED_CONTENT_DESCRIPTION, bis, 0); System.out.println(read1); assertTrue(read1 instanceof MetadataContainer); assertEquals(tmp.length, ((MetadataContainer) read1) .getCurrentAsfChunkSize()); ByteArrayOutputStream bos = new ByteArrayOutputStream(); ((MetadataContainer) read1).writeInto(bos); assertEquals(tmp.length, bos.toByteArray().length); bis = new ByteArrayInputStream(bos.toByteArray()); readGUID = Utils.readGUID(bis); assertEquals(GUID.GUID_EXTENDED_CONTENT_DESCRIPTION, readGUID); Chunk read2 = reader.read(GUID.GUID_EXTENDED_CONTENT_DESCRIPTION, bis, 0); System.out.println(MetadataContainerUtils.equals( (MetadataContainer) read1, (MetadataContainer) read2)); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/wma/WmaContentDescriptionTest.java0000644000175000017500000000443211277264361031747 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.wma; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.audio.asf.data.AsfHeader; import org.jaudiotagger.audio.asf.data.ContentDescription; import org.jaudiotagger.audio.asf.io.AsfHeaderReader; import org.jaudiotagger.tag.asf.AsfFieldKey; import org.jaudiotagger.tag.asf.AsfTag; import org.jaudiotagger.audio.asf.util.TagConverter; /** * This testcase tests the handling of the content description chunk. * * @author Christian Laireiter */ public class WmaContentDescriptionTest extends WmaTestCase { /** * Testfile to use as source. */ public final static String TEST_FILE = "test1.wma"; //$NON-NLS-1$ /** * Creates an instance. */ public WmaContentDescriptionTest() { super(TEST_FILE); } /** * tests whether the content description chunk will disappear if not * necessary.
* @throws Exception On I/O Errors */ public void testContentDescriptionRemoval() throws Exception { AudioFile file = getAudioFile(); AsfTag tag = (AsfTag) file.getTag(); for (String curr : ContentDescription.ALLOWED) { tag.deleteField(AsfFieldKey.getAsfFieldKey(curr)); } file.commit(); AsfHeader header = AsfHeaderReader.readHeader(file.getFile()); assertNull(header.getContentDescription()); for (String currKey : ContentDescription.ALLOWED) { AsfFieldKey curr = AsfFieldKey.getAsfFieldKey(currKey); AudioFileIO.delete(file); header = AsfHeaderReader.readHeader(file.getFile()); assertNull(header.getContentDescription()); assertNull(header.getExtendedContentDescription()); file = AudioFileIO.read(file.getFile()); tag = (AsfTag) file.getTag(); tag.addField(tag.createField(curr, curr.getFieldName())); file.commit(); header = AsfHeaderReader.readHeader(file.getFile()); assertNotNull(header.getContentDescription()); assertNull("Key: " + curr.getFieldName(), header.getExtendedContentDescription()); assertEquals(curr.getFieldName(), TagConverter.createTagOf(header).getFirst(curr.getFieldName())); } } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/reference/0000755000175000017500000000000011556363201025121 5ustar drazzibdrazziblibjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/reference/ISOCountryTest.java0000644000175000017500000000207111041064726030641 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.reference; import org.jaudiotagger.AbstractTestCase; /** * Testing of ISCountries */ public class ISOCountryTest extends AbstractTestCase { /** * This tests lower case genre names identifications */ public void testCountryMatches() { //Find by Code assertEquals(ISOCountry.Country.UNITED_KINGDOM, ISOCountry.getCountryByCode("GB")); //Find by Description - case senstive assertEquals(ISOCountry.Country.UNITED_KINGDOM, ISOCountry.getCountryByDescription("United Kingdom")); assertNull(ISOCountry.getCountryByDescription("united kingdom")); //Doesnt exist assertNull(ISOCountry.getCountryByCode("GBE")); assertNull(ISOCountry.getCountryByDescription("england")); //All values can be found for (ISOCountry.Country country : ISOCountry.Country.values()) { assertNotNull(ISOCountry.getCountryByCode(country.getCode())); assertNotNull(ISOCountry.getCountryByDescription(country.getDescription())); } } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/tag/reference/GenreTest.java0000644000175000017500000000214611041064726027666 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.reference; import org.jaudiotagger.AbstractTestCase; /** * Testing of Genres */ public class GenreTest extends AbstractTestCase { /** * This tests lower case genre names identifications */ public void testLowercaseGenrematch() { //Case sensitive assertNull(GenreTypes.getInstanceOf().getIdForValue("rock")); assertEquals(17, (int) GenreTypes.getInstanceOf().getIdForValue("Rock")); //Case insensitive assertEquals(17, (int) GenreTypes.getInstanceOf().getIdForName("Rock")); assertEquals(17, (int) GenreTypes.getInstanceOf().getIdForName("rock")); //Doesnt exist assertNull(GenreTypes.getInstanceOf().getIdForValue("rocky")); assertNull(GenreTypes.getInstanceOf().getIdForName("rocky")); //All values can be found for (String value : GenreTypes.getInstanceOf().getAlphabeticalValueList()) { assertNotNull(GenreTypes.getInstanceOf().getIdForName(value)); assertNotNull(GenreTypes.getInstanceOf().getIdForName(value.toLowerCase())); } } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/issues/0000755000175000017500000000000011556363177023737 5ustar drazzibdrazziblibjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/issues/Issue283Test.java0000644000175000017500000000413111276777123026765 0ustar drazzibdrazzibpackage org.jaudiotagger.issues; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.tag.FieldKey; import java.io.File; /** * Audio Books */ public class Issue283Test extends AbstractTestCase { public void testRead() { File orig = new File("testdata", "test56.m4b"); if (!orig.isFile()) { System.err.println("Unable to test file - not available"); return; } File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("test56.m4b"); AudioFile af = AudioFileIO.read(testFile); System.out.println(af.getTag().toString()); assertEquals("Aesop",af.getTag().getFirst(FieldKey.ARTIST)); assertEquals("Aesop's Fables (Unabridged)",af.getTag().getFirst(FieldKey.TITLE)); assertEquals("Aesop's Fables (Unabridged)",af.getTag().getFirst(FieldKey.ALBUM)); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } public void testWrite() { File orig = new File("testdata", "test56.m4b"); if (!orig.isFile()) { System.err.println("Unable to test file - not available"); return; } File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("test56.m4b"); AudioFile af = AudioFileIO.read(testFile); af.getTag().setField(FieldKey.ARTIST,"Aesops"); af.commit(); af = AudioFileIO.read(testFile); assertEquals("Aesops",af.getTag().getFirst(FieldKey.ARTIST)); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/issues/Issue249Test.java0000644000175000017500000000421411470746136026765 0ustar drazzibdrazzibpackage org.jaudiotagger.issues; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.audio.mp3.MP3File; import org.jaudiotagger.tag.id3.*; import org.jaudiotagger.tag.id3.framebody.FrameBodyIPLS; import org.jaudiotagger.tag.id3.framebody.FrameBodyTIPL; import java.io.File; /** * Test Writing to new urls with common interface */ public class Issue249Test extends AbstractTestCase { /** * Test New Urls ID3v24 */ public void testConvertv22tagWithIPLSToV24() { ID3v24Tag v24tag=null; ID3v22Tag v22tag=null; File orig = new File("testdata", "test34.mp3"); if (!orig.isFile()) { return; } Exception exceptionCaught = null; try { //This is a V2 File with an IPL frame File testFile = AbstractTestCase.copyAudioToTmp("test34.mp3"); //Convert to v24Tag AudioFile af = AudioFileIO.read(testFile); MP3File mp3File= (MP3File)af; v24tag = mp3File.getID3v2TagAsv24(); v22tag = (ID3v22Tag)mp3File.getID3v2Tag(); } catch(Exception e) { e.printStackTrace(); exceptionCaught=e; } assertNull(exceptionCaught); ID3v24Frame frame = (ID3v24Frame) v24tag.getFrame(ID3v24Frames.FRAME_ID_INVOLVED_PEOPLE); ID3v22Frame framev2 = (ID3v22Frame) v22tag.getFrame(ID3v22Frames.FRAME_ID_V2_IPLS); assertNotNull(frame); assertNotNull(framev2); //Original FrameBodyIPLS framebodyv2 = (FrameBodyIPLS)framev2.getBody(); assertEquals(1,framebodyv2.getNumberOfPairs()); assertEquals("",framebodyv2.getKeyAtIndex(0)); assertEquals("PRAISE J.R. \"BOB\" DOBBS!!!",framebodyv2.getValueAtIndex(0)); //Converted to v24 FrameBodyTIPL framebody = (FrameBodyTIPL)frame.getBody(); assertEquals(1,framebody.getNumberOfPairs()); assertEquals("",framebody.getKeyAtIndex(0)); assertEquals("PRAISE J.R. \"BOB\" DOBBS!!!",framebody.getValueAtIndex(0)); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/issues/Issue324Test.java0000644000175000017500000000224211470746136026756 0ustar drazzibdrazzibpackage org.jaudiotagger.issues; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.audio.mp3.MP3File; import org.jaudiotagger.tag.FieldDataInvalidException; import org.jaudiotagger.tag.FieldKey; import org.jaudiotagger.tag.Tag; import org.jaudiotagger.tag.id3.ID3v11Tag; import org.jaudiotagger.tag.id3.ID3v1Tag; import java.io.File; /** * Test deletions of ID3v1 tag */ public class Issue324Test extends AbstractTestCase { public void testID3v1TagHandling() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("test32.mp3"); assertEquals(1853744,testFile.length()); MP3File f = (MP3File)AudioFileIO.read(testFile); assertEquals("Iron Maiden",f.getID3v1Tag().getFirst(FieldKey.ARTIST)); f.setID3v1Tag(new ID3v11Tag()); f.getID3v1Tag().setField(FieldKey.ARTIST,"Iron Mask"); f.commit(); assertEquals(1853744,testFile.length()); f = (MP3File)AudioFileIO.read(testFile); assertEquals("Iron Mask",f.getID3v1Tag().getFirst(FieldKey.ARTIST)); } }libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/issues/Issue248Test.java0000644000175000017500000000255111277311523026757 0ustar drazzibdrazzibpackage org.jaudiotagger.issues; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.mp3.MP3File; import java.io.File; public class Issue248Test extends AbstractTestCase { public static int countExceptions =0; public void testMultiThreadedMP3HeaderAccess() throws Exception { final File testFile = AbstractTestCase.copyAudioToTmp("testV1vbrOld0.mp3"); final MP3File mp3File = new MP3File(testFile); final Thread[] threads = new Thread[1000]; for(int i = 0; i < 1000; i++) { threads[i] = new Thread(new Runnable() { public void run() { try { //System.out.println("Output is"+mp3File.getMP3AudioHeader().getTrackLengthAsString()); } catch (RuntimeException e) { e.printStackTrace(); countExceptions++; } catch (Exception e) { e.printStackTrace(); countExceptions++; } } }); } for(int i = 0; i < 1000; i++) { threads[i].start(); } assertEquals(0, countExceptions); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/issues/Issue285Test.java0000644000175000017500000000247211276777123026775 0ustar drazzibdrazzibpackage org.jaudiotagger.issues; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.tag.FieldKey; import java.io.File; /** * Converting FrameBodyUnsupported with known identifier to FrameBodyIPLS (v23) causing NoSuchMethodException. * Not really sure why this is happening but we should check and take action instead of failing as we currently do */ public class Issue285Test extends AbstractTestCase { public void testSavingOggFile() { File orig = new File("testdata", "test57.ogg"); if (!orig.isFile()) { System.err.println("Unable to test file - not available"); return; } File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("test57.ogg"); //OggFileReader ofr = new OggFileReader(); //ofr.summarizeOggPageHeaders(testFile); AudioFile af = AudioFileIO.read(testFile); af.getTag().setField(FieldKey.COMMENT,"TEST"); af.commit(); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/issues/Issue260Test.java0000644000175000017500000001173411276777123026767 0ustar drazzibdrazzibpackage org.jaudiotagger.issues; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.tag.FieldKey; import java.io.File; /** * Test read m4a without udta/meta atom */ public class Issue260Test extends AbstractTestCase { /** * Test read mp4 ok without any udta/meta atoms */ public void testReadMp4WithoutUdta() { File orig = new File("testdata", "test40.m4a"); if (!orig.isFile()) { System.err.println("Unable to test file - not available"); return; } File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("test40.m4a"); //Read File okay AudioFile af = AudioFileIO.read(testFile); assertTrue(af.getTag().isEmpty()); } catch(Exception e) { e.printStackTrace(); exceptionCaught=e; } assertNull(exceptionCaught); } /** * Test write mp4 ok without any udta/meta atoms */ public void testWriteMp4WithoutUdta() { File orig = new File("testdata", "test40.m4a"); if (!orig.isFile()) { System.err.println("Unable to test file - not available"); return; } File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("test40.m4a"); //Read File okay AudioFile af = AudioFileIO.read(testFile); assertTrue(af.getTag().isEmpty()); //Write file af.getTag().setField(FieldKey.ARTIST,"artist"); af.getTag().setField(FieldKey.ALBUM,"album"); af.getTag().setField(FieldKey.TITLE,"title"); af.getTag().setField(FieldKey.GENRE,"genre"); af.getTag().setField(FieldKey.YEAR,"year"); af.commit(); //Read file again okay af = AudioFileIO.read(testFile); assertEquals("artist",af.getTag().getFirst(FieldKey.ARTIST)); assertEquals("album",af.getTag().getFirst(FieldKey.ALBUM)); assertEquals("title",af.getTag().getFirst(FieldKey.TITLE)); assertEquals("genre",af.getTag().getFirst(FieldKey.GENRE)); assertEquals("year",af.getTag().getFirst(FieldKey.YEAR)); } catch(Exception e) { e.printStackTrace(); exceptionCaught=e; } assertNull(exceptionCaught); } /** * Test read mp4 ok with udta at start of moov (created by picardqt) */ public void testReadMp4WithUdtaAtStart() { File orig = new File("testdata", "test43.m4a"); if (!orig.isFile()) { System.err.println("Unable to test file - not available"); return; } File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("test43.m4a"); //Read File okay AudioFile af = AudioFileIO.read(testFile); assertEquals("test43",af.getTag().getFirst(FieldKey.TITLE)); } catch(Exception e) { e.printStackTrace(); exceptionCaught=e; } assertNull(exceptionCaught); } /** * Test write mp4 ok udta at start of moov (created by picardqt) */ public void testWriteMp4WithUdtaAtStart() { File orig = new File("testdata", "test43.m4a"); if (!orig.isFile()) { System.err.println("Unable to test file - not available"); return; } File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("test43.m4a"); //Read File okay AudioFile af = AudioFileIO.read(testFile); assertEquals("test43",af.getTag().getFirst(FieldKey.TITLE)); //Write file af.getTag().setField(FieldKey.ARTIST,"artist"); af.getTag().setField(FieldKey.ALBUM,"album"); af.getTag().setField(FieldKey.TITLE,"title"); af.getTag().setField(FieldKey.GENRE,"genre"); af.getTag().setField(FieldKey.YEAR,"year"); af.commit(); //Read file again okay af = AudioFileIO.read(testFile); assertEquals("artist",af.getTag().getFirst(FieldKey.ARTIST)); assertEquals("album",af.getTag().getFirst(FieldKey.ALBUM)); assertEquals("title",af.getTag().getFirst(FieldKey.TITLE)); assertEquals("genre",af.getTag().getFirst(FieldKey.GENRE)); assertEquals("year",af.getTag().getFirst(FieldKey.YEAR)); } catch(Exception e) { e.printStackTrace(); exceptionCaught=e; } assertNull(exceptionCaught); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/issues/Issue289Test.java0000644000175000017500000000275111276777123027001 0ustar drazzibdrazzibpackage org.jaudiotagger.issues; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.audio.ogg.OggFileReader; import org.jaudiotagger.tag.FieldKey; import java.io.File; /** *File corrupt after write */ public class Issue289Test extends AbstractTestCase { public void testSavingOggFile() { File orig = new File("testdata", "test58.ogg"); if (!orig.isFile()) { System.err.println("Unable to test file - not available"); return; } File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("test58.ogg"); OggFileReader ofr = new OggFileReader(); //ofr.shortSummarizeOggPageHeaders(testFile); AudioFile af = AudioFileIO.read(testFile); System.out.println(af.getTag().toString()); af.getTag().setField(af.getTag().createField(FieldKey.MUSICIP_ID,"91421a81-50b9-f577-70cf-20356eea212e")); af.commit(); af = AudioFileIO.read(testFile); assertEquals("91421a81-50b9-f577-70cf-20356eea212e",af.getTag().getFirst(FieldKey.MUSICIP_ID)); ofr.shortSummarizeOggPageHeaders(testFile); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/issues/Issue294Test.java0000644000175000017500000001040211302731457026753 0ustar drazzibdrazzibpackage org.jaudiotagger.issues; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.audio.mp3.MP3File; import org.jaudiotagger.audio.mp3.MPEGFrameHeader; import org.jaudiotagger.logging.Hex; import org.jaudiotagger.tag.TagOptionSingleton; import org.jaudiotagger.tag.datatype.Artwork; import org.jaudiotagger.tag.id3.valuepair.ImageFormats; import java.io.File; import java.util.ArrayList; import java.util.Arrays; import java.util.List; /** * Jpg added to this mp3 fails on read back */ public class Issue294Test extends AbstractTestCase { public void testSavingArtworkToMp3File() { File orig = new File("testdata", "test70.mp3"); if (!orig.isFile()) { System.err.println("Unable to test file - not available"); return; } File testFile = AbstractTestCase.copyAudioToTmp("test70.mp3"); File testPix = AbstractTestCase.copyAudioToTmp("test70.jpg"); File originalFileBackup = null; Exception exceptionCaught = null; try { TagOptionSingleton.getInstance().setUnsyncTags(false); //Read and save changes MP3File af = (MP3File)AudioFileIO.read(testFile); //File is corrupt assertEquals(1,af.getTag().getArtworkList().size()); Artwork artwork = af.getTag().getFirstArtwork(); assertEquals("image/jpeg",artwork.getMimeType()); assertTrue(ImageFormats.isPortableFormat(artwork.getBinaryData())); //Delete and commit //af.getTag().deleteArtworkField(); //af.commit(); //af.getID3v2TagAsv24().removeFrame("APIC"); final List multiFrames = new ArrayList(); multiFrames.add(af.getID3v2Tag().createField(Artwork.createArtworkFromFile(testPix))); af.getID3v2Tag().setFrame("APIC", multiFrames); af.commit(); //Can we read this image file artwork = Artwork.createArtworkFromFile(testPix); assertEquals(118145,artwork.getBinaryData().length); assertEquals(0xFF,(int)artwork.getBinaryData()[0] & MPEGFrameHeader.SYNC_BYTE1); assertEquals(0xD8,(int)artwork.getBinaryData()[1] & MPEGFrameHeader.SYNC_BYTE1); assertEquals(0xFF,(int)artwork.getBinaryData()[2] & MPEGFrameHeader.SYNC_BYTE1); assertEquals(0xE0,(int)artwork.getBinaryData()[3] & MPEGFrameHeader.SYNC_BYTE1); assertEquals("image/jpeg",artwork.getMimeType()); assertNotNull(artwork.getImage()); assertEquals(500,artwork.getImage().getHeight()); assertEquals(500,artwork.getImage().getWidth()); byte[]origData=artwork.getBinaryData(); af = (MP3File)AudioFileIO.read(testFile); assertEquals(1,af.getTag().getArtworkList().size()); artwork = af.getTag().getArtworkList().get(0); assertEquals(118145,artwork.getBinaryData().length); assertEquals(0xFF,(int)artwork.getBinaryData()[0] & MPEGFrameHeader.SYNC_BYTE1); assertEquals(0xD8,(int)artwork.getBinaryData()[1] & MPEGFrameHeader.SYNC_BYTE1); assertEquals(0xFF,(int)artwork.getBinaryData()[2] & MPEGFrameHeader.SYNC_BYTE1); assertEquals(0xE0,(int)artwork.getBinaryData()[3] & MPEGFrameHeader.SYNC_BYTE1); assertEquals("image/jpeg",artwork.getMimeType()); for(int i=0;i * TODO currently we cant decrypt it, that will come later */ public void testReadMp3WithEncryptedField() { File orig = new File("testdata", "test48.mp3"); if (!orig.isFile()) { System.err.println("Unable to test file - not available"); return; } File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("test48.mp3"); //Read File okay AudioFile af = AudioFileIO.read(testFile); System.out.println(af.getTag().toString()); assertEquals("Don't Leave Me", af.getTag().getFirst(FieldKey.TITLE)); assertEquals("All-American Rejects", af.getTag().getFirst(FieldKey.ARTIST)); ID3v23Tag id3v23Tag = (ID3v23Tag) af.getTag(); assertEquals(0, id3v23Tag.getPaddingSize()); AbstractID3v2Frame frame = (AbstractID3v2Frame) id3v23Tag.getFrame(ID3v23Frames.FRAME_ID_V3_ENCODEDBY); af.getTag().setField(FieldKey.ALBUM,"FRED"); af.commit(); af = AudioFileIO.read(testFile); System.out.println(af.getTag().toString()); assertEquals("FRED", af.getTag().getFirst(FieldKey.ALBUM)); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * Test read flags */ public void testReadFlagsCompressed() { File orig = new File("testdata", "test51.mp3"); if (!orig.isFile()) { System.err.println("Unable to test file - not available"); return; } File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("test51.mp3"); //Read File okay AudioFile af = AudioFileIO.read(testFile); MP3File mp3File = (MP3File) af; System.out.println(mp3File.displayStructureAsXML()); ID3v22Tag v22tag = (ID3v22Tag) af.getTag(); assertTrue(v22tag.isCompression()); assertFalse(v22tag.isUnsynchronization()); //Now write to tag we dont preservbe compressed flag because cant actualy define compression v22tag.setField(FieldKey.TITLE,"A new start"); assertEquals("A new start", v22tag.getFirst(FieldKey.TITLE)); af.commit(); af = AudioFileIO.read(testFile); v22tag = (ID3v22Tag) af.getTag(); assertFalse(v22tag.isCompression()); assertFalse(v22tag.isUnsynchronization()); TagOptionSingleton.getInstance().setUnsyncTags(true); v22tag.setField(FieldKey.TITLE,"B new start"); af.commit(); af = AudioFileIO.read(testFile); v22tag = (ID3v22Tag) af.getTag(); assertFalse(v22tag.isCompression()); assertTrue(v22tag.isUnsynchronization()); assertEquals("B new start", v22tag.getFirst(FieldKey.TITLE)); TagOptionSingleton.getInstance().setUnsyncTags(false); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * Test read flags */ public void testReadFlagsUnsyced() { File orig = new File("testdata", "test52.mp3"); if (!orig.isFile()) { System.err.println("Unable to test file - not available"); return; } File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("test52.mp3"); //Read File okay AudioFile af = AudioFileIO.read(testFile); MP3File mp3File = (MP3File) af; System.out.println(mp3File.displayStructureAsXML()); ID3v22Tag v22tag = (ID3v22Tag) af.getTag(); assertFalse(v22tag.isCompression()); assertTrue(v22tag.isUnsynchronization()); //Now write to tag we dont preservbe compressed flag because cant actualy define compression //We dont preserve compression because based on TagOptionDinglton which is false by default v22tag.setField(FieldKey.TITLE,"A new start"); af.commit(); af = AudioFileIO.read(testFile); v22tag = (ID3v22Tag) af.getTag(); assertFalse(v22tag.isCompression()); assertFalse(v22tag.isUnsynchronization()); assertEquals("A new start", v22tag.getFirst(FieldKey.TITLE)); TagOptionSingleton.getInstance().setUnsyncTags(true); v22tag.setField(FieldKey.TITLE,"B new start"); af.commit(); af = AudioFileIO.read(testFile); v22tag = (ID3v22Tag) af.getTag(); assertFalse(v22tag.isCompression()); assertTrue(v22tag.isUnsynchronization()); assertEquals("B new start", v22tag.getFirst(FieldKey.TITLE)); TagOptionSingleton.getInstance().setUnsyncTags(false); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * Test read flags */ public void testReadFlagsUnsycedCompressed() { File orig = new File("testdata", "test53.mp3"); if (!orig.isFile()) { System.err.println("Unable to test file - not available"); return; } File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("test53.mp3"); //Read File okay AudioFile af = AudioFileIO.read(testFile); MP3File mp3File = (MP3File) af; System.out.println(mp3File.displayStructureAsXML()); ID3v22Tag v22tag = (ID3v22Tag) af.getTag(); assertTrue(v22tag.isCompression()); assertTrue(v22tag.isUnsynchronization()); //Now write to tag we dont preserve compressed flag because cant actually define compression //We dont preserve compression because based on TagOptionDinglton which is false by default v22tag.setField(FieldKey.TITLE,"A new start"); af.commit(); af = AudioFileIO.read(testFile); v22tag = (ID3v22Tag) af.getTag(); assertFalse(v22tag.isCompression()); assertFalse(v22tag.isUnsynchronization()); assertEquals("A new start", v22tag.getFirst(FieldKey.TITLE)); TagOptionSingleton.getInstance().setUnsyncTags(true); v22tag.setField(FieldKey.TITLE,"B new start"); af.commit(); af = AudioFileIO.read(testFile); v22tag = (ID3v22Tag) af.getTag(); assertFalse(v22tag.isCompression()); assertTrue(v22tag.isUnsynchronization()); assertEquals("B new start", v22tag.getFirst(FieldKey.TITLE)); TagOptionSingleton.getInstance().setUnsyncTags(false); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/issues/Issue178Test.java0000644000175000017500000000267511111242072026755 0ustar drazzibdrazzibpackage org.jaudiotagger.issues; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.audio.exceptions.CannotReadException; import org.jaudiotagger.audio.mp4.Mp4AtomTree; import java.io.File; import java.io.RandomAccessFile; import java.util.Date; /** * Test Fail bad Ogg Quicker */ public class Issue178Test extends AbstractTestCase { /** * Test Read empty file pretenidng to be an Ogg, should fail quickly */ public void testReadBadOgg() { File orig = new File("testdata", "test36.ogg"); if (!orig.isFile()) { System.err.println("Unable to test file - not available"); return; } File testFile = null; Exception exceptionCaught = null; Date startDate = new Date(); System.out.println("start:"+startDate); try { testFile = AbstractTestCase.copyAudioToTmp("test36.ogg"); //Read File AudioFile af = AudioFileIO.read(testFile); //Print Out Tree } catch(Exception e) { e.printStackTrace(); exceptionCaught=e; } Date endDate = new Date(); System.out.println("end :"+endDate); assertTrue(exceptionCaught instanceof CannotReadException); assertTrue(endDate.getTime() - startDate.getTime() < 1000); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/issues/Issue270Test.java0000644000175000017500000000224711276777123026767 0ustar drazzibdrazzibpackage org.jaudiotagger.issues; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.audio.exceptions.CannotReadException; import java.io.File; /** * Test read large mp3 with extended header */ public class Issue270Test extends AbstractTestCase { /** * Test read mp3 that says it has extended header but doesnt really */ public void testReadMp4WithCorruptMdata() { File orig = new File("testdata", "test49.m4a"); if (!orig.isFile()) { System.err.println("Unable to test file - not available"); return; } File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("test49.m4a"); //Read FileFails AudioFile af = AudioFileIO.read(testFile); System.out.println(af.getTag().toString()); } catch(Exception e) { e.printStackTrace(); exceptionCaught=e; } assertTrue(exceptionCaught instanceof CannotReadException); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/issues/Issue265Test.java0000644000175000017500000001214111276777123026765 0ustar drazzibdrazzibpackage org.jaudiotagger.issues; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.tag.FieldKey; import org.jaudiotagger.tag.Tag; import org.jaudiotagger.tag.TagOptionSingleton; import java.io.File; /** * Truncation haling for string data and picture data */ public class Issue265Test extends AbstractTestCase { /** * Try an d write too large a file */ public void testWriteTooLargeStringToFile() { File orig = new File("testdata", "test7.wma"); if (!orig.isFile()) { System.err.println("Unable to test file - not available"); return; } Exception exceptionCaught = null; try { TagOptionSingleton.getInstance().setTruncateTextWithoutErrors(false); File testFile = AbstractTestCase.copyAudioToTmp("test7.wma"); AudioFile f = AudioFileIO.read(testFile); Tag tag = f.getTag(); assertEquals(0, tag.getFields(FieldKey.COVER_ART).size()); //Now createField artwork field StringBuffer sb = new StringBuffer(); for (int i = 0; i < 34000;i++) { sb.append("x"); } tag.setField(FieldKey.ARTIST,sb.toString()); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNotNull(exceptionCaught); assertTrue(exceptionCaught instanceof IllegalArgumentException); } /** * Try and write too large a file, automtically truncated if option set */ public void testWriteTruncateStringToFile() { File orig = new File("testdata", "test7.wma"); if (!orig.isFile()) { System.err.println("Unable to test file - not available"); return; } Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test7.wma"); AudioFile f = AudioFileIO.read(testFile); Tag tag = f.getTag(); assertEquals(0, tag.getFields(FieldKey.COVER_ART).size()); //Enable value TagOptionSingleton.getInstance().setTruncateTextWithoutErrors(true); //Now createField artwork field StringBuffer sb = new StringBuffer(); for (int i = 0; i < 34000;i++) { sb.append("x"); } tag.setField(FieldKey.ARTIST,sb.toString()); f.commit(); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * Try an d write too large a file */ public void testWriteTooLargeStringToFileContentDesc() { File orig = new File("testdata", "test7.wma"); if (!orig.isFile()) { System.err.println("Unable to test file - not available"); return; } Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test7.wma"); AudioFile f = AudioFileIO.read(testFile); Tag tag = f.getTag(); TagOptionSingleton.getInstance().setTruncateTextWithoutErrors(false); StringBuffer sb = new StringBuffer(); for (int i = 0; i < 34000;i++) { sb.append("x"); } tag.setField(FieldKey.TITLE,sb.toString()); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNotNull(exceptionCaught); assertTrue(exceptionCaught instanceof IllegalArgumentException); } /** * Try and write too large a file, automtically truncated if option set */ public void testWriteTruncateStringToFileContentDesc() { File orig = new File("testdata", "test7.wma"); if (!orig.isFile()) { System.err.println("Unable to test file - not available"); return; } Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test7.wma"); AudioFile f = AudioFileIO.read(testFile); Tag tag = f.getTag(); //Enable value TagOptionSingleton.getInstance().setTruncateTextWithoutErrors(true); //Now createField artwork field StringBuffer sb = new StringBuffer(); for (int i = 0; i < 34000;i++) { sb.append("x"); } tag.setField(FieldKey.TITLE,sb.toString()); f.commit(); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/issues/Issue232Test.java0000644000175000017500000000145511041655600026746 0ustar drazzibdrazzibpackage org.jaudiotagger.issues; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.tag.Tag; import org.jaudiotagger.tag.id3.ID3v23Tag; import org.jaudiotagger.tag.id3.framebody.FrameBodyTDRC; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.AudioFileIO; import java.io.File; /** * Test Creating Null fields */ public class Issue232Test extends AbstractTestCase { //TODO this is meant to be test but cant find a string that causes a failure public void testDodgyTDRCFrame() { Exception exceptionCaught = null; try { FrameBodyTDRC framebody = new FrameBodyTDRC((byte)0,"195666..4.1"); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/issues/Issue279Test.java0000644000175000017500000000251011276777123026771 0ustar drazzibdrazzibpackage org.jaudiotagger.issues; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.tag.FieldKey; import java.io.File; /** * ID3 Tag Specific flags */ public class Issue279Test extends AbstractTestCase { /** * Test write to ogg, cant find parent setup header */ public void testWriteToOgg() { File orig = new File("testdata", "test55.ogg"); if (!orig.isFile()) { System.err.println("Unable to test file - not available"); return; } File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("test55.ogg"); //Read File okay AudioFile af = AudioFileIO.read(testFile); System.out.println(af.getTag().toString()); af.getTag().setField(FieldKey.ALBUM,"FRED"); af.commit(); af = AudioFileIO.read(testFile); System.out.println(af.getTag().toString()); assertEquals("FRED", af.getTag().getFirst(FieldKey.ALBUM)); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/issues/Issue100Test.java0000644000175000017500000001240611276777123026755 0ustar drazzibdrazzibpackage org.jaudiotagger.issues; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.audio.mp3.MP3File; import org.jaudiotagger.tag.datatype.DataTypes; import org.jaudiotagger.tag.id3.*; import java.io.File; import java.util.Iterator; import java.util.Set; /** * Test Writing to mp3 always writes the fields in a sensible order to minimize problems with iTunes and other * players. */ public class Issue100Test extends AbstractTestCase { public void testID3v24WriteFieldsInPreferredOrder() { Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); //Create tag ID3v24Tag tag = new ID3v24Tag(); { ID3v24Frame frame = new ID3v24Frame(ID3v24Frames.FRAME_ID_PRIVATE); tag.setFrame(frame); } { ID3v24Frame frame = new ID3v24Frame(ID3v24Frames.FRAME_ID_UNIQUE_FILE_ID); tag.setFrame(frame); } AudioFile af = AudioFileIO.read(testFile); MP3File mp3File = (MP3File)af; mp3File.setID3v2Tag(tag); //PRIV is listed first because added first Set keys = mp3File.getID3v2Tag().frameMap.keySet(); Iterator iter = keys.iterator(); assertEquals("PRIV",iter.next()); assertEquals("UFID",iter.next()); mp3File.save(); af = AudioFileIO.read(testFile); mp3File = (MP3File)af; assertEquals(2,mp3File.getID3v2Tag().getFieldCount()); //After save UFID first because in order of written and UFID should be first keys = mp3File.getID3v2Tag().frameMap.keySet(); iter = keys.iterator(); assertEquals("UFID",iter.next()); assertEquals("PRIV",iter.next()); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); } public void testID3v23WriteFieldsInPreferredOrder() { Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); //Create tag ID3v23Tag tag = new ID3v23Tag(); { ID3v23Frame frame = new ID3v23Frame(ID3v23Frames.FRAME_ID_V3_PRIVATE); tag.setFrame(frame); } { ID3v23Frame frame = new ID3v23Frame(ID3v23Frames.FRAME_ID_V3_UNIQUE_FILE_ID); tag.setFrame(frame); } AudioFile af = AudioFileIO.read(testFile); MP3File mp3File = (MP3File)af; mp3File.setID3v2Tag(tag); //PRIV is listed first because added first Set keys = mp3File.getID3v2Tag().frameMap.keySet(); Iterator iter = keys.iterator(); assertEquals("PRIV",iter.next()); assertEquals("UFID",iter.next()); mp3File.save(); af = AudioFileIO.read(testFile); mp3File = (MP3File)af; assertEquals(2,mp3File.getID3v2Tag().getFieldCount()); //After save UFID first because in order of written and UFID should be first keys = mp3File.getID3v2Tag().frameMap.keySet(); iter = keys.iterator(); assertEquals("UFID",iter.next()); assertEquals("PRIV",iter.next()); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); } public void testID3v22WriteFieldsInPreferredOrder() { Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); //Create tag ID3v22Tag tag = new ID3v22Tag(); { ID3v22Frame frame = new ID3v22Frame(ID3v22Frames.FRAME_ID_V2_ATTACHED_PICTURE); frame.getBody().setObjectValue(DataTypes.OBJ_DESCRIPTION,""); tag.setFrame(frame); } { ID3v22Frame frame = new ID3v22Frame(ID3v22Frames.FRAME_ID_V2_UNIQUE_FILE_ID); tag.setFrame(frame); } AudioFile af = AudioFileIO.read(testFile); MP3File mp3File = (MP3File)af; mp3File.setID3v2Tag(tag); //PRIV is listed first because added first Set keys = mp3File.getID3v2Tag().frameMap.keySet(); Iterator iter = keys.iterator(); assertEquals("PIC",iter.next()); assertEquals("UFI",iter.next()); mp3File.save(); af = AudioFileIO.read(testFile); mp3File = (MP3File)af; assertEquals(2,mp3File.getID3v2Tag().getFieldCount()); //After save UFID first because in order of written and UFID should be first keys = mp3File.getID3v2Tag().frameMap.keySet(); iter = keys.iterator(); assertEquals("UFI",iter.next()); assertEquals("PIC",iter.next()); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/issues/Issue322Test.java0000644000175000017500000000235511470746136026761 0ustar drazzibdrazzibpackage org.jaudiotagger.issues; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.audio.mp3.MP3File; import org.jaudiotagger.tag.FieldDataInvalidException; import org.jaudiotagger.tag.FieldKey; import org.jaudiotagger.tag.Tag; import java.io.File; /** * Test tag Equality (specifically PartOfSet) */ public class Issue322Test extends AbstractTestCase { /* * Test exception thrown * @throws Exception */ public void testNumberFieldHandling() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("test.m4a"); AudioFile f = AudioFileIO.read(testFile); Tag tag = f.getTag(); Exception expected=null; try { tag.createField(FieldKey.TRACK_TOTAL, ""); } catch (Exception e) { expected = e; } assertNotNull(expected); assertTrue(expected instanceof FieldDataInvalidException); expected=null; try { tag.createField(FieldKey.TRACK_TOTAL, "1"); } catch (Exception e) { expected = e; } assertNull(expected); } }libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/issues/Issue309Test.java0000644000175000017500000000171611276777123026772 0ustar drazzibdrazzibpackage org.jaudiotagger.issues; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.AudioFileIO; import java.io.File; /** * Reading mp4 with corrupt length recorded in tag ending up in middle of free atom should fail */ public class Issue309Test extends AbstractTestCase { public static int countExceptions =0; public void testAddingLargeImageToOgg() throws Exception { File orig = new File("testdata", "test73.m4a"); if (!orig.isFile()) { System.err.println("Unable to test file - not available"); return; } Exception e=null; try { final File testFile = AbstractTestCase.copyAudioToTmp("test73.m4a"); AudioFile af = AudioFileIO.read(testFile); } catch(Exception ex) { e=ex; ex.printStackTrace(); } assertNotNull(e); } }libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/issues/Issue222Test.java0000644000175000017500000000206711115261153026743 0ustar drazzibdrazzibpackage org.jaudiotagger.issues; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.AudioFileIO; import java.io.File; /** * Test read m4a without udta/meta atom */ public class Issue222Test extends AbstractTestCase { /** * Test read mp4 with meta but not udata atom */ public void testreadMp4WithoutUUuidButNoUdta() { File orig = new File("testdata", "test4.m4a"); if (!orig.isFile()) { System.err.println("Unable to test file - not available"); return; } File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("test4.m4a"); //Read File okay AudioFile af = AudioFileIO.read(testFile); assertTrue(af.getTag().isEmpty()); //But empty } catch(Exception e) { e.printStackTrace(); exceptionCaught=e; } assertNull(exceptionCaught); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/issues/Issue284Test.java0000644000175000017500000001270511145351203026752 0ustar drazzibdrazzibpackage org.jaudiotagger.issues; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.tag.id3.*; import org.jaudiotagger.tag.id3.framebody.FrameBodyTIPL; import org.jaudiotagger.tag.id3.framebody.FrameBodyUnsupported; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.audio.mp3.MP3File; import java.io.File; /** * Converting FrameBodyUnsupported with known identifier to FrameBodyIPLS (v23) causing NoSuchMethodException. * Not really sure why this is happening but we should check and take action instead of failing as we currently do */ public class Issue284Test extends AbstractTestCase { public void testConvertv23v24() { File orig = new File("testdata", "testV1.mp3"); if (!orig.isFile()) { System.err.println("Unable to test file - not available"); return; } File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); MP3File af = (MP3File)AudioFileIO.read(testFile); ID3v24Frame frame = new ID3v24Frame(ID3v24Frames.FRAME_ID_INVOLVED_PEOPLE); FrameBodyUnsupported fb = new FrameBodyUnsupported(ID3v24Frames.FRAME_ID_INVOLVED_PEOPLE); frame.setBody(fb); assertTrue(frame.getBody() instanceof FrameBodyUnsupported); ID3v23Frame framev23 = new ID3v23Frame(frame); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } public void testConvertv22v24() { File orig = new File("testdata", "testV1.mp3"); if (!orig.isFile()) { System.err.println("Unable to test file - not available"); return; } File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); MP3File af = (MP3File)AudioFileIO.read(testFile); ID3v24Frame frame = new ID3v24Frame(ID3v24Frames.FRAME_ID_INVOLVED_PEOPLE); FrameBodyUnsupported fb = new FrameBodyUnsupported(ID3v24Frames.FRAME_ID_INVOLVED_PEOPLE); frame.setBody(fb); assertTrue(frame.getBody() instanceof FrameBodyUnsupported); ID3v22Frame framev22 = new ID3v22Frame(frame); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } public void testConvertv24v23() { File orig = new File("testdata", "testV1.mp3"); if (!orig.isFile()) { System.err.println("Unable to test file - not available"); return; } File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); MP3File af = (MP3File)AudioFileIO.read(testFile); ID3v23Frame frame = new ID3v23Frame(ID3v23Frames.FRAME_ID_V3_IPLS); FrameBodyUnsupported fb = new FrameBodyUnsupported(ID3v23Frames.FRAME_ID_V3_IPLS); frame.setBody(fb); assertTrue(frame.getBody() instanceof FrameBodyUnsupported); ID3v24Frame framev24 = new ID3v24Frame(frame); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } public void testConvertv24v22() { File orig = new File("testdata", "testV1.mp3"); if (!orig.isFile()) { System.err.println("Unable to test file - not available"); return; } File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); MP3File af = (MP3File)AudioFileIO.read(testFile); ID3v22Frame frame = new ID3v22Frame(ID3v22Frames.FRAME_ID_V2_TITLE); FrameBodyUnsupported fb = new FrameBodyUnsupported(ID3v22Frames.FRAME_ID_V2_TITLE); frame.setBody(fb); assertTrue(frame.getBody() instanceof FrameBodyUnsupported); ID3v24Frame framev24 = new ID3v24Frame(frame); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } public void testConvertv22v23() { File orig = new File("testdata", "testV1.mp3"); if (!orig.isFile()) { System.err.println("Unable to test file - not available"); return; } File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); MP3File af = (MP3File)AudioFileIO.read(testFile); ID3v23Frame frame = new ID3v23Frame(ID3v23Frames.FRAME_ID_V3_TITLE); FrameBodyUnsupported fb = new FrameBodyUnsupported(ID3v23Frames.FRAME_ID_V3_TITLE); frame.setBody(fb); assertTrue(frame.getBody() instanceof FrameBodyUnsupported); ID3v22Frame framev22 = new ID3v22Frame(frame); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/issues/Issue273Test.java0000644000175000017500000000526511276777123026775 0ustar drazzibdrazzibpackage org.jaudiotagger.issues; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.tag.FieldKey; import org.jaudiotagger.tag.id3.AbstractID3v2Frame; import org.jaudiotagger.tag.id3.ID3v23Tag; import org.jaudiotagger.tag.id3.framebody.FrameBodyCOMM; import java.io.File; /** COMM Frames with non-standard lang values */ public class Issue273Test extends AbstractTestCase { /** * Test Read/Write Comment with funny lang */ public void testCommentWithLanguage() { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); Exception exceptionCaught = null; try { //Read File okay AudioFile af = AudioFileIO.read(testFile); af.getTagOrCreateAndSetDefault(); af.commit(); af = AudioFileIO.read(testFile); ID3v23Tag tag = (ID3v23Tag)af.getTag(); tag.addField(FieldKey.COMMENT,"COMMENTVALUE"); af.commit(); af = AudioFileIO.read(testFile); tag = (ID3v23Tag)af.getTag(); assertEquals("COMMENTVALUE",tag.getFirst(FieldKey.COMMENT)); AbstractID3v2Frame frame = tag.getFirstField("COMM"); FrameBodyCOMM fb = (FrameBodyCOMM)frame.getBody(); assertEquals("eng",fb.getLanguage()); af.commit(); fb.setLanguage("XXX"); assertEquals("XXX",fb.getLanguage()); af.commit(); af = AudioFileIO.read(testFile); tag = (ID3v23Tag)af.getTag(); assertEquals("COMMENTVALUE",tag.getFirst(FieldKey.COMMENT)); frame = tag.getFirstField("COMM"); fb = (FrameBodyCOMM)frame.getBody(); assertEquals("XXX",fb.getLanguage()); af.commit(); fb.setLanguage("\0\0\0"); af.commit(); af = AudioFileIO.read(testFile); tag = (ID3v23Tag)af.getTag(); assertEquals("COMMENTVALUE",tag.getFirst(FieldKey.COMMENT)); frame = tag.getFirstField("COMM"); fb = (FrameBodyCOMM)frame.getBody(); assertEquals("\0\0\0",fb.getLanguage()); af.commit(); } catch(Exception e) { e.printStackTrace(); exceptionCaught=e; } assertNull(exceptionCaught); } public void testCommentSetGet() { FrameBodyCOMM comm = new FrameBodyCOMM(); comm.setLanguage("XXX"); assertEquals("XXX",comm.getLanguage()); comm = new FrameBodyCOMM(); comm.setLanguage("\0\0\0"); assertEquals("\0\0\0",comm.getLanguage()); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/issues/Issue256Test.java0000644000175000017500000000203411330305227026744 0ustar drazzibdrazzibpackage org.jaudiotagger.issues; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.audio.exceptions.CannotReadException; import org.jaudiotagger.audio.mp4.Mp4AtomTree; import org.jaudiotagger.tag.FieldKey; import org.jaudiotagger.tag.Tag; import java.io.File; import java.io.RandomAccessFile; /** * Test Writing to new urls with common interface */ public class Issue256Test extends AbstractTestCase { /** * Test Mp3 */ public void testReadMp3() { File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("test74.mp3"); AudioFile af = AudioFileIO.read(testFile); Tag tag = af.getTag(); String value = tag.getFirst(FieldKey.TRACK); } catch(Exception e) { e.printStackTrace(); exceptionCaught=e; } assertNull(exceptionCaught); } }libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/issues/Issue255Test.java0000644000175000017500000000666611276777123027003 0ustar drazzibdrazzibpackage org.jaudiotagger.issues; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.audio.exceptions.CannotReadException; import org.jaudiotagger.audio.mp4.Mp4AtomTree; import org.jaudiotagger.tag.FieldKey; import java.io.File; import java.io.RandomAccessFile; /** * Test Writing to new urls with common interface */ public class Issue255Test extends AbstractTestCase { /** * Test Mp4 with padding after last atom */ public void testReadMp4FileWithPaddingAfterLastAtom() { File orig = new File("testdata", "test35.m4a"); if (!orig.isFile()) { System.err.println("Unable to test file - not available"); return; } File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("test35.m4a"); //Read File AudioFile af = AudioFileIO.read(testFile); //Print Out Tree } catch(Exception e) { e.printStackTrace(); exceptionCaught=e; } assertNull(exceptionCaught); try { //Now just createField tree Mp4AtomTree atomTree = new Mp4AtomTree(new RandomAccessFile(testFile, "r")); atomTree.printAtomTree(); } catch(Exception e) { e.printStackTrace(); exceptionCaught=e; } assertNull(exceptionCaught); } /** * Test to write all data to a m4p which has a padding but no MDAT Dat aso fails on read *

*/ public void testReadFileWithInvalidPadding() { File orig = new File("testdata", "test28.m4p"); if (!orig.isFile()) { System.err.println("Unable to test file - not available"); return; } Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test28.m4p", new File("WriteFileWithInvalidFreeAtom.m4p")); AudioFile f = AudioFileIO.read(testFile); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertTrue(exceptionCaught instanceof CannotReadException); } /** * Test Mp4 with padding after last atom */ public void testWriteMp4FileWithPaddingAfterLastAtom() { File orig = new File("testdata", "test35.m4a"); if (!orig.isFile()) { System.err.println("Unable to test file - not available"); return; } File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("test35.m4a"); //Add a v24Tag AudioFile af = AudioFileIO.read(testFile); af.getTag().setField(FieldKey.ALBUM,"NewValue"); af.commit(); } catch(Exception e) { e.printStackTrace(); exceptionCaught=e; } //Ensure temp file deleted File[] files = testFile.getParentFile().listFiles(); for(File file:files) { System.out.println("Checking "+file.getName()); assertFalse(file.getName().matches(".*test35.*.tmp")); } assertNull(exceptionCaught); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/issues/Issue036Test.java0000644000175000017500000001245511470746136026765 0ustar drazzibdrazzibpackage org.jaudiotagger.issues; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.tag.FieldKey; import org.jaudiotagger.tag.id3.*; /** * Test frame and Tag Equality */ public class Issue036Test extends AbstractTestCase { public void testIDv24Frame() throws Exception { ID3v24Frame frame1 = new ID3v24Frame(); ID3v24Frame frame2 = new ID3v24Frame(); ID3v24Frame frame3 = new ID3v24Frame("TPE1"); ID3v24Frame frame4 = new ID3v24Frame("TPE1"); ID3v24Frame frame5 = new ID3v24Frame("TPE1"); frame5.getBody().setTextEncoding((byte)1); assertTrue(frame1.equals(frame1)); assertTrue(frame1.equals(frame2)); assertFalse(frame1.equals(frame3)); assertTrue(frame3.equals(frame3)); assertTrue(frame3.equals(frame4)); assertFalse(frame3.equals(frame5)); } public void testAllID3v24Frames() throws Exception { for(String frameId : ID3v24Frames.getInstanceOf().getSupportedFrames()) { //System.out.println("Testing:"+frameId); ID3v24Frame frame1 = new ID3v24Frame(frameId); ID3v24Frame frame2 = new ID3v24Frame(frameId); assertTrue(frame1.equals(frame2)); } } public void testIDv24Tag() throws Exception { ID3v24Tag tag1 = new ID3v24Tag(); ID3v24Tag tag2 = new ID3v24Tag(); ID3v24Tag tag3 = new ID3v24Tag(); ID3v24Tag tag4 = new ID3v24Tag(); ID3v24Tag tag5 = new ID3v24Tag(); tag3.addField(FieldKey.ALBUM,"Porcupine"); tag4.addField(FieldKey.ALBUM,"Porcupine"); tag5.addField(FieldKey.ALBUM,"Porcupine"); tag5.addField(FieldKey.ARTIST,"Echo & the Bunnymen"); assertTrue(tag1.equals(tag1)); assertTrue(tag1.equals(tag2)); assertFalse(tag1.equals(tag3)); assertTrue(tag3.equals(tag3)); assertTrue(tag3.equals(tag4)); assertFalse(tag3.equals(tag5)); } public void testIDv23Frame() throws Exception { ID3v23Frame frame1 = new ID3v23Frame(); ID3v23Frame frame2 = new ID3v23Frame(); ID3v23Frame frame3 = new ID3v23Frame("TPE1"); ID3v23Frame frame4 = new ID3v23Frame("TPE1"); ID3v23Frame frame5 = new ID3v23Frame("TPE1"); frame5.getBody().setTextEncoding((byte)1); assertTrue(frame1.equals(frame1)); assertTrue(frame1.equals(frame2)); assertFalse(frame1.equals(frame3)); assertTrue(frame3.equals(frame3)); assertTrue(frame3.equals(frame4)); assertFalse(frame3.equals(frame5)); } public void testAllID3v23Frames() throws Exception { for(String frameId : ID3v23Frames.getInstanceOf().getSupportedFrames()) { //System.out.println("Testing:"+frameId); ID3v23Frame frame1 = new ID3v23Frame(frameId); ID3v23Frame frame2 = new ID3v23Frame(frameId); assertTrue(frame1.equals(frame2)); } } public void testIDv23Tag() throws Exception { ID3v23Tag tag1 = new ID3v23Tag(); ID3v23Tag tag2 = new ID3v23Tag(); ID3v23Tag tag3 = new ID3v23Tag(); ID3v23Tag tag4 = new ID3v23Tag(); ID3v23Tag tag5 = new ID3v23Tag(); tag3.addField(FieldKey.ALBUM,"Porcupine"); tag4.addField(FieldKey.ALBUM,"Porcupine"); tag5.addField(FieldKey.ALBUM,"Porcupine"); tag5.addField(FieldKey.ARTIST,"Echo & the Bunnymen"); assertTrue(tag1.equals(tag1)); assertTrue(tag1.equals(tag2)); assertFalse(tag1.equals(tag3)); assertTrue(tag3.equals(tag3)); assertTrue(tag3.equals(tag4)); assertFalse(tag3.equals(tag5)); } public void testIDv22Frame() throws Exception { ID3v22Frame frame1 = new ID3v22Frame(); ID3v22Frame frame2 = new ID3v22Frame(); ID3v22Frame frame3 = new ID3v22Frame("TP1"); ID3v22Frame frame4 = new ID3v22Frame("TP1"); ID3v22Frame frame5 = new ID3v22Frame("TP1"); frame5.getBody().setTextEncoding((byte)1); assertTrue(frame1.equals(frame1)); assertTrue(frame1.equals(frame2)); assertFalse(frame1.equals(frame3)); assertTrue(frame3.equals(frame3)); assertTrue(frame3.equals(frame4)); assertFalse(frame3.equals(frame5)); } public void testAllID3v22Frames() throws Exception { for(String frameId : ID3v22Frames.getInstanceOf().getSupportedFrames()) { ID3v22Frame frame1 = new ID3v22Frame(frameId); ID3v22Frame frame2 = new ID3v22Frame(frameId); assertTrue(frame1.equals(frame2)); } } public void testIDv22Tag() throws Exception { ID3v22Tag tag1 = new ID3v22Tag(); ID3v22Tag tag2 = new ID3v22Tag(); ID3v22Tag tag3 = new ID3v22Tag(); ID3v22Tag tag4 = new ID3v22Tag(); ID3v22Tag tag5 = new ID3v22Tag(); tag3.addField(FieldKey.ALBUM,"Porcupine"); tag4.addField(FieldKey.ALBUM,"Porcupine"); tag5.addField(FieldKey.ALBUM,"Porcupine"); tag5.addField(FieldKey.ARTIST,"Echo & the Bunnymen"); assertTrue(tag1.equals(tag1)); assertTrue(tag1.equals(tag2)); assertFalse(tag1.equals(tag3)); assertTrue(tag3.equals(tag3)); assertTrue(tag3.equals(tag4)); assertFalse(tag3.equals(tag5)); } }libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/issues/Issue225Test.java0000644000175000017500000000231611276777123026764 0ustar drazzibdrazzibpackage org.jaudiotagger.issues; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.tag.FieldKey; import org.jaudiotagger.tag.Tag; import java.io.File; /** * Test Mp4 genres can be invalid */ public class Issue225Test extends AbstractTestCase { /** * Reading a file contains genre field but set to invalid value 149, because Mp4genreField always * store the value the genre is mapped to we return null. This is correct behaviour. */ public void testReadInvalidGenre() { String genre = null; File orig = new File("testdata", "test30.m4a"); if (!orig.isFile()) { return; } Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test30.m4a"); AudioFile f = AudioFileIO.read(testFile); Tag tag = f.getTag(); genre = tag.getFirst(FieldKey.GENRE); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); assertNull(genre); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/issues/Issue005Test.java0000644000175000017500000000662511470746136026763 0ustar drazzibdrazzibpackage org.jaudiotagger.issues; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.audio.mp3.MP3File; import org.jaudiotagger.tag.Tag; import org.jaudiotagger.tag.id3.ID3v23Tag; import java.io.File; import java.io.FileNotFoundException; /** * Test trying to read non existent mp3 file */ public class Issue005Test extends AbstractTestCase { public void testReadingNonExistentFile() throws Exception { Exception e=null; try { File orig = new File("testdata", "testNonExistent.mp3"); MP3File f = (MP3File)AudioFileIO.read(orig); } catch(Exception ex) { e=ex; } assertTrue(e instanceof FileNotFoundException); } public void testReadingNonExistentFileMp3() throws Exception { Exception e=null; try { File orig = new File("testdata", "testNonExistent.mp3"); MP3File f = new MP3File(orig); } catch(Exception ex) { e=ex; } assertTrue(e instanceof FileNotFoundException); } public void testReadingNonExistentFileFlac() throws Exception { Exception e=null; try { File orig = new File("testdata", "testNonExistent.flac"); AudioFile af = AudioFileIO.read(orig); af.getTag(); } catch(Exception ex) { e=ex; } assertNotNull(e); assertTrue(e instanceof FileNotFoundException); } public void testReadingNonExistentFileOgg() throws Exception { Exception e=null; try { File orig = new File("testdata", "testNonExistent.ogg"); AudioFile af = AudioFileIO.read(orig); af.getTag(); } catch(Exception ex) { e=ex; } assertNotNull(e); assertTrue(e instanceof FileNotFoundException); } public void testReadingNonExistentFileM4a() throws Exception { Exception e=null; try { File orig = new File("testdata", "testNonExistent.m4a"); AudioFile af = AudioFileIO.read(orig); af.getTag(); } catch(Exception ex) { e=ex; } assertNotNull(e); assertTrue(e instanceof FileNotFoundException); } public void testReadingNonExistentFileWma() throws Exception { Exception e=null; try { File orig = new File("testdata", "testNonExistent.wma"); AudioFile af = AudioFileIO.read(orig); af.getTag(); } catch(Exception ex) { e=ex; } assertNotNull(e); assertTrue(e instanceof FileNotFoundException); } public void testReadingNonExistentFileWav() throws Exception { Exception e=null; try { File orig = new File("testdata", "testNonExistent.wav"); AudioFile af = AudioFileIO.read(orig); af.getTag(); } catch(Exception ex) { e=ex; } assertNotNull(e); assertTrue(e instanceof FileNotFoundException); } }libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/issues/Issue220Test.java0000644000175000017500000002102411276777123026754 0ustar drazzibdrazzibpackage org.jaudiotagger.issues; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.tag.FieldKey; import java.io.File; /** * Test read m4a without udta/meta atom */ public class Issue220Test extends AbstractTestCase { /** * Test read mp4 ok without any udta atom (but does have meta atom under trak) */ public void testReadMp4WithoutUdta() { File orig = new File("testdata", "test41.m4a"); if (!orig.isFile()) { System.err.println("Unable to test file - not available"); return; } File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("test41.m4a"); //Read File okay AudioFile af = AudioFileIO.read(testFile); assertTrue(af.getTag().isEmpty()); } catch(Exception e) { e.printStackTrace(); exceptionCaught=e; } assertNull(exceptionCaught); } /** * Test write mp4 ok without any udta atom (but does have meta atom under trak) */ public void testWriteMp4WithoutUdta() { File orig = new File("testdata", "test41.m4a"); if (!orig.isFile()) { System.err.println("Unable to test file - not available"); return; } File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("test41.m4a"); //Read File okay AudioFile af = AudioFileIO.read(testFile); assertTrue(af.getTag().isEmpty()); //Write file af.getTag().setField(FieldKey.ARTIST,"FREDDYCOUGAR"); af.getTag().setField(FieldKey.ALBUM,"album"); af.getTag().setField(FieldKey.TITLE,"title"); af.getTag().setField(FieldKey.GENRE,"genre"); af.getTag().setField(FieldKey.YEAR,"year"); af.commit(); //Read file again okay af = AudioFileIO.read(testFile); assertEquals("FREDDYCOUGAR",af.getTag().getFirst(FieldKey.ARTIST)); assertEquals("album",af.getTag().getFirst(FieldKey.ALBUM)); assertEquals("title",af.getTag().getFirst(FieldKey.TITLE)); assertEquals("genre",af.getTag().getFirst(FieldKey.GENRE)); assertEquals("year",af.getTag().getFirst(FieldKey.YEAR)); } catch(Exception e) { e.printStackTrace(); exceptionCaught=e; } assertNull(exceptionCaught); } /** * Test read mp4 ok which originally had just meta under trak, then processed in picard and now has a seperate udta atom * before mvhd atom (and still has the meta atom under trak) */ public void testReadMp4WithUdtaAndMetaHierachy() { File orig = new File("testdata", "test42.m4a"); if (!orig.isFile()) { System.err.println("Unable to test file - not available"); return; } File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("test42.m4a"); //Read File okay AudioFile af = AudioFileIO.read(testFile); assertEquals("artist",af.getTag().getFirst(FieldKey.ARTIST)); assertEquals("album",af.getTag().getFirst(FieldKey.ALBUM)); assertEquals("test42",af.getTag().getFirst(FieldKey.TITLE)); } catch(Exception e) { e.printStackTrace(); exceptionCaught=e; } assertNull(exceptionCaught); } /** * Test write mp4 ok which originally had just meta under trak, then processed in picard and now has a seperate udta atom * before mvhd atom (and still has the meta atom under trak) */ public void testWriteMp4WithUdtaAndMetaHierachy() { File orig = new File("testdata", "test42.m4a"); if (!orig.isFile()) { System.err.println("Unable to test file - not available"); return; } File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("test42.m4a"); //Read File okay AudioFile af = AudioFileIO.read(testFile); af.getTag().setField(FieldKey.ALBUM,"KARENTAYLORALBUM"); af.getTag().setField(FieldKey.TITLE,"KARENTAYLORTITLE"); af.getTag().setField(FieldKey.GENRE,"KARENTAYLORGENRE"); af.getTag().setField(af.getTag().createField(FieldKey.AMAZON_ID,"12345678")); af.commit(); System.out.println("All is going well"); af = AudioFileIO.read(testFile); assertEquals("KARENTAYLORALBUM",af.getTag().getFirst(FieldKey.ALBUM)); assertEquals("KARENTAYLORTITLE",af.getTag().getFirst(FieldKey.TITLE)); assertEquals("KARENTAYLORGENRE",af.getTag().getFirst(FieldKey.GENRE)); assertEquals("12345678",af.getTag().getFirst(FieldKey.AMAZON_ID)); } catch(Exception e) { e.printStackTrace(); exceptionCaught=e; } assertNull(exceptionCaught); } /** * Test write mp4 ok without any udta atom (but does have meta atom under trak) */ public void testWriteMp4WithUdtaAfterTrackSmaller() { File orig = new File("testdata", "test44.m4a"); if (!orig.isFile()) { System.err.println("Unable to test file - not available"); return; } File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("test44.m4a"); //Read File okay AudioFile af = AudioFileIO.read(testFile); //Write file af.getTag().setField(FieldKey.TITLE,"ti"); af.commit(); //Read file again okay af = AudioFileIO.read(testFile); assertEquals("ti",af.getTag().getFirst(FieldKey.TITLE)); } catch(Exception e) { e.printStackTrace(); exceptionCaught=e; } assertNull(exceptionCaught); } /** * Test write mp4 ok without any udta atom (but does have meta atom under trak) */ public void testWriteMp4WithUdtaAfterTrack() { File orig = new File("testdata", "test44.m4a"); if (!orig.isFile()) { System.err.println("Unable to test file - not available"); return; } File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("test44.m4a"); //Read File okay AudioFile af = AudioFileIO.read(testFile); //Write file af.getTag().setField(FieldKey.ARTIST,"FREDDYCOUGAR"); af.getTag().setField(FieldKey.ALBUM,"album"); af.getTag().setField(FieldKey.TITLE,"title"); af.getTag().setField(FieldKey.GENRE,"genre"); af.getTag().setField(FieldKey.YEAR,"year"); af.commit(); //Read file again okay af = AudioFileIO.read(testFile); assertEquals("FREDDYCOUGAR",af.getTag().getFirst(FieldKey.ARTIST)); assertEquals("album",af.getTag().getFirst(FieldKey.ALBUM)); assertEquals("title",af.getTag().getFirst(FieldKey.TITLE)); assertEquals("genre",af.getTag().getFirst(FieldKey.GENRE)); assertEquals("year",af.getTag().getFirst(FieldKey.YEAR)); } catch(Exception e) { e.printStackTrace(); exceptionCaught=e; } assertNull(exceptionCaught); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/issues/Issue307Test.java0000644000175000017500000000322211470746136026756 0ustar drazzibdrazzibpackage org.jaudiotagger.issues; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.mp3.MP3File; import org.jaudiotagger.tag.id3.ID3v23Frame; import org.jaudiotagger.tag.id3.ID3v23Tag; import org.jaudiotagger.tag.id3.framebody.FrameBodyIPLS; import java.io.File; /** * Test Reading dodgy IPLS frame shouldnt cause file not to be loaded */ public class Issue307Test extends AbstractTestCase { public static int countExceptions =0; public void testMultiThreadedMP3HeaderAccess() throws Exception { File orig = new File("testdata", "test71.mp3"); if (!orig.isFile()) { System.err.println("Unable to test file - not available"); return; } Exception e=null; MP3File mp3File = null; try { final File testFile = AbstractTestCase.copyAudioToTmp("test71.mp3"); if (!testFile.isFile()) { System.err.println("Unable to test file - not available"); return; } mp3File = new MP3File(testFile); } catch(Exception ex) { e=ex; ex.printStackTrace(); } assertNull(e); FrameBodyIPLS frameBody = (FrameBodyIPLS)(((ID3v23Frame)((ID3v23Tag)mp3File.getTag()).getFirstField("IPLS")).getBody()); assertEquals(3,frameBody.getNumberOfPairs()); assertEquals("producer",frameBody.getKeyAtIndex(0)); assertEquals("Tom Wilson",frameBody.getValueAtIndex(0)); assertEquals("producer",frameBody.getKeyAtIndex(1)); assertEquals("John H. Hammond",frameBody.getValueAtIndex(1)); } }libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/issues/Issue250Test.java0000644000175000017500000000303511470746136026755 0ustar drazzibdrazzibpackage org.jaudiotagger.issues; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.audio.mp3.MP3File; import org.jaudiotagger.tag.Tag; import org.jaudiotagger.tag.id3.ID3v23Tag; import java.io.File; /** * Test if read a tag with a corrupt frame that in certain circumstances continue to read the other frames * regardless. */ public class Issue250Test extends AbstractTestCase { public void testReadingFileWithCorruptFirstFrame() throws Exception { File orig = new File("testdata", "test78.mp3"); if (!orig.isFile()) { System.err.println("Unable to test file - not available"); return; } File testFile = AbstractTestCase.copyAudioToTmp("test78.mp3"); MP3File f = (MP3File)AudioFileIO.read(testFile); Tag tag = f.getTag(); assertTrue(f.getTag() instanceof ID3v23Tag); ID3v23Tag id3v23tag = (ID3v23Tag)tag; //Dodgy frame is not counted assertEquals(13,id3v23tag.getFieldCount()); assertEquals(3,id3v23tag.getFields("PRIV").size()); assertEquals(1,id3v23tag.getInvalidFrames()); //PRIV frame f.commit(); f = (MP3File)AudioFileIO.read(testFile); tag = f.getTag(); id3v23tag = (ID3v23Tag)tag; assertEquals(13,id3v23tag.getFieldCount()); assertEquals(3,id3v23tag.getFields("PRIV").size()); assertEquals(0,id3v23tag.getInvalidFrames()); //PRIV frame thrown away } }libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/issues/Issue185Test.java0000644000175000017500000000401411276777123026766 0ustar drazzibdrazzibpackage org.jaudiotagger.issues; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.tag.Tag; import org.jaudiotagger.tag.id3.ID3v23Tag; import java.io.File; /** * Test Creating Null fields */ public class Issue185Test extends AbstractTestCase { public void testDefaultTagMp3() { Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); AudioFile af = AudioFileIO.read(testFile); //No Tag assertNull(af.getTag()); //Tag Created Tag tag = af.createDefaultTag(); assertTrue(tag instanceof ID3v23Tag); //but not setField in tag itself assertNull(af.getTag()); //Now setField af.setTag(tag); assertTrue(af.getTag() instanceof ID3v23Tag); //Save changes af.commit(); af = AudioFileIO.read(testFile); assertTrue(af.getTag() instanceof ID3v23Tag); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); } public void testDefaultTagMp3AndCreate() { Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); AudioFile af = AudioFileIO.read(testFile); //No Tag assertNull(af.getTag()); //Tag Created and setField Tag tag = af.getTagOrCreateAndSetDefault(); assertTrue(tag instanceof ID3v23Tag); assertTrue(af.getTag() instanceof ID3v23Tag); //Save changes af.commit(); af = AudioFileIO.read(testFile); assertTrue(af.getTag() instanceof ID3v23Tag); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/issues/Issue302Test.java0000644000175000017500000000332111330522400026726 0ustar drazzibdrazzibpackage org.jaudiotagger.issues; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.audio.mp3.MP3File; import org.jaudiotagger.tag.FieldKey; import org.jaudiotagger.tag.Tag; import org.jaudiotagger.tag.TagOptionSingleton; import org.jaudiotagger.tag.id3.ID3v24Frame; import org.jaudiotagger.tag.id3.ID3v24Frames; import org.jaudiotagger.tag.id3.ID3v24Tag; import org.jaudiotagger.tag.id3.framebody.FrameBodyTXXX; import org.jaudiotagger.tag.id3.framebody.FrameBodyTXXXTest; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; import java.io.File; /** * Test Android ByteBuffer fix */ public class Issue302Test extends AbstractTestCase { public void testAndroidReadFix() throws Exception { TagOptionSingleton.getInstance().setToDefault(); TagOptionSingleton.getInstance().setAndroid(true); ID3v24Frame frame = new ID3v24Frame(ID3v24Frames.FRAME_ID_USER_DEFINED_INFO); FrameBodyTXXX fb = FrameBodyTXXXTest.getInitialisedBody(); frame.setBody(fb); File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); MP3File mp3File = new MP3File(testFile); //Create and Save ID3v24Tag tag = new ID3v24Tag(); tag.setFrame(frame); mp3File.setID3v2Tag(tag); mp3File.save(); //Reload mp3File = new MP3File(testFile); frame = (ID3v24Frame) mp3File.getID3v2Tag().getFrame(ID3v24Frames.FRAME_ID_USER_DEFINED_INFO); FrameBodyTXXX body = (FrameBodyTXXX) frame.getBody(); assertEquals(TextEncoding.ISO_8859_1, body.getTextEncoding()); TagOptionSingleton.getInstance().setToDefault(); } }libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/issues/Issue263Test.java0000644000175000017500000001545711470746136026774 0ustar drazzibdrazzibpackage org.jaudiotagger.issues; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.tag.FieldKey; import org.jaudiotagger.tag.KeyNotFoundException; import org.jaudiotagger.tag.Tag; import org.jaudiotagger.tag.id3.ID3v22Tag; import org.jaudiotagger.tag.id3.ID3v23Tag; import org.jaudiotagger.tag.id3.ID3v24Tag; import java.io.File; /** * Cannot cretaeTagField for creating artwork field */ public class Issue263Test extends AbstractTestCase { /** * Test writing Artwork to Mp3 ID3v24 */ public void testWriteArtworkFieldsToMp3ID3v24() { File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); //Read File okay AudioFile af = AudioFileIO.read(testFile); af.setTag(new ID3v24Tag()); Tag tag = af.getTag(); tag.createField(FieldKey.COVER_ART, "test"); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNotNull(exceptionCaught); assertTrue(exceptionCaught instanceof UnsupportedOperationException); } /** * Test writing Artwork to Mp3 ID3v22 */ public void testWriteArtworkFieldsToMp3ID3v22() { File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); //Read File okay AudioFile af = AudioFileIO.read(testFile); af.setTag(new ID3v22Tag()); Tag tag = af.getTag(); tag.createField(FieldKey.COVER_ART, "test"); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNotNull(exceptionCaught); assertTrue(exceptionCaught instanceof UnsupportedOperationException); } /** * Test writing Artwork to Mp3 ID3v23 */ public void testWriteArtworkFieldsToMp3ID3v23() { File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); //Read File okay AudioFile af = AudioFileIO.read(testFile); af.setTag(new ID3v23Tag()); Tag tag = af.getTag(); tag.createField(FieldKey.COVER_ART, "test"); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNotNull(exceptionCaught); assertTrue(exceptionCaught instanceof UnsupportedOperationException); } /** * Test reading/writing artwork to Ogg */ public void testReadWriteArtworkFieldsToOggVorbis() { File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("test3.ogg"); //Read File okay AudioFile af = AudioFileIO.read(testFile); Tag tag = af.getTag(); tag.createField(FieldKey.COVER_ART, "test"); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * Test reading/writing artwork to Flac */ public void testReadWriteArtworkFieldsToFlac() { File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("test.flac"); //Read File okay AudioFile af = AudioFileIO.read(testFile); Tag tag = af.getTag(); tag.createField(FieldKey.COVER_ART, "test"); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNotNull(exceptionCaught); assertTrue(exceptionCaught instanceof UnsupportedOperationException); } /** * Test reading/writing artwork to Wma */ public void testReadWriteArtworkFieldsToWma() { File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("test5.wma"); //Read File okay AudioFile af = AudioFileIO.read(testFile); Tag tag = af.getTag(); tag.createField(FieldKey.COVER_ART, "test"); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNotNull(exceptionCaught); assertTrue(exceptionCaught instanceof UnsupportedOperationException); } /** * Test reading/writing artwork to Mp4 */ public void testReadWriteArtworkFieldsToMp4() { File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("test2.m4a"); //Read File okay AudioFile af = AudioFileIO.read(testFile); Tag tag = af.getTag(); tag.createField(FieldKey.COVER_ART, "test"); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNotNull(exceptionCaught); assertTrue(exceptionCaught instanceof UnsupportedOperationException); } /** * Test Artwork cannot be written to Wav */ public void testReadWriteArtworkFieldsToWav() { File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("test.wav"); //Read File okay AudioFile af = AudioFileIO.read(testFile); Tag tag = af.getTag(); tag.createField(FieldKey.COVER_ART, "test"); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNotNull(exceptionCaught); assertTrue(exceptionCaught instanceof UnsupportedOperationException); } /** * Test Artwork cannot be written to Real */ public void testReadWriteArtworkFieldsToReal() { File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("test01.ra"); //Read File okay AudioFile af = AudioFileIO.read(testFile); Tag tag = af.getTag(); tag.createField(FieldKey.COVER_ART, "test"); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNotNull(exceptionCaught); assertTrue(exceptionCaught instanceof UnsupportedOperationException); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/issues/Issue290Test.java0000644000175000017500000000237211302736452026756 0ustar drazzibdrazzibpackage org.jaudiotagger.issues; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.tag.FieldKey; import java.io.File; /** *File corrupt after write */ public class Issue290Test extends AbstractTestCase { public void testSavingFile() { File orig = new File("testdata", "test59.mp4"); if (!orig.isFile()) { System.err.println("Unable to test file - not available"); return; } /* Issue still needs fixing File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("test59.mp4"); AudioFile af = AudioFileIO.read(testFile); System.out.println("Tag is"+af.getTag().toString()); af.getTag().setField(af.getTag().createField(FieldKey.ARTIST,"fred")); af.commit(); af = AudioFileIO.read(testFile); assertEquals("fred",af.getTag().getFirst(FieldKey.ARTIST)); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); */ } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/issues/Issue257Test.java0000644000175000017500000000237211111551270026750 0ustar drazzibdrazzibpackage org.jaudiotagger.issues; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.audio.exceptions.CannotReadException; import org.jaudiotagger.audio.mp4.Mp4AtomTree; import java.io.File; import java.io.RandomAccessFile; /** * Test Writing to new urls with common interface */ public class Issue257Test extends AbstractTestCase { /** * Test Mp4 with crap between free atom and mdat atom, shoud cause immediate failure */ public void testReadMp4FileWithPaddingAfterLastAtom() { File orig = new File("testdata", "test37.m4a"); if (!orig.isFile()) { System.err.println("Unable to test file - not available"); return; } File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("test37.m4a"); //Read File AudioFile af = AudioFileIO.read(testFile); //Print Out Tree } catch(Exception e) { e.printStackTrace(); exceptionCaught=e; } assertTrue(exceptionCaught instanceof CannotReadException); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/issues/Issue240Test.java0000644000175000017500000000304511276777123026761 0ustar drazzibdrazzibpackage org.jaudiotagger.issues; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.tag.FieldKey; import org.jaudiotagger.tag.mp4.Mp4Tag; import java.io.File; import java.io.RandomAccessFile; /** * Test Writing to mp4 with top level free data atoms but free atoms and mdat are before ilst so not useful */ public class Issue240Test extends AbstractTestCase { public void testWritelargeDataToFile() { File orig = new File("testdata", "test34.m4a"); if (!orig.isFile()) { return; } Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test34.m4a"); AudioFile af = AudioFileIO.read(testFile); assertEquals(0,((Mp4Tag)af.getTag()).getFields(FieldKey.COVER_ART).size()); //Add new image RandomAccessFile imageFile = new RandomAccessFile(new File("testdata", "coverart.png"), "r"); byte[] imagedata = new byte[(int) imageFile.length()]; imageFile.read(imagedata); af.getTag().addField(((Mp4Tag) af.getTag()).createArtworkField(imagedata)); af.commit(); //Read File back af = AudioFileIO.read(testFile); assertEquals(1,((Mp4Tag)af.getTag()).getFields(FieldKey.COVER_ART).size()); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/issues/Issue242Test.java0000644000175000017500000003522411276777123026767 0ustar drazzibdrazzibpackage org.jaudiotagger.issues; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.audio.mp3.MP3File; import org.jaudiotagger.tag.FieldKey; import org.jaudiotagger.tag.id3.ID3v22Tag; import org.jaudiotagger.tag.id3.ID3v23Tag; import org.jaudiotagger.tag.id3.ID3v24Tag; import java.io.File; /** * Test Writing to new urls with common interface */ public class Issue242Test extends AbstractTestCase { /** * Test New Urls ID3v24 */ public void testWriteNewUrlsFilev24() { Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3", new File("test1030.mp3")); //Add a v24Tag AudioFile af = AudioFileIO.read(testFile); MP3File mp3File= (MP3File)af; //Checking not overwriting audio when have to pad to fix data long mp3AudioLength=testFile.length() - mp3File.getMP3AudioHeader().getMp3StartByte(); mp3File.setID3v2Tag(new ID3v24Tag()); mp3File.save(); af = AudioFileIO.read(testFile); mp3File= (MP3File)af; assertEquals(mp3AudioLength,testFile.length() - mp3File.getMP3AudioHeader().getMp3StartByte()); //Check mapped okay ands empty assertEquals(0,mp3File.getTag().getFields(FieldKey.URL_OFFICIAL_RELEASE_SITE).size()); assertEquals(0,mp3File.getTag().getFields(FieldKey.URL_OFFICIAL_ARTIST_SITE).size()); assertEquals(0,mp3File.getTag().getFields(FieldKey.URL_DISCOGS_RELEASE_SITE).size()); assertEquals(0,mp3File.getTag().getFields(FieldKey.URL_DISCOGS_ARTIST_SITE).size()); assertEquals(0,mp3File.getTag().getFields(FieldKey.URL_WIKIPEDIA_RELEASE_SITE).size()); assertEquals(0,mp3File.getTag().getFields(FieldKey.URL_WIKIPEDIA_ARTIST_SITE).size()); assertEquals(0,mp3File.getTag().getFields(FieldKey.URL_LYRICS_SITE).size()); //Now write these fields mp3File.getTag().setField(mp3File.getTag().createField(FieldKey.URL_OFFICIAL_RELEASE_SITE,"http://test1")); mp3File.getTag().setField(mp3File.getTag().createField(FieldKey.URL_DISCOGS_RELEASE_SITE,"http://test2")); mp3File.getTag().setField(mp3File.getTag().createField(FieldKey.URL_DISCOGS_ARTIST_SITE,"http://test3")); mp3File.getTag().setField(mp3File.getTag().createField(FieldKey.URL_WIKIPEDIA_RELEASE_SITE,"http://test4")); mp3File.getTag().setField(mp3File.getTag().createField(FieldKey.URL_WIKIPEDIA_ARTIST_SITE,"http://test5")); mp3File.getTag().setField(mp3File.getTag().createField(FieldKey.URL_OFFICIAL_ARTIST_SITE,"http://test6")); mp3File.getTag().setField(mp3File.getTag().createField(FieldKey.URL_LYRICS_SITE,"http://test7")); mp3File.save(); af = AudioFileIO.read(testFile); mp3File= (MP3File)af; //Check mapped okay ands empty assertTrue(mp3File.getTag() instanceof ID3v24Tag); assertEquals(1,mp3File.getTag().getFields(FieldKey.URL_OFFICIAL_RELEASE_SITE).size()); assertEquals(1,mp3File.getTag().getFields(FieldKey.URL_DISCOGS_RELEASE_SITE).size()); assertEquals(1,mp3File.getTag().getFields(FieldKey.URL_DISCOGS_ARTIST_SITE).size()); assertEquals(1,mp3File.getTag().getFields(FieldKey.URL_WIKIPEDIA_RELEASE_SITE).size()); assertEquals(1,mp3File.getTag().getFields(FieldKey.URL_WIKIPEDIA_ARTIST_SITE).size()); assertEquals(1,mp3File.getTag().getFields(FieldKey.URL_OFFICIAL_ARTIST_SITE).size()); assertEquals(1,mp3File.getTag().getFields(FieldKey.URL_LYRICS_SITE).size()); //Delete Fields mp3File.getTag().deleteField(FieldKey.URL_OFFICIAL_RELEASE_SITE); mp3File.getTag().deleteField(FieldKey.URL_DISCOGS_RELEASE_SITE); mp3File.getTag().deleteField(FieldKey.URL_DISCOGS_ARTIST_SITE); mp3File.getTag().deleteField(FieldKey.URL_WIKIPEDIA_RELEASE_SITE); mp3File.getTag().deleteField(FieldKey.URL_WIKIPEDIA_ARTIST_SITE); mp3File.getTag().deleteField(FieldKey.URL_OFFICIAL_ARTIST_SITE); mp3File.getTag().deleteField(FieldKey.URL_LYRICS_SITE); mp3File.save(); af = AudioFileIO.read(testFile); mp3File= (MP3File)af; assertEquals(0,mp3File.getTag().getFields(FieldKey.URL_OFFICIAL_RELEASE_SITE).size()); assertEquals(0,mp3File.getTag().getFields(FieldKey.URL_OFFICIAL_ARTIST_SITE).size()); assertEquals(0,mp3File.getTag().getFields(FieldKey.URL_DISCOGS_RELEASE_SITE).size()); assertEquals(0,mp3File.getTag().getFields(FieldKey.URL_DISCOGS_ARTIST_SITE).size()); assertEquals(0,mp3File.getTag().getFields(FieldKey.URL_WIKIPEDIA_RELEASE_SITE).size()); assertEquals(0,mp3File.getTag().getFields(FieldKey.URL_WIKIPEDIA_ARTIST_SITE).size()); assertEquals(0,mp3File.getTag().getFields(FieldKey.URL_LYRICS_SITE).size()); } catch (Exception e) { exceptionCaught = e; e.printStackTrace(); } assertNull(exceptionCaught); } /** * Test New Urls ID3v23 */ public void testWriteNewUrlsFilev23() { Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3", new File("test1031.mp3")); //Add a v24Tag AudioFile af = AudioFileIO.read(testFile); MP3File mp3File= (MP3File)af; //Checking not overwriting audio when have to pad to fix data long mp3AudioLength=testFile.length() - mp3File.getMP3AudioHeader().getMp3StartByte(); mp3File.setID3v2Tag(new ID3v23Tag()); mp3File.save(); af = AudioFileIO.read(testFile); mp3File= (MP3File)af; assertEquals(mp3AudioLength,testFile.length() - mp3File.getMP3AudioHeader().getMp3StartByte()); //Check mapped okay ands empty assertEquals(0,mp3File.getTag().getFields(FieldKey.URL_OFFICIAL_RELEASE_SITE).size()); assertEquals(0,mp3File.getTag().getFields(FieldKey.URL_OFFICIAL_ARTIST_SITE).size()); assertEquals(0,mp3File.getTag().getFields(FieldKey.URL_DISCOGS_RELEASE_SITE).size()); assertEquals(0,mp3File.getTag().getFields(FieldKey.URL_DISCOGS_ARTIST_SITE).size()); assertEquals(0,mp3File.getTag().getFields(FieldKey.URL_WIKIPEDIA_RELEASE_SITE).size()); assertEquals(0,mp3File.getTag().getFields(FieldKey.URL_WIKIPEDIA_ARTIST_SITE).size()); assertEquals(0,mp3File.getTag().getFields(FieldKey.URL_LYRICS_SITE).size()); //Now write these fields mp3File.getTag().setField(mp3File.getTag().createField(FieldKey.URL_OFFICIAL_RELEASE_SITE,"http://test1")); mp3File.getTag().setField(mp3File.getTag().createField(FieldKey.URL_DISCOGS_RELEASE_SITE,"http://test2")); mp3File.getTag().setField(mp3File.getTag().createField(FieldKey.URL_DISCOGS_ARTIST_SITE,"http://test3")); mp3File.getTag().setField(mp3File.getTag().createField(FieldKey.URL_WIKIPEDIA_RELEASE_SITE,"http://test4")); mp3File.getTag().setField(mp3File.getTag().createField(FieldKey.URL_WIKIPEDIA_ARTIST_SITE,"http://test5")); mp3File.getTag().setField(mp3File.getTag().createField(FieldKey.URL_OFFICIAL_ARTIST_SITE,"http://test6")); mp3File.getTag().setField(mp3File.getTag().createField(FieldKey.URL_LYRICS_SITE,"http://test7")); mp3File.save(); af = AudioFileIO.read(testFile); mp3File= (MP3File)af; //Check mapped okay ands empty assertEquals(1,mp3File.getTag().getFields(FieldKey.URL_OFFICIAL_RELEASE_SITE).size()); assertEquals(1,mp3File.getTag().getFields(FieldKey.URL_DISCOGS_RELEASE_SITE).size()); assertEquals(1,mp3File.getTag().getFields(FieldKey.URL_DISCOGS_ARTIST_SITE).size()); assertEquals(1,mp3File.getTag().getFields(FieldKey.URL_WIKIPEDIA_RELEASE_SITE).size()); assertEquals(1,mp3File.getTag().getFields(FieldKey.URL_WIKIPEDIA_ARTIST_SITE).size()); assertEquals(1,mp3File.getTag().getFields(FieldKey.URL_OFFICIAL_ARTIST_SITE).size()); assertEquals(1,mp3File.getTag().getFields(FieldKey.URL_LYRICS_SITE).size()); //Delete Fields mp3File.getTag().deleteField(FieldKey.URL_OFFICIAL_RELEASE_SITE); mp3File.getTag().deleteField(FieldKey.URL_DISCOGS_RELEASE_SITE); mp3File.getTag().deleteField(FieldKey.URL_DISCOGS_ARTIST_SITE); mp3File.getTag().deleteField(FieldKey.URL_WIKIPEDIA_RELEASE_SITE); mp3File.getTag().deleteField(FieldKey.URL_WIKIPEDIA_ARTIST_SITE); mp3File.getTag().deleteField(FieldKey.URL_OFFICIAL_ARTIST_SITE); mp3File.getTag().deleteField(FieldKey.URL_LYRICS_SITE); mp3File.save(); af = AudioFileIO.read(testFile); mp3File= (MP3File)af; assertEquals(0,mp3File.getTag().getFields(FieldKey.URL_OFFICIAL_RELEASE_SITE).size()); assertEquals(0,mp3File.getTag().getFields(FieldKey.URL_OFFICIAL_ARTIST_SITE).size()); assertEquals(0,mp3File.getTag().getFields(FieldKey.URL_DISCOGS_RELEASE_SITE).size()); assertEquals(0,mp3File.getTag().getFields(FieldKey.URL_DISCOGS_ARTIST_SITE).size()); assertEquals(0,mp3File.getTag().getFields(FieldKey.URL_WIKIPEDIA_RELEASE_SITE).size()); assertEquals(0,mp3File.getTag().getFields(FieldKey.URL_WIKIPEDIA_ARTIST_SITE).size()); assertEquals(0,mp3File.getTag().getFields(FieldKey.URL_OFFICIAL_RELEASE_SITE).size()); assertEquals(0,mp3File.getTag().getFields(FieldKey.URL_LYRICS_SITE).size()); } catch (Exception e) { exceptionCaught = e; e.printStackTrace(); } assertNull(exceptionCaught); } /** * Test New Urls ID3v24 */ public void testWriteNewUrlsFilev22() { Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3", new File("test1032.mp3")); //Add a v24Tag AudioFile af = AudioFileIO.read(testFile); MP3File mp3File= (MP3File)af; //Checking not overwriting audio when have to pad to fix data long mp3AudioLength=testFile.length() - mp3File.getMP3AudioHeader().getMp3StartByte(); mp3File.setID3v2Tag(new ID3v22Tag()); mp3File.save(); af = AudioFileIO.read(testFile); mp3File= (MP3File)af; assertEquals(mp3AudioLength,testFile.length() - mp3File.getMP3AudioHeader().getMp3StartByte()); //Check mapped okay ands empty assertEquals(0,mp3File.getTag().getFields(FieldKey.URL_OFFICIAL_RELEASE_SITE).size()); assertEquals(0,mp3File.getTag().getFields(FieldKey.URL_OFFICIAL_ARTIST_SITE).size()); assertEquals(0,mp3File.getTag().getFields(FieldKey.URL_DISCOGS_RELEASE_SITE).size()); assertEquals(0,mp3File.getTag().getFields(FieldKey.URL_DISCOGS_ARTIST_SITE).size()); assertEquals(0,mp3File.getTag().getFields(FieldKey.URL_WIKIPEDIA_RELEASE_SITE).size()); assertEquals(0,mp3File.getTag().getFields(FieldKey.URL_WIKIPEDIA_ARTIST_SITE).size()); assertEquals(0,mp3File.getTag().getFields(FieldKey.URL_LYRICS_SITE).size()); //Now write these fields mp3File.getTag().setField(mp3File.getTag().createField(FieldKey.URL_OFFICIAL_RELEASE_SITE,"http://test1")); mp3File.getTag().setField(mp3File.getTag().createField(FieldKey.URL_DISCOGS_RELEASE_SITE,"http://test2")); mp3File.getTag().setField(mp3File.getTag().createField(FieldKey.URL_DISCOGS_ARTIST_SITE,"http://test3")); mp3File.getTag().setField(mp3File.getTag().createField(FieldKey.URL_WIKIPEDIA_RELEASE_SITE,"http://test4")); mp3File.getTag().setField(mp3File.getTag().createField(FieldKey.URL_WIKIPEDIA_ARTIST_SITE,"http://test5")); mp3File.getTag().setField(mp3File.getTag().createField(FieldKey.URL_OFFICIAL_ARTIST_SITE,"http://test6")); mp3File.getTag().setField(mp3File.getTag().createField(FieldKey.URL_LYRICS_SITE,"http://test7")); mp3File.save(); af = AudioFileIO.read(testFile); mp3File= (MP3File)af; //Check mapped okay ands empty assertEquals(1,mp3File.getTag().getFields(FieldKey.URL_OFFICIAL_RELEASE_SITE).size()); assertEquals(1,mp3File.getTag().getFields(FieldKey.URL_DISCOGS_RELEASE_SITE).size()); assertEquals(1,mp3File.getTag().getFields(FieldKey.URL_DISCOGS_ARTIST_SITE).size()); assertEquals(1,mp3File.getTag().getFields(FieldKey.URL_WIKIPEDIA_RELEASE_SITE).size()); assertEquals(1,mp3File.getTag().getFields(FieldKey.URL_WIKIPEDIA_ARTIST_SITE).size()); assertEquals(1,mp3File.getTag().getFields(FieldKey.URL_OFFICIAL_ARTIST_SITE).size()); assertEquals(1,mp3File.getTag().getFields(FieldKey.URL_LYRICS_SITE).size()); //Delete Fields mp3File.getTag().deleteField(FieldKey.URL_OFFICIAL_RELEASE_SITE); mp3File.getTag().deleteField(FieldKey.URL_DISCOGS_RELEASE_SITE); mp3File.getTag().deleteField(FieldKey.URL_DISCOGS_ARTIST_SITE); mp3File.getTag().deleteField(FieldKey.URL_WIKIPEDIA_RELEASE_SITE); mp3File.getTag().deleteField(FieldKey.URL_WIKIPEDIA_ARTIST_SITE); mp3File.getTag().deleteField(FieldKey.URL_OFFICIAL_ARTIST_SITE); mp3File.getTag().deleteField(FieldKey.URL_LYRICS_SITE); mp3File.save(); af = AudioFileIO.read(testFile); mp3File= (MP3File)af; assertEquals(0,mp3File.getTag().getFields(FieldKey.URL_OFFICIAL_RELEASE_SITE).size()); assertEquals(0,mp3File.getTag().getFields(FieldKey.URL_OFFICIAL_ARTIST_SITE).size()); assertEquals(0,mp3File.getTag().getFields(FieldKey.URL_DISCOGS_RELEASE_SITE).size()); assertEquals(0,mp3File.getTag().getFields(FieldKey.URL_DISCOGS_ARTIST_SITE).size()); assertEquals(0,mp3File.getTag().getFields(FieldKey.URL_WIKIPEDIA_RELEASE_SITE).size()); assertEquals(0,mp3File.getTag().getFields(FieldKey.URL_WIKIPEDIA_ARTIST_SITE).size()); assertEquals(0,mp3File.getTag().getFields(FieldKey.URL_LYRICS_SITE).size()); } catch (Exception e) { exceptionCaught = e; e.printStackTrace(); } assertNull(exceptionCaught); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/issues/Issue261Test.java0000644000175000017500000000240011276777123026756 0ustar drazzibdrazzibpackage org.jaudiotagger.issues; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.tag.FieldKey; import java.io.File; /** * Test read m4a without udta/meta atom */ public class Issue261Test extends AbstractTestCase { /** * Test write mp4 ok without any udta/meta atoms */ public void testWriteMp4() { File orig = new File("testdata", "test45.m4a"); if (!orig.isFile()) { System.err.println("Unable to test file - not available"); return; } File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("test45.m4a"); //Read File okay AudioFile af = AudioFileIO.read(testFile); //Write file af.getTag().setField(FieldKey.YEAR,"2007"); af.commit(); af = AudioFileIO.read(testFile); assertEquals("2007",af.getTag().getFirst(FieldKey.YEAR)); } catch(Exception e) { e.printStackTrace(); exceptionCaught=e; } assertNull(exceptionCaught); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/issues/Issue221Test.java0000644000175000017500000001342411276777123026762 0ustar drazzibdrazzibpackage org.jaudiotagger.issues; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.tag.FieldKey; import org.jaudiotagger.tag.id3.ID3v22Tag; import org.jaudiotagger.tag.id3.ID3v23Tag; import org.jaudiotagger.tag.id3.ID3v24Tag; import org.jaudiotagger.tag.mp4.Mp4Tag; import org.jaudiotagger.tag.vorbiscomment.VorbisCommentTag; import java.io.FileOutputStream; /** * Test Creating Null fields */ public class Issue221Test extends AbstractTestCase { public void testCreateNullMp4FrameTitle() { Exception exceptionCaught = null; try { Mp4Tag tag = new Mp4Tag(); tag.setField(FieldKey.TITLE,null); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertTrue(exceptionCaught instanceof IllegalArgumentException); } public void testCreateNullOggVorbisFrameTitle() { Exception exceptionCaught = null; try { VorbisCommentTag tag = VorbisCommentTag.createNewTag(); tag.setField(FieldKey.TITLE,null); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertTrue(exceptionCaught instanceof IllegalArgumentException); } public void testCreateNullID3v23FrameTitle() { Exception exceptionCaught = null; try { ID3v23Tag tag = new ID3v23Tag(); tag.setField(FieldKey.TITLE,null); FileOutputStream os = new FileOutputStream("testdatatmp/issue_221_title_v23.mp3"); tag.write(os.getChannel()); os.close(); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertTrue(exceptionCaught instanceof IllegalArgumentException); } public void testCreateNullID3v23FrameAlbum() { Exception exceptionCaught = null; try { ID3v23Tag tag = new ID3v23Tag(); tag.setField(FieldKey.ALBUM,null); FileOutputStream os = new FileOutputStream("testdatatmp/issue_221_title_v23.mp3"); tag.write(os.getChannel()); os.close(); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertTrue(exceptionCaught instanceof IllegalArgumentException); } public void testCreateNullID3v23FrameArtist() { Exception exceptionCaught = null; try { ID3v23Tag tag = new ID3v23Tag(); tag.setField(FieldKey.ARTIST,null); FileOutputStream os = new FileOutputStream("testdatatmp/issue_221_title_v23.mp3"); tag.write(os.getChannel()); os.close(); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertTrue(exceptionCaught instanceof IllegalArgumentException); } public void testCreateNullID3v23FrameComment() { Exception exceptionCaught = null; try { ID3v23Tag tag = new ID3v23Tag(); tag.setField(FieldKey.COMMENT,null); FileOutputStream os = new FileOutputStream("testdatatmp/issue_221_title_v23.mp3"); tag.write(os.getChannel()); os.close(); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertTrue(exceptionCaught instanceof IllegalArgumentException); } public void testCreateNullID3v23FrameGenre() { Exception exceptionCaught = null; try { ID3v23Tag tag = new ID3v23Tag(); tag.setField(FieldKey.GENRE,null); FileOutputStream os = new FileOutputStream("testdatatmp/issue_221_title_v23.mp3"); tag.write(os.getChannel()); os.close(); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertTrue(exceptionCaught instanceof IllegalArgumentException); } public void testCreateNullID3v23FrameTrack() { Exception exceptionCaught = null; try { ID3v23Tag tag = new ID3v23Tag(); tag.setField(FieldKey.TRACK,null); FileOutputStream os = new FileOutputStream("testdatatmp/issue_221_title_v23.mp3"); tag.write(os.getChannel()); os.close(); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertTrue(exceptionCaught instanceof IllegalArgumentException); } public void testCreateNullID3v24Frame() { Exception exceptionCaught = null; try { ID3v24Tag tag = new ID3v24Tag(); tag.setField(FieldKey.TITLE,null); FileOutputStream os = new FileOutputStream("testdatatmp/issue_221_title_v24.mp3"); tag.write(os.getChannel()); os.close(); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertTrue(exceptionCaught instanceof IllegalArgumentException); } public void testCreateNullID3v22Frame() { Exception exceptionCaught = null; try { ID3v22Tag tag = new ID3v22Tag(); tag.setField(FieldKey.TITLE,null); FileOutputStream os = new FileOutputStream("testdatatmp/issue_221_title_v24.mp3"); tag.write(os.getChannel()); os.close(); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertTrue(exceptionCaught instanceof IllegalArgumentException); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/issues/Issue315Test.java0000644000175000017500000000237711310522141026744 0ustar drazzibdrazzibpackage org.jaudiotagger.issues; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.tag.FieldKey; import java.io.File; /** * Test can read FlacTag with spec breaking PICTUREBLOCK as first block and then write chnages * to it reordering so that STREAMINFO is the first block */ public class Issue315Test extends AbstractTestCase { /* * * @throws Exception */ public void testReadWriteTagWithPictureBlockAtStart() throws Exception { File orig = new File("testdata", "test54.flac"); if (!orig.isFile()) { System.err.println("Unable to test file - not available"); return; } Exception e=null; try { final File testFile = AbstractTestCase.copyAudioToTmp("test54.flac"); AudioFile af = AudioFileIO.read(testFile); //Modify File af.getTag().setField(FieldKey.TITLE,"newtitle"); af.commit(); //Reread File af = AudioFileIO.read(testFile); } catch(Exception ex) { e=ex; ex.printStackTrace(); } assertNull(e); } }libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/issues/Issue345Test.java0000644000175000017500000004625411470746136026774 0ustar drazzibdrazzibpackage org.jaudiotagger.issues; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.tag.FieldKey; import org.jaudiotagger.tag.Tag; import org.jaudiotagger.tag.TagField; import org.jaudiotagger.tag.TagTextField; import org.jaudiotagger.tag.id3.ID3v22Tag; import org.jaudiotagger.tag.id3.ID3v23Tag; import org.jaudiotagger.tag.id3.ID3v24Frame; import org.jaudiotagger.tag.id3.ID3v24Tag; import org.jaudiotagger.tag.id3.framebody.FrameBodyCOMM; import org.jaudiotagger.tag.id3.framebody.FrameBodyPOPM; import org.jaudiotagger.tag.reference.Languages; import java.io.File; import java.util.List; /** * Support For Custom fields */ public class Issue345Test extends AbstractTestCase { /** * Test writing Custom fields */ public void testWriteFieldsToMp3ID3v24() { File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); //Read File okay AudioFile af = AudioFileIO.read(testFile); af.setTag(new ID3v24Tag()); Tag tag = af.getTag(); tag.setField(tag.createField(FieldKey.RATING,"50")); tag.setField(tag.createField(FieldKey.MIXER,"mixer")); tag.setField(tag.createField(FieldKey.ENGINEER,"engineervalue")); tag.setField(tag.createField(FieldKey.DJMIXER,"djmixervalue")); tag.setField(tag.createField(FieldKey.PRODUCER,"producervalue")); tag.setField(tag.createField(FieldKey.ARRANGER,"arrangervalue")); assertEquals("50",af.getTag().getFirst(FieldKey.RATING)); assertEquals("mixer",af.getTag().getFirst(FieldKey.MIXER)); assertEquals("engineervalue",af.getTag().getFirst(FieldKey.ENGINEER)); assertEquals("djmixervalue",af.getTag().getFirst(FieldKey.DJMIXER)); assertEquals("producervalue",af.getTag().getFirst(FieldKey.PRODUCER)); assertEquals("arrangervalue",af.getTag().getFirst(FieldKey.ARRANGER)); { TagField tagField = af.getTag().getFirstField(FieldKey.RATING); assertTrue(tagField instanceof ID3v24Frame); assertTrue(((ID3v24Frame)tagField).getBody() instanceof FrameBodyPOPM); } af.commit(); af = AudioFileIO.read(testFile); tag = af.getTag(); assertEquals("50",af.getTag().getFirst(FieldKey.RATING)); assertEquals("mixer",af.getTag().getFirst(FieldKey.MIXER)); assertEquals("engineervalue",af.getTag().getFirst(FieldKey.ENGINEER)); assertEquals("djmixervalue",af.getTag().getFirst(FieldKey.DJMIXER)); assertEquals("producervalue",af.getTag().getFirst(FieldKey.PRODUCER)); assertEquals("arrangervalue",af.getTag().getFirst(FieldKey.ARRANGER)); { TagField tagField = af.getTag().getFirstField(FieldKey.RATING); assertTrue(tagField instanceof ID3v24Frame); assertTrue(((ID3v24Frame)tagField).getBody() instanceof FrameBodyPOPM); } List fields = tag.getFields(FieldKey.PRODUCER); for(TagField field:fields) { System.out.println(((TagTextField)field).getContent()); } tag.deleteField(FieldKey.ENGINEER); assertEquals("",af.getTag().getFirst(FieldKey.ENGINEER)); assertEquals("djmixervalue",af.getTag().getFirst(FieldKey.DJMIXER)); fields = tag.getFields(FieldKey.PRODUCER); for(TagField field:fields) { System.out.println(((TagTextField)field).getContent()); } af.commit(); af = AudioFileIO.read(testFile); tag = af.getTag(); assertEquals("",af.getTag().getFirst(FieldKey.ENGINEER)); assertEquals("djmixervalue",af.getTag().getFirst(FieldKey.DJMIXER)); tag.deleteField(FieldKey.PRODUCER); tag.deleteField(FieldKey.MIXER); tag.deleteField(FieldKey.DJMIXER); tag.deleteField(FieldKey.ARRANGER); af.commit(); af = AudioFileIO.read(testFile); tag = af.getTag(); assertEquals("",af.getTag().getFirst(FieldKey.ENGINEER)); assertEquals("",af.getTag().getFirst(FieldKey.DJMIXER)); } catch(Exception e) { e.printStackTrace(); exceptionCaught=e; } assertNull(exceptionCaught); } /** * Test writing Custom fields */ public void testWriteFieldsToMp3ID3v23() { File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); AudioFile af = AudioFileIO.read(testFile); af.setTag(new ID3v23Tag()); Tag tag = af.getTag(); tag.setField(tag.createField(FieldKey.RATING,"50")); tag.setField(tag.createField(FieldKey.MIXER,"mixer")); tag.setField(tag.createField(FieldKey.ENGINEER,"engineervalue")); tag.setField(tag.createField(FieldKey.DJMIXER,"djmixervalue")); tag.setField(tag.createField(FieldKey.PRODUCER,"producervalue")); tag.setField(tag.createField(FieldKey.ARRANGER,"arrangervalue")); assertEquals("50",af.getTag().getFirst(FieldKey.RATING)); assertEquals("mixer",af.getTag().getFirst(FieldKey.MIXER)); assertEquals("engineervalue",af.getTag().getFirst(FieldKey.ENGINEER)); assertEquals("djmixervalue",af.getTag().getFirst(FieldKey.DJMIXER)); assertEquals("producervalue",af.getTag().getFirst(FieldKey.PRODUCER)); assertEquals("arrangervalue",af.getTag().getFirst(FieldKey.ARRANGER)); af.commit(); af = AudioFileIO.read(testFile); tag = af.getTag(); assertEquals("50",tag.getFirst(FieldKey.RATING)); assertEquals("mixer",tag.getFirst(FieldKey.MIXER)); assertEquals("engineervalue",tag.getFirst(FieldKey.ENGINEER)); assertEquals("djmixervalue",tag.getFirst(FieldKey.DJMIXER)); assertEquals("producervalue",tag.getFirst(FieldKey.PRODUCER)); assertEquals("arrangervalue",tag.getFirst(FieldKey.ARRANGER)); List fields = tag.getFields(FieldKey.PRODUCER); for(TagField field:fields) { System.out.println(((TagTextField)field).getContent()); } tag.deleteField(FieldKey.ARRANGER); assertEquals(0,tag.getFields(FieldKey.ARRANGER).size()); assertEquals("",tag.getFirst(FieldKey.ARRANGER)); assertEquals("djmixervalue",tag.getFirst(FieldKey.DJMIXER)); fields = tag.getFields(FieldKey.PRODUCER); for(TagField field:fields) { System.out.println(((TagTextField)field).getContent()); } af.commit(); af = AudioFileIO.read(testFile); tag = af.getTag(); assertEquals("",af.getTag().getFirst(FieldKey.ARRANGER)); assertEquals("djmixervalue",af.getTag().getFirst(FieldKey.DJMIXER)); tag.deleteField(FieldKey.ENGINEER); tag.deleteField(FieldKey.PRODUCER); tag.deleteField(FieldKey.MIXER); tag.deleteField(FieldKey.DJMIXER); tag.deleteField(FieldKey.ARRANGER); af.commit(); af = AudioFileIO.read(testFile); tag = af.getTag(); assertEquals("",af.getTag().getFirst(FieldKey.ENGINEER)); assertEquals("",af.getTag().getFirst(FieldKey.DJMIXER)); } catch(Exception e) { e.printStackTrace(); exceptionCaught=e; } assertNull(exceptionCaught); } /** * Test writing Custom fields to Mp3 ID3v23 */ public void testWriteFieldsToMp3ID3v22() { File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); //Read File okay AudioFile af = AudioFileIO.read(testFile); af.setTag(new ID3v22Tag()); Tag tag = af.getTag(); tag.setField(tag.createField(FieldKey.RATING,"50")); tag.setField(tag.createField(FieldKey.MIXER,"mixer")); tag.setField(tag.createField(FieldKey.ENGINEER,"engineervalue")); tag.setField(tag.createField(FieldKey.DJMIXER,"djmixervalue")); tag.setField(tag.createField(FieldKey.PRODUCER,"producervalue")); tag.setField(tag.createField(FieldKey.ARRANGER,"arrangervalue")); assertEquals("50",af.getTag().getFirst(FieldKey.RATING)); assertEquals("mixer",af.getTag().getFirst(FieldKey.MIXER)); assertEquals("engineervalue",af.getTag().getFirst(FieldKey.ENGINEER)); assertEquals("djmixervalue",af.getTag().getFirst(FieldKey.DJMIXER)); assertEquals("producervalue",af.getTag().getFirst(FieldKey.PRODUCER)); assertEquals("arrangervalue",af.getTag().getFirst(FieldKey.ARRANGER)); af.commit(); af = AudioFileIO.read(testFile); tag=af.getTag(); assertEquals("50",tag.getFirst(FieldKey.RATING)); assertEquals("mixer",tag.getFirst(FieldKey.MIXER)); assertEquals("engineervalue",tag.getFirst(FieldKey.ENGINEER)); assertEquals("djmixervalue",tag.getFirst(FieldKey.DJMIXER)); assertEquals("producervalue",tag.getFirst(FieldKey.PRODUCER)); assertEquals("arrangervalue",tag.getFirst(FieldKey.ARRANGER)); List fields = tag.getFields(FieldKey.PRODUCER); for(TagField field:fields) { System.out.println(((TagTextField)field).getContent()); } tag.deleteField(FieldKey.ENGINEER); for(TagField field:fields) { System.out.println(((TagTextField)field).getContent()); } assertEquals(0,tag.getFields(FieldKey.ENGINEER).size()); assertEquals("",tag.getFirst(FieldKey.ENGINEER)); assertEquals("djmixervalue",tag.getFirst(FieldKey.DJMIXER)); fields = tag.getFields(FieldKey.PRODUCER); for(TagField field:fields) { System.out.println(((TagTextField)field).getContent()); } af.commit(); af = AudioFileIO.read(testFile); tag = af.getTag(); assertEquals("",tag.getFirst(FieldKey.ENGINEER)); assertEquals("djmixervalue",af.getTag().getFirst(FieldKey.DJMIXER)); tag.deleteField(FieldKey.PRODUCER); tag.deleteField(FieldKey.MIXER); tag.deleteField(FieldKey.DJMIXER); tag.deleteField(FieldKey.ARRANGER); af.commit(); af = AudioFileIO.read(testFile); tag = af.getTag(); assertEquals("",tag.getFirst(FieldKey.ENGINEER)); assertEquals("",tag.getFirst(FieldKey.DJMIXER)); } catch(Exception e) { e.printStackTrace(); exceptionCaught=e; } assertNull(exceptionCaught); } /** * Test writing Custom fields to Ogg Vorbis */ public void testWriteFieldsToOggVorbis() { File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("test.ogg"); //Read File okay AudioFile af = AudioFileIO.read(testFile); Tag tag = af.getTag(); tag.setField(tag.createField(FieldKey.RATING,"50")); tag.setField(tag.createField(FieldKey.MIXER,"mixer")); tag.setField(tag.createField(FieldKey.ENGINEER,"engineervalue")); tag.setField(tag.createField(FieldKey.DJMIXER,"djmixervalue")); tag.setField(tag.createField(FieldKey.PRODUCER,"producervalue")); tag.setField(tag.createField(FieldKey.ARRANGER,"arrangervalue")); assertEquals("50",af.getTag().getFirst(FieldKey.RATING)); assertEquals("mixer",af.getTag().getFirst(FieldKey.MIXER)); assertEquals("engineervalue",af.getTag().getFirst(FieldKey.ENGINEER)); assertEquals("djmixervalue",af.getTag().getFirst(FieldKey.DJMIXER)); assertEquals("producervalue",af.getTag().getFirst(FieldKey.PRODUCER)); assertEquals("arrangervalue",af.getTag().getFirst(FieldKey.ARRANGER)); af.commit(); af = AudioFileIO.read(testFile); assertEquals("50",af.getTag().getFirst(FieldKey.RATING)); assertEquals("mixer",af.getTag().getFirst(FieldKey.MIXER)); assertEquals("engineervalue",af.getTag().getFirst(FieldKey.ENGINEER)); assertEquals("djmixervalue",af.getTag().getFirst(FieldKey.DJMIXER)); assertEquals("producervalue",af.getTag().getFirst(FieldKey.PRODUCER)); assertEquals("arrangervalue",af.getTag().getFirst(FieldKey.ARRANGER)); } catch(Exception e) { e.printStackTrace(); exceptionCaught=e; } assertNull(exceptionCaught); } /** * Test writing Custom fields to Flac */ public void testWriteFieldsToFlac() { File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("test.flac"); //Read File okay AudioFile af = AudioFileIO.read(testFile); Tag tag = af.getTag(); tag.setField(tag.createField(FieldKey.RATING,"50")); tag.setField(tag.createField(FieldKey.MIXER,"mixer")); tag.setField(tag.createField(FieldKey.ENGINEER,"engineervalue")); tag.setField(tag.createField(FieldKey.DJMIXER,"djmixervalue")); tag.setField(tag.createField(FieldKey.PRODUCER,"producervalue")); tag.setField(tag.createField(FieldKey.ARRANGER,"arrangervalue")); assertEquals("50",af.getTag().getFirst(FieldKey.RATING)); assertEquals("mixer",af.getTag().getFirst(FieldKey.MIXER)); assertEquals("engineervalue",af.getTag().getFirst(FieldKey.ENGINEER)); assertEquals("djmixervalue",af.getTag().getFirst(FieldKey.DJMIXER)); assertEquals("producervalue",af.getTag().getFirst(FieldKey.PRODUCER)); assertEquals("arrangervalue",af.getTag().getFirst(FieldKey.ARRANGER)); af.commit(); af = AudioFileIO.read(testFile); assertEquals("50",af.getTag().getFirst(FieldKey.RATING)); assertEquals("mixer",af.getTag().getFirst(FieldKey.MIXER)); assertEquals("engineervalue",af.getTag().getFirst(FieldKey.ENGINEER)); assertEquals("djmixervalue",af.getTag().getFirst(FieldKey.DJMIXER)); assertEquals("producervalue",af.getTag().getFirst(FieldKey.PRODUCER)); assertEquals("arrangervalue",af.getTag().getFirst(FieldKey.ARRANGER)); } catch(Exception e) { e.printStackTrace(); exceptionCaught=e; } assertNull(exceptionCaught); } /** * Test writing Custom fields to Wma */ public void testWriteFieldsToWma() { File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("test1.wma"); //Read File okay AudioFile af = AudioFileIO.read(testFile); Tag tag = af.getTag(); tag.setField(tag.createField(FieldKey.RATING,"50")); tag.setField(tag.createField(FieldKey.MIXER,"mixer")); tag.setField(tag.createField(FieldKey.ENGINEER,"engineervalue")); tag.setField(tag.createField(FieldKey.DJMIXER,"djmixervalue")); tag.setField(tag.createField(FieldKey.PRODUCER,"producervalue")); tag.setField(tag.createField(FieldKey.ARRANGER,"arrangervalue")); assertEquals("50",af.getTag().getFirst(FieldKey.RATING)); assertEquals("mixer",af.getTag().getFirst(FieldKey.MIXER)); assertEquals("engineervalue",af.getTag().getFirst(FieldKey.ENGINEER)); assertEquals("djmixervalue",af.getTag().getFirst(FieldKey.DJMIXER)); assertEquals("producervalue",af.getTag().getFirst(FieldKey.PRODUCER)); assertEquals("arrangervalue",af.getTag().getFirst(FieldKey.ARRANGER)); af.commit(); af = AudioFileIO.read(testFile); assertEquals("50",af.getTag().getFirst(FieldKey.RATING)); assertEquals("mixer",af.getTag().getFirst(FieldKey.MIXER)); assertEquals("engineervalue",af.getTag().getFirst(FieldKey.ENGINEER)); assertEquals("djmixervalue",af.getTag().getFirst(FieldKey.DJMIXER)); assertEquals("producervalue",af.getTag().getFirst(FieldKey.PRODUCER)); assertEquals("arrangervalue",af.getTag().getFirst(FieldKey.ARRANGER)); } catch(Exception e) { e.printStackTrace(); exceptionCaught=e; } assertNull(exceptionCaught); } /** * Test writing Custom fields to Mp4 */ public void testWriteFieldsToMp4() { File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("test.m4a"); //Read File okay AudioFile af = AudioFileIO.read(testFile); Tag tag = af.getTag(); tag.setField(tag.createField(FieldKey.RATING,"50")); tag.setField(tag.createField(FieldKey.MIXER,"mixer")); tag.setField(tag.createField(FieldKey.ENGINEER,"engineervalue")); tag.setField(tag.createField(FieldKey.DJMIXER,"djmixervalue")); tag.setField(tag.createField(FieldKey.PRODUCER,"producervalue")); tag.setField(tag.createField(FieldKey.ARRANGER,"arrangervalue")); assertEquals("50",af.getTag().getFirst(FieldKey.RATING)); assertEquals("mixer",af.getTag().getFirst(FieldKey.MIXER)); assertEquals("engineervalue",af.getTag().getFirst(FieldKey.ENGINEER)); assertEquals("djmixervalue",af.getTag().getFirst(FieldKey.DJMIXER)); assertEquals("producervalue",af.getTag().getFirst(FieldKey.PRODUCER)); assertEquals("arrangervalue",af.getTag().getFirst(FieldKey.ARRANGER)); af.commit(); af = AudioFileIO.read(testFile); assertEquals("50",af.getTag().getFirst(FieldKey.RATING)); assertEquals("mixer",af.getTag().getFirst(FieldKey.MIXER)); assertEquals("engineervalue",af.getTag().getFirst(FieldKey.ENGINEER)); assertEquals("djmixervalue",af.getTag().getFirst(FieldKey.DJMIXER)); assertEquals("producervalue",af.getTag().getFirst(FieldKey.PRODUCER)); assertEquals("arrangervalue",af.getTag().getFirst(FieldKey.ARRANGER)); } catch(Exception e) { e.printStackTrace(); exceptionCaught=e; } assertNull(exceptionCaught); } }libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/issues/Issue245Test.java0000644000175000017500000004272711470746136026774 0ustar drazzibdrazzibpackage org.jaudiotagger.issues; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.tag.asf.AsfTagCoverField; import org.jaudiotagger.tag.FieldKey; import org.jaudiotagger.tag.Tag; import org.jaudiotagger.tag.datatype.Artwork; import org.jaudiotagger.tag.id3.ID3v22Tag; import org.jaudiotagger.tag.id3.ID3v24Tag; import org.jaudiotagger.tag.id3.valuepair.ImageFormats; import java.io.File; /** * Support For Common Interface for reading and writing coverart */ public class Issue245Test extends AbstractTestCase { /** * Test writing Artwork to Mp3 ID3v24 */ public void testWriteArtworkFieldsToMp3ID3v24() { File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); //Read File okay AudioFile af = AudioFileIO.read(testFile); af.setTag(new ID3v24Tag()); Tag tag = af.getTag(); assertEquals(0, tag.getArtworkList().size()); //Now addField the image Artwork newartwork = Artwork.createArtworkFromFile(new File("testdata", "coverart.png")); assertTrue(ImageFormats.isPortableFormat(newartwork.getBinaryData())); newartwork.setPictureType(5); tag.setField(newartwork); af.commit(); af = AudioFileIO.read(testFile); tag = af.getTag(); assertEquals(1, tag.getArtworkList().size()); assertTrue(tag.getArtworkList().get(0) instanceof Artwork); Artwork artwork = tag.getFirstArtwork(); assertEquals("image/png", artwork.getMimeType()); assertNotNull(artwork.getImage()); assertEquals(200, artwork.getImage().getWidth()); assertEquals(5,artwork.getPictureType()); tag.deleteArtworkField(); assertEquals(0, tag.getArtworkList().size()); af.commit(); af = AudioFileIO.read(testFile); tag = af.getTag(); assertEquals(0, tag.getArtworkList().size()); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * Test writing Artwork to Mp3 ID3v23 */ public void testWriteArtworkFieldsToMp3ID3v23() { File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); //Read File okay AudioFile af = AudioFileIO.read(testFile); af.getTagOrCreateAndSetDefault(); Tag tag = af.getTag(); assertEquals(0, tag.getArtworkList().size()); //Now addField the image Artwork newartwork = Artwork.createArtworkFromFile(new File("testdata", "coverart.png")); assertTrue(ImageFormats.isPortableFormat(newartwork.getBinaryData())); newartwork.setPictureType(11); tag.setField(newartwork); af.commit(); af = AudioFileIO.read(testFile); tag = af.getTag(); assertEquals(1, tag.getArtworkList().size()); assertTrue(tag.getArtworkList().get(0) instanceof Artwork); Artwork artwork = tag.getFirstArtwork(); assertEquals("image/png", artwork.getMimeType()); assertNotNull(artwork.getImage()); assertEquals(200, artwork.getImage().getWidth()); assertEquals(11,artwork.getPictureType()); tag.deleteArtworkField(); assertEquals(0, tag.getArtworkList().size()); af.commit(); af = AudioFileIO.read(testFile); tag = af.getTag(); assertEquals(0, tag.getArtworkList().size()); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * Test writing Artwork to Mp3 ID3v22 */ public void testWriteArtworkFieldsToMp3ID3v22() { File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); //Read File okay AudioFile af = AudioFileIO.read(testFile); af.setTag(new ID3v22Tag()); Tag tag = af.getTag(); assertEquals(0, tag.getArtworkList().size()); //Now addField the image Artwork newartwork = Artwork.createArtworkFromFile(new File("testdata", "coverart.png")); assertTrue(ImageFormats.isPortableFormat(newartwork.getBinaryData())); newartwork.setPictureType(5); tag.setField(newartwork); af.commit(); af = AudioFileIO.read(testFile); tag = af.getTag(); assertEquals(1, tag.getArtworkList().size()); assertTrue(tag.getArtworkList().get(0) instanceof Artwork); Artwork artwork = tag.getFirstArtwork(); assertEquals("image/png", artwork.getMimeType()); assertNotNull(artwork.getImage()); assertEquals(200, artwork.getImage().getWidth()); assertEquals(5,artwork.getPictureType()); tag.deleteArtworkField(); assertEquals(0, tag.getArtworkList().size()); af.commit(); af = AudioFileIO.read(testFile); tag = af.getTag(); assertEquals(0, tag.getArtworkList().size()); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * Test reading/writing artwork to Ogg */ public void testReadWriteArtworkFieldsToOggVorbis() { File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("test3.ogg"); //Read File okay AudioFile af = AudioFileIO.read(testFile); Tag tag = af.getTag(); assertEquals(1, tag.getArtworkList().size()); assertTrue(tag.getArtworkList().get(0) instanceof Artwork); Artwork artwork = tag.getFirstArtwork(); assertEquals("image/png", artwork.getMimeType()); assertNotNull(artwork.getImage()); assertEquals(200, artwork.getImage().getWidth()); //Now replace the image Artwork newartwork = Artwork.createArtworkFromFile(new File("testdata", "coverart.png")); assertTrue(ImageFormats.isPortableFormat(newartwork.getBinaryData())); tag.setField(newartwork); af.commit(); af = AudioFileIO.read(testFile); tag = af.getTag(); assertEquals(1, tag.getArtworkList().size()); assertTrue(tag.getArtworkList().get(0) instanceof Artwork); artwork = tag.getFirstArtwork(); assertEquals("image/png", artwork.getMimeType()); assertNotNull(artwork.getImage()); assertEquals(200, artwork.getImage().getWidth()); tag.deleteArtworkField(); assertEquals(0, tag.getArtworkList().size()); af.commit(); af = AudioFileIO.read(testFile); tag = af.getTag(); assertEquals(0, tag.getArtworkList().size()); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * Test reading/writing artwork to Flac */ public void testReadWriteArtworkFieldsToFlac() { File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("test.flac",new File("testwriteartwork.flac")); //Read File okay AudioFile af = AudioFileIO.read(testFile); Tag tag = af.getTag(); assertEquals(2, tag.getArtworkList().size()); assertTrue(tag.getArtworkList().get(0) instanceof Artwork); Artwork artwork = tag.getFirstArtwork(); assertEquals("image/png", artwork.getMimeType()); assertNotNull(artwork.getImage()); assertEquals(200, artwork.getImage().getWidth()); assertEquals(3,artwork.getPictureType()); //Now replace the image Artwork newartwork = Artwork.createArtworkFromFile(new File("testdata", "coverart.png")); assertTrue(ImageFormats.isPortableFormat(newartwork.getBinaryData())); newartwork.setDescription("freddy"); newartwork.setPictureType(7); tag.setField(newartwork); af.commit(); af = AudioFileIO.read(testFile); tag = af.getTag(); assertEquals(2, tag.getArtworkList().size()); assertTrue(tag.getArtworkList().get(0) instanceof Artwork); artwork = tag.getFirstArtwork(); assertEquals("image/png", artwork.getMimeType()); assertNotNull(artwork.getImage()); assertEquals(200, artwork.getImage().getWidth()); assertEquals(7,artwork.getPictureType()); tag.deleteArtworkField(); assertEquals(0, tag.getArtworkList().size()); af.commit(); af = AudioFileIO.read(testFile); tag = af.getTag(); assertEquals(0, tag.getArtworkList().size()); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * Test reading/writing artwork to Wma */ public void testReadWriteArtworkFieldsToWma() { File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("test5.wma"); //Read File okay AudioFile af = AudioFileIO.read(testFile); Tag tag = af.getTag(); assertEquals(1, tag.getArtworkList().size()); assertTrue(tag.getArtworkList().get(0) instanceof Artwork); Artwork artwork = tag.getFirstArtwork(); assertEquals("image/png", artwork.getMimeType()); assertNotNull(artwork.getImage()); assertEquals(200, artwork.getImage().getWidth()); assertEquals(3,artwork.getPictureType()); //Now replace the image Artwork newartwork = Artwork.createArtworkFromFile(new File("testdata", "coverart.png")); assertTrue(ImageFormats.isPortableFormat(newartwork.getBinaryData())); newartwork.setDescription("freddy"); newartwork.setPictureType(8); tag.setField(newartwork); af.commit(); af = AudioFileIO.read(testFile); tag = af.getTag(); assertTrue(tag.getFirstField(FieldKey.COVER_ART) instanceof AsfTagCoverField); assertEquals(1, tag.getArtworkList().size()); assertTrue(tag.getArtworkList().get(0) instanceof Artwork); artwork = tag.getFirstArtwork(); assertEquals("image/png", artwork.getMimeType()); assertNotNull(artwork.getImage()); assertEquals(200, artwork.getImage().getWidth()); assertEquals(8,artwork.getPictureType()); tag.deleteArtworkField(); assertEquals(0, tag.getArtworkList().size()); af.commit(); af = AudioFileIO.read(testFile); tag = af.getTag(); assertEquals(0, tag.getArtworkList().size()); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * Test reading/writing artwork to Mp4 */ public void testReadWriteArtworkFieldsToMp4() { File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("test.m4a"); //Read File okay AudioFile af = AudioFileIO.read(testFile); Tag tag = af.getTag(); assertEquals(1, tag.getArtworkList().size()); assertTrue(tag.getArtworkList().get(0) instanceof Artwork); Artwork artwork = tag.getFirstArtwork(); assertEquals("image/jpeg", artwork.getMimeType()); assertNotNull(artwork.getImage()); assertEquals(159, artwork.getImage().getWidth()); //Now replace the image Artwork newartwork = Artwork.createArtworkFromFile(new File("testdata", "coverart.png")); assertTrue(ImageFormats.isPortableFormat(newartwork.getBinaryData())); tag.setField(newartwork); af.commit(); af = AudioFileIO.read(testFile); tag = af.getTag(); assertEquals(1, tag.getArtworkList().size()); assertTrue(tag.getArtworkList().get(0) instanceof Artwork); artwork = tag.getFirstArtwork(); assertEquals("image/png", artwork.getMimeType()); assertNotNull(artwork.getImage()); assertEquals(200, artwork.getImage().getWidth()); tag.deleteArtworkField(); assertEquals(0, tag.getArtworkList().size()); af.commit(); af = AudioFileIO.read(testFile); tag = af.getTag(); assertEquals(0, tag.getArtworkList().size()); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * Test Artwork cannot be written to Wav */ public void testReadWriteArtworkFieldsToWav() { File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("test.wav"); //Read File okay AudioFile af = AudioFileIO.read(testFile); Tag tag = af.getTag(); assertEquals(0, tag.getArtworkList().size()); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); try { //Now try and addField image AudioFile af = AudioFileIO.read(testFile); Artwork newartwork = Artwork.createArtworkFromFile(new File("testdata", "coverart.png")); assertTrue(ImageFormats.isPortableFormat(newartwork.getBinaryData())); Tag tag = af.getTag(); tag.setField(newartwork); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNotNull(exceptionCaught); assertTrue(exceptionCaught instanceof UnsupportedOperationException); //Not Supported try { //Now try and addField image AudioFile af = AudioFileIO.read(testFile); Tag tag = af.getTag(); tag.deleteArtworkField(); assertEquals(0, tag.getArtworkList().size()); af.commit(); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNotNull(exceptionCaught); assertTrue(exceptionCaught instanceof UnsupportedOperationException); } /** * Test Artwork cannot be written to Real */ public void testReadWriteArtworkFieldsToReal() { File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("test01.ra"); //Read File okay AudioFile af = AudioFileIO.read(testFile); Tag tag = af.getTag(); assertEquals(0, tag.getArtworkList().size()); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); try { //Now try and addField image AudioFile af = AudioFileIO.read(testFile); Artwork newartwork = Artwork.createArtworkFromFile(new File("testdata", "coverart.png")); assertTrue(ImageFormats.isPortableFormat(newartwork.getBinaryData())); Tag tag = af.getTag(); tag.setField(newartwork); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNotNull(exceptionCaught); assertTrue(exceptionCaught instanceof UnsupportedOperationException); //Not supported try { AudioFile af = AudioFileIO.read(testFile); Tag tag = af.getTag(); tag.deleteArtworkField(); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNotNull(exceptionCaught); assertTrue(exceptionCaught instanceof UnsupportedOperationException); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/issues/Issue258Test.java0000644000175000017500000000411111276777123026765 0ustar drazzibdrazzibpackage org.jaudiotagger.issues; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.tag.FieldKey; import org.jaudiotagger.tag.Tag; import java.io.File; /** * Test Creating Temp file when filename < 3 */ public class Issue258Test extends AbstractTestCase { /** * Test write of mp3 with very short filename */ public void testWriteToShortMp3File() { File orig = new File("testdata", "01.mp3"); if (!orig.isFile()) { System.err.println("Unable to test file - not available"); return; } File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("01.mp3"); //Read File, and write tag cause padding to be adjusted and temp file created AudioFile af = AudioFileIO.read(testFile); Tag t = af.getTagOrCreateAndSetDefault(); t.setField(FieldKey.ARTIST,"fred"); af.commit(); } catch(Exception e) { e.printStackTrace(); exceptionCaught=e; } assertNull(exceptionCaught); } /** * Test write to mp4 with very short file name */ public void testWriteToShortMp4File() { File orig = new File("testdata", "01.m4a"); if (!orig.isFile()) { System.err.println("Unable to test file - not available"); return; } File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("01.m4a"); //Read File AudioFile af = AudioFileIO.read(testFile); Tag t = af.getTagOrCreateAndSetDefault(); t.setField(FieldKey.ARTIST,"fred"); af.commit(); } catch(Exception e) { e.printStackTrace(); exceptionCaught=e; } assertNull(exceptionCaught); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/issues/Issue239Test.java0000644000175000017500000000403511276777123026771 0ustar drazzibdrazzibpackage org.jaudiotagger.issues; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.audio.mp3.MP3File; import org.jaudiotagger.tag.FieldKey; import org.jaudiotagger.tag.id3.ID3v23Tag; import java.io.File; /** * Test Deleteing comments with common interface */ public class Issue239Test extends AbstractTestCase { /** * Test Deleting Comments */ public void testDeletingCOMMFrames() { Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); //Add a v24Tag AudioFile af = AudioFileIO.read(testFile); MP3File mp3File= (MP3File)af; mp3File.setID3v2Tag(new ID3v23Tag()); mp3File.save(); mp3File = new MP3File(testFile); af = AudioFileIO.read(testFile); mp3File= (MP3File)af; //Check mapped okay ands empty assertEquals(0,mp3File.getTag().getFields(FieldKey.COMMENT).size()); //Now write these fields mp3File.getTag().setField(mp3File.getTag().createField(FieldKey.COMMENT,"comment1")); mp3File.getTag().addField(mp3File.getTag().createField(FieldKey.COMMENT,"comment2")); mp3File.save(); af = AudioFileIO.read(testFile); mp3File= (MP3File)af; //Check mapped okay ands empty assertTrue(mp3File.getTag() instanceof ID3v23Tag); assertEquals(2,mp3File.getTag().getFields(FieldKey.COMMENT).size()); //Delete Fields mp3File.getTag().deleteField(FieldKey.COMMENT); mp3File.save(); af = AudioFileIO.read(testFile); mp3File= (MP3File)af; assertEquals(0,mp3File.getTag().getFields(FieldKey.COMMENT).size()); } catch (Exception e) { exceptionCaught = e; e.printStackTrace(); } assertNull(exceptionCaught); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/issues/Issue292Test.java0000644000175000017500000000652511276777123026776 0ustar drazzibdrazzibpackage org.jaudiotagger.issues; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.tag.FieldKey; import java.io.File; /** * Unable to save changes to file if backup .old file already exists */ public class Issue292Test extends AbstractTestCase { public void testSavingMp3File() { File testFile = AbstractTestCase.copyAudioToTmp("testV1Cbr128ID3v2.mp3"); if (!testFile.isFile()) { System.err.println("Unable to test file - not available"); return; } File originalFileBackup = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("testV1Cbr128ID3v2.mp3"); //Put file in backup location originalFileBackup = new File(testFile.getAbsoluteFile().getParentFile().getPath(), AudioFile.getBaseFilename(testFile)+ ".old"); testFile.renameTo(originalFileBackup); //Copy over again testFile = AbstractTestCase.copyAudioToTmp("testV1Cbr128ID3v2.mp3"); //Read and save chnages AudioFile af = AudioFileIO.read(testFile); af.getTag().setField(af.getTag().createField(FieldKey.ARTIST,"fredqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq")); af.getTag().setField(af.getTag().createField(FieldKey.AMAZON_ID,"fredqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq")); af.commit(); af = AudioFileIO.read(testFile); assertEquals("fredqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq",af.getTag().getFirst(FieldKey.ARTIST)); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } finally { originalFileBackup.delete(); } assertNull(exceptionCaught); } public void testSavingMp4File() { File testFile = AbstractTestCase.copyAudioToTmp("test8.m4a"); if (!testFile.isFile()) { System.err.println("Unable to test file - not available"); return; } File originalFileBackup = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("test8.m4a"); //Put file in backup location originalFileBackup = new File(testFile.getAbsoluteFile().getParentFile().getPath(), AudioFile.getBaseFilename(testFile)+ ".old"); testFile.renameTo(originalFileBackup); //Copy over again testFile = AbstractTestCase.copyAudioToTmp("test8.m4a"); //Read and save chnages AudioFile af = AudioFileIO.read(testFile); af.getTag().setField(af.getTag().createField(FieldKey.ARTIST,"fredqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq")); af.getTag().setField(af.getTag().createField(FieldKey.AMAZON_ID,"fredqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq")); af.commit(); af = AudioFileIO.read(testFile); assertEquals("fredqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq",af.getTag().getFirst(FieldKey.ARTIST)); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } finally { originalFileBackup.delete(); } assertNull(exceptionCaught); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/issues/Issue320Test.java0000644000175000017500000000210211470746136026745 0ustar drazzibdrazzibpackage org.jaudiotagger.issues; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.audio.mp3.MP3File; import org.jaudiotagger.tag.FieldKey; import org.jaudiotagger.tag.Tag; import java.io.File; /** Test tag Equality (specifically PartOfSet) */ public class Issue320Test extends AbstractTestCase { /* * Test File Equality * @throws Exception */ public void testTagEquality() throws Exception { File orig = new File("testdata", "test26.mp3"); if (!orig.isFile()) { System.err.println("Unable to test file - not available"); return; } File file1 = new File("testdata", "test26.mp3"); File file2 = new File("testdata", "test26.mp3"); MP3File audioFile1 = (MP3File)AudioFileIO.read(file1); Tag tag1 = audioFile1.getTag(); MP3File audioFile2 = (MP3File)AudioFileIO.read(file2); Tag tag2 = audioFile2.getTag(); assertTrue(tag1.equals(tag2)); } }libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/issues/Issue241Test.java0000644000175000017500000002757311276777123026776 0ustar drazzibdrazzibpackage org.jaudiotagger.issues; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.tag.FieldKey; import org.jaudiotagger.tag.Tag; import org.jaudiotagger.tag.TagField; import org.jaudiotagger.tag.id3.ID3v22Tag; import org.jaudiotagger.tag.id3.ID3v24FieldKey; import org.jaudiotagger.tag.id3.ID3v24Frame; import org.jaudiotagger.tag.id3.ID3v24Tag; import org.jaudiotagger.tag.id3.framebody.FrameBodyTKEY; import org.jaudiotagger.tag.id3.framebody.FrameBodyTLAN; import org.jaudiotagger.tag.reference.Languages; import org.jaudiotagger.tag.reference.MusicalKey; import java.io.File; /** * Support For LANGUAGE and INITIAL_KEY */ public class Issue241Test extends AbstractTestCase { /** * Test writing INITIAL_KEY and LANGUAGE to Mp3 ID3v23 */ public void testWriteFieldsToMp3ID3v24() { File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); //Read File okay AudioFile af = AudioFileIO.read(testFile); af.setTag(new ID3v24Tag()); Tag tag = af.getTag(); tag.setField(tag.createField(FieldKey.LANGUAGE,"eng")); tag.setField(tag.createField(FieldKey.KEY,"C#")); af.commit(); af = AudioFileIO.read(testFile); tag = af.getTag(); assertEquals("eng",af.getTag().getFirst(FieldKey.LANGUAGE)); assertEquals("C#",af.getTag().getFirst(FieldKey.KEY)); assertEquals("English",Languages.getInstanceOf().getValueForId(af.getTag().getFirst(FieldKey.LANGUAGE))); TagField tagField = af.getTag().getFirstField(ID3v24FieldKey.LANGUAGE.getFieldName()); assertTrue(tagField instanceof ID3v24Frame); assertTrue(((ID3v24Frame)tagField).getBody() instanceof FrameBodyTLAN); assertTrue(((FrameBodyTLAN)((ID3v24Frame)tagField).getBody()).isValid()); tagField = af.getTag().getFirstField(ID3v24FieldKey.KEY.getFieldName()); assertTrue(tagField instanceof ID3v24Frame); assertTrue(((ID3v24Frame)tagField).getBody() instanceof FrameBodyTKEY); assertTrue(((FrameBodyTKEY)((ID3v24Frame)tagField).getBody()).isValid()); tag.setField(tag.createField(FieldKey.LANGUAGE,"fred")); af.commit(); assertEquals("fred",af.getTag().getFirst(FieldKey.LANGUAGE)); tagField = af.getTag().getFirstField(ID3v24FieldKey.LANGUAGE.getFieldName()); assertTrue(tagField instanceof ID3v24Frame); assertTrue(((ID3v24Frame)tagField).getBody() instanceof FrameBodyTLAN); assertFalse(((FrameBodyTLAN)((ID3v24Frame)tagField).getBody()).isValid()); tag.setField(tag.createField(FieldKey.KEY,"keys")); af.commit(); assertEquals("keys",af.getTag().getFirst(FieldKey.KEY)); tagField = af.getTag().getFirstField(ID3v24FieldKey.KEY.getFieldName()); assertTrue(tagField instanceof ID3v24Frame); assertTrue(((ID3v24Frame)tagField).getBody() instanceof FrameBodyTKEY); assertFalse(((FrameBodyTKEY)((ID3v24Frame)tagField).getBody()).isValid()); } catch(Exception e) { e.printStackTrace(); exceptionCaught=e; } assertNull(exceptionCaught); } /** * Test writing INITIAL_KEY and LANGUAGE to Mp3 ID3v23 */ public void testWriteFieldsToMp3ID3v23() { File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); //Read File okay AudioFile af = AudioFileIO.read(testFile); af.getTagOrCreateAndSetDefault(); Tag tag = af.getTag(); tag.setField(tag.createField(FieldKey.LANGUAGE,"eng")); tag.setField(tag.createField(FieldKey.KEY,"C#")); af.commit(); af = AudioFileIO.read(testFile); assertEquals("eng",af.getTag().getFirst(FieldKey.LANGUAGE)); assertEquals("C#",af.getTag().getFirst(FieldKey.KEY)); assertEquals("English",Languages.getInstanceOf().getValueForId(af.getTag().getFirst(FieldKey.LANGUAGE))); } catch(Exception e) { e.printStackTrace(); exceptionCaught=e; } assertNull(exceptionCaught); } /** * Test writing INITIAL_KEY and LANGUAGE to Mp3 ID3v23 */ public void testWriteFieldsToMp3ID3v22() { File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); //Read File okay AudioFile af = AudioFileIO.read(testFile); af.setTag(new ID3v22Tag()); Tag tag = af.getTag(); tag.setField(tag.createField(FieldKey.LANGUAGE,"eng")); tag.setField(tag.createField(FieldKey.KEY,"C#")); af.commit(); af = AudioFileIO.read(testFile); assertEquals("eng",af.getTag().getFirst(FieldKey.LANGUAGE)); assertEquals("C#",af.getTag().getFirst(FieldKey.KEY)); assertEquals("English",Languages.getInstanceOf().getValueForId(af.getTag().getFirst(FieldKey.LANGUAGE))); } catch(Exception e) { e.printStackTrace(); exceptionCaught=e; } assertNull(exceptionCaught); } /** * Test writing INITIAL_KEY and LANGUAGE to Ogg Vorbis */ public void testWriteFieldsToOggVorbis() { File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("test.ogg"); //Read File okay AudioFile af = AudioFileIO.read(testFile); Tag tag = af.getTag(); tag.setField(tag.createField(FieldKey.LANGUAGE,"eng")); tag.setField(tag.createField(FieldKey.KEY,"C#")); af.commit(); af = AudioFileIO.read(testFile); assertEquals("eng",af.getTag().getFirst(FieldKey.LANGUAGE)); assertEquals("C#",af.getTag().getFirst(FieldKey.KEY)); assertEquals("English",Languages.getInstanceOf().getValueForId(af.getTag().getFirst(FieldKey.LANGUAGE))); } catch(Exception e) { e.printStackTrace(); exceptionCaught=e; } assertNull(exceptionCaught); } /** * Test writing INITIAL_KEY and LANGUAGE to Flac */ public void testWriteFieldsToFlac() { File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("test.flac"); //Read File okay AudioFile af = AudioFileIO.read(testFile); Tag tag = af.getTag(); tag.setField(tag.createField(FieldKey.LANGUAGE,"eng")); tag.setField(tag.createField(FieldKey.KEY,"C#")); af.commit(); af = AudioFileIO.read(testFile); assertEquals("eng",af.getTag().getFirst(FieldKey.LANGUAGE)); assertEquals("C#",af.getTag().getFirst(FieldKey.KEY)); assertEquals("English",Languages.getInstanceOf().getValueForId(af.getTag().getFirst(FieldKey.LANGUAGE))); } catch(Exception e) { e.printStackTrace(); exceptionCaught=e; } assertNull(exceptionCaught); } /** * Test writing INITIAL_KEY and LANGUAGE to Wma */ public void testWriteFieldsToWma() { File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("test1.wma"); //Read File okay AudioFile af = AudioFileIO.read(testFile); Tag tag = af.getTag(); tag.setField(tag.createField(FieldKey.LANGUAGE,"eng")); tag.setField(tag.createField(FieldKey.KEY,"C#")); af.commit(); af = AudioFileIO.read(testFile); assertEquals("eng",af.getTag().getFirst(FieldKey.LANGUAGE)); assertEquals("C#",af.getTag().getFirst(FieldKey.KEY)); assertEquals("English",Languages.getInstanceOf().getValueForId(af.getTag().getFirst(FieldKey.LANGUAGE))); } catch(Exception e) { e.printStackTrace(); exceptionCaught=e; } assertNull(exceptionCaught); } /** * Test writing INITIAL_KEY and LANGUAGE to Mp4 */ public void testWriteFieldsToMp4() { File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("test.m4a"); //Read File okay AudioFile af = AudioFileIO.read(testFile); Tag tag = af.getTag(); tag.setField(tag.createField(FieldKey.LANGUAGE,"eng")); tag.setField(tag.createField(FieldKey.KEY,"C#")); af.commit(); af = AudioFileIO.read(testFile); assertEquals("eng",af.getTag().getFirst(FieldKey.LANGUAGE)); assertEquals("C#",af.getTag().getFirst(FieldKey.KEY)); assertEquals("English",Languages.getInstanceOf().getValueForId(af.getTag().getFirst(FieldKey.LANGUAGE))); } catch(Exception e) { e.printStackTrace(); exceptionCaught=e; } assertNull(exceptionCaught); } /** * Key Validation */ public void testValidateMusicalKey() { File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); //Read File okay AudioFile af = AudioFileIO.read(testFile); af.setTag(new ID3v24Tag()); Tag tag = af.getTag(); tag.setField(tag.createField(FieldKey.KEY,"G")); assertEquals("G",af.getTag().getFirst(FieldKey.KEY)); assertTrue(MusicalKey.isValid(tag.getFirst(FieldKey.KEY))); tag.setField(tag.createField(FieldKey.KEY,"C#")); assertEquals("C#",af.getTag().getFirst(FieldKey.KEY)); assertTrue(MusicalKey.isValid(tag.getFirst(FieldKey.KEY))); tag.setField(tag.createField(FieldKey.KEY,"Cm")); assertEquals("Cm",af.getTag().getFirst(FieldKey.KEY)); assertTrue(MusicalKey.isValid(tag.getFirst(FieldKey.KEY))); tag.setField(tag.createField(FieldKey.KEY,"C#m")); assertEquals("C#m",af.getTag().getFirst(FieldKey.KEY)); assertTrue(MusicalKey.isValid(tag.getFirst(FieldKey.KEY))); tag.setField(tag.createField(FieldKey.KEY,"C")); assertEquals("C",af.getTag().getFirst(FieldKey.KEY)); assertTrue(MusicalKey.isValid(tag.getFirst(FieldKey.KEY))); tag.setField(tag.createField(FieldKey.KEY,"o")); assertEquals("o",af.getTag().getFirst(FieldKey.KEY)); assertTrue(MusicalKey.isValid(tag.getFirst(FieldKey.KEY))); tag.setField(tag.createField(FieldKey.KEY,"R#")); assertEquals("R#",af.getTag().getFirst(FieldKey.KEY)); assertFalse(MusicalKey.isValid(tag.getFirst(FieldKey.KEY))); tag.setField(tag.createField(FieldKey.KEY,"Cp")); assertEquals("Cp",af.getTag().getFirst(FieldKey.KEY)); assertFalse(MusicalKey.isValid(tag.getFirst(FieldKey.KEY))); tag.setField(tag.createField(FieldKey.KEY,"C##")); assertEquals("C##",af.getTag().getFirst(FieldKey.KEY)); assertFalse(MusicalKey.isValid(tag.getFirst(FieldKey.KEY))); } catch(Exception e) { e.printStackTrace(); exceptionCaught=e; } assertNull(exceptionCaught); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/issues/Issue308Test.java0000644000175000017500000000326511302731457026760 0ustar drazzibdrazzibpackage org.jaudiotagger.issues; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.tag.FieldKey; import org.jaudiotagger.tag.datatype.Artwork; import org.jaudiotagger.tag.id3.valuepair.ImageFormats; import java.io.File; /** * Writing to Ogg file */ public class Issue308Test extends AbstractTestCase { public static int countExceptions =0; public void testAddingLargeImageToOgg() throws Exception { File orig = new File("testdata", "test72.ogg"); if (!orig.isFile()) { System.err.println("Unable to test file - not available"); return; } Exception e=null; try { final File testFile = AbstractTestCase.copyAudioToTmp("test72.ogg"); if (!testFile.isFile()) { System.err.println("Unable to test file - not available"); return; } AudioFile af = AudioFileIO.read(testFile); Artwork artwork = new Artwork(); artwork.setFromFile(new File("testdata","coverart_large.jpg")); af.getTag().setField(artwork); af.commit(); //Reread System.out.println("Read Audio"); af = AudioFileIO.read(testFile); System.out.println("Rewrite Audio"); af.commit(); //Resave af.getTag().addField(FieldKey.TITLE,"TESTdddddddddddddddddddddddd"); af.commit(); } catch(Exception ex) { e=ex; ex.printStackTrace(); } assertNull(e); } }libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/issues/Issue269Test.java0000644000175000017500000001753011470746136026774 0ustar drazzibdrazzibpackage org.jaudiotagger.issues; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.tag.FieldKey; import org.jaudiotagger.tag.id3.AbstractID3v2Frame; import org.jaudiotagger.tag.id3.ID3v23Frame; import org.jaudiotagger.tag.id3.ID3v23Frames; import org.jaudiotagger.tag.id3.ID3v23Tag; import org.jaudiotagger.tag.id3.framebody.FrameBodyTCOP; import org.jaudiotagger.tag.id3.framebody.FrameBodyTENC; import java.io.File; /** * Test read large mp3 with extended header */ public class Issue269Test extends AbstractTestCase { /** * Test read mp3 that says it has extended header but doesnt really */ public void testReadMp3WithExtendedHeaderFlagSetButNoExtendedHeader() { File orig = new File("testdata", "test46.mp3"); if (!orig.isFile()) { System.err.println("Unable to test file - not available"); return; } File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("test46.mp3"); //Read File okay AudioFile af = AudioFileIO.read(testFile); System.out.println(af.getTag().toString()); assertEquals("00000",af.getTag().getFirst(FieldKey.BPM)); assertEquals("thievery corporation - Om Lounge",af.getTag().getFirst(FieldKey.ARTIST)); af.getTag().setField(FieldKey.ALBUM,"FRED"); af.commit(); af = AudioFileIO.read(testFile); System.out.println(af.getTag().toString()); assertEquals("FRED",af.getTag().getFirst(FieldKey.ALBUM)); } catch(Exception e) { e.printStackTrace(); exceptionCaught=e; } assertNull(exceptionCaught); } /** * Test read mp3 with extended header and crc-32 check */ public void testReadID3v23Mp3WithExtendedHeaderAndCrc() { File orig = new File("testdata", "test47.mp3"); if (!orig.isFile()) { System.err.println("Unable to test file - not available"); return; } File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("test47.mp3"); //Read File okay AudioFile af = AudioFileIO.read(testFile); System.out.println(af.getTag().toString()); assertEquals("tonight (instrumental)",af.getTag().getFirst(FieldKey.TITLE)); assertEquals("Young Gunz",af.getTag().getFirst(FieldKey.ARTIST)); ID3v23Tag id3v23Tag = (ID3v23Tag)af.getTag(); assertEquals(156497728,id3v23Tag.getCrc32()); assertEquals(0,id3v23Tag.getPaddingSize()); af.getTag().setField(FieldKey.ALBUM,"FRED"); af.commit(); af = AudioFileIO.read(testFile); System.out.println(af.getTag().toString()); assertEquals("FRED",af.getTag().getFirst(FieldKey.ALBUM)); } catch(Exception e) { e.printStackTrace(); exceptionCaught=e; } assertNull(exceptionCaught); } /** * Test read and stores encrypted frames separately, and that they are preserved when writing frame * */ public void testReadMp3WithEncryptedField() { File orig = new File("testdata", "test48.mp3"); if (!orig.isFile()) { System.err.println("Unable to test file - not available"); return; } File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("test48.mp3"); //Read File okay AudioFile af = AudioFileIO.read(testFile); System.out.println(af.getTag().toString()); assertEquals("Don't Leave Me",af.getTag().getFirst(FieldKey.TITLE)); assertEquals("All-American Rejects",af.getTag().getFirst(FieldKey.ARTIST)); ID3v23Tag id3v23Tag = (ID3v23Tag)af.getTag(); assertEquals(0,id3v23Tag.getPaddingSize()); AbstractID3v2Frame frame1 = (AbstractID3v2Frame)id3v23Tag.getFrame(ID3v23Frames.FRAME_ID_V3_COPYRIGHTINFO); assertNotNull(frame1); assertEquals("",((FrameBodyTCOP)frame1.getBody()).getText()); //This frame is marked as encrypted(Although it actually isn't) so we cant decode it we should just store it //as a special encrypted frame. ID3v23Frame frame = (ID3v23Frame)id3v23Tag.getFrame(ID3v23Frames.FRAME_ID_V3_ENCODEDBY); assertNull(frame); frame = (ID3v23Frame)id3v23Tag.getEncryptedFrame(ID3v23Frames.FRAME_ID_V3_ENCODEDBY); assertNotNull(frame); assertEquals(0x22,frame.getEncryptionMethod()); assertEquals(0,frame.getGroupIdentifier()); assertEquals(0,frame.getStatusFlags().getOriginalFlags()); //jaudiotagger converts to this because encodeby frame should be updated if the audio is changed and so //this falg should be set assertEquals(0x40,frame.getStatusFlags().getWriteFlags()); af.getTag().setField(FieldKey.ALBUM,"FRED"); af.commit(); af = AudioFileIO.read(testFile); id3v23Tag = (ID3v23Tag)af.getTag(); System.out.println(af.getTag().toString()); assertEquals("FRED",af.getTag().getFirst(FieldKey.ALBUM)); //The frame is preserved and still encrypted frame = (ID3v23Frame)id3v23Tag.getFrame(ID3v23Frames.FRAME_ID_V3_ENCODEDBY); assertNull(frame); frame = (ID3v23Frame)id3v23Tag.getEncryptedFrame(ID3v23Frames.FRAME_ID_V3_ENCODEDBY); assertNotNull(frame); //Encryption Method Preserved assertEquals(0x22,frame.getEncryptionMethod()); assertEquals(0,frame.getGroupIdentifier()); //Note fiel preservation flag now set assertEquals(0x40,frame.getStatusFlags().getOriginalFlags()); assertEquals(0x40,frame.getStatusFlags().getWriteFlags()); } catch(Exception e) { e.printStackTrace(); exceptionCaught=e; } assertNull(exceptionCaught); } /** * Test read mp3 with extended header and crc-32 check */ public void testReadID3v24Mp3WithExtendedHeaderAndCrc() { File orig = new File("testdata", "test47.mp3"); if (!orig.isFile()) { System.err.println("Unable to test file - not available"); return; } File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("test47.mp3"); //Read File okay AudioFile af = AudioFileIO.read(testFile); System.out.println(af.getTag().toString()); assertEquals("tonight (instrumental)",af.getTag().getFirst(FieldKey.TITLE)); assertEquals("Young Gunz",af.getTag().getFirst(FieldKey.ARTIST)); ID3v23Tag id3v23Tag = (ID3v23Tag)af.getTag(); assertEquals(156497728,id3v23Tag.getCrc32()); assertEquals(0,id3v23Tag.getPaddingSize()); af.getTag().setField(FieldKey.ALBUM,"FRED"); af.commit(); af = AudioFileIO.read(testFile); System.out.println(af.getTag().toString()); assertEquals("FRED",af.getTag().getFirst(FieldKey.ALBUM)); } catch(Exception e) { e.printStackTrace(); exceptionCaught=e; } assertNull(exceptionCaught); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/issues/Issue277Test.java0000644000175000017500000001054011277264361026765 0ustar drazzibdrazzibpackage org.jaudiotagger.issues; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.tag.FieldKey; import org.jaudiotagger.tag.mp4.Mp4FieldKey; import org.jaudiotagger.tag.mp4.Mp4Tag; import java.io.File; /** * Test writing booleans to mp4 */ public class Issue277Test extends AbstractTestCase { /** * Set isCompilation */ public void testSetIsCompilation() { File orig = new File("testdata", "test1.m4a"); if (!orig.isFile()) { System.err.println("Unable to test file - not available"); return; } File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("test1.m4a"); AudioFile af = AudioFileIO.read(testFile); assertEquals(0,af.getTag().getFields(FieldKey.IS_COMPILATION).size()); //Old way af.getTag().setField(af.getTag().createField(FieldKey.IS_COMPILATION,"1")); af.commit(); af = AudioFileIO.read(testFile); assertEquals(1,af.getTag().getFields(FieldKey.IS_COMPILATION).size()); assertEquals("1",af.getTag().getFirst(FieldKey.IS_COMPILATION)); } catch(Exception e) { exceptionCaught=e; } assertNull(exceptionCaught); } /** * Set isCompilation new way */ public void testSetIsCompilation2() { File orig = new File("testdata", "test1.m4a"); if (!orig.isFile()) { System.err.println("Unable to test file - not available"); return; } File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("test1.m4a"); AudioFile af = AudioFileIO.read(testFile); assertEquals(0,af.getTag().getFields(FieldKey.IS_COMPILATION).size()); //Old way af.getTag().setField(af.getTag().createField(FieldKey.IS_COMPILATION,"true")); af.commit(); af = AudioFileIO.read(testFile); assertEquals(1,af.getTag().getFields(FieldKey.IS_COMPILATION).size()); assertEquals("1",af.getTag().getFirst(FieldKey.IS_COMPILATION)); } catch(Exception e) { exceptionCaught=e; } assertNull(exceptionCaught); } /** * Set isCompilation and rating fields */ public void testSetRating() { File orig = new File("testdata", "test1.m4a"); if (!orig.isFile()) { System.err.println("Unable to test file - not available"); return; } File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("test1.m4a"); AudioFile af = AudioFileIO.read(testFile); Mp4Tag tag = (Mp4Tag)af.getTag(); assertEquals(0,tag.get(Mp4FieldKey.RATING).size()); //Old way af.getTag().setField(tag.createField(Mp4FieldKey.RATING,"1")); af.commit(); af = AudioFileIO.read(testFile); assertEquals(1,tag.get(Mp4FieldKey.RATING).size()); assertEquals("1",tag.getFirst(Mp4FieldKey.RATING)); } catch(Exception e) { exceptionCaught=e; } assertNull(exceptionCaught); } /** * Set rating is one byte but not true and false so should fail */ public void testSetRating2() { File orig = new File("testdata", "test1.m4a"); if (!orig.isFile()) { System.err.println("Unable to test file - not available"); return; } File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("test1.m4a"); AudioFile af = AudioFileIO.read(testFile); Mp4Tag tag = (Mp4Tag)af.getTag(); assertEquals(0,tag.get(Mp4FieldKey.RATING).size()); af.getTag().setField(tag.createField(Mp4FieldKey.RATING,"true")); } catch(Exception e) { exceptionCaught=e; } assertNotNull(exceptionCaught); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/issues/Issue233Test.java0000644000175000017500000000746011276777123026770 0ustar drazzibdrazzibpackage org.jaudiotagger.issues; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.audio.mp3.MP3File; import org.jaudiotagger.tag.FieldKey; import org.jaudiotagger.tag.id3.ID3v22Tag; import org.jaudiotagger.tag.id3.ID3v23Tag; import org.jaudiotagger.tag.id3.ID3v24Tag; import java.io.File; /** * Test Deleting v2 tags */ public class Issue233Test extends AbstractTestCase { public void testDeletingID3v2Tag() { Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); //No Tags MP3File mp3File = new MP3File(testFile); assertFalse(mp3File.hasID3v1Tag()); assertFalse(mp3File.hasID3v2Tag()); //Save and deleteField v24 tag mp3File.setID3v2Tag(new ID3v24Tag()); mp3File.save(); mp3File = new MP3File(testFile); assertFalse(mp3File.hasID3v1Tag()); assertTrue(mp3File.hasID3v2Tag()); mp3File.setID3v2Tag(null); mp3File.save(); mp3File = new MP3File(testFile); assertFalse(mp3File.hasID3v1Tag()); assertFalse(mp3File.hasID3v2Tag()); //Save and deleteField v23 tag mp3File.setID3v2Tag(new ID3v23Tag()); mp3File.save(); mp3File = new MP3File(testFile); assertFalse(mp3File.hasID3v1Tag()); assertTrue(mp3File.hasID3v2Tag()); mp3File.setID3v2Tag(null); mp3File.save(); mp3File = new MP3File(testFile); assertFalse(mp3File.hasID3v1Tag()); assertFalse(mp3File.hasID3v2Tag()); //Save and deleteField v22 tag mp3File.setID3v2Tag(new ID3v22Tag()); mp3File.save(); mp3File = new MP3File(testFile); assertFalse(mp3File.hasID3v1Tag()); assertTrue(mp3File.hasID3v2Tag()); mp3File.setID3v2Tag(null); mp3File.save(); mp3File = new MP3File(testFile); assertFalse(mp3File.hasID3v1Tag()); assertFalse(mp3File.hasID3v2Tag()); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); } public void testDeletingID3v1Tag() { File orig = new File("testdata", "test32.mp3"); if (!orig.isFile()) { return; } Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test32.mp3"); AudioFile af = AudioFileIO.read(testFile); AudioFileIO.delete(af); } catch (Exception e) { exceptionCaught = e; e.printStackTrace(); } assertNull(exceptionCaught); } public void testReadingID3v1Tag() { File orig = new File("testdata", "test32.mp3"); if (!orig.isFile()) { return; } Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test32.mp3"); AudioFile af = AudioFileIO.read(testFile); MP3File mf = (MP3File)af; assertEquals("The Ides Of March",af.getTag().getFirst(FieldKey.TITLE)); assertEquals("Iron Maiden",mf.getID3v1Tag().getFirst(FieldKey.ARTIST)); assertEquals("",mf.getID3v2Tag().getFirst(FieldKey.ARTIST)); assertEquals("",af.getTag().getFirst(FieldKey.ARTIST)); } catch (Exception e) { exceptionCaught = e; e.printStackTrace(); } assertNull(exceptionCaught); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/issues/Issue327Test.java0000644000175000017500000000541311470746136026764 0ustar drazzibdrazzibpackage org.jaudiotagger.issues; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.audio.mp3.MP3File; import org.jaudiotagger.tag.FieldKey; import org.jaudiotagger.tag.TagField; import org.jaudiotagger.tag.id3.AbstractID3v2Frame; import org.jaudiotagger.tag.id3.ID3v11Tag; import org.jaudiotagger.tag.id3.ID3v23Tag; import org.jaudiotagger.tag.id3.ID3v24Tag; import java.io.File; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; /** * Test when write multiple strings using UTF16 with BOM that it writes the BOM * for all strings not just the first one */ public class Issue327Test extends AbstractTestCase { public void testUTF16BOMMultipleFieldSepertaors() throws Exception { File testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); MP3File f = (MP3File)AudioFileIO.read(testFile); f.setID3v2Tag(new ID3v23Tag()); f.getID3v2Tag().addField(FieldKey.MOOD,"For Checking End"); f.getID3v2Tag().addField(FieldKey.ALBUM_ARTIST,"Ϟ"); f.getID3v2Tag().addField(FieldKey.ALBUM_ARTIST,"Ϟ"); f.commit(); ByteBuffer bb = ByteBuffer.allocate(40); FileChannel fc = new RandomAccessFile(testFile,"r").getChannel(); fc.read(bb); assertEquals('T',bb.get(10) & 0xFF); assertEquals('P',bb.get(11) & 0xFF); assertEquals('E',bb.get(12) & 0xFF); assertEquals('2',bb.get(13) & 0xFF); //BOM for first String assertEquals(0xFF,bb.get(21) & 0xFF); assertEquals(0xFE,bb.get(22) & 0xFF); //First String char assertEquals(0xDE,bb.get(23) & 0xFF); assertEquals(0x03,bb.get(24) & 0xFF); //Null Separator (2 bytes because of encoding assertEquals(0x00,bb.get(25) & 0xFF); assertEquals(0x00,bb.get(26) & 0xFF); //BOM for second String assertEquals(0xFF,bb.get(27) & 0xFF); assertEquals(0xFE,bb.get(28) & 0xFF); //Second String char assertEquals(0xDE,bb.get(29) & 0xFF); assertEquals(0x03,bb.get(30) & 0xFF); //Next Frame assertEquals(0x54,bb.get(31) & 0xFF); assertEquals(0x58,bb.get(32) & 0xFF); assertEquals(0x58,bb.get(33) & 0xFF); assertEquals(0x58,bb.get(34) & 0xFF); fc.close(); //What does jaudiotagger read the values back as f = (MP3File)AudioFileIO.read(testFile); assertEquals("Ϟ\u0000Ϟ",f.getTag().getFirst(FieldKey.ALBUM_ARTIST)); assertEquals("*Ϟ*","*"+f.getTag().getSubValue(FieldKey.ALBUM_ARTIST,0,0)+"*"); assertEquals("*Ϟ*","*"+f.getTag().getSubValue(FieldKey.ALBUM_ARTIST,0,1)+"*"); } }libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/issues/Issue282Test.java0000644000175000017500000000556711302731457026770 0ustar drazzibdrazzibpackage org.jaudiotagger.issues; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.tag.datatype.Artwork; import org.jaudiotagger.tag.id3.valuepair.ImageFormats; import java.io.File; /** * Problem when relative filename has been specified */ public class Issue282Test extends AbstractTestCase { public void testWriteToRelativeWmaFile() { File orig = new File("testdata", "test1.wma"); if (!orig.isFile()) { System.err.println("Unable to test file - not available"); return; } File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("test1.wma"); //Copy up a level coz we need it to be in same folder as working directory so can just specify filename File outputFile = new File(testFile.getName()); boolean result = copy(testFile, outputFile); assertTrue(result); //make Relative assertTrue(outputFile.exists()); //Read File okay AudioFile af = AudioFileIO.read(outputFile); System.out.println(af.getTag().toString()); //Change File af.getTag().setField(Artwork.createArtworkFromFile(new File("testdata/coverart.jpg"))); af.commit(); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } public void testWriteToRelativeMp3File() { File orig = new File("testdata", "testV1.mp3"); if (!orig.isFile()) { System.err.println("Unable to test file - not available"); return; } File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("testV1.mp3"); //Copy up a level coz we need it to be in same folder as working directory so can just specify filename File outputFile = new File(testFile.getName()); boolean result = copy(testFile, outputFile); assertTrue(result); //make Relative assertTrue(outputFile.exists()); //Read File okay AudioFile af = AudioFileIO.read(outputFile); //Create tag and Change File af.getTagOrCreateAndSetDefault(); af.getTag().setField(Artwork.createArtworkFromFile(new File("testdata/coverart.jpg"))); af.commit(); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/issues/Issue319Test.java0000644000175000017500000000217411470746136026766 0ustar drazzibdrazzibpackage org.jaudiotagger.issues; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.audio.mp3.MP3File; import org.jaudiotagger.tag.FieldKey; import org.jaudiotagger.tag.KeyNotFoundException; import org.jaudiotagger.tag.Tag; import java.io.File; /** Test tag Equality (specifically PartOfSet) */ public class Issue319Test extends AbstractTestCase { /* * Test File Equality * @throws Exception */ public void testTagEquality() throws Exception { File orig = new File("testdata", "test26.mp3"); if (!orig.isFile()) { System.err.println("Unable to test file - not available"); return; } File file1 = new File("testdata", "test26.mp3"); MP3File audioFile = (MP3File)AudioFileIO.read(file1); Tag tag = audioFile.getTag(); FieldKey key = FieldKey.DISC_NO; try { String fieldValue = tag.getFirst(key); System.out.println("Fieldvalue is"+fieldValue); } catch (KeyNotFoundException e) { e.printStackTrace(); } } }libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/issues/Issue335Test.java0000644000175000017500000001462611470746136026771 0ustar drazzibdrazzibpackage org.jaudiotagger.issues; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.audio.mp3.MP3File; import org.jaudiotagger.tag.FieldKey; import org.jaudiotagger.tag.Tag; import org.jaudiotagger.tag.TagField; import org.jaudiotagger.tag.id3.*; import org.jaudiotagger.tag.id3.framebody.AbstractFrameBodyTextInfo; import java.io.File; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; /** * Test when write multiple strings using UTF16 with BOM that it writes the BOM * for all strings not just the first one */ public class Issue335Test extends AbstractTestCase { public void testConvertv24Tov23ConvertsUTF8ToISO8859IfItCan() throws Exception { File orig = new File("testdata", "test79.mp3"); if (!orig.isFile()) { System.err.println("Unable to test file - not available"); return; } //TagOptionSingleton.getInstance().setResetTextEncodingForExistingFrames(false); File testFile = AbstractTestCase.copyAudioToTmp("test79.mp3"); MP3File f = (MP3File) AudioFileIO.read(testFile); assertEquals("Familial", f.getID3v2Tag().getFirst("TALB")); AbstractID3v2Frame frame = (AbstractID3v2Frame) f.getID3v2Tag().getFrame("TALB"); AbstractTagFrameBody body = frame.getBody(); assertEquals(3, body.getTextEncoding()); ID3v23Tag tag = new ID3v23Tag(f.getID3v2Tag()); assertEquals(3, body.getTextEncoding()); f.setID3v2Tag(tag); f.commit(); f = (MP3File) AudioFileIO.read(testFile); assertEquals("Familial", f.getID3v2Tag().getFirst("TALB")); frame = (AbstractID3v2Frame) f.getID3v2Tag().getFrame("TALB"); body = frame.getBody(); assertEquals(0, body.getTextEncoding()); } public void testConvertv24Tov23OnlyConvertsUTF8ToISO8859IfItCan() throws Exception { File orig = new File("testdata", "test79.mp3"); if (!orig.isFile()) { System.err.println("Unable to test file - not available"); return; } //TagOptionSingleton.getInstance().setResetTextEncodingForExistingFrames(false); File testFile = AbstractTestCase.copyAudioToTmp("test79.mp3"); MP3File f = (MP3File) AudioFileIO.read(testFile); assertEquals("Familial", f.getID3v2Tag().getFirst("TALB")); assertEquals(4, f.getID3v2Tag().getMajorVersion()); AbstractID3v2Frame frame = (AbstractID3v2Frame) f.getID3v2Tag().getFrame("TALB"); AbstractFrameBodyTextInfo body = (AbstractFrameBodyTextInfo) frame.getBody(); body.setText("ǿ"); //It was UTF8 assertEquals(3, body.getTextEncoding()); ID3v23Tag tag = new ID3v23Tag(f.getID3v2Tag()); frame = (AbstractID3v2Frame) tag.getFrame("TALB"); body = (AbstractFrameBodyTextInfo) frame.getBody(); //We default to 0 assertEquals(0, body.getTextEncoding()); f.setID3v2Tag(tag); f.commit(); f = (MP3File) AudioFileIO.read(testFile); assertEquals("ǿ", f.getID3v2Tag().getFirst("TALB")); frame = (AbstractID3v2Frame) f.getID3v2Tag().getFrame("TALB"); body = (AbstractFrameBodyTextInfo) frame.getBody(); //But need UTF16 to store this value assertEquals(1, body.getTextEncoding()); } public void testConvertv23Twice() throws Exception { File orig = new File("testdata", "test79.mp3"); if (!orig.isFile()) { System.err.println("Unable to test file - not available"); return; } //TagOptionSingleton.getInstance().setResetTextEncodingForExistingFrames(false); File testFile = AbstractTestCase.copyAudioToTmp("test79.mp3"); MP3File f = (MP3File) AudioFileIO.read(testFile); assertEquals("Familial", f.getID3v2Tag().getFirst("TALB")); assertEquals(4, f.getID3v2Tag().getMajorVersion()); AbstractID3v2Frame frame = (AbstractID3v2Frame) f.getID3v2Tag().getFrame("TALB"); AbstractFrameBodyTextInfo body = (AbstractFrameBodyTextInfo) frame.getBody(); body.setText("ǿ"); //It was UTF8 assertEquals(3, body.getTextEncoding()); ID3v23Tag tag = new ID3v23Tag(f.getID3v2Tag()); frame = (AbstractID3v2Frame) tag.getFrame("TALB"); body = (AbstractFrameBodyTextInfo) frame.getBody(); //We default to 0 assertEquals(0, body.getTextEncoding()); f.setID3v2Tag(tag); f.commit(); f = (MP3File) AudioFileIO.read(testFile); tag = (ID3v23Tag) f.getID3v2Tag(); frame = (AbstractID3v2Frame) tag.getFrame("TALB"); body = (AbstractFrameBodyTextInfo) frame.getBody(); //It got converted to UTF16 at previous commit stage in order to store the value assertEquals(1, body.getTextEncoding()); ID3v24Tag v24tag = f.getID3v2TagAsv24(); frame = (AbstractID3v2Frame) v24tag.getFrame("TALB"); body = (AbstractFrameBodyTextInfo) frame.getBody(); //And not lost when convert to v24 assertEquals(1, body.getTextEncoding()); tag = new ID3v23Tag(v24tag); frame = (AbstractID3v2Frame) tag.getFrame("TALB"); body = (AbstractFrameBodyTextInfo) frame.getBody(); //or if convert from v24 view back down to v23 view assertEquals(1, body.getTextEncoding()); } public void testConvertCharsAtStartOfFile() throws Exception { File orig = new File("testdata", "test79.mp3"); if (!orig.isFile()) { System.err.println("Unable to test file - not available"); return; } boolean isMP3v2 = false; ID3v24Tag v24tag=null; Tag tag=null; MP3File mP3AudioFile = (MP3File) AudioFileIO.read(orig); mP3AudioFile.getID3v2Tag().setField(FieldKey.ARTIST,"fred"); mP3AudioFile.commit(); mP3AudioFile = (MP3File) AudioFileIO.read(orig); if (mP3AudioFile.hasID3v2Tag()) { isMP3v2 = true; v24tag = mP3AudioFile.getID3v2TagAsv24(); // Abstracting any v2 tag as v2.4 } else { tag = mP3AudioFile.getTag(); isMP3v2 = false; } String s = (isMP3v2) ? v24tag.getFirst(ID3v24Frames.FRAME_ID_ARTIST) : tag.getFirst(FieldKey.ARTIST); System.out.println("IS v2:"+isMP3v2); System.out.println(s); } }libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/issues/Issue274Test.java0000644000175000017500000000207011123715062026746 0ustar drazzibdrazzibpackage org.jaudiotagger.issues; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.tag.id3.ID3v22Tag; import org.jaudiotagger.tag.TagOptionSingleton; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.audio.mp3.MP3File; import java.io.File; /** Flac Reading */ public class Issue274Test extends AbstractTestCase { /** * Test Flac */ public void testReadFlac() { File orig = new File("testdata", "test54.flac"); if (!orig.isFile()) { System.err.println("Unable to test file - not available"); return; } File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("test54.flac"); //Read File okay AudioFile af = AudioFileIO.read(testFile); } catch(Exception e) { e.printStackTrace(); exceptionCaught=e; } assertNull(exceptionCaught); } }libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/issues/Issue224Test.java0000644000175000017500000000472711041064726026757 0ustar drazzibdrazzibpackage org.jaudiotagger.issues; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.tag.Tag; import org.jaudiotagger.tag.TagField; import org.jaudiotagger.tag.id3.ID3v23Frame; import org.jaudiotagger.tag.id3.ID3v23Tag; import org.jaudiotagger.tag.id3.framebody.FrameBodyAPIC; import javax.imageio.ImageIO; import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.io.File; /** * Test APIC Frame with no PictureType Field */ public class Issue224Test extends AbstractTestCase { public void testReadInvalidPicture() { String genre = null; File orig = new File("testdata", "test31.mp3"); if (!orig.isFile()) { return; } Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test31.mp3"); AudioFile f = AudioFileIO.read(testFile); Tag tag = f.getTag(); assertEquals(10, tag.getFieldCount()); assertTrue(tag instanceof ID3v23Tag); ID3v23Tag id3v23Tag = (ID3v23Tag) tag; TagField coverArtField = id3v23Tag.getFirstField(org.jaudiotagger.tag.id3.ID3v23FieldKey.COVER_ART.getFieldName()); assertTrue(coverArtField instanceof ID3v23Frame); assertTrue(((ID3v23Frame) coverArtField).getBody() instanceof FrameBodyAPIC); FrameBodyAPIC body = (FrameBodyAPIC) ((ID3v23Frame) coverArtField).getBody(); byte[] imageRawData = body.getImageData(); BufferedImage bi = ImageIO.read(ImageIO.createImageInputStream(new ByteArrayInputStream(imageRawData))); assertEquals(953, bi.getWidth()); assertEquals(953, bi.getHeight()); assertEquals("image/png", body.getMimeType()); assertEquals("", body.getDescription()); assertEquals("", body.getImageUrl()); //This is an invalid value (probably first value of PictureType) assertEquals(208, body.getPictureType()); assertFalse(body.isImageUrl()); //SetDescription body.setDescription("FREDDY"); assertEquals("FREDDY", body.getDescription()); f.commit(); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); assertNull(genre); } }libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/issues/Issue291Test.java0000644000175000017500000000267611276777123027000 0ustar drazzibdrazzibpackage org.jaudiotagger.issues; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.tag.FieldKey; import java.io.File; /** * Unable to write, offsets do not match * * TODO Unable to reproduce at the moment */ public class Issue291Test extends AbstractTestCase { public void testSavingFile() { File orig = new File("testdata", "test60.m4p"); if (!orig.isFile()) { System.err.println("Unable to test file - not available"); return; } File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("test60.m4p"); AudioFile af = AudioFileIO.read(testFile); System.out.println("Tag is"+af.getTag().toString()); af.getTag().setField(af.getTag().createField(FieldKey.ARTIST,"fredqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq")); af.getTag().setField(af.getTag().createField(FieldKey.AMAZON_ID,"fredqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq")); af.commit(); af = AudioFileIO.read(testFile); assertEquals("fredqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq",af.getTag().getFirst(FieldKey.ARTIST)); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/issues/Issue286Test.java0000644000175000017500000001005511470746136026766 0ustar drazzibdrazzibpackage org.jaudiotagger.issues; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.audio.mp3.MP3File; import org.jaudiotagger.tag.FieldKey; import org.jaudiotagger.tag.KeyNotFoundException; import org.jaudiotagger.tag.Tag; import org.jaudiotagger.tag.datatype.Artwork; import org.jaudiotagger.tag.id3.valuepair.ImageFormats; import org.jaudiotagger.tag.reference.PictureTypes; import java.io.File; /** Vorbis Comment reading new Image Format */ public class Issue286Test extends AbstractTestCase { /* * TestRead Vorbis COverArt One * @throws Exception */ public void testReadVorbisCoverartOne() throws Exception { File file = new File("testdata", "test76.ogg"); AudioFile af = AudioFileIO.read(file); assertEquals(1,af.getTag().getArtworkList().size()); Artwork artwork = af.getTag().getFirstArtwork(); System.out.println(artwork); assertEquals(600,artwork.getImage().getWidth()); assertEquals(800,artwork.getImage().getHeight()); assertEquals("image/jpeg",artwork.getMimeType()); assertEquals(3,artwork.getPictureType()); } /* * TestRead Vorbis CoverArt Two * @throws Exception */ public void testReadVorbisCoverartTwo() throws Exception { File file = new File("testdata", "test77.ogg"); AudioFile af = AudioFileIO.read(file); assertEquals(1,af.getTag().getArtworkList().size()); Artwork artwork = af.getTag().getFirstArtwork(); System.out.println(artwork); assertEquals(600,artwork.getImage().getWidth()); assertEquals(800,artwork.getImage().getHeight()); assertEquals("image/jpeg",artwork.getMimeType()); assertEquals(3,artwork.getPictureType()); } /** * Test reading/writing artwork to Ogg */ public void testReadWriteArtworkFieldsToOggVorbis() { File testFile = null; Exception exceptionCaught = null; try { testFile = AbstractTestCase.copyAudioToTmp("test3.ogg"); //Read File okay AudioFile af = AudioFileIO.read(testFile); Tag tag = af.getTag(); assertEquals(1, tag.getArtworkList().size()); assertTrue(tag.getArtworkList().get(0) instanceof Artwork); Artwork artwork = tag.getFirstArtwork(); assertEquals("image/png", artwork.getMimeType()); assertNotNull(artwork.getImage()); assertEquals("",artwork.getDescription()); assertEquals(200, artwork.getImage().getWidth()); //Now add new image Artwork newartwork = Artwork.createArtworkFromFile(new File("testdata", "coverart.png")); newartwork.setDescription("A new file"); assertTrue(ImageFormats.isPortableFormat(newartwork.getBinaryData())); tag.addField(newartwork); af.commit(); af = AudioFileIO.read(testFile); tag = af.getTag(); assertEquals(2, tag.getArtworkList().size()); assertTrue(tag.getArtworkList().get(0) instanceof Artwork); artwork = tag.getFirstArtwork(); assertEquals("image/png", artwork.getMimeType()); assertNotNull(artwork.getImage()); assertEquals("",artwork.getDescription()); assertEquals(200, artwork.getImage().getWidth()); assertTrue(tag.getArtworkList().get(1) instanceof Artwork); artwork = tag.getArtworkList().get(1); assertEquals("image/png", artwork.getMimeType()); assertNotNull(artwork.getImage()); assertEquals("A new file",artwork.getDescription()); assertEquals(200, artwork.getImage().getWidth()); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } }libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/AbstractTestCase.java0000644000175000017500000001474511277311416026466 0ustar drazzibdrazzib/* * Jaudiotagger Copyright (C)2004,2005 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can getFields a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger; import junit.framework.TestCase; import org.jaudiotagger.logging.ErrorMessage; import org.jaudiotagger.tag.TagOptionSingleton; import java.io.*; import java.util.EnumMap; import java.util.regex.Pattern; /** * */ public abstract class AbstractTestCase extends TestCase { @Override public void setUp() { TagOptionSingleton.getInstance().setToDefault(); } /** * Stores a {@link Pattern} for each {@link ErrorMessage}.
* Place holders like "{<number>}" will be replaced with * ".*".
*/ private final static EnumMap ERROR_PATTERNS; static { ERROR_PATTERNS = new EnumMap(ErrorMessage.class); for (ErrorMessage curr : ErrorMessage.values()) { final String regex = curr.getMsg().replaceAll("\\{\\d+\\}", ".*"); ERROR_PATTERNS.put(curr, Pattern.compile(regex, Pattern.CASE_INSENSITIVE | Pattern.DOTALL)); } } private static boolean append(File fromFile1, File fromFile2, File toFile) { try { FileInputStream in = new FileInputStream(fromFile1); FileInputStream in2 = new FileInputStream(fromFile2); FileOutputStream out = new FileOutputStream(toFile); BufferedInputStream inBuffer = new BufferedInputStream(in); BufferedInputStream inBuffer2 = new BufferedInputStream(in2); BufferedOutputStream outBuffer = new BufferedOutputStream(out); int theByte; while ((theByte = inBuffer.read()) > -1) { outBuffer.write(theByte); } while ((theByte = inBuffer2.read()) > -1) { outBuffer.write(theByte); } outBuffer.close(); inBuffer.close(); inBuffer2.close(); out.close(); in.close(); in2.close(); // cleanupif files are not the same length if ((fromFile1.length() + fromFile2.length()) != toFile.length()) { toFile.delete(); return false; } return true; } catch (IOException e) { e.printStackTrace(); return false; } } /** * Copy a File * * @param fromFile * The existing File * @param toFile * The new File * @return true if and only if the renaming succeeded; * false otherwise */ public static boolean copy(File fromFile, File toFile) { try { FileInputStream in = new FileInputStream(fromFile); FileOutputStream out = new FileOutputStream(toFile); byte[] buf = new byte[8192]; int len; while ((len = in.read(buf)) > -1) { out.write(buf, 0, len); } in.close(); out.close(); // cleanupif files are not the same length if (fromFile.length() != toFile.length()) { toFile.delete(); return false; } return true; } catch (IOException e) { e.printStackTrace(); return false; } } /** * Copy audiofile to processing dir ready for use in test * * @param fileName * @return */ public static File copyAudioToTmp(String fileName) { File inputFile = new File("testdata", fileName); File outputFile = new File("testdatatmp", fileName); if (!outputFile.getParentFile().exists()) { outputFile.getParentFile().mkdirs(); } boolean result = copy(inputFile, outputFile); assertTrue(result); return outputFile; } /** * Copy audiofile to processing dir ready for use in test, use this if using * same file in multiple tests because with junit multithreading can have * problemsa otherwise * * @param fileName * @return */ public static File copyAudioToTmp(String fileName, File newFileName) { File inputFile = new File("testdata", fileName); File outputFile = new File("testdatatmp", newFileName.getName()); if (!outputFile.getParentFile().exists()) { outputFile.getParentFile().mkdirs(); } boolean result = copy(inputFile, outputFile); assertTrue(result); return outputFile; } /** * Prepends file with tag file in order to create an mp3 with a valid id3 * * @param tagfile * @param fileName * @return */ public static File copyAudioToTmp(String tagfile, String fileName) { File inputTagFile = new File("testtagdata", tagfile); File inputFile = new File("testdata", fileName); File outputFile = new File("testdatatmp", fileName); if (!outputFile.getParentFile().exists()) { outputFile.getParentFile().mkdirs(); } boolean result = append(inputTagFile, inputFile, outputFile); assertTrue(result); return outputFile; } /** * This method asserts that the given actual message is * constructed with the expected message string.
*
* * @param expected * the expected message source. * @param actual * the message to compare against. */ public void assertErrorMessage(final ErrorMessage expected, final String actual) { assertTrue("Message not correctly constructed.", ERROR_PATTERNS.get( expected).matcher(actual).matches()); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/audio/0000755000175000017500000000000011556363176023524 5ustar drazzibdrazziblibjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/audio/asf/0000755000175000017500000000000011556363176024275 5ustar drazzibdrazziblibjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/audio/asf/tag/0000755000175000017500000000000011556363176025050 5ustar drazzibdrazziblibjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/audio/asf/tag/AsfKeyMappingTest.java0000644000175000017500000000155411277264361031252 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.asf.tag; import junit.framework.TestCase; import org.jaudiotagger.tag.FieldKey; import org.jaudiotagger.tag.Tag; import org.jaudiotagger.tag.asf.AsfTag; /** * @author Christian Laireiter * */ public class AsfKeyMappingTest extends TestCase { /** * This method tests whether each {@link org.jaudiotagger.tag.FieldKey} is mapped * to an {@link org.jaudiotagger.tag.asf.AsfFieldKey}.
*/ public void testTagFieldKeyMappingComplete() { Exception exceptionCaught=null; Tag tag = new AsfTag(); try { for (FieldKey curr : FieldKey.values()) { tag.getFields(curr); } } catch(Exception e) { e.printStackTrace(); exceptionCaught=e; } assertNull(exceptionCaught); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/audio/asf/tag/AsfTagTest.java0000644000175000017500000000733011470746136027717 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.asf.tag; import junit.framework.TestCase; import org.jaudiotagger.tag.FieldDataInvalidException; import org.jaudiotagger.tag.FieldKey; import org.jaudiotagger.tag.TagField; import org.jaudiotagger.tag.TagTextField; import org.jaudiotagger.tag.asf.AsfFieldKey; import org.jaudiotagger.tag.asf.AsfTag; import org.jaudiotagger.tag.asf.AsfTagTextField; import java.util.List; /** * Tests tag implementations. * * @author Christian Laireiter */ public class AsfTagTest extends TestCase { /** * This method tests the insertion of fields (or data) with empty content.
*/ public void testEmptyField() throws FieldDataInvalidException { //Copy fields flag setField AsfTag asfTag = new AsfTag(true); asfTag.addField(FieldKey.ALBUM,""); asfTag.setField(FieldKey.TITLE,""); assertFalse(asfTag.hasField(AsfFieldKey.ALBUM.getFieldName())); assertFalse(asfTag.hasField(AsfFieldKey.TITLE.getFieldName())); assertTrue(asfTag.isEmpty()); assertTrue(asfTag.getFieldCount() == 0); //Copy field flag not setField asfTag = new AsfTag(); asfTag.addField(FieldKey.ALBUM,""); asfTag.setField(FieldKey.TITLE,""); assertFalse(asfTag.hasField(AsfFieldKey.ALBUM.getFieldName())); assertFalse(asfTag.hasField(AsfFieldKey.TITLE.getFieldName())); assertTrue(asfTag.isEmpty()); assertTrue(asfTag.getFieldCount() == 0); } /** * tests the mixed use of {@link AsfFieldKey} and {@link org.jaudiotagger.tag.FieldKey}. */ public void testIdentifierConversion() throws FieldDataInvalidException { final AsfTag asfTag = new AsfTag(); TagField albumField = asfTag.createField(FieldKey.ALBUM, AsfFieldKey.ALBUM.getFieldName()); asfTag.addField(albumField); assertSame(albumField, asfTag.getFields(FieldKey.ALBUM).get(0)); assertSame(albumField, asfTag.getFields(AsfFieldKey.ALBUM.getFieldName()).get(0)); } public void testMixedIdentifiers() throws Exception { final AsfTag asfTag = new AsfTag(); AsfTagTextField textField = asfTag.createField(AsfFieldKey.ALBUM, AsfFieldKey.ALBUM.toString()); asfTag.setField(textField); assertSame(textField, asfTag.getFirstField(AsfFieldKey.ALBUM.getFieldName())); } public void testUncommonAsfTagFields() { AsfTag asfTag = new AsfTag(true); asfTag.addCopyright("copyright1"); asfTag.addCopyright("copyright2"); asfTag.addRating("rating1"); asfTag.addRating("rating2"); // No Multivalue assertEquals("copyright2", asfTag.getFirstCopyright()); assertEquals("rating2", asfTag.getFirstRating()); asfTag.setCopyright("copyright3"); asfTag.setRating("rating3"); // You dont believe it, but the following did the trick. I am convinced of unit testing from now on. assertEquals("copyright3", asfTag.getFirstCopyright()); assertEquals("rating3", asfTag.getFirstRating()); List copies = asfTag.getCopyright(); List ratings = asfTag.getRating(); assertEquals(1, copies.size()); assertEquals(1, ratings.size()); assertEquals("copyright3", ((TagTextField) copies.get(0)).getContent()); assertEquals("rating3", ((TagTextField) ratings.get(0)).getContent()); asfTag = new AsfTag(true); asfTag.setCopyright("copyright4"); asfTag.setRating("rating4"); assertEquals("copyright4", asfTag.getFirstCopyright()); assertEquals("rating4", asfTag.getFirstRating()); assertEquals(1, asfTag.getCopyright().size()); assertEquals(1, asfTag.getRating().size()); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/audio/asf/AsfCodeCheckTest.java0000644000175000017500000000371311277264361030242 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.asf; import junit.framework.TestCase; import org.jaudiotagger.audio.asf.data.AsfHeader; import org.jaudiotagger.tag.asf.AsfFieldKey; import org.jaudiotagger.tag.asf.AsfTag; import org.jaudiotagger.tag.FieldKey; /** * This test covers some mistakes that could be made by changing the implementation.
* For example, constants which are assigned at class loading being null. * * @author Christian Laireiter */ public class AsfCodeCheckTest extends TestCase { /** * Tests the correct implementation of {@link AsfTag}.
* For example if {@link AsfTag#createAlbumField(String)} returns a field whose {@link org.jaudiotagger.tag.TagField#getId()} * equals {@link org.jaudiotagger.tag.asf.AsfFieldKey#ALBUM}s }. */ public void testAsfTagImpl() throws Exception { final AsfTag asfTag = new AsfTag(); assertEquals(asfTag.createField(FieldKey.ALBUM,new String()).getId(), AsfFieldKey.ALBUM.getFieldName()); assertEquals(asfTag.createField(FieldKey.ARTIST,new String()).getId(), AsfFieldKey.AUTHOR.getFieldName()); assertEquals(asfTag.createField(FieldKey.COMMENT,new String()).getId(), AsfFieldKey.DESCRIPTION.getFieldName()); assertEquals(asfTag.createField(FieldKey.GENRE,new String()).getId(), AsfFieldKey.GENRE.getFieldName()); assertEquals(asfTag.createField(FieldKey.TITLE,new String()).getId(), AsfFieldKey.TITLE.getFieldName()); assertEquals(asfTag.createField(FieldKey.TRACK,new String()).getId(), AsfFieldKey.TRACK.getFieldName()); assertEquals(asfTag.createField(FieldKey.YEAR,new String()).getId(), AsfFieldKey.YEAR.getFieldName()); } /** * Tests some constants which must have values. */ public void testConstants() { // UTF16-LE by specification assertEquals("ONLY \"UTF-16LE\" text encoding specified", "UTF-16LE", AsfHeader.ASF_CHARSET.name()); // $NON-NLS-1$ //$NON-NLS-2$ } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/audio/asf/data/0000755000175000017500000000000011556363176025206 5ustar drazzibdrazziblibjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/audio/asf/data/ChunkTest.java0000644000175000017500000000446611222471043027752 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.asf.data; import java.math.BigInteger; /** * Test for simple {@link Chunk}. * * @author Christian Laireiter */ public class ChunkTest extends AbstractChunk { /** * Creates a chunk instance. * * @param chunkGUID * GUID * @param pos * position of chunk * @param chunkLength * length of chunk * @return chunk instance. */ protected Chunk createChunk(final GUID chunkGUID, final long pos, final BigInteger chunkLength) { return new Chunk(chunkGUID, pos, chunkLength); } /** * {@inheritDoc} */ @Override protected Chunk createChunk(long pos, BigInteger size) { return new Chunk(GUID.GUID_UNSPECIFIED, pos, size); } /** * Tests the creation of chunks and should fail.
* * @param chunkGUID * GUID. * @param pos * position of the chunk * @param chunkLength * chunk size. * @return The occurred exception on * {@link #createChunk(GUID,long, BigInteger)}. */ public Exception failOn(final GUID chunkGUID, final long pos, final BigInteger chunkLength) { Exception result = null; try { createChunk(chunkGUID, pos, chunkLength); } catch (Exception e) { result = e; } return result; } /** * Test method for * {@link org.jaudiotagger.audio.asf.data.Chunk#Chunk(GUID, BigInteger)}. */ public void testChunk() { assertTrue("IllegalArgumentException expected", failOn(null, 0, null) instanceof IllegalArgumentException); assertTrue( "IllegalArgumentException expected", failOn(GUID.GUID_UNSPECIFIED, 0, null) instanceof IllegalArgumentException); assertTrue("IllegalArgumentException expected", failOn( GUID.GUID_UNSPECIFIED, 0, BigInteger.TEN.multiply(BigInteger .valueOf(-1))) instanceof IllegalArgumentException); assertNull("Should have worked fine", failOn(GUID.GUID_UNSPECIFIED, 0, BigInteger.TEN)); assertNull("Should have worked fine", failOn(GUID.GUID_UNSPECIFIED, 0, BigInteger.ZERO)); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/audio/asf/data/ContentBrandingTest.java0000644000175000017500000000622311222471043031752 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.asf.data; import java.math.BigInteger; import java.util.ArrayList; import java.util.List; /** * Tests the content branding container. * * @author Christian Laireiter */ public class ContentBrandingTest extends AbstractMetadataContainer { /** * {@inheritDoc} */ @Override protected ContentBranding createChunk(long pos, BigInteger size) { return new ContentBranding(pos, size); } /** * {@inheritDoc} */ @Override protected MetadataDescriptor[] createSupportedDescriptors( ContentBranding container) { assertSame(ContainerType.CONTENT_BRANDING, container .getContainerType()); final List result = new ArrayList(); MetadataDescriptor curr = new MetadataDescriptor( ContentBranding.KEY_COPYRIGHT_URL); curr.setString("http://www.copyright.url"); result.add(curr); curr = new MetadataDescriptor(ContentBranding.KEY_BANNER_URL); curr.setString("http://www.banner.url"); result.add(curr); curr = new MetadataDescriptor(ContentBranding.KEY_BANNER_TYPE); curr.setWordValue(0); result.add(curr); curr = new MetadataDescriptor(ContentBranding.KEY_BANNER_IMAGE); curr.setBinaryValue(new byte[10]); result.add(curr); return result.toArray(new MetadataDescriptor[result.size()]); } /** * {@inheritDoc} */ @Override protected ContentBranding[] createTestContainers() { return new ContentBranding[] { createChunk(0, BigInteger.ZERO) }; } /** * Test method for * {@link org.jaudiotagger.audio.asf.data.ContentBranding#isAddSupported(org.jaudiotagger.audio.asf.data.MetadataDescriptor)} * . */ public void testIsAddSupported() { final ContentBranding chunk = createChunk(0, BigInteger.ZERO); assertFalse(chunk.isAddSupported(new MetadataDescriptor("arbitrary"))); assertTrue(chunk .isAddSupported(new MetadataDescriptor( ContainerType.CONTENT_BRANDING, ContentBranding.KEY_BANNER_URL, MetadataDescriptor.TYPE_STRING))); } /** * Test method for {@link ContentBranding#setBannerImageURL(String)}. */ public void testSetBannerImageURL() { final ContentBranding chunk = createChunk(0, BigInteger.ZERO); assertTrue(chunk.isEmpty()); assertEquals("", chunk.getBannerImageURL()); chunk.setBannerImageURL("banner image url"); assertEquals("banner image url", chunk.getBannerImageURL()); assertFalse(chunk.isEmpty()); } /** * Test method for {@link ContentBranding#setCopyRightURL(String)}. */ public void testSetCopyrightURL() { final ContentBranding chunk = createChunk(0, BigInteger.ZERO); assertTrue(chunk.isEmpty()); assertEquals("", chunk.getCopyRightURL()); chunk.setCopyRightURL("copyright url"); assertEquals("copyright url", chunk.getCopyRightURL()); assertFalse(chunk.isEmpty()); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/audio/asf/data/ContentDescriptionTest.java0000644000175000017500000001404111222471043032506 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.asf.data; import org.jaudiotagger.logging.ErrorMessage; import java.math.BigInteger; import java.util.ArrayList; import java.util.List; /** * Tests the content description container. * * @author Christian Laireiter */ public class ContentDescriptionTest extends AbstractMetadataContainer { /** * {@inheritDoc} */ @Override protected ContentDescription createChunk(long pos, BigInteger size) { return new ContentDescription(pos, size); } /** * {@inheritDoc} */ @Override protected MetadataDescriptor[] createSupportedDescriptors( ContentDescription container) { final List result = new ArrayList(); MetadataDescriptor desc = new MetadataDescriptor( ContentDescription.KEY_AUTHOR); desc.setStringValue("author"); result.add(desc); desc = new MetadataDescriptor(ContentDescription.KEY_COPYRIGHT); desc.setStringValue("copyright"); result.add(desc); desc = new MetadataDescriptor(ContentDescription.KEY_DESCRIPTION); desc.setStringValue("description"); result.add(desc); desc = new MetadataDescriptor(ContentDescription.KEY_RATING); desc.setStringValue("rating"); result.add(desc); desc = new MetadataDescriptor(ContentDescription.KEY_TITLE); desc.setStringValue("title"); result.add(desc); return result.toArray(new MetadataDescriptor[result.size()]); } /** * {@inheritDoc} */ @Override protected ContentDescription[] createTestContainers() { return new ContentDescription[] { new ContentDescription() }; } /** * Test method for * {@link org.jaudiotagger.audio.asf.data.ContentDescription#setAuthor(java.lang.String)} * . */ public void testSetAuthor() { final ContentDescription chunk = createChunk(0, BigInteger.ZERO); assertTrue(chunk.isEmpty()); assertEquals("", chunk.getAuthor()); chunk.setAuthor(""); assertTrue(chunk.isEmpty()); chunk.setAuthor("author"); assertEquals("author", chunk.getAuthor()); assertFalse(chunk.isEmpty()); try { chunk.setAuthor(AbstractChunk .createAString(MetadataDescriptor.WORD_MAXVALUE + 1)); fail("Exception expected"); } catch (IllegalArgumentException iae) { assertErrorMessage(ErrorMessage.WMA_LENGTH_OF_DATA_IS_TOO_LARGE, iae.getMessage()); } } /** * Test method for * {@link org.jaudiotagger.audio.asf.data.ContentDescription#setComment(java.lang.String)} * . */ public void testSetComment() { final ContentDescription chunk = createChunk(0, BigInteger.ZERO); assertTrue(chunk.isEmpty()); assertEquals("", chunk.getComment()); chunk.setComment(""); assertTrue(chunk.isEmpty()); chunk.setComment("comment"); assertEquals("comment", chunk.getComment()); assertFalse(chunk.isEmpty()); try { chunk.setComment(AbstractChunk .createAString(MetadataDescriptor.WORD_MAXVALUE + 1)); fail("Exception expected"); } catch (IllegalArgumentException iae) { assertErrorMessage(ErrorMessage.WMA_LENGTH_OF_DATA_IS_TOO_LARGE, iae.getMessage()); } } /** * Test method for * {@link org.jaudiotagger.audio.asf.data.ContentDescription#setCopyright(java.lang.String)} * . */ public void testSetCopyRight() { final ContentDescription chunk = createChunk(0, BigInteger.ZERO); assertTrue(chunk.isEmpty()); assertEquals("", chunk.getCopyRight()); chunk.setCopyright(""); assertTrue(chunk.isEmpty()); chunk.setCopyright("copyright"); assertEquals("copyright", chunk.getCopyRight()); assertFalse(chunk.isEmpty()); try { chunk.setCopyright(AbstractChunk .createAString(MetadataDescriptor.WORD_MAXVALUE + 1)); fail("Exception expected"); } catch (IllegalArgumentException iae) { assertErrorMessage(ErrorMessage.WMA_LENGTH_OF_DATA_IS_TOO_LARGE, iae.getMessage()); } } /** * Test method for * {@link org.jaudiotagger.audio.asf.data.ContentDescription#setRating(java.lang.String)} * . */ public void testSetRating() { final ContentDescription chunk = createChunk(0, BigInteger.ZERO); assertTrue(chunk.isEmpty()); assertEquals("", chunk.getRating()); chunk.setRating(""); assertTrue(chunk.isEmpty()); chunk.setRating("rating"); assertEquals("rating", chunk.getRating()); assertFalse(chunk.isEmpty()); try { chunk.setRating(AbstractChunk .createAString(MetadataDescriptor.WORD_MAXVALUE + 1)); fail("Exception expected"); } catch (IllegalArgumentException iae) { assertErrorMessage(ErrorMessage.WMA_LENGTH_OF_DATA_IS_TOO_LARGE, iae.getMessage()); } } /** * Test method for * {@link org.jaudiotagger.audio.asf.data.ContentDescription#setTitle(java.lang.String)} * . */ public void testSetTitle() { final ContentDescription chunk = createChunk(0, BigInteger.ZERO); assertTrue(chunk.isEmpty()); assertEquals("", chunk.getTitle()); chunk.setTitle(""); assertTrue(chunk.isEmpty()); chunk.setTitle("title"); assertEquals("title", chunk.getTitle()); assertFalse(chunk.isEmpty()); try { chunk.setTitle(AbstractChunk .createAString(MetadataDescriptor.WORD_MAXVALUE + 1)); fail("Exception expected"); } catch (IllegalArgumentException iae) { assertErrorMessage(ErrorMessage.WMA_LENGTH_OF_DATA_IS_TOO_LARGE, iae.getMessage()); } } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/audio/asf/data/LanguageListTest.java0000644000175000017500000000233111222471043031246 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.asf.data; import java.math.BigInteger; /** * Test for {@link LanguageList}.
* * @author Christian Laireiter */ public class LanguageListTest extends AbstractChunk { /** * {@inheritDoc} */ @Override protected LanguageList createChunk(long pos, BigInteger size) { return new LanguageList(pos, size); } /** * Test method for * {@link org.jaudiotagger.audio.asf.data.LanguageList#addLanguage(java.lang.String)} * . */ public void testLanguage() { final LanguageList chunk = createChunk(0, BigInteger.ZERO); chunk.addLanguage("language"); assertEquals("language", chunk.getLanguage(0)); assertEquals(1, chunk.getLanguageCount()); chunk.removeLanguage(0); assertEquals(0, chunk.getLanguageCount()); for (int i = 0; i < MetadataDescriptor.MAX_LANG_INDEX; i++) { chunk.addLanguage("lang" + i); assertEquals("lang" + i, chunk.getLanguage(i)); assertEquals(i + 1, chunk.getLanguageCount()); assertEquals(i + 1, chunk.getLanguages().size()); assertTrue(chunk.getLanguages().contains("lang" + i)); } } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/audio/asf/data/MetadataContainerUtils.java0000644000175000017500000000352211222471043032436 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.asf.data; import java.util.Collections; import java.util.List; import java.util.logging.Logger; /** * This class provides methods for working with {@link MetadataContainer} * objects.
* * @author Christian Laireiter */ public final class MetadataContainerUtils { // Logger Object public static Logger logger = Logger .getLogger("org.jaudiotagger.audio.asf"); public static boolean equals(List l1, List l2) { boolean result = true;// l1.size() == l2.size(); Collections.sort(l1, new MetadataDescriptorComparator()); Collections.sort(l2, new MetadataDescriptorComparator()); for (int i = 0; result && i < l1.size(); i++) { result &= MetadataDescriptorUtils.equals(l1.get(i), l2.get(i)); if (!result) { logger.warning("Unequal descriptors: " + l1.get(i) + " -> " + l2.get(i)); } } return result; } /** * Tests two containers, if they are equal.
* {@link MetadataContainer#getPosition()} and * {@link MetadataContainer#getChunkLength()} are ignored. * * @param c1 * container 1 * @param c2 * container 2 * @return true if data is equal. */ public static boolean equals(final MetadataContainer c1, MetadataContainer c2) { if (c1 == c2) { throw new IllegalArgumentException("Made a mistake?"); } boolean result = c1.getGuid().equals(c2.getGuid()); result &= c1.getContainerType() == c2.getContainerType(); result &= c1.getDescriptorCount() == c2.getDescriptorCount(); result &= equals(c1.getDescriptors(), c2.getDescriptors()); return result; } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/audio/asf/data/MetadataDescriptorTest.java0000644000175000017500000005324511222471043032460 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.asf.data; import junit.framework.TestCase; import org.jaudiotagger.tag.TagOptionSingleton; import java.math.BigInteger; import java.util.Arrays; import java.util.Random; /** * Tests the most important data structure for the basic ASF implementations * metadata. * * @author Christian Laireiter */ public class MetadataDescriptorTest extends TestCase { /** * A test descriptor instance. */ private final MetadataDescriptor descriptor1 = new MetadataDescriptor( "testDescriptor"); /** * Helper method for creating string with charAmount of 'a's.
* * @param charAmount * amount of characters to include in result. * @return see description. */ private String createAString(final long charAmount) { final StringBuffer result = new StringBuffer("a"); long amount = charAmount / 2; while (amount > 0) { result.append(result); amount /= 2; } if ((charAmount % 2) != 0) { result.append('a'); } return result.toString(); } /** * This method calls {@link MetadataDescriptor#setString(String)} on given * descriptor and expects an {@link IllegalArgumentException} to be thrown. * * @param desc * descriptor to call. * @param value * value to pass. */ protected void setStringFail(final MetadataDescriptor desc, final String value) { try { desc.setString(value); fail("Exception expected"); } catch (Exception e) { // excpected } } /** * Test method for * {@link org.jaudiotagger.audio.asf.data.MetadataDescriptor#createCopy()}. */ public void testCreateCopy() { final Random rand = new Random(System.currentTimeMillis()); for (ContainerType curr : ContainerType.getOrdered()) { int stream = ContainerType.areInCorrectOrder( ContainerType.METADATA_OBJECT, curr) ? rand.nextInt(5) + 1 : 0; int lang = ContainerType.areInCorrectOrder( ContainerType.METADATA_LIBRARY_OBJECT, curr) ? rand .nextInt(5) + 1 : 0; final MetadataDescriptor orig = new MetadataDescriptor(curr, "name", MetadataDescriptor.TYPE_STRING, stream, lang); final MetadataDescriptor copy = orig.createCopy(); assertNotSame(orig, copy); assertTrue(orig.equals(copy)); assertEquals(orig.getName(), copy.getName()); assertEquals(orig.getContainerType(), copy.getContainerType()); assertEquals(orig.getType(), copy.getType()); assertEquals(orig.getStreamNumber(), copy.getStreamNumber()); assertEquals(orig.getLanguageIndex(), copy.getLanguageIndex()); } } /** * Test method for * {@link org.jaudiotagger.audio.asf.data.MetadataDescriptor#equals(java.lang.Object)} * . */ public void testEqualsObject() { final ContainerType[] types = ContainerType.getOrdered(); for (int i = 0; i < types.length; i++) { MetadataDescriptor one = new MetadataDescriptor(types[i], types[i] .name(), MetadataDescriptor.TYPE_STRING, types[i] .isStreamNumberEnabled() ? 3 : 0, types[i] .isLanguageEnabled() ? 3 : 0); one.setStringValue(createAString(i)); assertFalse(one.equals(null)); assertFalse(one.equals(new Object())); for (int j = 0; j < types.length; j++) { MetadataDescriptor two = new MetadataDescriptor(types[j], types[j].name(), MetadataDescriptor.TYPE_STRING, types[j].isStreamNumberEnabled() ? 3 : 0, types[j] .isLanguageEnabled() ? 3 : 0); two.setStringValue(createAString(j)); assertEquals(i == j, one.equals(two)); two.setStringValue(createAString(types.length)); assertFalse(one.equals(two)); } } } /** * Test method for * {@link org.jaudiotagger.audio.asf.data.MetadataDescriptor#getBoolean()}. */ public void testGetBoolean() { this.descriptor1.setBooleanValue(true); assertTrue(this.descriptor1.getBoolean()); this.descriptor1.setBooleanValue(false); assertFalse(this.descriptor1.getBoolean()); this.descriptor1.setWordValue(1); assertTrue(this.descriptor1.getBoolean()); } /** * Test method for * {@link org.jaudiotagger.audio.asf.data.MetadataDescriptor#getContainerType()} * . */ public void testGetContainerType() { for (ContainerType curr : ContainerType.values()) { assertSame(curr, new MetadataDescriptor(curr, "name", MetadataDescriptor.TYPE_STRING).getContainerType()); } } /** * Test method for * {@link org.jaudiotagger.audio.asf.data.MetadataDescriptor#getLanguageIndex()} * . */ public void testGetLanguageIndex() { assertSame(4, new MetadataDescriptor( ContainerType.METADATA_LIBRARY_OBJECT, "name", MetadataDescriptor.TYPE_STRING, 0, 4).getLanguageIndex()); } /** * Test method for * {@link org.jaudiotagger.audio.asf.data.MetadataDescriptor#getName()}. */ public void testGetName() { assertEquals("descriptorName", new MetadataDescriptor( ContainerType.METADATA_LIBRARY_OBJECT, "descriptorName", MetadataDescriptor.TYPE_STRING, 0, 4).getName()); } /** * Test method for * {@link org.jaudiotagger.audio.asf.data.MetadataDescriptor#getNumber()}. */ public void testGetNumber() { final MetadataDescriptor desc = new MetadataDescriptor("name"); desc.setWordValue(555); assertEquals(555l, desc.getNumber()); desc.setDWordValue(444); assertEquals(444l, desc.getNumber()); desc.setQWordValue(333); assertEquals(333l, desc.getNumber()); desc.setBooleanValue(true); assertEquals(1l, desc.getNumber()); desc.setStringValue("Hallo"); try { desc.getNumber(); fail("Exception excpected."); } catch (UnsupportedOperationException e) { // excpected } desc.setBinaryValue(new byte[] { 1, 1, 1, 1 }); try { desc.getNumber(); fail("Exception excpected."); } catch (UnsupportedOperationException e) { // excpected } } /** * Test method for * {@link org.jaudiotagger.audio.asf.data.MetadataDescriptor#getRawDataSize()} * . */ public void testGetRawDataSize() { this.descriptor1.setBinaryValue(new byte[20]); assertEquals(this.descriptor1.getRawData().length, this.descriptor1 .getRawDataSize()); } /** * Test method for * {@link org.jaudiotagger.audio.asf.data.MetadataDescriptor#getStreamNumber()} * . */ public void testGetStreamNumber() { this.descriptor1.setStreamNumber(55); assertEquals(55, this.descriptor1.getStreamNumber()); assertEquals(55, new MetadataDescriptor(ContainerType.METADATA_OBJECT, "name", MetadataDescriptor.TYPE_STRING, 55, 0) .getStreamNumber()); } /** * Test method for * {@link org.jaudiotagger.audio.asf.data.MetadataDescriptor#getString()}. */ public void testGetString() { this.descriptor1.setBooleanValue(true); assertEquals(Boolean.TRUE.toString(), this.descriptor1.getString()); this.descriptor1.setBooleanValue(false); assertEquals(Boolean.FALSE.toString(), this.descriptor1.getString()); this.descriptor1.setWordValue(334); assertEquals("334", this.descriptor1.getString()); this.descriptor1.setDWordValue(12345); assertEquals("12345", this.descriptor1.getString()); this.descriptor1.setQWordValue(123456); assertEquals("123456", this.descriptor1.getString()); this.descriptor1.setStringValue("this is a test string"); assertEquals("this is a test string", this.descriptor1.getString()); this.descriptor1.setBinaryValue(new byte[20]); assertEquals("binary data", this.descriptor1.getString()); } /** * Test method for * {@link org.jaudiotagger.audio.asf.data.MetadataDescriptor#isEmpty()}. */ public void testIsEmpty() { this.descriptor1.setBinaryValue(new byte[0]); assertTrue(this.descriptor1.isEmpty()); this.descriptor1.setStringValue(""); assertTrue(this.descriptor1.isEmpty()); this.descriptor1.setBinaryValue(new byte[1]); assertFalse(this.descriptor1.isEmpty()); this.descriptor1.setStringValue("a"); assertFalse(this.descriptor1.isEmpty()); this.descriptor1.setBinaryValue(new byte[0]); this.descriptor1.setWordValue(22); assertFalse(this.descriptor1.isEmpty()); this.descriptor1.setBinaryValue(new byte[0]); this.descriptor1.setDWordValue(22); assertFalse(this.descriptor1.isEmpty()); this.descriptor1.setBinaryValue(new byte[0]); this.descriptor1.setQWordValue(22); assertFalse(this.descriptor1.isEmpty()); this.descriptor1.setBinaryValue(new byte[0]); this.descriptor1 .setGUIDValue(GUID.GUID_AUDIO_ERROR_CONCEALEMENT_ABSENT); assertFalse(this.descriptor1.isEmpty()); } /** * Test method for * {@link org.jaudiotagger.audio.asf.data.MetadataDescriptor#setBinaryValue(byte[])} * . */ public void testSetBinaryValue() { MetadataDescriptor desc = new MetadataDescriptor("name", MetadataDescriptor.TYPE_BOOLEAN); desc.setBinaryValue(new byte[0]); assertEquals(MetadataDescriptor.TYPE_BINARY, desc.getType()); assertTrue(desc.isEmpty()); byte[] test = new byte[8192]; Random rand = new Random(System.currentTimeMillis()); rand.nextBytes(test); desc.setBinaryValue(test); assertTrue(Arrays.equals(test, desc.getRawData())); // Test size violations. desc = new MetadataDescriptor(ContainerType.EXTENDED_CONTENT, "name", MetadataDescriptor.TYPE_BINARY); test = new byte[MetadataDescriptor.WORD_MAXVALUE + 1]; try { desc.setBinaryValue(test); fail("Exception expected"); } catch (IllegalArgumentException iae) { // expected } } /** * Test method for * {@link org.jaudiotagger.audio.asf.data.MetadataDescriptor#setBooleanValue(boolean)} * . */ public void testSetBooleanValue() { final MetadataDescriptor desc = new MetadataDescriptor("name", MetadataDescriptor.TYPE_BINARY); desc.setBooleanValue(true); assertEquals(MetadataDescriptor.TYPE_BOOLEAN, desc.getType()); assertEquals(BigInteger.ONE, desc.asNumber()); desc.setBooleanValue(false); assertEquals(BigInteger.ZERO, desc.asNumber()); } /** * Test method for * {@link org.jaudiotagger.audio.asf.data.MetadataDescriptor#setDWordValue(long)} * . */ public void testSetDWordValue() { final BigInteger dwordMax = new BigInteger("FFFFFFFF", 16); final MetadataDescriptor desc = new MetadataDescriptor("name", MetadataDescriptor.TYPE_BINARY); desc.setDWordValue(dwordMax.longValue()); assertEquals(MetadataDescriptor.TYPE_DWORD, desc.getType()); assertEquals(dwordMax.longValue(), desc.getNumber()); assertEquals(dwordMax, desc.asNumber()); final long[] invalidValues = { -1, dwordMax.longValue() + 1 }; for (long curr : invalidValues) { try { desc.setDWordValue(curr); fail("Exception expected with value: " + curr); } catch (IllegalArgumentException iae) { // expected } } } /** * Test method for * {@link org.jaudiotagger.audio.asf.data.MetadataDescriptor#setGUIDValue(org.jaudiotagger.audio.asf.data.GUID)} * . */ public void testSetGUIDValue() { final MetadataDescriptor desc = new MetadataDescriptor("name", MetadataDescriptor.TYPE_BINARY); desc.setGUIDValue(GUID.GUID_UNSPECIFIED); assertEquals(MetadataDescriptor.TYPE_GUID, desc.getType()); for (ContainerType curr : ContainerType.values()) { if (!curr.isGuidEnabled()) { try { new MetadataDescriptor(curr, "bla", MetadataDescriptor.TYPE_GUID); fail("Exception expected"); } catch (IllegalArgumentException e) { // expected } try { new MetadataDescriptor(curr, "bla", MetadataDescriptor.TYPE_STRING) .setGUIDValue(GUID.GUID_AUDIO_ERROR_CONCEALEMENT_ABSENT); fail("Exception expected"); } catch (IllegalArgumentException e) { // expected } } } } /** * Test method for * {@link org.jaudiotagger.audio.asf.data.MetadataDescriptor#setLanguageIndex(int)} * . */ public void testSetLanguageIndex() { final MetadataDescriptor desc = new MetadataDescriptor( ContainerType.METADATA_LIBRARY_OBJECT, "name", MetadataDescriptor.TYPE_BINARY, 0, 0); assertEquals(0, desc.getLanguageIndex()); desc.setLanguageIndex(5); assertEquals(5, desc.getLanguageIndex()); final int[] invalidValues = { -1, 127 }; for (int curr : invalidValues) { try { desc.setLanguageIndex(curr); fail("Exception expected with value: " + curr); } catch (IllegalArgumentException iae) { // expected } } try { new MetadataDescriptor(ContainerType.CONTENT_BRANDING, "name", MetadataDescriptor.TYPE_STRING, 0, 5); fail("Exception expected"); } catch (IllegalArgumentException iae) { // expected } } /** * Test method for * {@link org.jaudiotagger.audio.asf.data.MetadataDescriptor#setQWordValue(java.math.BigInteger)} * . */ public void testSetQWordValueBigInteger() { final BigInteger qwordMax = new BigInteger("FFFFFFFFFFFFFFFF", 16); final MetadataDescriptor desc = new MetadataDescriptor("name", MetadataDescriptor.TYPE_BINARY); desc.setQWordValue(qwordMax); assertEquals(MetadataDescriptor.TYPE_QWORD, desc.getType()); assertEquals(qwordMax, desc.asNumber()); desc.setQWordValue(BigInteger.ONE); assertEquals(BigInteger.ONE, desc.asNumber()); desc.setQWordValue(BigInteger.valueOf(65536 + 255)); assertEquals(BigInteger.valueOf(65536 + 255), desc.asNumber()); final BigInteger[] invalidValues = { BigInteger.valueOf(-1l), qwordMax.add(BigInteger.ONE), null }; for (BigInteger curr : invalidValues) { try { desc.setQWordValue(curr); fail("Exception expected with value: " + curr); } catch (IllegalArgumentException iae) { // expected } } } /** * Test method for * {@link org.jaudiotagger.audio.asf.data.MetadataDescriptor#setQWordValue(long)} * . */ public void testSetQWordValueLong() { final MetadataDescriptor desc = new MetadataDescriptor("name", MetadataDescriptor.TYPE_BINARY); desc.setQWordValue(Long.MAX_VALUE); assertEquals(MetadataDescriptor.TYPE_QWORD, desc.getType()); assertEquals(Long.MAX_VALUE, desc.getNumber()); desc.setQWordValue(Long.MAX_VALUE); assertEquals(BigInteger.valueOf(Long.MAX_VALUE), desc.asNumber()); try { desc.setDWordValue(-1l); fail("Exception expected"); } catch (IllegalArgumentException iae) { // expected } } /** * Test method for * {@link org.jaudiotagger.audio.asf.data.MetadataDescriptor#setStreamNumber(int)} * . */ public void testSetStreamNumber() { final MetadataDescriptor desc = new MetadataDescriptor( ContainerType.METADATA_OBJECT, "name", MetadataDescriptor.TYPE_BINARY, 0, 0); assertEquals(0, desc.getStreamNumber()); desc.setStreamNumber(127); assertEquals(127, desc.getStreamNumber()); final int[] invalidValues = { -1, 128 }; for (int curr : invalidValues) { try { desc.setStreamNumber(curr); fail("Exception expected with value: " + curr); } catch (IllegalArgumentException iae) { // expected } } try { new MetadataDescriptor(ContainerType.EXTENDED_CONTENT, "name", MetadataDescriptor.TYPE_STRING, 5, 0); fail("Exception expected"); } catch (IllegalArgumentException iae) { // expected } } /** * Test method for * {@link org.jaudiotagger.audio.asf.data.MetadataDescriptor#setString(java.lang.String)} * . */ public void testSetString() { MetadataDescriptor desc = new MetadataDescriptor( ContainerType.METADATA_LIBRARY_OBJECT, "name", MetadataDescriptor.TYPE_BOOLEAN); desc.setString("true"); assertTrue(desc.getBoolean()); desc.setString("false"); assertFalse(desc.getBoolean()); // switch to word and test desc.setWordValue(10); desc.setString("60"); assertEquals(60, desc.getNumber()); setStringFail(desc, "nonumber"); setStringFail(desc, String.valueOf(Long.MAX_VALUE)); // too big. setStringFail(desc, String.valueOf(-1)); // too small // switch to dword and test desc.setDWordValue(10); desc.setString("60"); assertEquals(60, desc.getNumber()); setStringFail(desc, "nonumber"); setStringFail(desc, String.valueOf(Long.MAX_VALUE)); // too big. setStringFail(desc, String.valueOf(-1)); // too small // switch to qword and test desc.setQWordValue(10); desc.setString("60"); assertEquals(60, desc.getNumber()); desc.setString(MetadataDescriptor.QWORD_MAXVALUE.toString(10)); setStringFail(desc, "nonumber"); setStringFail(desc, MetadataDescriptor.QWORD_MAXVALUE.add( BigInteger.ONE).toString(10)); // too big. setStringFail(desc, String.valueOf(-1)); // too small // switch to GUID and test desc.setGUIDValue(GUID.GUID_AUDIO_ERROR_CONCEALEMENT_ABSENT); desc.setString(GUID.GUID_AUDIOSTREAM.toString()); setStringFail(desc, ""); setStringFail(desc, GUID.GUID_AUDIOSTREAM.toString() + "a"); } /** * Test method for * {@link org.jaudiotagger.audio.asf.data.MetadataDescriptor#setStringValue(java.lang.String)} * . */ public void testSetStringValue() { MetadataDescriptor desc = new MetadataDescriptor( ContainerType.CONTENT_DESCRIPTION, "name", MetadataDescriptor.TYPE_STRING); desc.setStringValue(createAString(5)); assertEquals(createAString(5), desc.getString()); desc.setStringValue(createAString(0)); assertEquals(createAString(0), desc.getString()); try { desc .setStringValue(createAString(MetadataDescriptor.WORD_MAXVALUE + 1)); fail("Exception expected"); } catch (IllegalArgumentException iae) { // expected } desc = new MetadataDescriptor(ContainerType.EXTENDED_CONTENT, "name", MetadataDescriptor.TYPE_STRING); TagOptionSingleton.getInstance().setTruncateTextWithoutErrors(true); desc .setStringValue(createAString(MetadataDescriptor.WORD_MAXVALUE + 1)); TagOptionSingleton.getInstance().setTruncateTextWithoutErrors(false); try { desc .setStringValue(createAString(MetadataDescriptor.WORD_MAXVALUE + 1)); fail("Exception expected"); } catch (IllegalArgumentException iae) { // expected } desc = new MetadataDescriptor(ContainerType.METADATA_LIBRARY_OBJECT, "name", MetadataDescriptor.TYPE_STRING); desc .setStringValue(createAString(MetadataDescriptor.WORD_MAXVALUE + 1)); } /** * Test method for * {@link org.jaudiotagger.audio.asf.data.MetadataDescriptor#setWordValue(int)} * . */ public void testSetWordValue() { final BigInteger wordMax = new BigInteger("FFFF", 16); final MetadataDescriptor desc = new MetadataDescriptor("name", MetadataDescriptor.TYPE_BINARY); desc.setWordValue(wordMax.intValue()); assertEquals(MetadataDescriptor.TYPE_WORD, desc.getType()); assertEquals(wordMax.intValue(), desc.getNumber()); assertEquals(wordMax, desc.asNumber()); final int[] invalidValues = { -1, wordMax.intValue() + 1 }; for (int curr : invalidValues) { try { desc.setWordValue(curr); fail("Exception expected with value: " + curr); } catch (IllegalArgumentException iae) { // expected } } } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/audio/asf/data/ContainerTypeTest.java0000644000175000017500000002537411222471043031467 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.asf.data; import junit.framework.TestCase; import java.math.BigInteger; /** * Since the tested enumeration {@link ContainerType} is more a definition of * constant nature, these tests are more a safety precaution to prevent numerous * cases of accidental modifications (e.g. changes for debugging purposes). * [thats what tests are always for somehow :)] * * @author Christian Laireiter */ public class ContainerTypeTest extends TestCase { /** * Helper method for creating string with charAmount of 'a's.
* * @param charAmount * amount of characters to include in result. * @return see description. */ private String createAString(int charAmount) { final StringBuffer result = new StringBuffer(); for (int i = 0; i < charAmount; i++) { result.append('a'); } return result.toString(); } /** * Test method for * {@link org.jaudiotagger.audio.asf.data.ContainerType#areInCorrectOrder(org.jaudiotagger.audio.asf.data.ContainerType, org.jaudiotagger.audio.asf.data.ContainerType)} * . */ public void testAreInCorrectOrder() { for (int i = 0; i < ContainerType.values().length; i++) { for (int j = i + 1; j < ContainerType.values().length; j++) { assertTrue(ContainerType.areInCorrectOrder(ContainerType .getOrdered()[i], ContainerType.getOrdered()[j])); } for (int j = 0; j < i; j++) { assertFalse(ContainerType.areInCorrectOrder(ContainerType .getOrdered()[i], ContainerType.getOrdered()[j])); } } } /** * Test method for * {@link org.jaudiotagger.audio.asf.data.ContainerType#assertConstraints(java.lang.String, byte[], int, int, int)} * . */ public void testAssertConstraints() { try { ContainerType.CONTENT_BRANDING.assertConstraints(null, null, 0, 0, 0); fail("Exception should have occurred"); } catch (IllegalArgumentException e) { // expected } } /** * Test method for * {@link org.jaudiotagger.audio.asf.data.ContainerType#checkConstraints(java.lang.String, byte[], int, int, int)} * . */ public void testCheckCtonstraints() { assertNotNull(ContainerType.CONTENT_DESCRIPTION.checkConstraints(null, null, 0, 0, 0)); assertNotNull(ContainerType.CONTENT_DESCRIPTION.checkConstraints( "name", null, 0, 0, 0)); assertNotNull(ContainerType.CONTENT_DESCRIPTION.checkConstraints( createAString(65536), new byte[0], 0, 0, 0)); assertNotNull(ContainerType.CONTENT_DESCRIPTION.checkConstraints( "name", createAString(65536).getBytes(), 0, 0, 0)); assertNotNull(ContainerType.CONTENT_DESCRIPTION.checkConstraints( "name", createAString(30).getBytes(), 5, 0, 0)); assertNull(ContainerType.METADATA_LIBRARY_OBJECT.checkConstraints( "name", createAString(30).getBytes(), 5, 0, 0)); assertNotNull(ContainerType.METADATA_LIBRARY_OBJECT.checkConstraints( "name", createAString(30).getBytes(), MetadataDescriptor.TYPE_BOOLEAN, -1, 0)); assertNotNull(ContainerType.METADATA_LIBRARY_OBJECT.checkConstraints( "name", createAString(30).getBytes(), MetadataDescriptor.TYPE_BOOLEAN, 128, 0)); assertNotNull(ContainerType.METADATA_OBJECT.checkConstraints("name", createAString(30).getBytes(), MetadataDescriptor.TYPE_BOOLEAN, 0, 2)); assertNull(ContainerType.METADATA_LIBRARY_OBJECT.checkConstraints( "name", createAString(30).getBytes(), MetadataDescriptor.TYPE_BOOLEAN, 0, 3)); assertNull(ContainerType.METADATA_LIBRARY_OBJECT.checkConstraints( "name", createAString(30).getBytes(), MetadataDescriptor.TYPE_BOOLEAN, 0, 126)); } /** * Test method for * {@link org.jaudiotagger.audio.asf.data.ContainerType#getContainerGUID()} * . */ public void testGetContainerGUID() { assertEquals(GUID.GUID_CONTENTDESCRIPTION, ContainerType.CONTENT_DESCRIPTION.getContainerGUID()); assertEquals(GUID.GUID_CONTENT_BRANDING, ContainerType.CONTENT_BRANDING.getContainerGUID()); assertEquals(GUID.GUID_EXTENDED_CONTENT_DESCRIPTION, ContainerType.EXTENDED_CONTENT.getContainerGUID()); assertEquals(GUID.GUID_METADATA, ContainerType.METADATA_OBJECT .getContainerGUID()); assertEquals(GUID.GUID_METADATA_LIBRARY, ContainerType.METADATA_LIBRARY_OBJECT.getContainerGUID()); } /** * Test method for * {@link org.jaudiotagger.audio.asf.data.ContainerType#getMaximumDataLength()} * . */ public void testGetMaximumDataLength() { final BigInteger wordSize = new BigInteger("FFFF", 16); final BigInteger dwordSize = new BigInteger("FFFFFFFF", 16); assertEquals(wordSize, ContainerType.CONTENT_DESCRIPTION .getMaximumDataLength()); assertEquals(dwordSize, ContainerType.CONTENT_BRANDING .getMaximumDataLength()); assertEquals(wordSize, ContainerType.EXTENDED_CONTENT .getMaximumDataLength()); assertEquals(wordSize, ContainerType.METADATA_OBJECT .getMaximumDataLength()); assertEquals(dwordSize, ContainerType.METADATA_LIBRARY_OBJECT .getMaximumDataLength()); } /** * Test method for * {@link org.jaudiotagger.audio.asf.data.ContainerType#getOrdered()}. */ public void testGetOrdered() { assertSame(ContainerType.CONTENT_DESCRIPTION, ContainerType .getOrdered()[0]); assertSame(ContainerType.CONTENT_BRANDING, ContainerType.getOrdered()[1]); assertSame(ContainerType.EXTENDED_CONTENT, ContainerType.getOrdered()[2]); assertSame(ContainerType.METADATA_OBJECT, ContainerType.getOrdered()[3]); assertSame(ContainerType.METADATA_LIBRARY_OBJECT, ContainerType .getOrdered()[4]); } /** * Test method for * {@link org.jaudiotagger.audio.asf.data.ContainerType#isGuidEnabled()}. */ public void testIsGuidEnabled() { assertFalse(ContainerType.CONTENT_DESCRIPTION.isGuidEnabled()); assertFalse(ContainerType.CONTENT_BRANDING.isGuidEnabled()); assertFalse(ContainerType.EXTENDED_CONTENT.isGuidEnabled()); assertFalse(ContainerType.METADATA_OBJECT.isGuidEnabled()); assertTrue(ContainerType.METADATA_LIBRARY_OBJECT.isLanguageEnabled()); } /** * Test method for * {@link org.jaudiotagger.audio.asf.data.ContainerType#isLanguageEnabled()} * . */ public void testIsLanguageEnabled() { assertFalse(ContainerType.CONTENT_DESCRIPTION.isLanguageEnabled()); assertFalse(ContainerType.CONTENT_BRANDING.isLanguageEnabled()); assertFalse(ContainerType.EXTENDED_CONTENT.isLanguageEnabled()); assertFalse(ContainerType.METADATA_OBJECT.isLanguageEnabled()); assertTrue(ContainerType.METADATA_LIBRARY_OBJECT.isLanguageEnabled()); } /** * Test method for * {@link org.jaudiotagger.audio.asf.data.ContainerType#isMultiValued()}. */ public void testIsMultiValued() { assertFalse(ContainerType.CONTENT_DESCRIPTION.isMultiValued()); assertFalse(ContainerType.CONTENT_BRANDING.isMultiValued()); assertFalse(ContainerType.EXTENDED_CONTENT.isMultiValued()); assertTrue(ContainerType.METADATA_OBJECT.isMultiValued()); assertTrue(ContainerType.METADATA_LIBRARY_OBJECT.isMultiValued()); } /** * Test method for * {@link org.jaudiotagger.audio.asf.data.ContainerType#isStreamNumberEnabled()} * . */ public void testIsStreamNumberEnabled() { assertFalse(ContainerType.CONTENT_DESCRIPTION.isStreamNumberEnabled()); assertFalse(ContainerType.CONTENT_BRANDING.isStreamNumberEnabled()); assertFalse(ContainerType.EXTENDED_CONTENT.isStreamNumberEnabled()); assertTrue(ContainerType.METADATA_OBJECT.isStreamNumberEnabled()); assertTrue(ContainerType.METADATA_LIBRARY_OBJECT.isGuidEnabled()); } /** * Test method for * {@link org.jaudiotagger.audio.asf.data.ContainerType#isWithinValueRange(long)} * . */ public void testIsWithinThanValueRange() { final BigInteger wordSize = new BigInteger("FFFF", 16); final BigInteger dwordSize = new BigInteger("FFFFFFFF", 16); // Content Description assertTrue(ContainerType.CONTENT_DESCRIPTION.isWithinValueRange(0)); assertTrue(ContainerType.CONTENT_DESCRIPTION .isWithinValueRange(wordSize.longValue())); assertFalse(ContainerType.CONTENT_DESCRIPTION.isWithinValueRange(-1)); assertFalse(ContainerType.CONTENT_DESCRIPTION .isWithinValueRange((wordSize.longValue() + 1l))); // Content Branding assertTrue(ContainerType.CONTENT_BRANDING.isWithinValueRange(0)); assertTrue(ContainerType.CONTENT_BRANDING.isWithinValueRange(dwordSize .longValue())); assertFalse(ContainerType.CONTENT_BRANDING.isWithinValueRange(-1)); assertFalse(ContainerType.CONTENT_BRANDING .isWithinValueRange((dwordSize.longValue() + 1l))); // Extended Content Description assertTrue(ContainerType.EXTENDED_CONTENT.isWithinValueRange(0)); assertTrue(ContainerType.EXTENDED_CONTENT.isWithinValueRange(wordSize .longValue())); assertFalse(ContainerType.EXTENDED_CONTENT.isWithinValueRange(-1)); assertFalse(ContainerType.EXTENDED_CONTENT .isWithinValueRange((wordSize.longValue() + 1l))); // Metadata Object assertTrue(ContainerType.METADATA_OBJECT.isWithinValueRange(0)); assertTrue(ContainerType.METADATA_OBJECT.isWithinValueRange(wordSize .longValue())); assertFalse(ContainerType.METADATA_OBJECT.isWithinValueRange(-1)); assertFalse(ContainerType.METADATA_OBJECT.isWithinValueRange((wordSize .longValue() + 1l))); // Metadata Library Object assertTrue(ContainerType.METADATA_LIBRARY_OBJECT.isWithinValueRange(0)); assertTrue(ContainerType.METADATA_LIBRARY_OBJECT .isWithinValueRange(dwordSize.longValue())); assertFalse(ContainerType.METADATA_LIBRARY_OBJECT .isWithinValueRange(-1)); assertFalse(ContainerType.METADATA_LIBRARY_OBJECT .isWithinValueRange(dwordSize.longValue() + 1l)); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/audio/asf/data/AbstractChunk.java0000644000175000017500000000642211222471043030570 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.asf.data; import org.jaudiotagger.AbstractTestCase; import junit.framework.TestCase; import java.math.BigInteger; /** * Specifies methods for creating {@link Chunk} objects.
* * @author Christian Laireiter * @param * The chunk class under test. */ public abstract class AbstractChunk extends AbstractTestCase { /** * Helper method for creating string with charAmount of 'a's.
* * @param charAmount * amount of characters to include in result. * @return see description. */ public static String createAString(final long charAmount) { final StringBuffer result = new StringBuffer("a"); long amount = charAmount / 2; while (amount > 0) { result.append(result); amount /= 2; } if ((charAmount % 2) != 0) { result.append('a'); } return result.toString(); } /** * Creates a chunk instance. * * @param pos * position of chunk. * @param size * size of chunk * @return Chunk instance. */ protected abstract T createChunk(final long pos, final BigInteger size); /** * Invokes {@link #createChunk(long, BigInteger)} and returns possible * occurred exceptions. * * @param pos * position * @param size * size * @return possibly occurred exception */ private Exception failOn(final long pos, final BigInteger size) { Exception result = null; try { createChunk(pos, size); } catch (Exception e) { result = e; } return result; } /** * Tests the correctness of various methods from {@link Chunk} directly * after construction.
*/ public void testBasicChunkMethods() { final BigInteger size = BigInteger.TEN; final long position = 300; final long newPosition = 400; T chunk = createChunk(position, size); assertNotNull(chunk); assertEquals(position, chunk.getPosition()); assertEquals(size, chunk.getChunkLength()); assertEquals(size.add(BigInteger.valueOf(position)).longValue(), chunk .getChunkEnd()); /* * No change the position */ chunk.setPosition(newPosition); assertEquals(newPosition, chunk.getPosition()); assertEquals(size, chunk.getChunkLength()); assertEquals(size.add(BigInteger.valueOf(newPosition)).longValue(), chunk .getChunkEnd()); } /** * Tests chunk creation by using invalid and valid creation arguments on * {@link #createChunk(long, BigInteger)}. */ public void testChunkCreation() { assertTrue(failOn(-1, null) instanceof IllegalArgumentException); assertTrue(failOn(0, null) instanceof IllegalArgumentException); assertTrue(failOn(0, BigInteger.TEN.negate()) instanceof IllegalArgumentException); assertTrue(failOn(0, BigInteger.ONE.negate()) instanceof IllegalArgumentException); assertNull(failOn(0, BigInteger.ZERO)); assertNull(failOn(0, BigInteger.TEN)); assertNull(failOn(100, BigInteger.TEN)); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/audio/asf/data/ChunkContainerTest.java0000644000175000017500000001031211222471043031600 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.asf.data; import java.math.BigInteger; import java.util.Arrays; import java.util.Collection; import java.util.HashSet; import java.util.Set; /** * Tests the correctness of the {@link ChunkContainer} implementation. * * @author Christian Laireiter */ public class ChunkContainerTest extends AbstractChunk { /** * {@inheritDoc} */ @Override protected ChunkContainer createChunk(long pos, BigInteger size) { return new ChunkContainer(GUID.GUID_UNSPECIFIED, pos, size); } /** * Creates an instance of {@link ChunkContainer} and adds a {@link Chunk} * for each (and with) GUID of {@link GUID#KNOWN_GUIDS}.
* * @return container with chunks added. */ protected ChunkContainer createFilledChunk() { final ChunkContainer container = createChunk(0, BigInteger.ZERO); long position = 0; for (GUID curr : GUID.KNOWN_GUIDS) { container.addChunk(new Chunk(curr, position++, BigInteger.ZERO)); } return container; } /** * Test method for * {@link org.jaudiotagger.audio.asf.data.ChunkContainer#addChunk(org.jaudiotagger.audio.asf.data.Chunk)} * . */ public void testAddChunk() { final ChunkContainer container = createFilledChunk(); long position = container.getChunks().size() + 1; for (GUID curr : GUID.KNOWN_GUIDS) { try { container .addChunk(new Chunk(curr, position++, BigInteger.ZERO)); if (!curr.equals(GUID.GUID_STREAM)) { fail("Only stream chunks may be added multiple times."); } } catch (IllegalArgumentException iae) { // expected } } assertTrue(ChunkContainer.chunkstartsUnique(container)); try { container.addChunk(new Chunk(GUID.GUID_STREAM, 0, BigInteger.ZERO)); } catch (AssertionError ae) { // expected, if assertions enabled } assertFalse(ChunkContainer.chunkstartsUnique(container)); } /** * Test method for * {@link org.jaudiotagger.audio.asf.data.ChunkContainer#getChunks()}. */ public void testGetChunks() { /* * We know createFilledChunk(), so we work with all GUIDs */ final ChunkContainer container = createFilledChunk(); final Collection chunks = container.getChunks(); final Set known = new HashSet(Arrays .asList(GUID.KNOWN_GUIDS)); for (Chunk curr : chunks) { known.remove(curr.getGuid()); } assertTrue(known.isEmpty()); } /** * Test method for * {@link org.jaudiotagger.audio.asf.data.ChunkContainer#getFirst(org.jaudiotagger.audio.asf.data.GUID, java.lang.Class)} * . */ public void testGetFirst() { final AudioStreamChunk audio = new AudioStreamChunk(BigInteger.ZERO); final VideoStreamChunk video = new VideoStreamChunk(BigInteger.ZERO); video.setPosition(1); ChunkContainer container = createChunk(0, BigInteger.ZERO); container.addChunk(audio); container.addChunk(video); assertSame(audio, container.getFirst(GUID.GUID_STREAM, AudioStreamChunk.class)); assertNull(container.getFirst(GUID.GUID_STREAM, VideoStreamChunk.class)); container = createChunk(0, BigInteger.ZERO); container.addChunk(video); container.addChunk(audio); assertSame(video, container.getFirst(GUID.GUID_STREAM, VideoStreamChunk.class)); assertNull(container.getFirst(GUID.GUID_STREAM, AudioStreamChunk.class)); } /** * Test method for * {@link org.jaudiotagger.audio.asf.data.ChunkContainer#hasChunkByGUID(org.jaudiotagger.audio.asf.data.GUID)} * . */ public void testHasChunkByGUID() { final ChunkContainer container = createChunk(0, BigInteger.ZERO); final ChunkContainer container2 = createFilledChunk(); for (GUID curr : GUID.KNOWN_GUIDS) { assertFalse(container.hasChunkByGUID(curr)); assertTrue(container2.hasChunkByGUID(curr)); } } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/audio/asf/data/MetadataDescriptorComparator.java0000644000175000017500000000205611222471043033642 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.asf.data; import java.io.Serializable; import java.util.Comparator; /** * @author Christian Laireiter * */ public class MetadataDescriptorComparator implements Comparator, Serializable { /** * */ private static final long serialVersionUID = 4503738612948660496L; /** * {@inheritDoc} */ public int compare(MetadataDescriptor o1, MetadataDescriptor o2) { assert o1 != o2; assert o1 != null && o2 != null; int result = o1.getContainerType().ordinal() - o2.getContainerType().ordinal(); result = 0; if (result == 0) { result = o1.getName().compareTo(o2.getName()); } if (result == 0) { result = o1.getType() - o2.getType(); } if (result == 0) { result = o1.getLanguageIndex() - o2.getLanguageIndex(); } if (result == 0) { result = o1.getStreamNumber() - o2.getStreamNumber(); } return result; } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/audio/asf/data/MetadataContainerTest.java0000644000175000017500000001174411222471043032262 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.asf.data; import java.math.BigInteger; import java.util.ArrayList; import java.util.Arrays; import java.util.List; /** * Implementation of {@link AbstractMetadataContainer} which tests * {@link MetadataContainer} for the container types:
*

    *
  • {@link ContainerType#EXTENDED_CONTENT}
  • *
  • {@link ContainerType#METADATA_OBJECT}
  • *
  • {@link ContainerType#METADATA_LIBRARY_OBJECT}
  • *
* * @author Christian Laireiter */ public class MetadataContainerTest extends AbstractMetadataContainer { /** * {@inheritDoc} */ @Override protected MetadataContainer createChunk(long pos, BigInteger size) { return new MetadataContainer(GUID.GUID_EXTENDED_CONTENT_DESCRIPTION, pos, size); } /** * {@inheritDoc} */ @Override protected MetadataDescriptor[] createSupportedDescriptors( MetadataContainer container) { assertTrue(Arrays.asList( new ContainerType[] { ContainerType.EXTENDED_CONTENT, ContainerType.METADATA_LIBRARY_OBJECT, ContainerType.METADATA_OBJECT }).contains( container.getContainerType())); final List supported = new ArrayList(); for (int nameCount = 0; nameCount < 5; nameCount++) { int typeCount = container.getContainerType().isGuidEnabled() ? 6 : 5; // 6 is the GUID for (int type = 0; type <= typeCount; type++) { if (type == MetadataDescriptor.TYPE_BINARY) { continue; } String descName = "name" + nameCount + "type" + type; final List tmp = new ArrayList(); tmp.add(new MetadataDescriptor(container.getContainerType(), descName, type, 0, 0)); if (container.getContainerType().isMultiValued()) { tmp .add(new MetadataDescriptor(container .getContainerType(), descName, type, 0, 0)); } if (container.getContainerType().isStreamNumberEnabled()) { tmp .add(new MetadataDescriptor(container .getContainerType(), descName, type, 1, 0)); } if (container.getContainerType().isLanguageEnabled()) { tmp .add(new MetadataDescriptor(container .getContainerType(), descName, type, 0, 1)); } int cnt = 0; for (MetadataDescriptor curr : tmp) { if (type == MetadataDescriptor.TYPE_GUID) { curr.setGUIDValue(GUID.KNOWN_GUIDS[type]); } else { curr.setString(String.valueOf(type+(cnt++))); } } supported.addAll(tmp); } } return supported.toArray(new MetadataDescriptor[supported.size()]); } /** * {@inheritDoc} */ @Override protected MetadataContainer[] createTestContainers() { return new MetadataContainer[] { new MetadataContainer(ContainerType.EXTENDED_CONTENT), new MetadataContainer(ContainerType.METADATA_OBJECT), new MetadataContainer(ContainerType.METADATA_LIBRARY_OBJECT) }; } /** * Test method for * {@link org.jaudiotagger.audio.asf.data.MetadataContainer#assertDescriptor(java.lang.String)} * . */ public void testAssertDescriptorString() { for (MetadataContainer curr : createTestContainers()) { curr.assertDescriptor("testKey"); assertTrue(curr.hasDescriptor("testKey")); } } /** * Test method for * {@link org.jaudiotagger.audio.asf.data.MetadataContainer#assertDescriptor(java.lang.String, int)} * . */ public void testAssertDescriptorStringInt() { for (int i = 0; i <= 5; i++) { for (MetadataContainer curr : createTestContainers()) { curr.assertDescriptor("testKey", i); assertEquals(i, curr.getDescriptorsByName("testKey").get(0) .getType()); } } } /** * Test method for * {@link org.jaudiotagger.audio.asf.data.MetadataContainer#getValueFor(java.lang.String)} * . */ public void testGetValueFor() { for (MetadataContainer curr : createTestContainers()) { assertEquals("", curr.getValueFor("testKey")); assertFalse(curr.hasDescriptor("testKey")); curr.setStringValue("testKey", "testValue"); assertTrue(curr.hasDescriptor("testKey")); assertEquals("testValue", curr.getValueFor("testKey")); } } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/audio/asf/data/GUIDTest.java0000644000175000017500000000362011222471043027421 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.asf.data; import org.jaudiotagger.AbstractTestCase; import junit.framework.TestCase; import java.util.Locale; /** * Tests the correctness of {@link GUID}. * * @author Christian Laireiter */ public class GUIDTest extends AbstractTestCase { /** * Test method for * {@link org.jaudiotagger.audio.asf.data.GUID#getConfigured(org.jaudiotagger.audio.asf.data.GUID)} * . */ public void testGetConfigured() { for (GUID curr : GUID.KNOWN_GUIDS) { // Loose all information except GUID raw data GUID newOne = new GUID(curr.getBytes()); // assert that the configured GUID instance is returned. assertSame(curr, GUID.getConfigured(newOne)); } } /** * Test method for * {@link org.jaudiotagger.audio.asf.data.GUID#parseGUID(java.lang.String)}. */ public void testParseGUID() { for (GUID curr : GUID.KNOWN_GUIDS) { assertSame(curr, GUID .getConfigured(GUID.parseGUID(curr.toString()))); } final String toParse = "f8699e40-5b4d-11cf-a8fd-00805f5c442b"; GUID parsed = GUID.parseGUID(toParse); assertEquals(GUID.GUID_AUDIOSTREAM, parsed); parsed = GUID.parseGUID(toParse.toUpperCase(Locale.getDefault())); assertEquals(GUID.GUID_AUDIOSTREAM, parsed); } /** * Test method for {@link org.jaudiotagger.audio.asf.data.GUID#toString()}. */ public void testToString() { assertEquals("f8699e40-5b4d-11cf-a8fd-00805f5c442b", GUID.GUID_AUDIOSTREAM.toString()); } /** * This method tests creation attempts of invalid GUIDs.
*/ public void testFailures() { try { new GUID(new byte[0]); fail ("Exception expected"); } catch (IllegalArgumentException iae){ // expected } } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/audio/asf/data/MetadataDescriptorUtils.java0000644000175000017500000000222711222471043032633 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.asf.data; import java.util.Arrays; /** * This class provides methods for working with {@link MetadataDescriptor} * objects.
* * @author Christian Laireiter */ public final class MetadataDescriptorUtils { /** * This method tests, if both descriptors contain the same content and type, * as well as if they belong to the same * {@linkplain MetadataDescriptor#getContainerType() container}. * * @param m1 * descriptor to test * @param m2 * descriptor to test * @return true if they represent the same. * @throws IllegalArgumentException * if they are the same object (m1 == m2). */ public static boolean equals(final MetadataDescriptor m1, final MetadataDescriptor m2) { if (m1 == m2) { throw new IllegalArgumentException("Made a mistake ?"); } boolean result = m1.getType() == m2.getType(); result &= m1.getContainerType() == m2.getContainerType(); result &= Arrays.equals(m1.getRawData(), m2.getRawData()); return result; } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/audio/asf/data/AbstractMetadataContainer.java0000644000175000017500000001027211222471043033101 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.asf.data; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * This class tests the correct implementation of {@link MetadataContainer} * implementations.
* * @author Christian Laireiter * @param * The actual container implementation. */ public abstract class AbstractMetadataContainer extends AbstractChunk { /** * This method creates some or all supported descriptors for the given * container.
* Passed containers will be one of {@link #createTestContainers()}.
* * @param container * the container to create test descriptors for. * * @return descriptors which are supported by the given container instance. */ protected abstract MetadataDescriptor[] createSupportedDescriptors( T container); /** * This method creates container instances which are to be tested.
* * @return all containers that may be tested by the implementation. */ protected abstract T[] createTestContainers(); /** * tests the following Methods.
*
    *
  • {@link AbstractMetadataContainer#createTestContainers()}
  • *
  • * {@link AbstractMetadataContainer#createSupportedDescriptors(MetadataContainer)} *
  • *
  • {@link MetadataContainer#isAddSupported(MetadataDescriptor)}
  • *
  • {@link MetadataContainer#addDescriptor(MetadataDescriptor)}
  • *
  • {@link MetadataContainer#hasDescriptor(String)}
  • *
  • {@link MetadataContainer#getDescriptorCount()}
  • *
  • {@link MetadataContainer#getDescriptors()}
  • *
  • {@link MetadataContainer#getDescriptorsByName(String)}
  • *
  • {@link MetadataContainer#containsDescriptor(MetadataDescriptor)}
  • *
  • {@link MetadataContainer#removeDescriptorsByName(String)}
  • *
*/ public void testVariousDescriptorMethods() { for (T curr : createTestContainers()) { assertTrue(curr.isEmpty()); final Map> descriptorMap = new HashMap>(); final List allDescriptors = new ArrayList(); for (MetadataDescriptor desc : createSupportedDescriptors(curr)) { if (!curr.isAddSupported(desc)) { System.out.println("laal"); } assertTrue(desc.toString(), curr.isAddSupported(desc)); curr.addDescriptor(desc); allDescriptors.add(desc); List list = descriptorMap.get(desc .getName()); if (list == null) { list = new ArrayList(); descriptorMap.put(desc.getName(), list); } list.add(desc); } assertFalse(allDescriptors.isEmpty()); final List removed = new ArrayList( allDescriptors); removed.removeAll(curr.getDescriptors()); assertTrue(removed.isEmpty()); assertEquals(allDescriptors.size(), curr.getDescriptorCount()); assertTrue(allDescriptors.containsAll(curr.getDescriptors())); for (String name : descriptorMap.keySet()) { assertTrue(curr.hasDescriptor(name)); assertTrue(descriptorMap.get(name).containsAll( curr.getDescriptorsByName(name))); } for (MetadataDescriptor desc : allDescriptors) { assertTrue(curr.containsDescriptor(desc)); } assertFalse(curr.isEmpty()); for (String name : descriptorMap.keySet()) { List list = descriptorMap.get(name); curr.removeDescriptorsByName(name); for (MetadataDescriptor desc : list) { assertFalse(curr.containsDescriptor(desc)); } assertFalse(curr.hasDescriptor(name)); } } } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/audio/asf/io/0000755000175000017500000000000011556363176024704 5ustar drazzibdrazziblibjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/audio/asf/io/ContentBrandingData.java0000644000175000017500000000222111222471043031374 0ustar drazzibdrazzib/** * */ package org.jaudiotagger.audio.asf.io; import org.jaudiotagger.audio.asf.util.Utils; import junit.framework.TestCase; import org.jaudiotagger.audio.asf.data.ContentBranding; import org.jaudiotagger.audio.asf.data.GUID; import org.jaudiotagger.audio.asf.data.MetadataContainerUtils; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; /** * @author Christian Laireiter * */ public class ContentBrandingData extends TestCase { public void testContentBrandingWriteRead() throws IOException { ContentBranding cb = new ContentBranding(); cb.setCopyRightURL("CP URL"); ByteArrayOutputStream bos = new ByteArrayOutputStream(); cb.writeInto(bos); assertEquals(cb.getCurrentAsfChunkSize(), bos.toByteArray().length); ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); assertEquals(GUID.GUID_CONTENT_BRANDING, Utils.readGUID(bis)); ContentBranding read = (ContentBranding) new ContentBrandingReader() .read(GUID.GUID_CONTENT_BRANDING, bis, 0); MetadataContainerUtils.equals(cb, read); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/audio/asf/io/AsfHeaderUtils.java0000644000175000017500000000742411305747025030410 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.asf.io; import junit.framework.TestCase; import org.jaudiotagger.audio.asf.data.ContainerType; import org.jaudiotagger.audio.asf.data.MetadataContainer; import org.jaudiotagger.audio.asf.data.AsfHeader; import org.jaudiotagger.audio.asf.data.Chunk; import org.jaudiotagger.audio.asf.data.ChunkContainer; import org.jaudiotagger.audio.asf.data.GUID; import org.jaudiotagger.audio.asf.util.Utils; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; import java.math.BigInteger; import java.util.Calendar; import java.util.Collection; import java.util.Date; /** * * @author Christian Laireiter */ public final class AsfHeaderUtils extends TestCase { public final static int BINARY_PRINT_COLUMNS = 20; public static String binary2ByteArrayString(final byte[] data) { StringBuffer result = new StringBuffer(); for (int i = 0; data != null && i < data.length; i++) { if (i > 0 && i % BINARY_PRINT_COLUMNS == 0) { result.append(Utils.LINE_SEPARATOR); } result.append("0x"); String hex = Integer.toHexString(data[i] & 0xFF); if (hex.length() == 1) { hex = "0" + hex; } result.append(hex); if (i < data.length - 1) { result.append(','); } } return result.toString(); } public static Chunk findChunk(Collection chunk, GUID chunkGUID) { Chunk result = null; for (Chunk curr : chunk) { if (curr instanceof ChunkContainer) { result = findChunk(((ChunkContainer) curr).getChunks(), chunkGUID); if (result != null) { break; } } else { if (curr.getGuid().equals(chunkGUID)) { result = curr; break; } } } return result; } public static byte[] getFirstChunk(File file, GUID chunkGUID) throws IOException { RandomAccessFile asfFile = null; try { asfFile = new RandomAccessFile(file,"r"); byte[] result = new byte[0]; AsfHeader readHeader = AsfHeaderReader.readHeader(asfFile); Chunk found = findChunk(readHeader.getChunks(), chunkGUID); if (found != null) { byte[] tmp = new byte[(int) found.getChunkLength().longValue()]; asfFile.seek(found.getPosition()); asfFile.readFully(tmp); result = tmp; } return result; } finally { asfFile.close(); } } public static MetadataContainer readContainer(File file, ContainerType type) throws IOException { AsfHeader readHeader = AsfHeaderReader.readHeader(file); return readHeader.findMetadataContainer(type); } /** * Test date conversion */ //TODO we dont know this is correct because need an independent way of checking our figures with an ASF file, //the previous calculation appeard incorrect. public void testDateHeaderConversion() { Calendar cal = org.jaudiotagger.audio.asf.util.Utils.getDateOf(BigInteger.valueOf(1964448000)); System.out.println(cal.getTime()); assertEquals(-11644273555200l,cal.getTimeInMillis()); } /** * Test to show the calculation done to derive the DIFF_BETWEEN_ASF_DATE_AND_JAVA_DATE constant */ public void testConversionDateConstant() { Date date1 = new Date((1601-1900),0,1); Date date2 = new Date((1970-1900),0,1); assertEquals(11644470000000l,date2.getTime() - date1.getTime()); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/audio/GenericTest.java0000644000175000017500000000176411041064726026577 0ustar drazzibdrazzibpackage org.jaudiotagger.audio; import junit.framework.TestCase; import java.io.File; /** * Generic tests */ public class GenericTest extends TestCase { /** * Test File filter, postive and negative tests */ public void testReadFileUnsupportedFormat() { File nonAudioFile = new File("testdata", "coverart.bmp"); AudioFileFilter aff = new AudioFileFilter(); aff.accept(nonAudioFile); assertFalse(aff.accept(nonAudioFile)); File audioFile = new File("testdata", "test.m4a"); aff.accept(audioFile); assertTrue(aff.accept(audioFile)); audioFile = new File("testdata", "test.flac"); aff.accept(audioFile); assertTrue(aff.accept(audioFile)); audioFile = new File("testdata", "test.ogg"); aff.accept(audioFile); assertTrue(aff.accept(audioFile)); audioFile = new File("testdata", "testV1.mp3"); aff.accept(audioFile); assertTrue(aff.accept(audioFile)); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/audio/flac/0000755000175000017500000000000011556363176024431 5ustar drazzibdrazziblibjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/audio/flac/FlacHeaderTest.java0000644000175000017500000001374311470746136030116 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.flac; import junit.framework.TestCase; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.audio.flac.metadatablock.MetadataBlockDataPicture; import org.jaudiotagger.audio.generic.Utils; import org.jaudiotagger.tag.FieldKey; import org.jaudiotagger.tag.flac.FlacTag; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; import org.jaudiotagger.tag.reference.PictureTypes; import javax.imageio.ImageIO; import java.awt.image.BufferedImage; import java.io.File; /** * basic Flac tests */ public class FlacHeaderTest extends TestCase { public void testReadFileWithVorbisComment() { Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test.flac"); AudioFile f = AudioFileIO.read(testFile); assertEquals("192", f.getAudioHeader().getBitRate()); assertEquals("FLAC 16 bits", f.getAudioHeader().getEncodingType()); assertEquals("2", f.getAudioHeader().getChannels()); assertEquals("44100", f.getAudioHeader().getSampleRate()); assertTrue(f.getTag() instanceof FlacTag); FlacTag tag = (FlacTag) f.getTag(); FlacInfoReader infoReader = new FlacInfoReader(); assertEquals(6, infoReader.countMetaBlocks(f.getFile())); //Ease of use methods for common fields assertEquals("Artist", tag.getFirst(FieldKey.ARTIST)); assertEquals("Album", tag.getFirst(FieldKey.ALBUM)); assertEquals("test3", tag.getFirst(FieldKey.TITLE)); assertEquals("comments", tag.getFirst(FieldKey.COMMENT)); assertEquals("1971", tag.getFirst(FieldKey.YEAR)); assertEquals("4", tag.getFirst(FieldKey.TRACK)); assertEquals("Crossover", tag.getFirst(FieldKey.GENRE)); //Lookup by generickey assertEquals("Artist", tag.getFirst(FieldKey.ARTIST)); assertEquals("Album", tag.getFirst(FieldKey.ALBUM)); assertEquals("test3", tag.getFirst(FieldKey.TITLE)); assertEquals("comments", tag.getFirst(FieldKey.COMMENT)); assertEquals("1971", tag.getFirst(FieldKey.YEAR)); assertEquals("4", tag.getFirst(FieldKey.TRACK)); assertEquals("Composer", tag.getFirst(FieldKey.COMPOSER)); //Images assertEquals(2, tag.getFields(FieldKey.COVER_ART).size()); assertEquals(2, tag.getFields(FieldKey.COVER_ART.name()).size()); assertEquals(2, tag.getImages().size()); //Image MetadataBlockDataPicture image = tag.getImages().get(0); assertEquals((int) PictureTypes.DEFAULT_ID, (int) image.getPictureType()); assertEquals("image/png", image.getMimeType()); assertFalse(image.isImageUrl()); assertEquals("", image.getImageUrl()); assertEquals("", image.getDescription()); assertEquals(0, image.getWidth()); assertEquals(0, image.getHeight()); assertEquals(0, image.getColourDepth()); assertEquals(0, image.getIndexedColourCount()); assertEquals(18545, image.getImageData().length); //Image Link image = tag.getImages().get(1); assertEquals(7, (int) image.getPictureType()); assertEquals("-->", image.getMimeType()); assertTrue(image.isImageUrl()); assertEquals("coverart.gif", Utils.getString(image.getImageData(), 0, image.getImageData().length, TextEncoding.CHARSET_ISO_8859_1)); assertEquals("coverart.gif", image.getImageUrl()); //Create Image Link tag.getImages().add((MetadataBlockDataPicture) tag.createLinkedArtworkField("../testdata/coverart.jpg")); f.commit(); f = AudioFileIO.read(testFile); image = tag.getImages().get(2); assertEquals(3, (int) image.getPictureType()); assertEquals("-->", image.getMimeType()); assertTrue(image.isImageUrl()); assertEquals("../testdata/coverart.jpg", Utils.getString(image.getImageData(), 0, image.getImageData().length, TextEncoding.CHARSET_ISO_8859_1)); assertEquals("../testdata/coverart.jpg", image.getImageUrl()); //Can we actually createField Buffered Image from the url of course remember url is relative to the audio file //not where we run the program from File file = new File("testdatatmp", image.getImageUrl()); assertTrue(file.exists()); BufferedImage bi = ImageIO.read(file); assertEquals(200, bi.getWidth()); assertEquals(200, bi.getHeight()); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * Only contains vorbis comment with minimum encoder info */ public void testReadFileWithOnlyVorbisCommentEncoder() { Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test2.flac"); AudioFile f = AudioFileIO.read(testFile); assertEquals("192", f.getAudioHeader().getBitRate()); assertEquals("FLAC 16 bits", f.getAudioHeader().getEncodingType()); assertEquals("2", f.getAudioHeader().getChannels()); assertEquals("44100", f.getAudioHeader().getSampleRate()); assertTrue(f.getTag() instanceof FlacTag); FlacTag tag = (FlacTag) f.getTag(); FlacInfoReader infoReader = new FlacInfoReader(); assertEquals(4, infoReader.countMetaBlocks(f.getFile())); //No Images assertEquals(0, tag.getImages().size()); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/audio/ogg/0000755000175000017500000000000011556363176024300 5ustar drazzibdrazziblibjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/audio/ogg/OggPageTest.java0000644000175000017500000001500611271532347027306 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.ogg; import junit.framework.TestCase; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.ogg.util.OggPageHeader; import java.io.File; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.util.Date; /** * Basic Vorbis tests */ public class OggPageTest extends TestCase { public void testReadOggPagesNew() { System.out.println("start:"+new Date()); Exception exceptionCaught = null; int count = 0; try { File testFile = AbstractTestCase.copyAudioToTmp("test.ogg", new File("testReadAllOggPages.ogg")); RandomAccessFile raf = new RandomAccessFile(testFile, "r"); OggPageHeader lastPageHeader = null; ByteBuffer bb = ByteBuffer.allocate((int)(raf.length())); raf.getChannel().read(bb); bb.rewind(); System.out.println("ByteBuffer:"+bb.position()+":"+bb.limit()); while(bb.hasRemaining()) { System.out.println("pageHeader starts at:" + bb.position()); OggPageHeader pageHeader = OggPageHeader.read(bb); int packetLengthTotal = 0; for (OggPageHeader.PacketStartAndLength packetAndStartLength : pageHeader.getPacketList()) { packetLengthTotal += packetAndStartLength.getLength(); } assertEquals(pageHeader.getPageLength(), packetLengthTotal); if (lastPageHeader != null) { assertEquals(lastPageHeader.getPageSequence() + 1, pageHeader.getPageSequence()); } System.out.println("pageHeader finishes at:" + bb.position()); System.out.println(pageHeader + "\n"); bb.position(bb.position() + pageHeader.getPageLength()); count++; lastPageHeader = pageHeader; } System.out.println(raf.length() + ":"+raf.getFilePointer()); assertEquals(raf.length(), raf.getFilePointer()); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(10, count); System.out.println("end:"+new Date()); } /** * Test Read Ogg Pages ok */ public void testReadAllOggPages() { System.out.println("start:"+new Date()); Exception exceptionCaught = null; int count = 0; try { File testFile = AbstractTestCase.copyAudioToTmp("test.ogg", new File("testReadAllOggPages.ogg")); RandomAccessFile raf = new RandomAccessFile(testFile, "r"); OggPageHeader lastPageHeader = null; while (raf.getFilePointer() < raf.length()) { System.out.println("pageHeader starts at:" + raf.getFilePointer()); OggPageHeader pageHeader = OggPageHeader.read(raf); int packetLengthTotal = 0; for (OggPageHeader.PacketStartAndLength packetAndStartLength : pageHeader.getPacketList()) { packetLengthTotal += packetAndStartLength.getLength(); } assertEquals(pageHeader.getPageLength(), packetLengthTotal); if (lastPageHeader != null) { assertEquals(lastPageHeader.getPageSequence() + 1, pageHeader.getPageSequence()); } System.out.println("pageHeader finishes at:" + raf.getFilePointer()); System.out.println(pageHeader + "\n"); raf.seek(raf.getFilePointer() + pageHeader.getPageLength()); count++; lastPageHeader = pageHeader; } assertEquals(raf.length(), raf.getFilePointer()); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(10, count); System.out.println("end:"+new Date()); } /** * test Read Ogg Pages ok */ public void testReadAllOggPagesLargeFile() { Exception exceptionCaught = null; int count = 0; try { File testFile = AbstractTestCase.copyAudioToTmp("testlargeimage.ogg", new File("testReadAllOggPagesLargeFile.ogg")); RandomAccessFile raf = new RandomAccessFile(testFile, "r"); while (raf.getFilePointer() < raf.length()) { System.out.println("pageHeader starts at:" + raf.getFilePointer()); OggPageHeader pageHeader = OggPageHeader.read(raf); System.out.println("pageHeader finishes at:" + raf.getFilePointer()); System.out.println(pageHeader + "\n"); raf.seek(raf.getFilePointer() + pageHeader.getPageLength()); count++; } assertEquals(raf.length(), raf.getFilePointer()); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(25, count); } /** * test Read Ogg Pages ok */ public void testReadAllOggPagesLargeFileNew() { Exception exceptionCaught = null; int count = 0; try { File testFile = AbstractTestCase.copyAudioToTmp("testlargeimage.ogg", new File("testReadAllOggPagesLargeFile.ogg")); RandomAccessFile raf = new RandomAccessFile(testFile, "r"); OggPageHeader lastPageHeader = null; ByteBuffer bb = ByteBuffer.allocate((int)(raf.length())); raf.getChannel().read(bb); bb.rewind(); System.out.println("ByteBuffer:"+bb.position()+":"+bb.limit()); while(bb.hasRemaining()) { System.out.println("pageHeader starts at:" + bb.position()); OggPageHeader pageHeader = OggPageHeader.read(bb); System.out.println("pageHeader finishes at:" + bb.position()); System.out.println(pageHeader + "\n"); bb.position(bb.position() + pageHeader.getPageLength()); count++; } assertEquals(raf.length(), raf.getFilePointer()); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(25, count); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/audio/ogg/OggVorbisHeaderTest.java0000644000175000017500000002706111277264361031017 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.ogg; import junit.framework.TestCase; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.audio.ogg.util.OggPageHeader; import org.jaudiotagger.tag.FieldKey; import org.jaudiotagger.tag.vorbiscomment.VorbisCommentFieldKey; import org.jaudiotagger.tag.vorbiscomment.VorbisCommentTag; import java.io.File; import java.io.RandomAccessFile; /** * Basic Vorbis tests */ public class OggVorbisHeaderTest extends TestCase { /** * Testing reading of vorbis audio header info */ public void testReadFile() { Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test.ogg", new File("testReadFile.ogg")); AudioFile f = AudioFileIO.read(testFile); //assertEquals("192",f.getAudioHeader().getBitRate()); //assertEquals("Ogg Vorbis v1",f.getAudioHeader().getEncodingType()); //assertEquals("2",f.getAudioHeader().getChannels()); //assertEquals("44100",f.getAudioHeader().getSampleRate()); assertTrue(f.getTag() instanceof VorbisCommentTag); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * Testing reading of vorbis audio header info *

* TODO, need to replace with file that is not copyrighted */ public void testReadPaddedFile() { Exception exceptionCaught = null; try { File orig = new File("testdata", "test2.ogg"); if (!orig.isFile()) { return; } File testFile = AbstractTestCase.copyAudioToTmp("test2.ogg", new File("test2.ogg")); AudioFile f = AudioFileIO.read(testFile); f.getTag().setField(FieldKey.ALBUM,"bbbbbbb"); f.commit(); //assertEquals("192",f.getAudioHeader().getBitRate()); //assertEquals("Ogg Vorbis v1",f.getAudioHeader().getEncodingType()); //assertEquals("2",f.getAudioHeader().getChannels()); //assertEquals("44100",f.getAudioHeader().getSampleRate()); //assertTrue(f.getTag() instanceof VorbisCommentTag); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * Test simple write to file, comment and setup header just spread over one page before and afterwards */ public void testWriteFile() { Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("test.ogg", new File("testWriteTagToFile.ogg")); AudioFile f = AudioFileIO.read(testFile); //Size of VorbisComment should increase assertTrue(f.getTag() instanceof VorbisCommentTag); f.getTag().setField(FieldKey.ALBUM,"bbbbbbb"); f.commit(); f = AudioFileIO.read(testFile); assertTrue(f.getTag() instanceof VorbisCommentTag); assertEquals("bbbbbbb", f.getTag().getFirst(FieldKey.ALBUM)); OggFileReader ofr = new OggFileReader(); OggPageHeader oph = ofr.readOggPageHeader(new RandomAccessFile(testFile, "r"), 0); assertEquals(30, oph.getPageLength()); assertEquals(0, oph.getPageSequence()); assertEquals(559748870, oph.getSerialNumber()); assertEquals(-2111591604, oph.getCheckSum()); oph = ofr.readOggPageHeader(new RandomAccessFile(testFile, "r"), 1); assertEquals(3745, oph.getPageLength()); assertEquals(1, oph.getPageSequence()); assertEquals(559748870, oph.getSerialNumber()); assertEquals(233133993, oph.getCheckSum()); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * Test writing to file where previoslu comment was spread over many pages, now only over one so the sequence nos * for all subsequent pages have to be redone with checksums */ public void testWritePreviouslyLargeFile() { Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("testlargeimage.ogg", new File("testWritePreviouslyLargeFile.ogg")); AudioFile f = AudioFileIO.read(testFile); //Size of VorbisComment should decrease just setting a nonsical but muuch smaller value for image assertTrue(f.getTag() instanceof VorbisCommentTag); VorbisCommentTag vorbisTag = (VorbisCommentTag) f.getTag(); vorbisTag.setField(vorbisTag.createField(VorbisCommentFieldKey.COVERART, "ccc")); f.commit(); f = AudioFileIO.read(testFile); assertTrue(f.getTag() instanceof VorbisCommentTag); OggFileReader ofr = new OggFileReader(); OggPageHeader oph = ofr.readOggPageHeader(new RandomAccessFile(testFile, "r"), 0); assertEquals(30, oph.getPageLength()); assertEquals(0, oph.getPageSequence()); assertEquals(559748870, oph.getSerialNumber()); assertEquals(-2111591604, oph.getCheckSum()); assertEquals(2, oph.getHeaderType()); oph = ofr.readOggPageHeader(new RandomAccessFile(testFile, "r"), 1); assertEquals(3783, oph.getPageLength()); assertEquals(1, oph.getPageSequence()); assertEquals(559748870, oph.getSerialNumber()); assertEquals(1677220898, oph.getCheckSum()); assertEquals(0, oph.getHeaderType()); //First Audio Frames oph = ofr.readOggPageHeader(new RandomAccessFile(testFile, "r"), 2); assertEquals(4156, oph.getPageLength()); assertEquals(2, oph.getPageSequence()); assertEquals(559748870, oph.getSerialNumber()); assertEquals(1176378771, oph.getCheckSum()); assertEquals(0, oph.getHeaderType()); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * Testing writing multi page comment header (existing header is multipage) */ public void testLargeWriteFile() { Exception exceptionCaught = null; try { File testFile = AbstractTestCase.copyAudioToTmp("testlargeimage.ogg", new File("testLargeWriteFile.ogg")); AudioFile f = AudioFileIO.read(testFile); //Size of VorbisComment should increase assertTrue(f.getTag() instanceof VorbisCommentTag); f.getTag().setField(FieldKey.ALBUM,"bbbbbbb"); f.commit(); f = AudioFileIO.read(testFile); assertTrue(f.getTag() instanceof VorbisCommentTag); assertEquals("bbbbbbb", f.getTag().getFirst(FieldKey.ALBUM)); OggFileReader ofr = new OggFileReader(); OggPageHeader oph = ofr.readOggPageHeader(new RandomAccessFile(testFile, "r"), 0); assertEquals(30, oph.getPageLength()); assertEquals(0, oph.getPageSequence()); assertEquals(559748870, oph.getSerialNumber()); assertEquals(-2111591604, oph.getCheckSum()); assertEquals(2, oph.getHeaderType()); oph = ofr.readOggPageHeader(new RandomAccessFile(testFile, "r"), 1); assertEquals(65025, oph.getPageLength()); assertEquals(1, oph.getPageSequence()); assertEquals(559748870, oph.getSerialNumber()); assertEquals(-1172108515, oph.getCheckSum()); assertEquals(0, oph.getHeaderType()); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); } /** * Testing writing multi page comment header where the setup header has to be split because there is not enough * room on the last Comment header Page */ public void testLargeWriteFileWithSplitSetupHeader() { Exception exceptionCaught = null; int count = 0; try { File testFile = AbstractTestCase.copyAudioToTmp("testlargeimage.ogg", new File("testAwkwardSizeWriteFile.ogg")); AudioFile f = AudioFileIO.read(testFile); //Size of VorbisComment should increase and to a level that the setupheader cant fit completely //in last page pf comment header so has to be split over two pages assertTrue(f.getTag() instanceof VorbisCommentTag); StringBuffer sb = new StringBuffer(); for (int i = 0; i < 24000; i++) { sb.append("z"); } f.getTag().setField(FieldKey.ALBUM,"bbbbbbb"); f.getTag().setField(FieldKey.TITLE,sb.toString()); f.commit(); f = AudioFileIO.read(testFile); assertTrue(f.getTag() instanceof VorbisCommentTag); assertEquals("bbbbbbb", f.getTag().getFirst(FieldKey.ALBUM)); assertEquals(sb.toString(), f.getTag().getFirst(FieldKey.TITLE)); //Identification Header type oggFlag =2 OggFileReader ofr = new OggFileReader(); OggPageHeader oph = ofr.readOggPageHeader(new RandomAccessFile(testFile, "r"), 0); assertEquals(30, oph.getPageLength()); assertEquals(0, oph.getPageSequence()); assertEquals(559748870, oph.getSerialNumber()); assertEquals(-2111591604, oph.getCheckSum()); assertEquals(2, oph.getHeaderType()); //Start of Comment Header, ogg Flag =0 oph = ofr.readOggPageHeader(new RandomAccessFile(testFile, "r"), 1); assertEquals(65025, oph.getPageLength()); assertEquals(1, oph.getPageSequence()); assertEquals(559748870, oph.getSerialNumber()); assertEquals(2037809131, oph.getCheckSum()); assertEquals(0, oph.getHeaderType()); //Continuing Comment Header, ogg Flag = 1 oph = ofr.readOggPageHeader(new RandomAccessFile(testFile, "r"), 2); assertEquals(1, oph.getHeaderType()); //Addtional checking that audio is also readable RandomAccessFile raf = new RandomAccessFile(testFile, "r"); OggPageHeader lastPageHeader = null; while (raf.getFilePointer() < raf.length()) { OggPageHeader pageHeader = OggPageHeader.read(raf); int packetLengthTotal = 0; for (OggPageHeader.PacketStartAndLength packetAndStartLength : pageHeader.getPacketList()) { packetLengthTotal += packetAndStartLength.getLength(); } assertEquals(pageHeader.getPageLength(), packetLengthTotal); if (lastPageHeader != null) { assertEquals(lastPageHeader.getPageSequence() + 1, pageHeader.getPageSequence()); } raf.seek(raf.getFilePointer() + pageHeader.getPageLength()); count++; lastPageHeader = pageHeader; } assertEquals(raf.length(), raf.getFilePointer()); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertNull(exceptionCaught); assertEquals(26, count); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/audio/mp3/0000755000175000017500000000000011556363176024223 5ustar drazzibdrazziblibjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/audio/mp3/LoggingTest.java0000644000175000017500000001076711102355012027300 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.mp3; import junit.framework.TestCase; import org.jaudiotagger.AbstractTestCase; import org.w3c.dom.Document; import org.xml.sax.InputSource; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathExpression; import javax.xml.xpath.XPathFactory; import java.io.File; import java.io.StringReader; import java.util.Date; import java.util.Locale; import java.text.SimpleDateFormat; /** * User: paul * Date: 09-Nov-2007 */ public class LoggingTest extends TestCase { /** * Check that xml is in xml format, and cleared out for each file */ public void testDisplayAsXml() throws Exception { XPathFactory xpf = XPathFactory.newInstance(); XPath path = xpf.newXPath(); XPathExpression xpath1 = path.compile("/file/tag/body/frame/@id"); File testFile = AbstractTestCase.copyAudioToTmp("Issue92.id3", "testV1.mp3"); MP3File mp3File = new MP3File(testFile); System.out.println(mp3File.displayStructureAsXML()); assertEquals("TALB", xpath1.evaluate(new InputSource(new StringReader(mp3File.displayStructureAsXML())))); File testFile2 = AbstractTestCase.copyAudioToTmp("Issue96-1.id3", "testV1.mp3"); MP3File mp3File2 = new MP3File(testFile2); System.out.println(mp3File2.displayStructureAsXML()); Document d2 = DocumentBuilderFactory.newInstance() .newDocumentBuilder().parse(new InputSource(new StringReader(mp3File2.displayStructureAsXML()))); assertEquals("TIT2", xpath1.evaluate(new InputSource(new StringReader(mp3File2.displayStructureAsXML())))); } public void testDateParsing() throws Exception { SimpleDateFormat timeInFormat = new SimpleDateFormat("ss"); SimpleDateFormat timeOutFormat = new SimpleDateFormat("mm:ss"); //handles negative numbers Date timeIn = timeInFormat.parse(String.valueOf(-100)); assertEquals("58:20",timeOutFormat.format(timeIn)); //handles large numbers timeIn = timeInFormat.parse(String.valueOf(1000000000)); assertEquals("46:40",timeOutFormat.format(timeIn)); //handles floats timeIn = timeInFormat.parse(String.valueOf(28.0f)); assertEquals("00:28",timeOutFormat.format(timeIn)); //handles floats with fractional timeIn = timeInFormat.parse(String.valueOf(28.05d)); assertEquals("00:28",timeOutFormat.format(timeIn)); //handles floats with fractional timeIn = timeInFormat.parse(String.valueOf(28.05122222d)); assertEquals("00:28",timeOutFormat.format(timeIn)); //handles floats with fractional timeIn = timeInFormat.parse(String.valueOf(-28.05122222d)); assertEquals("59:32",timeOutFormat.format(timeIn)); //Change Locale Locale.setDefault(Locale.US); timeInFormat = new SimpleDateFormat("ss"); timeIn = timeInFormat.parse(String.valueOf(-28.05122222d)); assertEquals("59:32",timeOutFormat.format(timeIn)); //Change Locale Locale.setDefault(Locale.FRANCE); timeInFormat = new SimpleDateFormat("ss"); timeIn = timeInFormat.parse(String.valueOf(-28.05122222d)); assertEquals("59:32",timeOutFormat.format(timeIn)); } public static int count=0; public void testMultiThreadedSimpleDataAccess() throws Exception { final SimpleDateFormat timeInFormat = new SimpleDateFormat("ss"); final Thread[] threads = new Thread[1000]; for(int i = 0; i < 1000; i++) { threads[i] = new Thread(new Runnable() { public void run() { try { //Must be synced fo rtest to reliably pass synchronized(timeInFormat) { Date timeIn = timeInFormat.parse(String.valueOf(-28.05122222d)); } } catch (RuntimeException e) { e.printStackTrace(); count++; } catch (Exception e) { e.printStackTrace(); count ++; } } }); } for(int i = 0; i < 1000; i++) { threads[i].start(); } assertEquals(0,count); } } libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/audio/mp3/MP3AudioHeaderTest.java0000644000175000017500000006460211276777123030430 0ustar drazzibdrazzib/* * Jaudiotagger Copyright (C)2004,2005 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can getFields a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.audio.mp3; import junit.framework.TestCase; import org.jaudiotagger.AbstractTestCase; import org.jaudiotagger.audio.exceptions.InvalidAudioFrameException; import org.jaudiotagger.tag.FieldKey; import org.jaudiotagger.tag.TagOptionSingleton; import org.jaudiotagger.tag.id3.ID3v24Tag; import java.io.File; import java.text.SimpleDateFormat; import java.util.Date; /** */ public class MP3AudioHeaderTest extends TestCase { public void testReadV1L3VbrOld() { Exception exceptionCaught = null; File testFile = AbstractTestCase.copyAudioToTmp("testV1vbrOld0.mp3"); MP3AudioHeader mp3AudioHeader = null; try { mp3AudioHeader = new MP3File(testFile).getMP3AudioHeader(); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals("44100", mp3AudioHeader.getSampleRate()); assertEquals("00:14", mp3AudioHeader.getTrackLengthAsString()); assertTrue(mp3AudioHeader.isVariableBitRate()); assertEquals(MPEGFrameHeader.mpegVersionMap.get(new Integer(MPEGFrameHeader.VERSION_1)), mp3AudioHeader.getMpegVersion()); assertEquals(MPEGFrameHeader.mpegLayerMap.get(new Integer(MPEGFrameHeader.LAYER_III)), mp3AudioHeader.getMpegLayer()); assertEquals(MPEGFrameHeader.modeMap.get(new Integer(MPEGFrameHeader.MODE_MONO)), mp3AudioHeader.getChannels()); assertTrue(mp3AudioHeader.isOriginal()); assertFalse(mp3AudioHeader.isCopyrighted()); assertFalse(mp3AudioHeader.isPrivate()); assertFalse(mp3AudioHeader.isProtected()); assertEquals("~127", mp3AudioHeader.getBitRate()); assertEquals("mp3", mp3AudioHeader.getEncodingType()); assertEquals("LAME3.96r", mp3AudioHeader.getEncoder()); } public void testReadV1L3VbrNew() { Exception exceptionCaught = null; File testFile = AbstractTestCase.copyAudioToTmp("testV1vbrNew0.mp3"); MP3AudioHeader mp3AudioHeader = null; try { mp3AudioHeader = new MP3File(testFile).getMP3AudioHeader(); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals("44100", mp3AudioHeader.getSampleRate()); assertEquals("00:14", mp3AudioHeader.getTrackLengthAsString()); assertTrue(mp3AudioHeader.isVariableBitRate()); assertEquals(MPEGFrameHeader.mpegVersionMap.get(new Integer(MPEGFrameHeader.VERSION_1)), mp3AudioHeader.getMpegVersion()); assertEquals(MPEGFrameHeader.mpegLayerMap.get(new Integer(MPEGFrameHeader.LAYER_III)), mp3AudioHeader.getMpegLayer()); assertEquals(MPEGFrameHeader.modeMap.get(new Integer(MPEGFrameHeader.MODE_MONO)), mp3AudioHeader.getChannels()); assertTrue(mp3AudioHeader.isOriginal()); assertFalse(mp3AudioHeader.isCopyrighted()); assertFalse(mp3AudioHeader.isPrivate()); assertFalse(mp3AudioHeader.isProtected()); assertEquals("~127", mp3AudioHeader.getBitRate()); assertEquals("mp3", mp3AudioHeader.getEncodingType()); assertEquals("LAME3.96r", mp3AudioHeader.getEncoder()); } public void testReadV1L3Cbr128() { Exception exceptionCaught = null; File testFile = AbstractTestCase.copyAudioToTmp("testV1Cbr128.mp3"); MP3AudioHeader mp3AudioHeader = null; try { mp3AudioHeader = new MP3File(testFile).getMP3AudioHeader(); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals("44100", mp3AudioHeader.getSampleRate()); assertEquals("00:14", mp3AudioHeader.getTrackLengthAsString()); assertFalse(mp3AudioHeader.isVariableBitRate()); assertEquals(MPEGFrameHeader.mpegVersionMap.get(new Integer(MPEGFrameHeader.VERSION_1)), mp3AudioHeader.getMpegVersion()); assertEquals(MPEGFrameHeader.mpegLayerMap.get(new Integer(MPEGFrameHeader.LAYER_III)), mp3AudioHeader.getMpegLayer()); assertEquals(MPEGFrameHeader.modeMap.get(new Integer(MPEGFrameHeader.MODE_MONO)), mp3AudioHeader.getChannels()); assertTrue(mp3AudioHeader.isOriginal()); assertFalse(mp3AudioHeader.isCopyrighted()); assertFalse(mp3AudioHeader.isPrivate()); assertFalse(mp3AudioHeader.isProtected()); assertEquals("128", mp3AudioHeader.getBitRate()); assertEquals("mp3", mp3AudioHeader.getEncodingType()); assertEquals("LAME3.96r", mp3AudioHeader.getEncoder()); } public void testReadV1L3Cbr192() { Exception exceptionCaught = null; File testFile = AbstractTestCase.copyAudioToTmp("testV1Cbr192.mp3"); MP3AudioHeader mp3AudioHeader = null; try { mp3AudioHeader = new MP3File(testFile).getMP3AudioHeader(); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals("44100", mp3AudioHeader.getSampleRate()); assertEquals("00:14", mp3AudioHeader.getTrackLengthAsString()); assertFalse(mp3AudioHeader.isVariableBitRate()); assertEquals(MPEGFrameHeader.mpegVersionMap.get(new Integer(MPEGFrameHeader.VERSION_1)), mp3AudioHeader.getMpegVersion()); assertEquals(MPEGFrameHeader.mpegLayerMap.get(new Integer(MPEGFrameHeader.LAYER_III)), mp3AudioHeader.getMpegLayer()); assertEquals(MPEGFrameHeader.modeMap.get(new Integer(MPEGFrameHeader.MODE_MONO)), mp3AudioHeader.getChannels()); assertTrue(mp3AudioHeader.isOriginal()); assertFalse(mp3AudioHeader.isCopyrighted()); assertFalse(mp3AudioHeader.isPrivate()); assertFalse(mp3AudioHeader.isProtected()); assertEquals("192", mp3AudioHeader.getBitRate()); assertEquals("mp3", mp3AudioHeader.getEncodingType()); assertEquals("LAME3.96r", mp3AudioHeader.getEncoder()); } public void testReadV2L3VbrOld() { Exception exceptionCaught = null; File testFile = AbstractTestCase.copyAudioToTmp("testV2vbrOld0.mp3"); MP3AudioHeader mp3AudioHeader = null; try { mp3AudioHeader = new MP3File(testFile).getMP3AudioHeader(); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals("22050", mp3AudioHeader.getSampleRate()); assertEquals("00:14", mp3AudioHeader.getTrackLengthAsString()); assertTrue(mp3AudioHeader.isVariableBitRate()); assertEquals(MPEGFrameHeader.mpegVersionMap.get(new Integer(MPEGFrameHeader.VERSION_2)), mp3AudioHeader.getMpegVersion()); assertEquals(MPEGFrameHeader.mpegLayerMap.get(new Integer(MPEGFrameHeader.LAYER_III)), mp3AudioHeader.getMpegLayer()); assertEquals(MPEGFrameHeader.modeMap.get(new Integer(MPEGFrameHeader.MODE_MONO)), mp3AudioHeader.getChannels()); assertTrue(mp3AudioHeader.isOriginal()); assertFalse(mp3AudioHeader.isCopyrighted()); assertFalse(mp3AudioHeader.isPrivate()); assertFalse(mp3AudioHeader.isProtected()); assertEquals("~127", mp3AudioHeader.getBitRate()); assertEquals("mp3", mp3AudioHeader.getEncodingType()); assertEquals("LAME3.96r", mp3AudioHeader.getEncoder()); } public void testReadV2L3MonoVbrNew() { Exception exceptionCaught = null; File testFile = AbstractTestCase.copyAudioToTmp("testV2vbrNew0.mp3"); MP3AudioHeader mp3AudioHeader = null; try { mp3AudioHeader = new MP3File(testFile).getMP3AudioHeader(); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals("22050", mp3AudioHeader.getSampleRate()); assertEquals("00:14", mp3AudioHeader.getTrackLengthAsString()); assertTrue(mp3AudioHeader.isVariableBitRate()); assertEquals(MPEGFrameHeader.mpegVersionMap.get(new Integer(MPEGFrameHeader.VERSION_2)), mp3AudioHeader.getMpegVersion()); assertEquals(MPEGFrameHeader.mpegLayerMap.get(new Integer(MPEGFrameHeader.LAYER_III)), mp3AudioHeader.getMpegLayer()); assertEquals(MPEGFrameHeader.modeMap.get(new Integer(MPEGFrameHeader.MODE_MONO)), mp3AudioHeader.getChannels()); assertTrue(mp3AudioHeader.isOriginal()); assertFalse(mp3AudioHeader.isCopyrighted()); assertFalse(mp3AudioHeader.isPrivate()); assertFalse(mp3AudioHeader.isProtected()); assertEquals("~127", mp3AudioHeader.getBitRate()); assertEquals("mp3", mp3AudioHeader.getEncodingType()); assertEquals("LAME3.96r", mp3AudioHeader.getEncoder()); } public void testReadV1L2Stereo() { Exception exceptionCaught = null; File testFile = AbstractTestCase.copyAudioToTmp("testV1L2stereo.mp3"); MP3AudioHeader mp3AudioHeader = null; try { mp3AudioHeader = new MP3File(testFile).getMP3AudioHeader(); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals("44100", mp3AudioHeader.getSampleRate()); //assertEquals("00:13", mp3AudioHeader.getTrackLengthAsString()); Incorrectly returning 6 assertFalse(mp3AudioHeader.isVariableBitRate()); assertEquals(MPEGFrameHeader.mpegVersionMap.get(new Integer(MPEGFrameHeader.VERSION_1)), mp3AudioHeader.getMpegVersion()); assertEquals(MPEGFrameHeader.mpegLayerMap.get(new Integer(MPEGFrameHeader.LAYER_II)), mp3AudioHeader.getMpegLayer()); assertEquals(MPEGFrameHeader.modeMap.get(new Integer(MPEGFrameHeader.MODE_STEREO)), mp3AudioHeader.getChannels()); assertFalse(mp3AudioHeader.isOriginal()); assertFalse(mp3AudioHeader.isCopyrighted()); assertFalse(mp3AudioHeader.isPrivate()); assertFalse(mp3AudioHeader.isProtected()); assertEquals("192", mp3AudioHeader.getBitRate()); assertEquals("mp3", mp3AudioHeader.getEncodingType()); assertEquals("", mp3AudioHeader.getEncoder()); } public void testReadV1L2Mono() { Exception exceptionCaught = null; File testFile = AbstractTestCase.copyAudioToTmp("testV1L2mono.mp3"); MP3AudioHeader mp3AudioHeader = null; try { mp3AudioHeader = new MP3File(testFile).getMP3AudioHeader(); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals("44100", mp3AudioHeader.getSampleRate()); assertEquals("00:13", mp3AudioHeader.getTrackLengthAsString()); assertFalse(mp3AudioHeader.isVariableBitRate()); assertEquals(MPEGFrameHeader.mpegVersionMap.get(new Integer(MPEGFrameHeader.VERSION_1)), mp3AudioHeader.getMpegVersion()); assertEquals(MPEGFrameHeader.mpegLayerMap.get(new Integer(MPEGFrameHeader.LAYER_II)), mp3AudioHeader.getMpegLayer()); assertEquals(MPEGFrameHeader.modeMap.get(new Integer(MPEGFrameHeader.MODE_MONO)), mp3AudioHeader.getChannels()); assertFalse(mp3AudioHeader.isOriginal()); assertFalse(mp3AudioHeader.isCopyrighted()); assertFalse(mp3AudioHeader.isPrivate()); assertFalse(mp3AudioHeader.isProtected()); assertEquals("192", mp3AudioHeader.getBitRate()); assertEquals("mp3", mp3AudioHeader.getEncodingType()); assertEquals("", mp3AudioHeader.getEncoder()); } public void testReadV25L3VbrOld() { Exception exceptionCaught = null; File testFile = AbstractTestCase.copyAudioToTmp("testV25vbrOld0.mp3"); MP3AudioHeader mp3AudioHeader = null; try { mp3AudioHeader = new MP3File(testFile).getMP3AudioHeader(); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals("12000", mp3AudioHeader.getSampleRate()); assertEquals("00:14", mp3AudioHeader.getTrackLengthAsString()); assertTrue(mp3AudioHeader.isVariableBitRate()); assertEquals(MPEGFrameHeader.mpegVersionMap.get(new Integer(MPEGFrameHeader.VERSION_2_5)), mp3AudioHeader.getMpegVersion()); assertEquals(MPEGFrameHeader.mpegLayerMap.get(new Integer(MPEGFrameHeader.LAYER_III)), mp3AudioHeader.getMpegLayer()); assertEquals(MPEGFrameHeader.modeMap.get(new Integer(MPEGFrameHeader.MODE_MONO)), mp3AudioHeader.getChannels()); assertTrue(mp3AudioHeader.isOriginal()); assertFalse(mp3AudioHeader.isCopyrighted()); assertFalse(mp3AudioHeader.isPrivate()); assertFalse(mp3AudioHeader.isProtected()); assertEquals("~128", mp3AudioHeader.getBitRate()); assertEquals("mp3", mp3AudioHeader.getEncodingType()); assertEquals("LAME3.96r", mp3AudioHeader.getEncoder()); } public void testReadV25L3() { Exception exceptionCaught = null; File testFile = AbstractTestCase.copyAudioToTmp("testV25.mp3"); MP3AudioHeader mp3AudioHeader = null; try { mp3AudioHeader = new MP3File(testFile).getMP3AudioHeader(); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals("12000", mp3AudioHeader.getSampleRate()); assertEquals("00:14", mp3AudioHeader.getTrackLengthAsString()); assertFalse(mp3AudioHeader.isVariableBitRate()); assertEquals(MPEGFrameHeader.mpegVersionMap.get(new Integer(MPEGFrameHeader.VERSION_2_5)), mp3AudioHeader.getMpegVersion()); assertEquals(MPEGFrameHeader.mpegLayerMap.get(new Integer(MPEGFrameHeader.LAYER_III)), mp3AudioHeader.getMpegLayer()); assertEquals(MPEGFrameHeader.modeMap.get(new Integer(MPEGFrameHeader.MODE_MONO)), mp3AudioHeader.getChannels()); assertTrue(mp3AudioHeader.isOriginal()); assertFalse(mp3AudioHeader.isCopyrighted()); assertFalse(mp3AudioHeader.isPrivate()); assertFalse(mp3AudioHeader.isProtected()); assertEquals("16", mp3AudioHeader.getBitRate()); //TODO Might be wrong assertEquals("mp3", mp3AudioHeader.getEncodingType()); assertEquals("", mp3AudioHeader.getEncoder()); //No Lame header so blank } public void testReadV25L3VbrNew() { Exception exceptionCaught = null; File testFile = AbstractTestCase.copyAudioToTmp("testV25vbrNew0.mp3"); MP3AudioHeader mp3AudioHeader = null; try { mp3AudioHeader = new MP3File(testFile).getMP3AudioHeader(); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals("12000", mp3AudioHeader.getSampleRate()); assertEquals("00:14", mp3AudioHeader.getTrackLengthAsString()); assertTrue(mp3AudioHeader.isVariableBitRate()); assertEquals(MPEGFrameHeader.mpegVersionMap.get(new Integer(MPEGFrameHeader.VERSION_2_5)), mp3AudioHeader.getMpegVersion()); assertEquals(MPEGFrameHeader.mpegLayerMap.get(new Integer(MPEGFrameHeader.LAYER_III)), mp3AudioHeader.getMpegLayer()); assertEquals(MPEGFrameHeader.modeMap.get(new Integer(MPEGFrameHeader.MODE_MONO)), mp3AudioHeader.getChannels()); assertTrue(mp3AudioHeader.isOriginal()); assertFalse(mp3AudioHeader.isCopyrighted()); assertFalse(mp3AudioHeader.isPrivate()); assertFalse(mp3AudioHeader.isProtected()); assertEquals("~128", mp3AudioHeader.getBitRate()); assertEquals("mp3", mp3AudioHeader.getEncodingType()); assertEquals("LAME3.96r", mp3AudioHeader.getEncoder()); } public void testReadV2L2() { Exception exceptionCaught = null; File testFile = AbstractTestCase.copyAudioToTmp("testV2L2.mp3"); MP3AudioHeader mp3AudioHeader = null; try { mp3AudioHeader = new MP3File(testFile).getMP3AudioHeader(); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals("24000", mp3AudioHeader.getSampleRate()); assertFalse(mp3AudioHeader.isVariableBitRate()); assertEquals(MPEGFrameHeader.mpegVersionMap.get(new Integer(MPEGFrameHeader.VERSION_2)), mp3AudioHeader.getMpegVersion()); assertEquals(MPEGFrameHeader.mpegLayerMap.get(new Integer(MPEGFrameHeader.LAYER_II)), mp3AudioHeader.getMpegLayer()); assertEquals(MPEGFrameHeader.modeMap.get(new Integer(MPEGFrameHeader.MODE_JOINT_STEREO)), mp3AudioHeader.getChannels()); //assertEquals("00:14", mp3AudioHeader.getTrackLengthAsString()); not working returning 0 assertTrue(mp3AudioHeader.isOriginal()); assertFalse(mp3AudioHeader.isCopyrighted()); assertFalse(mp3AudioHeader.isPrivate()); assertTrue(mp3AudioHeader.isProtected()); assertEquals("16", mp3AudioHeader.getBitRate()); assertEquals("mp3", mp3AudioHeader.getEncodingType()); assertEquals("", mp3AudioHeader.getEncoder()); //No Lame header so blank } public void testReadV2L3Stereo() { Exception exceptionCaught = null; File testFile = AbstractTestCase.copyAudioToTmp("testV2L3Stereo.mp3"); MP3AudioHeader mp3AudioHeader = null; try { mp3AudioHeader = new MP3File(testFile).getMP3AudioHeader(); } catch (Exception e) { exceptionCaught = e; } assertNull(exceptionCaught); assertEquals("24000", mp3AudioHeader.getSampleRate()); //assertEquals("00:14", mp3AudioHeader.getTrackLengthAsString()); assertFalse(mp3AudioHeader.isVariableBitRate()); assertEquals(MPEGFrameHeader.mpegVersionMap.get(new Integer(MPEGFrameHeader.VERSION_2)), mp3AudioHeader.getMpegVersion()); assertEquals(MPEGFrameHeader.mpegLayerMap.get(new Integer(MPEGFrameHeader.LAYER_III)), mp3AudioHeader.getMpegLayer()); assertEquals(MPEGFrameHeader.modeMap.get(new Integer(MPEGFrameHeader.MODE_JOINT_STEREO)), mp3AudioHeader.getChannels()); //assertEquals("00:14", mp3AudioHeader.getTrackLengthAsString()); not working returning 0 assertTrue(mp3AudioHeader.isOriginal()); assertFalse(mp3AudioHeader.isCopyrighted()); assertFalse(mp3AudioHeader.isPrivate()); assertFalse(mp3AudioHeader.isProtected()); assertEquals("64", mp3AudioHeader.getBitRate()); assertEquals("mp3", mp3AudioHeader.getEncodingType()); assertEquals("LAME3.97 ", mp3AudioHeader.getEncoder()); //TODO should we be removing trailing space } /** * Test trying to parse an mp3 file which is not a valid MP3 fails gracefully with expected exception */ public void testIssue79() { Exception exceptionCaught = null; File testFile = AbstractTestCase.copyAudioToTmp("Issue79.mp3"); MP3AudioHeader mp3AudioHeader = null; try { mp3AudioHeader = new MP3File(testFile).getMP3AudioHeader(); } catch (Exception e) { exceptionCaught = e; } assertTrue(exceptionCaught instanceof InvalidAudioFrameException); } /** * Test trying to parse an mp3 file which is not a valid MP3 and is extremely small * Should fail gracefully */ public void testIssue81() { Exception exceptionCaught = null; File testFile = AbstractTestCase.copyAudioToTmp("Issue81.mp3"); MP3AudioHeader mp3AudioHeader = null; try { mp3AudioHeader = new MP3File(testFile).getMP3AudioHeader(); } catch (Exception e) { exceptionCaught = e; } assertTrue(exceptionCaught instanceof InvalidAudioFrameException); } /** * Test trying to parse an mp3 file which is a valid MP3 but problems with frame */ public void testIssue199() { Exception exceptionCaught = null; File testFile = AbstractTestCase.copyAudioToTmp("testV2L2.mp3"); MP3AudioHeader mp3AudioHeader = null; try { mp3AudioHeader = new MP3File(testFile).getMP3AudioHeader(); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertTrue(exceptionCaught == null); } /** * Test mp3s display tracks over an hour correctly, dont actually have any such track so have to emulate * the mp3 rather than calling it directly. */ public void testIssue85() { Exception exceptionCaught = null; int NO_SECONDS_IN_HOUR = 3600; SimpleDateFormat timeInFormat = new SimpleDateFormat("ss"); SimpleDateFormat timeOutFormat = new SimpleDateFormat("mm:ss"); SimpleDateFormat timeOutOverAnHourFormat = new SimpleDateFormat("kk:mm:ss"); try { int lengthLessThanHour = 3500; Date timeIn = timeInFormat.parse(String.valueOf(lengthLessThanHour)); assertEquals("58:20", timeOutFormat.format(timeIn)); int lengthIsAnHour = 3600; timeIn = timeInFormat.parse(String.valueOf(lengthIsAnHour)); assertEquals("01:00:00", timeOutOverAnHourFormat.format(timeIn)); int lengthMoreThanHour = 4000; timeIn = timeInFormat.parse(String.valueOf(lengthMoreThanHour)); assertEquals("01:06:40", timeOutOverAnHourFormat.format(timeIn)); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertTrue(exceptionCaught == null); } /** * Test trying to parse an mp3 file with a ID3 tag header reporting to short causing * jaudiotagger to end up reading mp3 header from too early causing audio header to be * read incorrectly */ public void testIssue110() { File orig = new File("testdata", "test28.mp3"); if (!orig.isFile()) { return; } Exception exceptionCaught = null; File testFile = AbstractTestCase.copyAudioToTmp("test28.mp3"); MP3AudioHeader mp3AudioHeader = null; try { mp3AudioHeader = new MP3File(testFile).getMP3AudioHeader(); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertTrue(exceptionCaught == null); assertEquals(MPEGFrameHeader.mpegVersionMap.get(new Integer(MPEGFrameHeader.VERSION_1)), mp3AudioHeader.getMpegVersion()); assertEquals(MPEGFrameHeader.mpegLayerMap.get(new Integer(MPEGFrameHeader.LAYER_III)), mp3AudioHeader.getMpegLayer()); assertEquals(MPEGFrameHeader.modeMap.get(new Integer(MPEGFrameHeader.MODE_JOINT_STEREO)), mp3AudioHeader.getChannels()); } public void testReadVRBIFrame() { File orig = new File("testdata", "test30.mp3"); if (!orig.isFile()) { return; } Exception exceptionCaught = null; File testFile = AbstractTestCase.copyAudioToTmp("test30.mp3"); MP3AudioHeader mp3AudioHeader = null; try { mp3AudioHeader = new MP3File(testFile).getMP3AudioHeader(); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } assertTrue(exceptionCaught == null); assertEquals(MPEGFrameHeader.mpegVersionMap.get(new Integer(MPEGFrameHeader.VERSION_1)), mp3AudioHeader.getMpegVersion()); assertEquals(MPEGFrameHeader.mpegLayerMap.get(new Integer(MPEGFrameHeader.LAYER_III)), mp3AudioHeader.getMpegLayer()); assertEquals(MPEGFrameHeader.modeMap.get(new Integer(MPEGFrameHeader.MODE_STEREO)), mp3AudioHeader.getChannels()); assertTrue(mp3AudioHeader.isVariableBitRate()); assertEquals(147, mp3AudioHeader.getBitRateAsNumber()); assertEquals("Fraunhofer", mp3AudioHeader.getEncoder()); } public void testWriteToFileWithVRBIFrame() { File orig = new File("testdata", "test30.mp3"); if (!orig.isFile()) { return; } Exception exceptionCaught = null; File testFile = AbstractTestCase.copyAudioToTmp("test30.mp3"); MP3AudioHeader mp3AudioHeader = null; MP3File mp3file = null; try { mp3file = new MP3File(testFile); mp3AudioHeader = mp3file.getMP3AudioHeader(); //make change to file mp3file.getID3v2Tag().setField(FieldKey.TITLE,"FREDDY"); mp3file.getID3v2Tag().deleteField(FieldKey.COVER_ART); ((ID3v24Tag) mp3file.getID3v2Tag()).removeFrame("PRIV"); final TagOptionSingleton tagOptions = TagOptionSingleton.getInstance(); tagOptions.setToDefault(); mp3file.save(); mp3file = new MP3File(testFile); mp3AudioHeader = mp3file.getMP3AudioHeader(); } catch (Exception e) { e.printStackTrace(); exceptionCaught = e; } //change has been made and VBRI Frame is left intact assertEquals("FREDDY", mp3file.getID3v2Tag().getFirst(FieldKey.TITLE)); assertTrue(exceptionCaught == null); assertEquals(MPEGFrameHeader.mpegVersionMap.get(new Integer(MPEGFrameHeader.VERSION_1)), mp3AudioHeader.getMpegVersion()); assertEquals(MPEGFrameHeader.mpegLayerMap.get(new Integer(MPEGFrameHeader.LAYER_III)), mp3AudioHeader.getMpegLayer()); assertEquals(MPEGFrameHeader.modeMap.get(new Integer(MPEGFrameHeader.MODE_STEREO)), mp3AudioHeader.getChannels()); assertTrue(mp3AudioHeader.isVariableBitRate()); assertEquals(147, mp3AudioHeader.getBitRateAsNumber()); assertEquals("Fraunhofer", mp3AudioHeader.getEncoder()); } }libjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/audio/util/0000755000175000017500000000000011556363176024501 5ustar drazzibdrazziblibjaudiotagger-java-2.0.3/srctest/org/jaudiotagger/audio/util/UtilsTest.java0000644000175000017500000002116611055233036027273 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.util; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.RandomAccessFile; import java.math.BigInteger; import java.util.Arrays; import junit.framework.TestCase; import org.jaudiotagger.audio.asf.data.AsfHeader; import org.jaudiotagger.audio.asf.data.GUID; import org.jaudiotagger.audio.asf.util.Utils; /** * Tests the correctness of the methods in {@link Utils}.
* Except for methods related to {@link RandomAccessFile}, not worth the effort, * since this ASF access is just about to be replaced by streaming. * * @author Christian Laireiter */ public class UtilsTest extends TestCase { /** * Every bit in this 8 byte array is set. */ public final static byte[] FULL_SET = {(byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF}; /** * Max long value as UINT64 */ public final static byte[] MAX_LONG_64 = {(byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0x7F}; /** * Max UINT16 value. */ public final static byte[] MAX_UINT16 = {(byte) 0xFF, (byte) 0xFF}; /** * Max UINT32 value. */ public final static byte[] MAX_UINT32 = {(byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF}; /** * Test method for * {@link org.jaudiotagger.audio.asf.util.Utils#checkStringLengthNullSafe(java.lang.String)} */ public void testCheckStringLengthNullSafe() { Utils.checkStringLengthNullSafe(null); Utils.checkStringLengthNullSafe("AllOk"); //$NON-NLS-1$ StringBuffer buffer = new StringBuffer(); for (int i = 0; i < 65532 / 2; i++) { buffer.append("a"); } Utils.checkStringLengthNullSafe(buffer.toString()); boolean caught = false; try { buffer.append("a"); Utils.checkStringLengthNullSafe(buffer.toString()); } catch (IllegalArgumentException e) { caught = true; } assertTrue(caught); } /** * Test method for * {@link org.jaudiotagger.audio.asf.util.Utils#getBytes(long, int)}. */ public void testGetBytes() { assertTrue(Arrays.equals(MAX_UINT16, Utils.getBytes(Short.MAX_VALUE * 2 + 1, 2))); assertTrue(Arrays.equals(MAX_UINT32, Utils.getBytes(Integer.MAX_VALUE * 2 + 1, 4))); assertTrue(Arrays.equals(MAX_LONG_64, Utils.getBytes(Long.MAX_VALUE, 8))); } /** * Test method for * {@link org.jaudiotagger.audio.asf.util.Utils#isBlank(java.lang.String)}. */ public void testIsBlank() { assertTrue(Utils.isBlank(null)); assertTrue(Utils.isBlank("")); //$NON-NLS-1$ assertTrue(Utils.isBlank(" ")); //$NON-NLS-1$ assertFalse(Utils.isBlank("a")); //$NON-NLS-1$ assertFalse(Utils.isBlank(" a")); //$NON-NLS-1$ assertFalse(Utils.isBlank(" a")); //$NON-NLS-1$ } /** * Test method for * {@link org.jaudiotagger.audio.asf.util.Utils#readBig64(java.io.InputStream)} * . * @throws IOException Never */ public void testReadBig64InputStream() throws IOException { BigInteger big64 = Utils.readBig64(new ByteArrayInputStream(MAX_LONG_64)); assertEquals(Long.MAX_VALUE, big64.longValue()); } /** * Test method for * {@link org.jaudiotagger.audio.asf.util.Utils#readCharacterSizedString(java.io.InputStream)} * . * @throws IOException On I/O Errors. */ public void testReadCharacterSizedStringInputStream() throws IOException { ByteArrayOutputStream bos = new ByteArrayOutputStream(); String charSized = "This is a TestValue"; //$NON-NLS-1$ bos.write(Utils.getBytes(charSized.length() + 1, 2)); bos.write(Utils.getBytes(charSized, AsfHeader.ASF_CHARSET)); bos.write(AsfHeader.ZERO_TERM); assertEquals(charSized, Utils.readCharacterSizedString(new ByteArrayInputStream(bos.toByteArray()))); } /** * Test method for * {@link org.jaudiotagger.audio.asf.util.Utils#readGUID(java.io.InputStream)} * . * @throws IOException Should not */ public void testReadGUIDInputStream() throws IOException { for (int i = 0; i < GUID.KNOWN_GUIDS.length; i++) { ByteArrayOutputStream bos = new ByteArrayOutputStream(); bos.write(GUID.KNOWN_GUIDS[i].getBytes()); ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); GUID readGUID = Utils.readGUID(bis); assertTrue(readGUID.equals(GUID.KNOWN_GUIDS[i])); } } /** * Test method for * {@link org.jaudiotagger.audio.asf.util.Utils#readUINT16(java.io.InputStream)} * . * * @throws IOException * Never */ public void testReadUINT16InputStream() throws IOException { long value = Utils.readUINT16(new ByteArrayInputStream(MAX_UINT16)); assertEquals(Short.MAX_VALUE * 2 + 1, value); } /** * Test method for * {@link org.jaudiotagger.audio.asf.util.Utils#readUINT32(java.io.InputStream)} * . * * @throws IOException * Never */ public void testReadUINT32InputStream() throws IOException { long value = Utils.readUINT32(new ByteArrayInputStream(MAX_UINT32)); assertEquals((long) Integer.MAX_VALUE * 2 + 1, value); } /** * Test method for * {@link org.jaudiotagger.audio.asf.util.Utils#readUINT64(java.io.InputStream)} * . * @throws IOException Never */ public void testReadUINT64InputStream() throws IOException { long value = Utils.readUINT64(new ByteArrayInputStream(MAX_LONG_64)); assertEquals(Long.MAX_VALUE, value); } /** * Test method for * {@link org.jaudiotagger.audio.asf.util.Utils#readUTF16LEStr(java.io.InputStream)} * . * * @throws IOException * Never */ public void testReadUTF16LEStrInputStream() throws IOException { ByteArrayOutputStream bos = new ByteArrayOutputStream(); String testValue = "Testvalue"; //$NON-NLS-1$ // Test with zero term Utils.writeUINT16(testValue.length() * 2 + 2, bos); bos.write(Utils.getBytes(testValue, AsfHeader.ASF_CHARSET)); bos.write(AsfHeader.ZERO_TERM); String string = Utils.readUTF16LEStr(new ByteArrayInputStream(bos.toByteArray())); assertEquals(testValue, string); bos.reset(); // Test without zero term Utils.writeUINT16(testValue.length() * 2, bos); bos.write(Utils.getBytes(testValue, AsfHeader.ASF_CHARSET)); string = Utils.readUTF16LEStr(new ByteArrayInputStream(bos.toByteArray())); assertEquals(testValue, string); bos.reset(); // Test zero length zero term Utils.writeUINT16(2, bos); bos.write(AsfHeader.ZERO_TERM); string = Utils.readUTF16LEStr(new ByteArrayInputStream(bos.toByteArray())); assertEquals("", string); //$NON-NLS-1$ bos.reset(); // Test zero length Utils.writeUINT16(0, bos); string = Utils.readUTF16LEStr(new ByteArrayInputStream(bos.toByteArray())); assertEquals("", string); //$NON-NLS-1$ } /** * Test method for * {@link org.jaudiotagger.audio.asf.util.Utils#writeUINT16(int, java.io.OutputStream)} * . * * @throws IOException * Never */ public void testWriteUINT16() throws IOException { ByteArrayOutputStream bos = new ByteArrayOutputStream(); Utils.writeUINT16(Short.MAX_VALUE * 2 + 1, bos); assertTrue(Arrays.equals(MAX_UINT16, bos.toByteArray())); } /** * Test method for * {@link org.jaudiotagger.audio.asf.util.Utils#writeUINT32(long, java.io.OutputStream)} * . * * @throws IOException * Never */ public void testWriteUINT32() throws IOException { ByteArrayOutputStream bos = new ByteArrayOutputStream(); Utils.writeUINT32((long) Integer.MAX_VALUE * 2 + 1, bos); assertTrue(Arrays.equals(MAX_UINT32, bos.toByteArray())); } /** * Test method for * {@link org.jaudiotagger.audio.asf.util.Utils#writeUINT64(long, java.io.OutputStream)} * . * * @throws IOException * Never */ public void testWriteUINT64() throws IOException { ByteArrayOutputStream bos = new ByteArrayOutputStream(); Utils.writeUINT64(Long.MAX_VALUE, bos); assertTrue(Arrays.equals(MAX_LONG_64, bos.toByteArray())); } } libjaudiotagger-java-2.0.3/intellij_settings.jar0000644000175000017500000004565511041065035021725 0ustar drazzibdrazzibPKl[8options/colors.scheme.xmlUA 0{wu00 5ƚl?>~t|{Ƕ/|&tXRVblK}v͘pN+)HhZXa Y5.ViуG7v'|2^+ˢλ4CY%OA%j 8;kY;6ގG7PK*PKl[8options/filetypes.xmlUO 0 `n0X*QҲ1nLCBxy//+fXaŗ}r^ d)jU2i8KHj0rxR*l'"ޘlӳCyBX]wCEp<輏k=q~ HI C?H2{PKA?PK [B7 filetypes/PKl[8options/project.default.xml=koHWE{;~LnzF.$d2"PI`;l0TvF?98:UuƉhF}:Y:EN `ԍ(az:sPMNGoe濮{zwx{'o ^CRֿ[lku7sp zOiuU;:?Sį.;w|~&MS\R[3YaښjO rxKZ@t{'gq%qwSIVmSWd"QnOLSmmLb%gd 4[`DR{ oa!l~ Ϻ/N $ى=H')vͧн %U`RR~J>40S'퀎 S1 ,zCosz]vSR2fe1Z5v84KWAtƯ; 7~[kG >Msv_^}K嶛oſ*(~:gP:N6q&ua:A]0.`] &WQ,rz.6gblh3uDah A;d([5Tlm!GK\6g|J>PGj?#-֥> "6eelf\ Ph٪fu܄I.p2\7f*TWӔ ?ݶpaJ&! B'b_c<  p!=E35+mD%gꅪ]"]B,2]} #ٍKC{ @ \hH~Ͱ r)@uPW-pcn` k*7LQ#i:~8KgA\Y2neTmd &9 | S품qA4cX-zL4Øh%P٠ܒ@g*bW`!.(69V-rmc){XK,\qС(ū:ӟ'M@{?LSdyEi PǠ7;lZ;yXD0 ʪUq!G@'mڊ9Sw%t%AL m]S2YГRڀzf|0˽SXYy>l)x V` wjքx_+yp2Z܊sߢ'??t״e@K_:'])J2 ]}wgy4/N ,ͱgP |eNx- EB[fݐ,m"#;, Ak|ywx 'g')L۴ +JԞIM09(̝d~C=z?D޸6ºN8R܌LSʦes`hbcYEk ujlN(NhbMnӁ*Hlzn@`n ٍ'8rOicWN'27Iۑ@{QՅzMh%{6ɉ+wK:ke{\!M[DžY?w؉H7[CLͰlI'䁤4zՄcM!BDB.أ6x Ï ?|a~dʣQ]cU1ֶ ֚M634TTk6^͟8aOw {^D֎txgGO)ΝG>\YS[^Q"wL9\֭-hG&leʹl5LXvZ=Є97`rMQ.$r G, p"D =3{,'3D6{BF pYaBDlo2hNq)ӆmR4sZ!E;8hm tڶU,qELY*y^ǎdϔ~:tDwDxR.mabdSĉ# @*UAM#oY,ӰL~gJ ,j\Ch3hAy8;.: @Iiwq\XIO` soKijz04_p- NpP.޶@sҿgG\dL#YёS` ,xݐ7 4uAG>=&hĂsB>Yڠ#{^l%]Q=}MNDïwsdߗ"oy@{Qt(2CEd %1d)hr}̽BeuO*'":z,4u ݌AcTfu "=ժT> E=q-1luVhcY6M jߒU]]U!,fؖ<%F Xb|(~G\X5yqJJYi?>b[]i}_졄Te%9aBq%7nW/˛E3vgE/Iq{_}a?듾m cU C}_b63.5쥘/DrЀhvP_WtgK:,p~}=n*Kȶdrh53=1~ɔ丵R'Qibr>J6X|^ pSH ]Bo9/Dfj -'T9/DE)(Y L`yWNnEa; m'뺞X15bWȤ$ '=eHI'SԶpܓ,J*&WrglXyհ9W|񠰤s7՜ʗ$ 90}O9nӈA1K&Rr!˶2i?Dߣ_0yRKjEx6 ۅ]Eg_̇/e @p {$jz+ -3|y]RI ѧ0m9r4zS{fUmmqHh/w˕tUw:ߚ-7A& )Z|i LiDdUaosW֯K|m]Xse񮖤e޵8+?&0Qߺ"ѽ2d by:2Yn B>jyA#Yey gөT>bq63t]nfO;&`p ;78>1V TT ̱sd]3eqd.֬e!e7t}|e7ţ&%P: GQ~[JNJ):~<iQ~I}f/7,o#YMgx:Avh٪V\f7\Nk?Ŀ<q֪ztwE{"8CŠeǾ8O@T#h.2);`PKĠxPK ҝ'8 codeStyle/PKl[8 options/applicationLibraries.xmlQ(K-*ϳU23PRHKOKU qӵPI,(LN,*rls RJsSmr2*CrRAzQ5rPK`nPKl[8options/customization.xmluPn0 핛 hбKPdaIFۯ/-i3xwG}Y^yW|Ng->_T iYޡZ0"CI-DRl/ :qV[ZT2Qi$oB$ӾsƯAo}< BG7`*C24X޷Xl~PKSPK i7 migration/PKi7"migration/Swing__1_0_3____1_1_.xmlMN0rD,I `v8? *RV{>ηVБҚem$Mr-+!OD 7 :T- M1 fɗN6k-=hl :jPZ}kvi|NJ<; `ٷ< 8T=w &[ pl48*(]*OxPpM߬26zY΁u):VoV# '6tDKz$ܩE]7?>4PKSk\PK Z8 codestyles/PKl[8codestyles/jaudiotagger.xmlMk@GO=$GFӲ蘦$I6ҟߥRr&V%\iچ8MSaw -+k*tv&ϹA qgӕ@P_DoZ&)ŖZ!\Mٔ-#VDUvt?ߏFR({WͲ HoR[5D5ȢY% ƿ~ PK#PKl[8options/other.xml=ksH7b³v;n^~uxnKHpE nϯ*$@Q};hK2*UU\k=(v>j,\ᷣ5?]:as'fպ0|gE~;R ݇uDv2릙6z`ڒ*^)xk%uόm]2d-\t_q8JRlMuC" ,[%~)@"ZvH.cm6ݙ_?JW Й*[%049UHyȜh7`"c$-Խ[jk!lu=dMɓQ:[Z٢ܔH4XAL"a/_'g˻&v%Ɖ;Ĺ=ʏhAWO Fm9w}rDҷ_qXso 80-!qb'q霟wzgg'x LB;ǹ܂;k;wbkLMܧ\ۻP 6vG0 ilh35KspLk6ͫڌ42TvKp)h HԴ7 ͰMːuidt)ēz*.N6^gCI,is8Sp3az(5y`n!_b(6e \7{|Ԋ}d79d h_}?Hج%<$Yy~[6A0jpNQ.nSO62:o|$6U`*P3@2i*٪8gpAjy#zRϹg&+k Bjo3Kf i< /Fxԇ cg$zrAɷ}zh둼v˘ `OhsG fY9Pp5ciN-U-JSV'O4u];.C5g\ ҉˒7CK6hO2g~)zO A1f=_AUC'#7ܲ₇o7)^7ǻj1fћbRJ"rINy TȤ~";0†lAK0-%x1]á rV'qdY-/LpMnb~qIРGxQ= e >n$KE[m~5Ep(2vvZ}/_=pݭ]MnNw^٧7[\_zNIkPI|+0_q nЙ/IkxWE*~?LCÐ|4oG4\:HHKEs&]9HtaP!^ɶty6UK `jZH"4 f %N}兓:Vyk\AU#ː$Zn,H׵a0_mUu `@G DM˶dSNI=?]y[FU%%E/leS2TL*ʴ1rbh*YmX]J $,ؖ;3700ǒ {8y b"pH+Y>yW+N?xjlvLMyTnDnb2DN\Xw ZS]zv\j%\>;Q v聏nHHَ|V@]VG/nkZ1@|Mɸ7)o:>6iCBgiJN I?k&#E,Iχ5IyAqL7i,* lN@ӥb-[-hqhM^w{*rL`BG/k c6%L 1T fl:hm1'=ɒxEC TnI߬7򺀦:$:usz` \*X+=臁F `#q`H\rn2ծ+jSׂ'R,1ۦnYUiGc־CC|t3@ KCmL C/E\I. ? F&bm"LK 7ىɾ!xd`* z-IIog1z#[{,A626&Cmj`4@L:Wju;Xf(/a MVd{>$Sizg>3'P9P pv;ۚplpMJ-QƀcGik[f#i#w|z gf8pG b#  YJH9t㈄O SA`1MkΟ1^ 04^M" Oͯ+MD4Pj*/\s`E-fc9+{ -l^3QUSƨ7HDɍds IR` 0H+&;gSgEJW7ͯcT,fUTz9CND#N_%:| T]>T1._VLJV^9!z ȍ䯵N{/:N0S̏INEw)N awCb8uωpF#I pZtm 'I=i#㴊V+~ipZf쑨];˛5\ m2zśWT͏ Nwg/i|]ұ+C~KT,~^\)ȩ; Vex~禉׈8iWV{s5=,lxCݮ#$R? Bgq'gC8'z+ɡB縟(zV\6 *ᡕKj\<_o>g|utL4ѣ^6[M-y[,R[8Vӵ>%/,G3"qضe4!whi<7nN~JnVע2q+i()bsV}7{Z2l 8mf mSMdo˶ȆNexcw"n Uk"Y@w;qWh^&V[4CPMW{0tEEvXAÒtۚ8͙K5Ed71VZˈ8{L'eވ-]ٖ'A?;?VtS J;7}O/-NF52u\I)wj-@o?4"qAAV?Px-;n b/{Hϒzՙ щ^bг)x̡Uu2 a'_1QYQc=X`B~qVNEYy$ 1aIJ8(hSpfYB(>.1CS5aA .+Bxl';Kc+ W)(xTB%HFx7릁wmچrgPKJ,-ak q8SUB\aMs"a-^5Fka LhhQmukuJ@vYa*/@AY>b|' BmAP)չ=]!;tEy Rބ#rW&3FW\47; 7:@Czoyd,iex79mNt8g/TIJw[ԸE.ݜ]l͘ẃ!ΨrS\I@_15i_iYPC94TUReCS1m+I*1xENe|Ō֤4B3}bu9"r}4?_XZKAuo{fr敿#`cVw`^ryYq;tÊԗöINՐtvxGSsWsIn"͓V}nYءɡ=U <. LJ M䉽'!#D]#DoPL1k!#$䏐'$7nv۶h(1L0|}|P}+aR⯆Hx%` T2ٵ #UYri7qdkHnr[B5b4].leEA1a/wωp[PsDz$Yvno,+1+AM=<',90INnd2-9ټD#)r}<ʎݗnȁkb?)WtV½Rh +|0m9$f{V}@F[Kc=iM~1k5!^(IUg II<'^rCiwk®yl ۵% T۟zK y"RyD o9ը}Ηd UDyd~ OPKqC.3PK PkB7 inspection/PKZ8inspection/Default.xmlQO0ߗ?4}WCqq |$ \ 9%SsO=mo|[IcK:)T}{]^tJektYR]R%* =J)m*u y@ !-PL! w'v ޕ΄͍iwTPcg! gr?X7İ/a>Qʽs(\OM%n7z/W,ܾ%됓g,V  `[ tocAt]N~PKo5PK ҝ'8keymaps/PK [B7colors/PK Oni7fileTemplates/PK Oni7fileTemplates/includes/PKOni7'fileTemplates/includes/File Header.javaRRũEV *աA`ĒTc+XD PKɆ)3PK [B7 templates/PKl[8options/quicklists.xmlQ(K-*ϳU23PRHKOKU qӵPI,(LN,*rls RJsSmK3}2K}SAQurPKz esPK [B7tools/PKl[8options/keymap.xmlU1 0FBqjtsHEt#=K0{VǏn^E1lXl/vPWRR.XƐd l@DB=83"|~U7zOPKky~PKl[8options/editor.xmlA0+ro*]xBF؁Av j}'PҲe>y=جz_8qGuhy.5~v7jQu\ƟQ4ZmM5զǰ\u]>>qY5 5x jZ?CrP"8z (Σ(;1gZ_%#,#loz&߫^);a /3e8!G8͜MQ{dEl. !VMUSS–:<8lj2ɣOJg;&46!ThsP~nH͓])xC`3yY-& dy25%ЬN>7(P,(HpqgYm/ pɥ RQ*dyiٟD~3 za"ˤP }J&2K _z PK@;PKl[8options/jdk.table.xmlAo0LMhLa\&1Εg[S6S6~=vӴMp lS|`EaRL"e , iI #%% 4Ѳ^-4[W,w[m`xCEn>5Z7]IJ:{#;f7Uy!kzx ?(e7.nkRZt7l4^0K^IȰZA%Aqp?Zzx0oCWB ^ m5 ^PC*u,{i2iciH98s¦Q3J][IvuaDހK8%Ȣ.+)-WPت6)D-)I`bfs#gRPskCYaoKTO9xUs ޶># >Џ zd#B|(pGd@9> pIžIt$Mx2ƿ@i?a; {X<րGAHC>6ȰyqQrЂ ʼnMϣu$8qL 'PK_dP&PKl[8options/print.xmlK0 PZvDMkMJQBRMUo =&|d&`KQDgC:@e^'v̹;@yIJ4Y0.יJɝ:adeҘ{J'1o䀣Lf ~8P22L8&^%ldWϜhE8\Keqxa#1$( b.|snD`p~3e/u_WccJY@NC@aR3zL9`ΰ7O\1eS,_rӭ3!8Z^I@ 4]죦]Ї 'Lɵ*tcڔɿW^( 4CNպUa~ "Et voxPK7,vPKl[8options/macros.xmlQ(K-*ϳU23PRHKOKU qӵPI,(LN,*rls RJsSmArEyEJ ZyPK,ctPKl[8options/editor.codeinsight.xmlWQo0~֗=U&qGb{SʦɊڴC Zm;')F:}*}w^^dsZϋ784+U/Vӓa\fd Ų|"}JF ׽$-WDb3shļ<'جҞsql6mvalpq$PܘPYCޗWt<>$ٺu1݇tuYCEk$- Y c jyخF&ٚkV!usc Ռ8")5))ǂq}rkC%$Tv5ciL#1vqdZ*_u >("xlJ_%mf~MXT¬BH+xM`2Av(10options/print.xmlPKl[8,ct?options/macros.xmlPKl[8%: j@options/editor.codeinsight.xmlPK Z8CIntelliJ IDEA Global SettingsPKl+Dlibjaudiotagger-java-2.0.3/README.txt0000644000175000017500000000242411330335337017164 0ustar drazzibdrazzibJAudiotagger is a JAVA API for audio metatagging. Both a common API and format specific APIS are available, currently supports ID3,Flac,OggVorbis,Wma and Mp4. Build is with Maven, but was previously with ant. The ant files have not been deleted in case they are useful to those not familiar with Maven. Directory structure as follows: Under source control: src :source code directory srctest :source code directory www :java doc directory testdata :test files for use by the junit tests, not all tests are included in the distribution because of copyright target :contains the jadiotagger***.jar built from maven Other files: pom.xml :Maven build file Defunct ant build files: build.xml build.properties :properties likely to differ between users should be in here build.bat :wrapper to run build script on Windows lib :Third party libraries IDE files: jaudiotagger.iml :Intellij Jetbrains Module jaudiotagger.ipr :Intellij Jetbrains Project License: jaudiotagger.LICENSE :license file Build details: Install Maven2 Run mvn package to compile and test Admin only Run mvn deploy to upload to the java.net maven repository libjaudiotagger-java-2.0.3/MergeID3AndMP3.bat0000644000175000017500000000016210547435126020463 0ustar drazzibdrazzibset classpath=%classpath%;.\classes;\dist\jaudiotagger.jar java org.jaudiotagger.test.MergeID3AndMP3Files %1 %2 %3libjaudiotagger-java-2.0.3/build.bat0000644000175000017500000000014611470746136017264 0ustar drazzibdrazzibset JAVA_HOME=C:\Apps\Code\Java\jdk1.6.0_20 C:\apps\code\ant\bin\ant -propertyfile build.properties %1libjaudiotagger-java-2.0.3/www/0000755000175000017500000000000011556363167016324 5ustar drazzibdrazziblibjaudiotagger-java-2.0.3/build.properties0000644000175000017500000000005011277037612020701 0ustar drazzibdrazzibrelease.dir=./share build.release=v2.0.0libjaudiotagger-java-2.0.3/testdata/0000755000175000017500000000000011556363446017311 5ustar drazzibdrazziblibjaudiotagger-java-2.0.3/src/0000755000175000017500000000000011556363167016267 5ustar drazzibdrazziblibjaudiotagger-java-2.0.3/src/org/0000755000175000017500000000000011556363167017056 5ustar drazzibdrazziblibjaudiotagger-java-2.0.3/src/org/jaudiotagger/0000755000175000017500000000000011556363176021523 5ustar drazzibdrazziblibjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/0000755000175000017500000000000011556363176022276 5ustar drazzibdrazziblibjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/lyrics3/0000755000175000017500000000000011556363175023665 5ustar drazzibdrazziblibjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/lyrics3/FieldFrameBodyIMG.java0000644000175000017500000001656011277026507027704 0ustar drazzibdrazzib/** * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: FieldFrameBodyIMG.java 836 2009-11-12 15:44:07Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Description: */ package org.jaudiotagger.tag.lyrics3; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.TagOptionSingleton; import org.jaudiotagger.tag.datatype.Lyrics3Image; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Iterator; public class FieldFrameBodyIMG extends AbstractLyrics3v2FieldFrameBody { /** * */ private ArrayList images = new ArrayList(); /** * Creates a new FieldBodyIMG datatype. */ public FieldFrameBodyIMG() { } public FieldFrameBodyIMG(FieldFrameBodyIMG copyObject) { super(copyObject); Lyrics3Image old; for (int i = 0; i < copyObject.images.size(); i++) { old = copyObject.images.get(i); this.images.add(new Lyrics3Image(old)); } } /** * Creates a new FieldBodyIMG datatype. * * @param imageString */ public FieldFrameBodyIMG(String imageString) { readString(imageString); } /** * Creates a new FieldBodyIMG datatype. * * @param image */ public FieldFrameBodyIMG(Lyrics3Image image) { images.add(image); } /** * Creates a new FieldBodyIMG datatype. * * @param byteBuffer * @throws InvalidTagException */ public FieldFrameBodyIMG(ByteBuffer byteBuffer) throws InvalidTagException { this.read(byteBuffer); } /** * @return */ public String getIdentifier() { return "IMG"; } /** * @return */ public int getSize() { int size = 0; Lyrics3Image image; for (Object image1 : images) { image = (Lyrics3Image) image1; size += (image.getSize() + 2); // addField CRLF pair } return size - 2; // cut off trailing crlf pair } /** * @param obj * @return */ public boolean isSubsetOf(Object obj) { if (!(obj instanceof FieldFrameBodyIMG)) { return false; } ArrayList superset = ((FieldFrameBodyIMG) obj).images; for (Object image : images) { if (!superset.contains(image)) { return false; } } return super.isSubsetOf(obj); } /** * @param value */ public void setValue(String value) { readString(value); } /** * @return */ public String getValue() { return writeString(); } /** * @param image */ public void addImage(Lyrics3Image image) { images.add(image); } /** * @param obj * @return */ public boolean equals(Object obj) { if (!(obj instanceof FieldFrameBodyIMG)) { return false; } FieldFrameBodyIMG object = (FieldFrameBodyIMG) obj; return this.images.equals(object.images) && super.equals(obj); } /** * @return */ public Iterator iterator() { return images.iterator(); } public void read(ByteBuffer byteBuffer) throws InvalidTagException { String imageString; byte[] buffer = new byte[5]; // read the 5 character size byteBuffer.get(buffer, 0, 5); int size = Integer.parseInt(new String(buffer, 0, 5)); if ((size == 0) && (!TagOptionSingleton.getInstance().isLyrics3KeepEmptyFieldIfRead())) { throw new InvalidTagException("Lyircs3v2 Field has size of zero."); } buffer = new byte[size]; // read the SIZE length description byteBuffer.get(buffer); imageString = new String(buffer); readString(imageString); } /** * @return */ public String toString() { String str = getIdentifier() + " : "; for (Object image : images) { str += (image.toString() + " ; "); } return str; } /** * @param file * @throws java.io.IOException */ public void write(RandomAccessFile file) throws java.io.IOException { int size; int offset = 0; byte[] buffer = new byte[5]; String str; size = getSize(); str = Integer.toString(size); for (int i = 0; i < (5 - str.length()); i++) { buffer[i] = (byte) '0'; } offset += (5 - str.length()); for (int i = 0; i < str.length(); i++) { buffer[i + offset] = (byte) str.charAt(i); } offset += str.length(); file.write(buffer, 0, 5); if (size > 0) { str = writeString(); buffer = new byte[str.length()]; for (int i = 0; i < str.length(); i++) { buffer[i] = (byte) str.charAt(i); } file.write(buffer); } } /** * @param imageString */ private void readString(String imageString) { // now read each picture and put in the vector; Lyrics3Image image; String token; int offset = 0; int delim = imageString.indexOf(Lyrics3v2Fields.CRLF); images = new ArrayList(); while (delim >= 0) { token = imageString.substring(offset, delim); image = new Lyrics3Image("Image", this); image.setFilename(token); images.add(image); offset = delim + Lyrics3v2Fields.CRLF.length(); delim = imageString.indexOf(Lyrics3v2Fields.CRLF, offset); } if (offset < imageString.length()) { token = imageString.substring(offset); image = new Lyrics3Image("Image", this); image.setFilename(token); images.add(image); } } /** * @return */ private String writeString() { String str = ""; Lyrics3Image image; for (Object image1 : images) { image = (Lyrics3Image) image1; str += (image.writeString() + Lyrics3v2Fields.CRLF); } if (str.length() > 2) { return str.substring(0, str.length() - 2); } return str; } /** * TODO */ protected void setupObjectList() { } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/lyrics3/AbstractLyrics3.java0000644000175000017500000000313011041064726027526 0ustar drazzibdrazzib/** * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: AbstractLyrics3.java 625 2008-07-21 10:49:58Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Description: */ package org.jaudiotagger.tag.lyrics3; import org.jaudiotagger.tag.id3.AbstractTag; import org.jaudiotagger.tag.id3.ID3v1Tag; import java.io.IOException; import java.io.RandomAccessFile; public abstract class AbstractLyrics3 extends AbstractTag { public AbstractLyrics3() { } public AbstractLyrics3(AbstractLyrics3 copyObject) { super(copyObject); } /** * @param file * @throws IOException */ public void delete(RandomAccessFile file) throws IOException { long filePointer; ID3v1Tag id3v1tag = new ID3v1Tag(); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/lyrics3/FieldFrameBodyIND.java0000644000175000017500000000533011277006322027664 0ustar drazzibdrazzib/** * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: FieldFrameBodyIND.java 832 2009-11-12 13:25:38Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Description: * */ package org.jaudiotagger.tag.lyrics3; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.datatype.BooleanString; import java.nio.ByteBuffer; public class FieldFrameBodyIND extends AbstractLyrics3v2FieldFrameBody { /** * Creates a new FieldBodyIND datatype. */ public FieldFrameBodyIND() { // this.setObject("Lyrics Present", new Boolean(false)); // this.setObject("Timestamp Present", new Boolean(false)); } public FieldFrameBodyIND(FieldFrameBodyIND body) { super(body); } /** * Creates a new FieldBodyIND datatype. * * @param lyricsPresent * @param timeStampPresent */ public FieldFrameBodyIND(boolean lyricsPresent, boolean timeStampPresent) { this.setObjectValue("Lyrics Present", lyricsPresent); this.setObjectValue("Timestamp Present", timeStampPresent); } /** * Creates a new FieldBodyIND datatype. * * @param byteBuffer * @throws InvalidTagException */ public FieldFrameBodyIND(ByteBuffer byteBuffer) throws InvalidTagException { this.read(byteBuffer); } /** * @param author */ public void setAuthor(String author) { setObjectValue("Author", author); } /** * @return */ public String getAuthor() { return (String) getObjectValue("Author"); } /** * @return */ public String getIdentifier() { return "IND"; } /** * */ protected void setupObjectList() { objectList.add(new BooleanString("Lyrics Present", this)); objectList.add(new BooleanString("Timestamp Present", this)); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/lyrics3/Lyrics3v1Iterator.java0000644000175000017500000000506711277026507030044 0ustar drazzibdrazzib/** * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: Lyrics3v1Iterator.java 836 2009-11-12 15:44:07Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Description: */ package org.jaudiotagger.tag.lyrics3; import java.util.Iterator; import java.util.NoSuchElementException; public class Lyrics3v1Iterator implements Iterator { /** * */ private Lyrics3v1 tag = null; /** * */ private int lastIndex = 0; /** * */ private int removeIndex = 0; /** * Creates a new Lyrics3v1Iterator datatype. * * @param lyrics3v1Tag */ public Lyrics3v1Iterator(Lyrics3v1 lyrics3v1Tag) { tag = lyrics3v1Tag; } /** * @return */ public boolean hasNext() { return !((tag.getLyric().indexOf('\n', lastIndex) < 0) && (lastIndex > tag.getLyric().length())); } /** * @return * @throws NoSuchElementException */ public String next() { int nextIndex = tag.getLyric().indexOf('\n', lastIndex); removeIndex = lastIndex; String line; if (lastIndex >= 0) { if (nextIndex >= 0) { line = tag.getLyric().substring(lastIndex, nextIndex); } else { line = tag.getLyric().substring(lastIndex); } lastIndex = nextIndex; } else { throw new NoSuchElementException("Iteration has no more elements."); } return line; } /** * */ public void remove() { String lyric = tag.getLyric().substring(0, removeIndex) + tag.getLyric().substring(lastIndex); tag.setLyric(lyric); } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/lyrics3/Lyrics3v1.java0000644000175000017500000001666011277026507026333 0ustar drazzibdrazzib/** * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: Lyrics3v1.java 836 2009-11-12 15:44:07Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Description: */ package org.jaudiotagger.tag.lyrics3; import org.jaudiotagger.tag.TagException; import org.jaudiotagger.tag.TagNotFoundException; import org.jaudiotagger.tag.id3.AbstractTag; import org.jaudiotagger.tag.id3.ID3Tags; import org.jaudiotagger.tag.id3.ID3v1Tag; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.util.Iterator; public class Lyrics3v1 extends AbstractLyrics3 { /** * */ private String lyric = ""; /** * Creates a new Lyrics3v1 datatype. */ public Lyrics3v1() { } public Lyrics3v1(Lyrics3v1 copyObject) { super(copyObject); this.lyric = copyObject.lyric; } public Lyrics3v1(AbstractTag mp3Tag) { if (mp3Tag != null) { Lyrics3v2 lyricTag; if (mp3Tag instanceof Lyrics3v1) { throw new UnsupportedOperationException("Copy Constructor not called. Please type cast the argument"); } else if (mp3Tag instanceof Lyrics3v2) { lyricTag = (Lyrics3v2) mp3Tag; } else { lyricTag = new Lyrics3v2(mp3Tag); } FieldFrameBodyLYR lyricField; lyricField = (FieldFrameBodyLYR) lyricTag.getField("LYR").getBody(); this.lyric = lyricField.getLyric(); } } /** * Creates a new Lyrics3v1 datatype. * * @param file * @throws TagNotFoundException * @throws java.io.IOException * @param byteBuffer */ public Lyrics3v1(ByteBuffer byteBuffer) throws TagNotFoundException, java.io.IOException { try { this.read(byteBuffer); } catch (TagException e) { e.printStackTrace(); } } /** * @return */ public String getIdentifier() { return "Lyrics3v1.00"; } /** * @param lyric */ public void setLyric(String lyric) { this.lyric = ID3Tags.truncate(lyric, 5100); } /** * @return */ public String getLyric() { return lyric; } /** * @return */ public int getSize() { return "LYRICSBEGIN".length() + lyric.length() + "LYRICSEND".length(); } /** * @param obj * @return */ public boolean isSubsetOf(Object obj) { return (obj instanceof Lyrics3v1) && (((Lyrics3v1) obj).lyric.contains(this.lyric)); } /** * @param obj * @return */ public boolean equals(Object obj) { if (!(obj instanceof Lyrics3v1)) { return false; } Lyrics3v1 object = (Lyrics3v1) obj; return this.lyric.equals(object.lyric) && super.equals(obj); } /** * @return * @throws java.lang.UnsupportedOperationException * */ public Iterator iterator() { /** * @todo Implement this org.jaudiotagger.tag.AbstractMP3Tag abstract method */ throw new java.lang.UnsupportedOperationException("Method iterator() not yet implemented."); } /** * TODO implement * * @param byteBuffer * @return * @throws IOException */ public boolean seek(ByteBuffer byteBuffer) { return false; } /** * @param byteBuffer * @throws TagNotFoundException * @throws IOException */ public void read(ByteBuffer byteBuffer) throws TagException { byte[] buffer = new byte[5100 + 9 + 11]; String lyricBuffer; if (!seek(byteBuffer)) { throw new TagNotFoundException("ID3v1 tag not found"); } byteBuffer.get(buffer); lyricBuffer = new String(buffer); lyric = lyricBuffer.substring(0, lyricBuffer.indexOf("LYRICSEND")); } /** * @param file * @return * @throws IOException */ public boolean seek(RandomAccessFile file) throws IOException { byte[] buffer = new byte[5100 + 9 + 11]; String lyricsEnd; String lyricsStart; long offset; // check right before the ID3 1.0 tag for the lyrics tag file.seek(file.length() - 128 - 9); file.read(buffer, 0, 9); lyricsEnd = new String(buffer, 0, 9); if (lyricsEnd.equals("LYRICSEND")) { offset = file.getFilePointer(); } else { // check the end of the file for a lyrics tag incase an ID3 // tag wasn't placed after it. file.seek(file.length() - 9); file.read(buffer, 0, 9); lyricsEnd = new String(buffer, 0, 9); if (lyricsEnd.equals("LYRICSEND")) { offset = file.getFilePointer(); } else { return false; } } // the tag can at most only be 5100 bytes offset -= (5100 + 9 + 11); file.seek(offset); file.read(buffer); lyricsStart = new String(buffer); // search for the tag int i = lyricsStart.indexOf("LYRICSBEGIN"); if (i == -1) { return false; } file.seek(offset + i + 11); return true; } /** * @return */ public String toString() { String str = getIdentifier() + " " + this.getSize() + "\n"; return str + lyric; } /** * @param file * @throws IOException */ public void write(RandomAccessFile file) throws IOException { String str; int offset; byte[] buffer; ID3v1Tag id3v1tag; id3v1tag = null; delete(file); file.seek(file.length()); buffer = new byte[lyric.length() + 11 + 9]; str = "LYRICSBEGIN"; for (int i = 0; i < str.length(); i++) { buffer[i] = (byte) str.charAt(i); } offset = str.length(); str = ID3Tags.truncate(lyric, 5100); for (int i = 0; i < str.length(); i++) { buffer[i + offset] = (byte) str.charAt(i); } offset += str.length(); str = "LYRICSEND"; for (int i = 0; i < str.length(); i++) { buffer[i + offset] = (byte) str.charAt(i); } offset += str.length(); file.write(buffer, 0, offset); if (id3v1tag != null) { id3v1tag.write(file); } } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/lyrics3/Lyrics3v2Fields.java0000644000175000017500000000615311277006322027450 0ustar drazzibdrazzib/** * @author : Paul Taylor *

* Version @version:$Id: Lyrics3v2Fields.java 832 2009-11-12 13:25:38Z paultaylor $ *

* Jaudiotagger Copyright (C)2004,2005 *

* This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. *

* This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. *

* You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *

* Description: */ package org.jaudiotagger.tag.lyrics3; import org.jaudiotagger.tag.datatype.AbstractStringStringValuePair; public class Lyrics3v2Fields extends AbstractStringStringValuePair { private static Lyrics3v2Fields lyrics3Fields; /** * CRLF int set */ private static final byte[] crlfByte = {13, 10}; /** * CRLF int set */ public static final String CRLF = new String(crlfByte); public static Lyrics3v2Fields getInstanceOf() { if (lyrics3Fields == null) { lyrics3Fields = new Lyrics3v2Fields(); } return lyrics3Fields; } public static final String FIELD_V2_INDICATIONS = "IND"; public static final String FIELD_V2_LYRICS_MULTI_LINE_TEXT = "LYR"; public static final String FIELD_V2_ADDITIONAL_MULTI_LINE_TEXT = "INF"; public static final String FIELD_V2_AUTHOR = "AUT"; public static final String FIELD_V2_ALBUM = "EAL"; public static final String FIELD_V2_ARTIST = "EAR"; public static final String FIELD_V2_TRACK = "ETT"; public static final String FIELD_V2_IMAGE = "IMG"; private Lyrics3v2Fields() { idToValue.put(FIELD_V2_INDICATIONS, "Indications field"); idToValue.put(FIELD_V2_LYRICS_MULTI_LINE_TEXT, "Lyrics multi line text"); idToValue.put(FIELD_V2_ADDITIONAL_MULTI_LINE_TEXT, "Additional information multi line text"); idToValue.put(FIELD_V2_AUTHOR, "Lyrics/Music Author name"); idToValue.put(FIELD_V2_ALBUM, "Extended Album name"); idToValue.put(FIELD_V2_ARTIST, "Extended Artist name"); idToValue.put(FIELD_V2_TRACK, "Extended Track Title"); idToValue.put(FIELD_V2_IMAGE, "Link to an image files"); createMaps(); } /** * Returns true if the identifier is a valid Lyrics3v2 frame identifier * * @param identifier string to test * @return true if the identifier is a valid Lyrics3v2 frame identifier */ public static boolean isLyrics3v2FieldIdentifier(String identifier) { return identifier.length() >= 3 && getInstanceOf().getIdToValueMap().containsKey(identifier.substring(0, 3)); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/lyrics3/FieldFrameBodyETT.java0000644000175000017500000000461211277006322027710 0ustar drazzibdrazzib/** * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: FieldFrameBodyETT.java 832 2009-11-12 13:25:38Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Description: */ package org.jaudiotagger.tag.lyrics3; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.datatype.StringSizeTerminated; import java.nio.ByteBuffer; public class FieldFrameBodyETT extends AbstractLyrics3v2FieldFrameBody { /** * Creates a new FieldBodyETT datatype. */ public FieldFrameBodyETT() { // this.setObject("Title", ""); } public FieldFrameBodyETT(FieldFrameBodyETT body) { super(body); } /** * Creates a new FieldBodyETT datatype. * * @param title */ public FieldFrameBodyETT(String title) { this.setObjectValue("Title", title); } /** * Creates a new FieldBodyETT datatype. * * @param byteBuffer * @throws InvalidTagException */ public FieldFrameBodyETT(ByteBuffer byteBuffer) throws InvalidTagException { this.read(byteBuffer); } /** * @return */ public String getIdentifier() { return "ETT"; } /** * @param title */ public void setTitle(String title) { setObjectValue("Title", title); } /** * @return */ public String getTitle() { return (String) getObjectValue("Title"); } /** * */ protected void setupObjectList() { objectList.add(new StringSizeTerminated("Title", this)); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/lyrics3/FieldFrameBodyEAR.java0000644000175000017500000000463111277006322027664 0ustar drazzibdrazzib/** * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: FieldFrameBodyEAR.java 832 2009-11-12 13:25:38Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Description: */ package org.jaudiotagger.tag.lyrics3; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.datatype.StringSizeTerminated; import java.nio.ByteBuffer; public class FieldFrameBodyEAR extends AbstractLyrics3v2FieldFrameBody { /** * Creates a new FieldBodyEAR datatype. */ public FieldFrameBodyEAR() { // this.setObject("Artist", ""); } public FieldFrameBodyEAR(FieldFrameBodyEAR body) { super(body); } /** * Creates a new FieldBodyEAR datatype. * * @param artist */ public FieldFrameBodyEAR(String artist) { this.setObjectValue("Artist", artist); } /** * Creates a new FieldBodyEAR datatype. * * @param byteBuffer * @throws InvalidTagException */ public FieldFrameBodyEAR(ByteBuffer byteBuffer) throws InvalidTagException { this.read(byteBuffer); } /** * @param artist */ public void setArtist(String artist) { setObjectValue("Artist", artist); } /** * @return */ public String getArtist() { return (String) getObjectValue("Artist"); } /** * @return */ public String getIdentifier() { return "EAR"; } /** * */ protected void setupObjectList() { objectList.add(new StringSizeTerminated("Artist", this)); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/lyrics3/FieldFrameBodyAUT.java0000644000175000017500000000462611277006322027712 0ustar drazzibdrazzib/** * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: FieldFrameBodyAUT.java 832 2009-11-12 13:25:38Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Description: */ package org.jaudiotagger.tag.lyrics3; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.datatype.StringSizeTerminated; import java.nio.ByteBuffer; public class FieldFrameBodyAUT extends AbstractLyrics3v2FieldFrameBody { /** * Creates a new FieldBodyAUT datatype. */ public FieldFrameBodyAUT() { // this.setObject("Author", ""); } public FieldFrameBodyAUT(FieldFrameBodyAUT body) { super(body); } /** * Creates a new FieldBodyAUT datatype. * * @param author */ public FieldFrameBodyAUT(String author) { this.setObjectValue("Author", author); } /** * Creates a new FieldBodyAUT datatype. * * @param byteBuffer * @throws InvalidTagException */ public FieldFrameBodyAUT(ByteBuffer byteBuffer) throws InvalidTagException { this.read(byteBuffer); } /** * @param author */ public void setAuthor(String author) { setObjectValue("Author", author); } /** * @return */ public String getAuthor() { return (String) getObjectValue("Author"); } /** * @return */ public String getIdentifier() { return "AUT"; } /** * */ protected void setupObjectList() { objectList.add(new StringSizeTerminated("Author", this)); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/lyrics3/FieldFrameBodyLYR.java0000644000175000017500000002262411277026507027734 0ustar drazzibdrazzib/** * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: FieldFrameBodyLYR.java 836 2009-11-12 15:44:07Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Description: */ package org.jaudiotagger.tag.lyrics3; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.TagOptionSingleton; import org.jaudiotagger.tag.datatype.ID3v2LyricLine; import org.jaudiotagger.tag.datatype.Lyrics3Line; import org.jaudiotagger.tag.datatype.Lyrics3TimeStamp; import org.jaudiotagger.tag.id3.framebody.FrameBodySYLT; import org.jaudiotagger.tag.id3.framebody.FrameBodyUSLT; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; public class FieldFrameBodyLYR extends AbstractLyrics3v2FieldFrameBody { /** * */ private ArrayList lines = new ArrayList(); /** * Creates a new FieldBodyLYR datatype. */ public FieldFrameBodyLYR() { } public FieldFrameBodyLYR(FieldFrameBodyLYR copyObject) { super(copyObject); Lyrics3Line old; for (int i = 0; i < copyObject.lines.size(); i++) { old = copyObject.lines.get(i); this.lines.add(new Lyrics3Line(old)); } } /** * Creates a new FieldBodyLYR datatype. * * @param line */ public FieldFrameBodyLYR(String line) { readString(line); } /** * Creates a new FieldBodyLYR datatype. * * @param sync */ public FieldFrameBodyLYR(FrameBodySYLT sync) { addLyric(sync); } /** * Creates a new FieldBodyLYR datatype. * * @param unsync */ public FieldFrameBodyLYR(FrameBodyUSLT unsync) { addLyric(unsync); } /** * Creates a new FieldBodyLYR datatype. * @param byteBuffer * @throws org.jaudiotagger.tag.InvalidTagException */ public FieldFrameBodyLYR(ByteBuffer byteBuffer) throws InvalidTagException { this.read(byteBuffer); } /** * @return */ public String getIdentifier() { return "LYR"; } /** * @param str */ public void setLyric(String str) { readString(str); } /** * @return */ public String getLyric() { return writeString(); } /** * @return */ public int getSize() { int size = 0; Lyrics3Line line; for (Object line1 : lines) { line = (Lyrics3Line) line1; size += (line.getSize() + 2); } return size; //return size - 2; // cut off the last crlf pair } /** * @param obj * @return */ public boolean isSubsetOf(Object obj) { if (!(obj instanceof FieldFrameBodyLYR)) { return false; } ArrayList superset = ((FieldFrameBodyLYR) obj).lines; for (Object line : lines) { if (!superset.contains(line)) { return false; } } return super.isSubsetOf(obj); } /** * @param sync */ public void addLyric(FrameBodySYLT sync) { // SYLT frames are made of individual lines Iterator iterator = sync.iterator(); Lyrics3Line newLine; ID3v2LyricLine currentLine; Lyrics3TimeStamp timeStamp; HashMap lineMap = new HashMap(); while (iterator.hasNext()) { currentLine = iterator.next(); // createField copy to use in new tag currentLine = new ID3v2LyricLine(currentLine); timeStamp = new Lyrics3TimeStamp("Time Stamp", this); timeStamp.setTimeStamp(currentLine.getTimeStamp(), (byte) sync.getTimeStampFormat()); if (lineMap.containsKey(currentLine.getText())) { newLine = lineMap.get(currentLine.getText()); newLine.addTimeStamp(timeStamp); } else { newLine = new Lyrics3Line("Lyric Line", this); newLine.setLyric(currentLine); newLine.setTimeStamp(timeStamp); lineMap.put(currentLine.getText(), newLine); lines.add(newLine); } } } /** * @param unsync */ public void addLyric(FrameBodyUSLT unsync) { // USLT frames are just long text string; Lyrics3Line line = new Lyrics3Line("Lyric Line", this); line.setLyric(unsync.getLyric()); lines.add(line); } /** * @param obj * @return */ public boolean equals(Object obj) { if (!(obj instanceof FieldFrameBodyLYR)) { return false; } FieldFrameBodyLYR object = (FieldFrameBodyLYR) obj; return this.lines.equals(object.lines) && super.equals(obj); } /** * @return */ public boolean hasTimeStamp() { boolean present = false; for (Object line : lines) { if (((Lyrics3Line) line).hasTimeStamp()) { present = true; } } return present; } /** * @return */ public Iterator iterator() { return lines.iterator(); } /** * * * */ public void read(ByteBuffer byteBuffer) throws InvalidTagException { String lineString; byte[] buffer = new byte[5]; // read the 5 character size byteBuffer.get(buffer, 0, 5); int size = Integer.parseInt(new String(buffer, 0, 5)); if ((size == 0) && (!TagOptionSingleton.getInstance().isLyrics3KeepEmptyFieldIfRead())) { throw new InvalidTagException("Lyircs3v2 Field has size of zero."); } buffer = new byte[size]; // read the SIZE length description byteBuffer.get(buffer); lineString = new String(buffer); readString(lineString); } /** * @return */ public String toString() { String str = getIdentifier() + " : "; for (Object line : lines) { str += line.toString(); } return str; } /** * @param file * @throws java.io.IOException */ public void write(RandomAccessFile file) throws java.io.IOException { int size; int offset = 0; byte[] buffer = new byte[5]; String str; size = getSize(); str = Integer.toString(size); for (int i = 0; i < (5 - str.length()); i++) { buffer[i] = (byte) '0'; } offset += (5 - str.length()); for (int i = 0; i < str.length(); i++) { buffer[i + offset] = (byte) str.charAt(i); } offset += str.length(); file.write(buffer, 0, 5); if (size > 0) { str = writeString(); buffer = new byte[str.length()]; for (int i = 0; i < str.length(); i++) { buffer[i] = (byte) str.charAt(i); } file.write(buffer); } } /** * @param lineString */ private void readString(String lineString) { // now readString each line and put in the vector; String token; int offset = 0; int delim = lineString.indexOf(Lyrics3v2Fields.CRLF); lines = new ArrayList(); Lyrics3Line line; while (delim >= 0) { token = lineString.substring(offset, delim); line = new Lyrics3Line("Lyric Line", this); line.setLyric(token); lines.add(line); offset = delim + Lyrics3v2Fields.CRLF.length(); delim = lineString.indexOf(Lyrics3v2Fields.CRLF, offset); } if (offset < lineString.length()) { token = lineString.substring(offset); line = new Lyrics3Line("Lyric Line", this); line.setLyric(token); lines.add(line); } } /** * @return */ private String writeString() { Lyrics3Line line; String str = ""; for (Object line1 : lines) { line = (Lyrics3Line) line1; str += (line.writeString() + Lyrics3v2Fields.CRLF); } return str; //return str.substring(0,str.length()-2); // cut off the last CRLF pair } /** * TODO */ protected void setupObjectList() { } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/lyrics3/Lyrics3v2Field.java0000644000175000017500000002016111277026507027267 0ustar drazzibdrazzib/** * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: Lyrics3v2Field.java 836 2009-11-12 15:44:07Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Description: */ package org.jaudiotagger.tag.lyrics3; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.TagException; import org.jaudiotagger.tag.TagOptionSingleton; import org.jaudiotagger.tag.id3.AbstractID3v2Frame; import org.jaudiotagger.tag.id3.AbstractTagFrame; import org.jaudiotagger.tag.id3.framebody.AbstractFrameBodyTextInfo; import org.jaudiotagger.tag.id3.framebody.FrameBodyCOMM; import org.jaudiotagger.tag.id3.framebody.FrameBodySYLT; import org.jaudiotagger.tag.id3.framebody.FrameBodyUSLT; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.ByteBuffer; public class Lyrics3v2Field extends AbstractTagFrame { /** * Creates a new Lyrics3v2Field datatype. */ public Lyrics3v2Field() { } public Lyrics3v2Field(Lyrics3v2Field copyObject) { super(copyObject); } /** * Creates a new Lyrics3v2Field datatype. * * @param body */ public Lyrics3v2Field(AbstractLyrics3v2FieldFrameBody body) { this.frameBody = body; } /** * Creates a new Lyrics3v2Field datatype. * * @param frame * @throws TagException */ public Lyrics3v2Field(AbstractID3v2Frame frame) throws TagException { AbstractFrameBodyTextInfo textFrame; String text; String frameIdentifier = frame.getIdentifier(); if (frameIdentifier.startsWith("USLT")) { frameBody = new FieldFrameBodyLYR(""); ((FieldFrameBodyLYR) frameBody).addLyric((FrameBodyUSLT) frame.getBody()); } else if (frameIdentifier.startsWith("SYLT")) { frameBody = new FieldFrameBodyLYR(""); ((FieldFrameBodyLYR) frameBody).addLyric((FrameBodySYLT) frame.getBody()); } else if (frameIdentifier.startsWith("COMM")) { text = ((FrameBodyCOMM) frame.getBody()).getText(); frameBody = new FieldFrameBodyINF(text); } else if (frameIdentifier.equals("TCOM")) { textFrame = (AbstractFrameBodyTextInfo) frame.getBody(); frameBody = new FieldFrameBodyAUT(""); if ((textFrame != null) && (textFrame.getText().length() > 0)) { frameBody = new FieldFrameBodyAUT(textFrame.getText()); } } else if (frameIdentifier.equals("TALB")) { textFrame = (AbstractFrameBodyTextInfo) frame.getBody(); if ((textFrame != null) && (textFrame.getText().length() > 0)) { frameBody = new FieldFrameBodyEAL(textFrame.getText()); } } else if (frameIdentifier.equals("TPE1")) { textFrame = (AbstractFrameBodyTextInfo) frame.getBody(); if ((textFrame != null) && (textFrame.getText().length() > 0)) { frameBody = new FieldFrameBodyEAR(textFrame.getText()); } } else if (frameIdentifier.equals("TIT2")) { textFrame = (AbstractFrameBodyTextInfo) frame.getBody(); if ((textFrame != null) && (textFrame.getText().length() > 0)) { frameBody = new FieldFrameBodyETT(textFrame.getText()); } } else { throw new TagException("Cannot createField Lyrics3v2 field from given ID3v2 frame"); } } /** * Creates a new Lyrics3v2Field datatype. * * @param file * @throws InvalidTagException * @param byteBuffer */ public Lyrics3v2Field(ByteBuffer byteBuffer) throws InvalidTagException { this.read(byteBuffer); } /** * @return */ public String getIdentifier() { if (frameBody == null) { return ""; } return frameBody.getIdentifier(); } /** * @return */ public int getSize() { return frameBody.getSize() + 5 + getIdentifier().length(); } /** * @param byteBuffer * @throws InvalidTagException * @throws IOException */ public void read(ByteBuffer byteBuffer) throws InvalidTagException { byte[] buffer = new byte[6]; // lets scan for a non-zero byte; long filePointer; byte b; do { b = byteBuffer.get(); } while (b == 0); byteBuffer.position(byteBuffer.position() - 1); // read the 3 character ID byteBuffer.get(buffer, 0, 3); String identifier = new String(buffer, 0, 3); // is this a valid identifier? if (!Lyrics3v2Fields.isLyrics3v2FieldIdentifier(identifier)) { throw new InvalidTagException(identifier + " is not a valid ID3v2.4 frame"); } frameBody = readBody(identifier, byteBuffer); } /** * @return */ public String toString() { if (frameBody == null) { return ""; } return frameBody.toString(); } /** * @param file * @throws IOException */ public void write(RandomAccessFile file) throws IOException { if ((frameBody.getSize() > 0) || TagOptionSingleton.getInstance().isLyrics3SaveEmptyField()) { byte[] buffer = new byte[3]; String str = getIdentifier(); for (int i = 0; i < str.length(); i++) { buffer[i] = (byte) str.charAt(i); } file.write(buffer, 0, str.length()); //body.write(file); } } /** * Read a Lyrics3 Field from a file. * * @param identifier * @param byteBuffer * @return * @throws InvalidTagException */ private AbstractLyrics3v2FieldFrameBody readBody(String identifier, ByteBuffer byteBuffer) throws InvalidTagException { AbstractLyrics3v2FieldFrameBody newBody; if (identifier.equals(Lyrics3v2Fields.FIELD_V2_AUTHOR)) { newBody = new FieldFrameBodyAUT(byteBuffer); } else if (identifier.equals(Lyrics3v2Fields.FIELD_V2_ALBUM)) { newBody = new FieldFrameBodyEAL(byteBuffer); } else if (identifier.equals(Lyrics3v2Fields.FIELD_V2_ARTIST)) { newBody = new FieldFrameBodyEAR(byteBuffer); } else if (identifier.equals(Lyrics3v2Fields.FIELD_V2_TRACK)) { newBody = new FieldFrameBodyETT(byteBuffer); } else if (identifier.equals(Lyrics3v2Fields.FIELD_V2_IMAGE)) { newBody = new FieldFrameBodyIMG(byteBuffer); } else if (identifier.equals(Lyrics3v2Fields.FIELD_V2_INDICATIONS)) { newBody = new FieldFrameBodyIND(byteBuffer); } else if (identifier.equals(Lyrics3v2Fields.FIELD_V2_ADDITIONAL_MULTI_LINE_TEXT)) { newBody = new FieldFrameBodyINF(byteBuffer); } else if (identifier.equals(Lyrics3v2Fields.FIELD_V2_LYRICS_MULTI_LINE_TEXT)) { newBody = new FieldFrameBodyLYR(byteBuffer); } else { newBody = new FieldFrameBodyUnsupported(byteBuffer); } return newBody; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/lyrics3/AbstractLyrics3v2FieldFrameBody.java0000644000175000017500000001236411277026507032552 0ustar drazzibdrazzib/** * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: AbstractLyrics3v2FieldFrameBody.java 836 2009-11-12 15:44:07Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Description: */ package org.jaudiotagger.tag.lyrics3; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.TagOptionSingleton; import org.jaudiotagger.tag.datatype.AbstractDataType; import org.jaudiotagger.tag.id3.AbstractTagFrameBody; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.util.Iterator; public abstract class AbstractLyrics3v2FieldFrameBody extends AbstractTagFrameBody { public AbstractLyrics3v2FieldFrameBody() { } public AbstractLyrics3v2FieldFrameBody(AbstractLyrics3v2FieldFrameBody copyObject) { super(copyObject); } /** * This is called by superclass when attempt to read data from file. * * @param file * @return * @throws InvalidTagException * @throws IOException */ protected int readHeader(RandomAccessFile file) throws InvalidTagException, IOException { int size; byte[] buffer = new byte[5]; // read the 5 character size file.read(buffer, 0, 5); size = Integer.parseInt(new String(buffer, 0, 5)); if ((size == 0) && (!TagOptionSingleton.getInstance().isLyrics3KeepEmptyFieldIfRead())) { throw new InvalidTagException("Lyircs3v2 Field has size of zero."); } return size; } /** * This is called by superclass when attempt to write data from file. * * @param file * @param size * @throws IOException */ protected void writeHeader(RandomAccessFile file, int size) throws IOException { String str; int offset = 0; byte[] buffer = new byte[5]; /** * @todo change this to use pad String */ str = Integer.toString(getSize()); for (int i = 0; i < (5 - str.length()); i++) { buffer[i] = (byte) '0'; } offset += (5 - str.length()); for (int i = 0; i < str.length(); i++) { buffer[i + offset] = (byte) str.charAt(i); } file.write(buffer); } /** * This reads a frame body from its file into the appropriate FrameBody class * Read the data from the given file into this datatype. The file needs to * have its file pointer in the correct location. The size as indicated in the * header is passed to the frame constructor when reading from file. * * @param byteBuffer file to read * @throws IOException on any I/O error * @throws InvalidTagException if there is any error in the data format. */ public void read(ByteBuffer byteBuffer) throws InvalidTagException { int size = getSize(); //Allocate a buffer to the size of the Frame Body and read from file byte[] buffer = new byte[size]; byteBuffer.get(buffer); //Offset into buffer, incremented by length of previous MP3Object int offset = 0; //Go through the ObjectList of the Frame reading the data into the //correct datatype. AbstractDataType object; Iterator iterator = objectList.listIterator(); while (iterator.hasNext()) { //The read has extended further than the defined frame size if (offset > (size - 1)) { throw new InvalidTagException("Invalid size for Frame Body"); } //Get next Object and load it with data from the Buffer object = iterator.next(); object.readByteArray(buffer, offset); //Increment Offset to start of next datatype. offset += object.getSize(); } } /** * Write the contents of this datatype to the file at the position it is * currently at. * * @param file destination file * @throws IOException on any I/O error */ public void write(RandomAccessFile file) throws IOException { //Write the various fields to file in order byte[] buffer; AbstractDataType object; Iterator iterator = objectList.listIterator(); while (iterator.hasNext()) { object = iterator.next(); buffer = object.writeByteArray(); file.write(buffer); } } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/lyrics3/Lyrics3v2.java0000644000175000017500000003214611277026507026331 0ustar drazzibdrazzib/** * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: Lyrics3v2.java 836 2009-11-12 15:44:07Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Description: */ package org.jaudiotagger.tag.lyrics3; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.TagException; import org.jaudiotagger.tag.TagNotFoundException; import org.jaudiotagger.tag.TagOptionSingleton; import org.jaudiotagger.tag.id3.AbstractID3v2Frame; import org.jaudiotagger.tag.id3.AbstractTag; import org.jaudiotagger.tag.id3.ID3v1Tag; import org.jaudiotagger.tag.id3.ID3v24Tag; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.util.HashMap; import java.util.Iterator; public class Lyrics3v2 extends AbstractLyrics3 { /** * */ private HashMap fieldMap = new HashMap(); /** * Creates a new Lyrics3v2 datatype. */ public Lyrics3v2() { } public Lyrics3v2(Lyrics3v2 copyObject) { super(copyObject); Iterator iterator = copyObject.fieldMap.keySet().iterator(); String oldIdentifier; String newIdentifier; Lyrics3v2Field newObject; while (iterator.hasNext()) { oldIdentifier = iterator.next(); newIdentifier = oldIdentifier; newObject = new Lyrics3v2Field(copyObject.fieldMap.get(newIdentifier)); fieldMap.put(newIdentifier, newObject); } } /** * Creates a new Lyrics3v2 datatype. * * @param mp3tag * @throws UnsupportedOperationException */ public Lyrics3v2(AbstractTag mp3tag) { if (mp3tag != null) { // upgrade the tag to lyrics3v2 if (mp3tag instanceof Lyrics3v2) { throw new UnsupportedOperationException("Copy Constructor not called. Please type cast the argument"); } else if (mp3tag instanceof Lyrics3v1) { Lyrics3v1 lyricOld = (Lyrics3v1) mp3tag; Lyrics3v2Field newField; newField = new Lyrics3v2Field(new FieldFrameBodyLYR(lyricOld.getLyric())); fieldMap.put(newField.getIdentifier(), newField); } else { Lyrics3v2Field newField; Iterator iterator; iterator = (new ID3v24Tag(mp3tag)).iterator(); while (iterator.hasNext()) { try { newField = new Lyrics3v2Field(iterator.next()); if (newField != null) { fieldMap.put(newField.getIdentifier(), newField); } } catch (TagException ex) { //invalid frame to createField lyrics3 field. ignore and keep going } } } } } /** * Creates a new Lyrics3v2 datatype. * * @param file * @throws TagNotFoundException * @throws IOException * @param byteBuffer */ public Lyrics3v2(ByteBuffer byteBuffer) throws TagNotFoundException, IOException { try { this.read(byteBuffer); } catch (TagException e) { e.printStackTrace(); } } /** * @param field */ public void setField(Lyrics3v2Field field) { fieldMap.put(field.getIdentifier(), field); } /** * Gets the value of the frame identified by identifier * * @param identifier The three letter code * @return The value associated with the identifier */ public Lyrics3v2Field getField(String identifier) { return fieldMap.get(identifier); } /** * @return */ public int getFieldCount() { return fieldMap.size(); } /** * @return */ public String getIdentifier() { return "Lyrics3v2.00"; } /** * @return */ public int getSize() { int size = 0; Iterator iterator = fieldMap.values().iterator(); Lyrics3v2Field field; while (iterator.hasNext()) { field = iterator.next(); size += field.getSize(); } // include LYRICSBEGIN, but not 6 char size or LYRICSEND return 11 + size; } /** * @param obj * @return */ public boolean equals(Object obj) { if (!(obj instanceof Lyrics3v2)) { return false; } Lyrics3v2 object = (Lyrics3v2) obj; return this.fieldMap.equals(object.fieldMap) && super.equals(obj); } /** * @param identifier * @return */ public boolean hasField(String identifier) { return fieldMap.containsKey(identifier); } /** * @return */ public Iterator iterator() { return fieldMap.values().iterator(); } /** * TODO implement * * @param byteBuffer * @return * @throws IOException */ public boolean seek(ByteBuffer byteBuffer) { return false; } public void read(ByteBuffer byteBuffer) throws TagException { long filePointer; int lyricSize; if (seek(byteBuffer)) { lyricSize = seekSize(byteBuffer); } else { throw new TagNotFoundException("Lyrics3v2.00 Tag Not Found"); } // reset file pointer to the beginning of the tag; seek(byteBuffer); filePointer = byteBuffer.position(); fieldMap = new HashMap(); Lyrics3v2Field lyric; // read each of the fields while ((byteBuffer.position()) < (lyricSize - 11)) { try { lyric = new Lyrics3v2Field(byteBuffer); setField(lyric); } catch (InvalidTagException ex) { // keep reading until we're done } } } /** * @param identifier */ public void removeField(String identifier) { fieldMap.remove(identifier); } /** * @param file * @return * @throws IOException */ public boolean seek(RandomAccessFile file) throws IOException { byte[] buffer = new byte[11]; String lyricEnd; String lyricStart; long filePointer; long lyricSize; // check right before the ID3 1.0 tag for the lyrics tag file.seek(file.length() - 128 - 9); file.read(buffer, 0, 9); lyricEnd = new String(buffer, 0, 9); if (lyricEnd.equals("LYRICS200")) { filePointer = file.getFilePointer(); } else { // check the end of the file for a lyrics tag incase an ID3 // tag wasn't placed after it. file.seek(file.length() - 9); file.read(buffer, 0, 9); lyricEnd = new String(buffer, 0, 9); if (lyricEnd.equals("LYRICS200")) { filePointer = file.getFilePointer(); } else { return false; } } // read the 6 bytes for the length of the tag filePointer -= (9 + 6); file.seek(filePointer); file.read(buffer, 0, 6); lyricSize = Integer.parseInt(new String(buffer, 0, 6)); // read the lyrics begin tag if it exists. file.seek(filePointer - lyricSize); file.read(buffer, 0, 11); lyricStart = new String(buffer, 0, 11); return lyricStart.equals("LYRICSBEGIN"); } /** * @return */ public String toString() { Iterator iterator = fieldMap.values().iterator(); Lyrics3v2Field field; String str = getIdentifier() + " " + this.getSize() + "\n"; while (iterator.hasNext()) { field = iterator.next(); str += (field.toString() + "\n"); } return str; } /** * @param identifier */ public void updateField(String identifier) { Lyrics3v2Field lyrField; if (identifier.equals("IND")) { boolean lyricsPresent = fieldMap.containsKey("LYR"); boolean timeStampPresent = false; if (lyricsPresent) { lyrField = fieldMap.get("LYR"); FieldFrameBodyLYR lyrBody = (FieldFrameBodyLYR) lyrField.getBody(); timeStampPresent = lyrBody.hasTimeStamp(); } lyrField = new Lyrics3v2Field(new FieldFrameBodyIND(lyricsPresent, timeStampPresent)); setField(lyrField); } } /** * @param file * @throws IOException */ public void write(RandomAccessFile file) throws IOException { int offset = 0; long size; long filePointer; byte[] buffer = new byte[6 + 9]; String str; Lyrics3v2Field field; Iterator iterator; ID3v1Tag id3v1tag; new ID3v1Tag(); id3v1tag = null; delete(file); file.seek(file.length()); filePointer = file.getFilePointer(); str = "LYRICSBEGIN"; for (int i = 0; i < str.length(); i++) { buffer[i] = (byte) str.charAt(i); } file.write(buffer, 0, str.length()); // IND needs to go first. lets createField/update it and write it first. updateField("IND"); field = fieldMap.get("IND"); field.write(file); iterator = fieldMap.values().iterator(); while (iterator.hasNext()) { field = iterator.next(); String id = field.getIdentifier(); boolean save = TagOptionSingleton.getInstance().getLyrics3SaveField(id); if ((!id.equals("IND")) && save) { field.write(file); } } size = file.getFilePointer() - filePointer; if (this.getSize() != size) { //logger.info("Lyrics3v2 size didn't match up while writing."); //logger.info("this.getsize() = " + this.getSize()); //logger.info("size (filePointer) = " + size); } str = Long.toString(size); for (int i = 0; i < (6 - str.length()); i++) { buffer[i] = (byte) '0'; } offset += (6 - str.length()); for (int i = 0; i < str.length(); i++) { buffer[i + offset] = (byte) str.charAt(i); } offset += str.length(); str = "LYRICS200"; for (int i = 0; i < str.length(); i++) { buffer[i + offset] = (byte) str.charAt(i); } offset += str.length(); file.write(buffer, 0, offset); if (id3v1tag != null) { id3v1tag.write(file); } } /** * TODO * @param byteBuffer * @return */ private int seekSize(ByteBuffer byteBuffer) { /* byte[] buffer = new byte[11]; String lyricEnd = ""; long filePointer = 0; // check right before the ID3 1.0 tag for the lyrics tag file.seek(file.length() - 128 - 9); file.read(buffer, 0, 9); lyricEnd = new String(buffer, 0, 9); if (lyricEnd.equals("LYRICS200")) { filePointer = file.getFilePointer(); } else { // check the end of the file for a lyrics tag incase an ID3 // tag wasn't placed after it. file.seek(file.length() - 9); file.read(buffer, 0, 9); lyricEnd = new String(buffer, 0, 9); if (lyricEnd.equals("LYRICS200")) { filePointer = file.getFilePointer(); } else { return -1; } } // read the 6 bytes for the length of the tag filePointer -= (9 + 6); file.seek(filePointer); file.read(buffer, 0, 6); return Integer.parseInt(new String(buffer, 0, 6)); */ return -1; } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/lyrics3/FieldFrameBodyINF.java0000644000175000017500000000515511277026507027702 0ustar drazzibdrazzib/** * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: FieldFrameBodyINF.java 836 2009-11-12 15:44:07Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Description: */ package org.jaudiotagger.tag.lyrics3; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.datatype.StringSizeTerminated; import java.nio.ByteBuffer; public class FieldFrameBodyINF extends AbstractLyrics3v2FieldFrameBody { /** * Creates a new FieldBodyINF datatype. */ public FieldFrameBodyINF() { // this.setObject("Additional Information", ""); } public FieldFrameBodyINF(FieldFrameBodyINF body) { super(body); } /** * Creates a new FieldBodyINF datatype. * * @param additionalInformation */ public FieldFrameBodyINF(String additionalInformation) { this.setObjectValue("Additional Information", additionalInformation); } /** * Creates a new FieldBodyINF datatype. * @param byteBuffer * @throws org.jaudiotagger.tag.InvalidTagException */ public FieldFrameBodyINF(ByteBuffer byteBuffer) throws InvalidTagException { this.read(byteBuffer); } /** * @param additionalInformation */ public void setAdditionalInformation(String additionalInformation) { setObjectValue("Additional Information", additionalInformation); } /** * @return */ public String getAdditionalInformation() { return (String) getObjectValue("Additional Information"); } /** * @return */ public String getIdentifier() { return "INF"; } /** * */ protected void setupObjectList() { objectList.add(new StringSizeTerminated("Additional Information", this)); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/lyrics3/FieldFrameBodyUnsupported.java0000644000175000017500000001035311277026507031612 0ustar drazzibdrazzib/** * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: FieldFrameBodyUnsupported.java 836 2009-11-12 15:44:07Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Description: */ package org.jaudiotagger.tag.lyrics3; import org.jaudiotagger.tag.InvalidTagException; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.ByteBuffer; public class FieldFrameBodyUnsupported extends AbstractLyrics3v2FieldFrameBody { /** * */ private byte[] value = null; /** * Creates a new FieldBodyUnsupported datatype. */ public FieldFrameBodyUnsupported() { // this.value = new byte[0]; } public FieldFrameBodyUnsupported(FieldFrameBodyUnsupported copyObject) { super(copyObject); this.value = copyObject.value.clone(); } /** * Creates a new FieldBodyUnsupported datatype. * * @param value */ public FieldFrameBodyUnsupported(byte[] value) { this.value = value; } /** * Creates a new FieldBodyUnsupported datatype. * @param byteBuffer * @throws org.jaudiotagger.tag.InvalidTagException */ public FieldFrameBodyUnsupported(ByteBuffer byteBuffer) throws InvalidTagException { this.read(byteBuffer); } /** * @return */ public String getIdentifier() { return "ZZZ"; } /** * @param obj * @return */ public boolean isSubsetOf(Object obj) { if (!(obj instanceof FieldFrameBodyUnsupported)) { return false; } FieldFrameBodyUnsupported object = (FieldFrameBodyUnsupported) obj; String subset = new String(this.value); String superset = new String(object.value); return superset.contains(subset) && super.isSubsetOf(obj); } /** * @param obj * @return */ public boolean equals(Object obj) { if (!(obj instanceof FieldFrameBodyUnsupported)) { return false; } FieldFrameBodyUnsupported object = (FieldFrameBodyUnsupported) obj; return java.util.Arrays.equals(this.value, object.value) && super.equals(obj); } /** * @param byteBuffer * @throws IOException */ public void read(ByteBuffer byteBuffer) throws InvalidTagException { int size; byte[] buffer = new byte[5]; // read the 5 character size byteBuffer.get(buffer, 0, 5); size = Integer.parseInt(new String(buffer, 0, 5)); value = new byte[size]; // read the SIZE length description byteBuffer.get(value); } /** * @return */ public String toString() { return getIdentifier() + " : " + (new String(value)); } /** * @param file * @throws IOException */ public void write(RandomAccessFile file) throws IOException { int offset = 0; String str; byte[] buffer = new byte[5]; str = Integer.toString(value.length); for (int i = 0; i < (5 - str.length()); i++) { buffer[i] = (byte) '0'; } offset += (5 - str.length()); for (int i = 0; i < str.length(); i++) { buffer[i + offset] = (byte) str.charAt(i); } file.write(buffer); file.write(value); } /** * TODO */ protected void setupObjectList() { } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/lyrics3/FieldFrameBodyEAL.java0000644000175000017500000000460611277006322027660 0ustar drazzibdrazzib/** * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: FieldFrameBodyEAL.java 832 2009-11-12 13:25:38Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Description: */ package org.jaudiotagger.tag.lyrics3; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.datatype.StringSizeTerminated; import java.nio.ByteBuffer; public class FieldFrameBodyEAL extends AbstractLyrics3v2FieldFrameBody { /** * Creates a new FieldBodyEAL datatype. */ public FieldFrameBodyEAL() { // this.setObject("Album", ""); } public FieldFrameBodyEAL(FieldFrameBodyEAL body) { super(body); } /** * Creates a new FieldBodyEAL datatype. * * @param album */ public FieldFrameBodyEAL(String album) { this.setObjectValue("Album", album); } /** * Creates a new FieldBodyEAL datatype. * * @param byteBuffer * @throws InvalidTagException */ public FieldFrameBodyEAL(ByteBuffer byteBuffer) throws InvalidTagException { read(byteBuffer); } /** * @param album */ public void setAlbum(String album) { setObjectValue("Album", album); } /** * @return */ public String getAlbum() { return (String) getObjectValue("Album"); } /** * @return */ public String getIdentifier() { return "EAL"; } /** * */ protected void setupObjectList() { objectList.add(new StringSizeTerminated("Album", this)); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/TagException.java0000644000175000017500000000353710736454526025542 0ustar drazzibdrazzib/* * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: TagException.java 520 2008-01-01 15:16:38Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ package org.jaudiotagger.tag; /** * This is the exception that is always generated by any class in these * packages. * * @author Eric Farng * @version $Revision: 520 $ */ public class TagException extends Exception { /** * Creates a new TagException datatype. */ public TagException() { } /** * Creates a new TagException datatype. * * @param ex the cause. */ public TagException(Throwable ex) { super(ex); } /** * Creates a new TagException datatype. * * @param msg the detail message. */ public TagException(String msg) { super(msg); } /** * Creates a new TagException datatype. * * @param msg the detail message. * @param ex the cause. */ public TagException(String msg, Throwable ex) { super(msg, ex); } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/InvalidFrameException.java0000644000175000017500000000363410736454526027366 0ustar drazzibdrazzib/* * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: InvalidFrameException.java 520 2008-01-01 15:16:38Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ package org.jaudiotagger.tag; /** * Thrown if frame cannot be read correctly. * * @author Eric Farng * @version $Revision: 520 $ */ public class InvalidFrameException extends InvalidTagException { /** * Creates a new InvalidFrameException datatype. */ public InvalidFrameException() { } /** * Creates a new InvalidFrameException datatype. * * @param ex the cause. */ public InvalidFrameException(Throwable ex) { super(ex); } /** * Creates a new InvalidFrameException datatype. * * @param msg the detail message. */ public InvalidFrameException(String msg) { super(msg); } /** * Creates a new InvalidFrameException datatype. * * @param msg the detail message. * @param ex the cause. */ public InvalidFrameException(String msg, Throwable ex) { super(msg, ex); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/KeyNotFoundException.java0000644000175000017500000000165510736454526027233 0ustar drazzibdrazzibpackage org.jaudiotagger.tag; /** * Thrown if the key cannot be found *

*

Shoudl not happen with well written code, hence RuntimeException. */ public class KeyNotFoundException extends RuntimeException { /** * Creates a new KeyNotFoundException datatype. */ public KeyNotFoundException() { } /** * Creates a new KeyNotFoundException datatype. * * @param ex the cause. */ public KeyNotFoundException(Throwable ex) { super(ex); } /** * Creates a new KeyNotFoundException datatype. * * @param msg the detail message. */ public KeyNotFoundException(String msg) { super(msg); } /** * Creates a new KeyNotFoundException datatype. * * @param msg the detail message. * @param ex the cause. */ public KeyNotFoundException(String msg, Throwable ex) { super(msg, ex); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/FieldDataInvalidException.java0000644000175000017500000000204110736454526030140 0ustar drazzibdrazzibpackage org.jaudiotagger.tag; /** * Thrown if the try and create a field with invalid data *

*

For example if try and create an Mp4Field with type Byte using data that cannot be parsed as a number * then this exception will be thrown */ public class FieldDataInvalidException extends TagException { /** * Creates a new KeyNotFoundException datatype. */ public FieldDataInvalidException() { } /** * Creates a new KeyNotFoundException datatype. * * @param ex the cause. */ public FieldDataInvalidException(Throwable ex) { super(ex); } /** * Creates a new KeyNotFoundException datatype. * * @param msg the detail message. */ public FieldDataInvalidException(String msg) { super(msg); } /** * Creates a new KeyNotFoundException datatype. * * @param msg the detail message. * @param ex the cause. */ public FieldDataInvalidException(String msg, Throwable ex) { super(msg, ex); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/datatype/0000755000175000017500000000000011556363176024111 5ustar drazzibdrazziblibjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/datatype/BooleanByte.java0000644000175000017500000000702311470746136027155 0ustar drazzibdrazzib/** * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: BooleanByte.java 929 2010-11-17 12:36:46Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Description: * */ package org.jaudiotagger.tag.datatype; import org.jaudiotagger.tag.InvalidDataTypeException; import org.jaudiotagger.tag.id3.AbstractTagFrameBody; /** * Represents a bit flag within a byte */ public class BooleanByte extends AbstractDataType { /** * */ int bitPosition = -1; /** * Creates a new ObjectBooleanByte datatype. * * @param identifier * @param frameBody * @param bitPosition * @throws IndexOutOfBoundsException */ public BooleanByte(String identifier, AbstractTagFrameBody frameBody, int bitPosition) { super(identifier, frameBody); if ((bitPosition < 0) || (bitPosition > 7)) { throw new IndexOutOfBoundsException("Bit position needs to be from 0 - 7 : " + bitPosition); } this.bitPosition = bitPosition; } public BooleanByte(BooleanByte copy) { super(copy); this.bitPosition = copy.bitPosition; } /** * @return */ public int getBitPosition() { return bitPosition; } /** * @return */ public int getSize() { return 1; } /** * @param obj * @return */ public boolean equals(Object obj) { if (!(obj instanceof BooleanByte)) { return false; } BooleanByte object = (BooleanByte) obj; return this.bitPosition == object.bitPosition && super.equals(obj); } /** * @param arr * @param offset * @throws NullPointerException * @throws IndexOutOfBoundsException */ public void readByteArray(byte[] arr, int offset) throws InvalidDataTypeException { if (arr == null) { throw new NullPointerException("Byte array is null"); } if ((offset < 0) || (offset >= arr.length)) { throw new IndexOutOfBoundsException("Offset to byte array is out of bounds: offset = " + offset + ", array.length = " + arr.length); } byte newValue = arr[offset]; newValue >>= bitPosition; newValue &= 0x1; this.value = newValue == 1; } /** * @return */ public String toString() { return "" + value; } /** * @return */ public byte[] writeByteArray() { byte[] retValue; retValue = new byte[1]; if (value != null) { retValue[0] = (byte) ((Boolean) value ? 1 : 0); retValue[0] <<= bitPosition; } return retValue; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/datatype/TextEncodedStringSizeTerminated.java0000644000175000017500000003042411470746136033220 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.datatype; import org.jaudiotagger.logging.Hex; import org.jaudiotagger.tag.InvalidDataTypeException; import org.jaudiotagger.tag.TagOptionSingleton; import org.jaudiotagger.tag.id3.AbstractTagFrameBody; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; import java.nio.Buffer; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.charset.*; import java.util.ArrayList; import java.util.Arrays; import java.util.List; /** * Represents a String which is not delimited by null character. *

* This type of String will usually only be used when it is the last field within a frame, when reading the remainder of * the byte array will be read, when writing the frame will be accommodate the required size for the String. The String * will be encoded based upon the text encoding of the frame that it belongs to. *

* All TextInformation frames support multiple strings, stored as a null separated list, where null is represented by * the termination code for the character encoding. This functionality is only officially support in ID3v24. * * Most applications will ignore any but the first value, but some such as Foobar 2000 will decode them properly * * iTunes write null terminators characters after the String even though it only writes a single value. * * */ public class TextEncodedStringSizeTerminated extends AbstractString { /** * Creates a new empty TextEncodedStringSizeTerminated datatype. * * @param identifier identifies the frame type * @param frameBody */ public TextEncodedStringSizeTerminated(String identifier, AbstractTagFrameBody frameBody) { super(identifier, frameBody); } /** * Copy constructor * * @param object */ public TextEncodedStringSizeTerminated(TextEncodedStringSizeTerminated object) { super(object); } public boolean equals(Object obj) { if(this==obj) { return true; } return obj instanceof TextEncodedStringSizeTerminated && super.equals(obj); } /** * Read a 'n' bytes from buffer into a String where n is the framesize - offset * so thefore cannot use this if there are other objects after it because it has no * delimiter. *

* Must take into account the text encoding defined in the Encoding Object * ID3 Text Frames often allow multiple strings seperated by the null char * appropriate for the encoding. * * @param arr this is the buffer for the frame * @param offset this is where to start reading in the buffer for this field * @throws NullPointerException * @throws IndexOutOfBoundsException */ public void readByteArray(byte[] arr, int offset) throws InvalidDataTypeException { logger.finest("Reading from array from offset:" + offset); //Get the Specified Decoder String charSetName = getTextEncodingCharSet(); CharsetDecoder decoder = Charset.forName(charSetName).newDecoder(); decoder.reset(); //Decode sliced inBuffer ByteBuffer inBuffer; if(TagOptionSingleton.getInstance().isAndroid()) { //#302 [dallen] truncating array manually since the decoder.decode() does not honor the offset in the in buffer byte[] truncArr = new byte[arr.length - offset]; System.arraycopy(arr, offset, truncArr, 0, truncArr.length); inBuffer = ByteBuffer.wrap(truncArr); } else { inBuffer = ByteBuffer.wrap(arr, offset, arr.length - offset).slice(); } CharBuffer outBuffer = CharBuffer.allocate(arr.length - offset); CoderResult coderResult = decoder.decode(inBuffer, outBuffer, true); if (coderResult.isError()) { logger.warning("Decoding error:" + coderResult.toString()); } decoder.flush(outBuffer); outBuffer.flip(); //If using UTF16 with BOM we then search through the text removing any BOMs that could exist //for multiple values, BOM could be Big Endian or Little Endian if (charSetName.equals(TextEncoding.CHARSET_UTF_16)) { value = outBuffer.toString().replace("\ufeff","").replace("\ufffe",""); } else { value = outBuffer.toString(); } //SetSize, important this is correct for finding the next datatype setSize(arr.length - offset); logger.info("Read SizeTerminatedString:" + value + " size:" + size); } /** * Write String using specified encoding * * When this is called multiple times, all but the last value has a trailing null * * @param encoder * @param next * @param i * @param noOfValues * @return * @throws CharacterCodingException */ private ByteBuffer writeString( CharsetEncoder encoder, String next, int i, int noOfValues) throws CharacterCodingException { ByteBuffer bb; if(( i + 1) == noOfValues ) { bb = encoder.encode(CharBuffer.wrap(next)); } else { bb = encoder.encode(CharBuffer.wrap(next + '\0')); } bb.rewind(); return bb; } /** * Write String in UTF-LEBOM format * * When this is called multiple times, all but the last value has a trailing null * * Remember we are using this charset because the charset that writes BOM does it the wrong way for us * so we use this none and then manually add the BOM ourselves. * * @param next * @param i * @param noOfValues * @return * @throws CharacterCodingException */ private ByteBuffer writeStringUTF16LEBOM( String next, int i, int noOfValues) throws CharacterCodingException { CharsetEncoder encoder = Charset.forName(TextEncoding.CHARSET_UTF_16_ENCODING_FORMAT).newEncoder(); ByteBuffer bb = null; //Note remember LE BOM is ff fe but this is handled by encoder Unicode char is fe ff if(( i + 1)==noOfValues) { bb = encoder.encode(CharBuffer.wrap('\ufeff' + next )); } else { bb = encoder.encode(CharBuffer.wrap('\ufeff' + next + '\0')); } bb.rewind(); return bb; } /** * Removing trailing null from end of String, this should be there but some applications continue to write * this unnecessary null char. */ private void stripTrailingNull() { if (TagOptionSingleton.getInstance().isRemoveTrailingTerminatorOnWrite()) { String stringValue = (String) value; if (stringValue.length() > 0) { if (stringValue.charAt(stringValue.length() - 1) == '\0') { stringValue = (stringValue).substring(0, stringValue.length() - 1); value = stringValue; } } } } /** * Because nulls are stripped we need to check if not removing trailing nulls whether the original * value ended with a null and if so add it back in. * @param values * @param stringValue */ private void checkTrailingNull( List values, String stringValue) { if(!TagOptionSingleton.getInstance().isRemoveTrailingTerminatorOnWrite()) { if (stringValue.charAt(stringValue.length() - 1) == '\0') { String lastVal = values.get(values.size() - 1); String newLastVal = lastVal + '\0'; values.set(values.size() - 1,newLastVal); } } } /** * Write String into byte array *

* It will remove a trailing null terminator if exists if the option * RemoveTrailingTerminatorOnWrite has been set. * * @return the data as a byte array in format to write to file */ public byte[] writeByteArray() { byte[] data; //Try and write to buffer using the CharSet defined by getTextEncodingCharSet() try { stripTrailingNull(); //Special Handling because there is no UTF16 BOM LE charset String stringValue = (String)value; String charSetName = getTextEncodingCharSet(); if (charSetName.equals(TextEncoding.CHARSET_UTF_16)) { charSetName = TextEncoding.CHARSET_UTF_16_ENCODING_FORMAT; } //Ensure large enough for any encoding ByteBuffer outputBuffer = ByteBuffer.allocate((stringValue.length() + 3)* 3); //Ensure each string (if multiple values) is written with BOM by writing separately List values = splitByNullSeperator(stringValue); checkTrailingNull(values, stringValue); //For each value for(int i=0;i * The text encoding is defined by the frame body that the text field belongs to. * * @return the text encoding charset */ protected String getTextEncodingCharSet() { byte textEncoding = this.getBody().getTextEncoding(); String charSetName = TextEncoding.getInstanceOf().getValueForId(textEncoding); logger.finest("text encoding:" + textEncoding + " charset:" + charSetName); return charSetName; } /** * Split the values separated by null character * * @param value the raw value * @return list of values, guaranteed to be at least one value */ public static List splitByNullSeperator(String value) { String[] valuesarray = value.split("\\u0000"); List values = Arrays.asList(valuesarray); //Read only list so if empty have to create new list if (values.size() == 0) { values = new ArrayList(1); values.add(""); } return values; } /** * Add an additional String to the current String value * * @param value */ public void addValue(String value) { setValue(this.value + "\u0000" + value); } /** * How many values are held, each value is separated by a null terminator * * @return number of values held, usually this will be one. */ public int getNumberOfValues() { return splitByNullSeperator(((String) value)).size(); } /** * Get the nth value * * @param index * @return the nth value * @throws IndexOutOfBoundsException if value does not exist */ public String getValueAtIndex(int index) { //Split String into separate components List values = splitByNullSeperator((String) value); return (String) values.get(index); } /** * * @return list of all values */ public List getValues() { return splitByNullSeperator((String) value); } /** * Get value(s) whilst removing any trailing nulls * * @return */ public String getValueWithoutTrailingNull() { List values = splitByNullSeperator((String) value); StringBuffer sb = new StringBuffer(); for(int i=0;i * This type of String will usually only be used when it is the last field within a frame, when reading the remainder of the byte array will * be read, when writing the frame will accommodate the required size for the String. The String will be encoded * using the default encoding regardless of what encoding may be specified in the framebody */ public class StringSizeTerminated extends TextEncodedStringSizeTerminated { /** * Creates a new ObjectStringSizeTerminated datatype. * * @param identifier identifies the frame type * @param frameBody */ public StringSizeTerminated(String identifier, AbstractTagFrameBody frameBody) { super(identifier, frameBody); } public StringSizeTerminated(StringSizeTerminated object) { super(object); } public boolean equals(Object obj) { return obj instanceof StringSizeTerminated && super.equals(obj); } protected String getTextEncodingCharSet() { return TextEncoding.CHARSET_ISO_8859_1; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/datatype/PartOfSet.java0000644000175000017500000002462111470746136026624 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.datatype; import org.jaudiotagger.tag.InvalidDataTypeException; import org.jaudiotagger.tag.TagOptionSingleton; import org.jaudiotagger.tag.id3.AbstractTagFrameBody; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; import org.jaudiotagger.utils.EqualsUtil; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.charset.*; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * Represents the form 01/10 whereby the second part is optional. This is used by frame such as TRCK and TPOS * * Some applications like to prepend the count with a zero to aid sorting, (i.e 02 comes before 10) */ @SuppressWarnings({"EmptyCatchBlock"}) public class PartOfSet extends AbstractString { /** * Creates a new empty PartOfSet datatype. * * @param identifier identifies the frame type * @param frameBody */ public PartOfSet(String identifier, AbstractTagFrameBody frameBody) { super(identifier, frameBody); } /** * Copy constructor * * @param object */ public PartOfSet(PartOfSet object) { super(object); } public boolean equals(Object obj) { if(obj==this) { return true; } if (!(obj instanceof PartOfSet)) { return false; } PartOfSet that = (PartOfSet) obj; return EqualsUtil.areEqual(value, that.value); } /** * Read a 'n' bytes from buffer into a String where n is the framesize - offset * so thefore cannot use this if there are other objects after it because it has no * delimiter. *

* Must take into account the text encoding defined in the Encoding Object * ID3 Text Frames often allow multiple strings seperated by the null char * appropriate for the encoding. * * @param arr this is the buffer for the frame * @param offset this is where to start reading in the buffer for this field * @throws NullPointerException * @throws IndexOutOfBoundsException */ public void readByteArray(byte[] arr, int offset) throws InvalidDataTypeException { logger.finest("Reading from array from offset:" + offset); //Get the Specified Decoder String charSetName = getTextEncodingCharSet(); CharsetDecoder decoder = Charset.forName(charSetName).newDecoder(); //Decode sliced inBuffer ByteBuffer inBuffer = ByteBuffer.wrap(arr, offset, arr.length - offset).slice(); CharBuffer outBuffer = CharBuffer.allocate(arr.length - offset); decoder.reset(); CoderResult coderResult = decoder.decode(inBuffer, outBuffer, true); if (coderResult.isError()) { logger.warning("Decoding error:" + coderResult.toString()); } decoder.flush(outBuffer); outBuffer.flip(); //Store value String stringValue = outBuffer.toString(); value = new PartOfSetValue(stringValue); //SetSize, important this is correct for finding the next datatype setSize(arr.length - offset); logger.info("Read SizeTerminatedString:" + value + " size:" + size); } /** * Write String into byte array *

* It will remove a trailing null terminator if exists if the option * RemoveTrailingTerminatorOnWrite has been set. * * @return the data as a byte array in format to write to file */ public byte[] writeByteArray() { String value = getValue().toString(); byte[] data; //Try and write to buffer using the CharSet defined by getTextEncodingCharSet() try { if (TagOptionSingleton.getInstance().isRemoveTrailingTerminatorOnWrite()) { if (value.length() > 0) { if (value.charAt(value.length() - 1) == '\0') { value = value.substring(0, value.length() - 1); } } } String charSetName = getTextEncodingCharSet(); if (charSetName.equals(TextEncoding.CHARSET_UTF_16)) { charSetName = TextEncoding.CHARSET_UTF_16_ENCODING_FORMAT; CharsetEncoder encoder = Charset.forName(charSetName).newEncoder(); //Note remember LE BOM is ff fe but this is handled by encoder Unicode char is fe ff ByteBuffer bb = encoder.encode(CharBuffer.wrap('\ufeff' + value)); data = new byte[bb.limit()]; bb.get(data, 0, bb.limit()); } else { CharsetEncoder encoder = Charset.forName(charSetName).newEncoder(); ByteBuffer bb = encoder.encode(CharBuffer.wrap( value)); data = new byte[bb.limit()]; bb.get(data, 0, bb.limit()); } } //Should never happen so if does throw a RuntimeException catch (CharacterCodingException ce) { logger.severe(ce.getMessage()); throw new RuntimeException(ce); } setSize(data.length); return data; } /** * Get the text encoding being used. *

* The text encoding is defined by the frame body that the text field belongs to. * * @return the text encoding charset */ protected String getTextEncodingCharSet() { byte textEncoding = this.getBody().getTextEncoding(); String charSetName = TextEncoding.getInstanceOf().getValueForId(textEncoding); logger.finest("text encoding:" + textEncoding + " charset:" + charSetName); return charSetName; } /** * Holds data * */ public static class PartOfSetValue { private static final Pattern trackNoPatternWithTotalCount; private static final Pattern trackNoPattern; static { //Match track/total pattern allowing for extraneous nulls ectera at the end trackNoPatternWithTotalCount = Pattern.compile("([0-9]+)/([0-9]+)(.*)", Pattern.CASE_INSENSITIVE); trackNoPattern = Pattern.compile("([0-9]+)(.*)", Pattern.CASE_INSENSITIVE); } private static final String SEPARATOR = "/"; private Integer count; private Integer total; private String extra; //Any extraneous info such as null chars public PartOfSetValue() { } /** When constructing from data * * @param value */ public PartOfSetValue(String value) { Matcher m = trackNoPatternWithTotalCount.matcher(value); if (m.matches()) { this.count = Integer.parseInt(m.group(1)); this.total = Integer.parseInt(m.group(2)); this.extra = m.group(3); return; } m = trackNoPattern.matcher(value); if (m.matches()) { this.count = Integer.parseInt(m.group(1)); this.extra = m.group(2); } } /** * Newly created * * @param count * @param total */ public PartOfSetValue(Integer count,Integer total) { this.count = count; this.total = total; } public Integer getCount() { return count; } public Integer getTotal() { return total; } public void setCount(Integer count) { this.count=count; } public void setTotal(Integer total) { this.total=total; } public void setCount(String count) { try { this.count=Integer.parseInt(count); } catch(NumberFormatException nfe) { } } public void setTotal(String total) { try { this.total=Integer.parseInt(total); } catch(NumberFormatException nfe) { } } public String toString() { //Don't Pad StringBuffer sb = new StringBuffer(); if(!TagOptionSingleton.getInstance().isPadNumbers()) { if(count!=null) { sb.append(count.intValue()); } else if(total!=null) { sb.append('0'); } if(total!=null) { sb.append(SEPARATOR).append(total); } if(extra!=null) { sb.append(extra); } } else { if(count!=null) { if(count>0 && count<10) { sb.append("0").append(count); } else { sb.append(count.intValue()); } } else if(total!=null) { sb.append('0'); } if(total!=null) { if(total>0 && total<10) { sb.append(SEPARATOR + "0").append(total); } else { sb.append(SEPARATOR).append(total); } } if(extra!=null) { sb.append(extra); } } return sb.toString(); } public boolean equals(Object obj) { if(obj==this) { return true; } if (!(obj instanceof PartOfSetValue)) { return false; } PartOfSetValue that = (PartOfSetValue) obj; return EqualsUtil.areEqual(getCount(), that.getCount()) && EqualsUtil.areEqual(getTotal(), that.getTotal()); } } public PartOfSetValue getValue() { return (PartOfSetValue)value; } public String toString() { return value.toString(); } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/datatype/AbstractString.java0000644000175000017500000000673411470746136027714 0ustar drazzibdrazzib/** * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: AbstractString.java 929 2010-11-17 12:36:46Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Description: * */ package org.jaudiotagger.tag.datatype; import org.jaudiotagger.tag.id3.AbstractTagFrameBody; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; import java.nio.charset.Charset; import java.nio.charset.CharsetEncoder; /** * A partial implementation for String based ID3 fields */ public abstract class AbstractString extends AbstractDataType { /** * Creates a new datatype * * @param identifier * @param frameBody */ protected AbstractString(String identifier, AbstractTagFrameBody frameBody) { super(identifier, frameBody); } /** * Creates a new datatype, with value * * @param identifier * @param frameBody * @param value */ public AbstractString(String identifier, AbstractTagFrameBody frameBody, String value) { super(identifier, frameBody, value); } /** * Copy constructor * * @param object */ protected AbstractString(AbstractString object) { super(object); } /** * Return the size in bytes of this datatype as it was/is held in file this * will be effected by the encoding type. * * @return the size */ public int getSize() { return size; } /** * Sets the size in bytes of this data type. * This is set after writing the data to allow us to recalculate the size for * frame header. * @param size */ protected void setSize(int size) { this.size = size; } /** * Return String representation of data type * * @return a string representation of the value */ public String toString() { return (String) value; } /** * Check the value can be encoded with the specified encoding * @return */ public boolean canBeEncoded() { //Try and write to buffer using the CharSet defined by the textEncoding field (note if using UTF16 we dont //need to worry about LE,BE at this point it makes no difference) byte textEncoding = this.getBody().getTextEncoding(); String charSetName = TextEncoding.getInstanceOf().getValueForId(textEncoding); CharsetEncoder encoder = Charset.forName(charSetName).newEncoder(); if (encoder.canEncode((String) value)) { return true; } else { logger.finest("Failed Trying to decode" + value + "with" + encoder.toString()); return false; } } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/datatype/BooleanString.java0000644000175000017500000000503211277026507027514 0ustar drazzibdrazzib/** * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: BooleanString.java 836 2009-11-12 15:44:07Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Description: * */ package org.jaudiotagger.tag.datatype; import org.jaudiotagger.tag.InvalidDataTypeException; import org.jaudiotagger.tag.id3.AbstractTagFrameBody; public class BooleanString extends AbstractDataType { /** * Creates a new ObjectBooleanString datatype. * * @param identifier * @param frameBody */ public BooleanString(String identifier, AbstractTagFrameBody frameBody) { super(identifier, frameBody); } public BooleanString(BooleanString object) { super(object); } /** * @return */ public int getSize() { return 1; } public boolean equals(Object obj) { return obj instanceof BooleanString && super.equals(obj); } /** * @param offset * @throws NullPointerException * @throws IndexOutOfBoundsException */ public void readByteArray(byte[] arr, int offset) throws InvalidDataTypeException { byte b = arr[offset]; value = b != '0'; } /** * @return */ public String toString() { return "" + value; } /** * @return */ public byte[] writeByteArray() { byte[] booleanValue = new byte[1]; if (value == null) { booleanValue[0] = '0'; } else { if ((Boolean) value) { booleanValue[0] = '0'; } else { booleanValue[0] = '1'; } } return booleanValue; } } ././@LongLink0000000000000000000000000000015000000000000011561 Lustar rootrootlibjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/datatype/PairedTextEncodedStringNullTerminated.javalibjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/datatype/PairedTextEncodedStringNullTerminated.j0000644000175000017500000001730611470746136033661 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.datatype; import org.jaudiotagger.tag.InvalidDataTypeException; import org.jaudiotagger.tag.id3.AbstractTagFrameBody; import org.jaudiotagger.utils.EqualsUtil; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.*; import java.util.logging.Level; /** * Represents a data type that allow multiple Strings but they should be paired as key values, i.e should be 2,4,6.. * But keys are not unique so we don't store as a map, so could have same key pointing to two different values * such as two ENGINEER keys *

*/ public class PairedTextEncodedStringNullTerminated extends AbstractDataType { public PairedTextEncodedStringNullTerminated(String identifier, AbstractTagFrameBody frameBody) { super(identifier, frameBody); value = new PairedTextEncodedStringNullTerminated.ValuePairs(); } public PairedTextEncodedStringNullTerminated(TextEncodedStringSizeTerminated object) { super(object); value = new PairedTextEncodedStringNullTerminated.ValuePairs(); } public PairedTextEncodedStringNullTerminated(PairedTextEncodedStringNullTerminated object) { super(object); } public boolean equals(Object obj) { if (obj == this) { return true; } if (!(obj instanceof PairedTextEncodedStringNullTerminated)) { return false; } PairedTextEncodedStringNullTerminated that = (PairedTextEncodedStringNullTerminated) obj; return EqualsUtil.areEqual(value, that.value); } /** * Returns the size in bytes of this dataType when written to file * * @return size of this dataType */ public int getSize() { return size; } /** * Check the value can be encoded with the specified encoding * * @return */ public boolean canBeEncoded() { for (Pair entry : ((ValuePairs) value).mapping) { TextEncodedStringNullTerminated next = new TextEncodedStringNullTerminated(identifier, frameBody, entry.getValue()); if (!next.canBeEncoded()) { return false; } } return true; } /** * Read Null Terminated Strings from the array starting at offset, continue until unable to find any null terminated * Strings or until reached the end of the array. The offset should be set to byte after the last null terminated * String found. * * @param arr to read the Strings from * @param offset in the array to start reading from * @throws InvalidDataTypeException if unable to find any null terminated Strings */ public void readByteArray(byte[] arr, int offset) throws InvalidDataTypeException { logger.finer("Reading PairTextEncodedStringNullTerminated from array from offset:" + offset); //Continue until unable to read a null terminated String while (true) { try { //Read Key TextEncodedStringNullTerminated key = new TextEncodedStringNullTerminated(identifier, frameBody); key.readByteArray(arr, offset); size += key.getSize(); offset += key.getSize(); if (key.getSize() == 0) { break; } //Read Value TextEncodedStringNullTerminated result = new TextEncodedStringNullTerminated(identifier, frameBody); result.readByteArray(arr, offset); size += result.getSize(); offset += result.getSize(); if (result.getSize() == 0) { break; } //Add to value ((ValuePairs) value).add((String) key.getValue(),(String) result.getValue()); } catch (InvalidDataTypeException idte) { break; } if (size == 0) { logger.warning("No null terminated Strings found"); throw new InvalidDataTypeException("No null terminated Strings found"); } } logger.finer("Read PairTextEncodedStringNullTerminated:" + value + " size:" + size); } /** * For every String write to byteBuffer * * @return byteBuffer that should be written to file to persist this dataType. */ public byte[] writeByteArray() { logger.finer("Writing PairTextEncodedStringNullTerminated"); int localSize = 0; ByteArrayOutputStream buffer = new ByteArrayOutputStream(); try { for (Pair pair : ((ValuePairs) value).mapping) { { TextEncodedStringNullTerminated next = new TextEncodedStringNullTerminated(identifier, frameBody, pair.getKey()); buffer.write(next.writeByteArray()); localSize += next.getSize(); } { TextEncodedStringNullTerminated next = new TextEncodedStringNullTerminated(identifier, frameBody, pair.getValue()); buffer.write(next.writeByteArray()); localSize += next.getSize(); } } } catch (IOException ioe) { //This should never happen because the write is internal with the JVM it is not to a file logger.log(Level.SEVERE, "IOException in MultipleTextEncodedStringNullTerminated when writing byte array", ioe); throw new RuntimeException(ioe); } //Update size member variable size = localSize; logger.finer("Written PairTextEncodedStringNullTerminated"); return buffer.toByteArray(); } /** * This holds the values held by this PairedTextEncodedDataType, always held as pairs of values */ public static class ValuePairs { private List mapping = new ArrayList(); public ValuePairs() { super(); } /** * Add String Data type to the value list * * @param value to add to the list */ public void add(String key, String value) { mapping.add(new Pair(key,value)); } /** * Return the list of values * * @return the list of values */ public List getMapping() { return mapping; } /** * @return no of values */ public int getNumberOfValues() { return mapping.size(); } /** * Return the list of values as a single string separated by a colon,comma * * @return a string representation of the value */ public String toString() { StringBuffer sb = new StringBuffer(); for(Pair next:mapping) { sb.append(next.getKey()+':'+next.getValue()+','); } return sb.toString(); } /** * @return no of values */ public int getNumberOfPairs() { return mapping.size(); } public boolean equals(Object obj) { if (obj == this) { return true; } if (!(obj instanceof ValuePairs)) { return false; } ValuePairs that = (ValuePairs) obj; return EqualsUtil.areEqual(getNumberOfValues(), that.getNumberOfValues()); } } public ValuePairs getValue() { return (ValuePairs) value; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/datatype/StringFixedLength.java0000644000175000017500000002051211277026507030336 0ustar drazzibdrazzib/** * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: StringFixedLength.java 836 2009-11-12 15:44:07Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Description: * */ package org.jaudiotagger.tag.datatype; import org.jaudiotagger.tag.InvalidDataTypeException; import org.jaudiotagger.tag.id3.AbstractTagFrameBody; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.charset.CharacterCodingException; import java.nio.charset.Charset; import java.nio.charset.CharsetDecoder; import java.nio.charset.CharsetEncoder; /** * Represents a fixed length String, whereby the length of the String is known. The String * will be encoded based upon the text encoding of the frame that it belongs to. */ public class StringFixedLength extends AbstractString { /** * Creates a new ObjectStringFixedsize datatype. * * @param identifier * @param frameBody * @param size * @throws IllegalArgumentException */ public StringFixedLength(String identifier, AbstractTagFrameBody frameBody, int size) { super(identifier, frameBody); if (size < 0) { throw new IllegalArgumentException("size is less than zero: " + size); } setSize(size); } public StringFixedLength(StringFixedLength copyObject) { super(copyObject); this.size = copyObject.size; } /** * @param obj * @return if obj is equivalent to this */ public boolean equals(Object obj) { if (!(obj instanceof StringFixedLength)) { return false; } StringFixedLength object = (StringFixedLength) obj; return this.size == object.size && super.equals(obj); } /** * Read a string from buffer of fixed size(size has already been set in constructor) * * @param arr this is the buffer for the frame * @param offset this is where to start reading in the buffer for this field */ public void readByteArray(byte[] arr, int offset) throws InvalidDataTypeException { logger.info("Reading from array from offset:" + offset); try { String charSetName = getTextEncodingCharSet(); CharsetDecoder decoder = Charset.forName(charSetName).newDecoder(); //Decode buffer if runs into problems should through exception which we //catch and then set value to empty string. logger.finest("Array length is:" + arr.length + "offset is:" + offset + "Size is:" + size); if (arr.length - offset < size) { throw new InvalidDataTypeException("byte array is to small to retrieve string of declared length:" + size); } String str = decoder.decode(ByteBuffer.wrap(arr, offset, size)).toString(); if (str == null) { throw new NullPointerException("String is null"); } value = str; } catch (CharacterCodingException ce) { logger.severe(ce.getMessage()); value = ""; } logger.info("Read StringFixedLength:" + value); } /** * Write String into byte array *

* The string will be adjusted to ensure the correct number of bytes are written, If the current value is null * or to short the written value will have the 'space' character appended to ensure this. We write this instead of * the null character because the null character is likely to confuse the parser into misreading the next field. * * @return the byte array to be written to the file */ public byte[] writeByteArray() { ByteBuffer dataBuffer; byte[] data; //Create with a series of empty of spaces to try and ensure integrity of field if (value == null) { logger.warning("Value of StringFixedlength Field is null using default value instead"); data = new byte[size]; for (int i = 0; i < size; i++) { data[i] = ' '; } return data; } try { String charSetName = getTextEncodingCharSet(); if (charSetName.equals(TextEncoding.CHARSET_UTF_16)) { charSetName = TextEncoding.CHARSET_UTF_16_ENCODING_FORMAT; CharsetEncoder encoder = Charset.forName(charSetName).newEncoder(); //Note remember LE BOM is ff fe but tis is handled by encoder Unicode char is fe ff dataBuffer = encoder.encode(CharBuffer.wrap('\ufeff' + (String) value)); } else { CharsetEncoder encoder = Charset.forName(charSetName).newEncoder(); dataBuffer = encoder.encode(CharBuffer.wrap((String) value)); } } catch (CharacterCodingException ce) { logger.warning("There was a problem writing the following StringFixedlength Field:" + value + ":" + ce.getMessage() + "using default value instead"); data = new byte[size]; for (int i = 0; i < size; i++) { data[i] = ' '; } return data; } // We must return the defined size. // To check now because size is in bytes not chars if (dataBuffer != null) { //Everything ok if (dataBuffer.limit() == size) { data = new byte[dataBuffer.limit()]; dataBuffer.get(data, 0, dataBuffer.limit()); return data; } //There is more data available than allowed for this field strip else if (dataBuffer.limit() > size) { logger.warning("There was a problem writing the following StringFixedlength Field:" + value + " when converted to bytes has length of:" + dataBuffer.limit() + " but field was defined with length of:" + size + " too long so stripping extra length"); data = new byte[size]; dataBuffer.get(data, 0, size); return data; } //There is not enough data else { logger.warning("There was a problem writing the following StringFixedlength Field:" + value + " when converted to bytes has length of:" + dataBuffer.limit() + " but field was defined with length of:" + size + " too short so padding with spaces to make up extra length"); data = new byte[size]; dataBuffer.get(data, 0, dataBuffer.limit()); for (int i = dataBuffer.limit(); i < size; i++) { data[i] = ' '; } return data; } } else { logger.warning("There was a serious problem writing the following StringFixedlength Field:" + value + ":" + "using default value instead"); data = new byte[size]; for (int i = 0; i < size; i++) { data[i] = ' '; } return data; } } /** * @return the encoding of the frame body this datatype belongs to */ protected String getTextEncodingCharSet() { byte textEncoding = this.getBody().getTextEncoding(); String charSetName = TextEncoding.getInstanceOf().getValueForId(textEncoding); logger.finest("text encoding:" + textEncoding + " charset:" + charSetName); return charSetName; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/datatype/Artwork.java0000644000175000017500000000701311470746136026402 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.datatype; import org.jaudiotagger.audio.flac.metadatablock.MetadataBlockDataPicture; import org.jaudiotagger.tag.id3.valuepair.ImageFormats; import org.jaudiotagger.tag.reference.PictureTypes; import javax.imageio.ImageIO; import javax.imageio.stream.ImageInputStream; import java.awt.image.BufferedImage; import java.io.IOException; import java.io.ByteArrayInputStream; import java.io.RandomAccessFile; import java.io.File; /** * Represents artwork in a format independent way */ public class Artwork { private byte[] binaryData; private String mimeType=""; private String description=""; private boolean isLinked=false; private String imageUrl=""; private int pictureType=-1; public byte[] getBinaryData() { return binaryData; } public void setBinaryData(byte[] binaryData) { this.binaryData = binaryData; } public String getMimeType() { return mimeType; } public void setMimeType(String mimeType) { this.mimeType = mimeType; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public BufferedImage getImage() throws IOException { ByteArrayInputStream bais = new ByteArrayInputStream(getBinaryData()); ImageInputStream iis = ImageIO.createImageInputStream(bais); BufferedImage bi = ImageIO.read(iis); return bi; } public boolean isLinked() { return isLinked; } public void setLinked(boolean linked) { isLinked = linked; } public String getImageUrl() { return imageUrl; } public void setImageUrl(String imageUrl) { this.imageUrl = imageUrl; } public int getPictureType() { return pictureType; } public void setPictureType(int pictureType) { this.pictureType = pictureType; } public void setFromFile(File file) throws IOException { RandomAccessFile imageFile = new RandomAccessFile(file, "r"); byte[] imagedata = new byte[(int) imageFile.length()]; imageFile.read(imagedata); imageFile.close(); setBinaryData(imagedata); setMimeType(ImageFormats.getMimeTypeForBinarySignature(imagedata)); setDescription(""); setPictureType(PictureTypes.DEFAULT_ID); } public static Artwork createArtworkFromFile(File file) throws IOException { Artwork artwork = new Artwork(); artwork.setFromFile(file); return artwork; } /** * Populate Artwork from MetadataBlockDataPicture as used by Flac and VorbisComment * * @param coverArt */ public void setFromMetadataBlockDataPicture(MetadataBlockDataPicture coverArt) { setMimeType(coverArt.getMimeType()); setDescription(coverArt.getDescription()); setPictureType(coverArt.getPictureType()); if(coverArt.isImageUrl()) { setLinked(coverArt.isImageUrl()); setImageUrl(coverArt.getImageUrl()); } else { setBinaryData(coverArt.getImageData()); } } public static Artwork createArtworkFromMetadataBlockDataPicture(MetadataBlockDataPicture coverArt) { Artwork artwork = new Artwork(); artwork.setFromMetadataBlockDataPicture(coverArt); return artwork; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/datatype/DataTypes.java0000644000175000017500000001506010736454526026653 0ustar drazzibdrazzib/** * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: DataTypes.java 520 2008-01-01 15:16:38Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Description: * Object Types,all types used by the various frame bodies and associated objects are defined here * this works better than putting them with their associated bodies because bodies dont all fall * the neccessary hierachy, and values are also required in some Objects (which were previously * defined seperately). * * Warning:Values should not be seperated by space as this will break XML display of tag. * */ package org.jaudiotagger.tag.datatype; public class DataTypes { /** * Represents a text encoding, now only IDv2Frames not Lyrics3 tags use * text encoding objects but both use Object Strings and these check * for a text encoding. The method below returns a default if one not set. */ public static final String OBJ_TEXT_ENCODING = "TextEncoding"; //Reference to datatype holding the main textual data public static final String OBJ_TEXT = "Text"; //Reference to datatype holding non textual textual data public static final String OBJ_DATA = "Data"; //Reference to datatype holding a description of the textual data public static final String OBJ_DESCRIPTION = "Description"; //Reference to datatype holding reference to owner of frame. public static final String OBJ_OWNER = "Owner"; //Reference to datatype holding a number public static final String OBJ_NUMBER = "Number"; //Reference to timestamps public static final String OBJ_DATETIME = "DateTime"; /** * */ public static final String OBJ_GENRE = "Genre"; /** * */ public static final String OBJ_ID3V2_FRAME_DESCRIPTION = "ID3v2FrameDescription"; /** * */ public static final String OBJ_TYPE_OF_EVENT = "TypeOfEvent"; /** * */ public static final String OBJ_TIME_STAMP_FORMAT = "TimeStampFormat"; /** * */ public static final String OBJ_TYPE_OF_CHANNEL = "TypeOfChannel"; /** * */ public static final String OBJ_RECIEVED_AS = "RecievedAs"; //APIC Frame public static final String OBJ_PICTURE_TYPE = "PictureType"; public static final String OBJ_PICTURE_DATA = "PictureData"; public static final String OBJ_MIME_TYPE = "MIMEType"; public static final String OBJ_IMAGE_FORMAT = "ImageType"; //AENC Frame public static final String OBJ_PREVIEW_START = "PreviewStart"; public static final String OBJ_PREVIEW_LENGTH = "PreviewLength"; public static final String OBJ_ENCRYPTION_INFO = "EncryptionInfo"; //COMR Frame public static final String OBJ_PRICE_STRING = "PriceString"; public static final String OBJ_VALID_UNTIL = "ValidUntil"; public static final String OBJ_CONTACT_URL = "ContactURL"; public static final String OBJ_SELLER_NAME = "SellerName"; public static final String OBJ_SELLER_LOGO = "SellerLogo"; //CRM Frame public static final String OBJ_ENCRYPTED_DATABLOCK = "EncryptedDataBlock"; //ENCR Frame public static final String OBJ_METHOD_SYMBOL = "MethodSymbol"; //EQU2 Frame public static final String OBJ_FREQUENCY = "Frequency"; public static final String OBJ_VOLUME_ADJUSTMENT = "Volume Adjustment"; public static final String OBJ_INTERPOLATION_METHOD = "InterpolationMethod"; public static final String OBJ_FILENAME = "Filename"; //GRID Frame public static final String OBJ_GROUP_SYMBOL = "GroupSymbol"; public static final String OBJ_GROUP_DATA = "GroupData"; //LINK Frame public static final String OBJ_URL = "URL"; public static final String OBJ_ID = "ID"; //OWNE Frame public static final String OBJ_PRICE_PAID = "PricePaid"; public static final String OBJ_PURCHASE_DATE = "PurchaseDate"; //POPM Frame public static final String OBJ_EMAIL = "Email"; public static final String OBJ_RATING = "Rating"; public static final String OBJ_COUNTER = "Counter"; //POSS Frame public static final String OBJ_POSITION = "Position"; //RBUF Frame public static final String OBJ_BUFFER_SIZE = "BufferSize"; public static final String OBJ_EMBED_FLAG = "EmbedFlag"; public static final String OBJ_OFFSET = "Offset"; //RVRB Frame public static final String OBJ_REVERB_LEFT = "ReverbLeft"; public static final String OBJ_REVERB_RIGHT = "ReverbRight"; public static final String OBJ_REVERB_BOUNCE_LEFT = "ReverbBounceLeft"; public static final String OBJ_REVERB_BOUNCE_RIGHT = "ReverbBounceRight"; public static final String OBJ_REVERB_FEEDBACK_LEFT_TO_LEFT = "ReverbFeedbackLeftToLeft"; public static final String OBJ_REVERB_FEEDBACK_LEFT_TO_RIGHT = "ReverbFeedbackLeftToRight"; public static final String OBJ_REVERB_FEEDBACK_RIGHT_TO_RIGHT = "ReverbFeedbackRightToRight"; public static final String OBJ_REVERB_FEEDBACK_RIGHT_TO_LEFT = "ReverbFeedbackRightToLeft"; public static final String OBJ_PREMIX_LEFT_TO_RIGHT = "PremixLeftToRight"; public static final String OBJ_PREMIX_RIGHT_TO_LEFT = "PremixRightToLeft"; //SIGN Frame public static final String OBJ_SIGNATURE = "Signature"; //SYLT Frame public static final String OBJ_CONTENT_TYPE = "contentType"; //ULST Frame public static final String OBJ_LANGUAGE = "Language"; public static final String OBJ_LYRICS = "Lyrics"; public static final String OBJ_URLLINK = "URLLink"; //CHAP Frame public static final String OBJ_ELEMENT_ID = "ElementID"; public static final String OBJ_START_TIME = "StartTime"; public static final String OBJ_END_TIME = "EndTime"; public static final String OBJ_START_OFFSET = "StartOffset"; public static final String OBJ_END_OFFSET = "EndOffset"; //CTOC Frame } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/datatype/ByteArraySizeTerminated.java0000644000175000017500000000651111277026507031523 0ustar drazzibdrazzib/** * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: ByteArraySizeTerminated.java 836 2009-11-12 15:44:07Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Description: * */ package org.jaudiotagger.tag.datatype; import org.jaudiotagger.tag.InvalidDataTypeException; import org.jaudiotagger.tag.id3.AbstractTagFrameBody; /** * Represents a stream of bytes, continuing until the end of the buffer. Usually used for binary data or where * we havent yet mapped the data to a better fitting type. */ public class ByteArraySizeTerminated extends AbstractDataType { public ByteArraySizeTerminated(String identifier, AbstractTagFrameBody frameBody) { super(identifier, frameBody); } public ByteArraySizeTerminated(ByteArraySizeTerminated object) { super(object); } /** * Return the size in byte of this datatype * * @return the size in bytes */ public int getSize() { int len = 0; if (value != null) { len = ((byte[]) value).length; } return len; } public boolean equals(Object obj) { return obj instanceof ByteArraySizeTerminated && super.equals(obj); } /** * @param arr * @param offset * @throws NullPointerException * @throws IndexOutOfBoundsException */ public void readByteArray(byte[] arr, int offset) throws InvalidDataTypeException { if (arr == null) { throw new NullPointerException("Byte array is null"); } if (offset < 0) { throw new IndexOutOfBoundsException("Offset to byte array is out of bounds: offset = " + offset + ", array.length = " + arr.length); } //Empty Byte Array if (offset >= arr.length) { value = null; return; } int len = arr.length - offset; value = new byte[len]; System.arraycopy(arr, offset, value, 0, len); } /** * Because this is usually binary data and could be very long we just return * the number of bytes held * * @return the number of bytes */ public String toString() { return getSize() + " bytes"; } /** * Write contents to a byte array * * @return a byte array that that contians the data that should be perisisted to file */ public byte[] writeByteArray() { logger.info("Writing byte array" + this.getIdentifier()); return (byte[]) value; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/datatype/Pair.java0000644000175000017500000000103611470746136025643 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.datatype; /** * A pair */ public class Pair { private String key; private String value; public Pair(String key,String value) { setKey(key); setValue(value); } public String getKey() { return key; } public void setKey(String key) { this.key = key; } public String getValue() { return value; } public void setValue(String value) { this.value = value; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/datatype/StringDate.java0000644000175000017500000000412311277026507027012 0ustar drazzibdrazzib/** * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: StringDate.java 836 2009-11-12 15:44:07Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Description: * */ package org.jaudiotagger.tag.datatype; import org.jaudiotagger.tag.id3.AbstractTagFrameBody; import org.jaudiotagger.tag.id3.ID3Tags; /** * Represents a timestamp field */ public class StringDate extends StringFixedLength { /** * Creates a new ObjectStringDate datatype. * * @param identifier * @param frameBody */ public StringDate(String identifier, AbstractTagFrameBody frameBody) { super(identifier, frameBody, 8); } public StringDate(StringDate object) { super(object); } /** * @param value */ public void setValue(Object value) { if (value != null) { this.value = ID3Tags.stripChar(value.toString(), '-'); } } /** * @return */ public Object getValue() { if (value != null) { return ID3Tags.stripChar(value.toString(), '-'); } else { return null; } } public boolean equals(Object obj) { return obj instanceof StringDate && super.equals(obj); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/datatype/NumberVariableLength.java0000644000175000017500000001564511277026507031021 0ustar drazzibdrazzib/** * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: NumberVariableLength.java 836 2009-11-12 15:44:07Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Description: * */ package org.jaudiotagger.tag.datatype; import org.jaudiotagger.tag.InvalidDataTypeException; import org.jaudiotagger.tag.id3.AbstractTagFrameBody; import org.jaudiotagger.tag.id3.ID3Tags; /** * Represents a number which may span a number of bytes when written to file depending what size is to be represented. *

* The bitorder in ID3v2 is most significant bit first (MSB). The byteorder in multibyte numbers is most significant * byte first (e.g. $12345678 would be encoded $12 34 56 78), also known as big endian and network byte order. *

* In ID3Specification would be denoted as $xx xx xx xx (xx ...) , this denotes at least four bytes but may be more. * Sometimes may be completely optional (zero bytes) */ public class NumberVariableLength extends AbstractDataType { private static final int MINIMUM_NO_OF_DIGITS = 1; private static final int MAXIMUM_NO_OF_DIGITS = 8; int minLength = MINIMUM_NO_OF_DIGITS; /** * Creates a new ObjectNumberVariableLength datatype, set minimum length to zero * if this datatype is optional. * * @param identifier * @param frameBody * @param minimumSize */ public NumberVariableLength(String identifier, AbstractTagFrameBody frameBody, int minimumSize) { super(identifier, frameBody); //Set minimum length, which can be zero if optional this.minLength = minimumSize; } public NumberVariableLength(NumberVariableLength copy) { super(copy); this.minLength = copy.minLength; } /** * Return the maximum number of digits that can be used to express the number * * @return the maximum number of digits that can be used to express the number */ public int getMaximumLenth() { return MAXIMUM_NO_OF_DIGITS; } /** * Return the minimum number of digits that can be used to express the number * * @return the minimum number of digits that can be used to express the number */ public int getMinimumLength() { return minLength; } /** * @param minimumSize */ public void setMinimumSize(int minimumSize) { if (minimumSize > 0) { this.minLength = minimumSize; } } /** * @return the number of bytes required to write this to a file */ public int getSize() { if (value == null) { return 0; } else { int current; long temp = ID3Tags.getWholeNumber(value); int size = 0; for (int i = MINIMUM_NO_OF_DIGITS; i <= MAXIMUM_NO_OF_DIGITS; i++) { current = (byte) temp & 0xFF; if (current != 0) { size = i; } temp >>= MAXIMUM_NO_OF_DIGITS; } return (minLength > size) ? minLength : size; } } /** * @param obj * @return */ public boolean equals(Object obj) { if (!(obj instanceof NumberVariableLength)) { return false; } NumberVariableLength object = (NumberVariableLength) obj; return this.minLength == object.minLength && super.equals(obj); } /** * Read from Byte Array * * @param arr * @param offset * @throws NullPointerException * @throws IndexOutOfBoundsException */ public void readByteArray(byte[] arr, int offset) throws InvalidDataTypeException { //Coding error, should never happen if (arr == null) { throw new NullPointerException("Byte array is null"); } //Coding error, should never happen as far as I can see if (offset < 0) { throw new IllegalArgumentException("negativer offset into an array offset:" + offset); } //If optional then set value to zero, this will mean that if this frame is written back to file it will be created //with this additional datatype wheras it didnt exist but I think this is probably an advantage the frame is //more likely to be parsed by other applications if it contains optional fields. //if not optional problem with this frame if (offset >= arr.length) { if (minLength == 0) { value = (long) 0; return; } else { throw new InvalidDataTypeException("Offset to byte array is out of bounds: offset = " + offset + ", array.length = " + arr.length); } } long lvalue = 0; //Read the bytes (starting from offset), the most significant byte of the number being constructed is read first, //we then shift the resulting long one byte over to make room for the next byte for (int i = offset; i < arr.length; i++) { lvalue <<= 8; lvalue += (arr[i] & 0xff); } value = lvalue; } /** * @return String representation of the number */ public String toString() { if (value == null) { return ""; } else { return value.toString(); } } /** * Write to Byte Array * * @return the datatype converted to a byte array */ public byte[] writeByteArray() { int size = getSize(); byte[] arr; if (size == 0) { arr = new byte[0]; } else { long temp = ID3Tags.getWholeNumber(value); arr = new byte[size]; //keeps shifting the number downwards and masking the last 8 bist to get the value for the next byte //to be written for (int i = size - 1; i >= 0; i--) { arr[i] = (byte) (temp & 0xFF); temp >>= 8; } } return arr; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/datatype/HashMapInterface.java0000644000175000017500000000323311041064726030103 0ustar drazzibdrazzib/** * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: HashMapInterface.java 625 2008-07-21 10:49:58Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Description: * A simple Interface required by classes which use a HashMap to Store ValuePairs */ package org.jaudiotagger.tag.datatype; import java.util.Iterator; import java.util.Map; /** * Represents an interface allowing maping from key to value and value to key */ public interface HashMapInterface { /** * @return a mapping between the key within the frame and the value */ public Map getKeyToValue(); /** * @return a mapping between the value to the key within the frame */ public Map getValueToKey(); /** * @return an interator of the values within the map */ public Iterator iterator(); } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/datatype/AbstractIntStringValuePair.java0000644000175000017500000000372611277026507032174 0ustar drazzibdrazzib/** * @author : Paul Taylor *

* Version @version:$Id: AbstractIntStringValuePair.java 836 2009-11-12 15:44:07Z paultaylor $ *

* Jaudiotagger Copyright (C)2004,2005 *

* This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. *

* This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. *

* You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *

* Description: */ package org.jaudiotagger.tag.datatype; import java.util.Collections; import java.util.Map; /** * A two way mapping between an Integral Id and a String value */ public class AbstractIntStringValuePair extends AbstractValuePair { protected Integer key = null; /** * Get Id for Value * @param value * @return */ public Integer getIdForValue(String value) { return valueToId.get(value); } /** * Get value for Id * @param id * @return */ public String getValueForId(int id) { return idToValue.get(id); } protected void createMaps() { //Create the reverse the map for (Map.Entry entry : idToValue.entrySet()) { valueToId.put(entry.getValue(), entry.getKey()); } //Value List sort alphabetically valueList.addAll(idToValue.values()); Collections.sort(valueList); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/datatype/StringHashMap.java0000644000175000017500000001242311277026507027460 0ustar drazzibdrazzib/** * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: StringHashMap.java 836 2009-11-12 15:44:07Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Description: * */ package org.jaudiotagger.tag.datatype; import org.jaudiotagger.tag.id3.AbstractTagFrameBody; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; import org.jaudiotagger.tag.reference.Languages; import java.util.Iterator; import java.util.Map; import java.util.TreeSet; /** * Represents a String thats acts as a key into an enumeration of values. The String will be encoded * using the default encoding regardless of what encoding may be specified in the framebody */ public class StringHashMap extends StringFixedLength implements HashMapInterface { /** * */ Map keyToValue = null; /** * */ Map valueToKey = null; /** * */ boolean hasEmptyValue = false; /** * Creates a new ObjectStringHashMap datatype. * * @param identifier * @param frameBody * @param size * @throws IllegalArgumentException */ public StringHashMap(String identifier, AbstractTagFrameBody frameBody, int size) { super(identifier, frameBody, size); if (identifier.equals(DataTypes.OBJ_LANGUAGE)) { valueToKey = Languages.getInstanceOf().getValueToIdMap(); keyToValue = Languages.getInstanceOf().getIdToValueMap(); } else { throw new IllegalArgumentException("Hashmap identifier not defined in this class: " + identifier); } } public StringHashMap(StringHashMap copyObject) { super(copyObject); this.hasEmptyValue = copyObject.hasEmptyValue; this.keyToValue = copyObject.keyToValue; this.valueToKey = copyObject.valueToKey; } /** * @return */ public Map getKeyToValue() { return keyToValue; } /** * @return */ public Map getValueToKey() { return valueToKey; } /** * @param value */ public void setValue(Object value) { if (value instanceof String) { //Issue #273 temporary hack for MM if(value.equals("XXX")) { this.value=value.toString(); } else { this.value = ((String) value).toLowerCase(); } } else { this.value = value; } } /** * @param obj * @return */ public boolean equals(Object obj) { if (!(obj instanceof StringHashMap)) { return false; } StringHashMap object = (StringHashMap) obj; if (this.hasEmptyValue != object.hasEmptyValue) { return false; } if (this.keyToValue == null) { if (object.keyToValue != null) { return false; } } else { if (!this.keyToValue.equals(object.keyToValue)) { return false; } } if (this.keyToValue == null) { if (object.keyToValue != null) { return false; } } else { if (!this.valueToKey.equals(object.valueToKey)) { return false; } } return super.equals(obj); } /** * @return */ public Iterator iterator() { if (keyToValue == null) { return null; } else { // put them in a treeset first to sort them TreeSet treeSet = new TreeSet(keyToValue.values()); if (hasEmptyValue) { treeSet.add(""); } return treeSet.iterator(); } } /** * @return */ public String toString() { if (value == null) { return ""; } else if (keyToValue.get(value) == null) { return ""; } else { return keyToValue.get(value); } } /** * @return the ISO_8859 encoding for Datatypes of this type */ protected String getTextEncodingCharSet() { return TextEncoding.CHARSET_ISO_8859_1; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/datatype/ID3v2LyricLine.java0000644000175000017500000000772711277026507027425 0ustar drazzibdrazzib/** * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: ID3v2LyricLine.java 836 2009-11-12 15:44:07Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Description: * */ package org.jaudiotagger.tag.datatype; import org.jaudiotagger.audio.generic.Utils; import org.jaudiotagger.tag.InvalidDataTypeException; import org.jaudiotagger.tag.id3.AbstractTagFrameBody; public class ID3v2LyricLine extends AbstractDataType { /** * */ String text = ""; /** * */ long timeStamp = 0; public ID3v2LyricLine(String identifier, AbstractTagFrameBody frameBody) { super(identifier, frameBody); } public ID3v2LyricLine(ID3v2LyricLine copy) { super(copy); this.text = copy.text; this.timeStamp = copy.timeStamp; } /** * @return */ public int getSize() { return text.length() + 1 + 4; } public void setText(String text) { this.text = text; } /** * @return */ public String getText() { return text; } public void setTimeStamp(long timeStamp) { this.timeStamp = timeStamp; } /** * @return */ public long getTimeStamp() { return timeStamp; } /** * @param obj * @return */ public boolean equals(Object obj) { if (!(obj instanceof ID3v2LyricLine)) { return false; } ID3v2LyricLine object = (ID3v2LyricLine) obj; if (!this.text.equals(object.text)) { return false; } return this.timeStamp == object.timeStamp && super.equals(obj); } /** * @param arr * @param offset * @throws NullPointerException * @throws IndexOutOfBoundsException */ public void readByteArray(byte[] arr, int offset) throws InvalidDataTypeException { if (arr == null) { throw new NullPointerException("Byte array is null"); } if ((offset < 0) || (offset >= arr.length)) { throw new IndexOutOfBoundsException("Offset to byte array is out of bounds: offset = " + offset + ", array.length = " + arr.length); } //offset += (); text = Utils.getString(arr, offset, arr.length - offset - 4, "ISO-8859-1"); //text = text.substring(0, text.length() - 5); timeStamp = 0; for (int i = arr.length - 4; i < arr.length; i++) { timeStamp <<= 8; timeStamp += arr[i]; } } /** * @return */ public String toString() { return timeStamp + " " + text; } /** * @return */ public byte[] writeByteArray() { int i; byte[] arr = new byte[getSize()]; for (i = 0; i < text.length(); i++) { arr[i] = (byte) text.charAt(i); } arr[i++] = 0; arr[i++] = (byte) ((timeStamp & 0xFF000000) >> 24); arr[i++] = (byte) ((timeStamp & 0x00FF0000) >> 16); arr[i++] = (byte) ((timeStamp & 0x0000FF00) >> 8); arr[i++] = (byte) (timeStamp & 0x000000FF); return arr; } } ././@LongLink0000000000000000000000000000015200000000000011563 Lustar rootrootlibjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/datatype/MultipleTextEncodedStringNullTerminated.javalibjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/datatype/MultipleTextEncodedStringNullTerminated0000644000175000017500000001475711470746136034027 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.datatype; import org.jaudiotagger.tag.InvalidDataTypeException; import org.jaudiotagger.tag.id3.AbstractTagFrameBody; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.ListIterator; import java.util.logging.Level; /** * Represents a data type that supports multiple terminated Strings (there may only be one) */ public class MultipleTextEncodedStringNullTerminated extends AbstractDataType { /** * Creates a new ObjectStringSizeTerminated datatype. * * @param identifier identifies the frame type * @param frameBody */ public MultipleTextEncodedStringNullTerminated(String identifier, AbstractTagFrameBody frameBody) { super(identifier, frameBody); value = new MultipleTextEncodedStringNullTerminated.Values(); } public MultipleTextEncodedStringNullTerminated(TextEncodedStringSizeTerminated object) { super(object); value = new MultipleTextEncodedStringNullTerminated.Values(); } public MultipleTextEncodedStringNullTerminated(MultipleTextEncodedStringNullTerminated object) { super(object); } public boolean equals(Object obj) { return obj instanceof MultipleTextEncodedStringNullTerminated && super.equals(obj); } /** * Returns the size in bytes of this datatype when written to file * * @return size of this datatype */ public int getSize() { return size; } /** * Check the value can be encoded with the specified encoding * @return */ public boolean canBeEncoded() { for (ListIterator li = ((Values) value).getList().listIterator(); li.hasNext();) { TextEncodedStringNullTerminated next = new TextEncodedStringNullTerminated(identifier, frameBody, li.next()); if (!next.canBeEncoded()) { return false; } } return true; } /** * Read Null Terminated Strings from the array starting at offset, continue until unable to find any null terminated * Strings or until reached the end of the array. The offset should be set to byte after the last null terminated * String found. * * @param arr to read the Strings from * @param offset in the array to start reading from * @throws InvalidDataTypeException if unable to find any null terminated Strings */ public void readByteArray(byte[] arr, int offset) throws InvalidDataTypeException { logger.finer("Reading MultipleTextEncodedStringNullTerminated from array from offset:" + offset); //Continue until unable to read a null terminated String while (true) { try { //Read String TextEncodedStringNullTerminated next = new TextEncodedStringNullTerminated(identifier, frameBody); next.readByteArray(arr, offset); if (next.getSize() == 0) { break; } else { //Add to value ((Values) value).add((String) next.getValue()); //Add to size calculation size += next.getSize(); //Increment Offset to start of next datatype. offset += next.getSize(); } } catch (InvalidDataTypeException idte) { break; } if (size == 0) { logger.warning("No null terminated Strings found"); throw new InvalidDataTypeException("No null terminated Strings found"); } } logger.finer("Read MultipleTextEncodedStringNullTerminated:" + value + " size:" + size); } /** * For every String write to bytebuffer * * @return bytebuffer that should be written to file to persist this datatype. */ public byte[] writeByteArray() { logger.finer("Writing MultipleTextEncodedStringNullTerminated"); int localSize = 0; ByteArrayOutputStream buffer = new ByteArrayOutputStream(); try { for (ListIterator li = ((Values) value).getList().listIterator(); li.hasNext();) { TextEncodedStringNullTerminated next = new TextEncodedStringNullTerminated(identifier, frameBody, li.next()); buffer.write(next.writeByteArray()); localSize += next.getSize(); } } catch (IOException ioe) { //This should never happen because the write is internal with the JVM it is not to a file logger.log(Level.SEVERE, "IOException in MultipleTextEncodedStringNullTerminated when writing byte array", ioe); throw new RuntimeException(ioe); } //Update size member variable size = localSize; logger.finer("Written MultipleTextEncodedStringNullTerminated"); return buffer.toByteArray(); } /** * This holds the values held by a MultipleTextEncodedData type */ public static class Values { private List valueList = new ArrayList(); public Values() { } /** * Add String Data type to the value list * * @param value to add to the list */ public void add(String value) { valueList.add(value); } /** * Return the list of values * * @return the list of values */ public List getList() { return valueList; } /** * * @return no of values */ public int getNumberOfValues() { return valueList.size(); } /** * Return the list of values as a single string separated by a comma * * @return a string representation of the value */ public String toString() { StringBuffer sb = new StringBuffer(); for (ListIterator li = valueList.listIterator(); li.hasNext();) { String next = li.next(); sb.append(next); if (li.hasNext()) { sb.append(","); } } return sb.toString(); } } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/datatype/AbstractStringStringValuePair.java0000644000175000017500000000404211277026507032700 0ustar drazzibdrazzib/** * @author : Paul Taylor *

* Version @version:$Id: AbstractStringStringValuePair.java 836 2009-11-12 15:44:07Z paultaylor $ *

* Jaudiotagger Copyright (C)2004,2005 *

* This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. *

* This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. *

* You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *

* Description: */ package org.jaudiotagger.tag.datatype; import java.util.Collections; public class AbstractStringStringValuePair extends AbstractValuePair { protected String lkey = null; /** * Get Id for Value * @param value * @return */ public String getIdForValue(String value) { return valueToId.get(value); } /** * Get value for Id * @param id * @return */ public String getValueForId(String id) { return idToValue.get(id); } protected void createMaps() { iterator = idToValue.keySet().iterator(); while (iterator.hasNext()) { lkey = iterator.next(); value = idToValue.get(lkey); valueToId.put(value, lkey); } //Value List iterator = idToValue.keySet().iterator(); while (iterator.hasNext()) { valueList.add(idToValue.get(iterator.next())); } //Sort alphabetically Collections.sort(valueList); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/datatype/NumberHashMap.java0000644000175000017500000001766511305717447027461 0ustar drazzibdrazzib/** * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: NumberHashMap.java 857 2009-12-03 11:21:11Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Description: * */ package org.jaudiotagger.tag.datatype; import org.jaudiotagger.logging.ErrorMessage; import org.jaudiotagger.tag.InvalidDataTypeException; import org.jaudiotagger.tag.id3.AbstractTagFrameBody; import org.jaudiotagger.tag.id3.valuepair.*; import org.jaudiotagger.tag.reference.GenreTypes; import org.jaudiotagger.tag.reference.PictureTypes; import org.jaudiotagger.utils.EqualsUtil; import java.util.Iterator; import java.util.Map; import java.util.TreeSet; /** * Represents a number thats acts as a key into an enumeration of values */ public class NumberHashMap extends NumberFixedLength implements HashMapInterface { /** * key to value map */ private Map keyToValue = null; /** * value to key map */ private Map valueToKey = null; /** * */ private boolean hasEmptyValue = false; /** * Creates a new ObjectNumberHashMap datatype. * * @param identifier * @param frameBody * @param size * @throws IllegalArgumentException */ public NumberHashMap(String identifier, AbstractTagFrameBody frameBody, int size) { super(identifier, frameBody, size); if (identifier.equals(DataTypes.OBJ_GENRE)) { valueToKey = GenreTypes.getInstanceOf().getValueToIdMap(); keyToValue = GenreTypes.getInstanceOf().getIdToValueMap(); //genres can be an id or literal value hasEmptyValue = true; } else if (identifier.equals(DataTypes.OBJ_TEXT_ENCODING)) { valueToKey = TextEncoding.getInstanceOf().getValueToIdMap(); keyToValue = TextEncoding.getInstanceOf().getIdToValueMap(); } else if (identifier.equals(DataTypes.OBJ_INTERPOLATION_METHOD)) { valueToKey = InterpolationTypes.getInstanceOf().getValueToIdMap(); keyToValue = InterpolationTypes.getInstanceOf().getIdToValueMap(); } else if (identifier.equals(DataTypes.OBJ_PICTURE_TYPE)) { valueToKey = PictureTypes.getInstanceOf().getValueToIdMap(); keyToValue = PictureTypes.getInstanceOf().getIdToValueMap(); //Issue #224 Values should map, but have examples where they dont, this is a workaround hasEmptyValue = true; } else if (identifier.equals(DataTypes.OBJ_TYPE_OF_EVENT)) { valueToKey = EventTimingTypes.getInstanceOf().getValueToIdMap(); keyToValue = EventTimingTypes.getInstanceOf().getIdToValueMap(); } else if (identifier.equals(DataTypes.OBJ_TIME_STAMP_FORMAT)) { valueToKey = EventTimingTimestampTypes.getInstanceOf().getValueToIdMap(); keyToValue = EventTimingTimestampTypes.getInstanceOf().getIdToValueMap(); } else if (identifier.equals(DataTypes.OBJ_TYPE_OF_CHANNEL)) { valueToKey = ChannelTypes.getInstanceOf().getValueToIdMap(); keyToValue = ChannelTypes.getInstanceOf().getIdToValueMap(); } else if (identifier.equals(DataTypes.OBJ_RECIEVED_AS)) { valueToKey = ReceivedAsTypes.getInstanceOf().getValueToIdMap(); keyToValue = ReceivedAsTypes.getInstanceOf().getIdToValueMap(); } else if (identifier.equals(DataTypes.OBJ_CONTENT_TYPE)) { valueToKey = SynchronisedLyricsContentType.getInstanceOf().getValueToIdMap(); keyToValue = SynchronisedLyricsContentType.getInstanceOf().getIdToValueMap(); } else { throw new IllegalArgumentException("Hashmap identifier not defined in this class: " + identifier); } } public NumberHashMap(NumberHashMap copyObject) { super(copyObject); this.hasEmptyValue = copyObject.hasEmptyValue; // we don't need to clone/copy the maps here because they are static this.keyToValue = copyObject.keyToValue; this.valueToKey = copyObject.valueToKey; } /** * @return the key to value map */ public Map getKeyToValue() { return keyToValue; } /** * @return the value to key map */ public Map getValueToKey() { return valueToKey; } /** * @param value */ public void setValue(Object value) { if (value instanceof Byte) { this.value = (long) ((Byte) value).byteValue(); } else if (value instanceof Short) { this.value = (long) ((Short) value).shortValue(); } else if (value instanceof Integer) { this.value = (long) ((Integer) value).intValue(); } else { this.value = value; } } /** * @param obj * @return */ public boolean equals(Object obj) { if(obj==this) { return true; } if (!(obj instanceof NumberHashMap)) { return false; } NumberHashMap that = (NumberHashMap) obj; return EqualsUtil.areEqual(hasEmptyValue, that.hasEmptyValue) && EqualsUtil.areEqual(keyToValue, that.keyToValue) && EqualsUtil.areEqual(valueToKey, that.valueToKey) && super.equals(that); } /** * @return */ public Iterator iterator() { if (keyToValue == null) { return null; } else { // put them in a treeset first to sort them TreeSet treeSet = new TreeSet(keyToValue.values()); if (hasEmptyValue) { treeSet.add(""); } return treeSet.iterator(); } } /** * Read the key from the buffer. * * @param arr * @param offset * @throws InvalidDataTypeException if emptyValues are not allowed and the eky was invalid. */ public void readByteArray(byte[] arr, int offset) throws InvalidDataTypeException { super.readByteArray(arr, offset); //Mismatch:Superclass uses Long, but maps expect Integer Integer intValue = ((Long) value).intValue(); if (!keyToValue.containsKey(intValue)) { if (!hasEmptyValue) { throw new InvalidDataTypeException(ErrorMessage.MP3_REFERENCE_KEY_INVALID.getMsg(identifier, intValue)); } else if (identifier.equals(DataTypes.OBJ_PICTURE_TYPE)) { logger.warning(ErrorMessage.MP3_PICTURE_TYPE_INVALID.getMsg(value)); } } } /** * @return */ public String toString() { if (value == null) { return ""; } else if (keyToValue.get(value) == null) { return ""; } else { return keyToValue.get(value); } } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/datatype/TextEncodedStringNullTerminated.java0000644000175000017500000002153511470746136033223 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.datatype; import org.jaudiotagger.tag.InvalidDataTypeException; import org.jaudiotagger.tag.id3.AbstractTagFrameBody; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.charset.*; /** * Represents a String whose size is determined by finding of a null character at the end of the String. *

* The String itself might be of length zero (i.e just consist of the null character). The String will be encoded based * upon the text encoding of the frame that it belongs to. */ public class TextEncodedStringNullTerminated extends AbstractString { /** * Creates a new TextEncodedStringNullTerminated datatype. * * @param identifier identifies the frame type * @param frameBody */ public TextEncodedStringNullTerminated(String identifier, AbstractTagFrameBody frameBody) { super(identifier, frameBody); } /** * Creates a new TextEncodedStringNullTerminated datatype, with value * * @param identifier * @param frameBody * @param value */ public TextEncodedStringNullTerminated(String identifier, AbstractTagFrameBody frameBody, String value) { super(identifier, frameBody, value); } public TextEncodedStringNullTerminated(TextEncodedStringNullTerminated object) { super(object); } public boolean equals(Object obj) { return obj instanceof TextEncodedStringNullTerminated && super.equals(obj); } /** * Read a string from buffer upto null character (if exists) *

* Must take into account the text encoding defined in the Encoding Object * ID3 Text Frames often allow multiple strings seperated by the null char * appropriate for the encoding. * * @param arr this is the buffer for the frame * @param offset this is where to start reading in the buffer for this field */ public void readByteArray(byte[] arr, int offset) throws InvalidDataTypeException { if(offset>=arr.length) { throw new InvalidDataTypeException("Unable to find null terminated string"); } int bufferSize; logger.finer("Reading from array starting from offset:" + offset); int size; //Get the Specified Decoder String charSetName = getTextEncodingCharSet(); CharsetDecoder decoder = Charset.forName(charSetName).newDecoder(); //We only want to load up to null terminator, data after this is part of different //field and it may not be possible to decode it so do the check before we do //do the decoding,encoding dependent. ByteBuffer buffer = ByteBuffer.wrap(arr, offset, arr.length - offset); int endPosition = 0; //Latin-1 and UTF-8 strings are terminated by a single-byte null, //while UTF-16 and its variants need two bytes for the null terminator. final boolean nullIsOneByte = (charSetName.equals(TextEncoding.CHARSET_ISO_8859_1) || charSetName.equals(TextEncoding.CHARSET_UTF_8)); boolean isNullTerminatorFound = false; while (buffer.hasRemaining()) { byte nextByte = buffer.get(); if (nextByte == 0x00) { if (nullIsOneByte) { buffer.mark(); buffer.reset(); endPosition = buffer.position() - 1; logger.finest("Null terminator found starting at:" + endPosition); isNullTerminatorFound = true; break; } else { // Looking for two-byte null if (buffer.hasRemaining()) { nextByte = buffer.get(); if (nextByte == 0x00) { buffer.mark(); buffer.reset(); endPosition = buffer.position() - 2; logger.finest("UTF16:Null terminator found starting at:" + endPosition); isNullTerminatorFound = true; break; } else { //Nothing to do, we have checked 2nd value of pair it was not a null terminator //so will just start looking again in next invocation of loop } } else { buffer.mark(); buffer.reset(); endPosition = buffer.position() - 1; logger.warning("UTF16:Should be two null terminator marks but only found one starting at:" + endPosition); isNullTerminatorFound = true; break; } } } else { //If UTF16, we should only be looking on 2 byte boundaries if (!nullIsOneByte) { if (buffer.hasRemaining()) { buffer.get(); } } } } if (!isNullTerminatorFound) { throw new InvalidDataTypeException("Unable to find null terminated string"); } logger.finest("End Position is:" + endPosition + "Offset:" + offset); //Set Size so offset is ready for next field (includes the null terminator) size = endPosition - offset; size++; if (!nullIsOneByte) { size++; } setSize(size); //Decode buffer if runs into problems should throw exception which we //catch and then set value to empty string. (We don't read the null terminator //because we dont want to display this) bufferSize = endPosition - offset; logger.finest("Text size is:" + bufferSize); if (bufferSize == 0) { value = ""; } else { //Decode sliced inBuffer ByteBuffer inBuffer = ByteBuffer.wrap(arr, offset, bufferSize).slice(); CharBuffer outBuffer = CharBuffer.allocate(bufferSize); decoder.reset(); CoderResult coderResult = decoder.decode(inBuffer, outBuffer, true); if (coderResult.isError()) { logger.warning("Problem decoding text encoded null terminated string:" + coderResult.toString()); } decoder.flush(outBuffer); outBuffer.flip(); value = outBuffer.toString(); } //Set Size so offset is ready for next field (includes the null terminator) logger.info("Read NullTerminatedString:" + value + " size inc terminator:" + size); } /** * Write String into byte array, adding a null character to the end of the String * * @return the data as a byte array in format to write to file */ public byte[] writeByteArray() { logger.info("Writing NullTerminatedString." + value); byte[] data; //Write to buffer using the CharSet defined by getTextEncodingCharSet() //Add a null terminator which will be encoded based on encoding. try { String charSetName = getTextEncodingCharSet(); if (charSetName.equals(TextEncoding.CHARSET_UTF_16)) { charSetName = TextEncoding.CHARSET_UTF_16_ENCODING_FORMAT; CharsetEncoder encoder = Charset.forName(charSetName).newEncoder(); //Note remember LE BOM is ff fe but this is handled by encoder Unicode char is fe ff ByteBuffer bb = encoder.encode(CharBuffer.wrap('\ufeff' + (String) value + '\0')); data = new byte[bb.limit()]; bb.get(data, 0, bb.limit()); } else { CharsetEncoder encoder = Charset.forName(charSetName).newEncoder(); ByteBuffer bb = encoder.encode(CharBuffer.wrap((String) value + '\0')); data = new byte[bb.limit()]; bb.get(data, 0, bb.limit()); } } //Should never happen so if does throw a RuntimeException catch (CharacterCodingException ce) { logger.severe(ce.getMessage()); throw new RuntimeException(ce); } setSize(data.length); return data; } protected String getTextEncodingCharSet() { byte textEncoding = this.getBody().getTextEncoding(); String charSetName = TextEncoding.getInstanceOf().getValueForId(textEncoding); logger.finest("text encoding:" + textEncoding + " charset:" + charSetName); return charSetName; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/datatype/Lyrics3Image.java0000644000175000017500000001347111277026507027247 0ustar drazzibdrazzib/** * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: Lyrics3Image.java 836 2009-11-12 15:44:07Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Description: * */ package org.jaudiotagger.tag.datatype; import org.jaudiotagger.audio.generic.Utils; import org.jaudiotagger.tag.InvalidDataTypeException; import org.jaudiotagger.tag.id3.AbstractTagFrameBody; public class Lyrics3Image extends AbstractDataType { /** * */ private Lyrics3TimeStamp time = null; /** * */ private String description = ""; /** * */ private String filename = ""; /** * Creates a new ObjectLyrics3Image datatype. * * @param identifier * @param frameBody */ public Lyrics3Image(String identifier, AbstractTagFrameBody frameBody) { super(identifier, frameBody); } public Lyrics3Image(Lyrics3Image copy) { super(copy); this.time = new Lyrics3TimeStamp(copy.time); this.description = copy.description; this.filename = copy.filename; } /** * @param description */ public void setDescription(String description) { this.description = description; } /** * @return */ public String getDescription() { return this.description; } /** * @param filename */ public void setFilename(String filename) { this.filename = filename; } /** * @return */ public String getFilename() { return this.filename; } /** * @return */ public int getSize() { int size; size = filename.length() + 2 + description.length() + 2; if (time != null) { size += time.getSize(); } return size; } /** * @param time */ public void setTimeStamp(Lyrics3TimeStamp time) { this.time = time; } /** * @return */ public Lyrics3TimeStamp getTimeStamp() { return this.time; } /** * @param obj * @return */ public boolean equals(Object obj) { if (!(obj instanceof Lyrics3Image)) { return false; } Lyrics3Image object = (Lyrics3Image) obj; if (!this.description.equals(object.description)) { return false; } if (!this.filename.equals(object.filename)) { return false; } if (this.time == null) { if (object.time != null) { return false; } } else { if (!this.time.equals(object.time)) { return false; } } return super.equals(obj); } /** * @param imageString * @param offset * @throws NullPointerException * @throws IndexOutOfBoundsException */ public void readString(String imageString, int offset) { if (imageString == null) { throw new NullPointerException("Image string is null"); } if ((offset < 0) || (offset >= imageString.length())) { throw new IndexOutOfBoundsException("Offset to image string is out of bounds: offset = " + offset + ", string.length()" + imageString.length()); } if (imageString != null) { String timestamp; int delim; delim = imageString.indexOf("||", offset); filename = imageString.substring(offset, delim); offset = delim + 2; delim = imageString.indexOf("||", offset); description = imageString.substring(offset, delim); offset = delim + 2; timestamp = imageString.substring(offset); if (timestamp.length() == 7) { time = new Lyrics3TimeStamp("Time Stamp"); time.readString(timestamp); } } } /** * @return */ public String toString() { String str; str = "filename = " + filename + ", description = " + description; if (time != null) { str += (", timestamp = " + time.toString()); } return str + "\n"; } /** * @return */ public String writeString() { String str; if (filename == null) { str = "||"; } else { str = filename + "||"; } if (description == null) { str += "||"; } else { str += (description + "||"); } if (time != null) { str += time.writeString(); } return str; } public void readByteArray(byte[] arr, int offset) throws InvalidDataTypeException { readString(arr.toString(), offset); } public byte[] writeByteArray() { return Utils.getDefaultBytes(writeString(), "ISO-8859-1"); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/datatype/AbstractValuePair.java0000644000175000017500000000361711277026507030331 0ustar drazzibdrazzib/** * @author : Paul Taylor *

* Version @version:$Id: AbstractValuePair.java 836 2009-11-12 15:44:07Z paultaylor $ *

* Jaudiotagger Copyright (C)2004,2005 *

* This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. *

* This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. *

* You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *

* Description: */ package org.jaudiotagger.tag.datatype; import java.util.*; /** * A two way mapping between an id and a value */ public abstract class AbstractValuePair { protected final Map idToValue = new LinkedHashMap(); protected final Map valueToId = new LinkedHashMap(); protected final List valueList = new ArrayList(); protected Iterator iterator = idToValue.keySet().iterator(); protected String value; /** * Get list in alphabetical order * @return */ public List getAlphabeticalValueList() { return valueList; } public Map getIdToValueMap() { return idToValue; } public Map getValueToIdMap() { return valueToId; } /** * @return the number of elements in the mapping */ public int getSize() { return valueList.size(); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/datatype/StringDateTime.java0000644000175000017500000000407311277026507027635 0ustar drazzibdrazzib/** * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: StringDateTime.java 836 2009-11-12 15:44:07Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Description: * */ package org.jaudiotagger.tag.datatype; import org.jaudiotagger.tag.id3.AbstractTagFrameBody; /** * Represents a timestamp field */ public class StringDateTime extends StringSizeTerminated { /** * Creates a new ObjectStringDateTime datatype. * * @param identifier * @param frameBody */ public StringDateTime(String identifier, AbstractTagFrameBody frameBody) { super(identifier, frameBody); } public StringDateTime(StringDateTime object) { super(object); } /** * @param value */ public void setValue(Object value) { if (value != null) { this.value = value.toString().replace(' ', 'T'); } } /** * @return */ public Object getValue() { if (value != null) { return value.toString().replace(' ', 'T'); } else { return null; } } public boolean equals(Object obj) { return obj instanceof StringDateTime && super.equals(obj); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/datatype/Lyrics3TimeStamp.java0000644000175000017500000001177111277026507030131 0ustar drazzibdrazzib/** * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: Lyrics3TimeStamp.java 836 2009-11-12 15:44:07Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Description: * */ package org.jaudiotagger.tag.datatype; import org.jaudiotagger.audio.generic.Utils; import org.jaudiotagger.tag.InvalidDataTypeException; import org.jaudiotagger.tag.id3.AbstractTagFrameBody; public class Lyrics3TimeStamp extends AbstractDataType { /** * */ private long minute = 0; /** * */ private long second = 0; /** * Todo this is wrong * @param s */ public void readString(String s) { } /** * Creates a new ObjectLyrics3TimeStamp datatype. * * @param identifier * @param frameBody */ public Lyrics3TimeStamp(String identifier, AbstractTagFrameBody frameBody) { super(identifier, frameBody); } public Lyrics3TimeStamp(String identifier) { super(identifier, null); } public Lyrics3TimeStamp(Lyrics3TimeStamp copy) { super(copy); this.minute = copy.minute; this.second = copy.second; } public void setMinute(long minute) { this.minute = minute; } /** * @return */ public long getMinute() { return minute; } public void setSecond(long second) { this.second = second; } /** * @return */ public long getSecond() { return second; } /** * @return */ public int getSize() { return 7; } /** * Creates a new ObjectLyrics3TimeStamp datatype. * * @param timeStamp * @param timeStampFormat */ public void setTimeStamp(long timeStamp, byte timeStampFormat) { /** * @todo convert both types of formats */ timeStamp = timeStamp / 1000; minute = timeStamp / 60; second = timeStamp % 60; } /** * @param obj * @return */ public boolean equals(Object obj) { if (!(obj instanceof Lyrics3TimeStamp)) { return false; } Lyrics3TimeStamp object = (Lyrics3TimeStamp) obj; if (this.minute != object.minute) { return false; } return this.second == object.second && super.equals(obj); } /** * @param timeStamp * @param offset * @throws NullPointerException * @throws IndexOutOfBoundsException */ public void readString(String timeStamp, int offset) { if (timeStamp == null) { throw new NullPointerException("Image is null"); } if ((offset < 0) || (offset >= timeStamp.length())) { throw new IndexOutOfBoundsException("Offset to timeStamp is out of bounds: offset = " + offset + ", timeStamp.length()" + timeStamp.length()); } timeStamp = timeStamp.substring(offset); if (timeStamp.length() == 7) { minute = Integer.parseInt(timeStamp.substring(1, 3)); second = Integer.parseInt(timeStamp.substring(4, 6)); } else { minute = 0; second = 0; } } /** * @return */ public String toString() { return writeString(); } /** * @return */ public String writeString() { String str; str = "["; if (minute < 0) { str += "00"; } else { if (minute < 10) { str += '0'; } str += Long.toString(minute); } str += ':'; if (second < 0) { str += "00"; } else { if (second < 10) { str += '0'; } str += Long.toString(second); } str += ']'; return str; } public void readByteArray(byte[] arr, int offset) throws InvalidDataTypeException { readString(arr.toString(), offset); } public byte[] writeByteArray() { return Utils.getDefaultBytes(writeString(), "ISO8859-1"); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/datatype/StringNullTerminated.java0000644000175000017500000000413711277026507031071 0ustar drazzibdrazzib/** * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: StringNullTerminated.java 836 2009-11-12 15:44:07Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Description: * */ package org.jaudiotagger.tag.datatype; import org.jaudiotagger.tag.id3.AbstractTagFrameBody; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; /** * Represents a String whose size is determined by finding of a null character at the end of the String with fixed text encoding. *

* The String will be encoded using the default encoding regardless of what encoding may be specified in the framebody */ public class StringNullTerminated extends TextEncodedStringNullTerminated { /** * Creates a new ObjectStringNullTerminated datatype. * * @param identifier identifies the frame type * @param frameBody */ public StringNullTerminated(String identifier, AbstractTagFrameBody frameBody) { super(identifier, frameBody); } public StringNullTerminated(StringNullTerminated object) { super(object); } public boolean equals(Object obj) { return obj instanceof StringNullTerminated && super.equals(obj); } protected String getTextEncodingCharSet() { return TextEncoding.CHARSET_ISO_8859_1; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/datatype/AbstractDataType.java0000644000175000017500000003000311470746136030143 0ustar drazzibdrazzib/** * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: AbstractDataType.java 929 2010-11-17 12:36:46Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * */ package org.jaudiotagger.tag.datatype; import org.jaudiotagger.audio.mp3.MP3File; import org.jaudiotagger.tag.InvalidDataTypeException; import org.jaudiotagger.tag.id3.AbstractTagFrameBody; import java.util.Arrays; import java.util.logging.Logger; /** * Represents a field/data type that can be held within a frames body, these map loosely onto * Section 4. ID3v2 frame overview at http://www.id3.org/id3v2.4.0-structure.txt */ public abstract class AbstractDataType { protected static final String TYPE_ELEMENT = "element"; //Logger public static Logger logger = Logger.getLogger("org.jaudiotagger.tag.datatype"); /** * Holds the data */ protected Object value = null; /** * Holds the key such as "Text" or "PictureType", the naming of keys are fairly arbitary but are intended * to make it easier to for the developer, the keys themseleves are not written to the tag. */ protected String identifier = ""; /** * Holds the calling body, allows an datatype to query other objects in the * body such as the Text Encoding of the frame */ protected AbstractTagFrameBody frameBody = null; /** * Holds the size of the data in file when read/written */ protected int size; /** * Construct an abstract datatype identified by identifier and linked to a framebody without setting * an initial value. * * @param identifier to allow retrieval of this datatype by name from framebody * @param frameBody that the dataype is associated with */ protected AbstractDataType(String identifier, AbstractTagFrameBody frameBody) { this.identifier = identifier; this.frameBody = frameBody; } /** * Construct an abstract datatype identified by identifier and linked to a framebody initilised with a value * * @param identifier to allow retrieval of this datatype by name from framebody * @param frameBody that the dataype is associated with * @param value of this DataType */ protected AbstractDataType(String identifier, AbstractTagFrameBody frameBody, Object value) { this.identifier = identifier; this.frameBody = frameBody; setValue(value); } /** * This is used by subclasses, to clone the data within the copyObject *

* TODO:It seems to be missing some of the more complex value types. * @param copyObject */ public AbstractDataType(AbstractDataType copyObject) { // no copy constructor in super class this.identifier = copyObject.identifier; if (copyObject.value == null) { this.value = null; } else if (copyObject.value instanceof String) { this.value = copyObject.value; } else if (copyObject.value instanceof Boolean) { this.value = copyObject.value; } else if (copyObject.value instanceof Byte) { this.value = copyObject.value; } else if (copyObject.value instanceof Character) { this.value = copyObject.value; } else if (copyObject.value instanceof Double) { this.value = copyObject.value; } else if (copyObject.value instanceof Float) { this.value = copyObject.value; } else if (copyObject.value instanceof Integer) { this.value = copyObject.value; } else if (copyObject.value instanceof Long) { this.value = copyObject.value; } else if (copyObject.value instanceof Short) { this.value = copyObject.value; } else if(copyObject.value instanceof MultipleTextEncodedStringNullTerminated.Values) { this.value = copyObject.value; } else if(copyObject.value instanceof PairedTextEncodedStringNullTerminated.ValuePairs) { this.value = copyObject.value; } else if(copyObject.value instanceof PartOfSet.PartOfSetValue) { this.value = copyObject.value; } else if (copyObject.value instanceof boolean[]) { this.value = ((boolean[]) copyObject.value).clone(); } else if (copyObject.value instanceof byte[]) { this.value = ((byte[]) copyObject.value).clone(); } else if (copyObject.value instanceof char[]) { this.value = ((char[]) copyObject.value).clone(); } else if (copyObject.value instanceof double[]) { this.value = ((double[]) copyObject.value).clone(); } else if (copyObject.value instanceof float[]) { this.value = ((float[]) copyObject.value).clone(); } else if (copyObject.value instanceof int[]) { this.value = ((int[]) copyObject.value).clone(); } else if (copyObject.value instanceof long[]) { this.value = ((long[]) copyObject.value).clone(); } else if (copyObject.value instanceof short[]) { this.value = ((short[]) copyObject.value).clone(); } else if (copyObject.value instanceof Object[]) { this.value = ((Object[]) copyObject.value).clone(); } else { throw new UnsupportedOperationException("Unable to create copy of class " + copyObject.getClass()); } } /** * Set the framebody that this datatype is associated with * * @param frameBody */ public void setBody(AbstractTagFrameBody frameBody) { this.frameBody = frameBody; } /** * Get the framebody associated with this datatype * * @return the framebody that this datatype is associated with */ public AbstractTagFrameBody getBody() { return frameBody; } /** * Return the key as declared by the frame bodies datatype list * * @return the key used to reference this datatype from a framebody */ public String getIdentifier() { return identifier; } /** * Set the value held by this datatype, this is used typically used when the * user wants to modify the value in an existing frame. * * @param value */ public void setValue(Object value) { this.value = value; } /** * Get value held by this Object * * @return value held by this Object */ public Object getValue() { return value; } /** * Simplified wrapper for reading bytes from file into Object. * Used for reading Strings, this class should be overridden * for non String Objects * * @param arr * @throws org.jaudiotagger.tag.InvalidDataTypeException */ final public void readByteArray(byte[] arr) throws InvalidDataTypeException { readByteArray(arr, 0); } /** * This defines the size in bytes of the datatype being * held when read/written to file. * * @return the size in bytes of the datatype */ abstract public int getSize(); /** * @param obj * @return whether this and obj are deemed equivalent */ public boolean equals(Object obj) { if(this==obj) { return true; } if (!(obj instanceof AbstractDataType)) { return false; } AbstractDataType object = (AbstractDataType) obj; if (!this.identifier.equals(object.identifier)) { return false; } if ((this.value == null) && (object.value == null)) { return true; } else if ((this.value == null) || (object.value == null)) { return false; } // boolean[] if (this.value instanceof boolean[] && object.value instanceof boolean[]) { if (!Arrays.equals((boolean[]) this.value, (boolean[]) object.value)) { return false; } // byte[] } else if (this.value instanceof byte[] && object.value instanceof byte[]) { if (!Arrays.equals((byte[]) this.value, (byte[]) object.value)) { return false; } // char[] } else if (this.value instanceof char[] && object.value instanceof char[]) { if (!Arrays.equals((char[]) this.value, (char[]) object.value)) { return false; } // double[] } else if (this.value instanceof double[] && object.value instanceof double[]) { if (!Arrays.equals((double[]) this.value, (double[]) object.value)) { return false; } // float[] } else if (this.value instanceof float[] && object.value instanceof float[]) { if (!Arrays.equals((float[]) this.value, (float[]) object.value)) { return false; } // int[] } else if (this.value instanceof int[] && object.value instanceof int[]) { if (!Arrays.equals((int[]) this.value, (int[]) object.value)) { return false; } // long[] } else if (this.value instanceof long[] && object.value instanceof long[]) { if (!Arrays.equals((long[]) this.value, (long[]) object.value)) { return false; } // Object[] } else if (this.value instanceof Object[] && object.value instanceof Object[]) { if (!Arrays.equals((Object[]) this.value, (Object[]) object.value)) { return false; } // short[] } else if (this.value instanceof short[] && object.value instanceof short[]) { if (!Arrays.equals((short[]) this.value, (short[]) object.value)) { return false; } } else if (!this.value.equals(object.value)) { return false; } return true; } /** * This is the starting point for reading bytes from the file into the ID3 datatype * starting at offset. * This class must be overridden * * @param arr * @param offset * @throws org.jaudiotagger.tag.InvalidDataTypeException */ public abstract void readByteArray(byte[] arr, int offset) throws InvalidDataTypeException; /** * Starting point write ID3 Datatype back to array of bytes. * This class must be overridden. * * @return the array of bytes representing this datatype that should be written to file */ public abstract byte[] writeByteArray(); /** * Return String Representation of Datatype * */ public void createStructure() { MP3File.getStructureFormatter().addElement(identifier, getValue().toString()); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/datatype/NumberFixedLength.java0000644000175000017500000001221711277026507030323 0ustar drazzibdrazzib/** * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: NumberFixedLength.java 836 2009-11-12 15:44:07Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Description: * Represents a Number of a fixed number of decimal places. */ package org.jaudiotagger.tag.datatype; import org.jaudiotagger.tag.InvalidDataTypeException; import org.jaudiotagger.tag.id3.AbstractTagFrameBody; import org.jaudiotagger.tag.id3.ID3Tags; /** * Represents a number held as a fixed number of digits. *

* The bitorder in ID3v2 is most significant bit first (MSB). The byteorder in multibyte numbers is most significant * byte first (e.g. $12345678 would be encoded $12 34 56 78), also known as big endian and network byte order. *

* In ID3Specification would be denoted as $xx xx this denotes exactly two bytes required */ public class NumberFixedLength extends AbstractDataType { /** * Creates a new ObjectNumberFixedLength datatype. * * @param identifier * @param frameBody * @param size the number of significant places that the number is held to * @throws IllegalArgumentException */ public NumberFixedLength(String identifier, AbstractTagFrameBody frameBody, int size) { super(identifier, frameBody); if (size < 0) { throw new IllegalArgumentException("Length is less than zero: " + size); } this.size = size; } public NumberFixedLength(NumberFixedLength copy) { super(copy); this.size = copy.size; } /** * Set Size in Bytes of this Object * * @param size in bytes that this number will be held as */ public void setSize(int size) { if (size > 0) { this.size = size; } } /** * Return size * * @return the size of this number */ public int getSize() { return size; } public void setValue(Object value) { if (!(value instanceof Number)) { throw new IllegalArgumentException("Invalid value type for NumberFixedLength:" + value.getClass()); } super.setValue(value); } /** * @param obj * @return true if obj equivalent to this */ public boolean equals(Object obj) { if (!(obj instanceof NumberFixedLength)) { return false; } NumberFixedLength object = (NumberFixedLength) obj; return this.size == object.size && super.equals(obj); } /** * Read the number from the byte array * * @param arr * @param offset * @throws NullPointerException * @throws IndexOutOfBoundsException */ public void readByteArray(byte[] arr, int offset) throws InvalidDataTypeException { if (arr == null) { throw new NullPointerException("Byte array is null"); } if ((offset < 0) || (offset >= arr.length)) { throw new InvalidDataTypeException("Offset to byte array is out of bounds: offset = " + offset + ", array.length = " + arr.length); } if(offset + size > arr.length) { throw new InvalidDataTypeException("Offset plus size to byte array is out of bounds: offset = " + offset + ", size = "+size +" + arr.length "+ arr.length ); } long lvalue = 0; for (int i = offset; i < (offset + size); i++) { lvalue <<= 8; lvalue += (arr[i] & 0xff); } value = lvalue; logger.info("Read NumberFixedlength:" + value); } /** * @return String representation of this datatype */ public String toString() { if (value == null) { return ""; } else { return value.toString(); } } /** * Write data to byte array * * @return the datatype converted to a byte array */ public byte[] writeByteArray() { byte[] arr; arr = new byte[size]; if (value != null) { //Convert value to long long temp = ID3Tags.getWholeNumber(value); for (int i = size - 1; i >= 0; i--) { arr[i] = (byte) (temp & 0xFF); temp >>= 8; } } return arr; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/datatype/Lyrics3Line.java0000644000175000017500000001300411277026507027104 0ustar drazzibdrazzib/** * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: Lyrics3Line.java 836 2009-11-12 15:44:07Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Description: * */ package org.jaudiotagger.tag.datatype; import org.jaudiotagger.audio.generic.Utils; import org.jaudiotagger.tag.InvalidDataTypeException; import org.jaudiotagger.tag.id3.AbstractTagFrameBody; import java.util.Iterator; import java.util.LinkedList; public class Lyrics3Line extends AbstractDataType { /** * */ private LinkedList timeStamp = new LinkedList(); /** * */ private String lyric = ""; /** * Creates a new ObjectLyrics3Line datatype. * * @param identifier * @param frameBody */ public Lyrics3Line(String identifier, AbstractTagFrameBody frameBody) { super(identifier, frameBody); } public Lyrics3Line(Lyrics3Line copy) { super(copy); this.lyric = copy.lyric; Lyrics3TimeStamp newTimeStamp; for (int i = 0; i < copy.timeStamp.size(); i++) { newTimeStamp = new Lyrics3TimeStamp(copy.timeStamp.get(i)); this.timeStamp.add(newTimeStamp); } } public void setLyric(String lyric) { this.lyric = lyric; } public void setLyric(ID3v2LyricLine line) { this.lyric = line.getText(); } /** * @return */ public String getLyric() { return lyric; } /** * @return */ public int getSize() { int size = 0; for (Object aTimeStamp : timeStamp) { size += ((Lyrics3TimeStamp) aTimeStamp).getSize(); } return size + lyric.length(); } /** * @param time */ public void setTimeStamp(Lyrics3TimeStamp time) { timeStamp.clear(); timeStamp.add(time); } /** * @return */ public Iterator getTimeStamp() { return timeStamp.iterator(); } public void addLyric(String newLyric) { this.lyric += newLyric; } public void addLyric(ID3v2LyricLine line) { this.lyric += line.getText(); } /** * @param time */ public void addTimeStamp(Lyrics3TimeStamp time) { timeStamp.add(time); } /** * @param obj * @return */ public boolean equals(Object obj) { if (!(obj instanceof Lyrics3Line)) { return false; } Lyrics3Line object = (Lyrics3Line) obj; if (!this.lyric.equals(object.lyric)) { return false; } return this.timeStamp.equals(object.timeStamp) && super.equals(obj); } /** * @return */ public boolean hasTimeStamp() { return !timeStamp.isEmpty(); } /** * @param lineString * @param offset * @throws NullPointerException * @throws IndexOutOfBoundsException */ public void readString(String lineString, int offset) { if (lineString == null) { throw new NullPointerException("Image is null"); } if ((offset < 0) || (offset >= lineString.length())) { throw new IndexOutOfBoundsException("Offset to line is out of bounds: offset = " + offset + ", line.length()" + lineString.length()); } int delim; Lyrics3TimeStamp time; timeStamp = new LinkedList(); delim = lineString.indexOf("[", offset); while (delim >= 0) { offset = lineString.indexOf("]", delim) + 1; time = new Lyrics3TimeStamp("Time Stamp"); time.readString(lineString.substring(delim, offset)); timeStamp.add(time); delim = lineString.indexOf("[", offset); } lyric = lineString.substring(offset); } /** * @return */ public String toString() { String str = ""; for (Object aTimeStamp : timeStamp) { str += aTimeStamp.toString(); } return "timeStamp = " + str + ", lyric = " + lyric + "\n"; } /** * @return */ public String writeString() { String str = ""; Lyrics3TimeStamp time; for (Object aTimeStamp : timeStamp) { time = (Lyrics3TimeStamp) aTimeStamp; str += time.writeString(); } return str + lyric; } public void readByteArray(byte[] arr, int offset) throws InvalidDataTypeException { readString(arr.toString(), offset); } public byte[] writeByteArray() { return Utils.getDefaultBytes(writeString(), "ISO8859-1"); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/TagTextField.java0000644000175000017500000000322311247705415025456 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2003-2005 Raphaël Slinckx * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.tag; /** * This interface extends the default field definition by methods for working * with human readable text.
* A TagTextField does not store binary data. * * @author Rapha�l Slinckx */ public interface TagTextField extends TagField { /** * Returns the content of the field. * * @return Content */ public String getContent(); /** * Returns the current used charset encoding. * * @return Charset encoding. */ public String getEncoding(); /** * Sets the content of the field. * * @param content fields content. */ public void setContent(String content); /** * Sets the charset encoding used by the field. * * @param encoding charset. */ public void setEncoding(String encoding); }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/InvalidDataTypeException.java0000644000175000017500000000351610736454526030046 0ustar drazzibdrazzib/* * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag; /** * Indicates there was a problem parsing this datatype due to a problem with the data * such as the array being empty when trying to read from a file. * * @version $Revision: 520 $ */ public class InvalidDataTypeException extends InvalidTagException { /** * Creates a new InvalidDataTypeException datatype. */ public InvalidDataTypeException() { } /** * Creates a new InvalidDataTypeException datatype. * * @param ex the cause. */ public InvalidDataTypeException(Throwable ex) { super(ex); } /** * Creates a new InvalidDataTypeException datatype. * * @param msg the detail message. */ public InvalidDataTypeException(String msg) { super(msg); } /** * Creates a new InvalidDataTypeException datatype. * * @param msg the detail message. * @param ex the cause. */ public InvalidDataTypeException(String msg, Throwable ex) { super(msg, ex); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/asf/0000755000175000017500000000000011556363175023046 5ustar drazzibdrazziblibjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/asf/AsfTagTextField.java0000644000175000017500000000472111277264361026670 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.asf; import org.jaudiotagger.audio.asf.data.AsfHeader; import org.jaudiotagger.audio.asf.data.MetadataDescriptor; import org.jaudiotagger.audio.asf.util.Utils; import org.jaudiotagger.tag.TagTextField; import org.jaudiotagger.tag.asf.AsfFieldKey; import org.jaudiotagger.tag.asf.AsfTagField; /** * Represents a tag text field for ASF fields.
* * @author Christian Laireiter */ public class AsfTagTextField extends AsfTagField implements TagTextField { /** * Creates a tag text field and assigns the string value. * * @param field * ASF field to represent. * @param value * the value to assign. */ public AsfTagTextField(final AsfFieldKey field, final String value) { super(field); toWrap.setString(value); } /** * Creates an instance. * * @param source * The metadata descriptor, whose content is published.
* Must not be of type {@link MetadataDescriptor#TYPE_BINARY}. */ public AsfTagTextField(final MetadataDescriptor source) { super(source); if (source.getType() == MetadataDescriptor.TYPE_BINARY) { throw new IllegalArgumentException( "Cannot interpret binary as string."); } } /** * Creates a tag text field and assigns the string value. * * @param fieldKey * The fields identifier. * @param value * the value to assign. */ public AsfTagTextField(final String fieldKey, final String value) { super(fieldKey); toWrap.setString(value); } /** * {@inheritDoc} */ public String getContent() { return getDescriptor().getString(); } /** * {@inheritDoc} */ public String getEncoding() { return AsfHeader.ASF_CHARSET.name(); } /** * @return true if blank or only contains whitespace */ @Override public boolean isEmpty() { return Utils.isBlank(getContent()); } /** * {@inheritDoc} */ public void setContent(final String content) { getDescriptor().setString(content); } /** * {@inheritDoc} */ public void setEncoding(final String encoding) { if (!AsfHeader.ASF_CHARSET.name().equals(encoding)) { throw new IllegalArgumentException( "Only UTF-16LE is possible with ASF."); } } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/asf/AsfTagField.java0000644000175000017500000001023411277264361026017 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2004-2005 Christian Laireiter * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.tag.asf; import org.jaudiotagger.audio.asf.data.MetadataDescriptor; import org.jaudiotagger.tag.TagField; import org.jaudiotagger.tag.asf.AsfFieldKey; import org.jaudiotagger.tag.asf.AsfTag; /** * This class encapsulates a * {@link org.jaudiotagger.audio.asf.data.MetadataDescriptor}and provides access * to it.
* The metadata descriptor used for construction is copied. * * @author Christian Laireiter (liree) */ public class AsfTagField implements TagField, Cloneable { /** * This descriptor is wrapped. */ protected MetadataDescriptor toWrap; /** * Creates a tag field. * * @param field * the ASF field that should be represented. */ public AsfTagField(final AsfFieldKey field) { assert field != null; this.toWrap = new MetadataDescriptor(field.getHighestContainer(), field .getFieldName(), MetadataDescriptor.TYPE_STRING); } /** * Creates an instance. * * @param source * The descriptor which should be represented as a * {@link TagField}. */ public AsfTagField(final MetadataDescriptor source) { assert source != null; // XXX Copy ? maybe not really. this.toWrap = source.createCopy(); } /** * Creates a tag field. * * @param fieldKey * The field identifier to use. */ public AsfTagField(final String fieldKey) { assert fieldKey != null; this.toWrap = new MetadataDescriptor(AsfFieldKey.getAsfFieldKey( fieldKey).getHighestContainer(), fieldKey, MetadataDescriptor.TYPE_STRING); } /** * {@inheritDoc} */ @Override public Object clone() throws CloneNotSupportedException { return super.clone(); } /** * {@inheritDoc} */ public void copyContent(final TagField field) { throw new UnsupportedOperationException("Not implemented yet."); } /** * Returns the wrapped metadata descriptor (which actually stores the * values). * * @return the wrapped metadata descriptor */ public MetadataDescriptor getDescriptor() { return this.toWrap; } /** * {@inheritDoc} */ public String getId() { return this.toWrap.getName(); } /** * {@inheritDoc} */ public byte[] getRawContent() { return this.toWrap.getRawData(); } /** * {@inheritDoc} */ public boolean isBinary() { return this.toWrap.getType() == MetadataDescriptor.TYPE_BINARY; } /** * {@inheritDoc} */ public void isBinary(final boolean value) { if (!value && isBinary()) { throw new UnsupportedOperationException("No conversion supported."); } this.toWrap.setBinaryValue(this.toWrap.getRawData()); } /** * {@inheritDoc} */ public boolean isCommon() { // HashSet is safe against null comparison return AsfTag.COMMON_FIELDS.contains(AsfFieldKey .getAsfFieldKey(getId())); } /** * {@inheritDoc} */ public boolean isEmpty() { return this.toWrap.isEmpty(); } /** * {@inheritDoc} */ @Override public String toString() { return this.toWrap.getString(); } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/asf/AbstractAsfTagImageField.java0000644000175000017500000000370411277264361030452 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.asf; import org.jaudiotagger.audio.asf.data.MetadataDescriptor; import org.jaudiotagger.tag.asf.AsfTagField; import org.jaudiotagger.tag.asf.AsfFieldKey; import org.jaudiotagger.tag.TagField; import javax.imageio.ImageIO; import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.io.IOException; /** * An AbstractAsfTagImageField is an abstract class for representing tag * fields containing image data.
* * @author Christian Laireiter */ abstract class AbstractAsfTagImageField extends AsfTagField { /** * Creates a image tag field. * * @param field * the ASF field that should be represented. */ public AbstractAsfTagImageField(final AsfFieldKey field) { super(field); } /** * Creates an instance. * * @param source * The descriptor which should be represented as a * {@link TagField}. */ public AbstractAsfTagImageField(final MetadataDescriptor source) { super(source); } /** * Creates a tag field. * * @param fieldKey * The field identifier to use. */ public AbstractAsfTagImageField(final String fieldKey) { super(fieldKey); } /** * This method returns an image instance from the * {@linkplain #getRawImageData() image content}. * * @return the image instance * @throws IOException */ public BufferedImage getImage() throws IOException { return ImageIO.read(new ByteArrayInputStream(getRawImageData())); } /** * Returns the size of the {@linkplain #getRawImageData() image data}.
* * @return image data size in bytes. */ public abstract int getImageDataSize(); /** * Returns the raw data of the represented image.
* * @return raw image data */ public abstract byte[] getRawImageData(); } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/asf/AsfTag.java0000644000175000017500000005266711470746136025073 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.asf; import org.jaudiotagger.audio.asf.data.AsfHeader; import org.jaudiotagger.audio.generic.AbstractTag; import org.jaudiotagger.logging.ErrorMessage; import org.jaudiotagger.tag.*; import org.jaudiotagger.tag.datatype.Artwork; import org.jaudiotagger.tag.mp4.Mp4FieldKey; import org.jaudiotagger.tag.reference.PictureTypes; import java.io.UnsupportedEncodingException; import java.util.*; /** * Tag implementation for ASF.
* * @author Christian Laireiter */ public final class AsfTag extends AbstractTag { /** * This iterator is used to iterator an {@link Iterator} with * {@link TagField} objects and returns them by casting to * {@link AsfTagField}.
* * @author Christian Laireiter */ private static class AsfFieldIterator implements Iterator { /** * source iterator. */ private final Iterator fieldIterator; /** * Creates an isntance. * * @param iterator iterator to read from. */ public AsfFieldIterator(final Iterator iterator) { assert iterator != null; this.fieldIterator = iterator; } /** * {@inheritDoc} */ public boolean hasNext() { return this.fieldIterator.hasNext(); } /** * {@inheritDoc} */ public AsfTagField next() { return (AsfTagField) this.fieldIterator.next(); } /** * {@inheritDoc} */ public void remove() { this.fieldIterator.remove(); } } /** * Stores a list of field keys, which identify common fields.
*/ public final static Set COMMON_FIELDS; /** * This map contains the mapping from {@link org.jaudiotagger.tag.FieldKey} to * {@link AsfFieldKey}. */ private static final EnumMap tagFieldToAsfField; // Mapping from generic key to asf key static { tagFieldToAsfField = new EnumMap(FieldKey.class); tagFieldToAsfField.put(FieldKey.ALBUM, AsfFieldKey.ALBUM); tagFieldToAsfField.put(FieldKey.ALBUM_ARTIST, AsfFieldKey.ALBUM_ARTIST); tagFieldToAsfField.put(FieldKey.ALBUM_ARTIST_SORT, AsfFieldKey.ALBUM_ARTIST_SORT); tagFieldToAsfField.put(FieldKey.ALBUM_SORT, AsfFieldKey.ALBUM_SORT); tagFieldToAsfField.put(FieldKey.AMAZON_ID, AsfFieldKey.AMAZON_ID); tagFieldToAsfField.put(FieldKey.ARTIST, AsfFieldKey.AUTHOR); tagFieldToAsfField.put(FieldKey.ARTIST_SORT, AsfFieldKey.ARTIST_SORT); tagFieldToAsfField.put(FieldKey.BARCODE, AsfFieldKey.BARCODE); tagFieldToAsfField.put(FieldKey.BPM, AsfFieldKey.BPM); tagFieldToAsfField.put(FieldKey.CATALOG_NO, AsfFieldKey.CATALOG_NO); tagFieldToAsfField.put(FieldKey.COMMENT, AsfFieldKey.DESCRIPTION); tagFieldToAsfField.put(FieldKey.COMPOSER, AsfFieldKey.COMPOSER); tagFieldToAsfField.put(FieldKey.COMPOSER_SORT, AsfFieldKey.COMPOSER_SORT); tagFieldToAsfField.put(FieldKey.CONDUCTOR, AsfFieldKey.CONDUCTOR); tagFieldToAsfField.put(FieldKey.COVER_ART, AsfFieldKey.COVER_ART); tagFieldToAsfField.put(FieldKey.CUSTOM1, AsfFieldKey.CUSTOM1); tagFieldToAsfField.put(FieldKey.CUSTOM2, AsfFieldKey.CUSTOM2); tagFieldToAsfField.put(FieldKey.CUSTOM3, AsfFieldKey.CUSTOM3); tagFieldToAsfField.put(FieldKey.CUSTOM4, AsfFieldKey.CUSTOM4); tagFieldToAsfField.put(FieldKey.CUSTOM5, AsfFieldKey.CUSTOM5); tagFieldToAsfField.put(FieldKey.DISC_NO, AsfFieldKey.DISC_NO); tagFieldToAsfField.put(FieldKey.DISC_TOTAL, AsfFieldKey.DISC_TOTAL); tagFieldToAsfField.put(FieldKey.ENCODER, AsfFieldKey.ENCODER); tagFieldToAsfField.put(FieldKey.FBPM, AsfFieldKey.FBPM); tagFieldToAsfField.put(FieldKey.GENRE, AsfFieldKey.GENRE); tagFieldToAsfField.put(FieldKey.GROUPING, AsfFieldKey.GROUPING); tagFieldToAsfField.put(FieldKey.ISRC, AsfFieldKey.ISRC); tagFieldToAsfField.put(FieldKey.IS_COMPILATION, AsfFieldKey.IS_COMPILATION); tagFieldToAsfField.put(FieldKey.KEY, AsfFieldKey.INITIAL_KEY); tagFieldToAsfField.put(FieldKey.LANGUAGE, AsfFieldKey.LANGUAGE); tagFieldToAsfField.put(FieldKey.LYRICIST, AsfFieldKey.LYRICIST); tagFieldToAsfField.put(FieldKey.LYRICS, AsfFieldKey.LYRICS); tagFieldToAsfField.put(FieldKey.MEDIA, AsfFieldKey.MEDIA); tagFieldToAsfField.put(FieldKey.MOOD, AsfFieldKey.MOOD); tagFieldToAsfField.put(FieldKey.MUSICBRAINZ_ARTISTID, AsfFieldKey.MUSICBRAINZ_ARTISTID); tagFieldToAsfField.put(FieldKey.MUSICBRAINZ_DISC_ID, AsfFieldKey.MUSICBRAINZ_DISC_ID); tagFieldToAsfField.put(FieldKey.MUSICBRAINZ_RELEASEARTISTID, AsfFieldKey.MUSICBRAINZ_RELEASEARTISTID); tagFieldToAsfField.put(FieldKey.MUSICBRAINZ_RELEASEID, AsfFieldKey.MUSICBRAINZ_RELEASEID); tagFieldToAsfField.put(FieldKey.MUSICBRAINZ_RELEASE_COUNTRY, AsfFieldKey.MUSICBRAINZ_RELEASE_COUNTRY); tagFieldToAsfField.put(FieldKey.MUSICBRAINZ_RELEASE_GROUP_ID, AsfFieldKey.MUSICBRAINZ_RELEASEGROUPID); tagFieldToAsfField.put(FieldKey.MUSICBRAINZ_RELEASE_STATUS, AsfFieldKey.MUSICBRAINZ_RELEASE_STATUS); tagFieldToAsfField.put(FieldKey.MUSICBRAINZ_RELEASE_TYPE, AsfFieldKey.MUSICBRAINZ_RELEASE_TYPE); tagFieldToAsfField.put(FieldKey.MUSICBRAINZ_TRACK_ID, AsfFieldKey.MUSICBRAINZ_TRACK_ID); tagFieldToAsfField.put(FieldKey.MUSICBRAINZ_WORK_ID, AsfFieldKey.MUSICBRAINZ_WORKID); tagFieldToAsfField.put(FieldKey.MUSICIP_ID, AsfFieldKey.MUSICIP_ID); tagFieldToAsfField.put(FieldKey.OCCASION, AsfFieldKey.OCCASION); tagFieldToAsfField.put(FieldKey.ORIGINAL_ARTIST, AsfFieldKey.ORIGINAL_ARTIST); tagFieldToAsfField.put(FieldKey.ORIGINAL_ALBUM, AsfFieldKey.ORIGINAL_ALBUM); tagFieldToAsfField.put(FieldKey.ORIGINAL_LYRICIST, AsfFieldKey.ORIGINAL_LYRICIST); tagFieldToAsfField.put(FieldKey.ORIGINAL_YEAR, AsfFieldKey.ORIGINAL_YEAR); tagFieldToAsfField.put(FieldKey.RATING, AsfFieldKey.MM_RATING); tagFieldToAsfField.put(FieldKey.RECORD_LABEL, AsfFieldKey.RECORD_LABEL); tagFieldToAsfField.put(FieldKey.QUALITY, AsfFieldKey.QUALITY); tagFieldToAsfField.put(FieldKey.REMIXER, AsfFieldKey.REMIXER); tagFieldToAsfField.put(FieldKey.SCRIPT, AsfFieldKey.SCRIPT); tagFieldToAsfField.put(FieldKey.TAGS, AsfFieldKey.TAGS); tagFieldToAsfField.put(FieldKey.TEMPO, AsfFieldKey.TEMPO); tagFieldToAsfField.put(FieldKey.TITLE, AsfFieldKey.TITLE); tagFieldToAsfField.put(FieldKey.TITLE_SORT, AsfFieldKey.TITLE_SORT); tagFieldToAsfField.put(FieldKey.TRACK, AsfFieldKey.TRACK); tagFieldToAsfField.put(FieldKey.TRACK_TOTAL, AsfFieldKey.TRACK_TOTAL); tagFieldToAsfField.put(FieldKey.URL_DISCOGS_ARTIST_SITE, AsfFieldKey.URL_DISCOGS_ARTIST_SITE); tagFieldToAsfField.put(FieldKey.URL_DISCOGS_RELEASE_SITE, AsfFieldKey.URL_DISCOGS_RELEASE_SITE); tagFieldToAsfField.put(FieldKey.URL_LYRICS_SITE, AsfFieldKey.URL_LYRICS_SITE); tagFieldToAsfField.put(FieldKey.URL_OFFICIAL_ARTIST_SITE, AsfFieldKey.URL_OFFICIAL_ARTIST_SITE); tagFieldToAsfField.put(FieldKey.URL_OFFICIAL_RELEASE_SITE, AsfFieldKey.URL_OFFICIAL_RELEASE_SITE); tagFieldToAsfField.put(FieldKey.URL_WIKIPEDIA_ARTIST_SITE, AsfFieldKey.URL_WIKIPEDIA_ARTIST_SITE); tagFieldToAsfField.put(FieldKey.URL_WIKIPEDIA_RELEASE_SITE, AsfFieldKey.URL_WIKIPEDIA_RELEASE_SITE); tagFieldToAsfField.put(FieldKey.YEAR, AsfFieldKey.YEAR); tagFieldToAsfField.put(FieldKey.ENGINEER, AsfFieldKey.ENGINEER); tagFieldToAsfField.put(FieldKey.PRODUCER, AsfFieldKey.PRODUCER); tagFieldToAsfField.put(FieldKey.DJMIXER, AsfFieldKey.DJMIXER); tagFieldToAsfField.put(FieldKey.MIXER, AsfFieldKey.MIXER); tagFieldToAsfField.put(FieldKey.ARRANGER, AsfFieldKey.ARRANGER); } static { COMMON_FIELDS = new HashSet(); COMMON_FIELDS.add(AsfFieldKey.ALBUM); COMMON_FIELDS.add(AsfFieldKey.AUTHOR); COMMON_FIELDS.add(AsfFieldKey.DESCRIPTION); COMMON_FIELDS.add(AsfFieldKey.GENRE); COMMON_FIELDS.add(AsfFieldKey.TITLE); COMMON_FIELDS.add(AsfFieldKey.TRACK); COMMON_FIELDS.add(AsfFieldKey.YEAR); } /** * @see #isCopyingFields() */ private final boolean copyFields; /** * Creates an empty instance. */ public AsfTag() { this(false); } /** * Creates an instance and sets the field conversion property.
* * @param copy look at {@link #isCopyingFields()}. */ public AsfTag(final boolean copy) { super(); this.copyFields = copy; } /** * Creates an instance and copies the fields of the source into the own * structure.
* * @param source source to read tag fields from. * @param copy look at {@link #isCopyingFields()}. * @throws UnsupportedEncodingException {@link TagField#getRawContent()} which may be called */ public AsfTag(final Tag source, final boolean copy) throws UnsupportedEncodingException { this(copy); copyFrom(source); } /** * {@inheritDoc} */ @Override // TODO introduce copy idea to all formats public void addField(final TagField field) { if (isValidField(field)) { if (AsfFieldKey.isMultiValued(field.getId())) { super.addField(copyFrom(field)); } else { super.setField(copyFrom(field)); } } } /** * Creates a field for copyright and adds it.
* * @param copyRight copyright content */ public void addCopyright(final String copyRight) { addField(createCopyrightField(copyRight)); } /** * Creates a field for rating and adds it.
* * @param rating rating. */ public void addRating(final String rating) { addField(createRatingField(rating)); } /** * This method copies tag fields from the source.
* * @param source source to read tag fields from. */ private void copyFrom(final Tag source) { final Iterator fieldIterator = source.getFields(); // iterate over all fields while (fieldIterator.hasNext()) { final TagField copy = copyFrom(fieldIterator.next()); if (copy != null) { super.addField(copy); } } } /** * If {@link #isCopyingFields()} is true, Creates a copy of * source, if its not empty-
* However, plain {@link TagField} objects can only be transformed into * binary fields using their {@link TagField#getRawContent()} method.
* * @param source source field to copy. * @return A copy, which is as close to the source as possible, or * null if the field is empty (empty byte[] or blank * string}. */ private TagField copyFrom(final TagField source) { TagField result; if (isCopyingFields()) { if (source instanceof AsfTagField) { try { result = (TagField) ((AsfTagField) source).clone(); } catch (CloneNotSupportedException e) { result = new AsfTagField(((AsfTagField) source).getDescriptor()); } } else if (source instanceof TagTextField) { final String content = ((TagTextField) source).getContent(); result = new AsfTagTextField(source.getId(), content); } else { throw new RuntimeException("Unknown Asf Tag Field class:" // NOPMD // by // Christian // Laireiter // on // 5/9/09 // 5:44 // PM + source.getClass()); } } else { result = source; } return result; } /** * Creates an {@link AsfTagCoverField} from given artwork * * @param artwork artwork to create a ASF field from. * @return ASF field capable of storing artwork. */ public AsfTagCoverField createField(final Artwork artwork) { return new AsfTagCoverField(artwork.getBinaryData(), artwork.getPictureType(), artwork.getDescription(), artwork.getMimeType()); } /** * Create artwork field * * @param data raw image data * @return creates a default ASF picture field with default * {@linkplain PictureTypes#DEFAULT_ID picture type}. */ public AsfTagCoverField createArtworkField(final byte[] data) { return new AsfTagCoverField(data, PictureTypes.DEFAULT_ID, null, null); } /** * Creates a field for storing the copyright.
* * @param content Copyright value. * @return {@link AsfTagTextField} */ public AsfTagTextField createCopyrightField(final String content) { return new AsfTagTextField(AsfFieldKey.COPYRIGHT, content); } /** * Creates a field for storing the copyright.
* * @param content Rating value. * @return {@link AsfTagTextField} */ public AsfTagTextField createRatingField(final String content) { return new AsfTagTextField(AsfFieldKey.RATING, content); } /** * Create tag text field using ASF key *

* Uses the correct subclass for the key.
* * @param asfFieldKey field key to create field for. * @param value string value for the created field. * @return text field with given content. */ public AsfTagTextField createField(final AsfFieldKey asfFieldKey, final String value) { if (value == null) { throw new IllegalArgumentException(ErrorMessage.GENERAL_INVALID_NULL_ARGUMENT.getMsg()); } if (asfFieldKey == null) { throw new IllegalArgumentException(ErrorMessage.GENERAL_INVALID_NULL_ARGUMENT.getMsg()); } switch (asfFieldKey) { case COVER_ART: throw new UnsupportedOperationException("Cover Art cannot be created using this method"); case BANNER_IMAGE: throw new UnsupportedOperationException("Banner Image cannot be created using this method"); default: return new AsfTagTextField(asfFieldKey.getFieldName(), value); } } /** * {@inheritDoc} */ @Override public AsfTagTextField createField(final FieldKey genericKey, final String value) throws KeyNotFoundException, FieldDataInvalidException { if (value == null) { throw new IllegalArgumentException(ErrorMessage.GENERAL_INVALID_NULL_ARGUMENT.getMsg()); } if (genericKey == null) { throw new IllegalArgumentException(ErrorMessage.GENERAL_INVALID_NULL_ARGUMENT.getMsg()); } final AsfFieldKey asfFieldKey = tagFieldToAsfField.get(genericKey); if (asfFieldKey == null) { throw new KeyNotFoundException("No ASF fieldkey for " + genericKey.toString()); } return createField(asfFieldKey, value); } /** * Removes all fields which are stored to the provided field key. * * @param fieldKey fields to remove. */ public void deleteField(final AsfFieldKey fieldKey) { super.deleteField(fieldKey.getFieldName()); } /** * {@inheritDoc} */ @Override public void deleteField(final FieldKey fieldKey) throws KeyNotFoundException { if (fieldKey == null) { throw new KeyNotFoundException(); } super.deleteField(tagFieldToAsfField.get(fieldKey).getFieldName()); } /** * {@inheritDoc} */ @Override public List getFields(final FieldKey fieldKey) throws KeyNotFoundException { if (fieldKey == null) { throw new KeyNotFoundException(); } return super.getFields(tagFieldToAsfField.get(fieldKey).getFieldName()); } /** * @return */ public List getArtworkList() { final List coverartList = getFields(FieldKey.COVER_ART); final List artworkList = new ArrayList(coverartList.size()); for (final TagField next : coverartList) { final AsfTagCoverField coverArt = (AsfTagCoverField) next; final Artwork artwork = new Artwork(); artwork.setBinaryData(coverArt.getRawImageData()); artwork.setMimeType(coverArt.getMimeType()); artwork.setDescription(coverArt.getDescription()); artwork.setPictureType(coverArt.getPictureType()); artworkList.add(artwork); } return artworkList; } /** * This method iterates through all stored fields.
* This method can only be used if this class has been created with field * conversion turned on. * * @return Iterator for iterating through ASF fields. */ public Iterator getAsfFields() { if (!isCopyingFields()) { throw new IllegalStateException("Since the field conversion is not enabled, this method cannot be executed"); } return new AsfFieldIterator(getFields()); } /** * Returns a list of stored copyrights. * * @return list of stored copyrights. */ public List getCopyright() { return getFields(AsfFieldKey.COPYRIGHT.getFieldName()); } /** * {@inheritDoc} */ @Override public String getFirst(final FieldKey genericKey) throws KeyNotFoundException { return getValue(genericKey, 0); } /** * {@inheritDoc} */ public String getValue(final FieldKey genericKey, int index) throws KeyNotFoundException { if (genericKey == null) { throw new KeyNotFoundException(); } return super.getItem(tagFieldToAsfField.get(genericKey).getFieldName(), index); } /** * Returns the Copyright. * * @return the Copyright. */ public String getFirstCopyright() { return getFirst(AsfFieldKey.COPYRIGHT.getFieldName()); } /** * {@inheritDoc} */ @Override public AsfTagField getFirstField(final FieldKey genericKey) throws KeyNotFoundException { if (genericKey == null) { throw new KeyNotFoundException(); } return (AsfTagField) super.getFirstField(tagFieldToAsfField.get(genericKey).getFieldName()); } /** * Returns the Rating. * * @return the Rating. */ public String getFirstRating() { return getFirst(AsfFieldKey.RATING.getFieldName()); } /** * Returns a list of stored ratings. * * @return list of stored ratings. */ public List getRating() { return getFields(AsfFieldKey.RATING.getFieldName()); } /** * {@inheritDoc} */ @Override protected boolean isAllowedEncoding(final String enc) { return AsfHeader.ASF_CHARSET.name().equals(enc); } /** * If true, the {@link #copyFrom(TagField)} method creates a * new {@link AsfTagField} instance and copies the content from the source.
* This method is utilized by {@link #addField(TagField)} and * {@link #setField(TagField)}.
* So if true it is ensured that the {@link AsfTag} instance * has its own copies of fields, which cannot be modified after assignment * (which could pass some checks), and it just stores {@link AsfTagField} * objects.
* Only then {@link #getAsfFields()} can work. otherwise * {@link IllegalStateException} is thrown. * * @return state of field conversion. */ public boolean isCopyingFields() { return this.copyFields; } /** * Check field is valid and can be added to this tag * * @param field field to add * @return true if field may be added. */ // TODO introduce this concept to all formats private boolean isValidField(final TagField field) { if (field == null) { return false; } if (!(field instanceof AsfTagField)) { return false; } return !field.isEmpty(); } /** * {@inheritDoc} */ @Override // TODO introduce copy idea to all formats public void setField(final TagField field) { if (isValidField(field)) { // Copy only occurs if flag setField super.setField(copyFrom(field)); } } /** * Sets the copyright.
* * @param Copyright the copyright to set. */ public void setCopyright(final String Copyright) { setField(createCopyrightField(Copyright)); } /** * Sets the Rating.
* * @param rating the rating to set. */ public void setRating(final String rating) { setField(createRatingField(rating)); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/asf/AsfTagCoverField.java0000644000175000017500000001617111277264361027024 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.asf; import org.jaudiotagger.audio.asf.data.AsfHeader; import org.jaudiotagger.audio.asf.data.MetadataDescriptor; import org.jaudiotagger.logging.ErrorMessage; import org.jaudiotagger.tag.id3.valuepair.ImageFormats; import org.jaudiotagger.tag.asf.AbstractAsfTagImageField; import org.jaudiotagger.tag.asf.AsfFieldKey; import java.io.ByteArrayOutputStream; import java.io.UnsupportedEncodingException; import java.util.logging.Logger; /** * Encapsulates the WM/Pictures provides some convenience methods for decoding * the binary data it contains *

* The value of a WM/Pictures metadata descriptor is as follows: *

* byte0 Picture Type byte1-4 Length of the image data mime type encoded as * UTF-16LE null byte null byte description encoded as UTF-16LE (optional) null * byte null byte image data */ public class AsfTagCoverField extends AbstractAsfTagImageField { /** * Logger Object */ public final static Logger LOGGER = Logger .getLogger("org.jaudiotagger.audio.asf.tag"); /** * Description */ private String description; /** * We need this to retrieve the buffered image, if required */ private int endOfName = 0; /** * Image Data Size as read */ private int imageDataSize; /** * Mimetype of binary */ private String mimeType; /** * Picture Type */ private int pictureType; /** * Create New Image Field * * @param imageData * @param pictureType * @param description * @param mimeType */ public AsfTagCoverField(final byte[] imageData, final int pictureType, final String description, final String mimeType) { super(new MetadataDescriptor(AsfFieldKey.COVER_ART.getFieldName(), MetadataDescriptor.TYPE_BINARY)); this.getDescriptor() .setBinaryValue( createRawContent(imageData, pictureType, description, mimeType)); } /** * Creates an instance from a metadata descriptor * * @param source * The metadata descriptor, whose content is published.
*/ public AsfTagCoverField(final MetadataDescriptor source) { super(source); if (!source.getName().equals(AsfFieldKey.COVER_ART.getFieldName())) { throw new IllegalArgumentException( "Descriptor description must be WM/Picture"); } if (source.getType() != MetadataDescriptor.TYPE_BINARY) { throw new IllegalArgumentException("Descriptor type must be binary"); } try { processRawContent(); } catch (final UnsupportedEncodingException uee) { // Should never happen throw new RuntimeException(uee); // NOPMD by Christian Laireiter on 5/9/09 5:45 PM } } private byte[] createRawContent(final byte[] data, final int pictureType, final String description, String mimeType) { // NOPMD by Christian Laireiter on 5/9/09 5:46 PM this.description = description; // Get Mimetype from data if not already setField if (mimeType == null) { mimeType = ImageFormats.getMimeTypeForBinarySignature(data); // Couldnt identify lets default to png because probably error in // code because not 100% sure how to identify // formats if (mimeType == null) { LOGGER.warning(ErrorMessage.GENERAL_UNIDENITIFED_IMAGE_FORMAT .getMsg()); mimeType = ImageFormats.MIME_TYPE_PNG; } } final ByteArrayOutputStream baos = new ByteArrayOutputStream(); // PictureType baos.write(pictureType); // ImageDataSize baos.write(org.jaudiotagger.audio.generic.Utils .getSizeLEInt32(data.length), 0, 4); // mimetype byte[] mimeTypeData; try { mimeTypeData = mimeType.getBytes(AsfHeader.ASF_CHARSET.name()); } catch (final UnsupportedEncodingException uee) { // Should never happen throw new RuntimeException("Unable to find encoding:" // NOPMD by Christian Laireiter on 5/9/09 5:45 PM + AsfHeader.ASF_CHARSET.name()); } baos.write(mimeTypeData, 0, mimeTypeData.length); // Seperator baos.write(0x00); baos.write(0x00); // description if (description != null && description.length() > 0) { byte[] descriptionData; try { descriptionData = description.getBytes(AsfHeader.ASF_CHARSET .name()); } catch (final UnsupportedEncodingException uee) { // Should never happen throw new RuntimeException("Unable to find encoding:" // NOPMD by Christian Laireiter on 5/9/09 5:45 PM + AsfHeader.ASF_CHARSET.name()); } baos.write(descriptionData, 0, descriptionData.length); } // Seperator (always write whther or not we have descriptor field) baos.write(0x00); baos.write(0x00); // Image data baos.write(data, 0, data.length); return baos.toByteArray(); } public String getDescription() { return this.description; } @Override public int getImageDataSize() { return this.imageDataSize; } public String getMimeType() { return this.mimeType; } public int getPictureType() { return this.pictureType; } /** * @return the raw image data only */ @Override public byte[] getRawImageData() { final ByteArrayOutputStream baos = new ByteArrayOutputStream(); baos.write(getRawContent(), this.endOfName, this.toWrap .getRawDataSize() - this.endOfName); return baos.toByteArray(); } private void processRawContent() throws UnsupportedEncodingException { // PictureType this.pictureType = this.getRawContent()[0]; // ImageDataSize this.imageDataSize = org.jaudiotagger.audio.generic.Utils.getIntLE(this .getRawContent(), 1, 2); // Set Count to after picture type,datasize and two byte nulls int count = 5; this.mimeType = null; this.description = null; // Optional int endOfMimeType = 0; while (count < this.getRawContent().length - 1) { if (getRawContent()[count] == 0 && getRawContent()[count + 1] == 0) { if (this.mimeType == null) { this.mimeType = new String(getRawContent(), 5, (count) - 5, "UTF-16LE"); endOfMimeType = count + 2; } else if (this.description == null) { this.description = new String(getRawContent(), endOfMimeType, count - endOfMimeType, "UTF-16LE"); this.endOfName = count + 2; break; } } count += 2; // keep on two byte word boundary } } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/asf/AsfFieldKey.java0000644000175000017500000002553611470746136026047 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.asf; import org.jaudiotagger.audio.asf.data.ContainerType; import org.jaudiotagger.audio.asf.data.ContentBranding; import org.jaudiotagger.audio.asf.data.ContentDescription; import org.jaudiotagger.tag.reference.Tagger; import java.util.EnumSet; import java.util.HashMap; import java.util.Map; /** * Field keys which need to be mapped for ASF files, or only specified for ASF. * * TODO These attributes and their v23 mapping that havent been added to enum yet * * WMA ID3v1 ID3v22 ID3v2324 * * CopyrightURL WCP WCOP * Duration TLE TLEN * FileSize TSIZ * WM/AudioFileURL WAF WOAF * WM/AudioSourceURL WAS WOAS * WM/Binary GEO GEOB * WM/EncodingSettings TSS TSSE * WM/EncodingTime TDEN * WM/MCDI MCDI * WM/ModifiedBy TPE4 * WM/OriginalFilename TOF TOFN * WM/PlaylistDelay TDLY * WM/RadioStationName TRN TRSN * WM/RadioStationOwner TRO TRSO * WM/SetSubTitle TSST * WM/Text TXX TXXX * WM/UniqueFileIdentifier UFI UFID * WM/UserWebURL WXX WXXX * * @author Christian Laireiter */ public enum AsfFieldKey { /* * Keys are arbitrary because these fields don't have 'keys' internally because they are stored in preset contents descriptor */ // Content Description Object keys AUTHOR(ContentDescription.KEY_AUTHOR, false, ContainerType.CONTENT_DESCRIPTION), TITLE(ContentDescription.KEY_TITLE, false, ContainerType.CONTENT_DESCRIPTION), RATING(ContentDescription.KEY_RATING, false, ContainerType.CONTENT_DESCRIPTION), COPYRIGHT(ContentDescription.KEY_COPYRIGHT, false, ContainerType.CONTENT_DESCRIPTION), DESCRIPTION(ContentDescription.KEY_DESCRIPTION, false, ContainerType.CONTENT_DESCRIPTION), // Content Branding Object keys BANNER_IMAGE(ContentBranding.KEY_BANNER_IMAGE,false, ContainerType.CONTENT_BRANDING), BANNER_IMAGE_TYPE(ContentBranding.KEY_BANNER_TYPE,false, ContainerType.CONTENT_BRANDING), BANNER_IMAGE_URL(ContentBranding.KEY_BANNER_URL, false, ContainerType.CONTENT_BRANDING), COPYRIGHT_URL(ContentBranding.KEY_COPYRIGHT_URL, false, ContainerType.CONTENT_BRANDING), /* * keys are important because this is how values will be looked up by other applications */ ALBUM("WM/AlbumTitle", false), ALBUM_ARTIST("WM/AlbumArtist", true), ALBUM_ARTIST_SORT("WM/AlbumArtistSortOrder", false), ALBUM_SORT("WM/AlbumSortOrder", false), AMAZON_ID("ASIN", false), ARTIST_SORT("WM/ArtistSortOrder", false), BARCODE("WM/Barcode", false), BPM("WM/BeatsPerMinute", false), CATALOG_NO("WM/CatalogNo", false), CATEGORY("WM/Category", true), COMPOSER("WM/Composer", true), COMPOSER_SORT("WM/ComposerSort", false), CONDUCTOR("WM/Conductor", true), COVER_ART("WM/Picture", true), COVER_ART_URL("WM/AlbumCoverURL", true), CUSTOM1("CUSTOM1", true), CUSTOM2("CUSTOM2", true), CUSTOM3("CUSTOM3", true), CUSTOM4("CUSTOM4", true), CUSTOM5("CUSTOM5", true), DIRECTOR("WM/Director", true), DISC_NO("WM/PartOfSet", false), DISC_TOTAL("WM/DiscTotal", false), ENCODER("WM/ToolName", false), ENCODED_BY("WM/EncodedBy", false), FBPM("FBPM", true), GENRE("WM/Genre", true), GENRE_ID("WM/GenreID", true), GROUPING("WM/ContentGroupDescription", false), INITIAL_KEY("WM/InitialKey", false), IS_COMPILATION("WM/IsCompilation", false), ISRC("WM/ISRC", false), ISVBR("IsVBR", true), LANGUAGE("WM/Language", true), LYRICIST("WM/Writer", true), LYRICS("WM/Lyrics", false), LYRICS_SYNCHRONISED("WM/Lyrics_Synchronised", true), MEDIA("WM/Media", false), MOOD("WM/Mood", true), MUSICBRAINZ_ARTISTID("MusicBrainz/Artist Id", false), MUSICBRAINZ_DISC_ID("MusicBrainz/Disc Id", false), MUSICBRAINZ_RELEASE_COUNTRY("MusicBrainz/Album Release Country", false), MUSICBRAINZ_RELEASE_STATUS("MusicBrainz/Album Status", false), MUSICBRAINZ_RELEASE_TYPE("MusicBrainz/Album Type", false), MUSICBRAINZ_RELEASEARTISTID("MusicBrainz/Album Artist Id", false), MUSICBRAINZ_RELEASEID("MusicBrainz/Album Id", false), MUSICBRAINZ_RELEASEGROUPID("MusicBrainz/Release Group Id", false), MUSICBRAINZ_TRACK_ID("MusicBrainz/Track Id", false), MUSICBRAINZ_WORKID("MusicBrainz/Work Id", false), MUSICIP_ID("MusicIP/PUID", false), OCCASION("Occasion", true), ORIGINAL_ALBUM("WM/OriginalAlbumTitle", true), ORIGINAL_ARTIST("WM/OriginalArtist", true), ORIGINAL_LYRICIST("WM/OriginalLyricist", true), ORIGINAL_YEAR("WM/OriginalReleaseYear", true), PRODUCER("WM/Producer", false), QUALITY("Quality", true), MM_RATING("SDB/Rating", true), RECORD_LABEL("WM/Publisher", false), REMIXER("WM/ModifiedBy", false), SCRIPT("WM/Script", false), SUBTITLE("WM/SubTitle", false), TAGS("WM/Tags", false), TEMPO("Tempo", true), TITLE_SORT("WM/TitleSortOrder", false), TRACK("WM/TrackNumber", false), TRACK_TOTAL("WM/TrackTotal", false), URL_DISCOGS_ARTIST_SITE("WM/DiscogsArtistUrl", false), URL_DISCOGS_RELEASE_SITE("WM/DiscogsReleaseUrl", false), URL_OFFICIAL_ARTIST_SITE("WM/AuthorURL", false), URL_OFFICIAL_RELEASE_SITE("WM/OfficialReleaseUrl", false), URL_PROMOTIONAL_SITE("WM/PromotionURL", true), URL_WIKIPEDIA_ARTIST_SITE("WM/WikipediaArtistUrl", false), URL_WIKIPEDIA_RELEASE_SITE("WM/WikipediaReleaseUrl", false), URL_LYRICS_SITE("WM/LyricsUrl", false), YEAR("WM/Year", false), ENGINEER("WM/Engineer",false), DJMIXER("WM/DJMixer",false), MIXER("WM/Mixer",false), ARRANGER("WM/Arranger",false), // Special field for all unknown field names, which will getFields maximum support CUSTOM ("___CUSTOM___", true); /** * Stores the {@link AsfFieldKey#fieldName} to the field key. */ private final static Map FIELD_ID_MAP; static { FIELD_ID_MAP = new HashMap(AsfFieldKey.values().length); for (AsfFieldKey curr : AsfFieldKey.values()) { if (curr != CUSTOM) { assert !FIELD_ID_MAP.containsKey(curr.getFieldName()) : "duplicate field entry: "+curr.getFieldName(); FIELD_ID_MAP.put(curr.getFieldName(), curr); } } } /** * Searches for an ASF field key which represents the given id string.
* * @param fieldName the field name used for this key * @return the Enum that represents this field */ public static AsfFieldKey getAsfFieldKey(final String fieldName) { AsfFieldKey result = FIELD_ID_MAP.get(fieldName); if (result == null) { result = CUSTOM; } return result; } /** * Tests whether the field is enabled for multiple values.
* * @param fieldName field id to test. * @return true if ASF implementation supports multiple values for the field. */ public static boolean isMultiValued(final String fieldName) { final AsfFieldKey fieldKey = getAsfFieldKey(fieldName); return fieldKey != null && fieldKey.isMultiValued(); } /** * If set, the field has a standard id assigned. */ private final String fieldName; /** * If true, the field will be stored repeatedly if occurs so in tags. */ private final boolean multiValued; /** * The lowest possible container type, such a field can be stored into.
* Low means, container with least capabilities. */ private final ContainerType lowestContainer; /** * The highest possible container type, such a field can be stored into.
* High means, most capabilities, for example string length exceeds that of * the extended content description, it will be stored one level up (metadata library). */ private final ContainerType highestContainer; /** * Creates an instance
* Lowest/Highest will be {@link ContainerType#EXTENDED_CONTENT} / * {@link ContainerType#METADATA_LIBRARY_OBJECT} * * @param asfFieldName * standard field identifier. * @param multiValue * true if the this ASF field can have multiple * values. */ private AsfFieldKey(final String asfFieldName, final boolean multiValue) { this(asfFieldName, multiValue, ContainerType.EXTENDED_CONTENT, ContainerType.METADATA_LIBRARY_OBJECT); } /** * Creates an instance.
* * @param asfFieldName * standard field identifier. * @param multiValue * true if the this ASF field can have multiple * values. * @param restrictedTo * fields must be stored in this container. */ private AsfFieldKey(final String asfFieldName, final boolean multiValue, final ContainerType restrictedTo) { this(asfFieldName, multiValue, restrictedTo, restrictedTo); } /** * Creates an instance.
* * @param asfFieldName * standard field identifier. * @param multiValue * true if the this ASF field can have multiple * values. * @param lowest * fields must be stored at least in this container. * @param highest * fields aren't allowed to be stored in better containers than * this. */ private AsfFieldKey(final String asfFieldName, final boolean multiValue, final ContainerType lowest, final ContainerType highest) { this.fieldName = asfFieldName; assert !multiValue || highest.isMultiValued() : "Definition error"; this.multiValued = multiValue && highest.isMultiValued(); this.lowestContainer = lowest; this.highestContainer = highest; assert ContainerType.areInCorrectOrder(lowest, highest); } /** * Returns the standard field id. * * @return the standard field id. (may be null) */ public String getFieldName() { return this.fieldName; } /** * @return the highestContainer */ public ContainerType getHighestContainer() { return this.highestContainer; } /** * @return the lowestContainer */ public ContainerType getLowestContainer() { return this.lowestContainer; } /** * Returns true if this field can store multiple values. * * @return true if multiple values are supported for this field. */ public boolean isMultiValued() { return this.multiValued; } /** * {@inheritDoc} */ @Override public String toString() { return getFieldName(); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/asf/AsfTagBannerField.java0000644000175000017500000000336711277264361027156 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.asf; import org.jaudiotagger.audio.asf.data.ContentBranding; import org.jaudiotagger.audio.asf.data.ContainerType; import org.jaudiotagger.audio.asf.data.MetadataDescriptor; import org.jaudiotagger.tag.asf.AbstractAsfTagImageField; import org.jaudiotagger.tag.asf.AsfFieldKey; /** * This field represents the image content of the banner image which is stored * in the {@linkplain ContentBranding content branding} chunk of ASF files.
* * @author Christian Laireiter */ public class AsfTagBannerField extends AbstractAsfTagImageField { /** * Creates an instance with no image data.
*/ public AsfTagBannerField() { super(AsfFieldKey.BANNER_IMAGE); } /** * Creates an instance with given descriptor as image content.
* * @param descriptor * image content. */ public AsfTagBannerField(final MetadataDescriptor descriptor) { super(descriptor); assert descriptor.getName().equals( AsfFieldKey.BANNER_IMAGE.getFieldName()); } /** * Creates an instance with specified data as image content. * * @param imageData * image content. */ public AsfTagBannerField(final byte[] imageData) { super(new MetadataDescriptor(ContainerType.CONTENT_BRANDING, AsfFieldKey.BANNER_IMAGE.getFieldName(), MetadataDescriptor.TYPE_BINARY)); this.toWrap.setBinaryValue(imageData); } /** * {@inheritDoc} */ @Override public int getImageDataSize() { return this.toWrap.getRawDataSize(); } /** * {@inheritDoc} */ @Override public byte[] getRawImageData() { return getRawContent(); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/0000755000175000017500000000000011556363174022753 5ustar drazzibdrazziblibjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/ID3v22Frame.java0000644000175000017500000004411211470746136025502 0ustar drazzibdrazzib/* * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3; import org.jaudiotagger.audio.generic.Utils; import org.jaudiotagger.audio.mp3.MP3File; import org.jaudiotagger.tag.*; import org.jaudiotagger.tag.id3.framebody.AbstractID3v2FrameBody; import org.jaudiotagger.tag.id3.framebody.FrameBodyDeprecated; import org.jaudiotagger.tag.id3.framebody.FrameBodyUnsupported; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; import org.jaudiotagger.utils.EqualsUtil; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.math.BigInteger; import java.nio.ByteBuffer; import java.util.logging.Level; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * Represents an ID3v2.2 frame. * * @author : Paul Taylor * @author : Eric Farng * @version $Id: ID3v22Frame.java 929 2010-11-17 12:36:46Z paultaylor $ */ public class ID3v22Frame extends AbstractID3v2Frame { private static Pattern validFrameIdentifier = Pattern.compile("[A-Z][0-9A-Z]{2}"); protected static final int FRAME_ID_SIZE = 3; protected static final int FRAME_SIZE_SIZE = 3; protected static final int FRAME_HEADER_SIZE = FRAME_ID_SIZE + FRAME_SIZE_SIZE; public ID3v22Frame() { } protected int getFrameIdSize() { return FRAME_ID_SIZE; } protected int getFrameSizeSize() { return FRAME_SIZE_SIZE; } protected int getFrameHeaderSize() { return FRAME_HEADER_SIZE; } /** * Creates a new ID3v22 Frame with given body * * @param body New body and frame is based on this */ public ID3v22Frame(AbstractID3v2FrameBody body) { super(body); } /** * Compare for equality * To be deemed equal obj must be a IDv23Frame with the same identifier * and the same flags. * containing the same body,datatype list ectera. * equals() method is made up from all the various components * * @param obj * @return if true if this object is equivalent to obj */ public boolean equals(Object obj) { if ( this == obj ) return true; if (!(obj instanceof ID3v22Frame)) { return false; } ID3v22Frame that = (ID3v22Frame) obj; return EqualsUtil.areEqual(this.statusFlags, that.statusFlags) && EqualsUtil.areEqual(this.encodingFlags, that.encodingFlags) && super.equals(that); } /** * Creates a new ID3v22 Frame of type identifier. *

* An empty body of the correct type will be automatically created. This constructor should be used when wish to * create a new frame from scratch using user values * @param identifier */ @SuppressWarnings("unchecked") public ID3v22Frame(String identifier) { logger.info("Creating empty frame of type" + identifier); String bodyIdentifier = identifier; this.identifier = identifier; //If dealing with v22 identifier (Note this constructor is used by all three tag versions) if (ID3Tags.isID3v22FrameIdentifier(bodyIdentifier)) { //Does it have its own framebody (PIC,CRM) or are we using v23/v24 body (the normal case) if (ID3Tags.forceFrameID22To23(bodyIdentifier) != null) { //Do not convert } else if(bodyIdentifier.equals("CRM")) { //Do not convert. //TODO we don't have a way of converting this to v23 which is why its not in the ForceMap } //TODO Improve messy fix for datetime //TODO need to check in case v22 body does exist before using V23 body(e.g PIC) else if ((bodyIdentifier.equals(ID3v22Frames.FRAME_ID_V2_TYER)) || (bodyIdentifier.equals(ID3v22Frames.FRAME_ID_V2_TIME))) { bodyIdentifier = ID3v24Frames.FRAME_ID_YEAR; } // Have to check for v22 because most don't have own body they use v23 or v24 // body to hold the data, the frame is identified by its identifier, the body identifier // is just to create a body suitable for writing the data to else if (ID3Tags.isID3v22FrameIdentifier(bodyIdentifier)) { bodyIdentifier = ID3Tags.convertFrameID22To23(bodyIdentifier); } } // Use reflection to map id to frame body, which makes things much easier // to keep things up to date. try { Class c = (Class) Class.forName("org.jaudiotagger.tag.id3.framebody.FrameBody" + bodyIdentifier); frameBody = c.newInstance(); } catch (ClassNotFoundException cnfe) { logger.log(Level.SEVERE, cnfe.getMessage(), cnfe); frameBody = new FrameBodyUnsupported(identifier); } //Instantiate Interface/Abstract should not happen catch (InstantiationException ie) { logger.log(Level.SEVERE, ie.getMessage(), ie); throw new RuntimeException(ie); } //Private Constructor shouild not happen catch (IllegalAccessException iae) { logger.log(Level.SEVERE, iae.getMessage(), iae); throw new RuntimeException(iae); } frameBody.setHeader(this); logger.info("Created empty frame of type" + this.identifier + "with frame body of" + bodyIdentifier); } /** * Copy Constructor *

* Creates a new v22 frame based on another v22 frame * @param frame */ public ID3v22Frame(ID3v22Frame frame) { super(frame); logger.info("Creating frame from a frame of same version"); } private void createV22FrameFromV23Frame(ID3v23Frame frame) throws InvalidFrameException { identifier = ID3Tags.convertFrameID23To22(frame.getIdentifier()); if (identifier != null) { logger.info("V2:Orig id is:" + frame.getIdentifier() + ":New id is:" + identifier); this.frameBody = (AbstractID3v2FrameBody) ID3Tags.copyObject(frame.getBody()); } // Is it a known v3 frame which needs forcing to v2 frame e.g. APIC - PIC else if (ID3Tags.isID3v23FrameIdentifier(frame.getIdentifier())) { identifier = ID3Tags.forceFrameID23To22(frame.getIdentifier()); if (identifier != null) { logger.info("V2:Force:Orig id is:" + frame.getIdentifier() + ":New id is:" + identifier); this.frameBody = this.readBody(identifier, (AbstractID3v2FrameBody) frame.getBody()); } // No mechanism exists to convert it to a v22 frame else { throw new InvalidFrameException("Unable to convert v23 frame:" + frame.getIdentifier() + " to a v22 frame"); } } //Deprecated frame for v23 else if (frame.getBody() instanceof FrameBodyDeprecated) { //Was it valid for this tag version, if so try and reconstruct if (ID3Tags.isID3v22FrameIdentifier(frame.getIdentifier())) { this.frameBody = frame.getBody(); identifier = frame.getIdentifier(); logger.info("DEPRECATED:Orig id is:" + frame.getIdentifier() + ":New id is:" + identifier); } //or was it still deprecated, if so leave as is else { this.frameBody = new FrameBodyDeprecated((FrameBodyDeprecated) frame.getBody()); identifier = frame.getIdentifier(); logger.info("DEPRECATED:Orig id is:" + frame.getIdentifier() + ":New id is:" + identifier); } } // Unknown Frame e.g NCON else { this.frameBody = new FrameBodyUnsupported((FrameBodyUnsupported) frame.getBody()); identifier = frame.getIdentifier(); logger.info("v2:UNKNOWN:Orig id is:" + frame.getIdentifier() + ":New id is:" + identifier); } } /** * Creates a new ID3v22 Frame from another frame of a different tag version * * @param frame to construct the new frame from * @throws org.jaudiotagger.tag.InvalidFrameException */ public ID3v22Frame(AbstractID3v2Frame frame) throws InvalidFrameException { logger.info("Creating frame from a frame of a different version"); if (frame instanceof ID3v22Frame) { throw new UnsupportedOperationException("Copy Constructor not called. Please type cast the argument"); } // If it is a v24 frame is it possible to convert it into a v23 frame, anmd then convert from that if (frame instanceof ID3v24Frame) { ID3v23Frame v23Frame = new ID3v23Frame(frame); createV22FrameFromV23Frame(v23Frame); } //If it is a v23 frame is it possible to convert it into a v22 frame else if (frame instanceof ID3v23Frame) { createV22FrameFromV23Frame((ID3v23Frame) frame); } this.frameBody.setHeader(this); logger.info("Created frame from a frame of a different version"); } /** * Creates a new ID3v22Frame datatype by reading from byteBuffer. * * @param byteBuffer to read from * @param loggingFilename * @throws org.jaudiotagger.tag.InvalidFrameException */ public ID3v22Frame(ByteBuffer byteBuffer, String loggingFilename) throws InvalidFrameException, InvalidDataTypeException { setLoggingFilename(loggingFilename); read(byteBuffer); } /** * Creates a new ID3v23Frame datatype by reading from byteBuffer. * * @param byteBuffer to read from * @deprecated use {@link #ID3v22Frame(ByteBuffer,String)} instead * @throws org.jaudiotagger.tag.InvalidFrameException */ public ID3v22Frame(ByteBuffer byteBuffer) throws InvalidFrameException, InvalidDataTypeException { this(byteBuffer, ""); } /** * Return size of frame * * @return int size of frame */ public int getSize() { return frameBody.getSize() + getFrameHeaderSize(); } @Override protected boolean isPadding(byte[] buffer) { if( (buffer[0]=='\0')&& (buffer[1]=='\0')&& (buffer[2]=='\0') ) { return true; } return false; } /** * Read frame from file. * Read the frame header then delegate reading of data to frame body. * * @param byteBuffer */ public void read(ByteBuffer byteBuffer) throws InvalidFrameException, InvalidDataTypeException { String identifier = readIdentifier(byteBuffer); byte[] buffer = new byte[getFrameSizeSize()]; // Is this a valid identifier? if (!isValidID3v2FrameIdentifier(identifier)) { logger.info("Invalid identifier:" + identifier); byteBuffer.position(byteBuffer.position() - (getFrameIdSize() - 1)); throw new InvalidFrameIdentifierException(getLoggingFilename() + ":" + identifier + ":is not a valid ID3v2.20 frame"); } //Read Frame Size (same size as Frame Id so reuse buffer) byteBuffer.get(buffer, 0, getFrameSizeSize()); frameSize = decodeSize(buffer); if (frameSize < 0) { throw new InvalidFrameException(identifier + " has invalid size of:" + frameSize); } else if (frameSize == 0) { //We dont process this frame or add to framemap becuase contains no useful information logger.warning("Empty Frame:" + identifier); throw new EmptyFrameException(identifier + " is empty frame"); } else if (frameSize > byteBuffer.remaining()) { logger.warning("Invalid Frame size larger than size before mp3 audio:" + identifier); throw new InvalidFrameException(identifier + " is invalid frame"); } else { logger.fine("Frame Size Is:" + frameSize); //Convert v2.2 to v2.4 id just for reading the data String id = ID3Tags.convertFrameID22To24(identifier); if (id == null) { //OK,it may be convertable to a v.3 id even though not valid v.4 id = ID3Tags.convertFrameID22To23(identifier); if (id == null) { // Is it a valid v22 identifier so should be able to find a // frame body for it. if (ID3Tags.isID3v22FrameIdentifier(identifier)) { id = identifier; } // Unknown so will be created as FrameBodyUnsupported else { id = UNSUPPORTED_ID; } } } logger.fine("Identifier was:" + identifier + " reading using:" + id); //Create Buffer that only contains the body of this frame rather than the remainder of tag ByteBuffer frameBodyBuffer = byteBuffer.slice(); frameBodyBuffer.limit(frameSize); try { frameBody = readBody(id, frameBodyBuffer, frameSize); } finally { //Update position of main buffer, so no attempt is made to reread these bytes byteBuffer.position(byteBuffer.position() + frameSize); } } } /** * Read Frame Size, which has to be decoded * @param buffer * @return */ private int decodeSize(byte[] buffer) { BigInteger bi = new BigInteger(buffer); int tmpSize = bi.intValue(); if (tmpSize < 0) { logger.warning("Invalid Frame Size of:" + tmpSize + "Decoded from bin:" + Integer.toBinaryString(tmpSize) + "Decoded from hex:" + Integer.toHexString(tmpSize)); } return tmpSize; } /** * Write Frame raw data * * @throws IOException */ public void write(ByteArrayOutputStream tagBuffer) { logger.info("Write Frame to Buffer" + getIdentifier()); //This is where we will write header, move position to where we can //write body ByteBuffer headerBuffer = ByteBuffer.allocate(getFrameHeaderSize()); //Write Frame Body Data ByteArrayOutputStream bodyOutputStream = new ByteArrayOutputStream(); ((AbstractID3v2FrameBody) frameBody).write(bodyOutputStream); //Write Frame Header //Write Frame ID must adjust can only be 3 bytes long headerBuffer.put(Utils.getDefaultBytes(getIdentifier(), "ISO-8859-1"), 0, getFrameIdSize()); encodeSize(headerBuffer, frameBody.getSize()); //Add header to the Byte Array Output Stream try { tagBuffer.write(headerBuffer.array()); //Add body to the Byte Array Output Stream tagBuffer.write(bodyOutputStream.toByteArray()); } catch (IOException ioe) { //This could never happen coz not writing to file, so convert to RuntimeException throw new RuntimeException(ioe); } } /** * Write Frame Size (can now be accurately calculated, have to convert 4 byte int * to 3 byte format. * @param headerBuffer * @param size */ private void encodeSize(ByteBuffer headerBuffer, int size) { headerBuffer.put((byte) ((size & 0x00FF0000) >> 16)); headerBuffer.put((byte) ((size & 0x0000FF00) >> 8)); headerBuffer.put((byte) (size & 0x000000FF)); logger.fine("Frame Size Is Actual:" + size + ":Encoded bin:" + Integer.toBinaryString(size) + ":Encoded Hex" + Integer.toHexString(size)); } /** * Does the frame identifier meet the syntax for a idv3v2 frame identifier. * must start with a capital letter and only contain capital letters and numbers * * @param identifier * @return */ public boolean isValidID3v2FrameIdentifier(String identifier) { Matcher m = ID3v22Frame.validFrameIdentifier.matcher(identifier); return m.matches(); } /** * Return String Representation of body */ public void createStructure() { MP3File.getStructureFormatter().openHeadingElement(TYPE_FRAME, getIdentifier()); MP3File.getStructureFormatter().addElement(TYPE_FRAME_SIZE, frameSize); frameBody.createStructure(); MP3File.getStructureFormatter().closeHeadingElement(TYPE_FRAME); } /** * @return true if considered a common frame */ public boolean isCommon() { return ID3v22Frames.getInstanceOf().isCommon(getId()); } /** * @return true if considered a common frame */ public boolean isBinary() { return ID3v22Frames.getInstanceOf().isBinary(getId()); } /** * Sets the charset encoding used by the field. * * @param encoding charset. */ public void setEncoding(String encoding) { Integer encodingId = TextEncoding.getInstanceOf().getIdForValue(encoding); if(encoding!=null) { if(encodingId <2) { this.getBody().setTextEncoding(encodingId.byteValue()); } } } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/ID3SyncSafeInteger.java0000644000175000017500000000775111337531255027153 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3; import java.nio.ByteBuffer; /** * Peforms encoding/decoding of an syncsafe integer *

*

Syncsafe integers are used for the size in the tag header of v23 and v24 tags, and in the frame size in * the frame header of v24 frames. *

*

In some parts of the tag it is inconvenient to use the * unsychronisation scheme because the size of unsynchronised data is * not known in advance, which is particularly problematic with size * descriptors. The solution in ID3v2 is to use synchsafe integers, in * which there can never be any false synchs. Synchsafe integers are * integers that keep its highest bit (bit 7) zeroed, making seven bits * out of eight available. Thus a 32 bit synchsafe integer can store 28 * bits of information. *

* Example: *

* 255 (%11111111) encoded as a 16 bit synchsafe integer is 383 * (%00000001 01111111). */ public class ID3SyncSafeInteger { public static final int INTEGRAL_SIZE = 4; /** * Sizes equal or smaller than this are the same whether held as sync safe integer or normal integer so * it doesnt matter. */ public static final int MAX_SAFE_SIZE = 127; /** * Read syncsafe value from byteArray in format specified in spec and convert to int. * * @param buffer syncsafe integer * @return decoded int */ private static int bufferToValue(byte[] buffer) { //Note Need to && with 0xff otherwise if value is greater than 128 we get a negative number //when cast byte to int return ((buffer[0] & 0xff) << 21) + ((buffer[1] & 0xff) << 14) + ((buffer[2] & 0xff) << 7) + ((buffer[3]) & 0xff); } /** * Read syncsafe value from buffer in format specified in spec and convert to int. *

* The buffers position is moved to just after the location of the syncsafe integer * * @param buffer syncsafe integer * @return decoded int */ protected static int bufferToValue(ByteBuffer buffer) { byte byteBuffer[] = new byte[INTEGRAL_SIZE]; buffer.get(byteBuffer, 0, INTEGRAL_SIZE); return bufferToValue(byteBuffer); } /** * Is buffer holding a value that is definently not syncsafe *

* We cannot guarantee a buffer is holding a syncsafe integer but there are some checks * we can do to show that it definently is not. *

* The buffer is NOT moved after reading. *

* This function is useful for reading ID3v24 frames created in iTunes because iTunes does not use syncsafe * integers in its frames. * * @param buffer * @return true if this buffer is definently not holding a syncsafe integer */ protected static boolean isBufferNotSyncSafe(ByteBuffer buffer) { int position = buffer.position(); //Check Bit7 not set for (int i = 0; i < INTEGRAL_SIZE; i++) { byte nextByte = buffer.get(position + i); if ((nextByte & 0x80) > 0) { return true; } } return false; } /** * Checks if the buffer just contains zeros *

* This can be used to identify when accessing padding of a tag * * @param buffer * @return true if buffer only contains zeros */ protected static boolean isBufferEmpty(byte[] buffer) { for (byte aBuffer : buffer) { if (aBuffer != 0) { return false; } } return true; } /** * Convert int value to syncsafe value held in bytearray * * @param size * @return buffer syncsafe integer */ protected static byte[] valueToBuffer(int size) { byte[] buffer = new byte[4]; buffer[0] = (byte) ((size & 0x0FE00000) >> 21); buffer[1] = (byte) ((size & 0x001FC000) >> 14); buffer[2] = (byte) ((size & 0x00003F80) >> 7); buffer[3] = (byte) (size & 0x0000007F); return buffer; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/0000755000175000017500000000000011556363174024723 5ustar drazzibdrazziblibjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyTOPE.java0000644000175000017500000000513611470746136030131 0ustar drazzibdrazzib/* * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.id3.ID3v24Frames; import java.nio.ByteBuffer; /** * Original artist(s)/performer(s) Text information frame. *

The 'Original artist(s)/performer(s)' frame is intended for the performer(s) of the original recording, if for * example the music in the file should be a cover of a previously released song. The performers are separated with * the "/" character. *

*

For more details, please refer to the ID3 specifications: *

* * @author : Paul Taylor * @author : Eric Farng * @version $Id: FrameBodyTOPE.java 929 2010-11-17 12:36:46Z paultaylor $ */ public class FrameBodyTOPE extends AbstractFrameBodyTextInfo implements ID3v23FrameBody, ID3v24FrameBody { /** * Creates a new FrameBodyTOPE datatype. */ public FrameBodyTOPE() { } public FrameBodyTOPE(FrameBodyTOPE body) { super(body); } /** * Creates a new FrameBodyTOPE datatype. * * @param textEncoding * @param text */ public FrameBodyTOPE(byte textEncoding, String text) { super(textEncoding, text); } /** * Creates a new FrameBodyTOPE datatype. * * @param byteBuffer * @param frameSize * @throws InvalidTagException */ public FrameBodyTOPE(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_ORIGARTIST; } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyTSRC.java0000644000175000017500000000423511277006322030123 0ustar drazzibdrazzib/** * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: FrameBodyTSRC.java 832 2009-11-12 13:25:38Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Description: * */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.id3.ID3v24Frames; import java.nio.ByteBuffer; public class FrameBodyTSRC extends AbstractFrameBodyTextInfo implements ID3v24FrameBody, ID3v23FrameBody { /** * Creates a new FrameBodyTSRC datatype. */ public FrameBodyTSRC() { } public FrameBodyTSRC(FrameBodyTSRC body) { super(body); } /** * Creates a new FrameBodyTSRC datatype. * * @param textEncoding * @param text */ public FrameBodyTSRC(byte textEncoding, String text) { super(textEncoding, text); } /** * Creates a new FrameBodyTSRC datatype. * * @param byteBuffer * @param frameSize * @throws InvalidTagException */ public FrameBodyTSRC(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_ISRC; } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyTMCL.java0000644000175000017500000000423011277006322030102 0ustar drazzibdrazzib/** * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: FrameBodyTMCL.java 832 2009-11-12 13:25:38Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Description: * */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.id3.ID3v24Frames; import java.nio.ByteBuffer; public class FrameBodyTMCL extends AbstractFrameBodyTextInfo implements ID3v24FrameBody { /** * Creates a new FrameBodyTMCL datatype. */ public FrameBodyTMCL() { } public FrameBodyTMCL(FrameBodyTMCL body) { super(body); } /** * Creates a new FrameBodyTMCL datatype. * * @param textEncoding * @param text */ public FrameBodyTMCL(byte textEncoding, String text) { super(textEncoding, text); } /** * Creates a new FrameBodyTMCL datatype. * * @param byteBuffer * @param frameSize * @throws InvalidTagException */ public FrameBodyTMCL(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_MUSICIAN_CREDITS; } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyTRSO.java0000644000175000017500000000501611277006322030135 0ustar drazzibdrazzib/* * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.id3.ID3v24Frames; import java.nio.ByteBuffer; /** * Internet radio station owner Text information frame. *

The 'Internet radio station owner' frame contains the name of the owner of the internet radio station from which the audio is streamed. *

*

For more details, please refer to the ID3 specifications: *

* * @author : Paul Taylor * @author : Eric Farng * @version $Id: FrameBodyTRSO.java 832 2009-11-12 13:25:38Z paultaylor $ */ public class FrameBodyTRSO extends AbstractFrameBodyTextInfo implements ID3v23FrameBody, ID3v24FrameBody { /** * Creates a new FrameBodyTRSO datatype. */ public FrameBodyTRSO() { } public FrameBodyTRSO(FrameBodyTRSO body) { super(body); } /** * Creates a new FrameBodyTRSO datatype. * * @param textEncoding * @param text */ public FrameBodyTRSO(byte textEncoding, String text) { super(textEncoding, text); } /** * Creates a new FrameBodyTRSO datatype. * * @param byteBuffer * @param frameSize * @throws java.io.IOException * @throws InvalidTagException */ public FrameBodyTRSO(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_RADIO_OWNER; } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyTRCK.java0000644000175000017500000001152311470746136030122 0ustar drazzibdrazzib/* * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.datatype.DataTypes; import org.jaudiotagger.tag.datatype.NumberHashMap; import org.jaudiotagger.tag.datatype.PartOfSet; import org.jaudiotagger.tag.id3.ID3v24Frames; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; import java.nio.ByteBuffer; /** * Track number/position in set Text Information frame. * *

The 'Track number/Position in set' frame is a numeric string containing the order number of the audio-file on its original recording. * * This may be extended with a "/" character and a numeric string containing the total number of tracks/elements on the original recording. * e.g. "4/9". * * Some applications like to prepend the track number with a zero to aid sorting, (i.e 02 comes before 10) * *

*

For more details, please refer to the ID3 specifications: *

* * @author : Paul Taylor * @author : Eric Farng * @version $Id: FrameBodyTRCK.java 929 2010-11-17 12:36:46Z paultaylor $ */ public class FrameBodyTRCK extends AbstractID3v2FrameBody implements ID3v23FrameBody, ID3v24FrameBody { /** * Creates a new FrameBodyTRCK datatype. */ public FrameBodyTRCK() { setObjectValue(DataTypes.OBJ_TEXT_ENCODING, TextEncoding.ISO_8859_1); setObjectValue(DataTypes.OBJ_TEXT, new PartOfSet.PartOfSetValue()); } public FrameBodyTRCK(FrameBodyTRCK body) { super(body); } /** * Creates a new FrameBodyTRCK datatype, the value is parsed literally * * @param textEncoding * @param text */ public FrameBodyTRCK(byte textEncoding, String text) { setObjectValue(DataTypes.OBJ_TEXT_ENCODING, textEncoding); setObjectValue(DataTypes.OBJ_TEXT, new PartOfSet.PartOfSetValue(text)); } public FrameBodyTRCK(byte textEncoding, Integer trackNo,Integer trackTotal) { super(); setObjectValue(DataTypes.OBJ_TEXT_ENCODING, textEncoding); setObjectValue(DataTypes.OBJ_TEXT, new PartOfSet.PartOfSetValue(trackNo,trackTotal)); } public String getUserFriendlyValue() { return String.valueOf(getTrackNo()); } /** * Creates a new FrameBodyTRCK datatype. * * @param byteBuffer * @param frameSize * @throws java.io.IOException * @throws InvalidTagException */ public FrameBodyTRCK(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_TRACK; } public Integer getTrackNo() { PartOfSet.PartOfSetValue value = (PartOfSet.PartOfSetValue)getObjectValue(DataTypes.OBJ_TEXT); return value.getCount(); } public String getText() { return getObjectValue(DataTypes.OBJ_TEXT).toString(); } public void setTrackNo(Integer trackNo) { ((PartOfSet.PartOfSetValue)getObjectValue(DataTypes.OBJ_TEXT)).setCount(trackNo); } public void setTrackNo(String trackNo) { ((PartOfSet.PartOfSetValue)getObjectValue(DataTypes.OBJ_TEXT)).setCount(trackNo); } public Integer getTrackTotal() { return ((PartOfSet.PartOfSetValue)getObjectValue(DataTypes.OBJ_TEXT)).getTotal(); } public void setTrackTotal(Integer trackTotal) { ((PartOfSet.PartOfSetValue)getObjectValue(DataTypes.OBJ_TEXT)).setTotal(trackTotal); } public void setText(String text) { setObjectValue(DataTypes.OBJ_TEXT, new PartOfSet.PartOfSetValue(text)); } protected void setupObjectList() { objectList.add(new NumberHashMap(DataTypes.OBJ_TEXT_ENCODING, this, TextEncoding.TEXT_ENCODING_FIELD_SIZE)); objectList.add(new PartOfSet(DataTypes.OBJ_TEXT, this)); } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodySYTC.java0000644000175000017500000001100411277006322030122 0ustar drazzibdrazzib/* * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.datatype.ByteArraySizeTerminated; import org.jaudiotagger.tag.datatype.DataTypes; import org.jaudiotagger.tag.datatype.NumberHashMap; import org.jaudiotagger.tag.id3.ID3v24Frames; import org.jaudiotagger.tag.id3.valuepair.EventTimingTimestampTypes; import java.nio.ByteBuffer; /** * Synchronised tempo codes frame. *

*

* For a more accurate description of the tempo of a musical piece this * frame might be used. After the header follows one byte describing * which time stamp format should be used. Then follows one or more * tempo codes. Each tempo code consists of one tempo part and one time * part. The tempo is in BPM described with one or two bytes. If the * first byte has the value $FF, one more byte follows, which is added * to the first giving a range from 2 - 510 BPM, since $00 and $01 is * reserved. $00 is used to describe a beat-free time period, which is * not the same as a music-free time period. $01 is used to indicate one * single beat-stroke followed by a beat-free period. *

* The tempo descriptor is followed by a time stamp. Every time the * tempo in the music changes, a tempo descriptor may indicate this for * the player. All tempo descriptors should be sorted in chronological * order. The first beat-stroke in a time-period is at the same time as * the beat description occurs. There may only be one "SYTC" frame in * each tag. *

* * * *
<Header for 'Synchronised tempo codes', ID: "SYTC">
Time stamp format$xx
Tempo data <binary data>

* Where time stamp format is: *

* $01 Absolute time, 32 bit sized, using MPEG frames as unit
* $02 Absolute time, 32 bit sized, using milliseconds as unit *

* Abolute time means that every stamp contains the time from the * beginning of the file. *

*

*

For more details, please refer to the ID3 specifications: *

* * @author : Paul Taylor * @author : Eric Farng * @version $Id: FrameBodySYTC.java 832 2009-11-12 13:25:38Z paultaylor $ */ public class FrameBodySYTC extends AbstractID3v2FrameBody implements ID3v24FrameBody, ID3v23FrameBody { /** * Creates a new FrameBodySYTC datatype. */ public FrameBodySYTC() { } /** * @param timeStampFormat * @param tempo */ public FrameBodySYTC(int timeStampFormat, byte[] tempo) { setObjectValue(DataTypes.OBJ_TIME_STAMP_FORMAT, timeStampFormat); setObjectValue(DataTypes.OBJ_DATA, tempo); } /** * Creates a new FrameBody from buffer * * @param byteBuffer * @param frameSize * @throws InvalidTagException */ public FrameBodySYTC(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * Copy constructor * * @param body */ public FrameBodySYTC(FrameBodySYTC body) { super(body); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_SYNC_TEMPO; } protected void setupObjectList() { objectList.add(new NumberHashMap(DataTypes.OBJ_TIME_STAMP_FORMAT, this, EventTimingTimestampTypes.TIMESTAMP_KEY_FIELD_SIZE)); objectList.add(new ByteArraySizeTerminated(DataTypes.OBJ_DATA, this)); } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyXSOA.java0000644000175000017500000000253211277006322030120 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.id3.ID3v23Frames; import java.nio.ByteBuffer; /** * Album Sort name, this is what MusicBrainz uses in ID3v23 because TSOA not supported. *

* However iTunes uses TSOA even in ID3v23, so we have two possible options */ public class FrameBodyXSOA extends AbstractFrameBodyTextInfo implements ID3v23FrameBody { /** * Creates a new FrameBodyTSOT datatype. */ public FrameBodyXSOA() { } public FrameBodyXSOA(FrameBodyXSOA body) { super(body); } /** * Creates a new FrameBodyTSOT datatype. * * @param textEncoding * @param text */ public FrameBodyXSOA(byte textEncoding, String text) { super(textEncoding, text); } /** * Creates a new FrameBodyTSOT datatype. * * @param byteBuffer * @param frameSize * @throws InvalidTagException */ public FrameBodyXSOA(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v23Frames.FRAME_ID_V3_ALBUM_SORT_ORDER_MUSICBRAINZ; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyTMED.java0000644000175000017500000001604211277006322030100 0ustar drazzibdrazzib/* * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.id3.ID3v24Frames; import java.nio.ByteBuffer; /** * Length Text information frame. *

The 'Media type' frame describes from which media the sound * originated. This may be a text string or a reference to the * predefined media types found in the list below. References are made * within "(" and ")" and are optionally followed by a text refinement, * e.g. "(MC) with four channels". If a text refinement should begin * with a "(" character it should be replaced with "((" in the same way * as in the "TCO" frame. Predefined refinements is appended after the * media type, e.g. "(CD/A)" or "(VID/PAL/VHS)". *

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
DIG Other digital media
/A
 
Analog transfer from media
ANAOther analog media
/WACWax cylinder
/8CA
 
8-track tape cassette
CDCD
/AAnalog transfer from media
/DDDDD
/ADADD
/AA
 
AAD
LDLaserdisc
/A
 
Analog transfer from media
TTTurntable records
/3333.33 rpm
/4545 rpm
/7171.29 rpm
/7676.59 rpm
/7878.26 rpm
/80
 
80 rpm
MDMiniDisc
/A
 
Analog transfer from media
DATDAT
/AAnalog transfer from media
/1standard, 48 kHz/16 bits, linear
/2mode 2, 32 kHz/16 bits, linear
/3mode 3, 32 kHz/12 bits, nonlinear, low speed
/4mode 4, 32 kHz/12 bits, 4 channels
/5mode 5, 44.1 kHz/16 bits, linear
/6
 
mode 6, 44.1 kHz/16 bits, 'wide track' play
DCCDCC
/A
 
Analog transfer from media
DVDDVD
/A
 
Analog transfer from media
TVTelevision
/PALPAL
/NTSCNTSC
 /SECAM
 
SECAM
VIDVideo
/PALPAL
/NTSCNTSC
/SECAMSECAM
/VHSVHS
/SVHSS-VHS
/BETA
 
BETAMAX
RADRadio
/FMFM
/AMAM
/LWLW
/MW
 
MW
TELTelephone
/I
 
ISDN
MCMC (normal cassette)
/44.75 cm/s (normal speed for a two sided cassette)
/99.5 cm/s
/IType I cassette (ferric/normal)
/IIType II cassette (chrome)
/IIIType III cassette (ferric chrome)
/IV
 
Type IV cassette (metal)
REEReel
/99.5 cm/s
/1919 cm/s
/3838 cm/s
/7676 cm/s
/IType I cassette (ferric/normal)
/IIType II cassette (chrome)
/IIIType III cassette (ferric chrome)
/IV
 
Type IV cassette (metal)

*

*

For more details, please refer to the ID3 specifications: *

* * @author : Paul Taylor * @author : Eric Farng * @version $Id: FrameBodyTMED.java 832 2009-11-12 13:25:38Z paultaylor $ */ public class FrameBodyTMED extends AbstractFrameBodyTextInfo implements ID3v23FrameBody, ID3v24FrameBody { /** * Creates a new FrameBodyTMED datatype. */ public FrameBodyTMED() { } public FrameBodyTMED(FrameBodyTMED body) { super(body); } /** * Creates a new FrameBodyTMED datatype. * * @param textEncoding * @param text */ public FrameBodyTMED(byte textEncoding, String text) { super(textEncoding, text); } /** * Creates a new FrameBodyTMED datatype. * * @param byteBuffer * @param frameSize * @throws InvalidTagException */ public FrameBodyTMED(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_MEDIA_TYPE; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyTPE3.java0000644000175000017500000000465711277006322030073 0ustar drazzibdrazzib/* * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.id3.ID3v24Frames; import java.nio.ByteBuffer; /** * Conductor Text information frame. *

The 'Conductor' frame is used for the name of the conductor. *

*

For more details, please refer to the ID3 specifications: *

* * @author : Paul Taylor * @author : Eric Farng * @version $Id: FrameBodyTPE3.java 832 2009-11-12 13:25:38Z paultaylor $ */ public class FrameBodyTPE3 extends AbstractFrameBodyTextInfo implements ID3v24FrameBody, ID3v23FrameBody { /** * Creates a new FrameBodyTPE3 datatype. */ public FrameBodyTPE3() { } public FrameBodyTPE3(FrameBodyTPE3 body) { super(body); } /** * Creates a new FrameBodyTPE3 datatype. * * @param textEncoding * @param text */ public FrameBodyTPE3(byte textEncoding, String text) { super(textEncoding, text); } /** * Creates a new FrameBodyTPE3 datatype. * * @param byteBuffer * @param frameSize * @throws java.io.IOException * @throws InvalidTagException */ public FrameBodyTPE3(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_CONDUCTOR; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodySYLT.java0000644000175000017500000002162411277006322030144 0ustar drazzibdrazzib/* * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.datatype.*; import org.jaudiotagger.tag.id3.ID3v24Frames; import org.jaudiotagger.tag.id3.valuepair.EventTimingTimestampTypes; import org.jaudiotagger.tag.id3.valuepair.SynchronisedLyricsContentType; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; import org.jaudiotagger.tag.reference.Languages; import java.nio.ByteBuffer; /** * Synchronised lyrics/text frame. *

*

* This is another way of incorporating the words, said or sung lyrics, * in the audio file as text, this time, however, in sync with the * audio. It might also be used to describing events e.g. occurring on a * stage or on the screen in sync with the audio. The header includes a * content descriptor, represented with as terminated textstring. If no * descriptor is entered, 'Content descriptor' is $00 (00) only. *

* * * * * * *
<Header for 'Synchronised lyrics/text', ID: "SYLT">
Text encoding$xx
Language$xx xx xx
Time stamp format$xx
Content type$xx
Content descriptor<text string according to encoding> $00 (00)

*

* * *
Encoding:$00ISO-8859-1 character set is used => $00 is sync identifier.
$01Unicode character set is used => $00 00 is sync identifier.

*

* * * * * * * *
Content type:$00is other
$01is lyrics
$02is text transcription
$03is movement/part name (e.g. "Adagio")
$04is events (e.g. "Don Quijote enters the stage")
$05is chord (e.g. "Bb F Fsus")
$06is trivia/'pop up' information

*

* Time stamp format is: *

* $01 Absolute time, 32 bit sized, using MPEG frames as unit
* $02 Absolute time, 32 bit sized, using milliseconds as unit *

* Abolute time means that every stamp contains the time from the * beginning of the file. *

* The text that follows the frame header differs from that of the * unsynchronised lyrics/text transcription in one major way. Each * syllable (or whatever size of text is considered to be convenient by * the encoder) is a null terminated string followed by a time stamp * denoting where in the sound file it belongs. Each sync thus has the * following structure: *

* * * *
Terminated text to be synced (typically a syllable)
Sync identifier (terminator to above string)$00 (00)
Time stamp$xx (xx ...)

*

* The 'time stamp' is set to zero or the whole sync is omitted if * located directly at the beginning of the sound. All time stamps * should be sorted in chronological order. The sync can be considered * as a validator of the subsequent string. *

* Newline ($0A) characters are allowed in all "SYLT" frames and should * be used after every entry (name, event etc.) in a frame with the * content type $03 - $04. *

* A few considerations regarding whitespace characters: Whitespace * separating words should mark the beginning of a new word, thus * occurring in front of the first syllable of a new word. This is also * valid for new line characters. A syllable followed by a comma should * not be broken apart with a sync (both the syllable and the comma * should be before the sync). *

* An example: The "USLT" passage *

* "Strangers in the night" $0A "Exchanging glances" *

would be "SYLT" encoded as: *

* "Strang" $00 xx xx "ers" $00 xx xx " in" $00 xx xx " the" $00 xx xx * " night" $00 xx xx 0A "Ex" $00 xx xx "chang" $00 xx xx "ing" $00 xx * xx "glan" $00 xx xx "ces" $00 xx xx *

There may be more than one "SYLT" frame in each tag, but only one * with the same language and content descriptor.

*

*

For more details, please refer to the ID3 specifications: *

* * @author : Paul Taylor * @author : Eric Farng * @version $Id: FrameBodySYLT.java 832 2009-11-12 13:25:38Z paultaylor $ */ public class FrameBodySYLT extends AbstractID3v2FrameBody implements ID3v24FrameBody, ID3v23FrameBody { /** * Creates a new FrameBodySYLT datatype. */ public FrameBodySYLT() { } /** * Copy Constructor * * @param body */ public FrameBodySYLT(FrameBodySYLT body) { super(body); } /** * Creates a new FrameBodySYLT datatype. * * @param textEncoding * @param language * @param timeStampFormat * @param contentType * @param description * @param lyrics */ public FrameBodySYLT(int textEncoding, String language, int timeStampFormat, int contentType, String description, byte[] lyrics) { setObjectValue(DataTypes.OBJ_TEXT_ENCODING, textEncoding); setObjectValue(DataTypes.OBJ_LANGUAGE, language); setObjectValue(DataTypes.OBJ_TIME_STAMP_FORMAT, timeStampFormat); setObjectValue(DataTypes.OBJ_CONTENT_TYPE, contentType); setObjectValue(DataTypes.OBJ_DESCRIPTION, description); setObjectValue(DataTypes.OBJ_DATA, lyrics); } /** * Creates a new FrameBodySYLT datatype. * * @param byteBuffer * @param frameSize * @throws InvalidTagException if unable to create framebody from buffer */ public FrameBodySYLT(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * @return language code */ public String getLanguage() { return (String) getObjectValue(DataTypes.OBJ_LANGUAGE); } /** * @return timestamp format key */ public int getTimeStampFormat() { return ((Number) getObjectValue(DataTypes.OBJ_TIME_STAMP_FORMAT)).intValue(); } /** * @return content type key */ public int getContentType() { return ((Number) getObjectValue(DataTypes.OBJ_CONTENT_TYPE)).intValue(); } /** * @return description */ public String getDescription() { return (String) getObjectValue(DataTypes.OBJ_DESCRIPTION); } /** * @return frame identifier */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_SYNC_LYRIC; } /** * Set lyrics *

* TODO:provide a more user friendly way of adding lyrics * * @param data */ public void setLyrics(byte[] data) { this.setObjectValue(DataTypes.OBJ_DATA, data); } /** * Get lyrics *

* TODO:better format * * @return lyrics */ public byte[] getLyrics() { return (byte[]) this.getObjectValue(DataTypes.OBJ_DATA); } /** * Setup Object List */ protected void setupObjectList() { objectList.add(new NumberHashMap(DataTypes.OBJ_TEXT_ENCODING, this, TextEncoding.TEXT_ENCODING_FIELD_SIZE)); objectList.add(new StringHashMap(DataTypes.OBJ_LANGUAGE, this, Languages.LANGUAGE_FIELD_SIZE)); objectList.add(new NumberHashMap(DataTypes.OBJ_TIME_STAMP_FORMAT, this, EventTimingTimestampTypes.TIMESTAMP_KEY_FIELD_SIZE)); objectList.add(new NumberHashMap(DataTypes.OBJ_CONTENT_TYPE, this, SynchronisedLyricsContentType.CONTENT_KEY_FIELD_SIZE)); objectList.add(new StringNullTerminated(DataTypes.OBJ_DESCRIPTION, this)); //TODO:This hold the actual lyrics objectList.add(new ByteArraySizeTerminated(DataTypes.OBJ_DATA, this)); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyEncrypted.java0000644000175000017500000000501611470746136031314 0ustar drazzibdrazzib/* * Jthink Copyright (C)2010 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.datatype.ByteArraySizeTerminated; import org.jaudiotagger.tag.datatype.DataTypes; import org.jaudiotagger.tag.id3.ID3v23Frames; import java.nio.ByteBuffer; /** * Encrypted frame. *

*

* Container for an encrypted frame, we cannot decrypt encrypted frame but it may be possible * for the calling application to decrypt the frame if they understand how it has been encrypted, * information on this will be held within an ENCR frame * * @author : Paul Taylor */ public class FrameBodyEncrypted extends AbstractID3v2FrameBody implements ID3v24FrameBody, ID3v23FrameBody { private String identifier=null; /** * Creates a new FrameBodyEncrypted dataType. */ public FrameBodyEncrypted(String identifier) { this.identifier=identifier; } public FrameBodyEncrypted(FrameBodyEncrypted body) { super(body); } /** * Read from file * * @param identifier * @param byteBuffer * @param frameSize * @throws InvalidTagException */ public FrameBodyEncrypted(String identifier,ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); this.identifier=identifier; } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return identifier; } /** * TODO:proper mapping */ protected void setupObjectList() { objectList.add(new ByteArraySizeTerminated(DataTypes.OBJ_DATA, this)); } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyPCNT.java0000644000175000017500000000725511277006322030121 0ustar drazzibdrazzib/* * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.datatype.DataTypes; import org.jaudiotagger.tag.datatype.NumberVariableLength; import org.jaudiotagger.tag.id3.ID3v24Frames; import java.nio.ByteBuffer; /** * Play counter frame. *

*

* This is simply a counter of the number of times a file has been * played. The value is increased by one every time the file begins to * play. There may only be one "PCNT" frame in each tag. When the * counter reaches all one's, one byte is inserted in front of the * counter thus making the counter eight bits bigger. The counter must * be at least 32-bits long to begin with. *

* * *
<Header for 'Play counter', ID: "PCNT">
Counter $xx xx xx xx (xx ...)

*

*

For more details, please refer to the ID3 specifications: *

* * @author : Paul Taylor * @author : Eric Farng * @version $Id: FrameBodyPCNT.java 832 2009-11-12 13:25:38Z paultaylor $ */ public class FrameBodyPCNT extends AbstractID3v2FrameBody implements ID3v24FrameBody, ID3v23FrameBody { private static final int COUNTER_MINIMUM_FIELD_SIZE = 4; /** * Creates a new FrameBodyPCNT datatype. */ public FrameBodyPCNT() { this.setObjectValue(DataTypes.OBJ_NUMBER, 0L); } public FrameBodyPCNT(FrameBodyPCNT body) { super(body); } /** * Creates a new FrameBodyPCNT datatype. * * @param counter */ public FrameBodyPCNT(long counter) { this.setObjectValue(DataTypes.OBJ_NUMBER, counter); } /** * Creates a new FrameBodyPCNT datatype. * * @param byteBuffer * @param frameSize * @throws InvalidTagException if unable to create framebody from buffer */ public FrameBodyPCNT(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * @return the play count of this file */ public long getCounter() { return ((Number) getObjectValue(DataTypes.OBJ_NUMBER)).longValue(); } /** * Set the play counter of this file * * @param counter */ public void setCounter(long counter) { setObjectValue(DataTypes.OBJ_NUMBER, counter); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_PLAY_COUNTER; } /** * */ protected void setupObjectList() { objectList.add(new NumberVariableLength(DataTypes.OBJ_NUMBER, this, COUNTER_MINIMUM_FIELD_SIZE)); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyEQU2.java0000644000175000017500000000733511277006322030070 0ustar drazzibdrazzib/** * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: FrameBodyEQU2.java 832 2009-11-12 13:25:38Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Description: * */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.datatype.ByteArraySizeTerminated; import org.jaudiotagger.tag.datatype.DataTypes; import org.jaudiotagger.tag.id3.ID3v24Frames; import java.nio.ByteBuffer; /** * Equalisation (2) *

* This is another subjective, alignment frame. It allows the user to * predefine an equalisation curve within the audio file. There may be * more than one "EQU2" frame in each tag, but only one with the same * identification string. *

*

* Interpolation method $xx * Identification $00 *

* The 'interpolation method' describes which method is preferred when * an interpolation between the adjustment point that follows. The * following methods are currently defined: *

* $00 Band * No interpolation is made. A jump from one adjustment level to * another occurs in the middle between two adjustment points. * $01 Linear * Interpolation between adjustment points is linear. *

* The 'identification' string is used to identify the situation and/or * device where this adjustment should apply. The following is then * repeated for every adjustment point *

* Frequency $xx xx * Volume adjustment $xx xx *

* The frequency is stored in units of 1/2 Hz, giving it a range from 0 * to 32767 Hz. *

* The volume adjustment is encoded as a fixed point decibel value, 16 * bit signed integer representing (adjustment*512), giving +/- 64 dB * with a precision of 0.001953125 dB. E.g. +2 dB is stored as $04 00 * and -2 dB is $FC 00. *

* Adjustment points should be ordered by frequency and one frequency * should only be described once in the frame. */ public class FrameBodyEQU2 extends AbstractID3v2FrameBody implements ID3v24FrameBody { /** * Creates a new FrameBodyEQU2 datatype. */ public FrameBodyEQU2() { } public FrameBodyEQU2(FrameBodyEQU2 body) { super(body); } /** * Creates a new FrameBodyEQU2 datatype. * * @param byteBuffer * @param frameSize * @throws InvalidTagException if unable to create framebody from buffer */ public FrameBodyEQU2(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_EQUALISATION2; } /** * */ protected void setupObjectList() { objectList.add(new ByteArraySizeTerminated(DataTypes.OBJ_DATA, this)); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyWCOP.java0000644000175000017500000000472211277006322030121 0ustar drazzibdrazzib/* * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.id3.ID3v24Frames; import java.nio.ByteBuffer; /** * Copyright/Legal information URL link frames. *

The 'Copyright/Legal information' frame is a URL pointing at a webpage where the terms of use and ownership of the file is described. *

*

For more details, please refer to the ID3 specifications: *

* * @author : Paul Taylor * @author : Eric Farng * @version $Id: FrameBodyWCOP.java 832 2009-11-12 13:25:38Z paultaylor $ */ public class FrameBodyWCOP extends AbstractFrameBodyUrlLink implements ID3v24FrameBody, ID3v23FrameBody { /** * Creates a new FrameBodyWCOP datatype. */ public FrameBodyWCOP() { } /** * Creates a new FrameBodyWCOP datatype. * * @param urlLink */ public FrameBodyWCOP(String urlLink) { super(urlLink); } public FrameBodyWCOP(FrameBodyWCOP body) { super(body); } /** * Creates a new FrameBodyWCOP datatype. * * @param byteBuffer * @param frameSize * @throws java.io.IOException * @throws InvalidTagException */ public FrameBodyWCOP(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_URL_COPYRIGHT; } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/AbstractFrameBodyUrlLink.java0000644000175000017500000001225511470746136032426 0ustar drazzibdrazzib/** * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: AbstractFrameBodyUrlLink.java 929 2010-11-17 12:36:46Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.logging.ErrorMessage; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.datatype.DataTypes; import org.jaudiotagger.tag.datatype.StringSizeTerminated; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; import java.io.ByteArrayOutputStream; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.nio.ByteBuffer; import java.nio.charset.Charset; import java.nio.charset.CharsetEncoder; /** * Abstract super class of all URL Frames */ public abstract class AbstractFrameBodyUrlLink extends AbstractID3v2FrameBody { /** * Creates a new FrameBodyUrlLink datatype. */ protected AbstractFrameBodyUrlLink() { super(); } /** * Copy Constructor * @param body */ protected AbstractFrameBodyUrlLink(AbstractFrameBodyUrlLink body) { super(body); } /** * Creates a new FrameBodyUrlLink datatype., set up with data. * * @param urlLink */ public AbstractFrameBodyUrlLink(String urlLink) { setObjectValue(DataTypes.OBJ_URLLINK, urlLink); } /** * Creates a new FrameBodyUrlLink datatype. * * @param byteBuffer * @param frameSize * @throws InvalidTagException if unable to create framebody from buffer */ protected AbstractFrameBodyUrlLink(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } public String getUserFriendlyValue() { return getUrlLink(); } /** * Set URL Link * * @param urlLink */ public void setUrlLink(String urlLink) { if (urlLink == null) { throw new IllegalArgumentException(ErrorMessage.GENERAL_INVALID_NULL_ARGUMENT.getMsg()); } setObjectValue(DataTypes.OBJ_URLLINK, urlLink); } /** * Get URL Link * * @return the urllink */ public String getUrlLink() { return (String) getObjectValue(DataTypes.OBJ_URLLINK); } /** * If the description cannot be encoded using the current encoding change the encoder */ public void write(ByteArrayOutputStream tagBuffer) { CharsetEncoder encoder = Charset.forName(TextEncoding.CHARSET_ISO_8859_1).newEncoder(); String origUrl = getUrlLink(); if (!encoder.canEncode(origUrl)) { //ALL W Frames only support ISO-8859-1 for the url itself, if unable to encode let us assume //the link just needs url encoding setUrlLink(encodeURL(origUrl)); //We still cant convert so just set log error and set to blank to allow save to continue if (!encoder.canEncode(getUrlLink())) { logger.warning(ErrorMessage.MP3_UNABLE_TO_ENCODE_URL.getMsg(origUrl)); setUrlLink(""); } //it was ok, just note the modification made else { logger.warning(ErrorMessage.MP3_URL_SAVED_ENCODED.getMsg(origUrl, getUrlLink())); } } super.write(tagBuffer); } /** * */ protected void setupObjectList() { objectList.add(new StringSizeTerminated(DataTypes.OBJ_URLLINK, this)); } /** * Encode url because may receive url already encoded or not, but we can only store as ISO8859-1 * * @param url * @return */ private String encodeURL(String url) { try { final String[] splitURL = url.split("(?The 'Publisher' frame simply contains the name of the label or publisher. *

*

For more details, please refer to the ID3 specifications: *

* * @author : Paul Taylor * @author : Eric Farng * @version $Id: FrameBodyTPUB.java 832 2009-11-12 13:25:38Z paultaylor $ */ public class FrameBodyTPUB extends AbstractFrameBodyTextInfo implements ID3v23FrameBody, ID3v24FrameBody { /** * Creates a new FrameBodyTPUB datatype. */ public FrameBodyTPUB() { } public FrameBodyTPUB(FrameBodyTPUB body) { super(body); } /** * Creates a new FrameBodyTPUB datatype. * * @param textEncoding * @param text */ public FrameBodyTPUB(byte textEncoding, String text) { super(textEncoding, text); } /** * Creates a new FrameBodyTPUB datatype. * * @param byteBuffer * @param frameSize * @throws java.io.IOException * @throws InvalidTagException */ public FrameBodyTPUB(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_PUBLISHER; } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyWOAS.java0000644000175000017500000000466311470746136030137 0ustar drazzibdrazzib/* * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.id3.ID3v24Frames; import java.nio.ByteBuffer; /** * Official audio source webpage URL link frames. *

The 'Official audio source webpage' frame is a URL pointing at the official webpage for the source of the audio * file, e.g. a movie. *

*

For more details, please refer to the ID3 specifications: *

* * @author : Paul Taylor * @author : Eric Farng * @version $Id: FrameBodyWOAS.java 929 2010-11-17 12:36:46Z paultaylor $ */ public class FrameBodyWOAS extends AbstractFrameBodyUrlLink implements ID3v24FrameBody, ID3v23FrameBody { /** * Creates a new FrameBodyWOAS datatype. */ public FrameBodyWOAS() { } /** * Creates a new FrameBodyWOAS datatype. * * @param urlLink */ public FrameBodyWOAS(String urlLink) { super(urlLink); } public FrameBodyWOAS(FrameBodyWOAS body) { super(body); } /** * Creates a new FrameBodyWOAS datatype. * * @param byteBuffer * @param frameSize * @throws InvalidTagException */ public FrameBodyWOAS(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_URL_SOURCE_WEB; } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyLINK.java0000644000175000017500000001322511277006322030104 0ustar drazzibdrazzib/* * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.datatype.DataTypes; import org.jaudiotagger.tag.datatype.StringFixedLength; import org.jaudiotagger.tag.datatype.StringNullTerminated; import org.jaudiotagger.tag.datatype.StringSizeTerminated; import org.jaudiotagger.tag.id3.ID3v24Frames; import java.nio.ByteBuffer; /** * Linked information frame. *

*

* To keep space waste as low as possible this frame may be used to link * information from another ID3v2 tag that might reside in another audio * file or alone in a binary file. It is recommended that this method is * only used when the files are stored on a CD-ROM or other * circumstances when the risk of file seperation is low. The frame * contains a frame identifier, which is the frame that should be linked * into this tag, a URL field, where a reference to the file where * the frame is given, and additional ID data, if needed. Data should be * retrieved from the first tag found in the file to which this link * points. There may be more than one "LINK" frame in a tag, but only * one with the same contents. A linked frame is to be considered as * part of the tag and has the same restrictions as if it was a physical * part of the tag (i.e. only one "RVRB" frame allowed, whether it's * linked or not). *

* * * * *
<Header for 'Linked information', ID: "LINK">
Frame identifier $xx xx xx
URL <text string> $00
ID and additional data<text string(s)>

*

* Frames that may be linked and need no additional data are "IPLS", * "MCID", "ETCO", "MLLT", "SYTC", "RVAD", "EQUA", "RVRB", "RBUF", the * text information frames and the URL link frames. *

* The "TXXX", "APIC", "GEOB" and "AENC" frames may be linked with * the content descriptor as additional ID data. *

* The "COMM", "SYLT" and "USLT" frames may be linked with three bytes * of language descriptor directly followed by a content descriptor as * additional ID data. *

*

*

For more details, please refer to the ID3 specifications: *

* * @author : Paul Taylor * @author : Eric Farng * @version $Id: FrameBodyLINK.java 832 2009-11-12 13:25:38Z paultaylor $ */ public class FrameBodyLINK extends AbstractID3v2FrameBody implements ID3v24FrameBody, ID3v23FrameBody { /** * Creates a new FrameBodyLINK datatype. */ public FrameBodyLINK() { // this.setObject("Frame Identifier", ""); // this.setObject("URL", ""); // this.setObject("ID and Additional Data", ""); } public FrameBodyLINK(FrameBodyLINK body) { super(body); } /** * Creates a new FrameBodyLINK datatype. * * @param frameIdentifier * @param url * @param additionalData */ public FrameBodyLINK(String frameIdentifier, String url, String additionalData) { this.setObjectValue(DataTypes.OBJ_DESCRIPTION, frameIdentifier); this.setObjectValue(DataTypes.OBJ_URL, url); this.setObjectValue(DataTypes.OBJ_ID, additionalData); } /** * Creates a new FrameBodyLINK datatype. * * @param byteBuffer * @param frameSize * @throws InvalidTagException if unable to create framebody from buffer */ public FrameBodyLINK(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * @return */ public String getAdditionalData() { return (String) getObjectValue(DataTypes.OBJ_ID); } /** * @param additionalData */ public void getAdditionalData(String additionalData) { setObjectValue(DataTypes.OBJ_ID, additionalData); } /** * @return */ public String getFrameIdentifier() { return (String) getObjectValue(DataTypes.OBJ_DESCRIPTION); } /** * @param frameIdentifier */ public void getFrameIdentifier(String frameIdentifier) { setObjectValue(DataTypes.OBJ_DESCRIPTION, frameIdentifier); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_LINKED_INFO; } /** * */ protected void setupObjectList() { objectList.add(new StringFixedLength(DataTypes.OBJ_DESCRIPTION, this, 4)); objectList.add(new StringNullTerminated(DataTypes.OBJ_URL, this)); objectList.add(new StringSizeTerminated(DataTypes.OBJ_ID, this)); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/AbstractFrameBodyTextInfo.java0000644000175000017500000002013611470746136032603 0ustar drazzibdrazzib/** * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: AbstractFrameBodyTextInfo.java 929 2010-11-17 12:36:46Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Description: */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.logging.ErrorMessage; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.datatype.DataTypes; import org.jaudiotagger.tag.datatype.NumberHashMap; import org.jaudiotagger.tag.datatype.TextEncodedStringSizeTerminated; import org.jaudiotagger.tag.id3.ID3TextEncodingConversion; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; import java.io.ByteArrayOutputStream; import java.nio.ByteBuffer; /** * Abstract representation of a Text Frame *

* The text information frames are often the most important frames, containing information like artist, album and * more. There may only be one text information frame of its kind in an tag. In ID3v24 All text information frames * supports multiple strings, stored as a null separated list, where null is represented by the termination code * for the character encoding. All text frame identifiers begin with "T". Only text frame identifiers begin with "T", * with the exception of the "TXXX" frame. All the text information frames have the following format: *

* Text encoding $xx * Information *

* The list of valid text encodings increased from two in ID3v23 to four in ID3v24 *

* iTunes incorrectly writes null terminators at the end of every String, even though it only writes one String. *

* You can retrieve the first value without the null terminator using {@link #getFirstTextValue} */ public abstract class AbstractFrameBodyTextInfo extends AbstractID3v2FrameBody { /** * Creates a new FrameBodyTextInformation datatype. The super.super * Constructor sets up the Object list for the frame. */ protected AbstractFrameBodyTextInfo() { super(); setObjectValue(DataTypes.OBJ_TEXT_ENCODING, TextEncoding.ISO_8859_1); setObjectValue(DataTypes.OBJ_TEXT, ""); } /** * Copy Constructor * * @param body AbstractFrameBodyTextInformation */ protected AbstractFrameBodyTextInfo(AbstractFrameBodyTextInfo body) { super(body); } /** * Creates a new FrameBodyTextInformation data type. This is used when user * wants to create a new frame based on data in a user interface. * * @param textEncoding Specifies what encoding should be used to write * text to file. * @param text Specifies the text String. */ protected AbstractFrameBodyTextInfo(byte textEncoding, String text) { super(); setObjectValue(DataTypes.OBJ_TEXT_ENCODING, textEncoding); setObjectValue(DataTypes.OBJ_TEXT, text); } /** * Creates a new FrameBodyTextInformation data type from file. *

*

The super.super Constructor sets up the Object list for the frame. * * @param byteBuffer * @param frameSize * @throws InvalidTagException if unable to create framebody from buffer */ protected AbstractFrameBodyTextInfo(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * Set the Full Text String. *

*

If this String contains null terminator characters these are parsed as value * separators, allowing you to hold multiple strings within one text frame. This functionality is only * officially support in ID3v24. * * @param text to set */ public void setText(String text) { if (text == null) { throw new IllegalArgumentException(ErrorMessage.GENERAL_INVALID_NULL_ARGUMENT.getMsg()); } setObjectValue(DataTypes.OBJ_TEXT, text); } public String getUserFriendlyValue() { return getTextWithoutTrailingNulls(); } /** * Retrieve the complete text String as it is held internally. * * If multiple values are held these wil be returned, needless trailing nulls will also be returned * * @return the text string */ public String getText() { return (String) getObjectValue(DataTypes.OBJ_TEXT); } /** * Retrieve the complete text String but without any trailing nulls * * If multiple values are held these will be returned, needless trailing nulls will not be returned * * @return the text string */ public String getTextWithoutTrailingNulls() { TextEncodedStringSizeTerminated text = (TextEncodedStringSizeTerminated) getObject(DataTypes.OBJ_TEXT); return text.getValueWithoutTrailingNull(); } /** * Get first value * * @return value at index 0 */ public String getFirstTextValue() { TextEncodedStringSizeTerminated text = (TextEncodedStringSizeTerminated) getObject(DataTypes.OBJ_TEXT); return text.getValueAtIndex(0); } /** * Get text value at index * * When a multiple values are stored within a single text frame this method allows access to any of the * individual values. * * @param index * @return value at index */ public String getValueAtIndex(int index) { TextEncodedStringSizeTerminated text = (TextEncodedStringSizeTerminated) getObject(DataTypes.OBJ_TEXT); return text.getValueAtIndex(index); } /** * Add additional value to value * * @param value at index */ public void addTextValue(String value) { TextEncodedStringSizeTerminated text = (TextEncodedStringSizeTerminated) getObject(DataTypes.OBJ_TEXT); text.addValue(value); } /** * @return number of text values, usually one */ public int getNumberOfValues() { TextEncodedStringSizeTerminated text = (TextEncodedStringSizeTerminated) getObject(DataTypes.OBJ_TEXT); return text.getNumberOfValues(); } /** * Because Text frames have a text encoding we need to check the text * String does not contain characters that cannot be encoded in * current encoding before we write data. If there are change the text * encoding. */ public void write(ByteArrayOutputStream tagBuffer) { //Ensure valid for type setTextEncoding(ID3TextEncodingConversion.getTextEncoding(getHeader(), getTextEncoding())); //Ensure valid for data if (!((TextEncodedStringSizeTerminated) getObject(DataTypes.OBJ_TEXT)).canBeEncoded()) { this.setTextEncoding(ID3TextEncodingConversion.getUnicodeTextEncoding(getHeader())); } super.write(tagBuffer); } /** * Setup the Object List. All text frames contain a text encoding * and then a text string. *

* TODO:would like to make final but cannot because overridden by FrameBodyTXXX */ protected void setupObjectList() { objectList.add(new NumberHashMap(DataTypes.OBJ_TEXT_ENCODING, this, TextEncoding.TEXT_ENCODING_FIELD_SIZE)); objectList.add(new TextEncodedStringSizeTerminated(DataTypes.OBJ_TEXT, this)); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyRBUF.java0000644000175000017500000000660711277006322030113 0ustar drazzibdrazzib/** * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: FrameBodyRBUF.java 832 2009-11-12 13:25:38Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Description: * */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.datatype.BooleanByte; import org.jaudiotagger.tag.datatype.DataTypes; import org.jaudiotagger.tag.datatype.NumberFixedLength; import org.jaudiotagger.tag.id3.ID3v24Frames; import java.nio.ByteBuffer; /** * Body of Recommended buffer size frame, generally used for streaming audio */ public class FrameBodyRBUF extends AbstractID3v2FrameBody implements ID3v24FrameBody, ID3v23FrameBody { private static int BUFFER_FIELD_SIZE = 3; private static int EMBED_FLAG_BIT_POSITION = 1; private static int OFFSET_FIELD_SIZE = 4; /** * Creates a new FrameBodyRBUF datatype. */ public FrameBodyRBUF() { this.setObjectValue(DataTypes.OBJ_BUFFER_SIZE, (byte) 0); this.setObjectValue(DataTypes.OBJ_EMBED_FLAG, Boolean.FALSE); this.setObjectValue(DataTypes.OBJ_OFFSET, (byte) 0); } public FrameBodyRBUF(FrameBodyRBUF body) { super(body); } /** * Creates a new FrameBodyRBUF datatype. * * @param bufferSize * @param embeddedInfoFlag * @param offsetToNextTag */ public FrameBodyRBUF(byte bufferSize, boolean embeddedInfoFlag, byte offsetToNextTag) { this.setObjectValue(DataTypes.OBJ_BUFFER_SIZE, bufferSize); this.setObjectValue(DataTypes.OBJ_EMBED_FLAG, embeddedInfoFlag); this.setObjectValue(DataTypes.OBJ_OFFSET, offsetToNextTag); } /** * Creates a new FrameBodyRBUF datatype. * * @param byteBuffer * @param frameSize * @throws InvalidTagException if unable to create framebody from buffer */ public FrameBodyRBUF(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_RECOMMENDED_BUFFER_SIZE; } /** * */ protected void setupObjectList() { objectList.add(new NumberFixedLength(DataTypes.OBJ_BUFFER_SIZE, this, BUFFER_FIELD_SIZE)); objectList.add(new BooleanByte(DataTypes.OBJ_EMBED_FLAG, this, (byte) EMBED_FLAG_BIT_POSITION)); objectList.add(new NumberFixedLength(DataTypes.OBJ_OFFSET, this, OFFSET_FIELD_SIZE)); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyTDLY.java0000644000175000017500000000517611277006322030131 0ustar drazzibdrazzib/* * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.id3.ID3v24Frames; import java.nio.ByteBuffer; /** * Playlist delay Text information frame. *

The 'Playlist delay' defines the numbers of milliseconds of silence between every song in a playlist. The player should use the "ETC" frame, if present, to skip initial silence and silence at the end of the audio to match the 'Playlist delay' time. The time is represented as a numeric string. *

*

For more details, please refer to the ID3 specifications: *

* * @author : Paul Taylor * @author : Eric Farng * @version $Id: FrameBodyTDLY.java 832 2009-11-12 13:25:38Z paultaylor $ */ public class FrameBodyTDLY extends AbstractFrameBodyTextInfo implements ID3v24FrameBody, ID3v23FrameBody { /** * Creates a new FrameBodyTDLY datatype. */ public FrameBodyTDLY() { } public FrameBodyTDLY(FrameBodyTDLY body) { super(body); } /** * Creates a new FrameBodyTDLY datatype. * * @param textEncoding * @param text */ public FrameBodyTDLY(byte textEncoding, String text) { super(textEncoding, text); } /** * Creates a new FrameBodyTDLY datatype. * * @param byteBuffer * @param frameSize * @throws InvalidTagException */ public FrameBodyTDLY(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_PLAYLIST_DELAY; } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyTSOC.java0000644000175000017500000000233611277006322030120 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.id3.ID3v24Frames; import java.nio.ByteBuffer; /** * Composer Sort name (iTunes Only) */ public class FrameBodyTSOC extends AbstractFrameBodyTextInfo implements ID3v24FrameBody, ID3v23FrameBody { /** * Creates a new FrameBodyTSOC datatype. */ public FrameBodyTSOC() { } public FrameBodyTSOC(FrameBodyTSOC body) { super(body); } /** * Creates a new FrameBodyTSOA datatype. * * @param textEncoding * @param text */ public FrameBodyTSOC(byte textEncoding, String text) { super(textEncoding, text); } /** * Creates a new FrameBodyTSOA datatype. * * @param byteBuffer * @param frameSize * @throws InvalidTagException */ public FrameBodyTSOC(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_COMPOSER_SORT_ORDER_ITUNES; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyUFID.java0000644000175000017500000000775411277006322030110 0ustar drazzibdrazzib/** * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: FrameBodyUFID.java 832 2009-11-12 13:25:38Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Description: * Represents a Unique File ID for the file which relates * to an external database. * */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.datatype.ByteArraySizeTerminated; import org.jaudiotagger.tag.datatype.DataTypes; import org.jaudiotagger.tag.datatype.StringNullTerminated; import org.jaudiotagger.tag.id3.ID3v24Frames; import java.nio.ByteBuffer; /** * A UFID Framebody consists of an owner that identifies the server hosting the * unique identifier database, and the unique identifier itself which can be up to 64 * bytes in length. */ public class FrameBodyUFID extends AbstractID3v2FrameBody implements ID3v24FrameBody, ID3v23FrameBody { public static final String UFID_MUSICBRAINZ = "http://musicbrainz.org"; public static final String UFID_ID3TEST = "http://www.id3.org/dummy/ufid.html"; /** * Creates a new FrameBodyUFID datatype. */ public FrameBodyUFID() { setOwner(""); setUniqueIdentifier(new byte[0]); } public FrameBodyUFID(FrameBodyUFID body) { super(body); } /** * Creates a new FrameBodyUFID datatype. * * @param owner url of the database * @param uniqueIdentifier unique identifier */ public FrameBodyUFID(String owner, byte[] uniqueIdentifier) { setOwner(owner); setUniqueIdentifier(uniqueIdentifier); } /** * Creates FrameBodyUFID datatype from buffer * * @param byteBuffer * @param frameSize * @throws InvalidTagException */ public FrameBodyUFID(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_UNIQUE_FILE_ID; } /** * Set the owner of url of the the database that this ufid is stored in * * @param owner should be a valid url */ public void setOwner(String owner) { setObjectValue(DataTypes.OBJ_OWNER, owner); } /** * @return the url of the the database that this ufid is stored in */ public String getOwner() { return (String) getObjectValue(DataTypes.OBJ_OWNER); } /** * Set the unique identifier (within the owners domain) * * @param uniqueIdentifier */ public void setUniqueIdentifier(byte[] uniqueIdentifier) { setObjectValue(DataTypes.OBJ_DATA, uniqueIdentifier); } /** * @return the unique identifier (within the owners domain) */ public byte[] getUniqueIdentifier() { return (byte[]) getObjectValue(DataTypes.OBJ_DATA); } protected void setupObjectList() { objectList.add(new StringNullTerminated(DataTypes.OBJ_OWNER, this)); objectList.add(new ByteArraySizeTerminated(DataTypes.OBJ_DATA, this)); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyTENC.java0000644000175000017500000000507411470746136030114 0ustar drazzibdrazzib/* * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.id3.ID3v24Frames; import java.nio.ByteBuffer; /** * Encoded by Text information frame. *

The 'Encoded by' frame contains the name of the person or organisation that encoded the audio file. * This field may contain a copyright message, if the audio file also is copyrighted by the encoder. *

*

For more details, please refer to the ID3 specifications: *

* * @author : Paul Taylor * @author : Eric Farng * @version $Id: FrameBodyTENC.java 929 2010-11-17 12:36:46Z paultaylor $ */ public class FrameBodyTENC extends AbstractFrameBodyTextInfo implements ID3v24FrameBody, ID3v23FrameBody { /** * Creates a new FrameBodyTENC dataType. */ public FrameBodyTENC() { } public FrameBodyTENC(FrameBodyTENC body) { super(body); } /** * Creates a new FrameBodyTENC dataType. * * @param textEncoding * @param text */ public FrameBodyTENC(byte textEncoding, String text) { super(textEncoding, text); } /** * Creates a new FrameBodyTENC dataType. * * @param byteBuffer * @param frameSize * @throws java.io.IOException * @throws InvalidTagException */ public FrameBodyTENC(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_ENCODEDBY; } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyTOFN.java0000644000175000017500000000502011277006322030107 0ustar drazzibdrazzib/* * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.id3.ID3v24Frames; import java.nio.ByteBuffer; /** * Original filename Text information frame. *

The 'Original filename' frame contains the preferred filename for the file, since some media doesn't allow the desired length of the filename. The filename is case sensitive and includes its suffix. *

*

For more details, please refer to the ID3 specifications: *

* * @author : Paul Taylor * @author : Eric Farng * @version $Id: FrameBodyTOFN.java 832 2009-11-12 13:25:38Z paultaylor $ */ public class FrameBodyTOFN extends AbstractFrameBodyTextInfo implements ID3v23FrameBody { /** * Creates a new FrameBodyTOFN datatype. */ public FrameBodyTOFN() { } public FrameBodyTOFN(FrameBodyTOFN body) { super(body); } /** * Creates a new FrameBodyTOFN datatype. * * @param textEncoding * @param text */ public FrameBodyTOFN(byte textEncoding, String text) { super(textEncoding, text); } /** * Creates a new FrameBodyTOFN datatype. * * @param byteBuffer * @param frameSize * @throws InvalidTagException */ public FrameBodyTOFN(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_ORIG_FILENAME; } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyENCR.java0000644000175000017500000001154211305717447030107 0ustar drazzibdrazzib/* * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.datatype.ByteArraySizeTerminated; import org.jaudiotagger.tag.datatype.DataTypes; import org.jaudiotagger.tag.datatype.NumberFixedLength; import org.jaudiotagger.tag.datatype.StringNullTerminated; import org.jaudiotagger.tag.id3.ID3v24Frames; import java.nio.ByteBuffer; /** * Encryption method registration frame. *

*

* To identify with which method a frame has been encrypted the * encryption method must be registered in the tag with this frame. The * 'Owner identifier' is a null-terminated string with a URL * containing an email address, or a link to a location where an email * address can be found, that belongs to the organisation responsible * for this specific encryption method. Questions regarding the * encryption method should be sent to the indicated email address. The * 'Method symbol' contains a value that is associated with this method * throughout the whole tag. Values below $80 are reserved. The 'Method * symbol' may optionally be followed by encryption specific data. There * may be several "ENCR" frames in a tag but only one containing the * same symbol and only one containing the same owner identifier. The * method must be used somewhere in the tag. See section 3.3.1, flag j * for more information. *

* * * * *
<Header for 'Encryption method registration', ID: "ENCR">
Owner identifier<text string> $00
Method symbol $xx
Encryption data <binary data>

*

*

For more details, please refer to the ID3 specifications: *

* * @author : Paul Taylor * @author : Eric Farng * @version $Id: FrameBodyENCR.java 857 2009-12-03 11:21:11Z paultaylor $ */ public class FrameBodyENCR extends AbstractID3v2FrameBody implements ID3v24FrameBody, ID3v23FrameBody { /** * Creates a new FrameBodyENCR datatype. */ public FrameBodyENCR() { this.setObjectValue(DataTypes.OBJ_OWNER, ""); this.setObjectValue(DataTypes.OBJ_METHOD_SYMBOL, (byte) 0); this.setObjectValue(DataTypes.OBJ_ENCRYPTION_INFO, new byte[0]); } public FrameBodyENCR(FrameBodyENCR body) { super(body); } /** * Creates a new FrameBodyENCR datatype. * * @param owner * @param methodSymbol * @param data */ public FrameBodyENCR(String owner, byte methodSymbol, byte[] data) { this.setObjectValue(DataTypes.OBJ_OWNER, owner); this.setObjectValue(DataTypes.OBJ_METHOD_SYMBOL, methodSymbol); this.setObjectValue(DataTypes.OBJ_ENCRYPTION_INFO, data); } /** * Creates a new FrameBodyENCR datatype. * * @param byteBuffer * @param frameSize * @throws InvalidTagException if unable to create framebody from buffer */ public FrameBodyENCR(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_ENCRYPTION; } /** * @param owner */ public void setOwner(String owner) { setObjectValue(DataTypes.OBJ_OWNER, owner); } /** * @return */ public String getOwner() { return (String) getObjectValue(DataTypes.OBJ_OWNER); } /** * */ protected void setupObjectList() { objectList.add(new StringNullTerminated(DataTypes.OBJ_OWNER, this)); objectList.add(new NumberFixedLength(DataTypes.OBJ_METHOD_SYMBOL, this, 1)); objectList.add(new ByteArraySizeTerminated(DataTypes.OBJ_ENCRYPTION_INFO, this)); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyTCON.java0000644000175000017500000000763511277006322030122 0ustar drazzibdrazzib/* * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.id3.ID3v24Frames; import java.nio.ByteBuffer; /** * Content type Text information frame. *

*

The 'Content type', which previously was * stored as a one byte numeric value only, is now a numeric string. You * may use one or several of the types as ID3v1.1 did or, since the * category list would be impossible to maintain with accurate and up to * date categories, define your own. *

* ID3V23:References to the ID3v1 genres can be made by, as first byte, enter * "(" followed by a number from the genres list (appendix A) and * ended with a ")" character. This is optionally followed by a * refinement, e.g. "(21)" or "(4)Eurodisco". Several references can be * made in the same frame, e.g. "(51)(39)". If the refinement should * begin with a "(" character it should be replaced with "((", e.g. "((I * can figure out any genre)" or "(55)((I think...)". The following new * content types is defined in ID3v2 and is implemented in the same way * as the numeric content types, e.g. "(RX)". *

* * *
RXRemix
CRCover

*

*

For more details, please refer to the ID3 specifications: *

*

* ID3V24:The 'Content type', which ID3v1 was stored as a one byte numeric * value only, is now a string. You may use one or several of the ID3v1 * types as numerical strings, or, since the category list would be * impossible to maintain with accurate and up to date categories, * define your own. Example: "21" $00 "Eurodisco" $00 *

* You may also use any of the following keywords: *

* * *
RXRemix
CRCover

* * @author : Paul Taylor * @author : Eric Farng * @version $Id: FrameBodyTCON.java 832 2009-11-12 13:25:38Z paultaylor $ */ public class FrameBodyTCON extends AbstractFrameBodyTextInfo implements ID3v24FrameBody, ID3v23FrameBody { /** * Creates a new FrameBodyTCON datatype. */ public FrameBodyTCON() { } public FrameBodyTCON(FrameBodyTCON body) { super(body); } /** * Creates a new FrameBodyTCON datatype. * * @param textEncoding * @param text */ public FrameBodyTCON(byte textEncoding, String text) { super(textEncoding, text); } /** * Creates a new FrameBodyTCON datatype. * * @param byteBuffer * @param frameSize * @throws InvalidTagException */ public FrameBodyTCON(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_GENRE; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyPOSS.java0000644000175000017500000001005611330335337030133 0ustar drazzibdrazzib/* * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.datatype.DataTypes; import org.jaudiotagger.tag.datatype.NumberHashMap; import org.jaudiotagger.tag.datatype.NumberVariableLength; import org.jaudiotagger.tag.id3.ID3v24Frames; import org.jaudiotagger.tag.id3.valuepair.EventTimingTimestampTypes; import java.nio.ByteBuffer; /** * Position synchronisation frame. *

*

* This frame delivers information to the listener of how far into the * audio stream he picked up; in effect, it states the time offset of * the first frame in the stream. The frame layout is: *

* * * *
<Head for 'Position synchronisation', ID: "POSS">
Time stamp format $xx
Position $xx (xx ...)

*

* Where time stamp format is: *

* $01 Absolute time, 32 bit sized, using MPEG frames as unit
* $02 Absolute time, 32 bit sized, using milliseconds as unit *

* and position is where in the audio the listener starts to receive, * i.e. the beginning of the next frame. If this frame is used in the * beginning of a file the value is always 0. There may only be one * "POSS" frame in each tag. *

*

*

For more details, please refer to the ID3 specifications: *

* * @author : Paul Taylor * @author : Eric Farng * @version $Id: FrameBodyPOSS.java 867 2010-01-28 16:27:11Z paultaylor $ */ public class FrameBodyPOSS extends AbstractID3v2FrameBody implements ID3v24FrameBody, ID3v23FrameBody { /** * Creates a new FrameBodyPOSS datatype. */ public FrameBodyPOSS() { // this.setObject(ObjectNumberHashMap.OBJ_TIME_STAMP_FORMAT, new Byte((byte) 0)); // this.setObject("Position", new Long(0)); } public FrameBodyPOSS(FrameBodyPOSS body) { super(body); } /** * Creates a new FrameBodyPOSS datatype. * * @param timeStampFormat * @param position */ public FrameBodyPOSS(byte timeStampFormat, long position) { this.setObjectValue(DataTypes.OBJ_TIME_STAMP_FORMAT, timeStampFormat); this.setObjectValue(DataTypes.OBJ_POSITION, position); } /** * Creates a new FrameBodyPOSS datatype. * * @param byteBuffer * @param frameSize * @throws InvalidTagException if unable to create framebody from buffer */ public FrameBodyPOSS(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_POSITION_SYNC; } /** * */ protected void setupObjectList() { objectList.add(new NumberHashMap(DataTypes.OBJ_TIME_STAMP_FORMAT, this, EventTimingTimestampTypes.TIMESTAMP_KEY_FIELD_SIZE)); objectList.add(new NumberVariableLength(DataTypes.OBJ_POSITION, this, 1)); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodySIGN.java0000644000175000017500000000707311277006322030113 0ustar drazzibdrazzib/** * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: FrameBodySIGN.java 832 2009-11-12 13:25:38Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Description: * */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.datatype.ByteArraySizeTerminated; import org.jaudiotagger.tag.datatype.DataTypes; import org.jaudiotagger.tag.datatype.NumberFixedLength; import org.jaudiotagger.tag.id3.ID3v24Frames; import java.nio.ByteBuffer; public class FrameBodySIGN extends AbstractID3v2FrameBody implements ID3v24FrameBody { /** * Creates a new FrameBodySIGN datatype. */ public FrameBodySIGN() { // this.setObject("Group Symbol", new Byte((byte) 0)); // this.setObject("Signature", new byte[0]); } public FrameBodySIGN(FrameBodySIGN body) { super(body); } /** * Creates a new FrameBodySIGN datatype. * * @param groupSymbol * @param signature */ public FrameBodySIGN(byte groupSymbol, byte[] signature) { this.setObjectValue(DataTypes.OBJ_GROUP_SYMBOL, groupSymbol); this.setObjectValue(DataTypes.OBJ_SIGNATURE, signature); } /** * Creates a new FrameBodySIGN datatype. * * @param byteBuffer * @param frameSize * @throws InvalidTagException if unable to create framebody from buffer */ public FrameBodySIGN(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * @param groupSymbol */ public void setGroupSymbol(byte groupSymbol) { setObjectValue(DataTypes.OBJ_GROUP_SYMBOL, groupSymbol); } /** * @return */ public byte getGroupSymbol() { if (getObjectValue(DataTypes.OBJ_GROUP_SYMBOL) != null) { return (Byte) getObjectValue(DataTypes.OBJ_GROUP_SYMBOL); } else { return (byte) 0; } } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_SIGNATURE; } /** * @param signature */ public void setSignature(byte[] signature) { setObjectValue(DataTypes.OBJ_SIGNATURE, signature); } /** * @return */ public byte[] getSignature() { return (byte[]) getObjectValue(DataTypes.OBJ_SIGNATURE); } /** * */ protected void setupObjectList() { objectList.add(new NumberFixedLength(DataTypes.OBJ_GROUP_SYMBOL, this, 1)); objectList.add(new ByteArraySizeTerminated(DataTypes.OBJ_SIGNATURE, this)); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyCRM.java0000644000175000017500000001151711277006322027772 0ustar drazzibdrazzib/** * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: FrameBodyCRM.java 832 2009-11-12 13:25:38Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Description: * */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.datatype.ByteArraySizeTerminated; import org.jaudiotagger.tag.datatype.DataTypes; import org.jaudiotagger.tag.datatype.StringNullTerminated; import org.jaudiotagger.tag.id3.ID3v22Frames; import java.nio.ByteBuffer; /** * Encrypted meta frame *

* This frame contains one or more encrypted frames. This enables * protection of copyrighted information such as pictures and text, that * people might want to pay extra for. Since standardisation of such an * encryption scheme is beyond this document, all "CRM" frames begin with * a terminated string with a URL [URL] containing an email address, or a * link to a location where an email adress can be found, that belongs to * the organisation responsible for this specific encrypted meta frame. *

* Questions regarding the encrypted frame should be sent to the * indicated email address. If a $00 is found directly after the 'Frame * size', the whole frame should be ignored, and preferably be removed. * The 'Owner identifier' is then followed by a short content description * and explanation as to why it's encrypted. After the * 'content/explanation' description, the actual encrypted block follows. *

* When an ID3v2 decoder encounters a "CRM" frame, it should send the * datablock to the 'plugin' with the corresponding 'owner identifier' * and expect to receive either a datablock with one or several ID3v2 * frames after each other or an error. There may be more than one "CRM" * frames in a tag, but only one with the same 'owner identifier'. *

* Encrypted meta frame "CRM" * Frame size $xx xx xx * Owner identifier $00 (00) * Content/explanation $00 (00) * Encrypted datablock */ public class FrameBodyCRM extends AbstractID3v2FrameBody implements ID3v22FrameBody { /** * Creates a new FrameBodyCRM datatype. */ public FrameBodyCRM() { // this.setObject(ObjectTypes.OBJ_OWNER, ""); // this.setObject(ObjectTypes.OBJ_DESCRIPTION, ""); // this.setObject("Encrypted datablock", new byte[0]); } public FrameBodyCRM(FrameBodyCRM body) { super(body); } /** * Creates a new FrameBodyCRM datatype. * * @param owner * @param description * @param data */ public FrameBodyCRM(String owner, String description, byte[] data) { this.setObjectValue(DataTypes.OBJ_OWNER, owner); this.setObjectValue(DataTypes.OBJ_DESCRIPTION, description); this.setObjectValue(DataTypes.OBJ_ENCRYPTED_DATABLOCK, data); } /** * Creates a new FrameBodyCRM datatype. * * @param byteBuffer * @param frameSize * @throws InvalidTagException if unable to create framebody from buffer */ public FrameBodyCRM(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v22Frames.FRAME_ID_V2_ENCRYPTED_FRAME; } /** * @return */ public String getOwner() { return (String) getObjectValue(DataTypes.OBJ_OWNER); } /** * @param description */ public void getOwner(String description) { setObjectValue(DataTypes.OBJ_OWNER, description); } /** * */ protected void setupObjectList() { objectList.add(new StringNullTerminated(DataTypes.OBJ_OWNER, this)); objectList.add(new StringNullTerminated(DataTypes.OBJ_DESCRIPTION, this)); objectList.add(new ByteArraySizeTerminated(DataTypes.OBJ_ENCRYPTED_DATABLOCK, this)); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyRVA2.java0000644000175000017500000000510111277006322030053 0ustar drazzibdrazzib/** * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: FrameBodyRVA2.java 832 2009-11-12 13:25:38Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Description: * Relative Volume Adjustment * */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.datatype.ByteArraySizeTerminated; import org.jaudiotagger.tag.datatype.DataTypes; import org.jaudiotagger.tag.id3.ID3v24Frames; import java.nio.ByteBuffer; public class FrameBodyRVA2 extends AbstractID3v2FrameBody implements ID3v24FrameBody { /** * Creates a new FrameBodyRVA2 datatype. */ public FrameBodyRVA2() { } public FrameBodyRVA2(FrameBodyRVA2 body) { super(body); } /** * Convert from V3 to V4 Frame * @param body */ public FrameBodyRVA2(FrameBodyRVAD body) { setObjectValue(DataTypes.OBJ_DATA, body.getObjectValue(DataTypes.OBJ_DATA)); } /** * Creates a new FrameBodyRVAD datatype. * * @param byteBuffer * @param frameSize * @throws InvalidTagException if unable to create framebody from buffer */ public FrameBodyRVA2(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_RELATIVE_VOLUME_ADJUSTMENT2; } /** * Setup the Object List. A byte Array which will be read upto frame size * bytes. */ protected void setupObjectList() { objectList.add(new ByteArraySizeTerminated(DataTypes.OBJ_DATA, this)); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyTORY.java0000644000175000017500000000507011470746136030154 0ustar drazzibdrazzib/* * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.id3.ID3v23Frames; import java.nio.ByteBuffer; /** * Original release year Text information frame. *

The 'Original release year' frame is intended for the year when the original recording, if for example the music * in the file should be a cover of a previously released song, was released. The field is formatted as in the "TYER" * frame. *

*

For more details, please refer to the ID3 specifications: *

* * @author : Paul Taylor * @author : Eric Farng * @version $Id: FrameBodyTORY.java 929 2010-11-17 12:36:46Z paultaylor $ */ public class FrameBodyTORY extends AbstractFrameBodyTextInfo implements ID3v23FrameBody { /** * Creates a new FrameBodyTORY datatype. */ public FrameBodyTORY() { } public FrameBodyTORY(FrameBodyTORY body) { super(body); } /** * Creates a new FrameBodyTORY datatype. * * @param textEncoding * @param text */ public FrameBodyTORY(byte textEncoding, String text) { super(textEncoding, text); } /** * Creates a new FrameBodyTORY datatype. * * @param byteBuffer * @param frameSize * @throws InvalidTagException */ public FrameBodyTORY(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v23Frames.FRAME_ID_V3_TORY; } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyPIC.java0000644000175000017500000001700111277026507027765 0ustar drazzibdrazzib/** * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: FrameBodyPIC.java 836 2009-11-12 15:44:07Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Description: * */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.datatype.*; import org.jaudiotagger.tag.id3.ID3v22Frames; import org.jaudiotagger.tag.id3.valuepair.ImageFormats; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; import org.jaudiotagger.tag.reference.PictureTypes; import java.io.ByteArrayOutputStream; import java.nio.ByteBuffer; /** * ID3v22 Attached Picture *

*

This frame contains a picture directly related to the audio file. * Image format is preferably "PNG" [PNG] or "JPG" [JFIF]. Description * is a short description of the picture, represented as a terminated * textstring. The description has a maximum length of 64 characters, * but may be empty. There may be several pictures attached to one file, * each in their individual "PIC" frame, but only one with the same * ontent descriptor. There may only be one picture with the picture * type declared as picture type $01 and $02 respectively. There is a * possibility to put only a link to the image file by using the 'image * format' "-->" and having a complete URL [URL] instead of picture data. * The use of linked files should however be used restrictively since * there is the risk of separation of files. *

* Attached picture "PIC" * Frame size $xx xx xx * Text encoding $xx * Image format $xx xx xx * Picture type $xx * Description $00 (00) * Picture data *

*

* Picture type: $00 Other * $01 32x32 pixels 'file icon' (PNG only) * $02 Other file icon * $03 Cover (front) * $04 Cover (back) * $05 Leaflet page * $06 Media (e.g. lable side of CD) * $07 Lead artist/lead performer/soloist * $08 Artist/performer * $09 Conductor * $0A Band/Orchestra * $0B Composer * $0C Lyricist/text writer * $0D Recording Location * $0E During recording * $0F During performance * $10 Movie/video screen capture * $11 A bright coloured fish * $12 Illustration * $13 Band/artist logotype * $14 Publisher/Studio logotype */ public class FrameBodyPIC extends AbstractID3v2FrameBody implements ID3v22FrameBody { public static final String IMAGE_IS_URL = "-->"; /** * Creates a new FrameBodyPIC datatype. */ public FrameBodyPIC() { setObjectValue(DataTypes.OBJ_TEXT_ENCODING, TextEncoding.ISO_8859_1); } public FrameBodyPIC(FrameBodyPIC body) { super(body); } /** * Creates a new FrameBodyPIC datatype. * * @param textEncoding * @param imageFormat * @param pictureType * @param description * @param data */ public FrameBodyPIC(byte textEncoding, String imageFormat, byte pictureType, String description, byte[] data) { this.setObjectValue(DataTypes.OBJ_TEXT_ENCODING, textEncoding); this.setObjectValue(DataTypes.OBJ_IMAGE_FORMAT, imageFormat); this.setPictureType(pictureType); this.setDescription(description); this.setImageData(data); } /** * Conversion from v2 PIC to v3/v4 APIC * @param body */ public FrameBodyPIC(FrameBodyAPIC body) { this.setObjectValue(DataTypes.OBJ_TEXT_ENCODING, body.getTextEncoding()); this.setObjectValue(DataTypes.OBJ_IMAGE_FORMAT, ImageFormats.getFormatForMimeType((String) body.getObjectValue(DataTypes.OBJ_MIME_TYPE))); this.setObjectValue(DataTypes.OBJ_PICTURE_DATA, body.getObjectValue(DataTypes.OBJ_PICTURE_DATA)); this.setDescription(body.getDescription()); this.setImageData(body.getImageData()); } /** * Creates a new FrameBodyPIC datatype. * * @param byteBuffer * @param frameSize * @throws InvalidTagException if unable to create framebody from buffer */ public FrameBodyPIC(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * Set a description of the image * * @param description of the image */ public void setDescription(String description) { setObjectValue(DataTypes.OBJ_DESCRIPTION, description); } /** * Get a description of the image * * @return a description of the image */ public String getDescription() { return (String) getObjectValue(DataTypes.OBJ_DESCRIPTION); } /** * Set imageData * * @param imageData */ public void setImageData(byte[] imageData) { setObjectValue(DataTypes.OBJ_PICTURE_DATA, imageData); } /** * Get Image data * * @return */ public byte[] getImageData() { return (byte[]) getObjectValue(DataTypes.OBJ_PICTURE_DATA); } /** * Set Picture Type * * @param pictureType */ public void setPictureType(byte pictureType) { setObjectValue(DataTypes.OBJ_PICTURE_TYPE, pictureType); } /** * @return picturetype */ public int getPictureType() { return ((Long) getObjectValue(DataTypes.OBJ_PICTURE_TYPE)).intValue(); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v22Frames.FRAME_ID_V2_ATTACHED_PICTURE; } /** * If the description cannot be encoded using current encoder, change the encoder */ public void write(ByteArrayOutputStream tagBuffer) { if (!((AbstractString) getObject(DataTypes.OBJ_DESCRIPTION)).canBeEncoded()) { this.setTextEncoding(TextEncoding.UTF_16); } super.write(tagBuffer); } /** * Get a description of the image * * @return a description of the image */ public String getFormatType() { return (String) getObjectValue(DataTypes.OBJ_IMAGE_FORMAT); } public boolean isImageUrl() { return getFormatType() != null && getFormatType().equals(IMAGE_IS_URL); } /** * */ protected void setupObjectList() { objectList.add(new NumberHashMap(DataTypes.OBJ_TEXT_ENCODING, this, TextEncoding.TEXT_ENCODING_FIELD_SIZE)); objectList.add(new StringFixedLength(DataTypes.OBJ_IMAGE_FORMAT, this, 3)); objectList.add(new NumberHashMap(DataTypes.OBJ_PICTURE_TYPE, this, PictureTypes.PICTURE_TYPE_FIELD_SIZE)); objectList.add(new StringNullTerminated(DataTypes.OBJ_DESCRIPTION, this)); objectList.add(new ByteArraySizeTerminated(DataTypes.OBJ_PICTURE_DATA, this)); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyTPOS.java0000644000175000017500000001107711470746136030150 0ustar drazzibdrazzib/* * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.datatype.DataTypes; import org.jaudiotagger.tag.datatype.NumberHashMap; import org.jaudiotagger.tag.datatype.PartOfSet; import org.jaudiotagger.tag.id3.ID3v24Frames; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; import java.nio.ByteBuffer; /** * Part of a set Text information frame. * *

The 'Part of a set' frame is a numeric string that describes which part of a set the audio came from. * This frame is used if the source described in the "TALB" frame is divided into several mediums, e.g. a double CD. * The value may be extended with a "/" character and a numeric string containing the total number of parts in the set. * e.g. "1/2". *

*

For more details, please refer to the ID3 specifications: *

* * @author : Paul Taylor * @author : Eric Farng * @version $Id: FrameBodyTPOS.java 929 2010-11-17 12:36:46Z paultaylor $ */ public class FrameBodyTPOS extends AbstractID3v2FrameBody implements ID3v23FrameBody, ID3v24FrameBody { /** * Creates a new FrameBodyTRCK datatype. */ public FrameBodyTPOS() { setObjectValue(DataTypes.OBJ_TEXT_ENCODING, TextEncoding.ISO_8859_1); setObjectValue(DataTypes.OBJ_TEXT, new PartOfSet.PartOfSetValue()); } public FrameBodyTPOS(FrameBodyTPOS body) { super(body); } /** * Creates a new FrameBodyTRCK datatype, the value is parsed literally * * @param textEncoding * @param text */ public FrameBodyTPOS(byte textEncoding, String text) { setObjectValue(DataTypes.OBJ_TEXT_ENCODING, textEncoding); setObjectValue(DataTypes.OBJ_TEXT, new PartOfSet.PartOfSetValue(text)); } public FrameBodyTPOS(byte textEncoding, Integer discNo,Integer discTotal) { super(); setObjectValue(DataTypes.OBJ_TEXT_ENCODING, textEncoding); setObjectValue(DataTypes.OBJ_TEXT, new PartOfSet.PartOfSetValue(discNo,discTotal)); } /** * Creates a new FrameBodyTRCK datatype. * * @param byteBuffer * @param frameSize * @throws java.io.IOException * @throws InvalidTagException */ public FrameBodyTPOS(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_SET; } public String getUserFriendlyValue() { return String.valueOf(getDiscNo()); } public String getText() { return getObjectValue(DataTypes.OBJ_TEXT).toString(); } public Integer getDiscNo() { return ((PartOfSet.PartOfSetValue)getObjectValue(DataTypes.OBJ_TEXT)).getCount(); } public void setDiscNo(Integer discNo) { ((PartOfSet.PartOfSetValue)getObjectValue(DataTypes.OBJ_TEXT)).setCount(discNo); } public Integer getDiscTotal() { return ((PartOfSet.PartOfSetValue)getObjectValue(DataTypes.OBJ_TEXT)).getTotal(); } public void setDiscTotal(Integer discTotal) { ((PartOfSet.PartOfSetValue)getObjectValue(DataTypes.OBJ_TEXT)).setTotal(discTotal); } public void setText(String text) { setObjectValue(DataTypes.OBJ_TEXT, new PartOfSet.PartOfSetValue(text)); } protected void setupObjectList() { objectList.add(new NumberHashMap(DataTypes.OBJ_TEXT_ENCODING, this, TextEncoding.TEXT_ENCODING_FIELD_SIZE)); objectList.add(new PartOfSet(DataTypes.OBJ_TEXT, this)); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyAENC.java0000644000175000017500000001254011277006322030054 0ustar drazzibdrazzib/* * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.datatype.ByteArraySizeTerminated; import org.jaudiotagger.tag.datatype.DataTypes; import org.jaudiotagger.tag.datatype.NumberFixedLength; import org.jaudiotagger.tag.datatype.StringNullTerminated; import org.jaudiotagger.tag.id3.ID3v24Frames; import java.nio.ByteBuffer; /** * Audio encryption Frame. *

*

* This frame indicates if the actual audio stream is encrypted, and by * whom. Since standardisation of such encrypion scheme is beyond this * document, all "AENC" frames begin with a terminated string with a * URL containing an email address, or a link to a location where an * email address can be found, that belongs to the organisation * responsible for this specific encrypted audio file. Questions * regarding the encrypted audio should be sent to the email address * specified. If a $00 is found directly after the 'Frame size' and the * audiofile indeed is encrypted, the whole file may be considered * useless. *

* After the 'Owner identifier', a pointer to an unencrypted part of the * audio can be specified. The 'Preview start' and 'Preview length' is * described in frames. If no part is unencrypted, these fields should * be left zeroed. After the 'preview length' field follows optionally a * datablock required for decryption of the audio. There may be more * than one "AENC" frames in a tag, but only one with the same 'Owner * identifier'. *

* * * * * *
<Header for 'Audio encryption', ID: "AENC">
Owner identifier <text string> $00
Preview start $xx xx
Preview length $xx xx
Encryption info <binary data>

*

*

For more details, please refer to the ID3 specifications: *

* * @author : Paul Taylor * @author : Eric Farng * @version $Id: FrameBodyAENC.java 832 2009-11-12 13:25:38Z paultaylor $ */ public class FrameBodyAENC extends AbstractID3v2FrameBody implements ID3v24FrameBody, ID3v23FrameBody { /** * Creates a new FrameBodyAENC datatype. */ public FrameBodyAENC() { this.setObjectValue(DataTypes.OBJ_OWNER, ""); this.setObjectValue(DataTypes.OBJ_PREVIEW_START, (short) 0); this.setObjectValue(DataTypes.OBJ_PREVIEW_LENGTH, (short) 0); this.setObjectValue(DataTypes.OBJ_ENCRYPTION_INFO, new byte[0]); } public FrameBodyAENC(FrameBodyAENC body) { super(body); } /** * Creates a new FrameBodyAENC datatype. * * @param owner * @param previewStart * @param previewLength * @param data */ public FrameBodyAENC(String owner, short previewStart, short previewLength, byte[] data) { this.setObjectValue(DataTypes.OBJ_OWNER, owner); this.setObjectValue(DataTypes.OBJ_PREVIEW_START, previewStart); this.setObjectValue(DataTypes.OBJ_PREVIEW_LENGTH, previewLength); this.setObjectValue(DataTypes.OBJ_ENCRYPTION_INFO, data); } /** * Creates a new FrameBodyAENC datatype. * * @param byteBuffer * @param frameSize * @throws InvalidTagException if unable to create framebody from buffer */ public FrameBodyAENC(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_AUDIO_ENCRYPTION; } /** * @return owner */ public String getOwner() { return (String) getObjectValue(DataTypes.OBJ_OWNER); } /** * @param description */ public void getOwner(String description) { setObjectValue(DataTypes.OBJ_OWNER, description); } /** * */ protected void setupObjectList() { objectList.add(new StringNullTerminated(DataTypes.OBJ_OWNER, this)); objectList.add(new NumberFixedLength(DataTypes.OBJ_PREVIEW_START, this, 2)); objectList.add(new NumberFixedLength(DataTypes.OBJ_PREVIEW_LENGTH, this, 2)); objectList.add(new ByteArraySizeTerminated(DataTypes.OBJ_ENCRYPTION_INFO, this)); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyTCOP.java0000644000175000017500000000544211277006322030116 0ustar drazzibdrazzib/* * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.id3.ID3v24Frames; import java.nio.ByteBuffer; /** * Copyright message Text information frame. *

The 'Copyright message' frame, which must begin with a year and a space character (making five characters), is intended for the copyright holder of the original sound, not the audio file itself. The absence of this frame means only that the copyright information is unavailable or has been removed, and must not be interpreted to mean that the sound is public domain. Every time this field is displayed the field must be preceded with "Copyright ©". *

*

For more details, please refer to the ID3 specifications: *

* * @author : Paul Taylor * @author : Eric Farng * @version $Id: FrameBodyTCOP.java 832 2009-11-12 13:25:38Z paultaylor $ */ public class FrameBodyTCOP extends AbstractFrameBodyTextInfo implements ID3v24FrameBody, ID3v23FrameBody { /** * Creates a new FrameBodyTCOP datatype. */ public FrameBodyTCOP() { } public FrameBodyTCOP(FrameBodyTCOP body) { super(body); } /** * Creates a new FrameBodyTCOP datatype. * * @param textEncoding * @param text */ public FrameBodyTCOP(byte textEncoding, String text) { super(textEncoding, text); } /** * Creates a new FrameBodyTCOP datatype. * * @param byteBuffer * @param frameSize * @throws InvalidTagException */ public FrameBodyTCOP(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_COPYRIGHTINFO; } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyTSO2.java0000644000175000017500000000235011277006322030073 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.id3.ID3v24Frames; import java.nio.ByteBuffer; /** * Album Artist Sort name ( iTunes Only) */ public class FrameBodyTSO2 extends AbstractFrameBodyTextInfo implements ID3v24FrameBody, ID3v23FrameBody { /** * Creates a new FrameBodyTSOA datatype. */ public FrameBodyTSO2() { } public FrameBodyTSO2(FrameBodyTSO2 body) { super(body); } /** * Creates a new FrameBodyTSOA datatype. * * @param textEncoding * @param text */ public FrameBodyTSO2(byte textEncoding, String text) { super(textEncoding, text); } /** * Creates a new FrameBodyTSOA datatype. * * @param byteBuffer * @param frameSize * @throws InvalidTagException */ public FrameBodyTSO2(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_ALBUM_ARTIST_SORT_ORDER_ITUNES; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyTYER.java0000644000175000017500000000552711277006322030140 0ustar drazzibdrazzib/* * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.datatype.DataTypes; import org.jaudiotagger.tag.id3.ID3v23Frames; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; import java.nio.ByteBuffer; /** * Year Text information frame. *

The 'Year' frame is a numeric string with a year of the recording. This frames is always four characters long (until the year 10000). *

Deprecated in v2.4.0 *

*

For more details, please refer to the ID3 specifications: *

* * @author : Paul Taylor * @author : Eric Farng * @version $Id: FrameBodyTYER.java 832 2009-11-12 13:25:38Z paultaylor $ */ public class FrameBodyTYER extends AbstractFrameBodyTextInfo implements ID3v23FrameBody { /** * Creates a new FrameBodyTYER datatype. */ public FrameBodyTYER() { } public FrameBodyTYER(FrameBodyTYER body) { super(body); } /** * When converting v4 TDRC frame to v3 TYER * @param body */ public FrameBodyTYER(FrameBodyTDRC body) { setObjectValue(DataTypes.OBJ_TEXT_ENCODING, TextEncoding.ISO_8859_1); setObjectValue(DataTypes.OBJ_TEXT, body.getText()); } /** * Creates a new FrameBodyTYER datatype. * * @param textEncoding * @param text */ public FrameBodyTYER(byte textEncoding, String text) { super(textEncoding, text); } /** * Creates a new FrameBodyTYER datatype. * * @param byteBuffer * @param frameSize * @throws InvalidTagException */ public FrameBodyTYER(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v23Frames.FRAME_ID_V3_TYER; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyXSOT.java0000644000175000017500000000253211277006322030143 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.id3.ID3v23Frames; import java.nio.ByteBuffer; /** * Title Sort name, this is what MusicBrainz uses in ID3v23 because TSOT not supported. *

* However iTunes uses TSOT even in ID3v23, so we have two possible options */ public class FrameBodyXSOT extends AbstractFrameBodyTextInfo implements ID3v23FrameBody { /** * Creates a new FrameBodyTSOT datatype. */ public FrameBodyXSOT() { } public FrameBodyXSOT(FrameBodyXSOT body) { super(body); } /** * Creates a new FrameBodyTSOT datatype. * * @param textEncoding * @param text */ public FrameBodyXSOT(byte textEncoding, String text) { super(textEncoding, text); } /** * Creates a new FrameBodyTSOT datatype. * * @param byteBuffer * @param frameSize * @throws InvalidTagException */ public FrameBodyXSOT(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v23Frames.FRAME_ID_V3_TITLE_SORT_ORDER_MUSICBRAINZ; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyTSIZ.java0000644000175000017500000000465611277006322030150 0ustar drazzibdrazzib/* * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.id3.ID3v23Frames; import java.nio.ByteBuffer; /** * Size Text information frame. *

The 'Size' frame contains the size of the audiofile in bytes, excluding the ID3v2 tag, represented as a numeric string. *

*

For more details, please refer to the ID3 specifications: *

* * @author : Paul Taylor * @author : Eric Farng * @version $Id: FrameBodyTSIZ.java 832 2009-11-12 13:25:38Z paultaylor $ */ public class FrameBodyTSIZ extends AbstractFrameBodyTextInfo implements ID3v23FrameBody { /** * Creates a new FrameBodyTSIZ datatype. */ public FrameBodyTSIZ() { } public FrameBodyTSIZ(FrameBodyTSIZ body) { super(body); } /** * Creates a new FrameBodyTSIZ datatype. * * @param textEncoding * @param text */ public FrameBodyTSIZ(byte textEncoding, String text) { super(textEncoding, text); } /** * Creates a new FrameBodyTSIZ datatype. * * @param byteBuffer * @param frameSize * @throws InvalidTagException */ public FrameBodyTSIZ(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v23Frames.FRAME_ID_V3_TSIZ; } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyTSSE.java0000644000175000017500000000512611277006322030126 0ustar drazzibdrazzib/* * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.id3.ID3v24Frames; import java.nio.ByteBuffer; /** * Software/Hardware and settings used for encoding Text information frame. *

The 'Software/Hardware and settings used for encoding' frame includes the used audio encoder and its settings when the file was encoded. Hardware refers to hardware encoders, not the computer on which a program was run. *

*

For more details, please refer to the ID3 specifications: *

* * @author : Paul Taylor * @author : Eric Farng * @version $Id: FrameBodyTSSE.java 832 2009-11-12 13:25:38Z paultaylor $ */ public class FrameBodyTSSE extends AbstractFrameBodyTextInfo implements ID3v23FrameBody, ID3v24FrameBody { /** * Creates a new FrameBodyTSSE datatype. */ public FrameBodyTSSE() { } public FrameBodyTSSE(FrameBodyTSSE body) { super(body); } /** * Creates a new FrameBodyTSSE datatype. * * @param textEncoding * @param text */ public FrameBodyTSSE(byte textEncoding, String text) { super(textEncoding, text); } /** * Creates a new FrameBodyTSSE datatype. * * @param byteBuffer * @param frameSize * @throws InvalidTagException */ public FrameBodyTSSE(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_HW_SW_SETTINGS; } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyTXXX.java0000644000175000017500000001563211470746136030177 0ustar drazzibdrazzib/** * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: FrameBodyTXXX.java 929 2010-11-17 12:36:46Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Description: * */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.datatype.DataTypes; import org.jaudiotagger.tag.datatype.NumberHashMap; import org.jaudiotagger.tag.datatype.TextEncodedStringNullTerminated; import org.jaudiotagger.tag.datatype.TextEncodedStringSizeTerminated; import org.jaudiotagger.tag.id3.ID3TextEncodingConversion; import org.jaudiotagger.tag.id3.ID3v24Frames; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; import java.io.ByteArrayOutputStream; import java.nio.ByteBuffer; /** * User defined text information frame *

* This frame is intended for one-string text information concerning the * audio file in a similar way to the other "T"-frames. The frame body * consists of a description of the string, represented as a terminated * string, followed by the actual string. There may be more than one * "TXXX" frame in each tag, but only one with the same description. *

*

* Text encoding $xx * Description $00 (00) * Value */ public class FrameBodyTXXX extends AbstractFrameBodyTextInfo implements ID3v24FrameBody, ID3v23FrameBody { //Used by Picard and Jaikoz public static final String MUSICBRAINZ_ARTISTID = "MusicBrainz Artist Id"; public static final String MUSICBRAINZ_ALBUM_ARTISTID = "MusicBrainz Album Artist Id"; public static final String MUSICBRAINZ_ALBUMID = "MusicBrainz Album Id"; public static final String MUSICBRAINZ_RELEASE_GROUPID = "MusicBrainz Release Group Id"; public static final String MUSICBRAINZ_DISCID = "MusicBrainz Disc Id"; public static final String MUSICBRAINZ_ALBUM_TYPE = "MusicBrainz Album Type"; public static final String MUSICBRAINZ_ALBUM_STATUS = "MusicBrainz Album Status"; public static final String MUSICBRAINZ_ALBUM_COUNTRY = "MusicBrainz Album Release Country"; public static final String MUSICBRAINZ_WORKID = "MusicBrainz Work Id"; public static final String AMAZON_ASIN = "ASIN"; public static final String MUSICIP_ID = "MusicIP PUID"; public static final String BARCODE = "BARCODE"; public static final String CATALOG_NO = "CATALOGNUMBER"; public static final String MOOD = "MOOD"; //ID3 v23 only public static final String TAGS = "TAGS"; public static final String FBPM = "FBPM"; public static final String SCRIPT = "SCRIPT"; //used by Foobar 20000 public static final String ALBUM_ARTIST = "ALBUM ARTIST"; public static final String PERFORMER = "PERFORMER"; /** * Creates a new FrameBodyTXXX datatype. */ public FrameBodyTXXX() { this.setObjectValue(DataTypes.OBJ_TEXT_ENCODING, TextEncoding.ISO_8859_1); this.setObjectValue(DataTypes.OBJ_DESCRIPTION, ""); this.setObjectValue(DataTypes.OBJ_TEXT, ""); } /** * Convert from V4 TMOO Frame to V3 Frame * @param body */ public FrameBodyTXXX(FrameBodyTMOO body) { setObjectValue(DataTypes.OBJ_TEXT_ENCODING, body.getTextEncoding()); this.setObjectValue(DataTypes.OBJ_TEXT_ENCODING, TextEncoding.ISO_8859_1); this.setObjectValue(DataTypes.OBJ_DESCRIPTION, MOOD); this.setObjectValue(DataTypes.OBJ_TEXT, body.getText()); } public FrameBodyTXXX(FrameBodyTXXX body) { super(body); } /** * Creates a new FrameBodyTXXX datatype. * * @param textEncoding * @param description * @param text */ public FrameBodyTXXX(byte textEncoding, String description, String text) { this.setObjectValue(DataTypes.OBJ_TEXT_ENCODING, textEncoding); this.setObjectValue(DataTypes.OBJ_DESCRIPTION, description); this.setObjectValue(DataTypes.OBJ_TEXT, text); } /** * Creates a new FrameBodyTXXX datatype. * * @param byteBuffer * @param frameSize * @throws InvalidTagException */ public FrameBodyTXXX(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * Set the description field * * @param description */ public void setDescription(String description) { setObjectValue(DataTypes.OBJ_DESCRIPTION, description); } /** * @return the description field */ public String getDescription() { return (String) getObjectValue(DataTypes.OBJ_DESCRIPTION); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_USER_DEFINED_INFO; } /** * Because TXXX frames also have a text encoded description we need to check this as well. * */ public void write(ByteArrayOutputStream tagBuffer) { //Ensure valid for type setTextEncoding(ID3TextEncodingConversion.getTextEncoding(getHeader(), getTextEncoding())); //Ensure valid for description if (!((TextEncodedStringNullTerminated) getObject(DataTypes.OBJ_DESCRIPTION)).canBeEncoded()) { this.setTextEncoding(ID3TextEncodingConversion.getUnicodeTextEncoding(getHeader())); } super.write(tagBuffer); } /** * This is different to other text Frames */ protected void setupObjectList() { objectList.add(new NumberHashMap(DataTypes.OBJ_TEXT_ENCODING, this, TextEncoding.TEXT_ENCODING_FIELD_SIZE)); objectList.add(new TextEncodedStringNullTerminated(DataTypes.OBJ_DESCRIPTION, this)); objectList.add(new TextEncodedStringSizeTerminated(DataTypes.OBJ_TEXT, this)); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyPRIV.java0000644000175000017500000001060711277006322030130 0ustar drazzibdrazzib/* * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.datatype.ByteArraySizeTerminated; import org.jaudiotagger.tag.datatype.DataTypes; import org.jaudiotagger.tag.datatype.StringNullTerminated; import org.jaudiotagger.tag.id3.ID3v24Frames; import java.nio.ByteBuffer; /** * Private frame. *

*

* This frame is used to contain information from a software producer * that its program uses and does not fit into the other frames. The * frame consists of an 'Owner identifier' string and the binary data. * The 'Owner identifier' is a null-terminated string with a URL * containing an email address, or a link to a location where an email * address can be found, that belongs to the organisation responsible * for the frame. Questions regarding the frame should be sent to the * indicated email address. The tag may contain more than one "PRIV" * frame but only with different contents. It is recommended to keep the * number of "PRIV" frames as low as possible. *

* * * *
<Header for 'Private frame', ID: "PRIV">
Owner identifier<text string> $00
The private data<binary data>

*

*

For more details, please refer to the ID3 specifications: *

* * @author : Paul Taylor * @author : Eric Farng * @version $Id: FrameBodyPRIV.java 832 2009-11-12 13:25:38Z paultaylor $ */ public class FrameBodyPRIV extends AbstractID3v2FrameBody implements ID3v24FrameBody, ID3v23FrameBody { /** * Creates a new FrameBodyPRIV datatype. */ public FrameBodyPRIV() { this.setObjectValue(DataTypes.OBJ_OWNER, ""); this.setObjectValue(DataTypes.OBJ_DATA, new byte[0]); } public FrameBodyPRIV(FrameBodyPRIV body) { super(body); } /** * Creates a new FrameBodyPRIV datatype. * * @param owner * @param data */ public FrameBodyPRIV(String owner, byte[] data) { this.setObjectValue(DataTypes.OBJ_OWNER, owner); this.setObjectValue(DataTypes.OBJ_DATA, data); } /** * Creates a new FrameBodyPRIV datatype. * * @param byteBuffer * @param frameSize * @throws InvalidTagException if unable to create framebody from buffer */ public FrameBodyPRIV(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * @param data */ public void setData(byte[] data) { setObjectValue(DataTypes.OBJ_DATA, data); } /** * @return */ public byte[] getData() { return (byte[]) getObjectValue(DataTypes.OBJ_DATA); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_PRIVATE; } /** * @param owner */ public void setOwner(String owner) { setObjectValue(DataTypes.OBJ_OWNER, owner); } /** * @return */ public String getOwner() { return (String) getObjectValue(DataTypes.OBJ_OWNER); } /** * */ protected void setupObjectList() { objectList.add(new StringNullTerminated(DataTypes.OBJ_OWNER, this)); objectList.add(new ByteArraySizeTerminated(DataTypes.OBJ_DATA, this)); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyWORS.java0000644000175000017500000000466111277006322030145 0ustar drazzibdrazzib/* * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.id3.ID3v24Frames; import java.nio.ByteBuffer; /** * Official internet radio station homepage URL link frames. *

The 'Official internet radio station homepage' contains a URL pointing at the homepage of the internet radio station. *

*

For more details, please refer to the ID3 specifications: *

* * @author : Paul Taylor * @author : Eric Farng * @version $Id: FrameBodyWORS.java 832 2009-11-12 13:25:38Z paultaylor $ */ public class FrameBodyWORS extends AbstractFrameBodyUrlLink implements ID3v24FrameBody, ID3v23FrameBody { /** * Creates a new FrameBodyWORS datatype. */ public FrameBodyWORS() { } /** * Creates a new FrameBodyWORS datatype. * * @param urlLink */ public FrameBodyWORS(String urlLink) { super(urlLink); } public FrameBodyWORS(FrameBodyWORS body) { super(body); } /** * Creates a new FrameBodyWORS datatype. * * @param byteBuffer * @param frameSize * @throws InvalidTagException */ public FrameBodyWORS(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_URL_OFFICIAL_RADIO; } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/ID3v24FrameBody.java0000644000175000017500000000212310736454526030271 0ustar drazzibdrazzib/* * Jaudiotagger Copyright (C)2004,2005 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3.framebody; /** * Indicates that this is a framebody used in ID3v24Tags. * * @author Paul Taylor * @version $Id: ID3v24FrameBody.java 520 2008-01-01 15:16:38Z paultaylor $ */ public interface ID3v24FrameBody { } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyOWNE.java0000644000175000017500000001231711277026507030127 0ustar drazzibdrazzib/* * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.datatype.*; import org.jaudiotagger.tag.id3.ID3TextEncodingConversion; import org.jaudiotagger.tag.id3.ID3v24Frames; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; import java.io.ByteArrayOutputStream; import java.nio.ByteBuffer; /** * Ownership frame. *

*

* The ownership frame might be used as a reminder of a made transaction * or, if signed, as proof. Note that the "USER" and "TOWN" frames are * good to use in conjunction with this one. The frame begins, after the * frame ID, size and encoding fields, with a 'price payed' field. The * first three characters of this field contains the currency used for * the transaction, encoded according to ISO-4217 alphabetic * currency code. Concatenated to this is the actual price payed, as a * numerical string using "." as the decimal separator. Next is an 8 * character date string (YYYYMMDD) followed by a string with the name * of the seller as the last field in the frame. There may only be one * "OWNE" frame in a tag. *

* * * * * *
<Header for 'Ownership frame', ID: "OWNE">
Text encoding $xx
Price payed <text string> $00
Date of purch. <text string>
Seller<text string according to encoding>

*

*

For more details, please refer to the ID3 specifications: *

* * @author : Paul Taylor * @author : Eric Farng * @version $Id: FrameBodyOWNE.java 836 2009-11-12 15:44:07Z paultaylor $ */ public class FrameBodyOWNE extends AbstractID3v2FrameBody implements ID3v24FrameBody, ID3v23FrameBody { /** * Creates a new FrameBodyOWNE datatype. */ public FrameBodyOWNE() { // this.setObject("Text Encoding", new Byte((byte) 0)); // this.setObject("Price Paid", ""); // this.setObject("Date Of Purchase", ""); // this.setObject("Seller", ""); } public FrameBodyOWNE(FrameBodyOWNE body) { super(body); } /** * Creates a new FrameBodyOWNE datatype. * * @param textEncoding * @param pricePaid * @param dateOfPurchase * @param seller */ public FrameBodyOWNE(byte textEncoding, String pricePaid, String dateOfPurchase, String seller) { this.setObjectValue(DataTypes.OBJ_TEXT_ENCODING, textEncoding); this.setObjectValue(DataTypes.OBJ_PRICE_PAID, pricePaid); this.setObjectValue(DataTypes.OBJ_PURCHASE_DATE, dateOfPurchase); this.setObjectValue(DataTypes.OBJ_SELLER_NAME, seller); } /** * Creates a new FrameBodyOWNE datatype. * * @param byteBuffer * @param frameSize * @throws InvalidTagException if unable to create framebody from buffer */ public FrameBodyOWNE(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_OWNERSHIP; } /** * If the seller name cannot be encoded using current encoder, change the encoder */ public void write(ByteArrayOutputStream tagBuffer) { //Ensure valid for type setTextEncoding(ID3TextEncodingConversion.getTextEncoding(getHeader(), getTextEncoding())); //Ensure valid for data if (!((AbstractString) getObject(DataTypes.OBJ_SELLER_NAME)).canBeEncoded()) { this.setTextEncoding(ID3TextEncodingConversion.getUnicodeTextEncoding(getHeader())); } super.write(tagBuffer); } /** * */ protected void setupObjectList() { objectList.add(new NumberHashMap(DataTypes.OBJ_TEXT_ENCODING, this, TextEncoding.TEXT_ENCODING_FIELD_SIZE)); objectList.add(new StringNullTerminated(DataTypes.OBJ_PRICE_PAID, this)); objectList.add(new StringDate(DataTypes.OBJ_PURCHASE_DATE, this)); objectList.add(new TextEncodedStringSizeTerminated(DataTypes.OBJ_SELLER_NAME, this)); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/AbstractID3v2FrameBody.java0000644000175000017500000001716311470746136031700 0ustar drazzibdrazzib/** * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: AbstractID3v2FrameBody.java 929 2010-11-17 12:36:46Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Description: * Abstract Superclass of all Frame Bodys * */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.audio.mp3.MP3File; import org.jaudiotagger.tag.InvalidDataTypeException; import org.jaudiotagger.tag.InvalidFrameException; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.datatype.AbstractDataType; import org.jaudiotagger.tag.id3.AbstractTagFrameBody; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.nio.ByteBuffer; /** * Contains the content for an ID3v2 frame, (the header is held directly within the frame */ public abstract class AbstractID3v2FrameBody extends AbstractTagFrameBody { protected static final String TYPE_BODY = "body"; /** * Frame Body Size, originally this is size as indicated in frame header * when we come to writing data we recalculate it. */ private int size; /** * Create Empty Body. Super Constructor sets up Object list */ protected AbstractID3v2FrameBody() { } /** * Create Body based on another body * @param copyObject */ protected AbstractID3v2FrameBody(AbstractID3v2FrameBody copyObject) { super(copyObject); } /** * Creates a new FrameBody dataType from file. The super * Constructor sets up the Object list for the frame. * * @param byteBuffer from where to read the frame body from * @param frameSize * @throws org.jaudiotagger.tag.InvalidTagException */ protected AbstractID3v2FrameBody(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(); setSize(frameSize); this.read(byteBuffer); } /** * Return the ID3v2 Frame Identifier, must be implemented by concrete subclasses * * @return the frame identifier */ public abstract String getIdentifier(); /** * Return size of frame body,if frameBody already exist will take this value from the frame header * but it is always recalculated before writing any changes back to disk. * * @return size in bytes of this frame body */ public int getSize() { return size; } /** * Set size based on size passed as parameter from frame header, * done before read * @param size */ public void setSize(int size) { this.size = size; } /** * Set size based on size of the DataTypes making up the body,done after write */ public void setSize() { size = 0; for (AbstractDataType object : objectList) { size += object.getSize(); } } /** * Are two bodies equal * * @param obj */ public boolean equals(Object obj) { return (obj instanceof AbstractID3v2FrameBody) && super.equals(obj); } /** * This reads a frame body from a ByteBuffer into the appropriate FrameBody class and update the position of the * buffer to be just after the end of this frameBody *

* The ByteBuffer represents the tag and its position should be at the start of this frameBody. The size as * indicated in the header is passed to the frame constructor when reading from file. * * @param byteBuffer file to read * @throws InvalidFrameException if unable to construct a frameBody from the ByteBuffer */ //TODO why don't we just slice byteBuffer, set limit to size and convert readByteArray to take a ByteBuffer //then we wouldn't have to temporary allocate space for the buffer, using lots of needless memory //and providing extra work for the garbage collector. public void read(ByteBuffer byteBuffer) throws InvalidTagException { int size = getSize(); logger.info("Reading body for" + this.getIdentifier() + ":" + size); //Allocate a buffer to the size of the Frame Body and read from file byte[] buffer = new byte[size]; byteBuffer.get(buffer); //Offset into buffer, incremented by length of previous dataType //this offset is only used internally to decide where to look for the next //dataType within a frameBody, it does not decide where to look for the next frame body int offset = 0; //Go through the ObjectList of the Frame reading the data into the for (AbstractDataType object : objectList) //correct dataType. { logger.finest("offset:" + offset); //The read has extended further than the defined frame size (ok to extend upto //size because the next datatype may be of length 0.) if (offset > (size)) { logger.warning("Invalid Size for FrameBody"); throw new InvalidFrameException("Invalid size for Frame Body"); } //Try and load it with data from the Buffer //if it fails frame is invalid try { object.readByteArray(buffer, offset); } catch (InvalidDataTypeException e) { logger.warning("Problem reading datatype within Frame Body:" + e.getMessage()); throw e; } //Increment Offset to start of next datatype. offset += object.getSize(); } } /** * Write the contents of this datatype to the byte array * * @param tagBuffer * @throws IOException on any I/O error */ public void write(ByteArrayOutputStream tagBuffer) { logger.info("Writing frame body for" + this.getIdentifier() + ":Est Size:" + size); //Write the various fields to file in order for (AbstractDataType object : objectList) { byte[] objectData = object.writeByteArray(); if (objectData != null) { try { tagBuffer.write(objectData); } catch (IOException ioe) { //This could never happen coz not writing to file, so convert to RuntimeException throw new RuntimeException(ioe); } } } setSize(); logger.info("Written frame body for" + this.getIdentifier() + ":Real Size:" + size); } /** * Return String Representation of Datatype * */ public void createStructure() { MP3File.getStructureFormatter().openHeadingElement(TYPE_BODY, ""); for (AbstractDataType nextObject : objectList) { nextObject.createStructure(); } MP3File.getStructureFormatter().closeHeadingElement(TYPE_BODY); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyGRID.java0000644000175000017500000001263611277006322030101 0ustar drazzibdrazzib/* * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.datatype.ByteArraySizeTerminated; import org.jaudiotagger.tag.datatype.DataTypes; import org.jaudiotagger.tag.datatype.NumberFixedLength; import org.jaudiotagger.tag.datatype.StringNullTerminated; import org.jaudiotagger.tag.id3.ID3v24Frames; import java.nio.ByteBuffer; /** * Group identification registration frame. *

*

* This frame enables grouping of otherwise unrelated frames. This can * be used when some frames are to be signed. To identify which frames * belongs to a set of frames a group identifier must be registered in * the tag with this frame. The 'Owner identifier' is a null-terminated * string with a URL containing an email address, or a link to a * location where an email address can be found, that belongs to the * organisation responsible for this grouping. Questions regarding the * grouping should be sent to the indicated email address. The 'Group * symbol' contains a value that associates the frame with this group * throughout the whole tag. Values below $80 are reserved. The 'Group * symbol' may optionally be followed by some group specific data, e.g. * a digital signature. There may be several "GRID" frames in a tag but * only one containing the same symbol and only one containing the same * owner identifier. The group symbol must be used somewhere in the tag. * See section 3.3.1, flag j for more information. *

* * * * *
<Header for 'Group ID registration', ID: "GRID">
Owner identifier <text string> $00
Group symbol $xx
Group dependent data <binary data>

*

*

For more details, please refer to the ID3 specifications: *

* * @author : Paul Taylor * @author : Eric Farng * @version $Id: FrameBodyGRID.java 832 2009-11-12 13:25:38Z paultaylor $ */ public class FrameBodyGRID extends AbstractID3v2FrameBody implements ID3v24FrameBody, ID3v23FrameBody { /** * Creates a new FrameBodyGRID datatype. */ public FrameBodyGRID() { // this.setObject(ObjectTypes.OBJ_OWNER, ""); // this.setObject("Group Symbol", new Byte((byte) 0)); // this.setObject("Group Dependent Data", new byte[0]); } public FrameBodyGRID(FrameBodyGRID body) { super(body); } /** * Creates a new FrameBodyGRID datatype. * * @param owner * @param groupSymbol * @param data */ public FrameBodyGRID(String owner, byte groupSymbol, byte[] data) { this.setObjectValue(DataTypes.OBJ_OWNER, owner); this.setObjectValue(DataTypes.OBJ_GROUP_SYMBOL, groupSymbol); this.setObjectValue(DataTypes.OBJ_GROUP_DATA, data); } /** * Creates a new FrameBodyGRID datatype. * * @param byteBuffer * @param frameSize * @throws InvalidTagException if unable to create framebody from buffer */ public FrameBodyGRID(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * @param textEncoding */ public void setGroupSymbol(byte textEncoding) { setObjectValue(DataTypes.OBJ_GROUP_SYMBOL, textEncoding); } /** * @return */ public byte getGroupSymbol() { if (getObjectValue(DataTypes.OBJ_GROUP_SYMBOL) != null) { return ((Long) getObjectValue(DataTypes.OBJ_GROUP_SYMBOL)).byteValue(); } else { return (byte) 0; } } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_GROUP_ID_REG; } /** * @param owner */ public void setOwner(String owner) { setObjectValue(DataTypes.OBJ_OWNER, owner); } /** * @return */ public String getOwner() { return (String) getObjectValue(DataTypes.OBJ_OWNER); } /** * */ protected void setupObjectList() { objectList.add(new StringNullTerminated(DataTypes.OBJ_OWNER, this)); objectList.add(new NumberFixedLength(DataTypes.OBJ_GROUP_SYMBOL, this, 1)); objectList.add(new ByteArraySizeTerminated(DataTypes.OBJ_GROUP_DATA, this)); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyTIT3.java0000644000175000017500000000500611277006322030070 0ustar drazzibdrazzib/* * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.id3.ID3v24Frames; import java.nio.ByteBuffer; /** * Subtitle/Description refinement Text information frame. *

The 'Subtitle/Description refinement' frame is used for information directly related to the contents title (e.g. "Op. 16" or "Performed live at Wembley"). *

*

For more details, please refer to the ID3 specifications: *

* * @author : Paul Taylor * @author : Eric Farng * @version $Id: FrameBodyTIT3.java 832 2009-11-12 13:25:38Z paultaylor $ */ public class FrameBodyTIT3 extends AbstractFrameBodyTextInfo implements ID3v24FrameBody, ID3v23FrameBody { /** * Creates a new FrameBodyTIT3 datatype. */ public FrameBodyTIT3() { } public FrameBodyTIT3(FrameBodyTIT3 body) { super(body); } /** * Creates a new FrameBodyTIT3 datatype. * * @param textEncoding * @param text */ public FrameBodyTIT3(byte textEncoding, String text) { super(textEncoding, text); } /** * Creates a new FrameBodyTIT3 datatype. * * @param byteBuffer * @param frameSize * @throws InvalidTagException */ public FrameBodyTIT3(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_TITLE_REFINEMENT; } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyEQUA.java0000644000175000017500000000671511470746136030121 0ustar drazzibdrazzib/* * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.datatype.ByteArraySizeTerminated; import org.jaudiotagger.tag.datatype.DataTypes; import org.jaudiotagger.tag.id3.ID3v23Frames; /** * Equalisation frame. *

*

* This is another subjective, alignment frame. It allows the user to * predefine an equalisation curve within the audio file. There may only * be one "EQUA" frame in each tag. *

* * *
<Header of 'Equalisation', ID: "EQUA">
Adjustment bits$xx

* The 'adjustment bits' field defines the number of bits used for * representation of the adjustment. This is normally $10 (16 bits) for * MPEG 2 layer I, II and III and MPEG 2.5. This value may not be * $00. *

* This is followed by 2 bytes + ('adjustment bits' rounded up to the * nearest byte) for every equalisation band in the following format, * giving a frequency range of 0 - 32767Hz: *

* * * *
Increment/decrement%x (MSB of the Frequency)
Frequency (lower 15 bits)
Adjustment$xx (xx ...)

* The increment/decrement bit is 1 for increment and 0 for decrement. * The equalisation bands should be ordered increasingly with reference * to frequency. All frequencies don't have to be declared. The * equalisation curve in the reading software should be interpolated * between the values in this frame. Three equal adjustments for three * subsequent frequencies. A frequency should only be described once in * the frame. *

*

*

For more details, please refer to the ID3 specifications: *

* * @author : Paul Taylor * @author : Eric Farng * @version $Id: FrameBodyEQUA.java 929 2010-11-17 12:36:46Z paultaylor $ */ public class FrameBodyEQUA extends AbstractID3v2FrameBody implements ID3v23FrameBody { /** * Creates a new FrameBodyEQUA dataType. */ public FrameBodyEQUA() { } public FrameBodyEQUA(FrameBodyEQUA body) { super(body); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v23Frames.FRAME_ID_V3_EQUALISATION; } /** * TODO:proper mapping */ protected void setupObjectList() { objectList.add(new ByteArraySizeTerminated(DataTypes.OBJ_DATA, this)); } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyMLLT.java0000644000175000017500000000777510736454526030150 0ustar drazzibdrazzib/* * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.datatype.ByteArraySizeTerminated; import org.jaudiotagger.tag.datatype.DataTypes; import org.jaudiotagger.tag.id3.ID3v24Frames; /** * MPEG location lookup table frame. *

*

* To increase performance and accuracy of jumps within a MPEG * audio file, frames with timecodes in different locations in the file * might be useful. The ID3v2 frame includes references that the * software can use to calculate positions in the file. After the frame * header is a descriptor of how much the 'frame counter' should * increase for every reference. If this value is two then the first * reference points out the second frame, the 2nd reference the 4th * frame, the 3rd reference the 6th frame etc. In a similar way the * 'bytes between reference' and 'milliseconds between reference' points * out bytes and milliseconds respectively. *

* Each reference consists of two parts; a certain number of bits, as * defined in 'bits for bytes deviation', that describes the difference * between what is said in 'bytes between reference' and the reality and * a certain number of bits, as defined in 'bits for milliseconds * deviation', that describes the difference between what is said in * 'milliseconds between reference' and the reality. The number of bits * in every reference, i.e. 'bits for bytes deviation'+'bits for * milliseconds deviation', must be a multiple of four. There may only * be one "MLLT" frame in each tag. *

* * * * * * *
<Header for 'Location lookup table', ID: "MLLT">
MPEG frames between reference$xx xx
Bytes between reference$xx xx xx
Milliseconds between reference$xx xx xx
Bits for bytes deviation$xx
Bits for milliseconds dev.$xx

* Then for every reference the following data is included; *

* * *
Deviation in bytes%xxx....
Deviation in milliseconds%xxx....

*

*

For more details, please refer to the ID3 specifications: *

* * @author : Paul Taylor * @author : Eric Farng * @version $Id: FrameBodyMLLT.java 520 2008-01-01 15:16:38Z paultaylor $ */ public class FrameBodyMLLT extends AbstractID3v2FrameBody implements ID3v24FrameBody, ID3v23FrameBody { /** * Creates a new FrameBodyMLLT datatype. */ public FrameBodyMLLT() { } public FrameBodyMLLT(FrameBodyMLLT body) { super(body); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_MPEG_LOCATION_LOOKUP_TABLE; } /** * TODO:proper mapping */ protected void setupObjectList() { objectList.add(new ByteArraySizeTerminated(DataTypes.OBJ_DATA, this)); } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyTIT2.java0000644000175000017500000000472711277006322030100 0ustar drazzibdrazzib/* * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.id3.ID3v24Frames; import java.nio.ByteBuffer; /** * Title/Songname/Content description Text information frame. *

The 'Title/Songname/Content description' frame is the actual name of the piece (e.g. "Adagio", "Hurricane Donna"). *

*

For more details, please refer to the ID3 specifications: *

* * @author : Paul Taylor * @author : Eric Farng * @version $Id: FrameBodyTIT2.java 832 2009-11-12 13:25:38Z paultaylor $ */ public class FrameBodyTIT2 extends AbstractFrameBodyTextInfo implements ID3v24FrameBody, ID3v23FrameBody { /** * Creates a new FrameBodyTIT2 datatype. */ public FrameBodyTIT2() { } public FrameBodyTIT2(FrameBodyTIT2 body) { super(body); } /** * Creates a new FrameBodyTIT2 datatype. * * @param textEncoding * @param text */ public FrameBodyTIT2(byte textEncoding, String text) { super(textEncoding, text); } /** * Creates a new FrameBodyTIT2 datatype. * * @param byteBuffer * @param frameSize * @throws InvalidTagException */ public FrameBodyTIT2(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_TITLE; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyWCOM.java0000644000175000017500000000476411470746136030135 0ustar drazzibdrazzib/* * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.id3.ID3v24Frames; import java.nio.ByteBuffer; /** * Commercial information URL link frames. *

The 'Commercial information' frame is a URL pointing at a webpage with information such as where the album can be * bought. There may be more than one "WCOM" frame in a tag, but not with the same content. *

*

For more details, please refer to the ID3 specifications: *

* * @author : Paul Taylor * @author : Eric Farng * @version $Id: FrameBodyWCOM.java 929 2010-11-17 12:36:46Z paultaylor $ */ public class FrameBodyWCOM extends AbstractFrameBodyUrlLink implements ID3v24FrameBody, ID3v23FrameBody { /** * Creates a new FrameBodyWCOM datatype. */ public FrameBodyWCOM() { } /** * Creates a new FrameBodyWCOM datatype. * * @param urlLink */ public FrameBodyWCOM(String urlLink) { super(urlLink); } public FrameBodyWCOM(FrameBodyWCOM body) { super(body); } /** * Creates a new FrameBodyWCOM datatype. * * @param byteBuffer * @param frameSize * @throws InvalidTagException */ public FrameBodyWCOM(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_URL_COMMERCIAL; } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyTCMP.java0000644000175000017500000000362311277006322030113 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.datatype.DataTypes; import org.jaudiotagger.tag.id3.ID3v24Frames; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; import java.nio.ByteBuffer; /** * Is part of a Compilation (iTunes frame) *

*

determines whether or not track is part of compilation * * @author : Paul Taylor */ public class FrameBodyTCMP extends AbstractFrameBodyTextInfo implements ID3v24FrameBody, ID3v23FrameBody { //TODO does iTunes have to have null terminator? static String IS_COMPILATION = "1\u0000"; /** * Creates a new FrameBodyTCMP datatype, with compilation enabled *

* This is the preferred constructor to use because TCMP frames should not exist * unless they are set to true */ public FrameBodyTCMP() { setObjectValue(DataTypes.OBJ_TEXT_ENCODING, TextEncoding.ISO_8859_1); setObjectValue(DataTypes.OBJ_TEXT, IS_COMPILATION); } public FrameBodyTCMP(FrameBodyTCMP body) { super(body); } /** * Creates a new FrameBodyTCMP datatype. * * @param textEncoding * @param text */ public FrameBodyTCMP(byte textEncoding, String text) { super(textEncoding, text); } public boolean isCompilation() { return this.getText().equals(IS_COMPILATION); } /** * Creates a new FrameBodyTIT1 datatype. * * @param byteBuffer * @param frameSize * @throws InvalidTagException */ public FrameBodyTCMP(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_IS_COMPILATION; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyTEXT.java0000644000175000017500000000502411277006322030131 0ustar drazzibdrazzib/* * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.id3.ID3v24Frames; import java.nio.ByteBuffer; /** * Lyricist/Text writer Text information frame. *

The 'Lyricist(s)/Text writer(s)' frame is intended for the writer(s) of the text or lyrics in the recording. They are seperated with the "/" character. *

*

For more details, please refer to the ID3 specifications: *

* * @author : Paul Taylor * @author : Eric Farng * @version $Id: FrameBodyTEXT.java 832 2009-11-12 13:25:38Z paultaylor $ */ public class FrameBodyTEXT extends AbstractFrameBodyTextInfo implements ID3v24FrameBody, ID3v23FrameBody { /** * Creates a new FrameBodyTEXT datatype. */ public FrameBodyTEXT() { } public FrameBodyTEXT(FrameBodyTEXT body) { super(body); } /** * Creates a new FrameBodyTEXT datatype. * * @param textEncoding * @param text */ public FrameBodyTEXT(byte textEncoding, String text) { super(textEncoding, text); } /** * Creates a new FrameBodyTEXT datatype. * * @param byteBuffer * @param frameSize * @throws java.io.IOException * @throws InvalidTagException */ public FrameBodyTEXT(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_LYRICIST; } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyTIME.java0000644000175000017500000000473311277006322030111 0ustar drazzibdrazzib/* * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.id3.ID3v23Frames; import java.nio.ByteBuffer; /** * Time Text information frame. *

The 'Time' frame is a numeric string in the HHMM format containing the time for the recording. This field is always four characters long. *

Deprecated in v2.4.0 *

*

For more details, please refer to the ID3 specifications: *

* * @author : Paul Taylor * @author : Eric Farng * @version $Id: FrameBodyTIME.java 832 2009-11-12 13:25:38Z paultaylor $ */ public class FrameBodyTIME extends AbstractFrameBodyTextInfo implements ID3v23FrameBody { /** * Creates a new FrameBodyTIME datatype. */ public FrameBodyTIME() { } public FrameBodyTIME(FrameBodyTIME body) { super(body); } /** * Creates a new FrameBodyTIME datatype. * * @param textEncoding * @param text */ public FrameBodyTIME(byte textEncoding, String text) { super(textEncoding, text); } /** * Creates a new FrameBodyTIME datatype. * * @param byteBuffer * @param frameSize * @throws InvalidTagException */ public FrameBodyTIME(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v23Frames.FRAME_ID_V3_TIME; } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyUSER.java0000644000175000017500000001077311277026507030141 0ustar drazzibdrazzib/* * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.datatype.*; import org.jaudiotagger.tag.id3.ID3v24Frames; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; import org.jaudiotagger.tag.reference.Languages; import java.io.ByteArrayOutputStream; import java.nio.ByteBuffer; /** * Terms of use frame. *

*

* This frame contains a brief description of the terms of use and * ownership of the file. More detailed information concerning the legal * terms might be available through the "WCOP" frame. Newlines are * allowed in the text. There may only be one "USER" frame in a tag. *

* * * * *
<Header for 'Terms of use frame', ID: "USER">
Text encoding $xx
Language $xx xx xx
The actual text<text string according to encoding>

*

*

For more details, please refer to the ID3 specifications: *

* * @author : Paul Taylor * @author : Eric Farng * @version $Id: FrameBodyUSER.java 836 2009-11-12 15:44:07Z paultaylor $ */ public class FrameBodyUSER extends AbstractID3v2FrameBody implements ID3v24FrameBody, ID3v23FrameBody { /** * Creates a new FrameBodyUSER datatype. */ public FrameBodyUSER() { // setObject("Text Encoding", new Byte((byte) 0)); // setObject("Language", ""); // setObject("Text", ""); } public FrameBodyUSER(FrameBodyUSER body) { super(body); } /** * Creates a new FrameBodyUSER datatype. * * @param textEncoding * @param language * @param text */ public FrameBodyUSER(byte textEncoding, String language, String text) { setObjectValue(DataTypes.OBJ_TEXT_ENCODING, textEncoding); setObjectValue(DataTypes.OBJ_LANGUAGE, language); setObjectValue(DataTypes.OBJ_TEXT, text); } /** * Create a new FrameBodyUser by reading from byte buffer * * @param byteBuffer * @param frameSize * @throws InvalidTagException */ public FrameBodyUSER(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_TERMS_OF_USE; } /** * @return lanaguage */ public String getLanguage() { return (String) getObjectValue(DataTypes.OBJ_LANGUAGE); } /** * @param language */ public void setOwner(String language) { setObjectValue(DataTypes.OBJ_LANGUAGE, language); } /** * If the text cannot be encoded using current encoder, change the encoder * * @param tagBuffer * @throws java.io.IOException */ public void write(ByteArrayOutputStream tagBuffer) { if (!((AbstractString) getObject(DataTypes.OBJ_TEXT)).canBeEncoded()) { this.setTextEncoding(TextEncoding.UTF_16); } super.write(tagBuffer); } /** * */ protected void setupObjectList() { objectList.add(new NumberHashMap(DataTypes.OBJ_TEXT_ENCODING, this, TextEncoding.TEXT_ENCODING_FIELD_SIZE)); objectList.add(new StringHashMap(DataTypes.OBJ_LANGUAGE, this, Languages.LANGUAGE_FIELD_SIZE)); objectList.add(new StringSizeTerminated(DataTypes.OBJ_TEXT, this)); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyTPE2.java0000644000175000017500000000473011277006322030062 0ustar drazzibdrazzib/* * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.id3.ID3v24Frames; import java.nio.ByteBuffer; /** * Band/Orchestra/Accompaniment Text information frame. *

The 'Band/Orchestra/Accompaniment' frame is used for additional information about the performers in the recording. *

*

For more details, please refer to the ID3 specifications: *

* * @author : Paul Taylor * @author : Eric Farng * @version $Id: FrameBodyTPE2.java 832 2009-11-12 13:25:38Z paultaylor $ */ public class FrameBodyTPE2 extends AbstractFrameBodyTextInfo implements ID3v24FrameBody, ID3v23FrameBody { /** * Creates a new FrameBodyTPE2 datatype. */ public FrameBodyTPE2() { } public FrameBodyTPE2(FrameBodyTPE2 body) { super(body); } /** * Creates a new FrameBodyTPE2 datatype. * * @param textEncoding * @param text */ public FrameBodyTPE2(byte textEncoding, String text) { super(textEncoding, text); } /** * Creates a new FrameBodyTPE2 datatype. * * @param byteBuffer * @param frameSize * @throws InvalidTagException */ public FrameBodyTPE2(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_ACCOMPANIMENT; } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyTLEN.java0000644000175000017500000000466211277006322030116 0ustar drazzibdrazzib/* * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.id3.ID3v24Frames; import java.nio.ByteBuffer; /** * Length Text information frame. *

The 'Length' frame contains the length of the audiofile in milliseconds, represented as a numeric string. *

*

For more details, please refer to the ID3 specifications: *

* * @author : Paul Taylor * @author : Eric Farng * @version $Id: FrameBodyTLEN.java 832 2009-11-12 13:25:38Z paultaylor $ */ public class FrameBodyTLEN extends AbstractFrameBodyTextInfo implements ID3v24FrameBody, ID3v23FrameBody { /** * Creates a new FrameBodyTLEN datatype. */ public FrameBodyTLEN() { } public FrameBodyTLEN(FrameBodyTLEN body) { super(body); } /** * Creates a new FrameBodyTLEN datatype. * * @param textEncoding * @param text */ public FrameBodyTLEN(byte textEncoding, String text) { super(textEncoding, text); } /** * Creates a new FrameBodyTLEN datatype. * * @param byteBuffer * @param frameSize * @throws InvalidTagException */ public FrameBodyTLEN(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_LENGTH; } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyTDEN.java0000644000175000017500000000422711277006322030103 0ustar drazzibdrazzib/** * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: FrameBodyTDEN.java 832 2009-11-12 13:25:38Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Description: * */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.id3.ID3v24Frames; import java.nio.ByteBuffer; public class FrameBodyTDEN extends AbstractFrameBodyTextInfo implements ID3v24FrameBody { /** * Creates a new FrameBodyTDEN datatype. */ public FrameBodyTDEN() { } public FrameBodyTDEN(FrameBodyTDEN body) { super(body); } /** * Creates a new FrameBodyTDEN datatype. * * @param textEncoding * @param text */ public FrameBodyTDEN(byte textEncoding, String text) { super(textEncoding, text); } /** * Creates a new FrameBodyTDEN datatype. * * @param byteBuffer * @param frameSize * @throws InvalidTagException */ public FrameBodyTDEN(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_ENCODING_TIME; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyTCOM.java0000644000175000017500000000475011277006322030114 0ustar drazzibdrazzib/* * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.id3.ID3v24Frames; import java.nio.ByteBuffer; /** * Composer Text information frame. *

The 'Composer(s)' frame is intended for the name of the composer(s). They are seperated with the "/" character. *

*

For more details, please refer to the ID3 specifications: *

* * @author : Paul Taylor * @author : Eric Farng * @version $Id: FrameBodyTCOM.java 832 2009-11-12 13:25:38Z paultaylor $ */ public class FrameBodyTCOM extends AbstractFrameBodyTextInfo implements ID3v24FrameBody, ID3v23FrameBody { /** * Creates a new FrameBodyTCOM datatype. */ public FrameBodyTCOM() { } public FrameBodyTCOM(FrameBodyTCOM body) { super(body); } /** * Creates a new FrameBodyTCOM datatype. * * @param textEncoding * @param text */ public FrameBodyTCOM(byte textEncoding, String text) { super(textEncoding, text); } /** * Creates a new FrameBodyTCOM datatype. * * @param byteBuffer * @param frameSize * @throws InvalidTagException if unable to create framebody from buffer */ public FrameBodyTCOM(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_COMPOSER; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyTDAT.java0000644000175000017500000000473311277006322030107 0ustar drazzibdrazzib/* * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.id3.ID3v23Frames; import java.nio.ByteBuffer; /** * Date Text information frame. *

The 'Date' frame is a numeric string in the DDMM format containing the date for the recording. This field is always four characters long. *

Deprecated in v2.4.0 *

*

For more details, please refer to the ID3 specifications: *

* * @author : Paul Taylor * @author : Eric Farng * @version $Id: FrameBodyTDAT.java 832 2009-11-12 13:25:38Z paultaylor $ */ public class FrameBodyTDAT extends AbstractFrameBodyTextInfo implements ID3v23FrameBody { /** * Creates a new FrameBodyTDAT datatype. */ public FrameBodyTDAT() { } public FrameBodyTDAT(FrameBodyTDAT body) { super(body); } /** * Creates a new FrameBodyTDAT datatype. * * @param textEncoding * @param text */ public FrameBodyTDAT(byte textEncoding, String text) { super(textEncoding, text); } /** * Creates a new FrameBodyTDAT datatype. * * @param byteBuffer * @param frameSize * @throws InvalidTagException */ public FrameBodyTDAT(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v23Frames.FRAME_ID_V3_TDAT; } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyTDRL.java0000644000175000017500000000422511277006322030114 0ustar drazzibdrazzib/** * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: FrameBodyTDRL.java 832 2009-11-12 13:25:38Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Description: * */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.id3.ID3v24Frames; import java.nio.ByteBuffer; public class FrameBodyTDRL extends AbstractFrameBodyTextInfo implements ID3v24FrameBody { /** * Creates a new FrameBodyTDRL datatype. */ public FrameBodyTDRL() { } public FrameBodyTDRL(FrameBodyTDRL body) { super(body); } /** * Creates a new FrameBodyTDRL datatype. * * @param textEncoding * @param text */ public FrameBodyTDRL(byte textEncoding, String text) { super(textEncoding, text); } /** * Creates a new FrameBodyTDRL datatype. * * @param byteBuffer * @param frameSize * @throws InvalidTagException */ public FrameBodyTDRL(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_RELEASE_TIME; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyETCO.java0000644000175000017500000001337511277006322030107 0ustar drazzibdrazzib/* * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.datatype.ByteArraySizeTerminated; import org.jaudiotagger.tag.datatype.DataTypes; import org.jaudiotagger.tag.id3.ID3v24Frames; import java.nio.ByteBuffer; /** * Event timing codes frame. *

*

* This frame allows synchronisation with key events in a song or sound. * The header is: *

* * *
<Header for 'Event timing codes', ID: "ETCO">
Time stamp format$xx

* Where time stamp format is: *

* $01 Absolute time, 32 bit sized, using MPEG frames as unit
* $02 Absolute time, 32 bit sized, using milliseconds as unit *

* Abolute time means that every stamp contains the time from the * beginning of the file. *

* Followed by a list of key events in the following format: *

* * *
Type of event$xx
Time stamp$xx (xx ...)

* The 'Time stamp' is set to zero if directly at the beginning of the * sound or after the previous event. All events should be sorted in * chronological order. The type of event is as follows: *

* * * * * * * * * * * * * * * * * * * * * * * * * * * *
$00 padding (has no meaning)
$01 end of initial silence
$02 intro start
$03 mainpart start
$04 outro start
$05 outro end
$06 verse start
$07 refrain start
$08 interlude start
$09 theme start
$0A variation start
$0B key change
$0C time change
$0D momentary unwanted noise (Snap, Crackle & Pop)
$0E sustained noise
$0F sustained noise end
$10 intro end
$11 mainpart end
$12 verse end
$13 refrain end
$14 theme end
$15-$DFreserved for future use
$E0-$EFnot predefined sync 0-F
$F0-$FCreserved for future use
$FD audio end (start of silence)
$FE audio file ends
$FFone more byte of events follows (all the following bytes with the value $FF have the same function)
*

* Terminating the start events such as "intro start" is not required. * The 'Not predefined sync's ($E0-EF) are for user events. You might * want to synchronise your music to something, like setting of an * explosion on-stage, turning on your screensaver etc. *

* There may only be one "ETCO" frame in each tag.

*

*

For more details, please refer to the ID3 specifications: *

* * @author : Paul Taylor * @author : Eric Farng * @version $Id: FrameBodyETCO.java 832 2009-11-12 13:25:38Z paultaylor $ */ public class FrameBodyETCO extends AbstractID3v2FrameBody implements ID3v24FrameBody, ID3v23FrameBody { /** * Creates a new FrameBodyETCO datatype. */ public FrameBodyETCO() { } public FrameBodyETCO(FrameBodyETCO body) { super(body); } /** * Creates a new FrameBodyETCO datatype. * * @param byteBuffer * @param frameSize * @throws InvalidTagException if unable to create framebody from buffer */ public FrameBodyETCO(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * @return */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_EVENT_TIMING_CODES; } /** * */ protected void setupObjectList() { objectList.add(new ByteArraySizeTerminated(DataTypes.OBJ_DATA, this)); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/ID3v2ChapterFrameBody.java0000644000175000017500000000216010472306350031501 0ustar drazzibdrazzib/* * Horizon Wimba Copyright (C)2006 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3.framebody; /** * Indicates that this is a frame used in ID3v2 Chapter Tags. * * @author Marc Gimpel, Horizon Wimba S.A. * @version $Id: ID3v2ChapterFrameBody.java 177 2006-08-21 10:37:28Z mgimpel $ */ public interface ID3v2ChapterFrameBody { } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyCTOC.java0000644000175000017500000001275111277006322030102 0ustar drazzibdrazzib/* * Horizon Wimba Copyright (C)2006 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.datatype.ByteArraySizeTerminated; import org.jaudiotagger.tag.datatype.DataTypes; import org.jaudiotagger.tag.id3.ID3v2ChapterFrames; import java.nio.ByteBuffer; /** * Table of content frame. *

*

* The purpose of "CTOC" frames is to allow a table of contents to be * defined. In the simplest case, a single "CTOC" frame can be used to * provide a flat (single-level) table of contents. However, multiple * "CTOC" frames can also be used to define a hierarchical (multi-level) * table of contents. *

* There may be more than one frame of this type in a tag but each must * have an Element ID that is unique with respect to any other "CTOC" or * "CHAP" frame in the tag. *

* Each "CTOC" frame represents one level or element of a table of contents * by providing a list of Child Element IDs. These match the Element IDs of * other "CHAP" and "CTOC" frames in the tag. *

* * * * * * * *
<ID3v2.3 or ID3v2.4 frame header, ID: "CTOC">  (10 bytes)
Element ID<text string> $00
Flags%000000ab
Entry count$xx  (8-bit unsigned int)
<Child Element ID list>
<Optional embedded sub-frames>
*

* The Element ID uniquely identifies the frame. It is not intended to * be human readable and should not be presented to the end-user. *

* Flag a - Top-level bit
* This is set to 1 to identify the top-level "CTOC" frame. This frame * is the root of the Table of Contents tree and is not a child of any * other "CTOC" frame. Only one "CTOC" frame in an ID3v2 tag can have * this bit set to 1. In all other "CTOC" frames this bit shall be set * to 0. *

* Flag b - Ordered bit
* This should be set to 1 if the entries in the Child Element ID list * are ordered or set to 0 if they not are ordered. This provides a hint * as to whether the elements should be played as a continuous ordered * sequence or played individually. *

* The Entry count is the number of entries in the Child Element ID list * that follows and must be greater than zero. Each entry in the list * consists of: *

* * *
Child Element ID  <text string> $00
*

* The last entry in the child Element ID list is followed by a sequence * of optional frames that are embedded within the "CTOC" frame and which * describe this element of the table of contents (e.g. a "TIT2" frame * representing the name of the element) or provide related material such * as URLs and images. These sub-frames are contained within the bounds * of the "CTOC" frame as signalled by the size field in the "CTOC" * frame header. *

* If a parser does not recognise "CTOC" frames it can skip them using * the size field in the frame header. When it does this it will skip * any embedded sub-frames carried within the frame. *

*

*

For more details, please refer to the ID3 Chapter Frame specifications: *

* * @author Marc Gimpel, Horizon Wimba S.A. * @version $Id: FrameBodyCTOC.java 832 2009-11-12 13:25:38Z paultaylor $ */ public class FrameBodyCTOC extends AbstractID3v2FrameBody implements ID3v2ChapterFrameBody { /** * Creates a new FrameBodyCTOC datatype. */ public FrameBodyCTOC() { } /** * Creates a new FrameBodyCTOC datatype. * * @param body */ public FrameBodyCTOC(FrameBodyCTOC body) { super(body); } /** * Creates a new FrameBodyCTOC datatype. * * @param byteBuffer * @param frameSize * @throws InvalidTagException if unable to create framebody from buffer */ public FrameBodyCTOC(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v2ChapterFrames.FRAME_ID_TABLE_OF_CONTENT; } /** * TODO:proper mapping */ protected void setupObjectList() { objectList.add(new ByteArraySizeTerminated(DataTypes.OBJ_DATA, this)); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodySEEK.java0000644000175000017500000000504411277006322030076 0ustar drazzibdrazzib/** * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: FrameBodySEEK.java 832 2009-11-12 13:25:38Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Description: * */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.datatype.DataTypes; import org.jaudiotagger.tag.datatype.NumberFixedLength; import org.jaudiotagger.tag.id3.ID3v24Frames; import java.nio.ByteBuffer; public class FrameBodySEEK extends AbstractID3v2FrameBody implements ID3v24FrameBody { /** * Creates a new FrameBodySEEK datatype. */ public FrameBodySEEK() { // this.setObject("Minimum Offset to Next Tag", new Integer(0)); } /** * Creates a new FrameBodySEEK datatype. * * @param minOffsetToNextTag */ public FrameBodySEEK(int minOffsetToNextTag) { this.setObjectValue(DataTypes.OBJ_OFFSET, minOffsetToNextTag); } public FrameBodySEEK(FrameBodySEEK body) { super(body); } /** * Creates a new FrameBodySEEK datatype. * * @param byteBuffer * @param frameSize * @throws InvalidTagException if unable to create framebody from buffer */ public FrameBodySEEK(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_AUDIO_SEEK_POINT_INDEX; } /** * */ protected void setupObjectList() { objectList.add(new NumberFixedLength(DataTypes.OBJ_OFFSET, this, 4)); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyWOAR.java0000644000175000017500000000502111277006322030112 0ustar drazzibdrazzib/* * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.id3.ID3v24Frames; import java.nio.ByteBuffer; /** * Official artist/performer webpage URL link frames. *

The 'Official artist/performer webpage' frame is a URL pointing at the artists official webpage. There may be more than one "WOAR" frame in a tag if the audio contains more than one performer, but not with the same content. *

*

For more details, please refer to the ID3 specifications: *

* * @author : Paul Taylor * @author : Eric Farng * @version $Id: FrameBodyWOAR.java 832 2009-11-12 13:25:38Z paultaylor $ */ public class FrameBodyWOAR extends AbstractFrameBodyUrlLink implements ID3v24FrameBody, ID3v23FrameBody { /** * Creates a new FrameBodyWOAR datatype. */ public FrameBodyWOAR() { } /** * Creates a new FrameBodyWOAR datatype. * * @param urlLink */ public FrameBodyWOAR(String urlLink) { super(urlLink); } public FrameBodyWOAR(FrameBodyWOAR body) { super(body); } /** * Creates a new FrameBodyWOAR datatype. * * @param byteBuffer * @param frameSize * @throws InvalidTagException */ public FrameBodyWOAR(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_URL_ARTIST_WEB; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyTRDA.java0000644000175000017500000000502611277006322030101 0ustar drazzibdrazzib/* * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.id3.ID3v23Frames; import java.nio.ByteBuffer; /** * Recording dates Text information frame. *

The 'Recording dates' frame is a intended to be used as complement to the "TYER", "TDAT" and "TIME" frames. E.g. "4th-7th June, 12th June" in combination with the "TYER" frame. *

*

For more details, please refer to the ID3 specifications: *

* * @author : Paul Taylor * @author : Eric Farng * @version $Id: FrameBodyTRDA.java 832 2009-11-12 13:25:38Z paultaylor $ */ public class FrameBodyTRDA extends AbstractFrameBodyTextInfo implements ID3v23FrameBody { /** * Creates a new FrameBodyTRDA datatype. */ public FrameBodyTRDA() { } public FrameBodyTRDA(FrameBodyTRDA body) { super(body); } /** * Creates a new FrameBodyTRDA datatype. * * @param textEncoding * @param text */ public FrameBodyTRDA(byte textEncoding, String text) { super(textEncoding, text); } /** * Creates a new FrameBodyTRDA datatype. * * @param byteBuffer * @param frameSize * @throws java.io.IOException * @throws InvalidTagException */ public FrameBodyTRDA(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v23Frames.FRAME_ID_V3_TRDA; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyTPE1.java0000644000175000017500000000501511277006322030056 0ustar drazzibdrazzib/* * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.id3.ID3v24Frames; import java.nio.ByteBuffer; /** * Lead artist(s)/Lead performer(s)/Soloist(s)/Performing group Text information frame. *

The 'Lead artist(s)/Lead performer(s)/Soloist(s)/Performing group' is used for the main artist(s). They are seperated with the "/" character. *

*

For more details, please refer to the ID3 specifications: *

* * @author : Paul Taylor * @author : Eric Farng * @version $Id: FrameBodyTPE1.java 832 2009-11-12 13:25:38Z paultaylor $ */ public class FrameBodyTPE1 extends AbstractFrameBodyTextInfo implements ID3v24FrameBody, ID3v23FrameBody { /** * Creates a new FrameBodyTPE1 datatype. */ public FrameBodyTPE1() { } public FrameBodyTPE1(FrameBodyTPE1 body) { super(body); } /** * Creates a new FrameBodyTPE1 datatype. * * @param textEncoding * @param text */ public FrameBodyTPE1(byte textEncoding, String text) { super(textEncoding, text); } /** * Creates a new FrameBodyTPE1 datatype. * * @param byteBuffer * @param frameSize * @throws InvalidTagException */ public FrameBodyTPE1(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_ARTIST; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyTSST.java0000644000175000017500000000427011277006322030144 0ustar drazzibdrazzib/** * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: FrameBodyTSST.java 832 2009-11-12 13:25:38Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Description: * */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.id3.ID3v24Frames; import java.nio.ByteBuffer; public class FrameBodyTSST extends AbstractFrameBodyTextInfo implements ID3v24FrameBody { /** * Creates a new FrameBodyTSST datatype. */ public FrameBodyTSST() { } public FrameBodyTSST(FrameBodyTSST body) { super(body); } /** * Creates a new FrameBodyTSST datatype. * * @param textEncoding * @param text */ public FrameBodyTSST(byte textEncoding, String text) { super(textEncoding, text); } /** * Creates a new FrameBodyTSST datatype. * * @param byteBuffer * @param frameSize * @throws java.io.IOException * @throws InvalidTagException */ public FrameBodyTSST(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_SET_SUBTITLE; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/ID3v23FrameBody.java0000644000175000017500000000212310736454526030270 0ustar drazzibdrazzib/* * Jaudiotagger Copyright (C)2004,2005 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3.framebody; /** * Indicates that this is a framebody used in ID3v23Tags. * * @author Paul Taylor * @version $Id: ID3v23FrameBody.java 520 2008-01-01 15:16:38Z paultaylor $ */ public interface ID3v23FrameBody { } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyTMOO.java0000644000175000017500000000506711277006322030132 0ustar drazzibdrazzib/** * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: FrameBodyTMOO.java 832 2009-11-12 13:25:38Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Description: * */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.datatype.DataTypes; import org.jaudiotagger.tag.id3.ID3v24Frames; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; import java.nio.ByteBuffer; public class FrameBodyTMOO extends AbstractFrameBodyTextInfo implements ID3v24FrameBody { /** * Creates a new FrameBodyTMOO datatype. */ public FrameBodyTMOO() { } public FrameBodyTMOO(FrameBodyTMOO body) { super(body); } /** * Creates a new FrameBodyTMOO datatype. * * @param textEncoding * @param text */ public FrameBodyTMOO(byte textEncoding, String text) { super(textEncoding, text); } public FrameBodyTMOO(FrameBodyTXXX body) { setObjectValue(DataTypes.OBJ_TEXT_ENCODING, body.getTextEncoding()); this.setObjectValue(DataTypes.OBJ_TEXT_ENCODING, TextEncoding.ISO_8859_1); this.setObjectValue(DataTypes.OBJ_TEXT, body.getText()); } /** * Creates a new FrameBodyTMOO datatype. * * @param byteBuffer * @param frameSize * @throws java.io.IOException * @throws InvalidTagException */ public FrameBodyTMOO(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_MOOD; } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyCOMM.java0000644000175000017500000002200311470746136030105 0ustar drazzibdrazzib/* * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.logging.ErrorMessage; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.datatype.*; import org.jaudiotagger.tag.id3.ID3TextEncodingConversion; import org.jaudiotagger.tag.id3.ID3v24Frames; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; import org.jaudiotagger.tag.reference.Languages; import java.io.ByteArrayOutputStream; import java.nio.ByteBuffer; /** * Comments frame. *

*

* This frame is intended for any kind of full text information that does not fit in any other frame. It consists of a * frame header followed by encoding, language and content descriptors and is ended with the actual comment as a * text string. Newline characters are allowed in the comment text string. There may be more than one comment frame * in each tag, but only one with the same language and* content descriptor. * *

* * * * * *
<Header for 'Comment', ID: "COMM">
Text encoding $xx
Language $xx xx xx
Short content descrip.<text string according to encoding> $00 (00)
The actual text <full text string according to encoding>

*

*

For more details, please refer to the ID3 specifications: *

* * @author : Paul Taylor * @author : Eric Farng * @version $Id: FrameBodyCOMM.java 929 2010-11-17 12:36:46Z paultaylor $ */ public class FrameBodyCOMM extends AbstractID3v2FrameBody implements ID3v24FrameBody, ID3v23FrameBody { //Most players only read comment with description of blank public static final String DEFAULT = ""; //used by iTunes for volume normalization, although uses the COMMENT field not usually displayed as a comment public static final String ITUNES_NORMALIZATION = "iTunNORM"; //Various descriptions used by MediaMonkey, (note Media Monkey uses non-standard language field XXX) private static final String MM_PREFIX = "Songs-DB"; public static final String MM_CUSTOM1 = "Songs-DB_Custom1"; public static final String MM_CUSTOM2 = "Songs-DB_Custom2"; public static final String MM_CUSTOM3 = "Songs-DB_Custom3"; public static final String MM_CUSTOM4 = "Songs-DB_Custom4"; public static final String MM_CUSTOM5 = "Songs-DB_Custom5"; public static final String MM_OCCASION = "Songs-DB_Occasion"; public static final String MM_QUALITY = "Songs-DB_Preference"; public static final String MM_TEMPO = "Songs-DB_Tempo"; public boolean isMediaMonkeyFrame() { String desc = getDescription(); if(desc!=null && !(desc.length()==0)) { if(desc.startsWith(MM_PREFIX)) { return true; } } return false; } public boolean isItunesFrame() { String desc = getDescription(); if(desc!=null && !(desc.length()==0)) { if(desc.equals(ITUNES_NORMALIZATION)) { return true; } } return false; } /** * Creates a new FrameBodyCOMM datatype. */ public FrameBodyCOMM() { setObjectValue(DataTypes.OBJ_TEXT_ENCODING, TextEncoding.ISO_8859_1); setObjectValue(DataTypes.OBJ_LANGUAGE, Languages.DEFAULT_ID); setObjectValue(DataTypes.OBJ_DESCRIPTION, ""); setObjectValue(DataTypes.OBJ_TEXT, ""); } public FrameBodyCOMM(FrameBodyCOMM body) { super(body); } /** * Creates a new FrameBodyCOMM datatype. * * @param textEncoding * @param language * @param description * @param text */ public FrameBodyCOMM(byte textEncoding, String language, String description, String text) { setObjectValue(DataTypes.OBJ_TEXT_ENCODING, textEncoding); setObjectValue(DataTypes.OBJ_LANGUAGE, language); setObjectValue(DataTypes.OBJ_DESCRIPTION, description); setObjectValue(DataTypes.OBJ_TEXT, text); } /** * Construct a Comment frame body from the buffer * * @param byteBuffer * @param frameSize * @throws InvalidTagException if unable to create framebody from buffer */ public FrameBodyCOMM(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * Set the description field, which describes the type of comment * * @param description */ public void setDescription(String description) { if (description == null) { throw new IllegalArgumentException(ErrorMessage.GENERAL_INVALID_NULL_ARGUMENT.getMsg()); } setObjectValue(DataTypes.OBJ_DESCRIPTION, description); } /** * Get the description field, which describes the type of comment * * @return description field */ public String getDescription() { return (String) getObjectValue(DataTypes.OBJ_DESCRIPTION); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_COMMENT; } /** * Sets the language the comment is written in * * @param language */ public void setLanguage(String language) { //TODO not sure if this might break existing code /*if(language==null) { throw new IllegalArgumentException(ErrorMessage.GENERAL_INVALID_NULL_ARGUMENT.getMsg()); } */ setObjectValue(DataTypes.OBJ_LANGUAGE, language); } /** * Get the language the comment is written in * * @return the language */ public String getLanguage() { return (String) getObjectValue(DataTypes.OBJ_LANGUAGE); } /** * @param text */ public void setText(String text) { if (text == null) { throw new IllegalArgumentException(ErrorMessage.GENERAL_INVALID_NULL_ARGUMENT.getMsg()); } setObjectValue(DataTypes.OBJ_TEXT, text); } /** * Returns the the text field which holds the comment, adjusted to ensure does not return trailing null * which is due to a iTunes bug. * * @return the text field */ public String getText() { TextEncodedStringSizeTerminated text = (TextEncodedStringSizeTerminated) getObject(DataTypes.OBJ_TEXT); return text.getValueAtIndex(0); } public String getUserFriendlyValue() { return getText(); } /** * */ protected void setupObjectList() { objectList.add(new NumberHashMap(DataTypes.OBJ_TEXT_ENCODING, this, TextEncoding.TEXT_ENCODING_FIELD_SIZE)); objectList.add(new StringHashMap(DataTypes.OBJ_LANGUAGE, this, Languages.LANGUAGE_FIELD_SIZE)); objectList.add(new TextEncodedStringNullTerminated(DataTypes.OBJ_DESCRIPTION, this)); objectList.add(new TextEncodedStringSizeTerminated(DataTypes.OBJ_TEXT, this)); } /** * Because COMM have a text encoding we need to check the text String does * not contain characters that cannot be encoded in current encoding before * we write data. If there are we change the encoding. */ public void write(ByteArrayOutputStream tagBuffer) { //Ensure valid for type setTextEncoding(ID3TextEncodingConversion.getTextEncoding(getHeader(), getTextEncoding())); //Ensure valid for data if (!((AbstractString) getObject(DataTypes.OBJ_TEXT)).canBeEncoded()) { this.setTextEncoding(ID3TextEncodingConversion.getUnicodeTextEncoding(getHeader())); } if (!((AbstractString) getObject(DataTypes.OBJ_DESCRIPTION)).canBeEncoded()) { this.setTextEncoding(ID3TextEncodingConversion.getUnicodeTextEncoding(getHeader())); } super.write(tagBuffer); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyTBPM.java0000644000175000017500000000474311277006322030116 0ustar drazzibdrazzib/* * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.id3.ID3v24Frames; import java.nio.ByteBuffer; /** * Beats Per Minute Text information frame. *

The 'BPM' frame contains the number of beats per minute in the mainpart of the audio. The BPM is an integer and represented as a numerical string. *

*

For more details, please refer to the ID3 specifications: *

* * @author : Paul Taylor * @author : Eric Farng * @version $Id: FrameBodyTBPM.java 832 2009-11-12 13:25:38Z paultaylor $ */ public class FrameBodyTBPM extends AbstractFrameBodyTextInfo implements ID3v24FrameBody, ID3v23FrameBody { /** * Creates a new FrameBodyTBPM datatype. */ public FrameBodyTBPM() { } public FrameBodyTBPM(FrameBodyTBPM body) { super(body); } /** * Creates a new FrameBodyTBPM datatype. * * @param textEncoding * @param text */ public FrameBodyTBPM(byte textEncoding, String text) { super(textEncoding, text); } /** * Creates a new FrameBodyTBPM datatype. * * @param byteBuffer * @param frameSize * @throws InvalidTagException */ public FrameBodyTBPM(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_BPM; } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyTIT1.java0000644000175000017500000000511711277006322030071 0ustar drazzibdrazzib/* * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.id3.ID3v24Frames; import java.nio.ByteBuffer; /** * Content group description Text information frame. *

The 'Content group description' frame is used if the sound belongs to a larger category of sounds/music. * For example, classical music is often sorted in different musical sections (e.g. "Piano Concerto", "Weather - Hurricane"). *

*

For more details, please refer to the ID3 specifications: *

* * @author : Paul Taylor * @author : Eric Farng * @version $Id: FrameBodyTIT1.java 832 2009-11-12 13:25:38Z paultaylor $ */ public class FrameBodyTIT1 extends AbstractFrameBodyTextInfo implements ID3v24FrameBody, ID3v23FrameBody { /** * Creates a new FrameBodyTIT1 datatype. */ public FrameBodyTIT1() { } public FrameBodyTIT1(FrameBodyTIT1 body) { super(body); } /** * Creates a new FrameBodyTIT1 datatype. * * @param textEncoding * @param text */ public FrameBodyTIT1(byte textEncoding, String text) { super(textEncoding, text); } /** * Creates a new FrameBodyTIT1 datatype. * * @param byteBuffer * @param frameSize * @throws InvalidTagException */ public FrameBodyTIT1(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_CONTENT_GROUP_DESC; } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyTALB.java0000644000175000017500000000501611277006322030070 0ustar drazzibdrazzib/* * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.id3.ID3v24Frames; import java.nio.ByteBuffer; /** * Album/Movie/Show title Text information frame. *

The 'Album/Movie/Show title' frame is intended for the title of the recording(/source of sound) which the audio in the file is taken from. *

*

For more details, please refer to the ID3 specifications: *

* * @author : Paul Taylor * @author : Eric Farng * @version $Id: FrameBodyTALB.java 832 2009-11-12 13:25:38Z paultaylor $ */ public class FrameBodyTALB extends AbstractFrameBodyTextInfo implements ID3v24FrameBody, ID3v23FrameBody { /** * Creates a new FrameBodyTALB datatype. */ public FrameBodyTALB() { } public FrameBodyTALB(FrameBodyTALB body) { super(body); } /** * Creates a new FrameBodyTALB datatype. * * @param textEncoding * @param text */ public FrameBodyTALB(byte textEncoding, String text) { super(textEncoding, text); } /** * Creates a new FrameBodyTALB datatype. * * @param byteBuffer * @param frameSize * @throws InvalidTagException if unable to create framebody from buffer */ public FrameBodyTALB(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_ALBUM; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyASPI.java0000644000175000017500000001310411277006322030077 0ustar drazzibdrazzib/* * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.datatype.NumberFixedLength; import org.jaudiotagger.tag.datatype.NumberVariableLength; import org.jaudiotagger.tag.id3.ID3v24Frames; import java.nio.ByteBuffer; /** * Audio files with variable bit rates are intrinsically difficult to * deal with in the case of seeking within the file. The ASPI frame * makes seeking easier by providing a list a seek points within the * audio file. The seek points are a fractional offset within the audio * data, providing a starting point from which to find an appropriate * point to start decoding. The presence of an ASPI frame requires the * existence of a TLEN frame, indicating the duration of the file in * milliseconds. There may only be one 'audio seek point index' frame in * a tag. *

*

* Indexed data start (S) $xx xx xx xx * Indexed data length (L) $xx xx xx xx * Number of index points (N) $xx xx * Bits per index point (b) $xx *

* Then for every index point the following data is included; *

* Fraction at index (Fi) $xx (xx) *

* 'Indexed data start' is a byte offset from the beginning of the file. * 'Indexed data length' is the byte length of the audio data being * indexed. 'Number of index points' is the number of index points, as * the name implies. The recommended number is 100. 'Bits per index * point' is 8 or 16, depending on the chosen precision. 8 bits works * well for short files (less than 5 minutes of audio), while 16 bits is * advantageous for long files. 'Fraction at index' is the numerator of * the fraction representing a relative position in the data. The * denominator is 2 to the power of b. *

* Here are the algorithms to be used in the calculation. The known data * must be the offset of the start of the indexed data (S), the offset * of the end of the indexed data (E), the number of index points (N), * the offset at index i (Oi). We calculate the fraction at index i * (Fi). *

* Oi is the offset of the frame whose start is soonest after the point * for which the time offset is (i/N * duration). *

* The frame data should be calculated as follows: *

* Fi = Oi/L * 2^b (rounded down to the nearest integer) *

* Offset calculation should be calculated as follows from data in the * frame: *

* Oi = (Fi/2^b)*L (rounded up to the nearest integer) * * @author : Paul Taylor * @author : Eric Farng * @version $Id: FrameBodyASPI.java 832 2009-11-12 13:25:38Z paultaylor $ */ public class FrameBodyASPI extends AbstractID3v2FrameBody implements ID3v24FrameBody { private static final int DATA_START_FIELD_SIZE = 4; private static final int DATA_LENGTH_FIELD_SIZE = 4; private static final int NO_OF_INDEX_POINTS_FIELD_SIZE = 2; private static final int BITS_PER_INDEX_POINTS_FIELD_SIZE = 1; private static final int FRACTION_AT_INDEX_MINIMUM_FIELD_SIZE = 1; private static final String INDEXED_DATA_START = "IndexedDataStart"; private static final String INDEXED_DATA_LENGTH = "IndexedDataLength"; private static final String NUMBER_OF_INDEX_POINTS = "NumberOfIndexPoints"; private static final String BITS_PER_INDEX_POINT = "BitsPerIndexPoint"; private static final String FRACTION_AT_INDEX = "FractionAtIndex"; /** * Creates a new FrameBodyASPI datatype. */ public FrameBodyASPI() { } /** * Creates a new FrameBodyASPI from another FrameBodyASPI * * @param copyObject */ public FrameBodyASPI(FrameBodyASPI copyObject) { super(copyObject); } /** * Creates a new FrameBodyASPI datatype. * * @param byteBuffer * @param frameSize * @throws InvalidTagException */ public FrameBodyASPI(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_AUDIO_SEEK_POINT_INDEX; } protected void setupObjectList() { objectList.add(new NumberFixedLength(INDEXED_DATA_START, this, DATA_START_FIELD_SIZE)); objectList.add(new NumberFixedLength(INDEXED_DATA_LENGTH, this, DATA_LENGTH_FIELD_SIZE)); objectList.add(new NumberFixedLength(NUMBER_OF_INDEX_POINTS, this, NO_OF_INDEX_POINTS_FIELD_SIZE)); objectList.add(new NumberFixedLength(BITS_PER_INDEX_POINT, this, BITS_PER_INDEX_POINTS_FIELD_SIZE)); objectList.add(new NumberVariableLength(FRACTION_AT_INDEX, this, FRACTION_AT_INDEX_MINIMUM_FIELD_SIZE)); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyIPLS.java0000644000175000017500000001624411470746136030133 0ustar drazzibdrazzib/* * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.datatype.DataTypes; import org.jaudiotagger.tag.datatype.NumberHashMap; import org.jaudiotagger.tag.datatype.Pair; import org.jaudiotagger.tag.datatype.PairedTextEncodedStringNullTerminated; import org.jaudiotagger.tag.id3.ID3v23Frames; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; import java.io.ByteArrayOutputStream; import java.nio.ByteBuffer; import java.util.Map; import java.util.StringTokenizer; /** * Involved People List ID3v22/v23 Only *

* Since there might be a lot of people contributing to an audio file in various ways, such as musicians and technicians, * the 'Text information frames' are often insufficient to list everyone involved in a project. * The 'Involved people list' is a frame containing the names of those involved, and how they were involved. * The body simply contains a terminated string with the involvement directly followed by a terminated string with * the involvee followed by a new involvement and so on. There may only be one "IPLS" frame in each tag. *

*

* Text encoding $xx * People list strings *

*

For more details, please refer to the ID3 specifications: *

* * @author : Paul Taylor * @author : Eric Farng * @version $Id: FrameBodyIPLS.java 929 2010-11-17 12:36:46Z paultaylor $ */ public class FrameBodyIPLS extends AbstractID3v2FrameBody implements ID3v23FrameBody { /** * Creates a new FrameBodyIPLS datatype. */ public FrameBodyIPLS() { super(); setObjectValue(DataTypes.OBJ_TEXT_ENCODING, TextEncoding.ISO_8859_1); } public FrameBodyIPLS(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * The ID3v23 frame identifier * * @return the ID3v23 frame identifier for this frame type */ public String getIdentifier() { return ID3v23Frames.FRAME_ID_V3_IPLS; } public FrameBodyIPLS(FrameBodyIPLS body) { super(body); } /** * Creates a new FrameBodyIPLS data type. * * @param textEncoding * @param text */ public FrameBodyIPLS(byte textEncoding, String text) { setObjectValue(DataTypes.OBJ_TEXT_ENCODING, textEncoding); setText(text); } /** * Convert from V4 to V3 Frame * @param body */ public FrameBodyIPLS(FrameBodyTIPL body) { setObjectValue(DataTypes.OBJ_TEXT_ENCODING, body.getTextEncoding()); setText(body.getText()); } /** * Set the text, decoded as pairs of involvee - involvement * @param text */ public void setText(String text) { PairedTextEncodedStringNullTerminated.ValuePairs value = new PairedTextEncodedStringNullTerminated.ValuePairs(); StringTokenizer stz = new StringTokenizer(text, "\0"); while (stz.hasMoreTokens()) { String key =stz.nextToken(); if(stz.hasMoreTokens()) { value.add(key, stz.nextToken()); } } setObjectValue(DataTypes.OBJ_TEXT, value); } public void addPair(String text) { PairedTextEncodedStringNullTerminated.ValuePairs value = ((PairedTextEncodedStringNullTerminated) getObject(DataTypes.OBJ_TEXT)).getValue(); StringTokenizer stz = new StringTokenizer(text, "\0"); if (stz.hasMoreTokens()) { value.add(stz.nextToken(),stz.nextToken()); } } /** * Because have a text encoding we need to check the data values do not contain characters that cannot be encoded in * current encoding before we write data. If they do change the encoding. */ public void write(ByteArrayOutputStream tagBuffer) { if (!((PairedTextEncodedStringNullTerminated) getObject(DataTypes.OBJ_TEXT)).canBeEncoded()) { this.setTextEncoding(TextEncoding.UTF_16); } super.write(tagBuffer); } /** * Consists of a text encoding , and then a series of null terminated Strings, there should be an even number * of Strings as they are paired as involvement/involvee */ protected void setupObjectList() { objectList.add(new NumberHashMap(DataTypes.OBJ_TEXT_ENCODING, this, TextEncoding.TEXT_ENCODING_FIELD_SIZE)); objectList.add(new PairedTextEncodedStringNullTerminated(DataTypes.OBJ_TEXT, this)); } public PairedTextEncodedStringNullTerminated.ValuePairs getPairing() { return (PairedTextEncodedStringNullTerminated.ValuePairs)getObject(DataTypes.OBJ_TEXT).getValue(); } /** * Get key at index * * @param index * @return value at index */ public String getKeyAtIndex(int index) { PairedTextEncodedStringNullTerminated text = (PairedTextEncodedStringNullTerminated) getObject(DataTypes.OBJ_TEXT); return text.getValue().getMapping().get(index).getKey(); } /** * Get value at index * * @param index * @return value at index */ public String getValueAtIndex(int index) { PairedTextEncodedStringNullTerminated text = (PairedTextEncodedStringNullTerminated) getObject(DataTypes.OBJ_TEXT); return text.getValue().getMapping().get(index).getValue(); } /** * @return number of text pairs */ public int getNumberOfPairs() { PairedTextEncodedStringNullTerminated text = (PairedTextEncodedStringNullTerminated) getObject(DataTypes.OBJ_TEXT); return text.getValue().getNumberOfPairs(); } public String getText() { PairedTextEncodedStringNullTerminated text = (PairedTextEncodedStringNullTerminated) getObject(DataTypes.OBJ_TEXT); StringBuilder sb = new StringBuilder(); int count=1; for(Pair entry:text.getValue().getMapping()) { sb.append(entry.getKey()+'\0'+entry.getValue()); if(count!=getNumberOfPairs()) { sb.append('\0'); } count++; } return sb.toString(); } public String getUserFriendlyValue() { return getText(); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyXSOP.java0000644000175000017500000000253411277006322030141 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.id3.ID3v23Frames; import java.nio.ByteBuffer; /** * Artist Sort name, this is what MusicBrainz uses in ID3v23 because TSOP not supported. *

* However iTunes uses TSOP even in ID3v23, so we have two possible options */ public class FrameBodyXSOP extends AbstractFrameBodyTextInfo implements ID3v23FrameBody { /** * Creates a new FrameBodyTSOT datatype. */ public FrameBodyXSOP() { } public FrameBodyXSOP(FrameBodyXSOP body) { super(body); } /** * Creates a new FrameBodyTSOT datatype. * * @param textEncoding * @param text */ public FrameBodyXSOP(byte textEncoding, String text) { super(textEncoding, text); } /** * Creates a new FrameBodyTSOT datatype. * * @param byteBuffer * @param frameSize * @throws InvalidTagException */ public FrameBodyXSOP(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v23Frames.FRAME_ID_V3_ARTIST_SORT_ORDER_MUSICBRAINZ; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyUnsupported.java0000644000175000017500000001102111277026507031676 0ustar drazzibdrazzib/** * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: FrameBodyUnsupported.java 836 2009-11-12 15:44:07Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Description: * Frame that is not currently suported by this application * * */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.datatype.ByteArraySizeTerminated; import org.jaudiotagger.tag.datatype.DataTypes; import java.nio.ByteBuffer; /** * Represents a framebody for a frame identifier jaudiotagger has not implemented a framebody for. *

* This is likley to be because the FrameBody is not specified in the Specification but it may just be because the code * has yet to be written, the library uses this framebody when it cant find an alternative. This is different to the * ID3v2ExtensionFrameBody Interface which should be implemented by frame bodies that are non standard such as * iTunes compilation frame (TCMP) but are commonly used. */ public class FrameBodyUnsupported extends AbstractID3v2FrameBody implements ID3v24FrameBody, ID3v23FrameBody, ID3v22FrameBody { /** * Because used by any unknown frame identifier varies */ private String identifier = ""; /** * @deprecated because no identifier set */ public FrameBodyUnsupported() { } /** * Creates a new FrameBodyUnsupported * @param identifier */ public FrameBodyUnsupported(String identifier) { this.identifier = identifier; } /** * Create a new FrameBodyUnsupported * * @param identifier * @param value */ public FrameBodyUnsupported(String identifier, byte[] value) { this.identifier = identifier; setObjectValue(DataTypes.OBJ_DATA, value); } /** * Creates a new FrameBodyUnsupported datatype. * * @param value * @deprecated because no identifier set */ public FrameBodyUnsupported(byte[] value) { setObjectValue(DataTypes.OBJ_DATA, value); } /** * Copy constructor * * @param copyObject a copy is made of this */ public FrameBodyUnsupported(FrameBodyUnsupported copyObject) { super(copyObject); this.identifier = copyObject.identifier; } /** * Creates a new FrameBodyUnsupported datatype. * * @param byteBuffer * @param frameSize * @throws InvalidFrameException if unable to create framebody from buffer * @throws org.jaudiotagger.tag.InvalidTagException */ public FrameBodyUnsupported(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * Return the frame identifier * * @return the identifier */ public String getIdentifier() { return identifier; } /** * @param obj * @return whether obj is equivalent to this object */ public boolean equals(Object obj) { if (!(obj instanceof FrameBodyUnsupported)) { return false; } FrameBodyUnsupported object = (FrameBodyUnsupported) obj; return this.identifier.equals(object.identifier) && super.equals(obj); } /** * Because the contents of this frame are an array of bytes and could be large we just * return the identifier. * * @return a string representation of this frame */ public String toString() { return getIdentifier(); } /** * Setup the Object List. A byte Array which will be read upto frame size * bytes. */ protected void setupObjectList() { objectList.add(new ByteArraySizeTerminated(DataTypes.OBJ_DATA, this)); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyTOLY.java0000644000175000017500000000514611470746136030152 0ustar drazzibdrazzib/* * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.id3.ID3v24Frames; import java.nio.ByteBuffer; /** * Original lyricist(s)/text writer(s) Text information frame. *

The 'Original lyricist(s)/text writer(s)' frame is intended for the text writer(s) of the original recording, if for example the music in the file should be a cover of a previously released song. The text writers are seperated with the "/" character. *

*

For more details, please refer to the ID3 specifications: *

* * @author : Paul Taylor * @author : Eric Farng * @version $Id: FrameBodyTOLY.java 929 2010-11-17 12:36:46Z paultaylor $ */ public class FrameBodyTOLY extends AbstractFrameBodyTextInfo implements ID3v23FrameBody,ID3v24FrameBody { /** * Creates a new FrameBodyTOLY datatype. */ public FrameBodyTOLY() { } public FrameBodyTOLY(FrameBodyTOLY body) { super(body); } /** * Creates a new FrameBodyTOLY datatype. * * @param textEncoding * @param text */ public FrameBodyTOLY(byte textEncoding, String text) { super(textEncoding, text); } /** * Creates a new FrameBodyTOLY datatype. * * @param byteBuffer * @param frameSize * @throws InvalidTagException */ public FrameBodyTOLY(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_ORIG_LYRICIST; } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyWOAF.java0000644000175000017500000000457611277006322030114 0ustar drazzibdrazzib/* * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.id3.ID3v24Frames; import java.nio.ByteBuffer; /** * Official audio file webpage URL link frames. *

The 'Official audio file webpage' frame is a URL pointing at a file specific webpage. *

*

For more details, please refer to the ID3 specifications: *

* * @author : Paul Taylor * @author : Eric Farng * @version $Id: FrameBodyWOAF.java 832 2009-11-12 13:25:38Z paultaylor $ */ public class FrameBodyWOAF extends AbstractFrameBodyUrlLink implements ID3v24FrameBody, ID3v23FrameBody { /** * Creates a new FrameBodyWOAF datatype. */ public FrameBodyWOAF() { } /** * Creates a new FrameBodyWOAF datatype. * * @param urlLink */ public FrameBodyWOAF(String urlLink) { super(urlLink); } public FrameBodyWOAF(FrameBodyWOAF body) { super(body); } /** * Creates a new FrameBodyWOAF datatype. * * @param byteBuffer * @param frameSize * @throws InvalidTagException */ public FrameBodyWOAF(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_URL_FILE_WEB; } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyRVRB.java0000644000175000017500000001664111277006322030127 0ustar drazzibdrazzib/* * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.datatype.DataTypes; import org.jaudiotagger.tag.datatype.NumberFixedLength; import org.jaudiotagger.tag.id3.ID3v24Frames; import java.nio.ByteBuffer; /** * Reverb frame. *

*

* Yet another subjective one. You may here adjust echoes of different * kinds. Reverb left/right is the delay between every bounce in ms. * Reverb bounces left/right is the number of bounces that should be * made. $FF equals an infinite number of bounces. Feedback is the * amount of volume that should be returned to the next echo bounce. $00 * is 0%, $FF is 100%. If this value were $7F, there would be 50% volume * reduction on the first bounce, 50% of that on the second and so on. * Left to left means the sound from the left bounce to be played in the * left speaker, while left to right means sound from the left bounce to * be played in the right speaker. *

* 'Premix left to right' is the amount of left sound to be mixed in the * right before any reverb is applied, where $00 id 0% and $FF is 100%. * 'Premix right to left' does the same thing, but right to left. * Setting both premix to $FF would result in a mono output (if the * reverb is applied symmetric). There may only be one "RVRB" frame in * each tag. *

* * * * * * * * * * * *
<Header for 'Reverb', ID: "RVRB">
Reverb left (ms) $xx xx
Reverb right (ms) $xx xx
Reverb bounces, left $xx
Reverb bounces, right $xx
Reverb feedback, left to left $xx
Reverb feedback, left to right $xx
Reverb feedback, right to right $xx
Reverb feedback, right to left $xx
Premix left to right $xx
Premix right to left $xx

*

*

For more details, please refer to the ID3 specifications: *

* * @author : Paul Taylor * @author : Eric Farng * @version $Id: FrameBodyRVRB.java 832 2009-11-12 13:25:38Z paultaylor $ */ public class FrameBodyRVRB extends AbstractID3v2FrameBody implements ID3v24FrameBody, ID3v23FrameBody { /** * Creates a new FrameBodyRVRB datatype. */ public FrameBodyRVRB() { // this.setObject("Reverb Left", new Short((short) 0)); // this.setObject("Reverb Right", new Short((short) 0)); // this.setObject("Reverb Bounces Left", new Byte((byte) 0)); // this.setObject("Reverb Bounces Right", new Byte((byte) 0)); // this.setObject("Reverb Feedback Left To Left", new Byte((byte) 0)); // this.setObject("Reverb Feedback Left To Right", new Byte((byte) 0)); // this.setObject("Reverb Feedback Right To Right", new Byte((byte) 0)); // this.setObject("Reverb Feedback Right to Left", new Byte((byte) 0)); // this.setObject("Premix Left To Right", new Byte((byte) 0)); // this.setObject("Premix Right To Left", new Byte((byte) 0)); } public FrameBodyRVRB(FrameBodyRVRB body) { super(body); } /** * Creates a new FrameBodyRVRB datatype. * * @param reverbLeft * @param reverbRight * @param reverbBouncesLeft * @param reverbBouncesRight * @param reverbFeedbackLeftToLeft * @param reverbFeedbackLeftToRight * @param reverbFeedbackRightToRight * @param reverbFeedbackRightToLeft * @param premixLeftToRight * @param premixRightToLeft */ public FrameBodyRVRB(short reverbLeft, short reverbRight, byte reverbBouncesLeft, byte reverbBouncesRight, byte reverbFeedbackLeftToLeft, byte reverbFeedbackLeftToRight, byte reverbFeedbackRightToRight, byte reverbFeedbackRightToLeft, byte premixLeftToRight, byte premixRightToLeft) { this.setObjectValue(DataTypes.OBJ_REVERB_LEFT, reverbLeft); this.setObjectValue(DataTypes.OBJ_REVERB_RIGHT, reverbRight); this.setObjectValue(DataTypes.OBJ_REVERB_BOUNCE_LEFT, reverbBouncesLeft); this.setObjectValue(DataTypes.OBJ_REVERB_BOUNCE_RIGHT, reverbBouncesRight); this.setObjectValue(DataTypes.OBJ_REVERB_FEEDBACK_LEFT_TO_LEFT, reverbFeedbackLeftToLeft); this.setObjectValue(DataTypes.OBJ_REVERB_FEEDBACK_LEFT_TO_RIGHT, reverbFeedbackLeftToRight); this.setObjectValue(DataTypes.OBJ_REVERB_FEEDBACK_RIGHT_TO_RIGHT, reverbFeedbackRightToRight); this.setObjectValue(DataTypes.OBJ_REVERB_FEEDBACK_RIGHT_TO_LEFT, reverbFeedbackRightToLeft); this.setObjectValue(DataTypes.OBJ_PREMIX_LEFT_TO_RIGHT, premixLeftToRight); this.setObjectValue(DataTypes.OBJ_PREMIX_RIGHT_TO_LEFT, premixRightToLeft); } /** * Creates a new FrameBodyRVRB datatype. * * @param byteBuffer * @param frameSize * @throws InvalidTagException if unable to create framebody from buffer */ public FrameBodyRVRB(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_REVERB; } /** * */ protected void setupObjectList() { objectList.add(new NumberFixedLength(DataTypes.OBJ_REVERB_LEFT, this, 2)); objectList.add(new NumberFixedLength(DataTypes.OBJ_REVERB_RIGHT, this, 2)); objectList.add(new NumberFixedLength(DataTypes.OBJ_REVERB_BOUNCE_LEFT, this, 1)); objectList.add(new NumberFixedLength(DataTypes.OBJ_REVERB_BOUNCE_RIGHT, this, 1)); objectList.add(new NumberFixedLength(DataTypes.OBJ_REVERB_FEEDBACK_LEFT_TO_LEFT, this, 1)); objectList.add(new NumberFixedLength(DataTypes.OBJ_REVERB_FEEDBACK_LEFT_TO_RIGHT, this, 1)); objectList.add(new NumberFixedLength(DataTypes.OBJ_REVERB_FEEDBACK_RIGHT_TO_RIGHT, this, 1)); objectList.add(new NumberFixedLength(DataTypes.OBJ_REVERB_FEEDBACK_RIGHT_TO_LEFT, this, 1)); objectList.add(new NumberFixedLength(DataTypes.OBJ_PREMIX_LEFT_TO_RIGHT, this, 1)); objectList.add(new NumberFixedLength(DataTypes.OBJ_PREMIX_RIGHT_TO_LEFT, this, 1)); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyPOPM.java0000644000175000017500000001443711470746136030141 0ustar drazzibdrazzib/* * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.datatype.DataTypes; import org.jaudiotagger.tag.datatype.NumberFixedLength; import org.jaudiotagger.tag.datatype.NumberVariableLength; import org.jaudiotagger.tag.datatype.StringNullTerminated; import org.jaudiotagger.tag.id3.ID3v24Frames; import java.nio.ByteBuffer; /** * Popularimeter frame. *

*

* The purpose of this frame is to specify how good an audio file is. * Many interesting applications could be found to this frame such as a * playlist that features better audiofiles more often than others or it * could be used to profile a person's taste and find other 'good' files * by comparing people's profiles. The frame is very simple. It contains * the email address to the user, one rating byte and a four byte play * counter, intended to be increased with one for every time the file is * played. The email is a terminated string. The rating is 1-255 where * 1 is worst and 255 is best. 0 is unknown. If no personal counter is * wanted it may be omitted. When the counter reaches all one's, one * byte is inserted in front of the counter thus making the counter * eight bits bigger in the same away as the play counter ("PCNT"). * There may be more than one "POPM" frame in each tag, but only one * with the same email address. *

* * * * *
<Header for 'Popularimeter', ID: "POPM">
Email to user<text string> $00
Rating $xx
Counter $xx xx xx xx (xx ...)

*

*

For more details, please refer to the ID3 specifications: *

* * @author : Paul Taylor * @author : Eric Farng * @version $Id: FrameBodyPOPM.java 929 2010-11-17 12:36:46Z paultaylor $ * @todo : Counter should be optional, whereas we always expect it although allow a size of zero * needs testing. */ public class FrameBodyPOPM extends AbstractID3v2FrameBody implements ID3v24FrameBody, ID3v23FrameBody { private static final int RATING_FIELD_SIZE = 1; private static final int COUNTER_MINIMUM_FIELD_SIZE = 0; private static final String MEDIA_MONKEY_NO_EMAIL = "no@email"; /** * Creates a new FrameBodyPOPM datatype. */ public FrameBodyPOPM() { this.setObjectValue(DataTypes.OBJ_EMAIL, ""); this.setObjectValue(DataTypes.OBJ_RATING, (long) 0); this.setObjectValue(DataTypes.OBJ_COUNTER, (long) 0); } public FrameBodyPOPM(FrameBodyPOPM body) { super(body); } /** * Creates a new FrameBodyPOPM datatype. * * @param emailToUser * @param rating * @param counter */ public FrameBodyPOPM(String emailToUser, long rating, long counter) { this.setObjectValue(DataTypes.OBJ_EMAIL, emailToUser); this.setObjectValue(DataTypes.OBJ_RATING, rating); this.setObjectValue(DataTypes.OBJ_COUNTER, counter); } /** * Creates a new FrameBodyPOPM datatype. * * @param byteBuffer * @param frameSize * @throws InvalidTagException if unable to create framebody from buffer */ public FrameBodyPOPM(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * @param description */ public void setEmailToUser(String description) { setObjectValue(DataTypes.OBJ_EMAIL, description); } /** * @return the memail of the user who rated this */ public String getEmailToUser() { return (String) getObjectValue(DataTypes.OBJ_EMAIL); } /** * @return the rating given to this file */ public long getRating() { return ((Number) getObjectValue(DataTypes.OBJ_RATING)).longValue(); } /** * Set the rating given to this file * * @param rating */ public void setRating(long rating) { setObjectValue(DataTypes.OBJ_RATING, rating); } /** * @return the play count of this file */ public long getCounter() { return ((Number) getObjectValue(DataTypes.OBJ_COUNTER)).longValue(); } /** * Set the play counter of this file * * @param counter */ public void setCounter(long counter) { setObjectValue(DataTypes.OBJ_COUNTER, counter); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_POPULARIMETER; } public String getUserFriendlyValue() { return getEmailToUser()+":"+getRating()+":"+getCounter(); } public void parseString(String data) { try { int value = Integer.parseInt(data); setRating(value); setEmailToUser(MEDIA_MONKEY_NO_EMAIL); } catch(NumberFormatException nfe) { } } /** * */ protected void setupObjectList() { objectList.add(new StringNullTerminated(DataTypes.OBJ_EMAIL, this)); objectList.add(new NumberFixedLength(DataTypes.OBJ_RATING, this, RATING_FIELD_SIZE)); objectList.add(new NumberVariableLength(DataTypes.OBJ_COUNTER, this, COUNTER_MINIMUM_FIELD_SIZE)); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyRVAD.java0000644000175000017500000000514011305717447030111 0ustar drazzibdrazzib/* * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.datatype.ByteArraySizeTerminated; import org.jaudiotagger.tag.datatype.DataTypes; import org.jaudiotagger.tag.id3.ID3v23Frames; import java.nio.ByteBuffer; /** * Relative volume adjustment frame. *

* Only partially implemented. * * @author : Paul Taylor * @author : Eric Farng * @version $Id: FrameBodyRVAD.java 857 2009-12-03 11:21:11Z paultaylor $ */ public class FrameBodyRVAD extends AbstractID3v2FrameBody implements ID3v23FrameBody { /** * Creates a new FrameBodyRVAD datatype. */ public FrameBodyRVAD() { } public FrameBodyRVAD(FrameBodyRVAD copyObject) { super(copyObject); } /** * Convert from V4 to V3 Frame * @param body */ public FrameBodyRVAD(FrameBodyRVA2 body) { setObjectValue(DataTypes.OBJ_DATA, body.getObjectValue(DataTypes.OBJ_DATA)); } /** * Creates a new FrameBodyRVAD datatype. * * @param byteBuffer * @param frameSize * @throws InvalidTagException if unable to create framebody from buffer */ public FrameBodyRVAD(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v23Frames.FRAME_ID_V3_RELATIVE_VOLUME_ADJUSTMENT; } /** * Setup the Object List. A byte Array which will be read upto frame size * bytes. */ protected void setupObjectList() { objectList.add(new ByteArraySizeTerminated(DataTypes.OBJ_DATA, this)); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyTPE4.java0000644000175000017500000000510011277006322030054 0ustar drazzibdrazzib/* * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.id3.ID3v24Frames; import java.nio.ByteBuffer; /** * Interpreted, remixed, or otherwise modified by Text information frame. *

The 'Interpreted, remixed, or otherwise modified by' frame contains more information about the people behind a remix and similar interpretations of another existing piece. *

*

For more details, please refer to the ID3 specifications: *

* * @author : Paul Taylor * @author : Eric Farng * @version $Id: FrameBodyTPE4.java 832 2009-11-12 13:25:38Z paultaylor $ */ public class FrameBodyTPE4 extends AbstractFrameBodyTextInfo implements ID3v24FrameBody, ID3v23FrameBody { /** * Creates a new FrameBodyTPE4 datatype. */ public FrameBodyTPE4() { } public FrameBodyTPE4(FrameBodyTPE4 body) { super(body); } /** * Creates a new FrameBodyTPE4 datatype. * * @param textEncoding * @param text */ public FrameBodyTPE4(byte textEncoding, String text) { super(textEncoding, text); } /** * Creates a new FrameBodyTPE4 datatype. * * @param byteBuffer * @param frameSize * @throws java.io.IOException * @throws InvalidTagException */ public FrameBodyTPE4(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_REMIXED; } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyTSOA.java0000644000175000017500000000430011277006322030107 0ustar drazzibdrazzib/** * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: FrameBodyTSOA.java 832 2009-11-12 13:25:38Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Description: */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.id3.ID3v24Frames; import java.nio.ByteBuffer; /** * Album Sort name */ public class FrameBodyTSOA extends AbstractFrameBodyTextInfo implements ID3v24FrameBody, ID3v23FrameBody { /** * Creates a new FrameBodyTSOA datatype. */ public FrameBodyTSOA() { } public FrameBodyTSOA(FrameBodyTSOA body) { super(body); } /** * Creates a new FrameBodyTSOA datatype. * * @param textEncoding * @param text */ public FrameBodyTSOA(byte textEncoding, String text) { super(textEncoding, text); } /** * Creates a new FrameBodyTSOA datatype. * * @param byteBuffer * @param frameSize * @throws InvalidTagException */ public FrameBodyTSOA(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_ALBUM_SORT_ORDER; } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyWPUB.java0000644000175000017500000000466111277006322030130 0ustar drazzibdrazzib/* * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.id3.ID3v24Frames; import java.nio.ByteBuffer; /** * Publishers official webpage URL link frames. *

The 'Publishers official webpage' frame is a URL pointing at the official wepage for the publisher. *

*

For more details, please refer to the ID3 specifications: *

* * @author : Paul Taylor * @author : Eric Farng * @version $Id: FrameBodyWPUB.java 832 2009-11-12 13:25:38Z paultaylor $ */ public class FrameBodyWPUB extends AbstractFrameBodyUrlLink implements ID3v24FrameBody, ID3v23FrameBody { /** * Creates a new FrameBodyWPUB datatype. */ public FrameBodyWPUB() { } /** * Creates a new FrameBodyWPUB datatype. * * @param urlLink */ public FrameBodyWPUB(String urlLink) { super(urlLink); } public FrameBodyWPUB(FrameBodyWPUB body) { super(body); } /** * Creates a new FrameBodyWPUB datatype. * * @param byteBuffer * @param frameSize * @throws java.io.IOException * @throws InvalidTagException */ public FrameBodyWPUB(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_URL_PUBLISHERS; } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyGEOB.java0000644000175000017500000001321411277026507030070 0ustar drazzibdrazzib/* * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.datatype.*; import org.jaudiotagger.tag.id3.ID3v24Frames; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; import java.io.ByteArrayOutputStream; import java.nio.ByteBuffer; /** * General encapsulated object frame. *

*

* In this frame any type of file can be encapsulated. After the header, * 'Frame size' and 'Encoding' follows 'MIME type' represented as * as a terminated string encoded with ISO-8859-1. The * filename is case sensitive and is encoded as 'Encoding'. Then follows * a content description as terminated string, encoded as 'Encoding'. * The last thing in the frame is the actual object. The first two * strings may be omitted, leaving only their terminations. There may be more than one "GEOB" * frame in each tag, but only one with the same content descriptor. *

* * * * * * *
<Header for 'General encapsulated object', ID: "GEOB">
Text encoding $xx
MIME type <text string> $00
Filename <text string according to encoding> $00 (00)
Content description $00 (00)
Encapsulated object <binary data>

*

*

For more details, please refer to the ID3 specifications: *

* * @author : Paul Taylor * @author : Eric Farng * @version $Id: FrameBodyGEOB.java 836 2009-11-12 15:44:07Z paultaylor $ */ public class FrameBodyGEOB extends AbstractID3v2FrameBody implements ID3v24FrameBody, ID3v23FrameBody { /** * Creates a new FrameBodyGEOB datatype. */ public FrameBodyGEOB() { this.setObjectValue(DataTypes.OBJ_TEXT_ENCODING, TextEncoding.ISO_8859_1); this.setObjectValue(DataTypes.OBJ_MIME_TYPE, ""); this.setObjectValue(DataTypes.OBJ_FILENAME, ""); this.setObjectValue(DataTypes.OBJ_DESCRIPTION, ""); this.setObjectValue(DataTypes.OBJ_DATA, new byte[0]); } public FrameBodyGEOB(FrameBodyGEOB body) { super(body); } /** * Creates a new FrameBodyGEOB datatype. * * @param textEncoding * @param mimeType * @param filename * @param description * @param object */ public FrameBodyGEOB(byte textEncoding, String mimeType, String filename, String description, byte[] object) { this.setObjectValue(DataTypes.OBJ_TEXT_ENCODING, textEncoding); this.setObjectValue(DataTypes.OBJ_MIME_TYPE, mimeType); this.setObjectValue(DataTypes.OBJ_FILENAME, filename); this.setObjectValue(DataTypes.OBJ_DESCRIPTION, description); this.setObjectValue(DataTypes.OBJ_DATA, object); } /** * Creates a new FrameBodyGEOB datatype. * * @param byteBuffer * @param frameSize * @throws InvalidTagException if unable to create framebody from buffer */ public FrameBodyGEOB(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * @param description */ public void setDescription(String description) { setObjectValue(DataTypes.OBJ_DESCRIPTION, description); } /** * @return the description field */ public String getDescription() { return (String) getObjectValue(DataTypes.OBJ_DESCRIPTION); } /** * @return */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_GENERAL_ENCAPS_OBJECT; } /** * If the filename or description cannot be encoded using current encoder, change the encoder */ public void write(ByteArrayOutputStream tagBuffer) { if (!((AbstractString) getObject(DataTypes.OBJ_FILENAME)).canBeEncoded()) { this.setTextEncoding(TextEncoding.UTF_16); } if (!((AbstractString) getObject(DataTypes.OBJ_DESCRIPTION)).canBeEncoded()) { this.setTextEncoding(TextEncoding.UTF_16); } super.write(tagBuffer); } /** * */ protected void setupObjectList() { objectList.add(new NumberHashMap(DataTypes.OBJ_TEXT_ENCODING, this, TextEncoding.TEXT_ENCODING_FIELD_SIZE)); objectList.add(new StringNullTerminated(DataTypes.OBJ_MIME_TYPE, this)); objectList.add(new TextEncodedStringNullTerminated(DataTypes.OBJ_FILENAME, this)); objectList.add(new TextEncodedStringNullTerminated(DataTypes.OBJ_DESCRIPTION, this)); objectList.add(new ByteArraySizeTerminated(DataTypes.OBJ_DATA, this)); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyCOMR.java0000644000175000017500000002151111330335337030105 0ustar drazzibdrazzib/* * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.datatype.*; import org.jaudiotagger.tag.id3.ID3v24Frames; import org.jaudiotagger.tag.id3.valuepair.ReceivedAsTypes; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; import java.io.ByteArrayOutputStream; import java.nio.ByteBuffer; /** * Commercial frame. *

*

* This frame enables several competing offers in the same tag by * bundling all needed information. That makes this frame rather complex * but it's an easier solution than if one tries to achieve the same * result with several frames. The frame begins, after the frame ID, * size and encoding fields, with a price string field. A price is * constructed by one three character currency code, encoded according * to ISO-4217 alphabetic currency code, followed by a * numerical value where "." is used as decimal seperator. In the price * string several prices may be concatenated, seperated by a "/" * character, but there may only be one currency of each type. *

* The price string is followed by an 8 character date string in the * format YYYYMMDD, describing for how long the price is valid. After * that is a contact URL, with which the user can contact the seller, * followed by a one byte 'received as' field. It describes how the * audio is delivered when bought according to the following list: *

* * * * * * * * * *
$00 Other
$01 Standard CD album with other songs
$02 Compressed audio on CD
$03 File over the Internet
$04 Stream over the Internet
$05 As note sheets
$06 As note sheets in a book with other sheets
$07 Music on other media
$08 Non-musical merchandise

* Next follows a terminated string with the name of the seller followed * by a terminated string with a short description of the product. The * last thing is the ability to include a company logotype. The first of * them is the 'Picture MIME type' field containing information about * which picture format is used. In the event that the MIME media type * name is omitted, "image/" will be implied. Currently only "image/png" * and "image/jpeg" are allowed. This format string is followed by the * binary picture data. This two last fields may be omitted if no * picture is to attach. *

* * * * * * * * * * *
<Header for 'Commercial frame', ID: "COMR">
Text encoding $xx
Price string <text string> $00
Valid until <text string>
Contact URL <text string> $00
Received as $xx
Name of seller<text string according to encoding> $00 (00)
Description <text string according to encoding> $00 (00)
Picture MIME type<string> $00
Seller logo <binary data>

*

*

For more details, please refer to the ID3 specifications: *

* * @author : Paul Taylor * @author : Eric Farng * @version $Id: FrameBodyCOMR.java 867 2010-01-28 16:27:11Z paultaylor $ */ public class FrameBodyCOMR extends AbstractID3v2FrameBody implements ID3v24FrameBody, ID3v23FrameBody { /** * Creates a new FrameBodyCOMR datatype. */ public FrameBodyCOMR() { // this.setObject("Text Encoding", new Byte((byte) 0)); // this.setObject("Price String", ""); // this.setObject("Valid Until", ""); // this.setObject("Contact URL", ""); // this.setObject("Recieved As", new Byte((byte) 0)); // this.setObject("Name Of Seller", ""); // this.setObject(ObjectTypes.OBJ_DESCRIPTION, ""); // this.setObject("Picture MIME Type", ""); // this.setObject("Seller Logo", new byte[0]); } public FrameBodyCOMR(FrameBodyCOMR body) { super(body); } /** * Creates a new FrameBodyCOMR datatype. * * @param textEncoding * @param priceString * @param validUntil * @param contactUrl * @param recievedAs * @param nameOfSeller * @param description * @param mimeType * @param sellerLogo */ public FrameBodyCOMR(byte textEncoding, String priceString, String validUntil, String contactUrl, byte recievedAs, String nameOfSeller, String description, String mimeType, byte[] sellerLogo) { this.setObjectValue(DataTypes.OBJ_TEXT_ENCODING, textEncoding); this.setObjectValue(DataTypes.OBJ_PRICE_STRING, priceString); this.setObjectValue(DataTypes.OBJ_VALID_UNTIL, validUntil); this.setObjectValue(DataTypes.OBJ_CONTACT_URL, contactUrl); this.setObjectValue(DataTypes.OBJ_RECIEVED_AS, recievedAs); this.setObjectValue(DataTypes.OBJ_SELLER_NAME, nameOfSeller); this.setObjectValue(DataTypes.OBJ_DESCRIPTION, description); this.setObjectValue(DataTypes.OBJ_MIME_TYPE, mimeType); this.setObjectValue(DataTypes.OBJ_SELLER_LOGO, sellerLogo); } /** * Creates a new FrameBodyCOMR datatype. * * @param byteBuffer * @param frameSize * @throws InvalidTagException if unable to create framebody from buffer */ public FrameBodyCOMR(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_COMMERCIAL_FRAME; } /** * @return */ public String getOwner() { return (String) getObjectValue(DataTypes.OBJ_OWNER); } /** * @param description */ public void getOwner(String description) { setObjectValue(DataTypes.OBJ_OWNER, description); } /** * If the seller or description cannot be encoded using current encoder, change the encoder */ public void write(ByteArrayOutputStream tagBuffer) { if (!((AbstractString) getObject(DataTypes.OBJ_SELLER_NAME)).canBeEncoded()) { this.setTextEncoding(TextEncoding.UTF_16); } if (!((AbstractString) getObject(DataTypes.OBJ_DESCRIPTION)).canBeEncoded()) { this.setTextEncoding(TextEncoding.UTF_16); } super.write(tagBuffer); } /** * */ protected void setupObjectList() { objectList.add(new NumberHashMap(DataTypes.OBJ_TEXT_ENCODING, this, TextEncoding.TEXT_ENCODING_FIELD_SIZE)); objectList.add(new StringNullTerminated(DataTypes.OBJ_PRICE_STRING, this)); objectList.add(new StringDate(DataTypes.OBJ_VALID_UNTIL, this)); objectList.add(new StringNullTerminated(DataTypes.OBJ_CONTACT_URL, this)); objectList.add(new NumberHashMap(DataTypes.OBJ_RECIEVED_AS, this, ReceivedAsTypes.RECEIVED_AS_FIELD_SIZE)); objectList.add(new TextEncodedStringNullTerminated(DataTypes.OBJ_SELLER_NAME, this)); objectList.add(new TextEncodedStringNullTerminated(DataTypes.OBJ_DESCRIPTION, this)); objectList.add(new StringNullTerminated(DataTypes.OBJ_MIME_TYPE, this)); objectList.add(new ByteArraySizeTerminated(DataTypes.OBJ_SELLER_LOGO, this)); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/ID3v22FrameBody.java0000644000175000017500000000212310573256703030263 0ustar drazzibdrazzib/* * Jaudiotagger Copyright (C)2004,2005 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3.framebody; /** * Indicates that this is a framebody used in ID3v22Tags. * * @author Paul Taylor * @version $Id: ID3v22FrameBody.java 243 2007-03-06 12:25:39Z paultaylor $ */ public interface ID3v22FrameBody { } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyAPIC.java0000644000175000017500000002404011470746136030071 0ustar drazzibdrazzib/* * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.audio.generic.Utils; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.datatype.*; import org.jaudiotagger.tag.id3.ID3v24Frames; import org.jaudiotagger.tag.id3.valuepair.ImageFormats; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; import org.jaudiotagger.tag.reference.PictureTypes; import java.io.ByteArrayOutputStream; import java.nio.ByteBuffer; /** * Attached picture frame. *

*

* This frame contains a picture directly related to the audio file. * Image format is the MIME type and subtype for the image. In * the event that the MIME media type name is omitted, "image/" will be * implied. The "image/png" or "image/jpeg" picture format * should be used when interoperability is wanted. Description is a * short description of the picture, represented as a terminated * textstring. The description has a maximum length of 64 characters, * but may be empty. There may be several pictures attached to one file, * each in their individual "APIC" frame, but only one with the same * content descriptor. There may only be one picture with the picture * type declared as picture type $01 and $02 respectively. There is the * possibility to put only a link to the image file by using the 'MIME * type' "-->" and having a complete URL instead of picture data. * The use of linked files should however be used sparingly since there * is the risk of separation of files. *

* * * * * * *
<Header for 'Attached picture', ID: "APIC">
Text encoding $xx
MIME type <text string> $00
Picture type $xx
Description <text string according to encoding> $00 (00)
Picture data <binary data>

*

* * * * * * * * * * * * * * * * * * * * * * *
Picture type:$00 Other
$01 32x32 pixels 'file icon' (PNG only)
$02 Other file icon
$03 Cover (front)
$04 Cover (back)
$05 Leaflet page
$06 Media (e.g. lable side of CD)
$07 Lead artist/lead performer/soloist
$08 Artist/performer
$09 Conductor
$0A Band/Orchestra
$0B Composer
$0C Lyricist/text writer
$0D Recording Location
$0E During recording
$0F During performance
$10 Movie/video screen capture
$11 A bright coloured fish
$12 Illustration
$13 Band/artist logotype
$14 Publisher/Studio logotype

*

*

For more details, please refer to the ID3 specifications: *

* * @author : Paul Taylor * @author : Eric Farng * @version $Id: FrameBodyAPIC.java 929 2010-11-17 12:36:46Z paultaylor $ */ public class FrameBodyAPIC extends AbstractID3v2FrameBody implements ID3v24FrameBody, ID3v23FrameBody { public static final String IMAGE_IS_URL = "-->"; /** * Creates a new FrameBodyAPIC datatype. */ public FrameBodyAPIC() { //Initilise default text encoding setObjectValue(DataTypes.OBJ_TEXT_ENCODING, TextEncoding.ISO_8859_1); } public FrameBodyAPIC(FrameBodyAPIC body) { super(body); } /** * Conversion from v2 PIC to v3/v4 APIC * @param body */ public FrameBodyAPIC(FrameBodyPIC body) { this.setObjectValue(DataTypes.OBJ_TEXT_ENCODING, body.getTextEncoding()); this.setObjectValue(DataTypes.OBJ_MIME_TYPE, ImageFormats.getMimeTypeForFormat((String) body.getObjectValue(DataTypes.OBJ_IMAGE_FORMAT))); this.setObjectValue(DataTypes.OBJ_PICTURE_TYPE, body.getObjectValue(DataTypes.OBJ_PICTURE_TYPE)); this.setObjectValue(DataTypes.OBJ_DESCRIPTION, body.getDescription()); this.setObjectValue(DataTypes.OBJ_PICTURE_DATA, body.getObjectValue(DataTypes.OBJ_PICTURE_DATA)); } /** * Creates a new FrameBodyAPIC datatype. * * @param textEncoding * @param mimeType * @param pictureType * @param description * @param data */ public FrameBodyAPIC(byte textEncoding, String mimeType, byte pictureType, String description, byte[] data) { this.setObjectValue(DataTypes.OBJ_TEXT_ENCODING, textEncoding); this.setMimeType(mimeType); this.setPictureType(pictureType); this.setDescription(description); this.setImageData(data); } /** * Creates a new FrameBodyAPIC datatype. * * @param byteBuffer * @param frameSize * @throws InvalidTagException if unable to create framebody from buffer */ public FrameBodyAPIC(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } public String getUserFriendlyValue() { return getMimeType()+":"+getDescription()+":"+getImageData().length; } /** * Set a description of the image * * @param description */ public void setDescription(String description) { setObjectValue(DataTypes.OBJ_DESCRIPTION, description); } /** * Get a description of the image * * @return a description of the image */ public String getDescription() { return (String) getObjectValue(DataTypes.OBJ_DESCRIPTION); } /** * Set mimeType * * @param mimeType */ public void setMimeType(String mimeType) { setObjectValue(DataTypes.OBJ_MIME_TYPE, mimeType); } /** * Get mimetype * * @return a description of the image */ public String getMimeType() { return (String) getObjectValue(DataTypes.OBJ_MIME_TYPE); } /** * Set imageData * * @param imageData */ public void setImageData(byte[] imageData) { setObjectValue(DataTypes.OBJ_PICTURE_DATA, imageData); } /** * Get Image data * * @return */ public byte[] getImageData() { return (byte[]) getObjectValue(DataTypes.OBJ_PICTURE_DATA); } /** * Set Picture Type * * @param pictureType */ public void setPictureType(byte pictureType) { setObjectValue(DataTypes.OBJ_PICTURE_TYPE, pictureType); } /** * @return picturetype */ public int getPictureType() { return ((Long) getObjectValue(DataTypes.OBJ_PICTURE_TYPE)).intValue(); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_ATTACHED_PICTURE; } /** * If the description cannot be encoded using current encoder, change the encoder */ public void write(ByteArrayOutputStream tagBuffer) { if (!((AbstractString) getObject(DataTypes.OBJ_DESCRIPTION)).canBeEncoded()) { this.setTextEncoding(TextEncoding.UTF_16); } super.write(tagBuffer); } /** * */ protected void setupObjectList() { objectList.add(new NumberHashMap(DataTypes.OBJ_TEXT_ENCODING, this, TextEncoding.TEXT_ENCODING_FIELD_SIZE)); objectList.add(new StringNullTerminated(DataTypes.OBJ_MIME_TYPE, this)); objectList.add(new NumberHashMap(DataTypes.OBJ_PICTURE_TYPE, this, PictureTypes.PICTURE_TYPE_FIELD_SIZE)); objectList.add(new TextEncodedStringNullTerminated(DataTypes.OBJ_DESCRIPTION, this)); objectList.add(new ByteArraySizeTerminated(DataTypes.OBJ_PICTURE_DATA, this)); } /** * @return true if imagedata is held as a url rather than actually being imagedata */ public boolean isImageUrl() { return getMimeType() != null && getMimeType().equals(IMAGE_IS_URL); } /** * @return the image url if there is otherwise return an empty String */ public String getImageUrl() { if (isImageUrl()) { return Utils.getString(((byte[]) getObjectValue(DataTypes.OBJ_PICTURE_DATA)), 0, ((byte[]) getObjectValue(DataTypes.OBJ_PICTURE_DATA)).length, TextEncoding.CHARSET_ISO_8859_1); } else { return ""; } } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyTIPL.java0000644000175000017500000001576311470746136030141 0ustar drazzibdrazzib/** * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: FrameBodyTIPL.java 929 2010-11-17 12:36:46Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Description: * People List * */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.datatype.DataTypes; import org.jaudiotagger.tag.datatype.NumberHashMap; import org.jaudiotagger.tag.datatype.Pair; import org.jaudiotagger.tag.datatype.PairedTextEncodedStringNullTerminated; import org.jaudiotagger.tag.id3.ID3v24Frames; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; import java.io.ByteArrayOutputStream; import java.nio.ByteBuffer; import java.util.Map; import java.util.StringTokenizer; /** * The 'Involved people list' is intended as a mapping between functions like producer and names. Every odd field is a * function and every even is an name or a comma delimited list of names. *

*/ public class FrameBodyTIPL extends AbstractID3v2FrameBody implements ID3v24FrameBody { //Standard function names, taken from Picard Mapping public static final String ENGINEER = "engineer"; public static final String MIXER = "mix"; public static final String DJMIXER = "DJ-mix"; public static final String PRODUCER = "producer"; public static final String ARRANGER = "arranger"; /** * Creates a new FrameBodyTIPL datatype. */ public FrameBodyTIPL() { setObjectValue(DataTypes.OBJ_TEXT_ENCODING, TextEncoding.ISO_8859_1); } /** * Creates a new FrameBodyTIPL data type. * * @param textEncoding * @param text */ public FrameBodyTIPL(byte textEncoding, String text) { setObjectValue(DataTypes.OBJ_TEXT_ENCODING, textEncoding); setText(text); } /** * Creates a new FrameBodyTIPL data type. * * @param byteBuffer * @param frameSize * @throws InvalidTagException */ public FrameBodyTIPL(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * Convert from V3 to V4 Frame * * @param body */ public FrameBodyTIPL(FrameBodyIPLS body) { setObjectValue(DataTypes.OBJ_TEXT_ENCODING, body.getTextEncoding()); setObjectValue(DataTypes.OBJ_TEXT, body.getPairing()); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_INVOLVED_PEOPLE; } /** * Set the text, decoded as pairs of involvee - involvment * * @param text */ public void setText(String text) { PairedTextEncodedStringNullTerminated.ValuePairs value = new PairedTextEncodedStringNullTerminated.ValuePairs(); StringTokenizer stz = new StringTokenizer(text, "\0"); while (stz.hasMoreTokens()) { String key =stz.nextToken(); if(stz.hasMoreTokens()) { value.add(key, stz.nextToken()); } } setObjectValue(DataTypes.OBJ_TEXT, value); } public void addPair(String text) { PairedTextEncodedStringNullTerminated.ValuePairs value = ((PairedTextEncodedStringNullTerminated) getObject(DataTypes.OBJ_TEXT)).getValue(); StringTokenizer stz = new StringTokenizer(text, "\0"); if (stz.hasMoreTokens()) { value.add(stz.nextToken(),stz.nextToken()); } } /** * Because have a text encoding we need to check the data values do not contain characters that cannot be encoded in * current encoding before we write data. If they do change the encoding. */ public void write(ByteArrayOutputStream tagBuffer) { if (!((PairedTextEncodedStringNullTerminated) getObject(DataTypes.OBJ_TEXT)).canBeEncoded()) { this.setTextEncoding(TextEncoding.UTF_16); } super.write(tagBuffer); } /** * Consists of a text encoding , and then a series of null terminated Strings, there should be an even number * of Strings as they are paired as involvement/involvee */ protected void setupObjectList() { objectList.add(new NumberHashMap(DataTypes.OBJ_TEXT_ENCODING, this, TextEncoding.TEXT_ENCODING_FIELD_SIZE)); objectList.add(new PairedTextEncodedStringNullTerminated(DataTypes.OBJ_TEXT, this)); } public PairedTextEncodedStringNullTerminated.ValuePairs getPairing() { return (PairedTextEncodedStringNullTerminated.ValuePairs) getObject(DataTypes.OBJ_TEXT).getValue(); } /** * Get key at index * * @param index * @return value at index */ public String getKeyAtIndex(int index) { PairedTextEncodedStringNullTerminated text = (PairedTextEncodedStringNullTerminated) getObject(DataTypes.OBJ_TEXT); return (String) text.getValue().getMapping().get(index).getKey(); } /** * Get value at index * * @param index * @return value at index */ public String getValueAtIndex(int index) { PairedTextEncodedStringNullTerminated text = (PairedTextEncodedStringNullTerminated) getObject(DataTypes.OBJ_TEXT); return (String) text.getValue().getMapping().get(index).getValue(); } /** * @return number of text pairs */ public int getNumberOfPairs() { PairedTextEncodedStringNullTerminated text = (PairedTextEncodedStringNullTerminated) getObject(DataTypes.OBJ_TEXT); return text.getValue().getNumberOfPairs(); } public String getText() { PairedTextEncodedStringNullTerminated text = (PairedTextEncodedStringNullTerminated) getObject(DataTypes.OBJ_TEXT); StringBuilder sb = new StringBuilder(); int count = 1; for (Pair entry : text.getValue().getMapping()) { sb.append(entry.getKey() + '\0' + entry.getValue()); if (count != getNumberOfPairs()) { sb.append('\0'); } count++; } return sb.toString(); } public String getUserFriendlyValue() { return getText(); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyWPAY.java0000644000175000017500000000457411277006322030136 0ustar drazzibdrazzib/* * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.id3.ID3v24Frames; import java.nio.ByteBuffer; /** * Payment URL link frames. *

The 'Payment' frame is a URL pointing at a webpage that will handle the process of paying for this file. *

*

For more details, please refer to the ID3 specifications: *

* * @author : Paul Taylor * @author : Eric Farng * @version $Id: FrameBodyWPAY.java 832 2009-11-12 13:25:38Z paultaylor $ */ public class FrameBodyWPAY extends AbstractFrameBodyUrlLink implements ID3v24FrameBody, ID3v23FrameBody { /** * Creates a new FrameBodyWPAY datatype. */ public FrameBodyWPAY() { } /** * Creates a new FrameBodyWPAY datatype. * * @param urlLink */ public FrameBodyWPAY(String urlLink) { super(urlLink); } public FrameBodyWPAY(FrameBodyWPAY body) { super(body); } /** * Creates a new FrameBodyWPAY datatype. * * @param byteBuffer * @param frameSize * @throws InvalidTagException */ public FrameBodyWPAY(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_URL_PAYMENT; } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyMCDI.java0000644000175000017500000000676511277006322030076 0ustar drazzibdrazzib/* * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.datatype.ByteArraySizeTerminated; import org.jaudiotagger.tag.datatype.DataTypes; import org.jaudiotagger.tag.id3.ID3v24Frames; import java.nio.ByteBuffer; /** * Music CD identifier frame. *

*

* This frame is intended for music that comes from a CD, so that the CD * can be identified in databases such as the CDDB. The frame * consists of a binary dump of the Table Of Contents, TOC, from the CD, * which is a header of 4 bytes and then 8 bytes/track on the CD plus 8 * bytes for the 'lead out' making a maximum of 804 bytes. The offset to * the beginning of every track on the CD should be described with a * four bytes absolute CD-frame address per track, and not with absolute * time. This frame requires a present and valid "TRCK" frame, even if * the CD's only got one track. There may only be one "MCDI" frame in * each tag. *

* * *
<Header for 'Music CD identifier', ID: "MCDI">
CD TOC<binary data>

*

*

For more details, please refer to the ID3 specifications: *

* * @author : Paul Taylor * @author : Eric Farng * @version $Id: FrameBodyMCDI.java 832 2009-11-12 13:25:38Z paultaylor $ */ public class FrameBodyMCDI extends AbstractID3v2FrameBody implements ID3v24FrameBody, ID3v23FrameBody { /** * Creates a new FrameBodyMCDI datatype. */ public FrameBodyMCDI() { this.setObjectValue(DataTypes.OBJ_DATA, new byte[0]); } public FrameBodyMCDI(FrameBodyMCDI body) { super(body); } /** * Creates a new FrameBodyMCDI datatype. * * @param cdTOC */ public FrameBodyMCDI(byte[] cdTOC) { this.setObjectValue(DataTypes.OBJ_DATA, cdTOC); } /** * Creates a new FrameBodyMCDI datatype. * * @param byteBuffer * @param frameSize * @throws InvalidTagException if unable to create framebody from buffer */ public FrameBodyMCDI(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_MUSIC_CD_ID; } /** * */ protected void setupObjectList() { objectList.add(new ByteArraySizeTerminated(DataTypes.OBJ_DATA, this)); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyTDRC.java0000644000175000017500000003030511277026507030110 0ustar drazzibdrazzib/** * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: FrameBodyTDRC.java 836 2009-11-12 15:44:07Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Description: * */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.datatype.DataTypes; import org.jaudiotagger.tag.id3.ID3v23Frames; import org.jaudiotagger.tag.id3.ID3v24Frames; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; import java.nio.ByteBuffer; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Locale; import java.util.logging.Level; public class FrameBodyTDRC extends AbstractFrameBodyTextInfo implements ID3v24FrameBody { /** * Used when converting from v3 tags */ private String originalID; private String year = ""; private String time = ""; private String date = ""; private String reco = ""; private static SimpleDateFormat formatYearIn, formatYearOut; private static SimpleDateFormat formatDateIn, formatDateOut; private static SimpleDateFormat formatTimeIn, formatTimeOut; private static final List formatters = new ArrayList(); private static final int PRECISION_SECOND = 0; private static final int PRECISION_MINUTE = 1; private static final int PRECISION_HOUR = 2; private static final int PRECISION_DAY = 3; private static final int PRECISION_MONTH = 4; private static final int PRECISION_YEAR = 5; static { //This is allowable v24 format , we use UK Locale not because we are restricting to UK //but because these formats are fixed in ID3 spec, and could possibly get unexpected results if library //used with a default locale that has Date Format Symbols that intefere with the pattern formatters.add(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.UK)); formatters.add(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm", Locale.UK)); formatters.add(new SimpleDateFormat("yyyy-MM-dd'T'HH", Locale.UK)); formatters.add(new SimpleDateFormat("yyyy-MM-dd", Locale.UK)); formatters.add(new SimpleDateFormat("yyyy-MM", Locale.UK)); formatters.add(new SimpleDateFormat("yyyy", Locale.UK)); //These are formats used by v23 Frames formatYearIn = new SimpleDateFormat("yyyy", Locale.UK); formatYearOut = new SimpleDateFormat("yyyy", Locale.UK); formatDateIn = new SimpleDateFormat("ddMM", Locale.UK); formatDateOut = new SimpleDateFormat("-MM-dd", Locale.UK); formatTimeIn = new SimpleDateFormat("HHmm", Locale.UK); formatTimeOut = new SimpleDateFormat("'T'HH:mm", Locale.UK); } /** * Creates a new FrameBodyTDRC datatype. */ public FrameBodyTDRC() { super(); } public FrameBodyTDRC(FrameBodyTDRC body) { super(body); } /** * Retrieve the original identifier * @return */ public String getOriginalID() { return originalID; } /** * When this has been generated as an amalgamation of v3 frames assumes * the v3 frames match the the format in specification and convert them * to their equivalent v4 format and return the generated String. * i.e if the v3 frames contain a valid value this will return a valid * v4 value, if not this won't. */ /** * Synchronized because SimpleDatFormat arent thread safe * * @param formatDate * @param parseDate * @param text * @return */ private static synchronized String formatAndParse(SimpleDateFormat formatDate,SimpleDateFormat parseDate,String text) { try { return formatDate.format(parseDate.parse(text)); } catch (ParseException e) { logger.warning("Unable to parse:" + text); } return ""; } public String getFormattedText() { StringBuffer sb = new StringBuffer(); if (originalID == null) { return this.getText(); } else { if (year != null && !(year.equals(""))) { sb.append(formatAndParse(formatYearOut,formatYearIn,year)); } if (!date.equals("")) { sb.append(formatAndParse(formatDateOut,formatDateIn,date)); } if (!time.equals("")) { sb.append(formatAndParse(formatTimeOut,formatTimeIn,time)); } return sb.toString(); } } public void setYear(String year) { logger.finest("Setting year to" + year); this.year = year; } public void setTime(String time) { logger.finest("Setting time to:" + time); this.time = time; } public void setDate(String date) { logger.finest("Setting date to:" + date); this.date = date; } public void setReco(String reco) { this.reco = reco; } public String getYear() { return year; } public String getTime() { return time; } public String getDate() { return date; } public String getReco() { return reco; } /** * When converting v3 YEAR to v4 TDRC frame * @param body */ public FrameBodyTDRC(FrameBodyTYER body) { originalID = ID3v23Frames.FRAME_ID_V3_TYER; year = body.getText(); setObjectValue(DataTypes.OBJ_TEXT_ENCODING, TextEncoding.ISO_8859_1); setObjectValue(DataTypes.OBJ_TEXT, body.getText()); } /** * When converting v3 TIME to v4 TDRC frame * @param body */ public FrameBodyTDRC(FrameBodyTIME body) { originalID = ID3v23Frames.FRAME_ID_V3_TIME; time = body.getText(); setObjectValue(DataTypes.OBJ_TEXT_ENCODING, TextEncoding.ISO_8859_1); setObjectValue(DataTypes.OBJ_TEXT, body.getText()); } /** * When converting v3 TDAT to v4 TDRC frame * @param body */ public FrameBodyTDRC(FrameBodyTDAT body) { originalID = ID3v23Frames.FRAME_ID_V3_TDAT; date = body.getText(); setObjectValue(DataTypes.OBJ_TEXT_ENCODING, TextEncoding.ISO_8859_1); setObjectValue(DataTypes.OBJ_TEXT, body.getText()); } /** * When converting v3 TRDA to v4 TDRC frame * @param body */ public FrameBodyTDRC(FrameBodyTRDA body) { originalID = ID3v23Frames.FRAME_ID_V3_TRDA; reco = body.getText(); setObjectValue(DataTypes.OBJ_TEXT_ENCODING, TextEncoding.ISO_8859_1); setObjectValue(DataTypes.OBJ_TEXT, body.getText()); } /** * Creates a new FrameBodyTDRC datatype. * * @param textEncoding * @param text */ public FrameBodyTDRC(byte textEncoding, String text) { super(textEncoding, text); //Find the date format of the text for (int i = 0; i < formatters.size(); i++) { try { Date d; synchronized(formatters.get(i)) { d = formatters.get(i).parse(getText()); } //If able to parse a date from the text if (d != null) { extractID3v23Formats(d, i); break; } } //Dont display will occur for each failed format catch (ParseException e) { //Do nothing; } catch(NumberFormatException nfe) { //Do nothing except log warning because not really expecting this to happen logger.log(Level.WARNING,"Date Formatter:"+formatters.get(i).toPattern() + "failed to parse:"+getText()+ "with "+nfe.getMessage(),nfe); } } } /** * Creates a new FrameBodyTDRC datatype from File * * @param byteBuffer * @param frameSize * @throws InvalidTagException */ public FrameBodyTDRC(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); //Store the equivalent ID3v23 values in case convert //Find the date format of the v24Frame for (int i = 0; i < formatters.size(); i++) { try { Date d; synchronized(formatters.get(i)) { d = formatters.get(i).parse(getText()); } if (d != null) { extractID3v23Formats(d, i); break; } } //Dont display will occur for each failed format catch (ParseException e) { //Do nothing; } catch(NumberFormatException nfe) { //Do nothing except log warning because not really expecting this to happen (but it does !) logger.log(Level.WARNING,"Date Formatter:"+formatters.get(i).toPattern() + "failed to parse:"+getText()+ "with "+nfe.getMessage(),nfe); } } } /** * Format Date * * Synchronized because SimpleDateFormat is invalid * * @param d * @return */ private static synchronized String formatDateAsYear(Date d) { return formatYearOut.format(d); } /** * Format Date * * Synchronized because SimpleDateFormat is invalid * * @param d * @return */ private static synchronized String formatDateAsDate(Date d) { return formatDateOut.format(d); } /** * Format Date * * Synchronized because SimpleDateFormat is invalid * * @param d * @return */ private static synchronized String formatDateAsTime(Date d) { return formatTimeOut.format(d); } /** * Extract Format * * @param dateRecord * @param precision */ private void extractID3v23Formats(final Date dateRecord, final int precision) { Date d = dateRecord; //Precision Year if (precision == PRECISION_YEAR) { setYear(formatDateAsYear(d)); } //Precision Month else if (precision == PRECISION_MONTH) { setYear(formatDateAsYear(d)); } //Precision Day else if (precision == PRECISION_DAY) { setYear(formatDateAsYear(d)); setDate(formatDateAsDate(d)); } //Precision Hour else if (precision == PRECISION_HOUR) { setYear(formatDateAsYear(d)); setDate(formatDateAsDate(d)); } //Precision Minute else if (precision == PRECISION_MINUTE) { setYear(formatDateAsYear(d)); setDate(formatDateAsDate(d)); setTime(formatDateAsTime(d)); } //Precision Minute else if (precision == PRECISION_SECOND) { setYear(formatDateAsYear(d)); setDate(formatDateAsDate(d)); setTime(formatDateAsTime(d)); } } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_YEAR; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyTKEY.java0000644000175000017500000000570111277006322030123 0ustar drazzibdrazzib/* * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.id3.ID3v24Frames; import org.jaudiotagger.tag.reference.MusicalKey; import java.nio.ByteBuffer; /** * Initial key Text information frame. *

The 'Initial key' frame contains the musical key in which the sound starts. It is represented as a string with * a maximum length of three characters. The ground keys are represented with "A","B","C","D","E", "F" and "G" and halfkeys represented * with "b" and "#". Minor is represented as "m". Example "Cbm". Off key is represented with an "o" only. *

*

For more details, please refer to the ID3 specifications: *

* * @author : Paul Taylor * @author : Eric Farng * @version $Id: FrameBodyTKEY.java 832 2009-11-12 13:25:38Z paultaylor $ */ public class FrameBodyTKEY extends AbstractFrameBodyTextInfo implements ID3v24FrameBody, ID3v23FrameBody { /** * Creates a new FrameBodyTKEY datatype. */ public FrameBodyTKEY() { } public FrameBodyTKEY(FrameBodyTKEY body) { super(body); } /** * Creates a new FrameBodyTKEY datatype. * * @param textEncoding * @param text */ public FrameBodyTKEY(byte textEncoding, String text) { super(textEncoding, text); } /** * Creates a new FrameBodyTKEY datatype. * * @param byteBuffer * @param frameSize * @throws java.io.IOException * @throws InvalidTagException */ public FrameBodyTKEY(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_INITIAL_KEY; } /** * * @return true if text value is valid musical key notation */ public boolean isValid() { return MusicalKey.isValid(getFirstTextValue()); } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyTDTG.java0000644000175000017500000000444411331564261030116 0ustar drazzibdrazzib/** * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: FrameBodyTDTG.java 869 2010-02-01 14:44:01Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Description: * */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.id3.ID3v24Frames; import java.nio.ByteBuffer; /** *

The 'Tagging time' frame contains a timestamp describing then the * audio was tagged. Timestamp format is described in the ID3v2 * structure document

*/ public class FrameBodyTDTG extends AbstractFrameBodyTextInfo implements ID3v24FrameBody { /** * Creates a new FrameBodyTDTG datatype. */ public FrameBodyTDTG() { } public FrameBodyTDTG(FrameBodyTDTG body) { super(body); } /** * Creates a new FrameBodyTDTG datatype. * * @param textEncoding * @param text */ public FrameBodyTDTG(byte textEncoding, String text) { super(textEncoding, text); } /** * Creates a new FrameBodyTDTG datatype. * * @param byteBuffer * @param frameSize * @throws java.io.IOException * @throws InvalidTagException */ public FrameBodyTDTG(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * @return the frame identifier */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_TAGGING_TIME; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyTLAN.java0000644000175000017500000000611211277006322030102 0ustar drazzibdrazzib/* * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.id3.ID3v24Frames; import org.jaudiotagger.tag.reference.Languages; import java.nio.ByteBuffer; /** * Language(s) Text information frame. *

The 'Language(s)' frame should contain the languages of the text or lyrics spoken or sung in the audio. The language is represented with three characters according to ISO-639-2. If more than one language is used in the text their language codes should follow according to their usage. *

*

For more details, please refer to the ID3 specifications: *

*

* TODO:Although rare TLAN can actually return multiple language codes, at the moment they are all returned as a single * string via getText(), any additional parsrsing has to be done externally. * * @author : Paul Taylor * @author : Eric Farng * @version $Id: FrameBodyTLAN.java 832 2009-11-12 13:25:38Z paultaylor $ */ public class FrameBodyTLAN extends AbstractFrameBodyTextInfo implements ID3v24FrameBody, ID3v23FrameBody { /** * Creates a new FrameBodyTLAN datatype. */ public FrameBodyTLAN() { super(); } public FrameBodyTLAN(FrameBodyTLAN body) { super(body); } /** * Creates a new FrameBodyTLAN datatype. * * @param textEncoding * @param text */ public FrameBodyTLAN(byte textEncoding, String text) { super(textEncoding, text); } /** * Creates a new FrameBodyTLAN datatype. * * @param byteBuffer * @param frameSize * @throws InvalidTagException */ public FrameBodyTLAN(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_LANGUAGE; } /** * * @return true if text value is valid language code */ public boolean isValid() { return Languages.getInstanceOf().getValueForId(getFirstTextValue())!=null; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyDeprecated.java0000644000175000017500000000550411470746136031421 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3.framebody; /** * Represents a frameBody for a frame identifier that is not defined for the tag version but was valid for a for an * earlier tag version. * The body consists of an array of bytes representing all the bytes in the body. */ public class FrameBodyDeprecated extends AbstractID3v2FrameBody implements ID3v24FrameBody, ID3v23FrameBody { /** The original frameBody is held so can be retrieved * when converting a DeprecatedFrameBody back to a normal framebody */ private AbstractID3v2FrameBody originalFrameBody; /** * Creates a new FrameBodyDeprecated wrapper around the frameBody * @param frameBody */ public FrameBodyDeprecated(AbstractID3v2FrameBody frameBody) { this.originalFrameBody = frameBody; } /** * Copy constructor * * @param copyObject a copy is made of this */ public FrameBodyDeprecated(FrameBodyDeprecated copyObject) { super(copyObject); } /** * Return the frame identifier * * @return the identifier */ public String getIdentifier() { return originalFrameBody.getIdentifier(); } /** * Delgate size to size of original frameBody, if frameBody already exist will take this value from the frame header * but it is always recalculated before writing any changes back to disk. * * @return size in bytes of this frame body */ public int getSize() { return originalFrameBody.getSize(); } /** * @param obj * @return whether obj is equivalent to this object */ public boolean equals(Object obj) { if (!(obj instanceof FrameBodyDeprecated)) { return false; } FrameBodyDeprecated object = (FrameBodyDeprecated) obj; return this.getIdentifier().equals(object.getIdentifier()) && super.equals(obj); } /** * Return the original frameBody that was used to construct the DeprecatedFrameBody * * @return the original frameBody */ public AbstractID3v2FrameBody getOriginalFrameBody() { return originalFrameBody; } /** * Because the contents of this frame are an array of bytes and could be large we just * return the identifier. * * @return a string representation of this frame */ public String toString() { return getIdentifier(); } /** * Setup the Object List. *

* This is handled by the wrapped class */ protected void setupObjectList() { } public String getBriefDescription() { //TODO When is this null, it seems it can be but Im not sure why if (originalFrameBody != null) { return originalFrameBody.getBriefDescription(); } return ""; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyTFLT.java0000644000175000017500000000655111277006322030124 0ustar drazzibdrazzib/* * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.id3.ID3v24Frames; import java.nio.ByteBuffer; /** * File type Text information frame. *

*

The 'File type' frame indicates which type of audio this tag defines. * The following type and refinements are defined: *

* * * * * * * * *
MPG MPEG Audio
/1 MPEG 1/2 layer I
/2 MPEG 1/2 layer II
/3 MPEG 1/2 layer III
/2.5 MPEG 2.5
/AAC Advanced audio compression
VQFTransform-domain Weighted Interleave Vector Quantization
PCM Pulse Code Modulated audio

* but other types may be used, not for these types though. This is used * in a similar way to the predefined types in the "TMED" frame, but * without parentheses. If this frame is not present audio type is * assumed to be "MPG". *

*

*

For more details, please refer to the ID3 specifications: *

* * @author : Paul Taylor * @author : Eric Farng * @version $Id: FrameBodyTFLT.java 832 2009-11-12 13:25:38Z paultaylor $ */ public class FrameBodyTFLT extends AbstractFrameBodyTextInfo implements ID3v24FrameBody, ID3v23FrameBody { /** * Creates a new FrameBodyTFLT datatype. */ public FrameBodyTFLT() { } public FrameBodyTFLT(FrameBodyTFLT body) { super(body); } /** * Creates a new FrameBodyTFLT datatype. * * @param textEncoding * @param text */ public FrameBodyTFLT(byte textEncoding, String text) { super(textEncoding, text); } /** * Creates a new FrameBodyTFLT datatype. * * @param byteBuffer * @param frameSize * @throws InvalidTagException */ public FrameBodyTFLT(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_FILE_TYPE; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyTOAL.java0000644000175000017500000000506311470746136030120 0ustar drazzibdrazzib/* * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.id3.ID3v24Frames; import java.nio.ByteBuffer; /** * Original album/movie/show title Text information frame. *

The 'Original album/movie/show title' frame is intended for the title of the original recording (or source of sound), if for example the music * in the file should be a cover of a previously released song. *

*

For more details, please refer to the ID3 specifications: *

* * @author : Paul Taylor * @author : Eric Farng * @version $Id: FrameBodyTOAL.java 929 2010-11-17 12:36:46Z paultaylor $ */ public class FrameBodyTOAL extends AbstractFrameBodyTextInfo implements ID3v23FrameBody,ID3v24FrameBody { /** * Creates a new FrameBodyTOAL datatype. */ public FrameBodyTOAL() { } public FrameBodyTOAL(FrameBodyTOAL body) { super(body); } /** * Creates a new FrameBodyTOAL datatype. * * @param textEncoding * @param text */ public FrameBodyTOAL(byte textEncoding, String text) { super(textEncoding, text); } /** * Creates a new FrameBodyTOAL datatype. * * @param byteBuffer * @param frameSize * @throws InvalidTagException */ public FrameBodyTOAL(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_ORIG_TITLE; } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyTOWN.java0000644000175000017500000000466311277006322030144 0ustar drazzibdrazzib/* * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.id3.ID3v24Frames; import java.nio.ByteBuffer; /** * File owner/licensee Text information frame. *

The 'File owner/licensee' frame contains the name of the owner or licensee of the file and it's contents. *

*

For more details, please refer to the ID3 specifications: *

* * @author : Paul Taylor * @author : Eric Farng * @version $Id: FrameBodyTOWN.java 832 2009-11-12 13:25:38Z paultaylor $ */ public class FrameBodyTOWN extends AbstractFrameBodyTextInfo implements ID3v23FrameBody { /** * Creates a new FrameBodyTOWN datatype. */ public FrameBodyTOWN() { } public FrameBodyTOWN(FrameBodyTOWN body) { super(body); } /** * Creates a new FrameBodyTOWN datatype. * * @param textEncoding * @param text */ public FrameBodyTOWN(byte textEncoding, String text) { super(textEncoding, text); } /** * Creates a new FrameBodyTOWN datatype. * * @param byteBuffer * @param frameSize * @throws InvalidTagException */ public FrameBodyTOWN(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_FILE_OWNER; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyTSOT.java0000644000175000017500000000430511277006322030137 0ustar drazzibdrazzib/** * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: FrameBodyTSOT.java 832 2009-11-12 13:25:38Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Description: * */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.id3.ID3v24Frames; import java.nio.ByteBuffer; /** * Title Sort name */ public class FrameBodyTSOT extends AbstractFrameBodyTextInfo implements ID3v24FrameBody, ID3v23FrameBody { /** * Creates a new FrameBodyTSOT datatype. */ public FrameBodyTSOT() { } public FrameBodyTSOT(FrameBodyTSOT body) { super(body); } /** * Creates a new FrameBodyTSOT datatype. * * @param textEncoding * @param text */ public FrameBodyTSOT(byte textEncoding, String text) { super(textEncoding, text); } /** * Creates a new FrameBodyTSOT datatype. * * @param byteBuffer * @param frameSize * @throws InvalidTagException */ public FrameBodyTSOT(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_TITLE_SORT_ORDER; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyCHAP.java0000644000175000017500000001333511277006322030064 0ustar drazzibdrazzib/* * Horizon Wimba Copyright (C)2006 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.datatype.DataTypes; import org.jaudiotagger.tag.datatype.NumberFixedLength; import org.jaudiotagger.tag.datatype.StringNullTerminated; import org.jaudiotagger.tag.id3.ID3v2ChapterFrames; import java.nio.ByteBuffer; /** * Chapter frame. *

*

* The purpose of this frame is to describe a single chapter within an * audio file. There may be more than one frame of this type in a tag * but each must have an Element ID that is unique with respect to any * other "CHAP" frame or "CTOC" frame in the tag. *

* * * * * * * * *
<ID3v2.3 or ID3v2.4 frame header, ID: "CHAP">  (10 bytes)
Element ID<text string> $00
Start time$xx xx xx xx
End time$xx xx xx xx
Start offset$xx xx xx xx
End offset$xx xx xx xx
<Optional embedded sub-frames>
*

* The Element ID uniquely identifies the frame. It is not intended to * be human readable and should not be presented to the end user. *

* The Start and End times are a count in milliseconds from the * beginning of the file to the start and end of the chapter * respectively. *

* The Start offset is a zero-based count of bytes from the beginning * of the file to the first byte of the first audio frame in the * chapter. If these bytes are all set to 0xFF then the value should be * ignored and the start time value should be utilized. *

* The End offset is a zero-based count of bytes from the beginning of * the file to the first byte of the audio frame following the end of * the chapter. If these bytes are all set to 0xFF then the value should * be ignored and the end time value should be utilized. *

* There then follows a sequence of optional frames that are embedded * within the "CHAP" frame and which describe the content of the chapter * (e.g. a "TIT2" frame representing the chapter name) or provide * related material such as URLs and images. These sub-frames are * contained within the bounds of the "CHAP" frame as signalled by the * size field in the "CHAP" frame header. If a parser does not recognise * "CHAP" frames it can skip them using the size field in the frame * header. When it does this it will skip any embedded sub-frames * carried within the frame. *

*

*

For more details, please refer to the ID3 Chapter Frame specifications: *

* * @author Marc Gimpel, Horizon Wimba S.A. * @version $Id: FrameBodyCHAP.java 832 2009-11-12 13:25:38Z paultaylor $ */ public class FrameBodyCHAP extends AbstractID3v2FrameBody implements ID3v2ChapterFrameBody { /** * Creates a new FrameBodyCHAP datatype. */ public FrameBodyCHAP() { } /** * Creates a new FrameBodyCHAP datatype. * * @param body */ public FrameBodyCHAP(FrameBodyCHAP body) { super(body); } /** * Creates a new FrameBodyCHAP datatype. * * @param elementId * @param startTime * @param endTime * @param startOffset * @param endOffset */ public FrameBodyCHAP(String elementId, int startTime, int endTime, int startOffset, int endOffset) { this.setObjectValue(DataTypes.OBJ_ELEMENT_ID, elementId); this.setObjectValue(DataTypes.OBJ_START_TIME, startTime); this.setObjectValue(DataTypes.OBJ_END_TIME, endTime); this.setObjectValue(DataTypes.OBJ_START_OFFSET, startOffset); this.setObjectValue(DataTypes.OBJ_END_OFFSET, endOffset); } /** * Creates a new FrameBodyAENC datatype. * * @param byteBuffer * @param frameSize * @throws InvalidTagException if unable to create framebody from buffer */ public FrameBodyCHAP(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v2ChapterFrames.FRAME_ID_CHAPTER; } /** * */ protected void setupObjectList() { objectList.add(new StringNullTerminated(DataTypes.OBJ_ELEMENT_ID, this)); objectList.add(new NumberFixedLength(DataTypes.OBJ_START_TIME, this, 4)); objectList.add(new NumberFixedLength(DataTypes.OBJ_END_TIME, this, 4)); objectList.add(new NumberFixedLength(DataTypes.OBJ_START_OFFSET, this, 4)); objectList.add(new NumberFixedLength(DataTypes.OBJ_END_OFFSET, this, 4)); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyTRSN.java0000644000175000017500000000477611277006322030150 0ustar drazzibdrazzib/* * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.id3.ID3v24Frames; import java.nio.ByteBuffer; /** * Internet radio station name Text information frame. *

The 'Internet radio station name' frame contains the name of the internet radio station from which the audio is streamed. *

*

For more details, please refer to the ID3 specifications: *

* * @author : Paul Taylor * @author : Eric Farng * @version $Id: FrameBodyTRSN.java 832 2009-11-12 13:25:38Z paultaylor $ */ public class FrameBodyTRSN extends AbstractFrameBodyTextInfo implements ID3v23FrameBody, ID3v24FrameBody { /** * Creates a new FrameBodyTRSN datatype. */ public FrameBodyTRSN() { } public FrameBodyTRSN(FrameBodyTRSN body) { super(body); } /** * Creates a new FrameBodyTRSN datatype. * * @param textEncoding * @param text */ public FrameBodyTRSN(byte textEncoding, String text) { super(textEncoding, text); } /** * Creates a new FrameBodyTRSN datatype. * * @param byteBuffer * @param frameSize * @throws java.io.IOException * @throws InvalidTagException */ public FrameBodyTRSN(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_RADIO_NAME; } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyUSLT.java0000644000175000017500000001635611470746136030157 0ustar drazzibdrazzib/* * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.datatype.*; import org.jaudiotagger.tag.id3.ID3TextEncodingConversion; import org.jaudiotagger.tag.id3.ID3v24Frames; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; import org.jaudiotagger.tag.reference.Languages; import java.io.ByteArrayOutputStream; import java.nio.ByteBuffer; /** * Unsychronised lyrics/text transcription frame. *

*

* This frame contains the lyrics of the song or a text transcription of other vocal activities. The head includes an * encoding descriptor and a content descriptor. The body consists of the actual text. The 'Content descriptor' is a * terminated string. If no descriptor is entered, 'Content descriptor' is $00 (00) only. Newline characters are * allowed in the text. There may be more than one 'Unsynchronised lyrics/text transcription' frame in each tag, but * only one with the same language and content descriptor. * *

* * * * * *
<Header for 'Unsynchronised lyrics/text transcription', ID: "USLT">
Text encoding $xx
Language $xx xx xx
Content descriptor<text string according to encoding> $00 (00)
Lyrics/text <full text string according to encoding>

*

* You can retrieve the first value without the null terminator using {@link #getFirstTextValue} *

*

For more details, please refer to the ID3 specifications: *

* * @author : Paul Taylor * @author : Eric Farng * @version $Id: FrameBodyUSLT.java 929 2010-11-17 12:36:46Z paultaylor $ */ public class FrameBodyUSLT extends AbstractID3v2FrameBody implements ID3v23FrameBody, ID3v24FrameBody { /** * Creates a new FrameBodyUSLT dataType. */ public FrameBodyUSLT() { setObjectValue(DataTypes.OBJ_TEXT_ENCODING, TextEncoding.ISO_8859_1); setObjectValue(DataTypes.OBJ_LANGUAGE, ""); setObjectValue(DataTypes.OBJ_DESCRIPTION, ""); setObjectValue(DataTypes.OBJ_LYRICS, ""); } /** * Copy constructor * * @param body */ public FrameBodyUSLT(FrameBodyUSLT body) { super(body); } /** * Creates a new FrameBodyUSLT datatype. * * @param textEncoding * @param language * @param description * @param text */ public FrameBodyUSLT(byte textEncoding, String language, String description, String text) { setObjectValue(DataTypes.OBJ_TEXT_ENCODING, textEncoding); setObjectValue(DataTypes.OBJ_LANGUAGE, language); setObjectValue(DataTypes.OBJ_DESCRIPTION, description); setObjectValue(DataTypes.OBJ_LYRICS, text); } /** * Creates a new FrameBodyUSLT datatype, populated from buffer * * @param byteBuffer * @param frameSize * @throws InvalidTagException * @throws InvalidTagException */ public FrameBodyUSLT(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } public String getUserFriendlyValue() { return getFirstTextValue(); } /** * Set a description field * * @param description */ public void setDescription(String description) { setObjectValue(DataTypes.OBJ_DESCRIPTION, description); } /** * Get a description field * * @return description */ public String getDescription() { return (String) getObjectValue(DataTypes.OBJ_DESCRIPTION); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_UNSYNC_LYRICS; } /** * Set the language field * * @param language */ public void setLanguage(String language) { setObjectValue(DataTypes.OBJ_LANGUAGE, language); } /** * Get the language field * * @return language */ public String getLanguage() { return (String) getObjectValue(DataTypes.OBJ_LANGUAGE); } /** * Set the lyric field * * @param lyric */ public void setLyric(String lyric) { setObjectValue(DataTypes.OBJ_LYRICS, lyric); } /** * Get the lyric field * * @return lyrics */ public String getLyric() { return (String) getObjectValue(DataTypes.OBJ_LYRICS); } /** * Get first value * * @return value at index 0 */ public String getFirstTextValue() { TextEncodedStringSizeTerminated text = (TextEncodedStringSizeTerminated) getObject(DataTypes.OBJ_LYRICS); return text.getValueAtIndex(0); } /** * Add additional lyric to the lyric field * * @param text */ public void addLyric(String text) { setLyric(getLyric() + text); } /** * @param line */ public void addLyric(Lyrics3Line line) { setLyric(getLyric() + line.writeString()); } public void write(ByteArrayOutputStream tagBuffer) { //Ensure valid for type this.setTextEncoding(ID3TextEncodingConversion.getTextEncoding(getHeader(), getTextEncoding())); //Ensure valid for data if (!((AbstractString) getObject(DataTypes.OBJ_DESCRIPTION)).canBeEncoded()) { this.setTextEncoding(ID3TextEncodingConversion.getUnicodeTextEncoding(getHeader())); } if (!((AbstractString) getObject(DataTypes.OBJ_LYRICS)).canBeEncoded()) { this.setTextEncoding(ID3TextEncodingConversion.getUnicodeTextEncoding(getHeader())); } super.write(tagBuffer); } /** * */ protected void setupObjectList() { objectList.add(new NumberHashMap(DataTypes.OBJ_TEXT_ENCODING, this, TextEncoding.TEXT_ENCODING_FIELD_SIZE)); objectList.add(new StringHashMap(DataTypes.OBJ_LANGUAGE, this, Languages.LANGUAGE_FIELD_SIZE)); objectList.add(new TextEncodedStringNullTerminated(DataTypes.OBJ_DESCRIPTION, this)); objectList.add(new TextEncodedStringSizeTerminated(DataTypes.OBJ_LYRICS, this)); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/framebody/FrameBodyTDOR.java0000644000175000017500000000536011331564261030122 0ustar drazzibdrazzib/** * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: FrameBodyTDOR.java 869 2010-02-01 14:44:01Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Description: * */ package org.jaudiotagger.tag.id3.framebody; import org.jaudiotagger.tag.InvalidTagException; import org.jaudiotagger.tag.datatype.DataTypes; import org.jaudiotagger.tag.id3.ID3v24Frames; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; import java.nio.ByteBuffer; /** *

The 'Original release time' frame contains a timestamp describing * when the original recording of the audio was released. Timestamp * format is described in the ID3v2 structure document.

*/ public class FrameBodyTDOR extends AbstractFrameBodyTextInfo implements ID3v24FrameBody { /** * Creates a new FrameBodyTDOR datatype. */ public FrameBodyTDOR() { } public FrameBodyTDOR(FrameBodyTDOR body) { super(body); } /** * When converting v3 TDAT to v4 TDRC frame * @param body */ public FrameBodyTDOR(FrameBodyTORY body) { setObjectValue(DataTypes.OBJ_TEXT_ENCODING, TextEncoding.ISO_8859_1); setObjectValue(DataTypes.OBJ_TEXT, body.getText()); } /** * Creates a new FrameBodyTDOR datatype. * * @param textEncoding * @param text */ public FrameBodyTDOR(byte textEncoding, String text) { super(textEncoding, text); } /** * Creates a new FrameBodyTDOR datatype. * * @param byteBuffer * @param frameSize * @throws InvalidTagException */ public FrameBodyTDOR(ByteBuffer byteBuffer, int frameSize) throws InvalidTagException { super(byteBuffer, frameSize); } /** * The ID3v2 frame identifier * * @return the ID3v2 frame identifier for this frame type */ public String getIdentifier() { return ID3v24Frames.FRAME_ID_ORIGINAL_RELEASE_TIME; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/AbstractID3v2Frame.java0000644000175000017500000005116111470746136027106 0ustar drazzibdrazzib/* * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3; import org.jaudiotagger.audio.mp3.MP3File; import org.jaudiotagger.tag.*; import org.jaudiotagger.tag.id3.framebody.AbstractID3v2FrameBody; import org.jaudiotagger.tag.id3.framebody.FrameBodyEncrypted; import org.jaudiotagger.tag.id3.framebody.FrameBodyUnsupported; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; import org.jaudiotagger.utils.EqualsUtil; import java.io.ByteArrayOutputStream; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.nio.ByteBuffer; import java.util.logging.Level; /** * This abstract class is each frame header inside a ID3v2 tag. * * @author : Paul Taylor * @author : Eric Farng * @version $Id: AbstractID3v2Frame.java 929 2010-11-17 12:36:46Z paultaylor $ */ public abstract class AbstractID3v2Frame extends AbstractTagFrame implements TagTextField { protected static final String TYPE_FRAME = "frame"; protected static final String TYPE_FRAME_SIZE = "frameSize"; protected static final String UNSUPPORTED_ID = "Unsupported"; //Frame identifier protected String identifier = ""; //Frame Size protected int frameSize; //The purpose of this is to provide the filename that should be used when writing debug messages //when problems occur reading or writing to file, otherwise it is difficult to track down the error //when processing many files private String loggingFilename = ""; /** * * @return size in bytes of the frameid field */ protected abstract int getFrameIdSize(); /** * * @return the size in bytes of the frame size field */ protected abstract int getFrameSizeSize(); /** * * @return the size in bytes of the frame header */ protected abstract int getFrameHeaderSize(); /** * Create an empty frame */ protected AbstractID3v2Frame() { } /** * This holds the Status flags (not supported in v2.20 */ StatusFlags statusFlags = null; /** * This holds the Encoding flags (not supported in v2.20) */ EncodingFlags encodingFlags = null; /** * Create a frame based on another frame * @param frame */ public AbstractID3v2Frame(AbstractID3v2Frame frame) { super(frame); } /** * Create a frame based on a body * @param body */ public AbstractID3v2Frame(AbstractID3v2FrameBody body) { this.frameBody = body; this.frameBody.setHeader(this); } /** * Create a new frame with empty body based on identifier * @param identifier */ //TODO the identifier checks should be done in the relevent subclasses public AbstractID3v2Frame(String identifier) { logger.info("Creating empty frame of type" + identifier); this.identifier = identifier; // Use reflection to map id to frame body, which makes things much easier // to keep things up to date. try { Class c = (Class) Class.forName("org.jaudiotagger.tag.id3.framebody.FrameBody" + identifier); frameBody = c.newInstance(); } catch (ClassNotFoundException cnfe) { logger.severe(cnfe.getMessage()); frameBody = new FrameBodyUnsupported(identifier); } //Instantiate Interface/Abstract should not happen catch (InstantiationException ie) { logger.log(Level.SEVERE, "InstantiationException:" + identifier, ie); throw new RuntimeException(ie); } //Private Constructor shouild not happen catch (IllegalAccessException iae) { logger.log(Level.SEVERE, "IllegalAccessException:" + identifier, iae); throw new RuntimeException(iae); } frameBody.setHeader(this); if (this instanceof ID3v24Frame) { frameBody.setTextEncoding(TagOptionSingleton.getInstance().getId3v24DefaultTextEncoding()); } else if (this instanceof ID3v23Frame) { frameBody.setTextEncoding(TagOptionSingleton.getInstance().getId3v23DefaultTextEncoding()); } logger.info("Created empty frame of type" + identifier); } /** * Retrieve the logging filename to be used in debugging * * @return logging filename to be used in debugging */ protected String getLoggingFilename() { return loggingFilename; } /** * Set logging filename when construct tag for read from file * * @param loggingFilename */ protected void setLoggingFilename(String loggingFilename) { this.loggingFilename = loggingFilename; } /** * Return the frame identifier, this only identifies the frame it does not provide a unique * key, when using frames such as TXXX which are used by many fields * * * @return the frame identifier (Tag Field Interface) */ //TODO, this is confusing only returns the frameId, which does not neccessarily uniquely //identify the frame public String getId() { return getIdentifier(); } /** * Return the frame identifier * * @return the frame identifier */ public String getIdentifier() { return identifier; } //TODO:needs implementing but not sure if this method is required at all public void copyContent(TagField field) { } /** * Read the frameBody when frame marked as encrypted * * @param identifier * @param byteBuffer * @param frameSize * @return * @throws InvalidFrameException * @throws InvalidDataTypeException * @throws InvalidTagException */ protected AbstractID3v2FrameBody readEncryptedBody(String identifier, ByteBuffer byteBuffer, int frameSize) throws InvalidFrameException, InvalidDataTypeException { try { AbstractID3v2FrameBody frameBody = new FrameBodyEncrypted(identifier,byteBuffer, frameSize); frameBody.setHeader(this); return frameBody; } catch(InvalidTagException ite) { throw new InvalidDataTypeException(ite); } } protected boolean isPadding(byte[] buffer) { if( (buffer[0]=='\0')&& (buffer[1]=='\0')&& (buffer[2]=='\0')&& (buffer[3]=='\0') ) { return true; } return false; } /** * Read the frame body from the specified file via the buffer * * @param identifier the frame identifier * @param byteBuffer to read the frame body from * @param frameSize * @return a newly created FrameBody * @throws InvalidFrameException unable to construct a framebody from the data */ @SuppressWarnings("unchecked") //TODO using reflection is rather slow perhaps we should change this protected AbstractID3v2FrameBody readBody(String identifier, ByteBuffer byteBuffer, int frameSize) throws InvalidFrameException, InvalidDataTypeException { //Use reflection to map id to frame body, which makes things much easier //to keep things up to date,although slight performance hit. logger.finest("Creating framebody:start"); AbstractID3v2FrameBody frameBody; try { Class c = (Class) Class.forName("org.jaudiotagger.tag.id3.framebody.FrameBody" + identifier); Class[] constructorParameterTypes = {Class.forName("java.nio.ByteBuffer"), Integer.TYPE}; Object[] constructorParameterValues = {byteBuffer, frameSize}; Constructor construct = c.getConstructor(constructorParameterTypes); frameBody = (construct.newInstance(constructorParameterValues)); } //No class defined for this frame type,use FrameUnsupported catch (ClassNotFoundException cex) { logger.info(getLoggingFilename() + ":" + "Identifier not recognised:" + identifier + " using FrameBodyUnsupported"); try { frameBody = new FrameBodyUnsupported(byteBuffer, frameSize); } //Should only throw InvalidFrameException but unfortunately legacy hierachy forces //read method to declare it can throw InvalidtagException catch (InvalidFrameException ife) { throw ife; } catch (InvalidTagException te) { throw new InvalidFrameException(te.getMessage()); } } //An error has occurred during frame instantiation, if underlying cause is an unchecked exception or error //propagate it up otherwise mark this frame as invalid catch (InvocationTargetException ite) { logger.severe(getLoggingFilename() + ":" + "An error occurred within abstractID3v2FrameBody for identifier:" + identifier + ":" + ite.getCause().getMessage()); if (ite.getCause() instanceof Error) { throw (Error) ite.getCause(); } else if (ite.getCause() instanceof RuntimeException) { throw (RuntimeException) ite.getCause(); } else if(ite.getCause() instanceof InvalidFrameException ) { throw (InvalidFrameException)ite.getCause(); } else if(ite.getCause() instanceof InvalidDataTypeException ) { throw (InvalidDataTypeException)ite.getCause(); } else { throw new InvalidFrameException(ite.getCause().getMessage()); } } //No Such Method should not happen catch (NoSuchMethodException sme) { logger.log(Level.SEVERE, getLoggingFilename() + ":" + "No such method:" + sme.getMessage(), sme); throw new RuntimeException(sme.getMessage()); } //Instantiate Interface/Abstract should not happen catch (InstantiationException ie) { logger.log(Level.SEVERE, getLoggingFilename() + ":" + "Instantiation exception:" + ie.getMessage(), ie); throw new RuntimeException(ie.getMessage()); } //Private Constructor shouild not happen catch (IllegalAccessException iae) { logger.log(Level.SEVERE, getLoggingFilename() + ":" + "Illegal access exception :" + iae.getMessage(), iae); throw new RuntimeException(iae.getMessage()); } logger.finest(getLoggingFilename() + ":" + "Created framebody:end" + frameBody.getIdentifier()); frameBody.setHeader(this); return frameBody; } /** * Get the next frame id, throwing an exception if unable to do this and check against just having padded data * * @param byteBuffer * @return * @throws PaddingException * @throws InvalidFrameException */ protected String readIdentifier(ByteBuffer byteBuffer) throws PaddingException,InvalidFrameException { byte[] buffer = new byte[getFrameIdSize()]; if (byteBuffer.position() + getFrameHeaderSize() >= byteBuffer.limit()) { logger.warning(getLoggingFilename() + ":" + "No space to find another frame:"); throw new InvalidFrameException(getLoggingFilename() + ":" + "No space to find another frame"); } //Read the Frame Identifier byteBuffer.get(buffer, 0, getFrameIdSize()); if(isPadding(buffer)) { throw new PaddingException(getLoggingFilename() + ":only padding found"); } identifier = new String(buffer); logger.fine(getLoggingFilename() + ":" + "Identifier is" + identifier); return identifier; } /** * This creates a new body based of type identifier but populated by the data * in the body. This is a different type to the body being created which is why * TagUtility.copyObject() can't be used. This is used when converting between * different versions of a tag for frames that have a non-trivial mapping such * as TYER in v3 to TDRC in v4. This will only work where appropriate constructors * exist in the frame body to be created, for example a FrameBodyTYER requires a constructor * consisting of a FrameBodyTDRC. *

* If this method is called and a suitable constructor does not exist then an InvalidFrameException * will be thrown * * @param identifier to determine type of the frame * @param body * @return newly created framebody for this type * @throws InvalidFrameException if unable to construct a framebody for the identifier and body provided. */ @SuppressWarnings("unchecked") //TODO using reflection is rather slow perhaps we should change this protected AbstractID3v2FrameBody readBody(String identifier, AbstractID3v2FrameBody body) throws InvalidFrameException { /* Use reflection to map id to frame body, which makes things much easier * to keep things up to date, although slight performance hit. */ AbstractID3v2FrameBody frameBody; try { Class c = (Class) Class.forName("org.jaudiotagger.tag.id3.framebody.FrameBody" + identifier); Class[] constructorParameterTypes = {body.getClass()}; Object[] constructorParameterValues = {body}; Constructor construct = c.getConstructor(constructorParameterTypes); frameBody = (construct.newInstance(constructorParameterValues)); } catch (ClassNotFoundException cex) { logger.info("Identifier not recognised:" + identifier + " unable to create framebody"); throw new InvalidFrameException("FrameBody" + identifier + " does not exist"); } //If suitable constructor does not exist catch (NoSuchMethodException sme) { logger.log(Level.SEVERE, "No such method:" + sme.getMessage(), sme); throw new InvalidFrameException("FrameBody" + identifier + " does not have a constructor that takes:" + body.getClass().getName()); } catch (InvocationTargetException ite) { logger.severe("An error occurred within abstractID3v2FrameBody"); logger.log(Level.SEVERE, "Invocation target exception:" + ite.getCause().getMessage(), ite.getCause()); if (ite.getCause() instanceof Error) { throw (Error) ite.getCause(); } else if (ite.getCause() instanceof RuntimeException) { throw (RuntimeException) ite.getCause(); } else { throw new InvalidFrameException(ite.getCause().getMessage()); } } //Instantiate Interface/Abstract should not happen catch (InstantiationException ie) { logger.log(Level.SEVERE, "Instantiation exception:" + ie.getMessage(), ie); throw new RuntimeException(ie.getMessage()); } //Private Constructor shouild not happen catch (IllegalAccessException iae) { logger.log(Level.SEVERE, "Illegal access exception :" + iae.getMessage(), iae); throw new RuntimeException(iae.getMessage()); } logger.finer("frame Body created" + frameBody.getIdentifier()); frameBody.setHeader(this); return frameBody; } public byte[] getRawContent() { ByteArrayOutputStream baos = new ByteArrayOutputStream(); write(baos); return baos.toByteArray(); } public abstract void write(ByteArrayOutputStream tagBuffer); /** * @param b */ public void isBinary(boolean b) { //do nothing because whether or not a field is binary is defined by its id and is immutable } public boolean isEmpty() { AbstractTagFrameBody body = this.getBody(); if (body == null) { return true; } //TODO depends on the body return false; } public StatusFlags getStatusFlags() { return statusFlags; } public EncodingFlags getEncodingFlags() { return encodingFlags; } public class StatusFlags { protected static final String TYPE_FLAGS = "statusFlags"; protected byte originalFlags; protected byte writeFlags; protected StatusFlags() { } /** * This returns the flags as they were originally read or created * @return */ public byte getOriginalFlags() { return originalFlags; } /** * This returns the flags amended to meet specification * @return */ public byte getWriteFlags() { return writeFlags; } public void createStructure() { } public boolean equals(Object obj) { if ( this == obj ) return true; if (!(obj instanceof StatusFlags)) { return false; } StatusFlags that = (StatusFlags) obj; return EqualsUtil.areEqual(this.getOriginalFlags(), that.getOriginalFlags()) && EqualsUtil.areEqual(this.getWriteFlags(), that.getWriteFlags()) ; } } class EncodingFlags { protected static final String TYPE_FLAGS = "encodingFlags"; protected byte flags; protected EncodingFlags() { resetFlags(); } protected EncodingFlags(byte flags) { setFlags(flags); } public byte getFlags() { return flags; } public void setFlags(byte flags) { this.flags = flags; } public void resetFlags() { setFlags((byte) 0); } public void createStructure() { } public boolean equals(Object obj) { if ( this == obj ) return true; if (!(obj instanceof EncodingFlags)) { return false; } EncodingFlags that = (EncodingFlags) obj; return EqualsUtil.areEqual(this.getFlags(), that.getFlags()); } } /** * Return String Representation of frame */ public void createStructure() { MP3File.getStructureFormatter().openHeadingElement(TYPE_FRAME, getIdentifier()); MP3File.getStructureFormatter().closeHeadingElement(TYPE_FRAME); } public boolean equals(Object obj) { if ( this == obj ) return true; if (!(obj instanceof AbstractID3v2Frame)) { return false; } AbstractID3v2Frame that = (AbstractID3v2Frame) obj; return super.equals(that); } /** * Returns the content of the field. * * For frames consisting of different fields, this will return the value deemed to be most * likely to be required * * @return Content */ public String getContent() { return getBody().getUserFriendlyValue(); } /** * Returns the current used charset encoding. * * @return Charset encoding. */ public String getEncoding() { return TextEncoding.getInstanceOf().getValueForId(this.getBody().getTextEncoding()); } /** * Sets the content of the field. * * @param content fields content. */ public void setContent(String content) { throw new UnsupportedOperationException("Not implemeneted please use the generic tag methods for setting content"); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/ID3v24Tag.java0000644000175000017500000013373211470746136025174 0ustar drazzibdrazzib/* * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3; import org.jaudiotagger.FileConstants; import org.jaudiotagger.audio.mp3.MP3File; import org.jaudiotagger.logging.ErrorMessage; import org.jaudiotagger.tag.*; import org.jaudiotagger.tag.datatype.Artwork; import org.jaudiotagger.tag.datatype.DataTypes; import org.jaudiotagger.tag.id3.framebody.*; import org.jaudiotagger.tag.lyrics3.AbstractLyrics3; import org.jaudiotagger.tag.lyrics3.Lyrics3v2; import org.jaudiotagger.tag.lyrics3.Lyrics3v2Field; import org.jaudiotagger.tag.reference.GenreTypes; import org.jaudiotagger.tag.reference.PictureTypes; import java.io.File; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.WritableByteChannel; import java.util.*; import java.util.logging.Level; /** * Represents an ID3v2.4 tag. * * @author : Paul Taylor * @author : Eric Farng * @version $Id: ID3v24Tag.java 929 2010-11-17 12:36:46Z paultaylor $ */ public class ID3v24Tag extends AbstractID3v2Tag { protected static final String TYPE_FOOTER = "footer"; protected static final String TYPE_IMAGEENCODINGRESTRICTION = "imageEncodingRestriction"; protected static final String TYPE_IMAGESIZERESTRICTION = "imageSizeRestriction"; protected static final String TYPE_TAGRESTRICTION = "tagRestriction"; protected static final String TYPE_TAGSIZERESTRICTION = "tagSizeRestriction"; protected static final String TYPE_TEXTENCODINGRESTRICTION = "textEncodingRestriction"; protected static final String TYPE_TEXTFIELDSIZERESTRICTION = "textFieldSizeRestriction"; protected static final String TYPE_UPDATETAG = "updateTag"; protected static final String TYPE_CRCDATA = "crcdata"; protected static final String TYPE_EXPERIMENTAL = "experimental"; protected static final String TYPE_EXTENDED = "extended"; protected static final String TYPE_PADDINGSIZE = "paddingsize"; protected static final String TYPE_UNSYNCHRONISATION = "unsyncronisation"; protected static int TAG_EXT_HEADER_LENGTH = 6; protected static int TAG_EXT_HEADER_UPDATE_LENGTH = 1; protected static int TAG_EXT_HEADER_CRC_LENGTH = 6; protected static int TAG_EXT_HEADER_RESTRICTION_LENGTH = 2; protected static int TAG_EXT_HEADER_CRC_DATA_LENGTH = 5; protected static int TAG_EXT_HEADER_RESTRICTION_DATA_LENGTH = 1; protected static int TAG_EXT_NUMBER_BYTES_DATA_LENGTH = 1; /** * ID3v2.4 Header bit mask */ public static final int MASK_V24_UNSYNCHRONIZATION = FileConstants.BIT7; /** * ID3v2.4 Header bit mask */ public static final int MASK_V24_EXTENDED_HEADER = FileConstants.BIT6; /** * ID3v2.4 Header bit mask */ public static final int MASK_V24_EXPERIMENTAL = FileConstants.BIT5; /** * ID3v2.4 Header bit mask */ public static final int MASK_V24_FOOTER_PRESENT = FileConstants.BIT4; /** * ID3v2.4 Extended header bit mask */ public static final int MASK_V24_TAG_UPDATE = FileConstants.BIT6; /** * ID3v2.4 Extended header bit mask */ public static final int MASK_V24_CRC_DATA_PRESENT = FileConstants.BIT5; /** * ID3v2.4 Extended header bit mask */ public static final int MASK_V24_TAG_RESTRICTIONS = FileConstants.BIT4; /** * ID3v2.4 Extended header bit mask */ public static final int MASK_V24_TAG_SIZE_RESTRICTIONS = (byte) FileConstants.BIT7 | FileConstants.BIT6; /** * ID3v2.4 Extended header bit mask */ public static final int MASK_V24_TEXT_ENCODING_RESTRICTIONS = FileConstants.BIT5; /** * ID3v2.4 Extended header bit mask */ public static final int MASK_V24_TEXT_FIELD_SIZE_RESTRICTIONS = FileConstants.BIT4 | FileConstants.BIT3; /** * ID3v2.4 Extended header bit mask */ public static final int MASK_V24_IMAGE_ENCODING = FileConstants.BIT2; /** * ID3v2.4 Extended header bit mask */ public static final int MASK_V24_IMAGE_SIZE_RESTRICTIONS = FileConstants.BIT2 | FileConstants.BIT1; /** * ID3v2.4 Header Footer are the same as the header flags. WHY?!?! move the * flags from thier position in 2.3?????????? */ /** * ID3v2.4 Header Footer bit mask */ public static final int MASK_V24_TAG_ALTER_PRESERVATION = FileConstants.BIT6; /** * ID3v2.4 Header Footer bit mask */ public static final int MASK_V24_FILE_ALTER_PRESERVATION = FileConstants.BIT5; /** * ID3v2.4 Header Footer bit mask */ public static final int MASK_V24_READ_ONLY = FileConstants.BIT4; /** * ID3v2.4 Header Footer bit mask */ public static final int MASK_V24_GROUPING_IDENTITY = FileConstants.BIT6; /** * ID3v2.4 Header Footer bit mask */ public static final int MASK_V24_COMPRESSION = FileConstants.BIT4; /** * ID3v2.4 Header Footer bit mask */ public static final int MASK_V24_ENCRYPTION = FileConstants.BIT3; /** * ID3v2.4 Header Footer bit mask */ public static final int MASK_V24_FRAME_UNSYNCHRONIZATION = FileConstants.BIT2; /** * ID3v2.4 Header Footer bit mask */ public static final int MASK_V24_DATA_LENGTH_INDICATOR = FileConstants.BIT1; /** * CRC Checksum calculated */ protected boolean crcDataFlag = false; /** * Experiemntal tag */ protected boolean experimental = false; /** * Contains extended header */ protected boolean extended = false; /** * All frames in the tag uses unsynchronisation */ protected boolean unsynchronization = false; /** * CRC Checksum */ protected int crcData = 0; /** * Contains a footer */ protected boolean footer = false; /** * Tag is an update */ protected boolean updateTag = false; /** * Tag has restrictions */ protected boolean tagRestriction = false; /** * If Set Image encoding restrictions * * 0 No restrictions * 1 Images are encoded only with PNG [PNG] or JPEG [JFIF]. */ protected byte imageEncodingRestriction = 0; /** * If set Image size restrictions * * 00 No restrictions * 01 All images are 256x256 pixels or smaller. * 10 All images are 64x64 pixels or smaller. * 11 All images are exactly 64x64 pixels, unless required * otherwise. */ protected byte imageSizeRestriction = 0; /** * If set then Tag Size Restrictions * * 00 No more than 128 frames and 1 MB total tag size. * 01 No more than 64 frames and 128 KB total tag size. * 10 No more than 32 frames and 40 KB total tag size. * 11 No more than 32 frames and 4 KB total tag size. */ protected byte tagSizeRestriction = 0; /** * If set Text encoding restrictions * * 0 No restrictions * 1 Strings are only encoded with ISO-8859-1 [ISO-8859-1] or * UTF-8 [UTF-8]. */ protected byte textEncodingRestriction = 0; /** * Tag padding */ protected int paddingSize = 0; /** * If set Text fields size restrictions * * 00 No restrictions * 01 No string is longer than 1024 characters. * 10 No string is longer than 128 characters. * 11 No string is longer than 30 characters. * * Note that nothing is said about how many bytes is used to * represent those characters, since it is encoding dependent. If a * text frame consists of more than one string, the sum of the * strungs is restricted as stated. */ protected byte textFieldSizeRestriction = 0; public static final byte RELEASE = 2; public static final byte MAJOR_VERSION = 4; public static final byte REVISION = 0; /** * Retrieve the Release */ public byte getRelease() { return RELEASE; } /** * Retrieve the Major Version */ public byte getMajorVersion() { return MAJOR_VERSION; } /** * Retrieve the Revision */ public byte getRevision() { return REVISION; } /** * Creates a new empty ID3v2_4 datatype. */ public ID3v24Tag() { frameMap = new LinkedHashMap(); encryptedFrameMap = new LinkedHashMap(); } /** * Copy primitives applicable to v2.4, this is used when cloning a v2.4 datatype * and other objects such as v2.3 so need to check instanceof */ protected void copyPrimitives(AbstractID3v2Tag copyObj) { logger.info("Copying primitives"); super.copyPrimitives(copyObj); if (copyObj instanceof ID3v24Tag) { ID3v24Tag copyObject = (ID3v24Tag) copyObj; this.footer = copyObject.footer; this.tagRestriction = copyObject.tagRestriction; this.updateTag = copyObject.updateTag; this.imageEncodingRestriction = copyObject.imageEncodingRestriction; this.imageSizeRestriction = copyObject.imageSizeRestriction; this.tagSizeRestriction = copyObject.tagSizeRestriction; this.textEncodingRestriction = copyObject.textEncodingRestriction; this.textFieldSizeRestriction = copyObject.textFieldSizeRestriction; } } protected void addFrame(AbstractID3v2Frame frame) { try { if (frame instanceof ID3v24Frame) { copyFrameIntoMap(frame.getIdentifier(),frame); } else { ID3v24Frame newFrame = new ID3v24Frame(frame); copyFrameIntoMap(newFrame.getIdentifier(), newFrame); } } catch (InvalidFrameException ife) { logger.log(Level.SEVERE, "Unable to convert frame:" + frame.getIdentifier()); } } /* * Copy frame into map, whilst accounting for multiple frames of same type which can occur even if there were * not frames of the dame type in the original tag * * The frame already exists this shouldn't normally happen because frames * that are allowed to be multiple don't call this method. Frames that * aren't allowed to be multiple aren't added to hashMap in first place when * originally added. * * We only want to allow one of the frames going forward but we try and merge * all the information into the one frame. However there is a problem here that * if we then take this, modify it and try to write back the original values * we could lose some information although this info is probably invalid anyway. * * However converting some frames from tag of one version to another may * mean that two different frames both get converted to one frame, this * particularly applies to DateTime fields which were originally two fields * in v2.3 but are one field in v2.4. */ @Override protected void copyFrameIntoMap(String id, AbstractID3v2Frame newFrame) { if (frameMap.containsKey(newFrame.getIdentifier())) { Object o = frameMap.get(newFrame.getIdentifier()); if(o instanceof AbstractID3v2Frame) { //Retrieve the frame with the same id we have already loaded into the map AbstractID3v2Frame firstFrame = (AbstractID3v2Frame) frameMap.get(newFrame.getIdentifier()); //Two different frames both converted to TDRCFrames, now if this is the case one of them //may have actually have been created as a FrameUnsupportedBody because TDRC is only //supported in ID3v24, but is often created in v23 tags as well together with the valid TYER //frame if (newFrame.getBody() instanceof FrameBodyTDRC) { if (firstFrame.getBody() instanceof FrameBodyTDRC) { logger.finest("Modifying frame in map:" + newFrame.getIdentifier()); FrameBodyTDRC body = (FrameBodyTDRC) firstFrame.getBody(); FrameBodyTDRC newBody = (FrameBodyTDRC) newFrame.getBody(); //#304:Check for NullPointer, just ignore this frame if(newBody.getOriginalID()==null) { return; } //Just add the data to the frame if (newBody.getOriginalID().equals(ID3v23Frames.FRAME_ID_V3_TYER)) { body.setYear(newBody.getText()); } else if (newBody.getOriginalID().equals(ID3v23Frames.FRAME_ID_V3_TDAT)) { body.setDate(newBody.getText()); } else if (newBody.getOriginalID().equals(ID3v23Frames.FRAME_ID_V3_TIME)) { body.setTime(newBody.getText()); } else if (newBody.getOriginalID().equals(ID3v23Frames.FRAME_ID_V3_TRDA)) { body.setReco(newBody.getText()); } } // The first frame was a TDRC frame that was not really allowed, this new frame was probably a // valid frame such as TYER which has been converted to TDRC, replace the firstframe with this frame else if (firstFrame.getBody() instanceof FrameBodyUnsupported) { frameMap.put(newFrame.getIdentifier(), newFrame); } else { //we just lose this frame, weve already got one with the correct id. //TODO may want to store this somewhere logger.warning("Found duplicate TDRC frame in invalid situation,discarding:" + newFrame.getIdentifier()); } } else { List list = new ArrayList(); list.add(firstFrame); list.add(newFrame); frameMap.put(newFrame.getIdentifier(), list); } } else { List list = (List)o; list.add(newFrame); } } else { frameMap.put(newFrame.getIdentifier(), newFrame); } } /** * Copy Constructor, creates a new ID3v2_4 Tag based on another ID3v2_4 Tag * @param copyObject */ public ID3v24Tag(ID3v24Tag copyObject) { logger.info("Creating tag from another tag of same type"); copyPrimitives(copyObject); copyFrames(copyObject); } /** * Creates a new ID3v2_4 datatype based on another (non 2.4) tag * * @param mp3tag */ public ID3v24Tag(AbstractTag mp3tag) { logger.info("Creating tag from a tag of a different version"); frameMap = new LinkedHashMap(); encryptedFrameMap = new LinkedHashMap(); if (mp3tag != null) { //Should use simpler copy constructor if ((mp3tag instanceof ID3v24Tag)) { throw new UnsupportedOperationException("Copy Constructor not called. Please type cast the argument"); } /* If we get a tag, we want to convert to id3v2_4 * both id3v1 and lyrics3 convert to this type * id3v1 needs to convert to id3v2_4 before converting to lyrics3 */ else if (mp3tag instanceof AbstractID3v2Tag) { this.setLoggingFilename(((AbstractID3v2Tag)mp3tag).getLoggingFilename()); copyPrimitives((AbstractID3v2Tag) mp3tag); copyFrames((AbstractID3v2Tag) mp3tag); } //IDv1 else if (mp3tag instanceof ID3v1Tag) { // convert id3v1 tags. ID3v1Tag id3tag = (ID3v1Tag) mp3tag; ID3v24Frame newFrame; AbstractID3v2FrameBody newBody; if (id3tag.title.length() > 0) { newBody = new FrameBodyTIT2((byte) 0, id3tag.title); newFrame = new ID3v24Frame(ID3v24Frames.FRAME_ID_TITLE); newFrame.setBody(newBody); frameMap.put(newFrame.getIdentifier(), newFrame); } if (id3tag.artist.length() > 0) { newBody = new FrameBodyTPE1((byte) 0, id3tag.artist); newFrame = new ID3v24Frame(ID3v24Frames.FRAME_ID_ARTIST); newFrame.setBody(newBody); frameMap.put(newFrame.getIdentifier(), newFrame); } if (id3tag.album.length() > 0) { newBody = new FrameBodyTALB((byte) 0, id3tag.album); newFrame = new ID3v24Frame(ID3v24Frames.FRAME_ID_ALBUM); newFrame.setBody(newBody); frameMap.put(newFrame.getIdentifier(), newFrame); } if (id3tag.year.length() > 0) { newBody = new FrameBodyTDRC((byte) 0, id3tag.year); newFrame = new ID3v24Frame(ID3v24Frames.FRAME_ID_YEAR); newFrame.setBody(newBody); frameMap.put(newFrame.getIdentifier(), newFrame); } if (id3tag.comment.length() > 0) { newBody = new FrameBodyCOMM((byte) 0, "ENG", "", id3tag.comment); newFrame = new ID3v24Frame(ID3v24Frames.FRAME_ID_COMMENT); newFrame.setBody(newBody); frameMap.put(newFrame.getIdentifier(), newFrame); } if (((id3tag.genre & ID3v1Tag.BYTE_TO_UNSIGNED) >= 0) && ((id3tag.genre & ID3v1Tag.BYTE_TO_UNSIGNED) != ID3v1Tag.BYTE_TO_UNSIGNED)) { Integer genreId = id3tag.genre & ID3v1Tag.BYTE_TO_UNSIGNED; String genre = "(" + genreId + ") " + GenreTypes.getInstanceOf().getValueForId(genreId); newBody = new FrameBodyTCON((byte) 0, genre); newFrame = new ID3v24Frame(ID3v24Frames.FRAME_ID_GENRE); newFrame.setBody(newBody); frameMap.put(newFrame.getIdentifier(), newFrame); } if (mp3tag instanceof ID3v11Tag) { ID3v11Tag id3tag2 = (ID3v11Tag) mp3tag; if (id3tag2.track > 0) { newBody = new FrameBodyTRCK((byte) 0, Byte.toString(id3tag2.track)); newFrame = new ID3v24Frame(ID3v24Frames.FRAME_ID_TRACK); newFrame.setBody(newBody); frameMap.put(newFrame.getIdentifier(), newFrame); } } } //Lyrics 3 else if (mp3tag instanceof AbstractLyrics3) { //Put the conversion stuff in the individual frame code. Lyrics3v2 lyric; if (mp3tag instanceof Lyrics3v2) { lyric = new Lyrics3v2((Lyrics3v2) mp3tag); } else { lyric = new Lyrics3v2(mp3tag); } Iterator iterator = lyric.iterator(); Lyrics3v2Field field; ID3v24Frame newFrame; while (iterator.hasNext()) { try { field = iterator.next(); newFrame = new ID3v24Frame(field); frameMap.put(newFrame.getIdentifier(), newFrame); } catch (InvalidTagException ex) { logger.warning("Unable to convert Lyrics3 to v24 Frame:Frame Identifier"); } } } } } /** * Creates a new ID3v2_4 datatype. * * @param buffer * @param loggingFilename * @throws TagException */ public ID3v24Tag(ByteBuffer buffer, String loggingFilename) throws TagException { frameMap = new LinkedHashMap(); encryptedFrameMap = new LinkedHashMap(); setLoggingFilename(loggingFilename); this.read(buffer); } /** * Creates a new ID3v2_4 datatype. * * @param buffer * @throws TagException * @deprecated use {@link #ID3v24Tag(ByteBuffer,String)} instead */ public ID3v24Tag(ByteBuffer buffer) throws TagException { this(buffer, ""); } /** * @return identifier */ public String getIdentifier() { return "ID3v2.40"; } /** * Return tag size based upon the sizes of the frames rather than the physical * no of bytes between start of ID3Tag and start of Audio Data. * * @return size */ public int getSize() { int size = TAG_HEADER_LENGTH; if (extended) { size += TAG_EXT_HEADER_LENGTH; if (updateTag) { size += TAG_EXT_HEADER_UPDATE_LENGTH; } if (crcDataFlag) { size += TAG_EXT_HEADER_CRC_LENGTH; } if (tagRestriction) { size += TAG_EXT_HEADER_RESTRICTION_LENGTH; } } size += super.getSize(); logger.finer("Tag Size is" + size); return size; } /** * @param obj * @return equality */ public boolean equals(Object obj) { if (!(obj instanceof ID3v24Tag)) { return false; } ID3v24Tag object = (ID3v24Tag) obj; if (this.footer != object.footer) { return false; } if (this.imageEncodingRestriction != object.imageEncodingRestriction) { return false; } if (this.imageSizeRestriction != object.imageSizeRestriction) { return false; } if (this.tagRestriction != object.tagRestriction) { return false; } if (this.tagSizeRestriction != object.tagSizeRestriction) { return false; } if (this.textEncodingRestriction != object.textEncodingRestriction) { return false; } if (this.textFieldSizeRestriction != object.textFieldSizeRestriction) { return false; } return this.updateTag == object.updateTag && super.equals(obj); } /** * Read the size of a tag, based on the value written in the tag header * * @param buffer * @return * @throws TagException */ public int readSize(ByteBuffer buffer) { //Skip over flags buffer.get(); // Read the size, this is size of tag not including the tag header int size = ID3SyncSafeInteger.bufferToValue(buffer); //Return the exact size of tag as set in the tag header return size + TAG_HEADER_LENGTH; } /** * Read header flags *

*

Log info messages for falgs that have been set and log warnings when bits have been set for unknown flags

* * @param byteBuffer * @throws TagException */ private void readHeaderFlags(ByteBuffer byteBuffer) throws TagException { //Flags byte flags = byteBuffer.get(); unsynchronization = (flags & MASK_V24_UNSYNCHRONIZATION) != 0; extended = (flags & MASK_V24_EXTENDED_HEADER) != 0; experimental = (flags & MASK_V24_EXPERIMENTAL) != 0; footer = (flags & MASK_V24_FOOTER_PRESENT) != 0; //Not allowable/Unknown Flags if ((flags & FileConstants.BIT3) != 0) { logger.warning(ErrorMessage.ID3_INVALID_OR_UNKNOWN_FLAG_SET.getMsg(getLoggingFilename(), FileConstants.BIT3)); } if ((flags & FileConstants.BIT2) != 0) { logger.warning(ErrorMessage.ID3_INVALID_OR_UNKNOWN_FLAG_SET.getMsg(getLoggingFilename(), FileConstants.BIT2)); } if ((flags & FileConstants.BIT1) != 0) { logger.warning(ErrorMessage.ID3_INVALID_OR_UNKNOWN_FLAG_SET.getMsg(getLoggingFilename(), FileConstants.BIT1)); } if ((flags & FileConstants.BIT0) != 0) { logger.warning(ErrorMessage.ID3_INVALID_OR_UNKNOWN_FLAG_SET.getMsg(getLoggingFilename(), FileConstants.BIT0)); } if (isUnsynchronization()) { logger.info(ErrorMessage.ID3_TAG_UNSYNCHRONIZED.getMsg(getLoggingFilename())); } if (extended) { logger.info(ErrorMessage.ID3_TAG_EXTENDED.getMsg(getLoggingFilename())); } if (experimental) { logger.info(ErrorMessage.ID3_TAG_EXPERIMENTAL.getMsg(getLoggingFilename())); } if (footer) { logger.warning(ErrorMessage.ID3_TAG_FOOTER.getMsg(getLoggingFilename())); } } /** * Read the optional extended header * * @param byteBuffer * @param size * @throws org.jaudiotagger.tag.InvalidTagException */ private void readExtendedHeader(ByteBuffer byteBuffer, int size) throws InvalidTagException { byte[] buffer; // int is 4 bytes. int extendedHeaderSize = byteBuffer.getInt(); // the extended header must be at least 6 bytes if (extendedHeaderSize <= TAG_EXT_HEADER_LENGTH) { throw new InvalidTagException(ErrorMessage.ID3_EXTENDED_HEADER_SIZE_TOO_SMALL.getMsg(getLoggingFilename(), extendedHeaderSize)); } //Number of bytes byteBuffer.get(); // Read the extended flag bytes byte extFlag = byteBuffer.get(); updateTag = (extFlag & MASK_V24_TAG_UPDATE) != 0; crcDataFlag = (extFlag & MASK_V24_CRC_DATA_PRESENT) != 0; tagRestriction = (extFlag & MASK_V24_TAG_RESTRICTIONS) != 0; // read the length byte if the flag is set // this tag should always be zero but just in case // read this information. if (updateTag) { byteBuffer.get(); } //CRC-32 if (crcDataFlag) { // the CRC has a variable length byteBuffer.get(); buffer = new byte[TAG_EXT_HEADER_CRC_DATA_LENGTH]; byteBuffer.get(buffer, 0, TAG_EXT_HEADER_CRC_DATA_LENGTH); crcData = 0; for (int i = 0; i < TAG_EXT_HEADER_CRC_DATA_LENGTH; i++) { crcData <<= 8; crcData += buffer[i]; } } //Tag Restriction if (tagRestriction) { byteBuffer.get(); buffer = new byte[1]; byteBuffer.get(buffer, 0, 1); tagSizeRestriction = (byte) ((buffer[0] & MASK_V24_TAG_SIZE_RESTRICTIONS) >> 6); textEncodingRestriction = (byte) ((buffer[0] & MASK_V24_TEXT_ENCODING_RESTRICTIONS) >> 5); textFieldSizeRestriction = (byte) ((buffer[0] & MASK_V24_TEXT_FIELD_SIZE_RESTRICTIONS) >> 3); imageEncodingRestriction = (byte) ((buffer[0] & MASK_V24_IMAGE_ENCODING) >> 2); imageSizeRestriction = (byte) (buffer[0] & MASK_V24_IMAGE_SIZE_RESTRICTIONS); } } /** * {@inheritDoc} */ @Override public void read(ByteBuffer byteBuffer) throws TagException { int size; byte[] buffer; if (!seek(byteBuffer)) { throw new TagNotFoundException(getLoggingFilename() + ":" + getIdentifier() + " tag not found"); } logger.info(getLoggingFilename() + ":" + "Reading ID3v24 tag"); readHeaderFlags(byteBuffer); // Read the size, this is size of tag apart from tag header size = ID3SyncSafeInteger.bufferToValue(byteBuffer); logger.info(getLoggingFilename() + ":" + "Reading tag from file size set in header is" + size); if (extended) { readExtendedHeader(byteBuffer, size); } //Note if there was an extended header the size value has padding taken //off so we dont search it. readFrames(byteBuffer, size); } /** * Read frames from tag * @param byteBuffer * @param size */ protected void readFrames(ByteBuffer byteBuffer, int size) { logger.finest(getLoggingFilename() + ":" + "Start of frame body at" + byteBuffer.position()); //Now start looking for frames ID3v24Frame next; frameMap = new LinkedHashMap(); encryptedFrameMap = new LinkedHashMap(); //Read the size from the Tag Header this.fileReadSize = size; // Read the frames until got to upto the size as specified in header logger.finest(getLoggingFilename() + ":" + "Start of frame body at:" + byteBuffer.position() + ",frames data size is:" + size); while (byteBuffer.position() <= size) { String id; try { //Read Frame logger.finest(getLoggingFilename() + ":" + "looking for next frame at:" + byteBuffer.position()); next = new ID3v24Frame(byteBuffer, getLoggingFilename()); id = next.getIdentifier(); loadFrameIntoMap(id, next); } //Found Padding, no more frames catch (PaddingException ex) { logger.config(getLoggingFilename() + ":Found padding starting at:" + byteBuffer.position()); break; } //Found Empty Frame catch (EmptyFrameException ex) { logger.warning(getLoggingFilename() + ":" + "Empty Frame:" + ex.getMessage()); this.emptyFrameBytes += TAG_HEADER_LENGTH; } catch (InvalidFrameIdentifierException ifie) { logger.info(getLoggingFilename() + ":" + "Invalid Frame Identifier:" + ifie.getMessage()); this.invalidFrames++; //Don't try and find any more frames break; } //Problem trying to find frame catch (InvalidFrameException ife) { logger.warning(getLoggingFilename() + ":" + "Invalid Frame:" + ife.getMessage()); this.invalidFrames++; //Don't try and find any more frames break; } //Failed reading frame but may just have invalid data but correct length so lets carry on //in case we can read the next frame catch(InvalidDataTypeException idete) { logger.warning(getLoggingFilename() + ":Corrupt Frame:" + idete.getMessage()); this.invalidFrames++; continue; } } } /** * Write the ID3 header to the ByteBuffer. *

* TODO Calculate the CYC Data Check * TODO Reintroduce Extended Header * * @param padding is the size of the padding * @param size is the size of the body data * @return ByteBuffer * @throws IOException */ private ByteBuffer writeHeaderToBuffer(int padding, int size) throws IOException { //This would only be set if every frame in tag has been unsynchronized, I only unsychronize frames //that need it, in any case I have been advised not to set it even then. unsynchronization = false; // Flags,currently we never calculate the CRC // and if we dont calculate them cant keep orig values. Tags are not // experimental and we never create extended header to keep things simple. extended = false; experimental = false; footer = false; // Create Header Buffer,allocate maximum possible size for the header ByteBuffer headerBuffer = ByteBuffer.allocate(TAG_HEADER_LENGTH); //TAGID headerBuffer.put(TAG_ID); //Major Version headerBuffer.put(getMajorVersion()); //Minor Version headerBuffer.put(getRevision()); //Flags byte flagsByte = 0; if (isUnsynchronization()) { flagsByte |= MASK_V24_UNSYNCHRONIZATION; } if (extended) { flagsByte |= MASK_V24_EXTENDED_HEADER; } if (experimental) { flagsByte |= MASK_V24_EXPERIMENTAL; } if (footer) { flagsByte |= MASK_V24_FOOTER_PRESENT; } headerBuffer.put(flagsByte); //Size As Recorded in Header, don't include the main header length //Additional Header Size,(for completeness we never actually write the extended header, or footer) int additionalHeaderSize = 0; if (extended) { additionalHeaderSize += TAG_EXT_HEADER_LENGTH; if (updateTag) { additionalHeaderSize += TAG_EXT_HEADER_UPDATE_LENGTH; } if (crcDataFlag) { additionalHeaderSize += TAG_EXT_HEADER_CRC_LENGTH; } if (tagRestriction) { additionalHeaderSize += TAG_EXT_HEADER_RESTRICTION_LENGTH; } } //Size As Recorded in Header, don't include the main header length headerBuffer.put(ID3SyncSafeInteger.valueToBuffer(padding + size + additionalHeaderSize)); //Write Extended Header ByteBuffer extHeaderBuffer = null; if (extended) { //Write Extended Header Size int extendedSize = TAG_EXT_HEADER_LENGTH; if (updateTag) { extendedSize += TAG_EXT_HEADER_UPDATE_LENGTH; } if (crcDataFlag) { extendedSize += TAG_EXT_HEADER_CRC_LENGTH; } if (tagRestriction) { extendedSize += TAG_EXT_HEADER_RESTRICTION_LENGTH; } extHeaderBuffer = ByteBuffer.allocate(extendedSize); extHeaderBuffer.putInt(extendedSize); //Write Number of flags Byte extHeaderBuffer.put((byte) TAG_EXT_NUMBER_BYTES_DATA_LENGTH); //Write Extended Flags byte extFlag = 0; if (updateTag) { extFlag |= MASK_V24_TAG_UPDATE; } if (crcDataFlag) { extFlag |= MASK_V24_CRC_DATA_PRESENT; } if (tagRestriction) { extFlag |= MASK_V24_TAG_RESTRICTIONS; } extHeaderBuffer.put(extFlag); //Write Update Data if (updateTag) { extHeaderBuffer.put((byte) 0); } //Write CRC Data if (crcDataFlag) { extHeaderBuffer.put((byte) TAG_EXT_HEADER_CRC_DATA_LENGTH); extHeaderBuffer.put((byte) 0); extHeaderBuffer.putInt(crcData); } //Write Tag Restriction if (tagRestriction) { extHeaderBuffer.put((byte) TAG_EXT_HEADER_RESTRICTION_DATA_LENGTH); //todo not currently setting restrictions extHeaderBuffer.put((byte) 0); } } if (extHeaderBuffer != null) { extHeaderBuffer.flip(); headerBuffer.put(extHeaderBuffer); } headerBuffer.flip(); return headerBuffer; } /** * {@inheritDoc} */ @Override public void write(File file, long audioStartLocation) throws IOException { setLoggingFilename(file.getName()); logger.info("Writing tag to file:"+getLoggingFilename()); //Write Body Buffer byte[] bodyByteBuffer = writeFramesToBuffer().toByteArray(); //Calculate Tag Size including Padding int sizeIncPadding = calculateTagSize(bodyByteBuffer.length + TAG_HEADER_LENGTH, (int) audioStartLocation); //Calculate padding bytes required int padding = sizeIncPadding - (bodyByteBuffer.length + TAG_HEADER_LENGTH); ByteBuffer headerBuffer = writeHeaderToBuffer(padding, bodyByteBuffer.length); writeBufferToFile(file, headerBuffer, bodyByteBuffer, padding, sizeIncPadding, audioStartLocation); } /** * {@inheritDoc} */ @Override public void write(WritableByteChannel channel) throws IOException { logger.info("Writing tag to channel"); byte[] bodyByteBuffer = writeFramesToBuffer().toByteArray(); ByteBuffer headerBuffer = writeHeaderToBuffer(0, bodyByteBuffer.length); channel.write(headerBuffer); channel.write(ByteBuffer.wrap(bodyByteBuffer)); } /** * Display the tag in an XMLFormat */ public void createStructure() { MP3File.getStructureFormatter().openHeadingElement(TYPE_TAG, getIdentifier()); super.createStructureHeader(); //Header MP3File.getStructureFormatter().openHeadingElement(TYPE_HEADER, ""); MP3File.getStructureFormatter().addElement(TYPE_UNSYNCHRONISATION, this.isUnsynchronization()); MP3File.getStructureFormatter().addElement(TYPE_CRCDATA, this.crcData); MP3File.getStructureFormatter().addElement(TYPE_EXPERIMENTAL, this.experimental); MP3File.getStructureFormatter().addElement(TYPE_EXTENDED, this.extended); MP3File.getStructureFormatter().addElement(TYPE_PADDINGSIZE, this.paddingSize); MP3File.getStructureFormatter().addElement(TYPE_FOOTER, this.footer); MP3File.getStructureFormatter().addElement(TYPE_IMAGEENCODINGRESTRICTION, this.paddingSize); MP3File.getStructureFormatter().addElement(TYPE_IMAGESIZERESTRICTION, this.imageSizeRestriction); MP3File.getStructureFormatter().addElement(TYPE_TAGRESTRICTION, this.tagRestriction); MP3File.getStructureFormatter().addElement(TYPE_TAGSIZERESTRICTION, this.tagSizeRestriction); MP3File.getStructureFormatter().addElement(TYPE_TEXTFIELDSIZERESTRICTION, this.textFieldSizeRestriction); MP3File.getStructureFormatter().addElement(TYPE_TEXTENCODINGRESTRICTION, this.textEncodingRestriction); MP3File.getStructureFormatter().addElement(TYPE_UPDATETAG, this.updateTag); MP3File.getStructureFormatter().closeHeadingElement(TYPE_HEADER); //Body super.createStructureBody(); MP3File.getStructureFormatter().closeHeadingElement(TYPE_TAG); } /** * Are all frame swithin this tag unsynchronized *

*

Because synchronization occurs at the frame level it is not normally desirable to unsynchronize all frames * and hence this flag is not normally set. * * @return are all frames within the tag unsynchronized */ public boolean isUnsynchronization() { return unsynchronization; } /** * Create a new frame with the specified frameid * * @param id * @return */ public ID3v24Frame createFrame(String id) { return new ID3v24Frame(id); } /** * Create Frame for Id3 Key *

* Only textual data supported at the moment, should only be used with frames that * support a simple string argument. * * @param id3Key * @param value * @return * @throws KeyNotFoundException * @throws FieldDataInvalidException */ public TagField createField(ID3v24FieldKey id3Key, String value) throws KeyNotFoundException, FieldDataInvalidException { if (id3Key == null) { throw new KeyNotFoundException(); } return super.doCreateTagField(new FrameAndSubId(id3Key.getFrameId(), id3Key.getSubId()), value); } /** * Retrieve the first value that exists for this id3v24key * * @param id3v24FieldKey * @return * @throws org.jaudiotagger.tag.KeyNotFoundException */ public String getFirst(ID3v24FieldKey id3v24FieldKey) throws KeyNotFoundException { if (id3v24FieldKey == null) { throw new KeyNotFoundException(); } FrameAndSubId frameAndSubId = new FrameAndSubId(id3v24FieldKey.getFrameId(), id3v24FieldKey.getSubId()); if (id3v24FieldKey == ID3v24FieldKey.TRACK) { AbstractID3v2Frame frame = getFirstField(frameAndSubId.getFrameId()); return String.valueOf(((FrameBodyTRCK)frame.getBody()).getTrackNo()); } else if (id3v24FieldKey == ID3v24FieldKey.TRACK_TOTAL) { AbstractID3v2Frame frame = getFirstField(frameAndSubId.getFrameId()); return String.valueOf(((FrameBodyTRCK)frame.getBody()).getTrackTotal()); } else if (id3v24FieldKey == ID3v24FieldKey.DISC_NO) { AbstractID3v2Frame frame = getFirstField(frameAndSubId.getFrameId()); return String.valueOf(((FrameBodyTPOS)frame.getBody()).getDiscNo()); } else if (id3v24FieldKey == ID3v24FieldKey.DISC_TOTAL) { AbstractID3v2Frame frame = getFirstField(frameAndSubId.getFrameId()); return String.valueOf(((FrameBodyTPOS)frame.getBody()).getDiscTotal()); } else { return super.doGetValueAtIndex(frameAndSubId, 0); } } /** * Delete fields with this id3v24FieldKey * * @param id3v24FieldKey * @throws org.jaudiotagger.tag.KeyNotFoundException */ public void deleteField(ID3v24FieldKey id3v24FieldKey) throws KeyNotFoundException { if (id3v24FieldKey == null) { throw new KeyNotFoundException(); } super.doDeleteTagField(new FrameAndSubId(id3v24FieldKey.getFrameId(), id3v24FieldKey.getSubId())); } /** * Delete fields with this (frame) id * @param id */ public void deleteField(String id) { super.doDeleteTagField(new FrameAndSubId(id,null)); } protected FrameAndSubId getFrameAndSubIdFromGenericKey(FieldKey genericKey) { ID3v24FieldKey id3v24FieldKey = ID3v24Frames.getInstanceOf().getId3KeyFromGenericKey(genericKey); if (id3v24FieldKey == null) { throw new KeyNotFoundException("Unable to find key for "+genericKey.name()); } return new FrameAndSubId(id3v24FieldKey.getFrameId(), id3v24FieldKey.getSubId()); } protected ID3Frames getID3Frames() { return ID3v24Frames.getInstanceOf(); } /** * @return comparator used to order frames in preferred order for writing to file * so that most important frames are written first. */ public Comparator getPreferredFrameOrderComparator() { return ID3v24PreferredFrameOrderComparator.getInstanceof(); } public List getArtworkList() { List coverartList = getFields(FieldKey.COVER_ART); List artworkList = new ArrayList(coverartList.size()); for (TagField next : coverartList) { FrameBodyAPIC coverArt = (FrameBodyAPIC) ((AbstractID3v2Frame) next).getBody(); Artwork artwork = new Artwork(); artwork.setMimeType(coverArt.getMimeType()); artwork.setPictureType(coverArt.getPictureType()); if (coverArt.isImageUrl()) { artwork.setLinked(true); artwork.setImageUrl(coverArt.getImageUrl()); } else { artwork.setBinaryData(coverArt.getImageData()); } artworkList.add(artwork); } return artworkList; } public TagField createField(Artwork artwork) throws FieldDataInvalidException { AbstractID3v2Frame frame = createFrame(getFrameAndSubIdFromGenericKey(FieldKey.COVER_ART).getFrameId()); FrameBodyAPIC body = (FrameBodyAPIC) frame.getBody(); body.setObjectValue(DataTypes.OBJ_PICTURE_DATA, artwork.getBinaryData()); body.setObjectValue(DataTypes.OBJ_PICTURE_TYPE, artwork.getPictureType()); body.setObjectValue(DataTypes.OBJ_MIME_TYPE, artwork.getMimeType()); body.setObjectValue(DataTypes.OBJ_DESCRIPTION, ""); return frame; } /** * Create Artwork * * @param data * @param mimeType of the image * @see PictureTypes * @return */ public TagField createArtworkField(byte[] data, String mimeType) { AbstractID3v2Frame frame = createFrame(getFrameAndSubIdFromGenericKey(FieldKey.COVER_ART).getFrameId()); FrameBodyAPIC body = (FrameBodyAPIC) frame.getBody(); body.setObjectValue(DataTypes.OBJ_PICTURE_DATA, data); body.setObjectValue(DataTypes.OBJ_PICTURE_TYPE, PictureTypes.DEFAULT_ID); body.setObjectValue(DataTypes.OBJ_MIME_TYPE, mimeType); body.setObjectValue(DataTypes.OBJ_DESCRIPTION, ""); return frame; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/ID3v24Frames.java0000644000175000017500000006273311470746136025700 0ustar drazzibdrazzib/* * Jaudiotagger Copyright (C)2004,2005 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can getFields a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3; import org.jaudiotagger.tag.FieldKey; import java.util.EnumMap; /** * Defines ID3v24 frames and collections that categorise frames. *

*

You can include frames here that are not officially supported as long as they can be used within an * ID3v24Tag * * @author Paul Taylor * @version $Id: ID3v24Frames.java 929 2010-11-17 12:36:46Z paultaylor $ */ public class ID3v24Frames extends ID3Frames { /** * Frame IDs beginning with T are text frames, & with W are url frames */ public static final String FRAME_ID_ACCOMPANIMENT = "TPE2"; public static final String FRAME_ID_ALBUM = "TALB"; public static final String FRAME_ID_ALBUM_SORT_ORDER = "TSOA"; public static final String FRAME_ID_ARTIST = "TPE1"; public static final String FRAME_ID_ATTACHED_PICTURE = "APIC"; public static final String FRAME_ID_AUDIO_ENCRYPTION = "AENC"; public static final String FRAME_ID_AUDIO_SEEK_POINT_INDEX = "ASPI"; public static final String FRAME_ID_BPM = "TBPM"; public static final String FRAME_ID_COMMENT = "COMM"; public static final String FRAME_ID_COMMERCIAL_FRAME = "COMR"; public static final String FRAME_ID_COMPOSER = "TCOM"; public static final String FRAME_ID_CONDUCTOR = "TPE3"; public static final String FRAME_ID_CONTENT_GROUP_DESC = "TIT1"; public static final String FRAME_ID_COPYRIGHTINFO = "TCOP"; public static final String FRAME_ID_ENCODEDBY = "TENC"; public static final String FRAME_ID_ENCODING_TIME = "TDEN"; public static final String FRAME_ID_ENCRYPTION = "ENCR"; public static final String FRAME_ID_EQUALISATION2 = "EQU2"; public static final String FRAME_ID_EVENT_TIMING_CODES = "ETCO"; public static final String FRAME_ID_FILE_OWNER = "TOWN"; public static final String FRAME_ID_FILE_TYPE = "TFLT"; public static final String FRAME_ID_GENERAL_ENCAPS_OBJECT = "GEOB"; public static final String FRAME_ID_GENRE = "TCON"; public static final String FRAME_ID_GROUP_ID_REG = "GRID"; public static final String FRAME_ID_HW_SW_SETTINGS = "TSSE"; public static final String FRAME_ID_INITIAL_KEY = "TKEY"; public static final String FRAME_ID_INVOLVED_PEOPLE = "TIPL"; public static final String FRAME_ID_ISRC = "TSRC"; public static final String FRAME_ID_LANGUAGE = "TLAN"; public static final String FRAME_ID_LENGTH = "TLEN"; public static final String FRAME_ID_LINKED_INFO = "LINK"; public static final String FRAME_ID_LYRICIST = "TEXT"; public static final String FRAME_ID_MEDIA_TYPE = "TMED"; public static final String FRAME_ID_MOOD = "TMOO"; public static final String FRAME_ID_MPEG_LOCATION_LOOKUP_TABLE = "MLLT"; public static final String FRAME_ID_MUSICIAN_CREDITS = "TMCL"; public static final String FRAME_ID_MUSIC_CD_ID = "MCDI"; public static final String FRAME_ID_ORIGARTIST = "TOPE"; public static final String FRAME_ID_ORIGINAL_RELEASE_TIME = "TDOR"; public static final String FRAME_ID_ORIG_FILENAME = "TOFN"; public static final String FRAME_ID_ORIG_LYRICIST = "TOLY"; public static final String FRAME_ID_ORIG_TITLE = "TOAL"; public static final String FRAME_ID_OWNERSHIP = "OWNE"; public static final String FRAME_ID_ARTIST_SORT_ORDER = "TSOP"; public static final String FRAME_ID_PLAYLIST_DELAY = "TDLY"; public static final String FRAME_ID_PLAY_COUNTER = "PCNT"; public static final String FRAME_ID_POPULARIMETER = "POPM"; public static final String FRAME_ID_POSITION_SYNC = "POSS"; public static final String FRAME_ID_PRIVATE = "PRIV"; public static final String FRAME_ID_PRODUCED_NOTICE = "TPRO"; public static final String FRAME_ID_PUBLISHER = "TPUB"; public static final String FRAME_ID_RADIO_NAME = "TRSN"; public static final String FRAME_ID_RADIO_OWNER = "TRSO"; public static final String FRAME_ID_RECOMMENDED_BUFFER_SIZE = "RBUF"; public static final String FRAME_ID_RELATIVE_VOLUME_ADJUSTMENT2 = "RVA2"; public static final String FRAME_ID_RELEASE_TIME = "TDRL"; public static final String FRAME_ID_REMIXED = "TPE4"; public static final String FRAME_ID_REVERB = "RVRB"; public static final String FRAME_ID_SEEK = "SEEK"; public static final String FRAME_ID_SET = "TPOS"; public static final String FRAME_ID_SET_SUBTITLE = "TSST"; public static final String FRAME_ID_SIGNATURE = "SIGN"; public static final String FRAME_ID_SYNC_LYRIC = "SYLT"; public static final String FRAME_ID_SYNC_TEMPO = "SYTC"; public static final String FRAME_ID_TAGGING_TIME = "TDTG"; public static final String FRAME_ID_TERMS_OF_USE = "USER"; public static final String FRAME_ID_TITLE = "TIT2"; public static final String FRAME_ID_TITLE_REFINEMENT = "TIT3"; public static final String FRAME_ID_TITLE_SORT_ORDER = "TSOT"; public static final String FRAME_ID_TRACK = "TRCK"; public static final String FRAME_ID_UNIQUE_FILE_ID = "UFID"; public static final String FRAME_ID_UNSYNC_LYRICS = "USLT"; public static final String FRAME_ID_URL_ARTIST_WEB = "WOAR"; public static final String FRAME_ID_URL_COMMERCIAL = "WCOM"; public static final String FRAME_ID_URL_COPYRIGHT = "WCOP"; public static final String FRAME_ID_URL_FILE_WEB = "WOAF"; public static final String FRAME_ID_URL_OFFICIAL_RADIO = "WORS"; public static final String FRAME_ID_URL_PAYMENT = "WPAY"; public static final String FRAME_ID_URL_PUBLISHERS = "WPUB"; public static final String FRAME_ID_URL_SOURCE_WEB = "WOAS"; public static final String FRAME_ID_USER_DEFINED_INFO = "TXXX"; public static final String FRAME_ID_USER_DEFINED_URL = "WXXX"; public static final String FRAME_ID_YEAR = "TDRC"; public static final String FRAME_ID_ALBUM_ARTIST_SORT_ORDER_ITUNES = "TSO2"; public static final String FRAME_ID_COMPOSER_SORT_ORDER_ITUNES = "TSOC"; public static final String FRAME_ID_IS_COMPILATION = "TCMP"; //TODO this is temporary to provide backwards compatability public static final String FRAME_ID_PERFORMER_SORT_OWNER = FRAME_ID_ARTIST_SORT_ORDER; public static final String FRAME_ID_TITLE_SORT_OWNER = FRAME_ID_TITLE_SORT_ORDER; protected EnumMap tagFieldToId3 = new EnumMap(FieldKey.class); private static ID3v24Frames id3v24Frames; public static ID3v24Frames getInstanceOf() { if (id3v24Frames == null) { id3v24Frames = new ID3v24Frames(); } return id3v24Frames; } private ID3v24Frames() { supportedFrames.add(FRAME_ID_ACCOMPANIMENT); supportedFrames.add(FRAME_ID_ALBUM); supportedFrames.add(FRAME_ID_ALBUM_SORT_ORDER); supportedFrames.add(FRAME_ID_ARTIST); supportedFrames.add(FRAME_ID_ATTACHED_PICTURE); supportedFrames.add(FRAME_ID_AUDIO_ENCRYPTION); supportedFrames.add(FRAME_ID_AUDIO_SEEK_POINT_INDEX); supportedFrames.add(FRAME_ID_BPM); supportedFrames.add(FRAME_ID_COMMENT); supportedFrames.add(FRAME_ID_COMMERCIAL_FRAME); supportedFrames.add(FRAME_ID_COMPOSER); supportedFrames.add(FRAME_ID_CONDUCTOR); supportedFrames.add(FRAME_ID_CONTENT_GROUP_DESC); supportedFrames.add(FRAME_ID_COPYRIGHTINFO); supportedFrames.add(FRAME_ID_ENCODEDBY); supportedFrames.add(FRAME_ID_ENCODING_TIME); supportedFrames.add(FRAME_ID_ENCRYPTION); supportedFrames.add(FRAME_ID_EQUALISATION2); supportedFrames.add(FRAME_ID_EVENT_TIMING_CODES); supportedFrames.add(FRAME_ID_FILE_OWNER); supportedFrames.add(FRAME_ID_FILE_TYPE); supportedFrames.add(FRAME_ID_GENERAL_ENCAPS_OBJECT); supportedFrames.add(FRAME_ID_GENRE); supportedFrames.add(FRAME_ID_GROUP_ID_REG); supportedFrames.add(FRAME_ID_HW_SW_SETTINGS); supportedFrames.add(FRAME_ID_INITIAL_KEY); supportedFrames.add(FRAME_ID_INVOLVED_PEOPLE); supportedFrames.add(FRAME_ID_ISRC); supportedFrames.add(FRAME_ID_LANGUAGE); supportedFrames.add(FRAME_ID_LENGTH); supportedFrames.add(FRAME_ID_LINKED_INFO); supportedFrames.add(FRAME_ID_LYRICIST); supportedFrames.add(FRAME_ID_MEDIA_TYPE); supportedFrames.add(FRAME_ID_MOOD); supportedFrames.add(FRAME_ID_MPEG_LOCATION_LOOKUP_TABLE); supportedFrames.add(FRAME_ID_MUSIC_CD_ID); supportedFrames.add(FRAME_ID_ORIGARTIST); supportedFrames.add(FRAME_ID_ORIGINAL_RELEASE_TIME); supportedFrames.add(FRAME_ID_ORIG_FILENAME); supportedFrames.add(FRAME_ID_ORIG_LYRICIST); supportedFrames.add(FRAME_ID_ORIG_TITLE); supportedFrames.add(FRAME_ID_OWNERSHIP); supportedFrames.add(FRAME_ID_ARTIST_SORT_ORDER); supportedFrames.add(FRAME_ID_PLAYLIST_DELAY); supportedFrames.add(FRAME_ID_PLAY_COUNTER); supportedFrames.add(FRAME_ID_POPULARIMETER); supportedFrames.add(FRAME_ID_POSITION_SYNC); supportedFrames.add(FRAME_ID_PRIVATE); supportedFrames.add(FRAME_ID_PRODUCED_NOTICE); supportedFrames.add(FRAME_ID_PUBLISHER); supportedFrames.add(FRAME_ID_RADIO_NAME); supportedFrames.add(FRAME_ID_RADIO_OWNER); supportedFrames.add(FRAME_ID_RECOMMENDED_BUFFER_SIZE); supportedFrames.add(FRAME_ID_RELATIVE_VOLUME_ADJUSTMENT2); supportedFrames.add(FRAME_ID_RELEASE_TIME); supportedFrames.add(FRAME_ID_REMIXED); supportedFrames.add(FRAME_ID_REVERB); supportedFrames.add(FRAME_ID_SEEK); supportedFrames.add(FRAME_ID_SET); supportedFrames.add(FRAME_ID_SET_SUBTITLE); supportedFrames.add(FRAME_ID_SIGNATURE); supportedFrames.add(FRAME_ID_SYNC_LYRIC); supportedFrames.add(FRAME_ID_SYNC_TEMPO); supportedFrames.add(FRAME_ID_TAGGING_TIME); supportedFrames.add(FRAME_ID_TERMS_OF_USE); supportedFrames.add(FRAME_ID_TITLE); supportedFrames.add(FRAME_ID_TITLE_REFINEMENT); supportedFrames.add(FRAME_ID_TITLE_SORT_ORDER); supportedFrames.add(FRAME_ID_TRACK); supportedFrames.add(FRAME_ID_UNIQUE_FILE_ID); supportedFrames.add(FRAME_ID_UNSYNC_LYRICS); supportedFrames.add(FRAME_ID_URL_ARTIST_WEB); supportedFrames.add(FRAME_ID_URL_COMMERCIAL); supportedFrames.add(FRAME_ID_URL_COPYRIGHT); supportedFrames.add(FRAME_ID_URL_FILE_WEB); supportedFrames.add(FRAME_ID_URL_OFFICIAL_RADIO); supportedFrames.add(FRAME_ID_URL_PAYMENT); supportedFrames.add(FRAME_ID_URL_PUBLISHERS); supportedFrames.add(FRAME_ID_URL_SOURCE_WEB); supportedFrames.add(FRAME_ID_USER_DEFINED_INFO); supportedFrames.add(FRAME_ID_USER_DEFINED_URL); supportedFrames.add(FRAME_ID_YEAR); //Extension extensionFrames.add(FRAME_ID_IS_COMPILATION); extensionFrames.add(FRAME_ID_ALBUM_ARTIST_SORT_ORDER_ITUNES); extensionFrames.add(FRAME_ID_COMPOSER_SORT_ORDER_ITUNES); //Common commonFrames.add(FRAME_ID_ARTIST); commonFrames.add(FRAME_ID_ALBUM); commonFrames.add(FRAME_ID_TITLE); commonFrames.add(FRAME_ID_GENRE); commonFrames.add(FRAME_ID_TRACK); commonFrames.add(FRAME_ID_YEAR); commonFrames.add(FRAME_ID_COMMENT); //Binary binaryFrames.add(FRAME_ID_ATTACHED_PICTURE); binaryFrames.add(FRAME_ID_AUDIO_ENCRYPTION); binaryFrames.add(FRAME_ID_ENCRYPTION); binaryFrames.add(FRAME_ID_EQUALISATION2); binaryFrames.add(FRAME_ID_EVENT_TIMING_CODES); binaryFrames.add(FRAME_ID_GENERAL_ENCAPS_OBJECT); binaryFrames.add(FRAME_ID_RELATIVE_VOLUME_ADJUSTMENT2); binaryFrames.add(FRAME_ID_RECOMMENDED_BUFFER_SIZE); binaryFrames.add(FRAME_ID_UNIQUE_FILE_ID); // Map frameid to a name idToValue.put(FRAME_ID_ACCOMPANIMENT, "Text: Band/Orchestra/Accompaniment"); idToValue.put(FRAME_ID_ALBUM, "Text: Album/Movie/Show title"); idToValue.put(FRAME_ID_ALBUM_SORT_ORDER, "Album sort order"); idToValue.put(FRAME_ID_ARTIST, "Text: Lead artist(s)/Lead performer(s)/Soloist(s)/Performing group"); idToValue.put(FRAME_ID_ATTACHED_PICTURE, "Attached picture"); idToValue.put(FRAME_ID_AUDIO_ENCRYPTION, "Audio encryption"); idToValue.put(FRAME_ID_AUDIO_SEEK_POINT_INDEX, "Audio seek point index"); idToValue.put(FRAME_ID_BPM, "Text: BPM (Beats Per Minute)"); idToValue.put(FRAME_ID_COMMENT, "Comments"); idToValue.put(FRAME_ID_COMMERCIAL_FRAME, "Commercial Frame"); idToValue.put(FRAME_ID_COMPOSER, "Text: Composer"); idToValue.put(FRAME_ID_CONDUCTOR, "Text: Conductor/Performer refinement"); idToValue.put(FRAME_ID_CONTENT_GROUP_DESC, "Text: Content group description"); idToValue.put(FRAME_ID_COPYRIGHTINFO, "Text: Copyright message"); idToValue.put(FRAME_ID_ENCODEDBY, "Text: Encoded by"); idToValue.put(FRAME_ID_ENCODING_TIME, "Text: Encoding time"); idToValue.put(FRAME_ID_ENCRYPTION, "Encryption method registration"); idToValue.put(FRAME_ID_EQUALISATION2, "Equalization (2)"); idToValue.put(FRAME_ID_EVENT_TIMING_CODES, "Event timing codes"); idToValue.put(FRAME_ID_FILE_OWNER, "Text:File Owner"); idToValue.put(FRAME_ID_FILE_TYPE, "Text: File type"); idToValue.put(FRAME_ID_GENERAL_ENCAPS_OBJECT, "General encapsulated datatype"); idToValue.put(FRAME_ID_GENRE, "Text: Content type"); idToValue.put(FRAME_ID_GROUP_ID_REG, "Group ID Registration"); idToValue.put(FRAME_ID_HW_SW_SETTINGS, "Text: Software/hardware and settings used for encoding"); idToValue.put(FRAME_ID_INITIAL_KEY, "Text: Initial key"); idToValue.put(FRAME_ID_INVOLVED_PEOPLE, "Involved people list"); idToValue.put(FRAME_ID_ISRC, "Text: ISRC (International Standard Recording Code)"); idToValue.put(FRAME_ID_LANGUAGE, "Text: Language(s)"); idToValue.put(FRAME_ID_LENGTH, "Text: Length"); idToValue.put(FRAME_ID_LINKED_INFO, "Linked information"); idToValue.put(FRAME_ID_LYRICIST, "Text: Lyricist/text writer"); idToValue.put(FRAME_ID_MEDIA_TYPE, "Text: Media type"); idToValue.put(FRAME_ID_MOOD, "Text: Mood"); idToValue.put(FRAME_ID_MPEG_LOCATION_LOOKUP_TABLE, "MPEG location lookup table"); idToValue.put(FRAME_ID_MUSIC_CD_ID, "Music CD Identifier"); idToValue.put(FRAME_ID_ORIGARTIST, "Text: Original artist(s)/performer(s)"); idToValue.put(FRAME_ID_ORIGINAL_RELEASE_TIME, "Text: Original release time"); idToValue.put(FRAME_ID_ORIG_FILENAME, "Text: Original filename"); idToValue.put(FRAME_ID_ORIG_LYRICIST, "Text: Original Lyricist(s)/text writer(s)"); idToValue.put(FRAME_ID_ORIG_TITLE, "Text: Original album/Movie/Show title"); idToValue.put(FRAME_ID_OWNERSHIP, "Ownership"); idToValue.put(FRAME_ID_ARTIST_SORT_ORDER, "Performance Sort Order"); idToValue.put(FRAME_ID_PLAYLIST_DELAY, "Text: Playlist delay"); idToValue.put(FRAME_ID_PLAY_COUNTER, "Play counter"); idToValue.put(FRAME_ID_POPULARIMETER, "Popularimeter"); idToValue.put(FRAME_ID_POSITION_SYNC, "Position Sync"); idToValue.put(FRAME_ID_PRIVATE, "Private frame"); idToValue.put(FRAME_ID_PRODUCED_NOTICE, "Produced Notice"); idToValue.put(FRAME_ID_PUBLISHER, "Text: Publisher"); idToValue.put(FRAME_ID_RADIO_NAME, "Text: Radio Name"); idToValue.put(FRAME_ID_RADIO_OWNER, "Text: Radio Owner"); idToValue.put(FRAME_ID_RECOMMENDED_BUFFER_SIZE, "Recommended buffer size"); idToValue.put(FRAME_ID_RELATIVE_VOLUME_ADJUSTMENT2, "Relative volume adjustment(2)"); idToValue.put(FRAME_ID_RELEASE_TIME, "Release Time"); idToValue.put(FRAME_ID_REMIXED, "Text: Interpreted, remixed, or otherwise modified by"); idToValue.put(FRAME_ID_REVERB, "Reverb"); idToValue.put(FRAME_ID_SEEK, "Seek"); idToValue.put(FRAME_ID_SET, "Text: Part of a setField"); idToValue.put(FRAME_ID_SET_SUBTITLE, "Text: Set subtitle"); idToValue.put(FRAME_ID_SIGNATURE, "Signature"); idToValue.put(FRAME_ID_SYNC_LYRIC, "Synchronized lyric/text"); idToValue.put(FRAME_ID_SYNC_TEMPO, "Synced tempo codes"); idToValue.put(FRAME_ID_TAGGING_TIME, "Text: Tagaging time"); idToValue.put(FRAME_ID_TERMS_OF_USE, "Terms of Use"); idToValue.put(FRAME_ID_TITLE, "Text: title"); idToValue.put(FRAME_ID_TITLE_REFINEMENT, "Text: Subtitle/Description refinement"); idToValue.put(FRAME_ID_TITLE_SORT_ORDER, "Text: title sort order"); idToValue.put(FRAME_ID_TRACK, "Text: Track number/Position in setField"); idToValue.put(FRAME_ID_UNIQUE_FILE_ID, "Unique file identifier"); idToValue.put(FRAME_ID_UNSYNC_LYRICS, "Unsychronized lyric/text transcription"); idToValue.put(FRAME_ID_URL_ARTIST_WEB, "URL: Official artist/performer webpage"); idToValue.put(FRAME_ID_URL_COMMERCIAL, "URL: Commercial information"); idToValue.put(FRAME_ID_URL_COPYRIGHT, "URL: Copyright/Legal information"); idToValue.put(FRAME_ID_URL_FILE_WEB, "URL: Official audio file webpage"); idToValue.put(FRAME_ID_URL_OFFICIAL_RADIO, "URL: Official Radio website"); idToValue.put(FRAME_ID_URL_PAYMENT, "URL: Payment for this recording "); idToValue.put(FRAME_ID_URL_PUBLISHERS, "URL: Publishers official webpage"); idToValue.put(FRAME_ID_URL_SOURCE_WEB, "URL: Official audio source webpage"); idToValue.put(FRAME_ID_USER_DEFINED_INFO, "User defined text information frame"); idToValue.put(FRAME_ID_USER_DEFINED_URL, "User defined URL link frame"); idToValue.put(FRAME_ID_YEAR, "Text:Year"); idToValue.put(FRAME_ID_IS_COMPILATION, "Is Compilation"); idToValue.put(FRAME_ID_ALBUM_ARTIST_SORT_ORDER_ITUNES, "Text:Album Artist Sort Order Frame"); idToValue.put(FRAME_ID_COMPOSER_SORT_ORDER_ITUNES, "Text:Composer Sort Order Frame"); createMaps(); multipleFrames.add(FRAME_ID_USER_DEFINED_INFO); multipleFrames.add(FRAME_ID_USER_DEFINED_URL); multipleFrames.add(FRAME_ID_ATTACHED_PICTURE); multipleFrames.add(FRAME_ID_PRIVATE); multipleFrames.add(FRAME_ID_COMMENT); multipleFrames.add(FRAME_ID_UNIQUE_FILE_ID); multipleFrames.add(FRAME_ID_UNSYNC_LYRICS); multipleFrames.add(FRAME_ID_POPULARIMETER); multipleFrames.add(FRAME_ID_GENERAL_ENCAPS_OBJECT); discardIfFileAlteredFrames.add(FRAME_ID_EVENT_TIMING_CODES); discardIfFileAlteredFrames.add(FRAME_ID_MPEG_LOCATION_LOOKUP_TABLE); discardIfFileAlteredFrames.add(FRAME_ID_POSITION_SYNC); discardIfFileAlteredFrames.add(FRAME_ID_SYNC_LYRIC); discardIfFileAlteredFrames.add(FRAME_ID_SYNC_TEMPO); discardIfFileAlteredFrames.add(FRAME_ID_EVENT_TIMING_CODES); discardIfFileAlteredFrames.add(FRAME_ID_ENCODEDBY); discardIfFileAlteredFrames.add(FRAME_ID_LENGTH); tagFieldToId3.put(FieldKey.ALBUM, ID3v24FieldKey.ALBUM); tagFieldToId3.put(FieldKey.ALBUM_ARTIST, ID3v24FieldKey.ALBUM_ARTIST); tagFieldToId3.put(FieldKey.ALBUM_ARTIST_SORT, ID3v24FieldKey.ALBUM_ARTIST_SORT); tagFieldToId3.put(FieldKey.ALBUM_SORT, ID3v24FieldKey.ALBUM_SORT); tagFieldToId3.put(FieldKey.AMAZON_ID, ID3v24FieldKey.AMAZON_ID); tagFieldToId3.put(FieldKey.ARTIST, ID3v24FieldKey.ARTIST); tagFieldToId3.put(FieldKey.ARTIST_SORT, ID3v24FieldKey.ARTIST_SORT); tagFieldToId3.put(FieldKey.BARCODE, ID3v24FieldKey.BARCODE); tagFieldToId3.put(FieldKey.BPM, ID3v24FieldKey.BPM); tagFieldToId3.put(FieldKey.CATALOG_NO, ID3v24FieldKey.CATALOG_NO); tagFieldToId3.put(FieldKey.COMMENT, ID3v24FieldKey.COMMENT); tagFieldToId3.put(FieldKey.COMPOSER, ID3v24FieldKey.COMPOSER); tagFieldToId3.put(FieldKey.COMPOSER_SORT, ID3v24FieldKey.COMPOSER_SORT); tagFieldToId3.put(FieldKey.CONDUCTOR, ID3v24FieldKey.CONDUCTOR); tagFieldToId3.put(FieldKey.COVER_ART, ID3v24FieldKey.COVER_ART); tagFieldToId3.put(FieldKey.CUSTOM1, ID3v24FieldKey.CUSTOM1); tagFieldToId3.put(FieldKey.CUSTOM2, ID3v24FieldKey.CUSTOM2); tagFieldToId3.put(FieldKey.CUSTOM3, ID3v24FieldKey.CUSTOM3); tagFieldToId3.put(FieldKey.CUSTOM4, ID3v24FieldKey.CUSTOM4); tagFieldToId3.put(FieldKey.CUSTOM5, ID3v24FieldKey.CUSTOM5); tagFieldToId3.put(FieldKey.DISC_NO, ID3v24FieldKey.DISC_NO); tagFieldToId3.put(FieldKey.DISC_TOTAL, ID3v24FieldKey.DISC_NO); tagFieldToId3.put(FieldKey.ENCODER, ID3v24FieldKey.ENCODER); tagFieldToId3.put(FieldKey.FBPM, ID3v24FieldKey.FBPM); tagFieldToId3.put(FieldKey.GENRE, ID3v24FieldKey.GENRE); tagFieldToId3.put(FieldKey.GROUPING, ID3v24FieldKey.GROUPING); tagFieldToId3.put(FieldKey.ISRC, ID3v24FieldKey.ISRC); tagFieldToId3.put(FieldKey.IS_COMPILATION, ID3v24FieldKey.IS_COMPILATION); tagFieldToId3.put(FieldKey.KEY, ID3v24FieldKey.KEY); tagFieldToId3.put(FieldKey.LANGUAGE, ID3v24FieldKey.LANGUAGE); tagFieldToId3.put(FieldKey.LYRICIST, ID3v24FieldKey.LYRICIST); tagFieldToId3.put(FieldKey.LYRICS, ID3v24FieldKey.LYRICS); tagFieldToId3.put(FieldKey.MEDIA, ID3v24FieldKey.MEDIA); tagFieldToId3.put(FieldKey.MOOD, ID3v24FieldKey.MOOD); tagFieldToId3.put(FieldKey.MUSICBRAINZ_ARTISTID, ID3v24FieldKey.MUSICBRAINZ_ARTISTID); tagFieldToId3.put(FieldKey.MUSICBRAINZ_DISC_ID, ID3v24FieldKey.MUSICBRAINZ_DISC_ID); tagFieldToId3.put(FieldKey.MUSICBRAINZ_RELEASEARTISTID, ID3v24FieldKey.MUSICBRAINZ_RELEASEARTISTID); tagFieldToId3.put(FieldKey.MUSICBRAINZ_RELEASEID, ID3v24FieldKey.MUSICBRAINZ_RELEASEID); tagFieldToId3.put(FieldKey.MUSICBRAINZ_RELEASE_COUNTRY, ID3v24FieldKey.MUSICBRAINZ_RELEASE_COUNTRY); tagFieldToId3.put(FieldKey.MUSICBRAINZ_RELEASE_GROUP_ID, ID3v24FieldKey.MUSICBRAINZ_RELEASE_GROUP_ID); tagFieldToId3.put(FieldKey.MUSICBRAINZ_RELEASE_STATUS, ID3v24FieldKey.MUSICBRAINZ_RELEASE_STATUS); tagFieldToId3.put(FieldKey.MUSICBRAINZ_RELEASE_TYPE, ID3v24FieldKey.MUSICBRAINZ_RELEASE_TYPE); tagFieldToId3.put(FieldKey.MUSICBRAINZ_TRACK_ID, ID3v24FieldKey.MUSICBRAINZ_TRACK_ID); tagFieldToId3.put(FieldKey.MUSICBRAINZ_WORK_ID, ID3v24FieldKey.MUSICBRAINZ_WORK_ID); tagFieldToId3.put(FieldKey.MUSICIP_ID, ID3v24FieldKey.MUSICIP_ID); tagFieldToId3.put(FieldKey.OCCASION, ID3v24FieldKey.OCCASION); tagFieldToId3.put(FieldKey.ORIGINAL_ALBUM, ID3v24FieldKey.ORIGINAL_ALBUM); tagFieldToId3.put(FieldKey.ORIGINAL_ARTIST, ID3v24FieldKey.ORIGINAL_ARTIST); tagFieldToId3.put(FieldKey.ORIGINAL_LYRICIST, ID3v24FieldKey.ORIGINAL_LYRICIST); tagFieldToId3.put(FieldKey.ORIGINAL_YEAR, ID3v24FieldKey.ORIGINAL_YEAR); tagFieldToId3.put(FieldKey.QUALITY, ID3v24FieldKey.QUALITY); tagFieldToId3.put(FieldKey.RATING, ID3v24FieldKey.RATING); tagFieldToId3.put(FieldKey.RECORD_LABEL, ID3v24FieldKey.RECORD_LABEL); tagFieldToId3.put(FieldKey.REMIXER, ID3v24FieldKey.REMIXER); tagFieldToId3.put(FieldKey.SCRIPT, ID3v24FieldKey.SCRIPT); tagFieldToId3.put(FieldKey.TAGS, ID3v24FieldKey.TAGS); tagFieldToId3.put(FieldKey.TEMPO, ID3v24FieldKey.TEMPO); tagFieldToId3.put(FieldKey.TITLE, ID3v24FieldKey.TITLE); tagFieldToId3.put(FieldKey.TITLE_SORT, ID3v24FieldKey.TITLE_SORT); tagFieldToId3.put(FieldKey.TRACK, ID3v24FieldKey.TRACK); tagFieldToId3.put(FieldKey.TRACK_TOTAL, ID3v24FieldKey.TRACK_TOTAL); tagFieldToId3.put(FieldKey.URL_DISCOGS_ARTIST_SITE, ID3v24FieldKey.URL_DISCOGS_ARTIST_SITE); tagFieldToId3.put(FieldKey.URL_DISCOGS_RELEASE_SITE, ID3v24FieldKey.URL_DISCOGS_RELEASE_SITE); tagFieldToId3.put(FieldKey.URL_LYRICS_SITE, ID3v24FieldKey.URL_LYRICS_SITE); tagFieldToId3.put(FieldKey.URL_OFFICIAL_ARTIST_SITE, ID3v24FieldKey.URL_OFFICIAL_ARTIST_SITE); tagFieldToId3.put(FieldKey.URL_OFFICIAL_RELEASE_SITE, ID3v24FieldKey.URL_OFFICIAL_RELEASE_SITE); tagFieldToId3.put(FieldKey.URL_WIKIPEDIA_ARTIST_SITE, ID3v24FieldKey.URL_WIKIPEDIA_ARTIST_SITE); tagFieldToId3.put(FieldKey.URL_WIKIPEDIA_RELEASE_SITE, ID3v24FieldKey.URL_WIKIPEDIA_RELEASE_SITE); tagFieldToId3.put(FieldKey.YEAR, ID3v24FieldKey.YEAR); tagFieldToId3.put(FieldKey.ENGINEER, ID3v24FieldKey.ENGINEER); tagFieldToId3.put(FieldKey.PRODUCER, ID3v24FieldKey.PRODUCER); tagFieldToId3.put(FieldKey.MIXER, ID3v24FieldKey.MIXER); tagFieldToId3.put(FieldKey.DJMIXER, ID3v24FieldKey.DJMIXER); tagFieldToId3.put(FieldKey.ARRANGER, ID3v24FieldKey.ARRANGER); } /** * @param genericKey * @return id3 key for generic key */ public ID3v24FieldKey getId3KeyFromGenericKey(FieldKey genericKey) { return tagFieldToId3.get(genericKey); } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/ID3TextEncodingConversion.java0000644000175000017500000000730311470746136030560 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3; import org.jaudiotagger.tag.TagOptionSingleton; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; import java.util.logging.Logger; /** * Functions to encode text according to encodingoptions and ID3 version */ public class ID3TextEncodingConversion { //Logger public static Logger logger = Logger.getLogger("org.jaudiotagger.tag.id3"); /** * Check the text encoding is valid for this header type and is appropriate for * user text encoding options. * *

* This is called before writing any frames that use text encoding * * @param header used to identify the ID3tagtype * @param textEncoding currently set * @return valid encoding according to version type and user options */ public static byte getTextEncoding(AbstractTagFrame header, byte textEncoding) { //Should not happen, assume v23 and provide a warning if (header == null) { logger.warning("Header has not yet been set for this framebody"); if (TagOptionSingleton.getInstance().isResetTextEncodingForExistingFrames()) { return TagOptionSingleton.getInstance().getId3v23DefaultTextEncoding(); } else { return convertV24textEncodingToV23textEncoding(textEncoding); } } else if (header instanceof ID3v24Frame) { if (TagOptionSingleton.getInstance().isResetTextEncodingForExistingFrames()) { //Replace with default return TagOptionSingleton.getInstance().getId3v24DefaultTextEncoding(); } else { //All text encodings supported nothing to do return textEncoding; } } else { if (TagOptionSingleton.getInstance().isResetTextEncodingForExistingFrames()) { //Replace with default return TagOptionSingleton.getInstance().getId3v23DefaultTextEncoding(); } else { //If text encoding is an unsupported v24 one we use unicode v23 equivalent return convertV24textEncodingToV23textEncoding(textEncoding); } } } /** * Sets the text encoding to best Unicode type for the version * * @param header * @return */ public static byte getUnicodeTextEncoding(AbstractTagFrame header) { if (header == null) { logger.warning("Header has not yet been set for this framebody"); return TextEncoding.UTF_16; } else if (header instanceof ID3v24Frame) { return TagOptionSingleton.getInstance().getId3v24UnicodeTextEncoding(); } else { return TextEncoding.UTF_16; } } /** * Convert v24 text encoding to a valid v23 encoding * * @param textEncoding * @return valid encoding */ private static byte convertV24textEncodingToV23textEncoding(byte textEncoding) { //Convert to equivalent UTF16 format if (textEncoding == TextEncoding.UTF_16BE) { return TextEncoding.UTF_16; } //UTF-8 is not supported in ID3v23 and UTF-16 Format can be problematic on ID3v23 so change //to ISO-8859-1, a check before writing data will check the format is capable of writing the data else if (textEncoding == TextEncoding.UTF_8) { return TextEncoding.ISO_8859_1; } else { return textEncoding; } } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/ID3v24Frame.java0000644000175000017500000012144011470746136025504 0ustar drazzibdrazzib/* * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3; import org.jaudiotagger.FileConstants; import org.jaudiotagger.audio.generic.Utils; import org.jaudiotagger.audio.mp3.MP3File; import org.jaudiotagger.logging.ErrorMessage; import org.jaudiotagger.logging.Hex; import org.jaudiotagger.tag.*; import org.jaudiotagger.tag.datatype.Lyrics3Line; import org.jaudiotagger.tag.id3.framebody.*; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; import org.jaudiotagger.tag.lyrics3.*; import org.jaudiotagger.utils.EqualsUtil; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.nio.ByteBuffer; import java.util.Iterator; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * Represents an ID3v2.4 frame. * * @author : Paul Taylor * @author : Eric Farng * @version $Id: ID3v24Frame.java 929 2010-11-17 12:36:46Z paultaylor $ */ public class ID3v24Frame extends AbstractID3v2Frame { private static Pattern validFrameIdentifier = Pattern.compile("[A-Z][0-9A-Z]{3}"); protected static final int FRAME_DATA_LENGTH_SIZE = 4; protected static final int FRAME_ID_SIZE = 4; protected static final int FRAME_FLAGS_SIZE = 2; protected static final int FRAME_SIZE_SIZE = 4; protected static final int FRAME_ENCRYPTION_INDICATOR_SIZE = 1; protected static final int FRAME_GROUPING_INDICATOR_SIZE = 1; protected static final int FRAME_HEADER_SIZE = FRAME_ID_SIZE + FRAME_SIZE_SIZE + FRAME_FLAGS_SIZE; /** * If the frame is encrypted then the encryption method is stored in this byte */ private int encryptionMethod; /** * If the frame belongs in a group with other frames then the group identifier byte is stored */ private int groupIdentifier; protected int getFrameIdSize() { return FRAME_ID_SIZE; } protected int getFrameSizeSize() { return FRAME_SIZE_SIZE; } protected int getFrameFlagsSize() { return FRAME_FLAGS_SIZE; } protected int getFrameHeaderSize() { return FRAME_HEADER_SIZE; } public ID3v24Frame() { } /** * Creates a new ID3v2_4Frame of type identifier. An empty * body of the correct type will be automatically created. * This constructor should be used when wish to create a new * frame from scratch using user input * * @param identifier defines the type of body to be created */ public ID3v24Frame(String identifier) { //Super Constructor creates a frame with empty body of type specified super(identifier); statusFlags = new StatusFlags(); encodingFlags = new EncodingFlags(); } /** * Copy Constructor:Creates a new ID3v2_4Frame datatype based on another frame. * * @param frame */ public ID3v24Frame(ID3v24Frame frame) { super(frame); statusFlags = new StatusFlags(frame.getStatusFlags().getOriginalFlags()); encodingFlags = new EncodingFlags(frame.getEncodingFlags().getFlags()); } private void createV24FrameFromV23Frame(ID3v23Frame frame) throws InvalidFrameException { // Is it a straight conversion e.g TALB - TALB identifier = ID3Tags.convertFrameID23To24(frame.getIdentifier()); logger.finer("Creating V24frame from v23:" + frame.getIdentifier() + ":" + identifier); //We cant convert unsupported bodies properly if (frame.getBody() instanceof FrameBodyUnsupported) { this.frameBody = new FrameBodyUnsupported((FrameBodyUnsupported) frame.getBody()); this.frameBody.setHeader(this); identifier = frame.getIdentifier(); logger.finer("V3:UnsupportedBody:Orig id is:" + frame.getIdentifier() + ":New id is:" + identifier); }//Simple Copy else if (identifier != null) { //Special Case if ((frame.getIdentifier().equals(ID3v23Frames.FRAME_ID_V3_USER_DEFINED_INFO)) && (((FrameBodyTXXX) frame.getBody()).getDescription().equals(FrameBodyTXXX.MOOD))) { this.frameBody = new FrameBodyTMOO((FrameBodyTXXX) frame.getBody()); this.frameBody.setHeader(this); identifier = frameBody.getIdentifier(); } else { logger.finer("V3:Orig id is:" + frame.getIdentifier() + ":New id is:" + identifier); this.frameBody = (AbstractTagFrameBody) ID3Tags.copyObject(frame.getBody()); this.frameBody.setHeader(this); } } // Is it a known v3 frame which needs forcing to v4 frame e.g. TYER - TDRC else if (ID3Tags.isID3v23FrameIdentifier(frame.getIdentifier())) { identifier = ID3Tags.forceFrameID23To24(frame.getIdentifier()); if (identifier != null) { logger.info("V3:Orig id is:" + frame.getIdentifier() + ":New id is:" + identifier); this.frameBody = this.readBody(identifier, (AbstractID3v2FrameBody) frame.getBody()); this.frameBody.setHeader(this); } // No mechanism exists to convert it to a v24 frame, e.g deprecated frame e.g TSIZ, so hold // as a deprecated frame consisting of an array of bytes*/ else { this.frameBody = new FrameBodyDeprecated((AbstractID3v2FrameBody) frame.getBody()); this.frameBody.setHeader(this); identifier = frame.getIdentifier(); logger.finer("V3:Deprecated:Orig id is:" + frame.getIdentifier() + ":New id is:" + identifier); } } // Unknown Frame e.g NCON or TDRL (because TDRL unknown to V23) else { this.frameBody = new FrameBodyUnsupported((FrameBodyUnsupported) frame.getBody()); this.frameBody.setHeader(this); identifier = frame.getIdentifier(); logger.finer("V3:Unknown:Orig id is:" + frame.getIdentifier() + ":New id is:" + identifier); } } /** * Creates a new ID3v2_4Frame datatype based on another frame of different version * Converts the framebody to the equivalent v24 framebody or to UnsupportedFrameBody if identifier * is unknown. * * @param frame to construct a new frame from * @throws org.jaudiotagger.tag.InvalidFrameException * */ public ID3v24Frame(AbstractID3v2Frame frame) throws InvalidFrameException { //Should not be called if ((frame instanceof ID3v24Frame)) { throw new UnsupportedOperationException("Copy Constructor not called. Please type cast the argument"); } //Flags if (frame instanceof ID3v23Frame) { statusFlags = new StatusFlags((ID3v23Frame.StatusFlags) frame.getStatusFlags()); encodingFlags = new EncodingFlags(frame.getEncodingFlags().getFlags()); } else { statusFlags = new StatusFlags(); encodingFlags = new EncodingFlags(); } // Convert Identifier. If the id was a known id for the original // version we should be able to convert it to an v24 frame, although it may mean minor // modification to the data. If it was not recognised originally it should remain // unknown. if (frame instanceof ID3v23Frame) { createV24FrameFromV23Frame((ID3v23Frame) frame); } else if (frame instanceof ID3v22Frame) { ID3v23Frame v23Frame = new ID3v23Frame(frame); createV24FrameFromV23Frame(v23Frame); } this.frameBody.setHeader(this); } /** * Creates a new ID3v2_4Frame datatype based on Lyrics3. * * @param field * @throws InvalidTagException */ public ID3v24Frame(Lyrics3v2Field field) throws InvalidTagException { String id = field.getIdentifier(); String value; if (id.equals("IND")) { throw new InvalidTagException("Cannot create ID3v2.40 frame from Lyrics3 indications field."); } else if (id.equals("LYR")) { FieldFrameBodyLYR lyric = (FieldFrameBodyLYR) field.getBody(); Lyrics3Line line; Iterator iterator = lyric.iterator(); FrameBodySYLT sync; FrameBodyUSLT unsync; boolean hasTimeStamp = lyric.hasTimeStamp(); // we'll create only one frame here. // if there is any timestamp at all, we will create a sync'ed frame. sync = new FrameBodySYLT((byte) 0, "ENG", (byte) 2, (byte) 1, "", new byte[0]); unsync = new FrameBodyUSLT((byte) 0, "ENG", "", ""); while (iterator.hasNext()) { line = iterator.next(); if (hasTimeStamp) { // sync.addLyric(line); } else { unsync.addLyric(line); } } if (hasTimeStamp) { this.frameBody = sync; this.frameBody.setHeader(this); } else { this.frameBody = unsync; this.frameBody.setHeader(this); } } else if (id.equals("INF")) { value = ((FieldFrameBodyINF) field.getBody()).getAdditionalInformation(); this.frameBody = new FrameBodyCOMM((byte) 0, "ENG", "", value); this.frameBody.setHeader(this); } else if (id.equals("AUT")) { value = ((FieldFrameBodyAUT) field.getBody()).getAuthor(); this.frameBody = new FrameBodyTCOM((byte) 0, value); this.frameBody.setHeader(this); } else if (id.equals("EAL")) { value = ((FieldFrameBodyEAL) field.getBody()).getAlbum(); this.frameBody = new FrameBodyTALB((byte) 0, value); this.frameBody.setHeader(this); } else if (id.equals("EAR")) { value = ((FieldFrameBodyEAR) field.getBody()).getArtist(); this.frameBody = new FrameBodyTPE1((byte) 0, value); this.frameBody.setHeader(this); } else if (id.equals("ETT")) { value = ((FieldFrameBodyETT) field.getBody()).getTitle(); this.frameBody = new FrameBodyTIT2((byte) 0, value); this.frameBody.setHeader(this); } else if (id.equals("IMG")) { throw new InvalidTagException("Cannot create ID3v2.40 frame from Lyrics3 image field."); } else { throw new InvalidTagException("Cannot caret ID3v2.40 frame from " + id + " Lyrics3 field"); } } /** * Creates a new ID3v24Frame datatype by reading from byteBuffer. * * @param byteBuffer to read from * @param loggingFilename * @throws org.jaudiotagger.tag.InvalidFrameException * */ public ID3v24Frame(ByteBuffer byteBuffer, String loggingFilename) throws InvalidFrameException, InvalidDataTypeException { setLoggingFilename(loggingFilename); read(byteBuffer); } /** * Creates a new ID3v24Frame datatype by reading from byteBuffer. * * @param byteBuffer to read from * @throws org.jaudiotagger.tag.InvalidFrameException * * @deprecated use {@link #ID3v24Frame(ByteBuffer,String)} instead */ public ID3v24Frame(ByteBuffer byteBuffer) throws InvalidFrameException, InvalidDataTypeException { this(byteBuffer, ""); } /** * @param obj * @return if obj is equivalent to this frame */ public boolean equals(Object obj) { if (this == obj) return true; if (!(obj instanceof ID3v24Frame)) { return false; } ID3v24Frame that = (ID3v24Frame) obj; return EqualsUtil.areEqual(this.statusFlags, that.statusFlags) && EqualsUtil.areEqual(this.encodingFlags, that.encodingFlags) && super.equals(that); } /** * Return size of frame * * @return int frame size */ public int getSize() { return frameBody.getSize() + ID3v24Frame.FRAME_HEADER_SIZE; } /** * If frame is greater than certain size it will be decoded differently if unsynchronized to if synchronized * Frames with certain byte sequences should be unsynchronized but sometimes editors do not * unsynchronize them so this method checks both cases and goes with the option that fits best with the data * * @param byteBuffer * @throws InvalidFrameException */ private void checkIfFrameSizeThatIsNotSyncSafe(ByteBuffer byteBuffer) throws InvalidFrameException { if (frameSize > ID3SyncSafeInteger.MAX_SAFE_SIZE) { //Set Just after size field this is where we want to be when we leave this if statement int currentPosition = byteBuffer.position(); //Read as nonsync safe integer byteBuffer.position(currentPosition - getFrameIdSize()); int nonSyncSafeFrameSize = byteBuffer.getInt(); //Is the frame size syncsafe, should always be BUT some encoders such as Itunes do not do it properly //so do an easy check now. byteBuffer.position(currentPosition - getFrameIdSize()); boolean isNotSyncSafe = ID3SyncSafeInteger.isBufferNotSyncSafe(byteBuffer); //not relative so need to move position byteBuffer.position(currentPosition); if (isNotSyncSafe) { logger.warning(getLoggingFilename() + ":" + "Frame size is NOT stored as a sync safe integer:" + identifier); //This will return a larger frame size so need to check against buffer size if too large then we are //buggered , give up if (nonSyncSafeFrameSize > (byteBuffer.remaining() - -getFrameFlagsSize())) { logger.warning(getLoggingFilename() + ":" + "Invalid Frame size larger than size before mp3 audio:" + identifier); throw new InvalidFrameException(identifier + " is invalid frame"); } else { frameSize = nonSyncSafeFrameSize; } } else { //appears to be sync safe but lets look at the bytes just after the reported end of this //frame to see if find a valid frame header //Read the Frame Identifier byte[] readAheadbuffer = new byte[getFrameIdSize()]; byteBuffer.position(currentPosition + frameSize + getFrameFlagsSize()); if (byteBuffer.remaining() < getFrameIdSize()) { //There is no padding or framedata we are at end so assume syncsafe //reset position to just after framesize byteBuffer.position(currentPosition); } else { byteBuffer.get(readAheadbuffer, 0, getFrameIdSize()); //reset position to just after framesize byteBuffer.position(currentPosition); String readAheadIdentifier = new String(readAheadbuffer); if (isValidID3v2FrameIdentifier(readAheadIdentifier)) { //Everything ok, so continue } else if (ID3SyncSafeInteger.isBufferEmpty(readAheadbuffer)) { //no data found so assume entered padding in which case assume it is last //frame and we are ok } //haven't found identifier so maybe not syncsafe or maybe there are no more frames, just padding else { //Ok lets try using a non-syncsafe integer //size returned will be larger so is it valid if (nonSyncSafeFrameSize > byteBuffer.remaining() - getFrameFlagsSize()) { //invalid so assume syncsafe byteBuffer.position(currentPosition); } else { readAheadbuffer = new byte[getFrameIdSize()]; byteBuffer.position(currentPosition + nonSyncSafeFrameSize + getFrameFlagsSize()); if (byteBuffer.remaining() >= getFrameIdSize()) { byteBuffer.get(readAheadbuffer, 0, getFrameIdSize()); readAheadIdentifier = new String(readAheadbuffer); //reset position to just after framesize byteBuffer.position(currentPosition); //ok found a valid identifier using non-syncsafe so assume non-syncsafe size //and continue if (isValidID3v2FrameIdentifier(readAheadIdentifier)) { frameSize = nonSyncSafeFrameSize; logger.warning(getLoggingFilename() + ":" + "Assuming frame size is NOT stored as a sync safe integer:" + identifier); } //no data found so assume entered padding in which case assume it is last //frame and we are ok whereas we didn't hit padding when using syncsafe integer //or we wouldn't have got to this point. So assume syncsafe integer ended within //the frame data whereas this has reached end of frames. else if (ID3SyncSafeInteger.isBufferEmpty(readAheadbuffer)) { frameSize = nonSyncSafeFrameSize; logger.warning(getLoggingFilename() + ":" + "Assuming frame size is NOT stored as a sync safe integer:" + identifier); } //invalid so assume syncsafe as that is is the standard else { } } else { //reset position to just after framesize byteBuffer.position(currentPosition); //If the unsync framesize matches exactly the remaining bytes then assume it has the //correct size for the last frame if (byteBuffer.remaining() == 0) { frameSize = nonSyncSafeFrameSize; } //Inconclusive stick with syncsafe else { } } } } } } } } /** * Read the frame size form the header, check okay , if not try to fix * or just throw exception * * @param byteBuffer * @throws InvalidFrameException */ private void getFrameSize(ByteBuffer byteBuffer) throws InvalidFrameException { //Read frame size as syncsafe integer frameSize = ID3SyncSafeInteger.bufferToValue(byteBuffer); if (frameSize < 0) { logger.warning(getLoggingFilename() + ":" + "Invalid Frame size:" + identifier); throw new InvalidFrameException(identifier + " is invalid frame"); } else if (frameSize == 0) { logger.warning(getLoggingFilename() + ":" + "Empty Frame:" + identifier); //We dont process this frame or add to framemap becuase contains no useful information //Skip the two flag bytes so in correct position for subsequent frames byteBuffer.get(); byteBuffer.get(); throw new EmptyFrameException(identifier + " is empty frame"); } else if (frameSize > (byteBuffer.remaining() - FRAME_FLAGS_SIZE)) { logger.warning(getLoggingFilename() + ":" + "Invalid Frame size larger than size before mp3 audio:" + identifier); throw new InvalidFrameException(identifier + " is invalid frame"); } checkIfFrameSizeThatIsNotSyncSafe(byteBuffer); } /** * Read the frame from the specified file. * Read the frame header then delegate reading of data to frame body. * * @param byteBuffer to read the frame from */ public void read(ByteBuffer byteBuffer) throws InvalidFrameException, InvalidDataTypeException { String identifier = readIdentifier(byteBuffer); //Is this a valid identifier? if (!isValidID3v2FrameIdentifier(identifier)) { //If not valid move file pointer back to one byte after //the original check so can try again. logger.info(getLoggingFilename() + ":" + "Invalid identifier:" + identifier); byteBuffer.position(byteBuffer.position() - (getFrameIdSize() - 1)); throw new InvalidFrameIdentifierException(getLoggingFilename() + ":" + identifier + ":is not a valid ID3v2.30 frame"); } //Get the frame size, adjusted as necessary getFrameSize(byteBuffer); //Read the flag bytes statusFlags = new StatusFlags(byteBuffer.get()); encodingFlags = new EncodingFlags(byteBuffer.get()); //Read extra bits appended to frame header for various encodings //These are not included in header size but are included in frame size but wont be read when we actually //try to read the frame body data int extraHeaderBytesCount = 0; int dataLengthSize = -1; if (((EncodingFlags) encodingFlags).isGrouping()) { extraHeaderBytesCount = ID3v24Frame.FRAME_GROUPING_INDICATOR_SIZE; groupIdentifier=byteBuffer.get(); } if (((EncodingFlags) encodingFlags).isEncryption()) { //Read the Encryption byte, but do nothing with it extraHeaderBytesCount += ID3v24Frame.FRAME_ENCRYPTION_INDICATOR_SIZE; encryptionMethod=byteBuffer.get(); } if (((EncodingFlags) encodingFlags).isDataLengthIndicator()) { //Read the sync safe size field dataLengthSize = ID3SyncSafeInteger.bufferToValue(byteBuffer); extraHeaderBytesCount += FRAME_DATA_LENGTH_SIZE; logger.info(getLoggingFilename() + ":" + "Frame Size Is:" + frameSize + " Data Length Size:" + dataLengthSize); } //Work out the real size of the frameBody data int realFrameSize = frameSize - extraHeaderBytesCount; //Create Buffer that only contains the body of this frame rather than the remainder of tag ByteBuffer frameBodyBuffer = byteBuffer.slice(); frameBodyBuffer.limit(realFrameSize); //Do we need to synchronize the frame body int syncSize = realFrameSize; if (((EncodingFlags) encodingFlags).isUnsynchronised()) { //We only want to synchronize the buffer up to the end of this frame (remember this //buffer contains the remainder of this tag not just this frame), and we cannot just //create a new buffer because when this method returns the position of the buffer is used //to look for the next frame, so we need to modify the buffer. The action of synchronizing causes //bytes to be dropped so the existing buffer is large enough to hold the modifications frameBodyBuffer = ID3Unsynchronization.synchronize(frameBodyBuffer); syncSize = frameBodyBuffer.limit(); logger.info(getLoggingFilename() + ":" + "Frame Size After Syncing is:" + syncSize); } //Read the body data try { if (((EncodingFlags) encodingFlags).isCompression()) { frameBodyBuffer = ID3Compression.uncompress(identifier, getLoggingFilename(), byteBuffer, dataLengthSize, realFrameSize); frameBody = readBody(identifier, frameBodyBuffer, dataLengthSize); } else if (((EncodingFlags) encodingFlags).isEncryption()) { frameBodyBuffer = byteBuffer.slice(); frameBodyBuffer.limit(realFrameSize); frameBody = readEncryptedBody(identifier, byteBuffer,frameSize); } else { frameBody = readBody(identifier, frameBodyBuffer, syncSize); } if (!(frameBody instanceof ID3v24FrameBody)) { logger.info(getLoggingFilename() + ":" + "Converted frame body with:" + identifier + " to deprecated framebody"); frameBody = new FrameBodyDeprecated((AbstractID3v2FrameBody) frameBody); } } finally { //Update position of main buffer, so no attempt is made to reread these bytes byteBuffer.position(byteBuffer.position() + realFrameSize); } } /** * Write the frame. Writes the frame header but writing the data is delegated to the * frame body. * * @throws IOException */ public void write(ByteArrayOutputStream tagBuffer) { boolean unsynchronization; logger.info("Writing frame to file:" + getIdentifier()); //This is where we will write header, move position to where we can //write bodybuffer ByteBuffer headerBuffer = ByteBuffer.allocate(FRAME_HEADER_SIZE); //Write Frame Body Data to a new stream ByteArrayOutputStream bodyOutputStream = new ByteArrayOutputStream(); ((AbstractID3v2FrameBody) frameBody).write(bodyOutputStream); //Does it need unsynchronizing, and are we allowing unsychronizing byte[] bodyBuffer = bodyOutputStream.toByteArray(); unsynchronization = TagOptionSingleton.getInstance().isUnsyncTags() && ID3Unsynchronization.requiresUnsynchronization(bodyBuffer); if (unsynchronization) { bodyBuffer = ID3Unsynchronization.unsynchronize(bodyBuffer); logger.info("bodybytebuffer:sizeafterunsynchronisation:" + bodyBuffer.length); } //Write Frame Header //Write Frame ID, the identifier must be 4 bytes bytes long it may not be //because converted an unknown v2.2 id (only 3 bytes long) if (getIdentifier().length() == 3) { identifier = identifier + ' '; } headerBuffer.put(Utils.getDefaultBytes(getIdentifier(), "ISO-8859-1"), 0, FRAME_ID_SIZE); //Write Frame Size based on size of body buffer (if it has been unsynced then it size //will have increased accordingly int size = bodyBuffer.length; logger.fine("Frame Size Is:" + size); headerBuffer.put(ID3SyncSafeInteger.valueToBuffer(size)); //Write the Flags //Status Flags:leave as they were when we read headerBuffer.put(statusFlags.getWriteFlags()); //Remove any non standard flags ((ID3v24Frame.EncodingFlags) encodingFlags).unsetNonStandardFlags(); //Encoding we only support unsynchronization if (unsynchronization) { ((ID3v24Frame.EncodingFlags) encodingFlags).setUnsynchronised(); } else { ((ID3v24Frame.EncodingFlags) encodingFlags).unsetUnsynchronised(); } //These are not currently supported on write ((ID3v24Frame.EncodingFlags) encodingFlags).unsetCompression(); ((ID3v24Frame.EncodingFlags) encodingFlags).unsetDataLengthIndicator(); headerBuffer.put(encodingFlags.getFlags()); try { //Add header to the Byte Array Output Stream tagBuffer.write(headerBuffer.array()); if (((EncodingFlags) encodingFlags).isEncryption()) { tagBuffer.write(encryptionMethod); } if (((EncodingFlags) encodingFlags).isGrouping()) { tagBuffer.write(groupIdentifier); } //Add bodybuffer to the Byte Array Output Stream tagBuffer.write(bodyBuffer); } catch (IOException ioe) { //This could never happen coz not writing to file, so convert to RuntimeException throw new RuntimeException(ioe); } } /** * Get Status Flags Object */ public AbstractID3v2Frame.StatusFlags getStatusFlags() { return statusFlags; } /** * Get Encoding Flags Object */ public AbstractID3v2Frame.EncodingFlags getEncodingFlags() { return encodingFlags; } public int getEncryptionMethod() { return encryptionMethod; } public int getGroupIdentifier() { return groupIdentifier; } /** * Member Class This represents a frame headers Status Flags * Make adjustments if necessary based on frame type and specification. */ class StatusFlags extends AbstractID3v2Frame.StatusFlags { public static final String TYPE_TAGALTERPRESERVATION = "typeTagAlterPreservation"; public static final String TYPE_FILEALTERPRESERVATION = "typeFileAlterPreservation"; public static final String TYPE_READONLY = "typeReadOnly"; /** * Discard frame if tag altered */ public static final int MASK_TAG_ALTER_PRESERVATION = FileConstants.BIT6; /** * Discard frame if audio part of file altered */ public static final int MASK_FILE_ALTER_PRESERVATION = FileConstants.BIT5; /** * Frame tagged as read only */ public static final int MASK_READ_ONLY = FileConstants.BIT4; /** * Use this when creating a frame from scratch */ StatusFlags() { super(); } /** * Use this constructor when reading from file or from another v4 frame * * @param flags */ StatusFlags(byte flags) { originalFlags = flags; writeFlags = flags; modifyFlags(); } /** * Use this constructor when convert a v23 frame * * @param statusFlags */ StatusFlags(ID3v23Frame.StatusFlags statusFlags) { originalFlags = convertV3ToV4Flags(statusFlags.getOriginalFlags()); writeFlags = originalFlags; modifyFlags(); } /** * Convert V3 Flags to equivalent V4 Flags * * @param v3Flag * @return */ private byte convertV3ToV4Flags(byte v3Flag) { byte v4Flag = (byte) 0; if ((v3Flag & ID3v23Frame.StatusFlags.MASK_FILE_ALTER_PRESERVATION) != 0) { v4Flag |= (byte) MASK_FILE_ALTER_PRESERVATION; } if ((v3Flag & ID3v23Frame.StatusFlags.MASK_TAG_ALTER_PRESERVATION) != 0) { v4Flag |= (byte) MASK_TAG_ALTER_PRESERVATION; } return v4Flag; } /** * Makes modifications to flags based on specification and frameid */ protected void modifyFlags() { String str = getIdentifier(); if (ID3v24Frames.getInstanceOf().isDiscardIfFileAltered(str)) { writeFlags |= (byte) MASK_FILE_ALTER_PRESERVATION; writeFlags &= (byte) ~MASK_TAG_ALTER_PRESERVATION; } else { writeFlags &= (byte) ~MASK_FILE_ALTER_PRESERVATION; writeFlags &= (byte) ~MASK_TAG_ALTER_PRESERVATION; } } public void createStructure() { MP3File.getStructureFormatter().openHeadingElement(TYPE_FLAGS, ""); MP3File.getStructureFormatter().addElement(TYPE_TAGALTERPRESERVATION, originalFlags & MASK_TAG_ALTER_PRESERVATION); MP3File.getStructureFormatter().addElement(TYPE_FILEALTERPRESERVATION, originalFlags & MASK_FILE_ALTER_PRESERVATION); MP3File.getStructureFormatter().addElement(TYPE_READONLY, originalFlags & MASK_READ_ONLY); MP3File.getStructureFormatter().closeHeadingElement(TYPE_FLAGS); } } /** * This represents a frame headers Encoding Flags */ class EncodingFlags extends AbstractID3v2Frame.EncodingFlags { public static final String TYPE_COMPRESSION = "compression"; public static final String TYPE_ENCRYPTION = "encryption"; public static final String TYPE_GROUPIDENTITY = "groupidentity"; public static final String TYPE_FRAMEUNSYNCHRONIZATION = "frameUnsynchronisation"; public static final String TYPE_DATALENGTHINDICATOR = "dataLengthIndicator"; /** * Frame is part of a group */ public static final int MASK_GROUPING_IDENTITY = FileConstants.BIT6; /** * Frame is compressed */ public static final int MASK_COMPRESSION = FileConstants.BIT3; /** * Frame is encrypted */ public static final int MASK_ENCRYPTION = FileConstants.BIT2; /** * Unsynchronisation */ public static final int MASK_FRAME_UNSYNCHRONIZATION = FileConstants.BIT1; /** * Length */ public static final int MASK_DATA_LENGTH_INDICATOR = FileConstants.BIT0; /** * Use this when creating a frame from scratch */ EncodingFlags() { super(); } /** * Use this when creating a frame from existing flags in another v4 frame * * @param flags */ EncodingFlags(byte flags) { super(flags); logEnabledFlags(); } public void logEnabledFlags() { if(isNonStandardFlags()) { logger.warning(getLoggingFilename() + ":" + identifier + ":Unknown Encoding Flags:"+ Hex.asHex(flags)); } if (isCompression()) { logger.warning(ErrorMessage.MP3_FRAME_IS_COMPRESSED.getMsg(getLoggingFilename(), identifier)); } if (isEncryption()) { logger.warning(ErrorMessage.MP3_FRAME_IS_ENCRYPTED.getMsg(getLoggingFilename(), identifier)); } if (isGrouping()) { logger.info(ErrorMessage.MP3_FRAME_IS_GROUPED.getMsg(getLoggingFilename(), identifier)); } if (isUnsynchronised()) { logger.info(ErrorMessage.MP3_FRAME_IS_UNSYNCHRONISED.getMsg(getLoggingFilename(), identifier)); } if (isDataLengthIndicator()) { logger.info(ErrorMessage.MP3_FRAME_IS_DATA_LENGTH_INDICATOR.getMsg(getLoggingFilename(), identifier)); } } public byte getFlags() { return flags; } public boolean isCompression() { return (flags & MASK_COMPRESSION) > 0; } public boolean isEncryption() { return (flags & MASK_ENCRYPTION) > 0; } public boolean isGrouping() { return (flags & MASK_GROUPING_IDENTITY) > 0; } public boolean isUnsynchronised() { return (flags & MASK_FRAME_UNSYNCHRONIZATION) > 0; } public boolean isDataLengthIndicator() { return (flags & MASK_DATA_LENGTH_INDICATOR) > 0; } public void setCompression() { flags |= MASK_COMPRESSION; } public void setEncryption() { flags |= MASK_ENCRYPTION; } public void setGrouping() { flags |= MASK_GROUPING_IDENTITY; } public void setUnsynchronised() { flags |= MASK_FRAME_UNSYNCHRONIZATION; } public void setDataLengthIndicator() { flags |= MASK_DATA_LENGTH_INDICATOR; } public void unsetCompression() { flags &= (byte) ~MASK_COMPRESSION; } public void unsetEncryption() { flags &= (byte) ~MASK_ENCRYPTION; } public void unsetGrouping() { flags &= (byte) ~MASK_GROUPING_IDENTITY; } public void unsetUnsynchronised() { flags &= (byte) ~MASK_FRAME_UNSYNCHRONIZATION; } public void unsetDataLengthIndicator() { flags &= (byte) ~MASK_DATA_LENGTH_INDICATOR; } public boolean isNonStandardFlags() { return ((flags & FileConstants.BIT7) > 0) || ((flags & FileConstants.BIT5) > 0) || ((flags & FileConstants.BIT4) > 0); } public void unsetNonStandardFlags() { if(isNonStandardFlags()) { logger.warning(getLoggingFilename() + ":" + getIdentifier() + ":Unsetting Unknown Encoding Flags:"+ Hex.asHex(flags)); flags &= (byte) ~FileConstants.BIT7; flags &= (byte) ~FileConstants.BIT5; flags &= (byte) ~FileConstants.BIT4; } } public void createStructure() { MP3File.getStructureFormatter().openHeadingElement(TYPE_FLAGS, ""); MP3File.getStructureFormatter().addElement(TYPE_COMPRESSION, flags & MASK_COMPRESSION); MP3File.getStructureFormatter().addElement(TYPE_ENCRYPTION, flags & MASK_ENCRYPTION); MP3File.getStructureFormatter().addElement(TYPE_GROUPIDENTITY, flags & MASK_GROUPING_IDENTITY); MP3File.getStructureFormatter().addElement(TYPE_FRAMEUNSYNCHRONIZATION, flags & MASK_FRAME_UNSYNCHRONIZATION); MP3File.getStructureFormatter().addElement(TYPE_DATALENGTHINDICATOR, flags & MASK_DATA_LENGTH_INDICATOR); MP3File.getStructureFormatter().closeHeadingElement(TYPE_FLAGS); } } /** * Does the frame identifier meet the syntax for a idv3v2 frame identifier. * must start with a capital letter and only contain capital letters and numbers * * @param identifier to be checked * @return whether the identifier is valid */ public boolean isValidID3v2FrameIdentifier(String identifier) { Matcher m = ID3v24Frame.validFrameIdentifier.matcher(identifier); return m.matches(); } /** * Return String Representation of body */ public void createStructure() { MP3File.getStructureFormatter().openHeadingElement(TYPE_FRAME, getIdentifier()); MP3File.getStructureFormatter().addElement(TYPE_FRAME_SIZE, frameSize); statusFlags.createStructure(); encodingFlags.createStructure(); frameBody.createStructure(); MP3File.getStructureFormatter().closeHeadingElement(TYPE_FRAME); } /** * @return true if considered a common frame */ public boolean isCommon() { return ID3v24Frames.getInstanceOf().isCommon(getId()); } /** * @return true if considered a common frame */ public boolean isBinary() { return ID3v24Frames.getInstanceOf().isBinary(getId()); } /** * Sets the charset encoding used by the field. * * @param encoding charset. */ public void setEncoding(String encoding) { Integer encodingId = TextEncoding.getInstanceOf().getIdForValue(encoding); if(encoding!=null) { if(encodingId <4) { this.getBody().setTextEncoding(encodingId.byteValue()); } } } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/AbstractID3Tag.java0000644000175000017500000000550411277026507026315 0ustar drazzibdrazzib/** * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: AbstractID3Tag.java 836 2009-11-12 15:44:07Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Description: * Base class for all ID3 tags * */ package org.jaudiotagger.tag.id3; import java.util.logging.Logger; /** * This is the abstract base class for all ID3 tags. * * @author : Eric Farng * @author : Paul Taylor */ public abstract class AbstractID3Tag extends AbstractTag { //Logger public static Logger logger = Logger.getLogger("org.jaudiotagger.tag.id3"); public AbstractID3Tag() { } protected static final String TAG_RELEASE = "ID3v"; //The purpose of this is to provide the filename that should be used when writing debug messages //when problems occur reading or writing to file, otherwise it is difficult to track down the error //when processing many files private String loggingFilename = ""; /** * Get full version */ public String getIdentifier() { return TAG_RELEASE + getRelease() + "." + getMajorVersion() + "." + getRevision(); } /** * Retrieve the Release * @return */ public abstract byte getRelease(); /** * Retrieve the Major Version * @return */ public abstract byte getMajorVersion(); /** * Retrieve the Revision * @return */ public abstract byte getRevision(); public AbstractID3Tag(AbstractID3Tag copyObject) { super(copyObject); } public String toString() { return ""; } /** * Retrieve the logging filename to be used in debugging * * @return logging filename to be used in debugging */ protected String getLoggingFilename() { return loggingFilename; } /** * Set logging filename when construct tag for read from file * * @param loggingFilename */ protected void setLoggingFilename(String loggingFilename) { this.loggingFilename = loggingFilename; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/ID3v1FieldKey.java0000644000175000017500000000026310736454526026063 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3; /** * Basic ID3v11 Field Names */ public enum ID3v1FieldKey { ARTIST, ALBUM, GENRE, TITLE, YEAR, TRACK, COMMENT } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/ID3v23Frame.java0000644000175000017500000007372111470746136025513 0ustar drazzibdrazzib/* * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3; import org.jaudiotagger.FileConstants; import org.jaudiotagger.audio.generic.Utils; import org.jaudiotagger.audio.mp3.MP3File; import org.jaudiotagger.logging.Hex; import org.jaudiotagger.tag.EmptyFrameException; import org.jaudiotagger.tag.InvalidDataTypeException; import org.jaudiotagger.tag.InvalidFrameException; import org.jaudiotagger.tag.InvalidFrameIdentifierException; import org.jaudiotagger.tag.id3.framebody.*; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; import org.jaudiotagger.utils.EqualsUtil; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.nio.ByteBuffer; import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.zip.DataFormatException; import java.util.zip.Inflater; /** * Represents an ID3v2.3 frame. * * @author : Paul Taylor * @author : Eric Farng * @version $Id: ID3v23Frame.java 929 2010-11-17 12:36:46Z paultaylor $ */ public class ID3v23Frame extends AbstractID3v2Frame { private static Pattern validFrameIdentifier = Pattern.compile("[A-Z][0-9A-Z]{3}"); protected static final int FRAME_ID_SIZE = 4; protected static final int FRAME_FLAGS_SIZE = 2; protected static final int FRAME_SIZE_SIZE = 4; protected static final int FRAME_COMPRESSION_UNCOMPRESSED_SIZE = 4; protected static final int FRAME_ENCRYPTION_INDICATOR_SIZE = 1; protected static final int FRAME_GROUPING_INDICATOR_SIZE = 1; protected static final int FRAME_HEADER_SIZE = FRAME_ID_SIZE + FRAME_SIZE_SIZE + FRAME_FLAGS_SIZE; /** * If the frame is encrypted then the encryption method is stored in this byte */ private int encryptionMethod; /** * If the frame belongs in a group with other frames then the group identifier byte is stored */ private int groupIdentifier; protected int getFrameIdSize() { return FRAME_ID_SIZE; } protected int getFrameSizeSize() { return FRAME_SIZE_SIZE; } protected int getFrameHeaderSize() { return FRAME_HEADER_SIZE; } /** * Creates a new ID3v23 Frame */ public ID3v23Frame() { } /** * Creates a new ID3v23 Frame of type identifier. *

*

An empty body of the correct type will be automatically created. * This constructor should be used when wish to create a new * frame from scratch using user data. * @param identifier */ public ID3v23Frame(String identifier) { super(identifier); statusFlags = new StatusFlags(); encodingFlags = new EncodingFlags(); } /** * Copy Constructor *

* Creates a new v23 frame based on another v23 frame * @param frame */ public ID3v23Frame(ID3v23Frame frame) { super(frame); statusFlags = new StatusFlags(frame.getStatusFlags().getOriginalFlags()); encodingFlags = new EncodingFlags(frame.getEncodingFlags().getFlags()); } /** * Creates a new ID3v23Frame based on another frame of a different version. * * @param frame * @throws org.jaudiotagger.tag.InvalidFrameException */ public ID3v23Frame(AbstractID3v2Frame frame) throws InvalidFrameException { logger.finer("Creating frame from a frame of a different version"); if (frame instanceof ID3v23Frame) { throw new UnsupportedOperationException("Copy Constructor not called. Please type cast the argument"); } if (frame instanceof ID3v24Frame) { statusFlags = new StatusFlags((ID3v24Frame.StatusFlags) frame.getStatusFlags()); encodingFlags = new EncodingFlags(frame.getEncodingFlags().getFlags()); } if (frame instanceof ID3v24Frame) { //Unknown Frame e.g NCON, also protects when known id but has unsupported frame body if (frame.getBody() instanceof FrameBodyUnsupported) { this.frameBody = new FrameBodyUnsupported((FrameBodyUnsupported) frame.getBody()); this.frameBody.setHeader(this); identifier = frame.getIdentifier(); logger.info("UNKNOWN:Orig id is:" + frame.getIdentifier() + ":New id is:" + identifier); return; } // Deprecated frame for v24 else if (frame.getBody() instanceof FrameBodyDeprecated) { //Was it valid for this tag version, if so try and reconstruct if (ID3Tags.isID3v23FrameIdentifier(frame.getIdentifier())) { this.frameBody = ((FrameBodyDeprecated) frame.getBody()).getOriginalFrameBody(); this.frameBody.setHeader(this); this.frameBody.setTextEncoding(ID3TextEncodingConversion.getTextEncoding(this,this.frameBody.getTextEncoding())); identifier = frame.getIdentifier(); logger.info("DEPRECATED:Orig id is:" + frame.getIdentifier() + ":New id is:" + identifier); } //or was it still deprecated, if so leave as is else { this.frameBody = new FrameBodyDeprecated((FrameBodyDeprecated) frame.getBody()); this.frameBody.setHeader(this); this.frameBody.setTextEncoding(ID3TextEncodingConversion.getTextEncoding(this,this.frameBody.getTextEncoding())); identifier = frame.getIdentifier(); logger.info("DEPRECATED:Orig id is:" + frame.getIdentifier() + ":New id is:" + identifier); return; } } else if (ID3Tags.isID3v24FrameIdentifier(frame.getIdentifier())) { logger.finer("isID3v24FrameIdentifier"); //Version between v4 and v3 identifier = ID3Tags.convertFrameID24To23(frame.getIdentifier()); if (identifier != null) { logger.finer("V4:Orig id is:" + frame.getIdentifier() + ":New id is:" + identifier); this.frameBody = (AbstractTagFrameBody) ID3Tags.copyObject(frame.getBody()); this.frameBody.setHeader(this); this.frameBody.setTextEncoding(ID3TextEncodingConversion.getTextEncoding(this,this.frameBody.getTextEncoding())); return; } else { //Is it a known v4 frame which needs forcing to v3 frame e.g. TDRC - TYER,TDAT identifier = ID3Tags.forceFrameID24To23(frame.getIdentifier()); if (identifier != null) { logger.finer("V4:Orig id is:" + frame.getIdentifier() + ":New id is:" + identifier); this.frameBody = this.readBody(identifier, (AbstractID3v2FrameBody) frame.getBody()); this.frameBody.setHeader(this); this.frameBody.setTextEncoding(ID3TextEncodingConversion.getTextEncoding(this,this.frameBody.getTextEncoding())); return; } //It is a v24 frame that is not known and cannot be forced in v23 e.g TDRL,in which case //we convert to a frameBody unsupported by writing contents as a byte array and feeding //it into FrameBodyUnsupported else { ByteArrayOutputStream baos = new ByteArrayOutputStream(); ((AbstractID3v2FrameBody) frame.getBody()).write(baos); identifier = frame.getIdentifier(); this.frameBody = new FrameBodyUnsupported(identifier, baos.toByteArray()); this.frameBody.setHeader(this); logger.finer("V4:Orig id is:" + frame.getIdentifier() + ":New Id Unsupported is:" + identifier); return; } } } // Unable to find a suitable frameBody, this should not happen else { logger.severe("Orig id is:" + frame.getIdentifier() + "Unable to create Frame Body"); throw new InvalidFrameException("Orig id is:" + frame.getIdentifier() + "Unable to create Frame Body"); } } else if (frame instanceof ID3v22Frame) { if (ID3Tags.isID3v22FrameIdentifier(frame.getIdentifier())) { identifier = ID3Tags.convertFrameID22To23(frame.getIdentifier()); if (identifier != null) { logger.info("V3:Orig id is:" + frame.getIdentifier() + ":New id is:" + identifier); this.frameBody = (AbstractTagFrameBody) ID3Tags.copyObject(frame.getBody()); this.frameBody.setHeader(this); return; } //Is it a known v2 frame which needs forcing to v23 frame e.g PIC - APIC else if (ID3Tags.isID3v22FrameIdentifier(frame.getIdentifier())) { //Force v2 to v3 identifier = ID3Tags.forceFrameID22To23(frame.getIdentifier()); if (identifier != null) { logger.info("V22Orig id is:" + frame.getIdentifier() + "New id is:" + identifier); this.frameBody = this.readBody(identifier, (AbstractID3v2FrameBody) frame.getBody()); this.frameBody.setHeader(this); return; } //No mechanism exists to convert it to a v23 frame else { this.frameBody = new FrameBodyDeprecated((AbstractID3v2FrameBody) frame.getBody()); this.frameBody.setHeader(this); identifier = frame.getIdentifier(); logger.info("Deprecated:V22:orig id id is:" + frame.getIdentifier() + ":New id is:" + identifier); return; } } } // Unknown Frame e.g NCON else { this.frameBody = new FrameBodyUnsupported((FrameBodyUnsupported) frame.getBody()); this.frameBody.setHeader(this); identifier = frame.getIdentifier(); logger.info("UNKNOWN:Orig id is:" + frame.getIdentifier() + ":New id is:" + identifier); return; } } logger.warning("Frame is unknown version:"+frame.getClass()); } /** * Creates a new ID3v23Frame dataType by reading from byteBuffer. * * @param byteBuffer to read from * @param loggingFilename * @throws org.jaudiotagger.tag.InvalidFrameException */ public ID3v23Frame(ByteBuffer byteBuffer, String loggingFilename) throws InvalidFrameException, InvalidDataTypeException { setLoggingFilename(loggingFilename); read(byteBuffer); } /** * Creates a new ID3v23Frame dataType by reading from byteBuffer. * * @param byteBuffer to read from * @deprecated use {@link #ID3v23Frame(ByteBuffer,String)} instead * @throws org.jaudiotagger.tag.InvalidFrameException */ public ID3v23Frame(ByteBuffer byteBuffer) throws InvalidFrameException, InvalidDataTypeException { this(byteBuffer, ""); } /** * Return size of frame * * @return int frame size */ public int getSize() { return frameBody.getSize() + ID3v23Frame.FRAME_HEADER_SIZE; } /** * Compare for equality * To be deemed equal obj must be a IDv23Frame with the same identifier * and the same flags. * containing the same body,dataType list ectera. * equals() method is made up from all the various components * * @param obj * @return if true if this object is equivalent to obj */ public boolean equals(Object obj) { if ( this == obj ) return true; if (!(obj instanceof ID3v23Frame)) { return false; } ID3v23Frame that = (ID3v23Frame) obj; return EqualsUtil.areEqual(this.statusFlags, that.statusFlags) && EqualsUtil.areEqual(this.encodingFlags, that.encodingFlags) && super.equals(that); } /** * Read the frame from a byteBuffer * * @param byteBuffer buffer to read from */ public void read(ByteBuffer byteBuffer) throws InvalidFrameException, InvalidDataTypeException { String identifier = readIdentifier(byteBuffer); if (!isValidID3v2FrameIdentifier(identifier)) { logger.info(getLoggingFilename() + ":Invalid identifier:" + identifier); byteBuffer.position(byteBuffer.position() - (getFrameIdSize() - 1)); throw new InvalidFrameIdentifierException(getLoggingFilename() + ":" + identifier + ":is not a valid ID3v2.30 frame"); } //Read the size field (as Big Endian Int - byte buffers always initialised to Big Endian order) frameSize = byteBuffer.getInt(); if (frameSize < 0) { logger.warning(getLoggingFilename() + ":Invalid Frame Size:" + identifier); throw new InvalidFrameException(identifier + " is invalid frame"); } else if (frameSize == 0) { logger.warning(getLoggingFilename() + ":Empty Frame Size:" + identifier); //We don't process this frame or add to frameMap because contains no useful information //Skip the two flag bytes so in correct position for subsequent frames byteBuffer.get(); byteBuffer.get(); throw new EmptyFrameException(identifier + " is empty frame"); } else if (frameSize > byteBuffer.remaining()) { logger.warning(getLoggingFilename() + ":Invalid Frame size of " +frameSize +" larger than size of" + byteBuffer.remaining() + " before mp3 audio:" + identifier); throw new InvalidFrameException(identifier + " is invalid frame"); } //Read the flag bytes statusFlags = new StatusFlags(byteBuffer.get()); encodingFlags = new EncodingFlags(byteBuffer.get()); String id; //If this identifier is a valid v24 identifier or easily converted to v24 id = ID3Tags.convertFrameID23To24(identifier); // Cant easily be converted to v24 but is it a valid v23 identifier if (id == null) { // It is a valid v23 identifier so should be able to find a // frame body for it. if (ID3Tags.isID3v23FrameIdentifier(identifier)) { id = identifier; } // Unknown so will be created as FrameBodyUnsupported else { id = UNSUPPORTED_ID; } } logger.fine(getLoggingFilename() + ":Identifier was:" + identifier + " reading using:" + id + "with frame size:" + frameSize); //Read extra bits appended to frame header for various encodings //These are not included in header size but are included in frame size but won't be read when we actually //try to read the frame body data int extraHeaderBytesCount = 0; int decompressedFrameSize = -1; if (((EncodingFlags) encodingFlags).isCompression()) { //Read the Decompressed Size decompressedFrameSize = byteBuffer.getInt(); extraHeaderBytesCount = FRAME_COMPRESSION_UNCOMPRESSED_SIZE; logger.fine(getLoggingFilename() + ":Decompressed frame size is:" + decompressedFrameSize); } if (((EncodingFlags) encodingFlags).isEncryption()) { //Consume the encryption byte extraHeaderBytesCount += FRAME_ENCRYPTION_INDICATOR_SIZE; encryptionMethod = byteBuffer.get(); } if (((EncodingFlags) encodingFlags).isGrouping()) { //Read the Grouping byte, but do nothing with it extraHeaderBytesCount += FRAME_GROUPING_INDICATOR_SIZE; groupIdentifier = byteBuffer.get(); } //Work out the real size of the frameBody data int realFrameSize = frameSize - extraHeaderBytesCount; ByteBuffer frameBodyBuffer; //Read the body data try { if (((EncodingFlags) encodingFlags).isCompression()) { frameBodyBuffer = ID3Compression.uncompress(identifier,getLoggingFilename(),byteBuffer, decompressedFrameSize, realFrameSize); frameBody = readBody(id, frameBodyBuffer, decompressedFrameSize); } else if (((EncodingFlags) encodingFlags).isEncryption()) { frameBodyBuffer = byteBuffer.slice(); frameBodyBuffer.limit(realFrameSize); frameBody = readEncryptedBody(identifier, byteBuffer,frameSize); } else { //Create Buffer that only contains the body of this frame rather than the remainder of tag frameBodyBuffer = byteBuffer.slice(); frameBodyBuffer.limit(realFrameSize); frameBody = readBody(id, frameBodyBuffer, realFrameSize); } //TODO code seems to assume that if the frame created is not a v23FrameBody //it should be deprecated, but what about if somehow a V24Frame has been put into a V23 Tag, shouldn't //it then be created as FrameBodyUnsupported if (!(frameBody instanceof ID3v23FrameBody)) { logger.info(getLoggingFilename() + ":Converted frameBody with:" + identifier + " to deprecated frameBody"); frameBody = new FrameBodyDeprecated((AbstractID3v2FrameBody) frameBody); } } finally { //Update position of main buffer, so no attempt is made to reread these bytes byteBuffer.position(byteBuffer.position() + realFrameSize); } } /** * Write the frame to bufferOutputStream * * @throws IOException */ public void write(ByteArrayOutputStream tagBuffer) { logger.info("Writing frame to buffer:" + getIdentifier()); //This is where we will write header, move position to where we can //write body ByteBuffer headerBuffer = ByteBuffer.allocate(FRAME_HEADER_SIZE); //Write Frame Body Data ByteArrayOutputStream bodyOutputStream = new ByteArrayOutputStream(); ((AbstractID3v2FrameBody) frameBody).write(bodyOutputStream); //Write Frame Header write Frame ID if (getIdentifier().length() == 3) { identifier = identifier + ' '; } headerBuffer.put(Utils.getDefaultBytes(getIdentifier(), "ISO-8859-1"), 0, FRAME_ID_SIZE); //Write Frame Size int size = frameBody.getSize(); logger.fine("Frame Size Is:" + size); headerBuffer.putInt(frameBody.getSize()); //Write the Flags //Status Flags:leave as they were when we read headerBuffer.put(statusFlags.getWriteFlags()); //Remove any non standard flags ((EncodingFlags) encodingFlags).unsetNonStandardFlags(); //Unset Compression flag if previously set because we uncompress previously compressed frames on write. ((EncodingFlags)encodingFlags).unsetCompression(); headerBuffer.put(encodingFlags.getFlags()); try { //Add header to the Byte Array Output Stream tagBuffer.write(headerBuffer.array()); if (((EncodingFlags) encodingFlags).isEncryption()) { tagBuffer.write(encryptionMethod); } if (((EncodingFlags) encodingFlags).isGrouping()) { tagBuffer.write(groupIdentifier); } //Add body to the Byte Array Output Stream tagBuffer.write(bodyOutputStream.toByteArray()); } catch (IOException ioe) { //This could never happen coz not writing to file, so convert to RuntimeException throw new RuntimeException(ioe); } } public AbstractID3v2Frame.StatusFlags getStatusFlags() { return statusFlags; } public AbstractID3v2Frame.EncodingFlags getEncodingFlags() { return encodingFlags; } public int getEncryptionMethod() { return encryptionMethod; } public int getGroupIdentifier() { return groupIdentifier; } /** * This represents a frame headers Status Flags * Make adjustments if necessary based on frame type and specification. */ class StatusFlags extends AbstractID3v2Frame.StatusFlags { public static final String TYPE_TAGALTERPRESERVATION = "typeTagAlterPreservation"; public static final String TYPE_FILEALTERPRESERVATION = "typeFileAlterPreservation"; public static final String TYPE_READONLY = "typeReadOnly"; /** * Discard frame if tag altered */ public static final int MASK_TAG_ALTER_PRESERVATION = FileConstants.BIT7; /** * Discard frame if audio file part altered */ public static final int MASK_FILE_ALTER_PRESERVATION = FileConstants.BIT6; /** * Frame tagged as read only */ public static final int MASK_READ_ONLY = FileConstants.BIT5; public StatusFlags() { originalFlags = (byte) 0; writeFlags = (byte) 0; } StatusFlags(byte flags) { originalFlags = flags; writeFlags = flags; modifyFlags(); } /** * Use this constructor when convert a v24 frame * @param statusFlags */ StatusFlags(ID3v24Frame.StatusFlags statusFlags) { originalFlags = convertV4ToV3Flags(statusFlags.getOriginalFlags()); writeFlags = originalFlags; modifyFlags(); } private byte convertV4ToV3Flags(byte v4Flag) { byte v3Flag = (byte) 0; if ((v4Flag & ID3v24Frame.StatusFlags.MASK_FILE_ALTER_PRESERVATION) != 0) { v3Flag |= (byte) MASK_FILE_ALTER_PRESERVATION; } if ((v4Flag & ID3v24Frame.StatusFlags.MASK_TAG_ALTER_PRESERVATION) != 0) { v3Flag |= (byte) MASK_TAG_ALTER_PRESERVATION; } return v3Flag; } protected void modifyFlags() { String str = getIdentifier(); if (ID3v23Frames.getInstanceOf().isDiscardIfFileAltered(str)) { writeFlags |= (byte) MASK_FILE_ALTER_PRESERVATION; writeFlags &= (byte) ~MASK_TAG_ALTER_PRESERVATION; } else { writeFlags &= (byte) ~MASK_FILE_ALTER_PRESERVATION; writeFlags &= (byte) ~MASK_TAG_ALTER_PRESERVATION; } } public void createStructure() { MP3File.getStructureFormatter().openHeadingElement(TYPE_FLAGS, ""); MP3File.getStructureFormatter().addElement(TYPE_TAGALTERPRESERVATION, originalFlags & MASK_TAG_ALTER_PRESERVATION); MP3File.getStructureFormatter().addElement(TYPE_FILEALTERPRESERVATION, originalFlags & MASK_FILE_ALTER_PRESERVATION); MP3File.getStructureFormatter().addElement(TYPE_READONLY, originalFlags & MASK_READ_ONLY); MP3File.getStructureFormatter().closeHeadingElement(TYPE_FLAGS); } } /** * This represents a frame headers Encoding Flags */ class EncodingFlags extends AbstractID3v2Frame.EncodingFlags { public static final String TYPE_COMPRESSION = "compression"; public static final String TYPE_ENCRYPTION = "encryption"; public static final String TYPE_GROUPIDENTITY = "groupidentity"; /** * Frame is compressed */ public static final int MASK_COMPRESSION = FileConstants.BIT7; /** * Frame is encrypted */ public static final int MASK_ENCRYPTION = FileConstants.BIT6; /** * Frame is part of a group */ public static final int MASK_GROUPING_IDENTITY = FileConstants.BIT5; public EncodingFlags() { super(); } public EncodingFlags(byte flags) { super(flags); logEnabledFlags(); } public void setCompression() { flags |= MASK_COMPRESSION; } public void setEncryption() { flags |= MASK_ENCRYPTION; } public void setGrouping() { flags |= MASK_GROUPING_IDENTITY; } public void unsetCompression() { flags &= (byte) ~MASK_COMPRESSION; } public void unsetEncryption() { flags &= (byte) ~MASK_ENCRYPTION; } public void unsetGrouping() { flags &= (byte) ~MASK_GROUPING_IDENTITY; } public boolean isNonStandardFlags() { return ((flags & FileConstants.BIT4) > 0) || ((flags & FileConstants.BIT3) > 0) || ((flags & FileConstants.BIT2) > 0) || ((flags & FileConstants.BIT1) > 0) || ((flags & FileConstants.BIT0) > 0); } public void unsetNonStandardFlags() { if(isNonStandardFlags()) { logger.warning(getLoggingFilename() + ":" + getIdentifier() + ":Unsetting Unknown Encoding Flags:"+ Hex.asHex(flags)); flags &= (byte) ~FileConstants.BIT4; flags &= (byte) ~FileConstants.BIT3; flags &= (byte) ~FileConstants.BIT2; flags &= (byte) ~FileConstants.BIT1; flags &= (byte) ~FileConstants.BIT0; } } public void logEnabledFlags() { if(isNonStandardFlags()) { logger.warning(getLoggingFilename() + ":" + identifier + ":Unknown Encoding Flags:"+ Hex.asHex(flags)); } if (isCompression()) { logger.warning(getLoggingFilename() + ":" + identifier + " is compressed"); } if (isEncryption()) { logger.warning(getLoggingFilename() + ":" + identifier + " is encrypted"); } if (isGrouping()) { logger.warning(getLoggingFilename() + ":" + identifier + " is grouped"); } } public boolean isCompression() { return (flags & MASK_COMPRESSION) > 0; } public boolean isEncryption() { return (flags & MASK_ENCRYPTION) > 0; } public boolean isGrouping() { return (flags & MASK_GROUPING_IDENTITY) > 0; } public void createStructure() { MP3File.getStructureFormatter().openHeadingElement(TYPE_FLAGS, ""); MP3File.getStructureFormatter().addElement(TYPE_COMPRESSION, flags & MASK_COMPRESSION); MP3File.getStructureFormatter().addElement(TYPE_ENCRYPTION, flags & MASK_ENCRYPTION); MP3File.getStructureFormatter().addElement(TYPE_GROUPIDENTITY, flags & MASK_GROUPING_IDENTITY); MP3File.getStructureFormatter().closeHeadingElement(TYPE_FLAGS); } } /** * Does the frame identifier meet the syntax for a idv3v2 frame identifier. * must start with a capital letter and only contain capital letters and numbers * * @param identifier to be checked * @return whether the identifier is valid */ public boolean isValidID3v2FrameIdentifier(String identifier) { Matcher m = ID3v23Frame.validFrameIdentifier.matcher(identifier); return m.matches(); } /** * Return String Representation of body */ public void createStructure() { MP3File.getStructureFormatter().openHeadingElement(TYPE_FRAME, getIdentifier()); MP3File.getStructureFormatter().addElement(TYPE_FRAME_SIZE, frameSize); statusFlags.createStructure(); encodingFlags.createStructure(); frameBody.createStructure(); MP3File.getStructureFormatter().closeHeadingElement(TYPE_FRAME); } /** * @return true if considered a common frame */ public boolean isCommon() { return ID3v23Frames.getInstanceOf().isCommon(getId()); } /** * @return true if considered a common frame */ public boolean isBinary() { return ID3v23Frames.getInstanceOf().isBinary(getId()); } /** * Sets the charset encoding used by the field. * * @param encoding charset. */ public void setEncoding(String encoding) { Integer encodingId = TextEncoding.getInstanceOf().getIdForValue(encoding); if(encoding!=null) { if(encodingId <2) { this.getBody().setTextEncoding(encodingId.byteValue()); } } } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/ID3Compression.java0000644000175000017500000000461211470746136026420 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3; import org.jaudiotagger.logging.ErrorMessage; import org.jaudiotagger.tag.InvalidFrameException; import java.nio.ByteBuffer; import java.util.logging.Level; import java.util.logging.Logger; import java.util.zip.DataFormatException; import java.util.zip.Inflater; /** * compresses frame data *

* Is currently required for V23Frames and V24Frames *

*/ //TODO also need to support compress framedata public class ID3Compression { //Logger public static Logger logger = Logger.getLogger("org.jaudiotagger.tag.id3"); /** * Decompress realFrameSize bytes to decompressedFrameSize bytes and return as ByteBuffer * * @param byteBuffer * @param decompressedFrameSize * @param realFrameSize * @return * @throws org.jaudiotagger.tag.InvalidFrameException * */ protected static ByteBuffer uncompress(String identifier,String filename, ByteBuffer byteBuffer, int decompressedFrameSize, int realFrameSize) throws InvalidFrameException { logger.config(filename + ":About to decompress " + realFrameSize + " bytes, expect result to be:" + decompressedFrameSize + " bytes"); // Decompress the bytes into this buffer, size initialized from header field byte[] result = new byte[decompressedFrameSize]; byte[] input = new byte[realFrameSize]; //Store position ( just after frame header and any extra bits) //Read frame data into array, and then put buffer back to where it was int position = byteBuffer.position(); byteBuffer.get(input, 0, realFrameSize); byteBuffer.position(position); Inflater decompresser = new Inflater(); decompresser.setInput(input); try { int inflatedTo = decompresser.inflate(result); logger.config(filename + ":Decompressed to " + inflatedTo + " bytes"); } catch (DataFormatException dfe) { logger.log(Level.CONFIG,"Unable to decompress this frame:"+identifier,dfe); //Update position of main buffer, so no attempt is made to reread these bytes byteBuffer.position(byteBuffer.position() + realFrameSize); throw new InvalidFrameException(ErrorMessage.ID3_UNABLE_TO_DECOMPRESS_FRAME.getMsg(identifier,filename,dfe.getMessage())); } decompresser.end(); return ByteBuffer.wrap(result); } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/ID3Unsynchronization.java0000644000175000017500000002136611305662343027662 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3; import org.jaudiotagger.audio.mp3.MPEGFrameHeader; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.nio.ByteBuffer; import java.util.logging.Logger; import java.util.logging.Level; /** * Performs unsynchronization and synchronization tasks on a buffer. *

* Is currently required for V23Tags and V24Frames */ public class ID3Unsynchronization { //Logger public static Logger logger = Logger.getLogger("org.jaudiotagger.tag.id3"); /** * Check if a byte array will require unsynchronization before being written as a tag. * If the byte array contains any $FF $E0 bytes, then it will require unsynchronization. * * @param abySource the byte array to be examined * @return true if unsynchronization is required, false otherwise */ public static boolean requiresUnsynchronization(byte[] abySource) { for (int i = 0; i < abySource.length - 1; i++) { if (((abySource[i] & MPEGFrameHeader.SYNC_BYTE1) == MPEGFrameHeader.SYNC_BYTE1) && ((abySource[i + 1] & MPEGFrameHeader.SYNC_BYTE2) == MPEGFrameHeader.SYNC_BYTE2)) { if (logger.isLoggable(Level.FINEST)) { logger.finest("Unsynchronisation required found bit at:" + i); } return true; } } return false; } /** * Unsynchronize an array of bytes, this should only be called if the decision has already been made to * unsynchronize the byte array *

* In order to prevent a media player from incorrectly interpreting the contents of a tag, all $FF bytes * followed by a byte with value >=224 must be followed by a $00 byte (thus, $FF $F0 sequences become $FF $00 $F0). * Additionally because unsynchronisation is being applied any existing $FF $00 have to be converted to * $FF $00 $00 * * @param abySource a byte array to be unsynchronized * @return a unsynchronized representation of the source */ public static byte[] unsynchronize(byte[] abySource) { ByteArrayInputStream input = new ByteArrayInputStream(abySource); ByteArrayOutputStream output = new ByteArrayOutputStream(abySource.length); int count = 0; while (input.available() > 0) { int firstByte = input.read(); count++; output.write(firstByte); if ((firstByte & MPEGFrameHeader.SYNC_BYTE1) == MPEGFrameHeader.SYNC_BYTE1) { // if byte is $FF, we must check the following byte if there is one if (input.available() > 0) { input.mark(1); // remember where we were, if we don't need to unsynchronize int secondByte = input.read(); if ((secondByte & MPEGFrameHeader.SYNC_BYTE2) == MPEGFrameHeader.SYNC_BYTE2) { // we need to unsynchronize here if (logger.isLoggable(Level.FINEST)) { logger.finest("Writing unsynchronisation bit at:" + count); } output.write(0); } else if (secondByte == 0) { // we need to unsynchronize here if (logger.isLoggable(Level.FINEST)) { logger.finest("Inserting zero unsynchronisation bit at:" + count); } output.write(0); } input.reset(); } } } // if we needed to unsynchronize anything, and this tag ends with 0xff, we have to append a zero byte, // which will be removed on de-unsynchronization later if ((abySource[abySource.length - 1] & MPEGFrameHeader.SYNC_BYTE1) == MPEGFrameHeader.SYNC_BYTE1) { logger.finest("Adding unsynchronisation bit at end of stream"); output.write(0); } return output.toByteArray(); } /** * Synchronize an array of bytes, this should only be called if it has been determined the tag is unsynchronised *

* Any patterns of the form $FF $00 should be replaced by $FF * * @param source a ByteBuffer to be unsynchronized * @return a synchronized representation of the source */ /* public static ByteBuffer synchronize(ByteBuffer source) { long start = System.nanoTime(); int bufferSize = source.limit(); ByteArrayOutputStream oBAOS = new ByteArrayOutputStream(bufferSize); int position = 0; while (position < bufferSize) { int byteValue = source.get(); position ++; oBAOS.write(byteValue); if ((byteValue & MPEGFrameHeader.SYNC_BYTE1) == MPEGFrameHeader.SYNC_BYTE1) { // we are skipping if $00 byte but check not an end of stream if (position < bufferSize) { int unsyncByteValue = source.get(); position++; //If its the null byte we just ignore it if (unsyncByteValue != 0) { oBAOS.write(unsyncByteValue); } } } } long time = System.nanoTime() - start; ByteBuffer bb = ByteBuffer.wrap(oBAOS.toByteArray()); System.out.printf("Took %6.3f ms, was %d bytes, now %,d bytes%n", time/1e6, source.limit(), bb.limit()); return bb; } */ /** * Synchronize an array of bytes, this should only be called if it has been determined the tag is unsynchronised *

* Any patterns of the form $FF $00 should be replaced by $FF * * @param source a ByteBuffer to be unsynchronized * @return a synchronized representation of the source */ /* public static ByteBuffer synchronize(ByteBuffer source) { long start = System.nanoTime(); int bufferSize = source.limit(); ByteBuffer output = ByteBuffer.allocate(bufferSize); int position = 0; int offset = 0; int length = 0; while (position < bufferSize) { int byteValue = source.get(); position++; length++; if ((byteValue & MPEGFrameHeader.SYNC_BYTE1) == MPEGFrameHeader.SYNC_BYTE1) { // we are skipping if $00 byte but check not an end of stream if (position < bufferSize) { int unsyncByteValue = source.get(); position++; //If this is null byte, then write upto this point if (unsyncByteValue == 0) { output.put(source.array(), source.arrayOffset() + offset, length); offset = position; length = 0; } else { length++; } } } } if (length > 0) { output.put(source.array(), source.arrayOffset() + offset, length); } output.flip(); long time = System.nanoTime() - start; System.out.printf("Took %6.3f ms, was %d bytes, now %,d bytes%n", time/1e6, source.limit(), output.limit()); return output; } */ /** * Synchronize an array of bytes, this should only be called if it has been determined the tag is unsynchronised *

* Any patterns of the form $FF $00 should be replaced by $FF * * @param source a ByteBuffer to be unsynchronized * @return a synchronized representation of the source */ public static ByteBuffer synchronize(ByteBuffer source) { //long start = System.nanoTime(); int len = source.remaining(); byte[] bytes = new byte[len + 1]; // an extra byte saves a check later. source.get(bytes, 0, len); int from = 0, to = 0; boolean copy = true; // whether to copy the byte, if false, check the byte != 0. while (from < len) { byte byteValue = bytes[from++]; if (copy || byteValue != 0) bytes[to++] = byteValue; copy = ((byteValue & MPEGFrameHeader.SYNC_BYTE1) != MPEGFrameHeader.SYNC_BYTE1); } ByteBuffer bb2 = ByteBuffer.wrap(bytes, 0, to); //long time = System.nanoTime() - start; //System.out.printf("Took %6.3f ms, was %d bytes, now %,d bytes%n", time/1e6, source.limit(), bb2.limit()); return bb2; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/Id3FieldType.java0000644000175000017500000000026010716331722026030 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3; /** * Categorises id3 fields to aid in mapping to generic keys */ public enum Id3FieldType { TEXT, USER_DEFINED_TEXT, BINARY } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/AbstractTag.java0000644000175000017500000000512611277026507026015 0ustar drazzibdrazzib/** * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: AbstractTag.java 836 2009-11-12 15:44:07Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Description:This class represents any type of tag in an MP3 file, including ID3 and * Lyrics and the file name. */ package org.jaudiotagger.tag.id3; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.util.Iterator; /** * A tag is term given to a container that holds audio metadata */ public abstract class AbstractTag extends AbstractTagItem { protected static final String TYPE_TAG = "tag"; public AbstractTag() { } public AbstractTag(AbstractTag copyObject) { super(copyObject); } /** * Looks for this tag in the buffer * * @param byteBuffer * @return returns true if found, false otherwise. */ abstract public boolean seek(ByteBuffer byteBuffer); /** * Writes the tag to the file * * @param file * @throws IOException */ public abstract void write(RandomAccessFile file) throws IOException; /** * Removes the specific tag from the file * * @param file MP3 file to append to. * @throws IOException on any I/O error */ abstract public void delete(RandomAccessFile file) throws IOException; /** * Determines whether another datatype is equal to this tag. It just compares * if they are the same class, then calls super.equals(obj). * * @param obj The object to compare * @return if they are equal */ public boolean equals(Object obj) { return (obj instanceof AbstractTag) && super.equals(obj); } /** * @return */ abstract public Iterator iterator(); } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/ID3v2ChapterFrames.java0000644000175000017500000000402711276777123027117 0ustar drazzibdrazzib/* * Horizon Wimba Copyright (C)2006 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can getFields a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3; import java.util.TreeSet; /** * Defines ID3 Chapter frames and collections that categorise frames. *

*

For more details, please refer to the ID3 Chapter Frame specifications: *

* * @author Marc Gimpel, Horizon Wimba S.A. * @version $Id: ID3v2ChapterFrames.java 830 2009-11-12 12:23:47Z paultaylor $ */ public class ID3v2ChapterFrames extends ID3Frames { public static final String FRAME_ID_CHAPTER = "CHAP"; public static final String FRAME_ID_TABLE_OF_CONTENT = "CTOC"; private static ID3v2ChapterFrames id3v2ChapterFrames; public static ID3v2ChapterFrames getInstanceOf() { if (id3v2ChapterFrames == null) { id3v2ChapterFrames = new ID3v2ChapterFrames(); } return id3v2ChapterFrames; } private ID3v2ChapterFrames() { idToValue.put(FRAME_ID_CHAPTER, "Chapter"); idToValue.put(FRAME_ID_TABLE_OF_CONTENT, "Table of content"); createMaps(); multipleFrames = new TreeSet(); discardIfFileAlteredFrames = new TreeSet(); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/AbstractID3v2Tag.java0000644000175000017500000025033011470746136026566 0ustar drazzibdrazzib/* * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can getFields a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.exceptions.UnableToCreateFileException; import org.jaudiotagger.audio.exceptions.UnableToModifyFileException; import org.jaudiotagger.audio.exceptions.UnableToRenameFileException; import org.jaudiotagger.audio.generic.Utils; import org.jaudiotagger.audio.mp3.MP3File; import org.jaudiotagger.logging.ErrorMessage; import org.jaudiotagger.logging.FileSystemMessage; import org.jaudiotagger.tag.*; import org.jaudiotagger.tag.datatype.*; import org.jaudiotagger.tag.id3.framebody.*; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; import org.jaudiotagger.tag.reference.Languages; import org.jaudiotagger.tag.reference.PictureTypes; import java.io.*; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.nio.channels.FileLock; import java.nio.channels.WritableByteChannel; import java.util.*; import java.util.logging.Level; /** * This is the abstract base class for all ID3v2 tags. * * @author : Paul Taylor * @author : Eric Farng * @version $Id: AbstractID3v2Tag.java 929 2010-11-17 12:36:46Z paultaylor $ */ public abstract class AbstractID3v2Tag extends AbstractID3Tag implements Tag { protected static final String TYPE_HEADER = "header"; protected static final String TYPE_BODY = "body"; //Tag ID as held in file protected static final byte[] TAG_ID = {'I', 'D', '3'}; //The tag header is the same for ID3v2 versions public static final int TAG_HEADER_LENGTH = 10; protected static final int FIELD_TAGID_LENGTH = 3; protected static final int FIELD_TAG_MAJOR_VERSION_LENGTH = 1; protected static final int FIELD_TAG_MINOR_VERSION_LENGTH = 1; protected static final int FIELD_TAG_FLAG_LENGTH = 1; protected static final int FIELD_TAG_SIZE_LENGTH = 4; protected static final int FIELD_TAGID_POS = 0; protected static final int FIELD_TAG_MAJOR_VERSION_POS = 3; protected static final int FIELD_TAG_MINOR_VERSION_POS = 4; protected static final int FIELD_TAG_FLAG_POS = 5; protected static final int FIELD_TAG_SIZE_POS = 6; protected static final int TAG_SIZE_INCREMENT = 100; //The max size we try to write in one go to avoid out of memory errors (10mb) private static final long MAXIMUM_WRITABLE_CHUNK_SIZE = 10000000; /** * Map of all frames for this tag */ public HashMap frameMap = null; /** * Map of all encrypted frames, these cannot be unencrypted by jaudiotagger */ public HashMap encryptedFrameMap = null; /** * Holds the ids of invalid duplicate frames */ protected static final String TYPE_DUPLICATEFRAMEID = "duplicateFrameId"; protected String duplicateFrameId = ""; /** * Holds count the number of bytes used up by invalid duplicate frames */ protected static final String TYPE_DUPLICATEBYTES = "duplicateBytes"; protected int duplicateBytes = 0; /** * Holds count the number bytes used up by empty frames */ protected static final String TYPE_EMPTYFRAMEBYTES = "emptyFrameBytes"; protected int emptyFrameBytes = 0; /** * Holds the size of the tag as reported by the tag header */ protected static final String TYPE_FILEREADSIZE = "fileReadSize"; protected int fileReadSize = 0; /** * Holds count of invalid frames, (frames that could not be read) */ protected static final String TYPE_INVALIDFRAMES = "invalidFrames"; protected int invalidFrames = 0; /** * Empty Constructor */ public AbstractID3v2Tag() { } /** * This constructor is used when a tag is created as a duplicate of another * tag of the same type and version. * * @param copyObject */ protected AbstractID3v2Tag(AbstractID3v2Tag copyObject) { } /** * Copy primitives apply to all tags * * @param copyObject */ protected void copyPrimitives(AbstractID3v2Tag copyObject) { logger.info("Copying Primitives"); //Primitives type variables common to all IDv2 Tags this.duplicateFrameId = copyObject.duplicateFrameId; this.duplicateBytes = copyObject.duplicateBytes; this.emptyFrameBytes = copyObject.emptyFrameBytes; this.fileReadSize = copyObject.fileReadSize; this.invalidFrames = copyObject.invalidFrames; } /** * Copy frames from another tag, * * @param copyObject */ //TODO Copy Encrypted frames needs implementing protected void copyFrames(AbstractID3v2Tag copyObject) { frameMap = new LinkedHashMap(); encryptedFrameMap = new LinkedHashMap(); //Copy Frames that are a valid 2.4 type for (Object o1 : copyObject.frameMap.keySet()) { String id = (String) o1; Object o = copyObject.frameMap.get(id); //SingleFrames if (o instanceof AbstractID3v2Frame) { addFrame((AbstractID3v2Frame) o); } //MultiFrames else if (o instanceof ArrayList) { for (AbstractID3v2Frame frame : (ArrayList) o) { addFrame(frame); } } } } protected abstract void addFrame(AbstractID3v2Frame frame); /** * Returns the number of bytes which come from duplicate frames * * @return the number of bytes which come from duplicate frames */ public int getDuplicateBytes() { return duplicateBytes; } /** * Return the string which holds the ids of all * duplicate frames. * * @return the string which holds the ids of all duplicate frames. */ public String getDuplicateFrameId() { return duplicateFrameId; } /** * Returns the number of bytes which come from empty frames * * @return the number of bytes which come from empty frames */ public int getEmptyFrameBytes() { return emptyFrameBytes; } /** * Return byte count of invalid frames * * @return byte count of invalid frames */ public int getInvalidFrames() { return invalidFrames; } /** * Returns the tag size as reported by the tag header * * @return the tag size as reported by the tag header */ public int getFileReadBytes() { return fileReadSize; } /** * Return whether tag has frame with this identifier *

* Warning the match is only done against the identifier so if a tag contains a frame with an unsuported body * but happens to have an identifier that is valid for another version of the tag it will return true * * @param identifier frameId to lookup * @return true if tag has frame with this identifier */ public boolean hasFrame(String identifier) { return frameMap.containsKey(identifier); } /** * Return whether tag has frame with this identifier and a related body. This is required to protect * against circumstances whereby a tag contains a frame with an unsupported body * but happens to have an identifier that is valid for another version of the tag which it has been converted to *

* e.g TDRC is an invalid frame in a v23 tag but if somehow a v23tag has been created by another application * with a TDRC frame we construct an UnsupportedFrameBody to hold it, then this library constructs a * v24 tag, it will contain a frame with id TDRC but it will not have the expected frame body it is not really a * TDRC frame. * * @param identifier frameId to lookup * @return true if tag has frame with this identifier */ public boolean hasFrameAndBody(String identifier) { if (hasFrame(identifier)) { Object o = getFrame(identifier); if (o instanceof AbstractID3v2Frame) { return !(((AbstractID3v2Frame) o).getBody() instanceof FrameBodyUnsupported); } return true; } return false; } /** * Return whether tag has frame starting with this identifier *

* Warning the match is only done against the identifier so if a tag contains a frame with an unsupported body * but happens to have an identifier that is valid for another version of the tag it will return true * * @param identifier start of frameId to lookup * @return tag has frame starting with this identifier */ public boolean hasFrameOfType(String identifier) { Iterator iterator = frameMap.keySet().iterator(); String key; boolean found = false; while (iterator.hasNext() && !found) { key = iterator.next(); if (key.startsWith(identifier)) { found = true; } } return found; } /** * For single frames return the frame in this tag with given identifier if it exists, if multiple frames * exist with the same identifier it will return a list containing all the frames with this identifier *

* Warning the match is only done against the identifier so if a tag contains a frame with an unsupported body * but happens to have an identifier that is valid for another version of the tag it will be returned. *

* * @param identifier is an ID3Frame identifier * @return matching frame, or list of matching frames */ //TODO:This method is problematic because sometimes it returns a list and sometimes a frame, we need to //replace with two separate methods as in the tag interface. public Object getFrame(String identifier) { return frameMap.get(identifier); } /** * Return any encrypted frames with this identifier *

*

For single frames return the frame in this tag with given identifier if it exists, if multiple frames * exist with the same identifier it will return a list containing all the frames with this identifier * * @param identifier * @return */ public Object getEncryptedFrame(String identifier) { return encryptedFrameMap.get(identifier); } /** * Retrieve the first value that exists for this identifier *

* If the value is a String it returns that, otherwise returns a summary of the fields information *

* * @param identifier * @return */ public String getFirst(String identifier) { AbstractID3v2Frame frame = getFirstField(identifier); if (frame == null) { return ""; } return getTextValueForFrame(frame); } /** * @param frame * @return */ private String getTextValueForFrame(AbstractID3v2Frame frame) { return frame.getBody().getUserFriendlyValue(); } public TagField getFirstField(FieldKey genericKey) throws KeyNotFoundException { List fields = getFields(genericKey); if (fields.size() > 0) { return fields.get(0); } return null; } /** * Retrieve the first tag field that exists for this identifier * * @param identifier * @return tag field or null if doesn't exist */ public AbstractID3v2Frame getFirstField(String identifier) { Object object = getFrame(identifier); if (object == null) { return null; } if (object instanceof List) { return ((List) object).get(0); } else { return (AbstractID3v2Frame) object; } } /** * Add a frame to this tag * * @param frame the frame to add *

*

* Warning if frame(s) already exists for this identifier that they are overwritten *

*/ //TODO needs to ensure do not addField an invalid frame for this tag //TODO what happens if already contains a list with this ID public void setFrame(AbstractID3v2Frame frame) { frameMap.put(frame.getIdentifier(), frame); } protected abstract ID3Frames getID3Frames(); public void setField(FieldKey genericKey, String value) throws KeyNotFoundException, FieldDataInvalidException { TagField tagfield = createField(genericKey, value); setField(tagfield); } public void addField(FieldKey genericKey, String value) throws KeyNotFoundException, FieldDataInvalidException { TagField tagfield = createField(genericKey, value); addField(tagfield); } /** * Add frame taking into account existing frames of the same type * * @param newFrame * @param frames */ public void mergeDuplicateFrames(AbstractID3v2Frame newFrame, List frames) { for (ListIterator li = frames.listIterator(); li.hasNext();) { AbstractID3v2Frame nextFrame = li.next(); if (newFrame.getBody() instanceof FrameBodyTXXX) { //Value with matching key exists so replace if (((FrameBodyTXXX) newFrame.getBody()).getDescription().equals(((FrameBodyTXXX) nextFrame.getBody()).getDescription())) { li.set(newFrame); frameMap.put(newFrame.getId(), frames); return; } } else if (newFrame.getBody() instanceof FrameBodyWXXX) { //Value with matching key exists so replace if (((FrameBodyWXXX) newFrame.getBody()).getDescription().equals(((FrameBodyWXXX) nextFrame.getBody()).getDescription())) { li.set(newFrame); frameMap.put(newFrame.getId(), frames); return; } } else if (newFrame.getBody() instanceof FrameBodyCOMM) { if (((FrameBodyCOMM) newFrame.getBody()).getDescription().equals(((FrameBodyCOMM) nextFrame.getBody()).getDescription())) { li.set(newFrame); frameMap.put(newFrame.getId(), frames); return; } } else if (newFrame.getBody() instanceof FrameBodyUFID) { if (((FrameBodyUFID) newFrame.getBody()).getOwner().equals(((FrameBodyUFID) nextFrame.getBody()).getOwner())) { li.set(newFrame); frameMap.put(newFrame.getId(), frames); return; } } else if (newFrame.getBody() instanceof FrameBodyUSLT) { if (((FrameBodyUSLT) newFrame.getBody()).getDescription().equals(((FrameBodyUSLT) nextFrame.getBody()).getDescription())) { li.set(newFrame); frameMap.put(newFrame.getId(), frames); return; } } else if (newFrame.getBody() instanceof FrameBodyPOPM) { if (((FrameBodyPOPM) newFrame.getBody()).getEmailToUser().equals(((FrameBodyPOPM) nextFrame.getBody()).getEmailToUser())) { li.set(newFrame); frameMap.put(newFrame.getId(), frames); return; } } //Just grab any additional info from new TRCK Frame and add to the existing one else if (newFrame.getBody() instanceof FrameBodyTRCK) { FrameBodyTRCK newBody = (FrameBodyTRCK) newFrame.getBody(); FrameBodyTRCK oldBody = (FrameBodyTRCK) nextFrame.getBody(); if (newBody.getTrackNo() != null && newBody.getTrackNo() > 0) { oldBody.setTrackNo(newBody.getTrackNo()); } if (newBody.getTrackTotal() != null && newBody.getTrackTotal() > 0) { oldBody.setTrackTotal(newBody.getTrackTotal()); } return; } //Just grab any additional info from new TPOS Frame and add to the existing one else if (newFrame.getBody() instanceof FrameBodyTPOS) { FrameBodyTPOS newBody = (FrameBodyTPOS) newFrame.getBody(); FrameBodyTPOS oldBody = (FrameBodyTPOS) nextFrame.getBody(); Integer newDiscNo = newBody.getDiscNo(); if ((newDiscNo != null) && (newDiscNo > 0)) { oldBody.setDiscNo(newDiscNo); } Integer newDiscTotal = newBody.getDiscTotal(); if ((newDiscTotal != null) && (newDiscTotal > 0)) { oldBody.setDiscTotal(newDiscTotal); } return; } else if (newFrame.getBody() instanceof FrameBodyIPLS) { FrameBodyIPLS frameBody = (FrameBodyIPLS) newFrame.getBody(); FrameBodyIPLS existingFrameBody = (FrameBodyIPLS) nextFrame.getBody(); existingFrameBody.addPair(frameBody.getText()); return; } else if (newFrame.getBody() instanceof FrameBodyTIPL) { FrameBodyTIPL frameBody = (FrameBodyTIPL) newFrame.getBody(); FrameBodyTIPL existingFrameBody = (FrameBodyTIPL) nextFrame.getBody(); existingFrameBody.addPair(frameBody.getText()); return; } } if(!getID3Frames().isMultipleAllowed(newFrame.getId())) { frameMap.put(newFrame.getId(), newFrame); } else { //No match found so addField new one frames.add(newFrame); frameMap.put(newFrame.getId(), frames); } } /** * Handles adding of a new field that's shares a frame with other fields, so modifies the existing frame rather * than creating an ew frame for these special cases * * @param list * @param frameMap * @param existingFrame * @param frame */ private void addNewFrameOrAddField(List list, HashMap frameMap, AbstractID3v2Frame existingFrame, AbstractID3v2Frame frame) { /** * If the frame is a TextInformation (but not the TXXX) frame then we just add an extra string to the existing frame * otherwise we create a new frame */ if (frame.getBody() instanceof AbstractFrameBodyTextInfo && !(frame.getBody() instanceof FrameBodyTXXX)) { AbstractFrameBodyTextInfo frameBody = (AbstractFrameBodyTextInfo) frame.getBody(); AbstractFrameBodyTextInfo existingFrameBody = (AbstractFrameBodyTextInfo) existingFrame.getBody(); existingFrameBody.addTextValue(frameBody.getText()); } else if (frame.getBody() instanceof FrameBodyIPLS) { FrameBodyIPLS frameBody = (FrameBodyIPLS) frame.getBody(); FrameBodyIPLS existingFrameBody = (FrameBodyIPLS) existingFrame.getBody(); existingFrameBody.addPair(frameBody.getText()); } else if (frame.getBody() instanceof FrameBodyTIPL) { FrameBodyTIPL frameBody = (FrameBodyTIPL) frame.getBody(); FrameBodyTIPL existingFrameBody = (FrameBodyTIPL) existingFrame.getBody(); existingFrameBody.addPair(frameBody.getText()); } else { if (list.size() == 0) { list.add(existingFrame); list.add(frame); frameMap.put(frame.getId(), list); } else { list.add(frame); } } } /** * @param field * @throws FieldDataInvalidException */ public void setField(TagField field) throws FieldDataInvalidException { if (!(field instanceof AbstractID3v2Frame)) { throw new FieldDataInvalidException("Field " + field + " is not of type AbstractID3v2Frame"); } AbstractID3v2Frame newFrame = (AbstractID3v2Frame) field; Object obj = frameMap.get(field.getId()); //If no frame of this type exist or if multiples are not allowed if (obj == null) { frameMap.put(field.getId(), field); } //frame of this type already exists else if (obj instanceof AbstractID3v2Frame) { List frames = new ArrayList(); frames.add((AbstractID3v2Frame) obj); mergeDuplicateFrames(newFrame, frames); } //Multiple frames of this type already exist else if (obj instanceof List) { mergeDuplicateFrames(newFrame, (List) obj); } } /** * Add new field *

* There is a special handling if adding another text field of the same type, in this case the value will * be appended to the existing field, separated by the null character. * * @param field * @throws FieldDataInvalidException */ public void addField(TagField field) throws FieldDataInvalidException { if (field == null) { return; } if (!(field instanceof AbstractID3v2Frame)) { throw new FieldDataInvalidException("Field " + field + " is not of type AbstractID3v2Frame"); } AbstractID3v2Frame frame = (AbstractID3v2Frame) field; Object o = frameMap.get(field.getId()); //No frame of this type if (o == null) { frameMap.put(field.getId(), field); } //There are already frames of this type else if (o instanceof List) { List list = (List) o; addNewFrameOrAddField(list, frameMap, null, frame); } //One frame exists, we are adding another so may need to convert to list else { AbstractID3v2Frame existingFrame = (AbstractID3v2Frame) o; List list = new ArrayList(); addNewFrameOrAddField(list, frameMap, existingFrame, frame); } } /** * Used for setting multiple frames for a single frame Identifier *

* Warning if frame(s) already exists for this identifier thay are overwritten *

* TODO needs to ensure do not add an invalid frame for this tag * * @param identifier * @param multiFrame */ public void setFrame(String identifier, List multiFrame) { logger.finest("Adding " + multiFrame.size() + " frames for " + identifier); frameMap.put(identifier, multiFrame); } /** * Return the number of frames in this tag of a particular type, multiple frames * of the same time will only be counted once * * @return a count of different frames */ /* public int getFrameCount() { if (frameMap == null) { return 0; } else { return frameMap.size(); } } */ /** * Return all frames which start with the identifier, this * can be more than one which is useful if trying to retrieve * similar frames e.g TIT1,TIT2,TIT3 ... and don't know exactly * which ones there are. *

* Warning the match is only done against the identifier so if a tag contains a frame with an unsupported body * but happens to have an identifier that is valid for another version of the tag it will be returned. * * @param identifier * @return an iterator of all the frames starting with a particular identifier */ public Iterator getFrameOfType(String identifier) { Iterator iterator = frameMap.keySet().iterator(); HashSet result = new HashSet(); String key; while (iterator.hasNext()) { key = iterator.next(); if (key.startsWith(identifier)) { result.add(frameMap.get(key)); } } return result.iterator(); } /** * Delete Tag * * @param file to delete the tag from * @throws IOException if problem accessing the file *

*/ //TODO should clear all data and preferably recover lost space and go upto end of mp3s public void delete(RandomAccessFile file) throws IOException { // this works by just erasing the "ID3" tag at the beginning // of the file byte[] buffer = new byte[FIELD_TAGID_LENGTH]; //Read into Byte Buffer final FileChannel fc = file.getChannel(); fc.position(); ByteBuffer byteBuffer = ByteBuffer.allocate(TAG_HEADER_LENGTH); fc.read(byteBuffer, 0); byteBuffer.flip(); if (seek(byteBuffer)) { file.seek(0L); file.write(buffer); } } /** * Is this tag equivalent to another * * @param obj to test for equivalence * @return true if they are equivalent */ public boolean equals(Object obj) { if (!(obj instanceof AbstractID3v2Tag)) { return false; } AbstractID3v2Tag object = (AbstractID3v2Tag) obj; return this.frameMap.equals(object.frameMap) && super.equals(obj); } /** * Return the frames in the order they were added * * @return and iterator of the frmaes/list of multi value frames */ public Iterator iterator() { return frameMap.values().iterator(); } /** * Remove frame(s) with this identifier from tag * * @param identifier frameId to look for */ public void removeFrame(String identifier) { logger.finest("Removing frame with identifier:" + identifier); frameMap.remove(identifier); } /** * Remove all frame(s) which have an unsupported body, in other words * remove all frames that are not part of the standard frameSet for * this tag */ public void removeUnsupportedFrames() { for (Iterator i = iterator(); i.hasNext();) { Object o = i.next(); if (o instanceof AbstractID3v2Frame) { if (((AbstractID3v2Frame) o).getBody() instanceof FrameBodyUnsupported) { logger.finest("Removing frame" + ((AbstractID3v2Frame) o).getIdentifier()); i.remove(); } } } } /** * Remove any frames starting with this identifier from tag * * @param identifier start of frameId to look for */ public void removeFrameOfType(String identifier) { //First fine matching keys HashSet result = new HashSet(); for (Object match : frameMap.keySet()) { String key = (String) match; if (key.startsWith(identifier)) { result.add(key); } } //Then deleteField outside of loop to prevent concurrent modificatioon eception if there are two keys //with the same id for (String match : result) { logger.finest("Removing frame with identifier:" + match + "because starts with:" + identifier); frameMap.remove(match); } } /** * Write tag to file. * * @param file * @param audioStartByte * @throws IOException TODO should be abstract */ public void write(File file, long audioStartByte) throws IOException { } /** * Get file lock for writing too file *

* TODO:this appears to have little effect on Windows Vista * * @param fileChannel * @param filePath * @return lock or null if locking is not supported * @throws IOException if unable to get lock because already locked by another program * @throws java.nio.channels.OverlappingFileLockException * if already locked by another thread in the same VM, we dont catch this * because indicates a programming error */ protected FileLock getFileLockForWriting(FileChannel fileChannel, String filePath) throws IOException { logger.finest("locking fileChannel for " + filePath); FileLock fileLock; try { fileLock = fileChannel.tryLock(); } //Assumes locking is not supported on this platform so just returns null catch (IOException exception) { return null; } //Couldnt getFields lock because file is already locked by another application if (fileLock == null) { throw new IOException(ErrorMessage.GENERAL_WRITE_FAILED_FILE_LOCKED.getMsg(filePath)); } return fileLock; } /** * Write tag to file. * * @param file * @throws IOException TODO should be abstract */ public void write(RandomAccessFile file) throws IOException { } /** * Write tag to channel. * * @param channel * @throws IOException TODO should be abstract */ public void write(WritableByteChannel channel) throws IOException { } /** * Checks to see if the file contains an ID3tag and if so return its size as reported in * the tag header and return the size of the tag (including header), if no such tag exists return * zero. * * @param file * @return the end of the tag in the file or zero if no tag exists. * @throws java.io.IOException */ public static long getV2TagSizeIfExists(File file) throws IOException { FileInputStream fis = null; FileChannel fc = null; ByteBuffer bb = null; try { //Files fis = new FileInputStream(file); fc = fis.getChannel(); //Read possible Tag header Byte Buffer bb = ByteBuffer.allocate(TAG_HEADER_LENGTH); fc.read(bb); bb.flip(); if (bb.limit() < (TAG_HEADER_LENGTH)) { return 0; } } finally { if (fc != null) { fc.close(); } if (fis != null) { fis.close(); } } //ID3 identifier byte[] tagIdentifier = new byte[FIELD_TAGID_LENGTH]; bb.get(tagIdentifier, 0, FIELD_TAGID_LENGTH); if (!(Arrays.equals(tagIdentifier, TAG_ID))) { return 0; } //Is it valid Major Version byte majorVersion = bb.get(); if ((majorVersion != ID3v22Tag.MAJOR_VERSION) && (majorVersion != ID3v23Tag.MAJOR_VERSION) && (majorVersion != ID3v24Tag.MAJOR_VERSION)) { return 0; } //Skip Minor Version bb.get(); //Skip Flags bb.get(); //Get size as recorded in frame header int frameSize = ID3SyncSafeInteger.bufferToValue(bb); //addField header size to frame size frameSize += TAG_HEADER_LENGTH; return frameSize; } /** * Does a tag of the correct version exist in this file. * * @param byteBuffer to search through * @return true if tag exists. */ public boolean seek(ByteBuffer byteBuffer) { byteBuffer.rewind(); logger.info("ByteBuffer pos:" + byteBuffer.position() + ":limit" + byteBuffer.limit() + ":cap" + byteBuffer.capacity()); byte[] tagIdentifier = new byte[FIELD_TAGID_LENGTH]; byteBuffer.get(tagIdentifier, 0, FIELD_TAGID_LENGTH); if (!(Arrays.equals(tagIdentifier, TAG_ID))) { return false; } //Major Version if (byteBuffer.get() != getMajorVersion()) { return false; } //Minor Version return byteBuffer.get() == getRevision(); } /** * This method determines the total tag size taking into account * where the audio file starts, the size of the tagging data and * user options for defining how tags should shrink or grow. * * @param tagSize * @param audioStart * @return */ protected int calculateTagSize(int tagSize, int audioStart) { /** We can fit in the tag so no adjustments required */ if (tagSize <= audioStart) { return audioStart; } /** There is not enough room as we need to move the audio file we might * as well increase it more than neccessary for future changes */ return tagSize + TAG_SIZE_INCREMENT; } /** * Adjust the length of the padding at the beginning of the MP3 file, this is only called when there is currently * not enough space before the start of the audio to write the tag. *

* A new file will be created with enough size to fit the ID3v2 tag. * The old file will be deleted, and the new file renamed. * * @param paddingSize This is total size required to store tag before audio * @param audioStart * @param file The file to adjust the padding length of * @throws FileNotFoundException if the file exists but is a directory * rather than a regular file or cannot be opened for any other * reason * @throws IOException on any I/O error */ public void adjustPadding(File file, int paddingSize, long audioStart) throws FileNotFoundException, IOException { logger.finer("Need to move audio file to accomodate tag"); FileChannel fcIn = null; FileChannel fcOut; //Create buffer holds the necessary padding ByteBuffer paddingBuffer = ByteBuffer.wrap(new byte[paddingSize]); //Create Temporary File and write channel, make sure it is locked File paddedFile; try { paddedFile = File.createTempFile(Utils.getMinBaseFilenameAllowedForTempFile(file), ".new", file.getParentFile()); logger.finest("Created temp file:" + paddedFile.getName() + " for " + file.getName()); } //Vista:Can occur if have Write permission on folder this file would be created in Denied catch (IOException ioe) { logger.log(Level.SEVERE, ioe.getMessage(), ioe); if (ioe.getMessage().equals(FileSystemMessage.ACCESS_IS_DENIED.getMsg())) { logger.severe(ErrorMessage.GENERAL_WRITE_FAILED_TO_CREATE_TEMPORARY_FILE_IN_FOLDER.getMsg(file.getName(), file.getParentFile().getPath())); throw new UnableToCreateFileException(ErrorMessage.GENERAL_WRITE_FAILED_TO_CREATE_TEMPORARY_FILE_IN_FOLDER.getMsg(file.getName(), file.getParentFile().getPath())); } else { logger.severe(ErrorMessage.GENERAL_WRITE_FAILED_TO_CREATE_TEMPORARY_FILE_IN_FOLDER.getMsg(file.getName(), file.getParentFile().getPath())); throw new UnableToCreateFileException(ErrorMessage.GENERAL_WRITE_FAILED_TO_CREATE_TEMPORARY_FILE_IN_FOLDER.getMsg(file.getName(), file.getParentFile().getPath())); } } try { fcOut = new FileOutputStream(paddedFile).getChannel(); } //Vista:Can occur if have special permission Create Folder/Append Data denied catch (FileNotFoundException ioe) { logger.log(Level.SEVERE, ioe.getMessage(), ioe); logger.severe(ErrorMessage.GENERAL_WRITE_FAILED_TO_MODIFY_TEMPORARY_FILE_IN_FOLDER.getMsg(file.getName(), file.getParentFile().getPath())); throw new UnableToModifyFileException(ErrorMessage.GENERAL_WRITE_FAILED_TO_MODIFY_TEMPORARY_FILE_IN_FOLDER.getMsg(file.getName(), file.getParentFile().getPath())); } try { //Create read channel from original file //TODO lock so cant be modified by anything else whilst reading from it ? fcIn = new FileInputStream(file).getChannel(); //Write padding to new file (this is where the tag will be written to later) long written = fcOut.write(paddingBuffer); //Write rest of file starting from audio logger.finer("Copying:" + (file.length() - audioStart) + "bytes"); //If the amount to be copied is very large we split into 10MB lumps to try and avoid //out of memory errors long audiolength = file.length() - audioStart; if (audiolength <= MAXIMUM_WRITABLE_CHUNK_SIZE) { long written2 = fcIn.transferTo(audioStart, audiolength, fcOut); logger.finer("Written padding:" + written + " Data:" + written2); if (written2 != audiolength) { throw new RuntimeException(ErrorMessage.MP3_UNABLE_TO_ADJUST_PADDING.getMsg(audiolength, written2)); } } else { long noOfChunks = audiolength / MAXIMUM_WRITABLE_CHUNK_SIZE; long lastChunkSize = audiolength % MAXIMUM_WRITABLE_CHUNK_SIZE; long written2 = 0; for (int i = 0; i < noOfChunks; i++) { written2 += fcIn.transferTo(audioStart + (i * MAXIMUM_WRITABLE_CHUNK_SIZE), MAXIMUM_WRITABLE_CHUNK_SIZE, fcOut); } written2 += fcIn.transferTo(audioStart + (noOfChunks * MAXIMUM_WRITABLE_CHUNK_SIZE), lastChunkSize, fcOut); logger.finer("Written padding:" + written + " Data:" + written2); if (written2 != audiolength) { throw new RuntimeException(ErrorMessage.MP3_UNABLE_TO_ADJUST_PADDING.getMsg(audiolength, written2)); } } //Store original modification time long lastModified = file.lastModified(); //Close Channels and locks if (fcIn != null) { if (fcIn.isOpen()) { fcIn.close(); } } if (fcOut != null) { if (fcOut.isOpen()) { fcOut.close(); } } //Replace file with paddedFile replaceFile(file, paddedFile); //Update modification time //TODO is this the right file ? paddedFile.setLastModified(lastModified); } finally { try { //Whatever happens ensure all locks and channels are closed/released if (fcIn != null) { if (fcIn.isOpen()) { fcIn.close(); } } if (fcOut != null) { if (fcOut.isOpen()) { fcOut.close(); } } } catch (Exception e) { logger.log(Level.WARNING, "Problem closing channels and locks:" + e.getMessage(), e); } } } /** * Write the data from the buffer to the file * * @param file * @param headerBuffer * @param bodyByteBuffer * @param padding * @param sizeIncPadding * @param audioStartLocation * @throws IOException */ protected void writeBufferToFile(File file, ByteBuffer headerBuffer, byte[] bodyByteBuffer, int padding, int sizeIncPadding, long audioStartLocation) throws IOException { FileChannel fc = null; FileLock fileLock = null; //We need to adjust location of audio file if true if (sizeIncPadding > audioStartLocation) { logger.finest("Adjusting Padding"); adjustPadding(file, sizeIncPadding, audioStartLocation); } try { fc = new RandomAccessFile(file, "rws").getChannel(); fileLock = getFileLockForWriting(fc, file.getPath()); fc.write(headerBuffer); fc.write(ByteBuffer.wrap(bodyByteBuffer)); fc.write(ByteBuffer.wrap(new byte[padding])); } catch (FileNotFoundException fe) { logger.log(Level.SEVERE, getLoggingFilename() + fe.getMessage(), fe); if (fe.getMessage().equals(FileSystemMessage.ACCESS_IS_DENIED.getMsg())) { logger.severe(ErrorMessage.GENERAL_WRITE_FAILED_TO_OPEN_FILE_FOR_EDITING.getMsg(file.getPath())); throw new UnableToModifyFileException(ErrorMessage.GENERAL_WRITE_FAILED_TO_OPEN_FILE_FOR_EDITING.getMsg(file.getPath())); } else { logger.severe(ErrorMessage.GENERAL_WRITE_FAILED_TO_OPEN_FILE_FOR_EDITING.getMsg(file.getPath())); throw new UnableToCreateFileException(ErrorMessage.GENERAL_WRITE_FAILED_TO_OPEN_FILE_FOR_EDITING.getMsg(file.getPath())); } } catch (IOException ioe) { logger.log(Level.SEVERE, getLoggingFilename() + ioe.getMessage(), ioe); if (ioe.getMessage().equals(FileSystemMessage.ACCESS_IS_DENIED.getMsg())) { logger.severe(ErrorMessage.GENERAL_WRITE_FAILED_TO_OPEN_FILE_FOR_EDITING.getMsg(file.getParentFile().getPath())); throw new UnableToModifyFileException(ErrorMessage.GENERAL_WRITE_FAILED_TO_OPEN_FILE_FOR_EDITING.getMsg(file.getParentFile().getPath())); } else { logger.severe(ErrorMessage.GENERAL_WRITE_FAILED_TO_OPEN_FILE_FOR_EDITING.getMsg(file.getParentFile().getPath())); throw new UnableToCreateFileException(ErrorMessage.GENERAL_WRITE_FAILED_TO_OPEN_FILE_FOR_EDITING.getMsg(file.getParentFile().getPath())); } } finally { if (fc != null) { if (fileLock != null) { fileLock.release(); } fc.close(); } } } /** * Replace originalFile with the contents of newFile *

* Both files must exist in the same folder so that there are no problems with fileystem mount points * * @param newFile * @param originalFile * @throws IOException */ private void replaceFile(File originalFile, File newFile) throws IOException { boolean renameOriginalResult; //Rename Original File to make a backup in case problem with new file File originalFileBackup = new File(originalFile.getAbsoluteFile().getParentFile().getPath(), AudioFile.getBaseFilename(originalFile) + ".old"); //If already exists modify the suffix int count = 1; while (originalFileBackup.exists()) { originalFileBackup = new File(originalFile.getAbsoluteFile().getParentFile().getPath(), AudioFile.getBaseFilename(originalFile) + ".old" + count); count++; } renameOriginalResult = originalFile.renameTo(originalFileBackup); if (!renameOriginalResult) { logger.warning(ErrorMessage.GENERAL_WRITE_FAILED_TO_RENAME_ORIGINAL_FILE_TO_BACKUP.getMsg(originalFile.getAbsolutePath(), originalFileBackup.getName())); throw new UnableToRenameFileException(ErrorMessage.GENERAL_WRITE_FAILED_TO_RENAME_ORIGINAL_FILE_TO_BACKUP.getMsg(originalFile.getAbsolutePath(), originalFileBackup.getName())); } //Rename new Temporary file to the final file boolean renameResult = newFile.renameTo(originalFile); if (!renameResult) { //Renamed failed so lets do some checks rename the backup back to the original file //New File doesnt exist if (!newFile.exists()) { logger.warning(ErrorMessage.GENERAL_WRITE_FAILED_NEW_FILE_DOESNT_EXIST.getMsg(newFile.getAbsolutePath())); } //Rename the backup back to the original renameOriginalResult = originalFileBackup.renameTo(originalFile); if (!renameOriginalResult) { //TODO now if this happens we are left with testfile.old instead of testfile.mp3 logger.warning(ErrorMessage.GENERAL_WRITE_FAILED_TO_RENAME_ORIGINAL_BACKUP_TO_ORIGINAL.getMsg(originalFileBackup.getAbsolutePath(), originalFile.getName())); } logger.warning(ErrorMessage.GENERAL_WRITE_FAILED_TO_RENAME_TO_ORIGINAL_FILE.getMsg(originalFile.getAbsolutePath(), newFile.getName())); throw new UnableToRenameFileException(ErrorMessage.GENERAL_WRITE_FAILED_TO_RENAME_TO_ORIGINAL_FILE.getMsg(originalFile.getAbsolutePath(), newFile.getName())); } else { //Rename was okay so we can now deleteField the backup of the original boolean deleteResult = originalFileBackup.delete(); if (!deleteResult) { //Not a disaster but can't deleteField the backup so make a warning logger.warning(ErrorMessage.GENERAL_WRITE_WARNING_UNABLE_TO_DELETE_BACKUP_FILE.getMsg(originalFileBackup.getAbsolutePath())); } } } /* * Copy framne into map, whilst accounting for multiple frame of same type which can occur even if there were * not frames of the same type in the original tag */ protected void copyFrameIntoMap(String id, AbstractID3v2Frame newFrame) { if (frameMap.containsKey(newFrame.getIdentifier())) { Object o = frameMap.get(newFrame.getIdentifier()); if (o instanceof AbstractID3v2Frame) { List list = new ArrayList(); list.add((AbstractID3v2Frame) o); list.add(newFrame); frameMap.put(newFrame.getIdentifier(), list); } else { List list = (List) o; list.add(newFrame); } } else { frameMap.put(newFrame.getIdentifier(), newFrame); } } /** * Add frame to the frame map * * @param frameId * @param next */ protected void loadFrameIntoMap(String frameId, AbstractID3v2Frame next) { if (next.getBody() instanceof FrameBodyEncrypted) { loadFrameIntoSpecifiedMap(encryptedFrameMap, frameId, next); } else { loadFrameIntoSpecifiedMap(frameMap, frameId, next); } } /** * Decides what to with the frame that has just been read from file. * If the frame is an allowable duplicate frame and is a duplicate we add all * frames into an ArrayList and add the ArrayList to the HashMap. if not allowed * to be duplicate we store the number of bytes in the duplicateBytes variable and discard * the frame itself. * * @param frameId * @param next */ protected void loadFrameIntoSpecifiedMap(HashMap map, String frameId, AbstractID3v2Frame next) { if ((ID3v24Frames.getInstanceOf().isMultipleAllowed(frameId)) || (ID3v23Frames.getInstanceOf().isMultipleAllowed(frameId)) || (ID3v22Frames.getInstanceOf().isMultipleAllowed(frameId))) { //If a frame already exists of this type if (map.containsKey(frameId)) { Object o = map.get(frameId); if (o instanceof ArrayList) { ArrayList multiValues = (ArrayList) o; multiValues.add(next); logger.finer("Adding Multi Frame(1)" + frameId); } else { ArrayList multiValues = new ArrayList(); multiValues.add((AbstractID3v2Frame) o); multiValues.add(next); map.put(frameId, multiValues); logger.finer("Adding Multi Frame(2)" + frameId); } } else { logger.finer("Adding Multi FrameList(3)" + frameId); map.put(frameId, next); } } //If duplicate frame just stores the name of the frame and the number of bytes the frame contains else if (map.containsKey(frameId)) { logger.warning("Ignoring Duplicate Frame" + frameId); //If we have multiple duplicate frames in a tag separate them with semicolons if (this.duplicateFrameId.length() > 0) { this.duplicateFrameId += ";"; } this.duplicateFrameId += frameId; this.duplicateBytes += ((AbstractID3v2Frame) frameMap.get(frameId)).getSize(); } else { logger.finer("Adding Frame" + frameId); map.put(frameId, next); } } /** * Return tag size based upon the sizes of the tags rather than the physical * no of bytes between start of ID3Tag and start of Audio Data.Should be extended * by subclasses to include header. * * @return size of the tag */ public int getSize() { int size = 0; Iterator iterator = frameMap.values().iterator(); AbstractID3v2Frame frame; while (iterator.hasNext()) { Object o = iterator.next(); if (o instanceof AbstractID3v2Frame) { frame = (AbstractID3v2Frame) o; size += frame.getSize(); } else { ArrayList multiFrames = (ArrayList) o; for (ListIterator li = multiFrames.listIterator(); li.hasNext();) { frame = li.next(); size += frame.getSize(); } } } return size; } /** * Write all the frames to the byteArrayOutputStream *

*

Currently Write all frames, defaults to the order in which they were loaded, newly * created frames will be at end of tag. * * @return ByteBuffer Contains all the frames written within the tag ready for writing to file * @throws IOException */ protected ByteArrayOutputStream writeFramesToBuffer() throws IOException { ByteArrayOutputStream bodyBuffer = new ByteArrayOutputStream(); writeFramesToBufferStream(frameMap, bodyBuffer); writeFramesToBufferStream(encryptedFrameMap, bodyBuffer); return bodyBuffer; } /** * Write frames in map to bodyBuffer * * @param map * @param bodyBuffer * @throws IOException */ private void writeFramesToBufferStream(Map map, ByteArrayOutputStream bodyBuffer) throws IOException { //Sort keys into Preferred Order TreeSet sortedWriteOrder = new TreeSet(getPreferredFrameOrderComparator()); sortedWriteOrder.addAll(map.keySet()); AbstractID3v2Frame frame; for (String id : sortedWriteOrder) { Object o = map.get(id); if (o instanceof AbstractID3v2Frame) { frame = (AbstractID3v2Frame) o; frame.setLoggingFilename(getLoggingFilename()); frame.write(bodyBuffer); } else { List multiFrames = (List) o; for (AbstractID3v2Frame nextFrame : multiFrames) { nextFrame.setLoggingFilename(getLoggingFilename()); nextFrame.write(bodyBuffer); } } } } /** * @return comparator used to order frames in preferred order for writing to file * so that most important frames are written first. */ public abstract Comparator getPreferredFrameOrderComparator(); public void createStructure() { createStructureHeader(); createStructureBody(); } public void createStructureHeader() { MP3File.getStructureFormatter().addElement(TYPE_DUPLICATEBYTES, this.duplicateBytes); MP3File.getStructureFormatter().addElement(TYPE_DUPLICATEFRAMEID, this.duplicateFrameId); MP3File.getStructureFormatter().addElement(TYPE_EMPTYFRAMEBYTES, this.emptyFrameBytes); MP3File.getStructureFormatter().addElement(TYPE_FILEREADSIZE, this.fileReadSize); MP3File.getStructureFormatter().addElement(TYPE_INVALIDFRAMES, this.invalidFrames); } public void createStructureBody() { MP3File.getStructureFormatter().openHeadingElement(TYPE_BODY, ""); AbstractID3v2Frame frame; for (Object o : frameMap.values()) { if (o instanceof AbstractID3v2Frame) { frame = (AbstractID3v2Frame) o; frame.createStructure(); } else { ArrayList multiFrames = (ArrayList) o; for (ListIterator li = multiFrames.listIterator(); li.hasNext();) { frame = li.next(); frame.createStructure(); } } } MP3File.getStructureFormatter().closeHeadingElement(TYPE_BODY); } /** * Retrieve the values that exists for this id3 frame id */ public List getFields(String id) throws KeyNotFoundException { Object o = getFrame(id); if (o == null) { return new ArrayList(); } else if (o instanceof List) { //TODO should return copy return (List) o; } else if (o instanceof AbstractID3v2Frame) { List list = new ArrayList(); list.add((TagField) o); return list; } else { throw new RuntimeException("Found entry in frameMap that was not a frame or a list:" + o); } } /** * Create Frame of correct ID3 version with the specified id * * @param id * @return */ public abstract AbstractID3v2Frame createFrame(String id); //TODO public boolean hasCommonFields() { return true; } /** * Does this tag contain a field with the specified id * * @see org.jaudiotagger.tag.Tag#hasField(java.lang.String) */ public boolean hasField(String id) { return getFields(id).size() != 0; } /** * Is this tag empty * * @see org.jaudiotagger.tag.Tag#isEmpty() */ public boolean isEmpty() { return frameMap.size() == 0; } /** * @return iterator of all fields, multiple values for the same Id (e.g multiple TXXX frames) count as separate * fields */ public Iterator getFields() { //Iterator of each different frameId in this tag final Iterator> it = this.frameMap.entrySet().iterator(); //Iterator used by hasNext() so doesn't effect next() final Iterator> itHasNext = this.frameMap.entrySet().iterator(); return new Iterator() { Map.Entry latestEntry = null; //this iterates through frames through for a particular frameId private Iterator fieldsIt; private void changeIt() { if (!it.hasNext()) { return; } while (it.hasNext()) { Map.Entry e = it.next(); latestEntry = itHasNext.next(); if (e.getValue() instanceof List) { List l = (List) e.getValue(); //If list is empty (which it shouldn't be) we skip over this entry if (l.size() == 0) { continue; } else { fieldsIt = l.iterator(); break; } } else { //TODO must be a better way List l = new ArrayList(); l.add((TagField) e.getValue()); fieldsIt = l.iterator(); break; } } } //TODO assumes if have entry its valid, but what if empty list but very different to check this //without causing a side effect on next() so leaving for now public boolean hasNext() { //Check Current frameId, does it contain more values if (fieldsIt != null) { if (fieldsIt.hasNext()) { return true; } } //No remaining entries return false if (!itHasNext.hasNext()) { return false; } //Issue #236 //TODO assumes if have entry its valid, but what if empty list but very different to check this //without causing a side effect on next() so leaving for now return itHasNext.hasNext(); } public TagField next() { //Hasn't been initialized yet if (fieldsIt == null) { changeIt(); } if (fieldsIt != null) { //Go to the end of the run if (!fieldsIt.hasNext()) { changeIt(); } } if (fieldsIt == null) { throw new NoSuchElementException(); } return fieldsIt.next(); } public void remove() { fieldsIt.remove(); } }; } /** * Count number of frames/fields in this tag * * @return */ public int getFieldCount() { Iterator it = getFields(); int count = 0; //Done this way because it.hasNext() incorrectly counts empty list //whereas it.next() works correctly try { while (true) { TagField next = it.next(); count++; } } catch (NoSuchElementException nse) { //this is thrown when no more elements } return count; } /** * Return count of fields, this considers a text frame with two null separated values as two fields, if you want * a count of frames @see getFrameCount * * @return count of fields */ public int getFieldCountIncludingSubValues() { Iterator it = getFields(); int count = 0; //Done this way because it.hasNext() incorrectly counts empty list //whereas it.next() works correctly try { while (true) { TagField next = it.next(); if (next instanceof AbstractID3v2Frame) { AbstractID3v2Frame frame = (AbstractID3v2Frame) next; if ((frame.getBody() instanceof AbstractFrameBodyTextInfo) && !(frame.getBody() instanceof FrameBodyTXXX)) { AbstractFrameBodyTextInfo frameBody = (AbstractFrameBodyTextInfo) frame.getBody(); count += frameBody.getNumberOfValues(); continue; } } count++; } } catch (NoSuchElementException nse) { //this is thrown when no more elements } return count; } //TODO is this a special field? public boolean setEncoding(String enc) throws FieldDataInvalidException { throw new UnsupportedOperationException("Not Implemented Yet"); } /** * Retrieve the first value that exists for this generic key * * @param genericKey * @return */ public String getFirst(FieldKey genericKey) throws KeyNotFoundException { return getValue(genericKey, 0); } /** * Retrieve the mth value that exists in the nth frame for this generic key * * @param genericKey * @param n the index of the frame * @param m * @return */ public String getSubValue(FieldKey genericKey, int n, int m) { String wholeValue = getValue(genericKey, n); List values = TextEncodedStringSizeTerminated.splitByNullSeperator(wholeValue); if (values.size() > m) { return values.get(m); } return ""; } /** * Retrieve the value that exists for this generic key and this index *

* Have to do some special mapping for certain generic keys because they share frame * with another generic key. * * @param genericKey * @return */ public String getValue(FieldKey genericKey, int index) throws KeyNotFoundException { if (genericKey == null) { throw new KeyNotFoundException(); } FrameAndSubId frameAndSubId = getFrameAndSubIdFromGenericKey(genericKey); List fields = getFields(genericKey); if (fields != null && fields.size() > index) { AbstractID3v2Frame frame = (AbstractID3v2Frame) fields.get(index); if (frame != null) { if (genericKey == FieldKey.TRACK) { return String.valueOf(((FrameBodyTRCK) frame.getBody()).getTrackNo()); } else if (genericKey == FieldKey.TRACK_TOTAL) { return String.valueOf(((FrameBodyTRCK) frame.getBody()).getTrackTotal()); } else if (genericKey == FieldKey.DISC_NO) { return String.valueOf(((FrameBodyTPOS) frame.getBody()).getDiscNo()); } else if (genericKey == FieldKey.DISC_TOTAL) { return String.valueOf(((FrameBodyTPOS) frame.getBody()).getDiscTotal()); } else if (genericKey == FieldKey.RATING) { return String.valueOf(((FrameBodyPOPM) frame.getBody()).getRating()); } else { return doGetValueAtIndex(frameAndSubId, index); } } else { return ""; } } return ""; } /** * Create a new TagField *

* Only textual data supported at the moment. The genericKey will be mapped * to the correct implementation key and return a TagField. * * @param genericKey is the generic key * @param value to store * @return */ public TagField createField(FieldKey genericKey, String value) throws KeyNotFoundException, FieldDataInvalidException { if (genericKey == null) { throw new KeyNotFoundException(); } FrameAndSubId formatKey = getFrameAndSubIdFromGenericKey(genericKey); if (genericKey == FieldKey.TRACK) { AbstractID3v2Frame frame = createFrame(formatKey.getFrameId()); FrameBodyTRCK framebody = (FrameBodyTRCK) frame.getBody(); framebody.setTrackNo(Integer.parseInt(value)); return frame; } else if (genericKey == FieldKey.TRACK_TOTAL) { AbstractID3v2Frame frame = createFrame(formatKey.getFrameId()); FrameBodyTRCK framebody = (FrameBodyTRCK) frame.getBody(); framebody.setTrackTotal(Integer.parseInt(value)); return frame; } else if (genericKey == FieldKey.DISC_NO) { AbstractID3v2Frame frame = createFrame(formatKey.getFrameId()); FrameBodyTPOS framebody = (FrameBodyTPOS) frame.getBody(); framebody.setDiscNo(Integer.parseInt(value)); return frame; } else if (genericKey == FieldKey.DISC_TOTAL) { AbstractID3v2Frame frame = createFrame(formatKey.getFrameId()); FrameBodyTPOS framebody = (FrameBodyTPOS) frame.getBody(); framebody.setDiscTotal(Integer.parseInt(value)); return frame; } else { return doCreateTagField(formatKey, value); } } /** * Create Frame for Id3 Key *

* Only textual data supported at the moment, should only be used with frames that * support a simple string argument. * * @param formatKey * @param value * @return * @throws KeyNotFoundException * @throws FieldDataInvalidException */ protected TagField doCreateTagField(FrameAndSubId formatKey, String value) throws KeyNotFoundException, FieldDataInvalidException { AbstractID3v2Frame frame = createFrame(formatKey.getFrameId()); if (frame.getBody() instanceof FrameBodyUFID) { ((FrameBodyUFID) frame.getBody()).setOwner(formatKey.getSubId()); try { ((FrameBodyUFID) frame.getBody()).setUniqueIdentifier(value.getBytes("ISO-8859-1")); } catch (UnsupportedEncodingException uee) { //This will never happen because we are using a charset supported on all platforms //but just in case throw new RuntimeException("When encoding UFID charset ISO-8859-1 was deemed unsupported"); } } else if (frame.getBody() instanceof FrameBodyTXXX) { ((FrameBodyTXXX) frame.getBody()).setDescription(formatKey.getSubId()); ((FrameBodyTXXX) frame.getBody()).setText(value); } else if (frame.getBody() instanceof FrameBodyWXXX) { ((FrameBodyWXXX) frame.getBody()).setDescription(formatKey.getSubId()); ((FrameBodyWXXX) frame.getBody()).setUrlLink(value); } else if (frame.getBody() instanceof FrameBodyCOMM) { //Set description if set if (formatKey.getSubId() != null) { ((FrameBodyCOMM) frame.getBody()).setDescription(formatKey.getSubId()); //Special Handling for Media Monkey Compatability if (((FrameBodyCOMM) frame.getBody()).isMediaMonkeyFrame()) { ((FrameBodyCOMM) frame.getBody()).setLanguage(Languages.MEDIA_MONKEY_ID); } } ((FrameBodyCOMM) frame.getBody()).setText(value); } else if (frame.getBody() instanceof FrameBodyUSLT) { ((FrameBodyUSLT) frame.getBody()).setDescription(""); ((FrameBodyUSLT) frame.getBody()).setLyric(value); } else if (frame.getBody() instanceof FrameBodyWOAR) { ((FrameBodyWOAR) frame.getBody()).setUrlLink(value); } else if (frame.getBody() instanceof AbstractFrameBodyTextInfo) { ((AbstractFrameBodyTextInfo) frame.getBody()).setText(value); } else if (frame.getBody() instanceof FrameBodyPOPM) { ((FrameBodyPOPM) frame.getBody()).parseString(value); } else if (frame.getBody() instanceof FrameBodyIPLS) { PairedTextEncodedStringNullTerminated.ValuePairs pair = new PairedTextEncodedStringNullTerminated.ValuePairs(); pair.add(formatKey.getSubId(), value); frame.getBody().setObjectValue(DataTypes.OBJ_TEXT, pair); } else if (frame.getBody() instanceof FrameBodyTIPL) { PairedTextEncodedStringNullTerminated.ValuePairs pair = new PairedTextEncodedStringNullTerminated.ValuePairs(); pair.add(formatKey.getSubId(), value); frame.getBody().setObjectValue(DataTypes.OBJ_TEXT, pair); } else if ((frame.getBody() instanceof FrameBodyAPIC) || (frame.getBody() instanceof FrameBodyPIC)) { throw new UnsupportedOperationException(ErrorMessage.ARTWORK_CANNOT_BE_CREATED_WITH_THIS_METHOD.getMsg()); } else { throw new FieldDataInvalidException("Field with key of:" + formatKey.getFrameId() + ":does not accept cannot parse data:" + value); } return frame; } /** * @param formatKey * @param index * @return * @throws KeyNotFoundException */ protected String doGetValueAtIndex(FrameAndSubId formatKey, int index) throws KeyNotFoundException { //Simple 1 to 1 mapping if (formatKey.getSubId() == null) { List list = getFields(formatKey.getFrameId()); if (list.size() > index) { return getTextValueForFrame((AbstractID3v2Frame) list.get(index)); } } else { //Get list of frames that this uses List list = getFields(formatKey.getFrameId()); ListIterator li = list.listIterator(); List listOfMatches = new ArrayList(); while (li.hasNext()) { AbstractTagFrameBody next = ((AbstractID3v2Frame) li.next()).getBody(); if (next instanceof FrameBodyTXXX) { if (((FrameBodyTXXX) next).getDescription().equals(formatKey.getSubId())) { listOfMatches.add(((FrameBodyTXXX) next).getText()); } } else if (next instanceof FrameBodyWXXX) { if (((FrameBodyWXXX) next).getDescription().equals(formatKey.getSubId())) { listOfMatches.add(((FrameBodyWXXX) next).getUrlLink()); } } else if (next instanceof FrameBodyCOMM) { if (((FrameBodyCOMM) next).getDescription().equals(formatKey.getSubId())) { listOfMatches.add(((FrameBodyCOMM) next).getText()); } } else if (next instanceof FrameBodyUFID) { if (Arrays.equals(((FrameBodyUFID) next).getUniqueIdentifier(), formatKey.getSubId().getBytes())) { listOfMatches.add(new String(((FrameBodyUFID) next).getUniqueIdentifier())); } } else if (next instanceof FrameBodyIPLS) { for (Pair entry : ((FrameBodyIPLS) next).getPairing().getMapping()) { if (entry.getKey().equals(formatKey.getSubId())) { listOfMatches.add(entry.getValue()); } } } else if (next instanceof FrameBodyTIPL) { for (Pair entry : ((FrameBodyTIPL) next).getPairing().getMapping()) { if (entry.getKey().equals(formatKey.getSubId())) { listOfMatches.add(entry.getValue()); } } } else { throw new RuntimeException("Need to implement getFields(FieldKey genericKey) for:" + next.getClass()); } } if (listOfMatches.size() > index) { return listOfMatches.get(index); } else { return ""; } } return ""; } /** * Create a link to artwork, this is not recommended because the link may be broken if the mp3 or image * file is moved * * @param url specifies the link, it could be a local file or could be a full url * @return */ public TagField createLinkedArtworkField(String url) { AbstractID3v2Frame frame = createFrame(getFrameAndSubIdFromGenericKey(FieldKey.COVER_ART).getFrameId()); if (frame.getBody() instanceof FrameBodyAPIC) { FrameBodyAPIC body = (FrameBodyAPIC) frame.getBody(); body.setObjectValue(DataTypes.OBJ_PICTURE_DATA, Utils.getDefaultBytes(url, TextEncoding.CHARSET_ISO_8859_1)); body.setObjectValue(DataTypes.OBJ_PICTURE_TYPE, PictureTypes.DEFAULT_ID); body.setObjectValue(DataTypes.OBJ_MIME_TYPE, FrameBodyAPIC.IMAGE_IS_URL); body.setObjectValue(DataTypes.OBJ_DESCRIPTION, ""); } else if (frame.getBody() instanceof FrameBodyPIC) { FrameBodyPIC body = (FrameBodyPIC) frame.getBody(); body.setObjectValue(DataTypes.OBJ_PICTURE_DATA, Utils.getDefaultBytes(url, TextEncoding.CHARSET_ISO_8859_1)); body.setObjectValue(DataTypes.OBJ_PICTURE_TYPE, PictureTypes.DEFAULT_ID); body.setObjectValue(DataTypes.OBJ_IMAGE_FORMAT, FrameBodyAPIC.IMAGE_IS_URL); body.setObjectValue(DataTypes.OBJ_DESCRIPTION, ""); } return frame; } /** * Delete fields with this generic key * * @param genericKey */ public void deleteField(FieldKey genericKey) throws KeyNotFoundException { if (genericKey == null) { throw new KeyNotFoundException(); } FrameAndSubId formatKey = getFrameAndSubIdFromGenericKey(genericKey); doDeleteTagField(formatKey); } /** * Internal delete method * * @param formatKey * @throws KeyNotFoundException */ protected void doDeleteTagField(FrameAndSubId formatKey) throws KeyNotFoundException { //Simple 1 to 1 mapping if (formatKey.getSubId() == null) { removeFrame(formatKey.getFrameId()); } else { //Get list of frames that this uses List list = getFields(formatKey.getFrameId()); ListIterator li = list.listIterator(); while (li.hasNext()) { AbstractTagFrameBody next = ((AbstractID3v2Frame) li.next()).getBody(); if (next instanceof FrameBodyTXXX) { if (((FrameBodyTXXX) next).getDescription().equals(formatKey.getSubId())) { if(list.size()==1) { removeFrame(formatKey.getFrameId()); } else { li.remove(); } } } else if (next instanceof FrameBodyWXXX) { if (((FrameBodyWXXX) next).getDescription().equals(formatKey.getSubId())) { if(list.size()==1) { removeFrame(formatKey.getFrameId()); } else { li.remove(); } } } else if (next instanceof FrameBodyUFID) { if (Arrays.equals(((FrameBodyUFID) next).getUniqueIdentifier(), formatKey.getSubId().getBytes())) { if(list.size()==1) { removeFrame(formatKey.getFrameId()); } else { li.remove(); } } } //A single TIPL frame is used for multiple fields, so we just delete the matching pair rather than //deleting the frame itself unless now empty else if (next instanceof FrameBodyTIPL) { PairedTextEncodedStringNullTerminated.ValuePairs pairs = ((FrameBodyTIPL) next).getPairing(); ListIterator pairIterator = pairs.getMapping().listIterator(); while(pairIterator.hasNext()) { Pair nextPair = pairIterator.next(); if(nextPair.getKey().equals(formatKey.getSubId())) { pairIterator.remove(); } } if(pairs.getMapping().size()==0) { removeFrame(formatKey.getFrameId()); } } //A single IPLS frame is used for multiple fields, so we just delete the matching pair rather than //deleting the frame itself unless now empty else if (next instanceof FrameBodyIPLS) { PairedTextEncodedStringNullTerminated.ValuePairs pairs = ((FrameBodyIPLS) next).getPairing(); ListIterator pairIterator = pairs.getMapping().listIterator(); while(pairIterator.hasNext()) { Pair nextPair = pairIterator.next(); if(nextPair.getKey().equals(formatKey.getSubId())) { pairIterator.remove(); } } if(pairs.getMapping().size()==0) { removeFrame(formatKey.getFrameId()); } } else { throw new RuntimeException("Need to implement getFields(FieldKey genericKey) for:" + next.getClass()); } } } } protected abstract FrameAndSubId getFrameAndSubIdFromGenericKey(FieldKey genericKey); /** * Get field(s) for this key * * @param genericKey * @return * @throws KeyNotFoundException */ public List getFields(FieldKey genericKey) throws KeyNotFoundException { if (genericKey == null) { throw new KeyNotFoundException(); } FrameAndSubId formatKey = getFrameAndSubIdFromGenericKey(genericKey); //Get list of frames that this uses, as we are going to remove entries we don't want take a copy List list = getFields(formatKey.getFrameId()); List filteredList = new ArrayList(); String subFieldId = formatKey.getSubId(); //... do we need to refine the list further i.e we only want TXXX frames that relate to the particular //key that was passed as a parameter if (subFieldId != null) { for (TagField tagfield : list) { AbstractTagFrameBody next = ((AbstractID3v2Frame) tagfield).getBody(); if (next instanceof FrameBodyTXXX) { if (((FrameBodyTXXX) next).getDescription().equals(formatKey.getSubId())) { filteredList.add(tagfield); } } else if (next instanceof FrameBodyWXXX) { if (((FrameBodyWXXX) next).getDescription().equals(formatKey.getSubId())) { filteredList.add(tagfield); } } else if (next instanceof FrameBodyCOMM) { if (((FrameBodyCOMM) next).getDescription().equals(formatKey.getSubId())) { filteredList.add(tagfield); } } else if (next instanceof FrameBodyUFID) { if (Arrays.equals(((FrameBodyUFID) next).getUniqueIdentifier(), formatKey.getSubId().getBytes())) { filteredList.add(tagfield); } } else if (next instanceof FrameBodyIPLS) { for (Pair entry : ((FrameBodyIPLS) next).getPairing().getMapping()) { if (entry.getKey().equals(formatKey.getSubId())) { filteredList.add(tagfield); } } } else if (next instanceof FrameBodyTIPL) { for (Pair entry : ((FrameBodyTIPL) next).getPairing().getMapping()) { if (entry.getKey().equals(formatKey.getSubId())) { filteredList.add(tagfield); } } } else { throw new RuntimeException("Need to implement getFields(FieldKey genericKey) for:" + next.getClass()); } } return filteredList; } else { return list; } } /** * This class had to be created to minimize the duplicate code in concrete subclasses * of this class. It is required in some cases when using the fieldKey enums because enums * cannot be sub classed. We want to use enums instead of regular classes because they are * much easier for end users to to use. */ class FrameAndSubId { private String frameId; private String subId; public FrameAndSubId(String frameId, String subId) { this.frameId = frameId; this.subId = subId; } public String getFrameId() { return frameId; } public String getSubId() { return subId; } } public Artwork getFirstArtwork() { List artwork = getArtworkList(); if (artwork.size() > 0) { return artwork.get(0); } return null; } /** * Create field and then set within tag itself * * @param artwork * @throws FieldDataInvalidException */ public void setField(Artwork artwork) throws FieldDataInvalidException { this.setField(createField(artwork)); } /** * Create field and then set within tag itself * * @param artwork * @throws FieldDataInvalidException */ public void addField(Artwork artwork) throws FieldDataInvalidException { this.addField(createField(artwork)); } /** * Delete all instance of artwork Field * * @throws KeyNotFoundException */ public void deleteArtworkField() throws KeyNotFoundException { this.deleteField(FieldKey.COVER_ART); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/ID3v1TagField.java0000644000175000017500000001336411041064726026041 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3; import org.jaudiotagger.audio.generic.Utils; import org.jaudiotagger.tag.TagField; import org.jaudiotagger.tag.TagTextField; import java.io.UnsupportedEncodingException; /** * This class encapsulates the name and content of a tag entry in id3 fields *
* * @author @author Raphael Slinckx (KiKiDonK) * @author Christian Laireiter (liree) */ public class ID3v1TagField implements TagTextField { /** * If true, the id of the current encapsulated tag field is * specified as a common field.
* Example is "ARTIST" which should be interpreted by any application as the * artist of the media content.
* Will be set during construction with {@link #checkCommon()}. */ private boolean common; /** * Stores the content of the tag field.
*/ private String content; /** * Stores the id (name) of the tag field.
*/ private String id; /** * Creates an instance. * * @param raw Raw byte data of the tagfield. * @throws UnsupportedEncodingException If the data doesn't conform "UTF-8" specification. */ public ID3v1TagField(byte[] raw) throws UnsupportedEncodingException { String field = new String(raw, "ISO-8859-1"); int i = field.indexOf("="); if (i == -1) { //Beware that ogg ID, must be capitalized and contain no space.. this.id = "ERRONEOUS"; this.content = field; } else { this.id = field.substring(0, i).toUpperCase(); if (field.length() > i) { this.content = field.substring(i + 1); } else { //We have "XXXXXX=" with nothing after the "=" this.content = ""; } } checkCommon(); } /** * Creates an instance. * * @param fieldId ID (name) of the field. * @param fieldContent Content of the field. */ public ID3v1TagField(String fieldId, String fieldContent) { this.id = fieldId.toUpperCase(); this.content = fieldContent; checkCommon(); } /** * This method examines the ID of the current field and modifies * {@link #common}in order to reflect if the tag id is a commonly used one. *
*/ private void checkCommon() { this.common = id.equals(ID3v1FieldKey.TITLE.name()) || id.equals(ID3v1FieldKey.ALBUM.name()) || id.equals(ID3v1FieldKey.ARTIST.name()) || id.equals(ID3v1FieldKey.GENRE.name()) || id.equals(ID3v1FieldKey.YEAR.name()) || id.equals(ID3v1FieldKey.COMMENT.name()) || id.equals(ID3v1FieldKey.TRACK.name()); } /** * This method will copy all bytes of src to dst * at the specified location. * * @param src bytes to copy. * @param dst where to copy to. * @param dstOffset at which position of dst the data should be * copied. */ protected void copy(byte[] src, byte[] dst, int dstOffset) { // for (int i = 0; i < src.length; i++) // dst[i + dstOffset] = src[i]; /* * Heared that this method is optimized and does its job very near of * the system. */ System.arraycopy(src, 0, dst, dstOffset, src.length); } /** * @see TagField#copyContent(TagField) */ public void copyContent(TagField field) { if (field instanceof TagTextField) { this.content = ((TagTextField) field).getContent(); } } /** * @see TagTextField#getContent() */ public String getContent() { return content; } /** * @see TagTextField#getEncoding() */ public String getEncoding() { return "ISO-8859-1"; } /** * @see TagField#getId() */ public String getId() { return this.id; } /** * @see TagField#getRawContent() */ public byte[] getRawContent() throws UnsupportedEncodingException { byte[] size = new byte[4]; byte[] idBytes = this.id.getBytes("ISO-8859-1"); byte[] contentBytes = Utils.getDefaultBytes(this.content, "ISO-8859-1"); byte[] b = new byte[4 + idBytes.length + 1 + contentBytes.length]; int length = idBytes.length + 1 + contentBytes.length; size[3] = (byte) ((length & 0xFF000000) >> 24); size[2] = (byte) ((length & 0x00FF0000) >> 16); size[1] = (byte) ((length & 0x0000FF00) >> 8); size[0] = (byte) (length & 0x000000FF); int offset = 0; copy(size, b, offset); offset += 4; copy(idBytes, b, offset); offset += idBytes.length; b[offset] = (byte) 0x3D; offset++;// "=" copy(contentBytes, b, offset); return b; } /** * @see TagField#isBinary() */ public boolean isBinary() { return false; } /** * @see TagField#isBinary(boolean) */ public void isBinary(boolean b) { //Do nothing, always false } /** * @see TagField#isCommon() */ public boolean isCommon() { return common; } /** * @see TagField#isEmpty() */ public boolean isEmpty() { return this.content.equals(""); } /** * @see TagTextField#setContent(String) */ public void setContent(String s) { this.content = s; } /** * @see TagTextField#setEncoding(String) */ public void setEncoding(String s) { //Do nothing, encoding is always ISO-8859-1 for this tag } public String toString() { return getContent(); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/ID3v22FieldKey.java0000644000175000017500000002072711470746136026152 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3; import org.jaudiotagger.tag.id3.framebody.*; /** * List of known id3v22 metadata fields *

*

These provide a mapping from the generic key to the underlying ID3v22frames. For example most of the Musicbrainz * fields are implemnted using a User Defined Text Info Frame, but with a different description key, so this * enum provides the link between the two. */ public enum ID3v22FieldKey { ALBUM(ID3v22Frames.FRAME_ID_V2_ALBUM, Id3FieldType.TEXT), ALBUM_ARTIST(ID3v22Frames.FRAME_ID_V2_ACCOMPANIMENT, Id3FieldType.TEXT), ALBUM_ARTIST_SORT(ID3v22Frames.FRAME_ID_V2_ALBUM_ARTIST_SORT_ORDER_ITUNES, Id3FieldType.TEXT), ALBUM_SORT(ID3v22Frames.FRAME_ID_V2_ALBUM_SORT_ORDER_ITUNES, Id3FieldType.TEXT), AMAZON_ID(ID3v22Frames.FRAME_ID_V2_USER_DEFINED_INFO, FrameBodyTXXX.AMAZON_ASIN, Id3FieldType.TEXT), ARTIST(ID3v22Frames.FRAME_ID_V2_ARTIST, Id3FieldType.TEXT), ARTIST_SORT(ID3v22Frames.FRAME_ID_V2_ARTIST_SORT_ORDER_ITUNES, Id3FieldType.TEXT), BARCODE(ID3v22Frames.FRAME_ID_V2_USER_DEFINED_INFO, FrameBodyTXXX.BARCODE, Id3FieldType.TEXT), BPM(ID3v22Frames.FRAME_ID_V2_BPM, Id3FieldType.TEXT), CATALOG_NO(ID3v22Frames.FRAME_ID_V2_USER_DEFINED_INFO, FrameBodyTXXX.CATALOG_NO, Id3FieldType.TEXT), COMMENT(ID3v22Frames.FRAME_ID_V2_COMMENT, Id3FieldType.TEXT), COMPOSER(ID3v22Frames.FRAME_ID_V2_COMPOSER, Id3FieldType.TEXT), COMPOSER_SORT(ID3v22Frames.FRAME_ID_V2_COMPOSER_SORT_ORDER_ITUNES, Id3FieldType.TEXT), CONDUCTOR(ID3v22Frames.FRAME_ID_V2_CONDUCTOR, Id3FieldType.TEXT), COVER_ART(ID3v22Frames.FRAME_ID_V2_ATTACHED_PICTURE, Id3FieldType.BINARY), CUSTOM1(ID3v22Frames.FRAME_ID_V2_COMMENT, FrameBodyCOMM.MM_CUSTOM1,Id3FieldType.TEXT), CUSTOM2(ID3v22Frames.FRAME_ID_V2_COMMENT, FrameBodyCOMM.MM_CUSTOM2,Id3FieldType.TEXT), CUSTOM3(ID3v22Frames.FRAME_ID_V2_COMMENT, FrameBodyCOMM.MM_CUSTOM3,Id3FieldType.TEXT), CUSTOM4(ID3v22Frames.FRAME_ID_V2_COMMENT, FrameBodyCOMM.MM_CUSTOM4,Id3FieldType.TEXT), CUSTOM5(ID3v22Frames.FRAME_ID_V2_COMMENT, FrameBodyCOMM.MM_CUSTOM5,Id3FieldType.TEXT), DISC_NO(ID3v22Frames.FRAME_ID_V2_SET, Id3FieldType.TEXT), DISC_TOTAL(ID3v22Frames.FRAME_ID_V2_SET, Id3FieldType.TEXT), ENCODER(ID3v22Frames.FRAME_ID_V2_ENCODEDBY, Id3FieldType.TEXT), FBPM(ID3v22Frames.FRAME_ID_V2_USER_DEFINED_INFO, FrameBodyTXXX.FBPM, Id3FieldType.TEXT), GENRE(ID3v22Frames.FRAME_ID_V2_GENRE, Id3FieldType.TEXT), GROUPING(ID3v22Frames.FRAME_ID_V2_CONTENT_GROUP_DESC, Id3FieldType.TEXT), ISRC(ID3v22Frames.FRAME_ID_V2_ISRC, Id3FieldType.TEXT), IS_COMPILATION(ID3v22Frames.FRAME_ID_V2_IS_COMPILATION, Id3FieldType.TEXT), KEY(ID3v22Frames.FRAME_ID_V2_INITIAL_KEY,Id3FieldType.TEXT), LANGUAGE(ID3v22Frames.FRAME_ID_V2_LANGUAGE,Id3FieldType.TEXT), LYRICIST(ID3v22Frames.FRAME_ID_V2_LYRICIST, Id3FieldType.TEXT), LYRICS(ID3v22Frames.FRAME_ID_V2_UNSYNC_LYRICS, Id3FieldType.TEXT), MEDIA(ID3v22Frames.FRAME_ID_V2_MEDIA_TYPE, Id3FieldType.TEXT), MOOD(ID3v22Frames.FRAME_ID_V2_USER_DEFINED_INFO, FrameBodyTXXX.MOOD, Id3FieldType.TEXT), MUSICBRAINZ_ARTISTID(ID3v22Frames.FRAME_ID_V2_USER_DEFINED_INFO, FrameBodyTXXX.MUSICBRAINZ_ARTISTID, Id3FieldType.TEXT), MUSICBRAINZ_DISC_ID(ID3v22Frames.FRAME_ID_V2_USER_DEFINED_INFO, FrameBodyTXXX.MUSICBRAINZ_DISCID, Id3FieldType.TEXT), MUSICBRAINZ_RELEASEARTISTID(ID3v22Frames.FRAME_ID_V2_USER_DEFINED_INFO, FrameBodyTXXX.MUSICBRAINZ_ALBUM_ARTISTID, Id3FieldType.TEXT), MUSICBRAINZ_RELEASEID(ID3v22Frames.FRAME_ID_V2_USER_DEFINED_INFO, FrameBodyTXXX.MUSICBRAINZ_ALBUMID, Id3FieldType.TEXT), MUSICBRAINZ_RELEASE_COUNTRY(ID3v22Frames.FRAME_ID_V2_USER_DEFINED_INFO, FrameBodyTXXX.MUSICBRAINZ_ALBUM_COUNTRY, Id3FieldType.TEXT), MUSICBRAINZ_RELEASE_GROUP_ID(ID3v22Frames.FRAME_ID_V2_USER_DEFINED_INFO, FrameBodyTXXX.MUSICBRAINZ_RELEASE_GROUPID, Id3FieldType.TEXT), MUSICBRAINZ_RELEASE_STATUS(ID3v22Frames.FRAME_ID_V2_USER_DEFINED_INFO, FrameBodyTXXX.MUSICBRAINZ_ALBUM_STATUS, Id3FieldType.TEXT), MUSICBRAINZ_RELEASE_TYPE(ID3v22Frames.FRAME_ID_V2_USER_DEFINED_INFO, FrameBodyTXXX.MUSICBRAINZ_ALBUM_TYPE, Id3FieldType.TEXT), MUSICBRAINZ_TRACK_ID(ID3v22Frames.FRAME_ID_V2_UNIQUE_FILE_ID, FrameBodyUFID.UFID_MUSICBRAINZ, Id3FieldType.TEXT), MUSICBRAINZ_WORK_ID(ID3v22Frames.FRAME_ID_V2_USER_DEFINED_INFO, FrameBodyTXXX.MUSICBRAINZ_WORKID, Id3FieldType.TEXT), MUSICIP_ID(ID3v22Frames.FRAME_ID_V2_USER_DEFINED_INFO, FrameBodyTXXX.MUSICIP_ID, Id3FieldType.TEXT), OCCASION(ID3v22Frames.FRAME_ID_V2_COMMENT, FrameBodyCOMM.MM_OCCASION,Id3FieldType.TEXT), ORIGINAL_ALBUM(ID3v22Frames.FRAME_ID_V2_ORIG_TITLE, Id3FieldType.TEXT), ORIGINAL_ARTIST(ID3v22Frames.FRAME_ID_V2_ORIGARTIST, Id3FieldType.TEXT), ORIGINAL_LYRICIST(ID3v22Frames.FRAME_ID_V2_ORIG_LYRICIST, Id3FieldType.TEXT), ORIGINAL_YEAR(ID3v22Frames.FRAME_ID_V2_TORY, Id3FieldType.TEXT), QUALITY(ID3v22Frames.FRAME_ID_V2_COMMENT, FrameBodyCOMM.MM_QUALITY,Id3FieldType.TEXT), RATING(ID3v22Frames.FRAME_ID_V2_POPULARIMETER, Id3FieldType.TEXT), RECORD_LABEL(ID3v22Frames.FRAME_ID_V2_PUBLISHER, Id3FieldType.TEXT), REMIXER(ID3v22Frames.FRAME_ID_V2_REMIXED, Id3FieldType.TEXT), SCRIPT(ID3v22Frames.FRAME_ID_V2_USER_DEFINED_INFO, FrameBodyTXXX.SCRIPT, Id3FieldType.TEXT), TAGS(ID3v22Frames.FRAME_ID_V2_USER_DEFINED_INFO, FrameBodyTXXX.TAGS, Id3FieldType.TEXT), TEMPO(ID3v22Frames.FRAME_ID_V2_COMMENT, FrameBodyCOMM.MM_TEMPO,Id3FieldType.TEXT), TITLE(ID3v22Frames.FRAME_ID_V2_TITLE, Id3FieldType.TEXT), TITLE_SORT(ID3v22Frames.FRAME_ID_V2_TITLE_SORT_ORDER_ITUNES, Id3FieldType.TEXT), TRACK(ID3v22Frames.FRAME_ID_V2_TRACK, Id3FieldType.TEXT), TRACK_TOTAL(ID3v22Frames.FRAME_ID_V2_TRACK, Id3FieldType.TEXT), URL_DISCOGS_ARTIST_SITE(ID3v22Frames.FRAME_ID_V2_USER_DEFINED_URL, FrameBodyWXXX.URL_DISCOGS_ARTIST_SITE, Id3FieldType.TEXT), URL_DISCOGS_RELEASE_SITE(ID3v22Frames.FRAME_ID_V2_USER_DEFINED_URL, FrameBodyWXXX.URL_DISCOGS_RELEASE_SITE, Id3FieldType.TEXT), URL_LYRICS_SITE(ID3v22Frames.FRAME_ID_V2_USER_DEFINED_URL, FrameBodyWXXX.URL_LYRICS_SITE, Id3FieldType.TEXT), URL_OFFICIAL_ARTIST_SITE(ID3v22Frames.FRAME_ID_V2_URL_ARTIST_WEB, Id3FieldType.TEXT), URL_OFFICIAL_RELEASE_SITE(ID3v22Frames.FRAME_ID_V2_USER_DEFINED_URL, FrameBodyWXXX.URL_OFFICIAL_RELEASE_SITE, Id3FieldType.TEXT), URL_WIKIPEDIA_ARTIST_SITE(ID3v22Frames.FRAME_ID_V2_USER_DEFINED_URL, FrameBodyWXXX.URL_WIKIPEDIA_ARTIST_SITE, Id3FieldType.TEXT), URL_WIKIPEDIA_RELEASE_SITE(ID3v22Frames.FRAME_ID_V2_USER_DEFINED_URL, FrameBodyWXXX.URL_WIKIPEDIA_RELEASE_SITE, Id3FieldType.TEXT), YEAR(ID3v22Frames.FRAME_ID_V2_TYER, Id3FieldType.TEXT), ENGINEER(ID3v22Frames.FRAME_ID_V2_IPLS, FrameBodyTIPL.ENGINEER, Id3FieldType.TEXT), PRODUCER(ID3v22Frames.FRAME_ID_V2_IPLS, FrameBodyTIPL.PRODUCER, Id3FieldType.TEXT), MIXER(ID3v22Frames.FRAME_ID_V2_IPLS, FrameBodyTIPL.MIXER, Id3FieldType.TEXT), DJMIXER(ID3v22Frames.FRAME_ID_V2_IPLS, FrameBodyTIPL.DJMIXER, Id3FieldType.TEXT), ARRANGER(ID3v22Frames.FRAME_ID_V2_IPLS, FrameBodyTIPL.ARRANGER, Id3FieldType.TEXT), ; private String fieldName; private String frameId; private String subId; private Id3FieldType fieldType; /** * For usual metadata fields that use a data field * * @param frameId the frame that will be used * @param fieldType of data atom */ ID3v22FieldKey(String frameId, Id3FieldType fieldType) { this.frameId = frameId; this.fieldType = fieldType; this.fieldName = frameId; } /** * @param frameId the frame that will be used * @param subId the additioanl key required within the frame to uniquely identify this key * @param fieldType */ ID3v22FieldKey(String frameId, String subId, Id3FieldType fieldType) { this.frameId = frameId; this.subId = subId; this.fieldType = fieldType; this.fieldName = frameId + ":" + subId; } /** * @return fieldtype */ public Id3FieldType getFieldType() { return fieldType; } /** * This is the frame identifier used to write the field * * @return */ public String getFrameId() { return frameId; } /** * This is the subfield used within the frame for this type of field * * @return subId */ public String getSubId() { return subId; } /** * This is the value of the key that can uniquely identifer a key type * * @return */ public String getFieldName() { return fieldName; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/ID3v24PreferredFrameOrderComparator.java0000644000175000017500000001520411470746136032367 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3; import static org.jaudiotagger.tag.id3.ID3v24Frames.*; import java.util.ArrayList; import java.util.Comparator; import java.util.List; /** * Orders frame Ids so that the most important frames are writtne first */ public class ID3v24PreferredFrameOrderComparator implements Comparator { private static ID3v24PreferredFrameOrderComparator comparator; private static List frameIdsInPreferredOrder = new ArrayList(); static { //these are the key ones we want at the top frameIdsInPreferredOrder.add(FRAME_ID_UNIQUE_FILE_ID); frameIdsInPreferredOrder.add(FRAME_ID_TITLE); frameIdsInPreferredOrder.add(FRAME_ID_ARTIST); frameIdsInPreferredOrder.add(FRAME_ID_ALBUM); frameIdsInPreferredOrder.add(FRAME_ID_ALBUM_SORT_ORDER); frameIdsInPreferredOrder.add(FRAME_ID_GENRE); frameIdsInPreferredOrder.add(FRAME_ID_COMPOSER); frameIdsInPreferredOrder.add(FRAME_ID_CONDUCTOR); frameIdsInPreferredOrder.add(FRAME_ID_CONTENT_GROUP_DESC); frameIdsInPreferredOrder.add(FRAME_ID_TRACK); frameIdsInPreferredOrder.add(FRAME_ID_YEAR); frameIdsInPreferredOrder.add(FRAME_ID_ACCOMPANIMENT); frameIdsInPreferredOrder.add(FRAME_ID_BPM); frameIdsInPreferredOrder.add(FRAME_ID_ISRC); frameIdsInPreferredOrder.add(FRAME_ID_TITLE_SORT_ORDER); frameIdsInPreferredOrder.add(FRAME_ID_TITLE_REFINEMENT); frameIdsInPreferredOrder.add(FRAME_ID_UNSYNC_LYRICS); frameIdsInPreferredOrder.add(FRAME_ID_USER_DEFINED_INFO); frameIdsInPreferredOrder.add(FRAME_ID_USER_DEFINED_URL); frameIdsInPreferredOrder.add(FRAME_ID_URL_ARTIST_WEB); frameIdsInPreferredOrder.add(FRAME_ID_URL_COMMERCIAL); frameIdsInPreferredOrder.add(FRAME_ID_URL_COPYRIGHT); frameIdsInPreferredOrder.add(FRAME_ID_URL_FILE_WEB); frameIdsInPreferredOrder.add(FRAME_ID_URL_OFFICIAL_RADIO); frameIdsInPreferredOrder.add(FRAME_ID_URL_PAYMENT); frameIdsInPreferredOrder.add(FRAME_ID_URL_PUBLISHERS); frameIdsInPreferredOrder.add(FRAME_ID_URL_COMMERCIAL); frameIdsInPreferredOrder.add(FRAME_ID_LYRICIST); frameIdsInPreferredOrder.add(FRAME_ID_MEDIA_TYPE); frameIdsInPreferredOrder.add(FRAME_ID_INVOLVED_PEOPLE); frameIdsInPreferredOrder.add(FRAME_ID_LANGUAGE); frameIdsInPreferredOrder.add(FRAME_ID_ARTIST_SORT_ORDER); frameIdsInPreferredOrder.add(FRAME_ID_PLAYLIST_DELAY); frameIdsInPreferredOrder.add(FRAME_ID_PLAY_COUNTER); frameIdsInPreferredOrder.add(FRAME_ID_POPULARIMETER); frameIdsInPreferredOrder.add(FRAME_ID_PUBLISHER); frameIdsInPreferredOrder.add(FRAME_ID_ALBUM_ARTIST_SORT_ORDER_ITUNES); frameIdsInPreferredOrder.add(FRAME_ID_COMPOSER_SORT_ORDER_ITUNES); frameIdsInPreferredOrder.add(FRAME_ID_IS_COMPILATION); frameIdsInPreferredOrder.add(FRAME_ID_COMMENT); //Not so bothered about these frameIdsInPreferredOrder.add(FRAME_ID_AUDIO_SEEK_POINT_INDEX); frameIdsInPreferredOrder.add(FRAME_ID_COMMERCIAL_FRAME); frameIdsInPreferredOrder.add(FRAME_ID_COPYRIGHTINFO); frameIdsInPreferredOrder.add(FRAME_ID_ENCODEDBY); frameIdsInPreferredOrder.add(FRAME_ID_ENCODING_TIME); frameIdsInPreferredOrder.add(FRAME_ID_ENCRYPTION); frameIdsInPreferredOrder.add(FRAME_ID_EQUALISATION2); frameIdsInPreferredOrder.add(FRAME_ID_EVENT_TIMING_CODES); frameIdsInPreferredOrder.add(FRAME_ID_FILE_OWNER); frameIdsInPreferredOrder.add(FRAME_ID_FILE_TYPE); frameIdsInPreferredOrder.add(FRAME_ID_GROUP_ID_REG); frameIdsInPreferredOrder.add(FRAME_ID_HW_SW_SETTINGS); frameIdsInPreferredOrder.add(FRAME_ID_INITIAL_KEY); frameIdsInPreferredOrder.add(FRAME_ID_LENGTH); frameIdsInPreferredOrder.add(FRAME_ID_LINKED_INFO); frameIdsInPreferredOrder.add(FRAME_ID_MOOD); frameIdsInPreferredOrder.add(FRAME_ID_MPEG_LOCATION_LOOKUP_TABLE); frameIdsInPreferredOrder.add(FRAME_ID_MUSICIAN_CREDITS); frameIdsInPreferredOrder.add(FRAME_ID_ORIGARTIST); frameIdsInPreferredOrder.add(FRAME_ID_ORIGINAL_RELEASE_TIME); frameIdsInPreferredOrder.add(FRAME_ID_ORIG_FILENAME); frameIdsInPreferredOrder.add(FRAME_ID_ORIG_LYRICIST); frameIdsInPreferredOrder.add(FRAME_ID_ORIG_TITLE); frameIdsInPreferredOrder.add(FRAME_ID_OWNERSHIP); frameIdsInPreferredOrder.add(FRAME_ID_POSITION_SYNC); frameIdsInPreferredOrder.add(FRAME_ID_PRODUCED_NOTICE); frameIdsInPreferredOrder.add(FRAME_ID_RADIO_NAME); frameIdsInPreferredOrder.add(FRAME_ID_RADIO_OWNER); frameIdsInPreferredOrder.add(FRAME_ID_RECOMMENDED_BUFFER_SIZE); frameIdsInPreferredOrder.add(FRAME_ID_RELATIVE_VOLUME_ADJUSTMENT2); frameIdsInPreferredOrder.add(FRAME_ID_RELEASE_TIME); frameIdsInPreferredOrder.add(FRAME_ID_REMIXED); frameIdsInPreferredOrder.add(FRAME_ID_REVERB); frameIdsInPreferredOrder.add(FRAME_ID_SEEK); frameIdsInPreferredOrder.add(FRAME_ID_SET); frameIdsInPreferredOrder.add(FRAME_ID_SET_SUBTITLE); frameIdsInPreferredOrder.add(FRAME_ID_SIGNATURE); frameIdsInPreferredOrder.add(FRAME_ID_SYNC_LYRIC); frameIdsInPreferredOrder.add(FRAME_ID_SYNC_TEMPO); frameIdsInPreferredOrder.add(FRAME_ID_TAGGING_TIME); frameIdsInPreferredOrder.add(FRAME_ID_TERMS_OF_USE); //Want this near the end because can cause problems with unsyncing frameIdsInPreferredOrder.add(FRAME_ID_ATTACHED_PICTURE); //Itunes doesnt seem to like these, and of little use so put right at end frameIdsInPreferredOrder.add(FRAME_ID_PRIVATE); frameIdsInPreferredOrder.add(FRAME_ID_MUSIC_CD_ID); frameIdsInPreferredOrder.add(FRAME_ID_AUDIO_ENCRYPTION); frameIdsInPreferredOrder.add(FRAME_ID_GENERAL_ENCAPS_OBJECT); } private ID3v24PreferredFrameOrderComparator() { } public static ID3v24PreferredFrameOrderComparator getInstanceof() { if (comparator == null) { comparator = new ID3v24PreferredFrameOrderComparator(); } return comparator; } /** * @param frameId1 * @param frameId2 * @return */ public int compare(String frameId1, String frameId2) { int frameId1Index = frameIdsInPreferredOrder.indexOf(frameId1); int frameId2Index = frameIdsInPreferredOrder.indexOf(frameId2); return frameId1Index - frameId2Index; } public boolean equals(Object obj) { return obj instanceof ID3v24PreferredFrameOrderComparator; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/AbstractTagFrame.java0000644000175000017500000001023111305717447026763 0ustar drazzibdrazzib/** * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: AbstractTagFrame.java 857 2009-12-03 11:21:11Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Description: * This class represents 'parts of tags'. It contains methods that they all use * use. ID3v2 tags have frames. Lyrics3 tags have fields. ID3v1 tags do not * have parts. It also contains their header while the body contains the * actual fragments. */ package org.jaudiotagger.tag.id3; import org.jaudiotagger.utils.EqualsUtil; /** * A frame contains meta-information of a particular type. A frame contains a header and a body */ public abstract class AbstractTagFrame extends AbstractTagItem { /** * Actual data this fragment holds */ protected AbstractTagFrameBody frameBody; public AbstractTagFrame() { } /** * This constructs the bodies copy constructor this in turn invokes * * bodies objectlist. * @param copyObject */ public AbstractTagFrame(AbstractTagFrame copyObject) { this.frameBody = (AbstractTagFrameBody) ID3Tags.copyObject(copyObject.frameBody); this.frameBody.setHeader(this); } /** * Sets the body datatype for this fragment. The body datatype contains the * actual information for the fragment. * * @param frameBody the body datatype */ public void setBody(AbstractTagFrameBody frameBody) { this.frameBody = frameBody; this.frameBody.setHeader(this); } /** * Returns the body datatype for this fragment. The body datatype contains the * actual information for the fragment. * * @return the body datatype */ public AbstractTagFrameBody getBody() { return this.frameBody; } /** * Returns true if this datatype and it's body is a subset of the argument. * This datatype is a subset if the argument is the same class. * * @param obj datatype to determine if subset of * @return true if this datatype and it's body is a subset of the argument. */ public boolean isSubsetOf(Object obj) { if (!(obj instanceof AbstractTagFrame)) { return false; } if ((frameBody == null) && (((AbstractTagFrame) obj).frameBody == null)) { return true; } if ((frameBody == null) || (((AbstractTagFrame) obj).frameBody == null)) { return false; } return frameBody.isSubsetOf(((AbstractTagFrame) obj).frameBody) && super.isSubsetOf(obj); } /** * Returns true if this datatype and its body equals the argument and its * body. this datatype is equal if and only if they are the same class and * have the same getSubId id string. * * @param obj datatype to determine equality of * @return true if this datatype and its body equals the argument and its * body. */ public boolean equals(Object obj) { if ( this == obj ) return true; if (!(obj instanceof AbstractTagFrame)) { return false; } AbstractTagFrame that = (AbstractTagFrame) obj; return EqualsUtil.areEqual(this.getIdentifier(), that.getIdentifier()) && EqualsUtil.areEqual(this.frameBody, that.frameBody) && super.equals(that); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/AbstractID3v1Tag.java0000644000175000017500000001161211470746136026563 0ustar drazzibdrazzib/** * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: AbstractID3v1Tag.java 929 2010-11-17 12:36:46Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Description: * Abstract superclass of all URL Frames * */ package org.jaudiotagger.tag.id3; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.channels.FileChannel; import java.util.Arrays; import java.util.logging.Logger; import java.util.regex.Pattern; /** * This is the abstract base class for all ID3v1 tags. * * @author : Eric Farng * @author : Paul Taylor */ abstract public class AbstractID3v1Tag extends AbstractID3Tag { //Logger public static Logger logger = Logger.getLogger("org.jaudiotagger.tag.id3"); public AbstractID3v1Tag() { } public AbstractID3v1Tag(AbstractID3v1Tag copyObject) { super(copyObject); } //If field is less than maximum field length this is how it is terminated protected static final byte END_OF_FIELD = (byte) 0; //Used to detect end of field in String constructed from Data protected static Pattern endofStringPattern = Pattern.compile("\\x00"); //Tag ID as held in file protected static final byte[] TAG_ID = {(byte) 'T', (byte) 'A', (byte) 'G'}; //Fields Lengths common to v1 and v1.1 tags protected static final int TAG_LENGTH = 128; protected static final int TAG_DATA_LENGTH = 125; protected static final int FIELD_TAGID_LENGTH = 3; protected static final int FIELD_TITLE_LENGTH = 30; protected static final int FIELD_ARTIST_LENGTH = 30; protected static final int FIELD_ALBUM_LENGTH = 30; protected static final int FIELD_YEAR_LENGTH = 4; protected static final int FIELD_GENRE_LENGTH = 1; //Field Positions, starting from zero so fits in with Java Terminology protected static final int FIELD_TAGID_POS = 0; protected static final int FIELD_TITLE_POS = 3; protected static final int FIELD_ARTIST_POS = 33; protected static final int FIELD_ALBUM_POS = 63; protected static final int FIELD_YEAR_POS = 93; protected static final int FIELD_GENRE_POS = 127; //For writing output protected static final String TYPE_TITLE = "title"; protected static final String TYPE_ARTIST = "artist"; protected static final String TYPE_ALBUM = "album"; protected static final String TYPE_YEAR = "year"; protected static final String TYPE_GENRE = "genre"; /** * Return the size of this tag, the size is fixed for tags of this type * * @return size of this tag in bytes */ public int getSize() { return TAG_LENGTH; } /** * Does a v1tag or a v11tag exist * * @return whether tag exists within the byteBuffer */ public static boolean seekForV1OrV11Tag(ByteBuffer byteBuffer) { byte[] buffer = new byte[FIELD_TAGID_LENGTH]; // read the TAG value byteBuffer.get(buffer, 0, FIELD_TAGID_LENGTH); return (Arrays.equals(buffer, TAG_ID)); } /** * Delete tag from file * Looks for tag and if found lops it off the file. * * @param file to delete the tag from * @throws IOException if there was a problem accessing the file */ public void delete(RandomAccessFile file) throws IOException { //Read into Byte Buffer logger.info("Deleting ID3v1 from file if exists"); FileChannel fc; ByteBuffer byteBuffer; fc = file.getChannel(); if(file.length() < TAG_LENGTH) { throw new IOException("File not not appear large enough to contain a tag"); } fc.position(file.length() - TAG_LENGTH); byteBuffer = ByteBuffer.allocate(TAG_LENGTH); fc.read(byteBuffer); byteBuffer.rewind(); if (AbstractID3v1Tag.seekForV1OrV11Tag(byteBuffer)) { logger.config("Deleted ID3v1 tag"); file.setLength(file.length() - TAG_LENGTH); } else { logger.config("Unable to find ID3v1 tag to deleteField"); } } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/ID3v23Frames.java0000644000175000017500000006375311470746136025702 0ustar drazzibdrazzib/* * Jaudiotagger Copyright (C)2004,2005 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can getFields a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3; import org.jaudiotagger.tag.FieldKey; import java.util.EnumMap; /** * Defines ID3v23 frames and collections that categorise frames within an ID3v23 tag. *

* You can include frames here that are not officially supported as long as they can be used within an * ID3v23Tag * * @author Paul Taylor * @version $Id: ID3v23Frames.java 929 2010-11-17 12:36:46Z paultaylor $ */ public class ID3v23Frames extends ID3Frames { /** * Define all frames that are valid within ID3v23 * Frame IDs begining with T are text frames, & with W are url frames */ public static final String FRAME_ID_V3_ACCOMPANIMENT = "TPE2"; public static final String FRAME_ID_V3_ALBUM = "TALB"; public static final String FRAME_ID_V3_ARTIST = "TPE1"; public static final String FRAME_ID_V3_ATTACHED_PICTURE = "APIC"; public static final String FRAME_ID_V3_AUDIO_ENCRYPTION = "AENC"; public static final String FRAME_ID_V3_BPM = "TBPM"; public static final String FRAME_ID_V3_COMMENT = "COMM"; public static final String FRAME_ID_V3_COMMERCIAL_FRAME = "COMR"; public static final String FRAME_ID_V3_COMPOSER = "TCOM"; public static final String FRAME_ID_V3_CONDUCTOR = "TPE3"; public static final String FRAME_ID_V3_CONTENT_GROUP_DESC = "TIT1"; public static final String FRAME_ID_V3_COPYRIGHTINFO = "TCOP"; public static final String FRAME_ID_V3_ENCODEDBY = "TENC"; public static final String FRAME_ID_V3_ENCRYPTION = "ENCR"; public static final String FRAME_ID_V3_EQUALISATION = "EQUA"; public static final String FRAME_ID_V3_EVENT_TIMING_CODES = "ETCO"; public static final String FRAME_ID_V3_FILE_OWNER = "TOWN"; public static final String FRAME_ID_V3_FILE_TYPE = "TFLT"; public static final String FRAME_ID_V3_GENERAL_ENCAPS_OBJECT = "GEOB"; public static final String FRAME_ID_V3_GENRE = "TCON"; public static final String FRAME_ID_V3_GROUP_ID_REG = "GRID"; public static final String FRAME_ID_V3_HW_SW_SETTINGS = "TSSE"; public static final String FRAME_ID_V3_INITIAL_KEY = "TKEY"; public static final String FRAME_ID_V3_IPLS = "IPLS"; public static final String FRAME_ID_V3_ISRC = "TSRC"; public static final String FRAME_ID_V3_LANGUAGE = "TLAN"; public static final String FRAME_ID_V3_LENGTH = "TLEN"; public static final String FRAME_ID_V3_LINKED_INFO = "LINK"; public static final String FRAME_ID_V3_LYRICIST = "TEXT"; public static final String FRAME_ID_V3_MEDIA_TYPE = "TMED"; public static final String FRAME_ID_V3_MPEG_LOCATION_LOOKUP_TABLE = "MLLT"; public static final String FRAME_ID_V3_MUSIC_CD_ID = "MCDI"; public static final String FRAME_ID_V3_ORIGARTIST = "TOPE"; public static final String FRAME_ID_V3_ORIG_FILENAME = "TOFN"; public static final String FRAME_ID_V3_ORIG_LYRICIST = "TOLY"; public static final String FRAME_ID_V3_ORIG_TITLE = "TOAL"; public static final String FRAME_ID_V3_OWNERSHIP = "OWNE"; public static final String FRAME_ID_V3_PLAYLIST_DELAY = "TDLY"; public static final String FRAME_ID_V3_PLAY_COUNTER = "PCNT"; public static final String FRAME_ID_V3_POPULARIMETER = "POPM"; public static final String FRAME_ID_V3_POSITION_SYNC = "POSS"; public static final String FRAME_ID_V3_PRIVATE = "PRIV"; public static final String FRAME_ID_V3_PUBLISHER = "TPUB"; public static final String FRAME_ID_V3_RADIO_NAME = "TRSN"; public static final String FRAME_ID_V3_RADIO_OWNER = "TRSO"; public static final String FRAME_ID_V3_RECOMMENDED_BUFFER_SIZE = "RBUF"; public static final String FRAME_ID_V3_RELATIVE_VOLUME_ADJUSTMENT = "RVAD"; public static final String FRAME_ID_V3_REMIXED = "TPE4"; public static final String FRAME_ID_V3_REVERB = "RVRB"; public static final String FRAME_ID_V3_SET = "TPOS"; public static final String FRAME_ID_V3_SYNC_LYRIC = "SYLT"; public static final String FRAME_ID_V3_SYNC_TEMPO = "SYTC"; public static final String FRAME_ID_V3_TDAT = "TDAT"; public static final String FRAME_ID_V3_TERMS_OF_USE = "USER"; public static final String FRAME_ID_V3_TIME = "TIME"; public static final String FRAME_ID_V3_TITLE = "TIT2"; public static final String FRAME_ID_V3_TITLE_REFINEMENT = "TIT3"; public static final String FRAME_ID_V3_TORY = "TORY"; public static final String FRAME_ID_V3_TRACK = "TRCK"; public static final String FRAME_ID_V3_TRDA = "TRDA"; public static final String FRAME_ID_V3_TSIZ = "TSIZ"; public static final String FRAME_ID_V3_TYER = "TYER"; public static final String FRAME_ID_V3_UNIQUE_FILE_ID = "UFID"; public static final String FRAME_ID_V3_UNSYNC_LYRICS = "USLT"; public static final String FRAME_ID_V3_URL_ARTIST_WEB = "WOAR"; public static final String FRAME_ID_V3_URL_COMMERCIAL = "WCOM"; public static final String FRAME_ID_V3_URL_COPYRIGHT = "WCOP"; public static final String FRAME_ID_V3_URL_FILE_WEB = "WOAF"; public static final String FRAME_ID_V3_URL_OFFICIAL_RADIO = "WORS"; public static final String FRAME_ID_V3_URL_PAYMENT = "WPAY"; public static final String FRAME_ID_V3_URL_PUBLISHERS = "WPUB"; public static final String FRAME_ID_V3_URL_SOURCE_WEB = "WOAS"; public static final String FRAME_ID_V3_USER_DEFINED_INFO = "TXXX"; public static final String FRAME_ID_V3_USER_DEFINED_URL = "WXXX"; public static final String FRAME_ID_V3_IS_COMPILATION = "TCMP"; public static final String FRAME_ID_V3_TITLE_SORT_ORDER_ITUNES = "TSOT"; public static final String FRAME_ID_V3_ARTIST_SORT_ORDER_ITUNES = "TSOP"; public static final String FRAME_ID_V3_ALBUM_SORT_ORDER_ITUNES = "TSOA"; public static final String FRAME_ID_V3_TITLE_SORT_ORDER_MUSICBRAINZ = "XSOT"; public static final String FRAME_ID_V3_ARTIST_SORT_ORDER_MUSICBRAINZ = "XSOP"; public static final String FRAME_ID_V3_ALBUM_SORT_ORDER_MUSICBRAINZ = "XSOA"; public static final String FRAME_ID_V3_ALBUM_ARTIST_SORT_ORDER_ITUNES = "TSO2"; public static final String FRAME_ID_V3_COMPOSER_SORT_ORDER_ITUNES = "TSOC"; private static ID3v23Frames id3v23Frames; /** * Maps from Generic key to ID3 key */ protected EnumMap tagFieldToId3 = new EnumMap(FieldKey.class); public static ID3v23Frames getInstanceOf() { if (id3v23Frames == null) { id3v23Frames = new ID3v23Frames(); } return id3v23Frames; } private ID3v23Frames() { // The defined v23 frames, supportedFrames.add(FRAME_ID_V3_ACCOMPANIMENT); supportedFrames.add(FRAME_ID_V3_ALBUM); supportedFrames.add(FRAME_ID_V3_ARTIST); supportedFrames.add(FRAME_ID_V3_ATTACHED_PICTURE); supportedFrames.add(FRAME_ID_V3_AUDIO_ENCRYPTION); supportedFrames.add(FRAME_ID_V3_BPM); supportedFrames.add(FRAME_ID_V3_COMMENT); supportedFrames.add(FRAME_ID_V3_COMMERCIAL_FRAME); supportedFrames.add(FRAME_ID_V3_COMPOSER); supportedFrames.add(FRAME_ID_V3_CONDUCTOR); supportedFrames.add(FRAME_ID_V3_CONTENT_GROUP_DESC); supportedFrames.add(FRAME_ID_V3_COPYRIGHTINFO); supportedFrames.add(FRAME_ID_V3_ENCODEDBY); supportedFrames.add(FRAME_ID_V3_ENCRYPTION); supportedFrames.add(FRAME_ID_V3_EQUALISATION); supportedFrames.add(FRAME_ID_V3_EVENT_TIMING_CODES); supportedFrames.add(FRAME_ID_V3_FILE_OWNER); supportedFrames.add(FRAME_ID_V3_FILE_TYPE); supportedFrames.add(FRAME_ID_V3_GENERAL_ENCAPS_OBJECT); supportedFrames.add(FRAME_ID_V3_GENRE); supportedFrames.add(FRAME_ID_V3_GROUP_ID_REG); supportedFrames.add(FRAME_ID_V3_HW_SW_SETTINGS); supportedFrames.add(FRAME_ID_V3_INITIAL_KEY); supportedFrames.add(FRAME_ID_V3_IPLS); supportedFrames.add(FRAME_ID_V3_ISRC); supportedFrames.add(FRAME_ID_V3_LANGUAGE); supportedFrames.add(FRAME_ID_V3_LENGTH); supportedFrames.add(FRAME_ID_V3_LINKED_INFO); supportedFrames.add(FRAME_ID_V3_LYRICIST); supportedFrames.add(FRAME_ID_V3_MEDIA_TYPE); supportedFrames.add(FRAME_ID_V3_MPEG_LOCATION_LOOKUP_TABLE); supportedFrames.add(FRAME_ID_V3_MUSIC_CD_ID); supportedFrames.add(FRAME_ID_V3_ORIGARTIST); supportedFrames.add(FRAME_ID_V3_ORIG_FILENAME); supportedFrames.add(FRAME_ID_V3_ORIG_LYRICIST); supportedFrames.add(FRAME_ID_V3_ORIG_TITLE); supportedFrames.add(FRAME_ID_V3_OWNERSHIP); supportedFrames.add(FRAME_ID_V3_PLAYLIST_DELAY); supportedFrames.add(FRAME_ID_V3_PLAY_COUNTER); supportedFrames.add(FRAME_ID_V3_POPULARIMETER); supportedFrames.add(FRAME_ID_V3_POSITION_SYNC); supportedFrames.add(FRAME_ID_V3_PRIVATE); supportedFrames.add(FRAME_ID_V3_PUBLISHER); supportedFrames.add(FRAME_ID_V3_RADIO_NAME); supportedFrames.add(FRAME_ID_V3_RADIO_OWNER); supportedFrames.add(FRAME_ID_V3_RECOMMENDED_BUFFER_SIZE); supportedFrames.add(FRAME_ID_V3_RELATIVE_VOLUME_ADJUSTMENT); supportedFrames.add(FRAME_ID_V3_REMIXED); supportedFrames.add(FRAME_ID_V3_REVERB); supportedFrames.add(FRAME_ID_V3_SET); supportedFrames.add(FRAME_ID_V3_SYNC_LYRIC); supportedFrames.add(FRAME_ID_V3_SYNC_TEMPO); supportedFrames.add(FRAME_ID_V3_TDAT); supportedFrames.add(FRAME_ID_V3_TERMS_OF_USE); supportedFrames.add(FRAME_ID_V3_TIME); supportedFrames.add(FRAME_ID_V3_TITLE); supportedFrames.add(FRAME_ID_V3_TITLE_REFINEMENT); supportedFrames.add(FRAME_ID_V3_TORY); supportedFrames.add(FRAME_ID_V3_TRACK); supportedFrames.add(FRAME_ID_V3_TRDA); supportedFrames.add(FRAME_ID_V3_TSIZ); supportedFrames.add(FRAME_ID_V3_TYER); supportedFrames.add(FRAME_ID_V3_UNIQUE_FILE_ID); supportedFrames.add(FRAME_ID_V3_UNSYNC_LYRICS); supportedFrames.add(FRAME_ID_V3_URL_ARTIST_WEB); supportedFrames.add(FRAME_ID_V3_URL_COMMERCIAL); supportedFrames.add(FRAME_ID_V3_URL_COPYRIGHT); supportedFrames.add(FRAME_ID_V3_URL_FILE_WEB); supportedFrames.add(FRAME_ID_V3_URL_OFFICIAL_RADIO); supportedFrames.add(FRAME_ID_V3_URL_PAYMENT); supportedFrames.add(FRAME_ID_V3_URL_PUBLISHERS); supportedFrames.add(FRAME_ID_V3_URL_SOURCE_WEB); supportedFrames.add(FRAME_ID_V3_USER_DEFINED_INFO); supportedFrames.add(FRAME_ID_V3_USER_DEFINED_URL); //Extension extensionFrames.add(FRAME_ID_V3_IS_COMPILATION); extensionFrames.add(FRAME_ID_V3_TITLE_SORT_ORDER_ITUNES); extensionFrames.add(FRAME_ID_V3_ARTIST_SORT_ORDER_ITUNES); extensionFrames.add(FRAME_ID_V3_ALBUM_SORT_ORDER_ITUNES); extensionFrames.add(FRAME_ID_V3_TITLE_SORT_ORDER_MUSICBRAINZ); extensionFrames.add(FRAME_ID_V3_ARTIST_SORT_ORDER_MUSICBRAINZ); extensionFrames.add(FRAME_ID_V3_ALBUM_SORT_ORDER_MUSICBRAINZ); extensionFrames.add(FRAME_ID_V3_ALBUM_ARTIST_SORT_ORDER_ITUNES); extensionFrames.add(FRAME_ID_V3_COMPOSER_SORT_ORDER_ITUNES); //Common commonFrames.add(FRAME_ID_V3_ARTIST); commonFrames.add(FRAME_ID_V3_ALBUM); commonFrames.add(FRAME_ID_V3_TITLE); commonFrames.add(FRAME_ID_V3_GENRE); commonFrames.add(FRAME_ID_V3_TRACK); commonFrames.add(FRAME_ID_V3_TYER); commonFrames.add(FRAME_ID_V3_COMMENT); //Binary binaryFrames.add(FRAME_ID_V3_ATTACHED_PICTURE); binaryFrames.add(FRAME_ID_V3_AUDIO_ENCRYPTION); binaryFrames.add(FRAME_ID_V3_ENCRYPTION); binaryFrames.add(FRAME_ID_V3_EQUALISATION); binaryFrames.add(FRAME_ID_V3_EVENT_TIMING_CODES); binaryFrames.add(FRAME_ID_V3_GENERAL_ENCAPS_OBJECT); binaryFrames.add(FRAME_ID_V3_RELATIVE_VOLUME_ADJUSTMENT); binaryFrames.add(FRAME_ID_V3_RECOMMENDED_BUFFER_SIZE); binaryFrames.add(FRAME_ID_V3_UNIQUE_FILE_ID); // Map frameid to a name idToValue.put(FRAME_ID_V3_ACCOMPANIMENT, "Text: Band/Orchestra/Accompaniment"); idToValue.put(FRAME_ID_V3_ALBUM, "Text: Album/Movie/Show title"); idToValue.put(FRAME_ID_V3_ARTIST, "Text: Lead artist(s)/Lead performer(s)/Soloist(s)/Performing group"); idToValue.put(FRAME_ID_V3_ATTACHED_PICTURE, "Attached picture"); idToValue.put(FRAME_ID_V3_AUDIO_ENCRYPTION, "Audio encryption"); idToValue.put(FRAME_ID_V3_BPM, "Text: BPM (Beats Per Minute)"); idToValue.put(FRAME_ID_V3_COMMENT, "Comments"); idToValue.put(FRAME_ID_V3_COMMERCIAL_FRAME, ""); idToValue.put(FRAME_ID_V3_COMPOSER, "Text: Composer"); idToValue.put(FRAME_ID_V3_CONDUCTOR, "Text: Conductor/Performer refinement"); idToValue.put(FRAME_ID_V3_CONTENT_GROUP_DESC, "Text: Content group description"); idToValue.put(FRAME_ID_V3_COPYRIGHTINFO, "Text: Copyright message"); idToValue.put(FRAME_ID_V3_ENCODEDBY, "Text: Encoded by"); idToValue.put(FRAME_ID_V3_ENCRYPTION, "Encryption method registration"); idToValue.put(FRAME_ID_V3_EQUALISATION, "Equalization"); idToValue.put(FRAME_ID_V3_EVENT_TIMING_CODES, "Event timing codes"); idToValue.put(FRAME_ID_V3_FILE_OWNER, ""); idToValue.put(FRAME_ID_V3_FILE_TYPE, "Text: File type"); idToValue.put(FRAME_ID_V3_GENERAL_ENCAPS_OBJECT, "General encapsulated datatype"); idToValue.put(FRAME_ID_V3_GENRE, "Text: Content type"); idToValue.put(FRAME_ID_V3_GROUP_ID_REG, ""); idToValue.put(FRAME_ID_V3_HW_SW_SETTINGS, "Text: Software/hardware and settings used for encoding"); idToValue.put(FRAME_ID_V3_INITIAL_KEY, "Text: Initial key"); idToValue.put(FRAME_ID_V3_IPLS, "Involved people list"); idToValue.put(FRAME_ID_V3_ISRC, "Text: ISRC (International Standard Recording Code)"); idToValue.put(FRAME_ID_V3_LANGUAGE, "Text: Language(s)"); idToValue.put(FRAME_ID_V3_LENGTH, "Text: Length"); idToValue.put(FRAME_ID_V3_LINKED_INFO, "Linked information"); idToValue.put(FRAME_ID_V3_LYRICIST, "Text: Lyricist/text writer"); idToValue.put(FRAME_ID_V3_MEDIA_TYPE, "Text: Media type"); idToValue.put(FRAME_ID_V3_MPEG_LOCATION_LOOKUP_TABLE, "MPEG location lookup table"); idToValue.put(FRAME_ID_V3_MUSIC_CD_ID, "Music CD Identifier"); idToValue.put(FRAME_ID_V3_ORIGARTIST, "Text: Original artist(s)/performer(s)"); idToValue.put(FRAME_ID_V3_ORIG_FILENAME, "Text: Original filename"); idToValue.put(FRAME_ID_V3_ORIG_LYRICIST, "Text: Original Lyricist(s)/text writer(s)"); idToValue.put(FRAME_ID_V3_ORIG_TITLE, "Text: Original album/Movie/Show title"); idToValue.put(FRAME_ID_V3_OWNERSHIP, ""); idToValue.put(FRAME_ID_V3_PLAYLIST_DELAY, "Text: Playlist delay"); idToValue.put(FRAME_ID_V3_PLAY_COUNTER, "Play counter"); idToValue.put(FRAME_ID_V3_POPULARIMETER, "Popularimeter"); idToValue.put(FRAME_ID_V3_POSITION_SYNC, "Position Sync"); idToValue.put(FRAME_ID_V3_PRIVATE, "Private frame"); idToValue.put(FRAME_ID_V3_PUBLISHER, "Text: Publisher"); idToValue.put(FRAME_ID_V3_RADIO_NAME, ""); idToValue.put(FRAME_ID_V3_RADIO_OWNER, ""); idToValue.put(FRAME_ID_V3_RECOMMENDED_BUFFER_SIZE, "Recommended buffer size"); idToValue.put(FRAME_ID_V3_RELATIVE_VOLUME_ADJUSTMENT, "Relative volume adjustment"); idToValue.put(FRAME_ID_V3_REMIXED, "Text: Interpreted, remixed, or otherwise modified by"); idToValue.put(FRAME_ID_V3_REVERB, "Reverb"); idToValue.put(FRAME_ID_V3_SET, "Text: Part of a setField"); idToValue.put(FRAME_ID_V3_SYNC_LYRIC, "Synchronized lyric/text"); idToValue.put(FRAME_ID_V3_SYNC_TEMPO, "Synced tempo codes"); idToValue.put(FRAME_ID_V3_TDAT, "Text: Date"); idToValue.put(FRAME_ID_V3_TERMS_OF_USE, ""); idToValue.put(FRAME_ID_V3_TIME, "Text: Time"); idToValue.put(FRAME_ID_V3_TITLE, "Text: Title/Songname/Content description"); idToValue.put(FRAME_ID_V3_TITLE_REFINEMENT, "Text: Subtitle/Description refinement"); idToValue.put(FRAME_ID_V3_TORY, "Text: Original release year"); idToValue.put(FRAME_ID_V3_TRACK, "Text: Track number/Position in setField"); idToValue.put(FRAME_ID_V3_TRDA, "Text: Recording dates"); idToValue.put(FRAME_ID_V3_TSIZ, "Text: Size"); idToValue.put(FRAME_ID_V3_TYER, "Text: Year"); idToValue.put(FRAME_ID_V3_UNIQUE_FILE_ID, "Unique file identifier"); idToValue.put(FRAME_ID_V3_UNSYNC_LYRICS, "Unsychronized lyric/text transcription"); idToValue.put(FRAME_ID_V3_URL_ARTIST_WEB, "URL: Official artist/performer webpage"); idToValue.put(FRAME_ID_V3_URL_COMMERCIAL, "URL: Commercial information"); idToValue.put(FRAME_ID_V3_URL_COPYRIGHT, "URL: Copyright/Legal information"); idToValue.put(FRAME_ID_V3_URL_FILE_WEB, "URL: Official audio file webpage"); idToValue.put(FRAME_ID_V3_URL_OFFICIAL_RADIO, "Official Radio"); idToValue.put(FRAME_ID_V3_URL_PAYMENT, "URL: Payment"); idToValue.put(FRAME_ID_V3_URL_PUBLISHERS, "URL: Publishers official webpage"); idToValue.put(FRAME_ID_V3_URL_SOURCE_WEB, "URL: Official audio source webpage"); idToValue.put(FRAME_ID_V3_USER_DEFINED_INFO, "User defined text information frame"); idToValue.put(FRAME_ID_V3_USER_DEFINED_URL, "User defined URL link frame"); idToValue.put(FRAME_ID_V3_IS_COMPILATION, "Is Compilation"); idToValue.put(FRAME_ID_V3_TITLE_SORT_ORDER_ITUNES, "Text: title sort order"); idToValue.put(FRAME_ID_V3_ARTIST_SORT_ORDER_ITUNES, "Text: artist sort order"); idToValue.put(FRAME_ID_V3_ALBUM_SORT_ORDER_ITUNES, "Text: album sort order"); idToValue.put(FRAME_ID_V3_TITLE_SORT_ORDER_MUSICBRAINZ, "Text: title sort order"); idToValue.put(FRAME_ID_V3_ARTIST_SORT_ORDER_MUSICBRAINZ, "Text: artist sort order"); idToValue.put(FRAME_ID_V3_ALBUM_SORT_ORDER_MUSICBRAINZ, "Text: album sort order"); idToValue.put(FRAME_ID_V3_ALBUM_ARTIST_SORT_ORDER_ITUNES, "Text:Album Artist Sort Order Frame"); idToValue.put(FRAME_ID_V3_COMPOSER_SORT_ORDER_ITUNES, "Text:Composer Sort Order Frame"); createMaps(); multipleFrames.add(FRAME_ID_V3_USER_DEFINED_INFO); multipleFrames.add(FRAME_ID_V3_USER_DEFINED_URL); multipleFrames.add(FRAME_ID_V3_ATTACHED_PICTURE); multipleFrames.add(FRAME_ID_V3_PRIVATE); multipleFrames.add(FRAME_ID_V3_COMMENT); multipleFrames.add(FRAME_ID_V3_UNIQUE_FILE_ID); multipleFrames.add(FRAME_ID_V3_UNSYNC_LYRICS); multipleFrames.add(FRAME_ID_V3_POPULARIMETER); multipleFrames.add(FRAME_ID_V3_GENERAL_ENCAPS_OBJECT); discardIfFileAlteredFrames.add(FRAME_ID_V3_EVENT_TIMING_CODES); discardIfFileAlteredFrames.add(FRAME_ID_V3_EQUALISATION); discardIfFileAlteredFrames.add(FRAME_ID_V3_MPEG_LOCATION_LOOKUP_TABLE); discardIfFileAlteredFrames.add(FRAME_ID_V3_POSITION_SYNC); discardIfFileAlteredFrames.add(FRAME_ID_V3_SYNC_LYRIC); discardIfFileAlteredFrames.add(FRAME_ID_V3_SYNC_TEMPO); discardIfFileAlteredFrames.add(FRAME_ID_V3_RELATIVE_VOLUME_ADJUSTMENT); discardIfFileAlteredFrames.add(FRAME_ID_V3_EVENT_TIMING_CODES); discardIfFileAlteredFrames.add(FRAME_ID_V3_ENCODEDBY); discardIfFileAlteredFrames.add(FRAME_ID_V3_LENGTH); discardIfFileAlteredFrames.add(FRAME_ID_V3_TSIZ); //Mapping from generic key tagFieldToId3.put(FieldKey.ALBUM, ID3v23FieldKey.ALBUM); tagFieldToId3.put(FieldKey.ALBUM_ARTIST, ID3v23FieldKey.ALBUM_ARTIST); tagFieldToId3.put(FieldKey.ALBUM_ARTIST_SORT, ID3v23FieldKey.ALBUM_ARTIST_SORT); tagFieldToId3.put(FieldKey.ALBUM_SORT, ID3v23FieldKey.ALBUM_SORT); tagFieldToId3.put(FieldKey.AMAZON_ID, ID3v23FieldKey.AMAZON_ID); tagFieldToId3.put(FieldKey.ARTIST, ID3v23FieldKey.ARTIST); tagFieldToId3.put(FieldKey.ARTIST_SORT, ID3v23FieldKey.ARTIST_SORT); tagFieldToId3.put(FieldKey.BARCODE, ID3v23FieldKey.BARCODE); tagFieldToId3.put(FieldKey.BPM, ID3v23FieldKey.BPM); tagFieldToId3.put(FieldKey.CATALOG_NO, ID3v23FieldKey.CATALOG_NO); tagFieldToId3.put(FieldKey.COMMENT, ID3v23FieldKey.COMMENT); tagFieldToId3.put(FieldKey.COMPOSER, ID3v23FieldKey.COMPOSER); tagFieldToId3.put(FieldKey.COMPOSER_SORT, ID3v23FieldKey.COMPOSER_SORT); tagFieldToId3.put(FieldKey.CONDUCTOR, ID3v23FieldKey.CONDUCTOR); tagFieldToId3.put(FieldKey.COVER_ART, ID3v23FieldKey.COVER_ART); tagFieldToId3.put(FieldKey.CUSTOM1, ID3v23FieldKey.CUSTOM1); tagFieldToId3.put(FieldKey.CUSTOM2, ID3v23FieldKey.CUSTOM2); tagFieldToId3.put(FieldKey.CUSTOM3, ID3v23FieldKey.CUSTOM3); tagFieldToId3.put(FieldKey.CUSTOM4, ID3v23FieldKey.CUSTOM4); tagFieldToId3.put(FieldKey.CUSTOM5, ID3v23FieldKey.CUSTOM5); tagFieldToId3.put(FieldKey.DISC_NO, ID3v23FieldKey.DISC_NO); tagFieldToId3.put(FieldKey.DISC_TOTAL, ID3v23FieldKey.DISC_NO); tagFieldToId3.put(FieldKey.ENCODER, ID3v23FieldKey.ENCODER); tagFieldToId3.put(FieldKey.FBPM, ID3v23FieldKey.FBPM); tagFieldToId3.put(FieldKey.GENRE, ID3v23FieldKey.GENRE); tagFieldToId3.put(FieldKey.GROUPING, ID3v23FieldKey.GROUPING); tagFieldToId3.put(FieldKey.ISRC, ID3v23FieldKey.ISRC); tagFieldToId3.put(FieldKey.IS_COMPILATION, ID3v23FieldKey.IS_COMPILATION); tagFieldToId3.put(FieldKey.KEY, ID3v23FieldKey.KEY); tagFieldToId3.put(FieldKey.LANGUAGE, ID3v23FieldKey.LANGUAGE); tagFieldToId3.put(FieldKey.LYRICIST, ID3v23FieldKey.LYRICIST); tagFieldToId3.put(FieldKey.LYRICS, ID3v23FieldKey.LYRICS); tagFieldToId3.put(FieldKey.MEDIA, ID3v23FieldKey.MEDIA); tagFieldToId3.put(FieldKey.MOOD,ID3v23FieldKey.MOOD); tagFieldToId3.put(FieldKey.MUSICBRAINZ_ARTISTID, ID3v23FieldKey.MUSICBRAINZ_ARTISTID); tagFieldToId3.put(FieldKey.MUSICBRAINZ_DISC_ID, ID3v23FieldKey.MUSICBRAINZ_DISC_ID); tagFieldToId3.put(FieldKey.MUSICBRAINZ_RELEASEARTISTID, ID3v23FieldKey.MUSICBRAINZ_RELEASEARTISTID); tagFieldToId3.put(FieldKey.MUSICBRAINZ_RELEASEID, ID3v23FieldKey.MUSICBRAINZ_RELEASEID); tagFieldToId3.put(FieldKey.MUSICBRAINZ_RELEASE_COUNTRY, ID3v23FieldKey.MUSICBRAINZ_RELEASE_COUNTRY); tagFieldToId3.put(FieldKey.MUSICBRAINZ_RELEASE_GROUP_ID, ID3v23FieldKey.MUSICBRAINZ_RELEASE_GROUP_ID); tagFieldToId3.put(FieldKey.MUSICBRAINZ_RELEASE_STATUS, ID3v23FieldKey.MUSICBRAINZ_RELEASE_STATUS); tagFieldToId3.put(FieldKey.MUSICBRAINZ_RELEASE_TYPE, ID3v23FieldKey.MUSICBRAINZ_RELEASE_TYPE); tagFieldToId3.put(FieldKey.MUSICBRAINZ_TRACK_ID, ID3v23FieldKey.MUSICBRAINZ_TRACK_ID); tagFieldToId3.put(FieldKey.MUSICBRAINZ_WORK_ID, ID3v23FieldKey.MUSICBRAINZ_WORK_ID); tagFieldToId3.put(FieldKey.MUSICIP_ID, ID3v23FieldKey.MUSICIP_ID); tagFieldToId3.put(FieldKey.OCCASION, ID3v23FieldKey.OCCASION); tagFieldToId3.put(FieldKey.ORIGINAL_ALBUM, ID3v23FieldKey.ORIGINAL_ALBUM); tagFieldToId3.put(FieldKey.ORIGINAL_ARTIST, ID3v23FieldKey.ORIGINAL_ARTIST); tagFieldToId3.put(FieldKey.ORIGINAL_LYRICIST, ID3v23FieldKey.ORIGINAL_LYRICIST); tagFieldToId3.put(FieldKey.ORIGINAL_YEAR, ID3v23FieldKey.ORIGINAL_YEAR); tagFieldToId3.put(FieldKey.QUALITY, ID3v23FieldKey.QUALITY); tagFieldToId3.put(FieldKey.RATING, ID3v23FieldKey.RATING); tagFieldToId3.put(FieldKey.RECORD_LABEL, ID3v23FieldKey.RECORD_LABEL); tagFieldToId3.put(FieldKey.REMIXER, ID3v23FieldKey.REMIXER); tagFieldToId3.put(FieldKey.SCRIPT, ID3v23FieldKey.SCRIPT); tagFieldToId3.put(FieldKey.TAGS, ID3v23FieldKey.TAGS); tagFieldToId3.put(FieldKey.TEMPO, ID3v23FieldKey.TEMPO); tagFieldToId3.put(FieldKey.TITLE, ID3v23FieldKey.TITLE); tagFieldToId3.put(FieldKey.TITLE_SORT, ID3v23FieldKey.TITLE_SORT); tagFieldToId3.put(FieldKey.TRACK, ID3v23FieldKey.TRACK); tagFieldToId3.put(FieldKey.TRACK_TOTAL, ID3v23FieldKey.TRACK_TOTAL); tagFieldToId3.put(FieldKey.URL_DISCOGS_ARTIST_SITE, ID3v23FieldKey.URL_DISCOGS_ARTIST_SITE); tagFieldToId3.put(FieldKey.URL_DISCOGS_RELEASE_SITE, ID3v23FieldKey.URL_DISCOGS_RELEASE_SITE); tagFieldToId3.put(FieldKey.URL_LYRICS_SITE, ID3v23FieldKey.URL_LYRICS_SITE); tagFieldToId3.put(FieldKey.URL_OFFICIAL_ARTIST_SITE, ID3v23FieldKey.URL_OFFICIAL_ARTIST_SITE); tagFieldToId3.put(FieldKey.URL_OFFICIAL_RELEASE_SITE, ID3v23FieldKey.URL_OFFICIAL_RELEASE_SITE); tagFieldToId3.put(FieldKey.URL_WIKIPEDIA_ARTIST_SITE, ID3v23FieldKey.URL_WIKIPEDIA_ARTIST_SITE); tagFieldToId3.put(FieldKey.URL_WIKIPEDIA_RELEASE_SITE, ID3v23FieldKey.URL_WIKIPEDIA_RELEASE_SITE); tagFieldToId3.put(FieldKey.YEAR, ID3v23FieldKey.YEAR); tagFieldToId3.put(FieldKey.ENGINEER, ID3v23FieldKey.ENGINEER); tagFieldToId3.put(FieldKey.PRODUCER, ID3v23FieldKey.PRODUCER); tagFieldToId3.put(FieldKey.MIXER, ID3v23FieldKey.MIXER); tagFieldToId3.put(FieldKey.DJMIXER, ID3v23FieldKey.DJMIXER); tagFieldToId3.put(FieldKey.ARRANGER, ID3v23FieldKey.ARRANGER); } /** * @param genericKey * @return id3 key for generic key */ public ID3v23FieldKey getId3KeyFromGenericKey(FieldKey genericKey) { return tagFieldToId3.get(genericKey); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/ID3v24FieldKey.java0000644000175000017500000002041411470746136026145 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3; import org.jaudiotagger.tag.id3.framebody.*; /** * List of known id3v24 metadata fields *

*

These provide a mapping from the generic key to the underlying ID3v24frames. For example most of the Musicbrainz * fields are implemented using a User Defined Text Info Frame, but with a different description key, so this * enum provides the link between the two. */ public enum ID3v24FieldKey { ALBUM(ID3v24Frames.FRAME_ID_ALBUM, Id3FieldType.TEXT), ALBUM_ARTIST(ID3v24Frames.FRAME_ID_ACCOMPANIMENT, Id3FieldType.TEXT), ALBUM_ARTIST_SORT(ID3v24Frames.FRAME_ID_ALBUM_ARTIST_SORT_ORDER_ITUNES, Id3FieldType.TEXT), ALBUM_SORT(ID3v24Frames.FRAME_ID_ALBUM_SORT_ORDER, Id3FieldType.TEXT), AMAZON_ID(ID3v24Frames.FRAME_ID_USER_DEFINED_INFO, FrameBodyTXXX.AMAZON_ASIN, Id3FieldType.TEXT), ARTIST(ID3v24Frames.FRAME_ID_ARTIST, Id3FieldType.TEXT), ARTIST_SORT(ID3v24Frames.FRAME_ID_ARTIST_SORT_ORDER, Id3FieldType.TEXT), BARCODE(ID3v24Frames.FRAME_ID_USER_DEFINED_INFO, FrameBodyTXXX.BARCODE, Id3FieldType.TEXT), BPM(ID3v24Frames.FRAME_ID_BPM, Id3FieldType.TEXT), CATALOG_NO(ID3v24Frames.FRAME_ID_USER_DEFINED_INFO, FrameBodyTXXX.CATALOG_NO, Id3FieldType.TEXT), COMMENT(ID3v24Frames.FRAME_ID_COMMENT, Id3FieldType.TEXT), COMPOSER(ID3v24Frames.FRAME_ID_COMPOSER, Id3FieldType.TEXT), COMPOSER_SORT(ID3v24Frames.FRAME_ID_COMPOSER_SORT_ORDER_ITUNES, Id3FieldType.TEXT), CONDUCTOR(ID3v24Frames.FRAME_ID_CONDUCTOR, Id3FieldType.TEXT), COVER_ART(ID3v24Frames.FRAME_ID_ATTACHED_PICTURE, Id3FieldType.BINARY), CUSTOM1(ID3v24Frames.FRAME_ID_COMMENT, FrameBodyCOMM.MM_CUSTOM1,Id3FieldType.TEXT), CUSTOM2(ID3v24Frames.FRAME_ID_COMMENT, FrameBodyCOMM.MM_CUSTOM2,Id3FieldType.TEXT), CUSTOM3(ID3v24Frames.FRAME_ID_COMMENT, FrameBodyCOMM.MM_CUSTOM3,Id3FieldType.TEXT), CUSTOM4(ID3v24Frames.FRAME_ID_COMMENT, FrameBodyCOMM.MM_CUSTOM4,Id3FieldType.TEXT), CUSTOM5(ID3v24Frames.FRAME_ID_COMMENT, FrameBodyCOMM.MM_CUSTOM5,Id3FieldType.TEXT), DISC_NO(ID3v24Frames.FRAME_ID_SET, Id3FieldType.TEXT), DISC_TOTAL(ID3v24Frames.FRAME_ID_SET, Id3FieldType.TEXT), ENCODER(ID3v24Frames.FRAME_ID_ENCODEDBY, Id3FieldType.TEXT), FBPM(ID3v24Frames.FRAME_ID_USER_DEFINED_INFO, FrameBodyTXXX.FBPM, Id3FieldType.TEXT), GENRE(ID3v24Frames.FRAME_ID_GENRE, Id3FieldType.TEXT), GROUPING(ID3v24Frames.FRAME_ID_CONTENT_GROUP_DESC, Id3FieldType.TEXT), ISRC(ID3v24Frames.FRAME_ID_ISRC, Id3FieldType.TEXT), IS_COMPILATION(ID3v24Frames.FRAME_ID_IS_COMPILATION, Id3FieldType.TEXT), KEY(ID3v24Frames.FRAME_ID_INITIAL_KEY,Id3FieldType.TEXT), LANGUAGE(ID3v24Frames.FRAME_ID_LANGUAGE,Id3FieldType.TEXT), LYRICIST(ID3v24Frames.FRAME_ID_LYRICIST, Id3FieldType.TEXT), LYRICS(ID3v24Frames.FRAME_ID_UNSYNC_LYRICS, Id3FieldType.TEXT), MEDIA(ID3v24Frames.FRAME_ID_MEDIA_TYPE, Id3FieldType.TEXT), MOOD(ID3v24Frames.FRAME_ID_MOOD, Id3FieldType.TEXT), MUSICBRAINZ_ARTISTID(ID3v24Frames.FRAME_ID_USER_DEFINED_INFO, FrameBodyTXXX.MUSICBRAINZ_ARTISTID, Id3FieldType.TEXT), MUSICBRAINZ_DISC_ID(ID3v24Frames.FRAME_ID_USER_DEFINED_INFO, FrameBodyTXXX.MUSICBRAINZ_DISCID, Id3FieldType.TEXT), MUSICBRAINZ_RELEASEARTISTID(ID3v24Frames.FRAME_ID_USER_DEFINED_INFO, FrameBodyTXXX.MUSICBRAINZ_ALBUM_ARTISTID, Id3FieldType.TEXT), MUSICBRAINZ_RELEASEID(ID3v24Frames.FRAME_ID_USER_DEFINED_INFO, FrameBodyTXXX.MUSICBRAINZ_ALBUMID, Id3FieldType.TEXT), MUSICBRAINZ_RELEASE_COUNTRY(ID3v24Frames.FRAME_ID_USER_DEFINED_INFO, FrameBodyTXXX.MUSICBRAINZ_ALBUM_COUNTRY, Id3FieldType.TEXT), MUSICBRAINZ_RELEASE_GROUP_ID(ID3v24Frames.FRAME_ID_USER_DEFINED_INFO, FrameBodyTXXX.MUSICBRAINZ_RELEASE_GROUPID, Id3FieldType.TEXT), MUSICBRAINZ_RELEASE_STATUS(ID3v24Frames.FRAME_ID_USER_DEFINED_INFO, FrameBodyTXXX.MUSICBRAINZ_ALBUM_STATUS, Id3FieldType.TEXT), MUSICBRAINZ_RELEASE_TYPE(ID3v24Frames.FRAME_ID_USER_DEFINED_INFO, FrameBodyTXXX.MUSICBRAINZ_ALBUM_TYPE, Id3FieldType.TEXT), MUSICBRAINZ_TRACK_ID(ID3v24Frames.FRAME_ID_UNIQUE_FILE_ID, FrameBodyUFID.UFID_MUSICBRAINZ, Id3FieldType.TEXT), MUSICBRAINZ_WORK_ID(ID3v24Frames.FRAME_ID_USER_DEFINED_INFO, FrameBodyTXXX.MUSICBRAINZ_WORKID, Id3FieldType.TEXT), MUSICIP_ID(ID3v24Frames.FRAME_ID_USER_DEFINED_INFO, FrameBodyTXXX.MUSICIP_ID, Id3FieldType.TEXT), OCCASION(ID3v24Frames.FRAME_ID_COMMENT, FrameBodyCOMM.MM_OCCASION,Id3FieldType.TEXT), ORIGINAL_ALBUM(ID3v24Frames.FRAME_ID_ORIG_TITLE, Id3FieldType.TEXT), ORIGINAL_ARTIST(ID3v24Frames.FRAME_ID_ORIGARTIST, Id3FieldType.TEXT), ORIGINAL_LYRICIST(ID3v24Frames.FRAME_ID_ORIG_LYRICIST, Id3FieldType.TEXT), ORIGINAL_YEAR(ID3v24Frames.FRAME_ID_ORIGINAL_RELEASE_TIME, Id3FieldType.TEXT), QUALITY(ID3v24Frames.FRAME_ID_COMMENT, FrameBodyCOMM.MM_QUALITY,Id3FieldType.TEXT), RATING(ID3v24Frames.FRAME_ID_POPULARIMETER, Id3FieldType.TEXT), RECORD_LABEL(ID3v24Frames.FRAME_ID_PUBLISHER, Id3FieldType.TEXT), REMIXER(ID3v24Frames.FRAME_ID_REMIXED, Id3FieldType.TEXT), SCRIPT(ID3v24Frames.FRAME_ID_USER_DEFINED_INFO, FrameBodyTXXX.SCRIPT, Id3FieldType.TEXT), TAGS(ID3v24Frames.FRAME_ID_USER_DEFINED_INFO, FrameBodyTXXX.TAGS, Id3FieldType.TEXT), TEMPO(ID3v24Frames.FRAME_ID_COMMENT, FrameBodyCOMM.MM_TEMPO,Id3FieldType.TEXT), TITLE(ID3v24Frames.FRAME_ID_TITLE, Id3FieldType.TEXT), TITLE_SORT(ID3v24Frames.FRAME_ID_TITLE_SORT_ORDER, Id3FieldType.TEXT), TRACK(ID3v24Frames.FRAME_ID_TRACK, Id3FieldType.TEXT), TRACK_TOTAL(ID3v24Frames.FRAME_ID_TRACK, Id3FieldType.TEXT), URL_DISCOGS_ARTIST_SITE(ID3v24Frames.FRAME_ID_USER_DEFINED_URL, FrameBodyWXXX.URL_DISCOGS_ARTIST_SITE, Id3FieldType.TEXT), URL_DISCOGS_RELEASE_SITE(ID3v24Frames.FRAME_ID_USER_DEFINED_URL, FrameBodyWXXX.URL_DISCOGS_RELEASE_SITE, Id3FieldType.TEXT), URL_LYRICS_SITE(ID3v24Frames.FRAME_ID_USER_DEFINED_URL, FrameBodyWXXX.URL_LYRICS_SITE, Id3FieldType.TEXT), URL_OFFICIAL_ARTIST_SITE(ID3v24Frames.FRAME_ID_URL_ARTIST_WEB, Id3FieldType.TEXT), URL_OFFICIAL_RELEASE_SITE(ID3v24Frames.FRAME_ID_USER_DEFINED_URL, FrameBodyWXXX.URL_OFFICIAL_RELEASE_SITE, Id3FieldType.TEXT), URL_WIKIPEDIA_ARTIST_SITE(ID3v24Frames.FRAME_ID_USER_DEFINED_URL, FrameBodyWXXX.URL_WIKIPEDIA_ARTIST_SITE, Id3FieldType.TEXT), URL_WIKIPEDIA_RELEASE_SITE(ID3v24Frames.FRAME_ID_USER_DEFINED_URL, FrameBodyWXXX.URL_WIKIPEDIA_RELEASE_SITE, Id3FieldType.TEXT), YEAR(ID3v24Frames.FRAME_ID_YEAR, Id3FieldType.TEXT), ENGINEER(ID3v24Frames.FRAME_ID_INVOLVED_PEOPLE, FrameBodyTIPL.ENGINEER, Id3FieldType.TEXT), PRODUCER(ID3v24Frames.FRAME_ID_INVOLVED_PEOPLE, FrameBodyTIPL.PRODUCER, Id3FieldType.TEXT), MIXER(ID3v24Frames.FRAME_ID_INVOLVED_PEOPLE, FrameBodyTIPL.MIXER, Id3FieldType.TEXT), DJMIXER(ID3v24Frames.FRAME_ID_INVOLVED_PEOPLE, FrameBodyTIPL.DJMIXER, Id3FieldType.TEXT), ARRANGER(ID3v24Frames.FRAME_ID_INVOLVED_PEOPLE, FrameBodyTIPL.ARRANGER, Id3FieldType.TEXT), ; private String fieldName; private String frameId; private String subId; private Id3FieldType fieldType; /** * For usual metadata fields that use a data field * * @param frameId the frame that will be used * @param fieldType of data atom */ ID3v24FieldKey(String frameId, Id3FieldType fieldType) { this.frameId = frameId; this.fieldType = fieldType; this.fieldName = frameId; } /** * @param frameId the frame that will be used * @param subId the additional key required within the frame to uniquely identify this key * @param fieldType */ ID3v24FieldKey(String frameId, String subId, Id3FieldType fieldType) { this.frameId = frameId; this.subId = subId; this.fieldType = fieldType; this.fieldName = frameId + ":" + subId; } /** * @return fieldtype */ public Id3FieldType getFieldType() { return fieldType; } /** * This is the frame identifier used to write the field * * @return */ public String getFrameId() { return frameId; } /** * This is the subfield used within the frame for this type of field * * @return subId */ public String getSubId() { return subId; } /** * This is the value of the key that can uniquely identifer a key type * * @return */ public String getFieldName() { return fieldName; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/ID3v11Tag.java0000644000175000017500000004515111470746136025165 0ustar drazzibdrazzib/** * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: ID3v11Tag.java 929 2010-11-17 12:36:46Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Description: * This class is for a ID3v1.1 Tag * */ package org.jaudiotagger.tag.id3; import org.jaudiotagger.audio.generic.Utils; import org.jaudiotagger.audio.mp3.MP3File; import org.jaudiotagger.logging.ErrorMessage; import org.jaudiotagger.tag.*; import org.jaudiotagger.tag.id3.framebody.*; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.List; import java.util.logging.Level; import java.util.regex.Matcher; /** * Represents an ID3v11 tag. * * @author : Eric Farng * @author : Paul Taylor */ public class ID3v11Tag extends ID3v1Tag { //For writing output protected static final String TYPE_TRACK = "track"; protected static final int TRACK_UNDEFINED = 0; protected static final int TRACK_MAX_VALUE = 255; protected static final int TRACK_MIN_VALUE = 1; protected static final int FIELD_COMMENT_LENGTH = 28; protected static final int FIELD_COMMENT_POS = 97; protected static final int FIELD_TRACK_INDICATOR_LENGTH = 1; protected static final int FIELD_TRACK_INDICATOR_POS = 125; protected static final int FIELD_TRACK_LENGTH = 1; protected static final int FIELD_TRACK_POS = 126; /** * Track is held as a single byte in v1.1 */ protected byte track = (byte) TRACK_UNDEFINED; private static final byte RELEASE = 1; private static final byte MAJOR_VERSION = 1; private static final byte REVISION = 0; /** * Retrieve the Release */ public byte getRelease() { return RELEASE; } /** * Retrieve the Major Version */ public byte getMajorVersion() { return MAJOR_VERSION; } /** * Retrieve the Revision */ public byte getRevision() { return REVISION; } /** * Creates a new ID3v11 datatype. */ public ID3v11Tag() { } public int getFieldCount() { return 7; } public ID3v11Tag(ID3v11Tag copyObject) { super(copyObject); this.track = copyObject.track; } /** * Creates a new ID3v11 datatype from a non v11 tag * * @param mp3tag * @throws UnsupportedOperationException */ public ID3v11Tag(AbstractTag mp3tag) { if (mp3tag != null) { if (mp3tag instanceof ID3v1Tag) { if (mp3tag instanceof ID3v11Tag) { throw new UnsupportedOperationException("Copy Constructor not called. Please type cast the argument"); } // id3v1_1 objects are also id3v1 objects ID3v1Tag id3old = (ID3v1Tag) mp3tag; this.title = id3old.title; this.artist = id3old.artist; this.album = id3old.album; this.comment = id3old.comment; this.year = id3old.year; this.genre = id3old.genre; } else { ID3v24Tag id3tag; // first change the tag to ID3v2_4 tag if not one already if (!(mp3tag instanceof ID3v24Tag)) { id3tag = new ID3v24Tag(mp3tag); } else { id3tag = (ID3v24Tag) mp3tag; } ID3v24Frame frame; String text; if (id3tag.hasFrame(ID3v24Frames.FRAME_ID_TITLE)) { frame = (ID3v24Frame) id3tag.getFrame(ID3v24Frames.FRAME_ID_TITLE); text = ((FrameBodyTIT2) frame.getBody()).getText(); this.title = ID3Tags.truncate(text, FIELD_TITLE_LENGTH); } if (id3tag.hasFrame(ID3v24Frames.FRAME_ID_ARTIST)) { frame = (ID3v24Frame) id3tag.getFrame(ID3v24Frames.FRAME_ID_ARTIST); text = ((FrameBodyTPE1) frame.getBody()).getText(); this.artist = ID3Tags.truncate(text, FIELD_ARTIST_LENGTH); } if (id3tag.hasFrame(ID3v24Frames.FRAME_ID_ALBUM)) { frame = (ID3v24Frame) id3tag.getFrame(ID3v24Frames.FRAME_ID_ALBUM); text = ((FrameBodyTALB) frame.getBody()).getText(); this.album = ID3Tags.truncate(text, FIELD_ALBUM_LENGTH); } if (id3tag.hasFrame(ID3v24Frames.FRAME_ID_YEAR)) { frame = (ID3v24Frame) id3tag.getFrame(ID3v24Frames.FRAME_ID_YEAR); text = ((FrameBodyTDRC) frame.getBody()).getText(); this.year = ID3Tags.truncate(text, FIELD_YEAR_LENGTH); } if (id3tag.hasFrame(ID3v24Frames.FRAME_ID_COMMENT)) { Iterator iterator = id3tag.getFrameOfType(ID3v24Frames.FRAME_ID_COMMENT); text = ""; while (iterator.hasNext()) { frame = (ID3v24Frame) iterator.next(); text += (((FrameBodyCOMM) frame.getBody()).getText() + " "); } this.comment = ID3Tags.truncate(text, FIELD_COMMENT_LENGTH); } if (id3tag.hasFrame(ID3v24Frames.FRAME_ID_GENRE)) { frame = (ID3v24Frame) id3tag.getFrame(ID3v24Frames.FRAME_ID_GENRE); text = ((FrameBodyTCON) frame.getBody()).getText(); try { this.genre = (byte) ID3Tags.findNumber(text); } catch (TagException ex) { logger.log(Level.WARNING, getLoggingFilename() + ":" + "Unable to convert TCON frame to format suitable for v11 tag", ex); this.genre = (byte) ID3v1Tag.GENRE_UNDEFINED; } } if (id3tag.hasFrame(ID3v24Frames.FRAME_ID_TRACK)) { frame = (ID3v24Frame) id3tag.getFrame(ID3v24Frames.FRAME_ID_TRACK); this.track = (byte) ((FrameBodyTRCK) frame.getBody()).getTrackNo().intValue(); } } } } /** * Creates a new ID3v11 datatype. * * @param file * @param loggingFilename * @throws TagNotFoundException * @throws IOException */ public ID3v11Tag(RandomAccessFile file, String loggingFilename) throws TagNotFoundException, IOException { setLoggingFilename(loggingFilename); FileChannel fc; ByteBuffer byteBuffer = ByteBuffer.allocate(TAG_LENGTH); fc = file.getChannel(); fc.position(file.length() - TAG_LENGTH); fc.read(byteBuffer); byteBuffer.flip(); read(byteBuffer); } /** * Creates a new ID3v11 datatype. * * @param file * @throws TagNotFoundException * @throws IOException * @deprecated use {@link #ID3v11Tag(RandomAccessFile,String)} instead */ public ID3v11Tag(RandomAccessFile file) throws TagNotFoundException, IOException { this(file, ""); } /** * Set Comment * * @param comment */ public void setComment(String comment) { if (comment == null) { throw new IllegalArgumentException(ErrorMessage.GENERAL_INVALID_NULL_ARGUMENT.getMsg()); } this.comment = ID3Tags.truncate(comment, FIELD_COMMENT_LENGTH); } /** * Get Comment * * @return comment */ public String getFirstComment() { return comment; } /** * Set the track, v11 stores track numbers in a single byte value so can only * handle a simple number in the range 0-255. * * @param trackValue */ public void setTrack(String trackValue) { int trackAsInt; //Try and convert String representation of track into an integer try { trackAsInt = Integer.parseInt(trackValue); } catch (NumberFormatException e) { trackAsInt = 0; } //This value cannot be held in v1_1 if ((trackAsInt > TRACK_MAX_VALUE) || (trackAsInt < TRACK_MIN_VALUE)) { this.track = (byte) TRACK_UNDEFINED; } else { this.track = (byte) Integer.parseInt(trackValue); } } /** * Return the track number as a String. * * @return track */ public String getFirstTrack() { return String.valueOf(track & BYTE_TO_UNSIGNED); } public void addTrack(String track) { setTrack(track); } public List getTrack() { if (getFirst(FieldKey.TRACK).length() > 0) { ID3v1TagField field = new ID3v1TagField(ID3v1FieldKey.TRACK.name(), getFirst(FieldKey.TRACK)); return returnFieldToList(field); } else { return new ArrayList(); } } public void setField(TagField field) { FieldKey genericKey = FieldKey.valueOf(field.getId()); if (genericKey == FieldKey.TRACK) { setTrack(field.toString()); } else { super.setField(field); } } public List getFields(FieldKey genericKey) { if (genericKey == FieldKey.TRACK) { return getTrack(); } else { return super.getFields(genericKey); } } public String getFirst(FieldKey genericKey) { switch (genericKey) { case ARTIST: return getFirstArtist(); case ALBUM: return getFirstAlbum(); case TITLE: return getFirstTitle(); case GENRE: return getFirstGenre(); case YEAR: return getFirstYear(); case TRACK: return getFirstTrack(); case COMMENT: return getFirstComment(); default: return ""; } } public TagField getFirstField(String id) { List results; if (FieldKey.TRACK.name().equals(id)) { results = getTrack(); if (results != null) { if (results.size() > 0) { return results.get(0); } } return null; } else { return super.getFirstField(id); } } public boolean isEmpty() { return track <= 0 && super.isEmpty(); } /** * Delete any instance of tag fields with this key * * @param genericKey */ public void deleteField(FieldKey genericKey) { if (genericKey == FieldKey.TRACK) { track = 0; } else { super.deleteField(genericKey); } } /** * Compares Object with this only returns true if both v1_1 tags with all * fields set to same value * * @param obj Comparing Object * @return */ public boolean equals(Object obj) { if (!(obj instanceof ID3v11Tag)) { return false; } ID3v11Tag object = (ID3v11Tag) obj; return this.track == object.track && super.equals(obj); } /** * Find identifier within byteBuffer to indicate that a v11 tag exists within the buffer * * @param byteBuffer * @return true if find header for v11 tag within buffer */ public boolean seek(ByteBuffer byteBuffer) { byte[] buffer = new byte[FIELD_TAGID_LENGTH]; // read the TAG value byteBuffer.get(buffer, 0, FIELD_TAGID_LENGTH); if (!(Arrays.equals(buffer, TAG_ID))) { return false; } // Check for the empty byte before the TRACK byteBuffer.position(FIELD_TRACK_INDICATOR_POS); if (byteBuffer.get() != END_OF_FIELD) { return false; } //Now check for TRACK if the next byte is also null byte then not v1.1 //tag, however this means cannot have v1_1 tag with track setField to zero/undefined //because on next read will be v1 tag. return byteBuffer.get() != END_OF_FIELD; } /** * Read in a tag from the ByteBuffer * * @param byteBuffer from where to read in a tag * @throws TagNotFoundException if unable to read a tag in the byteBuffer */ public void read(ByteBuffer byteBuffer) throws TagNotFoundException { if (!seek(byteBuffer)) { throw new TagNotFoundException("ID3v1 tag not found"); } logger.finer("Reading v1.1 tag"); //Do single file read of data to cut down on file reads byte[] dataBuffer = new byte[TAG_LENGTH]; byteBuffer.position(0); byteBuffer.get(dataBuffer, 0, TAG_LENGTH); title = Utils.getString(dataBuffer, FIELD_TITLE_POS, FIELD_TITLE_LENGTH, "ISO-8859-1").trim(); Matcher m = AbstractID3v1Tag.endofStringPattern.matcher(title); if (m.find()) { title = title.substring(0, m.start()); } artist = Utils.getString(dataBuffer, FIELD_ARTIST_POS, FIELD_ARTIST_LENGTH, "ISO-8859-1").trim(); m = AbstractID3v1Tag.endofStringPattern.matcher(artist); if (m.find()) { artist = artist.substring(0, m.start()); } album = Utils.getString(dataBuffer, FIELD_ALBUM_POS, FIELD_ALBUM_LENGTH, "ISO-8859-1").trim(); m = AbstractID3v1Tag.endofStringPattern.matcher(album); if (m.find()) { album = album.substring(0, m.start()); } year = Utils.getString(dataBuffer, FIELD_YEAR_POS, FIELD_YEAR_LENGTH, "ISO-8859-1").trim(); m = AbstractID3v1Tag.endofStringPattern.matcher(year); if (m.find()) { year = year.substring(0, m.start()); } comment = Utils.getString(dataBuffer, FIELD_COMMENT_POS, FIELD_COMMENT_LENGTH, "ISO-8859-1").trim(); m = AbstractID3v1Tag.endofStringPattern.matcher(comment); if (m.find()) { comment = comment.substring(0, m.start()); } track = dataBuffer[FIELD_TRACK_POS]; genre = dataBuffer[FIELD_GENRE_POS]; } /** * Write this representation of tag to the file indicated * * @param file that this tag should be written to * @throws IOException thrown if there were problems writing to the file */ public void write(RandomAccessFile file) throws IOException { logger.info("Saving ID3v11 tag to file"); byte[] buffer = new byte[TAG_LENGTH]; int i; String str; delete(file); file.seek(file.length()); System.arraycopy(TAG_ID, FIELD_TAGID_POS, buffer, FIELD_TAGID_POS, TAG_ID.length); int offset = FIELD_TITLE_POS; if (TagOptionSingleton.getInstance().isId3v1SaveTitle()) { str = ID3Tags.truncate(title, FIELD_TITLE_LENGTH); for (i = 0; i < str.length(); i++) { buffer[i + offset] = (byte) str.charAt(i); } } offset = FIELD_ARTIST_POS; if (TagOptionSingleton.getInstance().isId3v1SaveArtist()) { str = ID3Tags.truncate(artist, FIELD_ARTIST_LENGTH); for (i = 0; i < str.length(); i++) { buffer[i + offset] = (byte) str.charAt(i); } } offset = FIELD_ALBUM_POS; if (TagOptionSingleton.getInstance().isId3v1SaveAlbum()) { str = ID3Tags.truncate(album, FIELD_ALBUM_LENGTH); for (i = 0; i < str.length(); i++) { buffer[i + offset] = (byte) str.charAt(i); } } offset = FIELD_YEAR_POS; if (TagOptionSingleton.getInstance().isId3v1SaveYear()) { str = ID3Tags.truncate(year, FIELD_YEAR_LENGTH); for (i = 0; i < str.length(); i++) { buffer[i + offset] = (byte) str.charAt(i); } } offset = FIELD_COMMENT_POS; if (TagOptionSingleton.getInstance().isId3v1SaveComment()) { str = ID3Tags.truncate(comment, FIELD_COMMENT_LENGTH); for (i = 0; i < str.length(); i++) { buffer[i + offset] = (byte) str.charAt(i); } } offset = FIELD_TRACK_POS; buffer[offset] = track; // skip one byte extra blank for 1.1 definition offset = FIELD_GENRE_POS; if (TagOptionSingleton.getInstance().isId3v1SaveGenre()) { buffer[offset] = genre; } file.write(buffer); logger.info("Saved ID3v11 tag to file"); } public void createStructure() { MP3File.getStructureFormatter().openHeadingElement(TYPE_TAG, getIdentifier()); //Header MP3File.getStructureFormatter().addElement(TYPE_TITLE, this.title); MP3File.getStructureFormatter().addElement(TYPE_ARTIST, this.artist); MP3File.getStructureFormatter().addElement(TYPE_ALBUM, this.album); MP3File.getStructureFormatter().addElement(TYPE_YEAR, this.year); MP3File.getStructureFormatter().addElement(TYPE_COMMENT, this.comment); MP3File.getStructureFormatter().addElement(TYPE_TRACK, this.track); MP3File.getStructureFormatter().addElement(TYPE_GENRE, this.genre); MP3File.getStructureFormatter().closeHeadingElement(TYPE_TAG); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/AbstractTagItem.java0000644000175000017500000000660611305717447026642 0ustar drazzibdrazzib/** * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: AbstractTagItem.java 857 2009-12-03 11:21:11Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Description: * This class is a facade for all classes that can write to an MP3 file. This includes * fragments and fragment body . It has abstract methods that needs to be implemented, * and a few default implementations of other methods. */ package org.jaudiotagger.tag.id3; import org.jaudiotagger.tag.TagException; import org.jaudiotagger.utils.EqualsUtil; import java.nio.ByteBuffer; import java.util.logging.Logger; /** * This specifies a series of methods that have to be implemented by all structural subclasses, * required to support all copy constructors,iterative methods and so on. *

* TODO Not sure if this is really correct, if really needed should probably be an interface */ public abstract class AbstractTagItem { //Logger public static Logger logger = Logger.getLogger("org.jaudiotagger.tag.id3"); public AbstractTagItem() { } public AbstractTagItem(AbstractTagItem copyObject) { // no copy constructor in super class } /** * ID string that usually corresponds to the class name, but can be * displayed to the user. It is not indended to identify each individual * instance. * * @return ID string */ abstract public String getIdentifier(); /** * Return size of this item * * @return size of this item */ abstract public int getSize(); /** * @param byteBuffer file to read from * @throws TagException on any exception generated by this library. */ abstract public void read(ByteBuffer byteBuffer) throws TagException; /** * Returns true if this datatype is a subset of the argument. This instance * is a subset if it is the same class as the argument. * * @param obj datatype to determine subset of * @return true if this instance and its entire datatype array list is a * subset of the argument. */ public boolean isSubsetOf(Object obj) { return obj instanceof AbstractTagItem; } /** * Returns true if this datatype and its body equals the argument and its * body. this datatype is equal if and only if they are the same class * * @param obj datatype to determine equality of * @return true if this datatype and its body are equal */ public boolean equals(Object obj) { if ( this == obj ) return true; return obj instanceof AbstractTagItem; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/ID3v1Tag.java0000644000175000017500000006504411470746136025107 0ustar drazzibdrazzib/** * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: ID3v1Tag.java 929 2010-11-17 12:36:46Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Description: * */ package org.jaudiotagger.tag.id3; import org.jaudiotagger.audio.generic.Utils; import org.jaudiotagger.audio.mp3.MP3File; import org.jaudiotagger.logging.ErrorMessage; import org.jaudiotagger.tag.*; import org.jaudiotagger.tag.datatype.Artwork; import org.jaudiotagger.tag.reference.GenreTypes; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.util.*; import java.util.regex.Matcher; /** * Represents an ID3v1 tag. * * @author : Eric Farng * @author : Paul Taylor */ public class ID3v1Tag extends AbstractID3v1Tag implements Tag { static EnumMap tagFieldToID3v1Field = new EnumMap(FieldKey.class); static { tagFieldToID3v1Field.put(FieldKey.ARTIST, ID3v1FieldKey.ARTIST); tagFieldToID3v1Field.put(FieldKey.ALBUM, ID3v1FieldKey.ALBUM); tagFieldToID3v1Field.put(FieldKey.TITLE, ID3v1FieldKey.TITLE); tagFieldToID3v1Field.put(FieldKey.TRACK, ID3v1FieldKey.TRACK); tagFieldToID3v1Field.put(FieldKey.YEAR, ID3v1FieldKey.YEAR); tagFieldToID3v1Field.put(FieldKey.GENRE, ID3v1FieldKey.GENRE); tagFieldToID3v1Field.put(FieldKey.COMMENT, ID3v1FieldKey.COMMENT); } //For writing output protected static final String TYPE_COMMENT = "comment"; protected static final int FIELD_COMMENT_LENGTH = 30; protected static final int FIELD_COMMENT_POS = 97; protected static final int BYTE_TO_UNSIGNED = 0xff; protected static final int GENRE_UNDEFINED = 0xff; /** * */ protected String album = ""; /** * */ protected String artist = ""; /** * */ protected String comment = ""; /** * */ protected String title = ""; /** * */ protected String year = ""; /** * */ protected byte genre = (byte) -1; private static final byte RELEASE = 1; private static final byte MAJOR_VERSION = 0; private static final byte REVISION = 0; /** * Retrieve the Release */ public byte getRelease() { return RELEASE; } /** * Retrieve the Major Version */ public byte getMajorVersion() { return MAJOR_VERSION; } /** * Retrieve the Revision */ public byte getRevision() { return REVISION; } /** * Creates a new ID3v1 datatype. */ public ID3v1Tag() { } public ID3v1Tag(ID3v1Tag copyObject) { super(copyObject); this.album = copyObject.album; this.artist = copyObject.artist; this.comment = copyObject.comment; this.title = copyObject.title; this.year = copyObject.year; this.genre = copyObject.genre; } public ID3v1Tag(AbstractTag mp3tag) { if (mp3tag != null) { ID3v11Tag convertedTag; if (mp3tag instanceof ID3v1Tag) { throw new UnsupportedOperationException("Copy Constructor not called. Please type cast the argument"); } if (mp3tag instanceof ID3v11Tag) { convertedTag = (ID3v11Tag) mp3tag; } else { convertedTag = new ID3v11Tag(mp3tag); } this.album = convertedTag.album; this.artist = convertedTag.artist; this.comment = convertedTag.comment; this.title = convertedTag.title; this.year = convertedTag.year; this.genre = convertedTag.genre; } } /** * Creates a new ID3v1 datatype. * * @param file * @param loggingFilename * @throws TagNotFoundException * @throws IOException */ public ID3v1Tag(RandomAccessFile file, String loggingFilename) throws TagNotFoundException, IOException { setLoggingFilename(loggingFilename); FileChannel fc; ByteBuffer byteBuffer; fc = file.getChannel(); fc.position(file.length() - TAG_LENGTH); byteBuffer = ByteBuffer.allocate(TAG_LENGTH); fc.read(byteBuffer); byteBuffer.flip(); read(byteBuffer); } /** * Creates a new ID3v1 datatype. * * @param file * @throws TagNotFoundException * @throws IOException * @deprecated use {@link #ID3v1Tag(RandomAccessFile,String)} instead */ public ID3v1Tag(RandomAccessFile file) throws TagNotFoundException, IOException { this(file, ""); } public void addField(TagField field) { //TODO } public List getFields(String id) { if (FieldKey.ARTIST.name().equals(id)) { return getArtist(); } else if (FieldKey.ALBUM.name().equals(id)) { return getAlbum(); } else if (FieldKey.TITLE.name().equals(id)) { return getTitle(); } else if (FieldKey.GENRE.name().equals(id)) { return getGenre(); } else if (FieldKey.YEAR.name().equals(id)) { return getYear(); } else if (FieldKey.COMMENT.name().equals(id)) { return getComment(); } return new ArrayList(); } public int getFieldCount() { return 6; } public int getFieldCountIncludingSubValues() { return getFieldCount(); } protected List returnFieldToList(ID3v1TagField field) { List fields = new ArrayList(); fields.add(field); return fields; } /** * Set Album * * @param album */ public void setAlbum(String album) { if (album == null) { throw new IllegalArgumentException(ErrorMessage.GENERAL_INVALID_NULL_ARGUMENT.getMsg()); } this.album = ID3Tags.truncate(album, FIELD_ALBUM_LENGTH); } /** * Get Album * * @return album */ protected String getFirstAlbum() { return album; } /** * @return album within list or empty if does not exist */ public List getAlbum() { if (getFirstAlbum().length() > 0) { ID3v1TagField field = new ID3v1TagField(ID3v1FieldKey.ALBUM.name(), getFirstAlbum()); return returnFieldToList(field); } else { return new ArrayList(); } } /** * Set Artist * * @param artist */ public void setArtist(String artist) { if (artist == null) { throw new IllegalArgumentException(ErrorMessage.GENERAL_INVALID_NULL_ARGUMENT.getMsg()); } this.artist = ID3Tags.truncate(artist, FIELD_ARTIST_LENGTH); } /** * Get Artist * * @return artist */ protected String getFirstArtist() { return artist; } /** * @return Artist within list or empty if does not exist */ public List getArtist() { if (getFirstArtist().length() > 0) { ID3v1TagField field = new ID3v1TagField(ID3v1FieldKey.ARTIST.name(), getFirstArtist()); return returnFieldToList(field); } else { return new ArrayList(); } } /** * Set Comment * * @param comment * @throws IllegalArgumentException if comment null */ public void setComment(String comment) { if (comment == null) { throw new IllegalArgumentException(ErrorMessage.GENERAL_INVALID_NULL_ARGUMENT.getMsg()); } this.comment = ID3Tags.truncate(comment, FIELD_COMMENT_LENGTH); } /** * @return comment within list or empty if does not exist */ public List getComment() { if (getFirstComment().length() > 0) { ID3v1TagField field = new ID3v1TagField(ID3v1FieldKey.COMMENT.name(), getFirstComment()); return returnFieldToList(field); } else { return new ArrayList(); } } /** * Get Comment * * @return comment */ public String getFirstComment() { return comment; } /** * Sets the genreID, *

*

ID3v1 only supports genres defined in a predefined list * so if unable to find value in list set 255, which seems to be the value * winamp uses for undefined. * * @param genreVal */ public void setGenre(String genreVal) { if (genreVal == null) { throw new IllegalArgumentException(ErrorMessage.GENERAL_INVALID_NULL_ARGUMENT.getMsg()); } Integer genreID = GenreTypes.getInstanceOf().getIdForValue(genreVal); if (genreID != null) { this.genre = genreID.byteValue(); } else { this.genre = (byte) GENRE_UNDEFINED; } } /** * Get Genre * * @return genre or empty string if not valid */ public String getFirstGenre() { Integer genreId = genre & BYTE_TO_UNSIGNED; String genreValue = GenreTypes.getInstanceOf().getValueForId(genreId); if (genreValue == null) { return ""; } else { return genreValue; } } /** * Get Genre field *

*

Only a single genre is available in ID3v1 * * @return */ public List getGenre() { if (getFirst(FieldKey.GENRE).length() > 0) { ID3v1TagField field = new ID3v1TagField(ID3v1FieldKey.GENRE.name(), getFirst(FieldKey.GENRE)); return returnFieldToList(field); } else { return new ArrayList(); } } /** * Set Title * * @param title */ public void setTitle(String title) { if (title == null) { throw new IllegalArgumentException(ErrorMessage.GENERAL_INVALID_NULL_ARGUMENT.getMsg()); } this.title = ID3Tags.truncate(title, FIELD_TITLE_LENGTH); } /** * Get title * * @return Title */ public String getFirstTitle() { return title; } /** * Get title field *

*

Only a single title is available in ID3v1 * * @return */ public List getTitle() { if (getFirst(FieldKey.TITLE).length() > 0) { ID3v1TagField field = new ID3v1TagField(ID3v1FieldKey.TITLE.name(), getFirst(FieldKey.TITLE)); return returnFieldToList(field); } else { return new ArrayList(); } } /** * Set year * * @param year */ public void setYear(String year) { this.year = ID3Tags.truncate(year, FIELD_YEAR_LENGTH); } /** * Get year * * @return year */ public String getFirstYear() { return year; } /** * Get year field *

*

Only a single year is available in ID3v1 * * @return */ public List getYear() { if (getFirst(FieldKey.YEAR).length() > 0) { ID3v1TagField field = new ID3v1TagField(ID3v1FieldKey.YEAR.name(), getFirst(FieldKey.YEAR)); return returnFieldToList(field); } else { return new ArrayList(); } } public String getFirstTrack() { throw new UnsupportedOperationException("ID3v10 cannot store track numbers"); } public List getTrack() { throw new UnsupportedOperationException("ID3v10 cannot store track numbers"); } public TagField getFirstField(String id) { List results = null; if (FieldKey.ARTIST.name().equals(id)) { results = getArtist(); } else if (FieldKey.ALBUM.name().equals(id)) { results = getAlbum(); } else if (FieldKey.TITLE.name().equals(id)) { results = getTitle(); } else if (FieldKey.GENRE.name().equals(id)) { results = getGenre(); } else if (FieldKey.YEAR.name().equals(id)) { results = getYear(); } else if (FieldKey.COMMENT.name().equals(id)) { results = getComment(); } if (results != null) { if (results.size() > 0) { return results.get(0); } } return null; } public Iterator getFields() { throw new UnsupportedOperationException("TODO:Not done yet"); } public boolean hasCommonFields() { //TODO return true; } public boolean hasField(String id) { //TODO throw new UnsupportedOperationException("TODO:Not done yet"); } public boolean isEmpty() { return !(getFirst(FieldKey.TITLE).length() > 0 || getFirstArtist().length() > 0 || getFirstAlbum().length() > 0 || getFirst(FieldKey.GENRE).length() > 0 || getFirst(FieldKey.YEAR).length() > 0 || getFirstComment().length() > 0); } public void setField(FieldKey genericKey, String value) throws KeyNotFoundException, FieldDataInvalidException { TagField tagfield = createField(genericKey,value); setField(tagfield); } public void addField(FieldKey genericKey, String value) throws KeyNotFoundException, FieldDataInvalidException { setField(genericKey,value); } public void setField(TagField field) { FieldKey genericKey = FieldKey.valueOf(field.getId()); switch (genericKey) { case ARTIST: setArtist(field.toString()); break; case ALBUM: setAlbum(field.toString()); break; case TITLE: setTitle(field.toString()); break; case GENRE: setGenre(field.toString()); break; case YEAR: setYear(field.toString()); break; case COMMENT: setComment(field.toString()); break; } } /** * @param encoding * @return */ public boolean setEncoding(String encoding) { return true; } /** * Create Tag Field using generic key */ public TagField createField(FieldKey genericKey, String value) { return new ID3v1TagField(tagFieldToID3v1Field.get(genericKey).name(), value); } public String getEncoding() { return "ISO-8859-1"; } public TagField getFirstField(FieldKey genericKey) { List l = getFields(genericKey); return (l.size() != 0) ? l.get(0) : null; } /** * Returns a {@linkplain List list} of {@link TagField} objects whose "{@linkplain TagField#getId() id}" * is the specified one.
* * @param genericKey The generic field key * @return A list of {@link TagField} objects with the given "id". */ public List getFields(FieldKey genericKey) { switch (genericKey) { case ARTIST: return getArtist(); case ALBUM: return getAlbum(); case TITLE: return getTitle(); case GENRE: return getGenre(); case YEAR: return getYear(); case COMMENT: return getComment(); default: return new ArrayList(); } } /** * Retrieve the first value that exists for this key id * * @param genericKey * @return */ public String getFirst(String genericKey) { FieldKey matchingKey = FieldKey.valueOf(genericKey); if (matchingKey != null) { return getFirst(matchingKey); } else { return ""; } } /** * Retrieve the first value that exists for this generic key * * @param genericKey * @return */ public String getFirst(FieldKey genericKey) { switch (genericKey) { case ARTIST: return getFirstArtist(); case ALBUM: return getFirstAlbum(); case TITLE: return getFirstTitle(); case GENRE: return getFirstGenre(); case YEAR: return getFirstYear(); case COMMENT: return getFirstComment(); default: return ""; } } /** * The m parameter is effectively ignored * * @param id * @param n * @param m * @return */ public String getSubValue(FieldKey id, int n, int m) { return getValue(id,n); } public String getValue(FieldKey genericKey, int index) { return getFirst(genericKey); } /** * Delete any instance of tag fields with this key * * @param genericKey */ public void deleteField(FieldKey genericKey) { switch (genericKey) { case ARTIST: setArtist(""); break; case ALBUM: setAlbum(""); break; case TITLE: setTitle(""); break; case GENRE: setGenre(""); break; case YEAR: setYear(""); break; case COMMENT: setComment(""); break; } } public void deleteField(String id) { FieldKey key = FieldKey.valueOf(id); if(key!=null) { deleteField(key); } } /** * @param obj * @return true if this and obj are equivalent */ public boolean equals(Object obj) { if (!(obj instanceof ID3v1Tag)) { return false; } ID3v1Tag object = (ID3v1Tag) obj; if (!this.album.equals(object.album)) { return false; } if (!this.artist.equals(object.artist)) { return false; } if (!this.comment.equals(object.comment)) { return false; } if (this.genre != object.genre) { return false; } if (!this.title.equals(object.title)) { return false; } return this.year.equals(object.year) && super.equals(obj); } /** * @return an iterator to iterate through the fields of the tag */ public Iterator iterator() { return new ID3v1Iterator(this); } /** * @param byteBuffer * @throws TagNotFoundException */ public void read(ByteBuffer byteBuffer) throws TagNotFoundException { if (!seek(byteBuffer)) { throw new TagNotFoundException(getLoggingFilename() + ":" + "ID3v1 tag not found"); } logger.finer(getLoggingFilename() + ":" + "Reading v1 tag"); //Do single file read of data to cut down on file reads byte[] dataBuffer = new byte[TAG_LENGTH]; byteBuffer.position(0); byteBuffer.get(dataBuffer, 0, TAG_LENGTH); title = Utils.getString(dataBuffer, FIELD_TITLE_POS, FIELD_TITLE_LENGTH, "ISO-8859-1").trim(); Matcher m = AbstractID3v1Tag.endofStringPattern.matcher(title); if (m.find()) { title = title.substring(0, m.start()); } artist = Utils.getString(dataBuffer, FIELD_ARTIST_POS, FIELD_ARTIST_LENGTH, "ISO-8859-1").trim(); m = AbstractID3v1Tag.endofStringPattern.matcher(artist); if (m.find()) { artist = artist.substring(0, m.start()); } album = Utils.getString(dataBuffer, FIELD_ALBUM_POS, FIELD_ALBUM_LENGTH, "ISO-8859-1").trim(); m = AbstractID3v1Tag.endofStringPattern.matcher(album); logger.finest(getLoggingFilename() + ":" + "Orig Album is:" + comment + ":"); if (m.find()) { album = album.substring(0, m.start()); logger.finest(getLoggingFilename() + ":" + "Album is:" + album + ":"); } year = Utils.getString(dataBuffer, FIELD_YEAR_POS, FIELD_YEAR_LENGTH, "ISO-8859-1").trim(); m = AbstractID3v1Tag.endofStringPattern.matcher(year); if (m.find()) { year = year.substring(0, m.start()); } comment = Utils.getString(dataBuffer, FIELD_COMMENT_POS, FIELD_COMMENT_LENGTH, "ISO-8859-1").trim(); m = AbstractID3v1Tag.endofStringPattern.matcher(comment); logger.finest(getLoggingFilename() + ":" + "Orig Comment is:" + comment + ":"); if (m.find()) { comment = comment.substring(0, m.start()); logger.finest(getLoggingFilename() + ":" + "Comment is:" + comment + ":"); } genre = dataBuffer[FIELD_GENRE_POS]; } /** * Does a tag of this version exist within the byteBuffer * * @return whether tag exists within the byteBuffer */ public boolean seek(ByteBuffer byteBuffer) { byte[] buffer = new byte[FIELD_TAGID_LENGTH]; // read the TAG value byteBuffer.get(buffer, 0, FIELD_TAGID_LENGTH); return (Arrays.equals(buffer, TAG_ID)); } /** * Write this tag to the file, replacing any tag previously existing * * @param file * @throws IOException */ public void write(RandomAccessFile file) throws IOException { logger.info("Saving ID3v1 tag to file"); byte[] buffer = new byte[TAG_LENGTH]; int i; String str; delete(file); file.seek(file.length()); //Copy the TAGID into new buffer System.arraycopy(TAG_ID, FIELD_TAGID_POS, buffer, FIELD_TAGID_POS, TAG_ID.length); int offset = FIELD_TITLE_POS; if (TagOptionSingleton.getInstance().isId3v1SaveTitle()) { str = ID3Tags.truncate(title, FIELD_TITLE_LENGTH); for (i = 0; i < str.length(); i++) { buffer[i + offset] = (byte) str.charAt(i); } } offset = FIELD_ARTIST_POS; if (TagOptionSingleton.getInstance().isId3v1SaveArtist()) { str = ID3Tags.truncate(artist, FIELD_ARTIST_LENGTH); for (i = 0; i < str.length(); i++) { buffer[i + offset] = (byte) str.charAt(i); } } offset = FIELD_ALBUM_POS; if (TagOptionSingleton.getInstance().isId3v1SaveAlbum()) { str = ID3Tags.truncate(album, FIELD_ALBUM_LENGTH); for (i = 0; i < str.length(); i++) { buffer[i + offset] = (byte) str.charAt(i); } } offset = FIELD_YEAR_POS; if (TagOptionSingleton.getInstance().isId3v1SaveYear()) { str = ID3Tags.truncate(year, AbstractID3v1Tag.FIELD_YEAR_LENGTH); for (i = 0; i < str.length(); i++) { buffer[i + offset] = (byte) str.charAt(i); } } offset = FIELD_COMMENT_POS; if (TagOptionSingleton.getInstance().isId3v1SaveComment()) { str = ID3Tags.truncate(comment, FIELD_COMMENT_LENGTH); for (i = 0; i < str.length(); i++) { buffer[i + offset] = (byte) str.charAt(i); } } offset = FIELD_GENRE_POS; if (TagOptionSingleton.getInstance().isId3v1SaveGenre()) { buffer[offset] = genre; } file.write(buffer); logger.info("Saved ID3v1 tag to file"); } /** * Create structured representation of this item. */ public void createStructure() { MP3File.getStructureFormatter().openHeadingElement(TYPE_TAG, getIdentifier()); //Header MP3File.getStructureFormatter().addElement(TYPE_TITLE, this.title); MP3File.getStructureFormatter().addElement(TYPE_ARTIST, this.artist); MP3File.getStructureFormatter().addElement(TYPE_ALBUM, this.album); MP3File.getStructureFormatter().addElement(TYPE_YEAR, this.year); MP3File.getStructureFormatter().addElement(TYPE_COMMENT, this.comment); MP3File.getStructureFormatter().addElement(TYPE_GENRE, this.genre); MP3File.getStructureFormatter().closeHeadingElement(TYPE_TAG); } public List getArtworkList() { return Collections.emptyList(); } public Artwork getFirstArtwork() { return null; } public TagField createField(Artwork artwork) throws FieldDataInvalidException { throw new UnsupportedOperationException(ErrorMessage.GENERIC_NOT_SUPPORTED.getMsg()); } public void setField(Artwork artwork) throws FieldDataInvalidException { throw new UnsupportedOperationException(ErrorMessage.GENERIC_NOT_SUPPORTED.getMsg()); } public void addField(Artwork artwork) throws FieldDataInvalidException { throw new UnsupportedOperationException(ErrorMessage.GENERIC_NOT_SUPPORTED.getMsg()); } /** * Delete all instance of artwork Field * * @throws KeyNotFoundException */ public void deleteArtworkField() throws KeyNotFoundException { throw new UnsupportedOperationException(ErrorMessage.GENERIC_NOT_SUPPORTED.getMsg()); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/valuepair/0000755000175000017500000000000011556363174024743 5ustar drazzibdrazziblibjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/valuepair/TextEncoding.java0000644000175000017500000000645111470746136030205 0ustar drazzibdrazzib/** * @author : Paul Taylor * * Version @version:$Id: TextEncoding.java 929 2010-11-17 12:36:46Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Description: * Valid Text Encodings */ package org.jaudiotagger.tag.id3.valuepair; import org.jaudiotagger.tag.datatype.AbstractIntStringValuePair; /** * Text Encoding supported by ID3v24, the id is recognised by ID3 * whereas the value maps to a java java.nio.charset.Charset, all the * charsets defined below are guaranteed on every Java platform. *

* Note in ID3 UTF_16 can be implemented as either UTF16BE or UTF16LE with byte ordering * marks, in JAudioTagger we always implement it as UTF16LE because only this order * is understood in Windows, OSX seem to understand both. */ public class TextEncoding extends AbstractIntStringValuePair { //Supported Java charsets public static final String CHARSET_ISO_8859_1 = "ISO-8859-1"; public static final String CHARSET_UTF_16 = "UTF-16"; //Want to use x-UTF-16LE-BOM but not always available public static final String CHARSET_UTF_16BE = "UTF-16BE"; public static final String CHARSET_UTF_8 = "UTF-8"; //This is a workaround to allow us to write the UTF-16 format using little endian rather than the default big endian //in Java because BE not understood in Windows, workaround means we use UTF-16 for reading unicode from ID3 //because it could be in either order but when writing we use UTF-16LE - but have to explicity insert //bom because it doesnt do it by default. public static final String CHARSET_UTF_16_ENCODING_FORMAT = "UTF-16LE"; //Supported ID3 charset ids public static final byte ISO_8859_1 = 0; public static final byte UTF_16 = 1; // We use UTF-16 with LE byteordering and byte order mark public static final byte UTF_16BE = 2; public static final byte UTF_8 = 3; //The number of bytes used to hold the text encoding field size public static final int TEXT_ENCODING_FIELD_SIZE = 1; private static TextEncoding textEncodings; public static TextEncoding getInstanceOf() { if (textEncodings == null) { textEncodings = new TextEncoding(); } return textEncodings; } private TextEncoding() { idToValue.put((int) ISO_8859_1, CHARSET_ISO_8859_1); idToValue.put((int) UTF_16, CHARSET_UTF_16); idToValue.put((int) UTF_16BE, CHARSET_UTF_16BE); idToValue.put((int) UTF_8, CHARSET_UTF_8); createMaps(); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/valuepair/ChannelTypes.java0000644000175000017500000000356310655643226030210 0ustar drazzibdrazzib/** * @author : Paul Taylor *

* Version @version:$Id: ChannelTypes.java 339 2007-08-06 16:04:38Z paultaylor $ *

* Jaudiotagger Copyright (C)2004,2005 *

* This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. *

* This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. *

* You should have received a copy of the GNU Lesser General Public License ainteger with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *

* Description: * Channel type used by */ package org.jaudiotagger.tag.id3.valuepair; import org.jaudiotagger.tag.datatype.AbstractIntStringValuePair; public class ChannelTypes extends AbstractIntStringValuePair { private static ChannelTypes channelTypes; public static ChannelTypes getInstanceOf() { if (channelTypes == null) { channelTypes = new ChannelTypes(); } return channelTypes; } private ChannelTypes() { idToValue.put(0x00, "Other"); idToValue.put(0x01, "Master volume"); idToValue.put(0x02, "Front right"); idToValue.put(0x03, "Front left"); idToValue.put(0x04, "Back right"); idToValue.put(0x05, "Back left"); idToValue.put(0x06, "Front centre"); idToValue.put(0x07, "Back centre"); idToValue.put(0x08, "Subwoofer"); createMaps(); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/valuepair/V2GenreTypes.java0000644000175000017500000000174211470746136030105 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3.valuepair; import org.jaudiotagger.tag.reference.GenreTypes; import java.util.Collections; import java.util.List; /** * ID3V2 Genre list *

*

Merging of Id3v2 genres and the extended ID3v2 genres

*/ public class V2GenreTypes { private static V2GenreTypes v2GenresTypes; private V2GenreTypes() { } public static V2GenreTypes getInstanceOf() { if (v2GenresTypes == null) { v2GenresTypes = new V2GenreTypes(); } return v2GenresTypes; } /** * @return list of all valid v2 genres in alphabetical order */ public List getAlphabeticalValueList() { List genres = GenreTypes.getInstanceOf().getAlphabeticalValueList(); genres.add(ID3V2ExtendedGenreTypes.CR.getDescription()); genres.add(ID3V2ExtendedGenreTypes.RX.getDescription()); //Sort Collections.sort(genres); return genres; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/valuepair/ImageFormats.java0000644000175000017500000002030511470746136030162 0ustar drazzibdrazzib/** * @author : Paul Taylor * * Version @version:$Id: ImageFormats.java 929 2010-11-17 12:36:46Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Description: * This class maps from v2.2 Image formats (PIC) to v2.3/v2.4 Mimetypes (APIC) and * vice versa. */ package org.jaudiotagger.tag.id3.valuepair; import java.util.HashMap; import java.util.Map; /** * Represents common image formats support by ID3 and provides a mapping between the format field supported in ID3v22 and the * mimetype field supported by ID3v23/ID3v24. * * * Note only JPG and PNG are mentioned specifically in the ID3 v22 Spec but it only says 'Image Format is preferably * PNG or JPG' , not mandatory. In the jaudiotagger library we also consider GIF as a portable format, and we recognise * BMP,PDF and TIFF but do not consider these formats as portable. * */ //TODO identifying PICT, bit more difficult because in certain formats has an empty 512byte header public class ImageFormats { public static final String V22_JPG_FORMAT = "JPG"; public static final String V22_PNG_FORMAT = "PNG"; public static final String V22_GIF_FORMAT = "GIF"; public static final String V22_BMP_FORMAT = "BMP"; public static final String V22_TIF_FORMAT = "TIF"; public static final String V22_PDF_FORMAT = "PDF"; public static final String V22_PIC_FORMAT = "PIC"; public static final String MIME_TYPE_JPEG = "image/jpeg"; public static final String MIME_TYPE_PNG = "image/png"; public static final String MIME_TYPE_GIF = "image/gif"; public static final String MIME_TYPE_BMP = "image/bmp"; public static final String MIME_TYPE_TIFF = "image/tiff"; public static final String MIME_TYPE_PDF = "image/pdf"; public static final String MIME_TYPE_PICT = "image/x-pict"; /** * Sometimes this is used for jpg instead :or have I made this up */ public static final String MIME_TYPE_JPG = "image/jpg"; private static Map imageFormatsToMimeType = new HashMap(); private static Map imageMimeTypeToFormat = new HashMap (); static { imageFormatsToMimeType.put(V22_JPG_FORMAT, MIME_TYPE_JPEG); imageFormatsToMimeType.put(V22_PNG_FORMAT, MIME_TYPE_PNG); imageFormatsToMimeType.put(V22_GIF_FORMAT, MIME_TYPE_GIF); imageFormatsToMimeType.put(V22_BMP_FORMAT, MIME_TYPE_BMP); imageFormatsToMimeType.put(V22_TIF_FORMAT, MIME_TYPE_TIFF); imageFormatsToMimeType.put(V22_PDF_FORMAT, MIME_TYPE_PDF); imageFormatsToMimeType.put(V22_PIC_FORMAT, MIME_TYPE_PICT); String value; for (String key : imageFormatsToMimeType.keySet()) { value = imageFormatsToMimeType.get(key); imageMimeTypeToFormat.put(value, key); } //The mapping isn't one-one lets add other mimetypes imageMimeTypeToFormat.put(MIME_TYPE_JPG, V22_JPG_FORMAT); } /** * Get v2.3 mimetype from v2.2 format * @param format * @return */ public static String getMimeTypeForFormat(String format) { return imageFormatsToMimeType.get(format); } /** * Get v2.2 format from v2.3 mimetype * @param mimeType * @return */ public static String getFormatForMimeType(String mimeType) { return imageMimeTypeToFormat.get(mimeType); } /** * Is this binary data a png image * * @param data * @return true if binary data matches expected header for a png */ public static boolean binaryDataIsPngFormat(byte[] data) { //Read signature if(data.length<4) { return false; } return (0x89 == (data[0] & 0xff)) && (0x50 == (data[1] & 0xff)) && (0x4E == (data[2] & 0xff)) && (0x47 == (data[3] & 0xff)); } /** * Is this binary data a jpg image * * @param data * @return true if binary data matches expected header for a jpg * * Some details http://www.obrador.com/essentialjpeg/headerinfo.htm */ public static boolean binaryDataIsJpgFormat(byte[] data) { if(data.length<4) { return false; } //Read signature //Can be FF D8 FF E0 or FF D8 FF E1 //FF D8 is SOI Marker, FFE0 or FFE1 is JFIF Marker return (0xff == (data[0] & 0xff)) && (0xd8 == (data[1] & 0xff)) && (0xff == (data[2] & 0xff)) && (0xe0 <= (data[3] & 0xff)); } /** * Is this binary data a gif image * * @param data * @return true if binary data matches expected header for a gif */ public static boolean binaryDataIsGifFormat(byte[] data) { if(data.length<3) { return false; } //Read signature return (0x47 == (data[0] & 0xff)) && (0x49 == (data[1] & 0xff)) && (0x46 == (data[2] & 0xff)); } /** * * Is this binary data a bmp image * * @param data * @return true if binary data matches expected header for a bmp */ public static boolean binaryDataIsBmpFormat(byte[] data) { //Read signature return (0x42 == (data[0] & 0xff)) && (0x4d == (data[1] & 0xff)); } /** * Is this binary data a pdf image * * Details at http://en.wikipedia.org/wiki/Magic_number_%28programming%29 * * @param data * @return true if binary data matches expected header for a pdf */ public static boolean binaryDataIsPdfFormat(byte[] data) { //Read signature return (0x25 == (data[0] & 0xff)) && (0x50 == (data[1] & 0xff)) && (0x44 == (data[2] & 0xff)) && (0x46 == (data[3] & 0xff)); } /** * is this binary data a tiff image * * Details at http://en.wikipedia.org/wiki/Magic_number_%28programming%29 * @param data * @return true if binary data matches expected header for a tiff */ public static boolean binaryDataIsTiffFormat(byte[] data) { //Read signature Intel return ( ((0x49 == (data[0] & 0xff)) && (0x49 == (data[1] & 0xff)) && (0x2a == (data[2] & 0xff)) && (0x00 == (data[3] & 0xff))) || ((0x4d == (data[0] & 0xff)) && (0x4d == (data[1] & 0xff)) && (0x00 == (data[2] & 0xff)) && (0x2a == (data[3] & 0xff))) ); } /** * * @param data * @return true if the image format is a portable format recognised across operating systems */ public static boolean isPortableFormat(byte[] data) { return binaryDataIsPngFormat(data) || binaryDataIsJpgFormat(data) || binaryDataIsGifFormat(data); } /** * * @param data * @return correct mimetype for the image data represented by this byte data */ public static String getMimeTypeForBinarySignature(byte[] data) { if(binaryDataIsPngFormat(data)) { return MIME_TYPE_PNG; } else if(binaryDataIsJpgFormat(data)) { return MIME_TYPE_JPEG; } else if(binaryDataIsGifFormat(data)) { return MIME_TYPE_GIF; } else if(binaryDataIsBmpFormat(data)) { return MIME_TYPE_BMP; } else if(binaryDataIsPdfFormat(data)) { return MIME_TYPE_PDF; } else if(binaryDataIsTiffFormat(data)) { return MIME_TYPE_TIFF; } else { return null; } } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/valuepair/EventTimingTimestampTypes.java0000644000175000017500000000344511330335337032744 0ustar drazzibdrazzib/** * @author : Paul Taylor *

* Version @version:$Id: EventTimingTimestampTypes.java 867 2010-01-28 16:27:11Z paultaylor $ *

* Jaudiotagger Copyright (C)2004,2005 *

* This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. *

* This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. *

* You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *

* Description: */ package org.jaudiotagger.tag.id3.valuepair; import org.jaudiotagger.tag.datatype.AbstractIntStringValuePair; public class EventTimingTimestampTypes extends AbstractIntStringValuePair { private static EventTimingTimestampTypes eventTimingTimestampTypes; public static EventTimingTimestampTypes getInstanceOf() { if (eventTimingTimestampTypes == null) { eventTimingTimestampTypes = new EventTimingTimestampTypes(); } return eventTimingTimestampTypes; } public static final int TIMESTAMP_KEY_FIELD_SIZE = 1; private EventTimingTimestampTypes() { idToValue.put(1, "Absolute time using MPEG [MPEG] frames as unit"); idToValue.put(2, "Absolute time using milliseconds as unit"); createMaps(); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/valuepair/SynchronisedLyricsContentType.java0000644000175000017500000000223310736454526033642 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3.valuepair; import org.jaudiotagger.tag.datatype.AbstractIntStringValuePair; /** * Content Type used by Sysnchronised Lyrics Frame (SYLT) */ public class SynchronisedLyricsContentType extends AbstractIntStringValuePair { private static SynchronisedLyricsContentType eventTimingTypes; public static SynchronisedLyricsContentType getInstanceOf() { if (SynchronisedLyricsContentType.eventTimingTypes == null) { SynchronisedLyricsContentType.eventTimingTypes = new SynchronisedLyricsContentType(); } return SynchronisedLyricsContentType.eventTimingTypes; } public static final int CONTENT_KEY_FIELD_SIZE = 1; private SynchronisedLyricsContentType() { idToValue.put(0x00, "other"); idToValue.put(0x01, "lyrics"); idToValue.put(0x02, "text transcription"); idToValue.put(0x03, "movement/part name"); idToValue.put(0x04, "events"); idToValue.put(0x05, "chord"); idToValue.put(0x06, "trivia"); idToValue.put(0x07, "URLs to webpages"); idToValue.put(0x08, "URLs to images"); createMaps(); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/valuepair/ID3V2ExtendedGenreTypes.java0000644000175000017500000000075611470746136032072 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3.valuepair; /** * ID3V2 Genre list *

*

These are additional genres added in the V2 Specification, they have a string key (RX,CV) rather than a * numeric key

*/ public enum ID3V2ExtendedGenreTypes { RX("Remix"), CR("Cover"); private String description; ID3V2ExtendedGenreTypes(String description) { this.description = description; } public String getDescription() { return description; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/valuepair/ReceivedAsTypes.java0000644000175000017500000000432111330335337030633 0ustar drazzibdrazzib/** * @author : Paul Taylor *

* Version @version:$Id: ReceivedAsTypes.java 867 2010-01-28 16:27:11Z paultaylor $ *

* Jaudiotagger Copyright (C)2004,2005 *

* This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. *

* This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. *

* You should have received a copy of the GNU Lesser General Public License ainteger with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *

* Description: * Used by Commercial Frame (COMR) */ package org.jaudiotagger.tag.id3.valuepair; import org.jaudiotagger.tag.datatype.AbstractIntStringValuePair; /** * Defines how song was purchased used by the COMR frame * */ public class ReceivedAsTypes extends AbstractIntStringValuePair { //The number of bytes used to hold the text encoding field size public static final int RECEIVED_AS_FIELD_SIZE = 1; private static ReceivedAsTypes receivedAsTypes; public static ReceivedAsTypes getInstanceOf() { if (receivedAsTypes == null) { receivedAsTypes = new ReceivedAsTypes(); } return receivedAsTypes; } private ReceivedAsTypes() { idToValue.put(0x00, "Other"); idToValue.put(0x01, "Standard CD album with other songs"); idToValue.put(0x02, "Compressed audio on CD"); idToValue.put(0x03, "File over the Internet"); idToValue.put(0x04, "Stream over the Internet"); idToValue.put(0x05, "As note sheets"); idToValue.put(0x06, "As note sheets in a book with other sheets"); idToValue.put(0x07, "Music on other media"); idToValue.put(0x08, "Non-musical merchandise"); createMaps(); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/valuepair/EventTimingTypes.java0000644000175000017500000000525710655643226031073 0ustar drazzibdrazzib/** * @author : Paul Taylor *

* Version @version:$Id: EventTimingTypes.java 339 2007-08-06 16:04:38Z paultaylor $ *

* Jaudiotagger Copyright (C)2004,2005 *

* This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. *

* This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. *

* You should have received a copy of the GNU Lesser General Public License ainteger with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *

* Description: */ package org.jaudiotagger.tag.id3.valuepair; import org.jaudiotagger.tag.datatype.AbstractIntStringValuePair; public class EventTimingTypes extends AbstractIntStringValuePair { private static EventTimingTypes eventTimingTypes; public static EventTimingTypes getInstanceOf() { if (eventTimingTypes == null) { eventTimingTypes = new EventTimingTypes(); } return eventTimingTypes; } private EventTimingTypes() { idToValue.put(0x00, "Padding (has no meaning)"); idToValue.put(0x01, "End of initial silence"); idToValue.put(0x02, "Intro start"); idToValue.put(0x03, "Main part start"); idToValue.put(0x04, "Outro start"); idToValue.put(0x05, "Outro end"); idToValue.put(0x06, "Verse start"); idToValue.put(0x07, "Refrain start"); idToValue.put(0x08, "Interlude start"); idToValue.put(0x09, "Theme start"); idToValue.put(0x0A, "Variation start"); idToValue.put(0x0B, "Key change"); idToValue.put(0x0C, "Time change"); idToValue.put(0x0D, "Momentary unwanted noise (Snap, Crackle & Pop)"); idToValue.put(0x0E, "Sustained noise"); idToValue.put(0x0F, "Sustained noise end"); idToValue.put(0x10, "Intro end"); idToValue.put(0x11, "Main part end"); idToValue.put(0x12, "Verse end"); idToValue.put(0x13, "Refrain end"); idToValue.put(0x14, "Theme end"); idToValue.put(0x15, "Profanity"); idToValue.put(0x16, "Profanity end"); idToValue.put(0xFD, "Audio end (start of silence)"); idToValue.put(0xFE, "Audio file ends"); createMaps(); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/valuepair/InterpolationTypes.java0000644000175000017500000000312610655643226031462 0ustar drazzibdrazzib/** * @author : Paul Taylor *

* Version @version:$Id: InterpolationTypes.java 339 2007-08-06 16:04:38Z paultaylor $ *

* Jaudiotagger Copyright (C)2004,2005 *

* This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. *

* This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. *

* You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *

* Description: */ package org.jaudiotagger.tag.id3.valuepair; import org.jaudiotagger.tag.datatype.AbstractIntStringValuePair; public class InterpolationTypes extends AbstractIntStringValuePair { private static InterpolationTypes interpolationTypes; public static InterpolationTypes getInstanceOf() { if (interpolationTypes == null) { interpolationTypes = new InterpolationTypes(); } return interpolationTypes; } private InterpolationTypes() { idToValue.put(0, "Band"); idToValue.put(1, "Linear"); createMaps(); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/ID3v1Iterator.java0000644000175000017500000001152310736454526026161 0ustar drazzibdrazzib/** * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: ID3v1Iterator.java 520 2008-01-01 15:16:38Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Description: * */ package org.jaudiotagger.tag.id3; import java.util.Iterator; import java.util.NoSuchElementException; public class ID3v1Iterator implements Iterator { /** * */ private static final int TITLE = 1; /** * */ private static final int ARTIST = 2; /** * */ private static final int ALBUM = 3; /** * */ private static final int COMMENT = 4; /** * */ private static final int YEAR = 5; /** * */ private static final int GENRE = 6; /** * */ private static final int TRACK = 7; /** * */ private ID3v1Tag id3v1tag; /** * */ private int lastIndex = 0; /** * Creates a new ID3v1Iterator datatype. * * @param id3v1tag */ public ID3v1Iterator(ID3v1Tag id3v1tag) { this.id3v1tag = id3v1tag; } /** * @return */ public boolean hasNext() { return hasNext(lastIndex); } /** * @return */ public Object next() { return next(lastIndex); } /** * */ public void remove() { switch (lastIndex) { case TITLE: id3v1tag.title = ""; case ARTIST: id3v1tag.artist = ""; case ALBUM: id3v1tag.album = ""; case COMMENT: id3v1tag.comment = ""; case YEAR: id3v1tag.year = ""; case GENRE: id3v1tag.genre = (byte) -1; case TRACK: if (id3v1tag instanceof ID3v11Tag) { ((ID3v11Tag) id3v1tag).track = (byte) -1; } } } /** * @param index * @return */ private boolean hasNext(int index) { switch (index) { case TITLE: return (id3v1tag.title.length() > 0) || hasNext(index + 1); case ARTIST: return (id3v1tag.artist.length() > 0) || hasNext(index + 1); case ALBUM: return (id3v1tag.album.length() > 0) || hasNext(index + 1); case COMMENT: return (id3v1tag.comment.length() > 0) || hasNext(index + 1); case YEAR: return (id3v1tag.year.length() > 0) || hasNext(index + 1); case GENRE: return (id3v1tag.genre >= (byte) 0) || hasNext(index + 1); case TRACK: if (id3v1tag instanceof ID3v11Tag) { return (((ID3v11Tag) id3v1tag).track >= (byte) 0) || hasNext(index + 1); } default: return false; } } /** * @param index * @return * @throws NoSuchElementException */ private Object next(int index) { switch (lastIndex) { case 0: return (id3v1tag.title.length() > 0) ? id3v1tag.title : next(index + 1); case TITLE: return (id3v1tag.artist.length() > 0) ? id3v1tag.artist : next(index + 1); case ARTIST: return (id3v1tag.album.length() > 0) ? id3v1tag.album : next(index + 1); case ALBUM: return (id3v1tag.comment.length() > 0) ? id3v1tag.comment : next(index + 1); case COMMENT: return (id3v1tag.year.length() > 0) ? id3v1tag.year : next(index + 1); case YEAR: return (id3v1tag.genre >= (byte) 0) ? id3v1tag.genre : next(index + 1); case GENRE: return (id3v1tag instanceof ID3v11Tag && (((ID3v11Tag) id3v1tag).track >= (byte) 0)) ? ((ID3v11Tag) id3v1tag).track : null; default: throw new NoSuchElementException("Iteration has no more elements."); } } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/ID3v23FieldKey.java0000644000175000017500000002073011470746136026145 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3; import org.jaudiotagger.tag.id3.framebody.*; /** * List of known id3v23 metadata fields *

*

These provide a mapping from the generic key to the underlying ID3v23frames. For example most of the Musicbrainz * fields are implemented using a User Defined Text Info Frame, but with a different description key, so this * enum provides the link between the two. */ public enum ID3v23FieldKey { ALBUM(ID3v23Frames.FRAME_ID_V3_ALBUM, Id3FieldType.TEXT), ALBUM_ARTIST(ID3v23Frames.FRAME_ID_V3_ACCOMPANIMENT, Id3FieldType.TEXT), ALBUM_ARTIST_SORT(ID3v23Frames.FRAME_ID_V3_ALBUM_ARTIST_SORT_ORDER_ITUNES, Id3FieldType.TEXT), ALBUM_SORT(ID3v23Frames.FRAME_ID_V3_ALBUM_SORT_ORDER_ITUNES, Id3FieldType.TEXT), AMAZON_ID(ID3v23Frames.FRAME_ID_V3_USER_DEFINED_INFO, FrameBodyTXXX.AMAZON_ASIN, Id3FieldType.TEXT), ARTIST(ID3v23Frames.FRAME_ID_V3_ARTIST, Id3FieldType.TEXT), ARTIST_SORT(ID3v23Frames.FRAME_ID_V3_ARTIST_SORT_ORDER_ITUNES, Id3FieldType.TEXT), BARCODE(ID3v23Frames.FRAME_ID_V3_USER_DEFINED_INFO, FrameBodyTXXX.BARCODE, Id3FieldType.TEXT), BPM(ID3v23Frames.FRAME_ID_V3_BPM, Id3FieldType.TEXT), CATALOG_NO(ID3v23Frames.FRAME_ID_V3_USER_DEFINED_INFO, FrameBodyTXXX.CATALOG_NO, Id3FieldType.TEXT), COMMENT(ID3v23Frames.FRAME_ID_V3_COMMENT, Id3FieldType.TEXT), COMPOSER(ID3v23Frames.FRAME_ID_V3_COMPOSER, Id3FieldType.TEXT), COMPOSER_SORT(ID3v23Frames.FRAME_ID_V3_COMPOSER_SORT_ORDER_ITUNES, Id3FieldType.TEXT), CONDUCTOR(ID3v23Frames.FRAME_ID_V3_CONDUCTOR, Id3FieldType.TEXT), COVER_ART(ID3v23Frames.FRAME_ID_V3_ATTACHED_PICTURE, Id3FieldType.BINARY), CUSTOM1(ID3v23Frames.FRAME_ID_V3_COMMENT, FrameBodyCOMM.MM_CUSTOM1,Id3FieldType.TEXT), CUSTOM2(ID3v23Frames.FRAME_ID_V3_COMMENT, FrameBodyCOMM.MM_CUSTOM2,Id3FieldType.TEXT), CUSTOM3(ID3v23Frames.FRAME_ID_V3_COMMENT, FrameBodyCOMM.MM_CUSTOM3,Id3FieldType.TEXT), CUSTOM4(ID3v23Frames.FRAME_ID_V3_COMMENT, FrameBodyCOMM.MM_CUSTOM4,Id3FieldType.TEXT), CUSTOM5(ID3v23Frames.FRAME_ID_V3_COMMENT, FrameBodyCOMM.MM_CUSTOM5,Id3FieldType.TEXT), DISC_NO(ID3v23Frames.FRAME_ID_V3_SET, Id3FieldType.TEXT), DISC_TOTAL(ID3v23Frames.FRAME_ID_V3_SET, Id3FieldType.TEXT), ENCODER(ID3v23Frames.FRAME_ID_V3_ENCODEDBY, Id3FieldType.TEXT), FBPM(ID3v23Frames.FRAME_ID_V3_USER_DEFINED_INFO, FrameBodyTXXX.FBPM, Id3FieldType.TEXT), GENRE(ID3v23Frames.FRAME_ID_V3_GENRE, Id3FieldType.TEXT), GROUPING(ID3v23Frames.FRAME_ID_V3_CONTENT_GROUP_DESC, Id3FieldType.TEXT), ISRC(ID3v23Frames.FRAME_ID_V3_ISRC, Id3FieldType.TEXT), IS_COMPILATION(ID3v23Frames.FRAME_ID_V3_IS_COMPILATION, Id3FieldType.TEXT), KEY(ID3v23Frames.FRAME_ID_V3_INITIAL_KEY,Id3FieldType.TEXT), LANGUAGE(ID3v23Frames.FRAME_ID_V3_LANGUAGE,Id3FieldType.TEXT), LYRICIST(ID3v23Frames.FRAME_ID_V3_LYRICIST, Id3FieldType.TEXT), LYRICS(ID3v23Frames.FRAME_ID_V3_UNSYNC_LYRICS, Id3FieldType.TEXT), MEDIA(ID3v23Frames.FRAME_ID_V3_MEDIA_TYPE, Id3FieldType.TEXT), MOOD(ID3v23Frames.FRAME_ID_V3_USER_DEFINED_INFO, FrameBodyTXXX.MOOD, Id3FieldType.TEXT), MUSICBRAINZ_ARTISTID(ID3v23Frames.FRAME_ID_V3_USER_DEFINED_INFO, FrameBodyTXXX.MUSICBRAINZ_ARTISTID, Id3FieldType.TEXT), MUSICBRAINZ_DISC_ID(ID3v23Frames.FRAME_ID_V3_USER_DEFINED_INFO, FrameBodyTXXX.MUSICBRAINZ_DISCID, Id3FieldType.TEXT), MUSICBRAINZ_RELEASEARTISTID(ID3v23Frames.FRAME_ID_V3_USER_DEFINED_INFO, FrameBodyTXXX.MUSICBRAINZ_ALBUM_ARTISTID, Id3FieldType.TEXT), MUSICBRAINZ_RELEASEID(ID3v23Frames.FRAME_ID_V3_USER_DEFINED_INFO, FrameBodyTXXX.MUSICBRAINZ_ALBUMID, Id3FieldType.TEXT), MUSICBRAINZ_RELEASE_COUNTRY(ID3v23Frames.FRAME_ID_V3_USER_DEFINED_INFO, FrameBodyTXXX.MUSICBRAINZ_ALBUM_COUNTRY, Id3FieldType.TEXT), MUSICBRAINZ_RELEASE_GROUP_ID(ID3v23Frames.FRAME_ID_V3_USER_DEFINED_INFO, FrameBodyTXXX.MUSICBRAINZ_RELEASE_GROUPID, Id3FieldType.TEXT), MUSICBRAINZ_RELEASE_STATUS(ID3v23Frames.FRAME_ID_V3_USER_DEFINED_INFO, FrameBodyTXXX.MUSICBRAINZ_ALBUM_STATUS, Id3FieldType.TEXT), MUSICBRAINZ_RELEASE_TYPE(ID3v23Frames.FRAME_ID_V3_USER_DEFINED_INFO, FrameBodyTXXX.MUSICBRAINZ_ALBUM_TYPE, Id3FieldType.TEXT), MUSICBRAINZ_TRACK_ID(ID3v23Frames.FRAME_ID_V3_UNIQUE_FILE_ID, FrameBodyUFID.UFID_MUSICBRAINZ, Id3FieldType.TEXT), MUSICBRAINZ_WORK_ID(ID3v23Frames.FRAME_ID_V3_USER_DEFINED_INFO, FrameBodyTXXX.MUSICBRAINZ_WORKID, Id3FieldType.TEXT), MUSICIP_ID(ID3v23Frames.FRAME_ID_V3_USER_DEFINED_INFO, FrameBodyTXXX.MUSICIP_ID, Id3FieldType.TEXT), OCCASION(ID3v23Frames.FRAME_ID_V3_COMMENT, FrameBodyCOMM.MM_OCCASION,Id3FieldType.TEXT), ORIGINAL_ALBUM(ID3v23Frames.FRAME_ID_V3_ORIG_TITLE, Id3FieldType.TEXT), ORIGINAL_ARTIST(ID3v23Frames.FRAME_ID_V3_ORIGARTIST, Id3FieldType.TEXT), ORIGINAL_LYRICIST(ID3v23Frames.FRAME_ID_V3_ORIG_LYRICIST, Id3FieldType.TEXT), ORIGINAL_YEAR(ID3v23Frames.FRAME_ID_V3_TORY, Id3FieldType.TEXT), QUALITY(ID3v23Frames.FRAME_ID_V3_COMMENT, FrameBodyCOMM.MM_QUALITY,Id3FieldType.TEXT), RATING(ID3v23Frames.FRAME_ID_V3_POPULARIMETER, Id3FieldType.TEXT), RECORD_LABEL(ID3v23Frames.FRAME_ID_V3_PUBLISHER, Id3FieldType.TEXT), REMIXER(ID3v23Frames.FRAME_ID_V3_REMIXED, Id3FieldType.TEXT), SCRIPT(ID3v23Frames.FRAME_ID_V3_USER_DEFINED_INFO, FrameBodyTXXX.SCRIPT, Id3FieldType.TEXT), TAGS(ID3v23Frames.FRAME_ID_V3_USER_DEFINED_INFO, FrameBodyTXXX.TAGS, Id3FieldType.TEXT), TEMPO(ID3v23Frames.FRAME_ID_V3_COMMENT, FrameBodyCOMM.MM_TEMPO,Id3FieldType.TEXT), TITLE(ID3v23Frames.FRAME_ID_V3_TITLE, Id3FieldType.TEXT), TITLE_SORT(ID3v23Frames.FRAME_ID_V3_TITLE_SORT_ORDER_ITUNES, Id3FieldType.TEXT), TRACK(ID3v23Frames.FRAME_ID_V3_TRACK, Id3FieldType.TEXT), TRACK_TOTAL(ID3v23Frames.FRAME_ID_V3_TRACK, Id3FieldType.TEXT), URL_DISCOGS_ARTIST_SITE(ID3v23Frames.FRAME_ID_V3_USER_DEFINED_URL, FrameBodyWXXX.URL_DISCOGS_ARTIST_SITE, Id3FieldType.TEXT), URL_DISCOGS_RELEASE_SITE(ID3v23Frames.FRAME_ID_V3_USER_DEFINED_URL, FrameBodyWXXX.URL_DISCOGS_RELEASE_SITE, Id3FieldType.TEXT), URL_LYRICS_SITE(ID3v23Frames.FRAME_ID_V3_USER_DEFINED_URL, FrameBodyWXXX.URL_LYRICS_SITE, Id3FieldType.TEXT), URL_OFFICIAL_ARTIST_SITE(ID3v23Frames.FRAME_ID_V3_URL_ARTIST_WEB, Id3FieldType.TEXT), URL_OFFICIAL_RELEASE_SITE(ID3v23Frames.FRAME_ID_V3_USER_DEFINED_URL, FrameBodyWXXX.URL_OFFICIAL_RELEASE_SITE, Id3FieldType.TEXT), URL_WIKIPEDIA_ARTIST_SITE(ID3v23Frames.FRAME_ID_V3_USER_DEFINED_URL, FrameBodyWXXX.URL_WIKIPEDIA_ARTIST_SITE, Id3FieldType.TEXT), URL_WIKIPEDIA_RELEASE_SITE(ID3v23Frames.FRAME_ID_V3_USER_DEFINED_URL, FrameBodyWXXX.URL_WIKIPEDIA_RELEASE_SITE, Id3FieldType.TEXT), YEAR(ID3v23Frames.FRAME_ID_V3_TYER, Id3FieldType.TEXT), ENGINEER(ID3v23Frames.FRAME_ID_V3_IPLS, FrameBodyTIPL.ENGINEER, Id3FieldType.TEXT), PRODUCER(ID3v23Frames.FRAME_ID_V3_IPLS, FrameBodyTIPL.PRODUCER, Id3FieldType.TEXT), MIXER(ID3v23Frames.FRAME_ID_V3_IPLS, FrameBodyTIPL.MIXER, Id3FieldType.TEXT), DJMIXER(ID3v23Frames.FRAME_ID_V3_IPLS, FrameBodyTIPL.DJMIXER, Id3FieldType.TEXT), ARRANGER(ID3v23Frames.FRAME_ID_V3_IPLS, FrameBodyTIPL.ARRANGER, Id3FieldType.TEXT), ; private String fieldName; private String frameId; private String subId; private Id3FieldType fieldType; /** * For usual metadata fields that use a data field * * @param frameId the frame that will be used * @param fieldType of data atom */ ID3v23FieldKey(String frameId, Id3FieldType fieldType) { this.frameId = frameId; this.fieldType = fieldType; this.fieldName = frameId; } /** * @param frameId the frame that will be used * @param subId the additional key required within the frame to uniquely identify this key * @param fieldType */ ID3v23FieldKey(String frameId, String subId, Id3FieldType fieldType) { this.frameId = frameId; this.subId = subId; this.fieldType = fieldType; this.fieldName = frameId + ":" + subId; } /** * @return fieldtype */ public Id3FieldType getFieldType() { return fieldType; } /** * This is the frame identifier used to write the field * * @return */ public String getFrameId() { return frameId; } /** * This is the subfield used within the frame for this type of field * * @return subId */ public String getSubId() { return subId; } /** * This is the value of the key that can uniquely identifer a key type * * @return */ public String getFieldName() { return fieldName; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/ID3v23Tag.java0000644000175000017500000010074211470746136025166 0ustar drazzibdrazzib/* * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can getFields a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3; import org.jaudiotagger.FileConstants; import org.jaudiotagger.audio.mp3.MP3File; import org.jaudiotagger.logging.ErrorMessage; import org.jaudiotagger.tag.*; import org.jaudiotagger.tag.datatype.Artwork; import org.jaudiotagger.tag.datatype.DataTypes; import org.jaudiotagger.tag.id3.framebody.*; import org.jaudiotagger.tag.reference.PictureTypes; import java.io.File; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.WritableByteChannel; import java.util.ArrayList; import java.util.Comparator; import java.util.LinkedHashMap; import java.util.List; import java.util.logging.Level; /** * Represents an ID3v2.3 tag. * * @author : Paul Taylor * @author : Eric Farng * @version $Id: ID3v23Tag.java 929 2010-11-17 12:36:46Z paultaylor $ */ public class ID3v23Tag extends AbstractID3v2Tag { protected static final String TYPE_CRCDATA = "crcdata"; protected static final String TYPE_EXPERIMENTAL = "experimental"; protected static final String TYPE_EXTENDED = "extended"; protected static final String TYPE_PADDINGSIZE = "paddingsize"; protected static final String TYPE_UNSYNCHRONISATION = "unsyncronisation"; protected static int TAG_EXT_HEADER_LENGTH = 10; protected static int TAG_EXT_HEADER_CRC_LENGTH = 4; protected static int FIELD_TAG_EXT_SIZE_LENGTH = 4; protected static int TAG_EXT_HEADER_DATA_LENGTH = TAG_EXT_HEADER_LENGTH - FIELD_TAG_EXT_SIZE_LENGTH; /** * ID3v2.3 Header bit mask */ public static final int MASK_V23_UNSYNCHRONIZATION = FileConstants.BIT7; /** * ID3v2.3 Header bit mask */ public static final int MASK_V23_EXTENDED_HEADER = FileConstants.BIT6; /** * ID3v2.3 Header bit mask */ public static final int MASK_V23_EXPERIMENTAL = FileConstants.BIT5; /** * ID3v2.3 Extended Header bit mask */ public static final int MASK_V23_CRC_DATA_PRESENT = FileConstants.BIT7; /** * ID3v2.3 RBUF frame bit mask */ public static final int MASK_V23_EMBEDDED_INFO_FLAG = FileConstants.BIT1; /** * CRC Checksum calculated */ protected boolean crcDataFlag = false; /** * Experiemntal tag */ protected boolean experimental = false; /** * Contains extended header */ protected boolean extended = false; /** * Crcdata Checksum in extended header */ private int crc32; /** * Tag padding */ private int paddingSize = 0; /** * All frames in the tag uses unsynchronisation */ protected boolean unsynchronization = false; /** * The tag is compressed */ protected boolean compression = false; public static final byte RELEASE = 2; public static final byte MAJOR_VERSION = 3; public static final byte REVISION = 0; /** * Retrieve the Release */ public byte getRelease() { return RELEASE; } /** * Retrieve the Major Version */ public byte getMajorVersion() { return MAJOR_VERSION; } /** * Retrieve the Revision */ public byte getRevision() { return REVISION; } /** * @return Cyclic Redundancy Check 32 Value */ public int getCrc32() { return crc32; } /** * Creates a new empty ID3v2_3 datatype. */ public ID3v23Tag() { frameMap = new LinkedHashMap(); encryptedFrameMap = new LinkedHashMap(); } /** * Copy primitives applicable to v2.3 */ protected void copyPrimitives(AbstractID3v2Tag copyObj) { logger.info("Copying primitives"); super.copyPrimitives(copyObj); if (copyObj instanceof ID3v23Tag) { ID3v23Tag copyObject = (ID3v23Tag) copyObj; this.crcDataFlag = copyObject.crcDataFlag; this.experimental = copyObject.experimental; this.extended = copyObject.extended; this.crc32 = copyObject.crc32; this.paddingSize = copyObject.paddingSize; } } protected void addFrame(AbstractID3v2Frame frame) { try { //Special case to handle TDRC frame from V24 that needs breaking up into separate frame in V23 if ((frame.getIdentifier().equals(ID3v24Frames.FRAME_ID_YEAR)) && (frame.getBody() instanceof FrameBodyTDRC)) { translateFrame(frame); } else if (frame instanceof ID3v23Frame) { copyFrameIntoMap(frame.getIdentifier(),frame); } else { ID3v23Frame newFrame = new ID3v23Frame(frame); copyFrameIntoMap(newFrame.getIdentifier(), newFrame); } } catch (InvalidFrameException ife) { logger.log(Level.SEVERE, "Unable to convert frame:" + frame.getIdentifier()); } } /** * This is used when we need to translate a single frame into multiple frames, * currently required for v24 TDRC frames. * @param frame */ //TODO will overwrite any existing TYER or TIME frame, do we ever want multiples of these protected void translateFrame(AbstractID3v2Frame frame) { FrameBodyTDRC tmpBody = (FrameBodyTDRC) frame.getBody(); ID3v23Frame newFrame; if (!tmpBody.getYear().equals("")) { newFrame = new ID3v23Frame(ID3v23Frames.FRAME_ID_V3_TYER); ((FrameBodyTYER) newFrame.getBody()).setText(tmpBody.getYear()); logger.info("Adding Frame:" + newFrame.getIdentifier()); frameMap.put(newFrame.getIdentifier(), newFrame); } if (!tmpBody.getDate().equals("")) { newFrame = new ID3v23Frame(ID3v23Frames.FRAME_ID_V3_TDAT); ((FrameBodyTDAT) newFrame.getBody()).setText(tmpBody.getDate()); logger.info("Adding Frame:" + newFrame.getIdentifier()); frameMap.put(newFrame.getIdentifier(), newFrame); } if (!tmpBody.getTime().equals("")) { newFrame = new ID3v23Frame(ID3v23Frames.FRAME_ID_V3_TIME); ((FrameBodyTIME) newFrame.getBody()).setText(tmpBody.getTime()); logger.info("Adding Frame:" + newFrame.getIdentifier()); frameMap.put(newFrame.getIdentifier(), newFrame); } } /** * Copy Constructor, creates a new ID3v2_3 Tag based on another ID3v2_3 Tag * @param copyObject */ public ID3v23Tag(ID3v23Tag copyObject) { //This doesnt do anything. super(copyObject); logger.info("Creating tag from another tag of same type"); copyPrimitives(copyObject); copyFrames(copyObject); } /** * Constructs a new tag based upon another tag of different version/type * @param mp3tag */ public ID3v23Tag(AbstractTag mp3tag) { logger.info("Creating tag from a tag of a different version"); frameMap = new LinkedHashMap(); encryptedFrameMap = new LinkedHashMap(); if (mp3tag != null) { ID3v24Tag convertedTag; //Should use simpler copy constructor if (mp3tag instanceof ID3v23Tag) { throw new UnsupportedOperationException("Copy Constructor not called. Please type cast the argument"); } if (mp3tag instanceof ID3v24Tag) { convertedTag = (ID3v24Tag) mp3tag; } //All tags types can be converted to v2.4 so do this to simplify things else { convertedTag = new ID3v24Tag(mp3tag); } this.setLoggingFilename(convertedTag.getLoggingFilename()); //Copy Primitives copyPrimitives(convertedTag); //Copy Frames copyFrames(convertedTag); logger.info("Created tag from a tag of a different version"); } } /** * Creates a new ID3v2_3 datatype. * * @param buffer * @param loggingFilename * @throws TagException */ public ID3v23Tag(ByteBuffer buffer, String loggingFilename) throws TagException { setLoggingFilename(loggingFilename); this.read(buffer); } /** * Creates a new ID3v2_3 datatype. * * @param buffer * @throws TagException * @deprecated use {@link #ID3v23Tag(ByteBuffer,String)} instead */ public ID3v23Tag(ByteBuffer buffer) throws TagException { this(buffer, ""); } /** * @return textual tag identifier */ public String getIdentifier() { return "ID3v2.30"; } /** * Return frame size based upon the sizes of the tags rather than the physical * no of bytes between start of ID3Tag and start of Audio Data. *

* TODO this is incorrect, because of subclasses * * @return size of tag */ public int getSize() { int size = TAG_HEADER_LENGTH; if (extended) { size += TAG_EXT_HEADER_LENGTH; if (crcDataFlag) { size += TAG_EXT_HEADER_CRC_LENGTH; } } size += super.getSize(); return size; } /** * Is Tag Equivalent to another tag * * @param obj * @return true if tag is equivalent to another */ public boolean equals(Object obj) { if (!(obj instanceof ID3v23Tag)) { return false; } ID3v23Tag object = (ID3v23Tag) obj; if (this.crc32 != object.crc32) { return false; } if (this.crcDataFlag != object.crcDataFlag) { return false; } if (this.experimental != object.experimental) { return false; } if (this.extended != object.extended) { return false; } return this.paddingSize == object.paddingSize && super.equals(obj); } /** * Read the size of a tag, based on the value written in the tag header * * @param buffer * @return * @throws TagException */ public int readSize(ByteBuffer buffer) { //Skip over flags byte flags = buffer.get(); // Read the size, this is size of tag not including the tag header int size = ID3SyncSafeInteger.bufferToValue(buffer); //Return the exact size of tag as setField in the tag header return size + TAG_HEADER_LENGTH; } /** * Read header flags * *

Log info messages for flags that have been set and log warnings when bits have been set for unknown flags

* @param buffer * @throws TagException */ private void readHeaderFlags(ByteBuffer buffer) throws TagException { //Allowable Flags byte flags = buffer.get(); unsynchronization = (flags & MASK_V23_UNSYNCHRONIZATION) != 0; extended = (flags & MASK_V23_EXTENDED_HEADER) != 0; experimental = (flags & MASK_V23_EXPERIMENTAL) != 0; //Not allowable/Unknown Flags if ((flags & FileConstants.BIT4) != 0) { logger.warning(ErrorMessage.ID3_INVALID_OR_UNKNOWN_FLAG_SET.getMsg(getLoggingFilename(), FileConstants.BIT4)); } if ((flags & FileConstants.BIT3) != 0) { logger.warning(ErrorMessage.ID3_INVALID_OR_UNKNOWN_FLAG_SET.getMsg(getLoggingFilename(), FileConstants.BIT3)); } if ((flags & FileConstants.BIT2) != 0) { logger.warning(ErrorMessage.ID3_INVALID_OR_UNKNOWN_FLAG_SET.getMsg(getLoggingFilename(), FileConstants.BIT2)); } if ((flags & FileConstants.BIT1) != 0) { logger.warning(ErrorMessage.ID3_INVALID_OR_UNKNOWN_FLAG_SET.getMsg(getLoggingFilename(), FileConstants.BIT1)); } if ((flags & FileConstants.BIT0) != 0) { logger.warning(ErrorMessage.ID3_INVALID_OR_UNKNOWN_FLAG_SET.getMsg(getLoggingFilename(), FileConstants.BIT0)); } if (isUnsynchronization()) { logger.info(ErrorMessage.ID3_TAG_UNSYNCHRONIZED.getMsg(getLoggingFilename())); } if (extended) { logger.info(ErrorMessage.ID3_TAG_EXTENDED.getMsg(getLoggingFilename())); } if (experimental) { logger.info(ErrorMessage.ID3_TAG_EXPERIMENTAL.getMsg(getLoggingFilename())); } } /** * Read the optional extended header * * @param buffer * @param size */ private void readExtendedHeader(ByteBuffer buffer, int size) { // Int is 4 bytes. int extendedHeaderSize = buffer.getInt(); // Extended header without CRC Data if (extendedHeaderSize == TAG_EXT_HEADER_DATA_LENGTH) { //Flag should not be setField , if is log a warning byte extFlag = buffer.get(); crcDataFlag = (extFlag & MASK_V23_CRC_DATA_PRESENT) != 0; if (crcDataFlag) { logger.warning(ErrorMessage.ID3_TAG_CRC_FLAG_SET_INCORRECTLY.getMsg(getLoggingFilename())); } //2nd Flag Byte (not used) buffer.get(); //Take padding and ext header size off the size to be read paddingSize=buffer.getInt(); if(paddingSize>0) { logger.info(ErrorMessage.ID3_TAG_PADDING_SIZE.getMsg(getLoggingFilename(),paddingSize)); } size = size - ( paddingSize + TAG_EXT_HEADER_LENGTH); } else if (extendedHeaderSize == TAG_EXT_HEADER_DATA_LENGTH + TAG_EXT_HEADER_CRC_LENGTH) { logger.info(ErrorMessage.ID3_TAG_CRC.getMsg(getLoggingFilename())); //Flag should be setField, if nor just act as if it is byte extFlag = buffer.get(); crcDataFlag = (extFlag & MASK_V23_CRC_DATA_PRESENT) != 0; if (!crcDataFlag) { logger.warning(ErrorMessage.ID3_TAG_CRC_FLAG_SET_INCORRECTLY.getMsg(getLoggingFilename())); } //2nd Flag Byte (not used) buffer.get(); //Take padding size of size to be read paddingSize = buffer.getInt(); if(paddingSize>0) { logger.info(ErrorMessage.ID3_TAG_PADDING_SIZE.getMsg(getLoggingFilename(),paddingSize)); } size = size - (paddingSize + TAG_EXT_HEADER_LENGTH + TAG_EXT_HEADER_CRC_LENGTH); //CRC Data crc32 = buffer.getInt(); logger.info(ErrorMessage.ID3_TAG_CRC_SIZE.getMsg(getLoggingFilename(),crc32)); } //Extended header size is only allowed to be six or ten bytes so this is invalid but instead //of giving up lets guess its six bytes and carry on and see if we can read file ok else { logger.warning(ErrorMessage.ID3_EXTENDED_HEADER_SIZE_INVALID.getMsg(getLoggingFilename(), extendedHeaderSize)); buffer.position(buffer.position() - FIELD_TAG_EXT_SIZE_LENGTH); } } /** * {@inheritDoc} */ @Override public void read(ByteBuffer buffer) throws TagException { int size; if (!seek(buffer)) { throw new TagNotFoundException(getIdentifier() + " tag not found"); } logger.info(getLoggingFilename() + ":" + "Reading ID3v23 tag"); readHeaderFlags(buffer); // Read the size, this is size of tag not including the tag header size = ID3SyncSafeInteger.bufferToValue(buffer); logger.info(ErrorMessage.ID_TAG_SIZE.getMsg(getLoggingFilename(),size)); //Extended Header if (extended) { readExtendedHeader(buffer, size); } //Slice Buffer, so position markers tally with size (i.e do not include tagHeader) ByteBuffer bufferWithoutHeader = buffer.slice(); //We need to synchronize the buffer if (isUnsynchronization()) { bufferWithoutHeader = ID3Unsynchronization.synchronize(bufferWithoutHeader); } readFrames(bufferWithoutHeader, size); logger.info(getLoggingFilename() + ":Loaded Frames,there are:" + frameMap.keySet().size()); } /** * Read the frames *

* Read from byteBuffer upto size * * @param byteBuffer * @param size */ protected void readFrames(ByteBuffer byteBuffer, int size) { //Now start looking for frames ID3v23Frame next; frameMap = new LinkedHashMap(); encryptedFrameMap = new LinkedHashMap(); //Read the size from the Tag Header this.fileReadSize = size; logger.finest(getLoggingFilename() + ":Start of frame body at:" + byteBuffer.position() + ",frames data size is:" + size); // Read the frames until got to up to the size as specified in header or until // we hit an invalid frame identifier or padding while (byteBuffer.position() < size) { String id; try { //Read Frame logger.finest(getLoggingFilename() + ":Looking for next frame at:" + byteBuffer.position()); next = new ID3v23Frame(byteBuffer, getLoggingFilename()); id = next.getIdentifier(); loadFrameIntoMap(id, next); } //Found Padding, no more frames catch (PaddingException ex) { logger.config(getLoggingFilename() + ":Found padding starting at:" + byteBuffer.position()); break; } //Found Empty Frame, log it - empty frames should not exist catch (EmptyFrameException ex) { logger.warning(getLoggingFilename() + ":Empty Frame:" + ex.getMessage()); this.emptyFrameBytes += ID3v23Frame.FRAME_HEADER_SIZE; } catch (InvalidFrameIdentifierException ifie) { logger.warning(getLoggingFilename() + ":Invalid Frame Identifier:" + ifie.getMessage()); this.invalidFrames++; //Don't try and find any more frames break; } //Problem trying to find frame, often just occurs because frameHeader includes padding //and we have reached padding catch (InvalidFrameException ife) { logger.warning(getLoggingFilename() + ":Invalid Frame:" + ife.getMessage()); this.invalidFrames++; //Don't try and find any more frames break; } //Failed reading frame but may just have invalid data but correct length so lets carry on //in case we can read the next frame catch(InvalidDataTypeException idete) { logger.warning(getLoggingFilename() + ":Corrupt Frame:" + idete.getMessage()); this.invalidFrames++; continue; } } } /** * Write the ID3 header to the ByteBuffer. *

* TODO Calculate the CYC Data Check * TODO Reintroduce Extended Header * * @param padding is the size of the padding portion of the tag * @param size is the size of the body data * @return ByteBuffer * @throws IOException */ private ByteBuffer writeHeaderToBuffer(int padding, int size) throws IOException { // Flags,currently we never calculate the CRC // and if we dont calculate them cant keep orig values. Tags are not // experimental and we never createField extended header to keep things simple. extended = false; experimental = false; crcDataFlag = false; // Create Header Buffer,allocate maximum possible size for the header ByteBuffer headerBuffer = ByteBuffer. allocate(TAG_HEADER_LENGTH + TAG_EXT_HEADER_LENGTH + TAG_EXT_HEADER_CRC_LENGTH); //TAGID headerBuffer.put(TAG_ID); //Major Version headerBuffer.put(getMajorVersion()); //Minor Version headerBuffer.put(getRevision()); //Flags byte flagsByte = 0; if (isUnsynchronization()) { flagsByte |= MASK_V23_UNSYNCHRONIZATION; } if (extended) { flagsByte |= MASK_V23_EXTENDED_HEADER; } if (experimental) { flagsByte |= MASK_V23_EXPERIMENTAL; } headerBuffer.put(flagsByte); //Additional Header Size,(for completeness we never actually write the extended header) int additionalHeaderSize = 0; if (extended) { additionalHeaderSize += TAG_EXT_HEADER_LENGTH; if (crcDataFlag) { additionalHeaderSize += TAG_EXT_HEADER_CRC_LENGTH; } } //Size As Recorded in Header, don't include the main header length headerBuffer.put(ID3SyncSafeInteger.valueToBuffer(padding + size + additionalHeaderSize)); //Write Extended Header if (extended) { byte extFlagsByte1 = 0; byte extFlagsByte2 = 0; //Contains CRCData if (crcDataFlag) { headerBuffer.putInt(TAG_EXT_HEADER_DATA_LENGTH + TAG_EXT_HEADER_CRC_LENGTH); extFlagsByte1 |= MASK_V23_CRC_DATA_PRESENT; headerBuffer.put(extFlagsByte1); headerBuffer.put(extFlagsByte2); headerBuffer.putInt(paddingSize); headerBuffer.putInt(crc32); } //Just extended Header else { headerBuffer.putInt(TAG_EXT_HEADER_DATA_LENGTH); headerBuffer.put(extFlagsByte1); headerBuffer.put(extFlagsByte2); //Newly Calculated Padding As Recorded in Extended Header headerBuffer.putInt(padding); } } headerBuffer.flip(); return headerBuffer; } /** * Write tag to file *

* TODO:we currently never write the Extended header , but if we did the size calculation in this * method would be slightly incorrect * * @param file The file to write to * @throws IOException */ public void write(File file, long audioStartLocation) throws IOException { setLoggingFilename(file.getName()); logger.info("Writing tag to file:"+getLoggingFilename()); //Write Body Buffer byte[] bodyByteBuffer = writeFramesToBuffer().toByteArray(); logger.info(getLoggingFilename() + ":bodybytebuffer:sizebeforeunsynchronisation:" + bodyByteBuffer.length); // Unsynchronize if option enabled and unsync required unsynchronization = TagOptionSingleton.getInstance().isUnsyncTags() && ID3Unsynchronization.requiresUnsynchronization(bodyByteBuffer); if (isUnsynchronization()) { bodyByteBuffer = ID3Unsynchronization.unsynchronize(bodyByteBuffer); logger.info(getLoggingFilename() + ":bodybytebuffer:sizeafterunsynchronisation:" + bodyByteBuffer.length); } int sizeIncPadding = calculateTagSize(bodyByteBuffer.length + TAG_HEADER_LENGTH, (int) audioStartLocation); int padding = sizeIncPadding - (bodyByteBuffer.length + TAG_HEADER_LENGTH); logger.info(getLoggingFilename() + ":Current audiostart:" + audioStartLocation); logger.info(getLoggingFilename() + ":Size including padding:" + sizeIncPadding); logger.info(getLoggingFilename() + ":Padding:" + padding); ByteBuffer headerBuffer = writeHeaderToBuffer(padding, bodyByteBuffer.length); writeBufferToFile(file, headerBuffer, bodyByteBuffer, padding, sizeIncPadding, audioStartLocation); } /** * {@inheritDoc} */ @Override public void write(WritableByteChannel channel) throws IOException { logger.info(getLoggingFilename() + ":Writing tag to channel"); byte[] bodyByteBuffer = writeFramesToBuffer().toByteArray(); logger.info(getLoggingFilename() + ":bodybytebuffer:sizebeforeunsynchronisation:" + bodyByteBuffer.length); // Unsynchronize if option enabled and unsync required unsynchronization = TagOptionSingleton.getInstance().isUnsyncTags() && ID3Unsynchronization.requiresUnsynchronization(bodyByteBuffer); if (isUnsynchronization()) { bodyByteBuffer = ID3Unsynchronization.unsynchronize(bodyByteBuffer); logger.info(getLoggingFilename() + ":bodybytebuffer:sizeafterunsynchronisation:" + bodyByteBuffer.length); } ByteBuffer headerBuffer = writeHeaderToBuffer(0, bodyByteBuffer.length); channel.write(headerBuffer); channel.write(ByteBuffer.wrap(bodyByteBuffer)); } /** * For representing the MP3File in an XML Format */ public void createStructure() { MP3File.getStructureFormatter().openHeadingElement(TYPE_TAG, getIdentifier()); super.createStructureHeader(); //Header MP3File.getStructureFormatter().openHeadingElement(TYPE_HEADER, ""); MP3File.getStructureFormatter().addElement(TYPE_UNSYNCHRONISATION, this.isUnsynchronization()); MP3File.getStructureFormatter().addElement(TYPE_EXTENDED, this.extended); MP3File.getStructureFormatter().addElement(TYPE_EXPERIMENTAL, this.experimental); MP3File.getStructureFormatter().addElement(TYPE_CRCDATA, this.crc32); MP3File.getStructureFormatter().addElement(TYPE_PADDINGSIZE, this.paddingSize); MP3File.getStructureFormatter().closeHeadingElement(TYPE_HEADER); //Body super.createStructureBody(); MP3File.getStructureFormatter().closeHeadingElement(TYPE_TAG); } /** * @return is tag unsynchronized */ public boolean isUnsynchronization() { return unsynchronization; } public ID3v23Frame createFrame(String id) { return new ID3v23Frame(id); } /** * Create Frame for Id3 Key *

* Only textual data supported at the moment, should only be used with frames that * support a simple string argument. * * @param id3Key * @param value * @return * @throws KeyNotFoundException * @throws FieldDataInvalidException */ public TagField createField(ID3v23FieldKey id3Key, String value) throws KeyNotFoundException, FieldDataInvalidException { if (id3Key == null) { throw new KeyNotFoundException(); } return super.doCreateTagField(new FrameAndSubId(id3Key.getFrameId(), id3Key.getSubId()), value); } /** * Retrieve the first value that exists for this id3v23key * * @param id3v23FieldKey * @return * @throws org.jaudiotagger.tag.KeyNotFoundException */ public String getFirst(ID3v23FieldKey id3v23FieldKey) throws KeyNotFoundException { if (id3v23FieldKey == null) { throw new KeyNotFoundException(); } FrameAndSubId frameAndSubId = new FrameAndSubId(id3v23FieldKey.getFrameId(), id3v23FieldKey.getSubId()); if (id3v23FieldKey == ID3v23FieldKey.TRACK) { AbstractID3v2Frame frame = getFirstField(frameAndSubId.getFrameId()); return String.valueOf(((FrameBodyTRCK)frame.getBody()).getTrackNo()); } else if (id3v23FieldKey == ID3v23FieldKey.TRACK_TOTAL) { AbstractID3v2Frame frame = getFirstField(frameAndSubId.getFrameId()); return String.valueOf(((FrameBodyTRCK)frame.getBody()).getTrackTotal()); } else if (id3v23FieldKey == ID3v23FieldKey.DISC_NO) { AbstractID3v2Frame frame = getFirstField(frameAndSubId.getFrameId()); return String.valueOf(((FrameBodyTPOS)frame.getBody()).getDiscNo()); } else if (id3v23FieldKey == ID3v23FieldKey.DISC_TOTAL) { AbstractID3v2Frame frame = getFirstField(frameAndSubId.getFrameId()); return String.valueOf(((FrameBodyTPOS)frame.getBody()).getDiscTotal()); } else { return super.doGetValueAtIndex(frameAndSubId, 0); } } /** * Delete fields with this id3v23FieldKey * * @param id3v23FieldKey * @throws org.jaudiotagger.tag.KeyNotFoundException */ public void deleteField(ID3v23FieldKey id3v23FieldKey) throws KeyNotFoundException { if (id3v23FieldKey == null) { throw new KeyNotFoundException(); } super.doDeleteTagField(new FrameAndSubId(id3v23FieldKey.getFrameId(), id3v23FieldKey.getSubId())); } /** * Delete fields with this (frame) id * @param id */ public void deleteField(String id) { super.doDeleteTagField(new FrameAndSubId(id,null)); } protected FrameAndSubId getFrameAndSubIdFromGenericKey(FieldKey genericKey) { ID3v23FieldKey id3v23FieldKey = ID3v23Frames.getInstanceOf().getId3KeyFromGenericKey(genericKey); if (id3v23FieldKey == null) { throw new KeyNotFoundException(); } return new FrameAndSubId(id3v23FieldKey.getFrameId(), id3v23FieldKey.getSubId()); } protected ID3Frames getID3Frames() { return ID3v23Frames.getInstanceOf(); } /** * @return comparator used to order frames in preferred order for writing to file * so that most important frames are written first. */ public Comparator getPreferredFrameOrderComparator() { return ID3v23PreferredFrameOrderComparator.getInstanceof(); } /** * {@inheritDoc} */ public List getArtworkList() { List coverartList = getFields(FieldKey.COVER_ART); List artworkList = new ArrayList(coverartList.size()); for (TagField next : coverartList) { FrameBodyAPIC coverArt = (FrameBodyAPIC) ((AbstractID3v2Frame) next).getBody(); Artwork artwork = new Artwork(); artwork.setMimeType(coverArt.getMimeType()); artwork.setPictureType(coverArt.getPictureType()); if (coverArt.isImageUrl()) { artwork.setLinked(true); artwork.setImageUrl(coverArt.getImageUrl()); } else { artwork.setBinaryData(coverArt.getImageData()); } artworkList.add(artwork); } return artworkList; } /** * {@inheritDoc} */ public TagField createField(Artwork artwork) throws FieldDataInvalidException { AbstractID3v2Frame frame = createFrame(getFrameAndSubIdFromGenericKey(FieldKey.COVER_ART).getFrameId()); FrameBodyAPIC body = (FrameBodyAPIC) frame.getBody(); body.setObjectValue(DataTypes.OBJ_PICTURE_DATA, artwork.getBinaryData()); body.setObjectValue(DataTypes.OBJ_PICTURE_TYPE, artwork.getPictureType()); body.setObjectValue(DataTypes.OBJ_MIME_TYPE, artwork.getMimeType()); body.setObjectValue(DataTypes.OBJ_DESCRIPTION, ""); return frame; } /** * Create Artwork * * @param data * @param mimeType of the image * @see PictureTypes * @return */ public TagField createArtworkField(byte[] data, String mimeType) { AbstractID3v2Frame frame = createFrame(getFrameAndSubIdFromGenericKey(FieldKey.COVER_ART).getFrameId()); FrameBodyAPIC body = (FrameBodyAPIC) frame.getBody(); body.setObjectValue(DataTypes.OBJ_PICTURE_DATA, data); body.setObjectValue(DataTypes.OBJ_PICTURE_TYPE, PictureTypes.DEFAULT_ID); body.setObjectValue(DataTypes.OBJ_MIME_TYPE, mimeType); body.setObjectValue(DataTypes.OBJ_DESCRIPTION, ""); return frame; } public int getPaddingSize() { return paddingSize; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/ID3v22Frames.java0000644000175000017500000005560211470746136025673 0ustar drazzibdrazzib/* * Jaudiotagger Copyright (C)2004,2005 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can getFields a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3; import org.jaudiotagger.tag.FieldKey; import java.util.EnumMap; /** * Defines ID3v22 frames and collections that categorise frames within an ID3v22 tag. *

* You can include frames here that are not officially supported as long as they can be used within an * ID3v22Tag * * @author Paul Taylor * @version $Id: ID3v22Frames.java 929 2010-11-17 12:36:46Z paultaylor $ */ public class ID3v22Frames extends ID3Frames { //V2 Frames (only 3 chars) public static final String FRAME_ID_V2_ACCOMPANIMENT = "TP2"; public static final String FRAME_ID_V2_ALBUM = "TAL"; public static final String FRAME_ID_V2_ARTIST = "TP1"; public static final String FRAME_ID_V2_ATTACHED_PICTURE = "PIC"; public static final String FRAME_ID_V2_AUDIO_ENCRYPTION = "CRA"; public static final String FRAME_ID_V2_BPM = "TBP"; public static final String FRAME_ID_V2_COMMENT = "COM"; public static final String FRAME_ID_V2_COMPOSER = "TCM"; public static final String FRAME_ID_V2_CONDUCTOR = "TPE"; public static final String FRAME_ID_V2_CONTENT_GROUP_DESC = "TT1"; public static final String FRAME_ID_V2_COPYRIGHTINFO = "TCR"; public static final String FRAME_ID_V2_ENCODEDBY = "TEN"; public static final String FRAME_ID_V2_ENCRYPTED_FRAME = "CRM"; public static final String FRAME_ID_V2_EQUALISATION = "EQU"; public static final String FRAME_ID_V2_EVENT_TIMING_CODES = "ETC"; public static final String FRAME_ID_V2_FILE_TYPE = "TFT"; public static final String FRAME_ID_V2_GENERAL_ENCAPS_OBJECT = "GEO"; public static final String FRAME_ID_V2_GENRE = "TCO"; public static final String FRAME_ID_V2_HW_SW_SETTINGS = "TSS"; public static final String FRAME_ID_V2_INITIAL_KEY = "TKE"; public static final String FRAME_ID_V2_IPLS = "IPL"; public static final String FRAME_ID_V2_ISRC = "TRC"; public static final String FRAME_ID_V2_LANGUAGE = "TLA"; public static final String FRAME_ID_V2_LENGTH = "TLE"; public static final String FRAME_ID_V2_LINKED_INFO = "LNK"; public static final String FRAME_ID_V2_LYRICIST = "TXT"; public static final String FRAME_ID_V2_MEDIA_TYPE = "TMT"; public static final String FRAME_ID_V2_MPEG_LOCATION_LOOKUP_TABLE = "MLL"; public static final String FRAME_ID_V2_MUSIC_CD_ID = "MCI"; public static final String FRAME_ID_V2_ORIGARTIST = "TOA"; public static final String FRAME_ID_V2_ORIG_FILENAME = "TOF"; public static final String FRAME_ID_V2_ORIG_LYRICIST = "TOL"; public static final String FRAME_ID_V2_ORIG_TITLE = "TOT"; public static final String FRAME_ID_V2_PLAYLIST_DELAY = "TDY"; public static final String FRAME_ID_V2_PLAY_COUNTER = "CNT"; public static final String FRAME_ID_V2_POPULARIMETER = "POP"; public static final String FRAME_ID_V2_PUBLISHER = "TPB"; public static final String FRAME_ID_V2_RECOMMENDED_BUFFER_SIZE = "BUF"; public static final String FRAME_ID_V2_RELATIVE_VOLUME_ADJUSTMENT = "RVA"; public static final String FRAME_ID_V2_REMIXED = "TP4"; public static final String FRAME_ID_V2_REVERB = "REV"; public static final String FRAME_ID_V2_SET = "TPA"; public static final String FRAME_ID_V2_SYNC_LYRIC = "SLT"; public static final String FRAME_ID_V2_SYNC_TEMPO = "STC"; public static final String FRAME_ID_V2_TDAT = "TDA"; public static final String FRAME_ID_V2_TIME = "TIM"; public static final String FRAME_ID_V2_TITLE = "TT2"; public static final String FRAME_ID_V2_TITLE_REFINEMENT = "TT3"; public static final String FRAME_ID_V2_TORY = "TOR"; public static final String FRAME_ID_V2_TRACK = "TRK"; public static final String FRAME_ID_V2_TRDA = "TRD"; public static final String FRAME_ID_V2_TSIZ = "TSI"; public static final String FRAME_ID_V2_TYER = "TYE"; public static final String FRAME_ID_V2_UNIQUE_FILE_ID = "UFI"; public static final String FRAME_ID_V2_UNSYNC_LYRICS = "ULT"; public static final String FRAME_ID_V2_URL_ARTIST_WEB = "WAR"; public static final String FRAME_ID_V2_URL_COMMERCIAL = "WCM"; public static final String FRAME_ID_V2_URL_COPYRIGHT = "WCP"; public static final String FRAME_ID_V2_URL_FILE_WEB = "WAF"; public static final String FRAME_ID_V2_URL_OFFICIAL_RADIO = "WRS"; public static final String FRAME_ID_V2_URL_PAYMENT = "WPAY"; public static final String FRAME_ID_V2_URL_PUBLISHERS = "WPB"; public static final String FRAME_ID_V2_URL_SOURCE_WEB = "WAS"; public static final String FRAME_ID_V2_USER_DEFINED_INFO = "TXX"; public static final String FRAME_ID_V2_USER_DEFINED_URL = "WXX"; public static final String FRAME_ID_V2_IS_COMPILATION = "TCP"; public static final String FRAME_ID_V2_TITLE_SORT_ORDER_ITUNES = "TST"; public static final String FRAME_ID_V2_ARTIST_SORT_ORDER_ITUNES = "TSP"; public static final String FRAME_ID_V2_ALBUM_SORT_ORDER_ITUNES = "TSA"; public static final String FRAME_ID_V2_ALBUM_ARTIST_SORT_ORDER_ITUNES = "TS2"; public static final String FRAME_ID_V2_COMPOSER_SORT_ORDER_ITUNES = "TSC"; private static ID3v22Frames id3v22Frames; /** * Maps from Generic key to ID3 key */ protected EnumMap tagFieldToId3 = new EnumMap(FieldKey.class); public static ID3v22Frames getInstanceOf() { if (id3v22Frames == null) { id3v22Frames = new ID3v22Frames(); } return id3v22Frames; } private ID3v22Frames() { // The defined v22 frames supportedFrames.add(FRAME_ID_V2_ACCOMPANIMENT); supportedFrames.add(FRAME_ID_V2_ALBUM); supportedFrames.add(FRAME_ID_V2_ARTIST); supportedFrames.add(FRAME_ID_V2_ATTACHED_PICTURE); supportedFrames.add(FRAME_ID_V2_AUDIO_ENCRYPTION); supportedFrames.add(FRAME_ID_V2_BPM); supportedFrames.add(FRAME_ID_V2_COMMENT); supportedFrames.add(FRAME_ID_V2_COMPOSER); supportedFrames.add(FRAME_ID_V2_ENCRYPTED_FRAME); supportedFrames.add(FRAME_ID_V2_CONDUCTOR); supportedFrames.add(FRAME_ID_V2_CONTENT_GROUP_DESC); supportedFrames.add(FRAME_ID_V2_COPYRIGHTINFO); supportedFrames.add(FRAME_ID_V2_ENCODEDBY); supportedFrames.add(FRAME_ID_V2_ENCRYPTED_FRAME); supportedFrames.add(FRAME_ID_V2_EQUALISATION); supportedFrames.add(FRAME_ID_V2_EVENT_TIMING_CODES); supportedFrames.add(FRAME_ID_V2_FILE_TYPE); supportedFrames.add(FRAME_ID_V2_GENERAL_ENCAPS_OBJECT); supportedFrames.add(FRAME_ID_V2_GENRE); supportedFrames.add(FRAME_ID_V2_HW_SW_SETTINGS); supportedFrames.add(FRAME_ID_V2_INITIAL_KEY); supportedFrames.add(FRAME_ID_V2_IPLS); supportedFrames.add(FRAME_ID_V2_ISRC); supportedFrames.add(FRAME_ID_V2_LANGUAGE); supportedFrames.add(FRAME_ID_V2_LENGTH); supportedFrames.add(FRAME_ID_V2_LINKED_INFO); supportedFrames.add(FRAME_ID_V2_LYRICIST); supportedFrames.add(FRAME_ID_V2_MEDIA_TYPE); supportedFrames.add(FRAME_ID_V2_MPEG_LOCATION_LOOKUP_TABLE); supportedFrames.add(FRAME_ID_V2_MUSIC_CD_ID); supportedFrames.add(FRAME_ID_V2_ORIGARTIST); supportedFrames.add(FRAME_ID_V2_ORIG_FILENAME); supportedFrames.add(FRAME_ID_V2_ORIG_LYRICIST); supportedFrames.add(FRAME_ID_V2_ORIG_TITLE); supportedFrames.add(FRAME_ID_V2_PLAYLIST_DELAY); supportedFrames.add(FRAME_ID_V2_PLAY_COUNTER); supportedFrames.add(FRAME_ID_V2_POPULARIMETER); supportedFrames.add(FRAME_ID_V2_PUBLISHER); supportedFrames.add(FRAME_ID_V2_RECOMMENDED_BUFFER_SIZE); supportedFrames.add(FRAME_ID_V2_RELATIVE_VOLUME_ADJUSTMENT); supportedFrames.add(FRAME_ID_V2_REMIXED); supportedFrames.add(FRAME_ID_V2_REVERB); supportedFrames.add(FRAME_ID_V2_SET); supportedFrames.add(FRAME_ID_V2_SYNC_LYRIC); supportedFrames.add(FRAME_ID_V2_SYNC_TEMPO); supportedFrames.add(FRAME_ID_V2_TDAT); supportedFrames.add(FRAME_ID_V2_TIME); supportedFrames.add(FRAME_ID_V2_TITLE); supportedFrames.add(FRAME_ID_V2_TITLE_REFINEMENT); supportedFrames.add(FRAME_ID_V2_TORY); supportedFrames.add(FRAME_ID_V2_TRACK); supportedFrames.add(FRAME_ID_V2_TRDA); supportedFrames.add(FRAME_ID_V2_TSIZ); supportedFrames.add(FRAME_ID_V2_TYER); supportedFrames.add(FRAME_ID_V2_UNIQUE_FILE_ID); supportedFrames.add(FRAME_ID_V2_UNSYNC_LYRICS); supportedFrames.add(FRAME_ID_V2_URL_ARTIST_WEB); supportedFrames.add(FRAME_ID_V2_URL_COMMERCIAL); supportedFrames.add(FRAME_ID_V2_URL_COPYRIGHT); supportedFrames.add(FRAME_ID_V2_URL_FILE_WEB); supportedFrames.add(FRAME_ID_V2_URL_OFFICIAL_RADIO); supportedFrames.add(FRAME_ID_V2_URL_PAYMENT); supportedFrames.add(FRAME_ID_V2_URL_PUBLISHERS); supportedFrames.add(FRAME_ID_V2_URL_SOURCE_WEB); supportedFrames.add(FRAME_ID_V2_USER_DEFINED_INFO); supportedFrames.add(FRAME_ID_V2_USER_DEFINED_URL); //Extension extensionFrames.add(FRAME_ID_V2_IS_COMPILATION); extensionFrames.add(FRAME_ID_V2_TITLE_SORT_ORDER_ITUNES); extensionFrames.add(FRAME_ID_V2_ARTIST_SORT_ORDER_ITUNES); extensionFrames.add(FRAME_ID_V2_ALBUM_SORT_ORDER_ITUNES); extensionFrames.add(FRAME_ID_V2_ALBUM_ARTIST_SORT_ORDER_ITUNES); extensionFrames.add(FRAME_ID_V2_COMPOSER_SORT_ORDER_ITUNES); //Common commonFrames.add(FRAME_ID_V2_ARTIST); commonFrames.add(FRAME_ID_V2_ALBUM); commonFrames.add(FRAME_ID_V2_TITLE); commonFrames.add(FRAME_ID_V2_GENRE); commonFrames.add(FRAME_ID_V2_TRACK); commonFrames.add(FRAME_ID_V2_TYER); commonFrames.add(FRAME_ID_V2_COMMENT); //Binary binaryFrames.add(FRAME_ID_V2_ATTACHED_PICTURE); binaryFrames.add(FRAME_ID_V2_AUDIO_ENCRYPTION); binaryFrames.add(FRAME_ID_V2_ENCRYPTED_FRAME); binaryFrames.add(FRAME_ID_V2_EQUALISATION); binaryFrames.add(FRAME_ID_V2_EVENT_TIMING_CODES); binaryFrames.add(FRAME_ID_V2_GENERAL_ENCAPS_OBJECT); binaryFrames.add(FRAME_ID_V2_RELATIVE_VOLUME_ADJUSTMENT); binaryFrames.add(FRAME_ID_V2_RECOMMENDED_BUFFER_SIZE); binaryFrames.add(FRAME_ID_V2_UNIQUE_FILE_ID); // Map frameid to a name idToValue.put(FRAME_ID_V2_ACCOMPANIMENT, "Text: Band/Orchestra/Accompaniment"); idToValue.put(FRAME_ID_V2_ALBUM, "Text: Album/Movie/Show title"); idToValue.put(FRAME_ID_V2_ARTIST, "Text: Lead artist(s)/Lead performer(s)/Soloist(s)/Performing group"); idToValue.put(FRAME_ID_V2_ATTACHED_PICTURE, "Attached picture"); idToValue.put(FRAME_ID_V2_AUDIO_ENCRYPTION, "Audio encryption"); idToValue.put(FRAME_ID_V2_BPM, "Text: BPM (Beats Per Minute)"); idToValue.put(FRAME_ID_V2_COMMENT, "Comments"); idToValue.put(FRAME_ID_V2_COMPOSER, "Text: Composer"); idToValue.put(FRAME_ID_V2_CONDUCTOR, "Text: Conductor/Performer refinement"); idToValue.put(FRAME_ID_V2_CONTENT_GROUP_DESC, "Text: Content group description"); idToValue.put(FRAME_ID_V2_COPYRIGHTINFO, "Text: Copyright message"); idToValue.put(FRAME_ID_V2_ENCODEDBY, "Text: Encoded by"); idToValue.put(FRAME_ID_V2_ENCRYPTED_FRAME, "Encrypted meta frame"); idToValue.put(FRAME_ID_V2_EQUALISATION, "Equalization"); idToValue.put(FRAME_ID_V2_EVENT_TIMING_CODES, "Event timing codes"); idToValue.put(FRAME_ID_V2_FILE_TYPE, "Text: File type"); idToValue.put(FRAME_ID_V2_GENERAL_ENCAPS_OBJECT, "General encapsulated datatype"); idToValue.put(FRAME_ID_V2_GENRE, "Text: Content type"); idToValue.put(FRAME_ID_V2_HW_SW_SETTINGS, "Text: Software/hardware and settings used for encoding"); idToValue.put(FRAME_ID_V2_INITIAL_KEY, "Text: Initial key"); idToValue.put(FRAME_ID_V2_IPLS, "Involved people list"); idToValue.put(FRAME_ID_V2_ISRC, "Text: ISRC (International Standard Recording Code)"); idToValue.put(FRAME_ID_V2_LANGUAGE, "Text: Language(s)"); idToValue.put(FRAME_ID_V2_LENGTH, "Text: Length"); idToValue.put(FRAME_ID_V2_LINKED_INFO, "Linked information"); idToValue.put(FRAME_ID_V2_LYRICIST, "Text: Lyricist/text writer"); idToValue.put(FRAME_ID_V2_MEDIA_TYPE, "Text: Media type"); idToValue.put(FRAME_ID_V2_MPEG_LOCATION_LOOKUP_TABLE, "MPEG location lookup table"); idToValue.put(FRAME_ID_V2_MUSIC_CD_ID, "Music CD Identifier"); idToValue.put(FRAME_ID_V2_ORIGARTIST, "Text: Original artist(s)/performer(s)"); idToValue.put(FRAME_ID_V2_ORIG_FILENAME, "Text: Original filename"); idToValue.put(FRAME_ID_V2_ORIG_LYRICIST, "Text: Original Lyricist(s)/text writer(s)"); idToValue.put(FRAME_ID_V2_ORIG_TITLE, "Text: Original album/Movie/Show title"); idToValue.put(FRAME_ID_V2_PLAYLIST_DELAY, "Text: Playlist delay"); idToValue.put(FRAME_ID_V2_PLAY_COUNTER, "Play counter"); idToValue.put(FRAME_ID_V2_POPULARIMETER, "Popularimeter"); idToValue.put(FRAME_ID_V2_PUBLISHER, "Text: Publisher"); idToValue.put(FRAME_ID_V2_RECOMMENDED_BUFFER_SIZE, "Recommended buffer size"); idToValue.put(FRAME_ID_V2_RELATIVE_VOLUME_ADJUSTMENT, "Relative volume adjustment"); idToValue.put(FRAME_ID_V2_REMIXED, "Text: Interpreted, remixed, or otherwise modified by"); idToValue.put(FRAME_ID_V2_REVERB, "Reverb"); idToValue.put(FRAME_ID_V2_SET, "Text: Part of a setField"); idToValue.put(FRAME_ID_V2_SYNC_LYRIC, "Synchronized lyric/text"); idToValue.put(FRAME_ID_V2_SYNC_TEMPO, "Synced tempo codes"); idToValue.put(FRAME_ID_V2_TDAT, "Text: Date"); idToValue.put(FRAME_ID_V2_TIME, "Text: Time"); idToValue.put(FRAME_ID_V2_TITLE, "Text: Title/Songname/Content description"); idToValue.put(FRAME_ID_V2_TITLE_REFINEMENT, "Text: Subtitle/Description refinement"); idToValue.put(FRAME_ID_V2_TORY, "Text: Original release year"); idToValue.put(FRAME_ID_V2_TRACK, "Text: Track number/Position in setField"); idToValue.put(FRAME_ID_V2_TRDA, "Text: Recording dates"); idToValue.put(FRAME_ID_V2_TSIZ, "Text: Size"); idToValue.put(FRAME_ID_V2_TYER, "Text: Year"); idToValue.put(FRAME_ID_V2_UNIQUE_FILE_ID, "Unique file identifier"); idToValue.put(FRAME_ID_V2_UNSYNC_LYRICS, "Unsychronized lyric/text transcription"); idToValue.put(FRAME_ID_V2_URL_ARTIST_WEB, "URL: Official artist/performer webpage"); idToValue.put(FRAME_ID_V2_URL_COMMERCIAL, "URL: Commercial information"); idToValue.put(FRAME_ID_V2_URL_COPYRIGHT, "URL: Copyright/Legal information"); idToValue.put(FRAME_ID_V2_URL_FILE_WEB, "URL: Official audio file webpage"); idToValue.put(FRAME_ID_V2_URL_OFFICIAL_RADIO, "URL: Official radio station"); idToValue.put(FRAME_ID_V2_URL_PAYMENT, "URL: Official payment site"); idToValue.put(FRAME_ID_V2_URL_PUBLISHERS, "URL: Publishers official webpage"); idToValue.put(FRAME_ID_V2_URL_SOURCE_WEB, "URL: Official audio source webpage"); idToValue.put(FRAME_ID_V2_USER_DEFINED_INFO, "User defined text information frame"); idToValue.put(FRAME_ID_V2_USER_DEFINED_URL, "User defined URL link frame"); idToValue.put(FRAME_ID_V2_IS_COMPILATION, "Is Compilation"); idToValue.put(FRAME_ID_V2_TITLE_SORT_ORDER_ITUNES, "Text: title sort order"); idToValue.put(FRAME_ID_V2_ARTIST_SORT_ORDER_ITUNES, "Text: artist sort order"); idToValue.put(FRAME_ID_V2_ALBUM_SORT_ORDER_ITUNES, "Text: album sort order"); idToValue.put(FRAME_ID_V2_ALBUM_ARTIST_SORT_ORDER_ITUNES, "Text:Album Artist Sort Order Frame"); idToValue.put(FRAME_ID_V2_COMPOSER_SORT_ORDER_ITUNES, "Text:Composer Sort Order Frame"); createMaps(); multipleFrames.add(FRAME_ID_V2_ATTACHED_PICTURE); multipleFrames.add(FRAME_ID_V2_UNIQUE_FILE_ID); multipleFrames.add(FRAME_ID_V2_POPULARIMETER); multipleFrames.add(FRAME_ID_V2_USER_DEFINED_INFO); multipleFrames.add(FRAME_ID_V2_USER_DEFINED_URL); multipleFrames.add(FRAME_ID_V2_COMMENT); multipleFrames.add(FRAME_ID_V2_UNSYNC_LYRICS); multipleFrames.add(FRAME_ID_V2_GENERAL_ENCAPS_OBJECT); //Mapping generic key to id3v22 key tagFieldToId3.put(FieldKey.ALBUM, ID3v22FieldKey.ALBUM); tagFieldToId3.put(FieldKey.ALBUM_ARTIST, ID3v22FieldKey.ALBUM_ARTIST); tagFieldToId3.put(FieldKey.ALBUM_ARTIST_SORT, ID3v22FieldKey.ALBUM_ARTIST_SORT); tagFieldToId3.put(FieldKey.ALBUM_SORT, ID3v22FieldKey.ALBUM_SORT); tagFieldToId3.put(FieldKey.AMAZON_ID, ID3v22FieldKey.AMAZON_ID); tagFieldToId3.put(FieldKey.ARTIST, ID3v22FieldKey.ARTIST); tagFieldToId3.put(FieldKey.ARTIST_SORT, ID3v22FieldKey.ARTIST_SORT); tagFieldToId3.put(FieldKey.BARCODE, ID3v22FieldKey.BARCODE); tagFieldToId3.put(FieldKey.BPM, ID3v22FieldKey.BPM); tagFieldToId3.put(FieldKey.CATALOG_NO, ID3v22FieldKey.CATALOG_NO); tagFieldToId3.put(FieldKey.COMMENT, ID3v22FieldKey.COMMENT); tagFieldToId3.put(FieldKey.COMPOSER, ID3v22FieldKey.COMPOSER); tagFieldToId3.put(FieldKey.COMPOSER_SORT, ID3v22FieldKey.COMPOSER_SORT); tagFieldToId3.put(FieldKey.CONDUCTOR, ID3v22FieldKey.CONDUCTOR); tagFieldToId3.put(FieldKey.COVER_ART, ID3v22FieldKey.COVER_ART); tagFieldToId3.put(FieldKey.CUSTOM1, ID3v22FieldKey.CUSTOM1); tagFieldToId3.put(FieldKey.CUSTOM2, ID3v22FieldKey.CUSTOM2); tagFieldToId3.put(FieldKey.CUSTOM3, ID3v22FieldKey.CUSTOM3); tagFieldToId3.put(FieldKey.CUSTOM4, ID3v22FieldKey.CUSTOM4); tagFieldToId3.put(FieldKey.CUSTOM5, ID3v22FieldKey.CUSTOM5); tagFieldToId3.put(FieldKey.DISC_NO, ID3v22FieldKey.DISC_NO); tagFieldToId3.put(FieldKey.DISC_TOTAL, ID3v22FieldKey.DISC_NO); tagFieldToId3.put(FieldKey.ENCODER, ID3v22FieldKey.ENCODER); tagFieldToId3.put(FieldKey.FBPM, ID3v22FieldKey.FBPM); tagFieldToId3.put(FieldKey.GENRE, ID3v22FieldKey.GENRE); tagFieldToId3.put(FieldKey.GROUPING, ID3v22FieldKey.GROUPING); tagFieldToId3.put(FieldKey.ISRC, ID3v22FieldKey.ISRC); tagFieldToId3.put(FieldKey.IS_COMPILATION, ID3v22FieldKey.IS_COMPILATION); tagFieldToId3.put(FieldKey.KEY, ID3v22FieldKey.KEY); tagFieldToId3.put(FieldKey.LANGUAGE, ID3v22FieldKey.LANGUAGE); tagFieldToId3.put(FieldKey.LYRICIST, ID3v22FieldKey.LYRICIST); tagFieldToId3.put(FieldKey.LYRICS, ID3v22FieldKey.LYRICS); tagFieldToId3.put(FieldKey.MEDIA, ID3v22FieldKey.MEDIA); tagFieldToId3.put(FieldKey.MOOD, ID3v22FieldKey.MOOD); tagFieldToId3.put(FieldKey.MUSICBRAINZ_ARTISTID, ID3v22FieldKey.MUSICBRAINZ_ARTISTID); tagFieldToId3.put(FieldKey.MUSICBRAINZ_DISC_ID, ID3v22FieldKey.MUSICBRAINZ_DISC_ID); tagFieldToId3.put(FieldKey.MUSICBRAINZ_RELEASEARTISTID, ID3v22FieldKey.MUSICBRAINZ_RELEASEARTISTID); tagFieldToId3.put(FieldKey.MUSICBRAINZ_RELEASEID, ID3v22FieldKey.MUSICBRAINZ_RELEASEID); tagFieldToId3.put(FieldKey.MUSICBRAINZ_RELEASE_COUNTRY, ID3v22FieldKey.MUSICBRAINZ_RELEASE_COUNTRY); tagFieldToId3.put(FieldKey.MUSICBRAINZ_RELEASE_GROUP_ID, ID3v22FieldKey.MUSICBRAINZ_RELEASE_GROUP_ID); tagFieldToId3.put(FieldKey.MUSICBRAINZ_RELEASE_STATUS, ID3v22FieldKey.MUSICBRAINZ_RELEASE_STATUS); tagFieldToId3.put(FieldKey.MUSICBRAINZ_RELEASE_TYPE, ID3v22FieldKey.MUSICBRAINZ_RELEASE_TYPE); tagFieldToId3.put(FieldKey.MUSICBRAINZ_TRACK_ID, ID3v22FieldKey.MUSICBRAINZ_TRACK_ID); tagFieldToId3.put(FieldKey.MUSICBRAINZ_WORK_ID, ID3v22FieldKey.MUSICBRAINZ_WORK_ID); tagFieldToId3.put(FieldKey.MUSICIP_ID, ID3v22FieldKey.MUSICIP_ID); tagFieldToId3.put(FieldKey.OCCASION, ID3v22FieldKey.OCCASION); tagFieldToId3.put(FieldKey.ORIGINAL_ALBUM, ID3v22FieldKey.ORIGINAL_ALBUM); tagFieldToId3.put(FieldKey.ORIGINAL_ARTIST, ID3v22FieldKey.ORIGINAL_ARTIST); tagFieldToId3.put(FieldKey.ORIGINAL_LYRICIST, ID3v22FieldKey.ORIGINAL_LYRICIST); tagFieldToId3.put(FieldKey.ORIGINAL_YEAR, ID3v22FieldKey.ORIGINAL_YEAR); tagFieldToId3.put(FieldKey.QUALITY, ID3v22FieldKey.QUALITY); tagFieldToId3.put(FieldKey.RATING, ID3v22FieldKey.RATING); tagFieldToId3.put(FieldKey.RECORD_LABEL, ID3v22FieldKey.RECORD_LABEL); tagFieldToId3.put(FieldKey.REMIXER, ID3v22FieldKey.REMIXER); tagFieldToId3.put(FieldKey.SCRIPT, ID3v22FieldKey.SCRIPT); tagFieldToId3.put(FieldKey.TAGS, ID3v22FieldKey.TAGS); tagFieldToId3.put(FieldKey.TEMPO, ID3v22FieldKey.TEMPO); tagFieldToId3.put(FieldKey.TITLE, ID3v22FieldKey.TITLE); tagFieldToId3.put(FieldKey.TITLE_SORT, ID3v22FieldKey.TITLE_SORT); tagFieldToId3.put(FieldKey.TRACK, ID3v22FieldKey.TRACK); tagFieldToId3.put(FieldKey.TRACK_TOTAL, ID3v22FieldKey.TRACK_TOTAL); tagFieldToId3.put(FieldKey.URL_DISCOGS_ARTIST_SITE, ID3v22FieldKey.URL_DISCOGS_ARTIST_SITE); tagFieldToId3.put(FieldKey.URL_DISCOGS_RELEASE_SITE, ID3v22FieldKey.URL_DISCOGS_RELEASE_SITE); tagFieldToId3.put(FieldKey.URL_LYRICS_SITE, ID3v22FieldKey.URL_LYRICS_SITE); tagFieldToId3.put(FieldKey.URL_OFFICIAL_ARTIST_SITE, ID3v22FieldKey.URL_OFFICIAL_ARTIST_SITE); tagFieldToId3.put(FieldKey.URL_OFFICIAL_RELEASE_SITE, ID3v22FieldKey.URL_OFFICIAL_RELEASE_SITE); tagFieldToId3.put(FieldKey.URL_WIKIPEDIA_ARTIST_SITE, ID3v22FieldKey.URL_WIKIPEDIA_ARTIST_SITE); tagFieldToId3.put(FieldKey.URL_WIKIPEDIA_RELEASE_SITE, ID3v22FieldKey.URL_WIKIPEDIA_RELEASE_SITE); tagFieldToId3.put(FieldKey.YEAR, ID3v22FieldKey.YEAR); tagFieldToId3.put(FieldKey.ENGINEER, ID3v22FieldKey.ENGINEER); tagFieldToId3.put(FieldKey.PRODUCER, ID3v22FieldKey.PRODUCER); tagFieldToId3.put(FieldKey.MIXER, ID3v22FieldKey.MIXER); tagFieldToId3.put(FieldKey.DJMIXER, ID3v22FieldKey.DJMIXER); tagFieldToId3.put(FieldKey.ARRANGER, ID3v22FieldKey.ARRANGER); } /** * @param genericKey * @return id3 key for generic key */ public ID3v22FieldKey getId3KeyFromGenericKey(FieldKey genericKey) { return tagFieldToId3.get(genericKey); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/ID3Tags.java0000644000175000017500000003402511470746136025016 0ustar drazzibdrazzib/* * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3; import org.jaudiotagger.tag.TagException; import java.lang.reflect.Constructor; import java.util.logging.Logger; /** * This contains static methods that can be performed on tags * and to convert between tags. * * @author : Paul Taylor * @author : Eric Farng * @version $Id: ID3Tags.java 929 2010-11-17 12:36:46Z paultaylor $ */ public class ID3Tags { //Logger public static Logger logger = Logger.getLogger("org.jaudiotagger.tag.id3"); private ID3Tags() { } /** * Returns true if the identifier is a valid ID3v2.2 frame identifier * * @param identifier string to test * @return true if the identifier is a valid ID3v2.2 frame identifier */ public static boolean isID3v22FrameIdentifier(String identifier) { //If less than 3 cant be an identifier if (identifier.length() < 3) { return false; } //If 3 is it a known identifier else return identifier.length() == 3 && ID3v22Frames.getInstanceOf().getIdToValueMap().containsKey(identifier); } /** * Returns true if the identifier is a valid ID3v2.3 frame identifier * * @param identifier string to test * @return true if the identifier is a valid ID3v2.3 frame identifier */ public static boolean isID3v23FrameIdentifier(String identifier) { return identifier.length() >= 4 && ID3v23Frames.getInstanceOf().getIdToValueMap().containsKey(identifier.substring(0, 4)); } /** * Returns true if the identifier is a valid ID3v2.4 frame identifier * * @param identifier string to test * @return true if the identifier is a valid ID3v2.4 frame identifier */ public static boolean isID3v24FrameIdentifier(String identifier) { return identifier.length() >= 4 && ID3v24Frames.getInstanceOf().getIdToValueMap().containsKey(identifier.substring(0, 4)); } /** * Given an datatype, try to return it as a long. This tries to * parse a string, and takes Long, Short, Byte, Integer * objects and gets their value. An exception is not explicitly thrown * here because it would causes too many other methods to also throw it. * * @param value datatype to find long from. * @return long value * @throws IllegalArgumentException */ static public long getWholeNumber(Object value) { long number; if (value instanceof String) { number = Long.parseLong((String) value); } else if (value instanceof Byte) { number = (Byte) value; } else if (value instanceof Short) { number = (Short) value; } else if (value instanceof Integer) { number = (Integer) value; } else if (value instanceof Long) { number = (Long) value; } else { throw new IllegalArgumentException("Unsupported value class: " + value.getClass().getName()); } return number; } /** * Convert from ID3v22 FrameIdentifier to ID3v23 * @param identifier * @return */ public static String convertFrameID22To23(String identifier) { if (identifier.length() < 3) { return null; } return ID3Frames.convertv22Tov23.get((String)identifier.subSequence(0, 3)); } /** * Convert from ID3v22 FrameIdentifier to ID3v24 * @param identifier * @return */ public static String convertFrameID22To24(String identifier) { //Idv22 identifiers are only of length 3 times if (identifier.length() < 3) { return null; } //Has idv22 been mapped to v23 String id = ID3Frames.convertv22Tov23.get(identifier.substring(0, 3)); if (id != null) { //has v2.3 been mapped to v2.4 String v23id = ID3Frames.convertv23Tov24.get(id); if (v23id == null) { //if not it may be because v2.3 and and v2.4 are same so wont be //in mapping if (ID3v24Frames.getInstanceOf().getIdToValueMap().get(id) != null) { return id; } else { return null; } } else { return v23id; } } else { return null; } } /** * Convert from ID3v23 FrameIdentifier to ID3v22 * @param identifier * @return */ public static String convertFrameID23To22(String identifier) { if (identifier.length() < 4) { return null; } //If it is a v23 identifier if (ID3v23Frames.getInstanceOf().getIdToValueMap().containsKey(identifier)) { //If only name has changed v22 and modified in v23 return result of. return ID3Frames.convertv23Tov22.get(identifier.substring(0, 4)); } return null; } /** * Convert from ID3v23 FrameIdentifier to ID3v24 * @param identifier * @return */ public static String convertFrameID23To24(String identifier) { if (identifier.length() < 4) { return null; } //If it is a ID3v23 identifier if (ID3v23Frames.getInstanceOf().getIdToValueMap().containsKey(identifier)) { //If no change between ID3v23 and ID3v24 should be in ID3v24 list. if (ID3v24Frames.getInstanceOf().getIdToValueMap().containsKey(identifier)) { return identifier; } //If only name has changed ID3v23 and modified in ID3v24 return result of. else { return ID3Frames.convertv23Tov24.get(identifier.substring(0, 4)); } } return null; } /** * Force from ID3v22 FrameIdentifier to ID3v23, this is where the frame and structure * has changed from v2 to v3 but we can still do some kind of conversion. * @param identifier * @return */ public static String forceFrameID22To23(String identifier) { return ID3Frames.forcev22Tov23.get(identifier); } /** * Force from ID3v22 FrameIdentifier to ID3v23, this is where the frame and structure * has changed from v2 to v3 but we can still do some kind of conversion. * @param identifier * @return */ public static String forceFrameID23To22(String identifier) { return ID3Frames.forcev23Tov22.get(identifier); } /** * Force from ID3v2.30 FrameIdentifier to ID3v2.40, this is where the frame and structure * has changed from v3 to v4 but we can still do some kind of conversion. * @param identifier * @return */ public static String forceFrameID23To24(String identifier) { return ID3Frames.forcev23Tov24.get(identifier); } /** * Force from ID3v2.40 FrameIdentifier to ID3v2.30, this is where the frame and structure * has changed between v4 to v3 but we can still do some kind of conversion. * @param identifier * @return */ public static String forceFrameID24To23(String identifier) { return ID3Frames.forcev24Tov23.get(identifier); } /** * Convert from ID3v24 FrameIdentifier to ID3v23 * @param identifier * @return */ public static String convertFrameID24To23(String identifier) { String id; if (identifier.length() < 4) { return null; } id = ID3Frames.convertv24Tov23.get(identifier); if (id == null) { if (ID3v23Frames.getInstanceOf().getIdToValueMap().containsKey(identifier)) { id = identifier; } } return id; } /** * Unable to instantiate abstract classes, so can't call the copy * constructor. So find out the instantiated class name and call the copy * constructor through reflection (e.g for a a FrameBody would have to have a constructor * that takes another frameBody as the same type as a parameter) * * @param copyObject * @return * @throws IllegalArgumentException if no suitable constructor exists */ public static Object copyObject(Object copyObject) { Constructor constructor; Class[] constructorParameterArray; Object[] parameterArray; if (copyObject == null) { return null; } try { constructorParameterArray = new Class[1]; constructorParameterArray[0] = copyObject.getClass(); constructor = copyObject.getClass().getConstructor(constructorParameterArray); parameterArray = new Object[1]; parameterArray[0] = copyObject; return constructor.newInstance(parameterArray); } catch (NoSuchMethodException ex) { throw new IllegalArgumentException("NoSuchMethodException: Error finding constructor to create copy:"+copyObject.getClass().getName()); } catch (IllegalAccessException ex) { throw new IllegalArgumentException("IllegalAccessException: No access to run constructor to create copy"+copyObject.getClass().getName()); } catch (InstantiationException ex) { throw new IllegalArgumentException("InstantiationException: Unable to instantiate constructor to copy"+copyObject.getClass().getName()); } catch (java.lang.reflect.InvocationTargetException ex) { if (ex.getCause() instanceof Error) { throw (Error) ex.getCause(); } else if (ex.getCause() instanceof RuntimeException) { throw (RuntimeException) ex.getCause(); } else { throw new IllegalArgumentException("InvocationTargetException: Unable to invoke constructor to create copy"); } } } /** * Find the first whole number that can be parsed from the string * * @param str string to search * @return first whole number that can be parsed from the string * @throws TagException */ public static long findNumber(String str) throws TagException { return findNumber(str, 0); } /** * Find the first whole number that can be parsed from the string * * @param str string to search * @param offset start seaching from this index * @return first whole number that can be parsed from the string * @throws TagException * @throws NullPointerException * @throws IndexOutOfBoundsException */ public static long findNumber(String str, int offset) throws TagException { if (str == null) { throw new NullPointerException("String is null"); } if ((offset < 0) || (offset >= str.length())) { throw new IndexOutOfBoundsException("Offset to image string is out of bounds: offset = " + offset + ", string.length()" + str.length()); } int i; int j; long num; i = offset; while (i < str.length()) { if (((str.charAt(i) >= '0') && (str.charAt(i) <= '9')) || (str.charAt(i) == '-')) { break; } i++; } j = i + 1; while (j < str.length()) { if (((str.charAt(j) < '0') || (str.charAt(j) > '9'))) { break; } j++; } if ((j <= str.length()) && (j > i)) { num = Long.parseLong(str.substring(i, j)); } else { throw new TagException("Unable to find integer in string: " + str); } return num; } /** * Remove all occurances of the given character from the string argument. * * @param str String to search * @param ch character to remove * @return new String without the given charcter */ static public String stripChar(String str, char ch) { if (str != null) { char[] buffer = new char[str.length()]; int next = 0; for (int i = 0; i < str.length(); i++) { if (str.charAt(i) != ch) { buffer[next++] = str.charAt(i); } } return new String(buffer, 0, next); } else { return null; } } /** * truncate a string if it longer than the argument * * @param str String to truncate * @param len maximum desired length of new string * @return */ public static String truncate(String str, int len) { if (str == null) { return null; } if (len < 0) { return null; } if (str.length() > len) { return str.substring(0, len); } else { return str; } } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/ID3v22PreferredFrameOrderComparator.java0000644000175000017500000001577611470746136032403 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3; import java.util.Comparator; import java.util.List; import java.util.ArrayList; import static org.jaudiotagger.tag.id3.ID3v24Frames.FRAME_ID_ACCOMPANIMENT; /** * Orders frame Ids so that the most important frames are writtne first */ public class ID3v22PreferredFrameOrderComparator implements Comparator { private static ID3v22PreferredFrameOrderComparator comparator; private static List frameIdsInPreferredOrder = new ArrayList(); static { //these are the key ones we want at the top frameIdsInPreferredOrder.add(ID3v22Frames.FRAME_ID_V2_UNIQUE_FILE_ID); frameIdsInPreferredOrder.add(ID3v22Frames.FRAME_ID_V2_TITLE); frameIdsInPreferredOrder.add(ID3v22Frames.FRAME_ID_V2_ARTIST); frameIdsInPreferredOrder.add(ID3v22Frames.FRAME_ID_V2_ALBUM); frameIdsInPreferredOrder.add(ID3v22Frames.FRAME_ID_V2_TORY); frameIdsInPreferredOrder.add(ID3v22Frames.FRAME_ID_V2_GENRE); frameIdsInPreferredOrder.add(ID3v22Frames.FRAME_ID_V2_COMPOSER); frameIdsInPreferredOrder.add(ID3v22Frames.FRAME_ID_V2_CONDUCTOR); frameIdsInPreferredOrder.add(ID3v22Frames.FRAME_ID_V2_CONTENT_GROUP_DESC); frameIdsInPreferredOrder.add(ID3v22Frames.FRAME_ID_V2_TRACK); frameIdsInPreferredOrder.add(ID3v22Frames.FRAME_ID_V2_TYER); frameIdsInPreferredOrder.add(ID3v22Frames.FRAME_ID_V2_TDAT); frameIdsInPreferredOrder.add(ID3v22Frames.FRAME_ID_V2_TIME); frameIdsInPreferredOrder.add(ID3v22Frames.FRAME_ID_V2_BPM); frameIdsInPreferredOrder.add(ID3v22Frames.FRAME_ID_V2_ISRC); frameIdsInPreferredOrder.add(ID3v22Frames.FRAME_ID_V2_TORY); frameIdsInPreferredOrder.add(ID3v22Frames.FRAME_ID_V2_ACCOMPANIMENT); frameIdsInPreferredOrder.add(ID3v22Frames.FRAME_ID_V2_TITLE_REFINEMENT); frameIdsInPreferredOrder.add(ID3v22Frames.FRAME_ID_V2_UNSYNC_LYRICS); frameIdsInPreferredOrder.add(ID3v22Frames.FRAME_ID_V2_USER_DEFINED_INFO); frameIdsInPreferredOrder.add(ID3v22Frames.FRAME_ID_V2_USER_DEFINED_URL); frameIdsInPreferredOrder.add(ID3v22Frames.FRAME_ID_V2_URL_ARTIST_WEB); frameIdsInPreferredOrder.add(ID3v22Frames.FRAME_ID_V2_URL_COMMERCIAL); frameIdsInPreferredOrder.add(ID3v22Frames.FRAME_ID_V2_URL_COPYRIGHT); frameIdsInPreferredOrder.add(ID3v22Frames.FRAME_ID_V2_URL_FILE_WEB); frameIdsInPreferredOrder.add(ID3v22Frames.FRAME_ID_V2_URL_OFFICIAL_RADIO); frameIdsInPreferredOrder.add(ID3v22Frames.FRAME_ID_V2_URL_PAYMENT); frameIdsInPreferredOrder.add(ID3v22Frames.FRAME_ID_V2_URL_PUBLISHERS); frameIdsInPreferredOrder.add(ID3v22Frames.FRAME_ID_V2_URL_COMMERCIAL); frameIdsInPreferredOrder.add(ID3v22Frames.FRAME_ID_V2_LYRICIST); frameIdsInPreferredOrder.add(ID3v22Frames.FRAME_ID_V2_MEDIA_TYPE); frameIdsInPreferredOrder.add(ID3v22Frames.FRAME_ID_V2_IPLS); frameIdsInPreferredOrder.add(ID3v22Frames.FRAME_ID_V2_LANGUAGE); frameIdsInPreferredOrder.add(ID3v22Frames.FRAME_ID_V2_TITLE_SORT_ORDER_ITUNES); frameIdsInPreferredOrder.add(ID3v22Frames.FRAME_ID_V2_PLAYLIST_DELAY); frameIdsInPreferredOrder.add(ID3v22Frames.FRAME_ID_V2_PLAY_COUNTER); frameIdsInPreferredOrder.add(ID3v22Frames.FRAME_ID_V2_POPULARIMETER); frameIdsInPreferredOrder.add(ID3v22Frames.FRAME_ID_V2_PUBLISHER); frameIdsInPreferredOrder.add(ID3v22Frames.FRAME_ID_V2_ALBUM_ARTIST_SORT_ORDER_ITUNES); frameIdsInPreferredOrder.add(ID3v22Frames.FRAME_ID_V2_COMPOSER_SORT_ORDER_ITUNES); frameIdsInPreferredOrder.add(ID3v22Frames.FRAME_ID_V2_IS_COMPILATION); frameIdsInPreferredOrder.add(ID3v22Frames.FRAME_ID_V2_TITLE_SORT_ORDER_ITUNES); frameIdsInPreferredOrder.add(ID3v22Frames.FRAME_ID_V2_ARTIST_SORT_ORDER_ITUNES); frameIdsInPreferredOrder.add(ID3v22Frames.FRAME_ID_V2_ALBUM_SORT_ORDER_ITUNES); frameIdsInPreferredOrder.add(ID3v22Frames.FRAME_ID_V2_ALBUM_ARTIST_SORT_ORDER_ITUNES); frameIdsInPreferredOrder.add(ID3v22Frames.FRAME_ID_V2_COMPOSER_SORT_ORDER_ITUNES); frameIdsInPreferredOrder.add(ID3v22Frames.FRAME_ID_V2_COMMENT); //Not so bothered about these frameIdsInPreferredOrder.add(ID3v22Frames.FRAME_ID_V2_TRDA); frameIdsInPreferredOrder.add(ID3v22Frames.FRAME_ID_V2_COPYRIGHTINFO); frameIdsInPreferredOrder.add(ID3v22Frames.FRAME_ID_V2_ENCODEDBY); frameIdsInPreferredOrder.add(ID3v22Frames.FRAME_ID_V2_EQUALISATION); frameIdsInPreferredOrder.add(ID3v22Frames.FRAME_ID_V2_EVENT_TIMING_CODES); frameIdsInPreferredOrder.add(ID3v22Frames.FRAME_ID_V2_FILE_TYPE); frameIdsInPreferredOrder.add(ID3v22Frames.FRAME_ID_V2_HW_SW_SETTINGS); frameIdsInPreferredOrder.add(ID3v22Frames.FRAME_ID_V2_INITIAL_KEY); frameIdsInPreferredOrder.add(ID3v22Frames.FRAME_ID_V2_LENGTH); frameIdsInPreferredOrder.add(ID3v22Frames.FRAME_ID_V2_LINKED_INFO); frameIdsInPreferredOrder.add(ID3v22Frames.FRAME_ID_V2_TSIZ); frameIdsInPreferredOrder.add(ID3v22Frames.FRAME_ID_V2_MPEG_LOCATION_LOOKUP_TABLE); frameIdsInPreferredOrder.add(ID3v22Frames.FRAME_ID_V2_ORIGARTIST); frameIdsInPreferredOrder.add(ID3v22Frames.FRAME_ID_V2_ORIG_FILENAME); frameIdsInPreferredOrder.add(ID3v22Frames.FRAME_ID_V2_ORIG_LYRICIST); frameIdsInPreferredOrder.add(ID3v22Frames.FRAME_ID_V2_ORIG_TITLE); frameIdsInPreferredOrder.add(ID3v22Frames.FRAME_ID_V2_RECOMMENDED_BUFFER_SIZE); frameIdsInPreferredOrder.add(ID3v22Frames.FRAME_ID_V2_REMIXED); frameIdsInPreferredOrder.add(ID3v22Frames.FRAME_ID_V2_REVERB); frameIdsInPreferredOrder.add(ID3v22Frames.FRAME_ID_V2_SET); frameIdsInPreferredOrder.add(ID3v22Frames.FRAME_ID_V2_SYNC_LYRIC); frameIdsInPreferredOrder.add(ID3v22Frames.FRAME_ID_V2_SYNC_TEMPO); //Want this near the end because can cause problems with unsyncing frameIdsInPreferredOrder.add(ID3v22Frames.FRAME_ID_V2_ATTACHED_PICTURE); //Itunes doesnt seem to like these, and of little use so put right at end frameIdsInPreferredOrder.add(ID3v22Frames.FRAME_ID_V2_MUSIC_CD_ID); frameIdsInPreferredOrder.add(ID3v22Frames.FRAME_ID_V2_AUDIO_ENCRYPTION); frameIdsInPreferredOrder.add(ID3v22Frames.FRAME_ID_V2_GENERAL_ENCAPS_OBJECT); } private ID3v22PreferredFrameOrderComparator() { } public static ID3v22PreferredFrameOrderComparator getInstanceof() { if(comparator ==null) { comparator =new ID3v22PreferredFrameOrderComparator(); } return comparator; } /** * * @param frameId1 * @param frameId2 * @return */ public int compare(String frameId1,String frameId2) { int frameId1Index= frameIdsInPreferredOrder.indexOf(frameId1); int frameId2Index= frameIdsInPreferredOrder.indexOf(frameId2); return frameId1Index - frameId2Index; } public boolean equals(Object obj) { return obj instanceof ID3v22PreferredFrameOrderComparator; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/ID3v22Tag.java0000644000175000017500000006264511470746136025176 0ustar drazzibdrazzib/* * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can getFields a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3; import org.jaudiotagger.FileConstants; import org.jaudiotagger.audio.mp3.MP3File; import org.jaudiotagger.logging.ErrorMessage; import org.jaudiotagger.tag.*; import org.jaudiotagger.tag.datatype.Artwork; import org.jaudiotagger.tag.datatype.DataTypes; import org.jaudiotagger.tag.id3.framebody.*; import org.jaudiotagger.tag.id3.valuepair.ImageFormats; import org.jaudiotagger.tag.reference.PictureTypes; import java.io.File; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.WritableByteChannel; import java.util.ArrayList; import java.util.Comparator; import java.util.LinkedHashMap; import java.util.List; import java.util.logging.Level; /** * Represents an ID3v2.2 tag. * * @author : Paul Taylor * @author : Eric Farng * @version $Id: ID3v22Tag.java 929 2010-11-17 12:36:46Z paultaylor $ */ public class ID3v22Tag extends AbstractID3v2Tag { protected static final String TYPE_COMPRESSION = "compression"; protected static final String TYPE_UNSYNCHRONISATION = "unsyncronisation"; /** * Bit mask to indicate tag is Unsychronization */ public static final int MASK_V22_UNSYNCHRONIZATION = FileConstants.BIT7; /** * Bit mask to indicate tag is compressed, although compression is not * actually defined in v22 so just ignored */ public static final int MASK_V22_COMPRESSION = FileConstants.BIT6; /** * The tag is compressed, although no compression scheme is defined in ID3v22 */ protected boolean compression = false; /** * If set all frames in the tag uses unsynchronisation */ protected boolean unsynchronization = false; public static final byte RELEASE = 2; public static final byte MAJOR_VERSION = 2; public static final byte REVISION = 0; /** * Retrieve the Release */ public byte getRelease() { return RELEASE; } /** * Retrieve the Major Version */ public byte getMajorVersion() { return MAJOR_VERSION; } /** * Retrieve the Revision */ public byte getRevision() { return REVISION; } /** * Creates a new empty ID3v2_2 tag. */ public ID3v22Tag() { frameMap = new LinkedHashMap(); encryptedFrameMap = new LinkedHashMap(); } /** * Copy primitives applicable to v2.2 */ protected void copyPrimitives(AbstractID3v2Tag copyObj) { logger.info("Copying primitives"); super.copyPrimitives(copyObj); //Set the primitive types specific to v2_2. if (copyObj instanceof ID3v22Tag) { ID3v22Tag copyObject = (ID3v22Tag) copyObj; this.compression = copyObject.compression; this.unsynchronization = copyObject.unsynchronization; } else if (copyObj instanceof ID3v23Tag) { ID3v23Tag copyObject = (ID3v23Tag) copyObj; this.compression = copyObject.compression; this.unsynchronization = copyObject.unsynchronization; } else if (copyObj instanceof ID3v24Tag) { ID3v24Tag copyObject = (ID3v24Tag) copyObj; this.compression = false; this.unsynchronization = copyObject.unsynchronization; } } /** * Copy Constructor, creates a new ID3v2_2 Tag based on another ID3v2_2 Tag * @param copyObject */ public ID3v22Tag(ID3v22Tag copyObject) { //This doesnt do anything. super(copyObject); logger.info("Creating tag from another tag of same type"); copyPrimitives(copyObject); copyFrames(copyObject); } /** * Constructs a new tag based upon another tag of different version/type * @param mp3tag */ public ID3v22Tag(AbstractTag mp3tag) { frameMap = new LinkedHashMap(); encryptedFrameMap = new LinkedHashMap(); logger.info("Creating tag from a tag of a different version"); //Default Superclass constructor does nothing if (mp3tag != null) { ID3v24Tag convertedTag; //Should use the copy constructor instead if ((!(mp3tag instanceof ID3v23Tag)) && (mp3tag instanceof ID3v22Tag)) { throw new UnsupportedOperationException("Copy Constructor not called. Please type cast the argument"); } //If v2.4 can getFields variables from this else if (mp3tag instanceof ID3v24Tag) { convertedTag = (ID3v24Tag) mp3tag; } //Any tag (e.g lyrics3 and idv1.1,idv2.3 can be converted to id32.4 so do that //to simplify things else { convertedTag = new ID3v24Tag(mp3tag); } this.setLoggingFilename(convertedTag.getLoggingFilename()); //Set the primitive types specific to v2_2. copyPrimitives(convertedTag); //Set v2.2 Frames copyFrames(convertedTag); logger.info("Created tag from a tag of a different version"); } } /** * Creates a new ID3v2_2 datatype. * * @param buffer * @param loggingFilename * @throws TagException */ public ID3v22Tag(ByteBuffer buffer, String loggingFilename) throws TagException { setLoggingFilename(loggingFilename); this.read(buffer); } /** * Creates a new ID3v2_2 datatype. * * @param buffer * @throws TagException * @deprecated use {@link #ID3v22Tag(ByteBuffer,String)} instead */ public ID3v22Tag(ByteBuffer buffer) throws TagException { this(buffer, ""); } /** * @return an indentifier of the tag type */ public String getIdentifier() { return "ID3v2_2.20"; } /** * Return frame size based upon the sizes of the frames rather than the size * including padding recorded in the tag header * * @return size */ public int getSize() { int size = TAG_HEADER_LENGTH; size += super.getSize(); return size; } /** * @param obj * @return equality */ public boolean equals(Object obj) { if (!(obj instanceof ID3v22Tag)) { return false; } ID3v22Tag object = (ID3v22Tag) obj; if (this.compression != object.compression) { return false; } return this.unsynchronization == object.unsynchronization && super.equals(obj); } protected void addFrame(AbstractID3v2Frame frame) { try { //Special case to handle TDRC frame from V24 that needs breaking up into separate frame in V23 if ((frame.getIdentifier().equals(ID3v24Frames.FRAME_ID_YEAR)) && (frame.getBody() instanceof FrameBodyTDRC)) { translateFrame(frame); } else if (frame instanceof ID3v22Frame) { copyFrameIntoMap(frame.getIdentifier(),frame); } else { ID3v22Frame newFrame = new ID3v22Frame(frame); copyFrameIntoMap(newFrame.getIdentifier(), newFrame); } } catch (InvalidFrameException ife) { logger.log(Level.SEVERE, "Unable to convert frame:" + frame.getIdentifier()); } } /** * Read the size of a tag, based on the value written in the tag header * * @param buffer * @return * @throws TagException */ public int readSize(ByteBuffer buffer) { //Skip over flags byte flags = buffer.get(); // Read the size, this is size of tag not including the tag header int size = ID3SyncSafeInteger.bufferToValue(buffer); //Return the exact size of tag as setField in the tag header return size + TAG_HEADER_LENGTH; } /** * Read tag Header Flags * * @param byteBuffer * @throws TagException */ private void readHeaderFlags(ByteBuffer byteBuffer) throws TagException { //Flags byte flags = byteBuffer.get(); unsynchronization = (flags & MASK_V22_UNSYNCHRONIZATION) != 0; compression = (flags & MASK_V22_COMPRESSION) != 0; if (unsynchronization) { logger.info(ErrorMessage.ID3_TAG_UNSYNCHRONIZED.getMsg(getLoggingFilename())); } if (compression) { logger.info(ErrorMessage.ID3_TAG_COMPRESSED.getMsg(getLoggingFilename())); } //Not allowable/Unknown Flags if ((flags & FileConstants.BIT5) != 0) { logger.warning(ErrorMessage.ID3_INVALID_OR_UNKNOWN_FLAG_SET.getMsg(getLoggingFilename(), FileConstants.BIT5)); } if ((flags & FileConstants.BIT4) != 0) { logger.warning(ErrorMessage.ID3_INVALID_OR_UNKNOWN_FLAG_SET.getMsg(getLoggingFilename(), FileConstants.BIT4)); } if ((flags & FileConstants.BIT3) != 0) { logger.warning(ErrorMessage.ID3_INVALID_OR_UNKNOWN_FLAG_SET.getMsg(getLoggingFilename(), FileConstants.BIT3)); } if ((flags & FileConstants.BIT2) != 0) { logger.warning(ErrorMessage.ID3_INVALID_OR_UNKNOWN_FLAG_SET.getMsg(getLoggingFilename(), FileConstants.BIT2)); } if ((flags & FileConstants.BIT1) != 0) { logger.warning(ErrorMessage.ID3_INVALID_OR_UNKNOWN_FLAG_SET.getMsg(getLoggingFilename(), FileConstants.BIT1)); } if ((flags & FileConstants.BIT0) != 0) { logger.warning(ErrorMessage.ID3_INVALID_OR_UNKNOWN_FLAG_SET.getMsg(getLoggingFilename(), FileConstants.BIT3)); } } /** * {@inheritDoc} */ @Override public void read(ByteBuffer byteBuffer) throws TagException { int size; if (!seek(byteBuffer)) { throw new TagNotFoundException("ID3v2.20 tag not found"); } logger.info(getLoggingFilename() + ":" + "Reading tag from file"); //Read the flags readHeaderFlags(byteBuffer); // Read the size size = ID3SyncSafeInteger.bufferToValue(byteBuffer); //Slice Buffer, so position markers tally with size (i.e do not include tagheader) ByteBuffer bufferWithoutHeader = byteBuffer.slice(); //We need to synchronize the buffer if (unsynchronization) { bufferWithoutHeader = ID3Unsynchronization.synchronize(bufferWithoutHeader); } readFrames(bufferWithoutHeader, size); logger.info(getLoggingFilename() + ":" + "Loaded Frames,there are:" + frameMap.keySet().size()); } /** * Read frames from tag * @param byteBuffer * @param size */ protected void readFrames(ByteBuffer byteBuffer, int size) { //Now start looking for frames ID3v22Frame next; frameMap = new LinkedHashMap(); encryptedFrameMap = new LinkedHashMap(); //Read the size from the Tag Header this.fileReadSize = size; logger.finest(getLoggingFilename() + ":" + "Start of frame body at:" + byteBuffer.position() + ",frames sizes and padding is:" + size); /* todo not done yet. Read the first Frame, there seems to be quite a ** common case of extra data being between the tag header and the first ** frame so should we allow for this when reading first frame, but not subsequent frames */ // Read the frames until got to upto the size as specified in header while (byteBuffer.position() < size) { try { //Read Frame logger.finest(getLoggingFilename() + ":" + "looking for next frame at:" + byteBuffer.position()); next = new ID3v22Frame(byteBuffer, getLoggingFilename()); String id = next.getIdentifier(); loadFrameIntoMap(id, next); } //Found Padding, no more frames catch (PaddingException ex) { logger.config(getLoggingFilename() + ":Found padding starting at:" + byteBuffer.position()); break; } //Found Empty Frame catch (EmptyFrameException ex) { logger.warning(getLoggingFilename() + ":" + "Empty Frame:" + ex.getMessage()); this.emptyFrameBytes += ID3v22Frame.FRAME_HEADER_SIZE; } catch (InvalidFrameIdentifierException ifie) { logger.info(getLoggingFilename() + ":" + "Invalid Frame Identifier:" + ifie.getMessage()); this.invalidFrames++; //Dont try and find any more frames break; } //Problem trying to find frame catch (InvalidFrameException ife) { logger.warning(getLoggingFilename() + ":" + "Invalid Frame:" + ife.getMessage()); this.invalidFrames++; //Dont try and find any more frames break; } //Failed reading frame but may just have invalid data but correct length so lets carry on //in case we can read the next frame catch(InvalidDataTypeException idete) { logger.warning(getLoggingFilename() + ":Corrupt Frame:" + idete.getMessage()); this.invalidFrames++; continue; } } } /** * This is used when we need to translate a single frame into multiple frames, * currently required for TDRC frames. * @param frame */ //TODO will overwrite any existing TYER or TIME frame, do we ever want multiples of these protected void translateFrame(AbstractID3v2Frame frame) { FrameBodyTDRC tmpBody = (FrameBodyTDRC) frame.getBody(); ID3v22Frame newFrame; if (tmpBody.getYear().length() != 0) { //Create Year frame (v2.2 id,but uses v2.3 body) newFrame = new ID3v22Frame(ID3v22Frames.FRAME_ID_V2_TYER); ((AbstractFrameBodyTextInfo) newFrame.getBody()).setText(tmpBody.getYear()); frameMap.put(newFrame.getIdentifier(), newFrame); } if (tmpBody.getTime().length() != 0) { //Create Time frame (v2.2 id,but uses v2.3 body) newFrame = new ID3v22Frame(ID3v22Frames.FRAME_ID_V2_TIME); ((AbstractFrameBodyTextInfo) newFrame.getBody()).setText(tmpBody.getTime()); frameMap.put(newFrame.getIdentifier(), newFrame); } } /** * Write the ID3 header to the ByteBuffer. *

* * @param padding * @param size * @return ByteBuffer * @throws IOException */ private ByteBuffer writeHeaderToBuffer(int padding, int size) throws IOException { compression = false; //Create Header Buffer ByteBuffer headerBuffer = ByteBuffer.allocate(TAG_HEADER_LENGTH); //TAGID headerBuffer.put(TAG_ID); //Major Version headerBuffer.put(getMajorVersion()); //Minor Version headerBuffer.put(getRevision()); //Flags byte flags = (byte) 0; if (unsynchronization) { flags |= (byte) MASK_V22_UNSYNCHRONIZATION; } if (compression) { flags |= (byte) MASK_V22_COMPRESSION; } headerBuffer.put(flags); //Size As Recorded in Header, don't include the main header length headerBuffer.put(ID3SyncSafeInteger.valueToBuffer(padding + size)); headerBuffer.flip(); return headerBuffer; } /** * {@inheritDoc} */ @Override public void write(File file, long audioStartLocation) throws IOException { setLoggingFilename(file.getName()); logger.info("Writing tag to file:"+getLoggingFilename()); // Write Body Buffer byte[] bodyByteBuffer = writeFramesToBuffer().toByteArray(); // Unsynchronize if option enabled and unsync required unsynchronization = TagOptionSingleton.getInstance().isUnsyncTags() && ID3Unsynchronization.requiresUnsynchronization(bodyByteBuffer); if (isUnsynchronization()) { bodyByteBuffer = ID3Unsynchronization.unsynchronize(bodyByteBuffer); logger.info(getLoggingFilename() + ":bodybytebuffer:sizeafterunsynchronisation:" + bodyByteBuffer.length); } int sizeIncPadding = calculateTagSize(bodyByteBuffer.length + TAG_HEADER_LENGTH, (int) audioStartLocation); int padding = sizeIncPadding - (bodyByteBuffer.length + TAG_HEADER_LENGTH); logger.info(getLoggingFilename() + ":Current audiostart:" + audioStartLocation); logger.info(getLoggingFilename() + ":Size including padding:" + sizeIncPadding); logger.info(getLoggingFilename() + ":Padding:" + padding); ByteBuffer headerBuffer = writeHeaderToBuffer(padding, bodyByteBuffer.length); writeBufferToFile(file,headerBuffer, bodyByteBuffer,padding,sizeIncPadding,audioStartLocation); } /** * {@inheritDoc} */ @Override public void write(WritableByteChannel channel) throws IOException { logger.info(getLoggingFilename() + ":Writing tag to channel"); byte[] bodyByteBuffer = writeFramesToBuffer().toByteArray(); logger.info(getLoggingFilename() + ":bodybytebuffer:sizebeforeunsynchronisation:" + bodyByteBuffer.length); //Unsynchronize if option enabled and unsync required unsynchronization = TagOptionSingleton.getInstance().isUnsyncTags() && ID3Unsynchronization.requiresUnsynchronization(bodyByteBuffer); if (isUnsynchronization()) { bodyByteBuffer = ID3Unsynchronization.unsynchronize(bodyByteBuffer); logger.info(getLoggingFilename() + ":bodybytebuffer:sizeafterunsynchronisation:" + bodyByteBuffer.length); } ByteBuffer headerBuffer = writeHeaderToBuffer(0, bodyByteBuffer.length); channel.write(headerBuffer); channel.write(ByteBuffer.wrap(bodyByteBuffer)); } public void createStructure() { MP3File.getStructureFormatter().openHeadingElement(TYPE_TAG, getIdentifier()); super.createStructureHeader(); //Header MP3File.getStructureFormatter().openHeadingElement(TYPE_HEADER, ""); MP3File.getStructureFormatter().addElement(TYPE_COMPRESSION, this.compression); MP3File.getStructureFormatter().addElement(TYPE_UNSYNCHRONISATION, this.unsynchronization); MP3File.getStructureFormatter().closeHeadingElement(TYPE_HEADER); //Body super.createStructureBody(); MP3File.getStructureFormatter().closeHeadingElement(TYPE_TAG); } /** * @return is tag unsynchronized */ public boolean isUnsynchronization() { return unsynchronization; } /** * @return is tag compressed */ public boolean isCompression() { return compression; } /** * Create Frame * * @param id frameid * @return */ public ID3v22Frame createFrame(String id) { return new ID3v22Frame(id); } /** * Create Frame for Id3 Key *

* Only textual data supported at the moment, should only be used with frames that * support a simple string argument. * * @param id3Key * @param value * @return * @throws KeyNotFoundException * @throws FieldDataInvalidException */ public TagField createField(ID3v22FieldKey id3Key, String value) throws KeyNotFoundException, FieldDataInvalidException { if (id3Key == null) { throw new KeyNotFoundException(); } return super.doCreateTagField(new FrameAndSubId(id3Key.getFrameId(), id3Key.getSubId()), value); } /** * Retrieve the first value that exists for this id3v22key * * @param id3v22FieldKey * @return * @throws org.jaudiotagger.tag.KeyNotFoundException */ public String getFirst(ID3v22FieldKey id3v22FieldKey) throws KeyNotFoundException { if (id3v22FieldKey == null) { throw new KeyNotFoundException(); } FrameAndSubId frameAndSubId = new FrameAndSubId(id3v22FieldKey.getFrameId(), id3v22FieldKey.getSubId()); if (id3v22FieldKey == ID3v22FieldKey.TRACK) { AbstractID3v2Frame frame = getFirstField(frameAndSubId.getFrameId()); return String.valueOf(((FrameBodyTRCK)frame.getBody()).getTrackNo()); } else if (id3v22FieldKey == ID3v22FieldKey.TRACK_TOTAL) { AbstractID3v2Frame frame = getFirstField(frameAndSubId.getFrameId()); return String.valueOf(((FrameBodyTRCK)frame.getBody()).getTrackTotal()); } else if (id3v22FieldKey == ID3v22FieldKey.DISC_NO) { AbstractID3v2Frame frame = getFirstField(frameAndSubId.getFrameId()); return String.valueOf(((FrameBodyTPOS)frame.getBody()).getDiscNo()); } else if (id3v22FieldKey == ID3v22FieldKey.DISC_TOTAL) { AbstractID3v2Frame frame = getFirstField(frameAndSubId.getFrameId()); return String.valueOf(((FrameBodyTPOS)frame.getBody()).getDiscTotal()); } else { return super.doGetValueAtIndex(frameAndSubId, 0); } } /** * Delete fields with this id3v22FieldKey * * @param id3v22FieldKey * @throws org.jaudiotagger.tag.KeyNotFoundException */ public void deleteField(ID3v22FieldKey id3v22FieldKey) throws KeyNotFoundException { if (id3v22FieldKey == null) { throw new KeyNotFoundException(); } super.doDeleteTagField(new FrameAndSubId(id3v22FieldKey.getFrameId(), id3v22FieldKey.getSubId())); } /** * Delete fields with this (frame) id * @param id */ public void deleteField(String id) { super.doDeleteTagField(new FrameAndSubId(id,null)); } protected FrameAndSubId getFrameAndSubIdFromGenericKey(FieldKey genericKey) { ID3v22FieldKey id3v22FieldKey = ID3v22Frames.getInstanceOf().getId3KeyFromGenericKey(genericKey); if (id3v22FieldKey == null) { throw new KeyNotFoundException(); } return new FrameAndSubId(id3v22FieldKey.getFrameId(), id3v22FieldKey.getSubId()); } protected ID3Frames getID3Frames() { return ID3v22Frames.getInstanceOf(); } /** * * @return comparator used to order frames in preffrred order for writing to file * so that most important frames are written first. */ public Comparator getPreferredFrameOrderComparator() { return ID3v22PreferredFrameOrderComparator.getInstanceof(); } /** * {@inheritDoc} */ public List getArtworkList() { List coverartList = getFields(FieldKey.COVER_ART); List artworkList = new ArrayList(coverartList.size()); for(TagField next:coverartList) { FrameBodyPIC coverArt = (FrameBodyPIC) ((AbstractID3v2Frame) next).getBody(); Artwork artwork = new Artwork(); artwork.setMimeType(ImageFormats.getMimeTypeForFormat(coverArt.getFormatType())); artwork.setPictureType(coverArt.getPictureType()); artwork.setBinaryData(coverArt.getImageData()); artworkList.add(artwork); } return artworkList; } /** * {@inheritDoc} */ public TagField createField(Artwork artwork) throws FieldDataInvalidException { AbstractID3v2Frame frame = createFrame(getFrameAndSubIdFromGenericKey(FieldKey.COVER_ART).getFrameId()); FrameBodyPIC body = (FrameBodyPIC) frame.getBody(); body.setObjectValue(DataTypes.OBJ_PICTURE_DATA, artwork.getBinaryData()); body.setObjectValue(DataTypes.OBJ_PICTURE_TYPE, artwork.getPictureType()); body.setObjectValue(DataTypes.OBJ_IMAGE_FORMAT, ImageFormats.getFormatForMimeType(artwork.getMimeType())); body.setObjectValue(DataTypes.OBJ_DESCRIPTION, ""); return frame; } public TagField createArtworkField(byte[] data, String mimeType) { AbstractID3v2Frame frame = createFrame(getFrameAndSubIdFromGenericKey(FieldKey.COVER_ART).getFrameId()); FrameBodyPIC body = (FrameBodyPIC) frame.getBody(); body.setObjectValue(DataTypes.OBJ_PICTURE_DATA, data); body.setObjectValue(DataTypes.OBJ_PICTURE_TYPE, PictureTypes.DEFAULT_ID); body.setObjectValue(DataTypes.OBJ_IMAGE_FORMAT, ImageFormats.getFormatForMimeType(mimeType)); body.setObjectValue(DataTypes.OBJ_DESCRIPTION, ""); return frame; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/ID3Frames.java0000644000175000017500000003754111470746136025343 0ustar drazzibdrazzib/* * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.tag.id3; import org.jaudiotagger.tag.datatype.AbstractStringStringValuePair; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.Map; import java.util.TreeSet; /** * Subclasses Defines ID3 frames for their Tag Version *

* Here we specify how frames are mapped between different Tag Versions * * @author Paul Taylor * @version $Id: ID3Frames.java 929 2010-11-17 12:36:46Z paultaylor $ */ public abstract class ID3Frames extends AbstractStringStringValuePair { /** * Holds frames whereby multiple occurences are allowed */ protected TreeSet multipleFrames = new TreeSet(); /** * These frames should be lost if file changes */ protected TreeSet discardIfFileAlteredFrames = new TreeSet(); /** * These frames are part of the Official Specification for that Tag Version */ protected TreeSet supportedFrames = new TreeSet(); /** * These frames are extensions to the Specification for that Tag Version */ protected TreeSet extensionFrames = new TreeSet(); /** * These frames are Common , this is a loose term */ protected TreeSet commonFrames = new TreeSet(); /** * These frames are Binary */ protected TreeSet binaryFrames = new TreeSet(); /** * If file changes discard these frames * @param frameID * @return */ public boolean isDiscardIfFileAltered(String frameID) { return discardIfFileAlteredFrames.contains(frameID); } /** * Are multiple occurrences of frame allowed * @param frameID * @return */ public boolean isMultipleAllowed(String frameID) { return multipleFrames.contains(frameID); } /** * @param frameID * @return true if frames with this id are part of the specification */ public boolean isSupportedFrames(String frameID) { return supportedFrames.contains(frameID); } public TreeSet getSupportedFrames() { return supportedFrames; } /** * @param frameID * @return true if frames with this id are considered common */ public boolean isCommon(String frameID) { return commonFrames.contains(frameID); } /** * @param frameID * @return true if frames with this id are binary (non textual data) */ public boolean isBinary(String frameID) { return binaryFrames.contains(frameID); } /** * @param frameID * @return true if frame is a known extension */ public boolean isExtensionFrames(String frameID) { return extensionFrames.contains(frameID); } /** * Mapping from v22 to v23 */ public static final Map convertv22Tov23 = new LinkedHashMap(); public static final Map convertv23Tov22 = new LinkedHashMap(); public static final Map forcev22Tov23 = new LinkedHashMap(); public static final Map forcev23Tov22 = new LinkedHashMap(); public static final Map convertv23Tov24 = new LinkedHashMap(); public static final Map convertv24Tov23 = new LinkedHashMap(); public static final Map forcev23Tov24 = new LinkedHashMap(); public static final Map forcev24Tov23 = new LinkedHashMap(); private static void loadID3v23ID3v24Mapping() { // Define the mapping from v23 to v24 only maps values where // the v23 ID is not a v24 ID and where the translation from v23 to v24 // ID does not affect the framebody. //This one way allows us to convert XSOT to TSOT,XSOP to TSOP and XSOA - TSOA but in the other direction gets converted to TSOT,TSOP,TSOA convertv23Tov24.put(ID3v23Frames.FRAME_ID_V3_TITLE_SORT_ORDER_MUSICBRAINZ, ID3v24Frames.FRAME_ID_TITLE_SORT_ORDER); convertv23Tov24.put(ID3v23Frames.FRAME_ID_V3_ARTIST_SORT_ORDER_MUSICBRAINZ, ID3v24Frames.FRAME_ID_ARTIST_SORT_ORDER); convertv23Tov24.put(ID3v23Frames.FRAME_ID_V3_ALBUM_SORT_ORDER_MUSICBRAINZ, ID3v24Frames.FRAME_ID_ALBUM_SORT_ORDER); // No others exist because most v23 mappings are identical to v24 therefore no mapping required and the ones that // are different need to be forced. // Force v23 to v24 These are deprecated and need to do a forced mapping forcev23Tov24.put(ID3v23Frames.FRAME_ID_V3_RELATIVE_VOLUME_ADJUSTMENT, ID3v24Frames.FRAME_ID_RELATIVE_VOLUME_ADJUSTMENT2); forcev23Tov24.put(ID3v23Frames.FRAME_ID_V3_EQUALISATION, ID3v24Frames.FRAME_ID_EQUALISATION2); forcev23Tov24.put(ID3v23Frames.FRAME_ID_V3_IPLS, ID3v24Frames.FRAME_ID_INVOLVED_PEOPLE); forcev23Tov24.put(ID3v23Frames.FRAME_ID_V3_TDAT, ID3v24Frames.FRAME_ID_YEAR); forcev23Tov24.put(ID3v23Frames.FRAME_ID_V3_TIME, ID3v24Frames.FRAME_ID_YEAR); forcev23Tov24.put(ID3v23Frames.FRAME_ID_V3_TORY, ID3v24Frames.FRAME_ID_ORIGINAL_RELEASE_TIME); forcev23Tov24.put(ID3v23Frames.FRAME_ID_V3_TRDA, ID3v24Frames.FRAME_ID_YEAR); forcev23Tov24.put(ID3v23Frames.FRAME_ID_V3_TYER, ID3v24Frames.FRAME_ID_YEAR); forcev23Tov24.put(ID3v23Frames.FRAME_ID_V3_TYER, ID3v24Frames.FRAME_ID_YEAR); //Note Force v24 to v23, TDRC is a 1M relationship handled specially. // @TODO EQUALISATION forcev24Tov23.put(ID3v24Frames.FRAME_ID_RELATIVE_VOLUME_ADJUSTMENT2, ID3v23Frames.FRAME_ID_V3_RELATIVE_VOLUME_ADJUSTMENT); //Used to be a special frame now a text frame forcev24Tov23.put(ID3v24Frames.FRAME_ID_INVOLVED_PEOPLE, ID3v23Frames.FRAME_ID_V3_IPLS); //No Mood frame in v23 so use a TXXX frame forcev24Tov23.put(ID3v24Frames.FRAME_ID_MOOD, ID3v23Frames.FRAME_ID_V3_USER_DEFINED_INFO); } private static void loadID3v22ID3v23Mapping() { Iterator iterator; String key; String value; // All v22 ids were renamed in v23, but are essentially the same convertv22Tov23.put(ID3v22Frames.FRAME_ID_V2_ACCOMPANIMENT, ID3v23Frames.FRAME_ID_V3_ACCOMPANIMENT); convertv22Tov23.put(ID3v22Frames.FRAME_ID_V2_ALBUM, ID3v23Frames.FRAME_ID_V3_ALBUM); convertv22Tov23.put(ID3v22Frames.FRAME_ID_V2_ARTIST, ID3v23Frames.FRAME_ID_V3_ARTIST); convertv22Tov23.put(ID3v22Frames.FRAME_ID_V2_AUDIO_ENCRYPTION, ID3v23Frames.FRAME_ID_V3_AUDIO_ENCRYPTION); convertv22Tov23.put(ID3v22Frames.FRAME_ID_V2_BPM, ID3v23Frames.FRAME_ID_V3_BPM); convertv22Tov23.put(ID3v22Frames.FRAME_ID_V2_COMMENT, ID3v23Frames.FRAME_ID_V3_COMMENT); convertv22Tov23.put(ID3v22Frames.FRAME_ID_V2_COMMENT, ID3v23Frames.FRAME_ID_V3_COMMENT); convertv22Tov23.put(ID3v22Frames.FRAME_ID_V2_COMPOSER, ID3v23Frames.FRAME_ID_V3_COMPOSER); convertv22Tov23.put(ID3v22Frames.FRAME_ID_V2_CONDUCTOR, ID3v23Frames.FRAME_ID_V3_CONDUCTOR); convertv22Tov23.put(ID3v22Frames.FRAME_ID_V2_CONTENT_GROUP_DESC, ID3v23Frames.FRAME_ID_V3_CONTENT_GROUP_DESC); convertv22Tov23.put(ID3v22Frames.FRAME_ID_V2_COPYRIGHTINFO, ID3v23Frames.FRAME_ID_V3_COPYRIGHTINFO); convertv22Tov23.put(ID3v22Frames.FRAME_ID_V2_ENCODEDBY, ID3v23Frames.FRAME_ID_V3_ENCODEDBY); convertv22Tov23.put(ID3v22Frames.FRAME_ID_V2_EQUALISATION, ID3v23Frames.FRAME_ID_V3_EQUALISATION); convertv22Tov23.put(ID3v22Frames.FRAME_ID_V2_EVENT_TIMING_CODES, ID3v23Frames.FRAME_ID_V3_EVENT_TIMING_CODES); convertv22Tov23.put(ID3v22Frames.FRAME_ID_V2_FILE_TYPE, ID3v23Frames.FRAME_ID_V3_FILE_TYPE); convertv22Tov23.put(ID3v22Frames.FRAME_ID_V2_GENERAL_ENCAPS_OBJECT, ID3v23Frames.FRAME_ID_V3_GENERAL_ENCAPS_OBJECT); convertv22Tov23.put(ID3v22Frames.FRAME_ID_V2_GENRE, ID3v23Frames.FRAME_ID_V3_GENRE); convertv22Tov23.put(ID3v22Frames.FRAME_ID_V2_HW_SW_SETTINGS, ID3v23Frames.FRAME_ID_V3_HW_SW_SETTINGS); convertv22Tov23.put(ID3v22Frames.FRAME_ID_V2_INITIAL_KEY, ID3v23Frames.FRAME_ID_V3_INITIAL_KEY); convertv22Tov23.put(ID3v22Frames.FRAME_ID_V2_IPLS, ID3v23Frames.FRAME_ID_V3_IPLS); convertv22Tov23.put(ID3v22Frames.FRAME_ID_V2_ISRC, ID3v23Frames.FRAME_ID_V3_ISRC); convertv22Tov23.put(ID3v22Frames.FRAME_ID_V2_LANGUAGE, ID3v23Frames.FRAME_ID_V3_LANGUAGE); convertv22Tov23.put(ID3v22Frames.FRAME_ID_V2_LENGTH, ID3v23Frames.FRAME_ID_V3_LENGTH); convertv22Tov23.put(ID3v22Frames.FRAME_ID_V2_LINKED_INFO, ID3v23Frames.FRAME_ID_V3_LINKED_INFO); convertv22Tov23.put(ID3v22Frames.FRAME_ID_V2_LYRICIST, ID3v23Frames.FRAME_ID_V3_LYRICIST); convertv22Tov23.put(ID3v22Frames.FRAME_ID_V2_MEDIA_TYPE, ID3v23Frames.FRAME_ID_V3_MEDIA_TYPE); convertv22Tov23.put(ID3v22Frames.FRAME_ID_V2_MPEG_LOCATION_LOOKUP_TABLE, ID3v23Frames.FRAME_ID_V3_MPEG_LOCATION_LOOKUP_TABLE); convertv22Tov23.put(ID3v22Frames.FRAME_ID_V2_MUSIC_CD_ID, ID3v23Frames.FRAME_ID_V3_MUSIC_CD_ID); convertv22Tov23.put(ID3v22Frames.FRAME_ID_V2_ORIGARTIST, ID3v23Frames.FRAME_ID_V3_ORIGARTIST); convertv22Tov23.put(ID3v22Frames.FRAME_ID_V2_ORIG_FILENAME, ID3v23Frames.FRAME_ID_V3_ORIG_FILENAME); convertv22Tov23.put(ID3v22Frames.FRAME_ID_V2_ORIG_LYRICIST, ID3v23Frames.FRAME_ID_V3_ORIG_LYRICIST); convertv22Tov23.put(ID3v22Frames.FRAME_ID_V2_ORIG_TITLE, ID3v23Frames.FRAME_ID_V3_ORIG_TITLE); convertv22Tov23.put(ID3v22Frames.FRAME_ID_V2_PLAYLIST_DELAY, ID3v23Frames.FRAME_ID_V3_PLAYLIST_DELAY); convertv22Tov23.put(ID3v22Frames.FRAME_ID_V2_PLAY_COUNTER, ID3v23Frames.FRAME_ID_V3_PLAY_COUNTER); convertv22Tov23.put(ID3v22Frames.FRAME_ID_V2_PLAY_COUNTER, ID3v23Frames.FRAME_ID_V3_PLAY_COUNTER); convertv22Tov23.put(ID3v22Frames.FRAME_ID_V2_POPULARIMETER, ID3v23Frames.FRAME_ID_V3_POPULARIMETER); convertv22Tov23.put(ID3v22Frames.FRAME_ID_V2_PUBLISHER, ID3v23Frames.FRAME_ID_V3_PUBLISHER); convertv22Tov23.put(ID3v22Frames.FRAME_ID_V2_RECOMMENDED_BUFFER_SIZE, ID3v23Frames.FRAME_ID_V3_RECOMMENDED_BUFFER_SIZE); convertv22Tov23.put(ID3v22Frames.FRAME_ID_V2_RECOMMENDED_BUFFER_SIZE, ID3v23Frames.FRAME_ID_V3_RECOMMENDED_BUFFER_SIZE); convertv22Tov23.put(ID3v22Frames.FRAME_ID_V2_RELATIVE_VOLUME_ADJUSTMENT, ID3v23Frames.FRAME_ID_V3_RELATIVE_VOLUME_ADJUSTMENT); convertv22Tov23.put(ID3v22Frames.FRAME_ID_V2_REMIXED, ID3v23Frames.FRAME_ID_V3_REMIXED); convertv22Tov23.put(ID3v22Frames.FRAME_ID_V2_REVERB, ID3v23Frames.FRAME_ID_V3_REVERB); convertv22Tov23.put(ID3v22Frames.FRAME_ID_V2_SET, ID3v23Frames.FRAME_ID_V3_SET); convertv22Tov23.put(ID3v22Frames.FRAME_ID_V2_SYNC_LYRIC, ID3v23Frames.FRAME_ID_V3_SYNC_LYRIC); convertv22Tov23.put(ID3v22Frames.FRAME_ID_V2_SYNC_TEMPO, ID3v23Frames.FRAME_ID_V3_SYNC_TEMPO); convertv22Tov23.put(ID3v22Frames.FRAME_ID_V2_TDAT, ID3v23Frames.FRAME_ID_V3_TDAT); convertv22Tov23.put(ID3v22Frames.FRAME_ID_V2_TIME, ID3v23Frames.FRAME_ID_V3_TIME); convertv22Tov23.put(ID3v22Frames.FRAME_ID_V2_TITLE_REFINEMENT, ID3v23Frames.FRAME_ID_V3_TITLE_REFINEMENT); convertv22Tov23.put(ID3v22Frames.FRAME_ID_V2_TORY, ID3v23Frames.FRAME_ID_V3_TORY); convertv22Tov23.put(ID3v22Frames.FRAME_ID_V2_TRACK, ID3v23Frames.FRAME_ID_V3_TRACK); convertv22Tov23.put(ID3v22Frames.FRAME_ID_V2_TRDA, ID3v23Frames.FRAME_ID_V3_TRDA); convertv22Tov23.put(ID3v22Frames.FRAME_ID_V2_TSIZ, ID3v23Frames.FRAME_ID_V3_TSIZ); convertv22Tov23.put(ID3v22Frames.FRAME_ID_V2_TYER, ID3v23Frames.FRAME_ID_V3_TYER); convertv22Tov23.put(ID3v22Frames.FRAME_ID_V2_UNIQUE_FILE_ID, ID3v23Frames.FRAME_ID_V3_UNIQUE_FILE_ID); convertv22Tov23.put(ID3v22Frames.FRAME_ID_V2_UNIQUE_FILE_ID, ID3v23Frames.FRAME_ID_V3_UNIQUE_FILE_ID); convertv22Tov23.put(ID3v22Frames.FRAME_ID_V2_UNSYNC_LYRICS, ID3v23Frames.FRAME_ID_V3_UNSYNC_LYRICS); convertv22Tov23.put(ID3v22Frames.FRAME_ID_V2_URL_ARTIST_WEB, ID3v23Frames.FRAME_ID_V3_URL_ARTIST_WEB); convertv22Tov23.put(ID3v22Frames.FRAME_ID_V2_URL_COMMERCIAL, ID3v23Frames.FRAME_ID_V3_URL_COMMERCIAL); convertv22Tov23.put(ID3v22Frames.FRAME_ID_V2_URL_COPYRIGHT, ID3v23Frames.FRAME_ID_V3_URL_COPYRIGHT); convertv22Tov23.put(ID3v22Frames.FRAME_ID_V2_URL_FILE_WEB, ID3v23Frames.FRAME_ID_V3_URL_FILE_WEB); convertv22Tov23.put(ID3v22Frames.FRAME_ID_V2_URL_OFFICIAL_RADIO, ID3v23Frames.FRAME_ID_V3_URL_OFFICIAL_RADIO); convertv22Tov23.put(ID3v22Frames.FRAME_ID_V2_URL_PAYMENT, ID3v23Frames.FRAME_ID_V3_URL_PAYMENT); convertv22Tov23.put(ID3v22Frames.FRAME_ID_V2_URL_PUBLISHERS, ID3v23Frames.FRAME_ID_V3_URL_PUBLISHERS); convertv22Tov23.put(ID3v22Frames.FRAME_ID_V2_URL_SOURCE_WEB, ID3v23Frames.FRAME_ID_V3_URL_SOURCE_WEB); convertv22Tov23.put(ID3v22Frames.FRAME_ID_V2_USER_DEFINED_INFO, ID3v23Frames.FRAME_ID_V3_USER_DEFINED_INFO); convertv22Tov23.put(ID3v22Frames.FRAME_ID_V2_USER_DEFINED_URL, ID3v23Frames.FRAME_ID_V3_USER_DEFINED_URL); convertv22Tov23.put(ID3v22Frames.FRAME_ID_V2_TITLE, ID3v23Frames.FRAME_ID_V3_TITLE); convertv22Tov23.put(ID3v22Frames.FRAME_ID_V2_IS_COMPILATION, ID3v23Frames.FRAME_ID_V3_IS_COMPILATION); convertv22Tov23.put(ID3v22Frames.FRAME_ID_V2_TITLE_SORT_ORDER_ITUNES, ID3v23Frames.FRAME_ID_V3_TITLE_SORT_ORDER_ITUNES); convertv22Tov23.put(ID3v22Frames.FRAME_ID_V2_ARTIST_SORT_ORDER_ITUNES, ID3v23Frames.FRAME_ID_V3_ARTIST_SORT_ORDER_ITUNES); convertv22Tov23.put(ID3v22Frames.FRAME_ID_V2_ALBUM_SORT_ORDER_ITUNES, ID3v23Frames.FRAME_ID_V3_ALBUM_SORT_ORDER_ITUNES); convertv22Tov23.put(ID3v22Frames.FRAME_ID_V2_ALBUM_ARTIST_SORT_ORDER_ITUNES, ID3v23Frames.FRAME_ID_V3_ALBUM_ARTIST_SORT_ORDER_ITUNES); convertv22Tov23.put(ID3v22Frames.FRAME_ID_V2_COMPOSER_SORT_ORDER_ITUNES, ID3v23Frames.FRAME_ID_V3_COMPOSER_SORT_ORDER_ITUNES); // v23 to v22 The translation is both way iterator = convertv22Tov23.keySet().iterator(); while (iterator.hasNext()) { key = iterator.next(); value = convertv22Tov23.get(key); convertv23Tov22.put(value, key); } //This one way translation allows us to convert XSOT to TST, but in the other direction gets converted to TSOT convertv23Tov22.put(ID3v23Frames.FRAME_ID_V3_TITLE_SORT_ORDER_MUSICBRAINZ, ID3v22Frames.FRAME_ID_V2_TITLE_SORT_ORDER_ITUNES); convertv23Tov22.put(ID3v23Frames.FRAME_ID_V3_ARTIST_SORT_ORDER_MUSICBRAINZ, ID3v22Frames.FRAME_ID_V2_ARTIST_SORT_ORDER_ITUNES); convertv23Tov22.put(ID3v23Frames.FRAME_ID_V3_ALBUM_SORT_ORDER_MUSICBRAINZ, ID3v22Frames.FRAME_ID_V2_ALBUM_SORT_ORDER_ITUNES); //TODO What does CRM Map to ? // Force v22 to v23, Extra fields in v23 version forcev22Tov23.put(ID3v22Frames.FRAME_ID_V2_ATTACHED_PICTURE, ID3v23Frames.FRAME_ID_V3_ATTACHED_PICTURE); // Force v23 to v22 forcev23Tov22.put(ID3v23Frames.FRAME_ID_V3_ATTACHED_PICTURE, ID3v22Frames.FRAME_ID_V2_ATTACHED_PICTURE); } static { loadID3v22ID3v23Mapping(); loadID3v23ID3v24Mapping(); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/AbstractTagFrameBody.java0000644000175000017500000002373511470746136027616 0ustar drazzibdrazzib/** * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: AbstractTagFrameBody.java 929 2010-11-17 12:36:46Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * FragmentBody contains the data for a fragment. * ID3v2 tags have frames bodys. Lyrics3 tags have fields bodys * ID3v1 tags do not have fragments bodys. * Fragment Bodies consist of a number of MP3Objects held in an objectList * Methods are additionally defined here to restrieve and set these objects. * We also specify methods for getting/setting the text encoding of textual * data. * Fragment bodies should not be concerned about their parent fragment. For * example most ID3v2 frames can be applied to ID3v2tags of different versions. * The frame header will need modification based on the frame version but this * should have no effect on the frame body. */ package org.jaudiotagger.tag.id3; import org.jaudiotagger.tag.datatype.AbstractDataType; import org.jaudiotagger.tag.datatype.DataTypes; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; import java.util.ArrayList; import java.util.Iterator; /** * A frame body contains the data content for a frame */ public abstract class AbstractTagFrameBody extends AbstractTagItem { public void createStructure() { } /** * Reference to the header associated with this frame body, a framebody can be created without a header * but one it is associated with a header this should be set. It is principally useful for the framebody to know * its header, because this will specify its tag version and some framebodies behave slighly different * between tag versions. */ private AbstractTagFrame header; /** * List of data types that make up this particular frame body. */ protected ArrayList objectList = new ArrayList(); /** * Return the Text Encoding * * @return the text encoding used by this framebody */ public final byte getTextEncoding() { AbstractDataType o = getObject(DataTypes.OBJ_TEXT_ENCODING); if (o != null) { Long encoding = (Long) (o.getValue()); return encoding.byteValue(); } else { return TextEncoding.ISO_8859_1; } } /** * Set the Text Encoding to use for this frame body * * @param textEncoding to use for this frame body */ public final void setTextEncoding(byte textEncoding) { //Number HashMap actually converts this byte to a long setObjectValue(DataTypes.OBJ_TEXT_ENCODING, textEncoding); } /** * Creates a new framebody, at this point the bodys * ObjectList is setup which defines what datatypes are expected in body */ protected AbstractTagFrameBody() { setupObjectList(); } /** * Copy Constructor for fragment body. Copies all objects in the * Object Iterator with data. * @param copyObject */ protected AbstractTagFrameBody(AbstractTagFrameBody copyObject) { AbstractDataType newObject; for (int i = 0; i < copyObject.objectList.size(); i++) { newObject = (AbstractDataType) ID3Tags.copyObject(copyObject.objectList.get(i)); newObject.setBody(this); this.objectList.add(newObject); } } /** * * @return the text value that the user would expect to see for this framebody type, this should be overrridden * for all framebodies */ public String getUserFriendlyValue() { return toString(); } /** * This method calls toString for all it's objects and appends * them without any newline characters. * * @return brief description string */ public String getBriefDescription() { String str = ""; for (AbstractDataType object : objectList) { if ((object.toString() != null) && (object.toString().length() > 0)) { str += (object.getIdentifier() + "=\"" + object.toString() + "\"; "); } } return str; } /** * This method calls toString for all it's objects and appends * them. It contains new line characters and is more suited for display * purposes * * @return formatted description string */ public final String getLongDescription() { String str = ""; for (AbstractDataType object : objectList) { if ((object.toString() != null) && (object.toString().length() > 0)) { str += (object.getIdentifier() + " = " + object.toString() + "\n"); } } return str; } /** * Sets all objects of identifier type to value defined by obj argument. * * @param identifier MP3Object identifier * @param value new datatype value */ public final void setObjectValue(String identifier, Object value) { AbstractDataType object; Iterator iterator = objectList.listIterator(); while (iterator.hasNext()) { object = iterator.next(); if (object.getIdentifier().equals(identifier)) { object.setValue(value); } } } /** * Returns the value of the datatype with the specified * identifier * * @param identifier * @return the value of the dattype with the specified * identifier */ public final Object getObjectValue(String identifier) { return getObject(identifier).getValue(); } /** * Returns the datatype with the specified * identifier * * @param identifier * @return the datatype with the specified * identifier */ public final AbstractDataType getObject(String identifier) { AbstractDataType object; Iterator iterator = objectList.listIterator(); while (iterator.hasNext()) { object = iterator.next(); if (object.getIdentifier().equals(identifier)) { return object; } } return null; } /** * Returns the size in bytes of this fragmentbody * * @return estimated size in bytes of this datatype */ public int getSize() { int size = 0; AbstractDataType object; Iterator iterator = objectList.listIterator(); while (iterator.hasNext()) { object = iterator.next(); size += object.getSize(); } return size; } /** * Returns true if this instance and its entire DataType * array list is a subset of the argument. This class is a subset if it is * the same class as the argument. * * @param obj datatype to determine subset of * @return true if this instance and its entire datatype array list is a * subset of the argument. */ public boolean isSubsetOf(Object obj) { if (!(obj instanceof AbstractTagFrameBody)) { return false; } ArrayList superset = ((AbstractTagFrameBody) obj).objectList; for (AbstractDataType anObjectList : objectList) { if (anObjectList.getValue() != null) { if (!superset.contains(anObjectList)) { return false; } } } return true; } /** * Returns true if this datatype and its entire DataType array * list equals the argument. This datatype is equal to the argument if they * are the same class. * * @param obj datatype to determine equality of * @return true if this datatype and its entire MP3Object array * list equals the argument. */ public boolean equals(Object obj) { if (!(obj instanceof AbstractTagFrameBody)) { return false; } AbstractTagFrameBody object = (AbstractTagFrameBody) obj; boolean check =this.objectList.equals(object.objectList) && super.equals(obj); return check; } /** * Returns an iterator of the DataType list. * * @return iterator of the DataType list. */ public Iterator iterator() { return objectList.iterator(); } /** * Return brief description of FrameBody * * @return brief description of FrameBody */ public String toString() { return getBriefDescription(); } /** * Create the list of Datatypes that this body * expects in the correct order This method needs to be implemented by concrete subclasses */ protected abstract void setupObjectList(); /** * Get Reference to header * * @return */ public AbstractTagFrame getHeader() { return header; } /** * Set header * * @param header */ public void setHeader(AbstractTagFrame header) { this.header = header; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/id3/ID3v23PreferredFrameOrderComparator.java0000644000175000017500000001771411470746136032376 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.id3; import java.util.Comparator; import java.util.List; import java.util.ArrayList; /** * Orders frame Ids so that the most important frames are writtne first */ public class ID3v23PreferredFrameOrderComparator implements Comparator { private static ID3v23PreferredFrameOrderComparator comparator; private static List frameIdsInPreferredOrder = new ArrayList(); static { //these are the key ones we want at the top frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_UNIQUE_FILE_ID); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_TITLE); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_ARTIST); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_ALBUM); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_TORY); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_GENRE); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_COMPOSER); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_CONDUCTOR); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_CONTENT_GROUP_DESC); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_TRACK); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_TYER); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_TDAT); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_TIME); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_BPM); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_ISRC); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_TORY); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_ACCOMPANIMENT); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_TITLE_REFINEMENT); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_UNSYNC_LYRICS); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_USER_DEFINED_INFO); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_USER_DEFINED_URL); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_URL_ARTIST_WEB); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_URL_COMMERCIAL); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_URL_COPYRIGHT); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_URL_FILE_WEB); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_URL_OFFICIAL_RADIO); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_URL_PAYMENT); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_URL_PUBLISHERS); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_URL_COMMERCIAL); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_LYRICIST); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_MEDIA_TYPE); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_IPLS); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_LANGUAGE); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_TITLE_SORT_ORDER_ITUNES); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_PLAYLIST_DELAY); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_PLAY_COUNTER); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_POPULARIMETER); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_PUBLISHER); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_ALBUM_ARTIST_SORT_ORDER_ITUNES); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_COMPOSER_SORT_ORDER_ITUNES); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_IS_COMPILATION); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_TITLE_SORT_ORDER_ITUNES); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_ARTIST_SORT_ORDER_ITUNES); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_ALBUM_SORT_ORDER_ITUNES); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_TITLE_SORT_ORDER_MUSICBRAINZ); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_ARTIST_SORT_ORDER_MUSICBRAINZ); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_ALBUM_SORT_ORDER_MUSICBRAINZ); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_ALBUM_ARTIST_SORT_ORDER_ITUNES); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_COMPOSER_SORT_ORDER_ITUNES); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_COMMENT); //Not so bothered about these frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_TRDA); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_COMMERCIAL_FRAME); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_COPYRIGHTINFO); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_ENCODEDBY); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_ENCRYPTION); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_EQUALISATION); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_EVENT_TIMING_CODES); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_FILE_OWNER); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_FILE_TYPE); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_GROUP_ID_REG); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_HW_SW_SETTINGS); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_INITIAL_KEY); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_LENGTH); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_LINKED_INFO); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_TSIZ); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_MPEG_LOCATION_LOOKUP_TABLE); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_ORIGARTIST); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_ORIG_FILENAME); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_ORIG_LYRICIST); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_ORIG_TITLE); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_OWNERSHIP); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_POSITION_SYNC); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_RADIO_NAME); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_RADIO_OWNER); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_RECOMMENDED_BUFFER_SIZE); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_REMIXED); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_REVERB); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_SET); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_SYNC_LYRIC); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_SYNC_TEMPO); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_TERMS_OF_USE); //Want this near the end because can cause problems with unsyncing frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_ATTACHED_PICTURE); //Itunes doesnt seem to like these, and of little use so put right at end frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_PRIVATE); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_MUSIC_CD_ID); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_AUDIO_ENCRYPTION); frameIdsInPreferredOrder.add(ID3v23Frames.FRAME_ID_V3_GENERAL_ENCAPS_OBJECT); } private ID3v23PreferredFrameOrderComparator() { } public static ID3v23PreferredFrameOrderComparator getInstanceof() { if(comparator==null) { comparator=new ID3v23PreferredFrameOrderComparator(); } return comparator; } /** * * @param frameId1 * @param frameId2 * @return */ public int compare(String frameId1,String frameId2) { int frameId1Index= frameIdsInPreferredOrder.indexOf(frameId1); int frameId2Index= frameIdsInPreferredOrder.indexOf(frameId2); return frameId1Index - frameId2Index; } public boolean equals(Object obj) { return obj instanceof ID3v23PreferredFrameOrderComparator; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/TagOptionSingleton.java0000644000175000017500000007162111470746136026733 0ustar drazzibdrazzib/** * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: TagOptionSingleton.java 929 2010-11-17 12:36:46Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Description: * Options that are used for every datatype and class in this library. * */ package org.jaudiotagger.tag; import org.jaudiotagger.tag.id3.framebody.AbstractID3v2FrameBody; import org.jaudiotagger.tag.id3.framebody.FrameBodyCOMM; import org.jaudiotagger.tag.id3.framebody.FrameBodyTIPL; import org.jaudiotagger.tag.id3.framebody.ID3v24FrameBody; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; import org.jaudiotagger.tag.lyrics3.Lyrics3v2Fields; import org.jaudiotagger.tag.reference.GenreTypes; import org.jaudiotagger.tag.reference.Languages; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; public class TagOptionSingleton { /** * */ private static HashMap tagOptionTable = new HashMap(); /** * */ private static String DEFAULT = "default"; /** * */ private static String defaultOptions = DEFAULT; /** * */ private HashMap, LinkedList> keywordMap = new HashMap, LinkedList>(); /** * Map of lyric ID's to Boolean objects if we should or should not save the * specific Kyrics3 field. Defaults to true. */ private HashMap lyrics3SaveFieldMap = new HashMap(); /** * parenthesis map stuff */ private HashMap parenthesisMap = new HashMap(); /** * HashMap listing words to be replaced if found */ private HashMap replaceWordMap = new HashMap(); /** * default language for any ID3v2 tags frameswhich require it. This string * is in the [ISO-639-2] ISO/FDIS 639-2 definition */ private String language = "eng"; /** * */ private boolean filenameTagSave = false; /** * if we should save any fields of the ID3v1 tag or not. Defaults to true. */ private boolean id3v1Save = true; /** * if we should save the album field of the ID3v1 tag or not. Defaults to * true. */ private boolean id3v1SaveAlbum = true; /** * if we should save the artist field of the ID3v1 tag or not. Defaults to * true. */ private boolean id3v1SaveArtist = true; /** * if we should save the comment field of the ID3v1 tag or not. Defaults to * true. */ private boolean id3v1SaveComment = true; /** * if we should save the genre field of the ID3v1 tag or not. Defaults to * true. */ private boolean id3v1SaveGenre = true; /** * if we should save the title field of the ID3v1 tag or not. Defaults to * true. */ private boolean id3v1SaveTitle = true; /** * if we should save the track field of the ID3v1 tag or not. Defaults to * true. */ private boolean id3v1SaveTrack = true; /** * if we should save the year field of the ID3v1 tag or not. Defaults to * true. */ private boolean id3v1SaveYear = true; /** * When adjusting the ID3v2 padding, if should we copy the current ID3v2 * tag to the new MP3 file. Defaults to true. */ private boolean id3v2PaddingCopyTag = true; /** * When adjusting the ID3v2 padding, if we should shorten the length of the * ID3v2 tag padding. Defaults to false. */ private boolean id3v2PaddingWillShorten = false; /** * if we should save any fields of the ID3v2 tag or not. Defaults to true. */ private boolean id3v2Save = true; /** * if we should keep an empty Lyrics3 field while we're reading. This is * different from a string of white space. Defaults to false. */ private boolean lyrics3KeepEmptyFieldIfRead = false; /** * if we should save any fields of the Lyrics3 tag or not. Defaults to * true. */ private boolean lyrics3Save = true; /** * if we should save empty Lyrics3 field or not. Defaults to false. *

* todo I don't think this is implemented yet. */ private boolean lyrics3SaveEmptyField = false; /** * */ private boolean originalSavedAfterAdjustingID3v2Padding = true; /** * default time stamp format for any ID3v2 tag frames which require it. */ private byte timeStampFormat = 2; /** * number of frames to sync when trying to find the start of the MP3 frame * data. The start of the MP3 frame data is the start of the music and is * different from the ID3v2 frame data. */ private int numberMP3SyncFrame = 3; /** * Unsynchronize tags/frames this is rarely required these days and can cause more * problems than it solves */ private boolean unsyncTags = false; /** * iTunes needlessly writes null terminators at the end for TextEncodedStringSizeTerminated values, * if this option is enabled these characters are removed */ private boolean removeTrailingTerminatorOnWrite = true; /** * This is the default text encoding to use for new v23 frames, when unicode is required * UTF16 will always be used because that is the only valid option for v23. */ private byte id3v23DefaultTextEncoding = TextEncoding.ISO_8859_1; /** * This is the default text encoding to use for new v24 frames, it defaults to simple ISO8859 * but by changing this value you could always used UTF8 for example whether you needed to or not */ private byte id3v24DefaultTextEncoding = TextEncoding.ISO_8859_1; /** * This is text encoding to use for new v24 frames when unicode is required, it defaults to UTF16 just * because this encoding is understand by all ID3 versions */ private byte id3v24UnicodeTextEncoding = TextEncoding.UTF_16; /** * When writing frames if this is set to true then the frame will be written * using the defaults disregarding the text encoding originally used to create * the frame. */ private boolean resetTextEncodingForExistingFrames = false; /** * Some formats impose maxmimum lengths for fields , if the text provided is longer * than the formats allows it will truncate and write a warning, if this is not set * it will throw an exception */ private boolean truncateTextWithoutErrors = false; /** * Frames such as TRCK and TPOS sometimes pad single digit numbers to aid sorting */ private boolean padNumbers = false; /** * There are a couple of problems with the Java implemenatation ono Google Android, enabling this value * switches on Google workarounds */ private boolean isAndroid = false; /** * Creates a new TagOptions datatype. All Options are set to their default * values */ private TagOptionSingleton() { setToDefault(); } /** * @return */ public static TagOptionSingleton getInstance() { return getInstance(defaultOptions); } /** * @param instanceKey * @return */ public static TagOptionSingleton getInstance(String instanceKey) { TagOptionSingleton tagOptions = tagOptionTable.get(instanceKey); if (tagOptions == null) { tagOptions = new TagOptionSingleton(); tagOptionTable.put(instanceKey, tagOptions); } return tagOptions; } /** * @param filenameTagSave */ public void setFilenameTagSave(boolean filenameTagSave) { this.filenameTagSave = filenameTagSave; } /** * @return */ public boolean isFilenameTagSave() { return filenameTagSave; } /** * @param instanceKey */ public void setInstanceKey(String instanceKey) { TagOptionSingleton.defaultOptions = instanceKey; } /** * @return */ public static String getInstanceKey() { return defaultOptions; } /** * @param id3v1Save */ public void setId3v1Save(boolean id3v1Save) { this.id3v1Save = id3v1Save; } /** * @return */ public boolean isId3v1Save() { return id3v1Save; } /** * @param id3v1SaveAlbum */ public void setId3v1SaveAlbum(boolean id3v1SaveAlbum) { this.id3v1SaveAlbum = id3v1SaveAlbum; } /** * @return */ public boolean isId3v1SaveAlbum() { return id3v1SaveAlbum; } /** * @param id3v1SaveArtist */ public void setId3v1SaveArtist(boolean id3v1SaveArtist) { this.id3v1SaveArtist = id3v1SaveArtist; } /** * @return */ public boolean isId3v1SaveArtist() { return id3v1SaveArtist; } /** * @param id3v1SaveComment */ public void setId3v1SaveComment(boolean id3v1SaveComment) { this.id3v1SaveComment = id3v1SaveComment; } /** * @return */ public boolean isId3v1SaveComment() { return id3v1SaveComment; } /** * @param id3v1SaveGenre */ public void setId3v1SaveGenre(boolean id3v1SaveGenre) { this.id3v1SaveGenre = id3v1SaveGenre; } /** * @return */ public boolean isId3v1SaveGenre() { return id3v1SaveGenre; } /** * @param id3v1SaveTitle */ public void setId3v1SaveTitle(boolean id3v1SaveTitle) { this.id3v1SaveTitle = id3v1SaveTitle; } /** * @return */ public boolean isId3v1SaveTitle() { return id3v1SaveTitle; } /** * @param id3v1SaveTrack */ public void setId3v1SaveTrack(boolean id3v1SaveTrack) { this.id3v1SaveTrack = id3v1SaveTrack; } /** * @return */ public boolean isId3v1SaveTrack() { return id3v1SaveTrack; } /** * @param id3v1SaveYear */ public void setId3v1SaveYear(boolean id3v1SaveYear) { this.id3v1SaveYear = id3v1SaveYear; } /** * @return */ public boolean isId3v1SaveYear() { return id3v1SaveYear; } /** * @param id3v2PaddingCopyTag */ public void setId3v2PaddingCopyTag(boolean id3v2PaddingCopyTag) { this.id3v2PaddingCopyTag = id3v2PaddingCopyTag; } /** * @return */ public boolean isId3v2PaddingCopyTag() { return id3v2PaddingCopyTag; } /** * @param id3v2PaddingWillShorten */ public void setId3v2PaddingWillShorten(boolean id3v2PaddingWillShorten) { this.id3v2PaddingWillShorten = id3v2PaddingWillShorten; } /** * @return */ public boolean isId3v2PaddingWillShorten() { return id3v2PaddingWillShorten; } /** * @param id3v2Save */ public void setId3v2Save(boolean id3v2Save) { this.id3v2Save = id3v2Save; } /** * @return */ public boolean isId3v2Save() { return id3v2Save; } /** * @return */ public Iterator> getKeywordIterator() { return keywordMap.keySet().iterator(); } /** * @param id3v2_4FrameBody * @return */ public Iterator getKeywordListIterator(Class id3v2_4FrameBody) { return keywordMap.get(id3v2_4FrameBody).iterator(); } /** * Sets the default language for any ID3v2 tag frames which require it. * While the value will already exist when reading from a file, this value * will be used when a new ID3v2 Frame is created from scratch. * * @param lang language ID, [ISO-639-2] ISO/FDIS 639-2 definition */ public void setLanguage(String lang) { if (Languages.getInstanceOf().getIdToValueMap().containsKey(lang)) { language = lang; } } /** * Returns the default language for any ID3v2 tag frames which require it. * * @return language ID, [ISO-639-2] ISO/FDIS 639-2 definition */ public String getLanguage() { return language; } /** * @param lyrics3KeepEmptyFieldIfRead */ public void setLyrics3KeepEmptyFieldIfRead(boolean lyrics3KeepEmptyFieldIfRead) { this.lyrics3KeepEmptyFieldIfRead = lyrics3KeepEmptyFieldIfRead; } /** * @return */ public boolean isLyrics3KeepEmptyFieldIfRead() { return lyrics3KeepEmptyFieldIfRead; } /** * @param lyrics3Save */ public void setLyrics3Save(boolean lyrics3Save) { this.lyrics3Save = lyrics3Save; } /** * @return */ public boolean isLyrics3Save() { return lyrics3Save; } /** * @param lyrics3SaveEmptyField */ public void setLyrics3SaveEmptyField(boolean lyrics3SaveEmptyField) { this.lyrics3SaveEmptyField = lyrics3SaveEmptyField; } /** * @return */ public boolean isLyrics3SaveEmptyField() { return lyrics3SaveEmptyField; } /** * Sets if we should save the Lyrics3 field. Defaults to true. * * @param id Lyrics3 id string * @param save true if you want to save this specific Lyrics3 field. */ public void setLyrics3SaveField(String id, boolean save) { this.lyrics3SaveFieldMap.put(id, save); } /** * Returns true if we should save the Lyrics3 field asked for in the * argument. Defaults to true. * * @param id Lyrics3 id string * @return true if we should save the Lyrics3 field. */ public boolean getLyrics3SaveField(String id) { return lyrics3SaveFieldMap.get(id); } /** * @return */ public HashMap getLyrics3SaveFieldMap() { return lyrics3SaveFieldMap; } /** * @param oldWord * @return */ public String getNewReplaceWord(String oldWord) { return replaceWordMap.get(oldWord); } /** * Sets the number of MP3 frames to sync when trying to find the start of * the MP3 frame data. The start of the MP3 frame data is the start of the * music and is different from the ID3v2 frame data. WinAmp 2.8 seems to * sync 3 frames. Default is 5. * * @param numberMP3SyncFrame number of MP3 frames to sync */ public void setNumberMP3SyncFrame(int numberMP3SyncFrame) { this.numberMP3SyncFrame = numberMP3SyncFrame; } /** * Returns the number of MP3 frames to sync when trying to find the start * of the MP3 frame data. The start of the MP3 frame data is the start of * the music and is different from the ID3v2 frame data. WinAmp 2.8 seems * to sync 3 frames. Default is 5. * * @return number of MP3 frames to sync */ public int getNumberMP3SyncFrame() { return numberMP3SyncFrame; } /** * @return */ public Iterator getOldReplaceWordIterator() { return replaceWordMap.keySet().iterator(); } /** * @param open * @return */ public boolean isOpenParenthesis(String open) { return parenthesisMap.containsKey(open); } /** * @return */ public Iterator getOpenParenthesisIterator() { return parenthesisMap.keySet().iterator(); } /** * @param originalSavedAfterAdjustingID3v2Padding * */ public void setOriginalSavedAfterAdjustingID3v2Padding(boolean originalSavedAfterAdjustingID3v2Padding) { this.originalSavedAfterAdjustingID3v2Padding = originalSavedAfterAdjustingID3v2Padding; } /** * @return */ public boolean isOriginalSavedAfterAdjustingID3v2Padding() { return originalSavedAfterAdjustingID3v2Padding; } /** * Sets the default time stamp format for ID3v2 tags which require it. * While the value will already exist when reading from a file, this value * will be used when a new ID3v2 Frame is created from scratch. *

*

* $01 Absolute time, 32 bit sized, using MPEG frames as unit
* $02 Absolute time, 32 bit sized, using milliseconds as unit
*

* * @param tsf the new default time stamp format */ public void setTimeStampFormat(byte tsf) { if ((tsf == 1) || (tsf == 2)) { timeStampFormat = tsf; } } /** * Returns the default time stamp format for ID3v2 tags which require it. *

*

* $01 Absolute time, 32 bit sized, using MPEG frames as unit
* $02 Absolute time, 32 bit sized, using milliseconds as unit
*

* * @return the default time stamp format */ public byte getTimeStampFormat() { return timeStampFormat; } /** * */ public void setToDefault() { keywordMap = new HashMap, LinkedList>(); filenameTagSave = false; id3v1Save = true; id3v1SaveAlbum = true; id3v1SaveArtist = true; id3v1SaveComment = true; id3v1SaveGenre = true; id3v1SaveTitle = true; id3v1SaveTrack = true; id3v1SaveYear = true; id3v2PaddingCopyTag = true; id3v2PaddingWillShorten = false; id3v2Save = true; language = "eng"; lyrics3KeepEmptyFieldIfRead = false; lyrics3Save = true; lyrics3SaveEmptyField = false; lyrics3SaveFieldMap = new HashMap(); numberMP3SyncFrame = 3; parenthesisMap = new HashMap(); replaceWordMap = new HashMap(); timeStampFormat = 2; unsyncTags = false; removeTrailingTerminatorOnWrite = true; id3v23DefaultTextEncoding = TextEncoding.ISO_8859_1; id3v24DefaultTextEncoding = TextEncoding.ISO_8859_1; id3v24UnicodeTextEncoding = TextEncoding.UTF_16; resetTextEncodingForExistingFrames = false; truncateTextWithoutErrors = false; padNumbers = false; isAndroid = false; //default all lyrics3 fields to save. id3v1 fields are individual // settings. id3v2 fields are always looked at to save. Iterator iterator = Lyrics3v2Fields.getInstanceOf().getIdToValueMap().keySet().iterator(); String fieldId; while (iterator.hasNext()) { fieldId = iterator.next(); lyrics3SaveFieldMap.put(fieldId, true); } try { addKeyword(FrameBodyCOMM.class, "ultimix"); addKeyword(FrameBodyCOMM.class, "dance"); addKeyword(FrameBodyCOMM.class, "mix"); addKeyword(FrameBodyCOMM.class, "remix"); addKeyword(FrameBodyCOMM.class, "rmx"); addKeyword(FrameBodyCOMM.class, "live"); addKeyword(FrameBodyCOMM.class, "cover"); addKeyword(FrameBodyCOMM.class, "soundtrack"); addKeyword(FrameBodyCOMM.class, "version"); addKeyword(FrameBodyCOMM.class, "acoustic"); addKeyword(FrameBodyCOMM.class, "original"); addKeyword(FrameBodyCOMM.class, "cd"); addKeyword(FrameBodyCOMM.class, "extended"); addKeyword(FrameBodyCOMM.class, "vocal"); addKeyword(FrameBodyCOMM.class, "unplugged"); addKeyword(FrameBodyCOMM.class, "acapella"); addKeyword(FrameBodyCOMM.class, "edit"); addKeyword(FrameBodyCOMM.class, "radio"); addKeyword(FrameBodyCOMM.class, "original"); addKeyword(FrameBodyCOMM.class, "album"); addKeyword(FrameBodyCOMM.class, "studio"); addKeyword(FrameBodyCOMM.class, "instrumental"); addKeyword(FrameBodyCOMM.class, "unedited"); addKeyword(FrameBodyCOMM.class, "karoke"); addKeyword(FrameBodyCOMM.class, "quality"); addKeyword(FrameBodyCOMM.class, "uncensored"); addKeyword(FrameBodyCOMM.class, "clean"); addKeyword(FrameBodyCOMM.class, "dirty"); addKeyword(FrameBodyTIPL.class, "f."); addKeyword(FrameBodyTIPL.class, "feat"); addKeyword(FrameBodyTIPL.class, "feat."); addKeyword(FrameBodyTIPL.class, "featuring"); addKeyword(FrameBodyTIPL.class, "ftng"); addKeyword(FrameBodyTIPL.class, "ftng."); addKeyword(FrameBodyTIPL.class, "ft."); addKeyword(FrameBodyTIPL.class, "ft"); iterator = GenreTypes.getInstanceOf().getValueToIdMap().keySet().iterator(); while (iterator.hasNext()) { addKeyword(FrameBodyCOMM.class, iterator.next()); } } catch (TagException ex) { // this shouldn't happen, indicates coding error throw new RuntimeException(ex); } addReplaceWord("v.", "vs."); addReplaceWord("vs.", "vs."); addReplaceWord("versus", "vs."); addReplaceWord("f.", "feat."); addReplaceWord("feat", "feat."); addReplaceWord("featuring", "feat."); addReplaceWord("ftng.", "feat."); addReplaceWord("ftng", "feat."); addReplaceWord("ft.", "feat."); addReplaceWord("ft", "feat."); iterator = this.getKeywordListIterator(FrameBodyTIPL.class); addParenthesis("(", ")"); addParenthesis("[", "]"); addParenthesis("{", "}"); addParenthesis("<", ">"); } /** * @param id3v2FrameBodyClass * @param keyword * @throws TagException */ public void addKeyword(Class id3v2FrameBodyClass, String keyword) throws TagException { if (!AbstractID3v2FrameBody.class.isAssignableFrom(id3v2FrameBodyClass)) { throw new TagException("Invalid class type. Must be AbstractId3v2FrameBody " + id3v2FrameBodyClass); } if ((keyword != null) && (keyword.length() > 0)) { LinkedList keywordList; if (!keywordMap.containsKey(id3v2FrameBodyClass)) { keywordList = new LinkedList(); keywordMap.put(id3v2FrameBodyClass, keywordList); } else { keywordList = keywordMap.get(id3v2FrameBodyClass); } keywordList.add(keyword); } } /** * @param open * @param close */ public void addParenthesis(String open, String close) { parenthesisMap.put(open, close); } /** * @param oldWord * @param newWord */ public void addReplaceWord(String oldWord, String newWord) { replaceWordMap.put(oldWord, newWord); } /** * @return are tags unsynchronized when written if contain bit pattern that could be mistaken for audio marker */ public boolean isUnsyncTags() { return unsyncTags; } /** * Unsync tag where neccessary, currently only applies to IDv23 * * @param unsyncTags set whether tags are unsynchronized when written if contain bit pattern that could * be mistaken for audio marker */ public void setUnsyncTags(boolean unsyncTags) { this.unsyncTags = unsyncTags; } /** * Do we remove unnecessary trailing null characters on write * * @return true if we remove unnecessary trailing null characters on write */ public boolean isRemoveTrailingTerminatorOnWrite() { return removeTrailingTerminatorOnWrite; } /** * Remove unnecessary trailing null characters on write * * @param removeTrailingTerminatorOnWrite * */ public void setRemoveTrailingTerminatorOnWrite(boolean removeTrailingTerminatorOnWrite) { this.removeTrailingTerminatorOnWrite = removeTrailingTerminatorOnWrite; } /** * Get the default text encoding to use for new v23 frames, when unicode is required * UTF16 will always be used because that is the only valid option for v23/v22 * * @return */ public byte getId3v23DefaultTextEncoding() { return id3v23DefaultTextEncoding; } /** * Set the default text encoding to use for new v23 frames, when unicode is required * UTF16 will always be used because that is the only valid option for v23/v22 * * @param id3v23DefaultTextEncoding */ public void setId3v23DefaultTextEncoding(byte id3v23DefaultTextEncoding) { if ((id3v23DefaultTextEncoding == TextEncoding.ISO_8859_1) || (id3v23DefaultTextEncoding == TextEncoding.UTF_16)) { this.id3v23DefaultTextEncoding = id3v23DefaultTextEncoding; } } /** * Get the default text encoding to use for new v24 frames, it defaults to simple ISO8859 * but by changing this value you could always used UTF8 for example whether you needed to or not * * @return */ public byte getId3v24DefaultTextEncoding() { return id3v24DefaultTextEncoding; } /** * Set the default text encoding to use for new v24 frames, it defaults to simple ISO8859 * but by changing this value you could always used UTF8 for example whether you needed to or not * * @param id3v24DefaultTextEncoding */ public void setId3v24DefaultTextEncoding(byte id3v24DefaultTextEncoding) { if ((id3v24DefaultTextEncoding == TextEncoding.ISO_8859_1) || (id3v24DefaultTextEncoding == TextEncoding.UTF_16) || (id3v24DefaultTextEncoding == TextEncoding.UTF_16BE) || (id3v24DefaultTextEncoding == TextEncoding.UTF_8)) { this.id3v24DefaultTextEncoding = id3v24DefaultTextEncoding; } } /** * Get the text encoding to use for new v24 frames when unicode is required, it defaults to UTF16 just * because this encoding is understand by all ID3 versions * * @return */ public byte getId3v24UnicodeTextEncoding() { return id3v24UnicodeTextEncoding; } /** * Set the text encoding to use for new v24 frames when unicode is required, it defaults to UTF16 just * because this encoding is understand by all ID3 versions * * @param id3v24UnicodeTextEncoding */ public void setId3v24UnicodeTextEncoding(byte id3v24UnicodeTextEncoding) { if ((id3v24UnicodeTextEncoding == TextEncoding.UTF_16) || (id3v24UnicodeTextEncoding == TextEncoding.UTF_16BE) || (id3v24UnicodeTextEncoding == TextEncoding.UTF_8)) { this.id3v24UnicodeTextEncoding = id3v24UnicodeTextEncoding; } } /** * When writing frames if this is set to true then the frame will be written * using the defaults disregarding the text encoding originally used to create * the frame. * * @return */ public boolean isResetTextEncodingForExistingFrames() { return resetTextEncodingForExistingFrames; } /** * When writing frames if this is set to true then the frame will be written * using the defaults disregarding the text encoding originally used to create * the frame. * * @param resetTextEncodingForExistingFrames * */ public void setResetTextEncodingForExistingFrames(boolean resetTextEncodingForExistingFrames) { this.resetTextEncodingForExistingFrames = resetTextEncodingForExistingFrames; } /** * * @return truncate without errors */ public boolean isTruncateTextWithoutErrors() { return truncateTextWithoutErrors; } /** * Set truncate without errors * * @param truncateTextWithoutErrors */ public void setTruncateTextWithoutErrors(boolean truncateTextWithoutErrors) { this.truncateTextWithoutErrors = truncateTextWithoutErrors; } public boolean isPadNumbers() { return padNumbers; } public void setPadNumbers(boolean padNumbers) { this.padNumbers = padNumbers; } public boolean isAndroid() { return isAndroid; } public void setAndroid(boolean android) { isAndroid = android; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/TagField.java0000644000175000017500000001052011247705415024607 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2003-2005 Raphaël Slinckx * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.tag; import java.io.UnsupportedEncodingException; /** * Implementing classes represent a tag field for the entagged audio library.
* Very basic functionality is defined for use with * {@link org.jaudiotagger.tag.Tag}. * * @author Rapha�l Slinckx */ public interface TagField { /** * This method copies the data of the given field to the current data.
* * @param field The field containing the data to be taken. */ public void copyContent(TagField field); /** * Returns the Id of the represented tag field.
* This value should uniquely identify a kind of tag data, like title. * {@link org.jaudiotagger.audio.generic.AbstractTag} will use the "id" to summarize multiple * fields. * * @return Unique identifier for the fields type. (title, artist...) */ public String getId(); /** * This method delivers the binary representation of the fields data in * order to be directly written to the file.
* * @return Binary data representing the current tag field.
* @throws UnsupportedEncodingException Most tag data represents text. In some cases the underlying * implementation will need to convert the text data in java to * a specific charset encoding. In these cases an * {@link UnsupportedEncodingException} may occur. */ public byte[] getRawContent() throws UnsupportedEncodingException; /** * Determines whether the represented field contains (is made up of) binary * data, instead of text data.
* Software can identify fields to be displayed because they are human * readable if this method returns false. * * @return true if field represents binary data (not human * readable). */ public boolean isBinary(); /** * This method will set the field to represent binary data.
*

* Some implementations may support conversions.
* As of now (Octobre 2005) there is no implementation really using this * method to perform useful operations. * * @param b true, if the field contains binary data. * //@deprecated As for now is of no use. Implementations should use another * // way of setting this property. */ public void isBinary(boolean b); /** * Identifies a field to be of common use.
*

* Some software may differ between common and not common fields. A common * one is for sure the title field. A web link may not be of common use for * tagging. However some file formats, or future development of users * expectations will make more fields common than now can be known. * * @return true if the field is of common use. */ public boolean isCommon(); /** * Determines whether the content of the field is empty.
* * @return true if no data is stored (or empty String). */ public boolean isEmpty(); /** * This method returns a human readable description of the fields contents.
* For text fields it should be the text itself. Other fields containing * images may return a formatted string with image properties like width, * height and so on. * * @return Description of the fields content. */ public String toString(); }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/PaddingException.java0000644000175000017500000000341511470746136026365 0ustar drazzibdrazzib/* * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: PaddingException.java 929 2010-11-17 12:36:46Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ package org.jaudiotagger.tag; public class PaddingException extends InvalidFrameIdentifierException { /** * Creates a new PaddingException datatype. */ public PaddingException() { } /** * Creates a new PaddingException datatype. * * @param ex the cause. */ public PaddingException(Throwable ex) { super(ex); } /** * Creates a new PaddingException datatype. * * @param msg the detail message. */ public PaddingException(String msg) { super(msg); } /** * Creates a new PaddingException datatype. * * @param msg the detail message. * @param ex the cause. */ public PaddingException(String msg, Throwable ex) { super(msg, ex); } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/mp4/0000755000175000017500000000000011556363175022775 5ustar drazzibdrazziblibjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/mp4/Mp4Tag.java0000644000175000017500000005336511470746136024745 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2003-2005 Raphael Slinckx * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.tag.mp4; import org.jaudiotagger.audio.generic.AbstractTag; import org.jaudiotagger.audio.mp4.atom.Mp4BoxHeader; import org.jaudiotagger.logging.ErrorMessage; import org.jaudiotagger.tag.*; import org.jaudiotagger.tag.datatype.Artwork; import static org.jaudiotagger.tag.mp4.Mp4FieldKey.*; import org.jaudiotagger.tag.mp4.field.*; import org.jaudiotagger.tag.vorbiscomment.VorbisCommentFieldKey; import java.util.ArrayList; import java.util.EnumMap; import java.util.List; /** * A Logical representation of Mp4Tag, i.e the meta information stored in an Mp4 file underneath the * moov.udt.meta.ilst atom. */ public class Mp4Tag extends AbstractTag { private static final EnumMap tagFieldToMp4Field = new EnumMap(FieldKey.class); //Mapping from generic key to mp4 key static { tagFieldToMp4Field.put(FieldKey.ALBUM, Mp4FieldKey.ALBUM); tagFieldToMp4Field.put(FieldKey.ALBUM_ARTIST, Mp4FieldKey.ALBUM_ARTIST); tagFieldToMp4Field.put(FieldKey.ALBUM_ARTIST_SORT, Mp4FieldKey.ALBUM_ARTIST_SORT); tagFieldToMp4Field.put(FieldKey.ALBUM_SORT, Mp4FieldKey.ALBUM_SORT); tagFieldToMp4Field.put(FieldKey.AMAZON_ID, Mp4FieldKey.ASIN); tagFieldToMp4Field.put(FieldKey.ARTIST, Mp4FieldKey.ARTIST); tagFieldToMp4Field.put(FieldKey.ARTIST_SORT, Mp4FieldKey.ARTIST_SORT); tagFieldToMp4Field.put(FieldKey.BARCODE, Mp4FieldKey.BARCODE); tagFieldToMp4Field.put(FieldKey.BPM, Mp4FieldKey.BPM); tagFieldToMp4Field.put(FieldKey.CATALOG_NO, Mp4FieldKey.CATALOGNO); tagFieldToMp4Field.put(FieldKey.COMMENT, Mp4FieldKey.COMMENT); tagFieldToMp4Field.put(FieldKey.COMPOSER, Mp4FieldKey.COMPOSER); tagFieldToMp4Field.put(FieldKey.COMPOSER_SORT, Mp4FieldKey.COMPOSER_SORT); tagFieldToMp4Field.put(FieldKey.CONDUCTOR, Mp4FieldKey.CONDUCTOR); tagFieldToMp4Field.put(FieldKey.COVER_ART, Mp4FieldKey.ARTWORK); tagFieldToMp4Field.put(FieldKey.CUSTOM1, Mp4FieldKey.MM_CUSTOM_1); tagFieldToMp4Field.put(FieldKey.CUSTOM2, Mp4FieldKey.MM_CUSTOM_2); tagFieldToMp4Field.put(FieldKey.CUSTOM3, Mp4FieldKey.MM_CUSTOM_3); tagFieldToMp4Field.put(FieldKey.CUSTOM4, Mp4FieldKey.MM_CUSTOM_4); tagFieldToMp4Field.put(FieldKey.CUSTOM5, Mp4FieldKey.MM_CUSTOM_5); tagFieldToMp4Field.put(FieldKey.DISC_NO, Mp4FieldKey.DISCNUMBER); tagFieldToMp4Field.put(FieldKey.DISC_TOTAL, Mp4FieldKey.DISCNUMBER); tagFieldToMp4Field.put(FieldKey.ENCODER, Mp4FieldKey.ENCODER); tagFieldToMp4Field.put(FieldKey.FBPM, Mp4FieldKey.FBPM); tagFieldToMp4Field.put(FieldKey.GENRE, Mp4FieldKey.GENRE); tagFieldToMp4Field.put(FieldKey.GROUPING, Mp4FieldKey.GROUPING); tagFieldToMp4Field.put(FieldKey.ISRC, Mp4FieldKey.ISRC); tagFieldToMp4Field.put(FieldKey.IS_COMPILATION, Mp4FieldKey.COMPILATION); tagFieldToMp4Field.put(FieldKey.KEY, Mp4FieldKey.KEY); tagFieldToMp4Field.put(FieldKey.LANGUAGE, Mp4FieldKey.LANGUAGE); tagFieldToMp4Field.put(FieldKey.LYRICIST, Mp4FieldKey.LYRICIST); tagFieldToMp4Field.put(FieldKey.LYRICS, Mp4FieldKey.LYRICS); tagFieldToMp4Field.put(FieldKey.MEDIA, Mp4FieldKey.MEDIA); tagFieldToMp4Field.put(FieldKey.MOOD, Mp4FieldKey.MOOD); tagFieldToMp4Field.put(FieldKey.MUSICBRAINZ_ARTISTID, Mp4FieldKey.MUSICBRAINZ_ARTISTID); tagFieldToMp4Field.put(FieldKey.MUSICBRAINZ_DISC_ID, Mp4FieldKey.MUSICBRAINZ_DISCID); tagFieldToMp4Field.put(FieldKey.MUSICBRAINZ_RELEASEARTISTID, Mp4FieldKey.MUSICBRAINZ_ALBUMARTISTID); tagFieldToMp4Field.put(FieldKey.MUSICBRAINZ_RELEASEID, Mp4FieldKey.MUSICBRAINZ_ALBUMID); tagFieldToMp4Field.put(FieldKey.MUSICBRAINZ_RELEASE_COUNTRY, Mp4FieldKey.RELEASECOUNTRY); tagFieldToMp4Field.put(FieldKey.MUSICBRAINZ_RELEASE_GROUP_ID, Mp4FieldKey.MUSICBRAINZ_RELEASE_GROUPID); tagFieldToMp4Field.put(FieldKey.MUSICBRAINZ_RELEASE_STATUS, Mp4FieldKey.MUSICBRAINZ_ALBUM_STATUS); tagFieldToMp4Field.put(FieldKey.MUSICBRAINZ_RELEASE_TYPE, Mp4FieldKey.MUSICBRAINZ_ALBUM_TYPE); tagFieldToMp4Field.put(FieldKey.MUSICBRAINZ_TRACK_ID, Mp4FieldKey.MUSICBRAINZ_TRACKID); tagFieldToMp4Field.put(FieldKey.MUSICBRAINZ_WORK_ID, Mp4FieldKey.MUSICBRAINZ_WORKID); tagFieldToMp4Field.put(FieldKey.MUSICIP_ID, Mp4FieldKey.MUSICIP_PUID); tagFieldToMp4Field.put(FieldKey.OCCASION, Mp4FieldKey.OCCASION); tagFieldToMp4Field.put(FieldKey.ORIGINAL_ALBUM, Mp4FieldKey.MM_ORIGINAL_ALBUM_TITLE); tagFieldToMp4Field.put(FieldKey.ORIGINAL_ARTIST, Mp4FieldKey.MM_ORIGINAL_ARTIST); tagFieldToMp4Field.put(FieldKey.ORIGINAL_LYRICIST, Mp4FieldKey.MM_ORIGINAL_LYRICIST); tagFieldToMp4Field.put(FieldKey.ORIGINAL_YEAR, Mp4FieldKey.MM_ORIGINAL_YEAR); tagFieldToMp4Field.put(FieldKey.QUALITY, Mp4FieldKey.QUALITY); tagFieldToMp4Field.put(FieldKey.RATING, Mp4FieldKey.SCORE); tagFieldToMp4Field.put(FieldKey.RECORD_LABEL, Mp4FieldKey.LABEL); tagFieldToMp4Field.put(FieldKey.REMIXER, Mp4FieldKey.REMIXER); tagFieldToMp4Field.put(FieldKey.SCRIPT, Mp4FieldKey.SCRIPT); tagFieldToMp4Field.put(FieldKey.TAGS, Mp4FieldKey.TAGS); tagFieldToMp4Field.put(FieldKey.TEMPO, Mp4FieldKey.TEMPO); tagFieldToMp4Field.put(FieldKey.TITLE, Mp4FieldKey.TITLE); tagFieldToMp4Field.put(FieldKey.TITLE_SORT, Mp4FieldKey.TITLE_SORT); tagFieldToMp4Field.put(FieldKey.TRACK, Mp4FieldKey.TRACK); tagFieldToMp4Field.put(FieldKey.TRACK_TOTAL, Mp4FieldKey.TRACK); tagFieldToMp4Field.put(FieldKey.URL_DISCOGS_ARTIST_SITE, Mp4FieldKey.URL_DISCOGS_ARTIST_SITE); tagFieldToMp4Field.put(FieldKey.URL_DISCOGS_RELEASE_SITE, Mp4FieldKey.URL_DISCOGS_RELEASE_SITE); tagFieldToMp4Field.put(FieldKey.URL_LYRICS_SITE, Mp4FieldKey.URL_LYRICS_SITE); tagFieldToMp4Field.put(FieldKey.URL_OFFICIAL_ARTIST_SITE, Mp4FieldKey.URL_OFFICIAL_ARTIST_SITE); tagFieldToMp4Field.put(FieldKey.URL_OFFICIAL_RELEASE_SITE, Mp4FieldKey.URL_OFFICIAL_RELEASE_SITE); tagFieldToMp4Field.put(FieldKey.URL_WIKIPEDIA_ARTIST_SITE, Mp4FieldKey.URL_WIKIPEDIA_ARTIST_SITE); tagFieldToMp4Field.put(FieldKey.URL_WIKIPEDIA_RELEASE_SITE, Mp4FieldKey.URL_WIKIPEDIA_RELEASE_SITE); tagFieldToMp4Field.put(FieldKey.YEAR, Mp4FieldKey.DAY); tagFieldToMp4Field.put(FieldKey.ENGINEER, Mp4FieldKey.ENGINEER); tagFieldToMp4Field.put(FieldKey.PRODUCER, Mp4FieldKey.PRODUCER); tagFieldToMp4Field.put(FieldKey.DJMIXER, Mp4FieldKey.DJMIXER); tagFieldToMp4Field.put(FieldKey.MIXER, Mp4FieldKey.MIXER); tagFieldToMp4Field.put(FieldKey.ARRANGER, Mp4FieldKey.ARRANGER); } /** * Create genre field *

*

If the content can be parsed to one of the known values use the genre field otherwise * use the custom field. * * @param content * @return */ @SuppressWarnings({"JavaDoc"}) private TagField createGenreField(String content) { if (content == null) { throw new IllegalArgumentException(ErrorMessage.GENERAL_INVALID_NULL_ARGUMENT.getMsg()); } if (Mp4GenreField.isValidGenre(content)) { return new Mp4GenreField(content); } else { return new Mp4TagTextField(GENRE_CUSTOM.getFieldName(), content); } } protected boolean isAllowedEncoding(String enc) { return enc.equals(Mp4BoxHeader.CHARSET_UTF_8); } public String toString() { return "Mpeg4 " + super.toString(); } /** * Maps the generic key to the mp4 key and return the list of values for this field * * @param genericKey */ @SuppressWarnings({"JavaDoc"}) @Override public List getFields(FieldKey genericKey) throws KeyNotFoundException { if (genericKey == null) { throw new KeyNotFoundException(); } return super.getFields(tagFieldToMp4Field.get(genericKey).getFieldName()); } /** * Retrieve the values that exists for this mp4keyId (this is the internalid actually used) *

* * @param mp4FieldKey * @throws org.jaudiotagger.tag.KeyNotFoundException * @return */ public List get(Mp4FieldKey mp4FieldKey) throws KeyNotFoundException { if (mp4FieldKey == null) { throw new KeyNotFoundException(); } return super.getFields(mp4FieldKey.getFieldName()); } /** * Retrieve the indexed value that exists for this generic key * * @param genericKey * @return */ public String getValue(FieldKey genericKey, int index) throws KeyNotFoundException { if (genericKey == null) { throw new KeyNotFoundException(); } if(genericKey== FieldKey.GENRE) { List genres = getFields(GENRE.getFieldName()); if (genres.size() == 0) { genres = getFields(GENRE_CUSTOM.getFieldName()); } if(genres.size()>index) { return ((TagTextField)genres.get(index)).getContent(); } else { return ""; } } else if(genericKey== FieldKey.TRACK) { List list = get(tagFieldToMp4Field.get(genericKey)); if(list.size()>index) { Mp4TrackField trackField = (Mp4TrackField)list.get(index); if(trackField.getTrackNo()>0) { return String.valueOf(trackField.getTrackNo()); } } } else if(genericKey== FieldKey.TRACK_TOTAL) { List list = get(tagFieldToMp4Field.get(genericKey)); if(list.size()>index) { Mp4TrackField trackField = (Mp4TrackField)list.get(index); if(trackField.getTrackTotal()>0) { return String.valueOf(trackField.getTrackTotal()); } } } else if(genericKey== FieldKey.DISC_NO) { List list = get(tagFieldToMp4Field.get(genericKey)); if(list.size()>index) { Mp4DiscNoField discField = (Mp4DiscNoField)list.get(index); if(discField.getDiscNo()>0) { return String.valueOf(discField.getDiscNo()); } } } else if(genericKey== FieldKey.DISC_TOTAL) { List list = get(tagFieldToMp4Field.get(genericKey)); if(list.size()>index) { Mp4DiscNoField discField = (Mp4DiscNoField)list.get(index); if(discField.getDiscTotal()>0) { return String.valueOf(discField.getDiscTotal()); } } } else { return super.getItem(tagFieldToMp4Field.get(genericKey).getFieldName(), index); } return ""; } /** * Retrieve the first value that exists for this mp4key * * @param mp4Key * @return * @throws org.jaudiotagger.tag.KeyNotFoundException */ public String getFirst(Mp4FieldKey mp4Key) throws KeyNotFoundException { if (mp4Key == null) { throw new KeyNotFoundException(); } return super.getFirst(mp4Key.getFieldName()); } public Mp4TagField getFirstField(FieldKey genericKey) throws KeyNotFoundException { if (genericKey == null) { throw new KeyNotFoundException(); } return (Mp4TagField)super.getFirstField(tagFieldToMp4Field.get(genericKey).getFieldName()); } public Mp4TagField getFirstField(Mp4FieldKey mp4Key) throws KeyNotFoundException { if (mp4Key == null) { throw new KeyNotFoundException(); } return (Mp4TagField) super.getFirstField(mp4Key.getFieldName()); } /** * Delete fields with this generic key * * @param genericKey */ public void deleteField(FieldKey genericKey) throws KeyNotFoundException { if (genericKey == null) { throw new KeyNotFoundException(); } super.deleteField(tagFieldToMp4Field.get(genericKey).getFieldName()); } /** * Delete fields with this mp4key * * @param mp4Key * @throws org.jaudiotagger.tag.KeyNotFoundException */ public void deleteField(Mp4FieldKey mp4Key) throws KeyNotFoundException { if (mp4Key == null) { throw new KeyNotFoundException(); } super.deleteField(mp4Key.getFieldName()); } /** * Create artwork field * * @param data raw image data * @return * @throws org.jaudiotagger.tag.FieldDataInvalidException */ public TagField createArtworkField(byte[] data) { return new Mp4TagCoverField(data); } /** * Create artwork field * * @return */ public TagField createField(Artwork artwork) throws FieldDataInvalidException { return new Mp4TagCoverField(artwork.getBinaryData()); } /** * Create Tag Field using generic key *

* This should use the correct subclass for the key * * @param genericKey * @param value * @return * @throws KeyNotFoundException * @throws FieldDataInvalidException */ @Override public TagField createField(FieldKey genericKey, String value) throws KeyNotFoundException, FieldDataInvalidException { if (value == null) { throw new IllegalArgumentException(ErrorMessage.GENERAL_INVALID_NULL_ARGUMENT.getMsg()); } if (genericKey == null) { throw new KeyNotFoundException(); } //Special handling for these number fields if( (genericKey== FieldKey.TRACK)|| (genericKey== FieldKey.TRACK_TOTAL)|| (genericKey== FieldKey.DISC_NO)|| (genericKey== FieldKey.DISC_TOTAL) ) { try { int number = Integer.parseInt(value); if(genericKey== FieldKey.TRACK) { return new Mp4TrackField(number); } else if(genericKey== FieldKey.TRACK_TOTAL) { return new Mp4TrackField(0,number); } else if(genericKey== FieldKey.DISC_NO) { return new Mp4DiscNoField(number); } else if(genericKey== FieldKey.DISC_TOTAL) { return new Mp4DiscNoField(0,number); } } catch(NumberFormatException nfe) { //If not number we want to convert to an expected exception (which is not a RuntimeException) //so can be handled properly by calling program throw new FieldDataInvalidException("Value "+value + " is not a number as required",nfe); } } //Default for all other fields return createField(tagFieldToMp4Field.get(genericKey), value); } /** * Set field, special handling for track and disc because they hold two fields * * @param field */ @Override public void setField(TagField field) { if (field == null) { return; } if(field.getId().equals(TRACK.getFieldName())) { List list = fields.get(field.getId()); if(list==null||list.size()==0) { super.setField(field); } else { Mp4TrackField existingTrackField = (Mp4TrackField)list.get(0); Mp4TrackField newTrackField = (Mp4TrackField)field; Short trackNo = existingTrackField.getTrackNo(); Short trackTotal = existingTrackField.getTrackTotal(); if(newTrackField.getTrackNo()>0 ) { trackNo = newTrackField.getTrackNo(); } if(newTrackField.getTrackTotal()>0 ) { trackTotal = newTrackField.getTrackTotal(); } Mp4TrackField mergedTrackField = new Mp4TrackField(trackNo,trackTotal); super.setField(mergedTrackField); } } else if(field.getId().equals(DISCNUMBER.getFieldName())) { List list = fields.get(field.getId()); if(list==null||list.size()==0) { super.setField(field); } else { Mp4DiscNoField existingDiscNoField = (Mp4DiscNoField)list.get(0); Mp4DiscNoField newDiscNoField = (Mp4DiscNoField)field; Short discNo = existingDiscNoField.getDiscNo(); Short discTotal = existingDiscNoField.getDiscTotal(); if(newDiscNoField.getDiscNo()>0 ) { discNo = newDiscNoField.getDiscNo(); } if(newDiscNoField.getDiscTotal()>0 ) { discTotal = newDiscNoField.getDiscTotal(); } Mp4DiscNoField mergedDiscNoField = new Mp4DiscNoField(discNo,discTotal); super.setField(mergedDiscNoField); } } else { super.setField(field); } } /** * Create Tag Field using mp4 key *

* Uses the correct subclass for the key * * @param mp4FieldKey * @param value * @return * @throws KeyNotFoundException * @throws FieldDataInvalidException */ public TagField createField(Mp4FieldKey mp4FieldKey, String value) throws KeyNotFoundException, FieldDataInvalidException { if (value == null) { throw new IllegalArgumentException(ErrorMessage.GENERAL_INVALID_NULL_ARGUMENT.getMsg()); } if (mp4FieldKey == null) { throw new KeyNotFoundException(); } //This is boolean stored as 1, but calling program might setField as 'true' so we handle this //case internally if(mp4FieldKey==Mp4FieldKey.COMPILATION) { if(value.equals("true")) { value= Mp4TagByteField.TRUE_VALUE; } return new Mp4TagByteField(mp4FieldKey, value, mp4FieldKey.getFieldLength()); } else if(mp4FieldKey==Mp4FieldKey.GENRE) { return createGenreField(value); } else if(mp4FieldKey.getSubClassFieldType()==Mp4TagFieldSubType.DISC_NO) { return new Mp4DiscNoField(value); } else if(mp4FieldKey.getSubClassFieldType()==Mp4TagFieldSubType.TRACK_NO) { return new Mp4TrackField(value); } else if(mp4FieldKey.getSubClassFieldType()==Mp4TagFieldSubType.BYTE) { return new Mp4TagByteField(mp4FieldKey, value, mp4FieldKey.getFieldLength()); } else if(mp4FieldKey.getSubClassFieldType()==Mp4TagFieldSubType.NUMBER) { return new Mp4TagTextNumberField(mp4FieldKey.getFieldName(), value); } else if(mp4FieldKey.getSubClassFieldType()==Mp4TagFieldSubType.REVERSE_DNS) { return new Mp4TagReverseDnsField(mp4FieldKey, value); } else if(mp4FieldKey.getSubClassFieldType()==Mp4TagFieldSubType.ARTWORK) { throw new UnsupportedOperationException(ErrorMessage.ARTWORK_CANNOT_BE_CREATED_WITH_THIS_METHOD.getMsg()); } else if(mp4FieldKey.getSubClassFieldType()==Mp4TagFieldSubType.TEXT) { return new Mp4TagTextField(mp4FieldKey.getFieldName(), value); } else if(mp4FieldKey.getSubClassFieldType()==Mp4TagFieldSubType.UNKNOWN) { throw new UnsupportedOperationException(ErrorMessage.DO_NOT_KNOW_HOW_TO_CREATE_THIS_ATOM_TYPE.getMsg(mp4FieldKey.getFieldName())); } else { throw new UnsupportedOperationException(ErrorMessage.DO_NOT_KNOW_HOW_TO_CREATE_THIS_ATOM_TYPE.getMsg(mp4FieldKey.getFieldName())); } } public List getArtworkList() { List coverartList = get(Mp4FieldKey.ARTWORK); List artworkList = new ArrayList(coverartList.size()); for(TagField next:coverartList) { Mp4TagCoverField mp4CoverArt = (Mp4TagCoverField)next; Artwork artwork = new Artwork(); artwork.setBinaryData(mp4CoverArt.getData()); artwork.setMimeType(Mp4TagCoverField.getMimeTypeForImageType(mp4CoverArt.getFieldType())); artworkList.add(artwork); } return artworkList; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/mp4/field/0000755000175000017500000000000011556363175024060 5ustar drazzibdrazziblibjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/mp4/field/Mp4TrackField.java0000644000175000017500000001220511470746136027311 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.mp4.field; import org.jaudiotagger.audio.mp4.atom.Mp4BoxHeader; import org.jaudiotagger.tag.FieldDataInvalidException; import org.jaudiotagger.tag.mp4.Mp4FieldKey; import org.jaudiotagger.tag.mp4.atom.Mp4DataBox; import java.io.UnsupportedEncodingException; import java.nio.ByteBuffer; import java.util.ArrayList; /** * Represents the Track No field *

*

There are a number of reseved fields makeing matters more complicated * Reserved:2 bytes * Track Number:2 bytes * No of Tracks:2 bytes (or zero if not known) * PlayListTitleReserved: 1 byte * playtitlenameReserved:0 bytes *

*/ public class Mp4TrackField extends Mp4TagTextNumberField { private static final int NONE_VALUE_INDEX = 0; private static final int TRACK_NO_INDEX = 1; private static final int TRACK_TOTAL_INDEX = 2; private static final int NONE_END_VALUE_INDEX = 3; /** * Create new Track Field parsing the String for the trackno/total * * @param trackValue * @throws org.jaudiotagger.tag.FieldDataInvalidException */ public Mp4TrackField(String trackValue) throws FieldDataInvalidException { super(Mp4FieldKey.TRACK.getFieldName(), trackValue); numbers = new ArrayList(); numbers.add(new Short("0")); String values[] = trackValue.split("/"); switch (values.length) { case 1: try { numbers.add(Short.parseShort(values[0])); } catch (NumberFormatException nfe) { throw new FieldDataInvalidException("Value of:" + values[0] + " is invalid for field:" + id); } numbers.add(new Short("0")); numbers.add(new Short("0")); break; case 2: try { numbers.add(Short.parseShort(values[0])); } catch (NumberFormatException nfe) { throw new FieldDataInvalidException("Value of:" + values[0] + " is invalid for field:" + id); } try { numbers.add(Short.parseShort(values[1])); } catch (NumberFormatException nfe) { throw new FieldDataInvalidException("Value of:" + values[1] + " is invalid for field:" + id); } numbers.add(new Short("0")); break; default: throw new FieldDataInvalidException("Value is invalid for field:" + id); } } /** * Create new Track Field with only track No * * @param trackNo */ public Mp4TrackField(int trackNo) { super(Mp4FieldKey.TRACK.getFieldName(), String.valueOf(trackNo)); numbers = new ArrayList(); numbers.add(new Short("0")); numbers.add((short) trackNo); numbers.add(new Short("0")); numbers.add(new Short("0")); } /** * Create new Track Field with track No and total tracks * * @param trackNo * @param total */ public Mp4TrackField(int trackNo, int total) { super(Mp4FieldKey.TRACK.getFieldName(), String.valueOf(trackNo)); numbers = new ArrayList(); numbers.add(new Short("0")); numbers.add((short) trackNo); numbers.add((short) total); numbers.add(new Short("0")); } /** * Construct from filedata * * @param id * @param data * @throws UnsupportedEncodingException */ public Mp4TrackField(String id, ByteBuffer data) throws UnsupportedEncodingException { super(id, data); } protected void build(ByteBuffer data) throws UnsupportedEncodingException { //Data actually contains a 'Data' Box so process data using this Mp4BoxHeader header = new Mp4BoxHeader(data); Mp4DataBox databox = new Mp4DataBox(header, data); dataSize = header.getDataLength(); numbers = databox.getNumbers(); //Track number always hold three values, we can discard the first one, the second one is the track no //and the third is the total no of tracks so only use if not zero StringBuffer sb = new StringBuffer(); sb.append(numbers.get(TRACK_NO_INDEX)); if (numbers.get(TRACK_TOTAL_INDEX) > 0) { sb.append("/").append(numbers.get(TRACK_TOTAL_INDEX)); } content = sb.toString(); } /** * @return */ public Short getTrackNo() { return numbers.get(TRACK_NO_INDEX); } /** * @return */ public Short getTrackTotal() { return numbers.get(TRACK_TOTAL_INDEX); } /** * Set Track No * * @param trackNo */ public void setTrackNo(int trackNo) { numbers.set(TRACK_NO_INDEX, (short) trackNo); } /** * Set total number of tracks * * @param trackTotal */ public void setTrackTotal(int trackTotal) { numbers.set(TRACK_TOTAL_INDEX, (short) trackTotal); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/mp4/field/Mp4FieldType.java0000644000175000017500000000363611126411643027164 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.mp4.field; import org.jaudiotagger.tag.mp4.Mp4FieldKey; import java.util.EnumSet; import java.util.HashMap; /** * Describes the possible types of data held within a Databox */ public enum Mp4FieldType { IMPLICIT(0x0), //used for specialized formats such as TrackNo or DiscNo TEXT(0x1), //UTF-8 TEXT_UTF16BE(0x02), TEXT_JAPANESE(0x03), HTML(0x06), XML(0x07), GUID(0x08), ISRC(0x09), MI3P(0x0a), COVERART_GIF(0x0c), COVERART_JPEG(0x0d), COVERART_PNG(0x0e), URL(0x0f), DURATION(0x10), DATETIME(0x11), GENRES(0x12), INTEGER(0x15), //Formally known as byte RIAAPA(0x18), UPC(0x19), COVERART_BMP(0x1B), ; private int fileClassId; Mp4FieldType(int fileClassId) { this.fileClassId = fileClassId; } public int getFileClassId() { return fileClassId; } private final static HashMap fileClassIdFiedTypeMap; static { fileClassIdFiedTypeMap = new HashMap(Mp4FieldType.values().length); for (Mp4FieldType curr : Mp4FieldType.values()) { fileClassIdFiedTypeMap.put(curr.fileClassId,curr); } } /** * * @param fieldClassId * @return the Mp4FieldType that this fieldClassId maps to */ public static Mp4FieldType getFieldType(int fieldClassId) { return fileClassIdFiedTypeMap.get(fieldClassId); } private static EnumSet coverArtTypes; static { coverArtTypes = EnumSet.of(COVERART_GIF,COVERART_JPEG,COVERART_PNG,COVERART_BMP); } /** * * @param mp4FieldType * @return true if this type is for identifying a image format to be used in cover art */ public static boolean isCoverArtType(Mp4FieldType mp4FieldType) { return coverArtTypes.contains(mp4FieldType); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/mp4/field/Mp4TagBinaryField.java0000644000175000017500000000730311277006322030117 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2003-2005 Raphaël Slinckx * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.tag.mp4.field; import org.jaudiotagger.audio.mp4.atom.Mp4BoxHeader; import org.jaudiotagger.tag.TagField; import org.jaudiotagger.tag.mp4.Mp4TagField; import org.jaudiotagger.tag.mp4.atom.Mp4DataBox; import java.io.UnsupportedEncodingException; import java.nio.ByteBuffer; /** * Represents binary data *

*

Subclassed by cover art field, * TODO unaware of any other binary fields at the moment */ public class Mp4TagBinaryField extends Mp4TagField { protected int dataSize; protected byte[] dataBytes; protected boolean isBinary = false; /** * Construct an empty Binary Field * * @param id */ public Mp4TagBinaryField(String id) { super(id); } /** * Construct new binary field with binarydata provided * * @param id * @param data * @throws UnsupportedEncodingException */ public Mp4TagBinaryField(String id, byte[] data) { super(id); this.dataBytes = data; } /** * Construct binary field from rawdata of audio file * * @param id * @param raw * @throws UnsupportedEncodingException */ public Mp4TagBinaryField(String id, ByteBuffer raw) throws UnsupportedEncodingException { super(id, raw); } public Mp4FieldType getFieldType() { //TODO dont know what value this should be do we actually have any binary fields other //than cover art return Mp4FieldType.IMPLICIT; } /** * Used when creating raw content * * @return * @throws UnsupportedEncodingException */ protected byte[] getDataBytes() throws UnsupportedEncodingException { return dataBytes; } protected void build(ByteBuffer raw) { Mp4BoxHeader header = new Mp4BoxHeader(raw); dataSize = header.getDataLength(); //Skip the version and length fields raw.position(raw.position() + Mp4DataBox.PRE_DATA_LENGTH); //Read the raw data into byte array this.dataBytes = new byte[dataSize - Mp4DataBox.PRE_DATA_LENGTH]; for (int i = 0; i < dataBytes.length; i++) { this.dataBytes[i] = raw.get(); } //After returning buffers position will be after the end of this atom } public boolean isBinary() { return isBinary; } public boolean isEmpty() { return this.dataBytes.length == 0; } public int getDataSize() { return dataSize; } public byte[] getData() { return this.dataBytes; } public void setData(byte[] d) { this.dataBytes = d; } public void copyContent(TagField field) { if (field instanceof Mp4TagBinaryField) { this.dataBytes = ((Mp4TagBinaryField) field).getData(); this.isBinary = field.isBinary(); } } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/mp4/field/Mp4TagRawBinaryField.java0000644000175000017500000000604211126411643030567 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.mp4.field; import org.jaudiotagger.audio.generic.Utils; import org.jaudiotagger.audio.mp4.atom.Mp4BoxHeader; import org.jaudiotagger.tag.TagField; import org.jaudiotagger.tag.mp4.Mp4TagField; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.nio.ByteBuffer; /** * Represents raw binary data *

*

We use this when we find an atom under the ilst atom that we do not recognise , that does not * follow standard conventions in order to save the data without modification so it can be safetly * written back to file */ public class Mp4TagRawBinaryField extends Mp4TagField { protected int dataSize; protected byte[] dataBytes; /** * Construct binary field from rawdata of audio file * * @param header * @param raw * @throws java.io.UnsupportedEncodingException * */ public Mp4TagRawBinaryField(Mp4BoxHeader header, ByteBuffer raw) throws UnsupportedEncodingException { super(header.getId()); dataSize = header.getDataLength(); build(raw); } public Mp4FieldType getFieldType() { return Mp4FieldType.IMPLICIT; } /** * Used when creating raw content * * @return * @throws java.io.UnsupportedEncodingException * */ protected byte[] getDataBytes() throws UnsupportedEncodingException { return dataBytes; } /** * Build from data *

*

After returning buffers position will be after the end of this atom * * @param raw */ protected void build(ByteBuffer raw) { //Read the raw data into byte array this.dataBytes = new byte[dataSize]; for (int i = 0; i < dataBytes.length; i++) { this.dataBytes[i] = raw.get(); } } public boolean isBinary() { return true; } public boolean isEmpty() { return this.dataBytes.length == 0; } public int getDataSize() { return dataSize; } public byte[] getData() { return this.dataBytes; } public void setData(byte[] d) { this.dataBytes = d; } public void copyContent(TagField field) { throw new UnsupportedOperationException("not done"); } public byte[] getRawContent() throws UnsupportedEncodingException { logger.fine("Getting Raw data for:" + getId()); try { ByteArrayOutputStream outerbaos = new ByteArrayOutputStream(); outerbaos.write(Utils.getSizeBEInt32(Mp4BoxHeader.HEADER_LENGTH + dataSize)); outerbaos.write(Utils.getDefaultBytes(getId(), "ISO-8859-1")); outerbaos.write(dataBytes); System.out.println("SIZE" + outerbaos.size()); return outerbaos.toByteArray(); } catch (IOException ioe) { //This should never happen as were not actually writing to/from a file throw new RuntimeException(ioe); } } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/mp4/field/Mp4DiscNoField.java0000644000175000017500000001130411277026507027421 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.mp4.field; import org.jaudiotagger.audio.mp4.atom.Mp4BoxHeader; import org.jaudiotagger.tag.FieldDataInvalidException; import org.jaudiotagger.tag.mp4.Mp4FieldKey; import org.jaudiotagger.tag.mp4.atom.Mp4DataBox; import java.io.UnsupportedEncodingException; import java.nio.ByteBuffer; import java.util.ArrayList; /** * Represents the Disc No field *

*

Contains some reserved fields that we currently ignore * * Reserved:2 bytes * Disc Number:2 bytes * Total no of Discs:2 bytes *

*/ public class Mp4DiscNoField extends Mp4TagTextNumberField { private static final int NONE_VALUE_INDEX = 0; private static final int DISC_NO_INDEX = 1; private static final int DISC_TOTAL_INDEX = 2; /** * Create new Disc Field parsing the String for the discno/total * * @param discValue * @throws org.jaudiotagger.tag.FieldDataInvalidException */ public Mp4DiscNoField(String discValue) throws FieldDataInvalidException { super(Mp4FieldKey.DISCNUMBER.getFieldName(), discValue); numbers = new ArrayList(); numbers.add(new Short("0")); String values[] = discValue.split("/"); switch (values.length) { case 1: try { numbers.add(Short.parseShort(values[0])); } catch (NumberFormatException nfe) { throw new FieldDataInvalidException("Value of:" + values[0] + " is invalid for field:" + id); } numbers.add(new Short("0")); break; case 2: try { numbers.add(Short.parseShort(values[0])); } catch (NumberFormatException nfe) { throw new FieldDataInvalidException("Value of:" + values[0] + " is invalid for field:" + id); } try { numbers.add(Short.parseShort(values[1])); } catch (NumberFormatException nfe) { throw new FieldDataInvalidException("Value of:" + values[1] + " is invalid for field:" + id); } break; default: throw new FieldDataInvalidException("Value is invalid for field:" + id); } } /** * Create new Disc No field with only discNo * * @param discNo */ public Mp4DiscNoField(int discNo) { super(Mp4FieldKey.DISCNUMBER.getFieldName(), String.valueOf(discNo)); numbers = new ArrayList(); numbers.add(new Short("0")); numbers.add((short) discNo); numbers.add(new Short("0")); } /** * Create new Disc No Field with Disc No and total number of discs * * @param discNo * @param total */ public Mp4DiscNoField(int discNo, int total) { super(Mp4FieldKey.DISCNUMBER.getFieldName(), String.valueOf(discNo)); numbers = new ArrayList(); numbers.add(new Short("0")); numbers.add((short) discNo); numbers.add((short) total); } public Mp4DiscNoField(String id, ByteBuffer data) throws UnsupportedEncodingException { super(id, data); } protected void build(ByteBuffer data) throws UnsupportedEncodingException { //Data actually contains a 'Data' Box so process data using this Mp4BoxHeader header = new Mp4BoxHeader(data); Mp4DataBox databox = new Mp4DataBox(header, data); dataSize = header.getDataLength(); numbers = databox.getNumbers(); //Disc number always hold four values, we can discard the first one and last one, the second one is the disc no //and the third is the total no of discs so only use if not zero StringBuffer sb = new StringBuffer(); sb.append(numbers.get(DISC_NO_INDEX)); if (numbers.get(DISC_TOTAL_INDEX) > 0) { sb.append("/").append(numbers.get(DISC_TOTAL_INDEX)); } content = sb.toString(); } /** * @return */ public Short getDiscNo() { return numbers.get(DISC_NO_INDEX); } /** * Set Disc No * * @param discNo */ public void setDiscNo(int discNo) { numbers.set(DISC_NO_INDEX, (short) discNo); } /** * @return */ public Short getDiscTotal() { return numbers.get(DISC_TOTAL_INDEX); } /** * Set total number of discs * * @param discTotal */ public void setDiscTotal(int discTotal) { numbers.set(DISC_TOTAL_INDEX, (short) discTotal); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/mp4/field/Mp4TagByteField.java0000644000175000017500000001121511470746136027604 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.mp4.field; import org.jaudiotagger.audio.generic.Utils; import org.jaudiotagger.audio.mp4.atom.Mp4BoxHeader; import org.jaudiotagger.tag.FieldDataInvalidException; import org.jaudiotagger.tag.mp4.Mp4FieldKey; import org.jaudiotagger.tag.mp4.atom.Mp4DataBox; import java.io.UnsupportedEncodingException; import java.nio.ByteBuffer; /** * Represents a single byte as a number *

*

Usually single byte fields are used as a boolean field, but not always so we dont do this conversion */ public class Mp4TagByteField extends Mp4TagTextField { public static String TRUE_VALUE="1"; //when using this field to hold a boolean //Holds the actual size of the data content as held in the databoxitem, this is required when creating new //items because we cant accurately work out the size by looking at the content because sometimes field must be longer //than is actually required to hold the value //e.g byte data length seems to be 1 for pgap and cpil but 2 for tmpo, so we stored the dataSize //when we loaded the value so if greater than 1 we pad the value. private int realDataLength; //Preserved from data from file private byte[] bytedata; /** * Create new field *

* Assume length of 1 which is correct for most but not all byte fields * * @param id * @param value is a String representation of a number * @throws org.jaudiotagger.tag.FieldDataInvalidException */ public Mp4TagByteField(Mp4FieldKey id, String value) throws FieldDataInvalidException { this(id, value, 1); } /** * Create new field with known length * * @param id * @param value is a String representation of a number * @param realDataLength * @throws org.jaudiotagger.tag.FieldDataInvalidException */ public Mp4TagByteField(Mp4FieldKey id, String value, int realDataLength) throws FieldDataInvalidException { super(id.getFieldName(), value); this.realDataLength = realDataLength; //Check that can actually be stored numercially, otherwise will have big problems //when try and save the field try { Long.parseLong(value); } catch (NumberFormatException nfe) { throw new FieldDataInvalidException("Value of:" + value + " is invalid for field:" + id); } } /** * Construct from rawdata from audio file * * @param id * @param raw * @throws UnsupportedEncodingException */ public Mp4TagByteField(String id, ByteBuffer raw) throws UnsupportedEncodingException { super(id, raw); } public Mp4FieldType getFieldType() { return Mp4FieldType.INTEGER; } /** * Return raw data bytes *

* TODO this code should be done better so generalised to any length * * @return * @throws UnsupportedEncodingException */ protected byte[] getDataBytes() throws UnsupportedEncodingException { //Write original data if (bytedata != null) { return bytedata; } //new field, lets hope the realDataLength is correct switch (realDataLength) { case 2: { //Save as two bytes Short shortValue = new Short(content); byte rawData[] = Utils.getSizeBEInt16(shortValue); return rawData; } case 1: { //Save as 1 bytes Short shortValue = new Short(content); byte rawData[] = new byte[1]; rawData[0] = shortValue.byteValue(); return rawData; } case 4: { //Assume could be int Integer intValue = new Integer(content); byte rawData[] = Utils.getSizeBEInt32(intValue); return rawData; } default: { //TODO throw new RuntimeException(id + ":" + realDataLength + ":" + "Dont know how to write byte fields of this length"); } } } protected void build(ByteBuffer data) throws UnsupportedEncodingException { //Data actually contains a 'Data' Box so process data using this Mp4BoxHeader header = new Mp4BoxHeader(data); Mp4DataBox databox = new Mp4DataBox(header, data); dataSize = header.getDataLength(); //Needed for subsequent write realDataLength = dataSize - Mp4DataBox.PRE_DATA_LENGTH; bytedata = databox.getByteData(); content = databox.getContent(); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/mp4/field/Mp4TagReverseDnsField.java0000644000175000017500000002161711277006322030757 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.mp4.field; import org.jaudiotagger.audio.generic.Utils; import org.jaudiotagger.audio.mp4.atom.Mp4BoxHeader; import org.jaudiotagger.logging.ErrorMessage; import org.jaudiotagger.tag.TagField; import org.jaudiotagger.tag.TagTextField; import org.jaudiotagger.tag.mp4.Mp4FieldKey; import org.jaudiotagger.tag.mp4.Mp4TagField; import org.jaudiotagger.tag.mp4.atom.Mp4DataBox; import org.jaudiotagger.tag.mp4.atom.Mp4MeanBox; import org.jaudiotagger.tag.mp4.atom.Mp4NameBox; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.nio.ByteBuffer; /** * Represents reverse dns field, used for custom information *

*

Originally only used by Itunes for information that was iTunes specific but now used in a wide range of uses, * for example Musicbrainz uses it for many of its fields. *

* These fields have a more complex setup * Box ---- shows this is a reverse dns metadata field * Box mean the issuer in the form of reverse DNS domain (e.g com.apple.iTunes) * Box name descriptor identifying the type of contents * Box data contents *

* The raw data passed starts from the mean box */ public class Mp4TagReverseDnsField extends Mp4TagField implements TagTextField { public static final String IDENTIFIER = "----"; protected int dataSize; //Issuer private String issuer; //Descriptor private String descriptor; //Data Content, //TODO assuming always text at the moment protected String content; /** * Construct from existing file data * * @param parentHeader * @param data * @throws UnsupportedEncodingException */ public Mp4TagReverseDnsField(Mp4BoxHeader parentHeader, ByteBuffer data) throws UnsupportedEncodingException { super(parentHeader, data); } /** * Newly created Reverse Dns field * * @param id * @param content */ public Mp4TagReverseDnsField(Mp4FieldKey id, String content) { super(id.getFieldName()); this.issuer = id.getIssuer(); this.descriptor = id.getIdentifier(); this.content = content; } /** * Newly created Reverse Dns field bypassing the Mp4TagField enum for creation of temporary reverse dns fields * @param fieldName * @param issuer * @param identifier * @param content */ public Mp4TagReverseDnsField(final String fieldName, final String issuer, final String identifier, final String content) { super(fieldName); this.issuer = issuer; this.descriptor = identifier; this.content = content; } public Mp4FieldType getFieldType() { //TODO always assuming text at moment but may not always be the case (though dont have any concrete //examples) return Mp4FieldType.TEXT; } protected void build(ByteBuffer data) throws UnsupportedEncodingException { //Read mean box, set the issuer and skip over data Mp4BoxHeader meanBoxHeader = new Mp4BoxHeader(data); Mp4MeanBox meanBox = new Mp4MeanBox(meanBoxHeader, data); setIssuer(meanBox.getIssuer()); data.position(data.position() + meanBoxHeader.getDataLength()); //Read name box, identify what type of field it is Mp4BoxHeader nameBoxHeader = new Mp4BoxHeader(data); Mp4NameBox nameBox = new Mp4NameBox(nameBoxHeader, data); setDescriptor(nameBox.getName()); data.position(data.position() + nameBoxHeader.getDataLength()); //Issue 198:There is not actually a data atom there cannot cant be because no room for one if (parentHeader.getDataLength() == meanBoxHeader.getLength() + nameBoxHeader.getLength()) { id = IDENTIFIER + ":" + issuer + ":" + descriptor; setContent(""); logger.warning(ErrorMessage.MP4_REVERSE_DNS_FIELD_HAS_NO_DATA.getMsg(id)); } //Usual Case else { //Read data box, identify the data Mp4BoxHeader dataBoxHeader = new Mp4BoxHeader(data); Mp4DataBox dataBox = new Mp4DataBox(dataBoxHeader, data); setContent(dataBox.getContent()); data.position(data.position() + dataBoxHeader.getDataLength()); //Now calculate the id which in order to be unique needs to use all htree values id = IDENTIFIER + ":" + issuer + ":" + descriptor; } } public void copyContent(TagField field) { if (field instanceof Mp4TagReverseDnsField) { this.issuer = ((Mp4TagReverseDnsField) field).getIssuer(); this.descriptor = ((Mp4TagReverseDnsField) field).getDescriptor(); this.content = ((Mp4TagReverseDnsField) field).getContent(); } } /** * @return content */ public String getContent() { return content; } protected byte[] getDataBytes() throws UnsupportedEncodingException { return content.getBytes(getEncoding()); } public String getEncoding() { return Mp4BoxHeader.CHARSET_UTF_8; } /** * Convert back to raw content, includes ----,mean,name and data atom as views as one thing externally * * @return * @throws UnsupportedEncodingException */ public byte[] getRawContent() throws UnsupportedEncodingException { try { ByteArrayOutputStream baos = new ByteArrayOutputStream(); //Create Meanbox data byte[] issuerRawData = issuer.getBytes(getEncoding()); baos.write(Utils.getSizeBEInt32(Mp4BoxHeader.HEADER_LENGTH + Mp4MeanBox.PRE_DATA_LENGTH + issuerRawData.length)); baos.write(Utils.getDefaultBytes(Mp4MeanBox.IDENTIFIER, "ISO-8859-1")); baos.write(new byte[]{0, 0, 0, 0}); baos.write(issuerRawData); //Create Namebox data byte[] nameRawData = descriptor.getBytes(getEncoding()); baos.write(Utils.getSizeBEInt32(Mp4BoxHeader.HEADER_LENGTH + Mp4NameBox.PRE_DATA_LENGTH + nameRawData.length)); baos.write(Utils.getDefaultBytes(Mp4NameBox.IDENTIFIER, "ISO-8859-1")); baos.write(new byte[]{0, 0, 0, 0}); baos.write(nameRawData); //Create DataBox data if we have data only if (content.length() > 0) { baos.write(getRawContentDataOnly()); } //Now wrap with reversedns box ByteArrayOutputStream outerbaos = new ByteArrayOutputStream(); outerbaos.write(Utils.getSizeBEInt32(Mp4BoxHeader.HEADER_LENGTH + baos.size())); outerbaos.write(Utils.getDefaultBytes(IDENTIFIER, "ISO-8859-1")); outerbaos.write(baos.toByteArray()); return outerbaos.toByteArray(); } catch (IOException ioe) { //This should never happen as were not actually writing to/from a file throw new RuntimeException(ioe); } } public byte[] getRawContentDataOnly() throws UnsupportedEncodingException { logger.fine("Getting Raw data for:" + getId()); try { //Create DataBox data ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte[] dataRawData = content.getBytes(getEncoding()); baos.write(Utils.getSizeBEInt32(Mp4BoxHeader.HEADER_LENGTH + Mp4DataBox.PRE_DATA_LENGTH + dataRawData.length)); baos.write(Utils.getDefaultBytes(Mp4DataBox.IDENTIFIER, "ISO-8859-1")); baos.write(new byte[]{0}); baos.write(new byte[]{0, 0, (byte) getFieldType().getFileClassId()}); baos.write(new byte[]{0, 0, 0, 0}); baos.write(dataRawData); return baos.toByteArray(); } catch (IOException ioe) { //This should never happen as were not actually writing to/from a file throw new RuntimeException(ioe); } } public boolean isBinary() { return false; } public boolean isEmpty() { return this.content.trim().equals(""); } public void setContent(String s) { this.content = s; } public void setEncoding(String s) { /* Not allowed */ } public String toString() { return content; } /** * @return the issuer */ public String getIssuer() { return issuer; } /** * @return the descriptor */ public String getDescriptor() { return descriptor; } /** * Set the issuer, usually reverse dns of the Companies domain * * @param issuer */ public void setIssuer(String issuer) { this.issuer = issuer; } /** * Set the descriptor for the data (what type of data it is) * * @param descriptor */ public void setDescriptor(String descriptor) { this.descriptor = descriptor; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/mp4/field/Mp4TagTextNumberField.java0000644000175000017500000000666011276536055031007 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2003-2005 Raphaël Slinckx * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.tag.mp4.field; import org.jaudiotagger.audio.generic.Utils; import org.jaudiotagger.audio.mp4.atom.Mp4BoxHeader; import org.jaudiotagger.tag.TagField; import org.jaudiotagger.tag.mp4.atom.Mp4DataBox; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.nio.ByteBuffer; import java.util.List; /** * Represents simple text field that contains an array of number, *

*

But reads the data content as an array of 16 bit unsigned numbers */ public class Mp4TagTextNumberField extends Mp4TagTextField { public static final int NUMBER_LENGTH = 2; //Holds the numbers decoded protected List numbers; /** * Create a new number, already parsed in subclasses * * @param id * @param numberArray */ public Mp4TagTextNumberField(String id, String numberArray) { super(id, numberArray); } public Mp4TagTextNumberField(String id, ByteBuffer data) throws UnsupportedEncodingException { super(id, data); } /** * Recreate the raw data content from the list of numbers * * @return */ protected byte[] getDataBytes() { ByteArrayOutputStream baos = new ByteArrayOutputStream(); for (Short number : numbers) { try { baos.write(Utils.getSizeBEInt16(number)); } catch (IOException e) { //This should never happen because we are not writing to file at this point. throw new RuntimeException(e); } } return baos.toByteArray(); } public void copyContent(TagField field) { if (field instanceof Mp4TagTextNumberField) { this.content = ((Mp4TagTextNumberField) field).getContent(); this.numbers = ((Mp4TagTextNumberField) field).getNumbers(); } } /** * @return type numeric */ public Mp4FieldType getFieldType() { return Mp4FieldType.IMPLICIT; } protected void build(ByteBuffer data) throws UnsupportedEncodingException { //Data actually contains a 'Data' Box so process data using this Mp4BoxHeader header = new Mp4BoxHeader(data); Mp4DataBox databox = new Mp4DataBox(header, data); dataSize = header.getDataLength(); content = databox.getContent(); numbers = databox.getNumbers(); } /** * @return the individual numbers making up this field */ public List getNumbers() { return numbers; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/mp4/field/Mp4TagCoverField.java0000644000175000017500000001415111247705415027756 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2003-2005 Raphaël Slinckx * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.tag.mp4.field; import org.jaudiotagger.audio.mp4.atom.Mp4BoxHeader; import org.jaudiotagger.tag.mp4.Mp4FieldKey; import org.jaudiotagger.tag.mp4.atom.Mp4DataBox; import org.jaudiotagger.tag.mp4.atom.Mp4NameBox; import org.jaudiotagger.tag.reference.PictureTypes; import org.jaudiotagger.tag.id3.valuepair.ImageFormats; import org.jaudiotagger.logging.ErrorMessage; import java.io.UnsupportedEncodingException; import java.nio.ByteBuffer; /** * Represents Cover Art *

*

Note:Within this library we have a seperate TagCoverField for every image stored, however this does not map * very directly to how they are physically stored within a file, because all are stored under a single covr atom, so * a more complex conversion has to be done then for other fields when writing multiple images back to file. */ public class Mp4TagCoverField extends Mp4TagBinaryField { //Type private Mp4FieldType imageType; //Contains the size of each atom including header, required because may only have data atom or //may have data and name atom private int dataAndHeaderSize; /** * Empty CoverArt Field */ public Mp4TagCoverField() { super(Mp4FieldKey.ARTWORK.getFieldName()); } /** * @return data and header size */ public int getDataAndHeaderSize() { return dataAndHeaderSize; } /** * Construct CoverField by reading data from audio file * * @param raw * @param imageType * @throws UnsupportedEncodingException */ public Mp4TagCoverField(ByteBuffer raw,Mp4FieldType imageType) throws UnsupportedEncodingException { super(Mp4FieldKey.ARTWORK.getFieldName(), raw); this.imageType=imageType; if(!Mp4FieldType.isCoverArtType(imageType)) { logger.warning(ErrorMessage.MP4_IMAGE_FORMAT_IS_NOT_TO_EXPECTED_TYPE.getMsg(imageType)); } } /** * Construct new cover art with binarydata provided *

*

* Identifies the imageType by looking at the data * * @param data * @throws UnsupportedEncodingException */ public Mp4TagCoverField(byte[] data) { super(Mp4FieldKey.ARTWORK.getFieldName(), data); //Read signature if (ImageFormats.binaryDataIsPngFormat(data)) { imageType = Mp4FieldType.COVERART_PNG; } else if (ImageFormats.binaryDataIsJpgFormat(data)) { imageType = Mp4FieldType.COVERART_JPEG; } else if (ImageFormats.binaryDataIsGifFormat(data)) { imageType = Mp4FieldType.COVERART_GIF; } else if (ImageFormats.binaryDataIsBmpFormat(data)) { imageType = Mp4FieldType.COVERART_BMP; } else { logger.warning(ErrorMessage.GENERAL_UNIDENITIFED_IMAGE_FORMAT.getMsg()); imageType = Mp4FieldType.COVERART_PNG; } } /** * Return field type, for artwork this also identifies the imagetype * * @return field type */ public Mp4FieldType getFieldType() { return imageType; } public boolean isBinary() { return true; } public String toString() { return imageType +":" + dataBytes.length + "bytes"; } protected void build(ByteBuffer raw) { Mp4BoxHeader header = new Mp4BoxHeader(raw); dataSize = header.getDataLength(); dataAndHeaderSize = header.getLength(); //Skip the version and length fields raw.position(raw.position() + Mp4DataBox.PRE_DATA_LENGTH); //Read the raw data into byte array this.dataBytes = new byte[dataSize - Mp4DataBox.PRE_DATA_LENGTH]; raw.get(dataBytes,0,dataBytes.length); //Is there room for another atom (remember actually passed all the data so unless Covr is last atom //there will be room even though more likely to be for the text top level atom) int positionAfterDataAtom = raw.position(); if (raw.position() + Mp4BoxHeader.HEADER_LENGTH <= raw.limit()) { //Is there a following name field (not the norm) Mp4BoxHeader nameHeader = new Mp4BoxHeader(raw); if (nameHeader.getId().equals(Mp4NameBox.IDENTIFIER)) { dataSize += nameHeader.getDataLength(); dataAndHeaderSize += nameHeader.getLength(); } else { raw.position(positionAfterDataAtom); } } //After returning buffers position will be after the end of this atom } /** * * @param imageType * @return the corresponding mimetype */ public static String getMimeTypeForImageType(Mp4FieldType imageType) { if(imageType==Mp4FieldType.COVERART_PNG) { return ImageFormats.MIME_TYPE_PNG; } else if(imageType==Mp4FieldType.COVERART_JPEG) { return ImageFormats.MIME_TYPE_JPEG; } else if(imageType==Mp4FieldType.COVERART_GIF) { return ImageFormats.MIME_TYPE_GIF; } else if(imageType==Mp4FieldType.COVERART_BMP) { return ImageFormats.MIME_TYPE_BMP; } else { return null; } } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/mp4/field/Mp4GenreField.java0000644000175000017500000000750211277026507027307 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.mp4.field; import org.jaudiotagger.audio.mp4.atom.Mp4BoxHeader; import org.jaudiotagger.logging.ErrorMessage; import org.jaudiotagger.tag.mp4.Mp4FieldKey; import org.jaudiotagger.tag.mp4.atom.Mp4DataBox; import org.jaudiotagger.tag.reference.GenreTypes; import java.io.UnsupportedEncodingException; import java.nio.ByteBuffer; import java.util.ArrayList; /** * Represents the Genre field , when user has selected from the set list of genres *

*

This class allows you to retrieve either the internal genreid, or the display value */ public class Mp4GenreField extends Mp4TagTextNumberField { public Mp4GenreField(String id, ByteBuffer data) throws UnsupportedEncodingException { super(id, data); } /** * Precheck to see if the value is a valid genre or whether you should use a custom genre. * * @param genreId * @return */ public static boolean isValidGenre(String genreId) { //Is it an id (within old id3 range) try { short genreVal = Short.parseShort(genreId); if ((genreVal - 1) <= GenreTypes.getMaxStandardGenreId()) { return true; } } catch (NumberFormatException nfe) { //Do Nothing test as String instead } //Is it the String value ? Integer id3GenreId = GenreTypes.getInstanceOf().getIdForValue(genreId); if (id3GenreId != null) { if (id3GenreId <= GenreTypes.getMaxStandardGenreId()) { return true; } } return false; } /** * Construct genre, if cant find match just default to first genre * * @param genreId key into ID3v1 list (offset by one) or String value in ID3list */ public Mp4GenreField(String genreId) { super(Mp4FieldKey.GENRE.getFieldName(), genreId); //Is it an id try { short genreVal = Short.parseShort(genreId); if ((genreVal - 1) <= GenreTypes.getMaxStandardGenreId()) { numbers = new ArrayList(); numbers.add(genreVal); return; } //Default numbers = new ArrayList(); numbers.add((short) (1)); return; } catch (NumberFormatException nfe) { //Do Nothing test as String instead } //Is it the String value ? Integer id3GenreId = GenreTypes.getInstanceOf().getIdForValue(genreId); if (id3GenreId != null) { if (id3GenreId <= GenreTypes.getMaxStandardGenreId()) { numbers = new ArrayList(); numbers.add((short) (id3GenreId + 1)); return; } } numbers = new ArrayList(); numbers.add((short) (1)); } protected void build(ByteBuffer data) throws UnsupportedEncodingException { //Data actually contains a 'Data' Box so process data using this Mp4BoxHeader header = new Mp4BoxHeader(data); Mp4DataBox databox = new Mp4DataBox(header, data); dataSize = header.getDataLength(); numbers = databox.getNumbers(); int genreId = numbers.get(0); //Get value, we have to adjust index by one because iTunes labels from one instead of zero content = GenreTypes.getInstanceOf().getValueForId(genreId - 1); //Some apps set genre to invalid value, we dont disguise this by setting content to empty string we leave //as null so apps can handle if they wish, but we do display a warning to make them aware. if (content == null) { logger.warning(ErrorMessage.MP4_GENRE_OUT_OF_RANGE.getMsg(genreId)); } } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/mp4/field/Mp4TagTextField.java0000644000175000017500000000750711247705415027633 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2003-2005 Raphaël Slinckx * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.tag.mp4.field; import org.jaudiotagger.audio.mp4.atom.Mp4BoxHeader; import org.jaudiotagger.tag.TagField; import org.jaudiotagger.tag.TagTextField; import org.jaudiotagger.tag.mp4.Mp4TagField; import org.jaudiotagger.tag.mp4.atom.Mp4DataBox; import java.io.UnsupportedEncodingException; import java.nio.ByteBuffer; /** * Represents a single text field *

*

Mp4 metadata normally held as follows: *

 * MP4Box Parent contains
 *      :length (includes length of data child)  (4 bytes)
 *      :name         (4 bytes)
 *      :child with
 *          :length          (4 bytes)
 *          :name 'Data'     (4 bytes)
 *          :atom version    (1 byte)
 *          :atom type flags (3 bytes)
 *          :null field      (4 bytes)
 *          :data
 * 
*

*

Note:This class is initilized with the child data atom only, the parent data has already been processed, this may * change as it seems that code should probably be enscapulated into this. Whereas the raw content returned by the * getRawContent() contais the byte data for parent and child. */ public class Mp4TagTextField extends Mp4TagField implements TagTextField { protected int dataSize; protected String content; /** * Construct from File * * @param id parent id * @param data atom data * @throws UnsupportedEncodingException */ public Mp4TagTextField(String id, ByteBuffer data) throws UnsupportedEncodingException { super(id, data); } /** * Construct new Field * * @param id parent id * @param content data atom data */ public Mp4TagTextField(String id, String content) { super(id); this.content = content; } protected void build(ByteBuffer data) throws UnsupportedEncodingException { //Data actually contains a 'Data' Box so process data using this Mp4BoxHeader header = new Mp4BoxHeader(data); Mp4DataBox databox = new Mp4DataBox(header, data); dataSize = header.getDataLength(); content = databox.getContent(); } public void copyContent(TagField field) { if (field instanceof Mp4TagTextField) { this.content = ((Mp4TagTextField) field).getContent(); } } public String getContent() { return content; } protected byte[] getDataBytes() throws UnsupportedEncodingException { return content.getBytes(getEncoding()); } public Mp4FieldType getFieldType() { return Mp4FieldType.TEXT; } public String getEncoding() { return Mp4BoxHeader.CHARSET_UTF_8; } public boolean isBinary() { return false; } public boolean isEmpty() { return this.content.trim().equals(""); } public void setContent(String s) { this.content = s; } public void setEncoding(String s) { /* Not allowed */ } public String toString() { return content; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/mp4/atom/0000755000175000017500000000000011556363175023735 5ustar drazzibdrazziblibjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/mp4/atom/Mp4DataBox.java0000644000175000017500000001147311126411643026474 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.mp4.atom; import org.jaudiotagger.audio.generic.Utils; import org.jaudiotagger.audio.mp4.atom.AbstractMp4Box; import org.jaudiotagger.audio.mp4.atom.Mp4BoxHeader; import org.jaudiotagger.tag.mp4.field.Mp4FieldType; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; import java.util.ListIterator; /** * This box is used within both normal metadat boxes and ---- boxes to hold the actual data. *

*

Format is as follows: * :length (4 bytes) * :name 'Data' (4 bytes) * :atom version (1 byte) * :atom type flags (3 bytes) * :locale field (4 bytes) //Currently always zero * :data */ public class Mp4DataBox extends AbstractMp4Box { public static final String IDENTIFIER = "data"; public static final int VERSION_LENGTH = 1; public static final int TYPE_LENGTH = 3; public static final int NULL_LENGTH = 4; public static final int PRE_DATA_LENGTH = VERSION_LENGTH + TYPE_LENGTH + NULL_LENGTH; public static final int DATA_HEADER_LENGTH = Mp4BoxHeader.HEADER_LENGTH + PRE_DATA_LENGTH; public static final int TYPE_POS = VERSION_LENGTH; //For use externally public static final int TYPE_POS_INCLUDING_HEADER = Mp4BoxHeader.HEADER_LENGTH + TYPE_POS; private int type; private String content; public static final int NUMBER_LENGTH = 2; //Holds the numbers decoded private List numbers; //Holds bytedata for byte fields as is not clear for multibyte fields exactly these should be wrttien private byte[] bytedata; /** * @param header parentHeader info * @param dataBuffer data of box (doesnt include parentHeader data) */ public Mp4DataBox(Mp4BoxHeader header, ByteBuffer dataBuffer) { this.header = header; //Double check if (!header.getId().equals(IDENTIFIER)) { throw new RuntimeException("Unable to process data box because identifier is:" + header.getId()); } //Make slice so operations here don't effect position of main buffer this.dataBuffer = dataBuffer.slice(); //Type type = Utils.getIntBE(this.dataBuffer, Mp4DataBox.TYPE_POS, Mp4DataBox.TYPE_POS + Mp4DataBox.TYPE_LENGTH - 1); if (type == Mp4FieldType.TEXT.getFileClassId()) { content = Utils.getString(this.dataBuffer, PRE_DATA_LENGTH, header.getDataLength() - PRE_DATA_LENGTH, header.getEncoding()); } else if (type == Mp4FieldType.IMPLICIT.getFileClassId()) { numbers = new ArrayList(); for (int i = 0; i < ((header.getDataLength() - PRE_DATA_LENGTH) / NUMBER_LENGTH); i++) { short number = Utils.getShortBE(this.dataBuffer, PRE_DATA_LENGTH + (i * NUMBER_LENGTH), PRE_DATA_LENGTH + (i * NUMBER_LENGTH) + (NUMBER_LENGTH - 1)); numbers.add(number); } //Make String representation (separate values with slash) StringBuffer sb = new StringBuffer(); ListIterator iterator = numbers.listIterator(); while (iterator.hasNext()) { sb.append(iterator.next()); if (iterator.hasNext()) { sb.append("/"); } } content = sb.toString(); } else if (type == Mp4FieldType.INTEGER.getFileClassId()) { //TODO byte data length seems to be 1 for pgap and cpil but 2 for tmpo ? //Create String representation for display content = Utils.getIntBE(this.dataBuffer, PRE_DATA_LENGTH, header.getDataLength() - 1) + ""; //But store data for safer writng back to file bytedata = new byte[header.getDataLength() - PRE_DATA_LENGTH]; int pos = dataBuffer.position(); dataBuffer.position(pos + PRE_DATA_LENGTH); dataBuffer.get(bytedata); dataBuffer.position(pos); } else if (type == Mp4FieldType.COVERART_JPEG.getFileClassId()) { content = Utils.getString(this.dataBuffer, PRE_DATA_LENGTH, header.getDataLength() - PRE_DATA_LENGTH, header.getEncoding()); } } public String getContent() { return content; } public int getType() { return type; } /** * Return numbers, only valid for numeric fields * * @return numbers */ //TODO this is only applicable for numeric databoxes, should we subclass dont know type until start //constructing and we also have Mp4tagTextNumericField class as well public List getNumbers() { return numbers; } /** * Return raw byte data only vaid for byte fields * * @return byte data */ public byte[] getByteData() { return bytedata; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/mp4/atom/Mp4NameBox.java0000644000175000017500000000266711041064726026512 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.mp4.atom; import org.jaudiotagger.audio.generic.Utils; import org.jaudiotagger.audio.mp4.atom.AbstractMp4Box; import org.jaudiotagger.audio.mp4.atom.Mp4BoxHeader; import java.nio.ByteBuffer; /** * This box is used within ---- boxes to hold the data name/descriptor */ public class Mp4NameBox extends AbstractMp4Box { public static final String IDENTIFIER = "name"; private String name; //TODO Are these misnamed, are these version flag bytes or just null bytes public static final int VERSION_LENGTH = 1; public static final int FLAGS_LENGTH = 3; public static final int PRE_DATA_LENGTH = VERSION_LENGTH + FLAGS_LENGTH; /** * @param header parentHeader info * @param dataBuffer data of box (doesnt include parentHeader data) */ public Mp4NameBox(Mp4BoxHeader header, ByteBuffer dataBuffer) { this.header = header; //Double check if (!header.getId().equals(IDENTIFIER)) { throw new RuntimeException("Unable to process name box because identifier is:" + header.getId()); } //Make slice so operations here don't effect position of main buffer this.dataBuffer = dataBuffer.slice(); //issuer this.name = Utils.getString(this.dataBuffer, PRE_DATA_LENGTH, header.getDataLength() - PRE_DATA_LENGTH, header.getEncoding()); } public String getName() { return name; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/mp4/atom/Mp4MeanBox.java0000644000175000017500000000266211041064726026505 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.mp4.atom; import org.jaudiotagger.audio.generic.Utils; import org.jaudiotagger.audio.mp4.atom.AbstractMp4Box; import org.jaudiotagger.audio.mp4.atom.Mp4BoxHeader; import java.nio.ByteBuffer; /** * This box is used within ---- boxes to hold the issuer */ public class Mp4MeanBox extends AbstractMp4Box { public static final String IDENTIFIER = "mean"; private String issuer; //TODO Are these misnamed, are these version flag bytes or just null bytes public static final int VERSION_LENGTH = 1; public static final int FLAGS_LENGTH = 3; public static final int PRE_DATA_LENGTH = VERSION_LENGTH + FLAGS_LENGTH; /** * @param header parentHeader info * @param dataBuffer data of box (doesnt include parentHeader data) */ public Mp4MeanBox(Mp4BoxHeader header, ByteBuffer dataBuffer) { this.header = header; //Double check if (!header.getId().equals(IDENTIFIER)) { throw new RuntimeException("Unable to process data box because identifier is:" + header.getId()); } //Make slice so operations here don't effect position of main buffer this.dataBuffer = dataBuffer.slice(); //issuer this.issuer = Utils.getString(this.dataBuffer, PRE_DATA_LENGTH, header.getDataLength() - PRE_DATA_LENGTH, header.getEncoding()); } public String getIssuer() { return issuer; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/mp4/atom/Mp4ContentTypeValue.java0000644000175000017500000000240111012063133030401 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.mp4.atom; /** * List of valid values for the Content Type (Stik) atom *

*

These are held as a byte field, normally only used for purcahed items, audio files use a stik of one */ public enum Mp4ContentTypeValue { MOVIE("Movie", 0), NORMAL("Normal", 1), AUDIO_BOOK("AudioBook", 2), BOOKMARK("Whacked Bookmark", 5), MUSIC_VIDEO("Music Video", 6), SHORT_FILM("Short Film", 9), TV_SHOW("TV Show", 10), BOOKLET("Booklet", 11); private String description; private int id; /** * @param description of value * @param id used internally */ Mp4ContentTypeValue(String description, int id) { this.description = description; this.id = id; } /** * Return id used in the file * * @return id */ public int getId() { return id; } /** * @return the id as a string (convenience method for use with mp4.createtagField() */ public String getIdAsString() { return String.valueOf(id); } /** * This is the value of the fieldname that is actually used to write mp4 * * @return */ public String getDescription() { return description; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/mp4/atom/Mp4RatingValue.java0000644000175000017500000000153310736454526027404 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.mp4.atom; /** * List of valid values for the Rating (rtng) atom *

* These are held as a byte field *

* TODO:Is this only used in video */ public enum Mp4RatingValue { CLEAN("Clean", 2), EXPLICIT("Explicit", 4); private String description; private int id; /** * @param description of value * @param id used internally */ Mp4RatingValue(String description, int id) { this.description = description; this.id = id; } /** * Return id used in the file * * @return id */ public int getId() { return id; } /** * This is the value of the fieldname that is actually used to write mp4 * * @return */ public String getDescription() { return description; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/mp4/Mp4NonStandardFieldKey.java0000644000175000017500000000277510736454526030064 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.mp4; import org.jaudiotagger.tag.reference.Tagger; /** * This a list of mp4boxes identifiers that break various rules, but should be documented nonetheless, they will * be created by applications other than iTunes, as we regard iTunes as the defacto standard for Mp4 files (but * certainly not any other format such as mp3 !). */ public enum Mp4NonStandardFieldKey { AAPR("AApr", "MM3 Album Art Attributes", Tagger.MEDIA_MONKEY), ALFN("Alfn", "MM3 Album Art Unknown", Tagger.MEDIA_MONKEY), AMIM("AMIM", "MM3 Album Art MimeType", Tagger.MEDIA_MONKEY), ADCP("Adcp", "MM3 Album Art Description", Tagger.MEDIA_MONKEY), APTY("Apty", "MM3 Album Art ID3 Picture Type", Tagger.MEDIA_MONKEY); private String fieldName; private String description; private Tagger tagger; Mp4NonStandardFieldKey(String fieldName, String description, Tagger tagger) { this.fieldName = fieldName; this.description = description; this.tagger = tagger; } /** * This is the value of the fieldname that is actually used to write mp4 * * @return */ public String getFieldName() { return fieldName; } /** * @return description, human redable description of the atom */ public String getDescription() { return description; } /** * @return tagger that defined (and probably craeted) instance of field */ public Tagger geTagger() { return tagger; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/mp4/Mp4FieldKey.java0000644000175000017500000003412011470746136025712 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.mp4; import org.jaudiotagger.tag.mp4.field.Mp4FieldType; import static org.jaudiotagger.tag.mp4.field.Mp4FieldType.*; import org.jaudiotagger.tag.mp4.field.Mp4TagReverseDnsField; import org.jaudiotagger.tag.reference.Tagger; /** * Starting list of known mp4 metadata fields that follow the Parent,Data or ---,issuer,name,data * convention. Atoms that contain metadata in other formats are not listed here because they need to be processed * specially. * *

*

Simple metaitems use the parent atom id as their identifier whereas reverse dns (----) atoms use * the reversedns,issuer and name fields as their identifier. When the atom is non-0standard but follws the rules * we list it here with an additional Tagger field to indicate where the field was originally designed. *

* From: * http://www.hydrogenaudio.org/forums/index.php?showtopic=29120&st=0&p=251686&#entry251686 * http://wiki.musicbrainz.org/PicardQt/TagMapping * http://atomicparsley.sourceforge.net/mpeg-4files.html *

*

*/ public enum Mp4FieldKey { ARTIST("©ART",Mp4TagFieldSubType.TEXT, TEXT), ALBUM("©alb",Mp4TagFieldSubType.TEXT, TEXT), ALBUM_ARTIST("aART",Mp4TagFieldSubType.TEXT, TEXT), GENRE_CUSTOM("©gen",Mp4TagFieldSubType.TEXT, TEXT), GENRE("gnre",Mp4TagFieldSubType.GENRE, IMPLICIT), TITLE("©nam",Mp4TagFieldSubType.TEXT, TEXT), TRACK("trkn",Mp4TagFieldSubType.TRACK_NO, IMPLICIT), BPM("tmpo",Mp4TagFieldSubType.BYTE, INTEGER, 2), DAY("©day",Mp4TagFieldSubType.TEXT, TEXT), COMMENT("©cmt",Mp4TagFieldSubType.TEXT, TEXT), COMPOSER("©wrt",Mp4TagFieldSubType.TEXT, TEXT), GROUPING("©grp",Mp4TagFieldSubType.TEXT, TEXT), DISCNUMBER("disk",Mp4TagFieldSubType.DISC_NO, IMPLICIT), LYRICS("©lyr",Mp4TagFieldSubType.TEXT, TEXT), RATING("rtng",Mp4TagFieldSubType.BYTE, INTEGER,1), //AFAIK Cant be setField in itunes, but if setField to explicit itunes will show as explicit ENCODER("©too",Mp4TagFieldSubType.TEXT, TEXT), COMPILATION("cpil",Mp4TagFieldSubType.BYTE, INTEGER, 1), COPYRIGHT("cprt",Mp4TagFieldSubType.TEXT, TEXT), CATEGORY("catg",Mp4TagFieldSubType.TEXT, TEXT), KEYWORD("keyw",Mp4TagFieldSubType.TEXT, TEXT), DESCRIPTION("desc",Mp4TagFieldSubType.TEXT, TEXT), ARTIST_SORT("soar",Mp4TagFieldSubType.TEXT, TEXT), ALBUM_ARTIST_SORT("soaa",Mp4TagFieldSubType.TEXT, TEXT), ALBUM_SORT("soal",Mp4TagFieldSubType.TEXT, TEXT), TITLE_SORT("sonm",Mp4TagFieldSubType.TEXT, TEXT), COMPOSER_SORT("soco",Mp4TagFieldSubType.TEXT, TEXT), SHOW_SORT("sosn",Mp4TagFieldSubType.TEXT, TEXT), SHOW("tvsh",Mp4TagFieldSubType.TEXT, TEXT), //tv show but also used just as show ARTWORK("covr",Mp4TagFieldSubType.ARTWORK, COVERART_JPEG), PURCHASE_DATE("purd",Mp4TagFieldSubType.TEXT, TEXT), MUSICBRAINZ_ARTISTID("com.apple.iTunes", "MusicBrainz Artist Id", TEXT, Tagger.PICARD), MUSICBRAINZ_ALBUMID("com.apple.iTunes", "MusicBrainz Album Id", TEXT, Tagger.PICARD), MUSICBRAINZ_ALBUMARTISTID("com.apple.iTunes", "MusicBrainz Album Artist Id", TEXT, Tagger.PICARD), MUSICBRAINZ_RELEASE_GROUPID("com.apple.iTunes", "MusicBrainz Release Group Id", TEXT, Tagger.PICARD), MUSICBRAINZ_TRACKID("com.apple.iTunes", "MusicBrainz Track Id", TEXT, Tagger.PICARD), MUSICBRAINZ_WORKID("com.apple.iTunes", "MusicBrainz Work Id", TEXT, Tagger.PICARD), MUSICBRAINZ_DISCID("com.apple.iTunes", "MusicBrainz Disc Id", TEXT, Tagger.PICARD), MUSICIP_PUID("com.apple.iTunes", "MusicIP PUID", TEXT, Tagger.PICARD), ASIN("com.apple.iTunes", "ASIN", TEXT, Tagger.PICARD), MUSICBRAINZ_ALBUM_STATUS("com.apple.iTunes", "MusicBrainz Album Status", TEXT, Tagger.PICARD), MUSICBRAINZ_ALBUM_TYPE("com.apple.iTunes", "MusicBrainz Album Type", TEXT, Tagger.PICARD), RELEASECOUNTRY("com.apple.iTunes", "MusicBrainz Album Release Country", TEXT, Tagger.PICARD), PART_OF_GAPLESS_ALBUM("pgap",Mp4TagFieldSubType.BYTE, INTEGER), ITUNES_SMPB("com.apple.iTunes", "iTunSMPB", TEXT), ITUNES_NORM("com.apple.iTunes", "iTunNORM", TEXT), CDDB_1("com.apple.iTunes", "iTunes_CDDB_1", TEXT), CDDB_TRACKNUMBER("com.apple.iTunes", "iTunes_CDDB_TrackNumber", TEXT), CDDB_IDS("com.apple.iTunes", "iTunes_CDDB_IDs", TEXT), LANGUAGE("com.apple.iTunes", "LANGUAGE", TEXT, Tagger.JAIKOZ), KEY("com.apple.iTunes", "KEY", TEXT, Tagger.JAIKOZ), FBPM("com.apple.iTunes", "fBPM", TEXT, Tagger.JAIKOZ), //AFAIK These arent actually used by Audio Only files, but there is nothing to prevent them being used CONTENT_TYPE("stik",Mp4TagFieldSubType.BYTE, INTEGER, 1), TOOL("tool",Mp4TagFieldSubType.BYTE, INTEGER, 4), PODCAST_KEYWORD("keyw",Mp4TagFieldSubType.TEXT, TEXT), PODCAST_URL("purl",Mp4TagFieldSubType.NUMBER, IMPLICIT), //TODO Actually seems to store text but is marked as numeric! EPISODE_GLOBAL_ID("egid",Mp4TagFieldSubType.NUMBER, IMPLICIT), //TODO Actually seems to store text but is marked as numeric! TV_NETWORK("tvnn",Mp4TagFieldSubType.TEXT, TEXT), TV_EPISODE_NUMBER("tven",Mp4TagFieldSubType.TEXT, TEXT), TV_SEASON("tvsn",Mp4TagFieldSubType.BYTE, INTEGER, 1), TV_EPISODE("tves",Mp4TagFieldSubType.BYTE, INTEGER, 1), //These seem to be used in DRM Files, of type byte , we need to know the byte length to allow them to be written //back correctly on saving them, we don't provides options to modify them as may break drm AP_ID("apID",Mp4TagFieldSubType.UNKNOWN, TEXT), AT_ID("atID",Mp4TagFieldSubType.UNKNOWN, INTEGER, 4), CN_ID("cnID",Mp4TagFieldSubType.UNKNOWN, INTEGER, 4), PL_ID("plID",Mp4TagFieldSubType.UNKNOWN, INTEGER, 8), GE_ID("geID",Mp4TagFieldSubType.UNKNOWN, INTEGER, 4), SF_ID("sfID",Mp4TagFieldSubType.UNKNOWN, INTEGER, 4), AK_ID("akID",Mp4TagFieldSubType.UNKNOWN, INTEGER, 1), //Media Monkey3 beta LYRICIST_MM3BETA("lyrc",Mp4TagFieldSubType.TEXT, TEXT, Tagger.MEDIA_MONKEY), CONDUCTOR_MM3BETA("cond",Mp4TagFieldSubType.TEXT, TEXT, Tagger.MEDIA_MONKEY), ISRC_MMBETA("isrc",Mp4TagFieldSubType.TEXT, TEXT, Tagger.MEDIA_MONKEY), MOOD_MM3BETA("mood",Mp4TagFieldSubType.TEXT, TEXT, Tagger.MEDIA_MONKEY), SCORE("rate",Mp4TagFieldSubType.TEXT, TEXT, Tagger.MEDIA_MONKEY), //As in mark out of 100 ORIGINAL_ARTIST("oart",Mp4TagFieldSubType.TEXT, TEXT, Tagger.MEDIA_MONKEY), ORIGINAL_ALBUM_TITLE("otit",Mp4TagFieldSubType.TEXT, TEXT, Tagger.MEDIA_MONKEY), ORIGINAL_LYRICIST("olyr",Mp4TagFieldSubType.TEXT, TEXT, Tagger.MEDIA_MONKEY), INVOLVED_PEOPLE("peop",Mp4TagFieldSubType.TEXT, TEXT, Tagger.MEDIA_MONKEY), TEMPO("empo",Mp4TagFieldSubType.TEXT, TEXT, Tagger.MEDIA_MONKEY), OCCASION("occa",Mp4TagFieldSubType.TEXT, TEXT, Tagger.MEDIA_MONKEY), QUALITY("qual",Mp4TagFieldSubType.TEXT, TEXT, Tagger.MEDIA_MONKEY), CUSTOM_1("cus1",Mp4TagFieldSubType.TEXT, TEXT, Tagger.MEDIA_MONKEY), CUSTOM_2("cus2",Mp4TagFieldSubType.TEXT, TEXT, Tagger.MEDIA_MONKEY), CUSTOM_3("cus3",Mp4TagFieldSubType.TEXT, TEXT, Tagger.MEDIA_MONKEY), CUSTOM_4("cus4",Mp4TagFieldSubType.TEXT, TEXT, Tagger.MEDIA_MONKEY), CUSTOM_5("cus5",Mp4TagFieldSubType.TEXT, TEXT, Tagger.MEDIA_MONKEY), //Media Monkey 3.0.6 Onwards MM_PUBLISHER("com.apple.iTunes", "ORGANIZATION", TEXT, Tagger.MEDIA_MONKEY), MM_ORIGINAL_ARTIST("com.apple.iTunes", "ORIGINAL ARTIST", TEXT, Tagger.MEDIA_MONKEY), MM_ORIGINAL_ALBUM_TITLE("com.apple.iTunes", "ORIGINAL ALBUM", TEXT, Tagger.MEDIA_MONKEY), MM_ORIGINAL_LYRICIST("com.apple.iTunes", "ORIGINAL LYRICIST", TEXT, Tagger.MEDIA_MONKEY), MM_INVOLVED_PEOPLE("com.apple.iTunes", "INVOLVED PEOPLE", TEXT, Tagger.MEDIA_MONKEY), MM_ORIGINAL_YEAR("com.apple.iTunes", "ORIGINAL YEAR", TEXT, Tagger.MEDIA_MONKEY), MM_TEMPO("com.apple.iTunes", "TEMPO", TEXT, Tagger.MEDIA_MONKEY), MM_OCCASION("com.apple.iTunes", "OCCASION", TEXT, Tagger.MEDIA_MONKEY), MM_QUALITY("com.apple.iTunes", "QUALITY", TEXT, Tagger.MEDIA_MONKEY), MM_CUSTOM_1("com.apple.iTunes", "CUSTOM1", TEXT, Tagger.MEDIA_MONKEY), MM_CUSTOM_2("com.apple.iTunes", "CUSTOM2", TEXT, Tagger.MEDIA_MONKEY), MM_CUSTOM_3("com.apple.iTunes", "CUSTOM3", TEXT, Tagger.MEDIA_MONKEY), MM_CUSTOM_4("com.apple.iTunes", "CUSTOM4", TEXT, Tagger.MEDIA_MONKEY), MM_CUSTOM_5("com.apple.iTunes", "CUSTOM5", TEXT, Tagger.MEDIA_MONKEY), //Picard Qt LYRICIST("com.apple.iTunes", "LYRICIST", TEXT, Tagger.PICARD), CONDUCTOR("com.apple.iTunes", "CONDUCTOR", TEXT, Tagger.PICARD), REMIXER("com.apple.iTunes", "REMIXER", TEXT, Tagger.PICARD), ENGINEER("com.apple.iTunes", "ENGINEER", TEXT, Tagger.PICARD), PRODUCER("com.apple.iTunes", "PRODUCER", TEXT, Tagger.PICARD), DJMIXER("com.apple.iTunes", "DJMIXER", TEXT, Tagger.PICARD), MIXER("com.apple.iTunes", "MIXER", TEXT, Tagger.PICARD), ARRANGER("com.apple.iTunes", "ARRANGER", TEXT, Tagger.PICARD), MOOD("com.apple.iTunes", "MOOD", TEXT, Tagger.PICARD), ISRC("com.apple.iTunes", "ISRC", TEXT, Tagger.PICARD), MEDIA("com.apple.iTunes", "MEDIA", TEXT, Tagger.PICARD), LABEL("com.apple.iTunes", "LABEL", TEXT, Tagger.PICARD), CATALOGNO("com.apple.iTunes", "CATALOGNUMBER", TEXT, Tagger.PICARD), BARCODE("com.apple.iTunes", "BARCODE", TEXT, Tagger.PICARD), //Jaikoz URL_LYRICS_SITE("com.apple.iTunes", "URL_LYRICS_SITE", TEXT, Tagger.JAIKOZ), URL_OFFICIAL_RELEASE_SITE("com.apple.iTunes", "URL_OFFICIAL_RELEASE_SITE", TEXT, Tagger.JAIKOZ), URL_DISCOGS_RELEASE_SITE("com.apple.iTunes", "URL_DISCOGS_RELEASE_SITE", TEXT, Tagger.JAIKOZ), URL_WIKIPEDIA_RELEASE_SITE("com.apple.iTunes", "URL_WIKIPEDIA_RELEASE_SITE", TEXT, Tagger.JAIKOZ), URL_OFFICIAL_ARTIST_SITE("com.apple.iTunes", "URL_OFFICIAL_ARTIST_SITE", TEXT, Tagger.JAIKOZ), URL_DISCOGS_ARTIST_SITE("com.apple.iTunes", "URL_DISCOGS_ARTIST_SITE", TEXT, Tagger.JAIKOZ), URL_WIKIPEDIA_ARTIST_SITE("com.apple.iTunes", "URL_WIKIPEDIA_ARTIST_SITE", TEXT, Tagger.JAIKOZ), SCRIPT("com.apple.iTunes", "SCRIPT", TEXT, Tagger.JAIKOZ), TAGS("com.apple.iTunes", "TAGS", TEXT, Tagger.JAIKOZ), //Winamp WINAMP_PUBLISHER("com.nullsoft.winamp", "publisher", TEXT, Tagger.WINAMP), //Unknown KEYS("keys",Mp4TagFieldSubType.TEXT,TEXT), ; private Tagger tagger; private String fieldName; private Mp4TagFieldSubType subclassType; private String issuer; private String identifier; private Mp4FieldType fieldType; private int fieldLength; /** * For usual metadata fields that use a data field * * @param fieldName * @param fieldType of data atom */ Mp4FieldKey(String fieldName, Mp4TagFieldSubType subclassType, Mp4FieldType fieldType) { this.fieldName = fieldName; this.subclassType = subclassType; this.fieldType = fieldType; } /** * For usual metadata fields that use a data field, but not recognised as standard field * * @param fieldName * @param fieldType of data atom * @param tagger */ Mp4FieldKey(String fieldName, Mp4TagFieldSubType subclassType,Mp4FieldType fieldType, Tagger tagger) { this.fieldName = fieldName; this.subclassType = subclassType; this.fieldType = fieldType; this.tagger = tagger; } /** * For usual metadata fields that use a data field where the field length is fixed * such as Byte fields * * @param fieldName * @param fieldType * @param fieldLength */ Mp4FieldKey(String fieldName, Mp4TagFieldSubType subclassType,Mp4FieldType fieldType, int fieldLength) { this.fieldName = fieldName; this.subclassType = subclassType; this.fieldType = fieldType; this.fieldLength = fieldLength; } /** * For reverse dns fields that use an internal fieldname of '----' and have additional issuer * and identifier fields, we use all three seperated by a ':' ) to give us a unique key * * @param issuer * @param identifier * @param fieldType of data atom */ Mp4FieldKey(String issuer, String identifier, Mp4FieldType fieldType) { this.issuer = issuer; this.identifier = identifier; this.fieldName = Mp4TagReverseDnsField.IDENTIFIER + ":" + issuer + ":" + identifier; this.subclassType = Mp4TagFieldSubType.REVERSE_DNS; this.fieldType = fieldType; } /** * For reverse dns fields that use an internal fieldname of '----' and have additional issuer * and identifier fields, we use all three seperated by a ':' ) to give us a unique key * For non-standard fields * * @param issuer * @param identifier * @param fieldType of data atom * @param tagger */ Mp4FieldKey(String issuer, String identifier, Mp4FieldType fieldType, Tagger tagger) { this.issuer = issuer; this.identifier = identifier; this.fieldName = Mp4TagReverseDnsField.IDENTIFIER + ":" + issuer + ":" + identifier; this.subclassType = Mp4TagFieldSubType.REVERSE_DNS; this.fieldType = fieldType; this.tagger = tagger; } /** * This is the value of the fieldname that is actually used to write mp4 * * @return */ public String getFieldName() { return fieldName; } /** * @return fieldtype */ public Mp4FieldType getFieldType() { return fieldType; } /** * @return subclassType */ public Mp4TagFieldSubType getSubClassFieldType() { return subclassType; } /** * @return true if this is a reverse dns key */ public boolean isReverseDnsType() { return identifier.startsWith(Mp4TagReverseDnsField.IDENTIFIER); } /** * @return issuer (Reverse Dns Fields Only) */ public String getIssuer() { return issuer; } /** * @return identifier (Reverse Dns Fields Only) */ public String getIdentifier() { return identifier; } /** * @return field length (currently only used by byte fields) */ public int getFieldLength() { return fieldLength; } public Tagger getTagger() { if (tagger != null) { return tagger; } return Tagger.ITUNES; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/mp4/Mp4TagCreator.java0000644000175000017500000001352611276777123026264 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2003-2005 Raphaël Slinckx * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.tag.mp4; import org.jaudiotagger.audio.generic.AbstractTagCreator; import org.jaudiotagger.audio.generic.Utils; import org.jaudiotagger.audio.mp4.Mp4NotMetaFieldKey; import org.jaudiotagger.audio.mp4.atom.Mp4BoxHeader; import org.jaudiotagger.tag.FieldKey; import org.jaudiotagger.tag.KeyNotFoundException; import org.jaudiotagger.tag.Tag; import org.jaudiotagger.tag.TagField; import org.jaudiotagger.tag.mp4.field.Mp4TagCoverField; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.nio.ByteBuffer; import java.util.Iterator; /** * Create raw content of mp4 tag data, concerns itself with atoms upto the ilst atom *

*

This level is was selected because the ilst atom can be recreated without reference to existing mp4 fields * but fields above this level are dependent upon other information that is not held in the tag. *

*

 * |--- ftyp
 * |--- moov
 * |......|
 * |......|----- mvdh
 * |......|----- trak
 * |......|----- udta
 * |..............|
 * |..............|-- meta
 * |....................|
 * |....................|-- hdlr
 * |....................|-- ilst
 * |....................|.. ..|
 * |....................|.....|---- @nam (Optional for each metadatafield)
 * |....................|.....|.......|-- data
 * |....................|.....|....... ecetera
 * |....................|.....|---- ---- (Optional for reverse dns field)
 * |....................|.............|-- mean
 * |....................|.............|-- name
 * |....................|.............|-- data
 * |....................|................ ecetere
 * |....................|-- free
 * |--- free
 * |--- mdat
 * 
*/ public class Mp4TagCreator extends AbstractTagCreator { /** * Convert tagdata to rawdata ready for writing to file * * @param tag * @param padding TODO padding parameter currently ignored * @return * @throws UnsupportedEncodingException */ public ByteBuffer convert(Tag tag, int padding) throws UnsupportedEncodingException { try { //Add metadata raw content ByteArrayOutputStream baos = new ByteArrayOutputStream(); Iterator it = tag.getFields(); boolean processedArtwork = false; while (it.hasNext()) { TagField frame = it.next(); //To ensure order is maintained dont process artwork until iterator hits it. if (frame instanceof Mp4TagCoverField) { if (processedArtwork) { //ignore } else { processedArtwork = true; //Because each artwork image is held within the tag as a seperate field, but when //they are written they are all held under a single covr box we need to do some checks //and special processing here if we have any artwork image (this code only neccessary //if we have more than 1 but do it anyway even if only have 1 image) ByteArrayOutputStream covrDataBaos = new ByteArrayOutputStream(); try { for (TagField artwork : tag.getFields(FieldKey.COVER_ART)) { covrDataBaos.write(((Mp4TagField) artwork).getRawContentDataOnly()); } } catch (KeyNotFoundException knfe) { //This cannot happen throw new RuntimeException("Unable to find COVERART Key"); } //Now create the parent Data byte[] data = covrDataBaos.toByteArray(); baos.write(Utils.getSizeBEInt32(Mp4BoxHeader.HEADER_LENGTH + data.length)); baos.write(Utils.getDefaultBytes(Mp4FieldKey.ARTWORK.getFieldName(), "ISO-8859-1")); baos.write(data); } } else { baos.write(frame.getRawContent()); } } //Wrap into ilst box ByteArrayOutputStream ilst = new ByteArrayOutputStream(); ilst.write(Utils.getSizeBEInt32(Mp4BoxHeader.HEADER_LENGTH + baos.size())); ilst.write(Utils.getDefaultBytes(Mp4NotMetaFieldKey.ILST.getFieldName(), "ISO-8859-1")); ilst.write(baos.toByteArray()); //Put into ByteBuffer ByteBuffer buf = ByteBuffer.wrap(ilst.toByteArray()); buf.rewind(); return buf; } catch (IOException ioe) { //Should never happen as not writing to file at this point throw new RuntimeException(ioe); } } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/mp4/Mp4TagField.java0000644000175000017500000001467611247705415025710 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2003-2005 Raphaël Slinckx * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.tag.mp4; import org.jaudiotagger.audio.generic.Utils; import org.jaudiotagger.audio.mp4.atom.Mp4BoxHeader; import org.jaudiotagger.tag.TagField; import org.jaudiotagger.tag.mp4.atom.Mp4DataBox; import org.jaudiotagger.tag.mp4.field.Mp4FieldType; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.nio.ByteBuffer; import java.util.logging.Logger; /** * This abstract class represents a link between piece of data, and how it is stored as an mp4 atom *

* Note there isnt a one to one correspondance between a tag field and a box because some fields are represented * by multiple boxes, for example many of the MusicBrainz fields use the '----' box, which in turn uses one of mean, * name and data box. So an instance of a tag field maps to one item of data such as 'Title', but it may have to read * multiple boxes to do this. *

* There are various subclasses that represent different types of fields */ public abstract class Mp4TagField implements TagField { // Logger Object public static Logger logger = Logger.getLogger("org.jaudiotagger.tag.mp4"); protected String id; //Just used by reverese dns class, so it knows the size of its aprent so it can detect end correctly protected Mp4BoxHeader parentHeader; protected Mp4TagField(String id) { this.id = id; } /** * Used by subclasses that canot identify their id until after they have been built such as ReverseDnsField * * @param data * @throws UnsupportedEncodingException */ protected Mp4TagField(ByteBuffer data) throws UnsupportedEncodingException { build(data); } /** * Used by reverese dns when reading from file, so can identify when there is a data atom * * @param parentHeader * @param data * @throws UnsupportedEncodingException */ protected Mp4TagField(Mp4BoxHeader parentHeader, ByteBuffer data) throws UnsupportedEncodingException { this.parentHeader = parentHeader; build(data); } protected Mp4TagField(String id, ByteBuffer data) throws UnsupportedEncodingException { this(id); build(data); } /** * @return field identifier */ public String getId() { return id; } public void isBinary(boolean b) { /* One cannot choose if an arbitrary block can be binary or not */ } public boolean isCommon() { return id.equals(Mp4FieldKey.ARTIST.getFieldName()) || id.equals(Mp4FieldKey.ALBUM.getFieldName()) || id.equals(Mp4FieldKey.TITLE.getFieldName()) || id.equals(Mp4FieldKey.TRACK.getFieldName()) || id.equals(Mp4FieldKey.DAY.getFieldName()) || id.equals(Mp4FieldKey.COMMENT.getFieldName()) || id.equals(Mp4FieldKey.GENRE.getFieldName()); } /** * @return field identifier as it will be held within the file */ protected byte[] getIdBytes() { return Utils.getDefaultBytes(getId(), "ISO-8859-1"); } /** * @return the data as it is held on file * @throws UnsupportedEncodingException */ protected abstract byte[] getDataBytes() throws UnsupportedEncodingException; /** * @return the field type of this field */ public abstract Mp4FieldType getFieldType(); /** * Processes the data and sets the position of the data buffer to just after the end of this fields data * ready for processing next field. * * @param data * @throws UnsupportedEncodingException */ protected abstract void build(ByteBuffer data) throws UnsupportedEncodingException; /** * Convert back to raw content, includes parent and data atom as views as one thing externally * * @return * @throws UnsupportedEncodingException */ public byte[] getRawContent() throws UnsupportedEncodingException { logger.fine("Getting Raw data for:" + getId()); try { //Create Data Box byte[] databox = getRawContentDataOnly(); //Wrap in Parent box ByteArrayOutputStream outerbaos = new ByteArrayOutputStream(); outerbaos.write(Utils.getSizeBEInt32(Mp4BoxHeader.HEADER_LENGTH + databox.length)); outerbaos.write(Utils.getDefaultBytes(getId(), "ISO-8859-1")); outerbaos.write(databox); return outerbaos.toByteArray(); } catch (IOException ioe) { //This should never happen as were not actually writing to/from a file throw new RuntimeException(ioe); } } /** * Get raw content for the data component only * * @return * @throws UnsupportedEncodingException */ public byte[] getRawContentDataOnly() throws UnsupportedEncodingException { logger.fine("Getting Raw data for:" + getId()); try { //Create Data Box ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte[] data = getDataBytes(); baos.write(Utils.getSizeBEInt32(Mp4DataBox.DATA_HEADER_LENGTH + data.length)); baos.write(Utils.getDefaultBytes(Mp4DataBox.IDENTIFIER, "ISO-8859-1")); baos.write(new byte[]{0}); baos.write(new byte[]{0, 0, (byte) getFieldType().getFileClassId()}); baos.write(new byte[]{0, 0, 0, 0}); baos.write(data); return baos.toByteArray(); } catch (IOException ioe) { //This should never happen as were not actually writing to/from a file throw new RuntimeException(ioe); } } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/mp4/Mp4TagFieldSubType.java0000644000175000017500000000064611470746136027217 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.mp4; /** * Defines the available types of Mp4TagField, this simplifies Mp4 code because when we add a new Mp4FieldKey we can * define the correct type instead of having to add additional code to Mp4tag.createField method */ public enum Mp4TagFieldSubType { TEXT, BYTE, NUMBER, REVERSE_DNS, GENRE, DISC_NO, TRACK_NO, ARTWORK, UNKNOWN } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/ImageHandling.java0000644000175000017500000001006411277026507025623 0ustar drazzibdrazzibpackage org.jaudiotagger.tag; import org.jaudiotagger.tag.datatype.Artwork; import org.jaudiotagger.tag.id3.valuepair.ImageFormats; import javax.imageio.ImageIO; import javax.imageio.ImageWriter; import java.awt.*; import java.awt.geom.AffineTransform; import java.awt.image.BufferedImage; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.Iterator; /** * User: paul * Date: 11-Dec-2008 */ public class ImageHandling { /** * Resize the image until the total size require to store the image is less than maxsize * @param artwork * @param maxSize * @throws IOException */ public static void reduceQuality(Artwork artwork, int maxSize) throws IOException { while(artwork.getBinaryData().length > maxSize) { Image srcImage = artwork.getImage(); int w = srcImage.getWidth(null); int newSize = w /2; makeSmaller(artwork,newSize); } } /** * Resize image using Java 2D * @param artwork * @param size * @throws java.io.IOException */ private static void makeSmaller(Artwork artwork,int size) throws IOException { Image srcImage = artwork.getImage(); int w = srcImage.getWidth(null); int h = srcImage.getHeight(null); // Determine the scaling required to get desired result. float scaleW = (float) size / (float) w; float scaleH = (float) size / (float) h; //Create an image buffer in which to paint on, create as an opaque Rgb type image, it doesnt matter what type //the original image is we want to convert to the best type for displaying on screen regardless BufferedImage bi = new BufferedImage(size, size, BufferedImage.TYPE_INT_RGB); // Set the scale. AffineTransform tx = new AffineTransform(); tx.scale(scaleW, scaleH); // Paint image. Graphics2D g2d = bi.createGraphics(); g2d.drawImage(srcImage, tx, null); g2d.dispose(); if(artwork.getMimeType()!=null && isMimeTypeWritable(artwork.getMimeType())) { artwork.setBinaryData(writeImage(bi,artwork.getMimeType())); } else { artwork.setBinaryData(writeImageAsPng(bi)); } } public static boolean isMimeTypeWritable(String mimeType) { Iterator writers = ImageIO.getImageWritersByMIMEType(mimeType); return writers.hasNext(); } /** * Write buffered image as required format * * @param bi * @param mimeType * @return * @throws IOException */ public static byte[] writeImage(BufferedImage bi,String mimeType) throws IOException { Iterator writers = ImageIO.getImageWritersByMIMEType(mimeType); if(writers.hasNext()) { ImageWriter writer = writers.next(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); writer.setOutput(ImageIO.createImageOutputStream(baos)); writer.write(bi); return baos.toByteArray(); } throw new IOException("Cannot write to this mimetype"); } /** * * @param bi * @return * @throws IOException */ public static byte[] writeImageAsPng(BufferedImage bi) throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); ImageIO.write(bi, ImageFormats.MIME_TYPE_PNG,baos); return baos.toByteArray(); } /** * Show read formats * * On Windows supports png/jpeg/bmp/gif */ public static void showReadFormats() { String[] formats = ImageIO.getReaderMIMETypes(); for(String f:formats) { System.out.println("r"+f); } } /** * Show write formats * * On Windows supports png/jpeg/bmp */ public static void showWriteFormats() { String[] formats = ImageIO.getWriterMIMETypes(); for(String f:formats) { System.out.println(f); } } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/FieldKey.java0000644000175000017500000000311711470746136024633 0ustar drazzibdrazzibpackage org.jaudiotagger.tag; /** * This is an enumeration of fields implemented by all major formats *

*

*

* This enumeration is used by subclasses to map from the common key to their implementation key, the keys * are grouped within EnumSets within Tag class. */ public enum FieldKey { ALBUM, ALBUM_ARTIST, ALBUM_ARTIST_SORT, ALBUM_SORT, AMAZON_ID, ARTIST, ARTIST_SORT, BARCODE, BPM, CATALOG_NO, COMMENT, COMPOSER, COMPOSER_SORT, CONDUCTOR, COVER_ART, CUSTOM1, CUSTOM2, CUSTOM3, CUSTOM4, CUSTOM5, DISC_NO, DISC_TOTAL, ENCODER, FBPM, GENRE, GROUPING, ISRC, IS_COMPILATION, KEY, LANGUAGE, LYRICIST, LYRICS, MEDIA, MOOD, MUSICBRAINZ_ARTISTID, MUSICBRAINZ_DISC_ID, MUSICBRAINZ_RELEASEARTISTID, MUSICBRAINZ_RELEASEID, MUSICBRAINZ_RELEASE_COUNTRY, MUSICBRAINZ_RELEASE_GROUP_ID, MUSICBRAINZ_RELEASE_STATUS, MUSICBRAINZ_RELEASE_TYPE, MUSICBRAINZ_TRACK_ID, MUSICBRAINZ_WORK_ID, MUSICIP_ID, OCCASION, ORIGINAL_ALBUM, ORIGINAL_ARTIST, ORIGINAL_LYRICIST, ORIGINAL_YEAR, QUALITY, RATING, RECORD_LABEL, REMIXER, SCRIPT, TAGS, TEMPO, TITLE, TITLE_SORT, TRACK, TRACK_TOTAL, URL_DISCOGS_ARTIST_SITE, URL_DISCOGS_RELEASE_SITE, URL_LYRICS_SITE, URL_OFFICIAL_ARTIST_SITE, URL_OFFICIAL_RELEASE_SITE, URL_WIKIPEDIA_ARTIST_SITE, URL_WIKIPEDIA_RELEASE_SITE, YEAR, ENGINEER, PRODUCER, DJMIXER, MIXER, ARRANGER, ; } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/flac/0000755000175000017500000000000011556363175023202 5ustar drazzibdrazziblibjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/flac/FlacTag.java0000644000175000017500000003351011470746136025345 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.flac; import org.jaudiotagger.audio.flac.metadatablock.MetadataBlockDataPicture; import org.jaudiotagger.audio.generic.Utils; import org.jaudiotagger.tag.*; import org.jaudiotagger.tag.datatype.Artwork; import org.jaudiotagger.tag.id3.valuepair.ImageFormats; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; import org.jaudiotagger.tag.reference.PictureTypes; import org.jaudiotagger.tag.vorbiscomment.VorbisCommentTag; import org.jaudiotagger.tag.vorbiscomment.VorbisCommentFieldKey; import org.jaudiotagger.logging.ErrorMessage; import javax.imageio.ImageIO; import java.awt.image.BufferedImage; import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; /** * Flac uses Vorbis Comment for most of its metadata and a Flac Picture Block for images *

*

* This class enscapulates the items into a single tag */ public class FlacTag implements Tag { private VorbisCommentTag tag = null; private List images = new ArrayList(); public FlacTag(VorbisCommentTag tag, List images) { this.tag = tag; this.images = images; } /** * @return images */ public List getImages() { return images; } /** * @return the vorbis tag (this is what handles text metadata) */ public VorbisCommentTag getVorbisCommentTag() { return tag; } public void addField(TagField field) throws FieldDataInvalidException { if (field instanceof MetadataBlockDataPicture) { images.add((MetadataBlockDataPicture) field); } else { tag.addField(field); } } public List getFields(String id) { if (id.equals(FieldKey.COVER_ART.name())) { List castImages = new ArrayList(); for (MetadataBlockDataPicture image : images) { castImages.add(image); } return castImages; } else { return tag.getFields(id); } } public boolean hasCommonFields() { return tag.hasCommonFields(); } public boolean hasField(String id) { if (id.equals(FieldKey.COVER_ART.name())) { return images.size() > 0; } else { return tag.hasField(id); } } /** * Determines whether the tag has no fields specified.
*

*

If there are no images we return empty if either there is no VorbisTag or if there is a * VorbisTag but it is empty * * @return true if tag contains no field. */ public boolean isEmpty() { return (tag == null || tag.isEmpty()) && images.size() == 0; } public void setField(FieldKey genericKey, String value) throws KeyNotFoundException, FieldDataInvalidException { TagField tagfield = createField(genericKey,value); setField(tagfield); } public void addField(FieldKey genericKey, String value) throws KeyNotFoundException, FieldDataInvalidException { TagField tagfield = createField(genericKey,value); addField(tagfield); } /** * Create and set field with name of vorbisCommentkey * * @param vorbisCommentKey * @param value * @throws KeyNotFoundException * @throws FieldDataInvalidException */ public void setField(String vorbisCommentKey, String value) throws KeyNotFoundException, FieldDataInvalidException { TagField tagfield = createField(vorbisCommentKey,value); setField(tagfield); } /** * Create and add field with name of vorbisCommentkey * @param vorbisCommentKey * @param value * @throws KeyNotFoundException * @throws FieldDataInvalidException */ public void addField(String vorbisCommentKey, String value) throws KeyNotFoundException, FieldDataInvalidException { TagField tagfield = createField(vorbisCommentKey,value); addField(tagfield); } /** * @param field * @throws FieldDataInvalidException */ public void setField(TagField field) throws FieldDataInvalidException { if (field instanceof MetadataBlockDataPicture) { if (images.size() == 0) { images.add(0, (MetadataBlockDataPicture) field); } else { images.set(0, (MetadataBlockDataPicture) field); } } else { tag.setField(field); } } public TagField createField(FieldKey genericKey, String value) throws KeyNotFoundException, FieldDataInvalidException { if (genericKey.equals(FieldKey.COVER_ART)) { throw new UnsupportedOperationException(ErrorMessage.ARTWORK_CANNOT_BE_CREATED_WITH_THIS_METHOD.getMsg()); } else { return tag.createField(genericKey, value); } } /** * Create Tag Field using ogg key * * @param vorbisCommentFieldKey * @param value * @return * @throws org.jaudiotagger.tag.KeyNotFoundException * @throws org.jaudiotagger.tag.FieldDataInvalidException */ public TagField createField(VorbisCommentFieldKey vorbisCommentFieldKey, String value) throws KeyNotFoundException,FieldDataInvalidException { if (vorbisCommentFieldKey.equals(VorbisCommentFieldKey.COVERART)) { throw new UnsupportedOperationException(ErrorMessage.ARTWORK_CANNOT_BE_CREATED_WITH_THIS_METHOD.getMsg()); } return tag.createField(vorbisCommentFieldKey,value); } /** * Create Tag Field using ogg key *

* This method is provided to allow you to create key of any value because VorbisComment allows * arbitary keys. * * @param vorbisCommentFieldKey * @param value * @return */ public TagField createField(String vorbisCommentFieldKey, String value) { if (vorbisCommentFieldKey.equals(VorbisCommentFieldKey.COVERART.getFieldName())) { throw new UnsupportedOperationException(ErrorMessage.ARTWORK_CANNOT_BE_CREATED_WITH_THIS_METHOD.getMsg()); } return tag.createField(vorbisCommentFieldKey,value); } public String getFirst(String id) { if (id.equals(FieldKey.COVER_ART.name())) { throw new UnsupportedOperationException(ErrorMessage.ARTWORK_CANNOT_BE_CREATED_WITH_THIS_METHOD.getMsg()); } else { return tag.getFirst(id); } } /** * The m parameter is effectively ignored * * @param id * @param n * @param m * @return */ public String getSubValue(FieldKey id, int n, int m) { return getValue(id,n); } public String getValue(FieldKey id,int index) throws KeyNotFoundException { if (id.equals(FieldKey.COVER_ART)) { throw new UnsupportedOperationException(ErrorMessage.ARTWORK_CANNOT_BE_RETRIEVED_WITH_THIS_METHOD.getMsg()); } else { return tag.getValue(id, index); } } public String getFirst(FieldKey id) throws KeyNotFoundException { return getValue(id,0); } public TagField getFirstField(String id) { if (id.equals(FieldKey.COVER_ART.name())) { if (images.size() > 0) { return images.get(0); } else { return null; } } else { return tag.getFirstField(id); } } public TagField getFirstField(FieldKey genericKey) throws KeyNotFoundException { if (genericKey == null) { throw new KeyNotFoundException(); } if(genericKey == FieldKey.COVER_ART ) { return getFirstField(FieldKey.COVER_ART.name()); } else { return tag.getFirstField(genericKey); } } /** * Delete any instance of tag fields with this key * * @param fieldKey */ public void deleteField(FieldKey fieldKey) throws KeyNotFoundException { if (fieldKey.equals(FieldKey.COVER_ART)) { images.clear(); } else { tag.deleteField(fieldKey); } } public void deleteField(String id) throws KeyNotFoundException { if (id.equals(FieldKey.COVER_ART.name())) { images.clear(); } else { tag.deleteField(id); } } //TODO addField images to iterator public Iterator getFields() { return tag.getFields(); } public int getFieldCount() { return tag.getFieldCount() + images.size(); } public int getFieldCountIncludingSubValues() { return getFieldCount(); } public boolean setEncoding(String enc) throws FieldDataInvalidException { return tag.setEncoding(enc); } public List getFields(FieldKey id) throws KeyNotFoundException { if (id.equals(FieldKey.COVER_ART)) { List castImages = new ArrayList(); for (MetadataBlockDataPicture image : images) { castImages.add(image); } return castImages; } else { return tag.getFields(id); } } public TagField createArtworkField(byte[] imageData, int pictureType, String mimeType, String description, int width, int height, int colourDepth, int indexedColouredCount) throws FieldDataInvalidException { return new MetadataBlockDataPicture(imageData, pictureType, mimeType, description, width, height, colourDepth, indexedColouredCount); } /** * Create Artwork when have the bufferedimage * * @param bi * @param pictureType * @param mimeType * @param description * @param colourDepth * @param indexedColouredCount * @return * @throws FieldDataInvalidException */ public TagField createArtworkField(BufferedImage bi, int pictureType, String mimeType, String description, int colourDepth, int indexedColouredCount) throws FieldDataInvalidException { //Convert to byte array try { final ByteArrayOutputStream output = new ByteArrayOutputStream(); ImageIO.write(bi, ImageFormats.getFormatForMimeType(mimeType), new DataOutputStream(output)); //Add to image list return new MetadataBlockDataPicture(output.toByteArray(), pictureType, mimeType, description, bi.getWidth(), bi.getHeight(), colourDepth, indexedColouredCount); } catch (IOException ioe) { throw new FieldDataInvalidException("Unable to convert image to bytearray, check mimetype parameter"); } } /** * Create Link to Image File, not recommended because if either flac or image file is moved link * will be broken. * @param url * @return */ public TagField createLinkedArtworkField(String url) { //Add to image list return new MetadataBlockDataPicture(Utils.getDefaultBytes(url, TextEncoding.CHARSET_ISO_8859_1), PictureTypes.DEFAULT_ID, MetadataBlockDataPicture.IMAGE_IS_URL, "", 0, 0, 0, 0); } /** * Create artwork field * * @return */ public TagField createField(Artwork artwork) throws FieldDataInvalidException { if(artwork.isLinked()) { return new MetadataBlockDataPicture( Utils.getDefaultBytes(artwork.getImageUrl(), TextEncoding.CHARSET_ISO_8859_1), artwork.getPictureType(), MetadataBlockDataPicture.IMAGE_IS_URL, "", 0, 0, 0, 0); } else { BufferedImage image; try { image = artwork.getImage(); } catch(IOException ioe) { throw new FieldDataInvalidException("Unable to createField bufferd image from the image"); } return new MetadataBlockDataPicture(artwork.getBinaryData(), artwork.getPictureType(), artwork.getMimeType(), artwork.getDescription(), image.getWidth(), image.getHeight(), 0, 0); } } public void setField(Artwork artwork) throws FieldDataInvalidException { this.setField(createField(artwork)); } public void addField(Artwork artwork) throws FieldDataInvalidException { this.addField(createField(artwork)); } public List getArtworkList() { List artworkList = new ArrayList(images.size()); for(MetadataBlockDataPicture coverArt:images) { Artwork artwork=Artwork.createArtworkFromMetadataBlockDataPicture(coverArt); artworkList.add(artwork); } return artworkList; } public Artwork getFirstArtwork() { List artwork = getArtworkList(); if(artwork.size()>0) { return artwork.get(0); } return null; } /** * Delete all instance of artwork Field * * @throws KeyNotFoundException */ public void deleteArtworkField() throws KeyNotFoundException { this.deleteField(FieldKey.COVER_ART); } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/vorbiscomment/0000755000175000017500000000000011556363175025164 5ustar drazzibdrazziblibjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/vorbiscomment/VorbisCommentReader.java0000644000175000017500000001347411277006322031736 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2003-2005 Raphaël Slinckx * Copyright (c) 2004-2005 Christian Laireiter * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.tag.vorbiscomment; import org.jaudiotagger.audio.exceptions.CannotReadException; import org.jaudiotagger.audio.generic.Utils; import org.jaudiotagger.audio.ogg.util.VorbisHeader; import org.jaudiotagger.fix.Fix; import org.jaudiotagger.logging.ErrorMessage; import java.io.IOException; import java.util.logging.Logger; /** * Create the VorbisCommentTag by reading from the raw packet data *

*

This is in the same format whether encoded with Ogg or Flac * except the framing bit is only present when used within Ogg Vorbis *

*

 * From the http://xiph.org/vorbis/doc/Vorbis_I_spec.html#vorbis-spec-comment
 * Read decodes the packet data using the following algorithm:
 *  [vendor_length] = read an unsigned integer of 32 bits
 *  [vendor_string] = read a UTF-8 vector as [vendor_length] octets
 *  [user_comment_list_length] = read an unsigned integer of 32 bits
 *  iterate [user_comment_list_length] times {
 *      5) [length] = read an unsigned integer of 32 bits
 *      6) this iteration's user comment = read a UTF-8 vector as [length] octets
 *    }
 *  [framing_bit] = read a single bit as boolean
 *  if ( [framing_bit] unset or end-of-packet ) then ERROR
 *  done.
 * 
*/ public class VorbisCommentReader { // Logger Object public static Logger logger = Logger.getLogger("org.jaudiotagger.tag.vorbiscomment.VorbisCommentReader"); public static final int FIELD_VENDOR_LENGTH_POS = 0; public static final int FIELD_VENDOR_STRING_POS = 4; public static final int FIELD_VENDOR_LENGTH_LENGTH = 4; public static final int FIELD_USER_COMMENT_LIST_LENGTH = 4; public static final int FIELD_COMMENT_LENGTH_LENGTH = 4; private Fix fix; /** * max comment length that jaudiotagger can handle, this isnt the maximum column length allowed but we dont * dont allow comments larger than this because of problem with allocating memory (10MB shoudl be fine for all apps) */ private static final int JAUDIOTAGGER_MAX_COMMENT_LENGTH = 10000000; public VorbisCommentReader() { } public VorbisCommentReader(Fix fix) { this.fix = fix; } /** * @param rawdata * @param isFramingBit * @return logical representation of VorbisCommentTag * @throws IOException * @throws CannotReadException */ public VorbisCommentTag read(byte[] rawdata, boolean isFramingBit) throws IOException, CannotReadException { VorbisCommentTag tag = new VorbisCommentTag(); byte[] b = new byte[FIELD_VENDOR_LENGTH_LENGTH]; System.arraycopy(rawdata, FIELD_VENDOR_LENGTH_POS, b, FIELD_VENDOR_LENGTH_POS, FIELD_VENDOR_LENGTH_LENGTH); int pos = FIELD_VENDOR_LENGTH_LENGTH; int vendorStringLength = Utils.getIntLE(b); b = new byte[vendorStringLength]; System.arraycopy(rawdata, pos, b, 0, vendorStringLength); pos += vendorStringLength; tag.setVendor(new String(b, VorbisHeader.CHARSET_UTF_8)); logger.info("Vendor is:"+tag.getVendor()); b = new byte[FIELD_USER_COMMENT_LIST_LENGTH]; System.arraycopy(rawdata, pos, b, 0, FIELD_USER_COMMENT_LIST_LENGTH); pos += FIELD_USER_COMMENT_LIST_LENGTH; int userComments = Utils.getIntLE(b); logger.info("Number of user comments:" + userComments); if (fix == Fix.FIX_OGG_VORBIS_COMMENT_NOT_COUNTING_EMPTY_COLUMNS) { userComments++; } for (int i = 0; i < userComments; i++) { b = new byte[FIELD_COMMENT_LENGTH_LENGTH]; System.arraycopy(rawdata, pos, b, 0, FIELD_COMMENT_LENGTH_LENGTH); pos += FIELD_COMMENT_LENGTH_LENGTH; int commentLength = Utils.getIntLE(b); logger.info("Next Comment Length:" + commentLength); if(commentLength> JAUDIOTAGGER_MAX_COMMENT_LENGTH) { logger.warning(ErrorMessage.VORBIS_COMMENT_LENGTH_TOO_LARGE.getMsg(commentLength)); break; } else if(commentLength>rawdata.length) { logger.warning(ErrorMessage.VORBIS_COMMENT_LENGTH_LARGE_THAN_HEADER.getMsg(commentLength,rawdata.length)); break; } else { b = new byte[commentLength]; System.arraycopy(rawdata, pos, b, 0, commentLength); pos += commentLength; VorbisCommentTagField fieldComment = new VorbisCommentTagField(b); logger.info("Adding:" + fieldComment.getId()); tag.addField(fieldComment); } } //Check framing bit, only exists when vorbisComment used within OggVorbis if (isFramingBit) { if ((rawdata[pos] & 0x01) != 1) { throw new CannotReadException(ErrorMessage.OGG_VORBIS_NO_FRAMING_BIT.getMsg((rawdata[pos] & 0x01))); } } return tag; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/vorbiscomment/VorbisCommentFieldKey.java0000644000175000017500000001630711470746136032237 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.vorbiscomment; import org.jaudiotagger.tag.reference.Tagger; import org.jaudiotagger.tag.mp4.field.Mp4FieldType; import java.util.List; import java.util.EnumSet; /** * Vorbis Comment Field Names *

*

*

* This partial list is derived fom the following sources: *

    *
  • http://xiph.org/vorbis/doc/v-comment.html
  • *
  • http://wiki.musicbrainz.org/PicardQt/TagMapping
  • *
  • http://legroom.net/2009/05/09/ogg-vorbis-and-flac-comment-field-recommendations
  • *
*/ public enum VorbisCommentFieldKey { ALBUM("ALBUM", EnumSet.of(Tagger.XIPH,Tagger.PICARD,Tagger.JAIKOZ)), ALBUMARTIST("ALBUMARTIST",EnumSet.of(Tagger.PICARD,Tagger.JAIKOZ)), ALBUMARTISTSORT("ALBUMARTISTSORT",EnumSet.of(Tagger.PICARD,Tagger.JAIKOZ)), ALBUMSORT("ALBUMSORT",EnumSet.of(Tagger.PICARD,Tagger.JAIKOZ)), ARTIST("ARTIST", EnumSet.of(Tagger.XIPH,Tagger.PICARD,Tagger.JAIKOZ)), ARTISTSORT("ARTISTSORT",EnumSet.of(Tagger.PICARD,Tagger.JAIKOZ)), ASIN("ASIN",EnumSet.of(Tagger.PICARD,Tagger.JAIKOZ)), BARCODE("BARCODE",EnumSet.of(Tagger.JAIKOZ)), BPM("BPM",EnumSet.of(Tagger.PICARD,Tagger.JAIKOZ)), CATALOGNUMBER("CATALOGNUMBER",EnumSet.of(Tagger.PICARD,Tagger.JAIKOZ)), COMMENT("COMMENT",EnumSet.of(Tagger.PICARD)), COMPILATION("COMPILATION",EnumSet.of(Tagger.PICARD,Tagger.JAIKOZ)), COMPOSER("COMPOSER",EnumSet.of(Tagger.PICARD,Tagger.JAIKOZ)), COMPOSERSORT("COMPOSERSORT",EnumSet.of(Tagger.JAIKOZ)), CONDUCTOR("CONDUCTOR",EnumSet.of(Tagger.PICARD,Tagger.JAIKOZ)), CONTACT("CONTACT",EnumSet.of(Tagger.XIPH)), COPYRIGHT("COPYRIGHT",EnumSet.of(Tagger.XIPH,Tagger.PICARD,Tagger.JAIKOZ)), COVERART("COVERART",EnumSet.of(Tagger.JAIKOZ)), COVERARTMIME("COVERARTMIME",EnumSet.of(Tagger.JAIKOZ)), CUSTOM1("CUSTOM1",EnumSet.of(Tagger.MEDIA_MONKEY)), CUSTOM2("CUSTOM2",EnumSet.of(Tagger.MEDIA_MONKEY)), CUSTOM3("CUSTOM3",EnumSet.of(Tagger.MEDIA_MONKEY)), CUSTOM4("CUSTOM4",EnumSet.of(Tagger.MEDIA_MONKEY)), CUSTOM5("CUSTOM5",EnumSet.of(Tagger.MEDIA_MONKEY)), DATE("DATE",EnumSet.of(Tagger.XIPH,Tagger.PICARD,Tagger.JAIKOZ)), DESCRIPTION("DESCRIPTION",EnumSet.of(Tagger.XIPH)), DISCNUMBER("DISCNUMBER",EnumSet.of(Tagger.PICARD,Tagger.JAIKOZ)), DISCTOTAL("DISCTOTAL",EnumSet.of(Tagger.XIPH,Tagger.PICARD)), ENCODEDBY("ENCODEDBY",EnumSet.of(Tagger.PICARD)), ENCODER("ENCODER"), ENSEMBLE("ENSEMBLE",EnumSet.of(Tagger.MEDIA_MONKEY)), //Uses this for ALBUM_ARTIST FBPM("FBPM",EnumSet.of(Tagger.BEATUNES)), GENRE("GENRE",EnumSet.of(Tagger.XIPH,Tagger.PICARD,Tagger.JAIKOZ)), GROUPING("GROUPING",EnumSet.of(Tagger.PICARD,Tagger.JAIKOZ)), ISRC("ISRC",EnumSet.of(Tagger.XIPH,Tagger.PICARD,Tagger.JAIKOZ)), KEY("KEY"), LABEL("LABEL",EnumSet.of(Tagger.PICARD,Tagger.JAIKOZ)), LANGUAGE("LANGUAGE"), LICENSE("LICENSE",EnumSet.of(Tagger.XIPH)), LOCATION("LOCATION",EnumSet.of(Tagger.XIPH)), LYRICIST("LYRICIST",EnumSet.of(Tagger.PICARD,Tagger.JAIKOZ)), LYRICS("LYRICS",EnumSet.of(Tagger.PICARD,Tagger.JAIKOZ)), MEDIA("MEDIA",EnumSet.of(Tagger.PICARD,Tagger.JAIKOZ)), METADATA_BLOCK_PICTURE("METADATA_BLOCK_PICTURE",EnumSet.of(Tagger.XIPH)), MOOD("MOOD",EnumSet.of(Tagger.PICARD,Tagger.JAIKOZ)), MUSICBRAINZ_ALBUMARTISTID("MUSICBRAINZ_ALBUMARTISTID",EnumSet.of(Tagger.PICARD,Tagger.JAIKOZ)), MUSICBRAINZ_ALBUMID("MUSICBRAINZ_ALBUMID",EnumSet.of(Tagger.PICARD,Tagger.JAIKOZ)), MUSICBRAINZ_ALBUMSTATUS("MUSICBRAINZ_ALBUMSTATUS",EnumSet.of(Tagger.PICARD,Tagger.JAIKOZ)), MUSICBRAINZ_ALBUMTYPE("MUSICBRAINZ_ALBUMTYPE",EnumSet.of(Tagger.PICARD,Tagger.JAIKOZ)), MUSICBRAINZ_ARTISTID("MUSICBRAINZ_ARTISTID",EnumSet.of(Tagger.PICARD,Tagger.JAIKOZ)), MUSICBRAINZ_DISCID("MUSICBRAINZ_DISCID",EnumSet.of(Tagger.PICARD,Tagger.JAIKOZ)), MUSICBRAINZ_RELEASEGROUPID("MUSICBRAINZ_RELEASEGROUPID",EnumSet.of(Tagger.PICARD,Tagger.JAIKOZ)), MUSICBRAINZ_TRACKID("MUSICBRAINZ_TRACKID",EnumSet.of(Tagger.PICARD,Tagger.JAIKOZ)), MUSICBRAINZ_WORKID("MUSICBRAINZ_WORKID",EnumSet.of(Tagger.PICARD,Tagger.JAIKOZ)), MUSICIP_PUID("MUSICIP_PUID",EnumSet.of(Tagger.PICARD,Tagger.JAIKOZ)), OCCASION("OCCASION",EnumSet.of(Tagger.MEDIA_MONKEY)), ORGANIZATION("ORGANIZATION",EnumSet.of(Tagger.XIPH)), // Name of the organization producing the track (i.e. the 'record label') ORIGINAL_ALBUM("ORIGINAL ALBUM",EnumSet.of(Tagger.JAIKOZ,Tagger.MEDIA_MONKEY)), ORIGINAL_ARTIST("ORIGINAL ARTIST",EnumSet.of(Tagger.JAIKOZ,Tagger.MEDIA_MONKEY)), ORIGINAL_LYRICIST("ORIGINAL LYRICIST",EnumSet.of(Tagger.MEDIA_MONKEY)), ORIGINAL_YEAR("ORIGINAL YEAR",EnumSet.of(Tagger.JAIKOZ,Tagger.MEDIA_MONKEY)), PERFORMER("PERFORMER",EnumSet.of(Tagger.XIPH,Tagger.PICARD)), PRODUCTNUMBER("PRODUCTNUMBER",EnumSet.of(Tagger.XIPH)), QUALITY("QUALITY",EnumSet.of(Tagger.MEDIA_MONKEY)), RATING("RATING",EnumSet.of(Tagger.MEDIA_MONKEY)), RELEASECOUNTRY("RELEASECOUNTRY",EnumSet.of(Tagger.PICARD,Tagger.JAIKOZ)), REMIXER("REMIXER",EnumSet.of(Tagger.PICARD,Tagger.JAIKOZ)), SCRIPT("SCRIPT",EnumSet.of(Tagger.JAIKOZ)), SOURCEMEDIA("SOURCEMEDIA",EnumSet.of(Tagger.XIPH)), TAGS("TAGS",EnumSet.of(Tagger.JAIKOZ)), TEMPO("TEMPO",EnumSet.of(Tagger.MEDIA_MONKEY)), TITLE("TITLE", EnumSet.of(Tagger.XIPH,Tagger.PICARD,Tagger.JAIKOZ)), TITLESORT("TITLESORT",EnumSet.of(Tagger.PICARD,Tagger.JAIKOZ)), TRACKNUMBER("TRACKNUMBER",EnumSet.of(Tagger.XIPH,Tagger.PICARD,Tagger.JAIKOZ)), TRACKTOTAL("TRACKTOTAL",EnumSet.of(Tagger.XIPH,Tagger.PICARD)), URL_DISCOGS_ARTIST_SITE("URL_DISCOGS_ARTIST_SITE",EnumSet.of(Tagger.JAIKOZ)), URL_DISCOGS_RELEASE_SITE("URL_DISCOGS_RELEASE_SITE",EnumSet.of(Tagger.JAIKOZ)), URL_LYRICS_SITE("URL_LYRICS_SITE",EnumSet.of(Tagger.JAIKOZ)), URL_OFFICIAL_ARTIST_SITE("URL_OFFICIAL_ARTIST_SITE",EnumSet.of(Tagger.JAIKOZ)), URL_OFFICIAL_RELEASE_SITE("URL_OFFICIAL_RELEASE_SITE",EnumSet.of(Tagger.JAIKOZ)), URL_WIKIPEDIA_ARTIST_SITE("URL_WIKIPEDIA_ARTIST_SITE",EnumSet.of(Tagger.JAIKOZ)), URL_WIKIPEDIA_RELEASE_SITE("URL_WIKIPEDIA_RELEASE_SITE",EnumSet.of(Tagger.JAIKOZ)), VENDOR("VENDOR"), VERSION("VERSION", EnumSet.of(Tagger.XIPH)),// The version field may be used to differentiate multiple versions of the same track title in a single collection. (e.g. remix info) ENGINEER("ENGINEER",EnumSet.of(Tagger.PICARD)), PRODUCER("PRODUCER",EnumSet.of(Tagger.PICARD)), DJMIXER("DJMIXER",EnumSet.of(Tagger.PICARD)), MIXER("MIXER",EnumSet.of(Tagger.PICARD)), ARRANGER("ARRANGER",EnumSet.of(Tagger.PICARD)), ; private String fieldName; private EnumSet taggers; VorbisCommentFieldKey(String fieldName) { this.fieldName = fieldName; } VorbisCommentFieldKey(String fieldName, EnumSet taggers) { this.fieldName = fieldName; this.taggers = taggers; } public String getFieldName() { return fieldName; } /** * List of taggers using this field, concentrates primarily on the original tagger to start using a field. * Tagger.XIPH means the field is either part of the Vorbis Standard or a Vorbis proposed extension to the * standard * * @return */ public EnumSet getTaggers() { return taggers; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/vorbiscomment/VorbisCommentTagField.java0000644000175000017500000001767411277264361032232 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2003-2005 Raphaël Slinckx * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.tag.vorbiscomment; import org.jaudiotagger.audio.generic.Utils; import org.jaudiotagger.audio.ogg.util.VorbisHeader; import org.jaudiotagger.tag.TagField; import org.jaudiotagger.tag.TagTextField; import static org.jaudiotagger.tag.vorbiscomment.VorbisCommentFieldKey.*; import java.io.UnsupportedEncodingException; /** * This class represents the name and content of a tag entry in ogg-files. *
* * @author @author Raphael Slinckx (KiKiDonK) * @author Christian Laireiter (liree) */ public class VorbisCommentTagField implements TagTextField { /** * If true, the id of the current encapsulated tag field is * specified as a common field.
* Example is "ARTIST" which should be interpreted by any application as the * artist of the media content.
* Will be set during construction with {@link #checkCommon()}. */ private boolean common; /** * Stores the content of the tag field.
*/ private String content; /** * Stores the id (name) of the tag field.
*/ private String id; /** * If id is invalid */ private static final String ERRONEOUS_ID = "ERRONEOUS"; /** * Creates an instance. * * @param raw Raw byte data of the tagfield. * @throws UnsupportedEncodingException If the data doesn't conform "UTF-8" specification. */ public VorbisCommentTagField(byte[] raw) throws UnsupportedEncodingException { String field = new String(raw, "UTF-8"); int i = field.indexOf("="); if (i == -1) { //Beware that ogg ID, must be capitalized and contain no space.. this.id = ERRONEOUS_ID; this.content = field; } else { this.id = field.substring(0, i).toUpperCase(); if (field.length() > i) { this.content = field.substring(i + 1); } else { //We have "XXXXXX=" with nothing after the "=" this.content = ""; } } checkCommon(); } /** * Creates an instance. * * @param fieldId ID (name) of the field. * @param fieldContent Content of the field. */ public VorbisCommentTagField(String fieldId, String fieldContent) { this.id = fieldId.toUpperCase(); this.content = fieldContent; checkCommon(); } /** * This method examines the ID of the current field and modifies * {@link #common}in order to reflect if the tag id is a commonly used one. *
*/ private void checkCommon() { this.common = id.equals(TITLE.getFieldName()) || id.equals(ALBUM.getFieldName()) || id.equals(ARTIST.getFieldName()) || id.equals(GENRE.getFieldName()) || id.equals(TRACKNUMBER.getFieldName()) || id.equals(DATE.getFieldName()) || id.equals(DESCRIPTION.getFieldName()) || id.equals(COMMENT.getFieldName()); } /** * This method will copy all bytes of src to dst * at the specified location. * * @param src bytes to copy. * @param dst where to copy to. * @param dstOffset at which position of dst the data should be * copied. */ protected void copy(byte[] src, byte[] dst, int dstOffset) { // for (int i = 0; i < src.length; i++) // dst[i + dstOffset] = src[i]; /* * Heared that this method is optimized and does its job very near of * the system. */ System.arraycopy(src, 0, dst, dstOffset, src.length); } /** * @see TagField#copyContent(TagField) */ public void copyContent(TagField field) { if (field instanceof TagTextField) { this.content = ((TagTextField) field).getContent(); } } /** * This method will try to return the byte representation of the given * string after it has been converted to the given encoding.
* * @param s The string whose converted bytes should be returned. * @param encoding The encoding type to which the string should be converted. * @return If encoding is supported the byte data of the * given string is returned in that encoding. * @throws UnsupportedEncodingException If the requested encoding is not available. */ protected byte[] getBytes(String s, String encoding) throws UnsupportedEncodingException { return s.getBytes(encoding); } /** * @see TagTextField#getContent() */ public String getContent() { return content; } /** * @see TagTextField#getEncoding() */ public String getEncoding() { return VorbisHeader.CHARSET_UTF_8; } /** * @see TagField#getId() */ public String getId() { return this.id; } /** * @see TagField#getRawContent() */ public byte[] getRawContent() throws UnsupportedEncodingException { byte[] size = new byte[VorbisCommentReader.FIELD_COMMENT_LENGTH_LENGTH]; byte[] idBytes = Utils.getDefaultBytes(this.id, "ISO-8859-1"); byte[] contentBytes = getBytes(this.content, "UTF-8"); byte[] b = new byte[4 + idBytes.length + 1 + contentBytes.length]; int length = idBytes.length + 1 + contentBytes.length; size[3] = (byte) ((length & 0xFF000000) >> 24); size[2] = (byte) ((length & 0x00FF0000) >> 16); size[1] = (byte) ((length & 0x0000FF00) >> 8); size[0] = (byte) (length & 0x000000FF); int offset = 0; copy(size, b, offset); offset += 4; copy(idBytes, b, offset); offset += idBytes.length; b[offset] = (byte) 0x3D; offset++;// "=" copy(contentBytes, b, offset); return b; } /** * @see TagField#isBinary() */ public boolean isBinary() { return false; } /** * @see TagField#isBinary(boolean) */ public void isBinary(boolean b) { if (b) { // Only throw if binary = true requested. throw new UnsupportedOperationException("OggTagFields cannot be changed to binary.\n" + "binary data should be stored elsewhere" + " according to Vorbis_I_spec."); } } /** * @see TagField#isCommon() */ public boolean isCommon() { return common; } /** * @see TagField#isEmpty() */ public boolean isEmpty() { return this.content.equals(""); } /** * @see TagTextField#setContent(String) */ public void setContent(String s) { this.content = s; } /** * @see TagTextField#setEncoding(String) */ public void setEncoding(String s) { if (s == null || !s.equalsIgnoreCase("UTF-8")) { throw new UnsupportedOperationException("The encoding of OggTagFields cannot be " + "changed.(specified to be UTF-8)"); } } public String toString() { return getContent(); } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/vorbiscomment/VorbisCommentCreator.java0000644000175000017500000000602211470746136032133 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2003-2005 Raphaël Slinckx * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.tag.vorbiscomment; import org.jaudiotagger.audio.generic.AbstractTagCreator; import org.jaudiotagger.audio.generic.Utils; import org.jaudiotagger.tag.Tag; import org.jaudiotagger.tag.TagField; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.nio.ByteBuffer; import java.util.Iterator; /** * Create the raw packet data for a Vorbis Comment Tag */ public class VorbisCommentCreator extends AbstractTagCreator { /** * Convert tagdata to rawdata ready for writing to file * * @param tag * @param padding * @return * @throws UnsupportedEncodingException */ //TODO padding parameter currently ignored public ByteBuffer convert(Tag tag, int padding) throws UnsupportedEncodingException { try { ByteArrayOutputStream baos = new ByteArrayOutputStream(); //Vendor String vendorString = ((VorbisCommentTag) tag).getVendor(); int vendorLength = Utils.getUTF8Bytes(vendorString).length; baos.write(Utils.getSizeLEInt32(vendorLength)); baos.write(Utils.getUTF8Bytes(vendorString)); //User Comment List int listLength = tag.getFieldCount() - 1; //Remove Vendor from count baos.write(Utils.getSizeLEInt32(listLength)); //Add metadata raw content Iterator it = tag.getFields(); while (it.hasNext()) { TagField frame = it.next(); if (frame.getId().equals(VorbisCommentFieldKey.VENDOR.getFieldName())) { //this is always stored above so ignore } else { baos.write(frame.getRawContent()); } } //Put into ByteBuffer ByteBuffer buf = ByteBuffer.wrap(baos.toByteArray()); buf.rewind(); return buf; } catch (IOException ioe) { //Should never happen as not writing to file at this point throw new RuntimeException(ioe); } } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/vorbiscomment/VorbisCommentTag.java0000644000175000017500000005461711470746136031264 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2003-2005 Rapha�l Slinckx * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.tag.vorbiscomment; import org.jaudiotagger.audio.flac.metadatablock.MetadataBlockDataPicture; import org.jaudiotagger.audio.generic.AbstractTag; import org.jaudiotagger.audio.generic.Utils; import org.jaudiotagger.audio.ogg.util.VorbisHeader; import org.jaudiotagger.logging.ErrorMessage; import org.jaudiotagger.tag.*; import org.jaudiotagger.tag.datatype.Artwork; import static org.jaudiotagger.tag.vorbiscomment.VorbisCommentFieldKey.VENDOR; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; import org.jaudiotagger.tag.reference.Tagger; import org.jaudiotagger.tag.vorbiscomment.util.Base64Coder; import java.awt.image.BufferedImage; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.EnumMap; import java.util.EnumSet; import java.util.List; /** * This is the logical representation of Vorbis Comment Data */ public class VorbisCommentTag extends AbstractTag { private static EnumMap tagFieldToOggField = new EnumMap(FieldKey.class); static { tagFieldToOggField.put(FieldKey.ALBUM, VorbisCommentFieldKey.ALBUM); tagFieldToOggField.put(FieldKey.ALBUM_ARTIST, VorbisCommentFieldKey.ALBUMARTIST); tagFieldToOggField.put(FieldKey.ALBUM_ARTIST_SORT, VorbisCommentFieldKey.ALBUMARTISTSORT); tagFieldToOggField.put(FieldKey.ALBUM_SORT, VorbisCommentFieldKey.ALBUMSORT); tagFieldToOggField.put(FieldKey.ARTIST, VorbisCommentFieldKey.ARTIST); tagFieldToOggField.put(FieldKey.AMAZON_ID, VorbisCommentFieldKey.ASIN); tagFieldToOggField.put(FieldKey.ARTIST_SORT, VorbisCommentFieldKey.ARTISTSORT); tagFieldToOggField.put(FieldKey.BARCODE, VorbisCommentFieldKey.BARCODE); tagFieldToOggField.put(FieldKey.BPM, VorbisCommentFieldKey.BPM); tagFieldToOggField.put(FieldKey.CATALOG_NO, VorbisCommentFieldKey.CATALOGNUMBER); tagFieldToOggField.put(FieldKey.COMMENT, VorbisCommentFieldKey.COMMENT); tagFieldToOggField.put(FieldKey.COMPOSER, VorbisCommentFieldKey.COMPOSER); tagFieldToOggField.put(FieldKey.COMPOSER_SORT, VorbisCommentFieldKey.COMPOSERSORT); tagFieldToOggField.put(FieldKey.CONDUCTOR, VorbisCommentFieldKey.CONDUCTOR); tagFieldToOggField.put(FieldKey.COVER_ART, VorbisCommentFieldKey.METADATA_BLOCK_PICTURE); tagFieldToOggField.put(FieldKey.CUSTOM1, VorbisCommentFieldKey.CUSTOM1); tagFieldToOggField.put(FieldKey.CUSTOM2, VorbisCommentFieldKey.CUSTOM2); tagFieldToOggField.put(FieldKey.CUSTOM3, VorbisCommentFieldKey.CUSTOM3); tagFieldToOggField.put(FieldKey.CUSTOM4, VorbisCommentFieldKey.CUSTOM4); tagFieldToOggField.put(FieldKey.CUSTOM5, VorbisCommentFieldKey.CUSTOM5); tagFieldToOggField.put(FieldKey.DISC_NO, VorbisCommentFieldKey.DISCNUMBER); tagFieldToOggField.put(FieldKey.DISC_TOTAL, VorbisCommentFieldKey.DISCTOTAL); tagFieldToOggField.put(FieldKey.ENCODER, VorbisCommentFieldKey.VENDOR); //Known as vendor in VorbisComment tagFieldToOggField.put(FieldKey.FBPM, VorbisCommentFieldKey.FBPM); tagFieldToOggField.put(FieldKey.GENRE, VorbisCommentFieldKey.GENRE); tagFieldToOggField.put(FieldKey.GROUPING, VorbisCommentFieldKey.GROUPING); tagFieldToOggField.put(FieldKey.ISRC, VorbisCommentFieldKey.ISRC); tagFieldToOggField.put(FieldKey.IS_COMPILATION, VorbisCommentFieldKey.COMPILATION); tagFieldToOggField.put(FieldKey.KEY, VorbisCommentFieldKey.KEY); tagFieldToOggField.put(FieldKey.LANGUAGE, VorbisCommentFieldKey.LANGUAGE); tagFieldToOggField.put(FieldKey.LYRICIST, VorbisCommentFieldKey.LYRICIST); tagFieldToOggField.put(FieldKey.LYRICS, VorbisCommentFieldKey.LYRICS); tagFieldToOggField.put(FieldKey.MEDIA, VorbisCommentFieldKey.MEDIA); tagFieldToOggField.put(FieldKey.MOOD, VorbisCommentFieldKey.MOOD); tagFieldToOggField.put(FieldKey.MUSICBRAINZ_ARTISTID, VorbisCommentFieldKey.MUSICBRAINZ_ARTISTID); tagFieldToOggField.put(FieldKey.MUSICBRAINZ_DISC_ID, VorbisCommentFieldKey.MUSICBRAINZ_DISCID); tagFieldToOggField.put(FieldKey.MUSICBRAINZ_RELEASEARTISTID, VorbisCommentFieldKey.MUSICBRAINZ_ALBUMARTISTID); tagFieldToOggField.put(FieldKey.MUSICBRAINZ_RELEASEID, VorbisCommentFieldKey.MUSICBRAINZ_ALBUMID); tagFieldToOggField.put(FieldKey.MUSICBRAINZ_RELEASE_GROUP_ID, VorbisCommentFieldKey.MUSICBRAINZ_RELEASEGROUPID); tagFieldToOggField.put(FieldKey.MUSICBRAINZ_RELEASE_COUNTRY, VorbisCommentFieldKey.RELEASECOUNTRY); tagFieldToOggField.put(FieldKey.MUSICBRAINZ_RELEASE_STATUS, VorbisCommentFieldKey.MUSICBRAINZ_ALBUMSTATUS); tagFieldToOggField.put(FieldKey.MUSICBRAINZ_RELEASE_TYPE, VorbisCommentFieldKey.MUSICBRAINZ_ALBUMTYPE); tagFieldToOggField.put(FieldKey.MUSICBRAINZ_TRACK_ID, VorbisCommentFieldKey.MUSICBRAINZ_TRACKID); tagFieldToOggField.put(FieldKey.MUSICBRAINZ_WORK_ID, VorbisCommentFieldKey.MUSICBRAINZ_WORKID); tagFieldToOggField.put(FieldKey.OCCASION, VorbisCommentFieldKey.OCCASION); tagFieldToOggField.put(FieldKey.ORIGINAL_ALBUM, VorbisCommentFieldKey.ORIGINAL_ALBUM); tagFieldToOggField.put(FieldKey.ORIGINAL_ARTIST, VorbisCommentFieldKey.ORIGINAL_ARTIST); tagFieldToOggField.put(FieldKey.ORIGINAL_LYRICIST, VorbisCommentFieldKey.ORIGINAL_LYRICIST); tagFieldToOggField.put(FieldKey.ORIGINAL_YEAR, VorbisCommentFieldKey.ORIGINAL_YEAR); tagFieldToOggField.put(FieldKey.MUSICIP_ID, VorbisCommentFieldKey.MUSICIP_PUID); tagFieldToOggField.put(FieldKey.QUALITY, VorbisCommentFieldKey.QUALITY); tagFieldToOggField.put(FieldKey.RATING, VorbisCommentFieldKey.RATING); tagFieldToOggField.put(FieldKey.RECORD_LABEL, VorbisCommentFieldKey.LABEL); tagFieldToOggField.put(FieldKey.REMIXER, VorbisCommentFieldKey.REMIXER); tagFieldToOggField.put(FieldKey.TAGS, VorbisCommentFieldKey.TAGS); tagFieldToOggField.put(FieldKey.SCRIPT, VorbisCommentFieldKey.SCRIPT); tagFieldToOggField.put(FieldKey.TEMPO, VorbisCommentFieldKey.TEMPO); tagFieldToOggField.put(FieldKey.TITLE, VorbisCommentFieldKey.TITLE); tagFieldToOggField.put(FieldKey.TITLE_SORT, VorbisCommentFieldKey.TITLESORT); tagFieldToOggField.put(FieldKey.TRACK, VorbisCommentFieldKey.TRACKNUMBER); tagFieldToOggField.put(FieldKey.TRACK_TOTAL, VorbisCommentFieldKey.TRACKTOTAL); tagFieldToOggField.put(FieldKey.URL_DISCOGS_ARTIST_SITE, VorbisCommentFieldKey.URL_DISCOGS_ARTIST_SITE); tagFieldToOggField.put(FieldKey.URL_DISCOGS_RELEASE_SITE, VorbisCommentFieldKey.URL_DISCOGS_RELEASE_SITE); tagFieldToOggField.put(FieldKey.URL_LYRICS_SITE, VorbisCommentFieldKey.URL_LYRICS_SITE); tagFieldToOggField.put(FieldKey.URL_OFFICIAL_ARTIST_SITE, VorbisCommentFieldKey.URL_OFFICIAL_ARTIST_SITE); tagFieldToOggField.put(FieldKey.URL_OFFICIAL_RELEASE_SITE, VorbisCommentFieldKey.URL_OFFICIAL_RELEASE_SITE); tagFieldToOggField.put(FieldKey.URL_WIKIPEDIA_ARTIST_SITE, VorbisCommentFieldKey.URL_WIKIPEDIA_ARTIST_SITE); tagFieldToOggField.put(FieldKey.URL_WIKIPEDIA_RELEASE_SITE, VorbisCommentFieldKey.URL_WIKIPEDIA_RELEASE_SITE); tagFieldToOggField.put(FieldKey.YEAR, VorbisCommentFieldKey.DATE); tagFieldToOggField.put(FieldKey.ENGINEER, VorbisCommentFieldKey.ENGINEER); tagFieldToOggField.put(FieldKey.PRODUCER, VorbisCommentFieldKey.PRODUCER); tagFieldToOggField.put(FieldKey.DJMIXER, VorbisCommentFieldKey.DJMIXER); tagFieldToOggField.put(FieldKey.MIXER, VorbisCommentFieldKey.MIXER); tagFieldToOggField.put(FieldKey.ARRANGER, VorbisCommentFieldKey.ARRANGER); } //This is the vendor string that will be written if no other is supplied. Should be the name of the software //that actually encoded the file in the first place. public static final String DEFAULT_VENDOR = "jaudiotagger"; /** * Only used within Package, hidden because it doesnt set Vendor * which should be done when created by end user */ VorbisCommentTag() { } /** * Use to construct a new tag properly initialized * * @return */ public static VorbisCommentTag createNewTag() { VorbisCommentTag tag = new VorbisCommentTag(); tag.setVendor(DEFAULT_VENDOR); return tag; } /** * @return the vendor, generically known as the encoder */ public String getVendor() { return getFirst(VENDOR.getFieldName()); } /** * Set the vendor, known as the encoder generally *

* We dont want this to be blank, when written to file this field is written to a different location * to all other fields but user of library can just reat it as another field * * @param vendor */ public void setVendor(String vendor) { if (vendor == null) { vendor = DEFAULT_VENDOR; } super.setField(new VorbisCommentTagField(VENDOR.getFieldName(), vendor)); } protected boolean isAllowedEncoding(String enc) { return enc.equals(VorbisHeader.CHARSET_UTF_8); } public String toString() { return "OGG " + super.toString(); } /** * Create Tag Field using generic key */ @Override public TagField createField(FieldKey genericKey, String value) throws KeyNotFoundException,FieldDataInvalidException { if (genericKey == null) { throw new KeyNotFoundException(); } return createField(tagFieldToOggField.get(genericKey), value); } /** * Create Tag Field using ogg key * * @param vorbisCommentFieldKey * @param value * @return * @throws org.jaudiotagger.tag.KeyNotFoundException * @throws org.jaudiotagger.tag.FieldDataInvalidException */ public TagField createField(VorbisCommentFieldKey vorbisCommentFieldKey, String value) throws KeyNotFoundException,FieldDataInvalidException { if (value == null) { throw new IllegalArgumentException(ErrorMessage.GENERAL_INVALID_NULL_ARGUMENT.getMsg()); } if (vorbisCommentFieldKey == null) { throw new KeyNotFoundException(); } return new VorbisCommentTagField(vorbisCommentFieldKey.getFieldName(), value); } /** * Create Tag Field using ogg key *

* This method is provided to allow you to create key of any value because VorbisComment allows * arbitary keys. * * @param vorbisCommentFieldKey * @param value * @return */ public TagField createField(String vorbisCommentFieldKey, String value) { if (value == null) { throw new IllegalArgumentException(ErrorMessage.GENERAL_INVALID_NULL_ARGUMENT.getMsg()); } return new VorbisCommentTagField(vorbisCommentFieldKey, value); } /** * Maps the generic key to the ogg key and return the list of values for this field * * @param genericKey */ @Override public List getFields(FieldKey genericKey) throws KeyNotFoundException { VorbisCommentFieldKey vorbisCommentFieldKey = tagFieldToOggField.get(genericKey); if (vorbisCommentFieldKey == null) { throw new KeyNotFoundException(); } return super.getFields(vorbisCommentFieldKey.getFieldName()); } /** * Retrieve the first value that exists for this vorbis comment key * * @param vorbisCommentKey * @return * @throws org.jaudiotagger.tag.KeyNotFoundException */ public List get(VorbisCommentFieldKey vorbisCommentKey) throws KeyNotFoundException { if (vorbisCommentKey == null) { throw new KeyNotFoundException(); } return super.getFields(vorbisCommentKey.getFieldName()); } public String getValue(FieldKey genericKey,int index) throws KeyNotFoundException { VorbisCommentFieldKey vorbisCommentFieldKey = tagFieldToOggField.get(genericKey); if (vorbisCommentFieldKey == null) { throw new KeyNotFoundException(); } return super.getItem(vorbisCommentFieldKey.getFieldName(),index); } /** * Retrieve the first value that exists for this vorbis comment key * * @param vorbisCommentKey * @return * @throws org.jaudiotagger.tag.KeyNotFoundException */ public String getFirst(VorbisCommentFieldKey vorbisCommentKey) throws KeyNotFoundException { if (vorbisCommentKey == null) { throw new KeyNotFoundException(); } return super.getFirst(vorbisCommentKey.getFieldName()); } /** * Delete fields with this generic key * * @param genericKey */ public void deleteField(FieldKey genericKey) throws KeyNotFoundException { if (genericKey == null) { throw new KeyNotFoundException(); } VorbisCommentFieldKey vorbisCommentFieldKey = tagFieldToOggField.get(genericKey); deleteField(vorbisCommentFieldKey); } /** * Delete fields with this vorbisCommentFieldKey * * @param vorbisCommentFieldKey * @throws org.jaudiotagger.tag.KeyNotFoundException */ public void deleteField(VorbisCommentFieldKey vorbisCommentFieldKey) throws KeyNotFoundException { if (vorbisCommentFieldKey == null) { throw new KeyNotFoundException(); } super.deleteField(vorbisCommentFieldKey.getFieldName()); } /** * Retrieve artwork raw data when using the deprecated COVERART format * * @return */ public byte[] getArtworkBinaryData() { String base64data = this.getFirst(VorbisCommentFieldKey.COVERART); byte[] rawdata = Base64Coder.decode(base64data.toCharArray()); return rawdata; } /** * Retrieve artwork mimeType when using deprecated COVERART format * * @return mimetype */ public String getArtworkMimeType() { return this.getFirst(VorbisCommentFieldKey.COVERARTMIME); } /** * Is this tag empty *

*

Overridden because check for size of one because there is always a vendor tag unless just * created an empty vorbis tag as part of flac tag in which case size could be zero * * @see org.jaudiotagger.tag.Tag#isEmpty() */ public boolean isEmpty() { return fields.size() <= 1; } /** * Add Field *

*

Overidden because there can only be one vendor set * * @param field */ public void addField(TagField field) { if (field.getId().equals(VorbisCommentFieldKey.VENDOR.getFieldName())) { super.setField(field); } else { super.addField(field); } } public TagField getFirstField(FieldKey genericKey) throws KeyNotFoundException { if (genericKey == null) { throw new KeyNotFoundException(); } return getFirstField(tagFieldToOggField.get(genericKey).getFieldName()); } /** * * @return list of artwork images */ public List getArtworkList() { List artworkList = new ArrayList(1); //Read Old Format if(getArtworkBinaryData()!=null & getArtworkBinaryData().length>0) { Artwork artwork=new Artwork(); artwork.setMimeType(getArtworkMimeType()); artwork.setBinaryData(getArtworkBinaryData()); artworkList.add(artwork); } //New Format (Supports Multiple Images) List metadataBlockPics = this.get(VorbisCommentFieldKey.METADATA_BLOCK_PICTURE); for(TagField tagField:metadataBlockPics) { try { byte[] imageBinaryData = Base64Coder.decode(((TagTextField)tagField).getContent()); MetadataBlockDataPicture coverArt = new MetadataBlockDataPicture(ByteBuffer.wrap(imageBinaryData)); Artwork artwork=Artwork.createArtworkFromMetadataBlockDataPicture(coverArt); artworkList.add(artwork); } catch(IOException ioe) { throw new RuntimeException(ioe); } catch(InvalidFrameException ife) { throw new RuntimeException(ife); } } return artworkList; } /** * Create MetadataBlockPicture field, this is the preferred way of storing artwork in VorbisComment tag now but * has to be base encoded to be stored in VorbisComment * * @return MetadataBlockDataPicture */ private MetadataBlockDataPicture createMetadataBlockDataPicture(Artwork artwork) throws FieldDataInvalidException { if(artwork.isLinked()) { return new MetadataBlockDataPicture( Utils.getDefaultBytes(artwork.getImageUrl(), TextEncoding.CHARSET_ISO_8859_1), artwork.getPictureType(), MetadataBlockDataPicture.IMAGE_IS_URL, "", 0, 0, 0, 0); } else { BufferedImage image; try { image = artwork.getImage(); } catch(IOException ioe) { throw new FieldDataInvalidException("Unable to create MetadataBlockDataPicture from buffered:"+ioe.getMessage()); } return new MetadataBlockDataPicture(artwork.getBinaryData(), artwork.getPictureType(), artwork.getMimeType(), artwork.getDescription(), image.getWidth(), image.getHeight(), 0, 0); } } /** * Create Artwork field * * @param artwork * @return * @throws FieldDataInvalidException */ public TagField createField(Artwork artwork) throws FieldDataInvalidException { try { char[] testdata = Base64Coder.encode(createMetadataBlockDataPicture(artwork).getRawContent()); String base64image = new String(testdata); TagField imageTagField = createField(VorbisCommentFieldKey.METADATA_BLOCK_PICTURE, base64image); return imageTagField; } catch(UnsupportedEncodingException uee) { throw new RuntimeException(uee); } } /** * Create and set artwork field * * @return */ @Override public void setField(Artwork artwork) throws FieldDataInvalidException { //Set field this.setField(createField(artwork)); //If worked okay above then that should be first artwork and if we still had old coverart format //that should be removed if(this.getFirst(VorbisCommentFieldKey.COVERART).length()>0) { this.deleteField(VorbisCommentFieldKey.COVERART); this.deleteField(VorbisCommentFieldKey.COVERARTMIME); } } /** * Add artwork field * * @param artwork * @throws FieldDataInvalidException */ public void addField(Artwork artwork) throws FieldDataInvalidException { this.addField(createField(artwork)); } /** * Create artwork field using the non-standard COVERART tag * *

* Actually create two fields , the data field and the mimetype. Its is not recommended that you use this * method anymore. * * @param data raw image data * @param mimeType mimeType of data *

* @return */ @Deprecated public void setArtworkField(byte[] data, String mimeType) { char[] testdata = Base64Coder.encode(data); String base64image = new String(testdata); VorbisCommentTagField dataField = new VorbisCommentTagField(VorbisCommentFieldKey.COVERART.getFieldName(), base64image); VorbisCommentTagField mimeField = new VorbisCommentTagField(VorbisCommentFieldKey.COVERARTMIME.getFieldName(), mimeType); setField(dataField); setField(mimeField); } /** * Create and set field with name of vorbisCommentkey * * @param vorbisCommentKey * @param value * @throws KeyNotFoundException * @throws FieldDataInvalidException */ public void setField(String vorbisCommentKey, String value) throws KeyNotFoundException, FieldDataInvalidException { TagField tagfield = createField(vorbisCommentKey,value); setField(tagfield); } /** * Create and add field with name of vorbisCommentkey * @param vorbisCommentKey * @param value * @throws KeyNotFoundException * @throws FieldDataInvalidException */ public void addField(String vorbisCommentKey, String value) throws KeyNotFoundException, FieldDataInvalidException { TagField tagfield = createField(vorbisCommentKey,value); addField(tagfield); } /** * Delete all instance of artwork Field * * @throws KeyNotFoundException */ public void deleteArtworkField() throws KeyNotFoundException { //New Method this.deleteField(VorbisCommentFieldKey.METADATA_BLOCK_PICTURE); //Old Method this.deleteField(VorbisCommentFieldKey.COVERART); this.deleteField(VorbisCommentFieldKey.COVERARTMIME); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/vorbiscomment/util/0000755000175000017500000000000011556363175026141 5ustar drazzibdrazziblibjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/vorbiscomment/util/Base64Coder.java0000644000175000017500000001134411470746136031005 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.vorbiscomment.util; import org.jaudiotagger.audio.generic.Utils; /** * Base64Coder */ public class Base64Coder { // Mapping table from 6-bit nibbles to Base64 characters. private static final char[] map1 = new char[64]; static { int i = 0; for (char c = 'A'; c <= 'Z'; c++) { map1[i++] = c; } for (char c = 'a'; c <= 'z'; c++) { map1[i++] = c; } for (char c = '0'; c <= '9'; c++) { map1[i++] = c; } map1[i++] = '+'; map1[i++] = '/'; } // Mapping table from Base64 characters to 6-bit nibbles. private static final byte[] map2 = new byte[128]; static { for (int i = 0; i < map2.length; i++) { map2[i] = -1; } for (int i = 0; i < 64; i++) { map2[map1[i]] = (byte) i; } } /** * Encodes a string into Base64 format. * No blanks or line breaks are inserted. * * @param s a String to be encoded. * @return A String with the Base64 encoded data. */ public static String encode(final String s) { return new String(encode(Utils.getDefaultBytes(s, "ISO-8859-1"))); } /** * Encodes a byte array into Base64 format. * No blanks or line breaks are inserted. * * @param in an array containing the data bytes to be encoded. * @return A character array with the Base64 encoded data. */ public static char[] encode(final byte[] in) { final int iLen = in.length; final int oDataLen = (iLen * 4 + 2) / 3; // output length without padding final int oLen = ((iLen + 2) / 3) * 4; // output length including padding final char[] out = new char[oLen]; int ip = 0; int op = 0; while (ip < iLen) { final int i0 = in[ip++] & 0xff; final int i1 = ip < iLen ? in[ip++] & 0xff : 0; final int i2 = ip < iLen ? in[ip++] & 0xff : 0; final int o0 = i0 >>> 2; final int o1 = ((i0 & 3) << 4) | (i1 >>> 4); final int o2 = ((i1 & 0xf) << 2) | (i2 >>> 6); final int o3 = i2 & 0x3F; out[op++] = map1[o0]; out[op++] = map1[o1]; out[op] = op < oDataLen ? map1[o2] : '='; op++; out[op] = op < oDataLen ? map1[o3] : '='; op++; } return out; } /** * Decodes a Base64 string. * * @param s a Base64 String to be decoded. * @return An array containing the decoded data bytes. * @throws IllegalArgumentException if the input is not valid Base64 encoded data. */ public static byte[] decode(final String s) { return decode(s.toCharArray()); } /** * Decodes Base64 data. * No blanks or line breaks are allowed within the Base64 encoded data. * * @param in a character array containing the Base64 encoded data. * @return An array containing the decoded data bytes. * @throws IllegalArgumentException if the input is not valid Base64 encoded data. */ public static byte[] decode(final char[] in) { int iLen = in.length; if (iLen % 4 != 0) { throw new IllegalArgumentException("Length of Base64 encoded input string is not a multiple of 4."); } while (iLen > 0 && in[iLen - 1] == '=') { iLen--; } final int oLen = (iLen * 3) / 4; final byte[] out = new byte[oLen]; int ip = 0; int op = 0; while (ip < iLen) { final int i0 = in[ip++]; final int i1 = in[ip++]; final int i2 = ip < iLen ? in[ip++] : 'A'; final int i3 = ip < iLen ? in[ip++] : 'A'; if (i0 > 127 || i1 > 127 || i2 > 127 || i3 > 127) { throw new IllegalArgumentException("Illegal character in Base64 encoded data."); } final int b0 = map2[i0]; final int b1 = map2[i1]; final int b2 = map2[i2]; final int b3 = map2[i3]; if (b0 < 0 || b1 < 0 || b2 < 0 || b3 < 0) { throw new IllegalArgumentException("Illegal character in Base64 encoded data."); } final int o0 = (b0 << 2) | (b1 >>> 4); final int o1 = ((b1 & 0xf) << 4) | (b2 >>> 2); final int o2 = ((b2 & 3) << 6) | b3; out[op++] = (byte) o0; if (op < oLen) { out[op++] = (byte) o1; } if (op < oLen) { out[op++] = (byte) o2; } } return out; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/TagNotFoundException.java0000644000175000017500000000430210736454526027206 0ustar drazzibdrazzib/* * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: TagNotFoundException.java 520 2008-01-01 15:16:38Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ package org.jaudiotagger.tag; /** * Thrown if the tag o isn't found. This is different from * the InvalidTagException. Each tag has an * ID string or some way saying that it simply exists. If this string is * missing, TagNotFoundException is thrown. If the ID string * exists, then any other error while reading throws an * InvalidTagException. * * @author Eric Farng * @version $Revision: 520 $ */ public class TagNotFoundException extends TagException { /** * Creates a new TagNotFoundException datatype. */ public TagNotFoundException() { } /** * Creates a new TagNotFoundException datatype. * * @param ex the cause. */ public TagNotFoundException(Throwable ex) { super(ex); } /** * Creates a new TagNotFoundException datatype. * * @param msg the detail message. */ public TagNotFoundException(String msg) { super(msg); } /** * Creates a new TagNotFoundException datatype. * * @param msg the detail message. * @param ex the cause. */ public TagNotFoundException(String msg, Throwable ex) { super(msg, ex); } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/InvalidTagException.java0000644000175000017500000000440210736454526027041 0ustar drazzibdrazzib/* * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: InvalidTagException.java 520 2008-01-01 15:16:38Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ package org.jaudiotagger.tag; /** * An InvalidTagException is thrown if a parse error occurs while * a tag is being read from a file. This is different from a * TagNotFoundException. Each tag (or MP3 Frame Header) has an ID * string or some way saying that it simply exists. If this string is missing, * TagNotFoundException is thrown. If the ID string exists, then * any other error while reading throws an InvalidTagException. * * @version $Revision: 520 $ */ public class InvalidTagException extends TagException { /** * Creates a new InvalidTagException datatype. */ public InvalidTagException() { } /** * Creates a new InvalidTagException datatype. * * @param ex the cause. */ public InvalidTagException(Throwable ex) { super(ex); } /** * Creates a new InvalidTagException datatype. * * @param msg the detail message. */ public InvalidTagException(String msg) { super(msg); } /** * Creates a new InvalidTagException datatype. * * @param msg the detail message. * @param ex the cause. */ public InvalidTagException(String msg, Throwable ex) { super(msg, ex); } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/EmptyFrameException.java0000644000175000017500000000357410736454526027101 0ustar drazzibdrazzib/* * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: EmptyFrameException.java 520 2008-01-01 15:16:38Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ package org.jaudiotagger.tag; /** * Thrown when find a Frame but it contains no data. * * @version $Revision: 520 $ */ public class EmptyFrameException extends InvalidFrameException { /** * Creates a new EmptyFrameException datatype. */ public EmptyFrameException() { } /** * Creates a new EmptyFrameException datatype. * * @param ex the cause. */ public EmptyFrameException(Throwable ex) { super(ex); } /** * Creates a new EmptyFrameException datatype. * * @param msg the detail message. */ public EmptyFrameException(String msg) { super(msg); } /** * Creates a new EmptyFrameException datatype. * * @param msg the detail message. * @param ex the cause. */ public EmptyFrameException(String msg, Throwable ex) { super(msg, ex); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/InvalidFrameIdentifierException.java0000644000175000017500000000400310736454526031360 0ustar drazzibdrazzib/* * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: InvalidFrameIdentifierException.java 520 2008-01-01 15:16:38Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ package org.jaudiotagger.tag; /** * Thrown if a frame identifier isn't valid. * * @author Eric Farng * @version $Revision: 520 $ */ public class InvalidFrameIdentifierException extends InvalidFrameException { /** * Creates a new InvalidFrameIdentifierException datatype. */ public InvalidFrameIdentifierException() { } /** * Creates a new InvalidFrameIdentifierException datatype. * * @param ex the cause. */ public InvalidFrameIdentifierException(Throwable ex) { super(ex); } /** * Creates a new InvalidFrameIdentifierException datatype. * * @param msg the detail message. */ public InvalidFrameIdentifierException(String msg) { super(msg); } /** * Creates a new InvalidFrameIdentifierException datatype. * * @param msg the detail message. * @param ex the cause. */ public InvalidFrameIdentifierException(String msg, Throwable ex) { super(msg, ex); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/Tag.java0000644000175000017500000002363111470746136023655 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2003-2010 Raphaël Slinckx * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.tag; import org.jaudiotagger.tag.datatype.Artwork; import java.util.Iterator; import java.util.List; /** * This interface represents the basic data structure for the default * audio library functionality.
*

* Some audio file tagging systems allow to specify multiple values for one type * of information. The artist for example. Some songs may be a cooperation of * two or more artists. Sometimes a tagging user wants to specify them in the * tag without making one long text string.
* * The addField() method can be used for this but it is possible the underlying implementation * does not support that kind of storing multiple values and will just overwrite the existing value
*
* Code Examples:
*

*

 * 
 * AudioFile file = AudioFileIO.read(new File("C:\\test.mp3"));
 * 

* Tag tag = file.getTag(); * *

* * @author Raphael Slinckx * @author Paul Taylor */ public interface Tag { /** * Create the field based on the generic key and set it in the tag * * @param genericKey * @param value * @throws KeyNotFoundException * @throws FieldDataInvalidException */ public void setField(FieldKey genericKey, String value) throws KeyNotFoundException, FieldDataInvalidException; /** * Create the field based on the generic key and add it to the tag * * This is handled differently by different formats * * @param genericKey * @param value * @throws KeyNotFoundException * @throws FieldDataInvalidException */ public void addField(FieldKey genericKey, String value) throws KeyNotFoundException, FieldDataInvalidException; /** * Delete any fields with this key * * @param fieldKey * @throws KeyNotFoundException */ public void deleteField(FieldKey fieldKey) throws KeyNotFoundException; /** * Delete any fields with this Flac (Vorbis Comment) id * * @param key * @throws KeyNotFoundException */ public void deleteField(String key)throws KeyNotFoundException; /** * Returns a {@linkplain List list} of {@link TagField} objects whose "{@linkplain TagField#getId() id}" * is the specified one.
* *

Can be used to retrieve fields with any identifier, useful if the identifier is not within {@link FieldKey} * * @param id The field id. * @return A list of {@link TagField} objects with the given "id". */ public List getFields(String id); /** * Returns a {@linkplain List list} of {@link TagField} objects whose "{@linkplain TagField#getId() id}" * is the specified one.
* * @param id The field id. * @return A list of {@link TagField} objects with the given "id". * @throws KeyNotFoundException */ public List getFields(FieldKey id) throws KeyNotFoundException; /** * Iterator over all the fields within the tag, handle multiple fields with the same id * * @return iterator over whole list */ public Iterator getFields(); /** * Retrieve String value of the first value that exists for this format specific key *

*

Can be used to retrieve fields with any identifier, useful if the identifier is not within {@link FieldKey} * * @param id * @return */ public String getFirst(String id); /** * Retrieve String value of the first tag field that exists for this generic key * * @param id * @return String value or empty string * @throws KeyNotFoundException */ public String getFirst(FieldKey id) throws KeyNotFoundException; /** * Retrieve String value of the nth tag field that exists for this generic key * * @param id * @param n * @return */ public String getValue(FieldKey id, int n); /** * Retrieve String value of the mth field within the nth tag field that exists for this id * *

This method id useful for formats that hold multiple values within one field, namely ID3v2 can * hold multiple values within one Text Frame. the #getValue() method will return all values within the * frame but this method lets you retrieve just the individual values. *

* * @param id * @param n * @return */ public String getSubValue(FieldKey id, int n, int m); /** * Retrieve the first field that exists for this format specific key *

*

Can be used to retrieve fields with any identifier, useful if the identifier is not within {@link FieldKey} * * @param id audio specific key * @return tag field or null if doesn't exist */ public TagField getFirstField(String id); /** * @param id * @return the first field that matches this generic key */ public TagField getFirstField(FieldKey id); /** * Returns true, if at least one of the contained * {@linkplain TagField fields} is a common field ({@link TagField#isCommon()}). * * @return true if a {@linkplain TagField#isCommon() common} * field is present. */ public boolean hasCommonFields(); /** * Determines whether the tag has at least one field with the specified * "id". * * @param id The field id to look for. * @return true if tag contains a {@link TagField} with the * given {@linkplain TagField#getId() id}. */ public boolean hasField(String id); /** * Determines whether the tag has no fields specified.
* * @return true if tag contains no field. */ public boolean isEmpty(); //TODO, do we need this public String toString(); /** * Return the number of fields *

*

Fields with the same identifiers are counted separately * * i.e two TITLE fields in a Vorbis Comment file would count as two * * @return total number of fields */ public int getFieldCount(); /** * Return the number of fields taking multiple value fields into consideration * * Fields that actually contain multiple values are counted seperately * * i.e. a TCON frame in ID3v24 frame containing multiple genres would add to count for each genre. * * @return total number of fields taking multiple value fields into consideration */ public int getFieldCountIncludingSubValues(); //TODO is this a special field? public boolean setEncoding(String enc) throws FieldDataInvalidException; /** * @return a list of all artwork in this file using the format indepedent Artwork class */ public List getArtworkList(); /** * @return first artwork or null if none exist */ public Artwork getFirstArtwork(); /** * Delete any instance of tag fields used to store artwork * *

We need this additional deleteField method because in some formats artwork can be stored * in multiple fields * * @throws KeyNotFoundException */ public void deleteArtworkField() throws KeyNotFoundException; /** * Create artwork field based on the data in artwork * * @param artwork * @return suitable tagfield for this format that represents the artwork data * @throws FieldDataInvalidException */ public TagField createField(Artwork artwork) throws FieldDataInvalidException; /** * Create artwork field based on the data in artwork and then set it in the tag itself *

* * @param artwork * @throws FieldDataInvalidException */ public void setField(Artwork artwork) throws FieldDataInvalidException; /** * Create artwork field based on the data in artwork and then add it to the tag itself *

* * @param artwork * @throws FieldDataInvalidException */ public void addField(Artwork artwork) throws FieldDataInvalidException; /** * Sets a field in the structure, used internally by the library
*

* * @param field The field to add. * @throws FieldDataInvalidException */ public void setField(TagField field) throws FieldDataInvalidException; /** * Adds a field to the structure, used internally by the library
*

* * @param field The field to add. * @throws FieldDataInvalidException */ public void addField(TagField field) throws FieldDataInvalidException; /** * Create a new field based on generic key, used internally by the library *

*

Only textual data supported at the moment. The genericKey will be mapped * to the correct implementation key and return a TagField. *

* * @param genericKey is the generic key * @param value to store * @return * @throws KeyNotFoundException * @throws FieldDataInvalidException */ public TagField createField(FieldKey genericKey, String value) throws KeyNotFoundException, FieldDataInvalidException; }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/reference/0000755000175000017500000000000011556363175024233 5ustar drazzibdrazziblibjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/reference/GenreTypes.java0000644000175000017500000002052511277460143027160 0ustar drazzibdrazzib/** * @author : Paul Taylor *

* Version @version:$Id: GenreTypes.java 848 2009-11-14 07:46:43Z paultaylor $ *

* Jaudiotagger Copyright (C)2004,2005 *

* This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. *

* This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. *

* You should have received a copy of the GNU Lesser General Public License ainteger with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *

* Description: */ package org.jaudiotagger.tag.reference; import org.jaudiotagger.tag.datatype.AbstractIntStringValuePair; import java.util.LinkedHashMap; import java.util.Map; /** * Genre list *

*

This is the IDv1 list with additional values as defined by Winamp, this list is also used in Mp4 * files, note iTunes doesn't understand genres above MAX_STANDARD_GENRE_ID, Winamp does

*/ public class GenreTypes extends AbstractIntStringValuePair { private static int MAX_STANDARD_GENRE_ID = 125; /** * @return the maximum genreId that is part of the official Standard, genres above this were added by * Winamp later. */ public static int getMaxStandardGenreId() { return MAX_STANDARD_GENRE_ID; } private static GenreTypes genreTypes; public static GenreTypes getInstanceOf() { if (genreTypes == null) { genreTypes = new GenreTypes(); } return genreTypes; } //This maps the lowercase version to the id, so applications can map from the lowercase value to the id private Map nameToIdMap; private GenreTypes() { idToValue.put(0, "Blues"); idToValue.put(1, "Classic Rock"); idToValue.put(2, "Country"); idToValue.put(3, "Dance"); idToValue.put(4, "Disco"); idToValue.put(5, "Funk"); idToValue.put(6, "Grunge"); idToValue.put(7, "Hip-Hop"); idToValue.put(8, "Jazz"); idToValue.put(9, "Metal"); idToValue.put(10, "New Age"); idToValue.put(11, "Oldies"); idToValue.put(12, "Other"); idToValue.put(13, "Pop"); idToValue.put(14, "R&B"); idToValue.put(15, "Rap"); idToValue.put(16, "Reggae"); idToValue.put(17, "Rock"); idToValue.put(18, "Techno"); idToValue.put(19, "Industrial"); idToValue.put(20, "Alternative"); idToValue.put(21, "Ska"); idToValue.put(22, "Death Metal"); idToValue.put(23, "Pranks"); idToValue.put(24, "Soundtrack"); idToValue.put(25, "Euro-Techno"); idToValue.put(26, "Ambient"); idToValue.put(27, "Trip-Hop"); idToValue.put(28, "Vocal"); idToValue.put(29, "Jazz+Funk"); idToValue.put(30, "Fusion"); idToValue.put(31, "Trance"); idToValue.put(32, "Classical"); idToValue.put(33, "Instrumental"); idToValue.put(34, "Acid"); idToValue.put(35, "House"); idToValue.put(36, "Game"); idToValue.put(37, "Sound Clip"); idToValue.put(38, "Gospel"); idToValue.put(39, "Noise"); idToValue.put(40, "AlternRock"); idToValue.put(41, "Bass"); idToValue.put(42, "Soul"); idToValue.put(43, "Punk"); idToValue.put(44, "Space"); idToValue.put(45, "Meditative"); idToValue.put(46, "Instrumental Pop"); idToValue.put(47, "Instrumental Rock"); idToValue.put(48, "Ethnic"); idToValue.put(49, "Gothic"); idToValue.put(50, "Darkwave"); idToValue.put(51, "Techno-Industrial"); idToValue.put(52, "Electronic"); idToValue.put(53, "Pop-Folk"); idToValue.put(54, "Eurodance"); idToValue.put(55, "Dream"); idToValue.put(56, "Southern Rock"); idToValue.put(57, "Comedy"); idToValue.put(58, "Cult"); idToValue.put(59, "Gangsta"); idToValue.put(60, "Top 40"); idToValue.put(61, "Christian Rap"); idToValue.put(62, "Pop/Funk"); idToValue.put(63, "Jungle"); idToValue.put(64, "Native American"); idToValue.put(65, "Cabaret"); idToValue.put(66, "New Wave"); idToValue.put(67, "Psychadelic"); idToValue.put(68, "Rave"); idToValue.put(69, "Showtunes"); idToValue.put(70, "Trailer"); idToValue.put(71, "Lo-Fi"); idToValue.put(72, "Tribal"); idToValue.put(73, "Acid Punk"); idToValue.put(74, "Acid Jazz"); idToValue.put(75, "Polka"); idToValue.put(76, "Retro"); idToValue.put(77, "Musical"); idToValue.put(78, "Rock & Roll"); idToValue.put(79, "Hard Rock"); idToValue.put(80, "Folk"); idToValue.put(81, "Folk-Rock"); idToValue.put(82, "National Folk"); idToValue.put(83, "Swing"); idToValue.put(84, "Fast Fusion"); idToValue.put(85, "Bebob"); idToValue.put(86, "Latin"); idToValue.put(87, "Revival"); idToValue.put(88, "Celtic"); idToValue.put(89, "Bluegrass"); idToValue.put(90, "Avantgarde"); idToValue.put(91, "Gothic Rock"); idToValue.put(92, "Progressive Rock"); idToValue.put(93, "Psychedelic Rock"); idToValue.put(94, "Symphonic Rock"); idToValue.put(95, "Slow Rock"); idToValue.put(96, "Big Band"); idToValue.put(97, "Chorus"); idToValue.put(98, "Easy Listening"); idToValue.put(99, "Acoustic"); idToValue.put(100, "Humour"); idToValue.put(101, "Speech"); idToValue.put(102, "Chanson"); idToValue.put(103, "Opera"); idToValue.put(104, "Chamber Music"); idToValue.put(105, "Sonata"); idToValue.put(106, "Symphony"); idToValue.put(107, "Booty Bass"); idToValue.put(108, "Primus"); idToValue.put(109, "Porn Groove"); idToValue.put(110, "Satire"); idToValue.put(111, "Slow Jam"); idToValue.put(112, "Club"); idToValue.put(113, "Tango"); idToValue.put(114, "Samba"); idToValue.put(115, "Folklore"); idToValue.put(116, "Ballad"); idToValue.put(117, "Power Ballad"); idToValue.put(118, "Rhythmic Soul"); idToValue.put(119, "Freestyle"); idToValue.put(120, "Duet"); idToValue.put(121, "Punk Rock"); idToValue.put(122, "Drum Solo"); idToValue.put(123, "Acapella"); idToValue.put(124, "Euro-House"); idToValue.put(125, "Dance Hall"); idToValue.put(126, "Goa"); idToValue.put(127, "Drum & Bass"); idToValue.put(128, "Club-House"); idToValue.put(129, "Hardcore"); idToValue.put(130, "Terror"); idToValue.put(131, "Indie"); idToValue.put(132, "BritPop"); idToValue.put(133, "Negerpunk"); idToValue.put(134, "Polsk Punk"); idToValue.put(135, "Beat"); idToValue.put(136, "Christian Gangsta Rap"); idToValue.put(137, "Heavy Metal"); idToValue.put(138, "Black Metal"); idToValue.put(139, "Crossover"); idToValue.put(140, "Contemporary Christian"); idToValue.put(141, "Christian Rock"); idToValue.put(142, "Merengue"); idToValue.put(143, "Salsa"); idToValue.put(144, "Thrash Metal"); idToValue.put(145, "Anime"); idToValue.put(146, "JPop"); idToValue.put(147, "SynthPop"); createMaps(); //We now need to map from lowercase version to Id nameToIdMap = new LinkedHashMap(idToValue.size()); for (Map.Entry entry : idToValue.entrySet()) { nameToIdMap.put(entry.getValue().toLowerCase(), entry.getKey()); } } /** * Get Id for name, match is not case sensitive * @param name * @return */ public Integer getIdForName(String name) { return nameToIdMap.get(name.toLowerCase()); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/reference/MusicalKey.java0000644000175000017500000000440011277026507027135 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.reference; import java.util.EnumSet; import java.util.HashMap; /** * Musical key used by the Key tagFieldKey * * It is not enforced but can be used to verify the Musical key according to the ID3 specification of the TKEY field */ public enum MusicalKey { NOTE_A("A"), NOTE_B("B"), NOTE_C("C"), NOTE_D("D"), NOTE_E("E"), NOTE_F("F"), NOTE_G("G"), FLAT("b"), SHARP("#"), MINOR("m"), OFF_KEY("o"); private String value; MusicalKey(String value) { this.value=value; } public String getValue() { return value; } private static final int MAX_KEY_LENGTH = 3; private final static HashMap groundKeyMap; private final static HashMap halfKeyMap; static { EnumSet groundKey = EnumSet.of(NOTE_A, NOTE_B, NOTE_C, NOTE_D, NOTE_E, NOTE_F, NOTE_G); groundKeyMap = new HashMap(MusicalKey.values().length); for (MusicalKey curr : groundKey) { groundKeyMap.put(curr.getValue(), curr); } EnumSet halfKey = EnumSet.of(FLAT, SHARP, MINOR); halfKeyMap = new HashMap(MusicalKey.values().length); for (MusicalKey curr : halfKey) { halfKeyMap.put(curr.getValue(), curr); } } public static boolean isValid(String musicalKey) { if(musicalKey==null || musicalKey.length()>MAX_KEY_LENGTH || musicalKey.length()==0) { return false; } if(musicalKey.length()==1) { if(musicalKey.equals(OFF_KEY.getValue())) { return true; } } if(!groundKeyMap.containsKey(musicalKey.substring(0,1))) { return false; } if(musicalKey.length()==2||musicalKey.length()==3) { if(!halfKeyMap.containsKey(musicalKey.substring(1,2))) { return false; } } if(musicalKey.length()==3) { if(!musicalKey.substring(2,3).equals(MINOR.getValue())) { return false; } } return true; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/reference/Languages.java0000644000175000017500000005354011470746136027010 0ustar drazzibdrazzib/** * @author : Paul Taylor *

* Version @version:$Id: Languages.java 929 2010-11-17 12:36:46Z paultaylor $ *

* Jaudiotagger Copyright (C)2004,2005 *

* This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. *

* This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. *

* You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *

* Description: * Valid Languages for ID Tags */ package org.jaudiotagger.tag.reference; import org.jaudiotagger.tag.datatype.AbstractStringStringValuePair; public class Languages extends AbstractStringStringValuePair { public static final String DEFAULT_ID = "eng"; public static final String MEDIA_MONKEY_ID = "XXX"; public static final String WINAMP_ID = "\0\0\0"; public static final String DEFAULT_VALUE = "English"; //The number of bytes used to hold the language field size public static final int LANGUAGE_FIELD_SIZE = 3; private static Languages languageTypes; public static Languages getInstanceOf() { if (languageTypes == null) { languageTypes = new Languages(); } return languageTypes; } private Languages() { idToValue.put("aar", "Afar"); idToValue.put("abk", "Abkhazian"); idToValue.put("ace", "Achinese"); idToValue.put("ach", "Acoli"); idToValue.put("ada", "Adangme"); idToValue.put("afa", "Afro-Asiatic (Other)"); idToValue.put("afh", "Afrihili"); idToValue.put("afr", "Afrikaans"); idToValue.put("aka", "Akan"); idToValue.put("akk", "Akkadian"); idToValue.put("alb", "Albanian"); idToValue.put("ale", "Aleut"); idToValue.put("alg", "Algonquian languages"); idToValue.put("amh", "Amharic"); idToValue.put("ang", "English, Old (ca.450-1100)"); idToValue.put("apa", "Apache languages"); idToValue.put("ara", "Arabic"); idToValue.put("arc", "Aramaic"); idToValue.put("arm", "Armenian"); idToValue.put("arn", "Araucanian"); idToValue.put("arp", "Arapaho"); idToValue.put("art", "Artificial (Other)"); idToValue.put("arw", "Arawak"); idToValue.put("asm", "Assamese"); idToValue.put("ast", "Asturian; Bable"); idToValue.put("ath", "Athapascan languages"); idToValue.put("aus", "Australian languages"); idToValue.put("ava", "Avaric"); idToValue.put("ave", "Avestan"); idToValue.put("awa", "Awadhi"); idToValue.put("aym", "Aymara"); idToValue.put("aze", "Azerbaijani"); idToValue.put("bad", "Banda"); idToValue.put("bai", "Bamileke languages"); idToValue.put("bak", "Bashkir"); idToValue.put("bal", "Baluchi"); idToValue.put("bam", "Bambara"); idToValue.put("ban", "Balinese"); idToValue.put("baq", "Basque"); idToValue.put("bas", "Basa"); idToValue.put("bat", "Baltic (Other)"); idToValue.put("bej", "Beja"); idToValue.put("bel", "Belarusian"); idToValue.put("bem", "Bemba"); idToValue.put("ben", "Bengali"); idToValue.put("ber", "Berber (Other)"); idToValue.put("bho", "Bhojpuri"); idToValue.put("bih", "Bihari"); idToValue.put("bik", "Bikol"); idToValue.put("bin", "Bini"); idToValue.put("bis", "Bislama"); idToValue.put("bla", "Siksika"); idToValue.put("bnt", "Bantu (Other)"); idToValue.put("bod", "Tibetan"); idToValue.put("bos", "Bosnian"); idToValue.put("bra", "Braj"); idToValue.put("bre", "Breton"); idToValue.put("btk", "Batak (Indonesia)"); idToValue.put("bua", "Buriat"); idToValue.put("bug", "Buginese"); idToValue.put("bul", "Bulgarian"); idToValue.put("bur", "Burmese"); idToValue.put("cad", "Caddo"); idToValue.put("cai", "Central American Indian (Other)"); idToValue.put("car", "Carib"); idToValue.put("cat", "Catalan"); idToValue.put("cau", "Caucasian (Other)"); idToValue.put("ceb", "Cebuano"); idToValue.put("cel", "Celtic (Other)"); idToValue.put("ces", "Czech"); idToValue.put("cha", "Chamorro"); idToValue.put("chb", "Chibcha"); idToValue.put("che", "Chechen"); idToValue.put("chg", "Chagatai"); idToValue.put("chi", "Chinese"); idToValue.put("chk", "Chuukese"); idToValue.put("chm", "Mari"); idToValue.put("chn", "Chinook jargon"); idToValue.put("cho", "Choctaw"); idToValue.put("chp", "Chipewyan"); idToValue.put("chr", "Cherokee"); idToValue.put("chu", "Church Slavic; Old Slavonic; Old Church Slavonic; Church Slavonic; Old Bulgarian"); idToValue.put("chv", "Chuvash"); idToValue.put("chy", "Cheyenne"); idToValue.put("cmc", "Chamic languages"); idToValue.put("cop", "Coptic"); idToValue.put("cor", "Cornish"); idToValue.put("cos", "Corsican"); idToValue.put("cpe", "Creoles and pidgins, English based (Other)"); idToValue.put("cpf", "Creoles and pidgins, French-based (Other)"); idToValue.put("cpp", "Creoles and pidgins,"); idToValue.put("cre", "Cree"); idToValue.put("crp", "Creoles and pidgins (Other)"); idToValue.put("cus", "Cushitic (Other)"); idToValue.put("cym", "Welsh"); idToValue.put("cze", "Czech"); idToValue.put("dak", "Dakota"); idToValue.put("dan", "Danish"); idToValue.put("day", "Dayak"); idToValue.put("del", "Delaware"); idToValue.put("den", "Slave (Athapascan)"); idToValue.put("deu", "German"); idToValue.put("dgr", "Dogrib"); idToValue.put("din", "Dinka"); idToValue.put("div", "Divehi"); idToValue.put("doi", "Dogri"); idToValue.put("dra", "Dravidian (Other)"); idToValue.put("dua", "Duala"); idToValue.put("dum", "Dutch, Middle (ca.1050-1350)"); idToValue.put("dut", "Dutch"); idToValue.put("dyu", "Dyula"); idToValue.put("dzo", "Dzongkha"); idToValue.put("efi", "Efik"); idToValue.put("egy", "Egyptian (Ancient)"); idToValue.put("eka", "Ekajuk"); idToValue.put("ell", "Greek, Modern (1453-)"); idToValue.put("elx", "Elamite"); idToValue.put("eng", "English"); idToValue.put("enm", "English, Middle (1100-1500)"); idToValue.put("epo", "Esperanto"); idToValue.put("est", "Estonian"); idToValue.put("eus", "Basque"); idToValue.put("ewe", "Ewe"); idToValue.put("ewo", "Ewondo"); idToValue.put("fan", "Fang"); idToValue.put("fao", "Faroese"); idToValue.put("fas", "Persian"); idToValue.put("fat", "Fanti"); idToValue.put("fij", "Fijian"); idToValue.put("fin", "Finnish"); idToValue.put("fiu", "Finno-Ugrian (Other)"); idToValue.put("fon", "Fon"); idToValue.put("fra", "French"); idToValue.put("frm", "French, Middle (ca.1400-1800)"); idToValue.put("fro", "French, Old (842-ca.1400)"); idToValue.put("fry", "Frisian"); idToValue.put("ful", "Fulah"); idToValue.put("fur", "Friulian"); idToValue.put("gaa", "Ga"); idToValue.put("gay", "Gayo"); idToValue.put("gba", "Gbaya"); idToValue.put("gem", "Germanic (Other)"); idToValue.put("geo", "Georgian"); idToValue.put("ger", "German"); idToValue.put("gez", "Geez"); idToValue.put("gil", "Gilbertese"); idToValue.put("gla", "Gaelic; Scottish Gaelic"); idToValue.put("gle", "Irish"); idToValue.put("glg", "Gallegan"); idToValue.put("glv", "Manx"); idToValue.put("gmh", "German, Middle High (ca.1050-1500)"); idToValue.put("goh", "German, Old High (ca.750-1050)"); idToValue.put("gon", "Gondi"); idToValue.put("gor", "Gorontalo"); idToValue.put("got", "Gothic"); idToValue.put("grb", "Grebo"); idToValue.put("grc", "Greek, Ancient (to 1453)"); idToValue.put("gre", "Greek, Modern (1453-)"); idToValue.put("grn", "Guarani"); idToValue.put("guj", "Gujarati"); idToValue.put("gwi", "Gwich´in"); idToValue.put("hai", "Haida"); idToValue.put("hau", "Hausa"); idToValue.put("haw", "Hawaiian"); idToValue.put("heb", "Hebrew"); idToValue.put("her", "Herero"); idToValue.put("hil", "Hiligaynon"); idToValue.put("him", "Himachali"); idToValue.put("hin", "Hindi"); idToValue.put("hit", "Hittite"); idToValue.put("hmn", "Hmong"); idToValue.put("hmo", "Hiri Motu"); idToValue.put("hrv", "Croatian"); idToValue.put("hun", "Hungarian"); idToValue.put("hup", "Hupa"); idToValue.put("hye", "Armenian"); idToValue.put("iba", "Iban"); idToValue.put("ibo", "Igbo"); idToValue.put("ice", "Icelandic"); idToValue.put("ido", "Ido"); idToValue.put("ijo", "Ijo"); idToValue.put("iku", "Inuktitut"); idToValue.put("ile", "Interlingue"); idToValue.put("ilo", "Iloko"); idToValue.put("ina", "Interlingua (International Auxiliary)"); idToValue.put("inc", "Indic (Other)"); idToValue.put("ind", "Indonesian"); idToValue.put("ine", "Indo-European (Other)"); idToValue.put("ipk", "Inupiaq"); idToValue.put("ira", "Iranian (Other)"); idToValue.put("iro", "Iroquoian languages"); idToValue.put("isl", "Icelandic"); idToValue.put("ita", "Italian"); idToValue.put("jav", "Javanese"); idToValue.put("jpn", "Japanese"); idToValue.put("jpr", "Judeo-Persian"); idToValue.put("jrb", "Judeo-Arabic"); idToValue.put("kaa", "Kara-Kalpak"); idToValue.put("kab", "Kabyle"); idToValue.put("kac", "Kachin"); idToValue.put("kal", "Kalaallisut"); idToValue.put("kam", "Kamba"); idToValue.put("kan", "Kannada"); idToValue.put("kar", "Karen"); idToValue.put("kas", "Kashmiri"); idToValue.put("kat", "Georgian"); idToValue.put("kau", "Kanuri"); idToValue.put("kaw", "Kawi"); idToValue.put("kaz", "Kazakh"); idToValue.put("kha", "Khasi"); idToValue.put("khi", "Khoisan (Other)"); idToValue.put("khm", "Khmer"); idToValue.put("kho", "Khotanese"); idToValue.put("kik", "Kikuyu; Gikuyu"); idToValue.put("kin", "Kinyarwanda"); idToValue.put("kir", "Kirghiz"); idToValue.put("kmb", "Kimbundu"); idToValue.put("kok", "Konkani"); idToValue.put("kom", "Komi"); idToValue.put("kon", "Kongo"); idToValue.put("kor", "Korean"); idToValue.put("kos", "Kosraean"); idToValue.put("kpe", "Kpelle"); idToValue.put("kro", "Kru"); idToValue.put("kru", "Kurukh"); idToValue.put("kua", "Kuanyama; Kwanyama"); idToValue.put("kum", "Kumyk"); idToValue.put("kur", "Kurdish"); idToValue.put("kut", "Kutenai"); idToValue.put("lad", "Ladino"); idToValue.put("lah", "Lahnda"); idToValue.put("lam", "Lamba"); idToValue.put("lao", "Lao"); idToValue.put("lat", "Latin"); idToValue.put("lav", "Latvian"); idToValue.put("lez", "Lezghian"); idToValue.put("lin", "Lingala"); idToValue.put("lit", "Lithuanian"); idToValue.put("lol", "Mongo"); idToValue.put("loz", "Lozi"); idToValue.put("ltz", "Luxembourgish; Letzeburgesch"); idToValue.put("lua", "Luba-Lulua"); idToValue.put("lub", "Luba-Katanga"); idToValue.put("lug", "Ganda"); idToValue.put("lui", "Luiseno"); idToValue.put("lun", "Lunda"); idToValue.put("luo", "Luo (Kenya and Tanzania)"); idToValue.put("lus", "lushai"); idToValue.put("mac", "Macedonian"); idToValue.put("mad", "Madurese"); idToValue.put("mag", "Magahi"); idToValue.put("mah", "Marshallese"); idToValue.put("mai", "Maithili"); idToValue.put("mak", "Makasar"); idToValue.put("mal", "Malayalam"); idToValue.put("man", "Mandingo"); idToValue.put("mao", "Maori"); idToValue.put("map", "Austronesian (Other)"); idToValue.put("mar", "Marathi"); idToValue.put("mas", "Masai"); idToValue.put("may", "Malay"); idToValue.put("mdr", "Mandar"); idToValue.put("men", "Mende"); idToValue.put("mga", "Irish, Middle (900-1200)"); idToValue.put("mic", "Micmac"); idToValue.put("min", "Minangkabau"); idToValue.put("mis", "Miscellaneous languages"); idToValue.put("mkd", "Macedonian"); idToValue.put("mkh", "Mon-Khmer (Other)"); idToValue.put("mlg", "Malagasy"); idToValue.put("mlt", "Maltese"); idToValue.put("mnc", "Manchu"); idToValue.put("mni", "Manipuri"); idToValue.put("mno", "Manobo languages"); idToValue.put("moh", "Mohawk"); idToValue.put("mol", "Moldavian"); idToValue.put("mon", "Mongolian"); idToValue.put("mos", "Mossi"); idToValue.put("mri", "Maori"); idToValue.put("msa", "Malay"); idToValue.put("mul", "Multiple languages"); idToValue.put("mun", "Munda languages"); idToValue.put("mus", "Creek"); idToValue.put("mwr", "Marwari"); idToValue.put("mya", "Burmese"); idToValue.put("myn", "Mayan languages"); idToValue.put("nah", "Nahuatl"); idToValue.put("nai", "North American Indian"); idToValue.put("nau", "Nauru"); idToValue.put("nav", "Navajo; Navaho"); idToValue.put("nbl", "South Ndebele"); idToValue.put("nde", "North Ndebele"); idToValue.put("ndo", "Ndonga"); idToValue.put("nds", "Low German; Low Saxon; German, Low; Saxon, Low"); idToValue.put("nep", "Nepali"); idToValue.put("new", "Newari"); idToValue.put("nia", "Nias"); idToValue.put("nic", "Niger-Kordofanian (Other)"); idToValue.put("niu", "Niuean"); idToValue.put("nld", "Dutch"); idToValue.put("nno", "Norwegian Nynorsk"); idToValue.put("nob", "Norwegian Bokmål"); idToValue.put("non", "Norse, Old"); idToValue.put("nor", "Norwegian"); idToValue.put("nso", "Sotho, Northern"); idToValue.put("nub", "Nubian languages"); idToValue.put("nya", "Chichewa; Chewa; Nyanja"); idToValue.put("nym", "Nyamwezi"); idToValue.put("nyn", "Nyankole"); idToValue.put("nyo", "Nyoro"); idToValue.put("nzi", "Nzima"); idToValue.put("oci", "Occitan (post 1500); Provençal"); idToValue.put("oji", "Ojibwa"); idToValue.put("ori", "Oriya"); idToValue.put("orm", "Oromo"); idToValue.put("osa", "Osage"); idToValue.put("oss", "Ossetian; Ossetic"); idToValue.put("ota", "Turkish, Ottoman (1500-1928)"); idToValue.put("oto", "Otomian languages"); idToValue.put("paa", "Papuan (Other)"); idToValue.put("pag", "Pangasinan"); idToValue.put("pal", "Pahlavi"); idToValue.put("pam", "Pampanga"); idToValue.put("pan", "Panjabi"); idToValue.put("pap", "Papiamento"); idToValue.put("pau", "Palauan"); idToValue.put("peo", "Persian, Old (ca.600-400 B.C.)"); idToValue.put("per", "Persian"); idToValue.put("per", "Persian"); idToValue.put("phi", "Philippine (Other)"); idToValue.put("phn", "Phoenician"); idToValue.put("pli", "Pali"); idToValue.put("pol", "Polish"); idToValue.put("pon", "Pohnpeian"); idToValue.put("por", "Portuguese"); idToValue.put("pra", "Prakrit languages"); idToValue.put("pro", "Provençal, Old (to 1500)"); idToValue.put("pus", "Pushto"); idToValue.put("que", "Quechua"); idToValue.put("raj", "Rajasthani"); idToValue.put("rap", "Rapanui"); idToValue.put("rar", "Rarotongan"); idToValue.put("roa", "Romance (Other)"); idToValue.put("roh", "Raeto-Romance"); idToValue.put("rom", "Romany"); idToValue.put("ron", "Romanian"); idToValue.put("rum", "Romanian"); idToValue.put("run", "Rundi"); idToValue.put("rus", "Russian"); idToValue.put("sad", "Sandawe"); idToValue.put("sag", "Sango"); idToValue.put("sah", "Yakut"); idToValue.put("sai", "South American Indian (Other)"); idToValue.put("sal", "Salishan languages"); idToValue.put("sam", "Samaritan Aramaic"); idToValue.put("san", "Sanskrit"); idToValue.put("sas", "Sasak"); idToValue.put("sat", "Santali"); idToValue.put("scc", "Serbian"); idToValue.put("sco", "Scots"); idToValue.put("scr", "Croatian"); idToValue.put("sel", "Selkup"); idToValue.put("sem", "Semitic (Other)"); idToValue.put("sga", "Irish, Old (to 900)"); idToValue.put("sgn", "Sign languages"); idToValue.put("shn", "Shan"); idToValue.put("sid", "Sidamo"); idToValue.put("sin", "Sinhales"); idToValue.put("sio", "Siouan languages"); idToValue.put("sit", "Sino-Tibetan (Other)"); idToValue.put("sla", "Slavic (Other)"); idToValue.put("slk", "Slovak"); idToValue.put("slo", "Slovak"); idToValue.put("slv", "Slovenian"); idToValue.put("sma", "Southern Sami"); idToValue.put("sme", "Northern Sami"); idToValue.put("smi", "Sami languages (Other)"); idToValue.put("smj", "Lule Sami"); idToValue.put("smn", "Inari Sami"); idToValue.put("smo", "Samoan"); idToValue.put("sms", "Skolt Sami"); idToValue.put("sna", "Shona"); idToValue.put("snd", "Sindhi"); idToValue.put("snk", "Soninke"); idToValue.put("sog", "Sogdian"); idToValue.put("som", "Somali"); idToValue.put("son", "Songhai"); idToValue.put("sot", "Sotho, Southern"); idToValue.put("spa", "Spanish; Castilia"); idToValue.put("sqi", "Albanian"); idToValue.put("srd", "Sardinian"); idToValue.put("srp", "Serbian"); idToValue.put("srr", "Serer"); idToValue.put("ssa", "Nilo-Saharan (Other)"); idToValue.put("sus", "Susu"); idToValue.put("sux", "Sumerian"); idToValue.put("swa", "Swahili"); idToValue.put("swe", "Swedish"); idToValue.put("syr", "Syriac"); idToValue.put("tah", "Tahitian"); idToValue.put("tai", "Tai (Other)"); idToValue.put("tam", "Tamil"); idToValue.put("tat", "Tatar"); idToValue.put("tel", "Telugu"); idToValue.put("tem", "Timne"); idToValue.put("ter", "Tereno"); idToValue.put("tet", "Tetum"); idToValue.put("tgk", "Tajik"); idToValue.put("tgl", "Tagalog"); idToValue.put("tha", "Thai"); idToValue.put("tib", "Tibetan"); idToValue.put("tig", "Tigre"); idToValue.put("tir", "Tigrinya"); idToValue.put("tiv", "Tiv"); idToValue.put("tkl", "Tokelau"); idToValue.put("tli", "Tlingit"); idToValue.put("tmh", "Tamashek"); idToValue.put("tog", "Tonga (Nyasa)"); idToValue.put("ton", "Tonga (Tonga Islands)"); idToValue.put("tpi", "Tok Pisin"); idToValue.put("tsi", "Tsimshian"); idToValue.put("tsn", "Tswana"); idToValue.put("tso", "Tsonga"); idToValue.put("tuk", "Turkmen"); idToValue.put("tum", "Tumbuka"); idToValue.put("tup", "Tupi languages"); idToValue.put("tur", "Turkish"); idToValue.put("tut", "Altaic (Other)"); idToValue.put("tvl", "Tuvalu"); idToValue.put("twi", "Twi"); idToValue.put("tyv", "Tuvinian"); idToValue.put("uga", "Ugaritic"); idToValue.put("uig", "Uighur"); idToValue.put("ukr", "Ukrainian"); idToValue.put("umb", "Umbundu"); idToValue.put("und", "Undetermined"); idToValue.put("urd", "Urdu"); idToValue.put("uzb", "Uzbek"); idToValue.put("vai", "Vai"); idToValue.put("ven", "Venda"); idToValue.put("vie", "Vietnamese"); idToValue.put("vol", "Volapük"); idToValue.put("vot", "Votic"); idToValue.put("wak", "Wakashan languages"); idToValue.put("wal", "Walamo"); idToValue.put("war", "Waray"); idToValue.put("was", "Washo"); idToValue.put("wel", "Welsh"); idToValue.put("wen", "Sorbian languages"); idToValue.put("wln", "Walloon"); idToValue.put("wol", "Wolof"); idToValue.put("xho", "Xhosa"); idToValue.put("yao", "Yao"); idToValue.put("yap", "Yapese"); idToValue.put("yid", "Yiddish"); idToValue.put("yor", "Yoruba"); idToValue.put("ypk", "Yupik languages"); idToValue.put("zap", "Zapotec"); idToValue.put("zen", "Zenaga"); idToValue.put("zha", "Zhuang; Chuang"); idToValue.put("zho", "Chinese"); idToValue.put("znd", "Zande"); idToValue.put("zul", "Zulu"); idToValue.put("zun", "Zuni"); idToValue.put("\0\0\0", "Winamp Format"); //Not Part of Spec but commonly used by some applications idToValue.put("XXX", "Media Monkey Format"); //Not Part of Spec but commonly used by some applications createMaps(); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/reference/PictureTypes.java0000644000175000017500000000553111123715062027524 0ustar drazzibdrazzib/** * @author : Paul Taylor *

* Version @version:$Id: PictureTypes.java 775 2008-12-22 13:46:26Z paultaylor $ *

* Jaudiotagger Copyright (C)2004,2005 *

* This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. *

* This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. *

* You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *

* Description: * Valid Picture Types in ID3 */ package org.jaudiotagger.tag.reference; import org.jaudiotagger.tag.datatype.AbstractIntStringValuePair; /** * Pictures types for Attached Pictures *

*

Note this list is used by APIC and PIC frames within ID3v2. It is also used by Flac format Picture blocks * and WMA Picture fields. */ public class PictureTypes extends AbstractIntStringValuePair { private static PictureTypes pictureTypes; public static PictureTypes getInstanceOf() { if (pictureTypes == null) { pictureTypes = new PictureTypes(); } return pictureTypes; } public static final int PICTURE_TYPE_FIELD_SIZE = 1; public static final String DEFAULT_VALUE = "Cover (front)"; public static final Integer DEFAULT_ID = 3; private PictureTypes() { idToValue.put(0, "Other"); idToValue.put(1, "32x32 pixels 'file icon' (PNG only)"); idToValue.put(2, "Other file icon"); idToValue.put(3, "Cover (front)"); idToValue.put(4, "Cover (back)"); idToValue.put(5, "Leaflet page"); idToValue.put(6, "Media (e.g. label side of CD)"); idToValue.put(7, "Lead artist/lead performer/soloist"); idToValue.put(8, "Artist/performer"); idToValue.put(9, "Conductor"); idToValue.put(10, "Band/Orchestra"); idToValue.put(11, "Composer"); idToValue.put(12, "Lyricist/text writer"); idToValue.put(13, "Recording Location"); idToValue.put(14, "During recording"); idToValue.put(15, "During performance"); idToValue.put(16, "Movie/video screen capture"); idToValue.put(17, "A bright coloured fish"); idToValue.put(18, "Illustration"); idToValue.put(19, "Band/artist logotype"); idToValue.put(20, "Publisher/Studio logotype"); createMaps(); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/reference/Tagger.java0000644000175000017500000000102111470746136026276 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.reference; /** * An enumeration of popular tagger applications *

*

This is not meant to be a definitive list but is first attempt to document a list of taggers in order * for us to link nonstandard fields, and link nonstandard tagging to them */ public enum Tagger { ITUNES, MEDIAPLAYER, WINAMP, MP3TAG, MEDIA_MONKEY, TAG_AND_RENAME, PICARD, JAIKOZ, TAGSCANNER, XIPH, //standards body rather than tagger xiph.org FOOBAR2000, BEATUNES } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/tag/reference/ISOCountry.java0000644000175000017500000002707711244776540027127 0ustar drazzibdrazzibpackage org.jaudiotagger.tag.reference; import java.util.HashMap; import java.util.Map; /** * Represents the ISO 3166-1 Country List with ISO 3166-1-alpha-2 code *

* Contains an enum of countries, their two letter code and description * with additional method to allow an enum to be found by its two letter code or its description. * More details at http://www.iso.org/iso/country_codes/iso_3166_code_lists/english_country_names_and_code_elements.htm#c */ public class ISOCountry { private static Map codeMap; private static Map descriptionMap; static { codeMap = new HashMap(); for (Country country : Country.values()) { codeMap.put(country.code, country); } descriptionMap = new HashMap(); for (Country country : Country.values()) { descriptionMap.put(country.description, country); } } /** * @param code * @return enum with this two letter code */ public static Country getCountryByCode(String code) { return codeMap.get(code); } /** * @param description * @return enum with this description */ public static Country getCountryByDescription(String description) { return descriptionMap.get(description); } /** * List of valid Iso Country, shows 2 letter abbreviation and country human readable name */ public static enum Country { AFGHANISTAN(" AF", "Afghanistan"), ALAND_ISLANDS("AX", "\u00e5land Islands"), ALBANIA("AL", "Albania"), ALGERIA("DZ", "Algeria"), AMERICAN_SAMOA("AS", "American Samoa"), ANDORRA("AD", "Andorra"), ANGOLA("AO", "Angola"), ANGUILLA("AI", "Anguilla"), ANTARCTICA("AQ", "Antarctica"), ANTIGUA_AND_BARBUDA("AG", "Antigua and Barbuda"), ARGENTINA("AR", "Argentina"), ARMENIA("AM", "Armenia"), ARUBA("AW", "Aruba"), AUSTRALIA("AU", "Australia"), AUSTRIA("AT", "Austria"), AZERBAIJAN("AZ", "Azerbaijan"), BAHAMAS("BS", "Bahamas"), BAHRAIN("BH", "Bahrain"), BANGLADESH("BD", "Bangladesh"), BARBADOS("BB", "Barbados"), BELARUS("BY", "Belarus"), BELGIUM("BE", "Belgium"), BELIZE("BZ", "Belize"), BENIN("BJ", "Benin"), BERMUDA("BM", "Bermuda"), BHUTAN("BT", "Bhutan"), BOLIVIA("BO", "Bolivia"), BOSNIA_AND_HERZEGOVINA("BA", "Bosnia and herzegovina"), BOTSWANA("BW", "Botswana"), BOUVET_ISLAND("BV", "Bouvet_Island"), BRAZIL("BR", "Brazil"), BRITISH_INDIAN_OCEAN_TERRITORY("IO", "British Indian Ocean Territory"), BRUNEI_DARUSSALAM("BN", "Brunei Darussalam"), BULGARIA("BG", "Bulgaria"), BURKINA_FASO("BF", "Burkina Faso"), BURUNDI("BI", "Burundi"), CAMBODIA("KH", "Cambodia"), CAMEROON("CM", "Cameroon"), CANADA("CA", "Canada"), CAPE_VERDE("CV", "Cape Verde"), CAYMAN_ISLANDS("KY", "Cayman Islands"), CENTRAL_AFRICAN_REPUBLIC("CF", "Central African Republic"), CHAD("TD", "Chad"), CHILE("CL", "Chile"), CHINA("CN", "China"), CHRISTMAS_ISLAND("CX", "Christmas Island"), COCOS_KEELING_ISLANDS("CC", "Cocos Keeling Islands"), COLOMBIA("CO", "Colombia"), COMOROS("KM", "Comoros"), CONGO("CG", "Congo"), THE_DEMOCRATIC_REPUBLIC_OF_CONGO("CD", "The Democratic Republic Of Congo"), COOK_ISLANDS("CK", "Cook Islands"), COSTA_RICA("CR", "Costa Rica"), COTE_D_IVOIRE("CI", "Ivory Coast"), CROATIA("HR", "Croatia"), CUBA("CU", "Cuba"), CYPRUS("CY", "Cyprus"), CZECH_REPUBLIC("CZ", "Czech Republic"), DENMARK("DK", "Denmark"), DJIBOUTI("DJ", "Djibouti"), DOMINICA("DM", "Dominica"), DOMINICAN_REPUBLIC("DO", "Dominican Republic"), ECUADOR("EC", "Ecuador"), EGYPT("EG", "Egypt"), EL_SALVADOR("SV", "El Salvador"), EQUATORIAL_GUINEA("GQ", "Equatorial Guinea"), ERITREA("ER", "Eritrea"), ESTONIA("EE", "Estonia"), ETHIOPIA("ET", "Ethiopia"), FALKLAND_ISLANDS("FK", "Falkland Islands"), FAROE_ISLANDS("FO", "Faroe Islands"), FIJI("FJ", "Fiji"), FINLAND("FI", "Finland"), FRANCE("FR", "France"), FRENCH_GUIANA("GF", "French Guiana"), FRENCH_POLYNESIA("PF", "French Polynesia"), FRENCH_SOUTHERN_TERRITORIES("TF", "French Southern Territories"), GABON("GA", "Gabon"), GAMBIA("GM", "Gambia"), GEORGIA("GE", "Georgia"), GERMANY("DE", "Germany"), GHANA("GH", "Ghana"), GIBRALTAR("GI", "Gibraltar"), GREECE("GR", "Greece"), GREENLAND("GL", "Greenland"), GRENADA("GD", "Grenada"), GUADELOUPE("GP", "Guadeloupe"), GUAM("GU", "Guam"), GUATEMALA("GT", "Guatemala"), GUERNSEY("GG", "Guernsey"), GUINEA("GN", "Guinea"), GUINEA_BISSAU("GW", "Guinea_Bissau"), GUYANA("GY", "Guyana"), HAITI("HT", "Haiti"), HEARD_ISLAND_AND_MCDONALD_ISLANDS("HM", "Heard Island and Mcdonald Islands"), HONDURAS("HN", "Honduras"), HONG_KONG("HK", "Hong Kong"), HUNGARY("HU", "Hungary"), ICELAND("IS", "Iceland"), INDIA("IN", "India"), INDONESIA("ID", "Indonesia"), IRAN("IR", "Iran"), IRAQ("IQ", "Iraq"), IRELAND("IE", "Ireland"), ISLE_OF_MAN("IM", "Isle Of Man"), ISRAEL("IL", "Israel"), ITALY("IT", "Italy"), JAMAICA("JM", "Jamaica"), JAPAN("JP", "Japan"), JERSEY("JE", "Jersey"), JORDAN("JO", "Jordan"), KAZAKHSTAN("KZ", "Kazakhstan"), KENYA("KE", "Kenya"), KIRIBATI("KI", "Kiribati"), KOREA_NORTH("KP", "North Korea"), KOREA_SOUTH("KR", "South Korea"), KUWAIT("KW", "Kuwait"), KYRGYZSTAN("KG", "Kyrgyzstan"), LAO_PEOPLES_DEMOCRATIC_REPUBLIC("LA", "Lao"), LATVIA("LV", "Latvia"), LEBANON("LB", "Lebanon"), LESOTHO("LS", "Lesotho"), LIBERIA("LR", "Liberia"), LIBYAN_ARAB_JAMAHIRIYA("LY", "Libyan Arab Jamahiriya"), LIECHTENSTEIN("LI", "Liechtenstein"), LITHUANIA("LT", "Lithuania"), LUXEMBOURG("LU", "Luxembourg"), MACAO("MO", "Macao"), MACEDONIA("MK", "Macedonia"), MADAGASCAR("MG", "Madagascar"), MALAWI("MW", "Malawi"), MALAYSIA("MY", "Malaysia"), MALDIVES("MV", "Maldives"), MALI("ML", "Mali"), MALTA("MT", "Malta"), MARSHALL_ISLANDS("MH", "Marshall Islands"), MARTINIQUE("MQ", "Martinique"), MAURITANIA("MR", "Mauritania"), MAURITIUS("MU", "Mauritius"), MAYOTTE("YT", "Mayotte"), MEXICO("MX", "Mexico"), MICRONESIA("FM", "Micronesia"), MOLDOVA("MD", "Moldova"), MONACO("MC", "Monaco"), MONGOLIA("MN", "Mongolia"), MONTENEGRO("ME", "Montenegro"), MONTSERRAT("MS", "Montserrat"), MOROCCO("MA", "Morocco"), MOZAMBIQUE("MZ", "Mozambique"), MYANMAR("MM", "Myanmar"), NAMIBIA("NA", "Namibia"), NAURU("NR", "Nauru"), NEPAL("NP", "Nepal"), NETHERLANDS("NL", "Netherlands"), NETHERLANDS_ANTILLES("AN", "Netherlands Antilles"), NEW_CALEDONIA("NC", "New Caledonia"), NEW_ZEALAND("NZ", "New Zealand"), NICARAGUA("NI", "Nicaragua"), NIGER("NE", "Niger"), NIGERIA("NG", "Nigeria"), NIUE("NU", "Niue"), NORFOLK_ISLAND("NF", "Norfolk Island"), NORTHERN_MARIANA_ISLANDS("MP", "Northern Mariana Islands"), NORWAY("NO", "Norway"), OMAN("OM", "Oman"), PAKISTAN("PK", "Pakistan"), PALAU("PW", "Palau"), PALESTINIAN_TERRITORY_OCCUPIED("PS", "Palestinian Territory Occupied"), PANAMA("PA", "Panama"), PAPUA_NEW_GUINEA("PG", "Papua New Guinea"), PARAGUAY("PY", "Paraguay"), PERU("PE", "Peru"), PHILIPPINES("PH", "Philippines"), PITCAIRN("PN", "Pitcairn"), POLAND("PL", "Poland"), PORTUGAL("PT", "Portugal"), PUERTO_RICO("PR", "Puerto Rico"), QATAR("QA", "Qatar"), REUNION("RE", "Union"), ROMANIA("RO", "Romania"), RUSSIAN_FEDERATION("RU", "Russia"), RWANDA("RW", "Rwanda"), SAINT_BARTHOLEMY("BL", "Lemy"), SAINT_HELENA("SH", "St Helena"), SAINT_KITTS_AND_NEVIS("KN", "St Kitts and Nevis"), SAINT_LUCIA("LC", "St Lucia"), SAINT_MARTIN("MF", "St Martin"), SAINT_PIERRE_AND_MIQUELON("PM", "St Pierre and Miquelon"), SAINT_VINCENT_AND_THE_GRENADINES("VC", "St Vincent and the Grenadines"), SAMOA("WS", "Samoa"), SAN_MARINO("SM", "San_Marino"), SAO_TOME_AND_PRINCIPE("ST", "Sao Tome and Principe"), SAUDI_ARABIA("SA", "Saudi Arabia"), SENEGAL("SN", "Senegal"), SERBIA("RS", "Serbia"), SEYCHELLES("SC", "Seychelles"), SIERRA_LEONE("SL", "Sierra Leone"), SINGAPORE("SG", "Singapore"), SLOVAKIA("SK", "Slovakia"), SLOVENIA("SI", "Slovenia"), SOLOMON_ISLANDS("SB", "Solomon Islands"), SOMALIA("SO", "Somalia"), SOUTH_AFRICA("ZA", "South Africa"), SOUTH_GEORGIA_AND_THE_SOUTH_SANDWICH_Islands("GS", "South Georgia and the South Sandwich Islands"), SPAIN("ES", "Spain"), SRI_LANKA("LK", "Sri Lanka"), SUDAN("SD", "Sudan"), SURINAME("SR", "Suriname"), SVALBARD_AND_JAN_MAYEN("SJ", "Svalbard and Jan Mayen"), SWAZILAND("SZ", "Swaziland"), SWEDEN("SE", "Sweden"), SWITZERLAND("CH", "Switzerland"), SYRIA("SY", "Syria"), TAIWAN("TW", "Taiwan"), TAJIKISTAN("TJ", "Tajikistan"), TANZANIA("TZ", "Tanzania"), THAILAND("TH", "Thailand"), TIMOR_LESTE("TL", "Timor Leste"), TOGO("TG", "Togo"), TOKELAU("TK", "Tokelau"), TONGA("TO", "Tonga"), TRINIDAD_AND_TOBAGO("TT", "Trinidad and Tobago"), TUNISIA("TN", "Tunisia"), TURKEY("TR", "Turkey"), TURKMENISTAN("TM", "Turkmenistan"), TURKS_AND_CAICOS_ISLANDS("TC", "Turks and Caicos Islands"), TUVALU("TV", "Tuvalu"), UGANDA("UG", "Uganda"), UKRAINE("UA", "Ukraine"), UNITED_ARAB_EMIRATES("AE", "United Arab Emirates"), UNITED_KINGDOM("GB", "United Kingdom"), UNITED_STATES("US", "United States"), UNITED_STATES_MINOR_OUTLYING_ISLANDS("UM", "United States Minor Outlying Islands"), URUGUAY("UY", "Uruguay"), UZBEKISTAN("UZ", "Uzbekistan"), VANUATU("VU", "Vanuatu"), VATICAN_CITY("VA", "Vatican City"), VENEZUELA("VE", "Venezuela"), VIETNAM("VN", "Vietnam"), VIRGIN_ISLANDS_BRITISH("VG", "British Virgin Islands"), VIRGIN_ISLANDS_US("VI", "US Virgin Islands"), WALLIS_AND_FUTUNA("WF", "Wallis and Futuna"), WESTERN_SAHARA("EH", "Western Sahara"), YEMEN("YE", "Yemen"), ZAMBIA("ZM", "Zambia"), ZIMBABWE("ZW", "Zimbabwe"); private String code; private String description; Country(String code, String description) { this.code = code; this.description = description; } public String getCode() { return code; } public String getDescription() { return description; } public String toString() { return getDescription(); } } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/Test.java0000644000175000017500000000046711222424615023276 0ustar drazzibdrazzibpackage org.jaudiotagger; /** * User: paul * Date: 09-Jun-2009 */ public class Test { static void writeIt() { System.out.println("hi"); } } class Test2 extends Test { public static void main(String[] args) { Test2 test2 = new Test2(); Test2.writeIt(); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/fix/0000755000175000017500000000000011556363172022305 5ustar drazzibdrazziblibjaudiotagger-java-2.0.3/src/org/jaudiotagger/fix/Fix202.java0000644000175000017500000001013311200061127024075 0ustar drazzibdrazzibpackage org.jaudiotagger.fix; import org.jaudiotagger.audio.ogg.OggFileReader; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.fix.Fix; import java.io.File; /** * Simple class that will attempt to recusively read all files within a directory, flags * errors that occur. */ public class Fix202 { public static void main(final String[] args) { Fix202 test = new Fix202(); if (args.length != 1) { System.err.println("usage Fix202 Folder"); System.err.println(" You must enter the folder containing the corrupted files"); System.exit(1); } File dir = new File(args[0]); if (!dir.exists()) { System.err.println("usage Fix202 Folder"); System.err.println(" File " + args[0] + " does not exist"); System.exit(1); } if (!dir.isDirectory()) { System.err.println("usage Fix202 Folder"); System.err.println(" File " + args[0] + " is not a folder"); System.exit(1); } try { final File[] audioFiles = dir.listFiles(new OggFileFilter()); if (audioFiles.length > 0) { for (File oggFile : audioFiles) { System.out.print("Processing " + oggFile.getPath() +" "); try { //Read as broken dir, and save to fix OggFileReader fileReader = new OggFileReader(); AudioFile audioFile = fileReader.read(oggFile); //Read normally so not broken System.out.println(":Not Broken"); continue; } catch (Throwable t) { //Nneds fix continue } try { //Read as broken dir, and save to fix OggFileReader fileReader = new OggFileReader(Fix.FIX_OGG_VORBIS_COMMENT_NOT_COUNTING_EMPTY_COLUMNS); AudioFile audioFile = fileReader.read(oggFile); audioFile.commit(); //Read again normally to check fix fileReader = new OggFileReader(); audioFile = fileReader.read(oggFile); audioFile.commit(); System.out.println(":********Fixed*************"); } catch (Throwable t) { System.err.println("Unable to fix"); } } } } catch (Exception e) { System.err.println("Unable to extract tag"); System.exit(1); } } static class OggFileFilter extends javax.swing.filechooser.FileFilter implements java.io.FileFilter { /** * Create a default OggFileFilter. The allowDirectories field will * default to false. */ public OggFileFilter() { } /** * Determines whether or not the file is an mp3 file. If the file is * a directory, whether or not is accepted depends upon the * allowDirectories flag passed to the constructor. * * @param file the file to test * @return true if this file or directory should be accepted */ public final boolean accept(final File file) { return ( (file.getName()).toLowerCase().endsWith(".ogg") ); } /** * Returns the Name of the Filter for use in the Chooser Dialog * * @return The Description of the Filter */ public final String getDescription() { return ".ogg Files"; } } public static final String IDENT = "$Id: Fix202.java 792 2009-05-05 15:59:19Z paultaylor $"; } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/fix/Fix.java0000644000175000017500000000022410757305272023673 0ustar drazzibdrazzibpackage org.jaudiotagger.fix; /** * User: paul * Date: 21-Feb-2008 */ public enum Fix { FIX_OGG_VORBIS_COMMENT_NOT_COUNTING_EMPTY_COLUMNS } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/utils/0000755000175000017500000000000011556363167022663 5ustar drazzibdrazziblibjaudiotagger-java-2.0.3/src/org/jaudiotagger/utils/EqualsUtil.java0000644000175000017500000000420111305717447025607 0ustar drazzibdrazzibpackage org.jaudiotagger.utils; /** * Collected methods which allow easy implementation of equals. *

* Example use case in a class called Car: *

 * public boolean equals(Object aThat){
 * if ( this == aThat ) return true;
 * if ( !(aThat instanceof Car) ) return false;
 * Car that = (Car)aThat;
 * return
 * EqualsUtil.areEqual(this.fName, that.fName) &&
 * EqualsUtil.areEqual(this.fNumDoors, that.fNumDoors) &&
 * EqualsUtil.areEqual(this.fGasMileage, that.fGasMileage) &&
 * EqualsUtil.areEqual(this.fColor, that.fColor) &&
 * Arrays.equals(this.fMaintenanceChecks, that.fMaintenanceChecks); //array!
 * }
 * 
*

* Arrays are not handled by this class. * This is because the Arrays.equals methods should be used for * array fields. */ public final class EqualsUtil { static public boolean areEqual(boolean aThis, boolean aThat) { //System.out.println("boolean"); return aThis == aThat; } static public boolean areEqual(char aThis, char aThat) { //System.out.println("char"); return aThis == aThat; } static public boolean areEqual(long aThis, long aThat) { /* * Implementation Note * Note that byte, short, and int are handled by this method, through * implicit conversion. */ //System.out.println("long"); return aThis == aThat; } static public boolean areEqual(float aThis, float aThat) { //System.out.println("float"); return Float.floatToIntBits(aThis) == Float.floatToIntBits(aThat); } static public boolean areEqual(double aThis, double aThat) { //System.out.println("double"); return Double.doubleToLongBits(aThis) == Double.doubleToLongBits(aThat); } /** * Possibly-null object field. *

* Includes type-safe enumerations and collections, but does not include * arrays. See class comment. */ static public boolean areEqual(Object aThis, Object aThat) { //System.out.println("Object"); return aThis == null ? aThat == null : aThis.equals(aThat); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/test/0000755000175000017500000000000011556363167022502 5ustar drazzibdrazziblibjaudiotagger-java-2.0.3/src/org/jaudiotagger/test/TestAudioTagger.java0000644000175000017500000001101211277006322026356 0ustar drazzibdrazzib/** * @author : Paul Taylor *

* Version @version:$Id: TestAudioTagger.java 832 2009-11-12 13:25:38Z paultaylor $ *

* Jaudiotagger Copyright (C)2004,2005 *

* This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. *

* This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. *

* You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *

* Description: */ package org.jaudiotagger.test; import org.jaudiotagger.audio.AudioFileFilter; import org.jaudiotagger.audio.AudioFileIO; import java.io.File; import java.text.DateFormat; import java.util.Date; /** * Simple class that will attempt to recusively read all files within a directory, flags * errors that occur. */ public class TestAudioTagger { public static void main(final String[] args) { TestAudioTagger test = new TestAudioTagger(); if (args.length == 0) { System.err.println("usage TestAudioTagger Dirname"); System.err.println(" You must enter the root directory"); System.exit(1); } else if (args.length > 1) { System.err.println("usage TestAudioTagger Dirname"); System.err.println(" Only one parameter accepted"); System.exit(1); } File rootDir = new File(args[0]); if (!rootDir.isDirectory()) { System.err.println("usage TestAudioTagger Dirname"); System.err.println(" Directory " + args[0] + " could not be found"); System.exit(1); } Date start = new Date(); System.out.println("Started to read from:" + rootDir.getPath() + " at " + DateFormat.getTimeInstance().format(start)); test.scanSingleDir(rootDir); Date finish = new Date(); System.out.println("Started to read from:" + rootDir.getPath() + " at " + DateFormat.getTimeInstance().format(start)); System.out.println("Finished to read from:" + rootDir.getPath() + DateFormat.getTimeInstance().format(finish)); System.out.println("Attempted to read:" + count); System.out.println("Successful to read:" + (count - failed)); System.out.println("Failed to read:" + failed); } private static int count = 0; private static int failed = 0; /** * Recursive function to scan directory * @param dir */ private void scanSingleDir(final File dir) { final File[] audioFiles = dir.listFiles(new AudioFileFilter(false)); if (audioFiles.length > 0) { for (File audioFile : audioFiles) { count++; try { AudioFileIO.read(audioFile); } catch (Throwable t) { System.err.println("Unable to read record:" + count + ":" + audioFile.getPath()); failed++; t.printStackTrace(); } } } final File[] audioFileDirs = dir.listFiles(new DirFilter()); if (audioFileDirs.length > 0) { for (File audioFileDir : audioFileDirs) { scanSingleDir(audioFileDir); } } } public final class DirFilter implements java.io.FileFilter { public DirFilter() { } /** * Determines whether or not the file is an mp3 file. If the file is * a directory, whether or not is accepted depends upon the * allowDirectories flag passed to the constructor. * * @param file the file to test * @return true if this file or directory should be accepted */ public final boolean accept(final java.io.File file) { return file.isDirectory(); } public static final String IDENT = "$Id: TestAudioTagger.java 832 2009-11-12 13:25:38Z paultaylor $"; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/test/MergeID3AndMP3Files.java0000644000175000017500000001730011277026507026625 0ustar drazzibdrazzibpackage org.jaudiotagger.test; import java.io.*; import java.text.DateFormat; import java.util.Date; /** * Simple class that will attempt to recusively read all files within a directory ending in .mp3 (but * only actually expected to contain id3 tags), merge them with a given mp3 and write them to the provided * output folder (which must already exist) */ public class MergeID3AndMP3Files { public static void main(final String[] args) { MergeID3AndMP3Files test = new MergeID3AndMP3Files(); if (args.length == 0) { System.err.println("usage MergeID3AndMP3Files FromDir ToDir mp3File"); System.err.println(" You must enter the from dir,outputdir and the mp3file to append"); System.exit(1); } else if (args.length != 3) { System.err.println("usage MergeID3AndMP3Files FromDir ToDir mp3File"); System.err.println(" Only three parameters accepted"); System.exit(1); } File rootDir = new File(args[0]); if (!rootDir.isDirectory()) { System.err.println("usage MergeID3AndMP3Files FromDir ToDir mp3File"); System.err.println(" Directory " + args[0] + " could not be found"); System.exit(1); } File toDir = new File(args[1]); if (!rootDir.isDirectory()) { System.err.println("usage MergeID3AndMP3Files FromDir ToDir mp3File"); System.err.println(" Directory " + args[1] + " could not be found"); System.exit(1); } File mp3File = new File(args[2]); if (!mp3File.isFile()) { System.err.println("usage MergeID3AndMP3Files FromDir ToDir mp3File"); System.err.println(" Mp3File " + args[2] + " could not be found"); System.exit(1); } Date start = new Date(); System.out.println("Started to merge from:" + rootDir.getPath() + " at " + DateFormat.getTimeInstance().format(start)); test.scanSingleDir(rootDir, toDir, mp3File); Date finish = new Date(); System.out.println("Finished to merge from:" + rootDir.getPath() + DateFormat.getTimeInstance().format(finish)); System.out.println("Attempted to merge:" + MergeID3AndMP3Files.count); System.out.println("Successful to merge:" + (MergeID3AndMP3Files.count - MergeID3AndMP3Files.failed)); System.out.println("Failed to merge:" + MergeID3AndMP3Files.failed); } private static int count = 0; private static int failed = 0; /** * Recursive function to scan directory * @param fromDir * @param toDir * @param mp3File */ private void scanSingleDir(final File fromDir, final File toDir, final File mp3File) { final File[] audioFiles = fromDir.listFiles(new MergeID3AndMP3Files.MP3FileFilter()); if (audioFiles.length > 0) { for (File audioFile : audioFiles) { MergeID3AndMP3Files.count++; try { copyAudioToTmp(toDir, audioFile, mp3File); } catch (Throwable t) { System.err.println("Unable to merge record:" + MergeID3AndMP3Files.count + ":" + mp3File.getPath()); MergeID3AndMP3Files.failed++; t.printStackTrace(); } } } final File[] audioFileDirs = fromDir.listFiles(new MergeID3AndMP3Files.DirFilter()); if (audioFileDirs.length > 0) { for (File audioFileDir : audioFileDirs) { scanSingleDir(audioFileDir, new File(toDir, audioFileDir.getName()), mp3File); } } } final class MP3FileFilter extends javax.swing.filechooser.FileFilter implements java.io.FileFilter { /** * allows Directories */ private final boolean allowDirectories; /** * Create a default MP3FileFilter. The allowDirectories field will * default to false. */ public MP3FileFilter() { this(false); } /** * Create an MP3FileFilter. If allowDirectories is true, then this filter * will accept directories as well as mp3 files. If it is false then * only mp3 files will be accepted. * * @param allowDirectories whether or not to accept directories */ private MP3FileFilter(final boolean allowDirectories) { this.allowDirectories = allowDirectories; } /** * Determines whether or not the file is an mp3 file. If the file is * a directory, whether or not is accepted depends upon the * allowDirectories flag passed to the constructor. * * @param file the file to test * @return true if this file or directory should be accepted */ public final boolean accept(final File file) { return (((file.getName()).toLowerCase().endsWith(".mp3")) || (file.isDirectory() && (this.allowDirectories))); } /** * Returns the Name of the Filter for use in the Chooser Dialog * * @return The Description of the Filter */ public final String getDescription() { return ".mp3 Files"; } } public final class DirFilter implements java.io.FileFilter { public DirFilter() { } /** * Determines whether or not the file is an mp3 file. If the file is * a directory, whether or not is accepted depends upon the * allowDirectories flag passed to the constructor. * * @param file the file to test * @return true if this file or directory should be accepted */ public final boolean accept(final File file) { return file.isDirectory(); } public static final String IDENT = "$Id: MergeID3AndMP3Files.java 836 2009-11-12 15:44:07Z paultaylor $"; } public static File copyAudioToTmp(File toDir, File tagFile, File mp3File) { File outputFile = new File(toDir.getPath(), tagFile.getName()); boolean result = append(tagFile, mp3File, outputFile); return outputFile; } private static boolean append(File fromFile1, File fromFile2, File toFile) { try { FileInputStream in = new FileInputStream(fromFile1); FileInputStream in2 = new FileInputStream(fromFile2); toFile.getParentFile().mkdirs(); FileOutputStream out = new FileOutputStream(toFile); BufferedInputStream inBuffer = new BufferedInputStream(in); BufferedInputStream inBuffer2 = new BufferedInputStream(in2); BufferedOutputStream outBuffer = new BufferedOutputStream(out); int theByte; while ((theByte = inBuffer.read()) > -1) { outBuffer.write(theByte); } while ((theByte = inBuffer2.read()) > -1) { outBuffer.write(theByte); } outBuffer.close(); inBuffer.close(); inBuffer2.close(); out.close(); in.close(); in2.close(); // cleanupif files are not the same length if ((fromFile1.length() + fromFile2.length()) != toFile.length()) { toFile.delete(); return false; } return true; } catch (IOException e) { e.printStackTrace(); return false; } } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/test/ExtractID3TagFromFile.java0000644000175000017500000000575211277026507027342 0ustar drazzibdrazzibpackage org.jaudiotagger.test; import org.jaudiotagger.audio.mp3.MP3File; import java.io.File; /** * Simple class that will attempt to recusively read all files within a directory, flags * errors that occur. */ public class ExtractID3TagFromFile { public static void main(final String[] args) { ExtractID3TagFromFile test = new ExtractID3TagFromFile(); if (args.length != 2) { System.err.println("usage ExtractID3TagFromFile Filename FilenameOut"); System.err.println(" You must enter the file to extract the tag from and where to extract to"); System.exit(1); } File file = new File(args[0]); File outFile = new File(args[1]); if (!file.isFile()) { System.err.println("usage ExtractID3TagFromFile Filename FilenameOut"); System.err.println(" File " + args[0] + " could not be found"); System.exit(1); } try { final MP3File tmpMP3 = new MP3File(file); tmpMP3.extractID3v2TagDataIntoFile(outFile); } catch (Exception e) { System.err.println("Unable to extract tag"); System.exit(1); } } final class MP3FileFilter extends javax.swing.filechooser.FileFilter implements java.io.FileFilter { /** * allows Directories */ private final boolean allowDirectories; /** * Create a default MP3FileFilter. The allowDirectories field will * default to false. */ public MP3FileFilter() { this(false); } /** * Create an MP3FileFilter. If allowDirectories is true, then this filter * will accept directories as well as mp3 files. If it is false then * only mp3 files will be accepted. * * @param allowDirectories whether or not to accept directories */ private MP3FileFilter(final boolean allowDirectories) { this.allowDirectories = allowDirectories; } /** * Determines whether or not the file is an mp3 file. If the file is * a directory, whether or not is accepted depends upon the * allowDirectories flag passed to the constructor. * * @param file the file to test * @return true if this file or directory should be accepted */ public final boolean accept(final File file) { return (((file.getName()).toLowerCase().endsWith(".mp3")) || (file.isDirectory() && (this.allowDirectories))); } /** * Returns the Name of the Filter for use in the Chooser Dialog * * @return The Description of the Filter */ public final String getDescription() { return ".mp3 Files"; } } public static final String IDENT = "$Id: ExtractID3TagFromFile.java 836 2009-11-12 15:44:07Z paultaylor $"; } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/logging/0000755000175000017500000000000011556363172023145 5ustar drazzibdrazziblibjaudiotagger-java-2.0.3/src/org/jaudiotagger/logging/PlainTextTagDisplayFormatter.java0000644000175000017500000000530211200061127031543 0ustar drazzibdrazzib/** * @author : Paul Taylor * * Version @version:$Id: PlainTextTagDisplayFormatter.java 792 2009-05-05 15:59:19Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.logging; /* * For Formatting metadata contents of a file as simple text */ public class PlainTextTagDisplayFormatter extends AbstractTagDisplayFormatter { private static PlainTextTagDisplayFormatter formatter; StringBuffer sb = new StringBuffer(); StringBuffer indent = new StringBuffer(); public PlainTextTagDisplayFormatter() { } public void openHeadingElement(String type, String value) { addElement(type, value); increaseLevel(); } public void openHeadingElement(String type, boolean value) { openHeadingElement(type, String.valueOf(value)); } public void openHeadingElement(String type, int value) { openHeadingElement(type, String.valueOf(value)); } public void closeHeadingElement(String type) { decreaseLevel(); } public void increaseLevel() { level++; indent.append(" "); } public void decreaseLevel() { level--; indent = new StringBuffer(indent.substring(0, indent.length() - 2)); } public void addElement(String type, String value) { sb.append(indent).append(type).append(":").append(value).append('\n'); } public void addElement(String type, int value) { addElement(type, String.valueOf(value)); } public void addElement(String type, boolean value) { addElement(type, String.valueOf(value)); } public String toString() { return sb.toString(); } public static AbstractTagDisplayFormatter getInstanceOf() { if (formatter == null) { formatter = new PlainTextTagDisplayFormatter(); } return formatter; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/logging/ErrorMessage.java0000644000175000017500000002366011470746136026415 0ustar drazzibdrazzibpackage org.jaudiotagger.logging; import java.text.MessageFormat; /** * Defines Error Messages */ public enum ErrorMessage { GENERAL_READ("File {0} being read"), MP4_FILE_NOT_CONTAINER("This file does not appear to be an Mp4 file"), MP4_FILE_NOT_AUDIO("This file does not appear to be an Mp4 Audio file, could be corrupted or video "), MP4_FILE_IS_VIDEO("This file appears to be an Mp4 Video file, video files are not supported "), MP4_UNABLE_TO_PRIME_FILE_FOR_WRITE_SAFETLY("Unable to safetly check consistency in Mp4 file so cancelling save"), MP4_FILE_CONTAINS_MULTIPLE_DATA_ATOMS("File contains multiple data atoms"), MP4_CHANGES_TO_FILE_FAILED("Unable to make changes to Mp4 file"), MP4_CHANGES_TO_FILE_FAILED_NO_DATA("Unable to make changes to Mp4 file, no data was written"), MP4_CHANGES_TO_FILE_FAILED_DATA_CORRUPT("Unable to make changes to Mp4 file, invalid data length has been written"), MP4_CHANGES_TO_FILE_FAILED_NO_TAG_DATA("Unable to make changes to Mp4 file, no tag data has been written"), MP4_CHANGES_TO_FILE_FAILED_INCORRECT_OFFSETS("Unable to make changes to Mp4 file, incorrect offsets written difference was {0}"), MP4_CHANGES_TO_FILE_FAILED_CANNOT_FIND_AUDIO("Unable to make changes to Mp4 file, unable to determine start of audio"), FLAC_NO_FLAC_HEADER_FOUND("Flac Header not found, not a flac file"), OGG_VORBIS_NO_VORBIS_HEADER_FOUND("Cannot find vorbis setup parentHeader"), MP4_REVERSE_DNS_FIELD_HAS_NO_DATA("Reverse dns field:{0} has no data"), MP4_UNABLE_READ_REVERSE_DNS_FIELD("Unable to create reverse dns field because of exception:{0} adding as binary data instead"), OGG_VORBIS_NO_FRAMING_BIT("The OGG Stream is not valid, Vorbis tag valid framing bit is wrong {0} "), GENERAL_WRITE_FAILED("Cannot make changes to file {0}"), GENERAL_WRITE_FAILED_FILE_LOCKED("Cannot make changes to file {0} because it is being used by another application"), GENERAL_WRITE_FAILED_BECAUSE_FILE_IS_TOO_SMALL("Cannot make changes to file {0} because too small to be an audio file"), GENERAL_WRITE_FAILED_TO_DELETE_ORIGINAL_FILE("Cannot make changes to file {0} because unable to delete the original file ready for updating from temporary file {1}"), GENERAL_WRITE_FAILED_TO_RENAME_TO_ORIGINAL_FILE("Cannot make changes to file {0} because unable to rename from temporary file {1}"), GENERAL_WRITE_FAILED_TO_RENAME_ORIGINAL_FILE_TO_BACKUP("Cannot make changes to file {0} because unable to rename the original file to {1}"), GENERAL_WRITE_FAILED_TO_RENAME_ORIGINAL_BACKUP_TO_ORIGINAL("Unable to rename backup {0} back to file {1}"), GENERAL_WRITE_FAILED_NEW_FILE_DOESNT_EXIST("New file {0} does not appear to exist"), GENERAL_WRITE_FAILED_BECAUSE("Cannot make changes to file {0} because {1}"), GENERAL_WRITE_FAILED_BECAUSE_FILE_NOT_FOUND("Cannot make changes to file {0} because the file cannot be found"), GENERAL_WRITE_WARNING_UNABLE_TO_DELETE_BACKUP_FILE("Unable to delete the backup file {0}"), GENERAL_WRITE_PROBLEM_CLOSING_FILE_HANDLE("Problem closing file handles for file {0} because {1}"), GENERAL_DELETE_FAILED("Cannot delete file {0}"), GENERAL_DELETE_FAILED_FILE_LOCKED("Cannot delete file {0} because it is being used by another application"), GENERAL_DELETE_FAILED_BECAUSE_FILE_IS_TOO_SMALL("Cannot write to file {0} because too small to be an audio file"), MP3_ID3TAG_LENGTH_INCORRECT(" {0}:Checking further because the ID3 Tag ends at {1} but the mp3 audio doesnt start until {2}"), MP3_RECALCULATED_POSSIBLE_START_OF_MP3_AUDIO("{0}: Recalculated possible start of the audio to be at {1}"), MP3_RECALCULATED_START_OF_MP3_AUDIO("{0}: Recalculated the start of the audio to be at {1}"), MP3_START_OF_AUDIO_CONFIRMED("{0}: Confirmed audio starts at {1} whether searching from start or from end of ID3 tag"), MP3_URL_SAVED_ENCODED("Url:{0} saved in encoded form as {1}"), MP3_UNABLE_TO_ENCODE_URL("Unable to save url:{0} because cannot encode all characters setting to blank instead"), MP4_UNABLE_TO_FIND_NEXT_ATOM_BECAUSE_IDENTIFIER_IS_INVALID("Unable to find next atom because identifier is invalid {0}"), MP4_UNABLE_TO_FIND_NEXT_ATOM_BECAUSE_LENGTH_IS_INVALID("Unable to find next atom {0} because length is invalid {1}"), GENERAL_INVALID_NULL_ARGUMENT("Argument cannot be null"), MP4_GENRE_OUT_OF_RANGE("Genre Id {0} does not map to a valid genre"), MP3_PICTURE_TYPE_INVALID("Picture Type is set to invalid value:{0}"), MP3_REFERENCE_KEY_INVALID("{0}:No key could be found with the value of:{1}"), MP3_UNABLE_TO_ADJUST_PADDING("Problem adjusting padding in large file, expecting to write:{0} only wrote:{1}"), GENERAL_WRITE_FAILED_TO_DELETE_TEMPORARY_FILE("Unable to delete the temporary file {0}"), GENERAL_WRITE_FAILED_TO_CREATE_TEMPORARY_FILE_IN_FOLDER("Cannot modify {0} because do not have permissions to create files in the folder {1}"), GENERAL_WRITE_FAILED_TO_MODIFY_TEMPORARY_FILE_IN_FOLDER("Cannot modify {0} because do not have permissions to modify files in the folder {1}"), GENERAL_WRITE_FAILED_TO_OPEN_FILE_FOR_EDITING("Cannot modify {0} because do not have permissions to modify file"), NULL_PADDING_FOUND_AT_END_OF_MP4("Null Padding found at end of file starting at offset {0}"), OGG_VORBIS_NO_SETUP_BLOCK("Could not find the Ogg Setup block"), OGG_HEADER_CANNOT_BE_FOUND("OggS Header could not be found, not an ogg stream {0}"), GENERAL_READ_FAILED_UNABLE_TO_CLOSE_RANDOM_ACCESS_FILE("Unable to close random access file: {0}"), GENERAL_READ_FAILED_FILE_TOO_SMALL("Unable to read file because it is too small to be valid audio file: {0}"), GENERAL_READ_FAILED_DO_NOT_HAVE_PERMISSION_TO_READ_FILE("Unable to read file do not have permission to read: {0}"), ASF_FILE_HEADER_SIZE_DOES_NOT_MATCH_FILE_SIZE("For file {0} the File header size is {1} but different to actual file size of {2}"), ASF_FILE_HEADER_MISSING("For file {0} the File Header missing. Invalid ASF/WMA file."), ASF_HEADER_MISSING("For file {0} the Asf Header missing. Invalid ASF/WMA file."), GENERAL_UNIDENITIFED_IMAGE_FORMAT("Cannot safetly identify the format of this image setting to default type of Png"), MP4_IMAGE_FORMAT_IS_NOT_TO_EXPECTED_TYPE("ImageFormat for cover art atom is not set to a known image format, instead set to {0}"), MP3_FRAME_IS_COMPRESSED("Filename {0}:{1} is compressed"), MP3_FRAME_IS_ENCRYPTED("Filename {0}:{1} is encrypted"), MP3_FRAME_IS_GROUPED("Filename {0}:{1} is grouped"), MP3_FRAME_IS_UNSYNCHRONISED("Filename {0}:{1} is unsynchronised"), MP3_FRAME_IS_DATA_LENGTH_INDICATOR("Filename {0}:{1} has a data length indicator"), MP4_FILE_HAS_NO_METADATA("This file does not currently contain any metadata"), MP4_FILE_META_ATOM_CHILD_DATA_NOT_NULL("Expect data in meta box to be null"), WMA_INVALID_FIELD_NAME ("The field name {0} is not allowed for {1}"), WMA_INVALID_LANGUAGE_USE ("The use of language {0} ist not allowed for {1} (only {2} allowed)"), WMA_INVALID_STREAM_REFERNCE ("The stream number {0} is invalid. Only {1} allowed for {2}."), WMA_INVALID_GUID_USE ("The use of GUID ist not allowed for {0}"), WMA_LENGTH_OF_DATA_IS_TOO_LARGE("Trying to create field with {0} bytes of data but the maximum data allowed in WMA files is {1} for {2}."), WMA_LENGTH_OF_LANGUAGE_IS_TOO_LARGE("Trying to create language entry, but UTF-16LE representation is {0} and exceeds maximum allowed of 255."), WMA_LENGTH_OF_STRING_IS_TOO_LARGE("Trying to create field but UTF-16LE representation is {0} and exceeds maximum allowed of 65535."), WMA_ONLY_STRING_IN_CD ("Only Strings are allowed in content description objects"), ID3_EXTENDED_HEADER_SIZE_INVALID("{0} Invalid Extended Header Size of {0} assuming no extended header after all"), ID3_EXTENDED_HEADER_SIZE_TOO_SMALL("{0} Invalid Extended Header Size of {0} is too smal to be valid"), ID3_INVALID_OR_UNKNOWN_FLAG_SET("{0} Invalid or unknown bit flag 0x{1} set in ID3 tag header"), ID3_TAG_UNSYNCHRONIZED("{0} the ID3 Tag is unsynchronized"), ID3_TAG_EXPERIMENTAL("{0} the ID3 Tag is experimental"), ID3_TAG_FOOTER("{0} the ID3 Tag is has a footer"), ID3_TAG_EXTENDED("{0} the ID3 Tag is extended"), ID3_TAG_CRC("{0} the ID3 Tag has crc check"), ID3_TAG_COMPRESSED("{0} the ID3 Tag is compressed"), ID3_TAG_CRC_SIZE("{0} According to Extended Header the ID3 Tag has crc32 of {1}"), ID3_TAG_PADDING_SIZE("{0} According to Extended Header the ID3 Tag has padding size of {1}"), ID_TAG_SIZE("{0} Tag size is {1} according to header (does not include header size, add 10)"), ID3_TAG_CRC_FLAG_SET_INCORRECTLY("{0} CRC Data flag not set correctly."), MP4_CANNOT_FIND_AUDIO("Unable to determine start of audio in file"), VORBIS_COMMENT_LENGTH_TOO_LARGE("Comment field length is very large {0} , assuming comment is corrupt"), VORBIS_COMMENT_LENGTH_LARGE_THAN_HEADER("Comment field length {0} is larger than total comment header {1} "), ARTWORK_CANNOT_BE_CREATED_WITH_THIS_METHOD("Cover Art cannot be created using this method"), ARTWORK_CANNOT_BE_RETRIEVED_WITH_THIS_METHOD("Cover Art cannot be retrieved using this method"), GENERIC_NOT_SUPPORTED("Not implemented for this format"), ID3_UNABLE_TO_DECOMPRESS_FRAME("Unable to decompress frame {0} in file {1} because {2}"), NO_WRITER_FOR_THIS_FORMAT("No Writer associated with this extension:{0}"), NO_READER_FOR_THIS_FORMAT("No Reader associated with this extension:{0}"), NO_DELETER_FOR_THIS_FORMAT("No Deleter associated with this extension:{0}"), UNABLE_TO_FIND_FILE("Unable to find:{0}"), NO_PERMISSIONS_TO_WRITE_TO_FILE("Unable to write to:{0}"), DO_NOT_KNOW_HOW_TO_CREATE_THIS_ATOM_TYPE("DO not know how to create this atom type {0}"), ; String msg; ErrorMessage(String msg) { this.msg = msg; } public String getMsg() { return msg; } public String getMsg(Object... args) { return MessageFormat.format(getMsg(), args); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/logging/XMLTagDisplayFormatter.java0000644000175000017500000001314611277026507030321 0ustar drazzibdrazzib/** * @author : Paul Taylor * * Version @version:$Id: XMLTagDisplayFormatter.java 836 2009-11-12 15:44:07Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ package org.jaudiotagger.logging; import java.text.CharacterIterator; import java.text.StringCharacterIterator; /* * For Formatting the metadata contents of a file in an XML format * * This could provide the basis of a representation of a files metadata, which can then be manipulated to * to create technical reports. */ public class XMLTagDisplayFormatter extends AbstractTagDisplayFormatter { private static XMLTagDisplayFormatter formatter; protected static final String xmlOpenStart = "<"; protected static final String xmlOpenEnd = ">"; protected static final String xmlCloseStart = ""; protected static final String xmlSingleTagClose = " />"; protected static final String xmlCDataTagOpen = ""; StringBuffer sb = new StringBuffer(); public XMLTagDisplayFormatter() { } /** * Return xml open tag round a string e.g * @param xmlName * @return */ public static String xmlOpen(String xmlName) { return xmlOpenStart + xmlName + xmlOpenEnd; } public static String xmlOpenHeading(String name, String data) { return (xmlOpen(name + " id=\"" + data + "\"")); } /** * Return CDATA tag around xml data e.g * We also need to deal with special chars * @param xmlData * @return */ public static String xmlCData(String xmlData) { char tempChar; StringBuffer replacedString = new StringBuffer(); for (int i = 0; i < xmlData.length(); i++) { tempChar = xmlData.charAt(i); if ((Character.isLetterOrDigit(tempChar)) || (Character.isSpaceChar(tempChar))) { replacedString.append(tempChar); } else { replacedString.append("#x").append(Character.digit(tempChar, 16)); } } return xmlCDataTagOpen + replacedString + xmlCDataTagClose; } /** * Return xml close tag around a string e.g * @param xmlName * @return */ public static String xmlClose(String xmlName) { return xmlCloseStart + xmlName + xmlCloseEnd; } public static String xmlSingleTag(String data) { return xmlOpenStart + data + xmlSingleTagClose; } public static String xmlFullTag(String xmlName, String data) { return xmlOpen(xmlName) + xmlCData(data) + xmlClose(xmlName); } public void openHeadingElement(String type, String value) { if (value.length() == 0) { sb.append(xmlOpen(type)); } else { sb.append(xmlOpenHeading(type, replaceXMLCharacters(value))); } } public void openHeadingElement(String type, boolean value) { openHeadingElement(type, String.valueOf(value)); } public void openHeadingElement(String type, int value) { openHeadingElement(type, String.valueOf(value)); } public void closeHeadingElement(String type) { sb.append(xmlClose(type)); } public void addElement(String type, String value) { sb.append(xmlFullTag(type, replaceXMLCharacters(value))); } public void addElement(String type, int value) { addElement(type, String.valueOf(value)); } public void addElement(String type, boolean value) { addElement(type, String.valueOf(value)); } public String toString() { return sb.toString(); } /** * Replace any special xml characters with the appropiate escape sequences * required to be done for the actual element names * @param xmlData * @return */ public static String replaceXMLCharacters(String xmlData) { StringBuffer sb = new StringBuffer(); StringCharacterIterator sCI = new StringCharacterIterator(xmlData); for (char c = sCI.first(); c != CharacterIterator.DONE; c = sCI.next()) { switch (c) { case'&': sb.append("&"); break; case'<': sb.append("<"); break; case'>': sb.append(">"); break; case'"': sb.append("""); break; case'\'': sb.append("'"); break; default: sb.append(c); } } return sb.toString(); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/logging/FileSystemMessage.java0000644000175000017500000000056111107070540027365 0ustar drazzibdrazzibpackage org.jaudiotagger.logging; /** * For parsing the exact cause of a file exception, because variations not handled well by Java */ public enum FileSystemMessage { ACCESS_IS_DENIED("Access is denied"), ; String msg; FileSystemMessage(String msg) { this.msg = msg; } public String getMsg() { return msg; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/logging/LogFormatter.java0000644000175000017500000000513011277026507026412 0ustar drazzibdrazzibpackage org.jaudiotagger.logging; import java.io.PrintWriter; import java.io.StringWriter; import java.text.SimpleDateFormat; import java.util.Date; import java.util.logging.Formatter; import java.util.logging.LogRecord; /** * For Formatting log output *

*

This is not required by jaudiotagger, but its advantage over the default formatter is that all the format for a log * entry is on one line, making it much easier to read. To use this formatter with your code edit loggin.properties * within your jre/lib folder and modify as follows * e.g java.util.logging.ConsoleHandler.formatter = org.jaudiotagger.logging.LogFormatter

*/ public final class LogFormatter extends Formatter { private boolean isObsfucated = false; public static final String ACTION_PERFORMED = "actionPerformed"; // Line separator string. This is the value of the line.separator // property at the moment that the SimpleFormatter was created. private final String lineSeparator = (String) java.security.AccessController.doPrivileged(new sun.security.action. GetPropertyAction("line.separator")); private final SimpleDateFormat sfDateOut = new SimpleDateFormat("dd/MM/yyyy HH.mm.ss:"); private final Date date = new Date(); public LogFormatter() { } public final String format(final LogRecord record) { final StringBuffer sb = new StringBuffer(); date.setTime(record.getMillis()); sb.append(sfDateOut.format(date)); String recordName; if (record.getSourceClassName() != null) { recordName = record.getSourceClassName() + ":" + record.getSourceMethodName(); } else { recordName = record.getLoggerName() + ":"; } if (recordName != null) { sb.append(recordName); sb.append(":"); } final String message = formatMessage(record); sb.append(record.getLevel().getLocalizedName()); sb.append(": "); sb.append(message); sb.append(lineSeparator); if (record.getThrown() != null) { try { final StringWriter sw = new StringWriter(); final PrintWriter pw = new PrintWriter(sw); record.getThrown().printStackTrace(pw); pw.close(); sb.append(sw.toString()); } catch (Exception ex) { } } return sb.toString(); } public static final String IDENT = "$Id: LogFormatter.java 836 2009-11-12 15:44:07Z paultaylor $"; } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/logging/Hex.java0000644000175000017500000000070211263107535024525 0ustar drazzibdrazzibpackage org.jaudiotagger.logging; /** * Display as hex */ public class Hex { /** * Display as hex * * @param value * @return */ public static String asHex(long value) { return "0x" + Long.toHexString(value); } /** * Display as hex * * @param value * @return */ public static String asHex(byte value) { return "0x" + Integer.toHexString(value); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/logging/AbstractTagDisplayFormatter.java0000644000175000017500000000733211277026507031424 0ustar drazzibdrazzib/** * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: AbstractTagDisplayFormatter.java 836 2009-11-12 15:44:07Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Description: * This abstract class defines methods for writing out the contents of a tag in a user-friendly way * Concrete subclasses could implement different versions such as XML Output, PDF and so on. The tag * in all cases is diaplyed as a sort of tree hierachy. */ package org.jaudiotagger.logging; import java.util.HashMap; /** * Abstract class that provides structure to use for displaying a files metadata content */ public abstract class AbstractTagDisplayFormatter { protected int level; private static HashMap hexBinaryMap = new HashMap(); public abstract void openHeadingElement(String type, String value); public abstract void openHeadingElement(String type, boolean value); public abstract void openHeadingElement(String type, int value); public abstract void closeHeadingElement(String type); public abstract void addElement(String type, String value); public abstract void addElement(String type, int value); public abstract void addElement(String type, boolean value); public abstract String toString(); /** * Use to display headers as their binary representation * @param buffer * @return */ public static String displayAsBinary(byte buffer) { //Convert buffer to hex representation String hexValue = Integer.toHexString(buffer); String char1 = ""; String char2 = ""; try { if (hexValue.length() == 8) { char1 = hexValue.substring(6, 7); char2 = hexValue.substring(7, 8); } else if (hexValue.length() == 2) { char1 = hexValue.substring(0, 1); char2 = hexValue.substring(1, 2); } else if (hexValue.length() == 1) { char1 = "0"; char2 = hexValue.substring(0, 1); } } catch (StringIndexOutOfBoundsException se) { return ""; } return hexBinaryMap.get(char1) + hexBinaryMap.get(char2); } static { hexBinaryMap.put("0", "0000"); hexBinaryMap.put("1", "0001"); hexBinaryMap.put("2", "0010"); hexBinaryMap.put("3", "0011"); hexBinaryMap.put("4", "0100"); hexBinaryMap.put("5", "0101"); hexBinaryMap.put("6", "0110"); hexBinaryMap.put("7", "0111"); hexBinaryMap.put("8", "1000"); hexBinaryMap.put("9", "1001"); hexBinaryMap.put("a", "1010"); hexBinaryMap.put("b", "1011"); hexBinaryMap.put("c", "1100"); hexBinaryMap.put("d", "1101"); hexBinaryMap.put("e", "1110"); hexBinaryMap.put("f", "1111"); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/FileConstants.java0000644000175000017500000000324310736454526025143 0ustar drazzibdrazzib/** * @author : Paul Taylor *

* Version @version:$Id: FileConstants.java 520 2008-01-01 15:16:38Z paultaylor $ *

* Jaudiotagger Copyright (C)2004,2005 *

* This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. *

* This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. *

* You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *

* Description: */ package org.jaudiotagger; /** * Definitions of the bit used when reading file format from file */ public interface FileConstants { /** * defined for convenience */ int BIT7 = 0x80; /** * defined for convenience */ int BIT6 = 0x40; /** * defined for convenience */ int BIT5 = 0x20; /** * defined for convenience */ int BIT4 = 0x10; /** * defined for convenience */ int BIT3 = 0x08; /** * defined for convenience */ int BIT2 = 0x04; /** * defined for convenience */ int BIT1 = 0x02; /** * defined for convenience */ int BIT0 = 0x01; } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/0000755000175000017500000000000011556363172022620 5ustar drazzibdrazziblibjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/wav/0000755000175000017500000000000011556363172023415 5ustar drazzibdrazziblibjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/wav/WavFileWriter.java0000644000175000017500000000300411041064726026777 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2003-2005 Rapha�l Slinckx * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.audio.wav; import org.jaudiotagger.audio.exceptions.CannotWriteException; import org.jaudiotagger.audio.generic.AudioFileWriter; import org.jaudiotagger.tag.Tag; import java.io.IOException; import java.io.RandomAccessFile; public class WavFileWriter extends AudioFileWriter { protected void writeTag(Tag tag, RandomAccessFile raf, RandomAccessFile rafTemp) throws CannotWriteException, IOException { //Nothing to do for wav file, no tag are supported } protected void deleteTag(RandomAccessFile raf, RandomAccessFile tempRaf) throws CannotWriteException, IOException { //Nothing to do for wav file, no tag are supported } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/wav/WavFileReader.java0000644000175000017500000000315711117741073026737 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2003-2005 Rapha�l Slinckx * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.audio.wav; import org.jaudiotagger.audio.exceptions.CannotReadException; import org.jaudiotagger.audio.generic.AudioFileReader; import org.jaudiotagger.audio.generic.GenericAudioHeader; import org.jaudiotagger.audio.generic.GenericTag; import org.jaudiotagger.audio.wav.util.WavInfoReader; import org.jaudiotagger.tag.Tag; import java.io.IOException; import java.io.RandomAccessFile; public class WavFileReader extends AudioFileReader { private WavInfoReader ir = new WavInfoReader(); protected GenericAudioHeader getEncodingInfo(RandomAccessFile raf) throws CannotReadException, IOException { return ir.read(raf); } protected Tag getTag(RandomAccessFile raf) throws CannotReadException { return new WavTag(); } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/wav/WavTag.java0000644000175000017500000000210510727201653025441 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2003-2005 Rapha�l Slinckx * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.audio.wav; import org.jaudiotagger.audio.generic.GenericTag; public class WavTag extends GenericTag { public String toString() { String output = "WAV " + super.toString(); return output; } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/wav/util/0000755000175000017500000000000011556363172024372 5ustar drazzibdrazziblibjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/wav/util/WavRIFFHeader.java0000644000175000017500000000276110727201653027552 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2003-2005 Rapha�l Slinckx * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.audio.wav.util; public class WavRIFFHeader { private boolean isValid = false; public WavRIFFHeader(byte[] b) { //System.err.println(b.length); String RIFF = new String(b, 0, 4); //System.err.println(RIFF); String WAVE = new String(b, 8, 4); //System.err.println(WAVE); if (RIFF.equals("RIFF") && WAVE.equals("WAVE")) { isValid = true; } } public boolean isValid() { return isValid; } public String toString() { String out = "RIFF-WAVE Header:\n"; out += "Is valid?: " + isValid; return out; } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/wav/util/WavFormatHeader.java0000644000175000017500000000423110727201653030246 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2003-2005 Rapha�l Slinckx * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.audio.wav.util; public class WavFormatHeader { private boolean isValid = false; private int channels, sampleRate, bytesPerSecond, bitrate; public WavFormatHeader(byte[] b) { String fmt = new String(b, 0, 3); //System.err.println(fmt); if (fmt.equals("fmt") && b[8] == 1) { channels = b[10]; //System.err.println(channels); sampleRate = u(b[15]) * 16777216 + u(b[14]) * 65536 + u(b[13]) * 256 + u(b[12]); //System.err.println(sampleRate); bytesPerSecond = u(b[19]) * 16777216 + u(b[18]) * 65536 + u(b[17]) * 256 + u(b[16]); //System.err.println(bytesPerSecond); bitrate = u(b[22]); isValid = true; } } public boolean isValid() { return isValid; } public int getChannelNumber() { return channels; } public int getSamplingRate() { return sampleRate; } public int getBytesPerSecond() { return bytesPerSecond; } public int getBitrate() { return bitrate; } private int u(int n) { return n & 0xff; } public String toString() { String out = "RIFF-WAVE Header:\n"; out += "Is valid?: " + isValid; return out; } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/wav/util/WavInfoReader.java0000644000175000017500000000510611041064726027723 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2003-2005 Rapha�l Slinckx * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.audio.wav.util; import org.jaudiotagger.audio.exceptions.CannotReadException; import org.jaudiotagger.audio.generic.GenericAudioHeader; import java.io.IOException; import java.io.RandomAccessFile; public class WavInfoReader { public GenericAudioHeader read(RandomAccessFile raf) throws CannotReadException, IOException { // Reads wav header---------------------------------------- GenericAudioHeader info = new GenericAudioHeader(); if (raf.length() < 12) { throw new CannotReadException("This is not a WAV File (<12 bytes)"); } byte[] b = new byte[12]; raf.read(b); WavRIFFHeader wh = new WavRIFFHeader(b); if (wh.isValid()) { b = new byte[24]; raf.read(b); WavFormatHeader wfh = new WavFormatHeader(b); if (wfh.isValid()) { // Populates // encodingInfo---------------------------------------------------- info.setPreciseLength(((float) raf.length() - (float) 36) / wfh.getBytesPerSecond()); info.setChannelNumber(wfh.getChannelNumber()); info.setSamplingRate(wfh.getSamplingRate()); info.setEncodingType("WAV-RIFF " + wfh.getBitrate() + " bits"); info.setExtraEncodingInfos(""); info.setBitrate(wfh.getBytesPerSecond() * 8 / 1000); info.setVariableBitRate(false); } else { throw new CannotReadException("Wav Format Header not valid"); } } else { throw new CannotReadException("Wav RIFF Header not valid"); } return info; } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/asf/0000755000175000017500000000000011556363171023370 5ustar drazzibdrazziblibjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/asf/tag/0000755000175000017500000000000011556363171024143 5ustar drazzibdrazziblibjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/asf/AsfFileWriter.java0000644000175000017500000001361711277264361026752 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2004-2005 Christian Laireiter * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.audio.asf; import org.jaudiotagger.audio.asf.data.AsfHeader; import org.jaudiotagger.audio.asf.data.ChunkContainer; import org.jaudiotagger.audio.asf.data.MetadataContainer; import org.jaudiotagger.audio.asf.io.*; import org.jaudiotagger.tag.asf.AsfTag; import org.jaudiotagger.audio.asf.util.TagConverter; import org.jaudiotagger.audio.exceptions.CannotWriteException; import org.jaudiotagger.audio.generic.AudioFileWriter; import org.jaudiotagger.tag.Tag; import java.io.IOException; import java.io.RandomAccessFile; import java.util.ArrayList; import java.util.List; /** * This class writes given tags to ASF files containing WMA content.
*
* * @author Christian Laireiter */ public class AsfFileWriter extends AudioFileWriter { /** * {@inheritDoc} */ @Override protected void deleteTag(final RandomAccessFile raf, final RandomAccessFile tempRaf) throws CannotWriteException, IOException { writeTag(new AsfTag(true), raf, tempRaf); } private boolean[] searchExistence(final ChunkContainer container, final MetadataContainer[] metaContainers) { assert container != null; assert metaContainers != null; final boolean[] result = new boolean[metaContainers.length]; for (int i = 0; i < result.length; i++) { result[i] = container.hasChunkByGUID(metaContainers[i] .getContainerType().getContainerGUID()); } return result; } /** * {@inheritDoc} */ @Override protected void writeTag(final Tag tag, final RandomAccessFile raf, final RandomAccessFile rafTemp) throws CannotWriteException, IOException { /* * Since this implementation should not change the structure of the ASF * file (locations of content description chunks), we need to read the * content description chunk and the extended content description chunk * from the source file. In the second step we need to determine which * modifier (asf header or asf extended header) gets the appropriate * modifiers. The following policies are applied: if the source does not * contain any descriptor, the necessary descriptors are appended to the * header object. * * if the source contains only one descriptor in the header extension * object, and the other type is needed as well, the other one will be * put into the header extension object. * * for each descriptor type, if an object is found, an updater will be * configured. */ final AsfHeader sourceHeader = AsfHeaderReader.readTagHeader(raf); raf.seek(0); // Reset for the streamer /* * Now createField modifiers for metadata descriptor and extended content * descriptor as implied by the given Tag. */ // TODO not convinced that we need to copy fields here final AsfTag copy = new AsfTag(tag, true); final MetadataContainer[] distribution = TagConverter .distributeMetadata(copy); final boolean[] existHeader = searchExistence(sourceHeader, distribution); final boolean[] existExtHeader = searchExistence(sourceHeader .getExtendedHeader(), distribution); // Modifiers for the asf header object final List headerModifier = new ArrayList(); // Modifiers for the asf header extension object final List extHeaderModifier = new ArrayList(); for (int i = 0; i < distribution.length; i++) { final WriteableChunkModifer modifier = new WriteableChunkModifer( distribution[i]); if (existHeader[i]) { // Will remove or modify chunks in ASF header headerModifier.add(modifier); } else if (existExtHeader[i]) { // Will remove or modify chunks in extended header extHeaderModifier.add(modifier); } else { // Objects (chunks) will be added here. if (i == 0 || i == 2 || i == 1) { // Add content description and extended content description // at header for maximum compatibility headerModifier.add(modifier); } else { // For now, the rest should be created at extended header // since other positions aren't known. extHeaderModifier.add(modifier); } } } // only addField an AsfExtHeaderModifier, if there is actually something to // change (performance) if (!extHeaderModifier.isEmpty()) { headerModifier.add(new AsfExtHeaderModifier(extHeaderModifier)); } new AsfStreamer() .createModifiedCopy(new RandomAccessFileInputstream(raf), new RandomAccessFileOutputStream(rafTemp), headerModifier); } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/asf/data/0000755000175000017500000000000011556363171024301 5ustar drazzibdrazziblibjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/asf/data/AsfHeader.java0000644000175000017500000001611011277026507026764 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2004-2005 Christian Laireiter * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.audio.asf.data; import org.jaudiotagger.audio.asf.util.Utils; import java.math.BigInteger; import java.nio.charset.Charset; import java.util.HashSet; import java.util.List; import java.util.Set; /** * Each ASF file starts with a so called header.
* This header contains other chunks. Each chunk starts with a 16 byte GUID * followed by the length (in bytes) of the chunk (including GUID). The length * number takes 8 bytes and is unsigned. Finally the chunk's data appears.
* * @author Christian Laireiter */ public final class AsfHeader extends ChunkContainer { /** * The charset "UTF-16LE" is mandatory for ASF handling. */ public final static Charset ASF_CHARSET = Charset.forName("UTF-16LE"); //$NON-NLS-1$ /** * Byte sequence representing the zero term character. */ public final static byte[] ZERO_TERM = { 0, 0 }; static { Set MULTI_CHUNKS = new HashSet(); MULTI_CHUNKS.add(GUID.GUID_STREAM); } /** * An ASF header contains multiple chunks.
* The count of those is stored here. */ private final long chunkCount; /** * Creates an instance. * * @param pos * see {@link Chunk#position} * @param chunkLen * see {@link Chunk#chunkLength} * @param chunkCnt */ public AsfHeader(final long pos, final BigInteger chunkLen, final long chunkCnt) { super(GUID.GUID_HEADER, pos, chunkLen); this.chunkCount = chunkCnt; } /** * This method looks for an content description object in this header * instance, if not found there, it tries to get one from a contained ASF * header extension object. * * @return content description if found, null otherwise. */ public ContentDescription findContentDescription() { ContentDescription result = getContentDescription(); if (result == null && getExtendedHeader() != null) { result = getExtendedHeader().getContentDescription(); } return result; } /** * This method looks for an extended content description object in this * header instance, if not found there, it tries to get one from a contained * ASF header extension object. * * @return extended content description if found, null * otherwise. */ public MetadataContainer findExtendedContentDescription() { MetadataContainer result = getExtendedContentDescription(); if (result == null && getExtendedHeader() != null) { result = getExtendedHeader().getExtendedContentDescription(); } return result; } /** * This method searches for a metadata container of the given type.
* * @param type * the type of the container to look up. * @return a container of specified type, of null if not * contained. */ public MetadataContainer findMetadataContainer(final ContainerType type) { MetadataContainer result = (MetadataContainer) getFirst(type .getContainerGUID(), MetadataContainer.class); if (result == null) { result = (MetadataContainer) getExtendedHeader().getFirst( type.getContainerGUID(), MetadataContainer.class); } return result; } /** * This method returns the first audio stream chunk found in the asf file or * stream. * * @return Returns the audioStreamChunk. */ public AudioStreamChunk getAudioStreamChunk() { AudioStreamChunk result = null; final List streamChunks = assertChunkList(GUID.GUID_STREAM); for (int i = 0; i < streamChunks.size() && result == null; i++) { if (streamChunks.get(i) instanceof AudioStreamChunk) { result = (AudioStreamChunk) streamChunks.get(i); } } return result; } /** * Returns the amount of chunks, when this instance was created.
* If chunks have been added, this won't be reflected with this call.
* For that use {@link #getChunks()}. * * @return Chunkcount at instance creation. */ public long getChunkCount() { return this.chunkCount; } /** * @return Returns the contentDescription. */ public ContentDescription getContentDescription() { return (ContentDescription) getFirst(GUID.GUID_CONTENTDESCRIPTION, ContentDescription.class); } /** * @return Returns the encodingChunk. */ public EncodingChunk getEncodingChunk() { return (EncodingChunk) getFirst(GUID.GUID_ENCODING, EncodingChunk.class); } /** * @return Returns the encodingChunk. */ public EncryptionChunk getEncryptionChunk() { return (EncryptionChunk) getFirst(GUID.GUID_CONTENT_ENCRYPTION, EncryptionChunk.class); } /** * @return Returns the tagHeader. */ public MetadataContainer getExtendedContentDescription() { return (MetadataContainer) getFirst( GUID.GUID_EXTENDED_CONTENT_DESCRIPTION, MetadataContainer.class); } /** * @return Returns the extended header. */ public AsfExtendedHeader getExtendedHeader() { return (AsfExtendedHeader) getFirst(GUID.GUID_HEADER_EXTENSION, AsfExtendedHeader.class); } /** * @return Returns the fileHeader. */ public FileHeader getFileHeader() { return (FileHeader) getFirst(GUID.GUID_FILE, FileHeader.class); } /** * @return Returns the streamBitratePropertiesChunk. */ public StreamBitratePropertiesChunk getStreamBitratePropertiesChunk() { return (StreamBitratePropertiesChunk) getFirst( GUID.GUID_STREAM_BITRATE_PROPERTIES, StreamBitratePropertiesChunk.class); } /** * * {@inheritDoc} */ @Override public String prettyPrint(final String prefix) { final StringBuilder result = new StringBuilder(super.prettyPrint(prefix, prefix + " | : Contains: \"" + getChunkCount() + "\" chunks" + Utils.LINE_SEPARATOR)); return result.toString(); } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/asf/data/VideoStreamChunk.java0000644000175000017500000000736211222471043030353 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2004-2005 Christian Laireiter * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.audio.asf.data; import org.jaudiotagger.audio.asf.util.Utils; import java.math.BigInteger; /** * @author Christian Laireiter */ public class VideoStreamChunk extends StreamChunk { /** * Stores the codecs id. Normally the Four-CC (4-Bytes). */ private byte[] codecId = new byte[0]; /** * This field stores the height of the video stream. */ private long pictureHeight; /** * This field stores the width of the video stream. */ private long pictureWidth; /** * Creates an instance. * * @param chunkLen * Length of the entire chunk (including guid and size) */ public VideoStreamChunk(final BigInteger chunkLen) { super(GUID.GUID_VIDEOSTREAM, chunkLen); } /** * @return Returns the codecId. */ public byte[] getCodecId() { return this.codecId.clone(); } /** * Returns the {@link #getCodecId()}, as a String, where each byte has been * converted to a char. * * @return Codec Id as String. */ public String getCodecIdAsString() { String result; if (this.codecId == null) { result = "Unknown"; } else { result = new String(getCodecId()); } return result; } /** * @return Returns the pictureHeight. */ public long getPictureHeight() { return this.pictureHeight; } /** * @return Returns the pictureWidth. */ public long getPictureWidth() { return this.pictureWidth; } /** * (overridden) * * @see org.jaudiotagger.audio.asf.data.StreamChunk#prettyPrint(String) */ @Override public String prettyPrint(final String prefix) { final StringBuilder result = new StringBuilder(super.prettyPrint(prefix)); result.insert(0, Utils.LINE_SEPARATOR + prefix + "|->VideoStream"); result.append(prefix).append("Video info:") .append(Utils.LINE_SEPARATOR); result.append(prefix).append(" |->Width : ").append( getPictureWidth()).append(Utils.LINE_SEPARATOR); result.append(prefix).append(" |->Heigth : ").append( getPictureHeight()).append(Utils.LINE_SEPARATOR); result.append(prefix).append(" |->Codec : ").append( getCodecIdAsString()).append(Utils.LINE_SEPARATOR); return result.toString(); } /** * @param codecIdentifier * The codecId to set. */ public void setCodecId(final byte[] codecIdentifier) { this.codecId = codecIdentifier.clone(); } /** * @param picHeight */ public void setPictureHeight(final long picHeight) { this.pictureHeight = picHeight; } /** * @param picWidth */ public void setPictureWidth(final long picWidth) { this.pictureWidth = picWidth; } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/asf/data/GUID.java0000644000175000017500000004552411222471043025672 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2004-2005 Christian Laireiter * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.audio.asf.data; import org.jaudiotagger.audio.asf.util.Utils; import java.util.Arrays; import java.util.HashMap; import java.util.Map; import java.util.regex.Pattern; /** * This class is used for representation of GUIDs and as a reference list of all * Known GUIDs.
* * @author Christian Laireiter */ public final class GUID { /** * This constant defines the GUID for stream chunks describing audio * streams, indicating the the audio stream has no error concealment.
*/ public final static GUID GUID_AUDIO_ERROR_CONCEALEMENT_ABSENT = new GUID( new int[] { 0x40, 0xA4, 0xF1, 0x49, 0xCE, 0x4E, 0xD0, 0x11, 0xA3, 0xAC, 0x00, 0xA0, 0xC9, 0x03, 0x48, 0xF6 }, "Audio error concealment absent."); /** * This constant defines the GUID for stream chunks describing audio * streams, indicating the the audio stream has interleaved error * concealment.
*/ public final static GUID GUID_AUDIO_ERROR_CONCEALEMENT_INTERLEAVED = new GUID( new int[] { 0x40, 0xA4, 0xF1, 0x49, 0xCE, 0x4E, 0xD0, 0x11, 0xA3, 0xAC, 0x00, 0xA0, 0xC9, 0x03, 0x48, 0xF6 }, "Interleaved audio error concealment."); /** * This constant stores the GUID indicating that stream type is audio. */ public final static GUID GUID_AUDIOSTREAM = new GUID(new int[] { 0x40, 0x9E, 0x69, 0xF8, 0x4D, 0x5B, 0xCF, 0x11, 0xA8, 0xFD, 0x00, 0x80, 0x5F, 0x5C, 0x44, 0x2B }, " Audio stream"); /** * This constant stores the GUID indicating a content branding object. */ public final static GUID GUID_CONTENT_BRANDING = new GUID(new int[] { 0xFA, 0xB3, 0x11, 0x22, 0x23, 0xBD, 0xD2, 0x11, 0xB4, 0xB7, 0x00, 0xA0, 0xC9, 0x55, 0xFC, 0x6E }, "Content Branding"); /** * This is for the Content Encryption Object * 2211B3FB-BD23-11D2-B4B7-00A0C955FC6E, needs to be little-endian. */ public final static GUID GUID_CONTENT_ENCRYPTION = new GUID(new int[] { 0xfb, 0xb3, 0x11, 0x22, 0x23, 0xbd, 0xd2, 0x11, 0xb4, 0xb7, 0x00, 0xa0, 0xc9, 0x55, 0xfc, 0x6e }, "Content Encryption Object"); /** * This constant represents the guidData for a chunk which contains Title, * author, copyright, description and rating. */ public final static GUID GUID_CONTENTDESCRIPTION = new GUID(new int[] { 0x33, 0x26, 0xB2, 0x75, 0x8E, 0x66, 0xCF, 0x11, 0xA6, 0xD9, 0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C }, "Content Description"); /** * This constant stores the GUID for Encoding-Info chunks. */ public final static GUID GUID_ENCODING = new GUID(new int[] { 0x40, 0x52, 0xD1, 0x86, 0x1D, 0x31, 0xD0, 0x11, 0xA3, 0xA4, 0x00, 0xA0, 0xC9, 0x03, 0x48, 0xF6 }, "Encoding description"); /** * This constant defines the GUID for a WMA "Extended Content Description" * chunk.
*/ public final static GUID GUID_EXTENDED_CONTENT_DESCRIPTION = new GUID( new int[] { 0x40, 0xA4, 0xD0, 0xD2, 0x07, 0xE3, 0xD2, 0x11, 0x97, 0xF0, 0x00, 0xA0, 0xC9, 0x5E, 0xA8, 0x50 }, "Extended Content Description"); /** * GUID of ASF file header. */ public final static GUID GUID_FILE = new GUID(new int[] { 0xA1, 0xDC, 0xAB, 0x8C, 0x47, 0xA9, 0xCF, 0x11, 0x8E, 0xE4, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65 }, "File header"); /** * This constant defines the GUID of a asf header chunk. */ public final static GUID GUID_HEADER = new GUID(new int[] { 0x30, 0x26, 0xb2, 0x75, 0x8e, 0x66, 0xcf, 0x11, 0xa6, 0xd9, 0x00, 0xaa, 0x00, 0x62, 0xce, 0x6c }, "Asf header"); /** * This constant stores a GUID whose functionality is unknown. */ public final static GUID GUID_HEADER_EXTENSION = new GUID(new int[] { 0xB5, 0x03, 0xBF, 0x5F, 0x2E, 0xA9, 0xCF, 0x11, 0x8E, 0xE3, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65 }, "Header Extension"); /** * This constant stores the GUID indicating the asf language list object.
*/ public final static GUID GUID_LANGUAGE_LIST = new GUID(new int[] { 0xa9, 0x46, 0x43, 0x7c, 0xe0, 0xef, 0xfc, 0x4b, 0xb2, 0x29, 0x39, 0x3e, 0xde, 0x41, 0x5c, 0x85 }, "Language List"); /** * This constant stores the length of GUIDs used with ASF streams.
*/ public final static int GUID_LENGTH = 16; /** * This constant stores the GUID indicating the asf metadata object.
*/ public final static GUID GUID_METADATA = new GUID(new int[] { 0xea, 0xcb, 0xf8, 0xc5, 0xaf, 0x5b, 0x77, 0x48, 0x84, 0x67, 0xaa, 0x8c, 0x44, 0xfa, 0x4c, 0xca }, "Metadata"); /** * This constant stores the GUID indicating the asf metadata library object.
*/ public final static GUID GUID_METADATA_LIBRARY = new GUID(new int[] { 0x94, 0x1c, 0x23, 0x44, 0x98, 0x94, 0xd1, 0x49, 0xa1, 0x41, 0x1d, 0x13, 0x4e, 0x45, 0x70, 0x54 }, "Metadata Library"); /** * The GUID String values format.
*/ private final static Pattern GUID_PATTERN = Pattern .compile( "[a-f0-9]{8}\\-[a-f0-9]{4}\\-[a-f0-9]{4}\\-[a-f0-9]{4}\\-[a-f0-9]{12}", Pattern.CASE_INSENSITIVE); /** * This constant stores the GUID indicating a stream object. */ public final static GUID GUID_STREAM = new GUID(new int[] { 0x91, 0x07, 0xDC, 0xB7, 0xB7, 0xA9, 0xCF, 0x11, 0x8E, 0xE6, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65 }, "Stream"); /** * This constant stores a GUID indicating a "stream bitrate properties" * chunk. */ public final static GUID GUID_STREAM_BITRATE_PROPERTIES = new GUID( new int[] { 0xCE, 0x75, 0xF8, 0x7B, 0x8D, 0x46, 0xD1, 0x11, 0x8D, 0x82, 0x00, 0x60, 0x97, 0xC9, 0xA2, 0xB2 }, "Stream bitrate properties"); /** * This map is used, to get the description of a GUID instance, which has * been created by reading.
* The map comparison is done against the {@link GUID#guidData} field. But * only the {@link #KNOWN_GUIDS} have a description set. */ private final static Map GUID_TO_CONFIGURED; /** * This constant represents a GUID implementation which can be used for * generic implementations, which have to provide a GUID, but do not really * require a specific GUID to work. */ public final static GUID GUID_UNSPECIFIED = new GUID(new int[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, "Unspecified"); /** * This constant stores the GUID indicating that stream type is video. */ public final static GUID GUID_VIDEOSTREAM = new GUID(new int[] { 0xC0, 0xEF, 0x19, 0xBC, 0x4D, 0x5B, 0xCF, 0x11, 0xA8, 0xFD, 0x00, 0x80, 0x5F, 0x5C, 0x44, 0x2B }, "Video stream"); /** * This field stores all known GUIDs. */ public final static GUID[] KNOWN_GUIDS; /** * This constant stores the GUID for a "script command object".
*/ public final static GUID SCRIPT_COMMAND_OBJECT = new GUID(new int[] { 0x30, 0x1a, 0xfb, 0x1e, 0x62, 0x0b, 0xd0, 0x11, 0xa3, 0x9b, 0x00, 0xa0, 0xc9, 0x03, 0x48, 0xf6 }, "Script Command Object"); static { KNOWN_GUIDS = new GUID[] { GUID_AUDIO_ERROR_CONCEALEMENT_ABSENT, GUID_CONTENTDESCRIPTION, GUID_AUDIOSTREAM, GUID_ENCODING, GUID_FILE, GUID_HEADER, GUID_STREAM, GUID_EXTENDED_CONTENT_DESCRIPTION, GUID_VIDEOSTREAM, GUID_HEADER_EXTENSION, GUID_STREAM_BITRATE_PROPERTIES, SCRIPT_COMMAND_OBJECT, GUID_CONTENT_ENCRYPTION, GUID_CONTENT_BRANDING, GUID_UNSPECIFIED, GUID_METADATA_LIBRARY, GUID_METADATA, GUID_LANGUAGE_LIST }; GUID_TO_CONFIGURED = new HashMap(KNOWN_GUIDS.length); for (final GUID curr : KNOWN_GUIDS) { assert !GUID_TO_CONFIGURED.containsKey(curr) : "Double definition: \"" + GUID_TO_CONFIGURED.get(curr).getDescription() + "\" <-> \"" + curr.getDescription() + "\""; GUID_TO_CONFIGURED.put(curr, curr); } } /** * This method checks if the given value is matching the GUID * specification of ASF streams.
* * @param value * possible GUID. * @return true if value matches the specification * of a GUID. */ public static boolean assertGUID(final int[] value) { return value != null && value.length == GUID.GUID_LENGTH; } /** * This method looks up a GUID instance from {@link #KNOWN_GUIDS} which * matches the value of the given GUID. * * @param orig * GUID to look up. * @return a GUID instance from {@link #KNOWN_GUIDS} if available. * null else. */ public static GUID getConfigured(final GUID orig) { // safe against null return GUID_TO_CONFIGURED.get(orig); } /** * This method searches a GUID in {@link #KNOWN_GUIDS}which is equal to the * given guidData and returns its description.
* This method is useful if a GUID was read out of a file and no * identification has been done yet. * * @param guid * GUID, which description is needed. * @return description of the GUID if found. Else null */ public static String getGuidDescription(final GUID guid) { String result = null; if (guid == null) { throw new IllegalArgumentException("Argument must not be null."); } if (getConfigured(guid) != null) { result = getConfigured(guid).getDescription(); } return result; } /** * This method parses a String as GUID.
* The format is like the one in the ASF specification.
* An Example: C5F8CBEA-5BAF-4877-8467-AA8C44FA4CCA
* * @param guid * the string to parse. * @return the GUID. * @throws GUIDFormatException * If the GUID has an invalid format. */ public static GUID parseGUID(final String guid) throws GUIDFormatException { if (guid == null) { throw new GUIDFormatException("null"); } if (!GUID_PATTERN.matcher(guid).matches()) { throw new GUIDFormatException("Invalid guidData format."); } final int[] bytes = new int[GUID_LENGTH]; /* * Don't laugh, but did not really come up with a nicer solution today */ final int[] arrayIndices = { 3, 2, 1, 0, 5, 4, 7, 6, 8, 9, 10, 11, 12, 13, 14, 15 }; int arrayPointer = 0; for (int i = 0; i < guid.length(); i++) { if (guid.charAt(i) == '-') { continue; } bytes[arrayIndices[arrayPointer++]] = Integer.parseInt(guid .substring(i, i + 2), 16); i++; } return new GUID(bytes); } /** * Stores an optionally description of the GUID. */ private String description = ""; /** * An instance of this class stores the value of the wrapped GUID in this * field.
*/ private int[] guidData = null; /** * Stores the hash code of the object.
* "-1" if not determined yet. */ private int hash; /** * Creates an instance and assigns given value.
* * @param value * GUID, which should be assigned. (will be converted to int[]) */ public GUID(final byte[] value) { assert value != null; final int[] tmp = new int[value.length]; for (int i = 0; i < value.length; i++) { tmp[i] = (0xFF & value[i]); } setGUID(tmp); } /** * Creates an instance and assigns given value.
* * @param value * GUID, which should be assigned. */ public GUID(final int[] value) { setGUID(value); } /** * Creates an instance like {@link #GUID(int[])}and sets the optional * description.
* * @param value * GUID, which should be assigned. * @param desc * Description for the GUID. */ public GUID(final int[] value, final String desc) { this(value); if (desc == null) { throw new IllegalArgumentException("Argument must not be null."); } this.description = desc; } /** * Creates an instance like {@link #GUID(int[])} and sets the optional * description. (the int[] is obtained by {@link GUID#parseGUID(String)})
* * @param guidString * GUID, which should be assigned. * @param desc * Description for the GUID. */ public GUID(final String guidString, final String desc) { this(parseGUID(guidString).getGUID()); if (desc == null) { throw new IllegalArgumentException("Argument must not be null."); } this.description = desc; } /** * This method compares two objects. If the given Object is a {@link GUID}, * the stored GUID values are compared.
* * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(final Object obj) { boolean result = false; if (obj instanceof GUID) { final GUID other = (GUID) obj; result = Arrays.equals(this.getGUID(), other.getGUID()); } return result; } /** * This method returns the GUID as an array of bytes.
* * @return The GUID as a byte array. * @see #getGUID() */ public byte[] getBytes() { final byte[] result = new byte[this.guidData.length]; for (int i = 0; i < result.length; i++) { result[i] = (byte) (this.guidData[i] & 0xFF); } return result; } /** * @return Returns the description. */ public String getDescription() { return this.description; } /** * This method returns the GUID of this object.
* * @return stored GUID. */ public int[] getGUID() { final int[] copy = new int[this.guidData.length]; System.arraycopy(this.guidData, 0, copy, 0, this.guidData.length); return copy; } /** * Convenience method to get 2digit hex values of each byte. * * @param bytes * bytes to convert. * @return each byte as 2 digit hex. */ private String[] getHex(final byte[] bytes) { final String[] result = new String[bytes.length]; final StringBuilder tmp = new StringBuilder(); for (int i = 0; i < bytes.length; i++) { tmp.delete(0, tmp.length()); tmp.append(Integer.toHexString(0xFF & bytes[i])); if (tmp.length() == 1) { tmp.insert(0, "0"); } result[i] = tmp.toString(); } return result; } /** * {@inheritDoc} */ @Override public int hashCode() { if (this.hash == -1) { int tmp = 0; for (final int curr : getGUID()) { tmp = tmp * 31 + curr; } this.hash = tmp; } return this.hash; } /** * This method checks if the currently stored GUID ({@link #guidData}) is * correctly filled.
* * @return true if it is. */ public boolean isValid() { return assertGUID(getGUID()); } /** * This method gives a hex formatted representation of {@link #getGUID()} * * @return hex formatted representation. */ public String prettyPrint() { final StringBuilder result = new StringBuilder(); String descr = getDescription(); if (Utils.isBlank(descr)) { descr = getGuidDescription(this); } if (!Utils.isBlank(descr)) { result.append("Description: ").append(descr).append( Utils.LINE_SEPARATOR).append(" "); } result.append(this.toString()); return result.toString(); } /** * This method saves a copy of the given value as the * represented value of this object.
* The given value is checked with {@link #assertGUID(int[])}.
* * @param value * GUID to assign. */ private void setGUID(final int[] value) { if (assertGUID(value)) { this.guidData = new int[GUID_LENGTH]; System.arraycopy(value, 0, this.guidData, 0, GUID_LENGTH); } else { throw new IllegalArgumentException( "The given guidData doesn't match the GUID specification."); } } /** * {@inheritDoc} */ @Override public String toString() { // C5F8CBEA-5BAF-4877-8467-AA8C44FA4CCA // 0xea, 0xcb,0xf8, 0xc5, 0xaf, 0x5b, 0x77, 0x48, 0x84, 0x67, 0xaa, // 0x8c, 0x44,0xfa, 0x4c, 0xca final StringBuilder result = new StringBuilder(); final String[] bytes = getHex(getBytes()); result.append(bytes[3]); result.append(bytes[2]); result.append(bytes[1]); result.append(bytes[0]); result.append('-'); result.append(bytes[5]); result.append(bytes[4]); result.append('-'); result.append(bytes[7]); result.append(bytes[6]); result.append('-'); result.append(bytes[8]); result.append(bytes[9]); result.append('-'); result.append(bytes[10]); result.append(bytes[11]); result.append(bytes[12]); result.append(bytes[13]); result.append(bytes[14]); result.append(bytes[15]); return result.toString(); } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/asf/data/ContentBranding.java0000644000175000017500000001410711222471043030212 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.asf.data; import org.jaudiotagger.audio.asf.util.Utils; import java.io.IOException; import java.io.OutputStream; import java.math.BigInteger; import java.util.HashSet; import java.util.Set; /** * This structure represents the value of the content branding object, which * stores the banner image, the banner image URL and the copyright URL.
* * @author Christian Laireiter */ public final class ContentBranding extends MetadataContainer { /** * Stores the allowed {@linkplain MetadataDescriptor#getName() descriptor * keys}. */ public final static Set ALLOWED; /** * Descriptor key representing the banner image. */ public final static String KEY_BANNER_IMAGE = "BANNER_IMAGE"; /** * Descriptor key representing the banner image type.
*
* Known/valid values are: *

    *
  1. 0: there is no image present
  2. *
  3. 1: there is a BMP image
  4. *
  5. 2: there is a JPEG image
  6. *
  7. 3: there is a GIF image
  8. *
*/ public final static String KEY_BANNER_TYPE = "BANNER_IMAGE_TYPE"; /** * Descriptor key representing the banner image URL. */ public final static String KEY_BANNER_URL = "BANNER_IMAGE_URL"; /** * Descriptor key representing the copyright URL. */ public final static String KEY_COPYRIGHT_URL = "COPYRIGHT_URL"; static { ALLOWED = new HashSet(); ALLOWED.add(KEY_BANNER_IMAGE); ALLOWED.add(KEY_BANNER_TYPE); ALLOWED.add(KEY_BANNER_URL); ALLOWED.add(KEY_COPYRIGHT_URL); } /** * Creates an instance. */ public ContentBranding() { this(0, BigInteger.ZERO); } /** * Creates an instance. * * @param pos * Position of content description within file or stream * @param size * Length of content description. */ public ContentBranding(final long pos, final BigInteger size) { super(ContainerType.CONTENT_BRANDING, pos, size); } /** * Returns the banner image URL. * * @return the banner image URL. */ public String getBannerImageURL() { return getValueFor(KEY_BANNER_URL); } /** * Returns the copyright URL. * * @return the banner image URL. */ public String getCopyRightURL() { return getValueFor(KEY_COPYRIGHT_URL); } /** * {@inheritDoc} */ @Override public long getCurrentAsfChunkSize() { // GUID, size, image type, image data size, image url data size, // copyright data size long result = 40; result += assertDescriptor(KEY_BANNER_IMAGE, MetadataDescriptor.TYPE_BINARY).getRawDataSize(); result += getBannerImageURL().length(); result += getCopyRightURL().length(); return result; } /** * Returns the binary image data. * * @return binary image data. */ public byte[] getImageData() { return assertDescriptor(KEY_BANNER_IMAGE, MetadataDescriptor.TYPE_BINARY).getRawData(); } /** * Returns the image type.
* * @see #KEY_BANNER_TYPE for known/valid values. * @return image type */ public long getImageType() { if (!hasDescriptor(KEY_BANNER_TYPE)) { final MetadataDescriptor descriptor = new MetadataDescriptor( ContainerType.CONTENT_BRANDING, KEY_BANNER_TYPE, MetadataDescriptor.TYPE_DWORD); descriptor.setDWordValue(0); addDescriptor(descriptor); } return assertDescriptor(KEY_BANNER_TYPE).getNumber(); } /** * {@inheritDoc} */ @Override public boolean isAddSupported(final MetadataDescriptor descriptor) { return ALLOWED.contains(descriptor.getName()) && super.isAddSupported(descriptor); } /** * This method sets the banner image URL, if imageURL is not * blank.
* * @param imageURL * image URL to set. */ public void setBannerImageURL(final String imageURL) { if (Utils.isBlank(imageURL)) { removeDescriptorsByName(KEY_BANNER_URL); } else { assertDescriptor(KEY_BANNER_URL).setStringValue(imageURL); } } /** * This method sets the copyright URL, if copyRight is not * blank.
* * @param copyRight * copyright URL to set. */ public void setCopyRightURL(final String copyRight) { if (Utils.isBlank(copyRight)) { removeDescriptorsByName(KEY_COPYRIGHT_URL); } else { assertDescriptor(KEY_COPYRIGHT_URL).setStringValue(copyRight); } } /** * @param imageType * @param imageData */ public void setImage(final long imageType, final byte[] imageData) { assert imageType >= 0 && imageType <= 3; assert imageType > 0 || imageData.length == 0; assertDescriptor(KEY_BANNER_TYPE, MetadataDescriptor.TYPE_DWORD) .setDWordValue(imageType); assertDescriptor(KEY_BANNER_IMAGE, MetadataDescriptor.TYPE_BINARY) .setBinaryValue(imageData); } /** * {@inheritDoc} */ @Override public long writeInto(final OutputStream out) throws IOException { final long chunkSize = getCurrentAsfChunkSize(); out.write(getGuid().getBytes()); Utils.writeUINT64(chunkSize, out); Utils.writeUINT32(getImageType(), out); assert getImageType() >= 0 && getImageType() <= 3; final byte[] imageData = getImageData(); assert getImageType() > 0 || imageData.length == 0; Utils.writeUINT32(imageData.length, out); out.write(imageData); Utils.writeUINT32(getBannerImageURL().length(), out); out.write(getBannerImageURL().getBytes("ASCII")); Utils.writeUINT32(getCopyRightURL().length(), out); out.write(getCopyRightURL().getBytes("ASCII")); return chunkSize; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/asf/data/LanguageList.java0000644000175000017500000000617111222471043027514 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.asf.data; import org.jaudiotagger.audio.asf.util.Utils; import org.jaudiotagger.logging.ErrorMessage; import java.math.BigInteger; import java.util.ArrayList; import java.util.List; /** * This structure represents the data of the ASF language object.
* The language list is simply a listing of language codes which should comply * to RFC-1766.
* Consider: the index of a language is used by other entries in the ASF * metadata. * * @author Christian Laireiter */ public class LanguageList extends Chunk { /** * List of language codes, complying RFC-1766 */ private final List languages = new ArrayList(); /** * Creates a new instance.
*/ public LanguageList() { super(GUID.GUID_LANGUAGE_LIST, 0, BigInteger.ZERO); } /** * Creates an instance. * * @param pos * position within the ASF file. * @param size * size of the chunk */ public LanguageList(final long pos, final BigInteger size) { super(GUID.GUID_LANGUAGE_LIST, pos, size); } /** * This method adds a language.
* * @param language * language code */ public void addLanguage(final String language) { if (language.length() < MetadataDescriptor.MAX_LANG_INDEX) { if (!this.languages.contains(language)) { this.languages.add(language); } } else { throw new IllegalArgumentException( ErrorMessage.WMA_LENGTH_OF_LANGUAGE_IS_TOO_LARGE .getMsg(language.length() * 2 + 2)); } } /** * Returns the language code at the specified index. * * @param index * the index of the language code to get. * @return the language code at given index. */ public String getLanguage(final int index) { return this.languages.get(index); } /** * Returns the amount of stored language codes. * * @return number of stored language codes. */ public int getLanguageCount() { return this.languages.size(); } /** * Returns all language codes in list. * * @return list of language codes. */ public List getLanguages() { return new ArrayList(this.languages); } /** * {@inheritDoc} */ @Override public String prettyPrint(final String prefix) { final StringBuilder result = new StringBuilder(super.prettyPrint(prefix)); for (int i = 0; i < getLanguageCount(); i++) { result.append(prefix); result.append(" |-> "); result.append(i); result.append(" : "); result.append(getLanguage(i)); result.append(Utils.LINE_SEPARATOR); } return result.toString(); } /** * Removes the language entry at specified index. * * @param index * index of language to remove. */ public void removeLanguage(final int index) { this.languages.remove(index); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/asf/data/EncryptionChunk.java0000644000175000017500000000731111277026507030270 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.asf.data; import org.jaudiotagger.audio.asf.util.Utils; import java.math.BigInteger; import java.util.ArrayList; import java.util.Collection; /** * @author eric */ public class EncryptionChunk extends Chunk { private String keyID; private String licenseURL; private String protectionType; private String secretData; /** * The read strings. */ private final ArrayList strings; /** * Creates an instance. * * @param chunkLen * Length of current chunk. */ public EncryptionChunk(final BigInteger chunkLen) { super(GUID.GUID_CONTENT_ENCRYPTION, chunkLen); this.strings = new ArrayList(); this.secretData = ""; this.protectionType = ""; this.keyID = ""; this.licenseURL = ""; } /** * This method appends a String. * * @param toAdd * String to add. */ public void addString(final String toAdd) { this.strings.add(toAdd); } /** * This method gets the keyID. * @return */ public String getKeyID() { return this.keyID; } /** * This method gets the license URL. * @return */ public String getLicenseURL() { return this.licenseURL; } /** * This method gets the secret data. * @return */ public String getProtectionType() { return this.protectionType; } /** * This method gets the secret data. * @return */ public String getSecretData() { return this.secretData; } /** * This method returns a collection of all {@link String}s which were addid * due {@link #addString(String)}. * * @return Inserted Strings. */ public Collection getStrings() { return new ArrayList(this.strings); } /** * {@inheritDoc} */ @Override public String prettyPrint(final String prefix) { final StringBuilder result = new StringBuilder(super.prettyPrint(prefix)); result.insert(0, Utils.LINE_SEPARATOR + prefix + " Encryption:" + Utils.LINE_SEPARATOR); result.append(prefix).append(" |->keyID ").append(this.keyID).append( Utils.LINE_SEPARATOR); result.append(prefix).append(" |->secretData ").append(this.secretData) .append(Utils.LINE_SEPARATOR); result.append(prefix).append(" |->protectionType ").append( this.protectionType).append(Utils.LINE_SEPARATOR); result.append(prefix).append(" |->licenseURL ").append(this.licenseURL) .append(Utils.LINE_SEPARATOR); this.strings.iterator(); for (final String string : this.strings) { result.append(prefix).append(" |->").append(string).append(Utils.LINE_SEPARATOR); } return result.toString(); } /** * This method appends a String. * * @param toAdd * String to add. */ public void setKeyID(final String toAdd) { this.keyID = toAdd; } /** * This method appends a String. * * @param toAdd * String to add. */ public void setLicenseURL(final String toAdd) { this.licenseURL = toAdd; } /** * This method appends a String. * * @param toAdd * String to add. */ public void setProtectionType(final String toAdd) { this.protectionType = toAdd; } /** * This method adds the secret data. * * @param toAdd * String to add. */ public void setSecretData(final String toAdd) { this.secretData = toAdd; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/asf/data/Chunk.java0000644000175000017500000001252311222471043026203 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2004-2005 Christian Laireiter * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.audio.asf.data; import org.jaudiotagger.audio.asf.util.Utils; import java.math.BigInteger; /** * This class represents a chunk within ASF streams.
* Each chunk starts with a 16byte {@linkplain GUID GUID} identifying the type. * After that a number (represented by 8 bytes) follows which shows the size in * bytes of the chunk. Finally there is the data of the chunk. * * @author Christian Laireiter */ public class Chunk { /** * The length of current chunk.
*/ protected final BigInteger chunkLength; /** * The GUID of represented chunk header. */ protected final GUID guid; /** * The position of current header object within file or stream. */ protected long position; /** * Creates an instance * * @param headerGuid * The GUID of header object. * @param chunkLen * Length of current chunk. */ public Chunk(final GUID headerGuid, final BigInteger chunkLen) { if (headerGuid == null) { throw new IllegalArgumentException("GUID must not be null."); } if (chunkLen == null || chunkLen.compareTo(BigInteger.ZERO) < 0) { throw new IllegalArgumentException( "chunkLen must not be null nor negative."); } this.guid = headerGuid; this.chunkLength = chunkLen; } /** * Creates an instance * * @param headerGuid * The GUID of header object. * @param pos * Position of header object within stream or file. * @param chunkLen * Length of current chunk. */ public Chunk(final GUID headerGuid, final long pos, final BigInteger chunkLen) { if (headerGuid == null) { throw new IllegalArgumentException("GUID must not be null"); } if (pos < 0) { throw new IllegalArgumentException( "Position of header can't be negative."); } if (chunkLen == null || chunkLen.compareTo(BigInteger.ZERO) < 0) { throw new IllegalArgumentException( "chunkLen must not be null nor negative."); } this.guid = headerGuid; this.position = pos; this.chunkLength = chunkLen; } /** * This method returns the End of the current chunk introduced by current * header object. * * @return Position after current chunk. * @deprecated typo, use {@link #getChunkEnd()} instead. */ @Deprecated public long getChunckEnd() { return this.position + this.chunkLength.longValue(); } /** * This method returns the End of the current chunk introduced by current * header object. * * @return Position after current chunk. */ public long getChunkEnd() { return this.position + this.chunkLength.longValue(); } /** * @return Returns the chunkLength. */ public BigInteger getChunkLength() { return this.chunkLength; } /** * @return Returns the guid. */ public GUID getGuid() { return this.guid; } /** * @return Returns the position. */ public long getPosition() { return this.position; } /** * This method creates a String containing useful information prepared to be * printed on STD-OUT.
* This method is intended to be overwritten by inheriting classes. * * @param prefix * each line gets this string prepended. * * @return Information of current Chunk Object. */ public String prettyPrint(final String prefix) { final StringBuilder result = new StringBuilder(); result.append(prefix).append("-> GUID: ").append( GUID.getGuidDescription(this.guid)) .append(Utils.LINE_SEPARATOR); result.append(prefix).append(" | : Starts at position: ").append( getPosition()).append(Utils.LINE_SEPARATOR); result.append(prefix).append(" | : Last byte at: ").append( getChunkEnd() - 1).append(Utils.LINE_SEPARATOR); return result.toString(); } /** * Sets the position. * * @param pos * position to set. */ public void setPosition(final long pos) { this.position = pos; } /** * (overridden) * * @see java.lang.Object#toString() */ @Override public String toString() { return prettyPrint(""); } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/asf/data/StreamBitratePropertiesChunk.java0000644000175000017500000000724611222471043032755 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2004-2005 Christian Laireiter * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.audio.asf.data; import org.jaudiotagger.audio.asf.util.Utils; import java.math.BigInteger; import java.util.ArrayList; import java.util.List; /** * This class represents the "Stream Bitrate Properties" chunk of an ASF media * file.
* It is optional, but contains useful information about the streams bitrate.
* * @author Christian Laireiter */ public class StreamBitratePropertiesChunk extends Chunk { /** * For each call of {@link #addBitrateRecord(int,long)} an {@link Long} * object is appended, which represents the average bitrate. */ private final List bitRates; /** * For each call of {@link #addBitrateRecord(int,long)} an {@link Integer} * object is appended, which represents the stream-number. */ private final List streamNumbers; /** * Creates an instance. * * @param chunkLen * Length of current chunk. */ public StreamBitratePropertiesChunk(final BigInteger chunkLen) { super(GUID.GUID_STREAM_BITRATE_PROPERTIES, chunkLen); this.bitRates = new ArrayList(); this.streamNumbers = new ArrayList(); } /** * Adds the public values of a stream-record. * * @param streamNum * The number of the referred stream. * @param averageBitrate * Its average bitrate. */ public void addBitrateRecord(final int streamNum, final long averageBitrate) { this.streamNumbers.add(streamNum); this.bitRates.add(averageBitrate); } /** * Returns the average bitrate of the given stream.
* * @param streamNumber * Number of the stream whose bitrate to determine. * @return The average bitrate of the numbered stream. -1 if no * information was given. */ public long getAvgBitrate(final int streamNumber) { final Integer seach = streamNumber; final int index = this.streamNumbers.indexOf(seach); long result; if (index == -1) { result = -1; } else { result = this.bitRates.get(index); } return result; } /** * (overridden) * * @see org.jaudiotagger.audio.asf.data.Chunk#prettyPrint(String) */ @Override public String prettyPrint(final String prefix) { final StringBuilder result = new StringBuilder(super.prettyPrint(prefix)); for (int i = 0; i < this.bitRates.size(); i++) { result.append(prefix).append(" |-> Stream no. \"").append( this.streamNumbers.get(i)).append( "\" has an average bitrate of \"").append( this.bitRates.get(i)).append('"').append( Utils.LINE_SEPARATOR); } return result.toString(); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/asf/data/GUIDFormatException.java0000644000175000017500000000102411222471043030705 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.asf.data; /** * This exception is used when a string was about to be interpreted as a GUID, * but did not match the format.
* * @author Christian Laireiter */ public class GUIDFormatException extends IllegalArgumentException { /** * */ private static final long serialVersionUID = 6035645678612384953L; /** * Creates an instance. * @param detail detail message. */ public GUIDFormatException(final String detail) { super(detail); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/asf/data/EncodingChunk.java0000644000175000017500000000520411222471043027650 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2004-2005 Christian Laireiter * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.audio.asf.data; import org.jaudiotagger.audio.asf.util.Utils; import java.math.BigInteger; import java.util.ArrayList; import java.util.Collection; import java.util.List; /** * This class was intended to store the data of a chunk which contained the * encoding parameters in textual form.
* Since the needed parameters were found in other chunks the implementation of * this class was paused.
* TODO complete analysis. * * @author Christian Laireiter */ public class EncodingChunk extends Chunk { /** * The read strings. */ private final List strings; /** * Creates an instance. * * @param chunkLen * Length of current chunk. */ public EncodingChunk(final BigInteger chunkLen) { super(GUID.GUID_ENCODING, chunkLen); this.strings = new ArrayList(); } /** * This method appends a String. * * @param toAdd * String to add. */ public void addString(final String toAdd) { this.strings.add(toAdd); } /** * This method returns a collection of all {@linkplain String Strings} which * were added due {@link #addString(String)}. * * @return Inserted Strings. */ public Collection getStrings() { return new ArrayList(this.strings); } /** * {@inheritDoc} */ @Override public String prettyPrint(final String prefix) { final StringBuilder result = new StringBuilder(super .prettyPrint(prefix)); this.strings.iterator(); for (final String string : this.strings) { result.append(prefix).append(" | : ").append(string).append( Utils.LINE_SEPARATOR); } return result.toString(); } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/asf/data/AsfExtendedHeader.java0000644000175000017500000000370211222471043030435 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.asf.data; import java.math.BigInteger; /** * This class represents the ASF extended header object (chunk).
* Like {@link AsfHeader} it contains multiple other ASF objects (chunks).
* * @author Christian Laireiter */ public final class AsfExtendedHeader extends ChunkContainer { /** * Creates an instance.
* * @param pos * Position within the stream.
* @param length * the length of the extended header object. */ public AsfExtendedHeader(final long pos, final BigInteger length) { super(GUID.GUID_HEADER_EXTENSION, pos, length); } /** * @return Returns the contentDescription. */ public ContentDescription getContentDescription() { return (ContentDescription) getFirst(GUID.GUID_CONTENTDESCRIPTION, ContentDescription.class); } /** * @return Returns the tagHeader. */ public MetadataContainer getExtendedContentDescription() { return (MetadataContainer) getFirst( GUID.GUID_EXTENDED_CONTENT_DESCRIPTION, MetadataContainer.class); } /** * Returns a language list object if present. * * @return a language list object. */ public LanguageList getLanguageList() { return (LanguageList) getFirst(GUID.GUID_LANGUAGE_LIST, LanguageList.class); } /** * Returns a metadata library object if present. * * @return metadata library objet */ public MetadataContainer getMetadataLibraryObject() { return (MetadataContainer) getFirst(GUID.GUID_METADATA_LIBRARY, MetadataContainer.class); } /** * Returns a metadata object if present. * * @return metadata object */ public MetadataContainer getMetadataObject() { return (MetadataContainer) getFirst(GUID.GUID_METADATA, MetadataContainer.class); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/asf/data/FileHeader.java0000644000175000017500000001603611222471043027126 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2004-2005 Christian Laireiter * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.audio.asf.data; import org.jaudiotagger.audio.asf.util.Utils; import java.math.BigInteger; import java.util.Date; /** * This class stores the information about the file, which is contained within a * special chunk of ASF files.
* * @author Christian Laireiter */ public class FileHeader extends Chunk { /** * Duration of the media content in 100ns steps. */ private final BigInteger duration; /** * The time the file was created. */ private final Date fileCreationTime; /** * Size of the file or stream. */ private final BigInteger fileSize; /** * Usually contains value of 2. */ private final long flags; /** * Maximum size of stream packages.
* Warning: must be same size as {@link #minPackageSize}. Its not * known how to handle deviating values. */ private final long maxPackageSize; /** * Minimun size of stream packages.
* Warning: must be same size as {@link #maxPackageSize}. Its not * known how to handle deviating values. */ private final long minPackageSize; /** * Number of stream packages within the File. */ private final BigInteger packageCount; /** * No Idea of the Meaning, but stored anyway.
* Source documentation says it is: "Timestamp of end position" */ private final BigInteger timeEndPos; /** * Like {@link #timeEndPos}no Idea. */ private final BigInteger timeStartPos; /** * Size of an uncompressed video frame. */ private final long uncompressedFrameSize; /** * Creates an instance. * * @param chunckLen * Length of the file header (chunk) * @param size * Size of file or stream * @param fileTime * Time file or stream was created. Time is calculated since 1st * january of 1601 in 100ns steps. * @param pkgCount * Number of stream packages. * @param dur * Duration of media clip in 100ns steps * @param timestampStart * Timestamp of start {@link #timeStartPos} * @param timestampEnd * Timestamp of end {@link #timeEndPos} * @param headerFlags * some stream related flags. * @param minPkgSize * minimum size of packages * @param maxPkgSize * maximum size of packages * @param uncmpVideoFrameSize * Size of an uncompressed Video Frame. */ public FileHeader(final BigInteger chunckLen, final BigInteger size, final BigInteger fileTime, final BigInteger pkgCount, final BigInteger dur, final BigInteger timestampStart, final BigInteger timestampEnd, final long headerFlags, final long minPkgSize, final long maxPkgSize, final long uncmpVideoFrameSize) { super(GUID.GUID_FILE, chunckLen); this.fileSize = size; this.packageCount = pkgCount; this.duration = dur; this.timeStartPos = timestampStart; this.timeEndPos = timestampEnd; this.flags = headerFlags; this.minPackageSize = minPkgSize; this.maxPackageSize = maxPkgSize; this.uncompressedFrameSize = uncmpVideoFrameSize; this.fileCreationTime = Utils.getDateOf(fileTime).getTime(); } /** * @return Returns the duration. */ public BigInteger getDuration() { return this.duration; } /** * This method converts {@link #getDuration()}from 100ns steps to normal * seconds. * * @return Duration of the media in seconds. */ public int getDurationInSeconds() { return this.duration.divide(new BigInteger("10000000")).intValue(); } /** * @return Returns the fileCreationTime. */ public Date getFileCreationTime() { return new Date(this.fileCreationTime.getTime()); } /** * @return Returns the fileSize. */ public BigInteger getFileSize() { return this.fileSize; } /** * @return Returns the flags. */ public long getFlags() { return this.flags; } /** * @return Returns the maxPackageSize. */ public long getMaxPackageSize() { return this.maxPackageSize; } /** * @return Returns the minPackageSize. */ public long getMinPackageSize() { return this.minPackageSize; } /** * @return Returns the packageCount. */ public BigInteger getPackageCount() { return this.packageCount; } /** * This method converts {@link #getDuration()} from 100ns steps to normal * seconds with a fractional part taking milliseconds.
* * @return The duration of the media in seconds (with a precision of * milliseconds) */ public float getPreciseDuration() { return (float) (getDuration().doubleValue() / 10000000d); } /** * @return Returns the timeEndPos. */ public BigInteger getTimeEndPos() { return this.timeEndPos; } /** * @return Returns the timeStartPos. */ public BigInteger getTimeStartPos() { return this.timeStartPos; } /** * @return Returns the uncompressedFrameSize. */ public long getUncompressedFrameSize() { return this.uncompressedFrameSize; } /** * (overridden) * * @see org.jaudiotagger.audio.asf.data.Chunk#prettyPrint(String) */ @Override public String prettyPrint(final String prefix) { final StringBuilder result = new StringBuilder(super.prettyPrint(prefix)); result.append(prefix).append(" |-> Filesize = ").append( getFileSize().toString()).append(" Bytes").append( Utils.LINE_SEPARATOR); result.append(prefix).append(" |-> Media duration= ").append( getDuration().divide(new BigInteger("10000")).toString()) .append(" ms").append(Utils.LINE_SEPARATOR); result.append(prefix).append(" |-> Created at = ").append( getFileCreationTime()).append(Utils.LINE_SEPARATOR); return result.toString(); } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/asf/data/ContainerType.java0000644000175000017500000002506511222471043027724 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.asf.data; import org.jaudiotagger.audio.asf.util.Utils; import org.jaudiotagger.logging.ErrorMessage; import java.math.BigInteger; import java.util.Arrays; import java.util.List; /** * Enumerates capabilities, respectively uses, of metadata descriptors.
*
* The {@link #METADATA_LIBRARY_OBJECT} allows the most variations of data, as * well as no size limitation (if it can be stored within a DWORD amount of * bytes).
* * @author Christian Laireiter */ public enum ContainerType { /** * The descriptor is used in the content branding object (chunk) */ CONTENT_BRANDING(GUID.GUID_CONTENT_BRANDING, 32, false, false, false, false), /** * The descriptor is used in the content description object (chunk), so * {@linkplain MetadataDescriptor#DWORD_MAXVALUE maximum data length} * applies, no language index and stream number are allowed, as well as no * multiple values. */ CONTENT_DESCRIPTION(GUID.GUID_CONTENTDESCRIPTION, 16, false, false, false, false), /** * The descriptor is used in an extended content description object, so the * {@linkplain MetadataDescriptor#DWORD_MAXVALUE maximum data size} applies, * and no language index and stream number other than "0" is * allowed. Additionally no multiple values are permitted. */ EXTENDED_CONTENT(GUID.GUID_EXTENDED_CONTENT_DESCRIPTION, 16, false, false, false, false), /** * The descriptor is used in a metadata library object. No real size limit * (except DWORD range) applies. Stream numbers and language indexes can be * specified. */ METADATA_LIBRARY_OBJECT(GUID.GUID_METADATA_LIBRARY, 32, true, true, true, true), /** * The descriptor is used in a metadata object. The * {@linkplain MetadataDescriptor#DWORD_MAXVALUE maximum data size} applies. * Stream numbers can be specified. But no language index (always * "0"). */ METADATA_OBJECT(GUID.GUID_METADATA, 16, false, true, false, true); /** * Determines if low has <= index as high, in respect to * {@link #getOrdered()} * * @param low * @param high * @return true if in correct order. */ public static boolean areInCorrectOrder(final ContainerType low, final ContainerType high) { final List asList = Arrays.asList(getOrdered()); return asList.indexOf(low) <= asList.indexOf(high); } /** * Returns the elements in an order, that indicates more capabilities * (ascending).
* * @return capability ordered types */ public static ContainerType[] getOrdered() { return new ContainerType[] {CONTENT_DESCRIPTION, CONTENT_BRANDING, EXTENDED_CONTENT, METADATA_OBJECT, METADATA_LIBRARY_OBJECT}; } /** * Stores the guid that identifies ASF chunks which store metadata of the * current type. */ private final GUID containerGUID; /** * true if the descriptor field can store {@link GUID} values. */ private final boolean guidEnabled; /** * true if descriptor field can refer to a language. */ private final boolean languageEnabled; /** * The maximum amount of bytes the descriptor data may consume.
*/ private final BigInteger maximumDataLength; /** * true if the container may store multiple values of the same * metadata descriptor specification (equality on name, language, and * stream).
* WindowsMedia players advanced tag editor for example stores the * WM/Picture attribute once in the extended content description, and all * others in the metadata library object. */ private final boolean multiValued; /** * if -1 a size value has to be compared against * {@link #maximumDataLength} because {@link Long#MAX_VALUE} is exceeded.
* Otherwise this is the {@link BigInteger#longValue()} representation. */ private final long perfMaxDataLen; /** * true if descriptor field can refer to specific streams. */ private final boolean streamEnabled; /** * Creates an instance * * @param guid * see {@link #containerGUID} * @param maxDataLenBits * The amount of bits that is used to represent an unsigned value * for the containers size descriptors. Will create a maximum * value for {@link #maximumDataLength}. (2 ^ maxDataLenBits -1) * @param guidAllowed * see {@link #guidEnabled} * @param stream * see {@link #streamEnabled} * @param language * see {@link #languageEnabled} * @param multiValue * see {@link #multiValued} */ private ContainerType(final GUID guid, final int maxDataLenBits, final boolean guidAllowed, final boolean stream, final boolean language, final boolean multiValue) { this.containerGUID = guid; this.maximumDataLength = BigInteger.valueOf(2).pow(maxDataLenBits) .subtract(BigInteger.ONE); if (this.maximumDataLength .compareTo(BigInteger.valueOf(Long.MAX_VALUE)) <= 0) { this.perfMaxDataLen = this.maximumDataLength.longValue(); } else { this.perfMaxDataLen = -1; } this.guidEnabled = guidAllowed; this.streamEnabled = stream; this.languageEnabled = language; this.multiValued = multiValue; } /** * Calls {@link #checkConstraints(String, byte[], int, int, int)} and * actually throws the exception if there is one. * * @param name * name of the descriptor * @param data * content * @param type * data type * @param stream * stream number * @param language * language index */ public void assertConstraints(final String name, final byte[] data, final int type, final int stream, final int language) { final RuntimeException result = checkConstraints(name, data, type, stream, language); if (result != null) { throw result; } } /** * Checks if the values for a {@linkplain MetadataDescriptor content * descriptor} match the contraints of the container type, and returns a * {@link RuntimeException} if the requirements aren't met. * * @param name * name of the descriptor * @param data * content * @param type * data type * @param stream * stream number * @param language * language index * @return null if everything is fine. */ public RuntimeException checkConstraints(final String name, final byte[] data, final int type, final int stream, final int language) { RuntimeException result = null; // TODO generate tests if (name == null || data == null) { result = new IllegalArgumentException("Arguments must not be null."); } else { if (!Utils.isStringLengthValidNullSafe(name)) { result = new IllegalArgumentException( ErrorMessage.WMA_LENGTH_OF_STRING_IS_TOO_LARGE .getMsg(name.length())); } } if (result == null && !isWithinValueRange(data.length)) { result = new IllegalArgumentException( ErrorMessage.WMA_LENGTH_OF_DATA_IS_TOO_LARGE.getMsg( data.length, getMaximumDataLength(), getContainerGUID().getDescription())); } if (result == null && (stream < 0 || stream > MetadataDescriptor.MAX_STREAM_NUMBER || (!isStreamNumberEnabled() && stream != 0))) { final String streamAllowed = isStreamNumberEnabled() ? "0 to 127" : "0"; result = new IllegalArgumentException( ErrorMessage.WMA_INVALID_STREAM_REFERNCE.getMsg(stream, streamAllowed, getContainerGUID().getDescription())); } if (result == null && type == MetadataDescriptor.TYPE_GUID && !isGuidEnabled()) { result = new IllegalArgumentException( ErrorMessage.WMA_INVALID_GUID_USE.getMsg(getContainerGUID() .getDescription())); } if (result == null && ((language != 0 && !isLanguageEnabled()) || (language < 0 || language >= MetadataDescriptor.MAX_LANG_INDEX))) { final String langAllowed = isStreamNumberEnabled() ? "0 to 126" : "0"; result = new IllegalArgumentException( ErrorMessage.WMA_INVALID_LANGUAGE_USE.getMsg(language, getContainerGUID().getDescription(), langAllowed)); } if (result == null && this == CONTENT_DESCRIPTION && type != MetadataDescriptor.TYPE_STRING) { result = new IllegalArgumentException( ErrorMessage.WMA_ONLY_STRING_IN_CD.getMsg()); } return result; } /** * @return the containerGUID */ public GUID getContainerGUID() { return this.containerGUID; } /** * @return the maximumDataLength */ public BigInteger getMaximumDataLength() { return this.maximumDataLength; } /** * @return the guidEnabled */ public boolean isGuidEnabled() { return this.guidEnabled; } /** * @return the languageEnabled */ public boolean isLanguageEnabled() { return this.languageEnabled; } /** * Tests if the given value is less than or equal to * {@link #getMaximumDataLength()}, and greater or equal to zero.
* * @param value * The value to test * @return true if size restrictions for binary data are met * with this container type. */ public boolean isWithinValueRange(final long value) { return (this.perfMaxDataLen == -1 || this.perfMaxDataLen >= value) && value >= 0; } /** * @return the multiValued */ public boolean isMultiValued() { return this.multiValued; } /** * @return the streamEnabled */ public boolean isStreamNumberEnabled() { return this.streamEnabled; } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/asf/data/ContentDescription.java0000644000175000017500000001765511277006322030770 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2004-2005 Christian Laireiter * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.audio.asf.data; import org.jaudiotagger.audio.asf.util.Utils; import java.io.IOException; import java.io.OutputStream; import java.math.BigInteger; import java.util.Arrays; import java.util.HashSet; import java.util.Set; /** * This class represents the data of a chunk which contains title, author, * copyright, description and the rating of the file.
* It is optional within ASF files. But if, exists only once. * * @author Christian Laireiter */ public final class ContentDescription extends MetadataContainer { /** * Stores the only allowed keys of this metadata container. */ public final static Set ALLOWED; /** * Field key for author. */ public final static String KEY_AUTHOR = "AUTHOR"; /** * Field key for copyright. */ public final static String KEY_COPYRIGHT = "COPYRIGHT"; /** * Field key for description. */ public final static String KEY_DESCRIPTION = "DESCRIPTION"; /** * Field key for rating. */ public final static String KEY_RATING = "RATING"; /** * Field key for title. */ public final static String KEY_TITLE = "TITLE"; static { ALLOWED = new HashSet(Arrays.asList(KEY_AUTHOR, KEY_COPYRIGHT, KEY_DESCRIPTION, KEY_RATING, KEY_TITLE)); } /** * Creates an instance.
*/ public ContentDescription() { this(0, BigInteger.ZERO); } /** * Creates an instance. * * @param pos * Position of content description within file or stream * @param chunkLen * Length of content description. */ public ContentDescription(final long pos,final BigInteger chunkLen) { super(ContainerType.CONTENT_DESCRIPTION, pos, chunkLen); } /** * @return Returns the author. */ public String getAuthor() { return getValueFor(KEY_AUTHOR); } /** * @return Returns the comment. */ public String getComment() { return getValueFor(KEY_DESCRIPTION); } /** * @return Returns the copyRight. */ public String getCopyRight() { return getValueFor(KEY_COPYRIGHT); } /** * {@inheritDoc} */ @Override public long getCurrentAsfChunkSize() { long result = 44; // GUID + UINT64 for size + 5 times string length // (each // 2 bytes) + 5 times zero term char (2 bytes each). result += getAuthor().length() * 2; // UTF-16LE result += getComment().length() * 2; result += getRating().length() * 2; result += getTitle().length() * 2; result += getCopyRight().length() * 2; return result; } /** * @return returns the rating. */ public String getRating() { return getValueFor(KEY_RATING); } /** * @return Returns the title. */ public String getTitle() { return getValueFor(KEY_TITLE); } /** * {@inheritDoc} */ @Override public boolean isAddSupported(final MetadataDescriptor descriptor) { return ALLOWED.contains(descriptor.getName()) && super.isAddSupported(descriptor); } /** * * {@inheritDoc} */ @Override public String prettyPrint(final String prefix) { final StringBuilder result = new StringBuilder(super.prettyPrint(prefix)); result.append(prefix).append(" |->Title : ").append(getTitle()) .append(Utils.LINE_SEPARATOR); result.append(prefix).append(" |->Author : ").append(getAuthor()) .append(Utils.LINE_SEPARATOR); result.append(prefix).append(" |->Copyright : ").append( getCopyRight()).append(Utils.LINE_SEPARATOR); result.append(prefix).append(" |->Description: ").append(getComment()) .append(Utils.LINE_SEPARATOR); result.append(prefix).append(" |->Rating :").append(getRating()) .append(Utils.LINE_SEPARATOR); return result.toString(); } /** * @param fileAuthor * The author to set. * @throws IllegalArgumentException * If "UTF-16LE"-byte-representation would take more than 65535 * bytes. */ public void setAuthor(final String fileAuthor) throws IllegalArgumentException { setStringValue(KEY_AUTHOR, fileAuthor); } /** * @param tagComment * The comment to set. * @throws IllegalArgumentException * If "UTF-16LE"-byte-representation would take more than 65535 * bytes. */ public void setComment(final String tagComment) throws IllegalArgumentException { setStringValue(KEY_DESCRIPTION, tagComment); } /** * @param cpright * The copyRight to set. * @throws IllegalArgumentException * If "UTF-16LE"-byte-representation would take more than 65535 * bytes. */ public void setCopyright(final String cpright) throws IllegalArgumentException { setStringValue(KEY_COPYRIGHT, cpright); } /** * @param ratingText * The rating to be set. * @throws IllegalArgumentException * If "UTF-16LE"-byte-representation would take more than 65535 * bytes. */ public void setRating(final String ratingText) throws IllegalArgumentException { setStringValue(KEY_RATING, ratingText); } /** * @param songTitle * The title to set. * @throws IllegalArgumentException * If "UTF-16LE"-byte-representation would take more than 65535 * bytes. */ public void setTitle(final String songTitle) throws IllegalArgumentException { setStringValue(KEY_TITLE, songTitle); } /** * {@inheritDoc} */ @Override public long writeInto(final OutputStream out) throws IOException { final long chunkSize = getCurrentAsfChunkSize(); out.write(this.getGuid().getBytes()); Utils.writeUINT64(getCurrentAsfChunkSize(), out); // write the sizes of the string representations plus 2 bytes zero term // character Utils.writeUINT16(getTitle().length() * 2 + 2, out); Utils.writeUINT16(getAuthor().length() * 2 + 2, out); Utils.writeUINT16(getCopyRight().length() * 2 + 2, out); Utils.writeUINT16(getComment().length() * 2 + 2, out); Utils.writeUINT16(getRating().length() * 2 + 2, out); // write the Strings out.write(Utils.getBytes(getTitle(), AsfHeader.ASF_CHARSET)); out.write(AsfHeader.ZERO_TERM); out.write(Utils.getBytes(getAuthor(), AsfHeader.ASF_CHARSET)); out.write(AsfHeader.ZERO_TERM); out.write(Utils.getBytes(getCopyRight(), AsfHeader.ASF_CHARSET)); out.write(AsfHeader.ZERO_TERM); out.write(Utils.getBytes(getComment(), AsfHeader.ASF_CHARSET)); out.write(AsfHeader.ZERO_TERM); out.write(Utils.getBytes(getRating(), AsfHeader.ASF_CHARSET)); out.write(AsfHeader.ZERO_TERM); return chunkSize; } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/asf/data/MetadataContainerFactory.java0000644000175000017500000000541611277026507032064 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.asf.data; import java.math.BigInteger; /** * A factory for creating appropriate {@link MetadataContainer} objects upon * specified {@linkplain ContainerType container types}.
* * @author Christian Laireiter */ public final class MetadataContainerFactory { /** * Factory instance. */ private final static MetadataContainerFactory INSTANCE = new MetadataContainerFactory(); /** * Returns an instance. * * @return an instance. */ public static MetadataContainerFactory getInstance() { return INSTANCE; } /** * Hidden utility class constructor. */ private MetadataContainerFactory() { // Hidden } /** * Creates an appropriate {@linkplain MetadataContainer container * implementation} for the given container type. * * @param type * the type of container to get a container instance for. * @return appropriate container implementation. */ public MetadataContainer createContainer(final ContainerType type) { return createContainer(type, 0, BigInteger.ZERO); } /** * Convenience Method for I/O. Same as * {@link #createContainer(ContainerType)}, but additionally assigns * position and size. (since a {@link MetadataContainer} is actually a * {@link Chunk}). * * @param type * The containers type. * @param pos * the position within the stream. * @param chunkSize * the size of the container. * @return an appropriate container implementation with assigned size and * position. */ public MetadataContainer createContainer(final ContainerType type, final long pos, final BigInteger chunkSize) { MetadataContainer result; if (type == ContainerType.CONTENT_DESCRIPTION) { result = new ContentDescription(pos, chunkSize); } else if (type == ContainerType.CONTENT_BRANDING) { result = new ContentBranding(pos, chunkSize); } else { result = new MetadataContainer(type, pos, chunkSize); } return result; } /** * Convenience method which calls {@link #createContainer(ContainerType)} * for each given container type. * * @param types * types of the container which are to be created. * @return appropriate container implementations. */ public MetadataContainer[] createContainers(final ContainerType[] types) { assert types != null; final MetadataContainer[] result = new MetadataContainer[types.length]; for (int i = 0; i < result.length; i++) { result[i] = createContainer(types[i]); } return result; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/asf/data/StreamChunk.java0000644000175000017500000001320711222471043027357 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2004-2005 Christian Laireiter * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.audio.asf.data; import org.jaudiotagger.audio.asf.util.Utils; import java.math.BigInteger; /** * This class is the base for all handled stream contents.
* A Stream chunk delivers information about a audio or video stream. Because of * this the stream chunk identifies in one field what type of stream it is * describing and so other data is provided. However some information is common * to all stream chunks which are stored in this hierarchy of the class tree. * * @author Christian Laireiter */ public abstract class StreamChunk extends Chunk { /** * If true, the stream data is encrypted. */ private boolean contentEncrypted; /** * This field stores the number of the current stream.
*/ private int streamNumber; /** * @see #typeSpecificDataSize */ private long streamSpecificDataSize; /** * Something technical.
* Format time in 100-ns steps. */ private long timeOffset; /** * Stores the stream type.
* * @see GUID#GUID_AUDIOSTREAM * @see GUID#GUID_VIDEOSTREAM */ private final GUID type; /** * Stores the size of type specific data structure within chunk. */ private long typeSpecificDataSize; /** * Creates an instance * * @param streamType * The GUID which tells the stream type represented ( * {@link GUID#GUID_AUDIOSTREAM} or {@link GUID#GUID_VIDEOSTREAM} * ): * @param chunkLen * length of chunk */ public StreamChunk(final GUID streamType, final BigInteger chunkLen) { super(GUID.GUID_STREAM, chunkLen); assert GUID.GUID_AUDIOSTREAM.equals(streamType) || GUID.GUID_VIDEOSTREAM.equals(streamType); this.type = streamType; } /** * @return Returns the streamNumber. */ public int getStreamNumber() { return this.streamNumber; } /** * @return Returns the streamSpecificDataSize. */ public long getStreamSpecificDataSize() { return this.streamSpecificDataSize; } /** * Returns the stream type of the stream chunk.
* * @return {@link GUID#GUID_AUDIOSTREAM} or {@link GUID#GUID_VIDEOSTREAM}. */ public GUID getStreamType() { return this.type; } /** * @return Returns the timeOffset. */ public long getTimeOffset() { return this.timeOffset; } /** * @return Returns the typeSpecificDataSize. */ public long getTypeSpecificDataSize() { return this.typeSpecificDataSize; } /** * @return Returns the contentEncrypted. */ public boolean isContentEncrypted() { return this.contentEncrypted; } /** * (overridden) * * @see org.jaudiotagger.audio.asf.data.Chunk#prettyPrint(String) */ @Override public String prettyPrint(final String prefix) { final StringBuilder result = new StringBuilder(super.prettyPrint(prefix)); result.append(prefix).append(" |-> Stream number: ").append( getStreamNumber()).append(Utils.LINE_SEPARATOR); result.append(prefix).append(" |-> Type specific data size : ") .append(getTypeSpecificDataSize()).append(Utils.LINE_SEPARATOR); result.append(prefix).append(" |-> Stream specific data size: ") .append(getStreamSpecificDataSize()).append( Utils.LINE_SEPARATOR); result.append(prefix).append(" |-> Time Offset : ") .append(getTimeOffset()).append(Utils.LINE_SEPARATOR); result.append(prefix).append(" |-> Content Encryption : ") .append(isContentEncrypted()).append(Utils.LINE_SEPARATOR); return result.toString(); } /** * @param cntEnc * The contentEncrypted to set. */ public void setContentEncrypted(final boolean cntEnc) { this.contentEncrypted = cntEnc; } /** * @param streamNum * The streamNumber to set. */ public void setStreamNumber(final int streamNum) { this.streamNumber = streamNum; } /** * @param strSpecDataSize * The streamSpecificDataSize to set. */ public void setStreamSpecificDataSize(final long strSpecDataSize) { this.streamSpecificDataSize = strSpecDataSize; } /** * @param timeOffs * sets the time offset */ public void setTimeOffset(final long timeOffs) { this.timeOffset = timeOffs; } /** * @param typeSpecDataSize * The typeSpecificDataSize to set. */ public void setTypeSpecificDataSize(final long typeSpecDataSize) { this.typeSpecificDataSize = typeSpecDataSize; } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/asf/data/MetadataContainer.java0000644000175000017500000003655611277026507030545 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.asf.data; import org.jaudiotagger.audio.asf.io.WriteableChunk; import org.jaudiotagger.audio.asf.util.Utils; import java.io.IOException; import java.io.OutputStream; import java.math.BigInteger; import java.util.*; /** * This structure represents the "Metadata Object","Metadata * Library Object" and "Extended Content Description".
* * @author Christian Laireiter */ public class MetadataContainer extends Chunk implements WriteableChunk { /** * This class is used to uniquely identify an enclosed descriptor by its * name, language index and stream number.
* The type of the descriptor is ignored, since it just specifies the data * content. * * @author Christian Laireiter */ private final static class DescriptorPointer { /** * The represented descriptor. */ private MetadataDescriptor desc; /** * Creates an instance. * * @param descriptor * the metadata descriptor to identify. */ public DescriptorPointer(final MetadataDescriptor descriptor) { setDescriptor(descriptor); } /** * {@inheritDoc} */ @Override public boolean equals(final Object obj) { boolean result = obj == this; if (obj instanceof DescriptorPointer && !result) { final MetadataDescriptor other = ((DescriptorPointer) obj).desc; result = this.desc.getName().equals(other.getName()); result &= this.desc.getLanguageIndex() == other .getLanguageIndex(); result &= this.desc.getStreamNumber() == other .getStreamNumber(); } return result; } /** * {@inheritDoc} */ @Override public int hashCode() { int hashCode; hashCode = this.desc.getName().hashCode(); hashCode = hashCode * 31 + this.desc.getLanguageIndex(); hashCode = hashCode * 31 + this.desc.getStreamNumber(); return hashCode; } /** * Sets the descriptor to identify. * * @param descriptor * the descriptor to identify. * @return this instance. */ protected DescriptorPointer setDescriptor( final MetadataDescriptor descriptor) { assert descriptor != null; this.desc = descriptor; return this; } } /** * Looks up all {@linkplain ContainerType#getContainerGUID() guids} and * returns the matching type. * * @param guid * GUID to look up * @return matching container type. * @throws IllegalArgumentException * if no container type matches */ private static ContainerType determineType(final GUID guid) throws IllegalArgumentException { assert guid != null; ContainerType result = null; for (final ContainerType curr : ContainerType.values()) { if (curr.getContainerGUID().equals(guid)) { result = curr; break; } } if (result == null) { throw new IllegalArgumentException( "Unknown metadata container specified by GUID (" + guid.toString() + ")"); } return result; } /** * stores the represented container type.
*/ private final ContainerType containerType; /** * Stores the descriptors. */ private final Map> descriptors = new Hashtable>(); /** * for performance reasons this instance is used to look up existing * descriptors in {@link #descriptors}.
*/ private final DescriptorPointer perfPoint = new DescriptorPointer( new MetadataDescriptor("")); /** * Creates an instance. * * @param type * determines the type of the container */ public MetadataContainer(final ContainerType type) { this(type, 0, BigInteger.ZERO); } /** * Creates an instance. * * @param type * determines the type of the container * @param pos * location in the ASF file * @param size * size of the chunk. */ public MetadataContainer(final ContainerType type, final long pos, final BigInteger size) { super(type.getContainerGUID(), pos, size); this.containerType = type; } /** * Creates an instance. * * @param containerGUID * the containers GUID * @param pos * location in the ASF file * @param size * size of the chunk. */ public MetadataContainer(final GUID containerGUID, final long pos, final BigInteger size) { this(determineType(containerGUID), pos, size); } /** * Adds a metadata descriptor. * * @param toAdd * the descriptor to add. * @throws IllegalArgumentException * if descriptor does not meet container requirements, or * already exist. */ public final void addDescriptor(final MetadataDescriptor toAdd) throws IllegalArgumentException { // check with throwing exceptions this.containerType.assertConstraints(toAdd.getName(), toAdd .getRawData(), toAdd.getType(), toAdd.getStreamNumber(), toAdd .getLanguageIndex()); // validate containers capabilities if (!isAddSupported(toAdd)) { throw new IllegalArgumentException( "Descriptor cannot be added, see isAddSupported(...)"); } /* * Check for containers types capabilities. */ // Search for descriptor list by name, language and stream. List list; synchronized (this.perfPoint) { list = this.descriptors.get(this.perfPoint.setDescriptor(toAdd)); } if (list == null) { list = new ArrayList(); this.descriptors.put(new DescriptorPointer(toAdd), list); } else { if (!list.isEmpty() && !this.containerType.isMultiValued()) { throw new IllegalArgumentException( "Container does not allow multiple values of descriptors with same name, language index and stream number"); } } list.add(toAdd); } /** * This method asserts that this container has a descriptor with the * specified key, means returns an existing or creates a new descriptor. * * @param key * the descriptor name to look up (or create) * @return the/a descriptor with the specified name (and initial type of * {@link MetadataDescriptor#TYPE_STRING}. */ protected final MetadataDescriptor assertDescriptor(final String key) { return assertDescriptor(key, MetadataDescriptor.TYPE_STRING); } /** * This method asserts that this container has a descriptor with the * specified key, means returns an existing or creates a new descriptor. * * @param key * the descriptor name to look up (or create) * @param type * if the descriptor is created, this data type is applied. * @return the/a descriptor with the specified name. */ protected final MetadataDescriptor assertDescriptor(final String key, final int type) { MetadataDescriptor desc; final List descriptorsByName = getDescriptorsByName(key); if (descriptorsByName == null || descriptorsByName.isEmpty()) { desc = new MetadataDescriptor(getContainerType(), key, type); addDescriptor(desc); } else { desc = descriptorsByName.get(0); } return desc; } /** * Checks whether a descriptor already exists.
* Name, stream number and language index are compared. Data and data type * are ignored. * * @param lookup * descriptor to look up. * @return true if such a descriptor already exists. */ public final boolean containsDescriptor(final MetadataDescriptor lookup) { assert lookup != null; return this.descriptors.containsKey(this.perfPoint .setDescriptor(lookup)); } /** * Returns the type of container this instance represents.
* * @return represented container type. */ public final ContainerType getContainerType() { return this.containerType; } /** * {@inheritDoc} */ public long getCurrentAsfChunkSize() { /* * 16 bytes GUID, 8 bytes chunk size, 2 bytes descriptor count */ long result = 26; for (final MetadataDescriptor curr : getDescriptors()) { result += curr.getCurrentAsfSize(this.containerType); } return result; } /** * Returns the number of contained descriptors. * * @return number of descriptors. */ public final int getDescriptorCount() { return this.getDescriptors().size(); } /** * Returns all stored descriptors. * * @return stored descriptors. */ public final List getDescriptors() { final List result = new ArrayList(); for (final List curr : this.descriptors.values()) { result.addAll(curr); } return result; } /** * Returns a list of descriptors with the given * {@linkplain MetadataDescriptor#getName() name}.
* * @param name * name of the descriptors to return * @return list of descriptors with given name. */ public final List getDescriptorsByName(final String name) { assert name != null; final List result = new ArrayList(); final Collection> values = this.descriptors .values(); for (final List currList : values) { if (!currList.isEmpty() && currList.get(0).getName().equals(name)) { result.addAll(currList); } } return result; } /** * This method looks up a descriptor with given name and returns its value * as string.
* * @param name * the name of the descriptor to look up. * @return the string representation of a found descriptors value. Even an * empty string if no descriptor has been found. */ protected final String getValueFor(final String name) { String result = ""; final List descs = getDescriptorsByName(name); if (descs != null) { assert descs.size() <= 1; if (!descs.isEmpty()) { result = descs.get(0).getString(); } } return result; } /** * Determines if this container contains a descriptor with given * {@linkplain MetadataDescriptor#getName() name}.
* * @param name * Name of the descriptor to look for. * @return true if descriptor has been found. */ public final boolean hasDescriptor(final String name) { return !getDescriptorsByName(name).isEmpty(); } /** * Determines/checks if the given descriptor may be added to the container.
* This implies a check for the capabilities of the container specified by * its {@linkplain #getContainerType() container type}.
* * @param descriptor * the descriptor to test. * @return true if {@link #addDescriptor(MetadataDescriptor)} * can be called with given descriptor. */ public boolean isAddSupported(final MetadataDescriptor descriptor) { boolean result = getContainerType().checkConstraints( descriptor.getName(), descriptor.getRawData(), descriptor.getType(), descriptor.getStreamNumber(), descriptor.getLanguageIndex()) == null; // Now check if there is already a value contained. if (result && !getContainerType().isMultiValued()) { synchronized (this.perfPoint) { final List list = this.descriptors .get(this.perfPoint.setDescriptor(descriptor)); if (list != null) { result = list.isEmpty(); } } } return result; } /** * {@inheritDoc} */ public final boolean isEmpty() { boolean result = true; if (getDescriptorCount() != 0) { final Iterator iterator = getDescriptors() .iterator(); while (result && iterator.hasNext()) { result &= iterator.next().isEmpty(); } } return result; } /** * {@inheritDoc} */ @Override public String prettyPrint(final String prefix) { final StringBuilder result = new StringBuilder(super.prettyPrint(prefix)); for (final MetadataDescriptor curr : getDescriptors()) { result.append(prefix).append(" |-> "); result.append(curr); result.append(Utils.LINE_SEPARATOR); } return result.toString(); } /** * Removes all stored descriptors with the given * {@linkplain MetadataDescriptor#getName() name}.
* * @param name * the name to remove. */ public final void removeDescriptorsByName(final String name) { assert name != null; final Iterator> iterator = this.descriptors .values().iterator(); while (iterator.hasNext()) { final List curr = iterator.next(); if (!curr.isEmpty() && curr.get(0).getName().equals(name)) { iterator.remove(); } } } /** * {@linkplain #assertDescriptor(String) asserts} the existence of a * descriptor with given name and * {@linkplain MetadataDescriptor#setStringValue(String) assings} the string * value. * * @param name * the name of the descriptor to set the value for. * @param value * the string value. */ protected final void setStringValue(final String name, final String value) { assertDescriptor(name).setStringValue(value); } /** * {@inheritDoc} */ public long writeInto(final OutputStream out) throws IOException { final long chunkSize = getCurrentAsfChunkSize(); final List descriptorList = getDescriptors(); out.write(getGuid().getBytes()); Utils.writeUINT64(chunkSize, out); Utils.writeUINT16(descriptorList.size(), out); for (final MetadataDescriptor curr : descriptorList) { curr.writeInto(out, this.containerType); } return chunkSize; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/asf/data/MetadataDescriptor.java0000644000175000017500000007341111222471043030715 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2004-2005 Christian Laireiter * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.audio.asf.data; import org.jaudiotagger.audio.asf.util.Utils; import org.jaudiotagger.logging.ErrorMessage; import org.jaudiotagger.tag.TagOptionSingleton; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.math.BigInteger; import java.util.Arrays; import java.util.logging.Logger; /** * This structure represents metadata objects in ASF {@link MetadataContainer}.
* The values are * {@linkplain ContainerType#assertConstraints(String, byte[], int, int, int) * checked} against the capability introduced by the given * {@link ContainerType} at construction.
*
* Limitation: Even though some container types do not restrict the data * size to {@link Integer#MAX_VALUE}, this implementation does it (due to java * nature).
* 2 GiB of data should suffice, and even be to large for normal java heap. * * @author Christian Laireiter */ public class MetadataDescriptor implements Comparable, Cloneable { /** * Maximum value for WORD. */ public static final long DWORD_MAXVALUE = new BigInteger("FFFFFFFF", 16) .longValue(); /** * Logger instance. */ private static final Logger LOGGER = Logger .getLogger("org.jaudiotagger.audio.asf.data"); /** * The maximum language index allowed. (exclusive) */ public static final int MAX_LANG_INDEX = 127; /** * Maximum stream number. (inclusive) */ public static final int MAX_STREAM_NUMBER = 127; /** * Maximum value for a QWORD value (64 bit unsigned).
*/ public static final BigInteger QWORD_MAXVALUE = new BigInteger( "FFFFFFFFFFFFFFFF", 16); /** * Constant for the metadata descriptor-type for binary data. */ public final static int TYPE_BINARY = 1; /** * Constant for the metadata descriptor-type for booleans. */ public final static int TYPE_BOOLEAN = 2; /** * Constant for the metadata descriptor-type for DWORD (32-bit unsigned).
*/ public final static int TYPE_DWORD = 3; /** * Constant for the metadata descriptor-type for GUIDs (128-bit).
*/ public final static int TYPE_GUID = 6; /** * Constant for the metadata descriptor-type for QWORD (64-bit unsinged).
*/ public final static int TYPE_QWORD = 4; /** * Constant for the metadata descriptor-type for Strings. */ public final static int TYPE_STRING = 0; /** * Constant for the metadata descriptor-type for WORD (16-bit unsigned).
*/ public final static int TYPE_WORD = 5; /** * Maximum value for WORD. */ public static final int WORD_MAXVALUE = 65535; /** * Stores the containerType of the descriptor. */ private final ContainerType containerType; /** * The binary representation of the value. */ /* * Note: The maximum data length could be up to a 64-Bit number (unsigned), * but java for now handles just int sized byte[]. Since this class stores * all data in primitive byte[] this size restriction is cascaded to all * dependent implementations. */ private byte[] content = new byte[0]; /** * This field shows the type of the metadata descriptor.
* * @see #TYPE_BINARY * @see #TYPE_BOOLEAN * @see #TYPE_DWORD * @see #TYPE_GUID * @see #TYPE_QWORD * @see #TYPE_STRING * @see #TYPE_WORD */ private int descriptorType; /** * the index of the language in the {@linkplain LanguageList language list} * this descriptor applies to.
* */ private int languageIndex = 0; /** * The name of the metadata descriptor. */ private final String name; /** * The number of the stream, this descriptor applies to.
*/ private int streamNumber = 0; /** * Creates an Instance.
* * @param type * the container type, this descriptor is resctricted to. * @param propName * Name of the MetadataDescriptor. * @param propType * Type of the metadata descriptor. See {@link #descriptorType} */ public MetadataDescriptor(final ContainerType type, final String propName, final int propType) { this(type, propName, propType, 0, 0); } /** * Creates an Instance. * * @param type * The container type the values (the whole descriptor) is * restricted to. * @param propName * Name of the MetadataDescriptor. * @param propType * Type of the metadata descriptor. See {@link #descriptorType} * @param stream * the number of the stream the descriptor refers to. * @param language * the index of the language entry in a {@link LanguageList} this * descriptor refers to.
* Consider: No checks performed if language entry exists. * */ public MetadataDescriptor(final ContainerType type, final String propName, final int propType, final int stream, final int language) { assert type != null; type.assertConstraints(propName, new byte[0], propType, stream, language); this.containerType = type; this.name = propName; this.descriptorType = propType; this.streamNumber = stream; this.languageIndex = language; } /** * Creates an instance.
* Capabilities are set to {@link ContainerType#METADATA_LIBRARY_OBJECT}.
* * @param propName * name of the metadata descriptor. */ public MetadataDescriptor(final String propName) { this(propName, TYPE_STRING); } /** * Creates an Instance.
* Capabilities are set to {@link ContainerType#METADATA_LIBRARY_OBJECT}.
* * @param propName * Name of the MetadataDescriptor. * @param propType * Type of the metadata descriptor. See {@link #descriptorType} */ public MetadataDescriptor(final String propName, final int propType) { this(ContainerType.METADATA_LIBRARY_OBJECT, propName, propType, 0, 0); } /** * Converts the descriptors value into a number if possible.
* A boolean will be converted to "1" if true, * otherwise "0".
* String will be interpreted as number with radix "10".
* Binary data will be interpreted as the default WORD,DWORD or QWORD binary * representation, but only if the data does not exceed 8 bytes. This * precaution is done to prevent creating a number of a multi kilobyte * image.
* A GUID cannot be converted in any case. * * @return number representation. * @throws NumberFormatException * If no conversion is supported. */ public BigInteger asNumber() { BigInteger result = null; switch (this.descriptorType) { case TYPE_BOOLEAN: case TYPE_WORD: case TYPE_DWORD: case TYPE_QWORD: case TYPE_BINARY: if (this.content.length > 8) { throw new NumberFormatException( "Binary data would exceed QWORD"); } break; case TYPE_GUID: throw new NumberFormatException( "GUID cannot be converted to a number."); case TYPE_STRING: result = new BigInteger(getString(), 10); break; default: throw new IllegalStateException(); } if (result == null) { final byte[] copy = new byte[this.content.length]; for (int i = 0; i < copy.length; i++) { copy[i] = this.content[this.content.length - (i + 1)]; } result = new BigInteger(1, copy); } return result; } /** * (overridden) * * @see java.lang.Object#clone() */ @Override public Object clone() throws CloneNotSupportedException { return super.clone(); } /** * {@inheritDoc} */ public int compareTo(final MetadataDescriptor other) { return getName().compareTo(other.getName()); } /** * This method creates a copy of the current object.
* All data will be copied, too.
* * @return A new metadata descriptor containing the same values as the * current one. */ public MetadataDescriptor createCopy() { final MetadataDescriptor result = new MetadataDescriptor( this.containerType, this.name, this.descriptorType, this.streamNumber, this.languageIndex); result.content = getRawData(); return result; } /** * (overridden) * * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(final Object obj) { boolean result = false; if (obj instanceof MetadataDescriptor) { if (obj == this) { result = true; } else { final MetadataDescriptor other = (MetadataDescriptor) obj; result = other.getName().equals(getName()) && other.descriptorType == this.descriptorType && other.languageIndex == this.languageIndex && other.streamNumber == this.streamNumber && Arrays.equals(this.content, other.content); } } return result; } /** * Returns the value of the MetadataDescriptor as a Boolean.
* If no Conversion is Possible false is returned.
* true if first byte of {@link #content}is not zero. * * @return boolean representation of the current value. */ public boolean getBoolean() { return this.content.length > 0 && this.content[0] != 0; } /** * This method will return a byte array, which can directly be written into * an "Extended Content Description"-chunk.
* * @return byte[] with the data, that occurs in ASF files. * @deprecated {@link #writeInto(OutputStream,ContainerType)} is used */ @Deprecated public byte[] getBytes() { final ByteArrayOutputStream result = new ByteArrayOutputStream(); try { writeInto(result, this.containerType); } catch (final IOException e) { LOGGER.warning(e.getMessage()); } return result.toByteArray(); } /** * Returns the container type this descriptor ist restricted to. * * @return the container type */ public ContainerType getContainerType() { return this.containerType; } /** * Returns the size (in bytes) this descriptor will take when written to an * ASF file.
* * @param type * the container type for which the size is calculated. * * @return size of the descriptor in an ASF file. */ public int getCurrentAsfSize(final ContainerType type) { /* * 2 bytes name length, 2 bytes name zero term, 2 bytes type, 2 bytes * content length */ int result = 8; if (type != ContainerType.EXTENDED_CONTENT) { // Stream number and language index (respectively reserved field). // And +2 bytes, because data type is 32 bit, not 16 result += 6; } result += getName().length() * 2; if (this.getType() == TYPE_BOOLEAN) { result += 2; if (type == ContainerType.EXTENDED_CONTENT) { // Extended content description boolean values are stored with // 32-bit result += 2; } } else { result += this.content.length; if (TYPE_STRING == this.getType()) { result += 2; // zero term of content string. } } return result; } /** * Returns the GUID value, if content could represent one. * * @return GUID value */ public GUID getGuid() { GUID result = null; if (getType() == TYPE_GUID && this.content.length == GUID.GUID_LENGTH) { result = new GUID(this.content); } return result; } /** * Returns the index of the language that is referred (see * {@link LanguageList}): * * @return the language index */ public int getLanguageIndex() { return this.languageIndex; } /** * This method returns the name of the metadata descriptor. * * @return Name. */ public String getName() { return this.name; } /** * This method returns the value of the metadata descriptor as a long.
* Converts the needed amount of byte out of {@link #content}to a number.
* Only possible if {@link #getType()}equals on of the following:
*
  • * * @return integer value. * @see #TYPE_BOOLEAN
  • * @see #TYPE_DWORD
  • * @see #TYPE_QWORD
  • * @see #TYPE_WORD
  • */ public long getNumber() { int bytesNeeded; switch (getType()) { case TYPE_BOOLEAN: bytesNeeded = 1; break; case TYPE_DWORD: bytesNeeded = 4; break; case TYPE_QWORD: bytesNeeded = 8; break; case TYPE_WORD: bytesNeeded = 2; break; default: throw new UnsupportedOperationException( "The current type doesn't allow an interpretation as a number. (" + getType() + ")"); } if (bytesNeeded > this.content.length) { throw new IllegalStateException( "The stored data cannot represent the type of current object."); } long result = 0; for (int i = 0; i < bytesNeeded; i++) { result |= (((long) this.content[i] & 0xFF) << (i * 8)); } return result; } /** * This method returns a copy of the content of the descriptor.
    * * @return The content in binary representation, as it would be written to * asf file.
    */ public byte[] getRawData() { final byte[] copy = new byte[this.content.length]; System.arraycopy(this.content, 0, copy, 0, this.content.length); return copy; } /** * Returns the size (in bytes) the binary representation of the content * uses. (length of {@link #getRawData()})
    * * @return size of binary representation of the content. */ public int getRawDataSize() { return this.content.length; } /** * Returns the stream number this descriptor applies to.
    * * @return the stream number. */ public int getStreamNumber() { return this.streamNumber; } /** * Returns the value of the MetadataDescriptor as a String.
    * * @return String - Representation Value */ public String getString() { String result = null; switch (getType()) { case TYPE_BINARY: result = "binary data"; break; case TYPE_BOOLEAN: result = String.valueOf(getBoolean()); break; case TYPE_GUID: result = getGuid() == null ? "Invalid GUID" : getGuid().toString(); break; case TYPE_QWORD: case TYPE_DWORD: case TYPE_WORD: result = String.valueOf(getNumber()); break; case TYPE_STRING: try { result = new String(this.content, "UTF-16LE"); } catch (final UnsupportedEncodingException e) { LOGGER.warning(e.getMessage()); } break; default: throw new IllegalStateException("Current type is not known."); } return result; } /** * Returns the type of the metadata descriptor.
    * * @return the value of {@link #descriptorType} * @see #TYPE_BINARY * @see #TYPE_BOOLEAN * @see #TYPE_DWORD * @see #TYPE_GUID * @see #TYPE_QWORD * @see #TYPE_STRING * @see #TYPE_WORD */ public int getType() { return this.descriptorType; } /** * {@inheritDoc} */ @Override public int hashCode() { return this.name.hashCode(); } /** * This method checks if the binary data is empty.
    * Disregarding the type of the descriptor its content is stored as a byte * array. * * @return true if no value is set. */ public boolean isEmpty() { return this.content.length == 0; } /** * Sets the Value of the current metadata descriptor.
    * Using this method will change {@link #descriptorType}to * {@link #TYPE_BINARY}.
    * * @param data * Value to set. * @throws IllegalArgumentException * if data is invalid for {@linkplain #getContainerType() * container}. */ public void setBinaryValue(final byte[] data) throws IllegalArgumentException { this.containerType.assertConstraints(this.name, data, this.descriptorType, this.streamNumber, this.languageIndex); this.content = data.clone(); this.descriptorType = TYPE_BINARY; } /** * Sets the Value of the current metadata descriptor.
    * Using this method will change {@link #descriptorType}to * {@link #TYPE_BOOLEAN}.
    * * @param value * Value to set. */ public void setBooleanValue(final boolean value) { this.content = new byte[] { value ? (byte) 1 : 0 }; this.descriptorType = TYPE_BOOLEAN; } /** * Sets the Value of the current metadata descriptor.
    * Using this method will change {@link #descriptorType}to * {@link #TYPE_DWORD}. * * @param value * Value to set. */ public void setDWordValue(final long value) { if (value < 0 || value > DWORD_MAXVALUE) { throw new IllegalArgumentException("value out of range (0-" + DWORD_MAXVALUE + ")"); } this.content = Utils.getBytes(value, 4); this.descriptorType = TYPE_DWORD; } /** * Sets the value of the metadata descriptor.
    * Using this method will change {@link #descriptorType} to * {@link #TYPE_GUID} * * @param value * value to set. */ public void setGUIDValue(final GUID value) { this.containerType.assertConstraints(this.name, value.getBytes(), TYPE_GUID, this.streamNumber, this.languageIndex); this.content = value.getBytes(); this.descriptorType = TYPE_GUID; } /** * Sets the index of the referred language (see {@link LanguageList}).
    * Consider: The {@linkplain #containerType requirements} must be * held. * * @param language * the language index to set */ public void setLanguageIndex(final int language) { this.containerType.assertConstraints(this.name, this.content, this.descriptorType, this.streamNumber, language); this.languageIndex = language; } /** * Sets the Value of the current metadata descriptor.
    * Using this method will change {@link #descriptorType}to * {@link #TYPE_QWORD} * * @param value * Value to set. * @throws NumberFormatException * on null values. * @throws IllegalArgumentException * on illegal values or values exceeding range. */ public void setQWordValue(final BigInteger value) throws IllegalArgumentException { if (value == null) { throw new NumberFormatException("null"); } if (BigInteger.ZERO.compareTo(value) > 0) { throw new IllegalArgumentException( "Only unsigned values allowed (no negative)"); } if (MetadataDescriptor.QWORD_MAXVALUE.compareTo(value) < 0) { throw new IllegalArgumentException( "Value exceeds QWORD (64 bit unsigned)"); } this.content = new byte[8]; final byte[] valuesBytes = value.toByteArray(); if (valuesBytes.length <= 8) { for (int i = valuesBytes.length - 1; i >= 0; i--) { this.content[valuesBytes.length - (i + 1)] = valuesBytes[i]; } } else { /* * In case of 64-Bit set */ Arrays.fill(this.content, (byte) 0xFF); } this.descriptorType = TYPE_QWORD; } /** * Sets the Value of the current metadata descriptor.
    * Using this method will change {@link #descriptorType}to * {@link #TYPE_QWORD} * * @param value * Value to set. */ public void setQWordValue(final long value) { if (value < 0) { throw new IllegalArgumentException("value out of range (0-" + MetadataDescriptor.QWORD_MAXVALUE.toString() + ")"); } this.content = Utils.getBytes(value, 8); this.descriptorType = TYPE_QWORD; } /** * Sets the stream number the descriptor applies to.
    * Consider: The {@linkplain #containerType requirements} must be * held. * * @param stream * the stream number to set */ public void setStreamNumber(final int stream) { this.containerType.assertConstraints(this.name, this.content, this.descriptorType, stream, this.languageIndex); this.streamNumber = stream; } /** * This method converts the given string value into the current * {@linkplain #getType() data type}. * * @param value * value to set. * @throws IllegalArgumentException * If conversion was impossible. */ public void setString(final String value) throws IllegalArgumentException { try { switch (getType()) { case TYPE_BINARY: throw new IllegalArgumentException( "Cannot interpret binary as string."); case TYPE_BOOLEAN: setBooleanValue(Boolean.parseBoolean(value)); break; case TYPE_DWORD: setDWordValue(Long.parseLong(value)); break; case TYPE_QWORD: setQWordValue(new BigInteger(value, 10)); break; case TYPE_WORD: setWordValue(Integer.parseInt(value)); break; case TYPE_GUID: setGUIDValue(GUID.parseGUID(value)); break; case TYPE_STRING: setStringValue(value); break; default: // new Type added but not handled. throw new IllegalStateException(); } } catch (final NumberFormatException nfe) { throw new IllegalArgumentException( "Value cannot be parsed as Number or is out of range (\"" + value + "\")", nfe); } } /** * Sets the Value of the current metadata descriptor.
    * Using this method will change {@link #descriptorType}to * {@link #TYPE_STRING}. * * @param value * Value to set. * @throws IllegalArgumentException * If byte representation would take more than 65535 Bytes. */ // TODO Test public void setStringValue(final String value) throws IllegalArgumentException { if (value == null) { this.content = new byte[0]; } else { final byte[] tmp = Utils.getBytes(value, AsfHeader.ASF_CHARSET); if (getContainerType().isWithinValueRange(tmp.length)) { // Everything is fine here, data can be stored. this.content = tmp; } else { // Normally a size violation, check if JAudiotagger my truncate // the string if (TagOptionSingleton.getInstance() .isTruncateTextWithoutErrors()) { // truncate the string final int copyBytes = (int) getContainerType() .getMaximumDataLength().longValue(); this.content = new byte[copyBytes % 2 == 0 ? copyBytes : copyBytes - 1]; System.arraycopy(tmp, 0, this.content, 0, this.content.length); } else { // We may not truncate, so its an error throw new IllegalArgumentException( ErrorMessage.WMA_LENGTH_OF_DATA_IS_TOO_LARGE .getMsg(tmp.length, getContainerType() .getMaximumDataLength(), getContainerType() .getContainerGUID() .getDescription())); } } } this.descriptorType = TYPE_STRING; } /** * Sets the Value of the current metadata descriptor.
    * Using this method will change {@link #descriptorType}to * {@link #TYPE_WORD} * * @param value * Value to set. * @throws IllegalArgumentException * on negative values. ASF just supports unsigned values. */ public void setWordValue(final int value) throws IllegalArgumentException { if (value < 0 || value > WORD_MAXVALUE) { throw new IllegalArgumentException("value out of range (0-" + WORD_MAXVALUE + ")"); } this.content = Utils.getBytes(value, 2); this.descriptorType = TYPE_WORD; } /** * (overridden) * * @see java.lang.Object#toString() */ @Override public String toString() { return getName() + " : " + new String[] { "String: ", "Binary: ", "Boolean: ", "DWORD: ", "QWORD:", "WORD:", "GUID:" }[this.descriptorType] + getString() + " (language: " + this.languageIndex + " / stream: " + this.streamNumber + ")"; } /** * Writes this descriptor into the specified output stream.
    * * @param out * stream to write into. * @param contType * the container type this descriptor is written to. * @return amount of bytes written. * @throws IOException * on I/O Errors */ public int writeInto(final OutputStream out, final ContainerType contType) throws IOException { final int size = getCurrentAsfSize(contType); /* * Booleans are stored as one byte, if a boolean is written, the data * must be converted according to the container type. */ byte[] binaryData; if (this.descriptorType == TYPE_BOOLEAN) { binaryData = new byte[contType == ContainerType.EXTENDED_CONTENT ? 4 : 2]; binaryData[0] = (byte) (getBoolean() ? 1 : 0); } else { binaryData = this.content; } // for Metadata objects the stream number and language index if (contType != ContainerType.EXTENDED_CONTENT) { Utils.writeUINT16(getLanguageIndex(), out); Utils.writeUINT16(getStreamNumber(), out); } Utils.writeUINT16(getName().length() * 2 + 2, out); // The name for the metadata objects come later if (contType == ContainerType.EXTENDED_CONTENT) { out.write(Utils.getBytes(getName(), AsfHeader.ASF_CHARSET)); out.write(AsfHeader.ZERO_TERM); } // type and content len follow up are identical final int type = getType(); Utils.writeUINT16(type, out); int contentLen = binaryData.length; if (TYPE_STRING == type) { contentLen += 2; // Zero Term } if (contType == ContainerType.EXTENDED_CONTENT) { Utils.writeUINT16(contentLen, out); } else { Utils.writeUINT32(contentLen, out); } // Metadata objects now write their descriptor name if (contType != ContainerType.EXTENDED_CONTENT) { out.write(Utils.getBytes(getName(), AsfHeader.ASF_CHARSET)); out.write(AsfHeader.ZERO_TERM); } // The content. out.write(binaryData); if (TYPE_STRING == type) { out.write(AsfHeader.ZERO_TERM); } return size; } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/asf/data/ChunkContainer.java0000644000175000017500000001426011222471043030046 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.asf.data; import org.jaudiotagger.audio.asf.util.ChunkPositionComparator; import org.jaudiotagger.audio.asf.util.Utils; import java.math.BigInteger; import java.util.*; /** * Stores multiple ASF objects (chunks) in form of {@link Chunk} objects, and is * itself an ASF object (chunk).
    *
    * Because current implementation is solely used for ASF metadata, all chunks * (except for {@link StreamChunk}) may only be {@linkplain #addChunk(Chunk) * inserted} once. * * @author Christian Laireiter */ public class ChunkContainer extends Chunk { /** * Stores the {@link GUID} instances, which are allowed multiple times * within an ASF header. */ private final static Set MULTI_CHUNKS; static { MULTI_CHUNKS = new HashSet(); MULTI_CHUNKS.add(GUID.GUID_STREAM); } /** * Tests whether all stored chunks have a unique starting position among * their brothers. * * @param container * the container to test. * * @return true if all chunks are located at an unique * position. However, no intersection is tested. */ protected static boolean chunkstartsUnique(final ChunkContainer container) { boolean result = true; final Set chunkStarts = new HashSet(); final Collection chunks = container.getChunks(); for (final Chunk curr : chunks) { result &= chunkStarts.add(curr.getPosition()); } return result; } /** * Stores the {@link Chunk} objects to their {@link GUID}. */ private final Map> chunkTable; /** * Creates an instance. * * @param chunkGUID * the GUID which identifies the chunk. * @param pos * the position of the chunk within the stream. * @param length * the length of the chunk. */ public ChunkContainer(final GUID chunkGUID, final long pos, final BigInteger length) { super(chunkGUID, pos, length); this.chunkTable = new Hashtable>(); } /** * Adds a chunk to the container.
    * * @param toAdd * The chunk which is to be added. * @throws IllegalArgumentException * If a chunk of same type is already added, except for * {@link StreamChunk}. */ public void addChunk(final Chunk toAdd) { final List list = assertChunkList(toAdd.getGuid()); if (!list.isEmpty() && !MULTI_CHUNKS.contains(toAdd.getGuid())) { throw new IllegalArgumentException( "The GUID of the given chunk indicates, that there is no more instance allowed."); //$NON-NLS-1$ } list.add(toAdd); assert chunkstartsUnique(this) : "Chunk has equal start position like an already inserted one."; //$NON-NLS-1$ } /** * This method asserts that a {@link List} exists for the given {@link GUID} * , in {@link #chunkTable}.
    * * @param lookFor * The GUID to get list for. * @return an already existing, or newly created list. */ protected List assertChunkList(final GUID lookFor) { List result = this.chunkTable.get(lookFor); if (result == null) { result = new ArrayList(); this.chunkTable.put(lookFor, result); } return result; } /** * Returns a collection of all contained chunks.
    * * @return all contained chunks */ public Collection getChunks() { final List result = new ArrayList(); for (final List curr : this.chunkTable.values()) { result.addAll(curr); } return result; } /** * Looks for the first stored chunk which has the given GUID. * * @param lookFor * GUID to look up. * @param instanceOf * The class which must additionally be matched. * @return null if no chunk was found, or the stored instance * doesn't match. */ protected Chunk getFirst(final GUID lookFor, final Class instanceOf) { Chunk result = null; final List list = this.chunkTable.get(lookFor); if (list != null && !list.isEmpty()) { final Chunk chunk = list.get(0); if (instanceOf.isAssignableFrom(chunk.getClass())) { result = chunk; } } return result; } /** * This method checks if a chunk has been {@linkplain #addChunk(Chunk) * added} with specified {@linkplain Chunk#getGuid() GUID}.
    * * @param lookFor * GUID to look up. * @return true if chunk with specified GUID has been added. */ public boolean hasChunkByGUID(final GUID lookFor) { return this.chunkTable.containsKey(lookFor); } /** * {@inheritDoc} */ @Override public String prettyPrint(final String prefix) { return prettyPrint(prefix, ""); } /** * Nearly the same as {@link #prettyPrint(String)} however, additional * information can be injected below the {@link Chunk#prettyPrint(String)} * output and the listing of the contained chunks.
    * * @param prefix * The prefix to prepend. * @param containerInfo * Information to inject. * @return Information of current Chunk Object. */ public String prettyPrint(final String prefix, final String containerInfo) { final StringBuilder result = new StringBuilder(super.prettyPrint(prefix)); result.append(containerInfo); result.append(prefix).append(" |").append(Utils.LINE_SEPARATOR); final ArrayList list = new ArrayList(getChunks()); Collections.sort(list, new ChunkPositionComparator()); for (Chunk curr : list) { result.append(curr.prettyPrint(prefix + " |")); result.append(prefix).append(" |").append(Utils.LINE_SEPARATOR); } return result.toString(); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/asf/data/AudioStreamChunk.java0000644000175000017500000002113011222471043030333 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2004-2005 Christian Laireiter * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.audio.asf.data; import org.jaudiotagger.audio.asf.util.Utils; import java.math.BigInteger; /** * This class represents the stream chunk describing an audio stream.
    * * @author Christian Laireiter */ public final class AudioStreamChunk extends StreamChunk { /** * Stores the hex values of codec identifiers to their descriptions.
    */ public final static String[][] CODEC_DESCRIPTIONS = { { "161", " (Windows Media Audio (ver 7,8,9))" }, { "162", " (Windows Media Audio 9 series (Professional))" }, { "163", "(Windows Media Audio 9 series (Lossless))" }, { "7A21", " (GSM-AMR (CBR))" }, { "7A22", " (GSM-AMR (VBR))" } }; /** * Stores the audio codec number for WMA */ public final static long WMA = 0x161; /** * Stores the audio codec number for WMA (CBR) */ public final static long WMA_CBR = 0x7A21; /** * Stores the audio codec number for WMA_LOSSLESS */ public final static long WMA_LOSSLESS = 0x163; /** * Stores the audio codec number for WMA_PRO */ public final static long WMA_PRO = 0x162; /** * Stores the audio codec number for WMA (VBR) */ public final static long WMA_VBR = 0x7A22; /** * Stores the average amount of bytes used by audio stream.
    * This value is a field within type specific data of audio stream. Maybe it * could be used to calculate the KBPs. */ private long averageBytesPerSec; /** * Amount of bits used per sample.
    */ private int bitsPerSample; /** * The block alignment of the audio data. */ private long blockAlignment; /** * Number of channels. */ private long channelCount; /** * Some data which needs to be interpreted if the codec is handled. */ private byte[] codecData = new byte[0]; /** * The audio compression format code. */ private long compressionFormat; /** * this field stores the error concealment type. */ private GUID errorConcealment; /** * Sampling rate of audio stream. */ private long samplingRate; /** * Creates an instance. * * @param chunkLen * Length of the entire chunk (including guid and size) */ public AudioStreamChunk(final BigInteger chunkLen) { super(GUID.GUID_AUDIOSTREAM, chunkLen); } /** * @return Returns the averageBytesPerSec. */ public long getAverageBytesPerSec() { return this.averageBytesPerSec; } /** * @return Returns the bitsPerSample. */ public int getBitsPerSample() { return this.bitsPerSample; } /** * @return Returns the blockAlignment. */ public long getBlockAlignment() { return this.blockAlignment; } /** * @return Returns the channelCount. */ public long getChannelCount() { return this.channelCount; } /** * @return Returns the codecData. */ public byte[] getCodecData() { return this.codecData.clone(); } /** * This method will take a look at {@link #compressionFormat}and returns a * String with its hex value and if known a textual note on what coded it * represents.
    * * @return A description for the used codec. */ public String getCodecDescription() { final StringBuilder result = new StringBuilder(Long .toHexString(getCompressionFormat())); String furtherDesc = " (Unknown)"; for (final String[] aCODEC_DESCRIPTIONS : CODEC_DESCRIPTIONS) { if (aCODEC_DESCRIPTIONS[0].equalsIgnoreCase(result.toString())) { furtherDesc = aCODEC_DESCRIPTIONS[1]; break; } } if (result.length() % 2 == 0) { result.insert(0, "0x"); } else { result.insert(0, "0x0"); } result.append(furtherDesc); return result.toString(); } /** * @return Returns the compressionFormat. */ public long getCompressionFormat() { return this.compressionFormat; } /** * @return Returns the errorConcealment. */ public GUID getErrorConcealment() { return this.errorConcealment; } /** * This method takes the value of {@link #getAverageBytesPerSec()}and * calculates the kbps out of it, by simply multiplying by 8 and dividing by * 1000.
    * * @return amount of bits per second in kilo bits. */ public int getKbps() { return (int) getAverageBytesPerSec() * 8 / 1000; } /** * @return Returns the samplingRate. */ public long getSamplingRate() { return this.samplingRate; } /** * This mehtod returns whether the audio stream data is error concealed.
    * For now only interleaved concealment is known.
    * * @return true if error concealment is used. */ public boolean isErrorConcealed() { return getErrorConcealment().equals( GUID.GUID_AUDIO_ERROR_CONCEALEMENT_INTERLEAVED); } /** * * {@inheritDoc} */ @Override public String prettyPrint(final String prefix) { final StringBuilder result = new StringBuilder(super.prettyPrint(prefix)); result.append(prefix).append(" |-> Audio info:").append( Utils.LINE_SEPARATOR); result.append(prefix).append(" | : Bitrate : ").append(getKbps()) .append(Utils.LINE_SEPARATOR); result.append(prefix).append(" | : Channels : ").append( getChannelCount()).append(" at ").append(getSamplingRate()) .append(" Hz").append(Utils.LINE_SEPARATOR); result.append(prefix).append(" | : Bits per Sample: ").append( getBitsPerSample()).append(Utils.LINE_SEPARATOR); result.append(prefix).append(" | : Formatcode: ").append( getCodecDescription()).append(Utils.LINE_SEPARATOR); return result.toString(); } /** * @param avgeBytesPerSec * The averageBytesPerSec to set. */ public void setAverageBytesPerSec(final long avgeBytesPerSec) { this.averageBytesPerSec = avgeBytesPerSec; } /** * Sets the bitsPerSample * * @param bps */ public void setBitsPerSample(final int bps) { this.bitsPerSample = bps; } /** * Sets the blockAlignment. * * @param align */ public void setBlockAlignment(final long align) { this.blockAlignment = align; } /** * @param channels * The channelCount to set. */ public void setChannelCount(final long channels) { this.channelCount = channels; } /** * Sets the codecData * * @param codecSpecificData */ public void setCodecData(final byte[] codecSpecificData) { if (codecSpecificData == null) { throw new IllegalArgumentException(); } this.codecData = codecSpecificData.clone(); } /** * @param cFormatCode * The compressionFormat to set. */ public void setCompressionFormat(final long cFormatCode) { this.compressionFormat = cFormatCode; } /** * This method sets the error concealment type which is given by two GUIDs.
    * * @param errConc * the type of error concealment the audio stream is stored as. */ public void setErrorConcealment(final GUID errConc) { this.errorConcealment = errConc; } /** * @param sampRate * The samplingRate to set. */ public void setSamplingRate(final long sampRate) { this.samplingRate = sampRate; } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/asf/io/0000755000175000017500000000000011556363171023777 5ustar drazzibdrazziblibjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/asf/io/FileHeaderReader.java0000644000175000017500000000574111222471043027750 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2004-2005 Christian Laireiter * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.audio.asf.io; import org.jaudiotagger.audio.asf.data.Chunk; import org.jaudiotagger.audio.asf.data.FileHeader; import org.jaudiotagger.audio.asf.data.GUID; import org.jaudiotagger.audio.asf.util.Utils; import java.io.IOException; import java.io.InputStream; import java.math.BigInteger; /** * Reads and interprets the data of the file header.
    * * @author Christian Laireiter */ public class FileHeaderReader implements ChunkReader { /** * The GUID this reader {@linkplain #getApplyingIds() applies to} */ private final static GUID[] APPLYING = { GUID.GUID_FILE }; /** * Should not be used for now. */ protected FileHeaderReader() { // NOTHING toDo } /** * {@inheritDoc} */ public boolean canFail() { return false; } /** * {@inheritDoc} */ public GUID[] getApplyingIds() { return APPLYING.clone(); } /** * {@inheritDoc} */ public Chunk read(final GUID guid, final InputStream stream, final long chunkStart) throws IOException { final BigInteger chunkLen = Utils.readBig64(stream); // Skip client GUID. stream.skip(16); final BigInteger fileSize = Utils.readBig64(stream); // fileTime in 100 ns since midnight of 1st january 1601 GMT final BigInteger fileTime = Utils.readBig64(stream); final BigInteger packageCount = Utils.readBig64(stream); final BigInteger timeEndPos = Utils.readBig64(stream); final BigInteger duration = Utils.readBig64(stream); final BigInteger timeStartPos = Utils.readBig64(stream); final long flags = Utils.readUINT32(stream); final long minPkgSize = Utils.readUINT32(stream); final long maxPkgSize = Utils.readUINT32(stream); final long uncompressedFrameSize = Utils.readUINT32(stream); final FileHeader result = new FileHeader(chunkLen, fileSize, fileTime, packageCount, duration, timeStartPos, timeEndPos, flags, minPkgSize, maxPkgSize, uncompressedFrameSize); result.setPosition(chunkStart); return result; } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/asf/io/ChunkReader.java0000644000175000017500000000360611222471043027026 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.asf.io; import org.jaudiotagger.audio.asf.data.Chunk; import org.jaudiotagger.audio.asf.data.GUID; import java.io.IOException; import java.io.InputStream; /** * A ChunkReader provides methods for reading an ASF chunk.
    * * @author Christian Laireiter */ public interface ChunkReader { /** * Tells whether the reader can fail to return a valid chunk.
    * The current Use would be a modified version of {@link StreamChunkReader}, * which is configured to only manage audio streams. However, the primary * GUID for audio and video streams is the same. So if a stream shows itself * to be a video stream, the reader would return null.
    * * @return true, if further analysis of the chunk can show, * that the reader is not applicable, despite the header GUID * {@linkplain #getApplyingIds() identification} told it can handle * the chunk. */ boolean canFail(); /** * Returns the GUIDs identifying the types of chunk, this reader will parse.
    * * @return the GUIDs identifying the types of chunk, this reader will parse.
    */ GUID[] getApplyingIds(); /** * Parses the chunk. * * @param guid * the GUID of the chunks header, which is about to be read. * @param stream * source to read chunk from.
    * No {@link GUID} is expected at the currents stream position. * The length of the chunk is about to follow. * @param streamPosition * the position in stream, the chunk starts.
    * @return the read chunk. (Mostly a subclass of {@link Chunk}).
    * @throws IOException * On I/O Errors. */ Chunk read(GUID guid, InputStream stream, long streamPosition) throws IOException; } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/asf/io/FullRequestInputStream.java0000644000175000017500000000376211222471043031305 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.asf.io; import java.io.FilterInputStream; import java.io.IOException; import java.io.InputStream; /** * This implementation repeatedly reads from the wrapped input stream until the * requested amount of bytes are read.
    * * @author Christian Laireiter */ public class FullRequestInputStream extends FilterInputStream { /** * Creates an instance. * * @param source * stream to read from. */ public FullRequestInputStream(final InputStream source) { super(source); } /** * {@inheritDoc} */ @Override public int read(final byte[] buffer) throws IOException { return read(buffer, 0, buffer.length); } /** * {@inheritDoc} */ @Override public int read(final byte[] buffer, final int off, final int len) throws IOException { int totalRead = 0; int read; while (totalRead < len) { read = super.read(buffer, off + totalRead, len - totalRead); if (read >= 0) { totalRead += read; } if (read == -1) { throw new IOException((len - totalRead) + " more bytes expected."); } } return totalRead; } /** * {@inheritDoc} */ @Override public long skip(final long amount) throws IOException { long skipped = 0; int zeroSkipCnt = 0; long currSkipped; while (skipped < amount) { currSkipped = super.skip(amount - skipped); if (currSkipped == 0) { zeroSkipCnt++; if (zeroSkipCnt == 2) { // If the skip value exceeds streams size, this and the // number is extremely large, this can lead to a very long // running loop. break; } } skipped += currSkipped; } return skipped; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/asf/io/StreamBitratePropertiesReader.java0000644000175000017500000000513311222471043032576 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2004-2005 Christian Laireiter * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.audio.asf.io; import org.jaudiotagger.audio.asf.data.Chunk; import org.jaudiotagger.audio.asf.data.GUID; import org.jaudiotagger.audio.asf.data.StreamBitratePropertiesChunk; import org.jaudiotagger.audio.asf.util.Utils; import java.io.IOException; import java.io.InputStream; import java.math.BigInteger; /** * This class reads the chunk containing the stream bitrate properties.
    * * @author Christian Laireiter */ public class StreamBitratePropertiesReader implements ChunkReader { /** * The GUID this reader {@linkplain #getApplyingIds() applies to} */ private final static GUID[] APPLYING = { GUID.GUID_STREAM_BITRATE_PROPERTIES }; /** * Should not be used for now. */ protected StreamBitratePropertiesReader() { // NOTHING toDo } /** * {@inheritDoc} */ public boolean canFail() { return false; } /** * {@inheritDoc} */ public GUID[] getApplyingIds() { return APPLYING.clone(); } /** * {@inheritDoc} */ public Chunk read(final GUID guid, final InputStream stream, final long chunkStart) throws IOException { final BigInteger chunkLen = Utils.readBig64(stream); final StreamBitratePropertiesChunk result = new StreamBitratePropertiesChunk( chunkLen); /* * Read the amount of bitrate records */ final long recordCount = Utils.readUINT16(stream); for (int i = 0; i < recordCount; i++) { final int flags = Utils.readUINT16(stream); final long avgBitrate = Utils.readUINT32(stream); result.addBitrateRecord(flags & 0x00FF, avgBitrate); } result.setPosition(chunkStart); return result; } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/asf/io/AsfExtHeaderReader.java0000644000175000017500000000441011222471043030253 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.asf.io; import org.jaudiotagger.audio.asf.data.AsfExtendedHeader; import org.jaudiotagger.audio.asf.data.GUID; import org.jaudiotagger.audio.asf.util.Utils; import java.io.IOException; import java.io.InputStream; import java.math.BigInteger; import java.util.List; /** * This reader reads an ASF header extension object from an {@link InputStream} * and creates an {@link AsfExtendedHeader} object.
    * * @author Christian Laireiter */ public class AsfExtHeaderReader extends ChunkContainerReader { /** * The GUID this reader {@linkplain #getApplyingIds() applies to} */ private final static GUID[] APPLYING = { GUID.GUID_HEADER_EXTENSION }; /** * Creates a reader instance, which only utilizes the given list of chunk * readers.
    * * @param toRegister * List of {@link ChunkReader} class instances, which are to be * utilized by the instance. * @param readChunkOnce * if true, each chunk type (identified by chunk * GUID) will handled only once, if a reader is available, other * chunks will be discarded. */ public AsfExtHeaderReader( final List> toRegister, final boolean readChunkOnce) { super(toRegister, readChunkOnce); } /** * {@inheritDoc} */ public boolean canFail() { return false; } /** * {@inheritDoc} */ @Override protected AsfExtendedHeader createContainer(final long streamPosition, final BigInteger chunkLength, final InputStream stream) throws IOException { Utils.readGUID(stream); // First reserved field (should be a specific // GUID. Utils.readUINT16(stream); // Second reserved field (should always be 6) final long extensionSize = Utils.readUINT32(stream); assert extensionSize == 0 || extensionSize >= 24; assert chunkLength.subtract(BigInteger.valueOf(46)).longValue() == extensionSize; return new AsfExtendedHeader(streamPosition, chunkLength); } /** * {@inheritDoc} */ public GUID[] getApplyingIds() { return APPLYING.clone(); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/asf/io/MetadataReader.java0000644000175000017500000001363611222471043027502 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.asf.io; import org.jaudiotagger.audio.asf.data.*; import org.jaudiotagger.audio.asf.util.Utils; import java.io.IOException; import java.io.InputStream; import java.math.BigInteger; /** * Reads an interprets "Metadata Object", "Metadata Library * Object" and "Extended Content Description" of ASF files.
    * * @author Christian Laireiter */ public class MetadataReader implements ChunkReader { /** * The GUID this reader {@linkplain #getApplyingIds() applies to} */ private final static GUID[] APPLYING = { ContainerType.EXTENDED_CONTENT.getContainerGUID(), ContainerType.METADATA_OBJECT.getContainerGUID(), ContainerType.METADATA_LIBRARY_OBJECT.getContainerGUID() }; /** * {@inheritDoc} */ public boolean canFail() { return false; } /** * {@inheritDoc} */ public GUID[] getApplyingIds() { return APPLYING.clone(); } /** * {@inheritDoc} */ public Chunk read(final GUID guid, final InputStream stream, final long streamPosition) throws IOException { final BigInteger chunkLen = Utils.readBig64(stream); final MetadataContainer result = new MetadataContainer(guid, streamPosition, chunkLen); // isExtDesc will be set to true, if a extended content description // chunk is read // otherwise it is a metadata object, there are only slight differences final boolean isExtDesc = result.getContainerType() == ContainerType.EXTENDED_CONTENT; final int recordCount = Utils.readUINT16(stream); for (int i = 0; i < recordCount; i++) { int languageIndex = 0; int streamNumber = 0; if (!isExtDesc) { /* * Metadata objects have a language index and a stream number */ languageIndex = Utils.readUINT16(stream); assert languageIndex >= 0 && languageIndex < MetadataDescriptor.MAX_LANG_INDEX; assert result.getContainerType() == ContainerType.METADATA_LIBRARY_OBJECT || languageIndex == 0; streamNumber = Utils.readUINT16(stream); assert streamNumber >= 0 && streamNumber <= MetadataDescriptor.MAX_STREAM_NUMBER; } final int nameLen = Utils.readUINT16(stream); String recordName = null; if (isExtDesc) { recordName = Utils.readFixedSizeUTF16Str(stream, nameLen); } final int dataType = Utils.readUINT16(stream); assert dataType >= 0 && dataType <= 6; final long dataLen = isExtDesc ? Utils.readUINT16(stream) : Utils .readUINT32(stream); assert dataLen >= 0; assert result.getContainerType() == ContainerType.METADATA_LIBRARY_OBJECT || dataLen <= MetadataDescriptor.DWORD_MAXVALUE; if (!isExtDesc) { recordName = Utils.readFixedSizeUTF16Str(stream, nameLen); } final MetadataDescriptor descriptor = new MetadataDescriptor(result .getContainerType(), recordName, dataType, streamNumber, languageIndex); switch (dataType) { case MetadataDescriptor.TYPE_STRING: descriptor.setStringValue(Utils.readFixedSizeUTF16Str(stream, (int) dataLen)); break; case MetadataDescriptor.TYPE_BINARY: descriptor.setBinaryValue(Utils.readBinary(stream, dataLen)); break; case MetadataDescriptor.TYPE_BOOLEAN: assert isExtDesc && dataLen == 4 || !isExtDesc && dataLen == 2; descriptor.setBooleanValue(readBoolean(stream, (int) dataLen)); break; case MetadataDescriptor.TYPE_DWORD: assert dataLen == 4; descriptor.setDWordValue(Utils.readUINT32(stream)); break; case MetadataDescriptor.TYPE_WORD: assert dataLen == 2; descriptor.setWordValue(Utils.readUINT16(stream)); break; case MetadataDescriptor.TYPE_QWORD: assert dataLen == 8; descriptor.setQWordValue(Utils.readUINT64(stream)); break; case MetadataDescriptor.TYPE_GUID: assert dataLen == GUID.GUID_LENGTH; descriptor.setGUIDValue(Utils.readGUID(stream)); break; default: // Unknown, hopefully the convention for the size of the // value // is given, so we could read it binary descriptor.setStringValue("Invalid datatype: " + new String(Utils.readBinary(stream, dataLen))); } result.addDescriptor(descriptor); } return result; } /** * Reads the given amount of bytes and checks the last byte, if its equal to * one or zero (true / false).
    * All other bytes must be zero. (if assertions enabled). * * @param stream * stream to read from. * @param bytes * amount of bytes * @return true or false. * @throws IOException * on I/O Errors */ private boolean readBoolean(final InputStream stream, final int bytes) throws IOException { final byte[] tmp = new byte[bytes]; stream.read(tmp); boolean result = false; for (int i = 0; i < bytes; i++) { if (i == bytes - 1) { result = tmp[i] == 1; assert tmp[i] == 0 || tmp[i] == 1; } else { assert tmp[i] == 0; } } return result; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/asf/io/WriteableChunk.java0000644000175000017500000000245511222471043027543 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.asf.io; import org.jaudiotagger.audio.asf.data.GUID; import java.io.IOException; import java.io.OutputStream; /** * Implementors can write themselves directly to an output stream, and have the * ability to tell the size they would need, as well as determine if they are * empty.
    * * @author Christian Laireiter */ public interface WriteableChunk { /** * This method calculates the total amount of bytes, the chunk would consume * in an ASF file.
    * * @return amount of bytes the chunk would currently need in an ASF file. */ long getCurrentAsfChunkSize(); /** * Returns the GUID of the chunk. * * @return GUID of the chunk. */ GUID getGuid(); /** * true if it is not necessary to write the chunk into an ASF * file, since it contains no information. * * @return true if no useful data will be preserved. */ boolean isEmpty(); /** * Writes the chunk into the specified output stream, as ASF stream chunk.
    * * @param out * stream to write into. * @return amount of bytes written. * @throws IOException * on I/O errors */ long writeInto(OutputStream out) throws IOException; } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/asf/io/ModificationResult.java0000644000175000017500000000515411222471043030437 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.asf.io; import org.jaudiotagger.audio.asf.data.GUID; import java.util.Arrays; import java.util.HashSet; import java.util.Set; /** * Structure to tell the differences occurred by altering a chunk. * * @author Christian Laireiter */ final class ModificationResult { /** * Stores the difference of bytes.
    */ private final long byteDifference; /** * Stores the difference of the amount of chunks.
    * "-1" if the chunk disappeared upon modification.
    * "0" if the chunk was just modified.
    * "1" if a chunk has been created.
    */ private final int chunkDifference; /** * Stores all GUIDs, which have been read.
    */ private final Set occuredGUIDs = new HashSet(); /** * Creates an instance.
    * * @param chunkCountDiff * amount of chunks appeared, disappeared * @param bytesDiffer * amount of bytes added or removed. * @param occurred * all GUIDs which have been occurred, during processing */ public ModificationResult(final int chunkCountDiff, final long bytesDiffer, final GUID... occurred) { assert occurred != null && occurred.length > 0; this.chunkDifference = chunkCountDiff; this.byteDifference = bytesDiffer; this.occuredGUIDs.addAll(Arrays.asList(occurred)); } /** * Creates an instance.
    * * @param chunkCountDiff * amount of chunks appeared, disappeared * @param bytesDiffer * amount of bytes added or removed. * @param occurred * all GUIDs which have been occurred, during processing */ public ModificationResult(final int chunkCountDiff, final long bytesDiffer, final Set occurred) { this.chunkDifference = chunkCountDiff; this.byteDifference = bytesDiffer; this.occuredGUIDs.addAll(occurred); } /** * Returns the difference of bytes. * * @return the byte difference */ public long getByteDifference() { return this.byteDifference; } /** * Returns the difference of the amount of chunks. * * @return the chunk count difference */ public int getChunkCountDifference() { return this.chunkDifference; } /** * Returns all GUIDs which have been occurred during processing. * * @return see description.s */ public Set getOccuredGUIDs() { return new HashSet(this.occuredGUIDs); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/asf/io/ChunkModifier.java0000644000175000017500000000232711222471043027361 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.asf.io; import org.jaudiotagger.audio.asf.data.GUID; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; /** * Reads an ASF chunk and writes a modified copy.
    * * @author Christian Laireiter */ public interface ChunkModifier { /** * Determines, whether the modifier handles chunks identified by given * guid. * * @param guid * GUID to test. * @return true, if this modifier can be used to modify the * chunk. */ boolean isApplicable(GUID guid); /** * Writes a modified copy of the chunk into the destination..
    * * @param guid * GUID of the chunk to modify. * @param source * a stream providing the chunk, starting at the chunks length * field. * @param destination * destination for the modified chunk. * @return the differences between source and destination. * @throws IOException * on I/O errors. */ ModificationResult modify(GUID guid, InputStream source, OutputStream destination) throws IOException; } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/asf/io/LanguageListReader.java0000644000175000017500000000340411222471043030331 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.asf.io; import org.jaudiotagger.audio.asf.data.Chunk; import org.jaudiotagger.audio.asf.data.GUID; import org.jaudiotagger.audio.asf.data.LanguageList; import org.jaudiotagger.audio.asf.util.Utils; import java.io.IOException; import java.io.InputStream; import java.math.BigInteger; /** * Reads and interprets the "Language List Object" of ASF files.
    * * @author Christian Laireiter */ public class LanguageListReader implements ChunkReader { /** * The GUID this reader {@linkplain #getApplyingIds() applies to} */ private final static GUID[] APPLYING = { GUID.GUID_LANGUAGE_LIST }; /** * {@inheritDoc} */ public boolean canFail() { return false; } /** * {@inheritDoc} */ public GUID[] getApplyingIds() { return APPLYING.clone(); } /** * {@inheritDoc} */ public Chunk read(final GUID guid, final InputStream stream, final long streamPosition) throws IOException { assert GUID.GUID_LANGUAGE_LIST.equals(guid); final BigInteger chunkLen = Utils.readBig64(stream); final int readUINT16 = Utils.readUINT16(stream); final LanguageList result = new LanguageList(streamPosition, chunkLen); for (int i = 0; i < readUINT16; i++) { final int langIdLen = (stream.read() & 0xFF); final String langId = Utils .readFixedSizeUTF16Str(stream, langIdLen); // langIdLen = 2 bytes for each char and optionally one zero // termination character assert langId.length() == langIdLen / 2 - 1 || langId.length() == langIdLen / 2; result.addLanguage(langId); } return result; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/asf/io/ChunkRemover.java0000644000175000017500000000360211277006322027243 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.asf.io; import org.jaudiotagger.audio.asf.data.GUID; import org.jaudiotagger.audio.asf.util.Utils; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.HashSet; import java.util.Set; /** * This {@link ChunkModifier} implementation is meant to remove selected chunks.
    * * @author Christian Laireiter */ @SuppressWarnings({"ManualArrayToCollectionCopy"}) public class ChunkRemover implements ChunkModifier { /** * Stores the GUIDs, which are about to be removed by this modifier.
    */ private final Set toRemove; /** * Creates an instance, for removing selected chunks.
    * * @param guids * the GUIDs which are about to be removed by this modifier. */ public ChunkRemover(final GUID... guids) { this.toRemove = new HashSet(); for (final GUID current : guids) { this.toRemove.add(current); } } /** * {@inheritDoc} */ public boolean isApplicable(final GUID guid) { return this.toRemove.contains(guid); } /** * {@inheritDoc} */ public ModificationResult modify(final GUID guid, final InputStream source, final OutputStream destination) throws IOException { ModificationResult result; if (guid == null) { // Now a chunk should be added, however, this implementation is for // removal. result = new ModificationResult(0, 0); } else { assert isApplicable(guid); // skip the chunk length minus 24 bytes for the already read length // and the guid. final long chunkLen = Utils.readUINT64(source); source.skip(chunkLen - 24); result = new ModificationResult(-1, -1 * chunkLen, guid); } return result; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/asf/io/ChunkContainerReader.java0000644000175000017500000002126611222471043030673 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.asf.io; import org.jaudiotagger.audio.asf.data.Chunk; import org.jaudiotagger.audio.asf.data.ChunkContainer; import org.jaudiotagger.audio.asf.data.GUID; import org.jaudiotagger.audio.asf.util.Utils; import java.io.IOException; import java.io.InputStream; import java.math.BigInteger; import java.util.*; import java.util.logging.Logger; /** * This class represents a reader implementation, which is able to read ASF * objects (chunks) which store other objects (chunks) within them.
    * * @author Christian Laireiter * @param * The {@link ChunkContainer} instance, the implementation will * create. */ abstract class ChunkContainerReader implements ChunkReader { /** * Logger */ protected static final Logger LOGGER = Logger .getLogger("org.jaudiotabgger.audio"); //$NON-NLS-1$ /** * Within this range, a {@link ChunkReader} should be aware if it fails. */ public final static int READ_LIMIT = 8192; /** * If true each chunk type will only be read once.
    */ protected final boolean eachChunkOnce; /** * If true due to a {@linkplain #register(Class) registered} * chunk reader, all {@link InputStream} objects passed to * {@link #read(GUID, InputStream, long)} must support mark/reset. */ protected boolean hasFailingReaders = false; /** * Registers GUIDs to their reader classes.
    */ protected final Map readerMap = new HashMap(); /** * Creates a reader instance, which only utilizes the given list of chunk * readers.
    * * @param toRegister * List of {@link ChunkReader} class instances, which are to be * utilized by the instance. * @param readChunkOnce * if true, each chunk type (identified by chunk * GUID) will handled only once, if a reader is available, other * chunks will be discarded. */ protected ChunkContainerReader( final List> toRegister, final boolean readChunkOnce) { this.eachChunkOnce = readChunkOnce; for (final Class curr : toRegister) { register(curr); } } /** * Checks for the constraints of this class. * * @param stream * stream to test. * @throws IllegalArgumentException * If stream does not meet the requirements. */ protected void checkStream(final InputStream stream) throws IllegalArgumentException { if (this.hasFailingReaders && !stream.markSupported()) { throw new IllegalArgumentException( "Stream has to support mark/reset."); } } /** * This method is called by {@link #read(GUID, InputStream, long)} in order * to create the resulting object. Implementations of this class should now * return a new instance of their implementation specific result AND * all data should be read, until the list of chunks starts. (The * {@link ChunkContainer#getChunkEnd()} must return a sane result, too)
    * * @param streamPosition * position of the stream, the chunk starts. * @param chunkLength * the length of the chunk (from chunk header) * @param stream * to read the implementation specific information. * @return instance of the implementations result. * @throws IOException * On I/O Errors and Invalid data. */ abstract protected ChunkType createContainer(long streamPosition, BigInteger chunkLength, InputStream stream) throws IOException; /** * Gets a configured {@linkplain ChunkReader reader} instance for ASF * objects (chunks) with the specified guid. * * @param guid * GUID which identifies the chunk to be read. * @return an appropriate reader implementation, null if not * {@linkplain #register(Class) registered}. */ protected ChunkReader getReader(final GUID guid) { return this.readerMap.get(guid); } /** * Tests whether {@link #getReader(GUID)} won't return null.
    * * @param guid * GUID which identifies the chunk to be read. * @return true if a reader is available. */ protected boolean isReaderAvailable(final GUID guid) { return this.readerMap.containsKey(guid); } /** * This Method implements the reading of a chunk container.
    * * @param guid * GUID of the currently read container. * @param stream * Stream which contains the chunk container. * @param chunkStart * The start of the chunk container from stream start.
    * For direct file streams one can assume 0 here. * @return null if no valid data found, else a Wrapper * containing all supported data. * @throws IOException * Read errors. * @throws IllegalArgumentException * If one used {@link ChunkReader} could * {@linkplain ChunkReader#canFail() fail} and the stream source * doesn't support mark/reset. */ public ChunkType read(final GUID guid, final InputStream stream, final long chunkStart) throws IOException, IllegalArgumentException { checkStream(stream); final CountingInputStream cis = new CountingInputStream(stream); if (!Arrays.asList(getApplyingIds()).contains(guid)) { throw new IllegalArgumentException( "provided GUID is not supported by this reader."); } // For Know the file pointer pointed to an ASF header chunk. final BigInteger chunkLen = Utils.readBig64(cis); /* * now read implementation specific information until the chunk * collection starts and create the resulting object. */ final ChunkType result = createContainer(chunkStart, chunkLen, cis); // 16 bytes have already been for providing the GUID long currentPosition = chunkStart + cis.getReadCount() + 16; final HashSet alreadyRead = new HashSet(); /* * Now reading header of chuncks. */ while (currentPosition < result.getChunkEnd()) { final GUID currentGUID = Utils.readGUID(cis); final boolean skip = this.eachChunkOnce && (!isReaderAvailable(currentGUID) || !alreadyRead .add(currentGUID)); Chunk chunk; /* * If one reader tells it could fail (new method), then check the * input stream for mark/reset. And use it if failed. */ if (!skip && isReaderAvailable(currentGUID)) { final ChunkReader reader = getReader(currentGUID); if (reader.canFail()) { cis.mark(READ_LIMIT); } chunk = getReader(currentGUID).read(currentGUID, cis, currentPosition); } else { chunk = ChunkHeaderReader.getInstance().read(currentGUID, cis, currentPosition); } if (chunk == null) { /* * Reader failed */ cis.reset(); } else { if (!skip) { result.addChunk(chunk); } currentPosition = chunk.getChunkEnd(); // Always take into account, that 16 bytes have been read prior // to calling this method assert cis.getReadCount() + chunkStart + 16 == currentPosition; } } return result; } /** * Registers the given reader.
    * * @param * The actual reader implementation. * * @param toRegister * chunk reader which is to be registered. */ private void register(final Class toRegister) { try { final T reader = toRegister.newInstance(); for (final GUID curr : reader.getApplyingIds()) { this.readerMap.put(curr, reader); } } catch (InstantiationException e) { LOGGER.severe(e.getMessage()); } catch (IllegalAccessException e) { LOGGER.severe(e.getMessage()); } } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/asf/io/CountingInputStream.java0000644000175000017500000000507211277026507030627 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.asf.io; import java.io.FilterInputStream; import java.io.IOException; import java.io.InputStream; /** * This implementation of {@link FilterInputStream} counts each read byte.
    * So at each time, with {@link #getReadCount()} one can determine how many * bytes have been read, by this classes read and skip methods (mark and reset * are also taken into account).
    * * @author Christian Laireiter */ class CountingInputStream extends FilterInputStream { /** * If {@link #mark(int)} has been called, the current value of * {@link #readCount} is stored, in order to reset it upon {@link #reset()}. */ private long markPos; /** * The amount of read or skipped bytes. */ private long readCount; /** * Creates an instance, which delegates the commands to the given stream. * * @param stream * stream to actually work with. */ public CountingInputStream(final InputStream stream) { super(stream); this.markPos = 0; this.readCount = 0; } /** * Counts the given amount of bytes. * * @param amountRead * number of bytes to increase. */ private synchronized void bytesRead(final long amountRead) { if (amountRead >= 0) { this.readCount += amountRead; } } /** * @return the readCount */ public synchronized long getReadCount() { return this.readCount; } /** * {@inheritDoc} */ @Override public synchronized void mark(final int readlimit) { super.mark(readlimit); this.markPos = this.readCount; } /** * {@inheritDoc} */ @Override public int read() throws IOException { final int result = super.read(); bytesRead(1); return result; } /** * {@inheritDoc} */ @Override public int read(final byte[] destination, final int off, final int len) throws IOException { final int result = super.read(destination, off, len); bytesRead(result); return result; } /** * {@inheritDoc} */ @Override public synchronized void reset() throws IOException { super.reset(); synchronized (this) { this.readCount = this.markPos; } } /** * {@inheritDoc} */ @Override public long skip(final long amount) throws IOException { final long skipped = super.skip(amount); bytesRead(skipped); return skipped; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/asf/io/StreamChunkReader.java0000644000175000017500000001536311277026507030220 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2004-2005 Christian Laireiter * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.audio.asf.io; import org.jaudiotagger.audio.asf.data.*; import org.jaudiotagger.audio.asf.util.Utils; import java.io.IOException; import java.io.InputStream; import java.math.BigInteger; /** * Reads and interprets the data of the audio or video stream information chunk.
    * * @author Christian Laireiter */ public class StreamChunkReader implements ChunkReader { /** * The GUID this reader {@linkplain #getApplyingIds() applies to} */ private final static GUID[] APPLYING = { GUID.GUID_STREAM }; /** * Shouldn't be used for now. */ protected StreamChunkReader() { // Nothing to do } /** * {@inheritDoc} */ public boolean canFail() { return true; } /** * {@inheritDoc} */ public GUID[] getApplyingIds() { return APPLYING.clone(); } /** * {@inheritDoc} */ public Chunk read(final GUID guid, final InputStream stream, final long chunkStart) throws IOException { StreamChunk result = null; final BigInteger chunkLength = Utils.readBig64(stream); // Now comes GUID indicating whether stream content type is audio or // video final GUID streamTypeGUID = Utils.readGUID(stream); if (GUID.GUID_AUDIOSTREAM.equals(streamTypeGUID) || GUID.GUID_VIDEOSTREAM.equals(streamTypeGUID)) { // A GUID is indicating whether the stream is error // concealed final GUID errorConcealment = Utils.readGUID(stream); /* * Read the Time Offset */ final long timeOffset = Utils.readUINT64(stream); final long typeSpecificDataSize = Utils.readUINT32(stream); final long streamSpecificDataSize = Utils.readUINT32(stream); /* * Read a bit field. (Contains stream number, and whether the stream * content is encrypted.) */ final int mask = Utils.readUINT16(stream); final int streamNumber = mask & 127; final boolean contentEncrypted = (mask & 0x8000) != 0; /* * Skip a reserved field */ stream.skip(4); /* * very important to set for every stream type. The size of bytes * read by the specific stream type, in order to skip the remaining * unread bytes of the stream chunk. */ long streamSpecificBytes; if (GUID.GUID_AUDIOSTREAM.equals(streamTypeGUID)) { /* * Reading audio specific information */ final AudioStreamChunk audioStreamChunk = new AudioStreamChunk( chunkLength); result = audioStreamChunk; /* * read WAVEFORMATEX and format extension. */ final long compressionFormat = Utils.readUINT16(stream); final long channelCount = Utils.readUINT16(stream); final long samplingRate = Utils.readUINT32(stream); final long avgBytesPerSec = Utils.readUINT32(stream); final long blockAlignment = Utils.readUINT16(stream); final int bitsPerSample = Utils.readUINT16(stream); final int codecSpecificDataSize = Utils.readUINT16(stream); final byte[] codecSpecificData = new byte[codecSpecificDataSize]; stream.read(codecSpecificData); audioStreamChunk.setCompressionFormat(compressionFormat); audioStreamChunk.setChannelCount(channelCount); audioStreamChunk.setSamplingRate(samplingRate); audioStreamChunk.setAverageBytesPerSec(avgBytesPerSec); audioStreamChunk.setErrorConcealment(errorConcealment); audioStreamChunk.setBlockAlignment(blockAlignment); audioStreamChunk.setBitsPerSample(bitsPerSample); audioStreamChunk.setCodecData(codecSpecificData); streamSpecificBytes = 18 + codecSpecificData.length; } else { /* * Reading video specific information */ final VideoStreamChunk videoStreamChunk = new VideoStreamChunk( chunkLength); result = videoStreamChunk; final long pictureWidth = Utils.readUINT32(stream); final long pictureHeight = Utils.readUINT32(stream); // Skip unknown field stream.skip(1); /* * Now read the format specific data */ // Size of the data section (formatDataSize) stream.skip(2); stream.skip(16); final byte[] fourCC = new byte[4]; stream.read(fourCC); videoStreamChunk.setPictureWidth(pictureWidth); videoStreamChunk.setPictureHeight(pictureHeight); videoStreamChunk.setCodecId(fourCC); streamSpecificBytes = 31; } /* * Setting common values for audio and video */ result.setStreamNumber(streamNumber); result.setStreamSpecificDataSize(streamSpecificDataSize); result.setTypeSpecificDataSize(typeSpecificDataSize); result.setTimeOffset(timeOffset); result.setContentEncrypted(contentEncrypted); result.setPosition(chunkStart); /* * Now skip remainder of chunks bytes. chunk-length - 24 (size of * GUID and chunklen) - streamSpecificBytes(stream type specific * data) - 54 (common data) */ stream .skip(chunkLength.longValue() - 24 - streamSpecificBytes - 54); } return result; } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/asf/io/ChunkHeaderReader.java0000644000175000017500000000467311222471043030144 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2004-2005 Christian Laireiter * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.audio.asf.io; import org.jaudiotagger.audio.asf.data.Chunk; import org.jaudiotagger.audio.asf.data.GUID; import org.jaudiotagger.audio.asf.util.Utils; import java.io.IOException; import java.io.InputStream; import java.math.BigInteger; /** * Default reader, Reads GUID and size out of an input stream and creates a * {@link org.jaudiotagger.audio.asf.data.Chunk}object, finally skips the * remaining chunk bytes. * * @author Christian Laireiter */ final class ChunkHeaderReader implements ChunkReader { /** * The GUID this reader {@linkplain #getApplyingIds() applies to} */ private final static GUID[] APPLYING = { GUID.GUID_UNSPECIFIED }; /** * Default instance. */ private static final ChunkHeaderReader INSTANCE = new ChunkHeaderReader(); /** * Returns an instance of the reader. * * @return instance. */ public static ChunkHeaderReader getInstance() { return INSTANCE; } /** * Hidden Utility class constructor. */ private ChunkHeaderReader() { // Hidden } /** * {@inheritDoc} */ public boolean canFail() { return false; } /** * {@inheritDoc} */ public GUID[] getApplyingIds() { return APPLYING.clone(); } /** * {@inheritDoc} */ public Chunk read(final GUID guid, final InputStream stream, final long chunkStart) throws IOException { final BigInteger chunkLen = Utils.readBig64(stream); stream.skip(chunkLen.longValue() - 24); return new Chunk(guid, chunkStart, chunkLen); } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/asf/io/RandomAccessFileInputstream.java0000644000175000017500000000317511222471043032232 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.asf.io; import java.io.IOException; import java.io.InputStream; import java.io.RandomAccessFile; /** * Wraps a {@link RandomAccessFile} into an {@link InputStream}.
    * * @author Christian Laireiter */ public final class RandomAccessFileInputstream extends InputStream { /** * The file access to read from.
    */ private final RandomAccessFile source; /** * Creates an instance that will provide {@link InputStream} functionality * on the given {@link RandomAccessFile} by delegating calls.
    * * @param file * The file to read. */ public RandomAccessFileInputstream(final RandomAccessFile file) { super(); if (file == null) { throw new IllegalArgumentException("null"); } this.source = file; } /** * {@inheritDoc} */ @Override public int read() throws IOException { return this.source.read(); } /** * {@inheritDoc} */ @Override public int read(final byte[] buffer, final int off, final int len) throws IOException { return this.source.read(buffer, off, len); } /** * {@inheritDoc} */ @Override public long skip(final long amount) throws IOException { if (amount < 0) { throw new IllegalArgumentException("invalid negative value"); } long left = amount; while (left > Integer.MAX_VALUE) { this.source.skipBytes(Integer.MAX_VALUE); left -= Integer.MAX_VALUE; } return this.source.skipBytes((int) left); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/asf/io/EncodingChunkReader.java0000644000175000017500000000607411222471043030477 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2004-2005 Christian Laireiter * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.audio.asf.io; import org.jaudiotagger.audio.asf.data.Chunk; import org.jaudiotagger.audio.asf.data.EncodingChunk; import org.jaudiotagger.audio.asf.data.GUID; import org.jaudiotagger.audio.asf.util.Utils; import java.io.IOException; import java.io.InputStream; import java.math.BigInteger; /** * This class reads the chunk containing encoding data
    * Warning:
    * Implementation is not completed. More analysis of this chunk is needed. * * @author Christian Laireiter */ class EncodingChunkReader implements ChunkReader { /** * The GUID this reader {@linkplain #getApplyingIds() applies to} */ private final static GUID[] APPLYING = { GUID.GUID_ENCODING }; /** * Should not be used for now. */ protected EncodingChunkReader() { // NOTHING toDo } /** * {@inheritDoc} */ public boolean canFail() { return false; } /** * {@inheritDoc} */ public GUID[] getApplyingIds() { return APPLYING.clone(); } /** * {@inheritDoc} */ public Chunk read(final GUID guid, final InputStream stream, final long chunkStart) throws IOException { final BigInteger chunkLen = Utils.readBig64(stream); final EncodingChunk result = new EncodingChunk(chunkLen); int readBytes = 24; // Can't be interpreted /* * What do I think of this data, well it seems to be another GUID. Then * followed by a UINT16 indicating a length of data following (by half). * My test files just had the length of one and a two bytes zero. */ stream.skip(20); readBytes += 20; /* * Read the number of strings which will follow */ final int stringCount = Utils.readUINT16(stream); readBytes += 2; /* * Now reading the specified amount of strings. */ for (int i = 0; i < stringCount; i++) { final String curr = Utils.readCharacterSizedString(stream); result.addString(curr); readBytes += 4 + 2 * curr.length(); } stream.skip(chunkLen.longValue() - readBytes); result.setPosition(chunkStart); return result; } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/asf/io/EncryptionChunkReader.java0000644000175000017500000000770611277026507031121 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2004-2005 Christian Laireiter * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.audio.asf.io; import org.jaudiotagger.audio.asf.data.Chunk; import org.jaudiotagger.audio.asf.data.EncryptionChunk; import org.jaudiotagger.audio.asf.data.GUID; import org.jaudiotagger.audio.asf.util.Utils; import java.io.IOException; import java.io.InputStream; import java.math.BigInteger; /** * This class reads the chunk containing encoding data
    * Warning:
    * Implementation is not completed. More analysis of this chunk is needed. * * @author Christian Laireiter */ class EncryptionChunkReader implements ChunkReader { /** * The GUID this reader {@linkplain #getApplyingIds() applies to} */ private final static GUID[] APPLYING = { GUID.GUID_CONTENT_ENCRYPTION }; /** * Should not be used for now. */ protected EncryptionChunkReader() { // NOTHING toDo } /** * {@inheritDoc} */ public boolean canFail() { return false; } /** * {@inheritDoc} */ public GUID[] getApplyingIds() { return APPLYING.clone(); } /** * {@inheritDoc} */ public Chunk read(final GUID guid, final InputStream stream, final long chunkStart) throws IOException { EncryptionChunk result; final BigInteger chunkLen = Utils.readBig64(stream); result = new EncryptionChunk(chunkLen); // Can't be interpreted /* * Object ID GUID 128 Object Size QWORD 64 Secret Data Length DWORD 32 * Secret Data INTEGER varies Protection Type Length DWORD 32 Protection * Type char varies Key ID Length DWORD 32 Key ID char varies License * URL Length DWORD 32 License URL char varies * Read the */ byte[] secretData; byte[] protectionType; byte[] keyID; byte[] licenseURL; // Secret Data length int fieldLength; fieldLength = (int) Utils.readUINT32(stream); // Secret Data secretData = new byte[fieldLength + 1]; stream.read(secretData, 0, fieldLength); secretData[fieldLength] = 0; // Protection type Length fieldLength = 0; fieldLength = (int) Utils.readUINT32(stream); // Protection Data Length protectionType = new byte[fieldLength + 1]; stream.read(protectionType, 0, fieldLength); protectionType[fieldLength] = 0; // Key ID length fieldLength = 0; fieldLength = (int) Utils.readUINT32(stream); // Key ID keyID = new byte[fieldLength + 1]; stream.read(keyID, 0, fieldLength); keyID[fieldLength] = 0; // License URL length fieldLength = 0; fieldLength = (int) Utils.readUINT32(stream); // License URL licenseURL = new byte[fieldLength + 1]; stream.read(licenseURL, 0, fieldLength); licenseURL[fieldLength] = 0; result.setSecretData(new String(secretData)); result.setProtectionType(new String(protectionType)); result.setKeyID(new String(keyID)); result.setLicenseURL(new String(licenseURL)); result.setPosition(chunkStart); return result; } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/asf/io/AsfExtHeaderModifier.java0000644000175000017500000001156311222471043030616 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.asf.io; import org.jaudiotagger.audio.asf.data.GUID; import org.jaudiotagger.audio.asf.util.Utils; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.math.BigInteger; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; /** * This modifier manipulates an ASF header extension object. * * @author Christian Laireiter */ public class AsfExtHeaderModifier implements ChunkModifier { /** * List of modifiers which are to be applied to contained chunks. */ private final List modifierList; /** * Creates an instance.
    * * @param modifiers * modifiers to apply. */ public AsfExtHeaderModifier(final List modifiers) { assert modifiers != null; this.modifierList = new ArrayList(modifiers); } /** * Simply copies a chunk from source to * destination.
    * The method assumes, that the GUID has already been read and will write * the provided one to the destination.
    * The chunk length however will be read and used to determine the amount of * bytes to copy. * * @param guid * GUID of the current CHUNK. * @param source * source of an ASF chunk, which is to be located at the chunk * length field. * @param destination * the destination to copy the chunk to. * @throws IOException * on I/O errors. */ private void copyChunk(final GUID guid, final InputStream source, final OutputStream destination) throws IOException { final long chunkSize = Utils.readUINT64(source); destination.write(guid.getBytes()); Utils.writeUINT64(chunkSize, destination); Utils.copy(source, destination, chunkSize - 24); } /** * {@inheritDoc} */ public boolean isApplicable(final GUID guid) { return GUID.GUID_HEADER_EXTENSION.equals(guid); } /** * {@inheritDoc} */ public ModificationResult modify(final GUID guid, final InputStream source, final OutputStream destination) throws IOException { assert GUID.GUID_HEADER_EXTENSION.equals(guid); long difference = 0; final List modders = new ArrayList( this.modifierList); final Set occuredGuids = new HashSet(); occuredGuids.add(guid); final BigInteger chunkLen = Utils.readBig64(source); final GUID reserved1 = Utils.readGUID(source); final int reserved2 = Utils.readUINT16(source); final long dataSize = Utils.readUINT32(source); assert dataSize == 0 || dataSize >= 24; assert chunkLen.subtract(BigInteger.valueOf(46)).longValue() == dataSize; /* * Stream buffer for the chunk list */ final ByteArrayOutputStream bos = new ByteArrayOutputStream(); /* * Stream which counts read bytes. Dirty but quick way of implementing * this. */ final CountingInputStream cis = new CountingInputStream(source); while (cis.getReadCount() < dataSize) { // read GUID final GUID curr = Utils.readGUID(cis); boolean handled = false; for (int i = 0; i < modders.size() && !handled; i++) { if (modders.get(i).isApplicable(curr)) { final ModificationResult modRes = modders.get(i).modify( curr, cis, bos); difference += modRes.getByteDifference(); occuredGuids.addAll(modRes.getOccuredGUIDs()); modders.remove(i); handled = true; } } if (!handled) { occuredGuids.add(curr); copyChunk(curr, cis, bos); } } // Now apply the left modifiers. for (final ChunkModifier curr : modders) { // chunks, which were not in the source file, will be added to the // destination final ModificationResult result = curr.modify(null, null, bos); difference += result.getByteDifference(); occuredGuids.addAll(result.getOccuredGUIDs()); } destination.write(GUID.GUID_HEADER_EXTENSION.getBytes()); Utils.writeUINT64(chunkLen.add(BigInteger.valueOf(difference)) .longValue(), destination); destination.write(reserved1.getBytes()); Utils.writeUINT16(reserved2, destination); Utils.writeUINT32(dataSize + difference, destination); destination.write(bos.toByteArray()); return new ModificationResult(0, difference, occuredGuids); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/asf/io/ContentDescriptionReader.java0000644000175000017500000000735511222471043031601 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2004-2005 Christian Laireiter * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.audio.asf.io; import org.jaudiotagger.audio.asf.data.Chunk; import org.jaudiotagger.audio.asf.data.ContentDescription; import org.jaudiotagger.audio.asf.data.GUID; import org.jaudiotagger.audio.asf.util.Utils; import java.io.IOException; import java.io.InputStream; import java.math.BigInteger; /** * Reads and interprets the data of a ASF chunk containing title, author...
    * * @author Christian Laireiter * @see org.jaudiotagger.audio.asf.data.ContentDescription */ public class ContentDescriptionReader implements ChunkReader { /** * The GUID this reader {@linkplain #getApplyingIds() applies to} */ private final static GUID[] APPLYING = { GUID.GUID_CONTENTDESCRIPTION }; /** * Should not be used for now. */ protected ContentDescriptionReader() { // NOTHING toDo } /** * {@inheritDoc} */ public boolean canFail() { return false; } /** * {@inheritDoc} */ public GUID[] getApplyingIds() { return APPLYING.clone(); } /** * Returns the next 5 UINT16 values as an array.
    * * @param stream * stream to read from * @return 5 int values read from stream. * @throws IOException * on I/O Errors. */ private int[] getStringSizes(final InputStream stream) throws IOException { final int[] result = new int[5]; for (int i = 0; i < result.length; i++) { result[i] = Utils.readUINT16(stream); } return result; } /** * {@inheritDoc} */ public Chunk read(final GUID guid, final InputStream stream, final long chunkStart) throws IOException { final BigInteger chunkSize = Utils.readBig64(stream); /* * Now comes 16-Bit values representing the length of the Strings which * follows. */ final int[] stringSizes = getStringSizes(stream); /* * Now we know the String length of each occuring String. */ final String[] strings = new String[stringSizes.length]; for (int i = 0; i < strings.length; i++) { if (stringSizes[i] > 0) { strings[i] = Utils .readFixedSizeUTF16Str(stream, stringSizes[i]); } } /* * Now create the result */ final ContentDescription result = new ContentDescription(chunkStart, chunkSize); if (stringSizes[0] > 0) { result.setTitle(strings[0]); } if (stringSizes[1] > 0) { result.setAuthor(strings[1]); } if (stringSizes[2] > 0) { result.setCopyright(strings[2]); } if (stringSizes[3] > 0) { result.setComment(strings[3]); } if (stringSizes[4] > 0) { result.setRating(strings[4]); } return result; } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/asf/io/ContentBrandingReader.java0000644000175000017500000000444211222471043031034 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.asf.io; import org.jaudiotagger.audio.asf.data.Chunk; import org.jaudiotagger.audio.asf.data.ContentBranding; import org.jaudiotagger.audio.asf.data.GUID; import org.jaudiotagger.audio.asf.util.Utils; import java.io.IOException; import java.io.InputStream; import java.math.BigInteger; /** * This reader is used to read the content branding object of ASF streams.
    * @see org.jaudiotagger.audio.asf.data.ContainerType#CONTENT_BRANDING * @see ContentBranding * * @author Christian Laireiter */ public class ContentBrandingReader implements ChunkReader { /** * The GUID this reader {@linkplain #getApplyingIds() applies to} */ private final static GUID[] APPLYING = { GUID.GUID_CONTENT_BRANDING }; /** * Should not be used for now. */ protected ContentBrandingReader() { // NOTHING toDo } /** * {@inheritDoc} */ public boolean canFail() { return false; } /** * {@inheritDoc} */ public GUID[] getApplyingIds() { return APPLYING.clone(); } /** * {@inheritDoc} */ public Chunk read(final GUID guid, final InputStream stream, final long streamPosition) throws IOException { assert GUID.GUID_CONTENT_BRANDING.equals(guid); final BigInteger chunkSize = Utils.readBig64(stream); final long imageType = Utils.readUINT32(stream); assert imageType >= 0 && imageType <= 3 : imageType; final long imageDataSize = Utils.readUINT32(stream); assert imageType > 0 || imageDataSize == 0 : imageDataSize; assert imageDataSize < Integer.MAX_VALUE; final byte[] imageData = Utils.readBinary(stream, imageDataSize); final long copyRightUrlLen = Utils.readUINT32(stream); final String copyRight = new String(Utils.readBinary(stream, copyRightUrlLen)); final long imageUrlLen = Utils.readUINT32(stream); final String imageUrl = new String(Utils .readBinary(stream, imageUrlLen)); final ContentBranding result = new ContentBranding(streamPosition, chunkSize); result.setImage(imageType, imageData); result.setCopyRightURL(copyRight); result.setBannerImageURL(imageUrl); return result; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/asf/io/AsfStreamer.java0000644000175000017500000001730311222471043027046 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.asf.io; import org.jaudiotagger.audio.asf.data.GUID; import org.jaudiotagger.audio.asf.util.Utils; import java.io.*; import java.util.ArrayList; import java.util.List; /** * This class creates a modified copy of an ASF file.
    * * @author Christian Laireiter */ public class AsfStreamer { /** * Simply copies a chunk from source to * destination.
    * The method assumes, that the GUID has already been read and will write * the provided one to the destination.
    * The chunk length however will be read and used to determine the amount of * bytes to copy. * * @param guid * GUID of the current chunk. * @param source * source of an ASF chunk, which is to be located at the chunk * length field. * @param destination * the destination to copy the chunk to. * @throws IOException * on I/O errors. */ private void copyChunk(final GUID guid, final InputStream source, final OutputStream destination) throws IOException { final long chunkSize = Utils.readUINT64(source); destination.write(guid.getBytes()); Utils.writeUINT64(chunkSize, destination); Utils.copy(source, destination, chunkSize - 24); } /** * Reads the source and applies the modifications provided by * the given modifiers, and puts it to dest.
    * Each {@linkplain ChunkModifier modifier} is used only once, so if one * should be used multiple times, it should be added multiple times into the * list.
    * * @param source * the source ASF file * @param dest * the destination to write the modified version to. * @param modifiers * list of chunk modifiers to apply. * @throws IOException * on I/O errors. */ public void createModifiedCopy(final InputStream source, final OutputStream dest, final List modifiers) throws IOException { final List modders = new ArrayList(); if (modifiers != null) { modders.addAll(modifiers); } // Read and check ASF GUID final GUID readGUID = Utils.readGUID(source); if (GUID.GUID_HEADER.equals(readGUID)) { // used to calculate differences long totalDiff = 0; long chunkDiff = 0; // read header information final long headerSize = Utils.readUINT64(source); final long chunkCount = Utils.readUINT32(source); final byte[] reserved = new byte[2]; reserved[0] = (byte) (source.read() & 0xFF); reserved[1] = (byte) (source.read() & 0xFF); /* * bos will get all unmodified and modified header chunks. This is * necessary, because the header chunk (and file properties chunk) * need to be adjusted but are written in front of the others. */ final ByteArrayOutputStream bos = new ByteArrayOutputStream(); // fileHeader will get the binary representation of the file // properties chunk, without GUID byte[] fileHeader = null; // Iterate through all chunks for (long i = 0; i < chunkCount; i++) { // Read GUID final GUID curr = Utils.readGUID(source); // special case for file properties chunk if (GUID.GUID_FILE.equals(curr)) { final ByteArrayOutputStream tmp = new ByteArrayOutputStream(); final long size = Utils.readUINT64(source); Utils.writeUINT64(size, tmp); Utils.copy(source, tmp, size - 24); fileHeader = tmp.toByteArray(); } else { /* * Now look for ChunkModifier objects which modify the * current chunk */ boolean handled = false; for (int j = 0; j < modders.size() && !handled; j++) { if (modders.get(j).isApplicable(curr)) { // alter current chunk final ModificationResult result = modders.get(j) .modify(curr, source, bos); // remember size differences. chunkDiff += result.getChunkCountDifference(); totalDiff += result.getByteDifference(); // remove current modifier from index. modders.remove(j); handled = true; } } if (!handled) { // copy chunks which are not modified. copyChunk(curr, source, bos); } } } // Now apply the left modifiers. for (final ChunkModifier curr : modders) { // chunks, which were not in the source file, will be added to // the destination final ModificationResult result = curr.modify(null, null, bos); chunkDiff += result.getChunkCountDifference(); totalDiff += result.getByteDifference(); } /* * Now all header objects have been read or manipulated and stored * in the internal buffer (bos). */ // write ASF GUID dest.write(readGUID.getBytes()); // write altered header object size Utils.writeUINT64(headerSize + totalDiff, dest); // write altered number of chunks Utils.writeUINT32(chunkCount + chunkDiff, dest); // write the reserved 2 bytes (0x01,0x02). dest.write(reserved); // write the new file header modifyFileHeader(new ByteArrayInputStream(fileHeader), dest, totalDiff); // write the header objects (chunks) dest.write(bos.toByteArray()); // copy the rest of the file (data and index) Utils.flush(source, dest); } else { throw new IllegalArgumentException("No ASF header object."); } } /** * This is a slight variation of * {@link #copyChunk(GUID, InputStream, OutputStream)}, it only handles file * property chunks correctly.
    * The copied chunk will have the file size field modified by the given * fileSizeDiff value. * * @param source * source of file properties chunk, located at its chunk length * field. * @param destination * the destination to copy the chunk to. * @param fileSizeDiff * the difference which should be applied. (negative values would * subtract the stored file size) * @throws IOException * on I/O errors. */ private void modifyFileHeader(final InputStream source, final OutputStream destination, final long fileSizeDiff) throws IOException { destination.write(GUID.GUID_FILE.getBytes()); final long chunkSize = Utils.readUINT64(source); Utils.writeUINT64(chunkSize, destination); destination.write(Utils.readGUID(source).getBytes()); final long fileSize = Utils.readUINT64(source); Utils.writeUINT64(fileSize + fileSizeDiff, destination); Utils.copy(source, destination, chunkSize - 48); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/asf/io/AsfHeaderReader.java0000644000175000017500000002122411222471043027574 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2004-2005 Christian Laireiter * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.audio.asf.io; import org.jaudiotagger.audio.asf.data.AsfHeader; import org.jaudiotagger.audio.asf.data.GUID; import org.jaudiotagger.audio.asf.util.Utils; import java.io.*; import java.math.BigInteger; import java.util.ArrayList; import java.util.List; /** * This class reads an ASF header out of an input stream an creates an * {@link org.jaudiotagger.audio.asf.data.AsfHeader} object if successful.
    * For now only ASF ver 1.0 is supported, because ver 2.0 seems not to be used * anywhere.
    * ASF headers contains other chunks. As of this other readers of current * package are called from within. * * @author Christian Laireiter */ public class AsfHeaderReader extends ChunkContainerReader { /** * The GUID this reader {@linkplain #getApplyingIds() applies to} */ private final static GUID[] APPLYING = { GUID.GUID_HEADER }; /** * ASF reader configured to extract all information. */ private final static AsfHeaderReader FULL_READER; /** * ASF reader configured to just extract information about audio streams.
    * If the ASF file only contains one audio stream it works fine.
    */ private final static AsfHeaderReader INFO_READER; /** * ASF reader configured to just extract metadata information.
    */ private final static AsfHeaderReader TAG_READER; static { final List> readers = new ArrayList>(); readers.add(FileHeaderReader.class); readers.add(StreamChunkReader.class); INFO_READER = new AsfHeaderReader(readers, true); readers.clear(); readers.add(ContentDescriptionReader.class); readers.add(ContentBrandingReader.class); readers.add(LanguageListReader.class); readers.add(MetadataReader.class); /* * Create the header extension object readers with just content * description reader, extended content description reader, language * list reader and both metadata object readers. */ final AsfExtHeaderReader extReader = new AsfExtHeaderReader(readers, true); final AsfExtHeaderReader extReader2 = new AsfExtHeaderReader(readers, true); TAG_READER = new AsfHeaderReader(readers, true); TAG_READER.setExtendedHeaderReader(extReader); readers.add(FileHeaderReader.class); readers.add(StreamChunkReader.class); readers.add(EncodingChunkReader.class); readers.add(EncryptionChunkReader.class); readers.add(StreamBitratePropertiesReader.class); FULL_READER = new AsfHeaderReader(readers, false); FULL_READER.setExtendedHeaderReader(extReader2); } /** * Creates a Stream that will read from the specified * {@link RandomAccessFile};
    * * @param raf * data source to read from. * @return a stream which accesses the source. */ private static InputStream createStream(final RandomAccessFile raf) { return new FullRequestInputStream(new BufferedInputStream( new RandomAccessFileInputstream(raf))); } /** * This method extracts the full ASF-Header from the given file.
    * If no header could be extracted null is returned.
    * * @param file * the ASF file to read.
    * @return AsfHeader-Wrapper, or null if no supported ASF * header was found. * @throws IOException * on I/O Errors. */ public static AsfHeader readHeader(final File file) throws IOException { final InputStream stream = new FileInputStream(file); final AsfHeader result = FULL_READER.read(Utils.readGUID(stream), stream, 0); stream.close(); return result; } /** * This method tries to extract a full ASF-header out of the given stream.
    * If no header could be extracted null is returned.
    * * @param file * File which contains the ASF header. * @return AsfHeader-Wrapper, or null if no supported ASF * header was found. * @throws IOException * Read errors */ public static AsfHeader readHeader(final RandomAccessFile file) throws IOException { final InputStream stream = createStream(file); return FULL_READER.read(Utils.readGUID(stream), stream, 0); } /** * This method tries to extract an ASF-header out of the given stream, which * only contains information about the audio stream.
    * If no header could be extracted null is returned.
    * * @param file * File which contains the ASF header. * @return AsfHeader-Wrapper, or null if no supported ASF * header was found. * @throws IOException * Read errors */ public static AsfHeader readInfoHeader(final RandomAccessFile file) throws IOException { final InputStream stream = createStream(file); return INFO_READER.read(Utils.readGUID(stream), stream, 0); } /** * This method tries to extract an ASF-header out of the given stream, which * only contains metadata.
    * If no header could be extracted null is returned.
    * * @param file * File which contains the ASF header. * @return AsfHeader-Wrapper, or null if no supported ASF * header was found. * @throws IOException * Read errors */ public static AsfHeader readTagHeader(final RandomAccessFile file) throws IOException { final InputStream stream = createStream(file); return TAG_READER.read(Utils.readGUID(stream), stream, 0); } /** * Creates an instance of this reader. * * @param toRegister * The chunk readers to utilize. * * @param readChunkOnce * if true, each chunk type (identified by chunk * GUID) will handled only once, if a reader is available, other * chunks will be discarded. */ public AsfHeaderReader(final List> toRegister, final boolean readChunkOnce) { super(toRegister, readChunkOnce); } /** * {@inheritDoc} */ public boolean canFail() { return false; } /** * {@inheritDoc} */ @Override protected AsfHeader createContainer(final long streamPosition, final BigInteger chunkLength, final InputStream stream) throws IOException { final long chunkCount = Utils.readUINT32(stream); /* * 2 reserved bytes. first should be equal to 0x01 and second 0x02. ASF * specification suggests to not read the content if second byte is not * 0x02. */ if (stream.read() != 1) { throw new IOException("No ASF"); //$NON-NLS-1$ } if (stream.read() != 2) { throw new IOException("No ASF"); //$NON-NLS-1$ } /* * Creating the resulting object */ return new AsfHeader(streamPosition, chunkLength, chunkCount); } /** * {@inheritDoc} */ public GUID[] getApplyingIds() { return APPLYING.clone(); } /** * Sets the {@link AsfExtHeaderReader}, which is to be used, when an header * extension object is found. * * @param extReader * header extension object reader. */ public void setExtendedHeaderReader(final AsfExtHeaderReader extReader) { for (final GUID curr : extReader.getApplyingIds()) { this.readerMap.put(curr, extReader); } } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/asf/io/WriteableChunkModifer.java0000644000175000017500000000440411222471043031045 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.asf.io; import org.jaudiotagger.audio.asf.data.GUID; import org.jaudiotagger.audio.asf.util.Utils; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; /** * A chunk modifier which works with information provided by * {@link WriteableChunk} objects.
    * * @author Christian Laireiter */ public class WriteableChunkModifer implements ChunkModifier { /** * The chunk to write. */ private final WriteableChunk writableChunk; /** * Creates an instance.
    * * @param chunk * chunk to write */ public WriteableChunkModifer(final WriteableChunk chunk) { this.writableChunk = chunk; } /** * {@inheritDoc} */ public boolean isApplicable(final GUID guid) { return guid.equals(this.writableChunk.getGuid()); } /** * {@inheritDoc} */ public ModificationResult modify(final GUID guid, final InputStream chunk, OutputStream destination) throws IOException { // NOPMD by Christian Laireiter on 5/9/09 5:03 PM int chunkDiff = 0; long newSize = 0; long oldSize = 0; /* * Replace the outputstream with the counting one, only if assert's are * evaluated. */ assert (destination = new CountingOutputstream(destination)) != null; if (!this.writableChunk.isEmpty()) { newSize = this.writableChunk.writeInto(destination); assert newSize == this.writableChunk.getCurrentAsfChunkSize(); /* * If assert's are evaluated, we have replaced destination by a * CountingOutpustream and can now verify if * getCurrentAsfChunkSize() really works correctly. */ assert ((CountingOutputstream) destination).getCount() == newSize; if (guid == null) { chunkDiff++; } } if (guid != null) { assert isApplicable(guid); if (this.writableChunk.isEmpty()) { chunkDiff--; } oldSize = Utils.readUINT64(chunk); chunk.skip(oldSize - 24); } return new ModificationResult(chunkDiff, (newSize - oldSize), guid); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/asf/io/RandomAccessFileOutputStream.java0000644000175000017500000000200211222471043032357 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.asf.io; import java.io.IOException; import java.io.OutputStream; import java.io.RandomAccessFile; /** * Wraps a {@link RandomAccessFile} into an {@link OutputStream}.
    * * @author Christian Laireiter */ public final class RandomAccessFileOutputStream extends OutputStream { /** * the file to write to. */ private final RandomAccessFile targetFile; /** * Creates an instance.
    * * @param target * file to write to. */ public RandomAccessFileOutputStream(final RandomAccessFile target) { super(); this.targetFile = target; } /** * {@inheritDoc} */ @Override public void write(final byte[] bytes, final int off, final int len) throws IOException { this.targetFile.write(bytes, off, len); } /** * {@inheritDoc} */ @Override public void write(final int toWrite) throws IOException { this.targetFile.write(toWrite); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/asf/io/CountingOutputstream.java0000644000175000017500000000356111222471043031056 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.asf.io; import java.io.IOException; import java.io.OutputStream; /** * This output stream wraps around another {@link OutputStream} and delegates * the write calls.
    * Additionally all written bytes are counted and available by * {@link #getCount()}. * * @author Christian Laireiter */ public class CountingOutputstream extends OutputStream { /** * Stores the amount of bytes written. */ private long count = 0; /** * The stream to forward the write calls. */ private final OutputStream wrapped; /** * Creates an instance which will delegate the write calls to the given * output stream. * * @param outputStream * stream to wrap. */ public CountingOutputstream(final OutputStream outputStream) { super(); assert outputStream != null; this.wrapped = outputStream; } /** * {@inheritDoc} */ @Override public void close() throws IOException { this.wrapped.close(); } /** * {@inheritDoc} */ @Override public void flush() throws IOException { this.wrapped.flush(); } /** * @return the count */ public long getCount() { return this.count; } /** * {@inheritDoc} */ @Override public void write(final byte[] bytes) throws IOException { this.wrapped.write(bytes); this.count += bytes.length; } /** * {@inheritDoc} */ @Override public void write(final byte[] bytes, final int off, final int len) throws IOException { this.wrapped.write(bytes, off, len); this.count += len; } /** * {@inheritDoc} */ @Override public void write(final int toWrite) throws IOException { this.wrapped.write(toWrite); this.count++; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/asf/AsfFileReader.java0000644000175000017500000002423611277264361026677 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2004-2005 Christian Laireiter * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.audio.asf; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.asf.data.AsfHeader; import org.jaudiotagger.audio.asf.data.AudioStreamChunk; import org.jaudiotagger.audio.asf.data.MetadataContainer; import org.jaudiotagger.audio.asf.data.MetadataDescriptor; import org.jaudiotagger.audio.asf.io.*; import org.jaudiotagger.tag.asf.AsfTag; import org.jaudiotagger.audio.asf.util.TagConverter; import org.jaudiotagger.audio.asf.util.Utils; import org.jaudiotagger.audio.exceptions.CannotReadException; import org.jaudiotagger.audio.exceptions.InvalidAudioFrameException; import org.jaudiotagger.audio.exceptions.ReadOnlyFileException; import org.jaudiotagger.audio.generic.AudioFileReader; import org.jaudiotagger.audio.generic.GenericAudioHeader; import org.jaudiotagger.logging.ErrorMessage; import org.jaudiotagger.tag.TagException; import java.io.*; import java.util.ArrayList; import java.util.List; import java.util.logging.Logger; /** * This reader can read ASF files containing any content (stream type).
    * * @author Christian Laireiter */ public class AsfFileReader extends AudioFileReader { /** * Logger instance */ private final static Logger LOGGER = Logger .getLogger("org.jaudiotagger.audio.asf"); /** * This reader will be configured to read tag and audio header information.
    */ private final static AsfHeaderReader HEADER_READER; static { final List> readers = new ArrayList>(); readers.add(ContentDescriptionReader.class); readers.add(ContentBrandingReader.class); readers.add(MetadataReader.class); readers.add(LanguageListReader.class); // Create the header extension object reader with just content // description reader as well // as extended content description reader. final AsfExtHeaderReader extReader = new AsfExtHeaderReader(readers, true); readers.add(FileHeaderReader.class); readers.add(StreamChunkReader.class); HEADER_READER = new AsfHeaderReader(readers, true); HEADER_READER.setExtendedHeaderReader(extReader); } /** * Determines if the "isVbr" field is set in the extended content * description.
    * * @param header * the header to look up. * @return true if "isVbr" is present with a * true value. */ private boolean determineVariableBitrate(final AsfHeader header) { assert header != null; boolean result = false; final MetadataContainer extDesc = header .findExtendedContentDescription(); if (extDesc != null) { final List descriptors = extDesc .getDescriptorsByName("IsVBR"); if (descriptors != null && !descriptors.isEmpty()) { result = Boolean.TRUE.toString().equals( descriptors.get(0).getString()); } } return result; } /** * Creates a generic audio header instance with provided data from header. * * @param header * ASF header which contains the information. * @return generic audio header representation. * @throws CannotReadException * If header does not contain mandatory information. (Audio * stream chunk and file header chunk) */ private GenericAudioHeader getAudioHeader(final AsfHeader header) throws CannotReadException { final GenericAudioHeader info = new GenericAudioHeader(); if (header.getFileHeader() == null) { throw new CannotReadException( "Invalid ASF/WMA file. File header object not available."); } if (header.getAudioStreamChunk() == null) { throw new CannotReadException( "Invalid ASF/WMA file. No audio stream contained."); } info.setBitrate(header.getAudioStreamChunk().getKbps()); info.setChannelNumber((int) header.getAudioStreamChunk() .getChannelCount()); info.setEncodingType("ASF (audio): " + header.getAudioStreamChunk().getCodecDescription()); info .setLossless(header.getAudioStreamChunk() .getCompressionFormat() == AudioStreamChunk.WMA_LOSSLESS); info.setPreciseLength(header.getFileHeader().getPreciseDuration()); info.setSamplingRate((int) header.getAudioStreamChunk() .getSamplingRate()); info.setVariableBitRate(determineVariableBitrate(header)); return info; } /** * (overridden) * * @see org.jaudiotagger.audio.generic.AudioFileReader#getEncodingInfo(java.io.RandomAccessFile) */ @Override protected GenericAudioHeader getEncodingInfo(final RandomAccessFile raf) throws CannotReadException, IOException { raf.seek(0); GenericAudioHeader info; try { final AsfHeader header = AsfHeaderReader.readInfoHeader(raf); if (header == null) { throw new CannotReadException( "Some values must have been " + "incorrect for interpretation as asf with wma content."); } info = getAudioHeader(header); } catch (final Exception e) { if (e instanceof IOException) { throw (IOException) e; } else if (e instanceof CannotReadException) { throw (CannotReadException) e; } else { throw new CannotReadException("Failed to read. Cause: " + e.getMessage(), e); } } return info; } /** * Creates a tag instance with provided data from header. * * @param header * ASF header which contains the information. * @return generic audio header representation. */ private AsfTag getTag(final AsfHeader header) { return TagConverter.createTagOf(header); } /** * (overridden) * * @see org.jaudiotagger.audio.generic.AudioFileReader#getTag(java.io.RandomAccessFile) */ @Override protected AsfTag getTag(final RandomAccessFile raf) throws CannotReadException, IOException { raf.seek(0); AsfTag tag; try { final AsfHeader header = AsfHeaderReader.readTagHeader(raf); if (header == null) { throw new CannotReadException( "Some values must have been " + "incorrect for interpretation as asf with wma content."); } tag = TagConverter.createTagOf(header); } catch (final Exception e) { logger.severe(e.getMessage()); if (e instanceof IOException) { throw (IOException) e; } else if (e instanceof CannotReadException) { throw (CannotReadException) e; } else { throw new CannotReadException("Failed to read. Cause: " + e.getMessage()); } } return tag; } /** * {@inheritDoc} */ @Override public AudioFile read(final File f) throws CannotReadException, IOException, TagException, ReadOnlyFileException, InvalidAudioFrameException { if (!f.canRead()) { throw new CannotReadException( ErrorMessage.GENERAL_READ_FAILED_DO_NOT_HAVE_PERMISSION_TO_READ_FILE .getMsg(f.getAbsolutePath())); } InputStream stream = null; try { stream = new FullRequestInputStream(new BufferedInputStream( new FileInputStream(f))); final AsfHeader header = HEADER_READER.read(Utils.readGUID(stream), stream, 0); if (header == null) { throw new CannotReadException(ErrorMessage.ASF_HEADER_MISSING .getMsg(f.getAbsolutePath())); } if (header.getFileHeader() == null) { throw new CannotReadException( ErrorMessage.ASF_FILE_HEADER_MISSING.getMsg(f .getAbsolutePath())); } // Just log a warning because file seems to play okay if (header.getFileHeader().getFileSize().longValue() != f.length()) { logger .warning(ErrorMessage.ASF_FILE_HEADER_SIZE_DOES_NOT_MATCH_FILE_SIZE .getMsg(f.getAbsolutePath(), header .getFileHeader().getFileSize() .longValue(), f.length())); } return new AudioFile(f, getAudioHeader(header), getTag(header)); } catch (final CannotReadException e) { throw e; } catch (final Exception e) { throw new CannotReadException("\"" + f + "\" :" + e, e); } finally { try { if (stream != null) { stream.close(); } } catch (final Exception ex) { LOGGER.severe("\"" + f + "\" :" + ex); } } } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/asf/util/0000755000175000017500000000000011556363171024345 5ustar drazzibdrazziblibjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/asf/util/Utils.java0000644000175000017500000004451011305747025026310 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2004-2005 Christian Laireiter * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.audio.asf.util; import org.jaudiotagger.audio.asf.data.AsfHeader; import org.jaudiotagger.audio.asf.data.GUID; import org.jaudiotagger.logging.ErrorMessage; import java.io.EOFException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.math.BigInteger; import java.nio.ByteBuffer; import java.nio.charset.Charset; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; /** * Some static Methods which are used in several Classes.
    * * @author Christian Laireiter */ public class Utils { public static final long DIFF_BETWEEN_ASF_DATE_AND_JAVA_DATE = 11644470000000l; /** * Stores the default line separator of the current underlying system. */ public final static String LINE_SEPARATOR = System .getProperty("line.separator"); //$NON-NLS-1$ /** * */ private static final int MAXIMUM_STRING_LENGTH_ALLOWED = 32766; /** * This method checks given string will not exceed limit in bytes[] when * converted UTF-16LE encoding (2 bytes per character) and checks whether * the length doesn't exceed 65535 bytes.
    * * @param value * The string to check. * @throws IllegalArgumentException * If byte representation takes more than 65535 bytes. */ public static void checkStringLengthNullSafe(String value) throws IllegalArgumentException { if (value != null) { if (value.length() > MAXIMUM_STRING_LENGTH_ALLOWED) { throw new IllegalArgumentException( ErrorMessage.WMA_LENGTH_OF_STRING_IS_TOO_LARGE .getMsg((value.length() * 2))); } } } /** * * @param value String to check for null * @return true unless string is too long */ public static boolean isStringLengthValidNullSafe(String value) { if (value != null) { if (value.length() > MAXIMUM_STRING_LENGTH_ALLOWED) { return false; } } return true; } /** * effectively copies a specified amount of bytes from one stream to * another. * * @param source * stream to read from * @param dest * stream to write to * @param amount * amount of bytes to copy * @throws IOException * on I/O errors, and if the source stream depletes before all * bytes have been copied. */ public static void copy(InputStream source, OutputStream dest, long amount) throws IOException { byte[] buf = new byte[8192]; long copied = 0; while (copied < amount) { int toRead = 8192; if ((amount - copied) < 8192) { toRead = (int) (amount - copied); } int read = source.read(buf, 0, toRead); if (read == -1) { throw new IOException( "Inputstream has to continue for another " + (amount - copied) + " bytes."); } dest.write(buf, 0, read); copied += read; } } /** * Copies all of the source to the destination.
    * * @param source * source to read from * @param dest * stream to write to * @throws IOException * on I/O errors. */ public static void flush(final InputStream source, final OutputStream dest) throws IOException { final byte[] buf = new byte[8192]; int read; while ((read = source.read(buf)) != -1) { dest.write(buf, 0, read); } } /** * This method will create a byte[] at the size of byteCount * and insert the bytes of value (starting from lowset byte) * into it.
    * You can easily create a Word (16-bit), DWORD (32-bit), QWORD (64 bit) out * of the value, ignoring the original type of value, since java * automatically performs transformations.
    * Warning: This method works with unsigned numbers only. * * @param value * The value to be written into the result. * @param byteCount * The number of bytes the array has got. * @return A byte[] with the size of byteCount containing the * lower byte values of value. */ public static byte[] getBytes(final long value, final int byteCount) { byte[] result = new byte[byteCount]; for (int i = 0; i < result.length; i ++) { result[i] = (byte) ((value >>> (i*8)) & 0xFF); } return result; } /** * Convenience method to convert the given string into a byte sequence which * has the format of the charset given. * * @param source * string to convert. * @param charset * charset to apply * @return the source's binary representation according to the charset. */ public static byte[] getBytes(final String source, final Charset charset) { assert charset != null; assert source != null; final ByteBuffer encoded = charset.encode(source); final byte[] result = new byte[encoded.limit()]; encoded.rewind(); encoded.get(result); return result; } /** * Since date values in ASF files are given in 100 ns steps since first * january of 1601 a little conversion must be done.
    * This method converts a date given in described manner to a calendar. * * @param fileTime * Time in 100ns since 1 jan 1601 * @return Calendar holding the date representation. */ /* Old method that ran very slowely and doesnt logical correct, how does dividing something at 10-4 by 10,000 convert it to 10 -3 public static GregorianCalendar getDateOf(final BigInteger fileTime) { final GregorianCalendar result = new GregorianCalendar(1601, 0, 1); // lose anything beyond milliseconds, because calendar can't handle // less value BigInteger time = fileTime.divide(new BigInteger("10000")); //$NON-NLS-1$ final BigInteger maxInt = new BigInteger(String .valueOf(Integer.MAX_VALUE)); while (time.compareTo(maxInt) > 0) { result.add(Calendar.MILLISECOND, Integer.MAX_VALUE); time = time.subtract(maxInt); } result.add(Calendar.MILLISECOND, time.intValue()); return result; } */ /** * Date values in ASF files are given in 100 ns (10 exp -4) steps since first * * @param fileTime * Time in 100ns since 1 jan 1601 * @return Calendar holding the date representation. */ public static GregorianCalendar getDateOf(final BigInteger fileTime) { final GregorianCalendar result = new GregorianCalendar(); // Divide by 10 to convert from -4 to -3 (millisecs) BigInteger time = fileTime.divide(new BigInteger("10")); // Construct Date taking into the diff between 1601 and 1970 Date date = new Date(time.longValue() - DIFF_BETWEEN_ASF_DATE_AND_JAVA_DATE); result.setTime(date); return result; } /** * Tests if the given string is null or just contains * whitespace characters. * * @param toTest * String to test. * @return see description. */ public static boolean isBlank(String toTest) { if (toTest == null) { return true; } for (int i = 0; i < toTest.length(); i++) { if(!Character.isWhitespace(toTest.charAt(i))) { return false; } } return true; } /** * Reads 8 bytes from stream and interprets them as a UINT64 which is * returned as {@link BigInteger}.
    * * @param stream * stream to readm from. * @return a BigInteger which represents the read 8 bytes value. * @throws IOException if problem reading bytes */ public static BigInteger readBig64(InputStream stream) throws IOException { byte[] bytes = new byte[8]; byte[] oa = new byte[8]; int read = stream.read(bytes); if (read != 8) { // 8 bytes mandatory. throw new EOFException(); } for (int i = 0; i < bytes.length; i++) { oa[7 - i] = bytes[i]; } return new BigInteger(oa); } /** * Reads size bytes from the stream.
    * * @param stream * stream to read from. * @param size * amount of bytes to read. * @return the read bytes. * @throws IOException * on I/O errors. */ public static byte[] readBinary(InputStream stream, long size) throws IOException { byte[] result = new byte[(int) size]; stream.read(result); return result; } /** * This method reads a UTF-16 String, which length is given on the number of * characters it consists of.
    * The stream must be at the number of characters. This number contains the * terminating zero character (UINT16). * * @param stream * Input source * @return String * @throws IOException * read errors */ public static String readCharacterSizedString(InputStream stream) throws IOException { StringBuilder result = new StringBuilder(); int strLen = readUINT16(stream); int character = stream.read(); character |= stream.read() << 8; do { if (character != 0) { result.append((char) character); character = stream.read(); character |= stream.read() << 8; } } while (character != 0 || (result.length() + 1) > strLen); if (strLen != (result.length() + 1)) { throw new IllegalStateException( "Invalid Data for current interpretation"); //$NON-NLS-1$ } return result.toString(); } /** * This method reads a UTF-16 encoded String.
    * For the use this method the number of bytes used by current string must * be known.
    * The ASF specification recommends that those strings end with a * terminating zero. However it also says that it is not always the case. * * @param stream * Input source * @param strLen * Number of bytes the String may take. * @return read String. * @throws IOException * read errors. */ public static String readFixedSizeUTF16Str(InputStream stream, int strLen) throws IOException { byte[] strBytes = new byte[strLen]; int read = stream.read(strBytes); if (read == strBytes.length) { if (strBytes.length >= 2) { /* * Zero termination is recommended but optional. So check and * if, remove. */ if (strBytes[strBytes.length - 1] == 0 && strBytes[strBytes.length - 2] == 0) { byte[] copy = new byte[strBytes.length - 2]; System.arraycopy(strBytes, 0, copy, 0, strBytes.length - 2); strBytes = copy; } } return new String(strBytes, "UTF-16LE"); } throw new IllegalStateException( "Couldn't read the necessary amount of bytes."); } /** * This Method reads a GUID (which is a 16 byte long sequence) from the * given raf and creates a wrapper.
    * Warning :
    * There is no way of telling if a byte sequence is a guid or not. The next * 16 bytes will be interpreted as a guid, whether it is or not. * * @param stream * Input source. * @return A class wrapping the guid. * @throws IOException * happens when the file ends before guid could be extracted. */ public static GUID readGUID(InputStream stream) throws IOException { if (stream == null) { throw new IllegalArgumentException("Argument must not be null"); //$NON-NLS-1$ } int[] binaryGuid = new int[GUID.GUID_LENGTH]; for (int i = 0; i < binaryGuid.length; i++) { binaryGuid[i] = stream.read(); } return new GUID(binaryGuid); } /** * Reads 2 bytes from stream and interprets them as UINT16.
    * * @param stream * stream to read from. * @return UINT16 value * @throws IOException * on I/O Errors. */ public static int readUINT16(InputStream stream) throws IOException { int result = stream.read(); result |= stream.read() << 8; return result; } /** * Reads 4 bytes from stream and interprets them as UINT32.
    * * @param stream * stream to read from. * @return UINT32 value * @throws IOException * on I/O Errors. */ public static long readUINT32(InputStream stream) throws IOException { long result = 0; for (int i = 0; i <= 24; i += 8) { // Warning, always cast to long here. Otherwise it will be // shifted as int, which may produce a negative value, which will // then be extended to long and assign the long variable a negative // value. result |= (long) stream.read() << i; } return result; } /** * Reads long as little endian. * * @param stream * Data source * @return long value * @throws IOException * read error, or eof is reached before long is completed */ public static long readUINT64(InputStream stream) throws IOException { long result = 0; for (int i = 0; i <= 56; i += 8) { // Warning, always cast to long here. Otherwise it will be // shifted as int, which may produce a negative value, which will // then be extended to long and assign the long variable a negative // value. result |= (long) stream.read() << i; } return result; } /** * This method reads a UTF-16 encoded String, beginning with a 16-bit value * representing the number of bytes needed. The String is terminated with as * 16-bit ZERO.
    * * @param stream * Input source * @return read String. * @throws IOException * read errors. */ public static String readUTF16LEStr(InputStream stream) throws IOException { int strLen = readUINT16(stream); byte[] buf = new byte[strLen]; int read = stream.read(buf); if (read == strLen || (strLen == 0 && read == -1)) { /* * Check on zero termination */ if (buf.length >= 2) { if (buf[buf.length - 1] == 0 && buf[buf.length - 2] == 0) { byte[] copy = new byte[buf.length - 2]; System.arraycopy(buf, 0, copy, 0, buf.length - 2); buf = copy; } } return new String(buf, AsfHeader.ASF_CHARSET.name()); } throw new IllegalStateException( "Invalid Data for current interpretation"); //$NON-NLS-1$ } /** * Writes the given value as UINT16 into the stream. * * @param number * value to write. * @param out * stream to write into. * @throws IOException * On I/O errors */ public static void writeUINT16(int number, OutputStream out) throws IOException { if (number < 0) { throw new IllegalArgumentException("positive value expected."); //$NON-NLS-1$ } byte[] toWrite = new byte[2]; for (int i = 0; i <= 8; i += 8) { toWrite[i / 8] = (byte) ((number >> i) & 0xFF); } out.write(toWrite); } /** * Writes the given value as UINT32 into the stream. * * @param number * value to write. * @param out * stream to write into. * @throws IOException * On I/O errors */ public static void writeUINT32(long number, OutputStream out) throws IOException { if (number < 0) { throw new IllegalArgumentException("positive value expected."); //$NON-NLS-1$ } byte[] toWrite = new byte[4]; for (int i = 0; i <= 24; i += 8) { toWrite[i / 8] = (byte) ((number >> i) & 0xFF); } out.write(toWrite); } /** * Writes the given value as UINT64 into the stream. * * @param number * value to write. * @param out * stream to write into. * @throws IOException * On I/O errors */ public static void writeUINT64(long number, OutputStream out) throws IOException { if (number < 0) { throw new IllegalArgumentException("positive value expected."); //$NON-NLS-1$ } byte[] toWrite = new byte[8]; for (int i = 0; i <= 56; i += 8) { toWrite[i / 8] = (byte) ((number >> i) & 0xFF); } out.write(toWrite); } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/asf/util/ChunkPositionComparator.java0000644000175000017500000000304111222471043032017 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2004-2005 Christian Laireiter * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.audio.asf.util; import org.jaudiotagger.audio.asf.data.Chunk; import java.io.Serializable; import java.util.Comparator; /** * This class is needed for ordering all types of * {@link org.jaudiotagger.audio.asf.data.Chunk}s ascending by their Position.
    * * @author Christian Laireiter */ public final class ChunkPositionComparator implements Comparator, Serializable { /** * */ private static final long serialVersionUID = -6337108235272376289L; /** * {@inheritDoc} */ public int compare(final Chunk first, final Chunk second) { return Long.valueOf(first.getPosition()) .compareTo(second.getPosition()); } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/asf/util/TagConverter.java0000644000175000017500000002030111277264361027610 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2004-2005 Christian Laireiter * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.audio.asf.util; import org.jaudiotagger.audio.asf.data.*; import org.jaudiotagger.tag.FieldKey; import org.jaudiotagger.tag.Tag; import org.jaudiotagger.tag.asf.*; import org.jaudiotagger.tag.reference.GenreTypes; import java.util.Iterator; import java.util.List; /** * This class provides functionality to convert * {@link org.jaudiotagger.audio.asf.data.AsfHeader}objects into * {@link org.jaudiotagger.tag.Tag}objects.
    * * @author Christian Laireiter (liree) */ public final class TagConverter { /** * This method assigns those tags of tag which are defined to * be common by jaudiotagger.
    * * @param tag * The tag from which the values are gathered.
    * Assigned values are:
    * @param description * The extended content description which should receive the * values.
    * Warning: the common values will be replaced. */ public static void assignCommonTagValues(Tag tag, MetadataContainer description) { assert description.getContainerType() == ContainerType.EXTENDED_CONTENT; MetadataDescriptor tmp; if (!Utils.isBlank(tag.getFirst(FieldKey.ALBUM))) { tmp = new MetadataDescriptor(description.getContainerType(), AsfFieldKey.ALBUM.getFieldName(), MetadataDescriptor.TYPE_STRING); tmp.setStringValue(tag.getFirst(FieldKey.ALBUM)); description.removeDescriptorsByName(tmp.getName()); description.addDescriptor(tmp); } else { description.removeDescriptorsByName(AsfFieldKey.ALBUM .getFieldName()); } if (!Utils.isBlank(tag.getFirst(FieldKey.TRACK))) { tmp = new MetadataDescriptor(description.getContainerType(), AsfFieldKey.TRACK.getFieldName(), MetadataDescriptor.TYPE_STRING); tmp.setStringValue(tag.getFirst(FieldKey.TRACK)); description.removeDescriptorsByName(tmp.getName()); description.addDescriptor(tmp); } else { description.removeDescriptorsByName(AsfFieldKey.TRACK .getFieldName()); } if (!Utils.isBlank(tag.getFirst(FieldKey.YEAR))) { tmp = new MetadataDescriptor(description.getContainerType(), AsfFieldKey.YEAR.getFieldName(), MetadataDescriptor.TYPE_STRING); tmp.setStringValue(tag.getFirst(FieldKey.YEAR)); description.removeDescriptorsByName(tmp.getName()); description.addDescriptor(tmp); } else { description .removeDescriptorsByName(AsfFieldKey.YEAR.getFieldName()); } if (!Utils.isBlank(tag.getFirst(FieldKey.GENRE))) { // Write Genre String value tmp = new MetadataDescriptor(description.getContainerType(), AsfFieldKey.GENRE.getFieldName(), MetadataDescriptor.TYPE_STRING); tmp.setStringValue(tag.getFirst(FieldKey.GENRE)); description.removeDescriptorsByName(tmp.getName()); description.addDescriptor(tmp); Integer genreNum = GenreTypes.getInstanceOf().getIdForName( tag.getFirst(FieldKey.GENRE)); // ..and if it is one of the standard genre types used the id as // well if (genreNum != null) { tmp = new MetadataDescriptor(description.getContainerType(), AsfFieldKey.GENRE_ID.getFieldName(), MetadataDescriptor.TYPE_STRING); tmp.setStringValue("(" + genreNum + ")"); description.removeDescriptorsByName(tmp.getName()); description.addDescriptor(tmp); } else { description.removeDescriptorsByName(AsfFieldKey.GENRE_ID .getFieldName()); } } else { description.removeDescriptorsByName(AsfFieldKey.GENRE .getFieldName()); description.removeDescriptorsByName(AsfFieldKey.GENRE_ID .getFieldName()); } } /** * This method creates a {@link Tag}and fills it with the contents of the * given {@link AsfHeader}.
    * * @param source * The ASF header which contains the information.
    * @return A Tag with all its values. */ public static AsfTag createTagOf(AsfHeader source) { // TODO do we need to copy here. AsfTag result = new AsfTag(true); for (int i = 0; i < ContainerType.values().length; i++) { MetadataContainer current = source .findMetadataContainer(ContainerType.values()[i]); if (current != null) { List descriptors = current.getDescriptors(); for (MetadataDescriptor descriptor : descriptors) { AsfTagField toAdd; if (descriptor.getType() == MetadataDescriptor.TYPE_BINARY) { if (descriptor.getName().equals( AsfFieldKey.COVER_ART.getFieldName())) { toAdd = new AsfTagCoverField(descriptor); } else if (descriptor.getName().equals( AsfFieldKey.BANNER_IMAGE.getFieldName())) { toAdd = new AsfTagBannerField(descriptor); } else { toAdd = new AsfTagField(descriptor); } } else { toAdd = new AsfTagTextField(descriptor); } result.addField(toAdd); } } } return result; } /** * This method distributes the tags fields among the * {@linkplain ContainerType#getOrdered()} {@linkplain MetadataContainer * containers}. * * @param tag * the tag with the fields to distribute. * @return distribution */ public static MetadataContainer[] distributeMetadata(final AsfTag tag) { final Iterator asfFields = tag.getAsfFields(); final MetadataContainer[] createContainers = MetadataContainerFactory .getInstance().createContainers(ContainerType.getOrdered()); boolean assigned; AsfTagField current; while (asfFields.hasNext()) { current = asfFields.next(); assigned = false; for (int i = 0; !assigned && i < createContainers.length; i++) { if (ContainerType.areInCorrectOrder(createContainers[i] .getContainerType(), AsfFieldKey.getAsfFieldKey( current.getId()).getHighestContainer())) { if (createContainers[i].isAddSupported(current .getDescriptor())) { createContainers[i].addDescriptor(current .getDescriptor()); assigned = true; } } } assert assigned; } return createContainers; } /** * Hidden utility class constructor. */ private TagConverter() { // Nothing to do. } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/generic/0000755000175000017500000000000011556363172024234 5ustar drazzibdrazziblibjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/generic/AudioFileWriter.java0000644000175000017500000005526711470746136030154 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2003-2005 Raphaël Slinckx * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.audio.generic; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.exceptions.CannotReadException; import org.jaudiotagger.audio.exceptions.CannotWriteException; import org.jaudiotagger.audio.exceptions.ModifyVetoException; import org.jaudiotagger.audio.mp3.MP3File; import org.jaudiotagger.logging.ErrorMessage; import org.jaudiotagger.tag.Tag; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; import java.util.logging.Level; import java.util.logging.Logger; /** * This abstract class is the skeleton for tag writers. *

    *

    * It handles the creation/closing of the randomaccessfile objects and then call * the subclass method writeTag or deleteTag. These two method have to be * implemented in the subclass. * * @author Raphael Slinckx * @version $Id: AudioFileWriter.java,v 1.21 2009/05/05 15:59:14 paultaylor Exp * $ * @since v0.02 */ public abstract class AudioFileWriter { private static final String TEMP_FILENAME_SUFFIX = ".tmp"; private static final String WRITE_MODE = "rws"; private static final int MINIMUM_FILESIZE = 150; // Logger Object public static Logger logger = Logger .getLogger("org.jaudiotagger.audio.generic"); /** * If not null, this listener is used to notify the listener * about modification events.
    */ private AudioFileModificationListener modificationListener = null; /** * Delete the tag (if any) present in the given file * * @param af The file to process * @throws CannotWriteException if anything went wrong * @throws org.jaudiotagger.audio.exceptions.CannotReadException */ public synchronized void delete(AudioFile af) throws CannotReadException, CannotWriteException { if (!af.getFile().canWrite()) { throw new CannotWriteException(ErrorMessage.GENERAL_DELETE_FAILED .getMsg(af.getFile().getPath())); } if (af.getFile().length() <= MINIMUM_FILESIZE) { throw new CannotWriteException(ErrorMessage.GENERAL_DELETE_FAILED .getMsg(af.getFile().getPath())); } RandomAccessFile raf = null; RandomAccessFile rafTemp = null; File tempF = null; // Will be set to true on VetoException, causing the finally block to // discard the tempfile. boolean revert = false; try { tempF = File.createTempFile(af.getFile().getName() .replace('.', '_'), TEMP_FILENAME_SUFFIX, af.getFile() .getParentFile()); rafTemp = new RandomAccessFile(tempF, WRITE_MODE); raf = new RandomAccessFile(af.getFile(), WRITE_MODE); raf.seek(0); rafTemp.seek(0); try { if (this.modificationListener != null) { this.modificationListener.fileWillBeModified(af, true); } deleteTag(raf, rafTemp); if (this.modificationListener != null) { this.modificationListener.fileModified(af, tempF); } } catch (ModifyVetoException veto) { throw new CannotWriteException(veto); } } catch (Exception e) { revert = true; throw new CannotWriteException("\"" + af.getFile().getAbsolutePath() + "\" :" + e, e); } finally { // will be set to the remaining file. File result = af.getFile(); try { if (raf != null) { raf.close(); } if (rafTemp != null) { rafTemp.close(); } if (tempF.length() > 0 && !revert) { boolean deleteResult = af.getFile().delete(); if (!deleteResult) { logger .warning(ErrorMessage.GENERAL_WRITE_FAILED_TO_DELETE_ORIGINAL_FILE .getMsg(af.getFile().getPath(), tempF .getPath())); throw new CannotWriteException(ErrorMessage.GENERAL_WRITE_FAILED_TO_DELETE_ORIGINAL_FILE .getMsg(af.getFile().getPath(), tempF .getPath())); } boolean renameResult = tempF.renameTo(af.getFile()); if (!renameResult) { logger .warning(ErrorMessage.GENERAL_WRITE_FAILED_TO_RENAME_TO_ORIGINAL_FILE .getMsg(af.getFile().getPath(), tempF .getPath())); throw new CannotWriteException(ErrorMessage.GENERAL_WRITE_FAILED_TO_RENAME_TO_ORIGINAL_FILE .getMsg(af.getFile().getPath(), tempF .getPath())); } result = tempF; // If still exists we can now delete if (tempF.exists()) { if (!tempF.delete()) { // Non critical failed deletion logger .warning(ErrorMessage.GENERAL_WRITE_FAILED_TO_DELETE_TEMPORARY_FILE .getMsg(tempF.getPath())); } } } else { // It was created but never used if (!tempF.delete()) { // Non critical failed deletion logger .warning(ErrorMessage.GENERAL_WRITE_FAILED_TO_DELETE_TEMPORARY_FILE .getMsg(tempF.getPath())); } } } catch (Exception ex) { logger.severe("AudioFileWriter exception cleaning up delete:" + af.getFile().getPath() + " or" + tempF.getAbsolutePath() + ":" + ex); } // Notify listener if (this.modificationListener != null) { this.modificationListener.fileOperationFinished(result); } } } /** * Delete the tag (if any) present in the given randomaccessfile, and do not * close it at the end. * * @param raf The source file, already opened in r-write mode * @param tempRaf The temporary file opened in r-write mode * @throws CannotWriteException if anything went wrong * @throws org.jaudiotagger.audio.exceptions.CannotReadException * @throws java.io.IOException */ public synchronized void delete(RandomAccessFile raf, RandomAccessFile tempRaf) throws CannotReadException, CannotWriteException, IOException { raf.seek(0); tempRaf.seek(0); deleteTag(raf, tempRaf); } /** * Same as above, but delete tag in the file. * * @param raf * @param tempRaf * @throws IOException is thrown when the RandomAccessFile operations throw it (you * should never throw them manually) * @throws CannotWriteException when an error occured during the deletion of the tag * @throws org.jaudiotagger.audio.exceptions.CannotReadException */ protected abstract void deleteTag(RandomAccessFile raf, RandomAccessFile tempRaf) throws CannotReadException, CannotWriteException, IOException; /** * This method sets the {@link AudioFileModificationListener}.
    * There is only one listener allowed, if you want more instances to be * supported, use the {@link ModificationHandler} to broadcast those events.
    * * @param listener The listener. null allowed to deregister. */ public synchronized void setAudioFileModificationListener(AudioFileModificationListener listener) { this.modificationListener = listener; } /** * Prechecks before normal write *

    *

      *
    • If the tag is actually empty, remove the tag
    • *
    • if the file is not writable, throw exception *
    • *
    • If the file is too small to be a valid file, throw exception *
    • *
    * * @param af * @throws CannotWriteException */ private void precheckWrite(AudioFile af) throws CannotWriteException { // Preliminary checks try { if (af.getTag().isEmpty()) { delete(af); return; } } catch (CannotReadException re) { throw new CannotWriteException(ErrorMessage.GENERAL_WRITE_FAILED .getMsg(af.getFile().getPath())); } if (!af.getFile().canWrite()) { logger.severe(ErrorMessage.GENERAL_WRITE_FAILED.getMsg(af.getFile() .getPath())); throw new CannotWriteException(ErrorMessage.GENERAL_WRITE_FAILED .getMsg(af.getFile().getPath())); } if (af.getFile().length() <= MINIMUM_FILESIZE) { logger .severe(ErrorMessage.GENERAL_WRITE_FAILED_BECAUSE_FILE_IS_TOO_SMALL .getMsg(af.getFile().getPath())); throw new CannotWriteException(ErrorMessage.GENERAL_WRITE_FAILED_BECAUSE_FILE_IS_TOO_SMALL .getMsg(af.getFile().getPath())); } } /** * Write the tag (if not empty) present in the AudioFile in the associated * File * * @param af The file we want to process * @throws CannotWriteException if anything went wrong */ // TODO Creates temp file in same folder as the original file, this is safe // but would impose a performance overhead if the original file is on a networked drive public synchronized void write(AudioFile af) throws CannotWriteException { logger.info("Started writing tag data for file:" + af.getFile().getName()); // Prechecks precheckWrite(af); //mp3's use a different mechanism to the other formats if(af instanceof MP3File) { af.commit(); return; } RandomAccessFile raf = null; RandomAccessFile rafTemp = null; File newFile; File result; // Create temporary File try { newFile = File.createTempFile(af.getFile().getName().replace('.', '_'), TEMP_FILENAME_SUFFIX, af.getFile().getParentFile()); } // Unable to create temporary file, can happen in Vista if have Create // Files/Write Data set to Deny catch (IOException ioe) { logger .log(Level.SEVERE, ErrorMessage.GENERAL_WRITE_FAILED_TO_CREATE_TEMPORARY_FILE_IN_FOLDER .getMsg(af.getFile().getName(), af .getFile().getParentFile() .getAbsolutePath()), ioe); throw new CannotWriteException(ErrorMessage.GENERAL_WRITE_FAILED_TO_CREATE_TEMPORARY_FILE_IN_FOLDER .getMsg(af.getFile().getName(), af.getFile() .getParentFile().getAbsolutePath())); } // Open temporary file and actual file for editing try { rafTemp = new RandomAccessFile(newFile, WRITE_MODE); raf = new RandomAccessFile(af.getFile(), WRITE_MODE); } // Unable to write to writable file, can happen in Vista if have Create // Folders/Append Data set to Deny catch (IOException ioe) { logger.log(Level.SEVERE, ErrorMessage.GENERAL_WRITE_FAILED_TO_OPEN_FILE_FOR_EDITING .getMsg(af.getFile().getAbsolutePath()), ioe); // If we managed to open either file, delete it. try { if (raf != null) { raf.close(); } if (rafTemp != null) { rafTemp.close(); } } catch (IOException ioe2) { // Warn but assume has worked okay logger.log(Level.WARNING, ErrorMessage.GENERAL_WRITE_PROBLEM_CLOSING_FILE_HANDLE .getMsg(af.getFile(), ioe.getMessage()), ioe2); } // Delete the temp file ( we cannot delete until closed corresponding // rafTemp) if (!newFile.delete()) { // Non critical failed deletion logger .warning(ErrorMessage.GENERAL_WRITE_FAILED_TO_DELETE_TEMPORARY_FILE .getMsg(newFile.getAbsolutePath())); } throw new CannotWriteException(ErrorMessage.GENERAL_WRITE_FAILED_TO_OPEN_FILE_FOR_EDITING .getMsg(af.getFile().getAbsolutePath())); } // Write data to File try { raf.seek(0); rafTemp.seek(0); try { if (this.modificationListener != null) { this.modificationListener.fileWillBeModified(af, false); } writeTag(af.getTag(), raf, rafTemp); if (this.modificationListener != null) { this.modificationListener.fileModified(af, newFile); } } catch (ModifyVetoException veto) { throw new CannotWriteException(veto); } } catch (Exception e) { logger.log(Level.SEVERE, ErrorMessage.GENERAL_WRITE_FAILED_BECAUSE .getMsg(af.getFile(), e.getMessage()), e); try { if (raf != null) { raf.close(); } if (rafTemp != null) { rafTemp.close(); } } catch (IOException ioe) { // Warn but assume has worked okay logger.log(Level.WARNING, ErrorMessage.GENERAL_WRITE_PROBLEM_CLOSING_FILE_HANDLE .getMsg(af.getFile().getAbsolutePath(), ioe .getMessage()), ioe); } // Delete the temporary file because either it was never used so // lets just tidy up or we did start writing to it but // the write failed and we havent renamed it back to the original // file so we can just delete it. if (!newFile.delete()) { // Non critical failed deletion logger .warning(ErrorMessage.GENERAL_WRITE_FAILED_TO_DELETE_TEMPORARY_FILE .getMsg(newFile.getAbsolutePath())); } throw new CannotWriteException(ErrorMessage.GENERAL_WRITE_FAILED_BECAUSE.getMsg(af .getFile(), e.getMessage())); } finally { try { if (raf != null) { raf.close(); } if (rafTemp != null) { rafTemp.close(); } } catch (IOException ioe) { // Warn but assume has worked okay logger.log(Level.WARNING, ErrorMessage.GENERAL_WRITE_PROBLEM_CLOSING_FILE_HANDLE .getMsg(af.getFile().getAbsolutePath(), ioe .getMessage()), ioe); } } // Result held in this file result = af.getFile(); // If the temporary file was used if (newFile.length() > 0) { // Rename Original File // Can fail on Vista if have Special Permission 'Delete' set Deny File originalFileBackup = new File(af.getFile().getAbsoluteFile().getParentFile().getPath(), AudioFile.getBaseFilename(af.getFile()) + ".old"); //If already exists modify the suffix int count=1; while(originalFileBackup.exists()) { originalFileBackup = new File(af.getFile().getAbsoluteFile().getParentFile().getPath(), AudioFile.getBaseFilename(af.getFile())+ ".old"+count); count++; } boolean renameResult = Utils.rename(af.getFile(),originalFileBackup); if (!renameResult) { logger .log(Level.SEVERE, ErrorMessage.GENERAL_WRITE_FAILED_TO_RENAME_ORIGINAL_FILE_TO_BACKUP .getMsg(af.getFile().getAbsolutePath(), originalFileBackup.getName())); throw new CannotWriteException(ErrorMessage.GENERAL_WRITE_FAILED_TO_RENAME_ORIGINAL_FILE_TO_BACKUP .getMsg(af.getFile().getPath(), originalFileBackup.getName())); } // Rename Temp File to Original File renameResult = Utils.rename(newFile,af.getFile()); if (!renameResult) { // Renamed failed so lets do some checks rename the backup back to the original file // New File doesnt exist if (!newFile.exists()) { logger .warning(ErrorMessage.GENERAL_WRITE_FAILED_NEW_FILE_DOESNT_EXIST .getMsg(newFile.getAbsolutePath())); } // Rename the backup back to the original if (!originalFileBackup.renameTo(af.getFile())) { // TODO now if this happens we are left with testfile.old // instead of testfile.mp4 logger .warning(ErrorMessage.GENERAL_WRITE_FAILED_TO_RENAME_ORIGINAL_BACKUP_TO_ORIGINAL .getMsg(originalFileBackup .getAbsolutePath(), af.getFile() .getName())); } logger .warning(ErrorMessage.GENERAL_WRITE_FAILED_TO_RENAME_TO_ORIGINAL_FILE .getMsg(af.getFile().getAbsolutePath(), newFile .getName())); throw new CannotWriteException(ErrorMessage.GENERAL_WRITE_FAILED_TO_RENAME_TO_ORIGINAL_FILE .getMsg(af.getFile().getAbsolutePath(), newFile .getName())); } else { // Rename was okay so we can now delete the backup of the // original boolean deleteResult = originalFileBackup.delete(); if (!deleteResult) { // Not a disaster but can't delete the backup so make a // warning logger .warning(ErrorMessage.GENERAL_WRITE_WARNING_UNABLE_TO_DELETE_BACKUP_FILE .getMsg(originalFileBackup .getAbsolutePath())); } } // Delete the temporary file if still exists if (newFile.exists()) { if (!newFile.delete()) { // Non critical failed deletion logger .warning(ErrorMessage.GENERAL_WRITE_FAILED_TO_DELETE_TEMPORARY_FILE .getMsg(newFile.getPath())); } } } else { // Delete the temporary file that wasn't ever used if (!newFile.delete()) { // Non critical failed deletion logger .warning(ErrorMessage.GENERAL_WRITE_FAILED_TO_DELETE_TEMPORARY_FILE .getMsg(newFile.getPath())); } } if (this.modificationListener != null) { this.modificationListener.fileOperationFinished(result); } } /** * This is called when a tag has to be written in a file. Three parameters * are provided, the tag to write (not empty) Two randomaccessfiles, the * first points to the file where we want to write the given tag, and the * second is an empty temporary file that can be used if e.g. the file has * to be bigger than the original. *

    * If something has been written in the temporary file, when this method * returns, the original file is deleted, and the temporary file is renamed * the the original name *

    * If nothing has been written to it, it is simply deleted. *

    * This method can assume the raf, rafTemp are pointing to the first byte of * the file. The subclass must not close these two files when the method * returns. * * @param tag * @param raf * @param rafTemp * @throws IOException is thrown when the RandomAccessFile operations throw it (you * should never throw them manually) * @throws CannotWriteException when an error occured during the generation of the tag * @throws org.jaudiotagger.audio.exceptions.CannotReadException */ protected abstract void writeTag(Tag tag, RandomAccessFile raf, RandomAccessFile rafTemp) throws CannotReadException, CannotWriteException, IOException; } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/generic/AudioFileModificationAdapter.java0000644000175000017500000000473011041064726032563 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2003-2005 Christian Laireiter * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.audio.generic; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.exceptions.ModifyVetoException; import java.io.File; /** * Adapter for * {@link org.jaudiotagger.audio.generic.AudioFileModificationListener}. * * @author Christian Laireiter */ public class AudioFileModificationAdapter implements AudioFileModificationListener { /** * (overridden) * * @see org.jaudiotagger.audio.generic.AudioFileModificationListener#fileModified(org.jaudiotagger.audio.AudioFile, *File) */ public void fileModified(AudioFile original, File temporary) throws ModifyVetoException { // Nothing to do } /** * (overridden) * * @see org.jaudiotagger.audio.generic.AudioFileModificationListener#fileOperationFinished(File) */ public void fileOperationFinished(File result) { // Nothing to do } /** * (overridden) * * @see org.jaudiotagger.audio.generic.AudioFileModificationListener#fileWillBeModified(org.jaudiotagger.audio.AudioFile, *boolean) */ public void fileWillBeModified(AudioFile file, boolean delete) throws ModifyVetoException { // Nothing to do } /** * (overridden) * * @see org.jaudiotagger.audio.generic.AudioFileModificationListener#vetoThrown(org.jaudiotagger.audio.generic.AudioFileModificationListener, *org.jaudiotagger.audio.AudioFile, *org.jaudiotagger.audio.exceptions.ModifyVetoException) */ public void vetoThrown(AudioFileModificationListener cause, AudioFile original, ModifyVetoException veto) { // Nothing to do } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/generic/Utils.java0000644000175000017500000003124511323646506026201 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2003-2005 Raphaël Slinckx * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.audio.generic; import org.jaudiotagger.audio.AudioFile; import java.io.*; import java.nio.ByteBuffer; import java.util.logging.Level; import java.util.logging.Logger; /** * Contains various frequently used static functions in the different tag * formats * * @author Raphael Slinckx */ public class Utils { // Logger Object public static Logger logger = Logger .getLogger("org.jaudiotagger.audio.generic.utils"); /** * Copies the bytes of srd to dst at the * specified offset. * * @param src The byte to be copied. * @param dst The array to copy to * @param dstOffset The start offset for the bytes to be copied. */ public static void copy(byte[] src, byte[] dst, int dstOffset) { System.arraycopy(src, 0, dst, dstOffset, src.length); } /** * Returns {@link String#getBytes()}.
    * * @param s The String to call, decode bytes using the specfied charset * @param charSet * @return The bytes. */ public static byte[] getDefaultBytes(String s, String charSet) { try { return s.getBytes(charSet); } catch (UnsupportedEncodingException uee) { throw new RuntimeException(uee); } } /* * Returns the extension of the given file. * The extension is empty if there is no extension * The extension is the string after the last "." * * @param f The file whose extension is requested * @return The extension of the given file */ public static String getExtension(File f) { String name = f.getName().toLowerCase(); int i = name.lastIndexOf("."); if (i == -1) { return ""; } return name.substring(i + 1); } /* * Computes a number whereby the 1st byte is the least signifcant and the last * byte is the most significant. * * @param b The byte array @param start The starting offset in b * (b[offset]). The less significant byte @param end The end index * (included) in b (b[end]). The most significant byte @return a long number * represented by the byte sequence. * * So if storing a number which only requires one byte it will be stored in the first * byte. */ public static long getLongLE(ByteBuffer b, int start, int end) { long number = 0; for (int i = 0; i < (end - start + 1); i++) { number += ((b.get(start + i) & 0xFF) << i * 8); } return number; } /* * Computes a number whereby the 1st byte is the most significant and the last * byte is the least significant. * * So if storing a number which only requires one byte it will be stored in the last * byte. */ public static long getLongBE(ByteBuffer b, int start, int end) { long number = 0; for (int i = 0; i < (end - start + 1); i++) { number += ((long)((b.get(end - i) & 0xFF)) << i * 8); } return number; } public static int getIntLE(byte[] b) { return (int) getLongLE(ByteBuffer.wrap(b), 0, b.length - 1); } /* * same as above, but returns an int instead of a long @param b The byte * array @param start The starting offset in b (b[offset]). The less * significant byte @param end The end index (included) in b (b[end]). The * most significant byte @return a int number represented by the byte * sequence. */ public static int getIntLE(byte[] b, int start, int end) { return (int) getLongLE(ByteBuffer.wrap(b), start, end); } public static int getIntBE(byte[] b, int start, int end) { return (int) getLongBE(ByteBuffer.wrap(b), start, end); } public static int getIntBE(ByteBuffer b, int start, int end) { return (int) getLongBE(b, start, end); } public static short getShortBE(ByteBuffer b, int start, int end) { return (short) getIntBE(b, start, end); } /** * Convert int to byte representation - Big Endian (as used by mp4) * * @param size * @return byte represenetation */ public static byte[] getSizeBEInt32(int size) { byte[] b = new byte[4]; b[0] = (byte) ((size >> 24) & 0xFF); b[1] = (byte) ((size >> 16) & 0xFF); b[2] = (byte) ((size >> 8) & 0xFF); b[3] = (byte) (size & 0xFF); return b; } /** * Convert short to byte representation - Big Endian (as used by mp4) * * @param size * @return byte represenetation */ public static byte[] getSizeBEInt16(short size) { byte[] b = new byte[2]; b[0] = (byte) ((size >> 8) & 0xFF); b[1] = (byte) (size & 0xFF); return b; } /** * Convert int to byte representation - Little Endian (as used by ogg vorbis) * * @param size * @return byte represenetation */ public static byte[] getSizeLEInt32(int size) { byte[] b = new byte[4]; b[0] = (byte) (size & 0xff); b[1] = (byte) ((size >>> 8) & 0xffL); b[2] = (byte) ((size >>> 16) & 0xffL); b[3] = (byte) ((size >>> 24) & 0xffL); return b; } /** * Create String starting from offset upto length using encoding * * @param b * @param offset * @param length * @param encoding * @return * @throws UnsupportedEncodingException */ public static String getString(byte[] b, int offset, int length, String encoding) { try { return new String(b, offset, length, encoding); } catch (UnsupportedEncodingException ue) { //Shouldnt have to worry about this exception as should only be calling with well defined charsets throw new RuntimeException(ue); } } /** * Create String offset from position by offset upto length using encoding, and position of buffer * is moved to after position + offset + length * * @param buffer * @param offset * @param length * @param encoding * @return */ public static String getString(ByteBuffer buffer, int offset, int length, String encoding) { byte[] b = new byte[length]; buffer.position(buffer.position() + offset); buffer.get(b); try { return new String(b, 0, length, encoding); } catch (UnsupportedEncodingException uee) { //TODO, will we ever use unsupported encodings throw new RuntimeException(uee); } } /* * Tries to convert a string into an UTF8 array of bytes If the conversion * fails, return the string converted with the default encoding. * * @param s The string to convert @return The byte array representation of * this string in UTF8 encoding */ public static byte[] getUTF8Bytes(String s) throws UnsupportedEncodingException { return s.getBytes("UTF-8"); } /** * Overflow checking since java can't handle unsigned numbers. * @param di * @throws java.io.IOException * @return */ public static int readUint32AsInt(DataInput di) throws IOException { final long l = readUint32(di); if (l > Integer.MAX_VALUE) { throw new IOException("uint32 value read overflows int"); } return (int) l; } public static long readUint32(DataInput di) throws IOException { final byte[] buf8 = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; di.readFully(buf8, 4, 4); final long l = ByteBuffer.wrap(buf8).getLong(); return l; } public static int readUint16(DataInput di) throws IOException { final byte[] buf = {0x00, 0x00, 0x00, 0x00}; di.readFully(buf, 2, 2); final int i = ByteBuffer.wrap(buf).getInt(); return i; } public static String readString(DataInput di, int charsToRead) throws IOException { final byte[] buf = new byte[charsToRead]; di.readFully(buf); return new String(buf); } public static long readUInt64(ByteBuffer b) { long result = 0; result += (readUBEInt32(b) << 32); result += readUBEInt32(b); return result; } public static int readUBEInt32(ByteBuffer b) { int result = 0; result += readUBEInt16(b) << 16; result += readUBEInt16(b); return result; } public static int readUBEInt24(ByteBuffer b) { int result = 0; result += readUBEInt16(b) << 16; result += readUInt8(b); return result; } public static int readUBEInt16(ByteBuffer b) { int result = 0; result += readUInt8(b) << 8; result += readUInt8(b); return result; } public static int readUInt8(ByteBuffer b) { return read(b); } public static int read(ByteBuffer b) { int result = (b.get() & 0xFF); return result; } /** * @param file * @return filename with audioformat seperator stripped of, lengthened to ensure not too small for valid tempfile * creation. */ public static String getMinBaseFilenameAllowedForTempFile(File file) { String s = AudioFile.getBaseFilename(file); if (s.length() >= 3) { return s; } if (s.length() == 1) { return s + "000"; } else if (s.length() == 1) { return s + "00"; } else if (s.length() == 2) { return s + "0"; } return s; } /** * Rename file, and if normal rename fails, try copy and delete instead * * @param fromFile * @param toFile * @return */ public static boolean rename(File fromFile, File toFile) { logger.log(Level.CONFIG,"Renaming From:"+fromFile.getAbsolutePath() + " to "+toFile.getAbsolutePath()); if(toFile.exists()) { logger.log(Level.SEVERE,"Destination File:"+toFile + " already exists"); return false; } //Rename File final boolean result = fromFile.renameTo(toFile); if (!result) { // Might be trying to rename over filesystem, so try copy and delete instead if (copy(fromFile, toFile)) { boolean deleteResult=fromFile.delete(); if(deleteResult) { logger.log(Level.SEVERE,"Unable to delete File:"+fromFile); return false; } return true; } else { return false; } } return true; } /** * Copy a File * * @param fromFile The existing File * @param toFile The new File * @return true if and only if the renaming succeeded; * false otherwise */ public static boolean copy(File fromFile, File toFile) { try { FileInputStream in = new FileInputStream(fromFile); FileOutputStream out = new FileOutputStream(toFile); byte[] buf = new byte[8192]; int len; while ((len = in.read(buf)) > -1) { out.write(buf, 0, len); } in.close(); out.close(); // cleanup if files are not the same length if (fromFile.length() != toFile.length()) { toFile.delete(); return false; } return true; } catch (IOException e) { e.printStackTrace(); return false; } } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/generic/GenericTag.java0000644000175000017500000001635511470746136027121 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2003-2005 Raphaël Slinckx * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.audio.generic; import org.jaudiotagger.logging.ErrorMessage; import org.jaudiotagger.tag.*; import org.jaudiotagger.tag.datatype.Artwork; import java.util.Collections; import java.util.EnumSet; import java.util.List; /** * This is a complete example implementation of * {@link AbstractTag} and it currenlty used to provide basic support to audio formats with only read tagging * ability such as Real or Wav files
    * * @author Raphaël Slinckx */ public abstract class GenericTag extends AbstractTag { private static EnumSet supportedKeys; static { supportedKeys = EnumSet.of(FieldKey.ALBUM,FieldKey.ARTIST,FieldKey.TITLE,FieldKey.TRACK,FieldKey.GENRE,FieldKey.COMMENT,FieldKey.YEAR); } /** * Implementations of {@link TagTextField} for use with * "ISO-8859-1" strings. * * @author Raphaël Slinckx */ private class GenericTagTextField implements TagTextField { /** * Stores the string. */ private String content; /** * Stores the identifier. */ private final String id; /** * Creates an instance. * * @param fieldId The identifier. * @param initialContent The string. */ public GenericTagTextField(String fieldId, String initialContent) { this.id = fieldId; this.content = initialContent; } /** * (overridden) * * @see org.jaudiotagger.tag.TagField#copyContent(org.jaudiotagger.tag.TagField) */ public void copyContent(TagField field) { if (field instanceof TagTextField) { this.content = ((TagTextField) field).getContent(); } } /** * (overridden) * * @see org.jaudiotagger.tag.TagTextField#getContent() */ public String getContent() { return this.content; } /** * (overridden) * * @see org.jaudiotagger.tag.TagTextField#getEncoding() */ public String getEncoding() { return "ISO-8859-1"; } /** * (overridden) * * @see org.jaudiotagger.tag.TagField#getId() */ public String getId() { return id; } /** * (overridden) * * @see org.jaudiotagger.tag.TagField#getRawContent() */ public byte[] getRawContent() { return this.content == null ? new byte[]{} : Utils.getDefaultBytes(this.content, getEncoding()); } /** * (overridden) * * @see org.jaudiotagger.tag.TagField#isBinary() */ public boolean isBinary() { return false; } /** * (overridden) * * @see org.jaudiotagger.tag.TagField#isBinary(boolean) */ public void isBinary(boolean b) { /* not supported */ } /** * (overridden) * * @see org.jaudiotagger.tag.TagField#isCommon() */ public boolean isCommon() { return true; } /** * (overridden) * * @see org.jaudiotagger.tag.TagField#isEmpty() */ public boolean isEmpty() { return this.content.equals(""); } /** * (overridden) * * @see org.jaudiotagger.tag.TagTextField#setContent(java.lang.String) */ public void setContent(String s) { this.content = s; } /** * (overridden) * * @see org.jaudiotagger.tag.TagTextField#setEncoding(java.lang.String) */ public void setEncoding(String s) { /* Not allowed */ } /** * (overridden) * * @see java.lang.Object#toString() */ public String toString() { return getContent(); } } /** * (overridden) * * @see org.jaudiotagger.audio.generic.AbstractTag#isAllowedEncoding(java.lang.String) */ protected boolean isAllowedEncoding(String enc) { return true; } public TagField createField(FieldKey genericKey, String value) throws KeyNotFoundException, FieldDataInvalidException { if(supportedKeys.contains(genericKey)) { return new GenericTagTextField(genericKey.name(),value); } else { throw new UnsupportedOperationException(ErrorMessage.GENERIC_NOT_SUPPORTED.getMsg()); } } /** * @param genericKey * @return * @throws KeyNotFoundException */ public String getFirst(FieldKey genericKey) throws KeyNotFoundException { return getValue(genericKey, 0); } public String getValue(FieldKey genericKey,int index) throws KeyNotFoundException { if(supportedKeys.contains(genericKey)) { return getItem(genericKey.name(),index); } else { throw new UnsupportedOperationException(ErrorMessage.GENERIC_NOT_SUPPORTED.getMsg()); } } /** * @param genericKey * @throws KeyNotFoundException */ public void deleteField(FieldKey genericKey) throws KeyNotFoundException { if(supportedKeys.contains(genericKey)) { deleteField(genericKey.name()); } else { throw new UnsupportedOperationException(ErrorMessage.GENERIC_NOT_SUPPORTED.getMsg()); } } /** * @param genericKey * @return * @throws KeyNotFoundException */ public TagField getFirstField(FieldKey genericKey) throws KeyNotFoundException { if(supportedKeys.contains(genericKey)) { return getFirstField(genericKey.name()); } else { throw new UnsupportedOperationException(ErrorMessage.GENERIC_NOT_SUPPORTED.getMsg()); } } public List getArtworkList() { return Collections.emptyList(); } public TagField createField(Artwork artwork) throws FieldDataInvalidException { throw new UnsupportedOperationException(ErrorMessage.GENERIC_NOT_SUPPORTED.getMsg()); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/generic/AbstractTag.java0000644000175000017500000002673411470746136027312 0ustar drazzibdrazzib/* * jaudiotagger library * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.audio.generic; import org.jaudiotagger.tag.*; import org.jaudiotagger.tag.datatype.Artwork; import java.util.*; /** * This class is the default implementation for * {@link org.jaudiotagger.tag.Tag} and introduces some more useful * functionality to be implemented.
    * * @author Raphaël Slinckx */ public abstract class AbstractTag implements Tag { /** * Stores the amount of {@link TagField} with {@link TagField#isCommon()} * true. */ protected int commonNumber = 0; /** * This map stores the {@linkplain TagField#getId() ids} of the stored * fields to the {@linkplain TagField fields} themselves. Because a linked hashMap is used the order * that they are added in is preserved, the only exception to this rule is when two fields of the same id * exist, both will be returned according to when the first item was added to the file.
    */ protected Map> fields = new LinkedHashMap>(); /** * Add field * * @see org.jaudiotagger.tag.Tag#addField(org.jaudiotagger.tag.TagField) *

    * Changed so add empty fields */ public void addField(TagField field) { if (field == null) { return; } List list = fields.get(field.getId()); // There was no previous item if (list == null) { list = new ArrayList(); list.add(field); fields.put(field.getId(), list); if (field.isCommon()) { commonNumber++; } } else { // We append to existing list list.add(field); } } /** * Get list of fields within this tag with the specified id * * @see org.jaudiotagger.tag.Tag#getFields(java.lang.String) */ public List getFields(String id) { List list = fields.get(id); if (list == null) { return new ArrayList(); } return list; } /** * @param id * @return */ //Needs to be overridden //TODO remove public List getFields(FieldKey id) throws KeyNotFoundException { List list = fields.get(id.name()); if (list == null) { return new ArrayList(); } return list; } /** * * @param id * @param index * @return */ public String getItem(String id,int index) { List l = getFields(id); return (l.size()>index) ? l.get(index).toString() : ""; } /** * Retrieve the first value that exists for this generic key * * @param genericKey * @return */ public String getFirst(FieldKey genericKey) throws KeyNotFoundException { return getValue(genericKey,0); } /** * * @param id * @return */ public String getFirst(String id) { List l = getFields(id); return (l.size() != 0) ? l.get(0).toString() : ""; } /** * * @param id audio specific key * @return */ public TagField getFirstField(String id) { List l = getFields(id); return (l.size() != 0) ? l.get(0) : null; } /** * @see org.jaudiotagger.tag.Tag#getFields() */ public Iterator getFields() { final Iterator>> it = this.fields.entrySet().iterator(); return new Iterator() { private Iterator fieldsIt; private void changeIt() { if (!it.hasNext()) { return; } Map.Entry> e = it.next(); List l = e.getValue(); fieldsIt = l.iterator(); } public boolean hasNext() { if (fieldsIt == null) { changeIt(); } return it.hasNext() || (fieldsIt != null && fieldsIt.hasNext()); } public TagField next() { if (!fieldsIt.hasNext()) { changeIt(); } return fieldsIt.next(); } public void remove() { fieldsIt.remove(); } }; } /** * Return field count *

    * TODO:There must be a more efficient way to do this. * * @return field count */ public int getFieldCount() { Iterator it = getFields(); int count = 0; while (it.hasNext()) { count++; it.next(); } return count; } public int getFieldCountIncludingSubValues() { return getFieldCount(); } /** * Does this tag contain any comon fields * * @see org.jaudiotagger.tag.Tag#hasCommonFields() */ public boolean hasCommonFields() { return commonNumber != 0; } /** * Does this tag contain a field with the specified id * * @see org.jaudiotagger.tag.Tag#hasField(java.lang.String) */ public boolean hasField(String id) { return getFields(id).size() != 0; } /** * Determines whether the given charset encoding may be used for the * represented tagging system. * * @param enc charset encoding. * @return true if the given encoding can be used. */ protected abstract boolean isAllowedEncoding(String enc); /** * Is this tag empty * * @see org.jaudiotagger.tag.Tag#isEmpty() */ public boolean isEmpty() { return fields.size() == 0; } /** * Create new field and set it in the tag * * @param genericKey * @param value * @throws KeyNotFoundException * @throws FieldDataInvalidException */ public void setField(FieldKey genericKey, String value) throws KeyNotFoundException, FieldDataInvalidException { TagField tagfield = createField(genericKey,value); setField(tagfield); } /** * Create new field and add it to the tag * * @param genericKey * @param value * @throws KeyNotFoundException * @throws FieldDataInvalidException */ public void addField(FieldKey genericKey, String value) throws KeyNotFoundException, FieldDataInvalidException { TagField tagfield = createField(genericKey,value); addField(tagfield); } /** * Set field *

    * Changed:Just because field is empty it doesn't mean it should be deleted. That should be the choice * of the developer. (Or does this break things) * * @see org.jaudiotagger.tag.Tag#setField(org.jaudiotagger.tag.TagField) */ public void setField(TagField field) { if (field == null) { return; } // If there is already an existing field with same id // and both are TextFields, we replace the first element List list = fields.get(field.getId()); if (list != null) { list.set(0, field); return; } // Else we put the new field in the fields. list = new ArrayList(); list.add(field); fields.put(field.getId(), list); if (field.isCommon()) { commonNumber++; } } /** * The m parameter is effectively ignored * * @param id * @param n * @param m * @return */ public String getSubValue(FieldKey id, int n, int m) { return getValue(id,n); } /** * Set or add encoding * * @see org.jaudiotagger.tag.Tag#setEncoding(java.lang.String) */ public boolean setEncoding(String enc) { if (!isAllowedEncoding(enc)) { return false; } Iterator it = getFields(); while (it.hasNext()) { TagField field = (TagField) it.next(); if (field instanceof TagTextField) { ((TagTextField) field).setEncoding(enc); } } return true; } /** * (overridden) * * @see java.lang.Object#toString() */ public String toString() { StringBuffer out = new StringBuffer(); out.append("Tag content:\n"); Iterator it = getFields(); while (it.hasNext()) { TagField field = (TagField) it.next(); out.append("\t"); out.append(field.getId()); out.append(":"); out.append(field.toString()); out.append("\n"); } return out.toString().substring(0, out.length() - 1); } /** * * @param genericKey * @param value * @return * @throws KeyNotFoundException * @throws FieldDataInvalidException */ public abstract TagField createField(FieldKey genericKey, String value) throws KeyNotFoundException, FieldDataInvalidException; /** * * @param genericKey * @return * @throws KeyNotFoundException */ public abstract TagField getFirstField(FieldKey genericKey) throws KeyNotFoundException; /** * * @param fieldKey * @throws KeyNotFoundException */ public abstract void deleteField(FieldKey fieldKey) throws KeyNotFoundException; /** * Delete all occurrences of field with this id. * * @param key */ public void deleteField(String key) { fields.remove(key); } public Artwork getFirstArtwork() { List artwork = getArtworkList(); if(artwork.size()>0) { return artwork.get(0); } return null; } /** * Create field and then set within tag itself * * @param artwork * @throws FieldDataInvalidException */ public void setField(Artwork artwork) throws FieldDataInvalidException { this.setField(createField(artwork)); } /** * Create field and then add within tag itself * * @param artwork * @throws FieldDataInvalidException */ public void addField(Artwork artwork) throws FieldDataInvalidException { this.addField(createField(artwork)); } /** * Delete all instance of artwork Field * * @throws KeyNotFoundException */ public void deleteArtworkField() throws KeyNotFoundException { this.deleteField(FieldKey.COVER_ART); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/generic/AbstractTagCreator.java0000644000175000017500000000336711247705415030624 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2003-2005 Raphaël Slinckx * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.audio.generic; import org.jaudiotagger.tag.Tag; import java.io.UnsupportedEncodingException; import java.nio.ByteBuffer; /** * Abstract class for creating the raw content that represents the tag so it can be written * to file. */ public abstract class AbstractTagCreator { /** * Convert tagdata to rawdata ready for writing to file with no additional padding * * @param tag * @return * @throws UnsupportedEncodingException */ public ByteBuffer convert(Tag tag) throws UnsupportedEncodingException { return convert(tag, 0); } /** * Convert tagdata to rawdata ready for writing to file * * @param tag * @param padding TODO is this padding or additional padding * @return * @throws UnsupportedEncodingException */ public abstract ByteBuffer convert(Tag tag, int padding) throws UnsupportedEncodingException; } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/generic/AudioFileModificationListener.java0000644000175000017500000001010411041064726032760 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2003-2005 Christian Laireiter * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.audio.generic; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.exceptions.ModifyVetoException; import java.io.File; /** * Classes implementing this interface will be notified on audio file's * modifications.
    *

    *

    It will be notified on several occasions:
    *

      *
    • An audio file is about to be modified * {@link #fileWillBeModified(AudioFile,boolean)}
      * Here one can modify the tag data because of global settings.
    • *
    • The write process has just finished. But if a copy was created the * original has not been replaced yet. ({@link #fileModified(AudioFile,File)}).
    • *
    • The operation has been finished. {@link #fileOperationFinished(File)}
    • *
    * * @author Christian Laireiter */ public interface AudioFileModificationListener { /** * Notifies that original has been processed.
    * Because the audiolibrary allows format implementors to either change the * original file or create a copy, it is possible that the real result is * located in the original and temporary is of zero size * or the original will be deleted and replaced by temporary.
    * * @param original The original file on which the operation was started. * @param temporary The modified copy. (It may be of zero size if the original was * modified) * @throws ModifyVetoException If the Results doesn't fit the expectations of the listener, * it can prevent the replacement of the original by temporary.
    * If the original is already modified, this exception results * in nothing. */ public void fileModified(AudioFile original, File temporary) throws ModifyVetoException; /** * Informs the listener that the process has been finished.
    * The given file is either the original file or the modified copy.
    * * @param result The remaining file. It's not of {@link AudioFile} since it may * be possible that a new file was created. In that case the * audiolibs would need to parse the file again, which leads to * long and unnecessary operation time, if the tag data is not * needed any more. */ public void fileOperationFinished(File result); /** * Notifies that the file is about to be modified. * * @param file The file that will be modified. * @param delete true if the deletion of tag data will be * performed. * @throws ModifyVetoException Thrown if the listener wants to prevent the process. */ public void fileWillBeModified(AudioFile file, boolean delete) throws ModifyVetoException; /** * This method notifies about a veto exception that has been thrown by * another listener.
    * * @param cause The instance which caused the veto. * @param original The original file, that was about to be modified. * @param veto The thrown exception. */ public void vetoThrown(AudioFileModificationListener cause, AudioFile original, ModifyVetoException veto); } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/generic/GenericAudioHeader.java0000644000175000017500000002217711277006322030546 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2003-2005 Rapha�l Slinckx * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.audio.generic; import org.jaudiotagger.audio.AudioHeader; import java.util.HashMap; import java.util.Set; /** * This class represents a structure for storing and retrieving information * about the codec respectively the encoding parameters.
    * Most of the parameters are available for nearly each audio format. Some * others would result in standard values.
    * Consider: None of the setter methods will actually affect the audio * file. This is just a structure for retrieving information, not manipulating * the audio file.
    * * @author Raphael Slinckx */ public class GenericAudioHeader implements AudioHeader { /** * The key for the Bitrate.({@link Integer})
    * * @see #content */ public final static String FIELD_BITRATE = "BITRATE"; /** * The key for the number of audio channels.({@link Integer})
    * * @see #content */ public final static String FIELD_CHANNEL = "CHANNB"; /** * The key for the extra encoding information.({@link String})
    * * @see #content */ public final static String FIELD_INFOS = "INFOS"; /** * The key for the audio clip duration in seconds. ({@link Float})
    * * @see #content */ public final static String FIELD_LENGTH = "LENGTH"; /** * The key for the audio sample rate in "Hz". ({@link Integer})
    * * @see #content */ public final static String FIELD_SAMPLERATE = "SAMPLING"; /** * The key for the audio type.({@link String})
    * * @see #content */ public final static String FIELD_TYPE = "TYPE"; /** * The key for the VBR flag. ({@link Boolean})
    * * @see #content */ public final static String FIELD_VBR = "VBR"; /** * Used for WMA files */ private boolean isLossless = false; /** * This table containts the parameters.
    */ protected HashMap content; /** * Creates an instance with emtpy values.
    */ public GenericAudioHeader() { content = new HashMap(6); content.put(FIELD_BITRATE, -1); content.put(FIELD_CHANNEL, -1); content.put(FIELD_TYPE, ""); content.put(FIELD_INFOS, ""); content.put(FIELD_SAMPLERATE, -1); content.put(FIELD_LENGTH, (float) -1); content.put(FIELD_VBR, true); } public String getBitRate() { return content.get(FIELD_BITRATE).toString(); } /** * This method returns the bitrate of the represented audio clip in * "Kbps".
    * * @return The bitrate in Kbps. */ public long getBitRateAsNumber() { return ((Integer) content.get(FIELD_BITRATE)).longValue(); } /** * This method returns the number of audio channels the clip contains.
    * (The stereo, mono thing). * * @return The number of channels. (2 for stereo, 1 for mono) */ public int getChannelNumber() { return (Integer) content.get(FIELD_CHANNEL); } /** * @return */ public String getChannels() { return String.valueOf(getChannelNumber()); } /** * Returns the encoding type. * * @return The encoding type */ public String getEncodingType() { return (String) content.get(FIELD_TYPE); } /** * Returns the format, same as encoding type * * @return The encoding type */ public String getFormat() { return (String) content.get(FIELD_TYPE); } /** * This method returns some extra information about the encoding.
    * This may not contain anything for some audio formats.
    * * @return Some extra information. */ public String getExtraEncodingInfos() { return (String) content.get(FIELD_INFOS); } /** * This method returns the duration of the represented audio clip in * seconds.
    * * @return The duration in seconds. * @see #getPreciseLength() */ public int getTrackLength() { return (int) getPreciseLength(); } /** * This method returns the duration of the represented audio clip in seconds * (single-precision).
    * * @return The duration in seconds. * @see #getTrackLength() */ public float getPreciseLength() { return (Float) content.get(FIELD_LENGTH); } /** * This method returns the sample rate, the audio clip was encoded with.
    * * @return Sample rate of the audio clip in "Hz". */ public String getSampleRate() { return content.get(FIELD_SAMPLERATE).toString(); } public int getSampleRateAsNumber() { return (Integer) content.get(FIELD_SAMPLERATE); } /** * This method returns true, if the audio file is encoded * with "Variable Bitrate".
    * * @return true if audio clip is encoded with VBR. */ public boolean isVariableBitRate() { return (Boolean) content.get(FIELD_VBR); } /** * This method returns true, if the audio file is encoded * with "Lossless".
    * * @return true if audio clip is encoded with VBR. */ public boolean isLossless() { return isLossless; } /** * This Method sets the bitrate in "Kbps".
    * * @param bitrate bitrate in kbps. */ public void setBitrate(int bitrate) { content.put(FIELD_BITRATE, bitrate); } /** * Sets the number of channels. * * @param chanNb number of channels (2 for stereo, 1 for mono). */ public void setChannelNumber(int chanNb) { content.put(FIELD_CHANNEL, chanNb); } /** * Sets the type of the encoding.
    * This is a bit format specific.
    * eg:Layer I/II/III * * @param encodingType Encoding type. */ public void setEncodingType(String encodingType) { content.put(FIELD_TYPE, encodingType); } /** * A string containing anything else that might be interesting * * @param infos Extra information. */ public void setExtraEncodingInfos(String infos) { content.put(FIELD_INFOS, infos); } /** * This method sets the audio duration of the represented clip.
    * * @param length The duration of the audio clip in seconds. */ public void setLength(int length) { content.put(FIELD_LENGTH, (float) length); } /** * This method sets the audio duration of the represented clip.
    * * @param seconds The duration of the audio clip in seconds (single-precision). */ public void setPreciseLength(float seconds) { content.put(FIELD_LENGTH, seconds); } /** * Sets the Sampling rate in "Hz"
    * * @param samplingRate Sample rate. */ public void setSamplingRate(int samplingRate) { content.put(FIELD_SAMPLERATE, samplingRate); } /** * Sets the VBR flag for the represented audio clip.
    * * @param b true if VBR. */ public void setVariableBitRate(boolean b) { content.put(FIELD_VBR, b); } /** * Sets the Lossless flag for the represented audio clip.
    * * @param b true if Lossless. */ public void setLossless(boolean b) { isLossless = b; } /** * Can be used to add additional information * * @param key * @param value */ public void setExtra(String key, Object value) { content.put(key, value); } /** * Pretty prints this encoding info * * @see java.lang.Object#toString() */ public String toString() { StringBuffer out = new StringBuffer(50); out.append("Encoding infos content:\n"); Set set = content.keySet(); for (String key : set) { Object val = content.get(key); out.append("\t"); out.append(key); out.append(" : "); out.append(val); out.append("\n"); } return out.toString().substring(0, out.length() - 1); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/generic/ModificationHandler.java0000644000175000017500000001074411470746136031010 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2003-2005 Christian Laireiter * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.audio.generic; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.exceptions.ModifyVetoException; import java.io.File; import java.util.Enumeration; import java.util.Vector; import java.util.Iterator; /** * This class multicasts the events to multiple listener instances.
    * Additionally the Vetos are handled. (other listeners are notified). * * @author Christian Laireiter */ public class ModificationHandler implements AudioFileModificationListener { /** * The listeners to wich events are broadcasted are stored here. */ private Vector listeners = new Vector(); /** * This method adds an {@link AudioFileModificationListener} * * @param l Listener to add. */ public void addAudioFileModificationListener(AudioFileModificationListener l) { if (!this.listeners.contains(l)) { this.listeners.add(l); } } /** * (overridden) * * @see org.jaudiotagger.audio.generic.AudioFileModificationListener#fileModified(org.jaudiotagger.audio.AudioFile, *File) */ public void fileModified(AudioFile original, File temporary) throws ModifyVetoException { for (AudioFileModificationListener listener : this.listeners) { AudioFileModificationListener current = listener; try { current.fileModified(original, temporary); } catch (ModifyVetoException e) { vetoThrown(current, original, e); throw e; } } } /** * (overridden) * * @see org.jaudiotagger.audio.generic.AudioFileModificationListener#fileOperationFinished(File) */ public void fileOperationFinished(File result) { for (AudioFileModificationListener listener : this.listeners) { AudioFileModificationListener current = listener; current.fileOperationFinished(result); } } /** * (overridden) * * @see org.jaudiotagger.audio.generic.AudioFileModificationListener#fileWillBeModified(org.jaudiotagger.audio.AudioFile, *boolean) */ public void fileWillBeModified(AudioFile file, boolean delete) throws ModifyVetoException { for (AudioFileModificationListener listener : this.listeners) { AudioFileModificationListener current = listener; try { current.fileWillBeModified(file, delete); } catch (ModifyVetoException e) { vetoThrown(current, file, e); throw e; } } } /** * This method removes an {@link AudioFileModificationListener} * * @param l Listener to remove. */ public void removeAudioFileModificationListener(AudioFileModificationListener l) { if (this.listeners.contains(l)) { this.listeners.remove(l); } } /** * (overridden) * * @see org.jaudiotagger.audio.generic.AudioFileModificationListener#vetoThrown(org.jaudiotagger.audio.generic.AudioFileModificationListener, *org.jaudiotagger.audio.AudioFile, *org.jaudiotagger.audio.exceptions.ModifyVetoException) */ public void vetoThrown(AudioFileModificationListener cause, AudioFile original, ModifyVetoException veto) { for (AudioFileModificationListener listener : this.listeners) { AudioFileModificationListener current = listener; current.vetoThrown(cause, original, veto); } } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/generic/AudioFileReader.java0000644000175000017500000001222111247705415030056 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2003-2005 Raphaël Slinckx * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.audio.generic; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.exceptions.CannotReadException; import org.jaudiotagger.audio.exceptions.InvalidAudioFrameException; import org.jaudiotagger.audio.exceptions.ReadOnlyFileException; import org.jaudiotagger.tag.Tag; import org.jaudiotagger.tag.TagException; import org.jaudiotagger.logging.ErrorMessage; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; import java.util.logging.Logger; import java.util.logging.Level; /* * This abstract class is the skeleton for tag readers. It handles the creation/closing of * the randomaccessfile objects and then call the subclass method getEncodingInfo and getTag. * These two method have to be implemented in the subclass. * *@author Raphael Slinckx *@version $Id: AudioFileReader.java 813 2009-09-03 09:23:25Z paultaylor $ *@since v0.02 */ public abstract class AudioFileReader { // Logger Object public static Logger logger = Logger.getLogger("org.jaudiotagger.audio.generic"); private static final int MINIMUM_SIZE_FOR_VALID_AUDIO_FILE = 150; /* * Returns the encoding info object associated wih the current File. * The subclass can assume the RAF pointer is at the first byte of the file. * The RandomAccessFile must be kept open after this function, but can point * at any offset in the file. * * @param raf The RandomAccessFile associtaed with the current file * @exception IOException is thrown when the RandomAccessFile operations throw it (you should never throw them manually) * @exception CannotReadException when an error occured during the parsing of the encoding infos */ protected abstract GenericAudioHeader getEncodingInfo(RandomAccessFile raf) throws CannotReadException, IOException; /* * Same as above but returns the Tag contained in the file, or a new one. * * @param raf The RandomAccessFile associted with the current file * @exception IOException is thrown when the RandomAccessFile operations throw it (you should never throw them manually) * @exception CannotReadException when an error occured during the parsing of the tag */ protected abstract Tag getTag(RandomAccessFile raf) throws CannotReadException, IOException; /* * Reads the given file, and return an AudioFile object containing the Tag * and the encoding infos present in the file. If the file has no tag, an * empty one is returned. If the encodinginfo is not valid , an exception is thrown. * * @param f The file to read * @exception CannotReadException If anything went bad during the read of this file */ public AudioFile read(File f) throws CannotReadException, IOException, TagException, ReadOnlyFileException, InvalidAudioFrameException { if(logger.isLoggable(Level.INFO)) { logger.info(ErrorMessage.GENERAL_READ.getMsg(f.getAbsolutePath())); } if (!f.canRead()) { throw new CannotReadException(ErrorMessage.GENERAL_READ_FAILED_FILE_TOO_SMALL.getMsg(f.getAbsolutePath())); } if (f.length() <= MINIMUM_SIZE_FOR_VALID_AUDIO_FILE) { throw new CannotReadException(ErrorMessage.GENERAL_READ_FAILED_FILE_TOO_SMALL.getMsg(f.getAbsolutePath())); } RandomAccessFile raf = null; try { raf = new RandomAccessFile(f, "r"); raf.seek(0); GenericAudioHeader info = getEncodingInfo(raf); raf.seek(0); Tag tag = getTag(raf); return new AudioFile(f, info, tag); } catch (CannotReadException cre) { throw cre; } catch (Exception e) { //TODO is this masking exceptions, i.e NullBoxIDException get converted to CannotReadException throw new CannotReadException(f.getAbsolutePath()+":" + e.getMessage(), e); } finally { try { if (raf != null) { raf.close(); } } catch (Exception ex) { logger.log(Level.WARNING, ErrorMessage.GENERAL_READ_FAILED_UNABLE_TO_CLOSE_RANDOM_ACCESS_FILE.getMsg(f.getAbsolutePath())); } } } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/SupportedFileFormat.java0000644000175000017500000000076311144526335027422 0ustar drazzibdrazzibpackage org.jaudiotagger.audio; /** * Files formats currently supported by Library */ public enum SupportedFileFormat { OGG("ogg"), MP3("mp3"), FLAC("flac"), MP4("mp4"), M4A("m4a"), M4P("m4p"), WMA("wma"), WAV("wav"), RA("ra"), RM("rm"), M4B("m4b"); private String filesuffix; SupportedFileFormat(String filesuffix) { this.filesuffix = filesuffix; } public String getFilesuffix() { return filesuffix; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/mp4/0000755000175000017500000000000011556363170023316 5ustar drazzibdrazziblibjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/mp4/Mp4InfoReader.java0000644000175000017500000003445111247705415026566 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2003-2005 Raphaël Slinckx * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.audio.mp4; import org.jaudiotagger.audio.exceptions.CannotReadException; import org.jaudiotagger.audio.exceptions.CannotReadVideoException; import org.jaudiotagger.audio.generic.GenericAudioHeader; import org.jaudiotagger.audio.mp4.atom.*; import org.jaudiotagger.logging.ErrorMessage; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.util.logging.Logger; /** * Read audio info from file. *

    *

    * The info is held in the mvdh and mdhd fields as shown below *

     * |--- ftyp
     * |--- moov
     * |......|
     * |......|----- mvdh
     * |......|----- trak
     * |...............|----- mdia
     * |.......................|---- mdhd
     * |.......................|---- minf
     * |..............................|---- smhd
     * |..............................|---- stbl
     * |......................................|--- stsd
     * |.............................................|--- mp4a
     * |......|----- udta
     * |
     * |--- mdat
     * 
    */ public class Mp4InfoReader { // Logger Object public static Logger logger = Logger.getLogger("org.jaudiotagger.audio.mp4.atom"); public GenericAudioHeader read(RandomAccessFile raf) throws CannotReadException, IOException { Mp4AudioHeader info = new Mp4AudioHeader(); //File Identification Mp4BoxHeader ftypHeader = Mp4BoxHeader.seekWithinLevel(raf, Mp4NotMetaFieldKey.FTYP.getFieldName()); if (ftypHeader == null) { throw new CannotReadException(ErrorMessage.MP4_FILE_NOT_CONTAINER.getMsg()); } ByteBuffer ftypBuffer = ByteBuffer.allocate(ftypHeader.getLength() - Mp4BoxHeader.HEADER_LENGTH); raf.getChannel().read(ftypBuffer); ftypBuffer.rewind(); Mp4FtypBox ftyp = new Mp4FtypBox(ftypHeader, ftypBuffer); ftyp.processData(); info.setBrand(ftyp.getMajorBrand()); //Get to the facts everything we are interested in is within the moov box, so just load data from file //once so no more file I/O needed Mp4BoxHeader moovHeader = Mp4BoxHeader.seekWithinLevel(raf, Mp4NotMetaFieldKey.MOOV.getFieldName()); if (moovHeader == null) { throw new CannotReadException(ErrorMessage.MP4_FILE_NOT_AUDIO.getMsg()); } ByteBuffer moovBuffer = ByteBuffer.allocate(moovHeader.getLength() - Mp4BoxHeader.HEADER_LENGTH); raf.getChannel().read(moovBuffer); moovBuffer.rewind(); //Level 2-Searching for "mvhd" somewhere within "moov", we make a slice after finding header //so all get() methods will be relative to mvdh positions Mp4BoxHeader boxHeader = Mp4BoxHeader.seekWithinLevel(moovBuffer, Mp4NotMetaFieldKey.MVHD.getFieldName()); if (boxHeader == null) { throw new CannotReadException(ErrorMessage.MP4_FILE_NOT_AUDIO.getMsg()); } ByteBuffer mvhdBuffer = moovBuffer.slice(); Mp4MvhdBox mvhd = new Mp4MvhdBox(boxHeader, mvhdBuffer); info.setLength(mvhd.getLength()); //Advance position, TODO should we put this in box code ? mvhdBuffer.position(mvhdBuffer.position() + boxHeader.getDataLength()); //Level 2-Searching for "trak" within "moov" boxHeader = Mp4BoxHeader.seekWithinLevel(mvhdBuffer, Mp4NotMetaFieldKey.TRAK.getFieldName()); int endOfFirstTrackInBuffer = mvhdBuffer.position() + boxHeader.getDataLength(); if (boxHeader == null) { throw new CannotReadException(ErrorMessage.MP4_FILE_NOT_AUDIO.getMsg()); } //Level 3-Searching for "mdia" within "trak" boxHeader = Mp4BoxHeader.seekWithinLevel(mvhdBuffer, Mp4NotMetaFieldKey.MDIA.getFieldName()); if (boxHeader == null) { throw new CannotReadException(ErrorMessage.MP4_FILE_NOT_AUDIO.getMsg()); } //Level 4-Searching for "mdhd" within "mdia" boxHeader = Mp4BoxHeader.seekWithinLevel(mvhdBuffer, Mp4NotMetaFieldKey.MDHD.getFieldName()); if (boxHeader == null) { throw new CannotReadException(ErrorMessage.MP4_FILE_NOT_AUDIO.getMsg()); } Mp4MdhdBox mdhd = new Mp4MdhdBox(boxHeader, mvhdBuffer.slice()); info.setSamplingRate(mdhd.getSampleRate()); //Level 4-Searching for "hdlr" within "mdia" /*We dont currently need to process this because contains nothing we want mvhdBuffer.position(mvhdBuffer.position() + boxHeader.getDataLength()); boxHeader = Mp4BoxHeader.seekWithinLevel(mvhdBuffer, Mp4NotMetaFieldKey.HDLR.getFieldName()); if (boxHeader == null) { throw new CannotReadException(ErrorMessage.MP4_FILE_NOT_AUDIO.getMsg()); } Mp4HdlrBox hdlr = new Mp4HdlrBox(boxHeader, mvhdBuffer.slice()); hdlr.processData(); */ //Level 4-Searching for "minf" within "mdia" mvhdBuffer.position(mvhdBuffer.position() + boxHeader.getDataLength()); boxHeader = Mp4BoxHeader.seekWithinLevel(mvhdBuffer, Mp4NotMetaFieldKey.MINF.getFieldName()); if (boxHeader == null) { throw new CannotReadException(ErrorMessage.MP4_FILE_NOT_AUDIO.getMsg()); } //Level 5-Searching for "smhd" within "minf" //Only an audio track would have a smhd frame boxHeader = Mp4BoxHeader.seekWithinLevel(mvhdBuffer, Mp4NotMetaFieldKey.SMHD.getFieldName()); if (boxHeader == null) { throw new CannotReadException(ErrorMessage.MP4_FILE_NOT_AUDIO.getMsg()); } mvhdBuffer.position(mvhdBuffer.position() + boxHeader.getDataLength()); //Level 5-Searching for "stbl within "minf" boxHeader = Mp4BoxHeader.seekWithinLevel(mvhdBuffer, Mp4NotMetaFieldKey.STBL.getFieldName()); if (boxHeader == null) { throw new CannotReadException(ErrorMessage.MP4_FILE_NOT_AUDIO.getMsg()); } //Level 6-Searching for "stsd within "stbl" and process it direct data, dont think these are mandatory so dont throw //exception if unable to find boxHeader = Mp4BoxHeader.seekWithinLevel(mvhdBuffer, Mp4NotMetaFieldKey.STSD.getFieldName()); if (boxHeader != null) { Mp4StsdBox stsd = new Mp4StsdBox(boxHeader, mvhdBuffer); stsd.processData(); int positionAfterStsdHeaderAndData = mvhdBuffer.position(); ///Level 7-Searching for "mp4a within "stsd" boxHeader = Mp4BoxHeader.seekWithinLevel(mvhdBuffer, Mp4NotMetaFieldKey.MP4A.getFieldName()); if (boxHeader != null) { ByteBuffer mp4aBuffer = mvhdBuffer.slice(); Mp4Mp4aBox mp4a = new Mp4Mp4aBox(boxHeader, mp4aBuffer); mp4a.processData(); //Level 8-Searching for "esds" within mp4a to get No Of Channels and bitrate boxHeader = Mp4BoxHeader.seekWithinLevel(mp4aBuffer, Mp4NotMetaFieldKey.ESDS.getFieldName()); if (boxHeader != null) { Mp4EsdsBox esds = new Mp4EsdsBox(boxHeader, mp4aBuffer.slice()); //Set Bitrate in kbps info.setBitrate(esds.getAvgBitrate() / 1000); //Set Number of Channels info.setChannelNumber(esds.getNumberOfChannels()); info.setKind(esds.getKind()); info.setProfile(esds.getAudioProfile()); info.setEncodingType(EncoderType.AAC.getDescription()); } } else { //Level 7 -Searching for drms within stsd instead (m4p files) mvhdBuffer.position(positionAfterStsdHeaderAndData); boxHeader = Mp4BoxHeader.seekWithinLevel(mvhdBuffer, Mp4NotMetaFieldKey.DRMS.getFieldName()); if (boxHeader != null) { Mp4DrmsBox drms = new Mp4DrmsBox(boxHeader, mvhdBuffer); drms.processData(); //Level 8-Searching for "esds" within drms to get No Of Channels and bitrate boxHeader = Mp4BoxHeader.seekWithinLevel(mvhdBuffer, Mp4NotMetaFieldKey.ESDS.getFieldName()); if (boxHeader != null) { Mp4EsdsBox esds = new Mp4EsdsBox(boxHeader, mvhdBuffer.slice()); //Set Bitrate in kbps info.setBitrate(esds.getAvgBitrate() / 1000); //Set Number of Channels info.setChannelNumber(esds.getNumberOfChannels()); info.setKind(esds.getKind()); info.setProfile(esds.getAudioProfile()); info.setEncodingType(EncoderType.DRM_AAC.getDescription()); } } //Level 7-Searching for alac (Apple Lossless) instead else { mvhdBuffer.position(positionAfterStsdHeaderAndData); boxHeader = Mp4BoxHeader.seekWithinLevel(mvhdBuffer, Mp4NotMetaFieldKey.ALAC.getFieldName()); if (boxHeader != null) { //Process First Alac Mp4AlacBox alac = new Mp4AlacBox(boxHeader, mvhdBuffer); alac.processData(); //Level 8-Searching for 2nd "alac" within box that contains the info we really want boxHeader = Mp4BoxHeader.seekWithinLevel(mvhdBuffer, Mp4NotMetaFieldKey.ALAC.getFieldName()); if (boxHeader != null) { alac = new Mp4AlacBox(boxHeader, mvhdBuffer); alac.processData(); info.setEncodingType(EncoderType.APPLE_LOSSLESS.getDescription()); info.setChannelNumber(alac.getChannels()); info.setBitrate(alac.getBitRate()/1000); } } } } } //Set default channels if couldnt calculate it if (info.getChannelNumber() == -1) { info.setChannelNumber(2); } //Set default bitrate if couldnt calculate it if (info.getBitRateAsNumber() == -1) { info.setBitrate(128); } //This is the most likley option if cant find a match if (info.getEncodingType().equals("")) { info.setEncodingType(EncoderType.AAC.getDescription()); } logger.info(info.toString()); //Level 2-Searching for another "trak" within "moov", if more than one track exists then probably //video so reject it, unless it fits into certain encoding patterns mvhdBuffer.position(endOfFirstTrackInBuffer); boxHeader = Mp4BoxHeader.seekWithinLevel(mvhdBuffer, Mp4NotMetaFieldKey.TRAK.getFieldName()); if (boxHeader != null) { //We only allow multiple tracks as audio if they follow the format used by the winamp encoder or //are marked as being audio only and if track contains a nmhd atom rather than smhd. //TODO this probably too restrictive but it fixes the test cases we have if (ftyp.getMajorBrand().equals(Mp4FtypBox.Brand.ISO14496_1_VERSION_2.getId()) || ftyp.getMajorBrand().equals(Mp4FtypBox.Brand.APPLE_AUDIO_ONLY.getId()) || ftyp.getMajorBrand().equals(Mp4FtypBox.Brand.APPLE_AUDIO.getId())) { //Ok, need to do further checks on this track to ensure it is a scene descriptor //Level 3-Searching for "mdia" within "trak" boxHeader = Mp4BoxHeader.seekWithinLevel(mvhdBuffer, Mp4NotMetaFieldKey.MDIA.getFieldName()); if (boxHeader == null) { throw new CannotReadVideoException(ErrorMessage.MP4_FILE_IS_VIDEO.getMsg()); } //Level 4-Searching for "mdhd" within "mdia" boxHeader = Mp4BoxHeader.seekWithinLevel(mvhdBuffer, Mp4NotMetaFieldKey.MDHD.getFieldName()); if (boxHeader == null) { throw new CannotReadVideoException(ErrorMessage.MP4_FILE_IS_VIDEO.getMsg()); } //Level 4-Searching for "minf" within "mdia" mvhdBuffer.position(mvhdBuffer.position() + boxHeader.getDataLength()); boxHeader = Mp4BoxHeader.seekWithinLevel(mvhdBuffer, Mp4NotMetaFieldKey.MINF.getFieldName()); if (boxHeader == null) { throw new CannotReadVideoException(ErrorMessage.MP4_FILE_IS_VIDEO.getMsg()); } //Level 5-Searching for "nmhd" within "minf" //Only an audio track would have a nmhd frame boxHeader = Mp4BoxHeader.seekWithinLevel(mvhdBuffer, Mp4NotMetaFieldKey.NMHD.getFieldName()); if (boxHeader == null) { throw new CannotReadVideoException(ErrorMessage.MP4_FILE_IS_VIDEO.getMsg()); } } else { logger.info(ErrorMessage.MP4_FILE_IS_VIDEO.getMsg() + ":" + ftyp.getMajorBrand()); throw new CannotReadVideoException(ErrorMessage.MP4_FILE_IS_VIDEO.getMsg()); } } //Build AtomTree to ensure it is valid, this means we can detect any problems early on Mp4AtomTree atomTree = new Mp4AtomTree(raf,false); return info; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/mp4/atom/0000755000175000017500000000000011556363170024256 5ustar drazzibdrazziblibjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/mp4/atom/Mp4Mp4aBox.java0000644000175000017500000000612711041064726026754 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.mp4.atom; import org.jaudiotagger.audio.exceptions.CannotReadException; import java.nio.ByteBuffer; /** * Mp4aBox ( sample (frame encoding) description box) *

    * At first glance appears to hold no of channels but actually always returns 2 even for mono recordings * so just need to skip over data in order to get to child atom esds *

    *

    4 bytes version/flags = byte hex version + 24-bit hex flags * (current = 0) *

    * -> 6 bytes reserved = 48-bit value set to zero * -> 2 bytes data reference index * = short unsigned index from 'dref' box * -> 2 bytes QUICKTIME audio encoding version = short hex version * - default = 0 ; audio data size before decompression = 1 * -> 2 bytes QUICKTIME audio encoding revision level * = byte hex version * - default = 0 ; video can revise this value * -> 4 bytes QUICKTIME audio encoding vendor * = long ASCII text string * - default = 0 * -> 2 bytes audio channels = short unsigned count * (mono = 1 ; stereo = 2) * -> 2 bytes audio sample size = short unsigned value * (8 or 16) * -> 2 bytes QUICKTIME audio compression id = short integer value * - default = 0 * -> 2 bytes QUICKTIME audio packet size = short value set to zero * -> 4 bytes audio sample rate = long unsigned fixed point rate */ public class Mp4Mp4aBox extends AbstractMp4Box { public static final int RESERVED_POS = 0; public static final int REFERENCE_INDEX_POS = 6; public static final int AUDIO_ENCODING_POS = 8; public static final int AUDIO_REVISION_POS = 10; public static final int AUDIO_ENCODING_VENDOR_POS = 12; public static final int CHANNELS_POS = 16; public static final int AUDIO_SAMPLE_SIZE_POS = 18; public static final int AUDIO_COMPRESSION_ID_POS = 20; public static final int AUDIO_PACKET_SIZE_POS = 22; public static final int AUDIO_SAMPLE_RATE_POS = 24; public static final int RESERVED_LENGTH = 6; public static final int REFERENCE_INDEX_LENGTH = 2; public static final int AUDIO_ENCODING_LENGTH = 2; public static final int AUDIO_REVISION_LENGTH = 2; public static final int AUDIO_ENCODING_VENDOR_LENGTH = 4; public static final int CHANNELS_LENGTH = 2; public static final int AUDIO_SAMPLE_SIZE_LENGTH = 2; public static final int AUDIO_COMPRESSION_ID_LENGTH = 2; public static final int AUDIO_PACKET_SIZE_LENGTH = 2; public static final int AUDIO_SAMPLE_RATE_LENGTH = 4; public static final int TOTAL_LENGTH = RESERVED_LENGTH + REFERENCE_INDEX_LENGTH + AUDIO_ENCODING_LENGTH + AUDIO_REVISION_LENGTH + AUDIO_ENCODING_VENDOR_LENGTH + CHANNELS_LENGTH + AUDIO_SAMPLE_SIZE_LENGTH + AUDIO_COMPRESSION_ID_LENGTH + AUDIO_PACKET_SIZE_LENGTH + AUDIO_SAMPLE_RATE_LENGTH; /** * @param header header info * @param dataBuffer data of box (doesnt include header data) */ public Mp4Mp4aBox(Mp4BoxHeader header, ByteBuffer dataBuffer) { this.header = header; this.dataBuffer = dataBuffer; } public void processData() throws CannotReadException { dataBuffer.position(dataBuffer.position() + TOTAL_LENGTH); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/mp4/atom/Mp4EsdsBox.java0000644000175000017500000002437511277026507027064 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.mp4.atom; import org.jaudiotagger.audio.generic.Utils; import java.nio.ByteBuffer; import java.util.HashMap; import java.util.Map; /** * EsdsBox ( stream specific description box), usually holds the Bitrate/No of Channels *

    * It contains a number of (possibly optional?) sections (section 3 - 6) (containing optional filler) with * differeent info in each section. *

    *

    * -> 4 bytes version/flags = 8-bit hex version + 24-bit hex flags * (current = 0) *

    * Section 3 * -> 1 byte ES descriptor type tag = 8-bit hex value 0x03 * -> 3 bytes optional extended descriptor type tag string = 3 * 8-bit hex value * - types are 0x80,0x81,0xFE * -> 1 byte descriptor type length = 8-bit unsigned length * -> 2 bytes ES ID = 16-bit unsigned value * -> 1 byte stream priority = 8-bit unsigned value * - Defaults to 16 and ranges from 0 through to 31 *

    * Section 4 * -> 1 byte decoder config descriptor type tag = 8-bit hex value 0x04 * -> 3 bytes optional extended descriptor type tag string = 3 * 8-bit hex value * - types are 0x80,0x81,0xFE * -> 1 byte descriptor type length = 8-bit unsigned length * * -> 1 byte object type ID = 8-bit unsigned value * -> 6 bits stream type = 3/4 byte hex value * - type IDs are object descript. = 1 ; clock ref. = 2 * - type IDs are scene descript. = 4 ; visual = 4 * - type IDs are audio = 5 ; MPEG-7 = 6 ; IPMP = 7 * - type IDs are OCI = 8 ; MPEG Java = 9 * - type IDs are user private = 32 * -> 1 bit upstream flag = 1/8 byte hex value * -> 1 bit reserved flag = 1/8 byte hex value set to 1 * -> 3 bytes buffer size = 24-bit unsigned value * -> 4 bytes maximum bit rate = 32-bit unsigned value * -> 4 bytes average bit rate = 32-bit unsigned value *

    * Section 5 * -> 1 byte decoder specific descriptor type tag 8-bit hex value 0x05 * -> 3 bytes optional extended descriptor type tag string = 3 * 8-bit hex value * - types are 0x80,0x81,0xFE * -> 1 byte descriptor type length = 8-bit unsigned length * -> 1 byte Audio profile Id * - 5 bits Profile Id * - 3 bits Unknown * -> 8 bits other flags * - 3 bits unknown * - 2 bits is No of Channels * - 3 bits unknown *

    * Section 6 *

    * -> 1 byte SL config descriptor type tag = 8-bit hex value 0x06 * -> 3 bytes optional extended descriptor type tag string = 3 * 8-bit hex value * - types are 0x80,0x81,0xFE * -> 1 byte descriptor type length = 8-bit unsigned length * -> 1 byte SL value = 8-bit hex value set to 0x02 */ public class Mp4EsdsBox extends AbstractMp4Box { public static final int VERSION_FLAG_LENGTH = 1; public static final int OTHER_FLAG_LENGTH = 3; public static final int DESCRIPTOR_TYPE_LENGTH = 1; public static final int ES_ID_LENGTH = 2; public static final int STREAM_PRIORITY_LENGTH = 1; public static final int CONFIG_TYPE_LENGTH = 1; public static final int OBJECT_TYPE_LENGTH = 1; public static final int STREAM_TYPE_LENGTH = 1; public static final int BUFFER_SIZE_LENGTH = 3; public static final int MAX_BITRATE_LENGTH = 4; public static final int AVERAGE_BITRATE_LENGTH = 4; public static final int DESCRIPTOR_OBJECT_TYPE_LENGTH = 1; public static final int CHANNEL_FLAGS_LENGTH = 1; //Data we are tring to extract private Kind kind; private AudioProfile audioProfile; private int numberOfChannels; private int maxBitrate; private int avgBitrate; //Section indentifiers private static final int SECTION_THREE = 0x03; private static final int SECTION_FOUR = 0x04; private static final int SECTION_FIVE = 0x05; private static final int SECTION_SIX = 0x06; //Possible Section Filler values private static final int FILLER_START = 0x80; private static final int FILLER_OTHER = 0x81; private static final int FILLER_END = 0xFE; private static Map kindMap; private static Map audioProfileMap; static { //Create maps to speed up lookup from raw value to enum kindMap = new HashMap(); for (Kind next : Kind.values()) { kindMap.put(next.getId(), next); } audioProfileMap = new HashMap(); for (AudioProfile next : AudioProfile.values()) { audioProfileMap.put(next.getId(), next); } } /** * DataBuffer must start from from the start of the body * * @param header header info * @param dataBuffer data of box (doesnt include header data) */ public Mp4EsdsBox(Mp4BoxHeader header, ByteBuffer dataBuffer) { this.header = header; //Not currently used, as lengths can extend over more than one section i think int sectionThreeLength; int sectionFourLength; int sectionFiveLength; int sectionSixLength; //As explained earlier the length of this atom is not fixed so processing is a bit more difficult //Process Flags dataBuffer.position(dataBuffer.position() + VERSION_FLAG_LENGTH + OTHER_FLAG_LENGTH); //Process Section 3 if exists if (dataBuffer.get() == SECTION_THREE) { sectionThreeLength = processSectionHeader(dataBuffer); //Skip Other Section 3 data dataBuffer.position(dataBuffer.position() + ES_ID_LENGTH + STREAM_PRIORITY_LENGTH); } //Process Section 4 (to getFields type and bitrate) if (dataBuffer.get() == SECTION_FOUR) { sectionFourLength = processSectionHeader(dataBuffer); //kind (in iTunes) kind = kindMap.get((int) dataBuffer.get()); //Skip Other Section 4 data dataBuffer.position(dataBuffer.position() + STREAM_TYPE_LENGTH + BUFFER_SIZE_LENGTH); //Bit rates this.maxBitrate = Utils.getIntBE(dataBuffer, dataBuffer.position(), (dataBuffer.position() + MAX_BITRATE_LENGTH - 1)); dataBuffer.position(dataBuffer.position() + MAX_BITRATE_LENGTH); this.avgBitrate = Utils.getIntBE(dataBuffer, dataBuffer.position(), (dataBuffer.position() + AVERAGE_BITRATE_LENGTH - 1)); dataBuffer.position(dataBuffer.position() + AVERAGE_BITRATE_LENGTH); } //Process Section 5,(to getFields no of channels and audioprofile(profile in itunes)) if (dataBuffer.get() == SECTION_FIVE) { sectionFiveLength = processSectionHeader(dataBuffer); //Audio Profile audioProfile = audioProfileMap.get((dataBuffer.get() >> 3)); //Channels byte channelByte = dataBuffer.get(); numberOfChannels = (channelByte << 1) >> 4; } //Process Section 6, not needed ... } public int getNumberOfChannels() { return numberOfChannels; } /** * @return maximum bit rate (bps) */ public int getMaxBitrate() { return maxBitrate; } /** * @return average bit rate (bps) */ public int getAvgBitrate() { return avgBitrate; } /** * Process header, skipping filler bytes and calculating size * * @param dataBuffer * @return section header */ public int processSectionHeader(ByteBuffer dataBuffer) { int datalength; byte nextByte = dataBuffer.get(); if (((nextByte & 0xFF) == FILLER_START) || ((nextByte & 0xFF) == FILLER_OTHER) || ((nextByte & 0xFF) == FILLER_END)) { dataBuffer.get(); dataBuffer.get(); datalength = dataBuffer.get(); } else { datalength = nextByte; } return datalength; } /** * Only expext MPG_Audio, * TODO shouldnt matter if another type of audio, but something gone wrong if type of video * * @return the file type for the track */ public Kind getKind() { return kind; } /** * Get audio profile, usually AAC Low Complexity * * @return the audio profile */ public AudioProfile getAudioProfile() { return audioProfile; } /** * File type, held in Section 4 , only really expecting type 0x64 (AAC) */ public static enum Kind { V1(1), V2(2), MPEG4_VIDEO(32), MPEG4_AVC_SPS(33), MPEG4_AVC_PPS(34), MPEG4_AUDIO(64), MPEG2_SIMPLE_VIDEO(96), MPEG2_MAIN_VIDEO(97), MPEG2_SNR_VIDEO(98), MPEG2_SPATIAL_VIDEO(99), MPEG2_HIGH_VIDEO(100), MPEG2_422_VIDEO(101), MPEG4_ADTS_MAIN(102), MPEG4_ADTS_LOW_COMPLEXITY(103), MPEG4_ADTS_SCALEABLE_SAMPLING(104), MPEG2_ADTS_MAIN(105), MPEG1_VIDEO(106), MPEG1_ADTS(107), JPEG_VIDEO(108), PRIVATE_AUDIO(192), PRIVATE_VIDEO(208), PCM_LITTLE_ENDIAN_AUDIO(224), VORBIS_AUDIO(225), DOLBY_V3_AUDIO(226), ALAW_AUDIO(227), MULAW_AUDIO(228), ADPCM_AUDIO(229), PCM_BIG_ENDIAN_AUDIO(230), YV12_VIDEO(240), H264_VIDEO(241), H263_VIDEO(242), H261_VIDEO(243); private int id; Kind(int id) { this.id = id; } public int getId() { return id; } } /** * Audio profile, held in Section 5 this is usually type LOW_COMPLEXITY */ public static enum AudioProfile { MAIN(1, "Main"), LOW_COMPLEXITY(2, "Low Complexity"), SCALEABLE(3, "Scaleable Sample rate"), T_F(4, "T/F"), T_F_MAIN(5, "T/F Main"), T_F_LC(6, "T/F LC"), TWIN_VQ(7, "TWIN"), CELP(8, "CELP"), HVXC(9, "HVXC"), HILN(10, "HILN"), TTSI(11, "TTSI"), MAIN_SYNTHESIS(12, "MAIN_SYNTHESIS"), WAVETABLE(13, "WAVETABLE"),; private int id; private String description; /** * @param id it is stored as in file * @param description human readable description */ AudioProfile(int id, String description) { this.id = id; this.description = description; } public int getId() { return id; } public String getDescription() { return description; } } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/mp4/atom/Mp4AlacBox.java0000644000175000017500000000665311110103625027004 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.mp4.atom; import org.jaudiotagger.audio.generic.Utils; import org.jaudiotagger.audio.exceptions.CannotReadException; import java.nio.ByteBuffer; /** * AlacBox ( Apple Lossless Codec information description box), * * Normally occurs twice, the first ALAC contaisn the default values, the second ALAC within contains the real * values for this audio. */ public class Mp4AlacBox extends AbstractMp4Box { public static final int OTHER_FLAG_LENGTH = 4; private int maxSamplePerFrame; // 32bit private int unknown1; // 8bit private int sampleSize; // 8bit private int historyMult; // 8bit private int initialHistory; // 8bit private int kModifier; // 8bit private int channels; // 8bit private int unknown2; // 16bit private int maxCodedFrameSize; // 32bit private int bitRate; // 32bit private int sampleRate; // 32bit /** * DataBuffer must start from from the start of the body * * @param header header info * @param dataBuffer data of box (doesnt include header data) */ public Mp4AlacBox(Mp4BoxHeader header, ByteBuffer dataBuffer) { this.header = header; this.dataBuffer = dataBuffer; } public void processData() throws CannotReadException { //Skip version/other flags dataBuffer.position(dataBuffer.position() + OTHER_FLAG_LENGTH); maxSamplePerFrame = Utils.readUBEInt32(dataBuffer); unknown1 = Utils.readUInt8(dataBuffer); sampleSize = Utils.readUInt8(dataBuffer); historyMult = Utils.readUInt8(dataBuffer); initialHistory = Utils.readUInt8(dataBuffer); kModifier = Utils.readUInt8(dataBuffer); channels = Utils.readUInt8(dataBuffer); unknown2 = Utils.readUBEInt16(dataBuffer); maxCodedFrameSize = Utils.readUBEInt32(dataBuffer); bitRate = Utils.readUBEInt32(dataBuffer); sampleRate = Utils.readUBEInt32(dataBuffer); } public int getMaxSamplePerFrame() { return maxSamplePerFrame; } public int getUnknown1() { return unknown1; } public int getSampleSize() { return sampleSize; } public int getHistoryMult() { return historyMult; } public int getInitialHistory() { return initialHistory; } public int getKModifier() { return kModifier; } public int getChannels() { return channels; } public int getUnknown2() { return unknown2; } public int getMaxCodedFrameSize() { return maxCodedFrameSize; } public int getBitRate() { return bitRate; } public int getSampleRate() { return sampleRate; } public String toString() { String s = "maxSamplePerFrame:" + maxSamplePerFrame + "unknown1:"+ unknown1 + "sampleSize:"+sampleSize + "historyMult:"+historyMult + "initialHistory:"+initialHistory + "kModifier:"+kModifier + "channels:"+channels + "unknown2 :"+unknown2 + "maxCodedFrameSize:"+maxCodedFrameSize + "bitRate:"+bitRate + "sampleRate:"+sampleRate; return s; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/mp4/atom/Mp4MvhdBox.java0000644000175000017500000000645311277026507027061 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2003-2005 Raphaël Slinckx * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.audio.mp4.atom; import org.jaudiotagger.audio.generic.Utils; import java.nio.ByteBuffer; /** * MvhdBox (movie (presentation) header box) *

    *

    This MP4Box contains important audio information we need. It can be used to calculate track length, * depending on the version field this can be in either short or long format */ public class Mp4MvhdBox extends AbstractMp4Box { public static final int VERSION_FLAG_POS = 0; public static final int OTHER_FLAG_POS = 1; public static final int CREATED_DATE_SHORT_POS = 4; public static final int MODIFIED_DATE_SHORT_POS = 8; public static final int TIMESCALE_SHORT_POS = 12; public static final int DURATION_SHORT_POS = 16; public static final int CREATED_DATE_LONG_POS = 4; public static final int MODIFIED_DATE_LONG_POS = 12; public static final int TIMESCALE_LONG_POS = 20; public static final int DURATION_LONG_POS = 24; public static final int VERSION_FLAG_LENGTH = 1; public static final int OTHER_FLAG_LENGTH = 3; public static final int CREATED_DATE_SHORT_LENGTH = 4; public static final int MODIFIED_DATE_SHORT_LENGTH = 4; public static final int CREATED_DATE_LONG_LENGTH = 8; public static final int MODIFIED_DATE_LONG_LENGTH = 8; public static final int TIMESCALE_LENGTH = 4; public static final int DURATION_SHORT_LENGTH = 4; public static final int DURATION_LONG_LENGTH = 8; private static final int LONG_FORMAT = 1; private int timeScale; private long timeLength; /** * @param header header info * @param dataBuffer data of box (doesnt include header data) */ public Mp4MvhdBox(Mp4BoxHeader header, ByteBuffer dataBuffer) { this.header = header; byte version = dataBuffer.get(VERSION_FLAG_POS); if (version == LONG_FORMAT) { this.timeScale = Utils.getIntBE(dataBuffer, TIMESCALE_LONG_POS, (TIMESCALE_LONG_POS + TIMESCALE_LENGTH - 1)); this.timeLength = Utils.getLongBE(dataBuffer, DURATION_LONG_POS, (DURATION_LONG_POS + DURATION_LONG_LENGTH - 1)); } else { this.timeScale = Utils.getIntBE(dataBuffer, TIMESCALE_SHORT_POS, (TIMESCALE_SHORT_POS + TIMESCALE_LENGTH - 1)); this.timeLength = Utils.getIntBE(dataBuffer, DURATION_SHORT_POS, (DURATION_SHORT_POS + DURATION_SHORT_LENGTH - 1)); } } public int getLength() { return (int) (this.timeLength / this.timeScale); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/mp4/atom/NullPadding.java0000644000175000017500000000114311111013054027275 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.mp4.atom; import java.nio.ByteBuffer; /** * Some mp4s contain null padding at the end of the file, possibly do with gapless playback. This is not really * allowable but seeing as seems to cccur in files encoded with iTunes 6 and players such as Winamp and iTunes deal * with it we should * * It isnt actually a box, but it helps to keep as a subclass of this type */ public class NullPadding extends Mp4BoxHeader { public NullPadding(long startPosition,long fileSize) { setFilePos(startPosition); length=((int)(fileSize - startPosition)); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/mp4/atom/Mp4DrmsBox.java0000644000175000017500000000262711110103625027046 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.mp4.atom; import org.jaudiotagger.audio.exceptions.CannotReadException; import java.nio.ByteBuffer; /** * DrmsBox Replaces mp4a box on drm files *

    * Need to skip over data in order to find esds atom *

    * Specification not known, so just look for byte by byte 'esds' and then step back four bytes for size */ public class Mp4DrmsBox extends AbstractMp4Box { /** * @param header header info * @param dataBuffer data of box (doesnt include header data) */ public Mp4DrmsBox(Mp4BoxHeader header, ByteBuffer dataBuffer) { this.header = header; this.dataBuffer = dataBuffer; } /** * Process direct data * * @throws CannotReadException */ public void processData() throws CannotReadException { while (dataBuffer.hasRemaining()) { byte next = dataBuffer.get(); if (next != (byte) 'e') { continue; } //Have we found esds identifier, if so adjust buffer to start of esds atom ByteBuffer tempBuffer = dataBuffer.slice(); if ((tempBuffer.get() == (byte) 's') & (tempBuffer.get() == (byte) 'd') & (tempBuffer.get() == (byte) 's')) { dataBuffer.position(dataBuffer.position() - 1 - Mp4BoxHeader.OFFSET_LENGTH); return; } } } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/mp4/atom/Mp4FreeBox.java0000644000175000017500000000274011117741073027032 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.mp4.atom; import org.jaudiotagger.audio.generic.Utils; import org.jaudiotagger.audio.mp4.Mp4NotMetaFieldKey; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.nio.ByteBuffer; /** * FreeBox ( padding) *

    *

    There are usually two free boxes, one beneath the meta atom and one toplevel atom */ public class Mp4FreeBox extends AbstractMp4Box { /** * Construct a new FreeBox containing datasize padding (i.e doesnt include header size) * * @param datasize padding size */ public Mp4FreeBox(int datasize) { try { //Header header = new Mp4BoxHeader(); ByteArrayOutputStream headerBaos = new ByteArrayOutputStream(); headerBaos.write(Utils.getSizeBEInt32(Mp4BoxHeader.HEADER_LENGTH + datasize)); headerBaos.write(Utils.getDefaultBytes(Mp4NotMetaFieldKey.FREE.getFieldName(), "ISO-8859-1")); header.update(ByteBuffer.wrap(headerBaos.toByteArray())); //Body ByteArrayOutputStream freeBaos = new ByteArrayOutputStream(); for (int i = 0; i < datasize; i++) { freeBaos.write(0x0); } dataBuffer = ByteBuffer.wrap(freeBaos.toByteArray()); } catch (IOException ioe) { //This should never happen as were not actually writing to/from a file throw new RuntimeException(ioe); } } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/mp4/atom/Mp4FtypBox.java0000644000175000017500000001154411117741073027075 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.mp4.atom; import org.jaudiotagger.audio.exceptions.CannotReadException; import org.jaudiotagger.audio.generic.Utils; import java.nio.ByteBuffer; import java.nio.charset.CharacterCodingException; import java.nio.charset.Charset; import java.nio.charset.CharsetDecoder; import java.nio.charset.CodingErrorAction; import java.util.ArrayList; import java.util.List; /** * Ftyp (File Type) is the first atom, can be used to help identify the mp4 container type */ public class Mp4FtypBox extends AbstractMp4Box { private String majorBrand; private int majorBrandVersion; private List compatibleBrands = new ArrayList(); private static final int MAJOR_BRAND_POS = 0; private static final int MAJOR_BRAND_LENGTH = 4; private static final int MAJOR_BRAND_VERSION_POS = 4; private static final int MAJOR_BRAND_VERSION_LENGTH = 4; private static final int COMPATIBLE_BRAND_LENGTH = 4; //Can be multiple of these /** * @param header header info * @param dataBuffer data of box (doesnt include header data) */ public Mp4FtypBox(Mp4BoxHeader header, ByteBuffer dataBuffer) { this.header = header; this.dataBuffer = dataBuffer; } public void processData() throws CannotReadException { CharsetDecoder decoder = Charset.forName("ISO-8859-1").newDecoder(); try { majorBrand = decoder.decode((ByteBuffer) dataBuffer.slice().limit(MAJOR_BRAND_LENGTH)).toString(); } catch (CharacterCodingException cee) { //Ignore } dataBuffer.position(dataBuffer.position() + MAJOR_BRAND_LENGTH); majorBrandVersion = Utils.getIntBE(dataBuffer, dataBuffer.position(), (dataBuffer.position() + MAJOR_BRAND_VERSION_LENGTH - 1)); dataBuffer.position(dataBuffer.position() + MAJOR_BRAND_VERSION_LENGTH); while ((dataBuffer.position() < dataBuffer.limit()) && (dataBuffer.limit() - dataBuffer.position() >= COMPATIBLE_BRAND_LENGTH)) { decoder.onMalformedInput(CodingErrorAction.REPORT); decoder.onMalformedInput(CodingErrorAction.REPORT); try { String brand = decoder.decode((ByteBuffer) dataBuffer.slice().limit(COMPATIBLE_BRAND_LENGTH)).toString(); //Sometimes just extra groups of four nulls if (!brand.equals("\u0000\u0000\u0000\u0000")) { compatibleBrands.add(brand); } } catch (CharacterCodingException cee) { //Ignore } dataBuffer.position(dataBuffer.position() + COMPATIBLE_BRAND_LENGTH); } } public String toString() { String info = "Major Brand:" + majorBrand + "Version:" + majorBrandVersion; if (compatibleBrands.size() > 0) { info += "Compatible:"; for (String brand : compatibleBrands) { info += brand; info += ","; } return info.substring(0, info.length() - 1); } return info; } public String getMajorBrand() { return majorBrand; } public int getMajorBrandVersion() { return majorBrandVersion; } public List getCompatibleBrands() { return compatibleBrands; } /** * Major brand, helps identify whats contained in the file, used by major and compatible brands * but this is not an exhaustive list, so for that reason we dont force the values read from the file * to tie in with this enum. */ public static enum Brand { ISO14496_1_BASE_MEDIA("isom", "ISO 14496-1"), ISO14496_12_BASE_MEDIA("iso2", "ISO 14496-12"), ISO14496_1_VERSION_1("mp41", "ISO 14496-1"), ISO14496_1_VERSION_2("mp42", "ISO 14496-2:Multi track with BIFS scenes"), QUICKTIME_MOVIE("qt ", "Original Quicktime"), JVT_AVC("avc1", "JVT"), THREEG_MOBILE_MP4("MPA ", "3G Mobile"), APPLE_AAC_AUDIO("M4P ", "Apple Audio"), AES_ENCRYPTED_AUDIO("M4B ", "Apple encrypted Audio"), APPLE_AUDIO("mp71", "Apple Audio"), ISO14496_12_MPEG7_METADATA("mp71", "MAIN_SYNTHESIS"), APPLE_AUDIO_ONLY("M4A ", "M4A Audio"), //SOmetimes used by protected mutli track audio ; private String id; private String description; /** * @param id it is stored as in file * @param description human readable description */ Brand(String id, String description) { this.id = id; this.description = description; } public String getId() { return id; } public String getDescription() { return description; } } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/mp4/atom/Mp4MetaBox.java0000644000175000017500000000350111115724327027034 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.mp4.atom; import org.jaudiotagger.audio.exceptions.CannotReadException; import org.jaudiotagger.audio.mp4.Mp4NotMetaFieldKey; import org.jaudiotagger.logging.ErrorMessage; import java.nio.ByteBuffer; /** * This MP4 MetaBox is the parent of metadata, it usually contains four bytes of data * that needs to be processed before we can examine the children. But I also have a file that caontsins * meta (and no udta) that does not have this children data. */ public class Mp4MetaBox extends AbstractMp4Box { public static final int FLAGS_LENGTH = 4; /** * @param header header info * @param dataBuffer data of box (doesnt include header data) */ public Mp4MetaBox(Mp4BoxHeader header, ByteBuffer dataBuffer) { this.header = header; this.dataBuffer = dataBuffer; } public void processData() throws CannotReadException { //4-skip the meta flags and check they are the meta flags byte[] b = new byte[FLAGS_LENGTH]; dataBuffer.get(b); if (b[0] != 0) { throw new CannotReadException(ErrorMessage.MP4_FILE_META_ATOM_CHILD_DATA_NOT_NULL.getMsg()); } } /** * Create an iTunes style Meta box * *

    Useful when writing to mp4 that previously didn't contain an mp4 meta atom

    * * @param childrenSize * @return */ public static Mp4MetaBox createiTunesStyleMetaBox(int childrenSize) { Mp4BoxHeader metaHeader = new Mp4BoxHeader(Mp4NotMetaFieldKey.META.getFieldName()); metaHeader.setLength(Mp4BoxHeader.HEADER_LENGTH + Mp4MetaBox.FLAGS_LENGTH + childrenSize); ByteBuffer metaData = ByteBuffer.allocate(Mp4MetaBox.FLAGS_LENGTH); Mp4MetaBox metaBox = new Mp4MetaBox(metaHeader,metaData); return metaBox; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/mp4/atom/Mp4StsdBox.java0000644000175000017500000000236711110103625027057 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.mp4.atom; import org.jaudiotagger.audio.exceptions.CannotReadException; import java.nio.ByteBuffer; /** * StsdBox ( sample (frame encoding) description box) *

    *

    4 bytes version/flags = byte hex version + 24-bit hex flags * (current = 0) * - > 4 bytes number of descriptions = long unsigned total * (default = 1) * Then if audio contains mp4a,alac or drms box */ public class Mp4StsdBox extends AbstractMp4Box { public static final int VERSION_FLAG_POS = 0; public static final int OTHER_FLAG_POS = 1; public static final int NO_OF_DESCRIPTIONS_POS = 4; public static final int VERSION_FLAG_LENGTH = 1; public static final int OTHER_FLAG_LENGTH = 3; public static final int NO_OF_DESCRIPTIONS_POS_LENGTH = 4; /** * @param header header info * @param dataBuffer data of box (doesnt include header data) */ public Mp4StsdBox(Mp4BoxHeader header, ByteBuffer dataBuffer) { this.header = header; this.dataBuffer = dataBuffer; } public void processData() throws CannotReadException { //Skip the data dataBuffer.position(dataBuffer.position() + VERSION_FLAG_LENGTH + OTHER_FLAG_LENGTH + NO_OF_DESCRIPTIONS_POS_LENGTH); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/mp4/atom/Mp4HdlrBox.java0000644000175000017500000001427111276777123027057 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.mp4.atom; import org.jaudiotagger.audio.exceptions.CannotReadException; import org.jaudiotagger.audio.mp4.Mp4NotMetaFieldKey; import java.nio.ByteBuffer; import java.nio.charset.CharacterCodingException; import java.nio.charset.Charset; import java.nio.charset.CharsetDecoder; import java.util.HashMap; import java.util.Map; /** * HdlrBox ( Handler box), *

    * Describes the type of metadata in the following ilst or minf atom */ public class Mp4HdlrBox extends AbstractMp4Box { public static final int VERSION_FLAG_LENGTH = 1; public static final int OTHER_FLAG_LENGTH = 3; public static final int RESERVED_FLAG_LENGTH = 4; public static final int HANDLER_LENGTH = 4; public static final int RESERVED1_LENGTH = 4; public static final int RESERVED2_LENGTH = 4; public static final int RESERVED3_LENGTH = 4; public static final int NAME_LENGTH = 2; public static final int HANDLER_POS = VERSION_FLAG_LENGTH + OTHER_FLAG_LENGTH + RESERVED_FLAG_LENGTH; public static final int RESERVED1_POS = HANDLER_POS + HANDLER_LENGTH; //Size used by iTunes, but other application could use different size because name field is variable public static final int ITUNES_META_HDLR_DAT_LENGTH = VERSION_FLAG_LENGTH + OTHER_FLAG_LENGTH + RESERVED_FLAG_LENGTH + HANDLER_LENGTH + RESERVED1_LENGTH + RESERVED2_LENGTH + RESERVED3_LENGTH + NAME_LENGTH; private int reserved; // 32 bit private String handlerType; // 4 bytes; private String name; // Variable length but 4 bytes in existing files private MediaDataType mediaDataType; private static Map mediaDataTypeMap; static { //Create maps to speed up lookup from raw value to enum mediaDataTypeMap = new HashMap(); for (MediaDataType next : MediaDataType.values()) { mediaDataTypeMap.put(next.getId(), next); } } /** * DataBuffer must start from from the start of the body * * @param header header info * @param dataBuffer data of box (doesnt include header data) */ public Mp4HdlrBox(Mp4BoxHeader header, ByteBuffer dataBuffer) { this.header = header; this.dataBuffer = dataBuffer; } public void processData() throws CannotReadException { //Skip other flags dataBuffer.position(dataBuffer.position() + VERSION_FLAG_LENGTH + OTHER_FLAG_LENGTH + RESERVED_FLAG_LENGTH); CharsetDecoder decoder = Charset.forName("ISO-8859-1").newDecoder(); try { handlerType = decoder.decode((ByteBuffer) dataBuffer.slice().limit(HANDLER_LENGTH)).toString(); } catch (CharacterCodingException cee) { //Ignore } //To getFields human readable name mediaDataType = mediaDataTypeMap.get( handlerType); } public String getHandlerType() { return handlerType; } public MediaDataType getMediaDataType() { return mediaDataType; } public String toString() { String s = "handlerType:" + handlerType + ":human readable:"+mediaDataType.getDescription(); return s; } public static enum MediaDataType { ODSM("odsm", "ObjectDescriptorStream - defined in ISO/IEC JTC1/SC29/WG11 - CODING OF MOVING PICTURES AND AUDIO"), CRSM("crsm", "ClockReferenceStream - defined in ISO/IEC JTC1/SC29/WG11 - CODING OF MOVING PICTURES AND AUDIO"), SDSM("sdsm", "SceneDescriptionStream - defined in ISO/IEC JTC1/SC29/WG11 - CODING OF MOVING PICTURES AND AUDIO"), M7SM("m7sm", "MPEG7Stream - defined in ISO/IEC JTC1/SC29/WG11 - CODING OF MOVING PICTURES AND AUDIO"), OCSM("ocsm", "ObjectContentInfoStream - defined in ISO/IEC JTC1/SC29/WG11 - CODING OF MOVING PICTURES AND AUDIO"), IPSM("ipsm", "IPMP Stream - defined in ISO/IEC JTC1/SC29/WG11 - CODING OF MOVING PICTURES AND AUDIO"), MJSM("mjsm", "MPEG-J Stream - defined in ISO/IEC JTC1/SC29/WG11 - CODING OF MOVING PICTURES AND AUDIO"), MDIR("mdir", "Apple Meta Data iTunes Reader"), MP7B("mp7b", "MPEG-7 binary XML"), MP7T("mp7t", "MPEG-7 XML"), VIDE("vide", "Video Track"), SOUN("soun", "Sound Track"), HINT("hint", "Hint Track"), APPL("appl", "Apple specific"), META("meta", "Timed Metadata track - defined in ISO/IEC JTC1/SC29/WG11 - CODING OF MOVING PICTURES AND AUDIO"),; private String id; private String description; MediaDataType(String id, String description) { this.id = id; this.description=description; } public String getId() { return id; } public String getDescription() { return description; } } /** * Create an iTunes style Hdlr box for use within Meta box * *

    Useful when writing to mp4 that previously didn't contain an mp4 meta atom

    * *

    Doesnt write the child data but uses it to se the header length, only sets the atoms immediate * data

    * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.audio.mp4.atom; import org.jaudiotagger.audio.exceptions.InvalidBoxHeaderException; import org.jaudiotagger.audio.exceptions.NullBoxIdException; import org.jaudiotagger.audio.generic.Utils; import org.jaudiotagger.logging.ErrorMessage; import java.io.IOException; import java.io.RandomAccessFile; import java.io.UnsupportedEncodingException; import java.nio.ByteBuffer; import java.util.logging.Logger; /** * Everything in MP4s are held in boxes (formally known as atoms), they are held as a hierachial tree within the MP4. *

    * We are most interested in boxes that are used to hold metadata, but we have to know about some other boxes * as well in order to find them. *

    * All boxes consist of a 4 byte box length (big Endian), and then a 4 byte identifier, this is the header * which is model in this class. *

    * The length includes the length of the box including the identifier and the length itself. * Then they may contain data and/or sub boxes, if they contain subboxes they are known as a parent box. Parent boxes * shouldn't really contain data, but sometimes they do. *

    * Parent boxes length includes the length of their immediate sub boxes *

    * This class is normally used by instantiating with the empty constructor, then use the update method * to pass the header data which is used to read the identifier and the the size of the box */ public class Mp4BoxHeader { // Logger Object public static Logger logger = Logger.getLogger("org.jaudiotagger.audio.mp4.atom"); public static final int OFFSET_POS = 0; public static final int IDENTIFIER_POS = 4; public static final int OFFSET_LENGTH = 4; public static final int IDENTIFIER_LENGTH = 4; public static final int HEADER_LENGTH = OFFSET_LENGTH + IDENTIFIER_LENGTH; //Box identifier private String id; //Box length protected int length; //If reading from file , this can be used to hold the headers position in the file private long filePos; //Raw Header data protected ByteBuffer dataBuffer; //Mp4 uses UTF-8 for all text public static final String CHARSET_UTF_8 = "UTF-8"; /** * Construct empty header *

    * Can be populated later with update method */ public Mp4BoxHeader() { } /** * Construct header to allow manual creation of header for writing to file *

    * @param id */ public Mp4BoxHeader(String id) { if(id.length()!=IDENTIFIER_LENGTH) { throw new RuntimeException("Invalid length:atom idenifier should always be 4 characters long"); } dataBuffer = ByteBuffer.allocate(HEADER_LENGTH); try { this.id = id; dataBuffer.put(4, id.getBytes("ISO-8859-1")[0]); dataBuffer.put(5, id.getBytes("ISO-8859-1")[1]); dataBuffer.put(6, id.getBytes("ISO-8859-1")[2]); dataBuffer.put(7, id.getBytes("ISO-8859-1")[3]); } catch(UnsupportedEncodingException uee) { //Should never happen throw new RuntimeException(uee); } } /** * Construct header *

    * Create header using headerdata, expected to find header at headerdata current position *

    * Note after processing adjusts position to immediately after header * * @param headerData */ public Mp4BoxHeader(ByteBuffer headerData) { update(headerData); } /** * Create header using headerdata, expected to find header at headerdata current position *

    * Note after processing adjusts position to immediately after header * * @param headerData */ public void update(ByteBuffer headerData) { //Read header data into byte array byte[] b = new byte[HEADER_LENGTH]; headerData.get(b); //Keep reference to copy of RawData dataBuffer = ByteBuffer.wrap(b); //Calculate box size this.length = Utils.getIntBE(b, OFFSET_POS, OFFSET_LENGTH - 1); //Calculate box id this.id = Utils.getString(b, IDENTIFIER_POS, IDENTIFIER_LENGTH, "ISO-8859-1"); logger.finest("Mp4BoxHeader id:"+id+":length:"+length); if (id.equals("\0\0\0\0")) { throw new NullBoxIdException(ErrorMessage.MP4_UNABLE_TO_FIND_NEXT_ATOM_BECAUSE_IDENTIFIER_IS_INVALID.getMsg(id)); } if(length * This will modify the databuffer accordingly * * @param length */ public void setLength(int length) { byte[] headerSize = Utils.getSizeBEInt32(length); dataBuffer.put(0, headerSize[0]); dataBuffer.put(1, headerSize[1]); dataBuffer.put(2, headerSize[2]); dataBuffer.put(3, headerSize[3]); this.length = length; } /** * Set the Id. *

    * Allows you to manully create a header * This will modify the databuffer accordingly * * @param length */ public void setId(int length) { byte[] headerSize = Utils.getSizeBEInt32(length); dataBuffer.put(5, headerSize[0]); dataBuffer.put(6, headerSize[1]); dataBuffer.put(7, headerSize[2]); dataBuffer.put(8, headerSize[3]); this.length = length; } /** * @return the 8 byte header buffer */ public ByteBuffer getHeaderData() { dataBuffer.rewind(); return dataBuffer; } /** * @return the length of the data only (does not include the header size) */ public int getDataLength() { return length - HEADER_LENGTH; } public String toString() { return "Box " + id + ":length" + length + ":filepos:" + filePos; } /** * @return UTF_8 (always used by Mp4) */ public String getEncoding() { return CHARSET_UTF_8; } /** * Seek for box with the specified id starting from the current location of filepointer, *

    * Note it wont find the box if it is contained with a level below the current level, nor if we are * at a parent atom that also contains data and we havent yet processed the data. It will work * if we are at the start of a child box even if it not the required box as long as the box we are * looking for is the same level (or the level above in some cases). * * @param raf * @param id * @throws java.io.IOException * @return */ public static Mp4BoxHeader seekWithinLevel(RandomAccessFile raf, String id) throws IOException { logger.finer("Started searching for:" + id + " in file at:" + raf.getChannel().position()); Mp4BoxHeader boxHeader = new Mp4BoxHeader(); ByteBuffer headerBuffer = ByteBuffer.allocate(HEADER_LENGTH); int bytesRead = raf.getChannel().read(headerBuffer); if (bytesRead != HEADER_LENGTH) { return null; } headerBuffer.rewind(); boxHeader.update(headerBuffer); while (!boxHeader.getId().equals(id)) { logger.finer("Found:" + boxHeader.getId() + " Still searching for:" + id + " in file at:" + raf.getChannel().position()); //Something gone wrong probably not at the start of an atom so return null; if (boxHeader.getLength() < Mp4BoxHeader.HEADER_LENGTH) { return null; } int noOfBytesSkipped = raf.skipBytes(boxHeader.getDataLength()); logger.finer("Skipped:" + noOfBytesSkipped); if (noOfBytesSkipped < boxHeader.getDataLength()) { return null; } headerBuffer.rewind(); bytesRead = raf.getChannel().read(headerBuffer); logger.finer("Header Bytes Read:" + bytesRead); headerBuffer.rewind(); if (bytesRead == Mp4BoxHeader.HEADER_LENGTH) { boxHeader.update(headerBuffer); } else { return null; } } return boxHeader; } /** * Seek for box with the specified id starting from the current location of filepointer, *

    * Note it won't find the box if it is contained with a level below the current level, nor if we are * at a parent atom that also contains data and we havent yet processed the data. It will work * if we are at the start of a child box even if it not the required box as long as the box we are * looking for is the same level (or the level above in some cases). * * @param data * @param id * @throws java.io.IOException * @return */ public static Mp4BoxHeader seekWithinLevel(ByteBuffer data, String id) throws IOException { logger.finer("Started searching for:" + id + " in bytebuffer at" + data.position()); Mp4BoxHeader boxHeader = new Mp4BoxHeader(); if (data.remaining() >= Mp4BoxHeader.HEADER_LENGTH) { boxHeader.update(data); } else { return null; } while (!boxHeader.getId().equals(id)) { logger.finer("Found:" + boxHeader.getId() + " Still searching for:" + id + " in bytebuffer at" + data.position()); //Something gone wrong probably not at the start of an atom so return null; if (boxHeader.getLength() < Mp4BoxHeader.HEADER_LENGTH) { return null; } if(data.remaining()<(boxHeader.getLength() - HEADER_LENGTH)) { //i.e Could happen if Moov header had size incorrectly recorded return null; } data.position(data.position() + (boxHeader.getLength() - HEADER_LENGTH)); if (data.remaining() >= Mp4BoxHeader.HEADER_LENGTH) { boxHeader.update(data); } else { return null; } } logger.finer("Found:" + id + " in bytebuffer at" + data.position()); return boxHeader; } /** * @return location in file of the start of file header (i.e where the 4 byte length field starts) */ public long getFilePos() { return filePos; } /** * Set location in file of the start of file header (i.e where the 4 byte length field starts) * * @param filePos */ public void setFilePos(long filePos) { this.filePos = filePos; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/mp4/Mp4TagWriter.java0000644000175000017500000011064511277026507026461 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2003-2005 Raphaël Slinckx * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.audio.mp4; import org.jaudiotagger.audio.exceptions.CannotReadException; import org.jaudiotagger.audio.exceptions.CannotWriteException; import org.jaudiotagger.audio.mp4.atom.*; import org.jaudiotagger.logging.ErrorMessage; import org.jaudiotagger.tag.Tag; import org.jaudiotagger.tag.mp4.Mp4Tag; import org.jaudiotagger.tag.mp4.Mp4TagCreator; import javax.swing.tree.DefaultMutableTreeNode; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.util.logging.Logger; /** * Writes metadata from mp4, the metadata tags are held under the ilst atom as shown below *

    *

    * When writing changes the size of all the atoms upto ilst has to be recalculated, then if the size of * the metadata is increased the size of the free atom (below meta) should be reduced accordingly or vice versa. * If the size of the metadata has increased by more than the size of the free atom then the size of meta, udta * and moov should be recalculated and the top level free atom reduced accordingly * If there is not enough space even if using both of the free atoms, then the mdat atom has to be shifted down * accordingly to make space, and the stco atom has to have its offsets to mdat chunks table adjusted accordingly. * * Exceptions are that the meta/udta/ilst do not currently exist, in which udta/meta/ilst are created. Note it is valid * to have meta/ilst without udta but this is less common so we always try to write files according to the Apple/iTunes * specification. * *

    *

    *

     * |--- ftyp
     * |--- moov
     * |......|
     * |......|----- mvdh
     * |......|----- trak
     * |......|----- udta
     * |..............|
     * |..............|-- meta
     * |....................|
     * |....................|-- hdlr
     * |....................|-- ilst
     * |....................|.. ..|
     * |....................|.....|---- @nam (Optional for each metadatafield)
     * |....................|.....|.......|-- data
     * |....................|.....|....... ecetera
     * |....................|.....|---- ---- (Optional for reverse dns field)
     * |....................|.............|-- mean
     * |....................|.............|-- name
     * |....................|.............|-- data
     * |....................|................ ecetere
     * |....................|-- free
     * |--- free
     * |--- mdat
     * 
    */ public class Mp4TagWriter { // Logger Object public static Logger logger = Logger.getLogger("org.jaudiotagger.tag.mp4"); private Mp4TagCreator tc = new Mp4TagCreator(); /** * Replace the ilst metadata *

    * Because it is the same size as the original data nothing else has to be modified * * @param rawIlstData * @param oldIlstSize * @param startIstWithinFile * @param fileReadChannel * @param fileWriteChannel * @throws CannotWriteException * @throws IOException */ private void writeMetadataSameSize(ByteBuffer rawIlstData, long oldIlstSize, long startIstWithinFile, FileChannel fileReadChannel, FileChannel fileWriteChannel) throws CannotWriteException, IOException { fileReadChannel.position(0); fileWriteChannel.transferFrom(fileReadChannel, 0, startIstWithinFile); fileWriteChannel.position(startIstWithinFile); fileWriteChannel.write(rawIlstData); fileReadChannel.position(startIstWithinFile + oldIlstSize); fileWriteChannel.transferFrom(fileReadChannel, fileWriteChannel.position(), fileReadChannel.size() - fileReadChannel.position()); } /** * When the size of the metadata has changed and it cant be compensated for by free atom * we have to adjust the size of the size field upto the moovheader level for the udta atom and * its child meta atom. * * @param moovHeader * @param moovBuffer * @param sizeAdjustment can be negative or positive * * @param udtaHeader * @param metaHeader * @return * @throws java.io.IOException */ private void adjustSizeOfMoovHeader (Mp4BoxHeader moovHeader, ByteBuffer moovBuffer, int sizeAdjustment, Mp4BoxHeader udtaHeader, Mp4BoxHeader metaHeader) throws IOException { //Adjust moov header size, adjusts the underlying buffer moovHeader.setLength(moovHeader.getLength() + sizeAdjustment); //Edit the fields in moovBuffer (note moovbuffer doesnt include header) if(udtaHeader!=null) { //Write the updated udta atom header to moov buffer udtaHeader.setLength(udtaHeader.getLength() + sizeAdjustment); moovBuffer.position((int)(udtaHeader.getFilePos() - moovHeader.getFilePos() - Mp4BoxHeader.HEADER_LENGTH)); moovBuffer.put(udtaHeader.getHeaderData()); } if(metaHeader!=null) { //Write the updated udta atom header to moov buffer metaHeader.setLength(metaHeader.getLength() + sizeAdjustment); moovBuffer.position((int)(metaHeader.getFilePos() - moovHeader.getFilePos()- Mp4BoxHeader.HEADER_LENGTH)); moovBuffer.put(metaHeader.getHeaderData()); } } private void createMetadataAtoms (Mp4BoxHeader moovHeader, ByteBuffer moovBuffer, int sizeAdjustment, Mp4BoxHeader udtaHeader, Mp4BoxHeader metaHeader) throws IOException { //Adjust moov header size moovHeader.setLength(moovHeader.getLength() + sizeAdjustment); } /** * Write tag to rafTemp file * * @param tag tag data * @param raf current file * @param rafTemp temporary file for writing * @throws CannotWriteException * @throws IOException */ public void write(Tag tag, RandomAccessFile raf, RandomAccessFile rafTemp) throws CannotWriteException, IOException { logger.info("Started writing tag data"); //Go through every field constructing the data that will appear starting from ilst box ByteBuffer rawIlstData = tc.convert(tag); rawIlstData.rewind(); //Read Channel for reading from old file FileChannel fileReadChannel = raf.getChannel(); //Write channel for writing to new file FileChannel fileWriteChannel = rafTemp.getChannel(); //Reference to a Box Header Mp4BoxHeader boxHeader; //TODO we shouldn't need all these variables, and some are very badly named - used by new and old methods int oldIlstSize = 0; int relativeIlstposition; int relativeIlstEndPosition; int startIlstWithinFile; int newIlstSize; int oldMetaLevelFreeAtomSize; long extraDataSize; int level1SearchPosition = 0; int topLevelFreePosition; int topLevelFreeSize; boolean topLevelFreeAtomComesBeforeMdatAtom; Mp4BoxHeader topLevelFreeHeader; Mp4AtomTree atomTree; //Build tree to check file is readable try { atomTree = new Mp4AtomTree(raf, false); } catch (CannotReadException cre) { throw new CannotWriteException(cre.getMessage()); } //Moov Box header Mp4BoxHeader moovHeader = atomTree.getBoxHeader(atomTree.getMoovNode()); long positionWithinFileAfterFindingMoovHeader = moovHeader.getFilePos() + Mp4BoxHeader.HEADER_LENGTH; Mp4StcoBox stco = atomTree.getStco(); Mp4BoxHeader ilstHeader = atomTree.getBoxHeader(atomTree.getIlstNode()); Mp4BoxHeader udtaHeader = atomTree.getBoxHeader(atomTree.getUdtaNode()); Mp4BoxHeader metaHeader = atomTree.getBoxHeader(atomTree.getMetaNode()); Mp4BoxHeader hdlrMetaHeader = atomTree.getBoxHeader(atomTree.getHdlrWithinMetaNode()); Mp4BoxHeader hdlrMdiaHeader = atomTree.getBoxHeader(atomTree.getHdlrWithinMdiaNode()); Mp4BoxHeader mdatHeader = atomTree.getBoxHeader(atomTree.getMdatNode()); //Unable to find audio so no chance of saving any changes if(mdatHeader==null) { throw new CannotWriteException(ErrorMessage.MP4_CHANGES_TO_FILE_FAILED_CANNOT_FIND_AUDIO.getMsg()); } Mp4BoxHeader trakHeader = (Mp4BoxHeader)atomTree.getTrakNodes().get(0).getUserObject(); ByteBuffer moovBuffer = atomTree.getMoovBuffer(); //Work out if we/what kind of metadata hierachy we currently have in the file //Udta if(udtaHeader !=null) { //Meta if(metaHeader != null) { //ilst - record where ilst is,and where it ends if (ilstHeader != null) { oldIlstSize = ilstHeader.getLength(); //Relative means relative to moov buffer after moov header startIlstWithinFile = (int) ilstHeader.getFilePos(); relativeIlstposition = (int) (startIlstWithinFile - (moovHeader.getFilePos() + Mp4BoxHeader.HEADER_LENGTH)); relativeIlstEndPosition = relativeIlstposition + ilstHeader.getLength(); } else { //Place ilst immediately after existing hdlr atom if(hdlrMetaHeader!=null) { startIlstWithinFile = (int) hdlrMetaHeader.getFilePos() + hdlrMetaHeader.getLength(); relativeIlstposition = (int) (startIlstWithinFile - (moovHeader.getFilePos() + Mp4BoxHeader.HEADER_LENGTH)); relativeIlstEndPosition = relativeIlstposition; } //Place ilst after data fields in meta atom //TODO Should we create a hdlr atom else { startIlstWithinFile = (int) metaHeader.getFilePos() + Mp4BoxHeader.HEADER_LENGTH + Mp4MetaBox.FLAGS_LENGTH; relativeIlstposition = (int) ((startIlstWithinFile) - (moovHeader.getFilePos() + Mp4BoxHeader.HEADER_LENGTH)); relativeIlstEndPosition = relativeIlstposition; } } } else { //There no ilst or meta header so we set to position where it would be if it existed relativeIlstposition = moovHeader.getLength() - Mp4BoxHeader.HEADER_LENGTH; relativeIlstEndPosition = relativeIlstposition ; startIlstWithinFile = (int)(moovHeader.getFilePos() + moovHeader.getLength()); } } //There no udta header so we are going to create a new structure, but we have to be aware that there might be //an existing meta box structure in which case we preserve it but rigth are new structure before it. else { //Create new structure just after the end of the trak atom if(metaHeader != null) { startIlstWithinFile = (int)trakHeader.getFilePos() + trakHeader.getLength(); relativeIlstposition = (int) (startIlstWithinFile - (moovHeader.getFilePos() + Mp4BoxHeader.HEADER_LENGTH)); relativeIlstEndPosition = relativeIlstposition + ilstHeader.getLength(); } else { //There no udta,ilst or meta header so we set to position where it would be if it existed relativeIlstposition = moovHeader.getLength() - Mp4BoxHeader.HEADER_LENGTH; relativeIlstEndPosition = relativeIlstposition; startIlstWithinFile = (int)(moovHeader.getFilePos() + moovHeader.getLength()); } } newIlstSize = rawIlstData.limit(); //Level 4 - Free oldMetaLevelFreeAtomSize = 0; extraDataSize = 0; for (DefaultMutableTreeNode freeNode : atomTree.getFreeNodes()) { DefaultMutableTreeNode parentNode = (DefaultMutableTreeNode) freeNode.getParent(); DefaultMutableTreeNode brotherNode = freeNode.getPreviousSibling(); if (!parentNode.isRoot()) { Mp4BoxHeader header = ((Mp4BoxHeader) parentNode.getUserObject()); Mp4BoxHeader freeHeader = ((Mp4BoxHeader) freeNode.getUserObject()); //We are only interested in free atoms at this level if they come after the ilst node if(brotherNode!=null) { Mp4BoxHeader brotherHeader = ((Mp4BoxHeader) brotherNode.getUserObject()); if (header.getId().equals(Mp4NotMetaFieldKey.META.getFieldName()) && brotherHeader.getId().equals(Mp4NotMetaFieldKey.ILST.getFieldName())) { oldMetaLevelFreeAtomSize = freeHeader.getLength(); //Is there anything else here that needs to be preserved such as uuid atoms extraDataSize = moovHeader.getFilePos() + moovHeader.getLength() - (freeHeader.getFilePos() + freeHeader.getLength()); break; } } } } //If no free atom, still check for unexpected items within meta, after ilst //TODO this logic probably incomplete if (oldMetaLevelFreeAtomSize == 0) { extraDataSize = moovHeader.getDataLength() - relativeIlstEndPosition; } //Level-1 free atom level1SearchPosition = 0; topLevelFreePosition = 0; topLevelFreeSize = 0; topLevelFreeAtomComesBeforeMdatAtom = true; for (DefaultMutableTreeNode freeNode : atomTree.getFreeNodes()) { DefaultMutableTreeNode parentNode = (DefaultMutableTreeNode) freeNode.getParent(); if (parentNode.isRoot()) { topLevelFreeHeader = ((Mp4BoxHeader) freeNode.getUserObject()); topLevelFreeSize = topLevelFreeHeader.getLength(); topLevelFreePosition = (int) topLevelFreeHeader.getFilePos(); level1SearchPosition = topLevelFreePosition; break; } } if (topLevelFreeSize > 0) { if (topLevelFreePosition > mdatHeader.getFilePos()) { topLevelFreeAtomComesBeforeMdatAtom = false; level1SearchPosition = (int) mdatHeader.getFilePos(); } } else { topLevelFreePosition = (int) mdatHeader.getFilePos(); level1SearchPosition = topLevelFreePosition; } logger.info("Read header successfully ready for writing"); //The easiest option since no difference in the size of the metadata so all we have to do is //create a new file identical to first file but with replaced metadata if (oldIlstSize == newIlstSize) { logger.info("Writing:Option 1:Same Size"); writeMetadataSameSize(rawIlstData, oldIlstSize, startIlstWithinFile, fileReadChannel, fileWriteChannel); } //.. we just need to increase the size of the free atom below the meta atom, and replace the metadata //no other changes neccessary and total file size remains the same else if (oldIlstSize > newIlstSize) { //Create an amended freeBaos atom and write it if it previously existed if (oldMetaLevelFreeAtomSize > 0) { logger.info("Writing:Option 2:Smaller Size have free atom:" + oldIlstSize + ":" + newIlstSize); fileReadChannel.position(0); fileWriteChannel.transferFrom(fileReadChannel, 0, startIlstWithinFile); fileWriteChannel.position(startIlstWithinFile); fileWriteChannel.write(rawIlstData); fileReadChannel.position(startIlstWithinFile + oldIlstSize); int newFreeSize = oldMetaLevelFreeAtomSize + (oldIlstSize - newIlstSize); Mp4FreeBox newFreeBox = new Mp4FreeBox(newFreeSize - Mp4BoxHeader.HEADER_LENGTH); fileWriteChannel.write(newFreeBox.getHeader().getHeaderData()); fileWriteChannel.write(newFreeBox.getData()); //Skip over the read channel old free atom fileReadChannel.position(fileReadChannel.position() + oldMetaLevelFreeAtomSize); //Now write the rest of the file which won't have changed fileWriteChannel.transferFrom(fileReadChannel, fileWriteChannel.position(), fileReadChannel.size() - fileReadChannel.position()); } //No free atom we need to create a new one or adjust top level free atom else { int newFreeSize = (oldIlstSize - newIlstSize) - Mp4BoxHeader.HEADER_LENGTH; //We need to create a new one, so dont have to adjust all the headers but only works if the size //of tags has decreased by more 8 characters so there is enough room for the free boxes header we take //into account size of new header in calculating size of box if (newFreeSize > 0) { logger.info("Writing:Option 3:Smaller Size can create free atom"); fileReadChannel.position(0); fileWriteChannel.transferFrom(fileReadChannel, 0, startIlstWithinFile); fileWriteChannel.position(startIlstWithinFile); fileWriteChannel.write(rawIlstData); fileReadChannel.position(startIlstWithinFile + oldIlstSize); //Create new free box Mp4FreeBox newFreeBox = new Mp4FreeBox(newFreeSize); fileWriteChannel.write(newFreeBox.getHeader().getHeaderData()); fileWriteChannel.write(newFreeBox.getData()); //Now write the rest of the file which wont have changed fileWriteChannel.transferFrom(fileReadChannel, fileWriteChannel.position(), fileReadChannel.size() - fileReadChannel.position()); } //Ok everything in this bit of tree has to be recalculated because eight or less bytes smaller else { logger.info("Writing:Option 4:Smaller Size <=8 cannot create free atoms"); //Size will be this amount smaller int sizeReducedBy = oldIlstSize - newIlstSize; //Write stuff before Moov (ftyp) fileReadChannel.position(0); fileWriteChannel.transferFrom(fileReadChannel, 0, moovHeader.getFilePos()); fileWriteChannel.position(moovHeader.getFilePos()); //Edit stco atom within moov header, we need to adjust offsets by the amount mdat is going to be shifted //unless mdat is at start of file if (mdatHeader.getFilePos() > moovHeader.getFilePos()) { stco.adjustOffsets(-sizeReducedBy); } //Edit and rewrite the Moov,Udta and Ilst header in moov buffer adjustSizeOfMoovHeader(moovHeader, moovBuffer, -sizeReducedBy,udtaHeader,metaHeader); fileWriteChannel.write(moovHeader.getHeaderData()); moovBuffer.rewind(); moovBuffer.limit(relativeIlstposition); fileWriteChannel.write(moovBuffer); //Now write ilst data fileWriteChannel.write(rawIlstData); fileReadChannel.position(startIlstWithinFile + oldIlstSize); //Writes any extra info such as uuid fields at the end of the meta atom after the ilst atom if (extraDataSize > 0) { fileWriteChannel.transferFrom(fileReadChannel, fileWriteChannel.position(), extraDataSize); fileWriteChannel.position(fileWriteChannel.position() + extraDataSize); } //Now write the rest of the file which won't have changed fileWriteChannel.transferFrom(fileReadChannel, fileWriteChannel.position(), fileReadChannel.size() - fileReadChannel.position()); } } } //Size of metadata has increased, the most complex situation, more atoms affected else { int additionalSpaceRequiredForMetadata = newIlstSize - oldIlstSize; //We can fit the metadata in under the meta item just by using some of the padding available in the free //atom under the meta atom need to take of the side of free header otherwise might end up with //solution where can fit in data, but cant fit in free atom header if (additionalSpaceRequiredForMetadata <= (oldMetaLevelFreeAtomSize - Mp4BoxHeader.HEADER_LENGTH)) { int newFreeSize = oldMetaLevelFreeAtomSize - (additionalSpaceRequiredForMetadata); logger.info("Writing:Option 5;Larger Size can use meta free atom need extra:" + newFreeSize + "bytes"); fileReadChannel.position(0); fileWriteChannel.transferFrom(fileReadChannel, 0, startIlstWithinFile); fileWriteChannel.position(startIlstWithinFile); fileWriteChannel.write(rawIlstData); fileReadChannel.position(startIlstWithinFile + oldIlstSize); //Create an amended smaller freeBaos atom and write it to file Mp4FreeBox newFreeBox = new Mp4FreeBox(newFreeSize - Mp4BoxHeader.HEADER_LENGTH); fileWriteChannel.write(newFreeBox.getHeader().getHeaderData()); fileWriteChannel.write(newFreeBox.getData()); //Skip over the read channel old free atom fileReadChannel.position(fileReadChannel.position() + oldMetaLevelFreeAtomSize); //Now write the rest of the file which won't have changed fileWriteChannel.transferFrom(fileReadChannel, fileWriteChannel.position(), fileReadChannel.size() - fileReadChannel.position()); } //There is not enough padding in the metadata free atom anyway //Size meta needs to be increased by (if not writing a free atom) //Special Case this could actually be negative (upto -8)if is actually enough space but would //not be able to write free atom properly, it doesnt matter the parent atoms would still //need their sizes adjusted. else { int additionalMetaSizeThatWontFitWithinMetaAtom = additionalSpaceRequiredForMetadata - (oldMetaLevelFreeAtomSize); //Write stuff before Moov (ftyp) fileReadChannel.position(0); fileWriteChannel.transferFrom(fileReadChannel, 0, positionWithinFileAfterFindingMoovHeader - Mp4BoxHeader.HEADER_LENGTH); fileWriteChannel.position(positionWithinFileAfterFindingMoovHeader - Mp4BoxHeader.HEADER_LENGTH); if(udtaHeader==null) { logger.info("Writing:Option 5.1;No udta atom"); Mp4HdlrBox hdlrBox = Mp4HdlrBox.createiTunesStyleHdlrBox(); Mp4MetaBox metaBox = Mp4MetaBox.createiTunesStyleMetaBox(hdlrBox.getHeader().getLength() + rawIlstData.limit()); udtaHeader = new Mp4BoxHeader(Mp4NotMetaFieldKey.UDTA.getFieldName()); udtaHeader.setLength(Mp4BoxHeader.HEADER_LENGTH +metaBox.getHeader().getLength()); additionalMetaSizeThatWontFitWithinMetaAtom = additionalMetaSizeThatWontFitWithinMetaAtom + (udtaHeader.getLength() - rawIlstData.limit()); //Edit stco atom within moov header, if the free atom comes after mdat OR //(there is not enough space in the top level free atom //or special case of matching exactly the free atom plus header) if ((!topLevelFreeAtomComesBeforeMdatAtom) || ((topLevelFreeSize - Mp4BoxHeader.HEADER_LENGTH < additionalMetaSizeThatWontFitWithinMetaAtom) && (topLevelFreeSize != additionalMetaSizeThatWontFitWithinMetaAtom))) { //We dont bother using the top level free atom coz not big enough anyway, we need to adjust offsets //by the amount mdat is going to be shifted if (mdatHeader.getFilePos() > moovHeader.getFilePos()) { stco.adjustOffsets(additionalMetaSizeThatWontFitWithinMetaAtom); } } //Edit and rewrite the Moov header moovHeader.setLength(moovHeader.getLength() + additionalMetaSizeThatWontFitWithinMetaAtom); //Adjust moov header size to allow a udta,meta and hdlr atom, we have already accounted for ilst data //moovHeader.setLength(moovHeader.getLength() + udtaHeader.getLength() - rawIlstData.limit()); fileWriteChannel.write(moovHeader.getHeaderData()); moovBuffer.rewind(); moovBuffer.limit(relativeIlstposition); fileWriteChannel.write(moovBuffer); //Write new atoms required for holding metadata in itunes format fileWriteChannel.write(udtaHeader.getHeaderData()); fileWriteChannel.write(metaBox.getHeader().getHeaderData()); fileWriteChannel.write(metaBox.getData()); fileWriteChannel.write(hdlrBox.getHeader().getHeaderData()); fileWriteChannel.write(hdlrBox.getData()); } else { logger.info("Writing:Option 5.2;udta atom exists"); //Edit stco atom within moov header, if the free atom comes after mdat OR //(there is not enough space in the top level free atom //or special case of matching exactly the free atom plus header) if ((!topLevelFreeAtomComesBeforeMdatAtom) || ((topLevelFreeSize - Mp4BoxHeader.HEADER_LENGTH < additionalMetaSizeThatWontFitWithinMetaAtom) && (topLevelFreeSize != additionalMetaSizeThatWontFitWithinMetaAtom))) { //We dont bother using the top level free atom coz not big enough anyway, we need to adjust offsets //by the amount mdat is going to be shifted if (mdatHeader.getFilePos() > moovHeader.getFilePos()) { stco.adjustOffsets(additionalMetaSizeThatWontFitWithinMetaAtom); } } //Edit and rewrite the Moov header adjustSizeOfMoovHeader(moovHeader, moovBuffer, additionalMetaSizeThatWontFitWithinMetaAtom,udtaHeader,metaHeader); fileWriteChannel.write(moovHeader.getHeaderData()); //Now write from this edited buffer up until ilst atom moovBuffer.rewind(); moovBuffer.limit(relativeIlstposition); fileWriteChannel.write(moovBuffer); } //Now write ilst data fileWriteChannel.write(rawIlstData); //Skip over the read channel old meta level free atom because now used up fileReadChannel.position(startIlstWithinFile + oldIlstSize); fileReadChannel.position(fileReadChannel.position() + oldMetaLevelFreeAtomSize); //Writes any extra info such as uuid fields at the end of the meta atom after the ilst atom if (extraDataSize > 0) { fileWriteChannel.transferFrom(fileReadChannel, fileWriteChannel.position(), extraDataSize); fileWriteChannel.position(fileWriteChannel.position() + extraDataSize); } //fileReadChannel.position(topLevelFreePosition); //fileReadChannel.position(level1SearchPosition); //If we have top level free atom that comes before mdat we might be able to use it but only if //the free atom actually come after the the metadata if (topLevelFreeAtomComesBeforeMdatAtom&&(topLevelFreePosition>startIlstWithinFile)) { //If the shift is less than the space available in this second free atom data size we should //minimize the free atom accordingly (then we don't have to update stco atom) //note could be a double negative as additionalMetaSizeThatWontFitWithinMetaAtom could be -1 to -8 but thats ok stills works //ok if (topLevelFreeSize - Mp4BoxHeader.HEADER_LENGTH >= additionalMetaSizeThatWontFitWithinMetaAtom) { logger.info("Writing:Option 6;Larger Size can use top free atom"); Mp4FreeBox freeBox = new Mp4FreeBox((topLevelFreeSize - Mp4BoxHeader.HEADER_LENGTH) - additionalMetaSizeThatWontFitWithinMetaAtom); fileWriteChannel.write(freeBox.getHeader().getHeaderData()); fileWriteChannel.write(freeBox.getData()); //Skip over the read channel old free atom fileReadChannel.position(fileReadChannel.position() + topLevelFreeSize); //Write Mdat fileWriteChannel.transferFrom(fileReadChannel, fileWriteChannel.position(), fileReadChannel.size() - fileReadChannel.position()); } //If the space required is identical to total size of the free space (inc header) //we could just remove the header else if (topLevelFreeSize == additionalMetaSizeThatWontFitWithinMetaAtom) { logger.info("Writing:Option 7;Larger Size uses top free atom including header"); //Skip over the read channel old free atom fileReadChannel.position(fileReadChannel.position() + topLevelFreeSize); //Write Mdat fileWriteChannel.transferFrom(fileReadChannel, fileWriteChannel.position(), fileReadChannel.size() - fileReadChannel.position()); } //Mdat is going to have to move anyway, so keep free atom as is and write it and mdat //(have already updated stco above) else { logger.info("Writing:Option 8;Larger Size cannot use top free atom"); fileWriteChannel.transferFrom(fileReadChannel, fileWriteChannel.position(), fileReadChannel.size() - fileReadChannel.position()); } } else { logger.info("Writing:Option 9;Top Level Free comes after Mdat or before Metadata so cant use it"); fileWriteChannel.transferFrom(fileReadChannel, fileWriteChannel.position(), fileReadChannel.size() - fileReadChannel.position()); } } } //Close all channels to original file fileReadChannel.close(); raf.close(); checkFileWrittenCorrectly(rafTemp,mdatHeader,fileWriteChannel,stco); } /** * Check File Written Correctly * * @param rafTemp * @param mdatHeader * @param fileWriteChannel * @param stco * @throws CannotWriteException * @throws IOException */ private void checkFileWrittenCorrectly(RandomAccessFile rafTemp,Mp4BoxHeader mdatHeader,FileChannel fileWriteChannel, Mp4StcoBox stco) throws CannotWriteException,IOException { logger.info("Checking file has been written correctly"); try { //Create a tree from the new file Mp4AtomTree newAtomTree; newAtomTree = new Mp4AtomTree(rafTemp, false); //Check we still have audio data file, and check length Mp4BoxHeader newMdatHeader = newAtomTree.getBoxHeader(newAtomTree.getMdatNode()); if (newMdatHeader == null) { throw new CannotWriteException(ErrorMessage.MP4_CHANGES_TO_FILE_FAILED_NO_DATA.getMsg()); } if (newMdatHeader.getLength() != mdatHeader.getLength()) { throw new CannotWriteException(ErrorMessage.MP4_CHANGES_TO_FILE_FAILED_DATA_CORRUPT.getMsg()); } //Should always have udta atom after writing to file Mp4BoxHeader newUdtaHeader = newAtomTree.getBoxHeader(newAtomTree.getUdtaNode()); if (newUdtaHeader == null) { throw new CannotWriteException(ErrorMessage.MP4_CHANGES_TO_FILE_FAILED_NO_TAG_DATA.getMsg()); } //Should always have meta atom after writing to file Mp4BoxHeader newMetaHeader = newAtomTree.getBoxHeader(newAtomTree.getMetaNode()); if (newMetaHeader == null) { throw new CannotWriteException(ErrorMessage.MP4_CHANGES_TO_FILE_FAILED_NO_TAG_DATA.getMsg()); } //Check offsets are correct, may not match exactly in original file so just want to make //sure that the discrepancy if any is preserved Mp4StcoBox newStco = newAtomTree.getStco(); logger.finer("stco:Original First Offset" + stco.getFirstOffSet()); logger.finer("stco:Original Diff" + (int) (stco.getFirstOffSet() - mdatHeader.getFilePos())); logger.finer("stco:Original Mdat Pos" + mdatHeader.getFilePos()); logger.finer("stco:New First Offset" + newStco.getFirstOffSet()); logger.finer("stco:New Diff" + (int) ((newStco.getFirstOffSet() - newMdatHeader.getFilePos()))); logger.finer("stco:New Mdat Pos" + newMdatHeader.getFilePos()); int diff = (int) (stco.getFirstOffSet() - mdatHeader.getFilePos()); if ((newStco.getFirstOffSet() - newMdatHeader.getFilePos()) != diff) { int discrepancy = (int)((newStco.getFirstOffSet() - newMdatHeader.getFilePos()) - diff); throw new CannotWriteException(ErrorMessage.MP4_CHANGES_TO_FILE_FAILED_INCORRECT_OFFSETS.getMsg(discrepancy)); } } catch (Exception e) { if (e instanceof CannotWriteException) { throw (CannotWriteException) e; } else { e.printStackTrace(); throw new CannotWriteException(ErrorMessage.MP4_CHANGES_TO_FILE_FAILED.getMsg() + ":" + e.getMessage()); } } finally { //Close references to new file rafTemp.close(); fileWriteChannel.close(); } logger.info("File has been written correctly"); } /** * Delete the tag *

    *

    *

    This is achieved by writing an empty ilst atom * * @param raf * @param rafTemp * @throws IOException */ public void delete(RandomAccessFile raf, RandomAccessFile rafTemp) throws IOException { Mp4Tag tag = new Mp4Tag(); try { write(tag, raf, rafTemp); } catch (CannotWriteException cwe) { throw new IOException(cwe.getMessage()); } } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/mp4/Mp4NotMetaFieldKey.java0000644000175000017500000000335011115461065027520 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.mp4; /** * This a list of mp4boxes identifiers, that are not part of the metadata info. *

    *

    These are of limited interest to JAudiotagger but are required when reading audio info * or when writing modifications to the file when the location of audio has shifted. */ public enum Mp4NotMetaFieldKey { FTYP("ftyp", "File type Identification"), MOOV("moov", "Top level Presentation"), MVHD("mvhd", "Movie Header"), UDTA("udta", "User Data"), META("meta", "MetaInformation"), ILST("ilst", "MetaInformation Optional"), MDAT("mdat", "Audio Data"), MDIA("mdia", "Media"), MDHD("mdhd", "Media Header"), TKHD("tkhd", "Track Header"), FREE("free", "Padding"), TRAK("trak", "Track"), SMHD("smhd", "Sound Media Header"), NMHD("nmhd", "Media Stream Header"), STBL("stbl", "Sample Table"), STSD("stsd", "Sample Description"), MP4A("mp4a", "AAC Audio"), ESDS("esds", "Track codec specific information"), MINF("minf", "Media Information"), STCO("stco", "Offsets into Audio Data"), DRMS("drms", "DRM protected File"), ALAC("alac", "Apple Lossless File"), HDLR("hdlr", "Metadata Handler"); private String fieldName; private String description; Mp4NotMetaFieldKey(String fieldName, String description) { this.fieldName = fieldName; this.description = description; } /** * This is the value of the fieldname that is actually used to write mp4 * * @return */ public String getFieldName() { return fieldName; } /** * @return description, human redable description of the atom */ public String getDescription() { return description; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/mp4/Mp4AtomTree.java0000644000175000017500000004175711277026507026300 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.mp4; import org.jaudiotagger.audio.exceptions.CannotReadException; import org.jaudiotagger.audio.exceptions.NullBoxIdException; import org.jaudiotagger.audio.mp4.atom.Mp4BoxHeader; import org.jaudiotagger.audio.mp4.atom.Mp4MetaBox; import org.jaudiotagger.audio.mp4.atom.Mp4StcoBox; import org.jaudiotagger.audio.mp4.atom.NullPadding; import org.jaudiotagger.logging.ErrorMessage; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.util.ArrayList; import java.util.Enumeration; import java.util.List; import java.util.logging.Logger; /** * Tree representing atoms in the mp4 file *

    * Note it doesn't create the complete tree it delves into subtrees for atom we know about and are interested in. (Note * it would be impossible to create a complete tree for any file without understanding all the nodes because * some atoms such as meta contain data and children and therefore need to be specially preprocessed) *

    * This class is currently only used when writing tags because it better handles the difficulties of mdat aand free * atoms being optional/multiple places then the older sequential method. It is expected this class will eventually * be used when reading tags as well. *

    * Uses a TreeModel for the tree, with convenience methods holding onto references to most common nodes so they * can be used without having to traverse the tree again. */ public class Mp4AtomTree { private DefaultMutableTreeNode rootNode; private DefaultTreeModel dataTree; private DefaultMutableTreeNode moovNode; private DefaultMutableTreeNode mdatNode; private DefaultMutableTreeNode stcoNode; private DefaultMutableTreeNode ilstNode; private DefaultMutableTreeNode metaNode; private DefaultMutableTreeNode udtaNode; private DefaultMutableTreeNode hdlrWithinMdiaNode; private DefaultMutableTreeNode hdlrWithinMetaNode; private List freeNodes = new ArrayList(); private List mdatNodes = new ArrayList(); private List trakNodes = new ArrayList(); private Mp4StcoBox stco; private ByteBuffer moovBuffer; //Contains all the data under moov private Mp4BoxHeader moovHeader; //Logger Object public static Logger logger = Logger.getLogger("org.jaudiotagger.audio.mp4"); /** * Create Atom Tree * * @param raf * @throws IOException * @throws CannotReadException */ public Mp4AtomTree(RandomAccessFile raf) throws IOException, CannotReadException { buildTree(raf, true); } /** * Create Atom Tree and maintain open channel to raf, should only be used if will continue * to use raf after this call, you will have to close raf yourself. * * @param raf * @param closeOnExit to keep randomfileaccess open, only used when randomaccessfile already being used * @throws IOException * @throws CannotReadException */ public Mp4AtomTree(RandomAccessFile raf, boolean closeOnExit) throws IOException, CannotReadException { buildTree(raf, closeOnExit); } /** * Build a tree of the atoms in the file * * @param raf * @param closeExit false to keep randomfileacces open, only used when randomaccessfile already being used * @return * @throws java.io.IOException * @throws org.jaudiotagger.audio.exceptions.CannotReadException */ public DefaultTreeModel buildTree(RandomAccessFile raf, boolean closeExit) throws IOException, CannotReadException { FileChannel fc = null; try { fc = raf.getChannel(); //make sure at start of file fc.position(0); //Build up map of nodes rootNode = new DefaultMutableTreeNode(); dataTree = new DefaultTreeModel(rootNode); //Iterate though all the top level Nodes ByteBuffer headerBuffer = ByteBuffer.allocate(Mp4BoxHeader.HEADER_LENGTH); while (fc.position() < fc.size()) { Mp4BoxHeader boxHeader = new Mp4BoxHeader(); headerBuffer.clear(); fc.read(headerBuffer); headerBuffer.rewind(); try { boxHeader.update(headerBuffer); } catch(NullBoxIdException ne) { //If we only get this error after all the expected data has been found we allow it if(moovNode!=null&mdatNode!=null) { NullPadding np = new NullPadding(fc.position() - Mp4BoxHeader.HEADER_LENGTH,fc.size()); DefaultMutableTreeNode trailingPaddingNode = new DefaultMutableTreeNode(np); rootNode.add(trailingPaddingNode); logger.warning(ErrorMessage.NULL_PADDING_FOUND_AT_END_OF_MP4.getMsg(np.getFilePos())); break; } else { //File appears invalid throw ne; } } boxHeader.setFilePos(fc.position() - Mp4BoxHeader.HEADER_LENGTH); DefaultMutableTreeNode newAtom = new DefaultMutableTreeNode(boxHeader); //Go down moov if (boxHeader.getId().equals(Mp4NotMetaFieldKey.MOOV.getFieldName())) { moovNode = newAtom; moovHeader = boxHeader; long filePosStart = fc.position(); moovBuffer = ByteBuffer.allocate(boxHeader.getDataLength()); fc.read(moovBuffer); moovBuffer.rewind(); /*Maybe needed but dont have test case yet if(filePosStart + boxHeader.getDataLength() > fc.size()) { throw new CannotReadException("The atom states its datalength to be "+boxHeader.getDataLength() + "but there are only "+fc.size()+"bytes in the file and already at position "+filePosStart); } */ buildChildrenOfNode(moovBuffer, newAtom); fc.position(filePosStart); } else if (boxHeader.getId().equals(Mp4NotMetaFieldKey.FREE.getFieldName())) { //Might be multiple in different locations freeNodes.add(newAtom); } else if (boxHeader.getId().equals(Mp4NotMetaFieldKey.MDAT.getFieldName())) { //mdatNode always points to the last mDatNode, normally there is just one mdatnode but do have //a valid example of multiple mdatnode //if(mdatNode!=null) //{ // throw new CannotReadException(ErrorMessage.MP4_FILE_CONTAINS_MULTIPLE_DATA_ATOMS.getMsg()); //} mdatNode = newAtom; mdatNodes.add(newAtom); } rootNode.add(newAtom); fc.position(fc.position() + boxHeader.getDataLength()); } return dataTree; } finally { //If we cant find the audio then we cannot modify this file so better to throw exception //now rather than later when try and write to it. if(mdatNode==null) { throw new CannotReadException(ErrorMessage.MP4_CANNOT_FIND_AUDIO.getMsg()); } if (closeExit) { fc.close(); } } } /** * Display atom tree */ @SuppressWarnings("unchecked") public void printAtomTree() { Enumeration e = rootNode.preorderEnumeration(); DefaultMutableTreeNode nextNode; while (e.hasMoreElements()) { nextNode = e.nextElement(); Mp4BoxHeader header = (Mp4BoxHeader) nextNode.getUserObject(); if (header != null) { String tabbing = ""; for (int i = 1; i < nextNode.getLevel(); i++) { tabbing += "\t"; } if(header instanceof NullPadding) { System.out.println(tabbing + "Null pad " + " @ " + header.getFilePos() + " of size:" + header.getLength() + " ,ends @ " + (header.getFilePos() + header.getLength())); } else { System.out.println(tabbing + "Atom " + header.getId() + " @ " + header.getFilePos() + " of size:" + header.getLength() + " ,ends @ " + (header.getFilePos() + header.getLength())); } } } } /** * * @param moovBuffer * @param parentNode * @throws IOException * @throws CannotReadException */ public void buildChildrenOfNode(ByteBuffer moovBuffer, DefaultMutableTreeNode parentNode) throws IOException, CannotReadException { Mp4BoxHeader boxHeader; //Preprocessing for nodes that contain data before their children atoms Mp4BoxHeader parentBoxHeader = (Mp4BoxHeader) parentNode.getUserObject(); //We set the buffers position back to this after processing the chikdren int justAfterHeaderPos = moovBuffer.position(); //Preprocessing for meta that normally contains 4 data bytes, but doesnt whre found under trak atom //TODO is it always under TRAK dont really know the rule if (parentBoxHeader.getId().equals(Mp4NotMetaFieldKey.META.getFieldName())) { Mp4MetaBox meta = new Mp4MetaBox(parentBoxHeader, moovBuffer); meta.processData(); try { boxHeader = new Mp4BoxHeader(moovBuffer); } catch(NullBoxIdException nbe) { //It might be that the meta box didnt actually have any additional data after it so we adjust the buffer //to be immediately after metabox and code can retry moovBuffer.position(moovBuffer.position()-Mp4MetaBox.FLAGS_LENGTH); } finally { //Skip back last header cos this was only a test moovBuffer.position(moovBuffer.position()- Mp4BoxHeader.HEADER_LENGTH); } } //Defines where to start looking for the first child node int startPos = moovBuffer.position(); while (moovBuffer.position() < ((startPos + parentBoxHeader.getDataLength()) - Mp4BoxHeader.HEADER_LENGTH)) { boxHeader = new Mp4BoxHeader(moovBuffer); if (boxHeader != null) { boxHeader.setFilePos(moovHeader.getFilePos() + moovBuffer.position()); logger.finest("Atom " + boxHeader.getId() + " @ " + boxHeader.getFilePos() + " of size:" + boxHeader.getLength() + " ,ends @ " + (boxHeader.getFilePos() + boxHeader.getLength())); DefaultMutableTreeNode newAtom = new DefaultMutableTreeNode(boxHeader); parentNode.add(newAtom); if (boxHeader.getId().equals(Mp4NotMetaFieldKey.UDTA.getFieldName())) { udtaNode = newAtom; } //only interested in metaNode that is child of udta node else if (boxHeader.getId().equals(Mp4NotMetaFieldKey.META.getFieldName())&&parentBoxHeader.getId().equals(Mp4NotMetaFieldKey.UDTA.getFieldName())) { metaNode = newAtom; } else if (boxHeader.getId().equals(Mp4NotMetaFieldKey.HDLR.getFieldName())&&parentBoxHeader.getId().equals(Mp4NotMetaFieldKey.META.getFieldName())) { hdlrWithinMetaNode = newAtom; } else if (boxHeader.getId().equals(Mp4NotMetaFieldKey.HDLR.getFieldName())) { hdlrWithinMdiaNode = newAtom; } else if (boxHeader.getId().equals(Mp4NotMetaFieldKey.STCO.getFieldName())) { if (stco == null) { stco = new Mp4StcoBox(boxHeader, moovBuffer); stcoNode = newAtom; } } else if (boxHeader.getId().equals(Mp4NotMetaFieldKey.ILST.getFieldName())) { DefaultMutableTreeNode parent = (DefaultMutableTreeNode)parentNode.getParent(); if(parent!=null) { Mp4BoxHeader parentsParent = (Mp4BoxHeader)(parent).getUserObject(); if(parentsParent!=null) { if(parentBoxHeader.getId().equals(Mp4NotMetaFieldKey.META.getFieldName())&&parentsParent.getId().equals(Mp4NotMetaFieldKey.UDTA.getFieldName())) { ilstNode = newAtom; } } } } else if (boxHeader.getId().equals(Mp4NotMetaFieldKey.FREE.getFieldName())) { //Might be multiple in different locations freeNodes.add(newAtom); } else if (boxHeader.getId().equals(Mp4NotMetaFieldKey.TRAK.getFieldName())) { //Might be multiple in different locations, although onely one shoud be audio track trakNodes.add(newAtom); } //For these atoms iterate down to build their children if ((boxHeader.getId().equals(Mp4NotMetaFieldKey.TRAK.getFieldName())) || (boxHeader.getId().equals(Mp4NotMetaFieldKey.MDIA.getFieldName())) || (boxHeader.getId().equals(Mp4NotMetaFieldKey.MINF.getFieldName())) || (boxHeader.getId().equals(Mp4NotMetaFieldKey.STBL.getFieldName())) || (boxHeader.getId().equals(Mp4NotMetaFieldKey.UDTA.getFieldName())) || (boxHeader.getId().equals(Mp4NotMetaFieldKey.META.getFieldName())) || (boxHeader.getId().equals(Mp4NotMetaFieldKey.ILST.getFieldName()))) { buildChildrenOfNode(moovBuffer, newAtom); } //Now adjust buffer for the next atom header at this level moovBuffer.position(moovBuffer.position() + boxHeader.getDataLength()); } } moovBuffer.position(justAfterHeaderPos); } /** * * @return */ public DefaultTreeModel getDataTree() { return dataTree; } /** * * @return */ public DefaultMutableTreeNode getMoovNode() { return moovNode; } /** * * @return */ public DefaultMutableTreeNode getStcoNode() { return stcoNode; } /** * * @return */ public DefaultMutableTreeNode getIlstNode() { return ilstNode; } /** * * @param node * @return */ public Mp4BoxHeader getBoxHeader(DefaultMutableTreeNode node) { if (node == null) { return null; } return (Mp4BoxHeader) node.getUserObject(); } /** * * @return */ public DefaultMutableTreeNode getMdatNode() { return mdatNode; } /** * * @return */ public DefaultMutableTreeNode getUdtaNode() { return udtaNode; } /** * * @return */ public DefaultMutableTreeNode getMetaNode() { return metaNode; } /** * * @return */ public DefaultMutableTreeNode getHdlrWithinMetaNode() { return hdlrWithinMetaNode; } /** * * @return */ public DefaultMutableTreeNode getHdlrWithinMdiaNode() { return hdlrWithinMdiaNode; } /** * * @return */ public List getFreeNodes() { return freeNodes; } /** * * @return */ public List getTrakNodes() { return trakNodes; } /** * * @return */ public Mp4StcoBox getStco() { return stco; } /** * * @return */ public ByteBuffer getMoovBuffer() { return moovBuffer; } /** * * @return */ public Mp4BoxHeader getMoovHeader() { return moovHeader; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/mp4/Mp4TagReader.java0000644000175000017500000003202411470746136026403 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2003-2005 Raphaël Slinckx * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.audio.mp4; import org.jaudiotagger.audio.exceptions.CannotReadException; import org.jaudiotagger.audio.generic.Utils; import org.jaudiotagger.audio.mp4.atom.Mp4BoxHeader; import org.jaudiotagger.audio.mp4.atom.Mp4MetaBox; import org.jaudiotagger.logging.ErrorMessage; import org.jaudiotagger.tag.TagField; import org.jaudiotagger.tag.mp4.Mp4FieldKey; import org.jaudiotagger.tag.mp4.Mp4NonStandardFieldKey; import org.jaudiotagger.tag.mp4.Mp4Tag; import org.jaudiotagger.tag.mp4.atom.Mp4DataBox; import org.jaudiotagger.tag.mp4.field.*; import java.io.IOException; import java.io.RandomAccessFile; import java.io.UnsupportedEncodingException; import java.nio.ByteBuffer; import java.util.logging.Logger; /** * Reads metadata from mp4, *

    *

    The metadata tags are usually held under the ilst atom as shown below

    *

    Valid Exceptions to the rule:

    *

    Can be no udta atom with meta rooted immediately under moov instead

    *

    Can be no udta/meta atom at all

    * *

     * |--- ftyp
     * |--- moov
     * |......|
     * |......|----- mvdh
     * |......|----- trak
     * |......|----- udta
     * |..............|
     * |..............|-- meta
     * |....................|
     * |....................|-- hdlr
     * |....................|-- ilst
     * |.........................|
     * |.........................|---- @nam (Optional for each metadatafield)
     * |.........................|.......|-- data
     * |.........................|....... ecetera
     * |.........................|---- ---- (Optional for reverse dns field)
     * |.................................|-- mean
     * |.................................|-- name
     * |.................................|-- data
     * |.................................... ecetere
     * |
     * |--- mdat
     * 
    * Note:In the case of coverart MP4 holds all the coverart within individual dataitems all within * a single covr atom, we will add separate mp4field for each image. * * @param tag * @param header * @param raw * @return * @throws UnsupportedEncodingException */ private void createMp4Field(Mp4Tag tag, Mp4BoxHeader header, ByteBuffer raw) throws UnsupportedEncodingException { //Reverse Dns Atom if (header.getId().equals(Mp4TagReverseDnsField.IDENTIFIER)) { // try { TagField field = new Mp4TagReverseDnsField(header, raw); tag.addField(field); } catch (Exception e) { logger.warning(ErrorMessage.MP4_UNABLE_READ_REVERSE_DNS_FIELD.getMsg(e.getMessage())); TagField field = new Mp4TagRawBinaryField(header, raw); tag.addField(field); } } //Normal Parent with Data atom else { int currentPos = raw.position(); boolean isDataIdentifier = Utils.getString(raw, Mp4BoxHeader.IDENTIFIER_POS, Mp4BoxHeader.IDENTIFIER_LENGTH, "ISO-8859-1").equals(Mp4DataBox.IDENTIFIER); raw.position(currentPos); if (isDataIdentifier) { //Need this to decide what type of Field to create int type = Utils.getIntBE(raw, Mp4DataBox.TYPE_POS_INCLUDING_HEADER, Mp4DataBox.TYPE_POS_INCLUDING_HEADER + Mp4DataBox.TYPE_LENGTH - 1); Mp4FieldType fieldType = Mp4FieldType.getFieldType(type); logger.info("Box Type id:" + header.getId() + ":type:" + fieldType); //Special handling for some specific identifiers otherwise just base on class id if (header.getId().equals(Mp4FieldKey.TRACK.getFieldName())) { TagField field = new Mp4TrackField(header.getId(), raw); tag.addField(field); } else if (header.getId().equals(Mp4FieldKey.DISCNUMBER.getFieldName())) { TagField field = new Mp4DiscNoField(header.getId(), raw); tag.addField(field); } else if (header.getId().equals(Mp4FieldKey.GENRE.getFieldName())) { TagField field = new Mp4GenreField(header.getId(), raw); tag.addField(field); } else if (header.getId().equals(Mp4FieldKey.ARTWORK.getFieldName()) || Mp4FieldType.isCoverArtType(fieldType)) { int processedDataSize = 0; int imageCount = 0; //The loop should run for each image (each data atom) while (processedDataSize < header.getDataLength()) { //There maybe a mixture of PNG and JPEG images so have to check type //for each subimage (if there are more than one image) if (imageCount > 0) { type = Utils.getIntBE(raw, processedDataSize + Mp4DataBox.TYPE_POS_INCLUDING_HEADER, processedDataSize + Mp4DataBox.TYPE_POS_INCLUDING_HEADER + Mp4DataBox.TYPE_LENGTH - 1); fieldType = Mp4FieldType.getFieldType(type); } Mp4TagCoverField field = new Mp4TagCoverField(raw,fieldType); tag.addField(field); processedDataSize += field.getDataAndHeaderSize(); imageCount++; } } else if (fieldType == Mp4FieldType.TEXT) { TagField field = new Mp4TagTextField(header.getId(), raw); tag.addField(field); } else if (fieldType == Mp4FieldType.IMPLICIT) { TagField field = new Mp4TagTextNumberField(header.getId(), raw); tag.addField(field); } else if (fieldType == Mp4FieldType.INTEGER) { TagField field = new Mp4TagByteField(header.getId(), raw); tag.addField(field); } else { boolean existingId = false; for (Mp4FieldKey key : Mp4FieldKey.values()) { if (key.getFieldName().equals(header.getId())) { //The parentHeader is a known id but its field type is not one of the expected types so //this field is invalid. i.e I received a file with the TMPO set to 15 (Oxf) when it should //be 21 (ox15) so looks like somebody got their decimal and hex numbering confused //So in this case best to ignore this field and just write a warning existingId = true; logger.warning("Known Field:" + header.getId() + " with invalid field type of:" + type + " is ignored"); break; } } //Unknown field id with unknown type so just create as binary if (!existingId) { logger.warning("UnKnown Field:" + header.getId() + " with invalid field type of:" + type + " created as binary"); TagField field = new Mp4TagBinaryField(header.getId(), raw); tag.addField(field); } } } //Special Cases else { //MediaMonkey 3 CoverArt Attributes field, does not have data items so just //copy parent and child as is without modification if (header.getId().equals(Mp4NonStandardFieldKey.AAPR.getFieldName())) { TagField field = new Mp4TagRawBinaryField(header, raw); tag.addField(field); } //Default case else { TagField field = new Mp4TagRawBinaryField(header, raw); tag.addField(field); } } } } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/mp4/Mp4FileWriter.java0000644000175000017500000000313511247705415026617 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2003-2005 Raphaël Slinckx * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.audio.mp4; import org.jaudiotagger.audio.exceptions.CannotWriteException; import org.jaudiotagger.audio.generic.AudioFileWriter; import org.jaudiotagger.tag.Tag; import java.io.IOException; import java.io.RandomAccessFile; /** * Mp4 File Writer *

    *

    This can write files containing either the .mp4 or .m4a suffixes */ public class Mp4FileWriter extends AudioFileWriter { private Mp4TagWriter tw = new Mp4TagWriter(); protected void writeTag(Tag tag, RandomAccessFile raf, RandomAccessFile rafTemp) throws CannotWriteException, IOException { tw.write(tag, raf, rafTemp); } protected void deleteTag(RandomAccessFile raf, RandomAccessFile rafTemp) throws IOException { tw.delete(raf, rafTemp); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/mp4/EncoderType.java0000644000175000017500000000077111041064726026401 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.mp4; /** * Encoder Type actually identifies the format of the audio within the mp4. This is because * mp4 container can be used to hold different types of files. */ public enum EncoderType { AAC("AAC"), DRM_AAC("DRM AAC"), APPLE_LOSSLESS("Apple Lossless"),; private String description; EncoderType(String description) { this.description = description; } public String getDescription() { return description; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/mp4/Mp4FileReader.java0000644000175000017500000000324311247705415026545 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2003-2005 Raphaël Slinckx * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.audio.mp4; import org.jaudiotagger.audio.exceptions.CannotReadException; import org.jaudiotagger.audio.generic.AudioFileReader; import org.jaudiotagger.audio.generic.GenericAudioHeader; import org.jaudiotagger.tag.Tag; import java.io.IOException; import java.io.RandomAccessFile; /** * Mp4 File Reader *

    *

    This can read files containing either the .mp4 or .m4a suffixes */ public class Mp4FileReader extends AudioFileReader { private Mp4InfoReader ir = new Mp4InfoReader(); private Mp4TagReader tr = new Mp4TagReader(); protected GenericAudioHeader getEncodingInfo(RandomAccessFile raf) throws CannotReadException, IOException { return ir.read(raf); } protected Tag getTag(RandomAccessFile raf) throws CannotReadException, IOException { return tr.read(raf); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/mp4/Mp4AudioHeader.java0000644000175000017500000000303611041064726026710 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.mp4; import org.jaudiotagger.audio.generic.GenericAudioHeader; import org.jaudiotagger.audio.mp4.atom.Mp4EsdsBox; /** * Store some additional attributes not available for all audio types */ public class Mp4AudioHeader extends GenericAudioHeader { /** * The key for the kind field
    * * @see #content */ public final static String FIELD_KIND = "KIND"; /** * The key for the profile
    * * @see #content */ public final static String FIELD_PROFILE = "PROFILE"; /** * The key for the ftyp brand
    * * @see #content */ public final static String FIELD_BRAND = "BRAND"; public void setKind(Mp4EsdsBox.Kind kind) { content.put(FIELD_KIND, kind); } /** * @return kind */ public Mp4EsdsBox.Kind getKind() { return (Mp4EsdsBox.Kind) content.get(FIELD_KIND); } /** * The key for the profile * * @param profile */ public void setProfile(Mp4EsdsBox.AudioProfile profile) { content.put(FIELD_PROFILE, profile); } /** * @return audio profile */ public Mp4EsdsBox.AudioProfile getProfile() { return (Mp4EsdsBox.AudioProfile) content.get(FIELD_PROFILE); } /** * @param brand */ public void setBrand(String brand) { content.put(FIELD_BRAND, brand); } /** * @return brand */ public String getBrand() { return (String) content.get(FIELD_BRAND); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/AudioHeader.java0000644000175000017500000000166411470746136025644 0ustar drazzibdrazzibpackage org.jaudiotagger.audio; /** * Representation of AudioHeader *

    *

    Contains info about the Audio Header */ public interface AudioHeader { /** * @return the audio file type */ public abstract String getEncodingType(); /** * @return the BitRate of the Audio */ public String getBitRate(); /** * @return birate as a number */ public long getBitRateAsNumber(); /** * @return the Sampling rate */ public String getSampleRate(); /** * @return */ public int getSampleRateAsNumber(); /** * @return the format */ public String getFormat(); /** * @return the Channel Mode such as Stereo or Mono */ public String getChannels(); /** * @return if the bitRate is variable */ public boolean isVariableBitRate(); /** * @return track length */ public int getTrackLength(); } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/flac/0000755000175000017500000000000011556363171023524 5ustar drazzibdrazziblibjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/flac/FlacFileWriter.java0000644000175000017500000000313411247705415027230 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2003-2005 Raphaël Slinckx * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.audio.flac; import org.jaudiotagger.audio.exceptions.CannotWriteException; import org.jaudiotagger.audio.generic.AudioFileWriter; import org.jaudiotagger.tag.Tag; import java.io.IOException; import java.io.RandomAccessFile; /** * Write/delete tag info for Flac file (opensource lossless encoding) */ public class FlacFileWriter extends AudioFileWriter { private FlacTagWriter tw = new FlacTagWriter(); protected void writeTag(Tag tag, RandomAccessFile raf, RandomAccessFile rafTemp) throws CannotWriteException, IOException { tw.write(tag, raf, rafTemp); } protected void deleteTag(RandomAccessFile raf, RandomAccessFile tempRaf) throws CannotWriteException, IOException { tw.delete(raf, tempRaf); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/flac/metadatablock/0000755000175000017500000000000011556363171026317 5ustar drazzibdrazziblibjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/flac/metadatablock/BlockType.java0000644000175000017500000000076010727201653031054 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.flac.metadatablock; /** * The different types of metadata block *

    * 7 - 126 are reserved for future use * 127 is invalid * User: Paul Taylor * Date: 21-Nov-2007 */ public enum BlockType { STREAMINFO(0), PADDING(1), APPLICATION(2), SEEKTABLE(3), VORBIS_COMMENT(4), CUESHEET(5), PICTURE(6); private int id; BlockType(int id) { this.id = id; } public int getId() { return id; } } ././@LongLink0000000000000000000000000000015100000000000011562 Lustar rootrootlibjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/flac/metadatablock/MetadataBlockDataSeekTable.javalibjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/flac/metadatablock/MetadataBlockDataSeekTable.0000644000175000017500000000403111247705415033361 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2003-2005 Raphaël Slinckx * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.audio.flac.metadatablock; import java.io.IOException; import java.io.RandomAccessFile; /** * SeekTable Block *

    *

    This is an optional block for storing seek points. It is possible to seek to any given sample in a FLAC stream * without a seek table, but the delay can be unpredictable since the bitrate may vary widely within a stream. * By adding seek points to a stream, this delay can be significantly reduced. Each seek point takes 18 bytes, so 1% * resolution within a stream adds less than 2k. There can be only one SEEKTABLE in a stream, but the table can have * any number of seek points. There is also a special 'placeholder' seekpoint which will be ignored by decoders but * which can be used to reserve space for future seek point insertion. */ public class MetadataBlockDataSeekTable implements MetadataBlockData { private byte[] data; public MetadataBlockDataSeekTable(MetadataBlockHeader header, RandomAccessFile raf) throws IOException { data = new byte[header.getDataLength()]; raf.readFully(data); } public byte[] getBytes() { return data; } public int getLength() { return data.length; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/flac/metadatablock/MetadataBlock.java0000644000175000017500000000316311247705415031656 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2003-2005 Raphaël Slinckx * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.audio.flac.metadatablock; /** * Metadata Block *

    *

    A FLAC bitstream consists of the "fLaC" marker at the beginning of the stream, * followed by a mandatory metadata block (called the STREAMINFO block), any number of other metadata blocks, * then the audio frames. */ public class MetadataBlock { private MetadataBlockHeader mbh; private MetadataBlockData mbd; public MetadataBlock(MetadataBlockHeader mbh, MetadataBlockData mbd) { this.mbh = mbh; this.mbd = mbd; } public MetadataBlockHeader getHeader() { return mbh; } public MetadataBlockData getData() { return mbd; } public int getLength() { return MetadataBlockHeader.HEADER_LENGTH + mbh.getDataLength(); } } ././@LongLink0000000000000000000000000000015200000000000011563 Lustar rootrootlibjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/flac/metadatablock/MetadataBlockDataStreamInfo.javalibjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/flac/metadatablock/MetadataBlockDataStreamInfo0000644000175000017500000001503511310522141033501 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2003-2005 Raphaël Slinckx * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.audio.flac.metadatablock; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.util.logging.Logger; /** * Stream Info *

    *

    This block has information about the whole stream, like sample rate, number of channels, total number of samples, * etc. It must be present as the first metadata block in the stream. Other metadata blocks may follow, and ones * that the decoder doesn't understand, it will skip. * Format: * Info * <16> The minimum block size (in samples) used in the stream. * <16> The maximum block size (in samples) used in the stream. (Minimum blocksize == maximum blocksize) implies a fixed-blocksize stream. * <24> The minimum frame size (in bytes) used in the stream. May be 0 to imply the value is not known. * <24> The maximum frame size (in bytes) used in the stream. May be 0 to imply the value is not known. * <20> Sample rate in Hz. Though 20 bits are available, the maximum sample rate is limited by the structure of frame headers to 655350Hz. Also, * a value of 0 is invalid. * <3> (number of channels)-1. FLAC supports from 1 to 8 channels * <5> (bits per sample)-1. FLAC supports from 4 to 32 bits per sample. Currently the reference encoder and decoders only support up to 24 bits per sample. * <36> Total samples in stream. 'Samples' means inter-channel sample, * i.e. one second of 44.1Khz audio will have 44100 samples regardless of the number of channels. * A value of zero here means the number of total samples is unknown. * <128> MD5 signature of the unencoded audio data. This allows the decoder to determine if an error exists in the audio data * even when the error does not result in an invalid bitstream. * NOTES * * FLAC specifies a minimum block size of 16 and a maximum block size of 65535, meaning the bit patterns corresponding to the numbers 0-15 in the minimum blocksize and maximum blocksize fields are invalid. */ public class MetadataBlockDataStreamInfo implements MetadataBlockData { public static final int STREAM_INFO_DATA_LENGTH = 34; // Logger Object public static Logger logger = Logger.getLogger("org.jaudiotagger.audio.flac.MetadataBlockDataStreamInfo"); private int minBlockSize, maxBlockSize, minFrameSize, maxFrameSize, samplingRate, samplingRatePerChannel, bitsPerSample, channelNumber, totalNumberOfSamples; private float songLength; private boolean isValid = true; private ByteBuffer rawdata; public MetadataBlockDataStreamInfo(MetadataBlockHeader header, RandomAccessFile raf) throws IOException { rawdata = ByteBuffer.allocate(header.getDataLength()); int bytesRead = raf.getChannel().read(rawdata); if (bytesRead < header.getDataLength()) { throw new IOException("Unable to read required number of databytes read:" + bytesRead + ":required:" + header.getDataLength()); } rawdata.rewind(); minBlockSize = rawdata.getShort(); maxBlockSize = rawdata.getShort(); minFrameSize = readThreeByteInteger(rawdata.get(), rawdata.get(), rawdata.get()); maxFrameSize = readThreeByteInteger(rawdata.get(), rawdata.get(), rawdata.get()); samplingRate = readSamplingRate(rawdata.get(), rawdata.get(), rawdata.get()); channelNumber = ((u(rawdata.get(12)) & 0x0E) >>> 1) + 1; samplingRatePerChannel = samplingRate / channelNumber; bitsPerSample = ((u(rawdata.get(12)) & 0x01) << 4) + ((u(rawdata.get(13)) & 0xF0) >>> 4) + 1; totalNumberOfSamples = readTotalNumberOfSamples(rawdata.get(13), rawdata.get(14), rawdata.get(15), rawdata.get(16), rawdata.get(17)); songLength = (float) ((double) totalNumberOfSamples / samplingRate); logger.info(this.toString()); } /** * @return the rawdata as it will be written to file */ public byte[] getBytes() { return rawdata.array(); } public int getLength() { return getBytes().length; } public String toString() { return "MinBlockSize:" + minBlockSize + "MaxBlockSize:" + maxBlockSize + "MinFrameSize:" + minFrameSize + "MaxFrameSize:" + maxFrameSize + "SampleRateTotal:" + samplingRate + "SampleRatePerChannel:" + samplingRatePerChannel + ":Channel number:" + channelNumber + ":Bits per sample: " + bitsPerSample + ":TotalNumberOfSamples: " + totalNumberOfSamples + ":Length: " + songLength; } public int getSongLength() { return (int) songLength; } public float getPreciseLength() { return songLength; } public int getChannelNumber() { return channelNumber; } public int getSamplingRate() { return samplingRate; } public int getSamplingRatePerChannel() { return samplingRatePerChannel; } public String getEncodingType() { return "FLAC " + bitsPerSample + " bits"; } public boolean isValid() { return isValid; } private int readThreeByteInteger(byte b1, byte b2, byte b3) { int rate = (u(b1) << 16) + (u(b2) << 8) + (u(b3)); return rate; } //TODO this code seems to be give a sampling rate over 21 bytes instead of 20 bytes but attempt to change //to 21 bytes give wrong value private int readSamplingRate(byte b1, byte b2, byte b3) { int rate = (u(b1) << 12) + (u(b2) << 4) + ((u(b3) & 0xF0) >>> 4); return rate; } private int readTotalNumberOfSamples(byte b1, byte b2, byte b3, byte b4, byte b5) { int nb = u(b5); nb += u(b4) << 8; nb += u(b3) << 16; nb += u(b2) << 24; nb += (u(b1) & 0x0F) << 32; return nb; } private int u(int i) { return i & 0xFF; } } ././@LongLink0000000000000000000000000000015300000000000011564 Lustar rootrootlibjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/flac/metadatablock/MetadataBlockDataApplication.javalibjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/flac/metadatablock/MetadataBlockDataApplicatio0000644000175000017500000000323211247705415033533 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2003-2005 Raphaël Slinckx * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.audio.flac.metadatablock; import java.io.IOException; import java.io.RandomAccessFile; /** * Application Block *

    *

    This block is for use by third-party applications. The only mandatory field is a 32-bit identifier. * This ID is granted upon request to an application by the FLAC maintainers. The remainder is of the block is defined * by the registered application. */ public class MetadataBlockDataApplication implements MetadataBlockData { private byte[] data; public MetadataBlockDataApplication(MetadataBlockHeader header, RandomAccessFile raf) throws IOException { data = new byte[header.getDataLength()]; raf.readFully(data); } public byte[] getBytes() { return data; } public int getLength() { return data.length; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/flac/metadatablock/MetadataBlockHeader.java0000644000175000017500000001001611277006322032754 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2003-2005 Raphaël Slinckx * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.audio.flac.metadatablock; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.ByteBuffer; /** * Metadata Block Header */ public class MetadataBlockHeader { public static final int HEADER_LENGTH = 4; private boolean isLastBlock; private int dataLength; private byte[] bytes; private BlockType blockType; /** * Create header by reading from file * * @param raf * @return * @throws IOException */ public static MetadataBlockHeader readHeader(RandomAccessFile raf) throws IOException { ByteBuffer rawdata = ByteBuffer.allocate(HEADER_LENGTH); int bytesRead = raf.getChannel().read(rawdata); if (bytesRead < HEADER_LENGTH) { throw new IOException("Unable to read required number of databytes read:" + bytesRead + ":required:" + HEADER_LENGTH); } rawdata.rewind(); return new MetadataBlockHeader(rawdata); } public String toString() { return "BlockType:"+blockType + " DataLength:"+dataLength + " isLastBlock:"+isLastBlock; } /** * Construct header by reading bytes * * @param rawdata */ public MetadataBlockHeader(ByteBuffer rawdata) { isLastBlock = ((rawdata.get(0) & 0x80) >>> 7) == 1; int type = rawdata.get(0) & 0x7F; if (type < BlockType.values().length) { blockType = BlockType.values()[type]; } dataLength = (u(rawdata.get(1)) << 16) + (u(rawdata.get(2)) << 8) + (u(rawdata.get(3))); bytes = new byte[HEADER_LENGTH]; for (int i = 0; i < HEADER_LENGTH; i++) { bytes[i] = rawdata.get(i); } } /** * Construct a new header in order to write metadatablock to file * * @param isLastBlock * @param blockType * @param dataLength */ public MetadataBlockHeader(boolean isLastBlock, BlockType blockType, int dataLength) { ByteBuffer rawdata = ByteBuffer.allocate(HEADER_LENGTH); this.blockType = blockType; this.isLastBlock = isLastBlock; this.dataLength = dataLength; byte type; if (isLastBlock) { type = (byte) (0x80 | blockType.getId()); } else { type = (byte) blockType.getId(); } rawdata.put(type); //Size is 3Byte BigEndian int rawdata.put((byte) ((dataLength & 0xFF0000) >>> 16)); rawdata.put((byte) ((dataLength & 0xFF00) >>> 8)); rawdata.put((byte) (dataLength & 0xFF)); bytes = new byte[HEADER_LENGTH]; for (int i = 0; i < HEADER_LENGTH; i++) { bytes[i] = rawdata.get(i); } } private int u(int i) { return i & 0xFF; } public int getDataLength() { return dataLength; } public BlockType getBlockType() { return blockType; } public boolean isLastBlock() { return isLastBlock; } public byte[] getBytesWithoutIsLastBlockFlag() { bytes[0] = (byte) (bytes[0] & 0x7F); return bytes; } public byte[] getBytes() { return bytes; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/flac/metadatablock/MetadataBlockData.java0000644000175000017500000000233611247705415032451 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2003-2005 Raphaël Slinckx * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.audio.flac.metadatablock; /** * This defines the interface required of the different metadata block types */ public interface MetadataBlockData { /** * @return the rawdata as it will be written to file */ public byte[] getBytes(); /** * @return the length in bytes that the data uses when written to file */ public int getLength(); } ././@LongLink0000000000000000000000000000014700000000000011567 Lustar rootrootlibjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/flac/metadatablock/MetadataBlockDataPadding.javalibjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/flac/metadatablock/MetadataBlockDataPadding.ja0000644000175000017500000000353211247705415033410 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2003-2005 Raphaël Slinckx * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.audio.flac.metadatablock; /** * Padding Block *

    *

    This block allows for an arbitrary amount of padding. The contents of a PADDING block have no meaning. * This block is useful when it is known that metadata will be edited after encoding; the user can instruct the encoder * to reserve a PADDING block of sufficient size so that when metadata is added, it will simply overwrite the padding * (which is relatively quick) instead of having to insert it into the right place in the existing file * (which would normally require rewriting the entire file). */ public class MetadataBlockDataPadding implements MetadataBlockData { private int length; public MetadataBlockDataPadding(int length) { this.length = length; } public byte[] getBytes() { byte[] data = new byte[length]; for (int i = 0; i < length; i++) { data[i] = 0; } return data; } public int getLength() { return length; } } ././@LongLink0000000000000000000000000000014700000000000011567 Lustar rootrootlibjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/flac/metadatablock/MetadataBlockDataPicture.javalibjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/flac/metadatablock/MetadataBlockDataPicture.ja0000644000175000017500000002656111470746136033467 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.flac.metadatablock; import org.jaudiotagger.audio.generic.Utils; import org.jaudiotagger.tag.FieldKey; import org.jaudiotagger.tag.InvalidFrameException; import org.jaudiotagger.tag.TagField; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; import org.jaudiotagger.tag.reference.PictureTypes; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.RandomAccessFile; import java.io.UnsupportedEncodingException; import java.nio.ByteBuffer; import java.util.logging.Logger; /** * Picture Block *

    *

    *

    This block is for storing pictures associated with the file, most commonly cover art from CDs. * There may be more than one PICTURE block in a file. The picture format is similar to the APIC frame in ID3v2. * The PICTURE block has a type, MIME type, and UTF-8 description like ID3v2, and supports external linking via URL * (though this is discouraged). The differences are that there is no uniqueness constraint on the description field, * and the MIME type is mandatory. The FLAC PICTURE block also includes the resolution, color depth, and palette size * so that the client can search for a suitable picture without having to scan them all *

    * Format: * Info * <32> The picture type according to the ID3v2 APIC frame: (There may only be one each of picture type 1 and 2 in a file) * <32> The length of the MIME type string in bytes. * The MIME type string, in printable ASCII characters 0x20-0x7e. The MIME type may also be --> to signify that the data part is a URL of the picture instead of the picture data itself. * <32> The length of the description string in bytes. * The description of the picture, in UTF-8. * <32> The width of the picture in pixels. * <32> The height of the picture in pixels. * <32> The color depth of the picture in bits-per-pixel. * <32> For indexed-color pictures (e.g. GIF), the number of colors used, or 0 for non-indexed pictures. * <32> The length of the picture data in bytes. * The binary picture data. */ public class MetadataBlockDataPicture implements MetadataBlockData, TagField { public static final String IMAGE_IS_URL = "-->"; private int pictureType; private String mimeType; private String description; private int width; private int height; private int colourDepth; private int indexedColouredCount; private byte[] imageData; // Logger Object public static Logger logger = Logger.getLogger("org.jaudiotagger.audio.flac.MetadataBlockDataPicture"); private void initFromByteBuffer(ByteBuffer rawdata) throws IOException, InvalidFrameException { //Picture Type pictureType = rawdata.getInt(); if (pictureType >= PictureTypes.getInstanceOf().getSize()) { throw new InvalidFrameException("PictureType was:" + pictureType + "but the maximum allowed is " + (PictureTypes.getInstanceOf().getSize() - 1)); } //MimeType int mimeTypeSize = rawdata.getInt(); mimeType = getString(rawdata, mimeTypeSize, "ISO-8859-1"); //Description int descriptionSize = rawdata.getInt(); description = getString(rawdata, descriptionSize, "UTF-8"); //Image width width = rawdata.getInt(); //Image height height = rawdata.getInt(); //Colour Depth colourDepth = rawdata.getInt(); //Indexed Colour Count indexedColouredCount = rawdata.getInt(); //ImageData int rawdataSize = rawdata.getInt(); imageData = new byte[rawdataSize]; rawdata.get(imageData); logger.info("Read image:" + this.toString()); } /** * Initialize MetaBlockDataPicture from byteBuffer * * @param rawdata * @throws IOException * @throws InvalidFrameException */ public MetadataBlockDataPicture(ByteBuffer rawdata) throws IOException, InvalidFrameException { initFromByteBuffer(rawdata); } /** * Construct picture block by reading from file, the header informs us how many bytes we should be reading from * * @param header * @param raf * @throws java.io.IOException * @throws org.jaudiotagger.tag.InvalidFrameException */ //TODO check for buffer underflows see http://research.eeye.com/html/advisories/published/AD20071115.html public MetadataBlockDataPicture(MetadataBlockHeader header, RandomAccessFile raf) throws IOException, InvalidFrameException { ByteBuffer rawdata = ByteBuffer.allocate(header.getDataLength()); int bytesRead = raf.getChannel().read(rawdata); if (bytesRead < header.getDataLength()) { throw new IOException("Unable to read required number of databytes read:" + bytesRead + ":required:" + header.getDataLength()); } rawdata.rewind(); initFromByteBuffer(rawdata); } /** * Construct new MetadataPicture block * @param imageData * @param pictureType * @param mimeType * @param description * @param width * @param height * @param colourDepth * @param indexedColouredCount */ public MetadataBlockDataPicture(byte[] imageData, int pictureType, String mimeType, String description, int width, int height, int colourDepth, int indexedColouredCount) { //Picture Type this.pictureType = pictureType; //MimeType this.mimeType = mimeType; //Description this.description = description; this.width = width; this.height = height; this.colourDepth = colourDepth; this.indexedColouredCount = indexedColouredCount; //ImageData this.imageData = imageData; } private String getString(ByteBuffer rawdata, int length, String charset) throws IOException { byte[] tempbuffer = new byte[length]; rawdata.get(tempbuffer); return new String(tempbuffer, charset); } public byte[] getBytes() { try { ByteArrayOutputStream baos = new ByteArrayOutputStream(); baos.write(Utils.getSizeBEInt32(pictureType)); baos.write(Utils.getSizeBEInt32(mimeType.length())); baos.write(mimeType.getBytes("ISO-8859-1")); baos.write(Utils.getSizeBEInt32(description.length())); baos.write(description.getBytes("UTF-8")); baos.write(Utils.getSizeBEInt32(width)); baos.write(Utils.getSizeBEInt32(height)); baos.write(Utils.getSizeBEInt32(colourDepth)); baos.write(Utils.getSizeBEInt32(indexedColouredCount)); baos.write(Utils.getSizeBEInt32(imageData.length)); baos.write(imageData); return baos.toByteArray(); } catch (IOException ioe) { throw new RuntimeException(ioe.getMessage()); } } public int getLength() { return getBytes().length; } public int getPictureType() { return pictureType; } public String getMimeType() { return mimeType; } public String getDescription() { return description; } public int getWidth() { return width; } public int getHeight() { return height; } public int getColourDepth() { return colourDepth; } public int getIndexedColourCount() { return indexedColouredCount; } public byte[] getImageData() { return imageData; } /** * @return true if imagedata is held as a url rather than actually being imagedata */ public boolean isImageUrl() { return getMimeType().equals(IMAGE_IS_URL); } /** * @return the image url if there is otherwise return an empty String */ public String getImageUrl() { if (isImageUrl()) { return Utils.getString(getImageData(), 0, getImageData().length, TextEncoding.CHARSET_ISO_8859_1); } else { return ""; } } public String toString() { return PictureTypes.getInstanceOf().getValueForId(pictureType) + ":" + mimeType + ":" + description + ":" + "width:" + width + ":height:" + height + ":colourdepth:" + colourDepth + ":indexedColourCount:" + indexedColouredCount + ":image size in bytes:" + imageData.length; } /** * This method copies the data of the given field to the current data.
    * * @param field The field containing the data to be taken. */ public void copyContent(TagField field) { throw new UnsupportedOperationException(); } /** * Returns the Id of the represented tag field.
    * This value should uniquely identify a kind of tag data, like title. * {@link org.jaudiotagger.audio.generic.AbstractTag} will use the "id" to summarize multiple * fields. * * @return Unique identifier for the fields type. (title, artist...) */ public String getId() { return FieldKey.COVER_ART.name(); } /** * This method delivers the binary representation of the fields data in * order to be directly written to the file.
    * * @return Binary data representing the current tag field.
    * @throws java.io.UnsupportedEncodingException * Most tag data represents text. In some cases the underlying * implementation will need to convert the text data in java to * a specific charset encoding. In these cases an * {@link java.io.UnsupportedEncodingException} may occur. */ public byte[] getRawContent() throws UnsupportedEncodingException { return getBytes(); } /** * Determines whether the represented field contains (is made up of) binary * data, instead of text data.
    * Software can identify fields to be displayed because they are human * readable if this method returns false. * * @return true if field represents binary data (not human * readable). */ public boolean isBinary() { return true; } /** * This method will set the field to represent binary data.
    *

    * Some implementations may support conversions.
    * As of now (Octobre 2005) there is no implementation really using this * method to perform useful operations. * * @param b true, if the field contains binary data. * @deprecated As for now is of no use. Implementations should use another * way of setting this property. */ public void isBinary(boolean b) { //Do nothing, always true } /** * Identifies a field to be of common use.
    *

    * Some software may differ between common and not common fields. A common * one is for sure the title field. A web link may not be of common use for * tagging. However some file formats, or future development of users * expectations will make more fields common than now can be known. * * @return true if the field is of common use. */ public boolean isCommon() { return true; } /** * Determines whether the content of the field is empty.
    * * @return true if no data is stored (or empty String). */ public boolean isEmpty() { return false; } } ././@LongLink0000000000000000000000000000015000000000000011561 Lustar rootrootlibjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/flac/metadatablock/MetadataBlockDataCueSheet.javalibjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/flac/metadatablock/MetadataBlockDataCueSheet.j0000644000175000017500000000342711247705415033411 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2003-2005 Raphaël Slinckx * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.audio.flac.metadatablock; import java.io.IOException; import java.io.RandomAccessFile; /** * Cuesheet Block *

    *

    This block is for storing various information that can be used in a cue sheet. It supports track and index points, * compatible with Red Book CD digital audio discs, as well as other CD-DA metadata such as media catalog number and * track ISRCs. The CUESHEET block is especially useful for backing up CD-DA discs, but it can be used as a general * purpose cueing mechanism for playback */ public class MetadataBlockDataCueSheet implements MetadataBlockData { private byte[] data; public MetadataBlockDataCueSheet(MetadataBlockHeader header, RandomAccessFile raf) throws IOException { data = new byte[header.getDataLength()]; raf.readFully(data); } public byte[] getBytes() { return data; } public int getLength() { return data.length; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/flac/FlacFileReader.java0000644000175000017500000000322511470746136027162 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2003-2005 Raphaël Slinckx * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.audio.flac; import org.jaudiotagger.audio.exceptions.CannotReadException; import org.jaudiotagger.audio.generic.AudioFileReader; import org.jaudiotagger.audio.generic.GenericAudioHeader; import org.jaudiotagger.tag.Tag; import java.io.IOException; import java.io.RandomAccessFile; /** * Read encoding and tag info for Flac file (open source lossless encoding) */ public class FlacFileReader extends AudioFileReader { private FlacInfoReader ir = new FlacInfoReader(); private FlacTagReader tr = new FlacTagReader(); protected GenericAudioHeader getEncodingInfo(RandomAccessFile raf) throws CannotReadException, IOException { return ir.read(raf); } protected Tag getTag(RandomAccessFile raf) throws CannotReadException, IOException { return tr.read(raf); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/flac/FlacTagReader.java0000644000175000017500000001110011247705415027002 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2003-2005 Raphaël Slinckx * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.audio.flac; import org.jaudiotagger.audio.exceptions.CannotReadException; import org.jaudiotagger.audio.flac.metadatablock.MetadataBlockDataPicture; import org.jaudiotagger.audio.flac.metadatablock.MetadataBlockHeader; import org.jaudiotagger.tag.InvalidFrameException; import org.jaudiotagger.tag.flac.FlacTag; import org.jaudiotagger.tag.vorbiscomment.VorbisCommentReader; import org.jaudiotagger.tag.vorbiscomment.VorbisCommentTag; import java.io.IOException; import java.io.RandomAccessFile; import java.util.ArrayList; import java.util.List; import java.util.logging.Logger; import java.util.logging.Level; /** * Read Flac Tag */ public class FlacTagReader { // Logger Object public static Logger logger = Logger.getLogger("org.jaudiotagger.audio.flac"); private VorbisCommentReader vorbisCommentReader = new VorbisCommentReader(); public FlacTag read(RandomAccessFile raf) throws CannotReadException, IOException { FlacStreamReader flacStream = new FlacStreamReader(raf); flacStream.findStream(); //Hold the metadata VorbisCommentTag tag = null; List images = new ArrayList(); //Seems like we have a valid stream boolean isLastBlock = false; while (!isLastBlock) { if(logger.isLoggable(Level.INFO)) { logger.info("Looking for MetaBlockHeader at:"+raf.getFilePointer()); } //Read the header MetadataBlockHeader mbh = MetadataBlockHeader.readHeader(raf); if(logger.isLoggable(Level.INFO)) { logger.info("Reading MetadataBlockHeader:"+mbh.toString() + " ending at "+raf.getFilePointer()); } //Is it one containing some sort of metadata, therefore interested in it? switch (mbh.getBlockType()) { //We got a vorbiscomment comment block, parse it case VORBIS_COMMENT: byte[] commentHeaderRawPacket = new byte[mbh.getDataLength()]; raf.read(commentHeaderRawPacket); tag = vorbisCommentReader.read(commentHeaderRawPacket, false); break; case PICTURE: try { MetadataBlockDataPicture mbdp = new MetadataBlockDataPicture(mbh, raf); images.add(mbdp); } catch (IOException ioe) { logger.warning("Unable to read picture metablock, ignoring:" + ioe.getMessage()); } catch (InvalidFrameException ive) { logger.warning("Unable to read picture metablock, ignoring" + ive.getMessage()); } break; //This is not a metadata block we are interested in so we skip to next block default: if(logger.isLoggable(Level.INFO)) { logger.info("Ignoring MetadataBlock:"+mbh.getBlockType()); } raf.seek(raf.getFilePointer() + mbh.getDataLength()); break; } isLastBlock = mbh.isLastBlock(); mbh = null; } //Note there may not be either a tag or any images, no problem this is valid however to make it easier we //just initialize Flac with an empty VorbisTag if (tag == null) { tag = VorbisCommentTag.createNewTag(); } FlacTag flacTag = new FlacTag(tag, images); return flacTag; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/flac/FlacStreamReader.java0000644000175000017500000001051111277026507027530 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.flac; import org.jaudiotagger.audio.exceptions.CannotReadException; import org.jaudiotagger.logging.ErrorMessage; import org.jaudiotagger.tag.id3.AbstractID3v2Tag; import org.jaudiotagger.tag.id3.ID3v22Tag; import org.jaudiotagger.tag.id3.ID3v23Tag; import org.jaudiotagger.tag.id3.ID3v24Tag; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.ByteBuffer; /** * Flac Stream *

    * Reader files and identifies if this is in fact a flac stream */ public class FlacStreamReader { public static final int FLAC_STREAM_IDENTIFIER_LENGTH = 4; public static final String FLAC_STREAM_IDENTIFIER = "fLaC"; private RandomAccessFile raf; private int startOfFlacInFile; /** * Create instance for holding stream info * @param raf */ public FlacStreamReader(RandomAccessFile raf) { this.raf = raf; } /** * Reads the stream block to ensure it is a flac file * * @throws IOException * @throws CannotReadException */ public void findStream() throws IOException, CannotReadException { //Begins tag parsing if (raf.length() == 0) { //Empty File throw new CannotReadException("Error: File empty"); } raf.seek(0); //FLAC Stream at start if (isFlacHeader()) { startOfFlacInFile = 0; return; } //Ok maybe there is an ID3v24tag first if (isId3v24Tag()) { startOfFlacInFile = (int) (raf.getFilePointer() - FLAC_STREAM_IDENTIFIER_LENGTH); return; } //Ok maybe there is an ID3v23tag first if (isId3v23Tag()) { startOfFlacInFile = (int) (raf.getFilePointer() - FLAC_STREAM_IDENTIFIER_LENGTH); return; } //Ok maybe there is an ID3v22tag first if (isId3v22Tag()) { startOfFlacInFile = (int) (raf.getFilePointer() - FLAC_STREAM_IDENTIFIER_LENGTH); return; } throw new CannotReadException(ErrorMessage.FLAC_NO_FLAC_HEADER_FOUND.getMsg()); } private boolean isId3v24Tag() throws IOException { int id3tagsize; ID3v24Tag id3tag = new ID3v24Tag(); ByteBuffer bb = ByteBuffer.allocate(AbstractID3v2Tag.TAG_HEADER_LENGTH); raf.seek(0); raf.getChannel().read(bb); if (id3tag.seek(bb)) { id3tagsize = id3tag.readSize(bb); raf.seek(id3tagsize); //FLAC Stream immediately after end of id3 tag if (isFlacHeader()) { return true; } } return false; } private boolean isId3v23Tag() throws IOException { int id3tagsize; ID3v23Tag id3tag = new ID3v23Tag(); ByteBuffer bb = ByteBuffer.allocate(AbstractID3v2Tag.TAG_HEADER_LENGTH); raf.seek(0); raf.getChannel().read(bb); if (id3tag.seek(bb)) { id3tagsize = id3tag.readSize(bb); raf.seek(id3tagsize); //FLAC Stream immediately after end of id3 tag if (isFlacHeader()) { return true; } } return false; } private boolean isId3v22Tag() throws IOException { int id3tagsize; ID3v22Tag id3tag = new ID3v22Tag(); ByteBuffer bb = ByteBuffer.allocate(AbstractID3v2Tag.TAG_HEADER_LENGTH); raf.seek(0); raf.getChannel().read(bb); if (id3tag.seek(bb)) { id3tagsize = id3tag.readSize(bb); raf.seek(id3tagsize); //FLAC Stream immediately after end of id3 tag if (isFlacHeader()) { return true; } } return false; } private boolean isFlacHeader() throws IOException { //FLAC Stream at start byte[] b = new byte[FLAC_STREAM_IDENTIFIER_LENGTH]; raf.read(b); String flac = new String(b); return flac.equals(FLAC_STREAM_IDENTIFIER); } /** * Usually flac header is at start of file, but unofficially and ID3 tag is allowed at the start of the file. * * @return the start of the Flac within file */ public int getStartOfFlacInFile() { return startOfFlacInFile; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/flac/FlacInfoReader.java0000644000175000017500000001055611310522141027160 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2003-2005 Raphaël Slinckx * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.audio.flac; import org.jaudiotagger.audio.exceptions.CannotReadException; import org.jaudiotagger.audio.flac.metadatablock.BlockType; import org.jaudiotagger.audio.flac.metadatablock.MetadataBlockDataStreamInfo; import org.jaudiotagger.audio.flac.metadatablock.MetadataBlockHeader; import org.jaudiotagger.audio.generic.GenericAudioHeader; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; import java.util.logging.Logger; /** * Read info from Flac file */ public class FlacInfoReader { // Logger Object public static Logger logger = Logger.getLogger("org.jaudiotagger.audio.flac"); private static final int NO_OF_BITS_IN_BYTE = 8; private static final int KILOBYTES_TO_BYTES_MULTIPLIER = 1000; public GenericAudioHeader read(RandomAccessFile raf) throws CannotReadException, IOException { FlacStreamReader flacStream = new FlacStreamReader(raf); flacStream.findStream(); MetadataBlockDataStreamInfo mbdsi = null; boolean isLastBlock = false; //Search for StreamInfo Block, but even after we found it we still have to continue through all //the metadata blocks so that we can find the start of the audio frames which we need to calculate //the bitrate while (!isLastBlock) { MetadataBlockHeader mbh = MetadataBlockHeader.readHeader(raf); if (mbh.getBlockType() == BlockType.STREAMINFO) { mbdsi = new MetadataBlockDataStreamInfo(mbh, raf); if (!mbdsi.isValid()) { throw new CannotReadException("FLAC StreamInfo not valid"); } } else { raf.seek(raf.getFilePointer() + mbh.getDataLength()); } isLastBlock = mbh.isLastBlock(); mbh = null; //Free memory } if (mbdsi == null) { throw new CannotReadException("Unable to find Flac StreamInfo"); } GenericAudioHeader info = new GenericAudioHeader(); info.setLength(mbdsi.getSongLength()); info.setPreciseLength(mbdsi.getPreciseLength()); info.setChannelNumber(mbdsi.getChannelNumber()); info.setSamplingRate(mbdsi.getSamplingRate()); info.setEncodingType(mbdsi.getEncodingType()); info.setExtraEncodingInfos(""); info.setBitrate(computeBitrate(mbdsi.getPreciseLength(), raf.length() - raf.getFilePointer())); return info; } private int computeBitrate(float length, long size) { return (int) ((size / KILOBYTES_TO_BYTES_MULTIPLIER) * NO_OF_BITS_IN_BYTE / length); } /** * Count the number of metadatablocks, useful for debugging * * @param f * @return * @throws CannotReadException * @throws IOException */ public int countMetaBlocks(File f) throws CannotReadException, IOException { RandomAccessFile raf = new RandomAccessFile(f, "r"); FlacStreamReader flacStream = new FlacStreamReader(raf); flacStream.findStream(); boolean isLastBlock = false; int count = 0; while (!isLastBlock) { MetadataBlockHeader mbh = MetadataBlockHeader.readHeader(raf); logger.info("Found block:" + mbh.getBlockType()); raf.seek(raf.getFilePointer() + mbh.getDataLength()); isLastBlock = mbh.isLastBlock(); mbh = null; //Free memory count++; } raf.close(); return count; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/flac/FlacTagWriter.java0000644000175000017500000002564611310522141027060 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2003-2005 Raphaël Slinckx * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.audio.flac; import org.jaudiotagger.audio.exceptions.CannotReadException; import org.jaudiotagger.audio.exceptions.CannotWriteException; import org.jaudiotagger.audio.flac.metadatablock.*; import org.jaudiotagger.tag.Tag; import org.jaudiotagger.tag.flac.FlacTag; import java.io.IOException; import java.io.RandomAccessFile; import java.util.ArrayList; import java.util.List; import java.util.logging.Logger; /** * Write Flac Tag */ public class FlacTagWriter { // Logger Object public static Logger logger = Logger.getLogger("org.jaudiotagger.audio.flac"); private MetadataBlock streamInfoBlock; private List metadataBlockPadding = new ArrayList(1); private List metadataBlockApplication = new ArrayList(1); private List metadataBlockSeekTable = new ArrayList(1); private List metadataBlockCueSheet = new ArrayList(1); private FlacTagCreator tc = new FlacTagCreator(); private FlacTagReader reader = new FlacTagReader(); /** * Delete Tag from file * * @param raf * @param tempRaf * @throws IOException * @throws CannotWriteException */ public void delete(RandomAccessFile raf, RandomAccessFile tempRaf) throws IOException, CannotWriteException { //This will save the file without any Comment or PictureData blocks FlacTag emptyTag = new FlacTag(null, new ArrayList()); raf.seek(0); tempRaf.seek(0); write(emptyTag, raf, tempRaf); } /** * Write tag to file * * @param tag * @param raf * @param rafTemp * @throws CannotWriteException * @throws IOException */ public void write(Tag tag, RandomAccessFile raf, RandomAccessFile rafTemp) throws CannotWriteException, IOException { logger.info("Writing tag"); //Clean up old data streamInfoBlock=null; metadataBlockPadding.clear(); metadataBlockApplication.clear(); metadataBlockSeekTable.clear(); metadataBlockCueSheet.clear(); //Read existing data FlacStreamReader flacStream = new FlacStreamReader(raf); try { flacStream.findStream(); } catch (CannotReadException cre) { throw new CannotWriteException(cre.getMessage()); } boolean isLastBlock = false; while (!isLastBlock) { MetadataBlockHeader mbh = MetadataBlockHeader.readHeader(raf); switch (mbh.getBlockType()) { case STREAMINFO: { streamInfoBlock = new MetadataBlock(mbh,new MetadataBlockDataStreamInfo(mbh, raf)); break; } case VORBIS_COMMENT: case PADDING: case PICTURE: { //All these will be replaced by the new metadata so we just treat as padding in order //to determine how much space is already allocated in the file raf.seek(raf.getFilePointer() + mbh.getDataLength()); MetadataBlockData mbd = new MetadataBlockDataPadding(mbh.getDataLength()); metadataBlockPadding.add(new MetadataBlock(mbh, mbd)); break; } case APPLICATION: { MetadataBlockData mbd = new MetadataBlockDataApplication(mbh, raf); metadataBlockApplication.add(new MetadataBlock(mbh, mbd)); break; } case SEEKTABLE: { MetadataBlockData mbd = new MetadataBlockDataSeekTable(mbh, raf); metadataBlockSeekTable.add(new MetadataBlock(mbh, mbd)); break; } case CUESHEET: { MetadataBlockData mbd = new MetadataBlockDataCueSheet(mbh, raf); metadataBlockCueSheet.add(new MetadataBlock(mbh, mbd)); break; } default: { //What are the consequences of doing this raf.seek(raf.getFilePointer() + mbh.getDataLength()); break; } } isLastBlock = mbh.isLastBlock(); } //Number of bytes in the existing file available before audio data int availableRoom = computeAvailableRoom(); //Minimum Size of the New tag data without padding int newTagSize = tc.convert(tag).limit(); //Number of bytes required for new tagdata and other metadata blocks int neededRoom = newTagSize + computeNeededRoom(); //Go to start of Flac within file raf.seek(flacStream.getStartOfFlacInFile()); logger.info("Writing tag available bytes:" + availableRoom + ":needed bytes:" + neededRoom); //There is enough room to fit the tag without moving the audio just need to //adjust padding accordingly need to allow space for padding header if padding required if ((availableRoom == neededRoom) || (availableRoom > neededRoom + MetadataBlockHeader.HEADER_LENGTH)) { //Jump over Id3 (if exists) Flac and StreamInfoBlock raf.seek(flacStream.getStartOfFlacInFile() + FlacStreamReader.FLAC_STREAM_IDENTIFIER_LENGTH); //Write StreamInfo, we always write this first even if wasnt first in original spec raf.write(streamInfoBlock.getHeader().getBytesWithoutIsLastBlockFlag()); raf.write(streamInfoBlock.getData().getBytes()); //Write Application Blocks for (MetadataBlock aMetadataBlockApplication : metadataBlockApplication) { raf.write(aMetadataBlockApplication.getHeader().getBytesWithoutIsLastBlockFlag()); raf.write(aMetadataBlockApplication.getData().getBytes()); } //Write Seek Table Blocks for (MetadataBlock aMetadataBlockSeekTable : metadataBlockSeekTable) { raf.write(aMetadataBlockSeekTable.getHeader().getBytesWithoutIsLastBlockFlag()); raf.write(aMetadataBlockSeekTable.getData().getBytes()); } //Write Cue sheet Blocks for (MetadataBlock aMetadataBlockCueSheet : metadataBlockCueSheet) { raf.write(aMetadataBlockCueSheet.getHeader().getBytesWithoutIsLastBlockFlag()); raf.write(aMetadataBlockCueSheet.getData().getBytes()); } //Write tag (and padding) raf.getChannel().write(tc.convert(tag, availableRoom - neededRoom)); } //Need to move audio else { //Skip to start of Audio //Write FlacStreamReader and StreamIfoMetablock to new file int dataStartSize = flacStream.getStartOfFlacInFile() + FlacStreamReader.FLAC_STREAM_IDENTIFIER_LENGTH + MetadataBlockHeader.HEADER_LENGTH + MetadataBlockDataStreamInfo.STREAM_INFO_DATA_LENGTH; raf.seek(0); rafTemp.getChannel().transferFrom(raf.getChannel(), 0, dataStartSize); rafTemp.seek(dataStartSize); //Write all the metadatablocks for (MetadataBlock aMetadataBlockApplication : metadataBlockApplication) { rafTemp.write(aMetadataBlockApplication.getHeader().getBytesWithoutIsLastBlockFlag()); rafTemp.write(aMetadataBlockApplication.getData().getBytes()); } for (MetadataBlock aMetadataBlockSeekTable : metadataBlockSeekTable) { rafTemp.write(aMetadataBlockSeekTable.getHeader().getBytesWithoutIsLastBlockFlag()); rafTemp.write(aMetadataBlockSeekTable.getData().getBytes()); } for (MetadataBlock aMetadataBlockCueSheet : metadataBlockCueSheet) { rafTemp.write(aMetadataBlockCueSheet.getHeader().getBytesWithoutIsLastBlockFlag()); rafTemp.write(aMetadataBlockCueSheet.getData().getBytes()); } //Write tag data use default padding rafTemp.write(tc.convert(tag, FlacTagCreator.DEFAULT_PADDING).array()); //Write audio to new file raf.seek(dataStartSize + availableRoom); rafTemp.getChannel().transferFrom(raf.getChannel(), rafTemp.getChannel().position(), raf.getChannel().size()); } } /** * @return space currently availble for writing all Flac metadatablocks exceprt for StreamInfo which is fixed size */ private int computeAvailableRoom() { int length = 0; for (MetadataBlock aMetadataBlockApplication : metadataBlockApplication) { length += aMetadataBlockApplication.getLength(); } for (MetadataBlock aMetadataBlockSeekTable : metadataBlockSeekTable) { length += aMetadataBlockSeekTable.getLength(); } for (MetadataBlock aMetadataBlockCueSheet : metadataBlockCueSheet) { length += aMetadataBlockCueSheet.getLength(); } for (MetadataBlock aMetadataBlockPadding : metadataBlockPadding) { length += aMetadataBlockPadding.getLength(); } return length; } /** * @return space required to write the metadata blocks that are part of Flac but are not part of tagdata * in the normal sense. */ private int computeNeededRoom() { int length = 0; for (MetadataBlock aMetadataBlockApplication : metadataBlockApplication) { length += aMetadataBlockApplication.getLength(); } for (MetadataBlock aMetadataBlockSeekTable : metadataBlockSeekTable) { length += aMetadataBlockSeekTable.getLength(); } for (MetadataBlock aMetadataBlockCueSheet : metadataBlockCueSheet) { length += aMetadataBlockCueSheet.getLength(); } return length; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/flac/FlacTagCreator.java0000644000175000017500000001110411247705415027203 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2003-2005 Raphaël Slinckx * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.audio.flac; import org.jaudiotagger.audio.flac.metadatablock.BlockType; import org.jaudiotagger.audio.flac.metadatablock.MetadataBlockDataPadding; import org.jaudiotagger.audio.flac.metadatablock.MetadataBlockDataPicture; import org.jaudiotagger.audio.flac.metadatablock.MetadataBlockHeader; import org.jaudiotagger.audio.generic.AbstractTagCreator; import org.jaudiotagger.tag.Tag; import org.jaudiotagger.tag.flac.FlacTag; import org.jaudiotagger.tag.vorbiscomment.VorbisCommentCreator; import java.io.UnsupportedEncodingException; import java.nio.ByteBuffer; import java.util.ListIterator; import java.util.logging.Logger; /** * Create the tag data ready for writing to flac file */ public class FlacTagCreator extends AbstractTagCreator { // Logger Object public static Logger logger = Logger.getLogger("org.jaudiotagger.audio.flac"); public static final int DEFAULT_PADDING = 4000; private static final VorbisCommentCreator creator = new VorbisCommentCreator(); /** * @param tag * @param paddingSize extra padding to be added * @return * @throws UnsupportedEncodingException */ public ByteBuffer convert(Tag tag, int paddingSize) throws UnsupportedEncodingException { logger.info("Convert flac tag:padding:" + paddingSize); FlacTag flacTag = (FlacTag) tag; int tagLength = 0; ByteBuffer vorbiscomment = null; if (flacTag.getVorbisCommentTag() != null) { vorbiscomment = creator.convert(flacTag.getVorbisCommentTag()); tagLength = vorbiscomment.capacity() + MetadataBlockHeader.HEADER_LENGTH; } for (MetadataBlockDataPicture image : flacTag.getImages()) { tagLength += image.getBytes().length + MetadataBlockHeader.HEADER_LENGTH; } logger.info("Convert flac tag:taglength:" + tagLength); ByteBuffer buf = ByteBuffer.allocate(tagLength + paddingSize); MetadataBlockHeader vorbisHeader; //If there are other metadata blocks if (flacTag.getVorbisCommentTag() != null) { if ((paddingSize > 0) || (flacTag.getImages().size() > 0)) { vorbisHeader = new MetadataBlockHeader(false, BlockType.VORBIS_COMMENT, vorbiscomment.capacity()); } else { vorbisHeader = new MetadataBlockHeader(true, BlockType.VORBIS_COMMENT, vorbiscomment.capacity()); } buf.put(vorbisHeader.getBytes()); buf.put(vorbiscomment); } //Images ListIterator li = flacTag.getImages().listIterator(); while (li.hasNext()) { MetadataBlockDataPicture imageField = li.next(); MetadataBlockHeader imageHeader; if (paddingSize > 0 || li.hasNext()) { imageHeader = new MetadataBlockHeader(false, BlockType.PICTURE, imageField.getLength()); } else { imageHeader = new MetadataBlockHeader(true, BlockType.PICTURE, imageField.getLength()); } buf.put(imageHeader.getBytes()); buf.put(imageField.getBytes()); } //Padding logger.info("Convert flac tag at" + buf.position()); if (paddingSize > 0) { int paddingDataSize = paddingSize - MetadataBlockHeader.HEADER_LENGTH; MetadataBlockHeader paddingHeader = new MetadataBlockHeader(true, BlockType.PADDING, paddingDataSize); MetadataBlockDataPadding padding = new MetadataBlockDataPadding(paddingDataSize); buf.put(paddingHeader.getBytes()); buf.put(padding.getBytes()); } buf.rewind(); return buf; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/ogg/0000755000175000017500000000000011556363172023374 5ustar drazzibdrazziblibjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/ogg/OggVorbisCommentTagCreator.java0000644000175000017500000000471511247705415031443 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2003-2005 Raphaël Slinckx * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.audio.ogg; import org.jaudiotagger.audio.ogg.util.VorbisHeader; import org.jaudiotagger.audio.ogg.util.VorbisPacketType; import org.jaudiotagger.tag.Tag; import org.jaudiotagger.tag.vorbiscomment.VorbisCommentCreator; import java.io.UnsupportedEncodingException; import java.nio.ByteBuffer; import java.util.logging.Logger; /** * Creates an OggVorbis Comment Tag from a VorbisComment for use within an OggVorbis Container *

    * When a Vorbis Comment is used within OggVorbis it additionally has a vorbis header and a framing * bit. */ public class OggVorbisCommentTagCreator { // Logger Object public static Logger logger = Logger.getLogger("org.jaudiotagger.audio.ogg"); public static final int FIELD_FRAMING_BIT_LENGTH = 1; public static final byte FRAMING_BIT_VALID_VALUE = (byte) 0x01; private VorbisCommentCreator creator = new VorbisCommentCreator(); //Creates the ByteBuffer for the ogg tag public ByteBuffer convert(Tag tag) throws UnsupportedEncodingException { ByteBuffer ogg = creator.convert(tag); int tagLength = ogg.capacity() + VorbisHeader.FIELD_PACKET_TYPE_LENGTH + VorbisHeader.FIELD_CAPTURE_PATTERN_LENGTH + OggVorbisCommentTagCreator.FIELD_FRAMING_BIT_LENGTH; ByteBuffer buf = ByteBuffer.allocate(tagLength); //[packet type=comment0x03]['vorbis'] buf.put((byte) VorbisPacketType.COMMENT_HEADER.getType()); buf.put(VorbisHeader.CAPTURE_PATTERN_AS_BYTES); //The actual tag buf.put(ogg); //Framing bit = 1 buf.put(FRAMING_BIT_VALID_VALUE); buf.rewind(); return buf; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/ogg/VorbisVersion.java0000644000175000017500000000065110656607117027053 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.ogg; /** * Vorbis Version *

    * Ordinal is used to map from internal representation */ public enum VorbisVersion { VERSION_ONE("Ogg Vorbis v1"); //The display name for this version private String displayName; VorbisVersion(String displayName) { this.displayName = displayName; } public String toString() { return displayName; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/ogg/OggFileReader.java0000644000175000017500000001211611277026507026675 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2003-2005 Raphaël Slinckx * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.audio.ogg; import org.jaudiotagger.audio.exceptions.CannotReadException; import org.jaudiotagger.audio.generic.AudioFileReader; import org.jaudiotagger.audio.generic.GenericAudioHeader; import org.jaudiotagger.audio.ogg.util.OggInfoReader; import org.jaudiotagger.audio.ogg.util.OggPageHeader; import org.jaudiotagger.fix.Fix; import org.jaudiotagger.tag.Tag; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; import java.util.logging.Logger; /** * Read Ogg File Tag and Encoding information *

    * Only implemented for ogg files containing a vorbis stream with vorbis comments */ public class OggFileReader extends AudioFileReader { // Logger Object public static Logger logger = Logger.getLogger("org.jaudiotagger.audio.ogg"); private OggInfoReader ir; private OggVorbisTagReader vtr; public OggFileReader() { ir = new OggInfoReader(); vtr = new OggVorbisTagReader(); } public OggFileReader(Fix fix) { Fix fix1 = fix; ir = new OggInfoReader(); vtr = new OggVorbisTagReader(fix); } protected GenericAudioHeader getEncodingInfo(RandomAccessFile raf) throws CannotReadException, IOException { return ir.read(raf); } protected Tag getTag(RandomAccessFile raf) throws CannotReadException, IOException { return vtr.read(raf); } /** * Return count Ogg Page header, count starts from zero *

    * count=0; should return PageHeader that contains Vorbis Identification Header * count=1; should return Pageheader that contains VorbisComment and possibly SetupHeader * count>=2; should return PageHeader containing remaining VorbisComment,SetupHeader and/or Audio * * @param raf * @param count * @return * @throws CannotReadException * @throws IOException */ public OggPageHeader readOggPageHeader(RandomAccessFile raf, int count) throws CannotReadException, IOException { OggPageHeader pageHeader = OggPageHeader.read(raf); while (count > 0) { raf.seek(raf.getFilePointer() + pageHeader.getPageLength()); pageHeader = OggPageHeader.read(raf); count--; } return pageHeader; } /** * Summarize all the ogg headers in a file *

    * A useful utility function * * @param oggFile * @throws CannotReadException * @throws IOException */ public void summarizeOggPageHeaders(File oggFile) throws CannotReadException, IOException { RandomAccessFile raf = new RandomAccessFile(oggFile, "r"); while (raf.getFilePointer() < raf.length()) { System.out.println("pageHeader starts at absolute file position:" + raf.getFilePointer()); OggPageHeader pageHeader = OggPageHeader.read(raf); System.out.println("pageHeader finishes at absolute file position:" + raf.getFilePointer()); System.out.println(pageHeader + "\n"); raf.seek(raf.getFilePointer() + pageHeader.getPageLength()); } System.out.println("Raf File Pointer at:" + raf.getFilePointer() + "File Size is:" + raf.length()); raf.close(); } /** * Summarizes the first five pages, normally all we are interested in * * @param oggFile * @throws CannotReadException * @throws IOException */ public void shortSummarizeOggPageHeaders(File oggFile) throws CannotReadException, IOException { RandomAccessFile raf = new RandomAccessFile(oggFile, "r"); int i = 0; while (raf.getFilePointer() < raf.length()) { System.out.println("pageHeader starts at absolute file position:" + raf.getFilePointer()); OggPageHeader pageHeader = OggPageHeader.read(raf); System.out.println("pageHeader finishes at absolute file position:" + raf.getFilePointer()); System.out.println(pageHeader + "\n"); raf.seek(raf.getFilePointer() + pageHeader.getPageLength()); i++; if(i>=5) { break; } } System.out.println("Raf File Pointer at:" + raf.getFilePointer() + "File Size is:" + raf.length()); raf.close(); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/ogg/OggFileWriter.java0000644000175000017500000000355411247705415026754 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2003-2005 Raphaël Slinckx * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.audio.ogg; import org.jaudiotagger.audio.exceptions.CannotReadException; import org.jaudiotagger.audio.exceptions.CannotWriteException; import org.jaudiotagger.audio.generic.AudioFileWriter; import org.jaudiotagger.tag.Tag; import java.io.IOException; import java.io.RandomAccessFile; import java.util.logging.Logger; /** * Write tag data to Ogg File *

    * Only works for Ogg files containing a vorbis stream */ public class OggFileWriter extends AudioFileWriter { // Logger Object public static Logger logger = Logger.getLogger("org.jaudiotagger.audio.ogg"); private OggVorbisTagWriter vtw = new OggVorbisTagWriter(); protected void writeTag(Tag tag, RandomAccessFile raf, RandomAccessFile rafTemp) throws CannotReadException, CannotWriteException, IOException { vtw.write(tag, raf, rafTemp); } protected void deleteTag(RandomAccessFile raf, RandomAccessFile tempRaf) throws CannotReadException, CannotWriteException, IOException { vtw.delete(raf, tempRaf); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/ogg/OggVorbisTagReader.java0000644000175000017500000006702511277026507027727 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2003-2005 Raphaël Slinckx * Copyright (c) 2004-2005 Christian Laireiter * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.audio.ogg; import org.jaudiotagger.audio.exceptions.CannotReadException; import org.jaudiotagger.audio.generic.Utils; import org.jaudiotagger.audio.ogg.util.OggPageHeader; import org.jaudiotagger.audio.ogg.util.VorbisHeader; import org.jaudiotagger.audio.ogg.util.VorbisPacketType; import org.jaudiotagger.fix.Fix; import org.jaudiotagger.logging.ErrorMessage; import org.jaudiotagger.tag.Tag; import org.jaudiotagger.tag.vorbiscomment.VorbisCommentReader; import org.jaudiotagger.tag.vorbiscomment.VorbisCommentTag; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.RandomAccessFile; import java.util.ArrayList; import java.util.List; import java.util.logging.Logger; /** * Read Vorbis Comment Tag within ogg *

    * Vorbis is the audiostream within an ogg file, Vorbis uses VorbisComments as its tag */ public class OggVorbisTagReader { // Logger Object public static Logger logger = Logger.getLogger("org.jaudiotagger.audio.ogg"); private VorbisCommentReader vorbisCommentReader; public OggVorbisTagReader() { vorbisCommentReader = new VorbisCommentReader(); } public OggVorbisTagReader(Fix fix) { Fix fix1 = fix; vorbisCommentReader = new VorbisCommentReader(fix); } /** * Read the Logical VorbisComment Tag from the file *

    *

    Read the CommenyTag, within an OggVorbis file the VorbisCommentTag is mandatory * * @param raf * @return * @throws CannotReadException * @throws IOException */ public Tag read(RandomAccessFile raf) throws CannotReadException, IOException { logger.info("Starting to read ogg vorbis tag from file:"); byte[] rawVorbisCommentData = readRawPacketData(raf); //Begin tag reading VorbisCommentTag tag = vorbisCommentReader.read(rawVorbisCommentData, true); logger.fine("CompletedReadCommentTag"); return tag; } /** * Retrieve the Size of the VorbisComment packet including the oggvorbis header * * @param raf * @return * @throws CannotReadException * @throws IOException */ public int readOggVorbisRawSize(RandomAccessFile raf) throws CannotReadException, IOException { byte[] rawVorbisCommentData = readRawPacketData(raf); return rawVorbisCommentData.length + VorbisHeader.FIELD_PACKET_TYPE_LENGTH + VorbisHeader.FIELD_CAPTURE_PATTERN_LENGTH; } /** * Retrieve the raw VorbisComment packet data, does not include the OggVorbis header * * @param raf * @return * @throws CannotReadException if unable to find vorbiscomment header * @throws IOException */ public byte[] readRawPacketData(RandomAccessFile raf) throws CannotReadException, IOException { logger.fine("Read 1st page"); //1st page = codec infos OggPageHeader pageHeader = OggPageHeader.read(raf); //Skip over data to end of page header 1 raf.seek(raf.getFilePointer() + pageHeader.getPageLength()); logger.fine("Read 2nd page"); //2nd page = comment, may extend to additional pages or not , may also have setup header pageHeader = OggPageHeader.read(raf); //Now at start of packets on page 2 , check this is the vorbis comment header byte[] b = new byte[VorbisHeader.FIELD_PACKET_TYPE_LENGTH + VorbisHeader.FIELD_CAPTURE_PATTERN_LENGTH]; raf.read(b); if (!isVorbisCommentHeader(b)) { throw new CannotReadException("Cannot find comment block (no vorbiscomment header)"); } //Convert the comment raw data which maybe over many pages back into raw packet byte[] rawVorbisCommentData = convertToVorbisCommentPacket(pageHeader, raf); return rawVorbisCommentData; } /** * Is this a Vorbis Comment header, check *

    * Note this check only applies to Vorbis Comments embedded within an OggVorbis File which is why within here * * @param headerData * @return true if the headerData matches a VorbisComment header i.e is a Vorbis header of type COMMENT_HEADER */ public boolean isVorbisCommentHeader(byte[] headerData) { String vorbis = Utils.getString(headerData, VorbisHeader.FIELD_CAPTURE_PATTERN_POS, VorbisHeader.FIELD_CAPTURE_PATTERN_LENGTH, "ISO-8859-1"); return !(headerData[VorbisHeader.FIELD_PACKET_TYPE_POS] != VorbisPacketType.COMMENT_HEADER.getType() || !vorbis.equals(VorbisHeader.CAPTURE_PATTERN)); } /** * Is this a Vorbis SetupHeader check * * @param headerData * @return true if matches vorbis setupheader */ public boolean isVorbisSetupHeader(byte[] headerData) { String vorbis = Utils.getString(headerData, VorbisHeader.FIELD_CAPTURE_PATTERN_POS, VorbisHeader.FIELD_CAPTURE_PATTERN_LENGTH, "ISO-8859-1"); return !(headerData[VorbisHeader.FIELD_PACKET_TYPE_POS] != VorbisPacketType.SETUP_HEADER.getType() || !vorbis.equals(VorbisHeader.CAPTURE_PATTERN)); } /** * The Vorbis Comment may span multiple pages so we we need to identify the pages they contain and then * extract the packet data from the pages * @param startVorbisCommentPage * @param raf * @throws org.jaudiotagger.audio.exceptions.CannotReadException * @throws java.io.IOException * @return */ private byte[] convertToVorbisCommentPacket(OggPageHeader startVorbisCommentPage, RandomAccessFile raf) throws IOException, CannotReadException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte[] b = new byte[startVorbisCommentPage.getPacketList().get(0).getLength() - (VorbisHeader.FIELD_PACKET_TYPE_LENGTH + VorbisHeader.FIELD_CAPTURE_PATTERN_LENGTH)]; raf.read(b); baos.write(b); //Because there is at least one other packet (SetupHeaderPacket) this means the Comment Packet has finished //on this page so thats all we need and we can return if (startVorbisCommentPage.getPacketList().size() > 1) { logger.info("Comments finish on 2nd Page because there is another packet on this page"); return baos.toByteArray(); } //There is only the VorbisComment packet on page if it has completed on this page we can return if (!startVorbisCommentPage.isLastPacketIncomplete()) { logger.info("Comments finish on 2nd Page because this packet is complete"); return baos.toByteArray(); } //The VorbisComment extends to the next page, so should be at end of page already //so carry on reading pages until we get to the end of comment while (true) { logger.info("Reading next page"); OggPageHeader nextPageHeader = OggPageHeader.read(raf); b = new byte[nextPageHeader.getPacketList().get(0).getLength()]; raf.read(b); baos.write(b); //Because there is at least one other packet (SetupHeaderPacket) this means the Comment Packet has finished //on this page so thats all we need and we can return if (nextPageHeader.getPacketList().size() > 1) { logger.info("Comments finish on Page because there is another packet on this page"); return baos.toByteArray(); } //There is only the VorbisComment packet on page if it has completed on this page we can return if (!nextPageHeader.isLastPacketIncomplete()) { logger.info("Comments finish on Page because this packet is complete"); return baos.toByteArray(); } } } /** * The Vorbis Setup Header may span multiple(2) pages, athough it doesnt normally. We pass the start of the * file offset of the OggPage it belongs on, it probably won't be first packet. * @param fileOffsetOfStartingOggPage * @param raf * @throws org.jaudiotagger.audio.exceptions.CannotReadException * @throws java.io.IOException * @return */ public byte[] convertToVorbisSetupHeaderPacket(long fileOffsetOfStartingOggPage, RandomAccessFile raf) throws IOException, CannotReadException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); //Seek to specified offset raf.seek(fileOffsetOfStartingOggPage); //Read Page OggPageHeader setupPageHeader = OggPageHeader.read(raf); //Assume that if multiple packets first packet is VorbisComment and second packet //is setupheader if (setupPageHeader.getPacketList().size() > 1) { raf.skipBytes(setupPageHeader.getPacketList().get(0).getLength()); } //Now should be at start of next packet, check this is the vorbis setup header byte[] b = new byte[VorbisHeader.FIELD_PACKET_TYPE_LENGTH + VorbisHeader.FIELD_CAPTURE_PATTERN_LENGTH]; raf.read(b); if (!isVorbisSetupHeader(b)) { throw new CannotReadException("Unable to find setup header(2), unable to write ogg file"); } //Go back to start of setupheader data raf.seek(raf.getFilePointer() - (VorbisHeader.FIELD_PACKET_TYPE_LENGTH + VorbisHeader.FIELD_CAPTURE_PATTERN_LENGTH)); //Read data if (setupPageHeader.getPacketList().size() > 1) { b = new byte[setupPageHeader.getPacketList().get(1).getLength()]; raf.read(b); baos.write(b); } else { b = new byte[setupPageHeader.getPacketList().get(0).getLength()]; raf.read(b); baos.write(b); } //Return Data if (!setupPageHeader.isLastPacketIncomplete() || setupPageHeader.getPacketList().size() > 2) { logger.info("Setupheader finishes on this page"); return baos.toByteArray(); } //The Setupheader extends to the next page, so should be at end of page already //so carry on reading pages until we get to the end of comment while (true) { logger.info("Reading another page"); OggPageHeader nextPageHeader = OggPageHeader.read(raf); b = new byte[nextPageHeader.getPacketList().get(0).getLength()]; raf.read(b); baos.write(b); //Because there is at least one other packet this means the Setupheader Packet has finished //on this page so thats all we need and we can return if (nextPageHeader.getPacketList().size() > 1) { logger.info("Setupheader finishes on this page"); return baos.toByteArray(); } //There is only the Setupheader packet on page if it has completed on this page we can return if (!nextPageHeader.isLastPacketIncomplete()) { logger.info("Setupheader finish on Page because this packet is complete"); return baos.toByteArray(); } } } /** * The Vorbis Setup Header may span multiple(2) pages, athough it doesnt normally. We pass the start of the * file offset of the OggPage it belongs on, it probably won't be first packet, also returns any addditional * packets that immediately follow the setup header in original file * @param fileOffsetOfStartingOggPage * @param raf * @throws org.jaudiotagger.audio.exceptions.CannotReadException * @throws java.io.IOException * @return */ public byte[] convertToVorbisSetupHeaderPacketAndAdditionalPackets(long fileOffsetOfStartingOggPage, RandomAccessFile raf) throws IOException, CannotReadException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); //Seek to specified offset raf.seek(fileOffsetOfStartingOggPage); //Read Page OggPageHeader setupPageHeader = OggPageHeader.read(raf); //Assume that if multiple packets first packet is VorbisComment and second packet //is setupheader if (setupPageHeader.getPacketList().size() > 1) { raf.skipBytes(setupPageHeader.getPacketList().get(0).getLength()); } //Now should be at start of next packet, check this is the vorbis setup header byte[] b = new byte[VorbisHeader.FIELD_PACKET_TYPE_LENGTH + VorbisHeader.FIELD_CAPTURE_PATTERN_LENGTH]; raf.read(b); if (!isVorbisSetupHeader(b)) { throw new CannotReadException("Unable to find setup header(2), unable to write ogg file"); } //Go back to start of setupheader data raf.seek(raf.getFilePointer() - (VorbisHeader.FIELD_PACKET_TYPE_LENGTH + VorbisHeader.FIELD_CAPTURE_PATTERN_LENGTH)); //Read data if (setupPageHeader.getPacketList().size() > 1) { b = new byte[setupPageHeader.getPacketList().get(1).getLength()]; raf.read(b); baos.write(b); } else { b = new byte[setupPageHeader.getPacketList().get(0).getLength()]; raf.read(b); baos.write(b); } //Return Data if (!setupPageHeader.isLastPacketIncomplete() || setupPageHeader.getPacketList().size() > 2) { logger.info("Setupheader finishes on this page"); if (setupPageHeader.getPacketList().size() > 2) { for (int i = 2; i < setupPageHeader.getPacketList().size(); i++) { b = new byte[setupPageHeader.getPacketList().get(i).getLength()]; raf.read(b); baos.write(b); } } return baos.toByteArray(); } //The Setupheader extends to the next page, so should be at end of page already //so carry on reading pages until we get to the end of comment while (true) { logger.info("Reading another page"); OggPageHeader nextPageHeader = OggPageHeader.read(raf); b = new byte[nextPageHeader.getPacketList().get(0).getLength()]; raf.read(b); baos.write(b); //Because there is at least one other packet this means the Setupheader Packet has finished //on this page so thats all we need and we can return if (nextPageHeader.getPacketList().size() > 1) { logger.info("Setupheader finishes on this page"); return baos.toByteArray(); } //There is only the Setupheader packet on page if it has completed on this page we can return if (!nextPageHeader.isLastPacketIncomplete()) { logger.info("Setupheader finish on Page because this packet is complete"); return baos.toByteArray(); } } } /** * Calculate the size of the packet data for the comment and setup headers * * @param raf * @return * @throws CannotReadException * @throws IOException */ public OggVorbisHeaderSizes readOggVorbisHeaderSizes(RandomAccessFile raf) throws CannotReadException, IOException { logger.fine("Started to read comment and setup header sizes:"); //Stores filepointers so return file in same state long filepointer = raf.getFilePointer(); //Extra Packets on same page as setup header List extraPackets = new ArrayList(); long commentHeaderStartPosition; long setupHeaderStartPosition; int commentHeaderSize = 0; int setupHeaderSize; //1st page = codec infos OggPageHeader pageHeader = OggPageHeader.read(raf); //Skip over data to end of page header 1 raf.seek(raf.getFilePointer() + pageHeader.getPageLength()); //2nd page = comment, may extend to additional pages or not , may also have setup header pageHeader = OggPageHeader.read(raf); commentHeaderStartPosition = raf.getFilePointer() - (OggPageHeader.OGG_PAGE_HEADER_FIXED_LENGTH + pageHeader.getSegmentTable().length); //Now at start of packets on page 2 , check this is the vorbis comment header byte[] b = new byte[VorbisHeader.FIELD_PACKET_TYPE_LENGTH + VorbisHeader.FIELD_CAPTURE_PATTERN_LENGTH]; raf.read(b); if (!isVorbisCommentHeader(b)) { throw new CannotReadException("Cannot find comment block (no vorbiscomment header)"); } raf.seek(raf.getFilePointer() - (VorbisHeader.FIELD_PACKET_TYPE_LENGTH + VorbisHeader.FIELD_CAPTURE_PATTERN_LENGTH)); logger.info("Found start of comment header at:" + raf.getFilePointer()); //Calculate Comment Size (not inc header) while (true) { List packetList = pageHeader.getPacketList(); commentHeaderSize += packetList.get(0).getLength(); raf.skipBytes(packetList.get(0).getLength()); //If this page contains multiple packets or if this last packet is complete then the Comment header //end son this page and we can break if (packetList.size() > 1 || !pageHeader.isLastPacketIncomplete()) { //done comment size logger.info("Found end of comment:size:" + commentHeaderSize + "finishes at file position:" + raf.getFilePointer()); break; } pageHeader = OggPageHeader.read(raf); } //If there are no more packets on this page we need to go to next page to get the setup header OggPageHeader.PacketStartAndLength packet; if(pageHeader.getPacketList().size()==1) { pageHeader = OggPageHeader.read(raf); List packetList = pageHeader.getPacketList(); packet = pageHeader.getPacketList().get(0); //Now at start of next packet , check this is the vorbis setup header b = new byte[VorbisHeader.FIELD_PACKET_TYPE_LENGTH + VorbisHeader.FIELD_CAPTURE_PATTERN_LENGTH]; raf.read(b); if (!isVorbisSetupHeader(b)) { throw new CannotReadException(ErrorMessage.OGG_VORBIS_NO_VORBIS_HEADER_FOUND.getMsg()); } raf.seek(raf.getFilePointer() - (VorbisHeader.FIELD_PACKET_TYPE_LENGTH + VorbisHeader.FIELD_CAPTURE_PATTERN_LENGTH)); logger.info("Found start of vorbis setup header at file position:" + raf.getFilePointer()); //Set this to the start of the OggPage that setupheader was found on setupHeaderStartPosition = raf.getFilePointer() - (OggPageHeader.OGG_PAGE_HEADER_FIXED_LENGTH + pageHeader.getSegmentTable().length); //Add packet data to size to the setup header size setupHeaderSize = packet.getLength(); logger.fine("Adding:" + packet.getLength() + " to setup header size"); //Skip over the packet data raf.skipBytes(packet.getLength()); //If there are other packets that follow this one, or if the last packet is complete then we must have //got the size of the setup header. if (packetList.size() > 1 || !pageHeader.isLastPacketIncomplete()) { logger.info("Found end of setupheader:size:" + setupHeaderSize + "finishes at:" + raf.getFilePointer()); if (packetList.size() > 1) { extraPackets = packetList.subList(1, packetList.size()); } } //The setup header continues onto the next page else { pageHeader = OggPageHeader.read(raf); packetList = pageHeader.getPacketList(); while (true) { setupHeaderSize += packetList.get(0).getLength(); logger.fine("Adding:" + packetList.get(0).getLength() + " to setup header size"); raf.skipBytes(packetList.get(0).getLength()); if (packetList.size() > 1 || !pageHeader.isLastPacketIncomplete()) { //done setup size logger.fine("Found end of setupheader:size:" + setupHeaderSize + "finishes at:" + raf.getFilePointer()); if (packetList.size() > 1) { extraPackets = packetList.subList(1, packetList.size()); } break; } //Continues onto another page pageHeader = OggPageHeader.read(raf); } } } //else its next packet on this page else { packet = pageHeader.getPacketList().get(1); List packetList = pageHeader.getPacketList(); //Now at start of next packet , check this is the vorbis setup header b = new byte[VorbisHeader.FIELD_PACKET_TYPE_LENGTH + VorbisHeader.FIELD_CAPTURE_PATTERN_LENGTH]; raf.read(b); if (!isVorbisSetupHeader(b)) { logger.warning("Expecting but got:"+new String(b)+ "at "+(raf.getFilePointer() - b.length)); throw new CannotReadException(ErrorMessage.OGG_VORBIS_NO_VORBIS_HEADER_FOUND.getMsg()); } raf.seek(raf.getFilePointer() - (VorbisHeader.FIELD_PACKET_TYPE_LENGTH + VorbisHeader.FIELD_CAPTURE_PATTERN_LENGTH)); logger.info("Found start of vorbis setup header at file position:" + raf.getFilePointer()); //Set this to the start of the OggPage that setupheader was found on setupHeaderStartPosition = raf.getFilePointer() - (OggPageHeader.OGG_PAGE_HEADER_FIXED_LENGTH + pageHeader.getSegmentTable().length) - pageHeader.getPacketList().get(0).getLength(); //Add packet data to size to the setup header size setupHeaderSize = packet.getLength(); logger.fine("Adding:" + packet.getLength() + " to setup header size"); //Skip over the packet data raf.skipBytes(packet.getLength()); //If there are other packets that follow this one, or if the last packet is complete then we must have //got the size of the setup header. if (packetList.size() > 2 || !pageHeader.isLastPacketIncomplete()) { logger.fine("Found end of setupheader:size:" + setupHeaderSize + "finishes at:" + raf.getFilePointer()); if (packetList.size() > 2) { extraPackets = packetList.subList(2, packetList.size()); } } //The setup header continues onto the next page else { pageHeader = OggPageHeader.read(raf); packetList = pageHeader.getPacketList(); while (true) { setupHeaderSize += packetList.get(0).getLength(); logger.fine("Adding:" + packetList.get(0).getLength() + " to setup header size"); raf.skipBytes(packetList.get(0).getLength()); if (packetList.size() > 1 || !pageHeader.isLastPacketIncomplete()) { //done setup size logger.fine("Found end of setupheader:size:" + setupHeaderSize + "finishes at:" + raf.getFilePointer()); if (packetList.size() > 1) { extraPackets = packetList.subList(1, packetList.size()); } break; } //Continues onto another page pageHeader = OggPageHeader.read(raf); } } } //Reset filepointer to location that it was in at start of method raf.seek(filepointer); return new OggVorbisHeaderSizes(commentHeaderStartPosition, setupHeaderStartPosition, commentHeaderSize, setupHeaderSize, extraPackets); } /** * Find the length of the raw packet data and the start position of the ogg page header they start in * for the two OggVorbisHeader we need to know about when writing data (sizes included vorbis header) */ public static class OggVorbisHeaderSizes { private long commentHeaderStartPosition; private long setupHeaderStartPosition; private int commentHeaderSize; private int setupHeaderSize; private List packetList; OggVorbisHeaderSizes(long commentHeaderStartPosition, long setupHeaderStartPosition, int commentHeaderSize, int setupHeaderSize, List packetList) { this.packetList = packetList; this.commentHeaderStartPosition = commentHeaderStartPosition; this.setupHeaderStartPosition = setupHeaderStartPosition; this.commentHeaderSize = commentHeaderSize; this.setupHeaderSize = setupHeaderSize; } /** * @return the size of the raw packet data for the vorbis comment header (includes vorbis header) */ public int getCommentHeaderSize() { return commentHeaderSize; } /** * @return he size of the raw packet data for the vorbis setup header (includes vorbis header) */ public int getSetupHeaderSize() { return setupHeaderSize; } /** * Return the size required by all the extra packets on same page as setup header, usually there are * no packets immediately after the setup packet. * * @return extra data size required for additional packets on same page */ public int getExtraPacketDataSize() { int extraPacketSize = 0; for (OggPageHeader.PacketStartAndLength packet : packetList) { extraPacketSize += packet.getLength(); } return extraPacketSize; } /** * @return the start position in the file of the ogg header which contains the start of the Vorbis Comment */ public long getCommentHeaderStartPosition() { return commentHeaderStartPosition; } /** * @return the start position in the file of the ogg header which contains the start of the Setup Header */ public long getSetupHeaderStartPosition() { return setupHeaderStartPosition; } public List getExtraPacketList() { return packetList; } } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/ogg/OggVorbisTagWriter.java0000644000175000017500000010135311470746136027774 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2003-2005 Raphaël Slinckx * Copyright (c) 2004-2005 Christian Laireiter * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.audio.ogg; import org.jaudiotagger.audio.exceptions.CannotReadException; import org.jaudiotagger.audio.exceptions.CannotWriteException; import org.jaudiotagger.audio.ogg.util.OggCRCFactory; import org.jaudiotagger.audio.ogg.util.OggPageHeader; import org.jaudiotagger.tag.Tag; import org.jaudiotagger.tag.vorbiscomment.VorbisCommentTag; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.List; import java.util.logging.Logger; /** * Write Vorbis Tag within an ogg *

    * VorbisComment holds the tag information within an ogg file */ public class OggVorbisTagWriter { // Logger Object public static Logger logger = Logger.getLogger("org.jaudiotagger.audio.ogg"); private OggVorbisCommentTagCreator tc = new OggVorbisCommentTagCreator(); private OggVorbisTagReader reader = new OggVorbisTagReader(); public void delete(RandomAccessFile raf, RandomAccessFile tempRaf) throws IOException, CannotReadException, CannotWriteException { try { reader.read(raf); } catch (CannotReadException e) { write(VorbisCommentTag.createNewTag(), raf, tempRaf); return; } VorbisCommentTag emptyTag = VorbisCommentTag.createNewTag(); //Go back to start of file raf.seek(0); write(emptyTag, raf, tempRaf); } public void write(Tag tag, RandomAccessFile raf, RandomAccessFile rafTemp) throws CannotReadException, CannotWriteException, IOException { logger.info("Starting to write file:"); //1st Page:Identification Header logger.fine("Read 1st Page:identificationHeader:"); OggPageHeader pageHeader = OggPageHeader.read(raf); raf.seek(0); //Write 1st page (unchanged) and place writer pointer at end of data rafTemp.getChannel().transferFrom(raf.getChannel(), 0, pageHeader.getPageLength() + OggPageHeader.OGG_PAGE_HEADER_FIXED_LENGTH + pageHeader.getSegmentTable().length); rafTemp.skipBytes(pageHeader.getPageLength() + OggPageHeader.OGG_PAGE_HEADER_FIXED_LENGTH + pageHeader.getSegmentTable().length); logger.fine("Written identificationHeader:"); //2nd page:Comment and Setup if there is enough room, may also (although not normally) contain audio frames OggPageHeader secondPageHeader = OggPageHeader.read(raf); //2nd Page:Store the end of Header long secondPageHeaderEndPos = raf.getFilePointer(); logger.fine("Read 2nd Page:comment and setup and possibly audio:Header finishes at file position:" + secondPageHeaderEndPos); //Get header sizes raf.seek(0); OggVorbisTagReader.OggVorbisHeaderSizes vorbisHeaderSizes = reader.readOggVorbisHeaderSizes(raf); //Convert the OggVorbisComment header to raw packet data ByteBuffer newComment = tc.convert(tag); //Compute new comment length(this may need to be spread over multiple pages) int newCommentLength = newComment.capacity(); //Calculate new size of new 2nd page int newSecondPageDataLength = vorbisHeaderSizes.getSetupHeaderSize() + newCommentLength + vorbisHeaderSizes.getExtraPacketDataSize(); logger.fine("Old 2nd Page no of packets: " + secondPageHeader.getPacketList().size()); logger.fine("Old 2nd Page size: " + secondPageHeader.getPageLength()); logger.fine("Old last packet incomplete: " + secondPageHeader.isLastPacketIncomplete()); logger.fine("Setup Header Size: " + vorbisHeaderSizes.getSetupHeaderSize()); logger.fine("Extra Packets: " + vorbisHeaderSizes.getExtraPacketList().size()); logger.fine("Extra Packet Data Size: " + vorbisHeaderSizes.getExtraPacketDataSize()); logger.fine("Old comment: " + vorbisHeaderSizes.getCommentHeaderSize()); logger.fine("New comment: " + newCommentLength); logger.fine("New Page Data Size: " + newSecondPageDataLength); //Second Page containing new vorbis, setup and possibly some extra packets can fit on one page if (isCommentAndSetupHeaderFitsOnASinglePage(newCommentLength, vorbisHeaderSizes.getSetupHeaderSize(), vorbisHeaderSizes.getExtraPacketList())) { //And if comment and setup header originally fitted on both, the length of the 2nd //page must be less than maximum size allowed //AND //there must be two packets with last being complete because they may have //elected to split the setup over multiple pages instead of using up whole page - (as long //as the last lacing value is 255 they can do this) // OR //There are more than the packets in which case have complete setup header and some audio packets //we dont care if the last audio packet is split on next page as long as we preserve it if ((secondPageHeader.getPageLength() < OggPageHeader.MAXIMUM_PAGE_DATA_SIZE) && (((secondPageHeader.getPacketList().size() == 2) && (!secondPageHeader.isLastPacketIncomplete())) || (secondPageHeader.getPacketList().size() > 2))) { logger.fine("Header and Setup remain on single page:"); replaceSecondPageOnly(vorbisHeaderSizes, newCommentLength, newSecondPageDataLength, secondPageHeader, newComment, secondPageHeaderEndPos, raf, rafTemp); } //Original 2nd page spanned multiple pages so more work to do else { logger.fine("Header and Setup now on single page:"); replaceSecondPageAndRenumberPageSeqs(vorbisHeaderSizes, newCommentLength, newSecondPageDataLength, secondPageHeader, newComment, raf, rafTemp); } } //Bit more complicated, have to create more than one new page and renumber subsequent audio else { logger.fine("Header and Setup with shift audio:"); replacePagesAndRenumberPageSeqs(vorbisHeaderSizes, newCommentLength, secondPageHeader, newComment, raf, rafTemp); } } /** * Calculate checkSum over the Page * * @param page */ private void calculateChecksumOverPage(ByteBuffer page) { //CRC should be zero before calculating it page.putInt(OggPageHeader.FIELD_PAGE_CHECKSUM_POS, 0); //Compute CRC over the page //TODO shouldnt really use array(); byte[] crc = OggCRCFactory.computeCRC(page.array()); for (int i = 0; i < crc.length; i++) { page.put(OggPageHeader.FIELD_PAGE_CHECKSUM_POS + i, crc[i]); } //Rewind to start of Page page.rewind(); } /** * Create a second Page, and add comment header to it, but page is incomplete may want to add addition header and need to calculate CRC * * @param vorbisHeaderSizes * @param newCommentLength * @param newSecondPageLength * @param secondPageHeader * @param newComment * @return * @throws IOException */ private ByteBuffer startCreateBasicSecondPage( OggVorbisTagReader.OggVorbisHeaderSizes vorbisHeaderSizes, int newCommentLength, int newSecondPageLength, OggPageHeader secondPageHeader, ByteBuffer newComment) throws IOException { logger.fine("WriteOgg Type 1"); byte[] segmentTable = createSegmentTable(newCommentLength, vorbisHeaderSizes.getSetupHeaderSize(), vorbisHeaderSizes.getExtraPacketList()); int newSecondPageHeaderLength = OggPageHeader.OGG_PAGE_HEADER_FIXED_LENGTH + segmentTable.length; logger.fine("New second page header length:" + newSecondPageHeaderLength); logger.fine("No of segments:" + segmentTable.length); ByteBuffer secondPageBuffer = ByteBuffer.allocate(newSecondPageLength + newSecondPageHeaderLength); secondPageBuffer.order(ByteOrder.LITTLE_ENDIAN); //Build the new 2nd page header, can mostly be taken from the original upto the segment length OggS capture secondPageBuffer.put(secondPageHeader.getRawHeaderData(), 0, OggPageHeader.OGG_PAGE_HEADER_FIXED_LENGTH - 1); //Number of Page Segments secondPageBuffer.put((byte) segmentTable.length); //Page segment table for (byte aSegmentTable : segmentTable) { secondPageBuffer.put(aSegmentTable); } //Add New VorbisComment secondPageBuffer.put(newComment); return secondPageBuffer; } /** * Usually can use this method, previously comment and setup header all fit on page 2 * and they still do, so just replace this page. And copy further pages as is. * * @param vorbisHeaderSizes * @param newCommentLength * @param newSecondPageLength * @param secondPageHeader * @param newComment * @param secondPageHeaderEndPos * @param raf * @param rafTemp * @throws IOException */ private void replaceSecondPageOnly( OggVorbisTagReader.OggVorbisHeaderSizes vorbisHeaderSizes, int newCommentLength, int newSecondPageLength, OggPageHeader secondPageHeader, ByteBuffer newComment, long secondPageHeaderEndPos, RandomAccessFile raf, RandomAccessFile rafTemp) throws IOException { logger.fine("WriteOgg Type 1"); ByteBuffer secondPageBuffer = startCreateBasicSecondPage(vorbisHeaderSizes, newCommentLength, newSecondPageLength, secondPageHeader, newComment); raf.seek(secondPageHeaderEndPos); //Skip comment header raf.skipBytes(vorbisHeaderSizes.getCommentHeaderSize()); //Read in setup header and extra packets raf.getChannel().read(secondPageBuffer); calculateChecksumOverPage(secondPageBuffer); rafTemp.getChannel().write(secondPageBuffer); rafTemp.getChannel().transferFrom(raf.getChannel(), rafTemp.getFilePointer(), raf.length() - raf.getFilePointer()); } /** * Previously comment and/or setup header was on a number of pages now can just replace this page fitting all * on 2nd page, and renumber subsequent sequence pages * * @param originalHeaderSizes * @param newCommentLength * @param newSecondPageLength * @param secondPageHeader * @param newComment * @param raf * @param rafTemp * @throws IOException * @throws org.jaudiotagger.audio.exceptions.CannotReadException * @throws org.jaudiotagger.audio.exceptions.CannotWriteException */ private void replaceSecondPageAndRenumberPageSeqs(OggVorbisTagReader.OggVorbisHeaderSizes originalHeaderSizes, int newCommentLength, int newSecondPageLength, OggPageHeader secondPageHeader, ByteBuffer newComment, RandomAccessFile raf, RandomAccessFile rafTemp) throws IOException, CannotReadException, CannotWriteException { logger.fine("WriteOgg Type 2"); ByteBuffer secondPageBuffer = startCreateBasicSecondPage(originalHeaderSizes, newCommentLength, newSecondPageLength, secondPageHeader, newComment); //Add setup header and packets int pageSequence = secondPageHeader.getPageSequence(); byte[] setupHeaderData = reader.convertToVorbisSetupHeaderPacketAndAdditionalPackets(originalHeaderSizes.getSetupHeaderStartPosition(), raf); logger.finest(setupHeaderData.length + ":" + secondPageBuffer.position() + ":" + secondPageBuffer.capacity()); secondPageBuffer.put(setupHeaderData); calculateChecksumOverPage(secondPageBuffer); rafTemp.getChannel().write(secondPageBuffer); writeRemainingPages(pageSequence, raf, rafTemp); } /** * CommentHeader extends over multiple pages OR Comment Header doesnt but it's got larger causing some extra * packets to be shifted onto another page. * * @param originalHeaderSizes * @param newCommentLength * @param secondPageHeader * @param newComment * @param raf * @param rafTemp * @throws IOException * @throws CannotReadException * @throws CannotWriteException */ private void replacePagesAndRenumberPageSeqs(OggVorbisTagReader.OggVorbisHeaderSizes originalHeaderSizes, int newCommentLength, OggPageHeader secondPageHeader, ByteBuffer newComment, RandomAccessFile raf, RandomAccessFile rafTemp) throws IOException, CannotReadException, CannotWriteException { int pageSequence = secondPageHeader.getPageSequence(); //We need to work out how to split the newcommentlength over the pages int noOfCompletePagesNeededForComment = newCommentLength / OggPageHeader.MAXIMUM_PAGE_DATA_SIZE; logger.info("Comment requires:" + noOfCompletePagesNeededForComment + " complete pages"); //Create the Pages int newCommentOffset = 0; if (noOfCompletePagesNeededForComment > 0) { for (int i = 0; i < noOfCompletePagesNeededForComment; i++) { //Create ByteBuffer for the New page byte[] segmentTable = this.createSegments(OggPageHeader.MAXIMUM_PAGE_DATA_SIZE, false); int pageHeaderLength = OggPageHeader.OGG_PAGE_HEADER_FIXED_LENGTH + segmentTable.length; ByteBuffer pageBuffer = ByteBuffer.allocate(pageHeaderLength + OggPageHeader.MAXIMUM_PAGE_DATA_SIZE); pageBuffer.order(ByteOrder.LITTLE_ENDIAN); //Now create the page basing it on the existing 2ndpageheader pageBuffer.put(secondPageHeader.getRawHeaderData(), 0, OggPageHeader.OGG_PAGE_HEADER_FIXED_LENGTH - 1); //Number of Page Segments pageBuffer.put((byte) segmentTable.length); //Page segment table for (byte aSegmentTable : segmentTable) { pageBuffer.put(aSegmentTable); } //Get next bit of Comment ByteBuffer nextPartOfComment = newComment.slice(); nextPartOfComment.limit(OggPageHeader.MAXIMUM_PAGE_DATA_SIZE); pageBuffer.put(nextPartOfComment); //Recalculate Page Sequence Number pageBuffer.putInt(OggPageHeader.FIELD_PAGE_SEQUENCE_NO_POS, pageSequence); pageSequence++; //Set Header Flag to indicate continuous (except for first flag) if (i != 0) { pageBuffer.put(OggPageHeader.FIELD_HEADER_TYPE_FLAG_POS, OggPageHeader.HeaderTypeFlag.CONTINUED_PACKET.getFileValue()); } calculateChecksumOverPage(pageBuffer); rafTemp.getChannel().write(pageBuffer); newCommentOffset += OggPageHeader.MAXIMUM_PAGE_DATA_SIZE; newComment.position(newCommentOffset); } } int lastPageCommentPacketSize = newCommentLength % OggPageHeader.MAXIMUM_PAGE_DATA_SIZE; logger.fine("Last comment packet size:" + lastPageCommentPacketSize); //End of comment and setup header cannot fit on the last page if (!isCommentAndSetupHeaderFitsOnASinglePage(lastPageCommentPacketSize, originalHeaderSizes.getSetupHeaderSize(), originalHeaderSizes.getExtraPacketList())) { logger.fine("WriteOgg Type 3"); //Write the last part of comment only (its possible it might be the only comment) { byte[] segmentTable = createSegments(lastPageCommentPacketSize, true); int pageHeaderLength = OggPageHeader.OGG_PAGE_HEADER_FIXED_LENGTH + segmentTable.length; ByteBuffer pageBuffer = ByteBuffer.allocate(lastPageCommentPacketSize + pageHeaderLength); pageBuffer.order(ByteOrder.LITTLE_ENDIAN); pageBuffer.put(secondPageHeader.getRawHeaderData(), 0, OggPageHeader.OGG_PAGE_HEADER_FIXED_LENGTH - 1); pageBuffer.put((byte) segmentTable.length); for (byte aSegmentTable : segmentTable) { pageBuffer.put(aSegmentTable); } newComment.position(newCommentOffset); pageBuffer.put(newComment.slice()); pageBuffer.putInt(OggPageHeader.FIELD_PAGE_SEQUENCE_NO_POS, pageSequence); if(noOfCompletePagesNeededForComment>0) { pageBuffer.put(OggPageHeader.FIELD_HEADER_TYPE_FLAG_POS, OggPageHeader.HeaderTypeFlag.CONTINUED_PACKET.getFileValue()); } logger.fine("Writing Last Comment Page "+pageSequence +" to file"); pageSequence++; calculateChecksumOverPage(pageBuffer); rafTemp.getChannel().write(pageBuffer); } //Now write header and extra packets onto next page { byte[] segmentTable = this.createSegmentTable(originalHeaderSizes.getSetupHeaderSize(),originalHeaderSizes.getExtraPacketList()); int pageHeaderLength = OggPageHeader.OGG_PAGE_HEADER_FIXED_LENGTH + segmentTable.length; byte[] setupHeaderData = reader.convertToVorbisSetupHeaderPacketAndAdditionalPackets(originalHeaderSizes.getSetupHeaderStartPosition(), raf); ByteBuffer pageBuffer = ByteBuffer.allocate(setupHeaderData.length + pageHeaderLength); pageBuffer.order(ByteOrder.LITTLE_ENDIAN); pageBuffer.put(secondPageHeader.getRawHeaderData(), 0, OggPageHeader.OGG_PAGE_HEADER_FIXED_LENGTH - 1); pageBuffer.put((byte) segmentTable.length); for (byte aSegmentTable : segmentTable) { pageBuffer.put(aSegmentTable); } pageBuffer.put(setupHeaderData); pageBuffer.putInt(OggPageHeader.FIELD_PAGE_SEQUENCE_NO_POS, pageSequence); //pageBuffer.put(OggPageHeader.FIELD_HEADER_TYPE_FLAG_POS, OggPageHeader.HeaderTypeFlag.CONTINUED_PACKET.getFileValue()); logger.fine("Writing Setup Header and packets Page "+pageSequence +" to file"); calculateChecksumOverPage(pageBuffer); rafTemp.getChannel().write(pageBuffer); } } else { //End of Comment and SetupHeader and extra packets can fit on one page logger.fine("WriteOgg Type 4"); //Create last header page int newSecondPageDataLength = originalHeaderSizes.getSetupHeaderSize() + lastPageCommentPacketSize + originalHeaderSizes.getExtraPacketDataSize(); newComment.position(newCommentOffset); ByteBuffer lastComment = newComment.slice(); ByteBuffer lastHeaderBuffer = startCreateBasicSecondPage( originalHeaderSizes, lastPageCommentPacketSize, newSecondPageDataLength, secondPageHeader, lastComment); //Now find the setupheader which is on a different page raf.seek(originalHeaderSizes.getSetupHeaderStartPosition()); //Add setup Header and Extra Packets (although it will fit in this page, it may be over multiple pages in its original form //so need to use this function to convert to raw data byte[] setupHeaderData = reader.convertToVorbisSetupHeaderPacketAndAdditionalPackets(originalHeaderSizes.getSetupHeaderStartPosition(), raf); lastHeaderBuffer.put(setupHeaderData); //Page Sequence No lastHeaderBuffer.putInt(OggPageHeader.FIELD_PAGE_SEQUENCE_NO_POS, pageSequence); //Set Header Flag to indicate continuous (contains end of comment) lastHeaderBuffer.put(OggPageHeader.FIELD_HEADER_TYPE_FLAG_POS, OggPageHeader.HeaderTypeFlag.CONTINUED_PACKET.getFileValue()); calculateChecksumOverPage(lastHeaderBuffer); rafTemp.getChannel().write(lastHeaderBuffer); } //Write the rest of the original file writeRemainingPages(pageSequence, raf, rafTemp); } /** * Write all the remaining pages as they are except that the page sequence needs to be modified. * * @param pageSequence * @param raf * @param rafTemp * @throws IOException * @throws CannotReadException * @throws CannotWriteException */ public void writeRemainingPages(int pageSequence, RandomAccessFile raf, RandomAccessFile rafTemp) throws IOException, CannotReadException, CannotWriteException { long startAudio = raf.getFilePointer(); long startAudioWritten = rafTemp.getFilePointer(); //TODO there is a risk we wont have enough memory to create these buffers ByteBuffer bb = ByteBuffer.allocate((int)(raf.length() - raf.getFilePointer())); ByteBuffer bbTemp = ByteBuffer.allocate((int)(raf.length() - raf.getFilePointer())); //Read in the rest of the data into bytebuffer and rewind it to start raf.getChannel().read(bb); bb.rewind(); while(bb.hasRemaining()) { OggPageHeader nextPage = OggPageHeader.read(bb); //Create buffer large enough for next page (header and data) and set byte order to LE so we can use //putInt method ByteBuffer nextPageHeaderBuffer = ByteBuffer.allocate(nextPage.getRawHeaderData().length + nextPage.getPageLength()); nextPageHeaderBuffer.order(ByteOrder.LITTLE_ENDIAN); nextPageHeaderBuffer.put(nextPage.getRawHeaderData()); ByteBuffer data = bb.slice(); data.limit(nextPage.getPageLength()); nextPageHeaderBuffer.put(data); nextPageHeaderBuffer.putInt(OggPageHeader.FIELD_PAGE_SEQUENCE_NO_POS, ++pageSequence); calculateChecksumOverPage(nextPageHeaderBuffer); bb.position(bb.position() + nextPage.getPageLength()); nextPageHeaderBuffer.rewind(); bbTemp.put(nextPageHeaderBuffer); } //Now just write as a single IO operation bbTemp.rewind(); rafTemp.getChannel().write(bbTemp); //Check we have written all the data //TODO could we do any other checks to check data written correctly ? if ((raf.length() - startAudio) != (rafTemp.length() - startAudioWritten)) { throw new CannotWriteException("File written counts don't match, file not written"); } } public void writeRemainingPagesOld(int pageSequence, RandomAccessFile raf, RandomAccessFile rafTemp) throws IOException, CannotReadException, CannotWriteException { //Now the Page Sequence Number for all the subsequent pages (containing audio frames) are out because there are //less pages before then there used to be, so need to adjust long startAudio = raf.getFilePointer(); long startAudioWritten = rafTemp.getFilePointer(); logger.fine("Writing audio, audio starts in original file at :" + startAudio + ":Written to:" + startAudioWritten); while (raf.getFilePointer() < raf.length()) { logger.fine("Reading Ogg Page"); OggPageHeader nextPage = OggPageHeader.read(raf); //Create buffer large enough for next page (header and data) and set byte order to LE so we can use //putInt method ByteBuffer nextPageHeaderBuffer = ByteBuffer.allocate(nextPage.getRawHeaderData().length + nextPage.getPageLength()); nextPageHeaderBuffer.order(ByteOrder.LITTLE_ENDIAN); nextPageHeaderBuffer.put(nextPage.getRawHeaderData()); raf.getChannel().read(nextPageHeaderBuffer); //Recalculate Page Sequence Number nextPageHeaderBuffer.putInt(OggPageHeader.FIELD_PAGE_SEQUENCE_NO_POS, ++pageSequence); //Calculate Checksum calculateChecksumOverPage(nextPageHeaderBuffer); rafTemp.getChannel().write(nextPageHeaderBuffer); } if ((raf.length() - startAudio) != (rafTemp.length() - startAudioWritten)) { throw new CannotWriteException("File written counts don't match, file not written"); } } /** * This method creates a new segment table for the second page (header). * * @param newCommentLength The length of the Vorbis Comment * @param setupHeaderLength The length of Setup Header, zero if comment String extends * over multiple pages and this is not the last page. * @param extraPackets If there are packets immediately after setup header in same page, they * need including in the segment table * @return new segment table. */ private byte[] createSegmentTable(int newCommentLength, int setupHeaderLength, List extraPackets) { logger.finest("Create SegmentTable CommentLength:" + newCommentLength + ":SetupHeaderLength:" + setupHeaderLength); ByteArrayOutputStream resultBaos = new ByteArrayOutputStream(); byte[] newStart; byte[] restShouldBe; byte[] nextPacket; //Vorbis Comment if (setupHeaderLength == 0) { //Comment Stream continues onto next page so last lacing value can be 255 newStart = createSegments(newCommentLength, false); return newStart; } else { //Comment Stream finishes on this page so if is a multiple of 255 //have to add an extra entry. newStart = createSegments(newCommentLength, true); } //Setup Header, should be closed if (extraPackets.size() > 0) { restShouldBe = createSegments(setupHeaderLength, true); } //.. continue sonto next page else { restShouldBe = createSegments(setupHeaderLength, false); } logger.finest("Created " + newStart.length + " segments for header"); logger.finest("Created " + restShouldBe.length + " segments for setup"); try { resultBaos.write(newStart); resultBaos.write(restShouldBe); if (extraPackets.size() > 0) { //Packets are being copied literally not converted from a length, so always pass //false parameter, TODO is this statement correct logger.finer("Creating segments for " + extraPackets.size() + " packets"); for (OggPageHeader.PacketStartAndLength packet : extraPackets) { nextPacket = createSegments(packet.getLength(), false); resultBaos.write(nextPacket); } } } catch (IOException ioe) { throw new RuntimeException("Unable to create segment table:" + ioe.getMessage()); } return resultBaos.toByteArray(); } /** * This method creates a new segment table for the second half of setup header * * @param setupHeaderLength The length of Setup Header, zero if comment String extends * over multiple pages and this is not the last page. * @param extraPackets If there are packets immediately after setup header in same page, they * need including in the segment table * @return new segment table. */ private byte[] createSegmentTable(int setupHeaderLength, List extraPackets) { ByteArrayOutputStream resultBaos = new ByteArrayOutputStream(); byte[] restShouldBe; byte[] nextPacket; //Setup Header restShouldBe = createSegments(setupHeaderLength, true); try { resultBaos.write(restShouldBe); if (extraPackets.size() > 0) { //Packets are being copied literally not converted from a length, so always pass //false parameter, TODO is this statement correct for (OggPageHeader.PacketStartAndLength packet : extraPackets) { nextPacket = createSegments(packet.getLength(), false); resultBaos.write(nextPacket); } } } catch (IOException ioe) { throw new RuntimeException("Unable to create segment table:" + ioe.getMessage()); } return resultBaos.toByteArray(); } /** * This method creates a byte array of values whose sum should * be the value of length.
    * * @param length Size of the page which should be * represented as 255 byte packets. * @param quitStream If true and a length is a multiple of 255 we need another * segment table entry with the value of 0. Else it's the last stream of the * table which is already ended. * @return Array of packet sizes. However only the last packet will * differ from 255. *

    */ //TODO if pass is data of max length (65025 bytes) and have quitStream==true //this will return 256 segments which is illegal, should be checked somewhere private byte[] createSegments(int length, boolean quitStream) { logger.finest("Create Segments for length:" + length + ":QuitStream:" + quitStream); //It is valid to have nil length packets if (length == 0) { byte[] result = new byte[1]; result[0] = (byte) 0x00; return result; } byte[] result = new byte[length / OggPageHeader.MAXIMUM_SEGMENT_SIZE + ((length % OggPageHeader.MAXIMUM_SEGMENT_SIZE == 0 && !quitStream) ? 0 : 1)]; int i = 0; for (; i < result.length - 1; i++) { result[i] = (byte) 0xFF; } result[result.length - 1] = (byte) (length - (i * OggPageHeader.MAXIMUM_SEGMENT_SIZE)); return result; } /** * @param commentLength * @param setupHeaderLength * @param extraPacketList * @return true if there is enough room to fit the comment and the setup headers on one page taking into * account the maximum no of segments allowed per page and zero lacing values. */ private boolean isCommentAndSetupHeaderFitsOnASinglePage(int commentLength, int setupHeaderLength, List extraPacketList) { int totalDataSize = 0; if (commentLength == 0) { totalDataSize++; } else { totalDataSize = (commentLength / OggPageHeader.MAXIMUM_SEGMENT_SIZE) + 1; if (commentLength % OggPageHeader.MAXIMUM_SEGMENT_SIZE == 0) { totalDataSize++; } } logger.finest("Require:" + totalDataSize + " segments for comment"); if (setupHeaderLength == 0) { totalDataSize++; } else { totalDataSize += (setupHeaderLength / OggPageHeader.MAXIMUM_SEGMENT_SIZE) + 1; if (setupHeaderLength % OggPageHeader.MAXIMUM_SEGMENT_SIZE == 0) { totalDataSize++; } } logger.finest("Require:" + totalDataSize + " segments for comment plus setup"); for (OggPageHeader.PacketStartAndLength extraPacket : extraPacketList) { if (extraPacket.getLength() == 0) { totalDataSize++; } else { totalDataSize += (extraPacket.getLength() / OggPageHeader.MAXIMUM_SEGMENT_SIZE) + 1; if (extraPacket.getLength() % OggPageHeader.MAXIMUM_SEGMENT_SIZE == 0) { totalDataSize++; } } } logger.finest("Total No Of Segment If New Comment And Header Put On One Page:" + totalDataSize); return totalDataSize <= OggPageHeader.MAXIMUM_NO_OF_SEGMENT_SIZE; } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/ogg/util/0000755000175000017500000000000011556363172024351 5ustar drazzibdrazziblibjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/ogg/util/VorbisHeader.java0000644000175000017500000000122010727201653027556 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.ogg.util; /** * Defines variables common to all vorbis headers */ public interface VorbisHeader { //Capture pattern at start of header public static final String CAPTURE_PATTERN = "vorbis"; public static final byte[] CAPTURE_PATTERN_AS_BYTES = {'v', 'o', 'r', 'b', 'i', 's'}; public static final int FIELD_PACKET_TYPE_POS = 0; public static final int FIELD_CAPTURE_PATTERN_POS = 1; public static final int FIELD_PACKET_TYPE_LENGTH = 1; public static final int FIELD_CAPTURE_PATTERN_LENGTH = 6; //Vorbis uses UTF-8 for all text public static final String CHARSET_UTF_8 = "UTF-8"; } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/ogg/util/VorbisSetupHeader.java0000644000175000017500000000212010727201653030577 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.ogg.util; import org.jaudiotagger.audio.generic.Utils; import java.util.logging.Logger; /** * Vorbis Setup header *

    * We dont need to decode a vorbis setup header for metatagging, but we should be able to identify * it. * * @author Paul Taylor * @version 12th August 2007 */ public class VorbisSetupHeader implements VorbisHeader { // Logger Object public static Logger logger = Logger.getLogger("org.jaudiotagger.audio.ogg.atom"); private boolean isValid = false; public VorbisSetupHeader(byte[] vorbisData) { decodeHeader(vorbisData); } public boolean isValid() { return isValid; } public void decodeHeader(byte[] b) { int packetType = b[FIELD_PACKET_TYPE_POS]; logger.fine("packetType" + packetType); String vorbis = Utils.getString(b, FIELD_CAPTURE_PATTERN_POS, FIELD_CAPTURE_PATTERN_LENGTH, "ISO-8859-1"); if (packetType == VorbisPacketType.SETUP_HEADER.getType() && vorbis.equals(CAPTURE_PATTERN)) { isValid = true; } } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/ogg/util/OggInfoReader.java0000644000175000017500000001323111277026507027665 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2003-2005 Raphaël Slinckx * Copyright (c) 2004-2005 Christian Laireiter * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.audio.ogg.util; import org.jaudiotagger.audio.exceptions.CannotReadException; import org.jaudiotagger.audio.generic.GenericAudioHeader; import org.jaudiotagger.logging.ErrorMessage; import java.io.IOException; import java.io.RandomAccessFile; import java.util.logging.Logger; import java.util.Arrays; /** * Read encoding info, only implemented for vorbis streams */ public class OggInfoReader { // Logger Object public static Logger logger = Logger.getLogger("org.jaudiotagger.audio.ogg.atom"); public GenericAudioHeader read(RandomAccessFile raf) throws CannotReadException, IOException { GenericAudioHeader info = new GenericAudioHeader(); logger.fine("Started"); long oldPos; //Check start of file does it have Ogg pattern byte[] b = new byte[OggPageHeader.CAPTURE_PATTERN.length]; raf.read(b); if (!(Arrays.equals(b, OggPageHeader.CAPTURE_PATTERN))) { throw new CannotReadException(ErrorMessage.OGG_HEADER_CANNOT_BE_FOUND.getMsg(new String(b))); } //Now work backwards from file looking for the last ogg page, it reads the granule position for this last page //which must be set. //TODO should do buffering to cut down the number of file reads raf.seek(0); double pcmSamplesNumber = -1; raf.seek(raf.length() - 2); while (raf.getFilePointer() >= 4) { if (raf.read() == OggPageHeader.CAPTURE_PATTERN[3]) { raf.seek(raf.getFilePointer() - OggPageHeader.FIELD_CAPTURE_PATTERN_LENGTH); byte[] ogg = new byte[3]; raf.readFully(ogg); if (ogg[0] == OggPageHeader.CAPTURE_PATTERN[0] && ogg[1] == OggPageHeader.CAPTURE_PATTERN[1] && ogg[2] == OggPageHeader.CAPTURE_PATTERN[2]) { raf.seek(raf.getFilePointer() - 3); oldPos = raf.getFilePointer(); raf.seek(raf.getFilePointer() + OggPageHeader.FIELD_PAGE_SEGMENTS_POS); int pageSegments = raf.readByte() & 0xFF; //Unsigned raf.seek(oldPos); b = new byte[OggPageHeader.OGG_PAGE_HEADER_FIXED_LENGTH + pageSegments]; raf.readFully(b); OggPageHeader pageHeader = new OggPageHeader(b); raf.seek(0); pcmSamplesNumber = pageHeader.getAbsoluteGranulePosition(); break; } } raf.seek(raf.getFilePointer() - 2); } if (pcmSamplesNumber == -1) { //According to spec a value of -1 indicates no packet finished on this page, this should not occur throw new CannotReadException(ErrorMessage.OGG_VORBIS_NO_SETUP_BLOCK.getMsg()); } //1st page = Identification Header OggPageHeader pageHeader = OggPageHeader.read(raf); byte[] vorbisData = new byte[pageHeader.getPageLength()]; raf.read(vorbisData); VorbisIdentificationHeader vorbisIdentificationHeader = new VorbisIdentificationHeader(vorbisData); //Map to generic encodingInfo info.setPreciseLength((float) (pcmSamplesNumber / vorbisIdentificationHeader.getSamplingRate())); info.setChannelNumber(vorbisIdentificationHeader.getChannelNumber()); info.setSamplingRate(vorbisIdentificationHeader.getSamplingRate()); info.setEncodingType(vorbisIdentificationHeader.getEncodingType()); info.setExtraEncodingInfos(""); //TODO this calculation should be done within identification header if (vorbisIdentificationHeader.getNominalBitrate() != 0 && vorbisIdentificationHeader.getMaxBitrate() == vorbisIdentificationHeader.getNominalBitrate() && vorbisIdentificationHeader.getMinBitrate() == vorbisIdentificationHeader.getNominalBitrate()) { //CBR (in kbps) info.setBitrate(vorbisIdentificationHeader.getNominalBitrate() / 1000); info.setVariableBitRate(false); } else if (vorbisIdentificationHeader.getNominalBitrate() != 0 && vorbisIdentificationHeader.getMaxBitrate() == 0 && vorbisIdentificationHeader.getMinBitrate() == 0) { //Average vbr (in kpbs) info.setBitrate(vorbisIdentificationHeader.getNominalBitrate() / 1000); info.setVariableBitRate(true); } else { //TODO need to remove comment from raf.getLength() info.setBitrate(computeBitrate(info.getTrackLength(), raf.length())); info.setVariableBitRate(true); } logger.fine("Finished"); return info; } private int computeBitrate(int length, long size) { return (int) ((size / 1000) * 8 / length); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/ogg/util/VorbisIdentificationHeader.java0000644000175000017500000001312211247705415032437 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2003-2005 Raphaël Slinckx * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.audio.ogg.util; import org.jaudiotagger.audio.generic.Utils; import org.jaudiotagger.audio.ogg.VorbisVersion; import java.util.logging.Logger; /** * Vorbis Identification header *

    * From http://xiph.org/vorbis/doc/Vorbis_I_spec.html#id326710 *

    * The identification header is a short header of only a few fields used to declare the stream definitively as Vorbis, * and provide a few externally relevant pieces of information about the audio stream. The identification header is * coded as follows: *

    * 1) [vorbis_version] = read 32 bits as unsigned integer * 2) [audio_channels] = read 8 bit integer as unsigned * 3) [audio_sample_rate] = read 32 bits as unsigned integer * 4) [bitrate_maximum] = read 32 bits as signed integer * 5) [bitrate_nominal] = read 32 bits as signed integer * 6) [bitrate_minimum] = read 32 bits as signed integer * 7) [blocksize_0] = 2 exponent (read 4 bits as unsigned integer) * 8) [blocksize_1] = 2 exponent (read 4 bits as unsigned integer) * 9) [framing_flag] = read one bit *

    * $Id: VorbisIdentificationHeader.java 813 2009-09-03 09:23:25Z paultaylor $ * * @author Raphael Slinckx (KiKiDonK) * @version 16 d�cembre 2003 */ public class VorbisIdentificationHeader implements VorbisHeader { // Logger Object public static Logger logger = Logger.getLogger("org.jaudiotagger.audio.ogg.atom"); private int audioChannels; private boolean isValid = false; private int vorbisVersion, audioSampleRate; private int bitrateMinimal, bitrateNominal, bitrateMaximal; public static final int FIELD_VORBIS_VERSION_POS = 7; public static final int FIELD_AUDIO_CHANNELS_POS = 11; public static final int FIELD_AUDIO_SAMPLE_RATE_POS = 12; public static final int FIELD_BITRATE_MAX_POS = 16; public static final int FIELD_BITRATE_NOMAIML_POS = 20; public static final int FIELD_BITRATE_MIN_POS = 24; public static final int FIELD_BLOCKSIZE_POS = 28; public static final int FIELD_FRAMING_FLAG_POS = 29; public static final int FIELD_VORBIS_VERSION_LENGTH = 4; public static final int FIELD_AUDIO_CHANNELS_LENGTH = 1; public static final int FIELD_AUDIO_SAMPLE_RATE_LENGTH = 4; public static final int FIELD_BITRATE_MAX_LENGTH = 4; public static final int FIELD_BITRATE_NOMAIML_LENGTH = 4; public static final int FIELD_BITRATE_MIN_LENGTH = 4; public static final int FIELD_BLOCKSIZE_LENGTH = 1; public static final int FIELD_FRAMING_FLAG_LENGTH = 1; public VorbisIdentificationHeader(byte[] vorbisData) { decodeHeader(vorbisData); } public int getChannelNumber() { return audioChannels; } public String getEncodingType() { return VorbisVersion.values()[vorbisVersion].toString(); } public int getSamplingRate() { return audioSampleRate; } public int getNominalBitrate() { return bitrateNominal; } public int getMaxBitrate() { return bitrateMaximal; } public int getMinBitrate() { return bitrateMinimal; } public boolean isValid() { return isValid; } public void decodeHeader(byte[] b) { int packetType = b[FIELD_PACKET_TYPE_POS]; logger.fine("packetType" + packetType); String vorbis = Utils.getString(b, VorbisHeader.FIELD_CAPTURE_PATTERN_POS, VorbisHeader.FIELD_CAPTURE_PATTERN_LENGTH, "ISO-8859-1"); if (packetType == VorbisPacketType.IDENTIFICATION_HEADER.getType() && vorbis.equals(CAPTURE_PATTERN)) { this.vorbisVersion = b[7] + (b[8] << 8) + (b[9] << 16) + (b[10] << 24); logger.fine("vorbisVersion" + vorbisVersion); this.audioChannels = u(b[FIELD_AUDIO_CHANNELS_POS]); logger.fine("audioChannels" + audioChannels); this.audioSampleRate = u(b[12]) + (u(b[13]) << 8) + (u(b[14]) << 16) + (u(b[15]) << 24); logger.fine("audioSampleRate" + audioSampleRate); logger.fine("audioSampleRate" + b[12] + " " + b[13] + " " + b[14]); //TODO is this right spec says signed this.bitrateMinimal = u(b[16]) + (u(b[17]) << 8) + (u(b[18]) << 16) + (u(b[19]) << 24); this.bitrateNominal = u(b[20]) + (u(b[21]) << 8) + (u(b[22]) << 16) + (u(b[23]) << 24); this.bitrateMaximal = u(b[24]) + (u(b[25]) << 8) + (u(b[26]) << 16) + (u(b[27]) << 24); //byte blockSize0 = (byte) ( b[28] & 240 ); //byte blockSize1 = (byte) ( b[28] & 15 ); int framingFlag = b[FIELD_FRAMING_FLAG_POS]; logger.fine("framingFlag" + framingFlag); if (framingFlag != 0) { isValid = true; } } } private int u(int i) { return i & 0xFF; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/ogg/util/OggCRCFactory.java0000644000175000017500000000510111277026507027603 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2003-2005 Raphaël Slinckx * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.audio.ogg.util; import java.util.logging.Logger; /** * OffCRC Calculations *

    * $Id: OggCRCFactory.java 836 2009-11-12 15:44:07Z paultaylor $ * * @author Raphael Slinckx (KiKiDonK) * @version 19 d�cembre 2003 */ public class OggCRCFactory { // Logger Object public static Logger logger = Logger.getLogger("org.jaudiotagger.audio.ogg"); private static long[] crc_lookup = new long[256]; private static boolean init = false; public static void init() { for (int i = 0; i < 256; i++) { long r = i << 24; for (int j = 0; j < 8; j++) { if ((r & 0x80000000L) != 0) { r = (r << 1) ^ 0x04c11db7L; } else { r <<= 1; } } crc_lookup[i] = (r); } init = true; } public boolean checkCRC(byte[] data, byte[] crc) { return new String(crc).equals(new String(computeCRC(data))); } public static byte[] computeCRC(byte[] data) { if (!init) { init(); } long crc_reg = 0; for (byte aData : data) { int tmp = (int) (((crc_reg >>> 24) & 0xff) ^ u(aData)); crc_reg = (crc_reg << 8) ^ crc_lookup[tmp]; crc_reg &= 0xffffffff; } byte[] sum = new byte[4]; sum[0] = (byte) (crc_reg & 0xffL); sum[1] = (byte) ((crc_reg >>> 8) & 0xffL); sum[2] = (byte) ((crc_reg >>> 16) & 0xffL); sum[3] = (byte) ((crc_reg >>> 24) & 0xffL); return sum; } private static int u(int n) { return n & 0xff; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/ogg/util/VorbisPacketType.java0000644000175000017500000000067210727201653030451 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.ogg.util; /** * Vorbis Packet Type *

    * In an Vorbis Stream there should be one instance of the three headers, and many audio packets */ public enum VorbisPacketType { AUDIO(0), IDENTIFICATION_HEADER(1), COMMENT_HEADER(3), SETUP_HEADER(5); int type; VorbisPacketType(int type) { this.type = type; } public int getType() { return type; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/ogg/util/OggPageHeader.java0000644000175000017500000002770511271532347027645 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2003-2005 Raphaël Slinckx * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.audio.ogg.util; import org.jaudiotagger.audio.exceptions.CannotReadException; import org.jaudiotagger.audio.generic.Utils; import org.jaudiotagger.logging.ErrorMessage; import java.io.IOException; import java.io.RandomAccessFile; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.logging.Logger; import java.util.logging.Level; import java.nio.ByteBuffer; /** * $Id: OggPageHeader.java 822 2009-10-27 08:52:55Z paultaylor $ *

    * reference:http://xiph.org/ogg/doc/framing.html * * @author Raphael Slinckx (KiKiDonK) * @version 16 d�cembre 2003 */ public class OggPageHeader { // Logger Object public static Logger logger = Logger.getLogger("org.jaudiotagger.audio.ogg.atom"); //Capture pattern at start of header public static final byte[] CAPTURE_PATTERN = {'O', 'g', 'g', 'S'}; //Ogg Page header is always 27 bytes plus the size of the segment table which is variable public static final int OGG_PAGE_HEADER_FIXED_LENGTH = 27; //Can have upto 255 segments in a page public static final int MAXIMUM_NO_OF_SEGMENT_SIZE = 255; //Each segment can be upto 255 bytes public static final int MAXIMUM_SEGMENT_SIZE = 255; //Maximum size of pageheader (27 + 255 = 282) public static final int MAXIMUM_PAGE_HEADER_SIZE = OGG_PAGE_HEADER_FIXED_LENGTH + MAXIMUM_NO_OF_SEGMENT_SIZE; //Maximum size of page data following the page header (255 * 255 = 65025) public static final int MAXIMUM_PAGE_DATA_SIZE = MAXIMUM_NO_OF_SEGMENT_SIZE * MAXIMUM_SEGMENT_SIZE; //Maximum size of page includes header and data (282 + 65025 = 65307 bytes) public static final int MAXIMUM_PAGE_SIZE = MAXIMUM_PAGE_HEADER_SIZE + MAXIMUM_PAGE_DATA_SIZE; //Starting positions of the various attributes public static final int FIELD_CAPTURE_PATTERN_POS = 0; public static final int FIELD_STREAM_STRUCTURE_VERSION_POS = 4; public static final int FIELD_HEADER_TYPE_FLAG_POS = 5; public static final int FIELD_ABSOLUTE_GRANULE_POS = 6; public static final int FIELD_STREAM_SERIAL_NO_POS = 14; public static final int FIELD_PAGE_SEQUENCE_NO_POS = 18; public static final int FIELD_PAGE_CHECKSUM_POS = 22; public static final int FIELD_PAGE_SEGMENTS_POS = 26; public static final int FIELD_SEGMENT_TABLE_POS = 27; //Length of various attributes public static final int FIELD_CAPTURE_PATTERN_LENGTH = 4; public static final int FIELD_STREAM_STRUCTURE_VERSION_LENGTH = 1; public static final int FIELD_HEADER_TYPE_FLAG_LENGTH = 1; public static final int FIELD_ABSOLUTE_GRANULE_LENGTH = 8; public static final int FIELD_STREAM_SERIAL_NO_LENGTH = 4; public static final int FIELD_PAGE_SEQUENCE_NO_LENGTH = 4; public static final int FIELD_PAGE_CHECKSUM_LENGTH = 4; public static final int FIELD_PAGE_SEGMENTS_LENGTH = 1; private byte[] rawHeaderData; private double absoluteGranulePosition; private int checksum; private byte headerTypeFlag; private boolean isValid = false; private int pageLength = 0; private int pageSequenceNumber, streamSerialNumber; private byte[] segmentTable; private List packetList = new ArrayList(); private boolean lastPacketIncomplete = false; /** * Read next PageHeader from Buffer * * @param byteBuffer * @return * @throws IOException * @throws CannotReadException */ public static OggPageHeader read(ByteBuffer byteBuffer) throws IOException, CannotReadException { //byteBuffer int start = byteBuffer.position(); logger.fine("Trying to read OggPage at:" + start); byte[] b = new byte[OggPageHeader.CAPTURE_PATTERN.length]; byteBuffer.get(b); if (!(Arrays.equals(b, OggPageHeader.CAPTURE_PATTERN))) { throw new CannotReadException(ErrorMessage.OGG_HEADER_CANNOT_BE_FOUND.getMsg(new String(b))); } byteBuffer.position(start + OggPageHeader.FIELD_PAGE_SEGMENTS_POS); int pageSegments = byteBuffer.get() & 0xFF; //unsigned byteBuffer.position(start); b = new byte[OggPageHeader.OGG_PAGE_HEADER_FIXED_LENGTH + pageSegments]; byteBuffer.get(b); OggPageHeader pageHeader = new OggPageHeader(b); //Now just after PageHeader, ready for Packet Data return pageHeader; } /** * Read next PageHeader from file * @param raf * @return * @throws IOException * @throws CannotReadException */ public static OggPageHeader read(RandomAccessFile raf) throws IOException, CannotReadException { long start = raf.getFilePointer(); logger.fine("Trying to read OggPage at:" + start); byte[] b = new byte[OggPageHeader.CAPTURE_PATTERN.length]; raf.read(b); if (!(Arrays.equals(b, OggPageHeader.CAPTURE_PATTERN))) { throw new CannotReadException(ErrorMessage.OGG_HEADER_CANNOT_BE_FOUND.getMsg(new String(b))); } raf.seek(start + OggPageHeader.FIELD_PAGE_SEGMENTS_POS); int pageSegments = raf.readByte() & 0xFF; //unsigned raf.seek(start); b = new byte[OggPageHeader.OGG_PAGE_HEADER_FIXED_LENGTH + pageSegments]; raf.read(b); OggPageHeader pageHeader = new OggPageHeader(b); //Now just after PageHeader, ready for Packet Data return pageHeader; } public OggPageHeader(byte[] b) { this.rawHeaderData = b; int streamStructureRevision = b[FIELD_STREAM_STRUCTURE_VERSION_POS]; headerTypeFlag = b[FIELD_HEADER_TYPE_FLAG_POS]; if (streamStructureRevision == 0) { this.absoluteGranulePosition = 0; for (int i = 0; i < FIELD_ABSOLUTE_GRANULE_LENGTH; i++) { this.absoluteGranulePosition += u(b[i + FIELD_ABSOLUTE_GRANULE_POS]) * Math.pow(2, 8 * i); } streamSerialNumber = Utils.getIntLE(b, FIELD_STREAM_SERIAL_NO_POS, 17); pageSequenceNumber = Utils.getIntLE(b, FIELD_PAGE_SEQUENCE_NO_POS, 21); checksum = Utils.getIntLE(b, FIELD_PAGE_CHECKSUM_POS, 25); int pageSegments = u(b[FIELD_PAGE_SEGMENTS_POS]); this.segmentTable = new byte[b.length - OGG_PAGE_HEADER_FIXED_LENGTH]; int packetLength = 0; Integer segmentLength = null; for (int i = 0; i < segmentTable.length; i++) { segmentTable[i] = b[OGG_PAGE_HEADER_FIXED_LENGTH + i]; segmentLength = u(segmentTable[i]); this.pageLength += segmentLength; packetLength += segmentLength; if (segmentLength < MAXIMUM_SEGMENT_SIZE) { packetList.add(new PacketStartAndLength(pageLength - packetLength, packetLength)); packetLength = 0; } } //If last segment value is 255 this packet continues onto next page //and will not have been added to the packetStartAndEnd list yet if(segmentLength!=null) { if (segmentLength == MAXIMUM_SEGMENT_SIZE) { packetList.add(new PacketStartAndLength(pageLength - packetLength, packetLength)); lastPacketIncomplete = true; } } isValid = true; } if(logger.isLoggable(Level.CONFIG)) { logger.config("Constructed OggPage:" + this.toString()); } } private int u(int i) { return i & 0xFF; } /** * @return true if the last packet on this page extends to the next page */ public boolean isLastPacketIncomplete() { return lastPacketIncomplete; } public double getAbsoluteGranulePosition() { logger.fine("Number Of Samples: " + absoluteGranulePosition); return this.absoluteGranulePosition; } public int getCheckSum() { return checksum; } public byte getHeaderType() { return headerTypeFlag; } public int getPageLength() { logger.fine("This page length: " + pageLength); return this.pageLength; } public int getPageSequence() { return pageSequenceNumber; } public int getSerialNumber() { return streamSerialNumber; } public byte[] getSegmentTable() { return this.segmentTable; } public boolean isValid() { return isValid; } /** * @return a list of packet start position and size within this page. */ public List getPacketList() { return packetList; } /** * @return the raw header data that this pageheader is derived from */ public byte[] getRawHeaderData() { return rawHeaderData; } public String toString() { String out = "Ogg Page Header:isValid:" + isValid + ":type:" + headerTypeFlag + ":oggPageHeaderLength:" + rawHeaderData.length + ":length:" + pageLength + ":seqNo:" + getPageSequence() + ":packetIncomplete:" + isLastPacketIncomplete() + ":serNum:" + this.getSerialNumber(); for (PacketStartAndLength packet : getPacketList()) { out += packet.toString(); } return out; } /** * Within the page specifies the start and length of each packet * in the page offset from the end of the pageheader (after the segment table) */ public static class PacketStartAndLength { private Integer startPosition = 0; private Integer length = 0; public PacketStartAndLength(int startPosition, int length) { this.startPosition = startPosition; this.length = length; } public int getStartPosition() { return startPosition; } public void setStartPosition(int startPosition) { this.startPosition = startPosition; } public int getLength() { return length; } public void setLength(int length) { this.length = length; } public String toString() { return "NextPkt(start:" + startPosition + ":length:" + length + "),"; } } /** * This represents all the flags that can be set in the headerType field. * Note these values can be ORED together. For example the last packet in * a file would normally have a value of 0x5 because both the CONTINUED_PACKET * bit and the END_OF_BITSTREAM bit would be set. */ public static enum HeaderTypeFlag { FRESH_PACKET((byte) 0x0), CONTINUED_PACKET((byte) 0x1), START_OF_BITSTREAM((byte) 0x2), END_OF_BITSTREAM((byte) 0x4); byte fileValue; HeaderTypeFlag(byte fileValue) { this.fileValue = fileValue; } /** * @return the value that should be written to file to enable this flag */ public byte getFileValue() { return fileValue; } } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/AudioFileIO.java0000644000175000017500000003034411470746136025560 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2003-2005 Raphaël Slinckx * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.audio; import org.jaudiotagger.audio.asf.AsfFileReader; import org.jaudiotagger.audio.asf.AsfFileWriter; import org.jaudiotagger.audio.exceptions.CannotReadException; import org.jaudiotagger.audio.exceptions.CannotWriteException; import org.jaudiotagger.audio.exceptions.InvalidAudioFrameException; import org.jaudiotagger.audio.exceptions.ReadOnlyFileException; import org.jaudiotagger.audio.flac.FlacFileReader; import org.jaudiotagger.audio.flac.FlacFileWriter; import org.jaudiotagger.audio.generic.*; import org.jaudiotagger.audio.mp3.MP3FileReader; import org.jaudiotagger.audio.mp3.MP3FileWriter; import org.jaudiotagger.audio.mp4.Mp4FileReader; import org.jaudiotagger.audio.mp4.Mp4FileWriter; import org.jaudiotagger.audio.ogg.OggFileReader; import org.jaudiotagger.audio.ogg.OggFileWriter; import org.jaudiotagger.audio.real.RealFileReader; import org.jaudiotagger.audio.wav.WavFileReader; import org.jaudiotagger.audio.wav.WavFileWriter; import org.jaudiotagger.logging.ErrorMessage; import org.jaudiotagger.tag.TagException; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.logging.Logger; /** *

    * The main entry point for the Tag Reading/Writing operations, this class will * select the appropriate reader/writer for the given file. *

    *

    * It selects the appropriate reader/writer based on the file extension (case * ignored). *

    *

    * Here is an simple example of use: *

    *

    * * AudioFile audioFile = AudioFileIO.read(new File("audiofile.mp3")); //Reads the given file.
    * int bitrate = audioFile.getBitrate(); //Retreives the bitrate of the file.
    * String artist = audioFile.getTag().getFirst(TagFieldKey.ARTIST); //Retreive the artist name.
    * audioFile.getTag().setGenre("Progressive Rock"); //Sets the genre to Prog. Rock, note the file on disk is still unmodified.
    * AudioFileIO.write(audioFile); //Write the modifications in the file on disk. *
    *

    *

    * You can also use the commit() method defined for * AudioFiles to achieve the same goal as * AudioFileIO.write(File), like this: *

    *

    * * AudioFile audioFile = AudioFileIO.read(new File("audiofile.mp3"));
    * audioFile.getTag().setGenre("Progressive Rock");
    * audioFile.commit(); //Write the modifications in the file on disk.
    *
    *

    * * @author Raphael Slinckx * @version $Id: AudioFileIO.java 929 2010-11-17 12:36:46Z paultaylor $ * @see AudioFile * @see org.jaudiotagger.tag.Tag * @since v0.01 */ public class AudioFileIO { //Logger public static Logger logger = Logger.getLogger("org.jaudiotagger.audio"); // !! Do not forget to also add new supported extensions to AudioFileFilter // !! /** * This field contains the default instance for static use. */ private static AudioFileIO defaultInstance; /** *

    * Delete the tag, if any, contained in the given file. *

    * * @param f The file where the tag will be deleted * @throws CannotWriteException If the file could not be written/accessed, the extension * wasn't recognized, or other IO error occurred. * @throws org.jaudiotagger.audio.exceptions.CannotReadException */ public static void delete(AudioFile f) throws CannotReadException, CannotWriteException { getDefaultAudioFileIO().deleteTag(f); } /** * This method returns the default instance for static use.
    * * @return The default instance. */ public static AudioFileIO getDefaultAudioFileIO() { if (defaultInstance == null) { defaultInstance = new AudioFileIO(); } return defaultInstance; } /** *

    * Read the tag contained in the given file. *

    * * @param f The file to read. * @return The AudioFile with the file tag and the file encoding info. * @throws CannotReadException If the file could not be read, the extension wasn't * recognized, or an IO error occurred during the read. * @throws org.jaudiotagger.tag.TagException * @throws org.jaudiotagger.audio.exceptions.ReadOnlyFileException * @throws java.io.IOException * @throws org.jaudiotagger.audio.exceptions.InvalidAudioFrameException */ public static AudioFile read(File f) throws CannotReadException, IOException, TagException, ReadOnlyFileException, InvalidAudioFrameException { return getDefaultAudioFileIO().readFile(f); } /** *

    * Write the tag contained in the audioFile in the actual file on the disk. *

    * * @param f The AudioFile to be written * @throws CannotWriteException If the file could not be written/accessed, the extension * wasn't recognized, or other IO error occurred. */ public static void write(AudioFile f) throws CannotWriteException { getDefaultAudioFileIO().writeFile(f); } /** * This member is used to broadcast modification events to registered */ private final ModificationHandler modificationHandler; // These tables contains all the readers/writers associated with extension // as a key private Map readers = new HashMap(); private Map writers = new HashMap(); /** * Creates an instance. */ public AudioFileIO() { this.modificationHandler = new ModificationHandler(); prepareReadersAndWriters(); } /** * Adds an listener for all file formats. * * @param listener listener */ public void addAudioFileModificationListener( AudioFileModificationListener listener) { this.modificationHandler.addAudioFileModificationListener(listener); } /** *

    * Delete the tag, if any, contained in the given file. *

    * * @param f The file where the tag will be deleted * @throws CannotWriteException If the file could not be written/accessed, the extension * wasn't recognized, or other IO error occurred. * @throws org.jaudiotagger.audio.exceptions.CannotReadException */ public void deleteTag(AudioFile f) throws CannotReadException, CannotWriteException { String ext = Utils.getExtension(f.getFile()); Object afw = writers.get(ext); if (afw == null) { throw new CannotWriteException(ErrorMessage.NO_DELETER_FOR_THIS_FORMAT.getMsg(ext)); } ((AudioFileWriter) afw).delete(f); } /** * Creates the readers and writers. */ private void prepareReadersAndWriters() { // Tag Readers readers.put(SupportedFileFormat.OGG.getFilesuffix(), new OggFileReader()); readers.put(SupportedFileFormat.FLAC.getFilesuffix(),new FlacFileReader()); readers.put(SupportedFileFormat.MP3.getFilesuffix(), new MP3FileReader()); readers.put(SupportedFileFormat.MP4.getFilesuffix(), new Mp4FileReader()); readers.put(SupportedFileFormat.M4A.getFilesuffix(), new Mp4FileReader()); readers.put(SupportedFileFormat.M4P.getFilesuffix(), new Mp4FileReader()); readers.put(SupportedFileFormat.M4B.getFilesuffix(), new Mp4FileReader()); readers.put(SupportedFileFormat.WAV.getFilesuffix(), new WavFileReader()); readers.put(SupportedFileFormat.WMA.getFilesuffix(), new AsfFileReader()); final RealFileReader realReader = new RealFileReader(); readers.put(SupportedFileFormat.RA.getFilesuffix(), realReader); readers.put(SupportedFileFormat.RM.getFilesuffix(), realReader); // Tag Writers writers.put(SupportedFileFormat.OGG.getFilesuffix(), new OggFileWriter()); writers.put(SupportedFileFormat.FLAC.getFilesuffix(), new FlacFileWriter()); writers.put(SupportedFileFormat.MP3.getFilesuffix(), new MP3FileWriter()); writers.put(SupportedFileFormat.MP4.getFilesuffix(), new Mp4FileWriter()); writers.put(SupportedFileFormat.M4A.getFilesuffix(), new Mp4FileWriter()); writers.put(SupportedFileFormat.M4P.getFilesuffix(), new Mp4FileWriter()); writers.put(SupportedFileFormat.M4B.getFilesuffix(), new Mp4FileWriter()); writers.put(SupportedFileFormat.WAV.getFilesuffix(), new WavFileWriter()); writers.put(SupportedFileFormat.WMA.getFilesuffix(), new AsfFileWriter()); // Register modificationHandler Iterator it = writers.values().iterator(); for (AudioFileWriter curr : writers.values()) { curr.setAudioFileModificationListener(this.modificationHandler); } } /** *

    * Read the tag contained in the given file. *

    * * @param f The file to read. * @return The AudioFile with the file tag and the file encoding info. * @throws CannotReadException If the file could not be read, the extension wasn't * recognized, or an IO error occurred during the read. * @throws org.jaudiotagger.tag.TagException * @throws org.jaudiotagger.audio.exceptions.ReadOnlyFileException * @throws java.io.IOException * @throws org.jaudiotagger.audio.exceptions.InvalidAudioFrameException */ public AudioFile readFile(File f) throws CannotReadException, IOException, TagException, ReadOnlyFileException, InvalidAudioFrameException { checkFileExists(f); String ext = Utils.getExtension(f); AudioFileReader afr = readers.get(ext); if (afr == null) { throw new CannotReadException(ErrorMessage.NO_READER_FOR_THIS_FORMAT.getMsg(ext)); } return afr.read(f); } /** * Check does file exist * * @param file * @throws java.io.FileNotFoundException */ public void checkFileExists(File file)throws FileNotFoundException { logger.info("Reading file:" + "path" + file.getPath() + ":abs:" + file.getAbsolutePath()); if (!file.exists()) { logger.severe("Unable to find:" + file.getPath()); throw new FileNotFoundException(ErrorMessage.UNABLE_TO_FIND_FILE.getMsg(file.getPath())); } } /** * Removes an listener for all file formats. * * @param listener listener */ public void removeAudioFileModificationListener( AudioFileModificationListener listener) { this.modificationHandler.removeAudioFileModificationListener(listener); } /** *

    * Write the tag contained in the audioFile in the actual file on the disk. *

    * * @param f The AudioFile to be written * @throws CannotWriteException If the file could not be written/accessed, the extension * wasn't recognized, or other IO error occurred. */ public void writeFile(AudioFile f) throws CannotWriteException { String ext = Utils.getExtension(f.getFile()); AudioFileWriter afw = writers.get(ext); if (afw == null) { throw new CannotWriteException(ErrorMessage.NO_WRITER_FOR_THIS_FORMAT.getMsg(ext)); } afw.write(f); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/AudioFile.java0000644000175000017500000002523611470746136025334 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2003-2005 Raphaël Slinckx * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.audio; import java.io.File; import java.io.FileNotFoundException; import java.io.RandomAccessFile; import java.util.logging.Logger; import java.util.ArrayList; import org.jaudiotagger.audio.exceptions.CannotWriteException; import org.jaudiotagger.audio.exceptions.ReadOnlyFileException; import org.jaudiotagger.audio.flac.metadatablock.MetadataBlockDataPicture; import org.jaudiotagger.logging.ErrorMessage; import org.jaudiotagger.tag.asf.AsfTag; import org.jaudiotagger.audio.wav.WavTag; import org.jaudiotagger.audio.real.RealTag; import org.jaudiotagger.tag.Tag; import org.jaudiotagger.tag.mp4.Mp4Tag; import org.jaudiotagger.tag.vorbiscomment.VorbisCommentTag; import org.jaudiotagger.tag.flac.FlacTag; /** *

    This is the main object manipulated by the user representing an audiofile, its properties and its tag.

    *

    The prefered way to obtain an AudioFile is to use the AudioFileIO.read(File) method.

    *

    The AudioFile contains every properties associated with the file itself (no meta-data), like the bitrate, the sampling rate, the encoding audioHeaders, etc.

    *

    To get the meta-data contained in this file you have to get the Tag of this AudioFile

    * * @author Raphael Slinckx * @version $Id: AudioFile.java 929 2010-11-17 12:36:46Z paultaylor $ * @see AudioFileIO * @see Tag * @since v0.01 */ public class AudioFile { //Logger public static Logger logger = Logger.getLogger("org.jaudiotagger.audio"); /** * The physical file that this instance represents. */ protected File file; /** * The Audio header info */ protected AudioHeader audioHeader; /** * The tag */ protected Tag tag; public AudioFile() { } /** *

    These constructors are used by the different readers, users should not use them, but use the AudioFileIO.read(File) method instead !.

    *

    Create the AudioFile representing file f, the encoding audio headers and containing the tag

    * * @param f The file of the audio file * @param audioHeader the encoding audioHeaders over this file * @param tag the tag contained in this file or null if no tag exists */ public AudioFile(File f, AudioHeader audioHeader, Tag tag) { this.file = f; this.audioHeader = audioHeader; this.tag = tag; } /** *

    These constructors are used by the different readers, users should not use them, but use the AudioFileIO.read(File) method instead !.

    *

    Create the AudioFile representing file denoted by pathnames, the encoding audio Headers and containing the tag

    * * @param s The pathname of the audio file * @param audioHeader the encoding audioHeaders over this file * @param tag the tag contained in this file */ public AudioFile(String s, AudioHeader audioHeader, Tag tag) { this.file = new File(s); this.audioHeader = audioHeader; this.tag = tag; } /** *

    Write the tag contained in this AudioFile in the actual file on the disk, this is the same as calling the AudioFileIO.write(this) method.

    * * @throws CannotWriteException If the file could not be written/accessed, the extension wasn't recognized, or other IO error occured. * @see AudioFileIO */ public void commit() throws CannotWriteException { AudioFileIO.write(this); } /** * Set the file to store the info in * * @param file */ public void setFile(File file) { this.file = file; } /** * Retrieve the physical file * * @return */ public File getFile() { return file; } public void setTag(Tag tag) { this.tag = tag; } /** * Return audio header * @return */ public AudioHeader getAudioHeader() { return audioHeader; } /** *

    Returns the tag contained in this AudioFile, the Tag contains any useful meta-data, like * artist, album, title, etc. If the file does not contain any tag the null is returned. Some audio formats do * not allow there to be no tag so in this case the reader would return an empty tag whereas for others such * as mp3 it is purely optional. * * @return Returns the tag contained in this AudioFile, or null if no tag exists. */ public Tag getTag() { return tag; } /** *

    Returns a multi-line string with the file path, the encoding audioHeader, and the tag contents.

    * * @return A multi-line string with the file path, the encoding audioHeader, and the tag contents. * TODO Maybe this can be changed ? */ public String toString() { return "AudioFile " + getFile().getAbsolutePath() + " --------\n" + audioHeader.toString() + "\n" + ((tag == null) ? "" : tag.toString()) + "\n-------------------"; } /** * Check does file exist * * @param file * @throws FileNotFoundException */ public void checkFileExists(File file)throws FileNotFoundException { logger.info("Reading file:" + "path" + file.getPath() + ":abs:" + file.getAbsolutePath()); if (!file.exists()) { logger.severe("Unable to find:" + file.getPath()); throw new FileNotFoundException(ErrorMessage.UNABLE_TO_FIND_FILE.getMsg(file.getPath())); } } /** * Checks the file is accessible with the correct permissions, otherwise exception occurs * * @param file * @param readOnly * @throws ReadOnlyFileException * @throws FileNotFoundException * @return */ protected RandomAccessFile checkFilePermissions(File file, boolean readOnly) throws ReadOnlyFileException, FileNotFoundException { RandomAccessFile newFile; checkFileExists(file); // Unless opened as readonly the file must be writable if (readOnly) { newFile = new RandomAccessFile(file, "r"); } else { if (!file.canWrite()) { logger.severe("Unable to write:" + file.getPath()); throw new ReadOnlyFileException(ErrorMessage.NO_PERMISSIONS_TO_WRITE_TO_FILE.getMsg(file.getPath())); } newFile = new RandomAccessFile(file, "rws"); } return newFile; } /** * Optional debugging method * * @return */ public String displayStructureAsXML() { return ""; } /** * Optional debugging method * * @return */ public String displayStructureAsPlainText() { return ""; } /** Create Default Tag * * @return */ //TODO might be better to instantiate classes such as Mp4File,FlacFile ecetera //TODO Generic tag is very misleading because soem of these formats cannot actually save the tag public Tag createDefaultTag() { if(SupportedFileFormat.FLAC.getFilesuffix().equals(file.getName().substring(file.getName().lastIndexOf('.')))) { return new FlacTag(VorbisCommentTag.createNewTag(), new ArrayList< MetadataBlockDataPicture >()); } else if(SupportedFileFormat.OGG.getFilesuffix().equals(file.getName().substring(file.getName().lastIndexOf('.')))) { return VorbisCommentTag.createNewTag(); } else if(SupportedFileFormat.MP4.getFilesuffix().equals(file.getName().substring(file.getName().lastIndexOf('.')))) { return new Mp4Tag(); } else if(SupportedFileFormat.M4A.getFilesuffix().equals(file.getName().substring(file.getName().lastIndexOf('.')))) { return new Mp4Tag(); } else if(SupportedFileFormat.M4P.getFilesuffix().equals(file.getName().substring(file.getName().lastIndexOf('.')))) { return new Mp4Tag(); } else if(SupportedFileFormat.WMA.getFilesuffix().equals(file.getName().substring(file.getName().lastIndexOf('.')))) { return new AsfTag(); } else if(SupportedFileFormat.WAV.getFilesuffix().equals(file.getName().substring(file.getName().lastIndexOf('.')))) { return new WavTag(); } else if(SupportedFileFormat.RA.getFilesuffix().equals(file.getName().substring(file.getName().lastIndexOf('.')))) { return new RealTag(); } else if(SupportedFileFormat.RM.getFilesuffix().equals(file.getName().substring(file.getName().lastIndexOf('.')))) { return new RealTag(); } else { throw new RuntimeException("Unable to create default tag for this file format"); } } /** * Get the tag or if the file doesn't have one at all, create a default tag and return * * @return */ public Tag getTagOrCreateDefault() { Tag tag = getTag(); if(tag==null) { return createDefaultTag(); } return tag; } /** * Get the tag or if the file doesn't have one at all, create a default tag and set it * * @return */ public Tag getTagOrCreateAndSetDefault() { Tag tag = getTag(); if(tag==null) { tag = createDefaultTag(); setTag(tag); return tag; } return tag; } /** * * @param file * @return filename with audioFormat separator stripped of. */ public static String getBaseFilename(File file) { int index=file.getName().toLowerCase().lastIndexOf("."); if(index>0) { return file.getName().substring(0,index); } return file.getName(); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/real/0000755000175000017500000000000011556363171023542 5ustar drazzibdrazziblibjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/real/RealFileReader.java0000644000175000017500000000667211276777123027233 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.real; import org.jaudiotagger.audio.exceptions.CannotReadException; import org.jaudiotagger.audio.generic.AudioFileReader; import org.jaudiotagger.audio.generic.GenericAudioHeader; import org.jaudiotagger.audio.generic.Utils; import org.jaudiotagger.tag.FieldDataInvalidException; import org.jaudiotagger.tag.FieldKey; import org.jaudiotagger.tag.Tag; import java.io.DataInputStream; import java.io.IOException; import java.io.RandomAccessFile; /** * Real Media File Format: Major Chunks: .RMF PROP MDPR CONT DATA INDX */ public class RealFileReader extends AudioFileReader { @Override protected GenericAudioHeader getEncodingInfo(RandomAccessFile raf) throws CannotReadException, IOException { final GenericAudioHeader rv = new GenericAudioHeader(); final RealChunk prop = findPropChunk(raf); final DataInputStream dis = prop.getDataInputStream(); final int objVersion = Utils.readUint16(dis); if (objVersion == 0) { final long maxBitRate = Utils.readUint32(dis) / 1000; final long avgBitRate = Utils.readUint32(dis) / 1000; final long maxPacketSize = Utils.readUint32(dis); final long avgPacketSize = Utils.readUint32(dis); final long packetCnt = Utils.readUint32(dis); final int duration = Utils.readUint32AsInt(dis) / 1000; final long preroll = Utils.readUint32(dis); final long indexOffset = Utils.readUint32(dis); final long dataOffset = Utils.readUint32(dis); final int numStreams = Utils.readUint16(dis); final int flags = Utils.readUint16(dis); rv.setBitrate((int) avgBitRate); rv.setLength(duration); rv.setVariableBitRate(maxBitRate != avgBitRate); } return rv; } private RealChunk findPropChunk(RandomAccessFile raf) throws IOException, CannotReadException { final RealChunk rmf = RealChunk.readChunk(raf); final RealChunk prop = RealChunk.readChunk(raf); return prop; } private RealChunk findContChunk(RandomAccessFile raf) throws IOException, CannotReadException { final RealChunk rmf = RealChunk.readChunk(raf); final RealChunk prop = RealChunk.readChunk(raf); RealChunk rv = RealChunk.readChunk(raf); while (!rv.isCONT()) rv = RealChunk.readChunk(raf); return rv; } @Override protected Tag getTag(RandomAccessFile raf) throws CannotReadException, IOException { final RealChunk cont = findContChunk(raf); final DataInputStream dis = cont.getDataInputStream(); final String title = Utils.readString(dis, Utils.readUint16(dis)); final String author = Utils.readString(dis, Utils.readUint16(dis)); final String copyright = Utils.readString(dis, Utils.readUint16(dis)); final String comment = Utils.readString(dis, Utils.readUint16(dis)); final RealTag rv = new RealTag(); // NOTE: frequently these fields are off-by-one, thus the crazy // logic below... try { rv.addField(FieldKey.TITLE,(title.length() == 0 ? author : title)); rv.addField(FieldKey.ARTIST, title.length() == 0 ? copyright : author); rv.addField(FieldKey.COMMENT,comment); } catch(FieldDataInvalidException fdie) { throw new RuntimeException(fdie); } return rv; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/real/RealTag.java0000644000175000017500000000037311276777123025734 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.real; import org.jaudiotagger.audio.generic.GenericTag; public class RealTag extends GenericTag { public String toString() { String output = "REAL " + super.toString(); return output; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/real/RealChunk.java0000644000175000017500000000366311041326601026253 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.real; import java.io.ByteArrayInputStream; import java.io.DataInputStream; import java.io.IOException; import java.io.RandomAccessFile; import org.jaudiotagger.audio.exceptions.CannotReadException; import org.jaudiotagger.audio.generic.Utils; public class RealChunk { protected static final String RMF = ".RMF"; protected static final String PROP = "PROP"; protected static final String MDPR = "MDPR"; protected static final String CONT = "CONT"; protected static final String DATA = "DATA"; protected static final String INDX = "INDX"; private final String id; private final int size; private final byte[] bytes; public static RealChunk readChunk(RandomAccessFile raf) throws CannotReadException, IOException { final String id = Utils.readString(raf, 4); final int size = Utils.readUint32AsInt(raf); if (size < 8) { throw new CannotReadException( "Corrupt file: RealAudio chunk length at position " + (raf.getFilePointer() - 4) + " cannot be less than 8"); } if (size > (raf.length() - raf.getFilePointer() + 8)) { throw new CannotReadException( "Corrupt file: RealAudio chunk length of " + size + " at position " + (raf.getFilePointer() - 4) + " extends beyond the end of the file"); } final byte[] bytes = new byte[size - 8]; raf.readFully(bytes); return new RealChunk(id, size, bytes); } public RealChunk(String id, int size, byte[] bytes) { super(); this.id = id; this.size = size; this.bytes = bytes; } public DataInputStream getDataInputStream() { return new DataInputStream(new ByteArrayInputStream(getBytes())); } public boolean isCONT() { return CONT.equals(id); } public boolean isPROP() { return PROP.equals(id); } public byte[] getBytes() { return bytes; } public String getId() { return id; } public int getSize() { return size; } @Override public String toString() { return id + "\t" + size; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/mp3/0000755000175000017500000000000011556363170023315 5ustar drazzibdrazziblibjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/mp3/XingFrame.java0000644000175000017500000001742211277026507026046 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.mp3; import org.jaudiotagger.audio.exceptions.InvalidAudioFrameException; import java.nio.ByteBuffer; import java.util.Arrays; /** * Xing Frame *

    *

    In some MP3s which variable bit rate the first frame in the file contains a special frame called a Xing Frame, * instead of audio data. This is used to store additional information about the file. The most important aspect for * this library is details allowing us to determine the bitrate of a Variable Bit Rate VBR file without having * to process the whole file. *

    * Xing VBR Tag data format is 120 bytes long * 4 bytes for Header Tag * 4 bytes for Header Flags * 4 bytes for FRAME SIZE * 4 bytes for AUDIO_SIZE * 100 bytes for entry (NUMTOCENTRIES) * 4 bytes for VBR SCALE. a VBR quality indicator: 0=best 100=worst *

    * It my then contain a Lame Frame ( a Lame frame is in essence an extended Xing Frame */ public class XingFrame { //The offset into first frame varies based on the MPEG frame properties private static final int MPEG_VERSION_1_MODE_MONO_OFFSET = 21; private static final int MPEG_VERSION_1_MODE_STEREO_OFFSET = 36; private static final int MPEG_VERSION_2_MODE_MONO_OFFSET = 13; private static final int MPEG_VERSION_2_MODE_STEREO_OFFSET = 21; private static final int XING_HEADER_BUFFER_SIZE = 120; private static final int XING_IDENTIFIER_BUFFER_SIZE = 4; private static final int XING_FLAG_BUFFER_SIZE = 4; private static final int XING_FRAMECOUNT_BUFFER_SIZE = 4; private static final int XING_AUDIOSIZE_BUFFER_SIZE = 4; public static final int MAX_BUFFER_SIZE_NEEDED_TO_READ_XING = MPEG_VERSION_1_MODE_STEREO_OFFSET + XING_HEADER_BUFFER_SIZE + LameFrame.LAME_HEADER_BUFFER_SIZE; private static final int BYTE_1 = 0; private static final int BYTE_2 = 1; private static final int BYTE_3 = 2; private static final int BYTE_4 = 3; /** * Use when it is a VBR (Variable Bitrate) file */ private static final byte[] XING_VBR_ID = {'X', 'i', 'n', 'g'}; /** * Use when it is a CBR (Constant Bitrate) file */ private static final byte[] XING_CBR_ID = {'I', 'n', 'f', 'o'}; private static ByteBuffer header; private boolean vbr = false; private boolean isFrameCountEnabled = false; private int frameCount = -1; private boolean isAudioSizeEnabled = false; private int audioSize = -1; private LameFrame lameFrame; /** * Read the Xing Properties from the buffer */ private XingFrame() { //Go to start of Buffer header.rewind(); //Set Vbr setVbr(); //Read Flags, only the fourth byte of interest to us byte flagBuffer[] = new byte[XING_FLAG_BUFFER_SIZE]; header.get(flagBuffer); //Read FrameCount if flag set if ((flagBuffer[BYTE_4] & (byte) (1)) != 0) { setFrameCount(); } //Read Size if flag set if ((flagBuffer[BYTE_4] & (byte) (1 << 1)) != 0) { setAudioSize(); } //TODO TOC //TODO VBR Quality //Look for LAME Header as long as we have enough bytes to do it properly if (header.limit() >= XING_HEADER_BUFFER_SIZE + LameFrame.LAME_HEADER_BUFFER_SIZE) { header.position(XING_HEADER_BUFFER_SIZE); lameFrame = LameFrame.parseLameFrame(header); } } public LameFrame getLameFrame() { return lameFrame; } /** * Set whether or not VBR, (Xing can also be used for CBR though this is less useful) */ private void setVbr() { //Is it VBR or CBR byte[] identifier = new byte[XING_IDENTIFIER_BUFFER_SIZE]; header.get(identifier); if (Arrays.equals(identifier, XING_VBR_ID)) { MP3File.logger.finest("Is Vbr"); vbr = true; } } /** * Set count of frames */ private void setFrameCount() { byte frameCountBuffer[] = new byte[XING_FRAMECOUNT_BUFFER_SIZE]; header.get(frameCountBuffer); isFrameCountEnabled = true; frameCount = (frameCountBuffer[BYTE_1] << 24) & 0xFF000000 | (frameCountBuffer[BYTE_2] << 16) & 0x00FF0000 | (frameCountBuffer[BYTE_3] << 8) & 0x0000FF00 | frameCountBuffer[BYTE_4] & 0x000000FF; } /** * @return true if frameCount has been specified in header */ public final boolean isFrameCountEnabled() { return isFrameCountEnabled; } /** * @return count of frames */ public final int getFrameCount() { return frameCount; } /** * Set size of AudioData */ private void setAudioSize() { byte frameSizeBuffer[] = new byte[XING_AUDIOSIZE_BUFFER_SIZE]; header.get(frameSizeBuffer); isAudioSizeEnabled = true; audioSize = (frameSizeBuffer[BYTE_1] << 24) & 0xFF000000 | (frameSizeBuffer[BYTE_2] << 16) & 0x00FF0000 | (frameSizeBuffer[BYTE_3] << 8) & 0x0000FF00 | frameSizeBuffer[BYTE_4] & 0x000000FF; } /** * @return true if audioSize has been specified in header */ public final boolean isAudioSizeEnabled() { return isAudioSizeEnabled; } /** * @return size of audio data in bytes */ public final int getAudioSize() { return audioSize; } /** * Parse the XingFrame of an MP3File, cannot be called until we have validated that * this is a XingFrame * * @return * @throws InvalidAudioFrameException */ public static XingFrame parseXingFrame() throws InvalidAudioFrameException { XingFrame xingFrame = new XingFrame(); return xingFrame; } /** * IS this a Xing frame * * @param bb * @param mpegFrameHeader * @return true if this is a Xing frame */ public static boolean isXingFrame(ByteBuffer bb, MPEGFrameHeader mpegFrameHeader) { //We store this so can return here after scanning through buffer int startPosition = bb.position(); //Get to Start of where Xing Frame Should be ( we dont know if it is one at this point) if (mpegFrameHeader.getVersion() == MPEGFrameHeader.VERSION_1) { if (mpegFrameHeader.getChannelMode() == MPEGFrameHeader.MODE_MONO) { bb.position(startPosition + MPEG_VERSION_1_MODE_MONO_OFFSET); } else { bb.position(startPosition + MPEG_VERSION_1_MODE_STEREO_OFFSET); } } //MPEGVersion 2 and 2.5 else { if (mpegFrameHeader.getChannelMode() == MPEGFrameHeader.MODE_MONO) { bb.position(startPosition + MPEG_VERSION_2_MODE_MONO_OFFSET); } else { bb.position(startPosition + MPEG_VERSION_2_MODE_STEREO_OFFSET); } } //Create header from here header = bb.slice(); // Return Buffer to start Point bb.position(startPosition); //Check Identifier byte[] identifier = new byte[XING_IDENTIFIER_BUFFER_SIZE]; header.get(identifier); if ((!Arrays.equals(identifier, XING_VBR_ID)) && (!Arrays.equals(identifier, XING_CBR_ID))) { return false; } MP3File.logger.finest("Found Xing Frame"); return true; } /** * Is this XingFrame detailing a varaible bit rate MPEG * * @return */ public final boolean isVbr() { return vbr; } /** * @return a string represntation */ public String toString() { return "xingheader" + " vbr:" + vbr + " frameCountEnabled:" + isFrameCountEnabled + " frameCount:" + frameCount + " audioSizeEnabled:" + isAudioSizeEnabled + " audioFileSize:" + audioSize; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/mp3/MP3FileWriter.java0000644000175000017500000000350611045554570026557 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.mp3; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.exceptions.CannotWriteException; import org.jaudiotagger.audio.exceptions.CannotReadException; import org.jaudiotagger.audio.generic.AudioFileWriter; import org.jaudiotagger.tag.Tag; import java.io.IOException; import java.io.RandomAccessFile; /** * Write Mp3 Info (retrofitted to entagged ,done differently to entagged which is why some methods throw RuntimeException) * because done elsewhere */ public class MP3FileWriter extends AudioFileWriter { public void deleteTag(AudioFile f) throws CannotWriteException { //Because audio file is an instanceof MP3File this directs it to save //taking into account if the tag has been sent to null in which case it will be deleted f.commit(); } public void writeFile(AudioFile f) throws CannotWriteException { //Because audio file is an instanceof MP3File this directs it to save f.commit(); } /** * Delete the Id3v1 and ID3v2 tags from file * * @param af * @throws CannotReadException * @throws CannotWriteException */ @Override public synchronized void delete(AudioFile af) throws CannotReadException, CannotWriteException { ((MP3File)af).setID3v1Tag(null); ((MP3File)af).setID3v2Tag(null); af.commit(); } protected void writeTag(Tag tag, RandomAccessFile raf, RandomAccessFile rafTemp) throws CannotWriteException, IOException { throw new RuntimeException("MP3FileReaderwriteTag should not be called"); } protected void deleteTag(RandomAccessFile raf, RandomAccessFile tempRaf) throws CannotWriteException, IOException { throw new RuntimeException("MP3FileReader.getEncodingInfo should be called"); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/mp3/ByteArrayMP3AudioHeader.java0000644000175000017500000000752311277026507030504 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.mp3; import org.jaudiotagger.audio.exceptions.InvalidAudioFrameException; import java.nio.ByteBuffer; public class ByteArrayMP3AudioHeader extends MP3AudioHeader { public ByteArrayMP3AudioHeader(byte[] fileBytes) { // This is substantially faster than updating the filechannels position long filePointerCount = 0; // Read into Byte Buffer in Chunks ByteBuffer bb = ByteBuffer.wrap(fileBytes); boolean syncFound = false; do { if (MPEGFrameHeader.isMPEGFrame(bb)) { try { mp3FrameHeader = MPEGFrameHeader.parseMPEGHeader(bb); syncFound = true; if (XingFrame.isXingFrame(bb, mp3FrameHeader)) { try { // Parses Xing frame without modifying position of main buffer mp3XingFrame = XingFrame.parseXingFrame(); } catch (InvalidAudioFrameException ex) { // We Ignore because even if Xing Header is corrupted // doesn't mean file is corrupted } break; } // There is a small but real chance that an unsynchronised ID3 Frame could fool the MPEG // Parser into thinking it was an MPEG Header. If this happens the chances of the next bytes // forming a Xing frame header are very remote. On the basis that most files these days have // Xing headers we do an additional check for when an apparent frame header has been found // but is not followed by a Xing Header:We check the next header this wont impose a large // overhead because wont apply to most Mpegs anyway ( Most likely to occur if audio // has an APIC frame which should have been unsynchronised but has not been) , or if the frame // has been encoded with as Unicode LE because these have a BOM of 0xFF 0xFE else { syncFound = isNextFrameValid(bb); if (syncFound) { break; } } } catch (InvalidAudioFrameException ex) { // We Ignore because likely to be incorrect sync bits , // will just continue in loop } } bb.position(bb.position() + 1); filePointerCount++; } while (!syncFound); setFileSize(fileBytes.length); setMp3StartByte(filePointerCount); setTimePerFrame(); setNumberOfFrames(); setTrackLength(); setBitRate(); setEncoder(); } private boolean isNextFrameValid(ByteBuffer bb) { boolean result = false; int currentPosition = bb.position(); bb.position(bb.position() + mp3FrameHeader.getFrameLength()); if (MPEGFrameHeader.isMPEGFrame(bb)) { try { MPEGFrameHeader.parseMPEGHeader(bb); MP3AudioHeader.logger.finer("Check next frame confirms is an audio header "); result = true; } catch (InvalidAudioFrameException ex) { MP3AudioHeader.logger.finer("Check next frame has identified this is not an audio header"); result = false; } } // Set back to the start of the previous frame bb.position(currentPosition); return result; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/mp3/MPEGFrameHeader.java0000644000175000017500000006476311277026507027014 0ustar drazzibdrazzib/** * @author : Paul Taylor *

    * Version @version:$Id: MPEGFrameHeader.java 836 2009-11-12 15:44:07Z paultaylor $ * Date :${DATE} *

    * Jaikoz Copyright Copyright (C) 2003 -2005 JThink Ltd */ package org.jaudiotagger.audio.mp3; import org.jaudiotagger.FileConstants; import org.jaudiotagger.audio.exceptions.InvalidAudioFrameException; import org.jaudiotagger.logging.AbstractTagDisplayFormatter; import java.nio.ByteBuffer; import java.util.HashMap; import java.util.Map; /** * Represents a MPEGFrameHeader, an MP3 is made up of a number of frames each frame starts with a four * byte frame header. */ @SuppressWarnings({"PointlessArithmeticExpression"}) public class MPEGFrameHeader { /** * Constants for MP3 Frame header, each frame has a basic header of * 4 bytes */ private static final int BYTE_1 = 0; private static final int BYTE_2 = 1; private static final int BYTE_3 = 2; private static final int BYTE_4 = 3; public static final int HEADER_SIZE = 4; /** * Sync Value to identify the start of an MPEGFrame */ public static final int SYNC_SIZE = 2; public static final int SYNC_BYTE1 = 0xFF; public static final int SYNC_BYTE2 = 0xE0; private static final byte[] header = new byte[HEADER_SIZE]; /** * Constants for MPEG Version */ public static final Map mpegVersionMap = new HashMap(); public final static int VERSION_2_5 = 0; public final static int VERSION_2 = 2; public final static int VERSION_1 = 3; static { mpegVersionMap.put(VERSION_2_5, "MPEG-2.5"); mpegVersionMap.put(VERSION_2, "MPEG-2"); mpegVersionMap.put(VERSION_1, "MPEG-1"); } /** * Constants for MPEG Layer */ public static final Map mpegLayerMap = new HashMap(); public final static int LAYER_I = 3; public final static int LAYER_II = 2; public final static int LAYER_III = 1; static { mpegLayerMap.put(LAYER_I, "Layer 1"); mpegLayerMap.put(LAYER_II, "Layer 2"); mpegLayerMap.put(LAYER_III, "Layer 3"); } /** * Slot Size is dependent on Layer */ public final static int LAYER_I_SLOT_SIZE = 4; public final static int LAYER_II_SLOT_SIZE = 1; public final static int LAYER_III_SLOT_SIZE = 1; /** * Bit Rates, the setBitrate varies for different Version and Layer */ private static final Map bitrateMap = new HashMap(); static { // MPEG-1, Layer I (E) bitrateMap.put(0x1E, 32); bitrateMap.put(0x2E, 64); bitrateMap.put(0x3E, 96); bitrateMap.put(0x4E, 128); bitrateMap.put(0x5E, 160); bitrateMap.put(0x6E, 192); bitrateMap.put(0x7E, 224); bitrateMap.put(0x8E, 256); bitrateMap.put(0x9E, 288); bitrateMap.put(0xAE, 320); bitrateMap.put(0xBE, 352); bitrateMap.put(0xCE, 384); bitrateMap.put(0xDE, 416); bitrateMap.put(0xEE, 448); // MPEG-1, Layer II (C) bitrateMap.put(0x1C, 32); bitrateMap.put(0x2C, 48); bitrateMap.put(0x3C, 56); bitrateMap.put(0x4C, 64); bitrateMap.put(0x5C, 80); bitrateMap.put(0x6C, 96); bitrateMap.put(0x7C, 112); bitrateMap.put(0x8C, 128); bitrateMap.put(0x9C, 160); bitrateMap.put(0xAC, 192); bitrateMap.put(0xBC, 224); bitrateMap.put(0xCC, 256); bitrateMap.put(0xDC, 320); bitrateMap.put(0xEC, 384); // MPEG-1, Layer III (A) bitrateMap.put(0x1A, 32); bitrateMap.put(0x2A, 40); bitrateMap.put(0x3A, 48); bitrateMap.put(0x4A, 56); bitrateMap.put(0x5A, 64); bitrateMap.put(0x6A, 80); bitrateMap.put(0x7A, 96); bitrateMap.put(0x8A, 112); bitrateMap.put(0x9A, 128); bitrateMap.put(0xAA, 160); bitrateMap.put(0xBA, 192); bitrateMap.put(0xCA, 224); bitrateMap.put(0xDA, 256); bitrateMap.put(0xEA, 320); // MPEG-2, Layer I (6) bitrateMap.put(0x16, 32); bitrateMap.put(0x26, 48); bitrateMap.put(0x36, 56); bitrateMap.put(0x46, 64); bitrateMap.put(0x56, 80); bitrateMap.put(0x66, 96); bitrateMap.put(0x76, 112); bitrateMap.put(0x86, 128); bitrateMap.put(0x96, 144); bitrateMap.put(0xA6, 160); bitrateMap.put(0xB6, 176); bitrateMap.put(0xC6, 192); bitrateMap.put(0xD6, 224); bitrateMap.put(0xE6, 256); // MPEG-2, Layer II (4) bitrateMap.put(0x14, 8); bitrateMap.put(0x24, 16); bitrateMap.put(0x34, 24); bitrateMap.put(0x44, 32); bitrateMap.put(0x54, 40); bitrateMap.put(0x64, 48); bitrateMap.put(0x74, 56); bitrateMap.put(0x84, 64); bitrateMap.put(0x94, 80); bitrateMap.put(0xA4, 96); bitrateMap.put(0xB4, 112); bitrateMap.put(0xC4, 128); bitrateMap.put(0xD4, 144); bitrateMap.put(0xE4, 160); // MPEG-2, Layer III (2) bitrateMap.put(0x12, 8); bitrateMap.put(0x22, 16); bitrateMap.put(0x32, 24); bitrateMap.put(0x42, 32); bitrateMap.put(0x52, 40); bitrateMap.put(0x62, 48); bitrateMap.put(0x72, 56); bitrateMap.put(0x82, 64); bitrateMap.put(0x92, 80); bitrateMap.put(0xA2, 96); bitrateMap.put(0xB2, 112); bitrateMap.put(0xC2, 128); bitrateMap.put(0xD2, 144); bitrateMap.put(0xE2, 160); } /** * Constants for Channel mode */ protected static final Map modeMap = new HashMap(); public final static int MODE_STEREO = 0; public final static int MODE_JOINT_STEREO = 1; public final static int MODE_DUAL_CHANNEL = 2; public final static int MODE_MONO = 3; static { modeMap.put(MODE_STEREO, "Stereo"); modeMap.put(MODE_JOINT_STEREO, "Joint Stereo"); modeMap.put(MODE_DUAL_CHANNEL, "Dual"); modeMap.put(MODE_MONO, "Mono"); } /** * Constants for Emphasis */ private static final Map emphasisMap = new HashMap(); public final static int EMPHASIS_NONE = 0; public final static int EMPHASIS_5015MS = 1; public final static int EMPHASIS_RESERVED = 2; public final static int EMPHASIS_CCITT = 3; static { emphasisMap.put(EMPHASIS_NONE, "None"); emphasisMap.put(EMPHASIS_5015MS, "5015MS"); emphasisMap.put(EMPHASIS_RESERVED, "Reserved"); emphasisMap.put(EMPHASIS_CCITT, "CCITT"); } private static final Map modeExtensionMap = new HashMap(); private final static int MODE_EXTENSION_NONE = 0; private final static int MODE_EXTENSION_ONE = 1; private final static int MODE_EXTENSION_TWO = 2; private final static int MODE_EXTENSION_THREE = 3; private static final Map modeExtensionLayerIIIMap = new HashMap(); private final static int MODE_EXTENSION_OFF_OFF = 0; private final static int MODE_EXTENSION_ON_OFF = 1; private final static int MODE_EXTENSION_OFF_ON = 2; private final static int MODE_EXTENSION_ON_ON = 3; static { modeExtensionMap.put(MODE_EXTENSION_NONE, "4-31"); modeExtensionMap.put(MODE_EXTENSION_ONE, "8-31"); modeExtensionMap.put(MODE_EXTENSION_TWO, "12-31"); modeExtensionMap.put(MODE_EXTENSION_THREE, "16-31"); modeExtensionLayerIIIMap.put(MODE_EXTENSION_OFF_OFF, "off-off"); modeExtensionLayerIIIMap.put(MODE_EXTENSION_ON_OFF, "on-off"); modeExtensionLayerIIIMap.put(MODE_EXTENSION_OFF_ON, "off-on"); modeExtensionLayerIIIMap.put(MODE_EXTENSION_ON_ON, "on-on"); } /** * Sampling Rate in Hz */ private static final Map> samplingRateMap = new HashMap>(); private static final Map samplingV1Map = new HashMap(); private static final Map samplingV2Map = new HashMap(); private static final Map samplingV25Map = new HashMap(); static { samplingV1Map.put(0, 44100); samplingV1Map.put(1, 48000); samplingV1Map.put(2, 32000); samplingV2Map.put(0, 22050); samplingV2Map.put(1, 24000); samplingV2Map.put(2, 16000); samplingV25Map.put(0, 11025); samplingV25Map.put(1, 12000); samplingV25Map.put(2, 8000); samplingRateMap.put(VERSION_1, samplingV1Map); samplingRateMap.put(VERSION_2, samplingV2Map); samplingRateMap.put(VERSION_2_5, samplingV25Map); } /* Samples Per Frame */ private static final Map> samplesPerFrameMap = new HashMap>(); private static final Map samplesPerFrameV1Map = new HashMap(); private static final Map samplesPerFrameV2Map = new HashMap(); private static final Map samplesPerFrameV25Map = new HashMap(); static { samplesPerFrameV1Map.put(LAYER_I, 384); samplesPerFrameV1Map.put(LAYER_II, 1152); samplesPerFrameV1Map.put(LAYER_III, 1152); samplesPerFrameV2Map.put(LAYER_I, 384); samplesPerFrameV2Map.put(LAYER_II, 1152); samplesPerFrameV2Map.put(LAYER_III, 1152); samplesPerFrameV25Map.put(LAYER_I, 384); samplesPerFrameV25Map.put(LAYER_II, 1152); samplesPerFrameV25Map.put(LAYER_III, 1152); samplesPerFrameMap.put(VERSION_1, samplesPerFrameV1Map); samplesPerFrameMap.put(VERSION_2, samplesPerFrameV2Map); samplesPerFrameMap.put(VERSION_2_5, samplesPerFrameV25Map); } private static final int SCALE_BY_THOUSAND = 1000; private static final int LAYER_I_FRAME_SIZE_COEFFICIENT = 12; private static final int LAYER_II_FRAME_SIZE_COEFFICIENT = 144; private static final int LAYER_III_FRAME_SIZE_COEFFICIENT = 144; /** * MP3 Frame Header bit mask */ private static final int MASK_MP3_ID = FileConstants.BIT3; /** * MP3 version, confusingly for MP3s the version is 1. */ private static final int MASK_MP3_VERSION = FileConstants.BIT4 | FileConstants.BIT3; /** * MP3 Layer, for MP3s the Layer is 3 */ private static final int MASK_MP3_LAYER = FileConstants.BIT2 | FileConstants.BIT1; /** * Does it include a CRC Checksum at end of header, this can be used to check the header. */ private static final int MASK_MP3_PROTECTION = FileConstants.BIT0; /** * The setBitrate of this MP3 */ private static final int MASK_MP3_BITRATE = FileConstants.BIT7 | FileConstants.BIT6 | FileConstants.BIT5 | FileConstants.BIT4; /** * The sampling/frequency rate */ private static final int MASK_MP3_FREQUENCY = FileConstants.BIT3 + FileConstants.BIT2; /** * An extra padding bit is sometimes used to make sure frames are exactly the right length */ private static final int MASK_MP3_PADDING = FileConstants.BIT1; /** * Private bit set, for application specific */ private static final int MASK_MP3_PRIVACY = FileConstants.BIT0; /** * Channel Mode, Stero/Mono/Dual Channel */ private static final int MASK_MP3_MODE = FileConstants.BIT7 | FileConstants.BIT6; /** * MP3 Frame Header bit mask */ private static final int MASK_MP3_MODE_EXTENSION = FileConstants.BIT5 | FileConstants.BIT4; /** * MP3 Frame Header bit mask */ private static final int MASK_MP3_COPY = FileConstants.BIT3; /** * MP3 Frame Header bit mask */ private static final int MASK_MP3_HOME = FileConstants.BIT2; /** * MP3 Frame Header bit mask */ private static final int MASK_MP3_EMPHASIS = FileConstants.BIT1 | FileConstants.BIT0; private byte[] mpegBytes; /** * The version of this MPEG frame (see the constants) */ private int version; private String versionAsString; /** * Contains the mpeg layer of this frame (see constants) */ private int layer; private String layerAsString; /** * Bitrate of this frame */ private Integer bitRate; /** * Channel Mode of this Frame (see constants) */ private int channelMode; /** * Channel Mode of this Frame As English String */ private String channelModeAsString; /** * Emphasis of this frame */ private int emphasis; /** * Emphasis mode string */ private String emphasisAsString; /** * Mode Extension */ private String modeExtension; /** * Flag indicating if this frame has padding byte */ private boolean isPadding; /** * Flag indicating if this frame contains copyrighted material */ private boolean isCopyrighted; /** * Flag indicating if this frame contains original material */ private boolean isOriginal; /** * Flag indicating if this frame is protected */ private boolean isProtected; /** * Flag indicating if this frame is private */ private boolean isPrivate; private Integer samplingRate; /** * Gets the layerVersion attribute of the MPEGFrame object * * @return The layerVersion value */ public int getLayer() { return layer; } public String getLayerAsString() { return layerAsString; } /** * Gets the copyrighted attribute of the MPEGFrame object */ private void setCopyrighted() { isCopyrighted = (mpegBytes[BYTE_4] & MASK_MP3_COPY) != 0; } /** * Set the version of this frame as an int value (see constants) * @throws org.jaudiotagger.audio.exceptions.InvalidAudioFrameException */ private void setVersion() throws InvalidAudioFrameException { //MPEG Version version = (byte) ((mpegBytes[BYTE_2] & MASK_MP3_VERSION) >> 3); versionAsString = mpegVersionMap.get(version); if (versionAsString == null) { throw new InvalidAudioFrameException("Invalid mpeg version"); } } /** * Sets the original attribute of the MPEGFrame object */ private void setOriginal() { isOriginal = (mpegBytes[BYTE_4] & MASK_MP3_HOME) != 0; } /** * Sets the protected attribute of the MPEGFrame object */ private void setProtected() { isProtected = (mpegBytes[BYTE_2] & MASK_MP3_PROTECTION) == 0x00; } /** * Sets the private attribute of the MPEGFrame object */ private void setPrivate() { isPrivate = (mpegBytes[BYTE_3] & MASK_MP3_PRIVACY) != 0; } /** * Get the setBitrate of this frame * @throws org.jaudiotagger.audio.exceptions.InvalidAudioFrameException */ private void setBitrate() throws InvalidAudioFrameException { /* BitRate, get by checking header setBitrate bits and MPEG Version and Layer */ int bitRateIndex = mpegBytes[BYTE_3] & MASK_MP3_BITRATE | mpegBytes[BYTE_2] & MASK_MP3_ID | mpegBytes[BYTE_2] & MASK_MP3_LAYER; bitRate = bitrateMap.get(bitRateIndex); if (bitRate == null) { throw new InvalidAudioFrameException("Invalid bitrate"); } } /** * Set the Mpeg channel mode of this frame as a constant (see constants) * @throws org.jaudiotagger.audio.exceptions.InvalidAudioFrameException */ private void setChannelMode() throws InvalidAudioFrameException { channelMode = (mpegBytes[BYTE_4] & MASK_MP3_MODE) >>> 6; channelModeAsString = modeMap.get(channelMode); if (channelModeAsString == null) { throw new InvalidAudioFrameException("Invalid channel mode"); } } /** * Get the setEmphasis mode of this frame in a string representation * @throws org.jaudiotagger.audio.exceptions.InvalidAudioFrameException */ private void setEmphasis() throws InvalidAudioFrameException { emphasis = mpegBytes[BYTE_4] & MASK_MP3_EMPHASIS; emphasisAsString = emphasisMap.get(emphasis); if (getEmphasisAsString() == null) { throw new InvalidAudioFrameException("Invalid emphasis"); } } /** * Set whether this frame uses padding bytes */ private void setPadding() { isPadding = (mpegBytes[BYTE_3] & MASK_MP3_PADDING) != 0; } /** * Get the layer version of this frame as a constant int value (see constants) * @throws org.jaudiotagger.audio.exceptions.InvalidAudioFrameException */ private void setLayer() throws InvalidAudioFrameException { layer = (mpegBytes[BYTE_2] & MASK_MP3_LAYER) >>> 1; layerAsString = mpegLayerMap.get(layer); if (layerAsString == null) { throw new InvalidAudioFrameException("Invalid Layer"); } } /** * Sets the string representation of the mode extension of this frame * @throws org.jaudiotagger.audio.exceptions.InvalidAudioFrameException */ private void setModeExtension() throws InvalidAudioFrameException { int index = (mpegBytes[BYTE_4] & MASK_MP3_MODE_EXTENSION) >> 4; if (layer == LAYER_III) { modeExtension = modeExtensionLayerIIIMap.get(index); if (getModeExtension() == null) { throw new InvalidAudioFrameException("Invalid Mode Extension"); } } else { modeExtension = modeExtensionMap.get(index); if (getModeExtension() == null) { throw new InvalidAudioFrameException("Invalid Mode Extension"); } } } /** * set the sampling rate in Hz of this frame * @throws org.jaudiotagger.audio.exceptions.InvalidAudioFrameException */ private void setSamplingRate() throws InvalidAudioFrameException { //Frequency int index = (mpegBytes[BYTE_3] & MASK_MP3_FREQUENCY) >>> 2; Map samplingRateMapForVersion = samplingRateMap.get(version); if (samplingRateMapForVersion == null) { throw new InvalidAudioFrameException("Invalid version"); } samplingRate = samplingRateMapForVersion.get(index); if (samplingRate == null) { throw new InvalidAudioFrameException("Invalid sampling rate"); } } /** * Gets the number of channels * * @return The setChannelMode value */ public int getNumberOfChannels() { switch (channelMode) { case MODE_DUAL_CHANNEL: return 2; case MODE_JOINT_STEREO: return 2; case MODE_MONO: return 1; case MODE_STEREO: return 2; default: return 0; } } public int getChannelMode() { return channelMode; } public String getChannelModeAsString() { return channelModeAsString; } /** * Gets the mPEGVersion attribute of the MPEGFrame object * * @return The mPEGVersion value */ public int getVersion() { return version; } public String getVersionAsString() { return versionAsString; } /** * Gets the paddingLength attribute of the MPEGFrame object * * @return The paddingLength value */ public int getPaddingLength() { if (isPadding()) { return 1; } else { return 0; } } public Integer getBitRate() { return bitRate; } public Integer getSamplingRate() { return samplingRate; } /* * Gets this frame length in bytes, value should always be rounded down to the nearest byte (not rounded up) * * Calculation is Bitrate (scaled to bps) divided by sampling frequency (in Hz), The larger the bitrate the larger * the frame but the more samples per second the smaller the value, also have to take into account frame padding * Have to multiple by a coefficient constant depending upon the layer it is encoded in, */ public int getFrameLength() { switch (version) { case VERSION_2: case VERSION_2_5: switch (layer) { case LAYER_I: return (LAYER_I_FRAME_SIZE_COEFFICIENT * (getBitRate() * SCALE_BY_THOUSAND) / getSamplingRate() + getPaddingLength()) * LAYER_I_SLOT_SIZE; case LAYER_II: if (this.getChannelMode() == MODE_MONO) { return (LAYER_II_FRAME_SIZE_COEFFICIENT / 2) * (getBitRate() * SCALE_BY_THOUSAND) / getSamplingRate() + getPaddingLength() * LAYER_II_SLOT_SIZE; } else { return (LAYER_II_FRAME_SIZE_COEFFICIENT) * (getBitRate() * SCALE_BY_THOUSAND) / getSamplingRate() + getPaddingLength() * LAYER_II_SLOT_SIZE; } case LAYER_III: if (this.getChannelMode() == MODE_MONO) { return (LAYER_III_FRAME_SIZE_COEFFICIENT / 2) * (getBitRate() * SCALE_BY_THOUSAND) / getSamplingRate() + getPaddingLength() * LAYER_III_SLOT_SIZE; } else { return (LAYER_III_FRAME_SIZE_COEFFICIENT) * (getBitRate() * SCALE_BY_THOUSAND) / getSamplingRate() + getPaddingLength() * LAYER_III_SLOT_SIZE; } default: throw new RuntimeException("Mp3 Unknown Layer:" + layer); } case VERSION_1: switch (layer) { case LAYER_I: return (LAYER_I_FRAME_SIZE_COEFFICIENT * (getBitRate() * SCALE_BY_THOUSAND) / getSamplingRate() + getPaddingLength()) * LAYER_I_SLOT_SIZE; case LAYER_II: return LAYER_II_FRAME_SIZE_COEFFICIENT * (getBitRate() * SCALE_BY_THOUSAND) / getSamplingRate() + getPaddingLength() * LAYER_II_SLOT_SIZE; case LAYER_III: return LAYER_III_FRAME_SIZE_COEFFICIENT * (getBitRate() * SCALE_BY_THOUSAND) / getSamplingRate() + getPaddingLength() * LAYER_III_SLOT_SIZE; default: throw new RuntimeException("Mp3 Unknown Layer:" + layer); } default: throw new RuntimeException("Mp3 Unknown Version:" + version); } } /** * Get the number of samples in a frame, all frames in a file have a set number of samples as defined by their MPEG Versiona * and Layer * @return */ public int getNoOfSamples() { Integer noOfSamples = samplesPerFrameMap.get(version).get(layer); return noOfSamples; } public boolean isPadding() { return isPadding; } public boolean isCopyrighted() { return isCopyrighted; } public boolean isOriginal() { return isOriginal; } public boolean isProtected() { return isProtected; } public boolean isPrivate() { return isPrivate; } public boolean isVariableBitRate() { return false; } public int getEmphasis() { return emphasis; } public String getEmphasisAsString() { return emphasisAsString; } public String getModeExtension() { return modeExtension; } /** * Hide Constructor * @throws org.jaudiotagger.audio.exceptions.InvalidAudioFrameException */ private MPEGFrameHeader() throws InvalidAudioFrameException { } /** * Try and create a new MPEG frame with the given byte array and decodes its contents * If decoding header causes a problem it is not a valid header * * @param b the array of bytes representing this mpeg frame * @throws InvalidAudioFrameException if does not match expected format */ private MPEGFrameHeader(byte[] b) throws InvalidAudioFrameException { mpegBytes = b; setVersion(); setLayer(); setProtected(); setBitrate(); setSamplingRate(); setPadding(); setPrivate(); setChannelMode(); setModeExtension(); setCopyrighted(); setOriginal(); setEmphasis(); } /** * Parse the MPEGFrameHeader of an MP3File, file pointer returns at end of the frame header * * @param bb the byte buffer containing the header * @return * @throws InvalidAudioFrameException if there is no header at this point */ public static MPEGFrameHeader parseMPEGHeader(ByteBuffer bb) throws InvalidAudioFrameException { int position = bb.position(); bb.get(header, 0, HEADER_SIZE); bb.position(position); MPEGFrameHeader frameHeader = new MPEGFrameHeader(header); return frameHeader; } /** * Gets the MPEGFrame attribute of the MPEGFrame object * * @param bb * @return The mPEGFrame value */ public static boolean isMPEGFrame(ByteBuffer bb) { int position = bb.position(); return (((bb.get(position) & SYNC_BYTE1) == SYNC_BYTE1) && ((bb.get(position + 1) & SYNC_BYTE2) == SYNC_BYTE2)); } /** * @return a string represntation */ public String toString() { return " mpeg frameheader:" + " frame length:" + getFrameLength() + " version:" + versionAsString + " layer:" + layerAsString + " channelMode:" + channelModeAsString + " noOfSamples:" + getNoOfSamples() + " samplingRate:" + samplingRate + " isPadding:" + isPadding + " isProtected:" + isProtected + " isPrivate:" + isPrivate + " isCopyrighted:" + isCopyrighted + " isOriginal:" + isCopyrighted + " isVariableBitRate" + this.isVariableBitRate() + " header as binary:" + AbstractTagDisplayFormatter.displayAsBinary(mpegBytes[BYTE_1]) + " " + AbstractTagDisplayFormatter.displayAsBinary(mpegBytes[BYTE_2]) + " " + AbstractTagDisplayFormatter.displayAsBinary(mpegBytes[BYTE_3]) + " " + AbstractTagDisplayFormatter.displayAsBinary(mpegBytes[BYTE_4]); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/mp3/MP3File.java0000644000175000017500000007161411470746136025372 0ustar drazzibdrazzib/** * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: MP3File.java 929 2010-11-17 12:36:46Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ package org.jaudiotagger.audio.mp3; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.exceptions.CannotWriteException; import org.jaudiotagger.audio.exceptions.InvalidAudioFrameException; import org.jaudiotagger.audio.exceptions.ReadOnlyFileException; import org.jaudiotagger.logging.*; import org.jaudiotagger.tag.Tag; import org.jaudiotagger.tag.TagException; import org.jaudiotagger.tag.TagNotFoundException; import org.jaudiotagger.tag.TagOptionSingleton; import org.jaudiotagger.tag.id3.*; import org.jaudiotagger.tag.lyrics3.AbstractLyrics3; import java.io.*; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.util.logging.Level; /** * This class represents a physical MP3 File */ public class MP3File extends AudioFile { private static final int MINIMUM_FILESIZE = 150; protected static AbstractTagDisplayFormatter tagFormatter; /** * the ID3v2 tag that this file contains. */ private AbstractID3v2Tag id3v2tag = null; /** * Representation of the idv2 tag as a idv24 tag */ private ID3v24Tag id3v2Asv24tag = null; /** * The Lyrics3 tag that this file contains. */ private AbstractLyrics3 lyrics3tag = null; /** * The ID3v1 tag that this file contains. */ private ID3v1Tag id3v1tag = null; /** * Creates a new empty MP3File datatype that is not associated with a * specific file. */ public MP3File() { } /** * Creates a new MP3File datatype and parse the tag from the given filename. * * @param filename MP3 file * @throws IOException on any I/O error * @throws TagException on any exception generated by this library. * @throws org.jaudiotagger.audio.exceptions.ReadOnlyFileException * @throws org.jaudiotagger.audio.exceptions.InvalidAudioFrameException */ public MP3File(String filename) throws IOException, TagException, ReadOnlyFileException, InvalidAudioFrameException { this(new File(filename)); } /* Load ID3V1tag if exists */ public static final int LOAD_IDV1TAG = 2; /* Load ID3V2tag if exists */ public static final int LOAD_IDV2TAG = 4; /** * This option is currently ignored */ public static final int LOAD_LYRICS3 = 8; public static final int LOAD_ALL = LOAD_IDV1TAG | LOAD_IDV2TAG | LOAD_LYRICS3; /** * Creates a new MP3File datatype and parse the tag from the given file * Object, files must be writable to use this constructor. * * @param file MP3 file * @param loadOptions decide what tags to load * @throws IOException on any I/O error * @throws TagException on any exception generated by this library. * @throws org.jaudiotagger.audio.exceptions.ReadOnlyFileException * @throws org.jaudiotagger.audio.exceptions.InvalidAudioFrameException */ public MP3File(File file, int loadOptions) throws IOException, TagException, ReadOnlyFileException, InvalidAudioFrameException { this(file, loadOptions, false); } /** * Read v1 tag * * @param file * @param newFile * @param loadOptions * @throws IOException */ private void readV1Tag(File file, RandomAccessFile newFile, int loadOptions) throws IOException { if ((loadOptions & LOAD_IDV1TAG) != 0) { logger.finer("Attempting to read id3v1tags"); try { id3v1tag = new ID3v11Tag(newFile, file.getName()); } catch (TagNotFoundException ex) { logger.info("No ids3v11 tag found"); } try { if (id3v1tag == null) { id3v1tag = new ID3v1Tag(newFile, file.getName()); } } catch (TagNotFoundException ex) { logger.info("No id3v1 tag found"); } } } /** * Read V2tag if exists *

    * TODO:shouldnt we be handing TagExceptions:when will they be thrown * * @param file * @param loadOptions * @throws IOException * @throws TagException */ private void readV2Tag(File file, int loadOptions) throws IOException, TagException { //We know where the Actual Audio starts so load all the file from start to that point into //a buffer then we can read the IDv2 information without needing any more file I/O int startByte = (int) ((MP3AudioHeader) audioHeader).getMp3StartByte(); if (startByte >= AbstractID3v2Tag.TAG_HEADER_LENGTH) { logger.finer("Attempting to read id3v2tags"); FileInputStream fis = null; FileChannel fc = null; ByteBuffer bb = null; try { fis = new FileInputStream(file); fc = fis.getChannel(); //Read into Byte Buffer bb = ByteBuffer.allocate(startByte); fc.read(bb); } finally { if (fc != null) { fc.close(); } if (fis != null) { fis.close(); } } bb.rewind(); if ((loadOptions & LOAD_IDV2TAG) != 0) { logger.info("Attempting to read id3v2tags"); try { this.setID3v2Tag(new ID3v24Tag(bb, file.getName())); } catch (TagNotFoundException ex) { logger.info("No id3v24 tag found"); } try { if (id3v2tag == null) { this.setID3v2Tag(new ID3v23Tag(bb, file.getName())); } } catch (TagNotFoundException ex) { logger.info("No id3v23 tag found"); } try { if (id3v2tag == null) { this.setID3v2Tag(new ID3v22Tag(bb, file.getName())); } } catch (TagNotFoundException ex) { logger.info("No id3v22 tag found"); } } } else { logger.info("Not enough room for valid id3v2 tag:" + startByte); } } /** * Read lyrics3 Tag *

    * TODO:not working * * @param file * @param newFile * @param loadOptions * @throws IOException */ private void readLyrics3Tag(File file, RandomAccessFile newFile, int loadOptions) throws IOException { /*if ((loadOptions & LOAD_LYRICS3) != 0) { try { lyrics3tag = new Lyrics3v2(newFile); } catch (TagNotFoundException ex) { } try { if (lyrics3tag == null) { lyrics3tag = new Lyrics3v1(newFile); } } catch (TagNotFoundException ex) { } } */ } /** * Regets the audio header starting from start of file, and write appropriate logging to indicate * potential problem to user. * * @param startByte * @param currentHeader * @return * @throws IOException * @throws InvalidAudioFrameException */ private MP3AudioHeader checkAudioStart(long startByte, MP3AudioHeader currentHeader) throws IOException, InvalidAudioFrameException { MP3AudioHeader newAudioHeader; MP3AudioHeader nextAudioHeader; logger.warning(ErrorMessage.MP3_ID3TAG_LENGTH_INCORRECT.getMsg(file.getPath(), Hex.asHex(startByte), Hex.asHex(currentHeader.getMp3StartByte()))); //because we cant agree on start location we reread the audioheader from the start of the file, at least //this way we cant overwrite the audio although we might overwrite part of the tag if we write this file //back later newAudioHeader = new MP3AudioHeader(file, 0); logger.info("Checking from start:" + newAudioHeader); if (currentHeader.getMp3StartByte() == newAudioHeader.getMp3StartByte()) { //Although the tag size appears to be incorrect at least we have found the same location for the start //of audio whether we start searching from start of file or at the end of the alleged of file so no real //problem logger.info(ErrorMessage.MP3_START_OF_AUDIO_CONFIRMED.getMsg(file.getPath(), Hex.asHex(newAudioHeader.getMp3StartByte()))); return currentHeader; } else { //We get a different value if read from start, can't guarantee 100% correct lets do some more checks logger.info((ErrorMessage.MP3_RECALCULATED_POSSIBLE_START_OF_MP3_AUDIO.getMsg(file.getPath(), Hex.asHex(newAudioHeader.getMp3StartByte())))); //Frame counts dont match so eiither currentHeader or newAudioHeader isnt really audio header if (currentHeader.getNumberOfFrames() != newAudioHeader.getNumberOfFrames()) { //Skip to the next header (header 2, counting from start of file) nextAudioHeader = new MP3AudioHeader(file, newAudioHeader.getMp3StartByte() + newAudioHeader.mp3FrameHeader.getFrameLength()); logger.info("Checking next:" + nextAudioHeader); //It matches the header we found when doing the original search from after the ID3Tag therefore it //seems that newAudioHeader was a false match and the original header was correct if (nextAudioHeader.getMp3StartByte() == currentHeader.getMp3StartByte()) { logger.warning((ErrorMessage.MP3_START_OF_AUDIO_CONFIRMED.getMsg(file.getPath(), Hex.asHex(currentHeader.getMp3StartByte())))); return currentHeader; } //it matches the header we just found so lends weight to the fact that the audio does indeed start at new header else if (nextAudioHeader.getNumberOfFrames() == newAudioHeader.getNumberOfFrames()) { logger.warning((ErrorMessage.MP3_RECALCULATED_START_OF_MP3_AUDIO.getMsg(file.getPath(), Hex.asHex(newAudioHeader.getMp3StartByte())))); return newAudioHeader; } ///Not sure but safer to return earlier audio beause stops jaudiotagger overwriting when writing tag else { logger.warning((ErrorMessage.MP3_RECALCULATED_START_OF_MP3_AUDIO.getMsg(file.getPath(), Hex.asHex(newAudioHeader.getMp3StartByte())))); return newAudioHeader; } } //Same frame count so probably both audio headers with newAudioHeader being the firt one else { logger.warning((ErrorMessage.MP3_RECALCULATED_START_OF_MP3_AUDIO.getMsg(file.getPath(), Hex.asHex(newAudioHeader.getMp3StartByte())))); return newAudioHeader; } } } /** * Creates a new MP3File dataType and parse the tag from the given file * Object, files can be opened read only if required. * * @param file MP3 file * @param loadOptions decide what tags to load * @param readOnly causes the files to be opened readonly * @throws IOException on any I/O error * @throws TagException on any exception generated by this library. * @throws org.jaudiotagger.audio.exceptions.ReadOnlyFileException * @throws org.jaudiotagger.audio.exceptions.InvalidAudioFrameException */ public MP3File(File file, int loadOptions, boolean readOnly) throws IOException, TagException, ReadOnlyFileException, InvalidAudioFrameException { RandomAccessFile newFile = null; try { this.file = file; //Check File accessibility newFile = checkFilePermissions(file, readOnly); //Read ID3v2 tag size (if tag exists) to allow audioHeader parsing to skip over tag long startByte = AbstractID3v2Tag.getV2TagSizeIfExists(file); //If exception reading Mpeg then we should give up no point continuing audioHeader = new MP3AudioHeader(file, startByte); if (startByte != ((MP3AudioHeader) audioHeader).getMp3StartByte()) { logger.info("First header found after tag:" + audioHeader); audioHeader = checkAudioStart(startByte, (MP3AudioHeader) audioHeader); } //Read v1 tags (if any) readV1Tag(file, newFile, loadOptions); //Read v2 tags (if any) readV2Tag(file, loadOptions); //If we have a v2 tag use that, if we dont but have v1 tag use that //otherwise use nothing //TODO:if have both should we merge //rather than just returning specific ID3v22 tag, would it be better to return v24 version ? if (this.getID3v2Tag() != null) { tag = this.getID3v2Tag(); } else if (id3v1tag != null) { tag = id3v1tag; } //Read Lyrics 3 //readLyrics3Tag(File file,RandomAccessFile newFile,int loadOptions) } finally { if (newFile != null) { newFile.close(); } } } /** * Used by tags when writing to calculate the location of the music file * * @param file * @return the location within the file that the audio starts * @throws java.io.IOException * @throws org.jaudiotagger.audio.exceptions.InvalidAudioFrameException */ public long getMP3StartByte(File file) throws InvalidAudioFrameException, IOException { try { //Read ID3v2 tag size (if tag exists) to allow audio header parsing to skip over tag long startByte = AbstractID3v2Tag.getV2TagSizeIfExists(file); MP3AudioHeader audioHeader = new MP3AudioHeader(file, startByte); if (startByte != audioHeader.getMp3StartByte()) { logger.info("First header found after tag:" + audioHeader); audioHeader = checkAudioStart(startByte, audioHeader); } return audioHeader.getMp3StartByte(); } catch (InvalidAudioFrameException iafe) { throw iafe; } catch (IOException ioe) { throw ioe; } } /** * Extracts the raw ID3v2 tag data into a file. *

    * This provides access to the raw data before manipulation, the data is written from the start of the file * to the start of the Audio Data. This is primarily useful for manipulating corrupted tags that are not * (fully) loaded using the standard methods. * * @param outputFile to write the data to * @return * @throws TagNotFoundException * @throws IOException */ public File extractID3v2TagDataIntoFile(File outputFile) throws TagNotFoundException, IOException { int startByte = (int) ((MP3AudioHeader) audioHeader).getMp3StartByte(); if (startByte >= 0) { //Read byte into buffer FileInputStream fis = new FileInputStream(file); FileChannel fc = fis.getChannel(); ByteBuffer bb = ByteBuffer.allocate(startByte); fc.read(bb); //Write bytes to outputFile FileOutputStream out = new FileOutputStream(outputFile); out.write(bb.array()); out.close(); fc.close(); fis.close(); return outputFile; } throw new TagNotFoundException("There is no ID3v2Tag data in this file"); } /** * Return audio header * @return */ public MP3AudioHeader getMP3AudioHeader() { return (MP3AudioHeader) getAudioHeader(); } /** * Returns true if this datatype contains an Id3v1 tag * * @return true if this datatype contains an Id3v1 tag */ public boolean hasID3v1Tag() { return (id3v1tag != null); } /** * Returns true if this datatype contains an Id3v2 tag * * @return true if this datatype contains an Id3v2 tag */ public boolean hasID3v2Tag() { return (id3v2tag != null); } /** * Returns true if this datatype contains a Lyrics3 tag * TODO disabled until Lyrics3 fixed * @return true if this datatype contains a Lyrics3 tag */ /* public boolean hasLyrics3Tag() { return (lyrics3tag != null); } */ /** * Creates a new MP3File datatype and parse the tag from the given file * Object. * * @param file MP3 file * @throws IOException on any I/O error * @throws TagException on any exception generated by this library. * @throws org.jaudiotagger.audio.exceptions.ReadOnlyFileException * @throws org.jaudiotagger.audio.exceptions.InvalidAudioFrameException */ public MP3File(File file) throws IOException, TagException, ReadOnlyFileException, InvalidAudioFrameException { this(file, LOAD_ALL); } /** * Sets the ID3v1(_1)tag to the tag provided as an argument. * * @param id3v1tag */ public void setID3v1Tag(ID3v1Tag id3v1tag) { logger.info("setting tagv1:v1 tag"); this.id3v1tag = id3v1tag; } public void setID3v1Tag(Tag id3v1tag) { logger.info("setting tagv1:v1 tag"); this.id3v1tag = (ID3v1Tag) id3v1tag; } /** * Sets the ID3v1 tag for this dataType. A new * ID3v1_1 dataType is created from the argument and then used * here. * * @param mp3tag Any MP3Tag dataType can be used and will be converted into a * new ID3v1_1 dataType. */ public void setID3v1Tag(AbstractTag mp3tag) { logger.info("setting tagv1:abstract"); id3v1tag = new ID3v11Tag(mp3tag); } /** * Returns the ID3v1 tag for this dataType. * * @return the ID3v1 tag for this dataType */ public ID3v1Tag getID3v1Tag() { return id3v1tag; } /** * Sets the ID3v2 tag for this dataType. A new * ID3v2_4 dataType is created from the argument and then used * here. * * @param mp3tag Any MP3Tag dataType can be used and will be converted into a * new ID3v2_4 dataType. */ public void setID3v2Tag(AbstractTag mp3tag) { id3v2tag = new ID3v24Tag(mp3tag); } /** * Sets the v2 tag to the v2 tag provided as an argument. * Also store a v24 version of tag as v24 is the interface to be used * when talking with client applications. * * @param id3v2tag */ public void setID3v2Tag(AbstractID3v2Tag id3v2tag) { this.id3v2tag = id3v2tag; if (id3v2tag instanceof ID3v24Tag) { this.id3v2Asv24tag = (ID3v24Tag) this.id3v2tag; } else { this.id3v2Asv24tag = new ID3v24Tag(id3v2tag); } } /** * Set v2 tag ,don't need to set v24 tag because saving *

    * @param id3v2tag */ //TODO temp its rather messy public void setID3v2TagOnly(AbstractID3v2Tag id3v2tag) { this.id3v2tag = id3v2tag; this.id3v2Asv24tag = null; } /** * Returns the ID3v2 tag for this datatype. * * @return the ID3v2 tag for this datatype */ public AbstractID3v2Tag getID3v2Tag() { return id3v2tag; } /** * @return a representation of tag as v24 */ public ID3v24Tag getID3v2TagAsv24() { return id3v2Asv24tag; } /** * Sets the Lyrics3 tag for this dataType. A new * Lyrics3v2 dataType is created from the argument and then * * used here. * * @param mp3tag Any MP3Tag dataType can be used and will be converted into a * new Lyrics3v2 dataType. */ /* public void setLyrics3Tag(AbstractTag mp3tag) { lyrics3tag = new Lyrics3v2(mp3tag); } */ /** * * * @param lyrics3tag */ /* public void setLyrics3Tag(AbstractLyrics3 lyrics3tag) { this.lyrics3tag = lyrics3tag; } */ /** * Returns the ID3v1 tag for this datatype. * * @return the ID3v1 tag for this datatype */ /* public AbstractLyrics3 getLyrics3Tag() { return lyrics3tag; } */ /** * Remove tag from file * * @param mp3tag * @throws FileNotFoundException * @throws IOException */ public void delete(AbstractTag mp3tag) throws FileNotFoundException, IOException { RandomAccessFile raf = new RandomAccessFile(this.file, "rws"); mp3tag.delete(raf); raf.close(); if(mp3tag instanceof ID3v1Tag) { id3v1tag=null; } if(mp3tag instanceof AbstractID3v2Tag) { id3v2tag=null; } } /** * Saves the tags in this dataType to the file referred to by this dataType. * * @throws IOException on any I/O error * @throws TagException on any exception generated by this library. */ public void save() throws IOException, TagException { save(this.file); } /** * Overridden for compatibility with merged code * * @throws CannotWriteException */ public void commit() throws CannotWriteException { try { save(); } catch (IOException ioe) { throw new CannotWriteException(ioe); } catch (TagException te) { throw new CannotWriteException(te); } } /** * Check can write to file * * @param file * @throws IOException */ public void precheck(File file) throws IOException { if (!file.exists()) { logger.severe(ErrorMessage.GENERAL_WRITE_FAILED_BECAUSE_FILE_NOT_FOUND.getMsg(file.getName())); throw new IOException(ErrorMessage.GENERAL_WRITE_FAILED_BECAUSE_FILE_NOT_FOUND.getMsg(file.getName())); } if (!file.canWrite()) { logger.severe(ErrorMessage.GENERAL_WRITE_FAILED.getMsg(file.getName())); throw new IOException(ErrorMessage.GENERAL_WRITE_FAILED.getMsg(file.getName())); } if (file.length() <= MINIMUM_FILESIZE) { logger.severe(ErrorMessage.GENERAL_WRITE_FAILED_BECAUSE_FILE_IS_TOO_SMALL.getMsg(file.getName())); throw new IOException(ErrorMessage.GENERAL_WRITE_FAILED_BECAUSE_FILE_IS_TOO_SMALL.getMsg(file.getName())); } } /** * Saves the tags in this dataType to the file argument. It will be saved as * TagConstants.MP3_FILE_SAVE_WRITE * * @param file file to save the this dataTypes tags to * @throws FileNotFoundException if unable to find file * @throws IOException on any I/O error */ public void save(File file) throws IOException { logger.info("Saving : " + file.getAbsolutePath()); //Checks before starting write precheck(file); RandomAccessFile rfile = null; try { //ID3v2 Tag if (TagOptionSingleton.getInstance().isId3v2Save()) { if (id3v2tag == null) { rfile = new RandomAccessFile(file, "rws"); (new ID3v24Tag()).delete(rfile); (new ID3v23Tag()).delete(rfile); (new ID3v22Tag()).delete(rfile); logger.info("Deleting ID3v2 tag:"+file.getName()); rfile.close(); } else { logger.info("Writing ID3v2 tag:"+file.getName()); id3v2tag.write(file, ((MP3AudioHeader) this.getAudioHeader()).getMp3StartByte()); } } rfile = new RandomAccessFile(file, "rws"); //Lyrics 3 Tag if (TagOptionSingleton.getInstance().isLyrics3Save()) { if (lyrics3tag != null) { lyrics3tag.write(rfile); } } //ID3v1 tag if (TagOptionSingleton.getInstance().isId3v1Save()) { logger.info("Processing ID3v1"); if (id3v1tag == null) { logger.info("Deleting ID3v1"); (new ID3v1Tag()).delete(rfile); } else { logger.info("Saving ID3v1"); id3v1tag.write(rfile); } } } catch (FileNotFoundException ex) { logger.log(Level.SEVERE, ErrorMessage.GENERAL_WRITE_FAILED_BECAUSE_FILE_NOT_FOUND.getMsg(file.getName()), ex); throw ex; } catch (IOException iex) { logger.log(Level.SEVERE, ErrorMessage.GENERAL_WRITE_FAILED_BECAUSE.getMsg(file.getName(), iex.getMessage()), iex); throw iex; } catch (RuntimeException re) { logger.log(Level.SEVERE, ErrorMessage.GENERAL_WRITE_FAILED_BECAUSE.getMsg(file.getName(), re.getMessage()), re); throw re; } finally { if (rfile != null) { rfile.close(); } } } /** * Displays MP3File Structure */ public String displayStructureAsXML() { createXMLStructureFormatter(); tagFormatter.openHeadingElement("file", this.getFile().getAbsolutePath()); if (this.getID3v1Tag() != null) { this.getID3v1Tag().createStructure(); } if (this.getID3v2Tag() != null) { this.getID3v2Tag().createStructure(); } tagFormatter.closeHeadingElement("file"); return tagFormatter.toString(); } /** * Displays MP3File Structure */ public String displayStructureAsPlainText() { createPlainTextStructureFormatter(); tagFormatter.openHeadingElement("file", this.getFile().getAbsolutePath()); if (this.getID3v1Tag() != null) { this.getID3v1Tag().createStructure(); } if (this.getID3v2Tag() != null) { this.getID3v2Tag().createStructure(); } tagFormatter.closeHeadingElement("file"); return tagFormatter.toString(); } private static void createXMLStructureFormatter() { tagFormatter = new XMLTagDisplayFormatter(); } private static void createPlainTextStructureFormatter() { tagFormatter = new PlainTextTagDisplayFormatter(); } public static AbstractTagDisplayFormatter getStructureFormatter() { return tagFormatter; } /** * Set the Tag *

    * If the parameter tag is a v1tag then the v1 tag is set if v2tag then the v2tag. * * @param tag */ public void setTag(Tag tag) { this.tag = tag; if (tag instanceof ID3v1Tag) { setID3v1Tag((ID3v1Tag) tag); } else { setID3v2Tag((AbstractID3v2Tag) tag); } } /** Create Default Tag * * @return */ @Override //TODO Should be able to change the Default public Tag createDefaultTag() { return new ID3v23Tag(); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/mp3/VbriFrame.java0000644000175000017500000001406011277026507026036 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.mp3; import org.jaudiotagger.audio.exceptions.InvalidAudioFrameException; import java.nio.ByteBuffer; import java.util.Arrays; /** * Vrbi Frame *

    *

    In MP3s encoded using the franhofer encoder which variable bit rate the first frame in the file contains a * special frame called a Vrbi Frame, instead of audio data (Other Vbr encoders use the more common Xing Frame). * This is used to store additional information about the file. The most important aspect for * this library is details allowing us to determine the bitrate of a Variable Bit Rate VBR file without having * to process the whole file. *

    * From http://www.codeproject.com/KB/audio-video/mpegaudioinfo.aspx#SideInfo *

    * This header is only used by MPEG audio files encoded with the Fraunhofer Encoder as far as I know. It is different from the XING header. You find it exactly * 32 bytes after the end of the first MPEG audio header in the file. (Note that the position is zero-based; position, length and example are each in byte-format.) * Position Length Meaning Example * 0 4 VBR header ID in 4 ASCII chars, always 'VBRI', not NULL-terminated 'VBRI' * 4 2 Version ID as Big-Endian WORD 1 * 6 2 Delay as Big-Endian float 7344 * 8 2 Quality indicator 75 * 10 4 Number of Bytes of Audio as Big-Endian DWORD 45000 * 14 4 Number of Frames as Big-Endian DWORD 7344 * 18 2 Number of entries within TOC table as Big-Endian WORD 100 * 20 2 Scale factor of TOC table entries as Big-Endian DWORD 1 * 22 2 Size per table entry in bytes (max 4) as Big-Endian WORD 2 * 24 2 Frames per table entry as Big-Endian WORD 845 * 26 TOC entries for seeking as Big-Endian integral. From size per table entry and number of entries, you can calculate the length of this field. *

    */ public class VbriFrame { //The offset into frame private static final int VBRI_OFFSET = MPEGFrameHeader.HEADER_SIZE + 32; private static final int VBRI_HEADER_BUFFER_SIZE = 120; //TODO this is just a guess, not right private static final int VBRI_IDENTIFIER_BUFFER_SIZE = 4; private static final int VBRI_DELAY_BUFFER_SIZE = 2; private static final int VBRI_QUALITY_BUFFER_SIZE = 2; private static final int VBRI_AUDIOSIZE_BUFFER_SIZE = 4; private static final int VBRI_FRAMECOUNT_BUFFER_SIZE = 4; private static final int VBRI_TOC_ENTRY_BUFFER_SIZE = 2; public static final int MAX_BUFFER_SIZE_NEEDED_TO_READ_VBRI = VBRI_OFFSET + VBRI_HEADER_BUFFER_SIZE; private static final int BYTE_1 = 0; private static final int BYTE_2 = 1; private static final int BYTE_3 = 2; private static final int BYTE_4 = 3; /** * Identifier */ private static final byte[] VBRI_VBR_ID = {'V', 'B', 'R', 'I'}; private static ByteBuffer header; private boolean vbr = false; private int frameCount = -1; private int audioSize = -1; private LameFrame lameFrame; /** * Read the VBRI Properties from the buffer */ private VbriFrame() { //Go to start of Buffer header.rewind(); header.position(10); setAudioSize(); setFrameCount(); } /** * Set size of AudioData */ private void setAudioSize() { byte frameSizeBuffer[] = new byte[VBRI_AUDIOSIZE_BUFFER_SIZE]; header.get(frameSizeBuffer); boolean audioSizeEnabled = true; audioSize = (frameSizeBuffer[BYTE_1] << 24) & 0xFF000000 | (frameSizeBuffer[BYTE_2] << 16) & 0x00FF0000 | (frameSizeBuffer[BYTE_3] << 8) & 0x0000FF00 | frameSizeBuffer[BYTE_4] & 0x000000FF; } /** * Set count of frames */ private void setFrameCount() { byte frameCountBuffer[] = new byte[VBRI_FRAMECOUNT_BUFFER_SIZE]; header.get(frameCountBuffer); boolean frameCountEnabled = true; frameCount = (frameCountBuffer[BYTE_1] << 24) & 0xFF000000 | (frameCountBuffer[BYTE_2] << 16) & 0x00FF0000 | (frameCountBuffer[BYTE_3] << 8) & 0x0000FF00 | frameCountBuffer[BYTE_4] & 0x000000FF; } /** * @return count of frames */ public final int getFrameCount() { return frameCount; } /** * @return size of audio data in bytes */ public final int getAudioSize() { return audioSize; } /** * Parse the VBRIFrame of an MP3File, cannot be called until we have validated that * this is a VBRIFrame * * @return * @throws org.jaudiotagger.audio.exceptions.InvalidAudioFrameException * */ public static VbriFrame parseVBRIFrame() throws InvalidAudioFrameException { VbriFrame VBRIFrame = new VbriFrame(); return VBRIFrame; } /** * IS this a VBRI frame * * @param bb * @param mpegFrameHeader * @return true if this is a VBRI frame */ public static boolean isVbriFrame(ByteBuffer bb, MPEGFrameHeader mpegFrameHeader) { //We store this so can return here after scanning through buffer int startPosition = bb.position(); MP3File.logger.finest("Checking VBRI Frame at" + startPosition); bb.position(startPosition + VBRI_OFFSET); //Create header from here header = bb.slice(); // Return Buffer to start Point bb.position(startPosition); //Check Identifier byte[] identifier = new byte[VBRI_IDENTIFIER_BUFFER_SIZE]; header.get(identifier); if ((!Arrays.equals(identifier, VBRI_VBR_ID))) { return false; } MP3File.logger.finest("Found VBRI Frame"); return true; } /** * Is this VBRIFrame detailing a varaible bit rate MPEG * * @return */ public final boolean isVbr() { return true; } public String getEncoder() { return "Fraunhofer"; } /** * @return a string represntation */ public String toString() { return "VBRIheader" + " vbr:" + vbr + " frameCount:" + frameCount + " audioFileSize:" + audioSize + " encoder:" + getEncoder(); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/mp3/MP3AudioHeader.java0000644000175000017500000006531611277026507026665 0ustar drazzibdrazzib/** * @author : Paul Taylor * * Version @version:$Id: MP3AudioHeader.java 836 2009-11-12 15:44:07Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jaudiotagger.audio.mp3; import org.jaudiotagger.audio.AudioHeader; import org.jaudiotagger.audio.exceptions.InvalidAudioFrameException; import org.jaudiotagger.logging.Hex; import java.io.EOFException; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale; import java.util.logging.Level; import java.util.logging.Logger; /** * Represents the audio header of an MP3 File *

    *

    The audio header consists of a number of * audio frames. Because we are not trying to play the audio but only extract some information * regarding the audio we only need to read the first audio frames to ensure that we have correctly * identified them as audio frames and extracted the metadata we reuire. *

    *

    Start of Audio id 0xFF (11111111) and then second byte anded with 0xE0(11100000). * For example 2nd byte doesnt have to be 0xE0 is just has to have the top 3 signicant * bits set. For example 0xFB (11111011) is a common occurence of the second match. The 2nd byte * defines flags to indicate various mp3 values. *

    *

    Having found these two values we then read the header which comprises these two bytes plus a further * two to ensure this really is a MP3Header, sometimes the first frame is actually a dummy frame with summary information * held within about the whole file, typically using a Xing Header or LAme Header. This is most useful when the file * is variable bit rate, if the file is variable bit rate but does not use a summary header it will not be correctly * identified as a VBR frame and the track length will be incorrectly calculated. Strictly speaking MP3 means * Layer III file but MP2 Layer II), MP1 Layer I) and MPEG-2 files are sometimes used and named with * the .mp3 suffix so this library attempts to supports all these formats. */ public class MP3AudioHeader implements AudioHeader { protected MPEGFrameHeader mp3FrameHeader; protected XingFrame mp3XingFrame; protected VbriFrame mp3VbriFrame; private long fileSize; private long startByte; private double timePerFrame; private double trackLength; private long numberOfFrames; private long numberOfFramesEstimate; private long bitrate; private String encoder = ""; private static final SimpleDateFormat timeInFormat = new SimpleDateFormat("ss", Locale.UK); private static final SimpleDateFormat timeOutFormat = new SimpleDateFormat("mm:ss",Locale.UK); private static final SimpleDateFormat timeOutOverAnHourFormat = new SimpleDateFormat("kk:mm:ss",Locale.UK); private static final char isVbrIdentifier = '~'; private static final int CONVERT_TO_KILOBITS = 1000; private static final String TYPE_MP3 = "mp3"; private static final int CONVERTS_BYTE_TO_BITS = 8; //Logger public static Logger logger = Logger.getLogger("org.jaudiotagger.audio.mp3"); /** * After testing the average location of the first MP3Header bit was at 5000 bytes so this is * why chosen as a default. */ private final static int FILE_BUFFER_SIZE = 5000; private final static int MIN_BUFFER_REMAINING_REQUIRED = MPEGFrameHeader.HEADER_SIZE + XingFrame.MAX_BUFFER_SIZE_NEEDED_TO_READ_XING; private static final int NO_SECONDS_IN_HOUR = 3600; public MP3AudioHeader() { } /** * Search for the first MP3Header in the file *

    * The search starts from the start of the file, it is usually safer to use the alternative constructor that * allows you to provide the length of the tag header as a parameter so the tag can be skipped over. * * @param seekFile * @throws IOException * @throws InvalidAudioFrameException */ public MP3AudioHeader(final File seekFile) throws IOException, InvalidAudioFrameException { if (!seek(seekFile, 0)) { throw new InvalidAudioFrameException("No audio header found within" + seekFile.getName()); } } /** * Search for the first MP3Header in the file *

    * Starts searching from location startByte, this is because there is likely to be an ID3TagHeader * before the start of the audio. If this tagHeader contains unsynchronized information there is a * possibility that it might be inaccurately identified as the start of the Audio data. Various checks * are done in this code to prevent this happening but it cannot be guaranteed. *

    * Of course if the startByte provided overstates the length of the tag header, this could mean the * start of the MP3AudioHeader is missed, further checks are done within the MP3 class to recognize * if this has occurred and take appropriate action. * * @param seekFile * @param startByte * @throws IOException * @throws InvalidAudioFrameException */ public MP3AudioHeader(final File seekFile, long startByte) throws IOException, InvalidAudioFrameException { if (!seek(seekFile, startByte)) { throw new InvalidAudioFrameException("No audio header found within" + seekFile.getName()); } } /** * Returns true if the first MP3 frame can be found for the MP3 file *

    * This is the first byte of music data and not the ID3 Tag Frame. * * * @param seekFile MP3 file to seek * @param startByte if there is an ID3v2tag we dont want to start reading from the start of the tag * @return true if the first MP3 frame can be found * @throws IOException on any I/O error * @noinspection NestedTryStatement */ public boolean seek(final File seekFile, long startByte) throws IOException { //This is substantially faster than updating the filechannels position long filePointerCount; final FileInputStream fis = new FileInputStream(seekFile); final FileChannel fc = fis.getChannel(); //Read into Byte Buffer in Chunks ByteBuffer bb = ByteBuffer.allocateDirect(FILE_BUFFER_SIZE); //Move FileChannel to the starting position (skipping over tag if any) fc.position(startByte); //Update filePointerCount filePointerCount = startByte; //Read from here into the byte buffer , doesn't move location of filepointer fc.read(bb, startByte); bb.flip(); boolean syncFound = false; try { do { //TODO remaining() is quite an expensive operation, isn't there a way we can work this out without //interrogating the bytebuffer. Also this is rarely going to be true, and could be made less true //by increasing FILE_BUFFER_SIZE if (bb.remaining() <= MIN_BUFFER_REMAINING_REQUIRED) { bb.clear(); fc.position(filePointerCount); fc.read(bb, fc.position()); bb.flip(); if (bb.limit() <= MIN_BUFFER_REMAINING_REQUIRED) { //No mp3 exists return false; } } //MP3File.logger.finest("fc:"+fc.position() + "bb"+bb.position()); if (MPEGFrameHeader.isMPEGFrame(bb)) { try { if (MP3AudioHeader.logger.isLoggable(Level.FINEST)) { MP3AudioHeader.logger.finest("Found Possible header at:" + filePointerCount); } mp3FrameHeader = MPEGFrameHeader.parseMPEGHeader(bb); syncFound = true; //if(2==1) use this line when you want to test getting the next frame without using xing if (XingFrame.isXingFrame(bb, mp3FrameHeader)) { if (MP3AudioHeader.logger.isLoggable(Level.FINEST)) { MP3AudioHeader.logger.finest("Found Possible XingHeader"); } try { //Parses Xing frame without modifying position of main buffer mp3XingFrame = XingFrame.parseXingFrame(); } catch (InvalidAudioFrameException ex) { // We Ignore because even if Xing Header is corrupted //doesn't mean file is corrupted } break; } else if (VbriFrame.isVbriFrame(bb, mp3FrameHeader)) { if (MP3AudioHeader.logger.isLoggable(Level.FINEST)) { MP3AudioHeader.logger.finest("Found Possible VbriHeader"); } try { //Parses Vbri frame without modifying position of main buffer mp3VbriFrame = VbriFrame.parseVBRIFrame(); } catch (InvalidAudioFrameException ex) { // We Ignore because even if Vbri Header is corrupted //doesn't mean file is corrupted } break; } // There is a small but real chance that an unsynchronised ID3 Frame could fool the MPEG // Parser into thinking it was an MPEG Header. If this happens the chances of the next bytes // forming a Xing frame header are very remote. On the basis that most files these days have // Xing headers we do an additional check for when an apparent frame header has been found // but is not followed by a Xing Header:We check the next header this wont impose a large // overhead because wont apply to most Mpegs anyway ( Most likely to occur if audio // has an APIC frame which should have been unsynchronised but has not been) , or if the frame // has been encoded with as Unicode LE because these have a BOM of 0xFF 0xFE else { syncFound = isNextFrameValid(seekFile, filePointerCount, bb, fc); if (syncFound) { break; } } } catch (InvalidAudioFrameException ex) { // We Ignore because likely to be incorrect sync bits , // will just continue in loop } } //TODO position() is quite an expensive operation, isn't there a way we can work this out without //interrogating the bytebuffer bb.position(bb.position() + 1); filePointerCount++; } while (!syncFound); } catch (EOFException ex) { MP3AudioHeader.logger.log(Level.WARNING, "Reached end of file without finding sync match", ex); syncFound = false; } catch (IOException iox) { MP3AudioHeader.logger.log(Level.SEVERE, "IOException occurred whilst trying to find sync", iox); syncFound = false; throw iox; } finally { if (fc != null) { fc.close(); } if (fis != null) { fis.close(); } } //Return to start of audio header if (MP3AudioHeader.logger.isLoggable(Level.FINEST)) { MP3AudioHeader.logger.finer("Return found matching mp3 header starting at" + filePointerCount); } setFileSize(seekFile.length()); setMp3StartByte(filePointerCount); setTimePerFrame(); setNumberOfFrames(); setTrackLength(); setBitRate(); setEncoder(); /*if((filePointerCount - startByte )>0) { logger.severe(seekFile.getName()+"length:"+startByte+"Difference:"+(filePointerCount - startByte)); } */ return syncFound; } /** * Called in some circumstances to check the next frame to ensure we have the correct audio header * * @param seekFile * @param filePointerCount * @param bb * @param fc * @return true if frame is valid * @throws java.io.IOException */ private boolean isNextFrameValid(File seekFile, long filePointerCount, ByteBuffer bb, FileChannel fc) throws IOException { if (MP3AudioHeader.logger.isLoggable(Level.FINEST)) { MP3AudioHeader.logger.finer("Checking next frame" + seekFile.getName() + ":fpc:" + filePointerCount + "skipping to:" + (filePointerCount + mp3FrameHeader.getFrameLength())); } boolean result = false; int currentPosition = bb.position(); //Our buffer is not large enough to fit in the whole of this frame, something must //have gone wrong because frames are not this large, so just return false //bad frame header if (mp3FrameHeader.getFrameLength() > (FILE_BUFFER_SIZE - MIN_BUFFER_REMAINING_REQUIRED)) { MP3AudioHeader.logger.finer("Frame size is too large to be a frame:" + mp3FrameHeader.getFrameLength()); return false; } //Check for end of buffer if not enough room get some more if (bb.remaining() <= MIN_BUFFER_REMAINING_REQUIRED + mp3FrameHeader.getFrameLength()) { MP3AudioHeader.logger.finer("Buffer too small, need to reload, buffer size:" + bb.remaining()); bb.clear(); fc.position(filePointerCount); fc.read(bb, fc.position()); bb.flip(); //So now original buffer has been replaced, so set current position to start of buffer currentPosition = 0; //Not enough left if (bb.limit() <= MIN_BUFFER_REMAINING_REQUIRED) { //No mp3 exists MP3AudioHeader.logger.finer("Nearly at end of file, no header found:"); return false; } //Still Not enough left for next alleged frame size so giving up if (bb.limit() <= MIN_BUFFER_REMAINING_REQUIRED + mp3FrameHeader.getFrameLength()) { //No mp3 exists MP3AudioHeader.logger.finer("Nearly at end of file, no room for next frame, no header found:"); return false; } } //Position bb to the start of the alleged next frame bb.position(bb.position() + mp3FrameHeader.getFrameLength()); if (MPEGFrameHeader.isMPEGFrame(bb)) { try { MPEGFrameHeader.parseMPEGHeader(bb); MP3AudioHeader.logger.finer("Check next frame confirms is an audio header "); result = true; } catch (InvalidAudioFrameException ex) { MP3AudioHeader.logger.finer("Check next frame has identified this is not an audio header"); result = false; } } else { MP3AudioHeader.logger.finer("isMPEGFrame has identified this is not an audio header"); } //Set back to the start of the previous frame bb.position(currentPosition); return result; } /** * Set the location of where the Audio file begins in the file * * @param startByte */ protected void setMp3StartByte(final long startByte) { this.startByte = startByte; } /** * Returns the byte position of the first MP3 Frame that the * file arguement refers to. This is the first byte of music * data and not the ID3 Tag Frame. * * @return the byte position of the first MP3 Frame */ public long getMp3StartByte() { return startByte; } /** * Set number of frames in this file, use Xing if exists otherwise ((File Size - Non Audio Part)/Frame Size) */ protected void setNumberOfFrames() { numberOfFramesEstimate = (fileSize - startByte) / mp3FrameHeader.getFrameLength(); if (mp3XingFrame != null && mp3XingFrame.isFrameCountEnabled()) { numberOfFrames = mp3XingFrame.getFrameCount(); } else if (mp3VbriFrame != null) { numberOfFrames = mp3VbriFrame.getFrameCount(); } else { numberOfFrames = numberOfFramesEstimate; } } /** * @return The number of frames within the Audio File, calculated as accurrately as possible */ public long getNumberOfFrames() { return numberOfFrames; } /** * @return The number of frames within the Audio File, calculated by dividing the filesize by * the number of frames, this may not be the most accurate method available. */ public long getNumberOfFramesEstimate() { return numberOfFramesEstimate; } /** * Set the time each frame contributes to the audio in fractions of seconds, the higher * the sampling rate the shorter the audio segment provided by the frame, * the number of samples is fixed by the MPEG Version and Layer */ protected void setTimePerFrame() { timePerFrame = mp3FrameHeader.getNoOfSamples() / mp3FrameHeader.getSamplingRate().doubleValue(); //Because when calculating framelength we may have altered the calculation slightly for MPEGVersion2 //to account for mono/stero we seem to have to make a corresponding modification to get the correct time if ((mp3FrameHeader.getVersion() == MPEGFrameHeader.VERSION_2) || (mp3FrameHeader.getVersion() == MPEGFrameHeader.VERSION_2_5)) { if ((mp3FrameHeader.getLayer() == MPEGFrameHeader.LAYER_II) || (mp3FrameHeader.getLayer() == MPEGFrameHeader.LAYER_III)) { if (mp3FrameHeader.getNumberOfChannels() == 1) { timePerFrame = timePerFrame / 2; } } } } /** * @return the the time each frame contributes to the audio in fractions of seconds */ private double getTimePerFrame() { return timePerFrame; } /** * Estimate the length of the audio track in seconds * Calculation is Number of frames multiplied by the Time Per Frame using the first frame as a prototype * Time Per Frame is the number of samples in the frame (which is defined by the MPEGVersion/Layer combination) * divided by the sampling rate, i.e the higher the sampling rate the shorter the audio represented by the frame is going * to be. */ protected void setTrackLength() { trackLength = numberOfFrames * getTimePerFrame(); } /** * @return Track Length in seconds */ public double getPreciseTrackLength() { return trackLength; } public int getTrackLength() { return (int) getPreciseTrackLength(); } /** * Return the length in user friendly format * @return */ public String getTrackLengthAsString() { final Date timeIn; try { final long lengthInSecs = getTrackLength(); synchronized(timeInFormat) { timeIn = timeInFormat.parse(String.valueOf(lengthInSecs)); } if (lengthInSecs < NO_SECONDS_IN_HOUR) { synchronized(timeOutFormat) { return timeOutFormat.format(timeIn); } } else { synchronized(timeOutOverAnHourFormat) { return timeOutOverAnHourFormat.format(timeIn); } } } catch (ParseException pe) { logger.warning("Unable to parse:"+getPreciseTrackLength() +" failed with ParseException:"+pe.getMessage()); return ""; } } /** * @return the audio file type */ public String getEncodingType() { return TYPE_MP3; } /** * Set bitrate in kbps, if Vbr use Xingheader if possible */ protected void setBitRate() { if (mp3XingFrame != null && mp3XingFrame.isVbr()) { if (mp3XingFrame.isAudioSizeEnabled() && mp3XingFrame.getAudioSize() > 0) { bitrate = (long) ((mp3XingFrame.getAudioSize() * CONVERTS_BYTE_TO_BITS) / (timePerFrame * getNumberOfFrames() * CONVERT_TO_KILOBITS)); } else { bitrate = (long) (((fileSize - startByte) * CONVERTS_BYTE_TO_BITS) / (timePerFrame * getNumberOfFrames() * CONVERT_TO_KILOBITS)); } } else if (mp3VbriFrame != null) { if (mp3VbriFrame.getAudioSize() > 0) { bitrate = (long) ((mp3VbriFrame.getAudioSize() * CONVERTS_BYTE_TO_BITS) / (timePerFrame * getNumberOfFrames() * CONVERT_TO_KILOBITS)); } else { bitrate = (long) (((fileSize - startByte) * CONVERTS_BYTE_TO_BITS) / (timePerFrame * getNumberOfFrames() * CONVERT_TO_KILOBITS)); } } else { bitrate = mp3FrameHeader.getBitRate(); } } protected void setEncoder() { if (mp3XingFrame != null) { if (mp3XingFrame.getLameFrame() != null) { encoder = mp3XingFrame.getLameFrame().getEncoder(); } } else if (mp3VbriFrame != null) { encoder = mp3VbriFrame.getEncoder(); } } /** * @return bitrate in kbps, no indicator is provided as to whether or not it is vbr */ public long getBitRateAsNumber() { return bitrate; } /** * @return the BitRate of the Audio, to distinguish cbr from vbr we add a '~' * for vbr. */ public String getBitRate() { if (mp3XingFrame != null && mp3XingFrame.isVbr()) { return isVbrIdentifier + String.valueOf(bitrate); } else if (mp3VbriFrame != null) { return isVbrIdentifier + String.valueOf(bitrate); } else { return String.valueOf(bitrate); } } /** * @return the sampling rate in Hz */ public int getSampleRateAsNumber() { return mp3FrameHeader.getSamplingRate(); } /** * @return the sampling rate as string */ public String getSampleRate() { return String.valueOf(mp3FrameHeader.getSamplingRate()); } /** * @return MPEG Version (1-3) */ public String getMpegVersion() { return mp3FrameHeader.getVersionAsString(); } /** * @return MPEG Layer (1-3) */ public String getMpegLayer() { return mp3FrameHeader.getLayerAsString(); } /** * @return the format of the audio (i.e. MPEG-1 Layer3) */ public String getFormat() { return mp3FrameHeader.getVersionAsString() + " " + mp3FrameHeader.getLayerAsString(); } /** * @return the Channel Mode such as Stero or Mono */ public String getChannels() { return mp3FrameHeader.getChannelModeAsString(); } /** * @return Emphasis */ public String getEmphasis() { return mp3FrameHeader.getEmphasisAsString(); } /** * @return if the bitrate is variable, Xing header takes precedence if we have one */ public boolean isVariableBitRate() { if (mp3XingFrame != null) { return mp3XingFrame.isVbr(); } else if (mp3VbriFrame != null) { return mp3VbriFrame.isVbr(); } else { return mp3FrameHeader.isVariableBitRate(); } } public boolean isProtected() { return mp3FrameHeader.isProtected(); } public boolean isPrivate() { return mp3FrameHeader.isPrivate(); } public boolean isCopyrighted() { return mp3FrameHeader.isCopyrighted(); } public boolean isOriginal() { return mp3FrameHeader.isOriginal(); } public boolean isPadding() { return mp3FrameHeader.isPadding(); } /** * @return encoder */ public String getEncoder() { return encoder; } /** * Set the size of the file, required in some calculations * * @param fileSize */ protected void setFileSize(long fileSize) { this.fileSize = fileSize; } /** * @return a string represntation */ public String toString() { String s = "fileSize:" + fileSize + " encoder:" + encoder + " startByte:" + Hex.asHex(startByte) + " numberOfFrames:" + numberOfFrames + " numberOfFramesEst:" + numberOfFramesEstimate + " timePerFrame:" + timePerFrame + " bitrate:" + bitrate + " trackLength:" + getTrackLengthAsString(); if (this.mp3FrameHeader != null) { s += mp3FrameHeader.toString(); } if (this.mp3XingFrame != null) { s += mp3XingFrame.toString(); } return s; } }libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/mp3/LameFrame.java0000644000175000017500000000531111277006322026002 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2003-2005 Raphaël Slinckx * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.audio.mp3; import org.jaudiotagger.audio.generic.Utils; import org.jaudiotagger.tag.id3.valuepair.TextEncoding; import java.nio.ByteBuffer; /** * The first frame can sometimes contain a LAME frame at the end of the Xing frame *

    *

    This useful to the library because it allows the encoder to be identified, full specification * can be found at http://gabriel.mp3-tech.org/mp3infotag.html *

    * Summarized here: * 4 bytes:LAME * 5 bytes:LAME Encoder Version * 1 bytes:VNR Method * 1 bytes:Lowpass filter value * 8 bytes:Replay Gain * 1 byte:Encoding Flags * 1 byte:minimal byte rate * 3 bytes:extra samples * 1 byte:Stereo Mode * 1 byte:MP3 Gain * 2 bytes:Surround Dound * 4 bytes:MusicLength * 2 bytes:Music CRC * 2 bytes:CRC Tag */ public class LameFrame { public static final int LAME_HEADER_BUFFER_SIZE = 36; public static final int ENCODER_SIZE = 9; //Includes LAME ID public static final int LAME_ID_SIZE = 4; public static final String LAME_ID = "LAME"; private String encoder; /** * Initilise a Lame Mpeg Frame * @param lameHeader */ private LameFrame(ByteBuffer lameHeader) { encoder = Utils.getString(lameHeader, 0, ENCODER_SIZE, TextEncoding.CHARSET_ISO_8859_1); } /** * Parse frame * * @param bb * @return frame or null if not exists */ public static LameFrame parseLameFrame(ByteBuffer bb) { ByteBuffer lameHeader = bb.slice(); String id = Utils.getString(lameHeader, 0, LAME_ID_SIZE, TextEncoding.CHARSET_ISO_8859_1); lameHeader.rewind(); if (id.equals(LAME_ID)) { LameFrame lameFrame = new LameFrame(lameHeader); return lameFrame; } return null; } /** * @return encoder */ public String getEncoder() { return encoder; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/mp3/MP3FileReader.java0000644000175000017500000000403511277026507026504 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.mp3; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.exceptions.CannotReadException; import org.jaudiotagger.audio.exceptions.InvalidAudioFrameException; import org.jaudiotagger.audio.exceptions.ReadOnlyFileException; import org.jaudiotagger.audio.generic.AudioFileReader; import org.jaudiotagger.audio.generic.GenericAudioHeader; import org.jaudiotagger.tag.Tag; import org.jaudiotagger.tag.TagException; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; /** * Read Mp3 Info (retrofitted to entagged ,done differently to entagged which is why some methods throw RuntimeException) * because done elsewhere */ public class MP3FileReader extends AudioFileReader { protected GenericAudioHeader getEncodingInfo(RandomAccessFile raf) throws CannotReadException, IOException { throw new RuntimeException("MP3FileReader.getEncodingInfo should be called"); } protected Tag getTag(RandomAccessFile raf) throws CannotReadException, IOException { throw new RuntimeException("MP3FileReader.getEncodingInfo should be called"); } /** * @param f * @return */ //Override because we read mp3s differently to the entagged code public AudioFile read(File f) throws IOException, TagException, ReadOnlyFileException, InvalidAudioFrameException { MP3File mp3File = new MP3File(f, MP3File.LOAD_IDV1TAG | MP3File.LOAD_IDV2TAG, true); return mp3File; } /** * Read * * @param f * @return * @throws ReadOnlyFileException thrown if the file is not writable * @throws org.jaudiotagger.tag.TagException * @throws java.io.IOException * @throws org.jaudiotagger.audio.exceptions.InvalidAudioFrameException */ public AudioFile readMustBeWritable(File f) throws IOException, TagException, ReadOnlyFileException, InvalidAudioFrameException { MP3File mp3File = new MP3File(f, MP3File.LOAD_IDV1TAG | MP3File.LOAD_IDV2TAG, false); return mp3File; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/AudioFileFilter.java0000644000175000017500000000477511277026507026505 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2003-2005 Raphaël Slinckx * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.audio; import org.jaudiotagger.audio.generic.Utils; import java.io.FileFilter; import java.io.File; /** *

    This is a simple FileFilter that will only allow the file supported by this library.

    *

    It will also accept directories. An additional condition is that file must be readable (read permission) and * are not hidden (dot files, or hidden files)

    * * @author Raphael Slinckx * @version $Id: AudioFileFilter.java 836 2009-11-12 15:44:07Z paultaylor $ * @since v0.01 */ public class AudioFileFilter implements FileFilter { /** * allows Directories */ private final boolean allowDirectories; public AudioFileFilter( boolean allowDirectories) { this.allowDirectories=allowDirectories; } public AudioFileFilter() { this(true); } /** *

    Check whether the given file meet the required conditions (supported by the library OR directory). * The File must also be readable and not hidden.

    * * @param f The file to test * @return a boolean indicating if the file is accepted or not */ public boolean accept(File f) { if (f.isHidden() || !f.canRead()) { return false; } if (f.isDirectory()) { return allowDirectories; } String ext = Utils.getExtension(f); try { if (SupportedFileFormat.valueOf(ext.toUpperCase()) != null) { return true; } } catch(IllegalArgumentException iae) { //Not known enum value return false; } return false; } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/exceptions/0000755000175000017500000000000011556363171025000 5ustar drazzibdrazziblibjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/exceptions/ReadOnlyFileException.java0000644000175000017500000000317410656115113032033 0ustar drazzibdrazzib/** * @author : Paul Taylor * @author : Eric Farng * * Version @version:$Id: ReadOnlyFileException.java 345 2007-08-07 16:14:03Z paultaylor $ * * MusicTag Copyright (C)2003,2004 * * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ package org.jaudiotagger.audio.exceptions; /** * This is the exception when try and access a read only file */ public class ReadOnlyFileException extends Exception { /** * Creates a new ReadOnlyException datatype. */ public ReadOnlyFileException() { } public ReadOnlyFileException(Throwable ex) { super(ex); } /** * Creates a new ReadOnlyException datatype. * * @param msg the detail message. */ public ReadOnlyFileException(String msg) { super(msg); } public ReadOnlyFileException(String msg, Throwable ex) { super(msg, ex); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/exceptions/InvalidBoxHeaderException.java0000644000175000017500000000043311111512505032652 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.exceptions; /** * Thrown if when trying to read box id the length doesn't make any sense */ public class InvalidBoxHeaderException extends RuntimeException { public InvalidBoxHeaderException(String message) { super(message); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/exceptions/CannotReadVideoException.java0000644000175000017500000000155211107562470032525 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.exceptions; /** * This exception should be thrown idf it appears the file is a video file, jaudiotagger only supports audio * files. */ public class CannotReadVideoException extends CannotReadException { /** * Creates an instance. */ public CannotReadVideoException() { super(); } public CannotReadVideoException(Throwable ex) { super(ex); } /** * Creates an instance. * * @param message The message. */ public CannotReadVideoException(String message) { super(message); } /** * Creates an instance. * * @param message The error message. * @param cause The throwable causing this exception. */ public CannotReadVideoException(String message, Throwable cause) { super(message, cause); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/exceptions/UnableToModifyFileException.java0000644000175000017500000000064711107070540033175 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.exceptions; import java.io.IOException; /** * Should be thrown when unable to modify a file when it is expected it should bemodifiable. For example because * you dont have permission to modify files in the folder that it is in. */ public class UnableToModifyFileException extends IOException { public UnableToModifyFileException(String message) { super(message); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/exceptions/CannotReadException.java0000644000175000017500000000325311247705415031541 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2003-2005 Raphaël Slinckx * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.audio.exceptions; /** * This exception is thrown if an audio file cannot be read.
    * Causes may be invalid data or IO errors. * * @author Raphaël Slinckx */ public class CannotReadException extends Exception { /** * Creates an instance. */ public CannotReadException() { super(); } public CannotReadException(Throwable ex) { super(ex); } /** * Creates an instance. * * @param message The message. */ public CannotReadException(String message) { super(message); } /** * Creates an instance. * * @param message The error message. * @param cause The throwable causing this exception. */ public CannotReadException(String message, Throwable cause) { super(message, cause); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/exceptions/NullBoxIdException.java0000644000175000017500000000047311111013054031341 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.exceptions; /** * Thrown if when trying to read box id just finds nulls * Normally an error, but if occurs at end of file we allow it */ public class NullBoxIdException extends RuntimeException { public NullBoxIdException(String message) { super(message); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/exceptions/UnableToRenameFileException.java0000644000175000017500000000065311107102572033153 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.exceptions; import java.io.IOException; /** * Should be thrown when unable to rename a file when it is expected it should rename. For example could occur on Vista * because you do not have Special Permission 'Delete' set to Denied. */ public class UnableToRenameFileException extends IOException { public UnableToRenameFileException(String message) { super(message); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/exceptions/InvalidAudioFrameException.java0000644000175000017500000000076210656115113033041 0ustar drazzibdrazzib/** * @author : Paul Taylor *

    * Version @version:$Id: InvalidAudioFrameException.java 345 2007-08-07 16:14:03Z paultaylor $ * Date :${DATE} *

    * Jaikoz Copyright Copyright (C) 2003 -2005 JThink Ltd */ package org.jaudiotagger.audio.exceptions; /** * Thrown if portion of file thought to be an AudioFrame is found to not be. */ public class InvalidAudioFrameException extends Exception { public InvalidAudioFrameException(String message) { super(message); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/exceptions/ModifyVetoException.java0000644000175000017500000000410411277006322031576 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2003-2005 Christian Laireiter * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.audio.exceptions; /** * This exception is thrown if a * {@link org.jaudiotagger.audio.generic.AudioFileModificationListener} wants to * prevent the "e;entagged audio library"e; from actually finishing its * operation.
    * This exception can be used in all methods but * {@link org.jaudiotagger.audio.generic.AudioFileModificationListener#fileOperationFinished(java.io.File)}. * * @author Christian Laireiter */ public class ModifyVetoException extends Exception { /** * (overridden) */ public ModifyVetoException() { super(); } /** * (overridden) * * @param message * @see Exception#Exception(java.lang.String) */ public ModifyVetoException(String message) { super(message); } /** * (overridden) * * @param message * @param cause * @see Exception#Exception(java.lang.String,java.lang.Throwable) */ public ModifyVetoException(String message, Throwable cause) { super(message, cause); } /** * (overridden) * * @param cause * @see Exception#Exception(java.lang.Throwable) */ public ModifyVetoException(Throwable cause) { super(cause); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/exceptions/CannotWriteException.java0000644000175000017500000000351511277006322031753 0ustar drazzibdrazzib/* * Entagged Audio Tag library * Copyright (c) 2003-2005 Raphaël Slinckx * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jaudiotagger.audio.exceptions; /** * This exception is thrown if the writing process of an audio file failed. * * @author Rapha�l Slinckx */ public class CannotWriteException extends Exception { /** * (overridden) * * @see Exception#Exception() */ public CannotWriteException() { super(); } /** * (overridden) * * @param message * @see Exception#Exception(java.lang.String) */ public CannotWriteException(String message) { super(message); } /** * (overridden) * * @param message * @param cause * @see Exception#Exception(java.lang.String,java.lang.Throwable) */ public CannotWriteException(String message, Throwable cause) { super(message, cause); } /** * (overridden) * * @param cause * @see Exception#Exception(java.lang.Throwable) */ public CannotWriteException(Throwable cause) { super(cause); } } libjaudiotagger-java-2.0.3/src/org/jaudiotagger/audio/exceptions/UnableToCreateFileException.java0000644000175000017500000000064011107070540033142 0ustar drazzibdrazzibpackage org.jaudiotagger.audio.exceptions; import java.io.IOException; /** * Should be thrown when unable to create a file when it is expected it should be creatable. For example because * you dont have permission to write to the folder that it is in. */ public class UnableToCreateFileException extends IOException { public UnableToCreateFileException(String message) { super(message); } } libjaudiotagger-java-2.0.3/jaudiotagger.iml0000644000175000017500000000373311470746136020652 0ustar drazzibdrazzib libjaudiotagger-java-2.0.3/jaudiotagger-LICENSE.txt0000644000175000017500000006346710411571403021765 0ustar drazzibdrazzibGNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it!libjaudiotagger-java-2.0.3/testtagdata/0000755000175000017500000000000011556363206017777 5ustar drazzibdrazziblibjaudiotagger-java-2.0.3/ExtractTag.bat0000644000175000017500000000016110512154462020217 0ustar drazzibdrazzibset classpath=%classpath%;.\classes;\dist\jaudiotagger.jar java org.jaudiotagger.test.ExtractID3TagFromFile %1 %2