FileDocCategorySizeDatePackage
ID3DataInputStream.javaAPI Docjid3 0.467944Sun Feb 06 18:11:25 GMT 2005org.blinkenlights.jid3.io

ID3DataInputStream.java

/*
 * Created on 1-Jan-2004
 *
 * Copyright (C)2004 Paul Grebenc
 *
 * 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
 * 
 * $Id: ID3DataInputStream.java,v 1.3 2005/02/06 18:11:25 paul Exp $
 */

package org.blinkenlights.jid3.io;

import java.io.*;

import org.blinkenlights.jid3.*;

/**
 * @author paul
 *
 * Custom DataInputStream containing convenience methods for reading ID3 tags.
 *
 */
public class ID3DataInputStream extends DataInputStream
{
    public ID3DataInputStream(InputStream oIS)
    {
        super(oIS);
    }
    
    /** Reads an unsigned big-endian 16-bit value and returns an int.
     * @return the integer value read
     * @throws IOException
     */
    public final int readBEUnsigned16()
        throws IOException
    {
        int iHi = readUnsignedByte();
        int iLo = readUnsignedByte();
        
        int iVal = iLo | (iHi << 8);
        
        return iVal;
    }
    
    /** Read an unsigned big-endian 24-bit value and returns an int.
     *
     * @return the integer value read
     * @throws IOException
     */
    public int readBE24()
        throws IOException
    {
        int iThree = readUnsignedByte();
        int iTwo = readUnsignedByte();
        int iOne = readUnsignedByte();
        
        int iVal = (iOne | (iTwo << 8) | (iThree << 16));
        
        return iVal;
    }
    
    /** Read a signed big-endian 32-bit value and returns an int.
     * 
     * @return the integer value read
     * @throws IOException
     */
    public int readBE32()
        throws IOException
    {
        int iFour = readUnsignedByte();
        int iThree = readUnsignedByte();
        int iTwo = readUnsignedByte();
        int iOne = readUnsignedByte();
        
        int iVal = (iOne | (iTwo << 8) | (iThree << 16) | (iFour << 24));
        
        return iVal;
    }

    /** Read an unsigned big-endian 32-bit value and returns a long.
     * 
     * @return the long value read
     * @throws IOException
     */
    public long readUnsignedBE32()
        throws IOException
    {
        long lFour = readUnsignedByte();
        long lThree = readUnsignedByte();
        long lTwo = readUnsignedByte();
        long lOne = readUnsignedByte();
        
        long lVal = (lOne | (lTwo << 8) | (lThree << 16) | (lFour << 24));
        
        return lVal;
    }
    
    /** Read an encoded four byte value.
     *  The encoding method uses only the lowest seven bits of each byte, to prevent synchronization
     *  errors in the MP3 data stream.
     */
    public int readID3Four()
        throws IOException, ID3Exception
    {
        int iValue = 0;
        byte[] abyValue = new byte[4];
        readFully(abyValue);
        
        if ( ((abyValue[0] & 0x80) != 0) ||
             ((abyValue[1] & 0x80) != 0) ||
             ((abyValue[2] & 0x80) != 0) ||
             ((abyValue[3] & 0x80) != 0) )
        {
            throw new ID3Exception("High bit cannot be set in encoded values.");
        }
        
        iValue |= ((abyValue[0] & 0x7f) << (3 * 7));
        iValue |= ((abyValue[1] & 0x7f) << (2 * 7));
        iValue |= ((abyValue[2] & 0x7f) << (1 * 7));
        iValue |= ((abyValue[3] & 0x7f) << (0 * 7));
        
        return iValue;
    }

    /** Read an ISO-8859-1 encoded string to null.
     * 
     * @return a String, or null if string would be zero length
     * @throws IOException
     */
    public String readStringToNull()
        throws IOException
    {
        return readStringToNull(Integer.MAX_VALUE);
    }

    /** Read an ISO-8859-1 string to null, not exceeding a predefined length.
     * 
     * @param iMaxLength a length beyond which not to read further
     * @return a String, or null if string would be zero length
     * @throws IOException on I/O error, or if string would exceed allowed length
     */
    public String readStringToNull(int iMaxLength)
        throws IOException
    {
        ByteArrayOutputStream oStringBAOS = new ByteArrayOutputStream();
        int iStringByte;
        do
        {
            iStringByte = readUnsignedByte();
            if (iStringByte != 0)
            {
                if (oStringBAOS.size() == iMaxLength)
                {
                    throw new IOException("String length exceeds set " + iMaxLength + " byte limit.");
                }
                oStringBAOS.write(iStringByte);
            }
        }
        while (iStringByte != 0);
        
        // return byte array as a string
        byte[] abyShortDescription = oStringBAOS.toByteArray();
        return new String(abyShortDescription);
    }
    
    /** Read a string in the specified encoding format to null.  Note that Unicode strings must be terminated by
     *  a double null (two zero bytes).
     * 
     * @param oTextEncoding the encoding format of the string to be read
     * @return a String, or null if string would be zero length
     * @throws IOException
     */
    public String readStringToNull(TextEncoding oTextEncoding)
        throws IOException
    {
        return readStringToNull(oTextEncoding, Integer.MAX_VALUE);
    }
    
    /** Read a string in the specified encoding format to null, not exceeding a predefined length.  Note that
     *  Unicode strings must be terminated by a double null (two zero bytes).
     * 
     * @param oTextEncoding the encoding format of the string to be read
     * @param iMaxLength a length beyond which not to read further (in characters, not necessarily bytes)
     * @return a String, or null if string would be zero length
     * @throws IOException on I/O error, or if string would exceed allowed length
     */
    public String readStringToNull(TextEncoding oTextEncoding, int iMaxLength)
        throws IOException
    {
        if (oTextEncoding == null)
        {
            throw new NullPointerException("Text encoding cannot be null.");
        }

        ByteArrayOutputStream oStringBAOS = new ByteArrayOutputStream();
        int iStringByte1;
        int iStringByte2 = 0;
        int iLength = 0;
        do
        {
            iStringByte1 = readUnsignedByte();
            if (oTextEncoding.equals(TextEncoding.UNICODE))
            {
                iStringByte2 = readUnsignedByte();
            }
            if ((iStringByte1 != 0) || (iStringByte2 != 0))
            {
                if (iLength == iMaxLength)
                {
                    throw new IOException("String length exceeds set " + iMaxLength + " byte limit.");
                }
                oStringBAOS.write(iStringByte1);
                if (oTextEncoding.equals(TextEncoding.UNICODE))
                {
                    oStringBAOS.write(iStringByte2);
                }
                iLength++;
            }
        }
        while ((iStringByte1 != 0) || (iStringByte2 != 0)) ;
        
        // return byte array as a string
        byte[] abyShortDescription = oStringBAOS.toByteArray();
        return new String(abyShortDescription, oTextEncoding.getEncodingString());
    }
}