ID3v24Tagpublic class ID3v24Tag extends AbstractID3v2Tag Represents an ID3v2.4 tag. |
Fields Summary |
---|
protected static final String | TYPE_FOOTER | protected static final String | TYPE_IMAGEENCODINGRESTRICTION | protected static final String | TYPE_IMAGESIZERESTRICTION | protected static final String | TYPE_TAGRESTRICTION | protected static final String | TYPE_TAGSIZERESTRICTION | protected static final String | TYPE_TEXTENCODINGRESTRICTION | protected static final String | TYPE_TEXTFIELDSIZERESTRICTION | protected static final String | TYPE_UPDATETAG | protected static final String | TYPE_CRCDATA | protected static final String | TYPE_EXPERIMENTAL | protected static final String | TYPE_EXTENDED | protected static final String | TYPE_PADDINGSIZE | protected static final String | TYPE_UNSYNCHRONISATION | protected static int | TAG_EXT_HEADER_LENGTH | protected static int | TAG_EXT_HEADER_UPDATE_LENGTH | protected static int | TAG_EXT_HEADER_CRC_LENGTH | protected static int | TAG_EXT_HEADER_RESTRICTION_LENGTH | protected static int | TAG_EXT_HEADER_CRC_DATA_LENGTH | protected static int | TAG_EXT_HEADER_RESTRICTION_DATA_LENGTH | protected static int | TAG_EXT_NUMBER_BYTES_DATA_LENGTH | public static final int | MASK_V24_UNSYNCHRONIZATIONID3v2.4 Header bit mask | public static final int | MASK_V24_EXTENDED_HEADERID3v2.4 Header bit mask | public static final int | MASK_V24_EXPERIMENTALID3v2.4 Header bit mask | public static final int | MASK_V24_FOOTER_PRESENTID3v2.4 Header bit mask | public static final int | MASK_V24_TAG_UPDATEID3v2.4 Extended header bit mask | public static final int | MASK_V24_CRC_DATA_PRESENTID3v2.4 Extended header bit mask | public static final int | MASK_V24_TAG_RESTRICTIONSID3v2.4 Extended header bit mask | public static final int | MASK_V24_TAG_SIZE_RESTRICTIONSID3v2.4 Extended header bit mask | public static final int | MASK_V24_TEXT_ENCODING_RESTRICTIONSID3v2.4 Extended header bit mask | public static final int | MASK_V24_TEXT_FIELD_SIZE_RESTRICTIONSID3v2.4 Extended header bit mask | public static final int | MASK_V24_IMAGE_ENCODINGID3v2.4 Extended header bit mask | public static final int | MASK_V24_IMAGE_SIZE_RESTRICTIONSID3v2.4 Extended header bit mask | public static final int | MASK_V24_TAG_ALTER_PRESERVATIONID3v2.4 Header Footer bit mask | public static final int | MASK_V24_FILE_ALTER_PRESERVATIONID3v2.4 Header Footer bit mask | public static final int | MASK_V24_READ_ONLYID3v2.4 Header Footer bit mask | public static final int | MASK_V24_GROUPING_IDENTITYID3v2.4 Header Footer bit mask | public static final int | MASK_V24_COMPRESSIONID3v2.4 Header Footer bit mask | public static final int | MASK_V24_ENCRYPTIONID3v2.4 Header Footer bit mask | public static final int | MASK_V24_FRAME_UNSYNCHRONIZATIONID3v2.4 Header Footer bit mask | public static final int | MASK_V24_DATA_LENGTH_INDICATORID3v2.4 Header Footer bit mask | protected boolean | crcDataFlagCRC Checksum calculated | protected boolean | experimentalExperiemntal tag | protected boolean | extendedContains extended header | protected boolean | unsynchronizationAll frames in the tag uses unsynchronisation | protected int | crcDataCRC Checksum | protected boolean | footerContains a footer | protected boolean | updateTagTag is an update | protected boolean | tagRestrictionTag has restrictions | protected byte | imageEncodingRestrictionIf Set Image encoding restrictions
0 No restrictions
1 Images are encoded only with PNG [PNG] or JPEG [JFIF]. | protected byte | imageSizeRestrictionIf 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 | tagSizeRestrictionIf 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 | textEncodingRestrictionIf 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 int | paddingSizeTag padding | protected byte | textFieldSizeRestrictionIf 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. | public static final byte | RELEASE | public static final byte | MAJOR_VERSION | public static final byte | REVISION |
Constructors Summary |
---|
public ID3v24Tag(ByteBuffer buffer, String loggingFilename)Creates a new ID3v2_4 datatype.
frameMap = new LinkedHashMap();
encryptedFrameMap = new LinkedHashMap();
setLoggingFilename(loggingFilename);
this.read(buffer);
| public ID3v24Tag(ByteBuffer buffer)Creates a new ID3v2_4 datatype.
this(buffer, "");
| public ID3v24Tag()Creates a new empty ID3v2_4 datatype.
frameMap = new LinkedHashMap();
encryptedFrameMap = new LinkedHashMap();
| public ID3v24Tag(ID3v24Tag copyObject)Copy Constructor, creates a new ID3v2_4 Tag based on another ID3v2_4 Tag
logger.config("Creating tag from another tag of same type");
copyPrimitives(copyObject);
copyFrames(copyObject);
| public ID3v24Tag(AbstractTag mp3tag)Creates a new ID3v2_4 datatype based on another (non 2.4) tag
logger.config("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<Lyrics3v2Field> 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");
}
}
}
}
|
Methods Summary |
---|
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());
}
| protected void | copyFrameIntoMap(java.lang.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 OR it might be that we have two v23 frames that map to TDRC such as TYER,TIME or TDAT
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.getYear());
}
else if (newBody.getOriginalID().equals(ID3v23Frames.FRAME_ID_V3_TDAT))
{
body.setDate(newBody.getDate());
body.setMonthOnly(newBody.isMonthOnly());
}
else if (newBody.getOriginalID().equals(ID3v23Frames.FRAME_ID_V3_TIME))
{
body.setTime(newBody.getTime());
body.setHoursOnly(newBody.isHoursOnly());
}
body.setObjectValue(DataTypes.OBJ_TEXT,body.getFormattedText());
}
// 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<AbstractID3v2Frame> list = new ArrayList<AbstractID3v2Frame>();
list.add(firstFrame);
list.add(newFrame);
frameMap.put(newFrame.getIdentifier(), list);
}
}
else
{
List<AbstractID3v2Frame> list = (List)o;
list.add(newFrame);
}
}
else
{
frameMap.put(newFrame.getIdentifier(), newFrame);
}
| protected void | copyPrimitives(AbstractID3v2Tag copyObj)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
logger.config("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;
}
| public TagField | createArtworkField(byte[] data, java.lang.String mimeType)Create Artwork
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 TagField | createField(ID3v24FieldKey id3Key, java.lang.String 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.
if (id3Key == null)
{
throw new KeyNotFoundException();
}
return super.doCreateTagField(new FrameAndSubId(id3Key.getFrameId(), id3Key.getSubId()), value);
| public TagField | createField(org.jaudiotagger.tag.images.Artwork artwork)
AbstractID3v2Frame frame = createFrame(getFrameAndSubIdFromGenericKey(FieldKey.COVER_ART).getFrameId());
FrameBodyAPIC body = (FrameBodyAPIC) frame.getBody();
if(!artwork.isLinked())
{
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;
}
else
{
try
{
body.setObjectValue(DataTypes.OBJ_PICTURE_DATA,artwork.getImageUrl().getBytes("ISO-8859-1"));
}
catch(UnsupportedEncodingException uoe)
{
throw new RuntimeException(uoe.getMessage());
}
body.setObjectValue(DataTypes.OBJ_PICTURE_TYPE, artwork.getPictureType());
body.setObjectValue(DataTypes.OBJ_MIME_TYPE, FrameBodyAPIC.IMAGE_IS_URL);
body.setObjectValue(DataTypes.OBJ_DESCRIPTION, "");
return frame;
}
| public ID3v24Frame | createFrame(java.lang.String id)Create a new frame with the specified frameid
return new ID3v24Frame(id);
| public void | createStructure()Display the tag in an XMLFormat
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);
| public void | deleteField(ID3v24FieldKey id3v24FieldKey)Delete fields with this id3v24FieldKey
if (id3v24FieldKey == null)
{
throw new KeyNotFoundException();
}
super.doDeleteTagField(new FrameAndSubId(id3v24FieldKey.getFrameId(), id3v24FieldKey.getSubId()));
| public void | deleteField(java.lang.String id)Delete fields with this (frame) id
super.doDeleteTagField(new FrameAndSubId(id,null));
| public boolean | equals(java.lang.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);
| public java.util.List | getArtworkList()
List<TagField> coverartList = getFields(FieldKey.COVER_ART);
List<Artwork> artworkList = new ArrayList<Artwork>(coverartList.size());
for (TagField next : coverartList)
{
FrameBodyAPIC coverArt = (FrameBodyAPIC) ((AbstractID3v2Frame) next).getBody();
Artwork artwork = ArtworkFactory.getNew();
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 java.lang.String | getFirst(ID3v24FieldKey id3v24FieldKey)Retrieve the first value that exists for this id3v24key
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);
}
| 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();
| public java.lang.String | getIdentifier()
return "ID3v2.40";
| public byte | getMajorVersion()Retrieve the Major Version
return MAJOR_VERSION;
| public java.util.Comparator | getPreferredFrameOrderComparator()
return ID3v24PreferredFrameOrderComparator.getInstanceof();
| public byte | getRelease()Retrieve the Release
return RELEASE;
| public byte | getRevision()Retrieve the Revision
return REVISION;
| public int | getSize()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.
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;
| public boolean | isUnsynchronization()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 unsynchronization;
| public void | read(java.nio.ByteBuffer byteBuffer){@inheritDoc}
int size;
byte[] buffer;
if (!seek(byteBuffer))
{
throw new TagNotFoundException(getLoggingFilename() + ":" + getIdentifier() + " tag not found");
}
logger.config(getLoggingFilename() + ":" + "Reading ID3v24 tag");
readHeaderFlags(byteBuffer);
// Read the size, this is size of tag apart from tag header
size = ID3SyncSafeInteger.bufferToValue(byteBuffer);
logger.config(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);
| private void | readExtendedHeader(java.nio.ByteBuffer byteBuffer, int size)Read the optional extended header
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);
}
| protected void | readFrames(java.nio.ByteBuffer byteBuffer, int size)Read frames from tag
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.config(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;
}
}
| private void | readHeaderFlags(java.nio.ByteBuffer byteBuffer)Read header flags
Log info messages for falgs that have been set and log warnings when bits have been set for unknown flags
//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.config(ErrorMessage.ID3_TAG_UNSYNCHRONIZED.getMsg(getLoggingFilename()));
}
if (extended)
{
logger.config(ErrorMessage.ID3_TAG_EXTENDED.getMsg(getLoggingFilename()));
}
if (experimental)
{
logger.config(ErrorMessage.ID3_TAG_EXPERIMENTAL.getMsg(getLoggingFilename()));
}
if (footer)
{
logger.warning(ErrorMessage.ID3_TAG_FOOTER.getMsg(getLoggingFilename()));
}
| public void | write(java.io.File file, long audioStartLocation){@inheritDoc}
setLoggingFilename(file.getName());
logger.config("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);
| public void | write(java.nio.channels.WritableByteChannel channel){@inheritDoc}
logger.config("Writing tag to channel");
byte[] bodyByteBuffer = writeFramesToBuffer().toByteArray();
ByteBuffer headerBuffer = writeHeaderToBuffer(0, bodyByteBuffer.length);
channel.write(headerBuffer);
channel.write(ByteBuffer.wrap(bodyByteBuffer));
| private java.nio.ByteBuffer | writeHeaderToBuffer(int padding, int size)Write the ID3 header to the ByteBuffer.
TODO Calculate the CYC Data Check
TODO Reintroduce Extended Header
//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;
|
|