ID3v23Framepublic class ID3v23Frame extends AbstractID3v2Frame Represents an ID3v2.3 frame. |
Fields Summary |
---|
private static Pattern | validFrameIdentifier | protected static final int | FRAME_ID_SIZE | protected static final int | FRAME_FLAGS_SIZE | protected static final int | FRAME_SIZE_SIZE | protected static final int | FRAME_COMPRESSION_UNCOMPRESSED_SIZE | protected static final int | FRAME_ENCRYPTION_INDICATOR_SIZE | protected static final int | FRAME_GROUPING_INDICATOR_SIZE | protected static final int | FRAME_HEADER_SIZE | private int | encryptionMethodIf the frame is encrypted then the encryption method is stored in this byte | private int | groupIdentifierIf the frame belongs in a group with other frames then the group identifier byte is stored |
Constructors Summary |
---|
public ID3v23Frame()Creates a new ID3v23 Frame
| public ID3v23Frame(String identifier)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.
super(identifier);
statusFlags = new StatusFlags();
encodingFlags = new EncodingFlags();
| public ID3v23Frame(ID3v23Frame frame)Copy Constructor
Creates a new v23 frame based on another v23 frame
super(frame);
statusFlags = new StatusFlags(frame.getStatusFlags().getOriginalFlags());
encodingFlags = new EncodingFlags(frame.getEncodingFlags().getFlags());
| public ID3v23Frame(AbstractID3v2Frame frame)Creates a new ID3v23Frame based on another frame of a different version.
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.config("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.config("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.config("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.config("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.config("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.config("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.config("UNKNOWN:Orig id is:" + frame.getIdentifier() + ":New id is:" + identifier);
return;
}
}
logger.warning("Frame is unknown version:"+frame.getClass());
| public ID3v23Frame(ByteBuffer byteBuffer, String loggingFilename)Creates a new ID3v23Frame dataType by reading from byteBuffer.
setLoggingFilename(loggingFilename);
read(byteBuffer);
| public ID3v23Frame(ByteBuffer byteBuffer)Creates a new ID3v23Frame dataType by reading from byteBuffer.
this(byteBuffer, "");
|
Methods Summary |
---|
public void | createStructure()Return String Representation of body
MP3File.getStructureFormatter().openHeadingElement(TYPE_FRAME, getIdentifier());
MP3File.getStructureFormatter().addElement(TYPE_FRAME_SIZE, frameSize);
statusFlags.createStructure();
encodingFlags.createStructure();
frameBody.createStructure();
MP3File.getStructureFormatter().closeHeadingElement(TYPE_FRAME);
| public boolean | equals(java.lang.Object obj)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
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);
| public AbstractID3v2Frame.EncodingFlags | getEncodingFlags()
return encodingFlags;
| public int | getEncryptionMethod()
return encryptionMethod;
| protected int | getFrameHeaderSize()
return FRAME_HEADER_SIZE;
| protected int | getFrameIdSize()
return FRAME_ID_SIZE;
| protected int | getFrameSizeSize()
return FRAME_SIZE_SIZE;
| public int | getGroupIdentifier()
return groupIdentifier;
| public int | getSize()Return size of frame
return frameBody.getSize() + ID3v23Frame.FRAME_HEADER_SIZE;
| public AbstractID3v2Frame.StatusFlags | getStatusFlags()
return statusFlags;
| public boolean | isBinary()
return ID3v23Frames.getInstanceOf().isBinary(getId());
| public boolean | isCommon()
return ID3v23Frames.getInstanceOf().isCommon(getId());
| public boolean | isValidID3v2FrameIdentifier(java.lang.String identifier)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
Matcher m = ID3v23Frame.validFrameIdentifier.matcher(identifier);
return m.matches();
| public void | read(java.nio.ByteBuffer byteBuffer)Read the frame from a byteBuffer
String identifier = readIdentifier(byteBuffer);
if (!isValidID3v2FrameIdentifier(identifier))
{
logger.config(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.config(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);
}
| public void | setEncoding(java.lang.String encoding)Sets the charset encoding used by the field.
Integer encodingId = TextEncoding.getInstanceOf().getIdForValue(encoding);
if(encoding!=null)
{
if(encodingId <2)
{
this.getBody().setTextEncoding(encodingId.byteValue());
}
}
| public void | write(java.io.ByteArrayOutputStream tagBuffer)Write the frame to bufferOutputStream
logger.config("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);
}
|
|