📄 id3v23tag.java
字号:
logger.warning(getLoggingFilename()+":"+"ID3v23 Tag is extended");
}
if(experimental)
{
logger.warning(getLoggingFilename()+":"+"ID3v23 Tag is experimental");
}
// Read the size, this is size of tag not including the tag header
size = ID3SyncSafeInteger.bufferToValue(buffer);
logger.info(getLoggingFilename()+":Tag size is:"+size+" according to header (does not include header size, add 10)");
//Extended Header
if (extended == true)
{
// Int is 4 bytes.
int extendedHeaderSize = buffer.getInt();
// Extended header without CRC Data
if (extendedHeaderSize == TAG_EXT_HEADER_DATA_LENGTH)
{
//Flag
byte extFlag = buffer.get();
crcDataFlag = (extFlag & MASK_V23_CRC_DATA_PRESENT) != 0;
if (crcDataFlag == true)
{
throw new InvalidTagException(getLoggingFilename()+":CRC Data flag not set correctly.");
}
//Flag Byte (not used)
buffer.get();
//Take padding and ext header size off size to be read
size = size - (buffer.getInt() + TAG_EXT_HEADER_LENGTH);
}
else if (extendedHeaderSize == TAG_EXT_HEADER_DATA_LENGTH + TAG_EXT_HEADER_CRC_LENGTH)
{
//Flag
byte extFlag = buffer.get();
crcDataFlag = (extFlag & MASK_V23_CRC_DATA_PRESENT) != 0;
if (crcDataFlag == false)
{
throw new InvalidTagException(getLoggingFilename()+":CRC Data flag not set correctly.");
}
//Flag Byte (not used)
buffer.get();
//Take padding size of size to be read
size = size - (buffer.getInt() + TAG_EXT_HEADER_LENGTH + TAG_EXT_HEADER_CRC_LENGTH);
//CRC Data
crcData = buffer.getInt();
}
else
{
throw new InvalidTagException("Invalid Extended Header Size.");
}
logger.info(getLoggingFilename()+":has Extended Header so adjusted Tag size is:"+size);
}
//Slice Buffer, so position markers tally with size (i.e do not include tagheader)
ByteBuffer bufferWithoutHeader = buffer.slice();
//We need to synchronize the buffer
if(isUnsynchronization() ==true)
{
bufferWithoutHeader=ID3Unsynchronization.synchronize(bufferWithoutHeader);
}
readFrames(bufferWithoutHeader,size);
logger.info(getLoggingFilename()+":Loaded Frames,there are:" + frameMap.keySet().size());
}
/**
* Read the frames
*
* Read from byteBuffer upto size
*
* @param byteBuffer
* @param size
*/
protected void readFrames(ByteBuffer byteBuffer, int size)
{
//Now start looking for frames
ID3v23Frame next;
frameMap = new LinkedHashMap();
//Read the size from the Tag Header
this.fileReadSize = size;
logger.finest(getLoggingFilename()+":Start of frame body at:" + byteBuffer.position() + ",frames data size is:" + size);
// Read the frames until got to upto the size as specified in header or until
// we hit an invalid frame identifier
while (byteBuffer.position()<size)
{
String id;
try
{
//Read Frame
logger.finest(getLoggingFilename()+":Looking for next frame at:" + byteBuffer.position());
next = new ID3v23Frame(byteBuffer,getLoggingFilename());
id = next.getIdentifier();
loadFrameIntoMap(id, next);
}
//Found Empty Frame
catch (EmptyFrameException ex)
{
logger.warning(getLoggingFilename()+":Empty Frame:"+ex.getMessage());
this.emptyFrameBytes += ID3v23Frame.FRAME_HEADER_SIZE;
}
catch ( InvalidFrameIdentifierException ifie)
{
logger.info(getLoggingFilename()+":Invalid Frame Identifier:"+ifie.getMessage());
this.invalidFrameBytes++;
//Dont try and find any more frames
break;
}
//Problem trying to find frame, often just occurs because frameheader includes padding
//and we have reached padding
catch (InvalidFrameException ife)
{
logger.warning(getLoggingFilename()+":Invalid Frame:"+ife.getMessage());
this.invalidFrameBytes++;
//Dont try and find any more frames
break;
}
;
}
}
/**
* Write the ID3 header to the ByteBuffer.
*
* TODO Calculate the CYC Data Check
* TODO Reintroduce Extended Header
*
* @param padding is the size of the padding portion of the tag
* @param size is the size of the body data
*
* @return ByteBuffer
* @throws IOException
*/
private ByteBuffer writeHeaderToBuffer(int padding,int size) throws IOException
{
// 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;
crcDataFlag = false;
// Create Header Buffer,allocate maximum possible size for the header
ByteBuffer headerBuffer = ByteBuffer.
allocate(TAG_HEADER_LENGTH + TAG_EXT_HEADER_LENGTH + TAG_EXT_HEADER_CRC_LENGTH);
//TAGID
headerBuffer.put(TAG_ID);
//Major Version
headerBuffer.put(getMajorVersion());
//Minor Version
headerBuffer.put(getRevision());
//Flags
byte flagsByte = 0;
if (isUnsynchronization() == true)
{
flagsByte |= MASK_V23_UNSYNCHRONIZATION;
}
if (extended == true)
{
flagsByte |= MASK_V23_EXTENDED_HEADER;
}
if (experimental == true)
{
flagsByte |= MASK_V23_EXPERIMENTAL;
}
headerBuffer.put(flagsByte);
//Additional Header Size,(for completeness we never actually write the extended header)
int additionalHeaderSize =0;
if (extended)
{
additionalHeaderSize += this.TAG_EXT_HEADER_LENGTH;
if (crcDataFlag)
{
additionalHeaderSize += this.TAG_EXT_HEADER_CRC_LENGTH;
}
}
//Size As Recorded in Header, don't include the main header length
headerBuffer.put(ID3SyncSafeInteger.valueToBuffer(padding + size + additionalHeaderSize));
//Write Extended Header
if (extended == true)
{
byte extFlagsByte1 = 0;
byte extFlagsByte2 = 0;
//Contains CRCData
if (crcDataFlag == true)
{
headerBuffer.putInt(TAG_EXT_HEADER_DATA_LENGTH + TAG_EXT_HEADER_CRC_LENGTH);
extFlagsByte1 |= MASK_V23_CRC_DATA_PRESENT;
headerBuffer.put(extFlagsByte1);
headerBuffer.put(extFlagsByte2);
headerBuffer.putInt(paddingSize);
headerBuffer.putInt(crcData);
}
//Just extended Header
else
{
headerBuffer.putInt(TAG_EXT_HEADER_DATA_LENGTH);
headerBuffer.put(extFlagsByte1);
headerBuffer.put(extFlagsByte2);
//Newly Calculated Padding As Recorded in Extended Header
headerBuffer.putInt(padding);
}
}
headerBuffer.flip();
return headerBuffer;
}
/**
* Write tag to file
*
* TODO:we currently never write the Extended header , but if we did the size calculation in this
* method would be slightly incorrect
*
* @param file The file to write to
* @throws IOException
*/
public void write(File file, long audioStartLocation)
throws IOException
{
logger.info(getLoggingFilename()+":Writing tag to file");
//Write Body Buffer
byte[] bodyByteBuffer = writeFramesToBuffer().toByteArray();
logger.info(getLoggingFilename()+":bodybytebuffer:sizebeforeunsynchronisation:"+bodyByteBuffer.length);
// Unsynchronize if option enabled and unsync required
if(TagOptionSingleton.getInstance().isUnsyncTags())
{
unsynchronization = ID3Unsynchronization.requiresUnsynchronization(bodyByteBuffer);
}
else
{
unsynchronization=false;
}
if(isUnsynchronization())
{
bodyByteBuffer=ID3Unsynchronization.unsynchronize(bodyByteBuffer);
logger.info(getLoggingFilename()+":bodybytebuffer:sizeafterunsynchronisation:"+bodyByteBuffer.length);
}
int sizeIncPadding = calculateTagSize(bodyByteBuffer.length + TAG_HEADER_LENGTH, (int) audioStartLocation);
int padding = sizeIncPadding - (bodyByteBuffer.length + TAG_HEADER_LENGTH) ;
logger.info(getLoggingFilename()+":Current audiostart:"+audioStartLocation);
logger.info(getLoggingFilename()+":Size including padding:"+sizeIncPadding);
logger.info(getLoggingFilename()+":Padding:"+padding);
ByteBuffer headerBuffer = writeHeaderToBuffer(padding,bodyByteBuffer.length);
//We need to adjust location of audio File
if (sizeIncPadding > audioStartLocation)
{
logger.info(getLoggingFilename()+":Adjusting Padding");
adjustPadding(file, sizeIncPadding, audioStartLocation);
}
//Write changes to file
FileChannel fc = null;
try
{
fc = new RandomAccessFile(file, "rw").getChannel();
fc.write(headerBuffer);
fc.write(ByteBuffer.wrap(bodyByteBuffer));
fc.write(ByteBuffer.wrap(new byte[padding]));
}
finally
{
if(fc!=null)
{
fc.close();
}
}
}
/**
* Write tag to channel
*
* @param channel
* @throws IOException
*/
public void write(WritableByteChannel channel)
throws IOException
{
logger.info(getLoggingFilename()+":Writing tag to channel");
byte[] bodyByteBuffer = writeFramesToBuffer().toByteArray();
logger.info(getLoggingFilename()+":bodybytebuffer:sizebeforeunsynchronisation:"+bodyByteBuffer.length);
// Unsynchronize if option enabled and unsync required
if(TagOptionSingleton.getInstance().isUnsyncTags())
{
unsynchronization = ID3Unsynchronization.requiresUnsynchronization(bodyByteBuffer);
}
else
{
unsynchronization=false;
}
if(isUnsynchronization())
{
bodyByteBuffer=ID3Unsynchronization.unsynchronize(bodyByteBuffer);
logger.info(getLoggingFilename()+":bodybytebuffer:sizeafterunsynchronisation:"+bodyByteBuffer.length);
}
ByteBuffer headerBuffer = writeHeaderToBuffer(0,bodyByteBuffer.length);
channel.write(headerBuffer);
channel.write(ByteBuffer.wrap(bodyByteBuffer));
}
/**
* For representing the MP3File in an XML Format
*
*/
public void createStructure()
{
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_EXTENDED, this.extended);
MP3File.getStructureFormatter().addElement(TYPE_EXPERIMENTAL, this.experimental);
MP3File.getStructureFormatter().addElement(TYPE_CRCDATA, this.crcData);
MP3File.getStructureFormatter().addElement(TYPE_PADDINGSIZE, this.paddingSize);
MP3File.getStructureFormatter().closeHeadingElement(TYPE_HEADER);
//Body
super.createStructureBody();
MP3File.getStructureFormatter().closeHeadingElement(TYPE_TAG);
}
/**
*
* @return is tag unsynchronized
*/
public boolean isUnsynchronization()
{
return unsynchronization;
}
protected String getArtistId()
{
return ID3v23Frames.FRAME_ID_V3_ARTIST;
}
protected String getAlbumId()
{
return ID3v23Frames.FRAME_ID_V3_ALBUM;
}
protected String getTitleId()
{
return ID3v23Frames.FRAME_ID_V3_TITLE;
}
protected String getTrackId()
{
return ID3v23Frames.FRAME_ID_V3_TRACK;
}
protected String getYearId()
{
return ID3v23Frames.FRAME_ID_V3_TYER;
}
protected String getCommentId()
{
return ID3v23Frames.FRAME_ID_V3_COMMENT;
}
protected String getGenreId()
{
return ID3v23Frames.FRAME_ID_V3_GENRE;
}
public ID3v23Frame createFrame(String id)
{
return new ID3v23Frame(id);
}
/**
* Create Frame for Id3 Key
* <p/>
* Only textual data supported at the moment, should only be used with frames that
* support a simple string argument.
*
* @param id3Key
* @param value
* @return
* @throws KeyNotFoundException
* @throws FieldDataInvalidException
*/
public TagField createTagField(ID3v23FieldKey id3Key, String value)
throws KeyNotFoundException, FieldDataInvalidException
{
if (id3Key == null)
{
throw new KeyNotFoundException();
}
return super.doCreateTagField(new FrameAndSubId(id3Key.getFrameId(),id3Key.getSubId()),value);
}
/**
* Retrieve the first value that exists for this id3v23key
*
* @param id3v23FieldKey
* @return
*/
public String getFirst(ID3v23FieldKey id3v23FieldKey) throws KeyNotFoundException
{
if (id3v23FieldKey == null)
{
throw new KeyNotFoundException();
}
return super.doGetFirst(new FrameAndSubId(id3v23FieldKey.getFrameId(),id3v23FieldKey.getSubId()));
}
/**
* Delete fields with this id3v23FieldKey
*
* @param id3v23FieldKey
*/
public void deleteTagField
(ID3v23FieldKey
id3v23FieldKey) throws KeyNotFoundException
{
if (id3v23FieldKey == null)
{
throw new KeyNotFoundException();
}
super.doDeleteTagField(new FrameAndSubId(id3v23FieldKey.getFrameId(),id3v23FieldKey.getSubId()));
}
protected FrameAndSubId getFrameAndSubIdFromGenericKey(TagFieldKey genericKey)
{
ID3v23FieldKey id3v23FieldKey = ID3v23Frames.getInstanceOf().getId3KeyFromGenericKey(genericKey);
if (id3v23FieldKey == null)
{
throw new KeyNotFoundException();
}
return new FrameAndSubId(id3v23FieldKey.getFrameId(),id3v23FieldKey.getSubId());
}
protected ID3Frames getID3Frames()
{
return ID3v23Frames.getInstanceOf();
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -