/* * 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()); } }