Logo Search packages:      
Sourcecode: jampal version File versions  Download package

ID3v2Header.java

package pgbennett.id3;

import java.io.RandomAccessFile;
import java.io.IOException;
import java.io.FileNotFoundException;
import java.io.File;
import java.io.UnsupportedEncodingException;

/*
   Copyright (C) 2001 Jonathan Hilliker
    This file is part of the jd3lib library.

    This copy of jd3lib has been incorporated into Jampal under the 
    GNU general Public License.

    Modifications to the file Copyright 2004 Peter Bennett.

    Jampal is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Jampal 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 General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Jampal.  If not, see <http://www.gnu.org/licenses/>.
 */
/**
 * This class reads all the information in the header of an id3v2 tag. <br />
 *
 * <dl>
 *   <dt> <b>Version History</b> </dt>
 *   <dt> 1.6.1 - <small>2002.1021 by gruni</small> </dt>
 *   <dd> -Made Sourcecode compliant to the Sun CodingConventions</dd>
 *   <dt> 1.6 - <small>2002.0131 by helliker</small> </dt>
 *   <dd> -Removed unneccessary encoding.</dd>
 *   <dt> 1.5 - <small>2001.1204 by helliker</small> </dt>
 *   <dd> -The getHeaderSize always returns 10 to make calculations in id3v2Tag
 *   easier.</dd>
 *   <dt> 1.4 - <small>2001.1129 by helliker</small> </dt>
 *   <dd> -Fixed file handle leaks</dd>
 *   <dt> 1.3 - <small>2001.1028 by helliker</small> </dt>
 *   <dd> -When the getBytes method is called the tag version will be updated to
 *   the version that this library implements so that programs that implement
 *   different versions will be able to read the correct format.</dd>
 *   <dt> 1.2 - <small>2001.1019 by helliker</small> </dt>
 *   <dd> -All set for release.</dd>
 * </dl>
 *
 *
 *@author    Jonathan Hilliker
 *@version   1.6.1
 */

00058 public class ID3v2Header {
    
    /**
     * Start String
     */
00063     private final String TAG_START = "ID3";
    /**
     * ???
     */
00067     private final int HEAD_SIZE = 10;
    /**
     * ???
     */
00071     private final int HEAD_LOCATION = 0;
    /**
     * ???
     */
00075     private final int NEW_MAJOR_VERSION = 3;// So winamp will accept it use
    /**
     * ???
     */
00079     private final int NEW_MINOR_VERSION = 0;// 3 instead of 4
    
    private final int MAX_SUPPORTED_VERSION = 4;// Read version 4 taqgs
    
    /**
     * The File
     */
00086     private File mp3 = null;
    /**
     * ???
     */
00090     private boolean headerExists;
    /**
     * ???
     */
00094     private int majorVersion;
    /**
     * ???
     */
00098     private int minorVersion;
    /**
     * ???
     */
00102     private boolean unsynchronisation;
    /**
     * ???
     */
00106     private boolean extended;
    /**
     * ???
     */
00110     private boolean experimental;
    /**
     * ???
     */
00114     private boolean footer;
    /**
     * ???
     */
00118     private int tagSize;
    
    
    /**
     * Create an id3v2header linked to the file passed as a parameter. An attempt
     * will be made to read the header from the file. If a header exists, then
     * information in the header will be extracted. If a header doesn't exist,
     * default data will be used.
     *
     *@param mp3                        the file to attempt to read data from
     *@exception FileNotFoundException  if an error occurs
     *@exception IOException            if an error occurs
     */
00131     public ID3v2Header(File mp3) throws FileNotFoundException, IOException {
        init(mp3,false);
    }
    
    public ID3v2Header(File mp3, boolean emptyTag) throws FileNotFoundException, IOException {
        init(mp3,emptyTag);
    }

    
    public void init(File mp3, boolean emptyTag)
    throws FileNotFoundException, IOException {
        
        this.mp3 = mp3;
        
        majorVersion = NEW_MAJOR_VERSION;
        minorVersion = NEW_MINOR_VERSION;
        unsynchronisation = false;
        extended = false;
        experimental = false;
        footer = false;
        tagSize = 0;
        
        RandomAccessFile in = null;
        
        if (emptyTag)
            headerExists=false;
        else {
            try {
                in = new RandomAccessFile(mp3, "r");
                headerExists = checkHeader(in);
                
                if (headerExists) {
                    readHeader(in);
                }
            } finally {
                if (in != null) {
                    in.close();
                }
            }
        }
    }
    
    
    /**
     * Checks to see if there is an id3v2 header in the file provided to the
     * constructor.
     *
     *@param raf                        the open file to read from
     *@return                           true if an id3v2 header exists in the file
     *@exception FileNotFoundException  if an error occurs
     *@exception IOException            if an error occurs
     */
00183     private boolean checkHeader(RandomAccessFile raf)
    throws FileNotFoundException, IOException {
        
        boolean exists = false;
        raf.seek(HEAD_LOCATION);
        byte[] buf = new byte[HEAD_SIZE];
        
        if (raf.read(buf) != HEAD_SIZE) {
            throw new IOException("Error encountered finding id3v2 header");
        }
        
        String result = new String(buf);
        if (result.substring(0, TAG_START.length()).equals(TAG_START)) {
            if ((buf[3] < 0xff) && (buf[4] < 0xff)) {
                if ((buf[6] < 0x80) && (buf[7] < 0x80)
                && (buf[8] < 0x80) && (buf[9] < 0x80)) {
                    
                    exists = true;
                }
            }
        }
        
        return exists;
    }
    
    
    /**
     * Extracts the information from the header.
     *
     *@param raf                        the open file to read from
     *@exception FileNotFoundException  if an error occurs
     *@exception IOException            if an error occurs
     */
00216     private void readHeader(RandomAccessFile raf)
    throws FileNotFoundException, IOException {
        
        raf.seek(HEAD_LOCATION);
        byte[] head = new byte[HEAD_SIZE];
        
        if (raf.read(head) != HEAD_SIZE) {
            throw new IOException("Error encountered reading id3v2 header");
        }
        
        majorVersion = (int) head[3];
        
        // This check prevents it from reading id3v2.4 tags. Why?
        //    if (majorVersion <= NEW_MAJOR_VERSION) {
        if (majorVersion <= MAX_SUPPORTED_VERSION) {
            minorVersion = (int) head[4];
            unsynchronisation = BinaryParser.bitSet(head[5], 7);
            extended = BinaryParser.bitSet(head[5], 6);
            experimental = BinaryParser.bitSet(head[5], 5);
            footer = BinaryParser.bitSet(head[5], 4);
            
            byte[] size = {head[6], head[7], head[8], head[9]};
            tagSize = BinaryParser.convertToSynchsafeInt(size);
        }
    }
    
    
    /**
     * Return an array of bytes representing the header. This can be used to
     * easily write the header to a file. When this method is called it
     * automatically updates the header to the newest format.
     *
     *@return   a binary representation of this header
     */
00250     public byte[] getBytes() {
        byte[] b = new byte[HEAD_SIZE];
        int bytesCopied = 0;
        
        if (majorVersion < NEW_MAJOR_VERSION) {
            majorVersion = NEW_MAJOR_VERSION;
        }
        
        System.arraycopy(TAG_START.getBytes(), 0, b, bytesCopied,
        TAG_START.length());
        bytesCopied += TAG_START.length();
        b[bytesCopied++] = (byte) majorVersion;
        b[bytesCopied++] = (byte) minorVersion;
        b[bytesCopied++] = getFlagByte();
        System.arraycopy(BinaryParser.convertToSynchsafeBytes(tagSize),
        0, b, bytesCopied, 4);
        bytesCopied += 4;
        
        return b;
    }
    
    
    /**
     * A helper function for the getBytes function that returns a byte with the
     * proper flags set.
     *
     *@return   the flags byte of this header
     */
00278     private byte getFlagByte() {
        byte ret = 0;
        
        if (unsynchronisation) {
            ret = BinaryParser.setBit(ret, 7);
        }
        if (extended) {
            ret = BinaryParser.setBit(ret, 6);
        }
        if (experimental) {
            ret = BinaryParser.setBit(ret, 5);
        }
        if (footer) {
            ret = BinaryParser.setBit(ret, 4);
        }
        
        return ret;
    }
    
    
    /**
     * Returns true if a header exists
     *
     *@return   true if a header exists
     */
00303     public boolean headerExists() {
        return headerExists;
    }
    
    
    /**
     * Returns the size (in bytes) of this header. This is always 10.
     *
     *@return   the size of this header
     */
00313     public int getHeaderSize() {
        return HEAD_SIZE;
    }
    
    
    /**
     * Returns the size (in bytes) of the frames and/or extended header portion of
     * the id3v2 tag according to the size field in the header.
     *
     *@return   the size field of the header
     */
00324     public int getTagSize() {
        return tagSize;
    }
    
    
    /**
     * Sets the size of the frames and/or extended header. If this function is
     * called, the headerExists function will return true. This is called every
     * time a frame is updated, added, or removed.
     *
     *@param size  a value of type 'int'
     */
00336     public void setTagSize(int size) {
        if (size > 0) {
            tagSize = size;
            headerExists = true;
        }
    }
    
    
    /**
     * Returns the major version of this id3v2 tag.
     *
     *@return   the major version of this id3v2 tag.
     */
00349     public int getMajorVersion() {
        return majorVersion;
    }
    
    
    public void setVersion(int majorVersion, int minorVersion) {
        this.majorVersion = majorVersion;
        this.minorVersion = minorVersion;
    }
    
    
    /**
     * Return the minor version/revision of this id3v2 tag.
     *
     *@return   the minor version/revision of this id3v2 tag.
     */
00365     public int getMinorVersion() {
        return minorVersion;
    }
    
    
    /**
     * Returns true if the unsynchronisation bit is set in this header.
     *
     *@return   true if the unsynchronisation bit is set in this header.
     */
00375     public boolean getUnsynchronisation() {
        return unsynchronisation;
    }
    
    
    /**
     * Set the unsynchronisation flag for this header.
     *
     *@param unsynch  the new value of the unsynchronisation flag
     */
00385     public void setUnsynchronisation(boolean unsynch) {
        unsynchronisation = unsynch;
    }
    
    
    /**
     * Returns true if this tag has an extended header.
     *
     *@return   true if this tag has an extended header
     */
00395     public boolean getExtendedHeader() {
        return extended;
    }
    
    
    /**
     * Set the value of the extended header bit of this header.
     *
     *@param extend  the new value of the extended header bit
     */
00405     public void setExtendedHeader(boolean extend) {
        extended = extend;
    }
    
    
    /**
     * Returns true if the experimental bit of this header is set.
     *
     *@return   true if the experimental bit of this header is set
     */
00415     public boolean getExperimental() {
        return experimental;
    }
    
    
    /**
     * Set the value of the experimental bit of this header.
     *
     *@param experiment  the new value of the experimental bit
     */
00425     public void setExperimental(boolean experiment) {
        experimental = experiment;
    }
    
    
    /**
     * Returns true if this tag has a footer.
     *
     *@return   true if this tag has a footer
     */
00435     public boolean getFooter() {
        return footer;
    }
    
    
    /**
     * Sets the value of the footer bit for this header.
     *
     *@param foot  the new value of the footer bit for this header
     */
00445     public void setFooter(boolean foot) {
        footer = foot;
    }
    
    
    /**
     * Return a string representation of this object. Contains all information
     * contained within.
     *
     *@return   a string representation of this object
     */
00456     public String toString() {
        return "ID3v2." + getMajorVersion() + "." + getMinorVersion() + "\n"
        + "TagSize:\t\t\t" + getTagSize()
        + " bytes\nUnsynchronisation:\t\t" + getUnsynchronisation()
        + "\nExtended Header:\t\t" + getExtendedHeader()
        + "\nExperimental:\t\t\t" + getExperimental()
        + "\nFooter:\t\t\t\t" + getFooter();
    }
    
}


Generated by  Doxygen 1.6.0   Back to index