📄 id3v23frame.java
字号:
//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 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())
{
//Read the Encryption byte, but do nothing with it
extraHeaderBytesCount += FRAME_ENCRYPTION_INDICATOR_SIZE;
byteBuffer.get();
}
if(((EncodingFlags)encodingFlags).isGrouping())
{
//Read the Grouping byte, but do nothing with it
extraHeaderBytesCount += FRAME_GROUPING_INDICATOR_SIZE;
byteBuffer.get();
}
//Work out the real size of the framebody data
int realFrameSize = frameSize - extraHeaderBytesCount;
ByteBuffer frameBodyBuffer=null;
//Uncompress the frame
if(((EncodingFlags)encodingFlags).isCompression())
{
// 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
{
decompresser.inflate(result);
}
catch(DataFormatException dfe)
{
dfe.printStackTrace();
//Update position of main buffer, so no attempt is made to reread these bytes
byteBuffer.position(byteBuffer.position()+realFrameSize);
throw new InvalidFrameException(getLoggingFilename()+"Unable to decompress this frame:"+identifier+":"+dfe.getMessage());
}
decompresser.end();
frameBodyBuffer = ByteBuffer.wrap(result);
}
//Read the body data
try
{
if(((EncodingFlags)encodingFlags).isCompression())
{
frameBody = readBody(id,frameBodyBuffer, decompressedFrameSize);
}
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, shouldnt
//it then be created as FrameBodyUnsupported
if(!(frameBody instanceof ID3v23FrameBody))
{
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 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());
//Enclosing Flags, first reset
encodingFlags.resetFlags();
//Encoding we dont support any of flags so don't set any
headerBuffer.put(encodingFlags.getFlags());
try
{
//Add header to the Byte Array Output Stream
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);
}
}
protected AbstractID3v2Frame.StatusFlags getStatusFlags()
{
return statusFlags;
}
protected AbstractID3v2Frame.EncodingFlags getEncodingFlags()
{
return encodingFlags;
}
/**
* 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
*/
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) == true)
{
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 logEnabledFlags()
{
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 = 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());
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -