/* * Copyright (C) 2011 in-somnia * * This file is part of JAAD. * * JAAD is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 3 of the * License, or (at your option) any later version. * * JAAD is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General * Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. * If not, see <http://www.gnu.org/licenses/>. */ package net.sourceforge.jaad.mp4.api; import java.io.DataInputStream; import java.io.IOException; import java.nio.charset.Charset; import java.text.ParsePosition; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale; class ID3Frame { static final int ALBUM_TITLE = 1413565506; //TALB static final int ALBUM_SORT_ORDER = 1414745921; //TSOA static final int ARTIST = 1414546737; //TPE1 static final int ATTACHED_PICTURE = 1095780675; //APIC static final int AUDIO_ENCRYPTION = 1095061059; //AENC static final int AUDIO_SEEK_POINT_INDEX = 1095979081; //ASPI static final int BAND = 1414546738; //TPE2 static final int BEATS_PER_MINUTE = 1413632077; //TBPM static final int COMMENTS = 1129270605; //COMM static final int COMMERCIAL_FRAME = 1129270610; //COMR static final int COMMERCIAL_INFORMATION = 1464029005; //WCOM static final int COMPOSER = 1413697357; //TCOM static final int CONDUCTOR = 1414546739; //TPE3 static final int CONTENT_GROUP_DESCRIPTION = 1414091825; //TIT1 static final int CONTENT_TYPE = 1413697358; //TCON static final int COPYRIGHT = 1464029008; //WCOP static final int COPYRIGHT_MESSAGE = 1413697360; //TCOP static final int ENCODED_BY = 1413828163; //TENC static final int ENCODING_TIME = 1413760334; //TDEN static final int ENCRYPTION_METHOD_REGISTRATION = 1162756946; //ENCR static final int EQUALISATION = 1162958130; //EQU2 static final int EVENT_TIMING_CODES = 1163150159; //ETCO static final int FILE_OWNER = 1414485838; //TOWN static final int FILE_TYPE = 1413893204; //TFLT static final int GENERAL_ENCAPSULATED_OBJECT = 1195724610; //GEOB static final int GROUP_IDENTIFICATION_REGISTRATION = 1196575044; //GRID static final int INITIAL_KEY = 1414219097; //TKEY static final int INTERNET_RADIO_STATION_NAME = 1414681422; //TRSN static final int INTERNET_RADIO_STATION_OWNER = 1414681423; //TRSO static final int MODIFIED_BY = 1414546740; //TPE4 static final int INVOLVED_PEOPLE_LIST = 1414090828; //TIPL static final int INTERNATIONAL_STANDARD_RECORDING_CODE = 1414746691; //TSRC static final int LANGUAGES = 1414283598; //TLAN static final int LENGTH = 1414284622; //TLEN static final int LINKED_INFORMATION = 1279872587; //LINK static final int LYRICIST = 1413830740; //TEXT static final int MEDIA_TYPE = 1414350148; //TMED static final int MOOD = 1414352719; //TMOO static final int MPEG_LOCATION_LOOKUP_TABLE = 1296845908; //MLLT static final int MUSICIAN_CREDITS_LIST = 1414349644; //TMCL static final int MUSIC_CD_IDENTIFIER = 1296254025; //MCDI static final int OFFICIAL_ARTIST_WEBPAGE = 1464811858; //WOAR static final int OFFICIAL_AUDIO_FILE_WEBPAGE = 1464811846; //WOAF static final int OFFICIAL_AUDIO_SOURCE_WEBPAGE = 1464811859; //WOAS static final int OFFICIAL_INTERNET_RADIO_STATION_HOMEPAGE = 1464816211; //WORS static final int ORIGINAL_ALBUM_TITLE = 1414480204; //TOAL static final int ORIGINAL_ARTIST = 1414484037; //TOPE static final int ORIGINAL_FILENAME = 1414481486; //TOFN static final int ORIGINAL_LYRICIST = 1414483033; //TOLY static final int ORIGINAL_RELEASE_TIME = 1413762898; //TDOR static final int OWNERSHIP_FRAME = 1331121733; //OWNE static final int PART_OF_A_SET = 1414549331; //TPOS static final int PAYMENT = 1464877401; //WPAY static final int PERFORMER_SORT_ORDER = 1414745936; //TSOP static final int PLAYLIST_DELAY = 1413762137; //TDLY static final int PLAY_COUNTER = 1346588244; //PCNT static final int POPULARIMETER = 1347375181; //POPM static final int POSITION_SYNCHRONISATION_FRAME = 1347375955; //POSS static final int PRIVATE_FRAME = 1347570006; //PRIV static final int PRODUCED_NOTICE = 1414550095; //TPRO static final int PUBLISHER = 1414550850; //TPUB static final int PUBLISHERS_OFFICIAL_WEBPAGE = 1464882498; //WPUB static final int RECOMMENDED_BUFFER_SIZE = 1380078918; //RBUF static final int RECORDING_TIME = 1413763651; //TDRC static final int RELATIVE_VOLUME_ADJUSTMENT = 1381384498; //RVA2 static final int RELEASE_TIME = 1413763660; //TDRL static final int REVERB = 1381388866; //RVRB static final int SEEK_FRAME = 1397048651; //SEEK static final int SET_SUBTITLE = 1414746964; //TSST static final int SIGNATURE_FRAME = 1397311310; //SIGN static final int ENCODING_TOOLS_AND_SETTINGS = 1414746949; //TSSE static final int SUBTITLE = 1414091827; //TIT3 static final int SYNCHRONISED_LYRIC = 1398361172; //SYLT static final int SYNCHRONISED_TEMPO_CODES = 1398363203; //SYTC static final int TAGGING_TIME = 1413764167; //TDTG static final int TERMS_OF_USE = 1431520594; //USER static final int TITLE = 1414091826; //TIT2 static final int TITLE_SORT_ORDER = 1414745940; //TSOT static final int TRACK_NUMBER = 1414677323; //TRCK static final int UNIQUE_FILE_IDENTIFIER = 1430669636; //UFID static final int UNSYNCHRONISED_LYRIC = 1431522388; //USLT static final int USER_DEFINED_TEXT_INFORMATION_FRAME = 1415075928; //TXXX static final int USER_DEFINED_URL_LINK_FRAME = 1465407576; //WXXX private static final String[] TEXT_ENCODINGS = {"ISO-8859-1", "UTF-16"/*BOM*/, "UTF-16", "UTF-8"}; private static final String[] VALID_TIMESTAMPS = {"yyyy, yyyy-MM", "yyyy-MM-dd", "yyyy-MM-ddTHH", "yyyy-MM-ddTHH:mm", "yyyy-MM-ddTHH:mm:ss"}; private static final String UNKNOWN_LANGUAGE = "xxx"; private long size; private int id, flags, groupID, encryptionMethod; private byte[] data; ID3Frame(DataInputStream in) throws IOException { id = in.readInt(); size = ID3Tag.readSynch(in); flags = in.readShort(); if(isInGroup()) groupID = in.read(); if(isEncrypted()) encryptionMethod = in.read(); //TODO: data length indicator, unsync data = new byte[(int) size]; in.readFully(data); } //header data public int getID() { return id; } public long getSize() { return size; } public final boolean isInGroup() { return (flags&0x40)==0x40; } public int getGroupID() { return groupID; } public final boolean isCompressed() { return (flags&8)==8; } public final boolean isEncrypted() { return (flags&4)==4; } public int getEncryptionMethod() { return encryptionMethod; } //content data public byte[] getData() { return data; } public String getText() { return new String(data, Charset.forName(TEXT_ENCODINGS[0])); } public String getEncodedText() { //first byte indicates encoding final int enc = data[0]; //charsets 0,3 end with '0'; 1,2 end with '00' int t = -1; for(int i = 1; i<data.length&&t<0; i++) { if(data[i]==0&&(enc==0||enc==3||data[i+1]==0)) t = i; } return new String(data, 1, t-1, Charset.forName(TEXT_ENCODINGS[enc])); } public int getNumber() { return Integer.parseInt(new String(data)); } public int[] getNumbers() { //multiple numbers separated by '/' final String x = new String(data, Charset.forName(TEXT_ENCODINGS[0])); final int i = x.indexOf('/'); final int[] y; if(i>0) y = new int[]{Integer.parseInt(x.substring(0, i)), Integer.parseInt(x.substring(i+1))}; else y = new int[]{Integer.parseInt(x)}; return y; } public Date getDate() { //timestamp lengths: 4,7,10,13,16,19 final int i = (int) Math.floor(data.length/3)-1; final Date date; if(i>=0&&i<VALID_TIMESTAMPS.length) { final SimpleDateFormat sdf = new SimpleDateFormat(VALID_TIMESTAMPS[i]); date = sdf.parse(new String(data), new ParsePosition(0)); } else date = null; return date; } public Locale getLocale() { final String s = new String(data).toLowerCase(); final Locale l; if(s.equals(UNKNOWN_LANGUAGE)) l = null; else l = new Locale(s); return l; } }