📄 id3v24frame.java
字号:
*
* @return int frame size
*/
public int getSize()
{
return frameBody.getSize() + ID3v24Frame.FRAME_HEADER_SIZE;
}
/**
* 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
{
byte[] buffer = new byte[FRAME_ID_SIZE];
if (byteBuffer.position() + FRAME_HEADER_SIZE >= 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, FRAME_ID_SIZE);
identifier = new String(buffer);
logger.fine(getLoggingFilename()+":"+"Identifier is" + identifier);
//Is this a valid identifier?
if (isValidID3v2FrameIdentifier(identifier) == false)
{
//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() - (FRAME_ID_SIZE - 1));
throw new InvalidFrameIdentifierException(identifier + " is not a valid ID3v2.40 frame");
}
//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);
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");
}
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 - FRAME_ID_SIZE);
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 - FRAME_ID_SIZE);
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() - - FRAME_FLAGS_SIZE))
{
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[FRAME_ID_SIZE];
byteBuffer.position(currentPosition + frameSize + FRAME_FLAGS_SIZE);
if(byteBuffer.remaining()<FRAME_ID_SIZE)
{
//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, FRAME_ID_SIZE);
//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
}
//havent 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() - FRAME_FLAGS_SIZE)
{
//invalid so assume syncsafe
byteBuffer.position(currentPosition);
}
else
{
readAheadbuffer = new byte[FRAME_ID_SIZE];
byteBuffer.position(currentPosition + nonSyncSafeFrameSize + FRAME_FLAGS_SIZE);
if(byteBuffer.remaining() >= FRAME_ID_SIZE)
{
byteBuffer.get(readAheadbuffer, 0, FRAME_ID_SIZE);
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 didnt hit padding when using syncsafe integer
//or we wouldnt have got to this point. So assume syncsafe ineteger 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 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;
boolean isDataLengthindicatorRead = false;
if(((EncodingFlags)encodingFlags).isGrouping())
{
extraHeaderBytesCount = ID3v24Frame.FRAME_GROUPING_INDICATOR_SIZE;
byteBuffer.get();
}
if(((EncodingFlags)encodingFlags).isCompression())
{
//Read the sync safe size field
int datalengthSize = ID3SyncSafeInteger.bufferToValue(byteBuffer);
logger.info(getLoggingFilename()+":"+"Frame Size Is:"+ frameSize + "Data Length Size:"+datalengthSize);
extraHeaderBytesCount += ID3v24Frame.FRAME_DATA_LENGTH_SIZE;
isDataLengthindicatorRead=true;
}
if(((EncodingFlags)encodingFlags).isEncryption())
{
//Read the Encryption byte, but do nothing with it
extraHeaderBytesCount += ID3v24Frame.FRAME_ENCRYPTION_INDICATOR_SIZE;
byteBuffer.get();
}
if(((EncodingFlags)encodingFlags).isDataLengthIndicator())
{
//There is only data length indicator it may have already been read depending on what flags
//are set
if(!isDataLengthindicatorRead)
{
//Read the sync safe size field
int datalengthSize = ID3SyncSafeInteger.bufferToValue(byteBuffer);
//Read the Grouping byte, but do nothing with it
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 upto the end of this frame (remember this
//buffer contains the remainder of this tag not just this frame), and we cant 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
{
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();
if(TagOptionSingleton.getInstance().isUnsyncTags())
{
unsynchronization = ID3Unsynchronization.requiresUnsynchronization(bodyBuffer);
}
else
{
unsynchronization=false;
}
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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -