📄 id3v2extendedheader.java
字号:
/**
* Copyright (C) 2001 Jonathan Hilliker
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Description:
* If the id3v2 tag has an extended header, this class will read/write the
* information contained within it. NOTE: this class is untested and has
* no mutators. In other words, this class will only be used if an mp3
* already has an extended header (at this point at least).
*
* @author: Jonathan Hilliker
* @version: $Id: ID3v2ExtendedHeader.java,v 1.2 2001/10/19 03:57:53 helliker Exp $
* Revsisions:
* $Log: ID3v2ExtendedHeader.java,v $
* Revision 1.2 2001/10/19 03:57:53 helliker
* All set for release.
*
*
*/
package helliker.id3;
import java.io.*;
public class ID3v2ExtendedHeader {
private final int EXT_HEAD_LOCATION = 10;
private final int MIN_SIZE = 6;
private final int CRC_SIZE = 5;
private final int[] MAX_TAG_FRAMES_TABLE = { 128, 64, 32, 32 };
private final int[] MAX_TAG_SIZE_TABLE = {8000000, 1024000, 320000, 32000};
private final int[] MAX_TEXT_SIZE_TABLE = { -1, 1024, 128, 30 };
private File mp3 = null;
private int size;
private int numFlagBytes;
private boolean update;
private boolean crced;
private byte[] crc;
private int maxFrames;
private int maxTagSize;
private boolean textEncode;
private int maxTextSize;
private boolean imageEncode;
private int imageRestrict;
/**
* Create an extended header object from the file passed. Information
* in the file's extended header will be read and stored.
*
* @param mp3 the file to read/write to
* @exception FileNotFoundException if an error occurs
* @exception IOException if an error occurs
* @exception ID3v2FormatException if an error occurs
*/
public ID3v2ExtendedHeader( File mp3 )
throws FileNotFoundException, IOException, ID3v2FormatException {
this.mp3 = mp3;
size = 0;
numFlagBytes = 0;
update = false;
crced = false;
crc = new byte[CRC_SIZE];
maxFrames = -1;
maxTagSize = -1;
textEncode = false;
maxTextSize = -1;
imageEncode = false;
imageRestrict = -1;
readExtendedHeader();
}
/**
* Read the information in the file's extended header
*
* @exception FileNotFoundException if an error occurs
* @exception IOException if an error occurs
* @exception ID3v2FormatException if an error occurs
*/
private void readExtendedHeader()
throws FileNotFoundException, IOException, ID3v2FormatException {
RandomAccessFile raf = new RandomAccessFile( mp3, "r" );
raf.seek( EXT_HEAD_LOCATION );
byte[] buf = new byte[4];
if( raf.read( buf ) != buf.length ) {
throw new IOException("Error reading extended header:size");
}
size = BinaryParser.convertToInt( buf );
if( size < MIN_SIZE ) {
throw new ID3v2FormatException( "The extended header size data" +
" is less than the minimum required size.");
}
buf = new byte[1];
if( raf.read( buf ) != buf.length ) {
throw new IOException("Error reading extended header:numflags");
}
numFlagBytes = (int)buf[0];
buf = new byte[numFlagBytes+1];
if( raf.read( buf ) != buf.length ) {
throw new IOException( "Error reading extended header:flags" );
}
parseFlags( buf );
raf.close();
}
/**
* Parse the extended header flag bytes
*
* @param flags the array of extended flags
* @exception ID3v2FormatException if an error occurs
*/
private void parseFlags( byte[] flags ) throws ID3v2FormatException {
int bytesRead = 1;
if( BinaryParser.bitSet( flags[0], 6 ) ) {
update = true;
bytesRead += 1;
}
if( BinaryParser.bitSet( flags[0], 5 ) ) {
crced = true;
bytesRead += 1;
for( int i = 0; i < crc.length; i++ ) {
crc[i] = flags[bytesRead++];
}
}
if( BinaryParser.bitSet( flags[0], 4 ) ) {
bytesRead += 1;
maxTagSize = BinaryParser.convertToDecimal(
flags[bytesRead], 6, 7 );
textEncode = BinaryParser.bitSet( flags[bytesRead], 5 );
maxTextSize = BinaryParser.convertToDecimal(
flags[bytesRead], 3, 4 );
imageEncode = BinaryParser.bitSet( flags[bytesRead], 2 );
imageRestrict = BinaryParser.convertToDecimal(
flags[bytesRead], 0, 1 );
bytesRead += 1;
}
if( bytesRead != numFlagBytes ) {
throw new ID3v2FormatException("The number of found flag bytes " +
"in the extended header is not " +
"equal to the number specified " +
"in the extended header." );
}
}
/**
* Return an array of bytes representing this extended header in the
* standard format to be written to a file.
*
* @return a binary represenation of this extended header
*/
public byte[] getBytes() {
byte[] b = new byte[size];
int bytesCopied = 0;
System.arraycopy( BinaryParser.convertToBytes(size), 0, b,
bytesCopied, 4 );
bytesCopied += 4;
b[bytesCopied++] = (byte)numFlagBytes;
System.arraycopy( getFlagBytes(), 0, b, bytesCopied, numFlagBytes );
bytesCopied += numFlagBytes;
return b;
}
/**
* A helper function for the getBytes method that returns a byte array
* representing the extended flags field of the extended header.
*
* @return the extended flags field of the extended header
*/
private byte[] getFlagBytes() {
byte[] b = new byte[numFlagBytes];
int bytesCopied = 1;
b[0] = 0;
if( update ) {
b[0] = BinaryParser.setBit( b[0], 7 );
b[bytesCopied++] = 0;
}
if( crced ) {
b[0] = BinaryParser.setBit( b[0], 6 );
b[bytesCopied++] = (byte)crc.length;
System.arraycopy( crc, 0, b, bytesCopied, crc.length );
bytesCopied += crc.length;
}
if( (maxTagSize != -1) || textEncode || (maxTextSize != -1) ||
imageEncode || (imageRestrict != -1) ) {
b[0] = BinaryParser.setBit( b[0], 5 );
b[bytesCopied++] = 0x01;
byte restrict = 0;
if( maxTagSize != -1 ) {
if( BinaryParser.bitSet( (byte)maxTagSize, 0 ) ) {
restrict = BinaryParser.setBit( restrict, 6 );
}
if( BinaryParser.bitSet( (byte)maxTagSize, 1 ) ) {
restrict = BinaryParser.setBit( restrict, 7 );
}
}
if( textEncode ) {
restrict = BinaryParser.setBit( restrict, 5 );
}
if( maxTextSize != -1 ) {
if( BinaryParser.bitSet( (byte)maxTextSize, 0 ) ) {
restrict = BinaryParser.setBit( restrict, 3 );
}
if( BinaryParser.bitSet( (byte)maxTextSize, 1 ) ) {
restrict = BinaryParser.setBit( restrict, 4 );
}
}
if( imageEncode ) {
restrict = BinaryParser.setBit( restrict, 2 );
}
if( imageRestrict != -1 ) {
if( BinaryParser.bitSet( (byte)imageRestrict, 0 ) ) {
restrict = BinaryParser.setBit( restrict, 0 );
}
if( BinaryParser.bitSet( (byte)imageRestrict, 1 ) ) {
restrict = BinaryParser.setBit( restrict, 1 );
}
}
b[bytesCopied++] = restrict;
}
return b;
}
/**
* Returns the size of the extended header
*
* @return the size of the extended header
*/
public int getSize() {
return size;
}
/**
* Returns the number of extended flag bytes
*
* @return the number of extended flag bytes
*/
public int getNumFlagBytes() {
return numFlagBytes;
}
/**
* Returns the maximum number of frames if set. If unset, returns -1
*
* @return the maximum number of frames or -1 if unset
*/
public int getMaxFrames() {
int retval = -1;
if( (maxTagSize >= 0) && (maxTagSize < MAX_TAG_FRAMES_TABLE.length) ) {
retval = MAX_TAG_FRAMES_TABLE[maxTagSize];
}
return retval;
}
/**
* Returns the maximum tag size or -1 if unset
*
* @return the maximum tag size or -1 if unset
*/
public int getMaxTagSize() {
int retval = -1;
if( (maxTagSize >= 0) && (maxTagSize < MAX_TAG_SIZE_TABLE.length) ) {
retval = MAX_TAG_SIZE_TABLE[maxTagSize];
}
return retval;
}
/**
* Returns true if the text encode flag is set
*
* @return true if the text encode flag is set
*/
public boolean getTextEncode() {
return textEncode;
}
/**
* Returns the maximum length of a string if set or -1
*
* @return the maximum length of a string if set or -1
*/
public int getMaxTextSize() {
int retval = -1;
if( (maxTextSize >= 0) && (maxTextSize < MAX_TEXT_SIZE_TABLE.length)) {
retval = MAX_TEXT_SIZE_TABLE[maxTextSize];
}
return retval;
}
/**
* Returns true if the image encode flag is set
*
* @return true if the image encode flag is set
*/
public boolean getImageEncode() {
return imageEncode;
}
/**
* Returns the value of the image restriction field or -1 if not set
*
* @return the value of the image restriction field or -1 if not set
*/
public int getImageRestriction() {
return imageRestrict;
}
/**
* Returns true if this tag is an update of a previous tag
*
* @return true if this tag is an update of a previous tag
*/
public boolean getUpdate() {
return update;
}
/**
* Returns true if CRC information is provided for this tag
*
* @return true if CRC information is provided for this tag
*/
public boolean getCRCed() {
return crced;
}
/**
* If there is crc data in the extended header, then the attached 5 byte
* crc will be returned. An empty array will be returned if this has
* not been set.
*
* @return the attached crc data if there is any
*/
public byte[] getCRC() {
return crc;
}
/**
* Returns a string representation of this object that contains all
* information within.
*
* @return a string representation of this object
*/
public String toString() {
return "ExtendedSize:\t\t\t" + getSize() + " bytes" +
"\nNumFlagBytes:\t\t\t" + getNumFlagBytes() +
"\nUpdated:\t\t\t" + getUpdate() + "\nCRC:\t\t\t\t" + getCRCed() +
"\nMaxFrames:\t\t\t"
+ getMaxFrames() + "\nMaxTagSize:\t\t\t" + getMaxTagSize() +
"\nTextEncoded:\t\t\t" + getTextEncode() + "\nMaxTextSize:\t\t\t"
+ getMaxTextSize() + "\nImageEncoded:\t\t\t" + getImageEncode()
+ "\nImageRestriction:\t\t" + getImageRestriction();
}
} // ID3v2ExtendedHeader
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -