// Parser.java // $Id: Parser.java,v 1.10 2008/01/03 04:35:51 dmitriy Exp $ // // de.vdheide.mp3: Access MP3 properties, ID3 and ID3v2 tags // Copyright (C) 1999 Jens Vonderheide <jens@vdheide.de> // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Library General Public // License as published by the Free Software Foundation; either // version 2 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 // Library General Public License for more details. // // You should have received a copy of the GNU Library 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. package de.vdheide.mp3; //import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; /** * Class used to parse a byte array and extract text or binary information * It maintained a pointer so that parse operations are always performed * on the first byte after end of the last operation. * All parsing is done until a 0x00 (or 0x00 0x00 for Unicode) is encountered. * Byte position is then placed on first byte after this terminator. */ class Parser { /** * Create new instance, use complete array * * @param in Array to parse * @param encoding True: First byte of input contains encoding. * False: Encoding is set to ISO-8859-1 */ public Parser(byte []in, boolean encoding, String targetEncoding) { this(in, encoding, 0, in.length - 1); //System.err.println("Created for "+targetEncoding); if (targetEncoding != null) this.targetEncoding = targetEncoding; } public Parser(byte []in, boolean encoding) { this(in, encoding, 0, in.length - 1); } /** * Create new instance, use part of array * * @param in Array to parse * @param encoding True: First byte of input contains encoding. * False: Encoding is set to ISO-8859-1 * @param start Offset of first byte to parse * @param stop Offset of last byte to parse */ public Parser(byte []in, boolean encoding, int start, int stop) { this.in = in; this.pos = start; this.stop = stop; if (encoding == true) { parseEncoding(); } else { this.encoding = TextFrame.NONE; } } /** * Set byte position * * @param pos New byte position */ public void setPosition(int pos) { this.pos = pos; } /** * @return Byte position */ public int getPosition() { return pos; } /** * Parse encoding byte. This is automatically done * in the constructor if encoding is set to true. */ public void parseEncoding() { encoding = in[pos]; pos++; } /** * Parse next bytes as text according to set encoding */ public String parseText() throws ParseException { return parseText(this.encoding); } /** * Parse next bytes as text according to given encoding */ public String parseText(byte encoding) throws ParseException { try { // find termination int term = pos; boolean doubleByte = encoding == TextFrame.UNICODE || encoding == TextFrame.UTF16BE; if (doubleByte == false) { while (in[term]!=0 && term<stop) { term++; } } else { while (term<stop-1 && (in[term]!=0 || in[term+1]!=0)) { term+=2; } } if (in[term]!=0 && encoding != TextFrame.NONE) term = stop + 1; // convert String ret = null; String charSet = targetEncoding; switch(encoding) { case TextFrame.UTF8: charSet = "UTF-8"; break; case TextFrame.UTF16BE: charSet = "UTF-16BE"; break; case TextFrame.UNICODE: charSet = "UTF-16LE"; //System.err.printf("!!!!!!pos0 %d, pos1 %d%n", in [pos], in [pos+1]); // check for BOM (FF FE or FE FF) if (in [pos] == -1 && in[pos+1] == -2) pos+=2; break; } try { ret = new String(in, pos, term - pos, charSet); } catch (java.io.UnsupportedEncodingException e) { // cannot happen } // advance position marker pos = term + (doubleByte ? 2 : 1); return ret; } catch (Exception e) { throw (ParseException)new ParseException().initCause(e); } } /** * Read next bytes to end (no real parsing, just copying) */ public byte[] parseBinary() throws ParseException { return parseBinary(stop - pos + 1); } /** * Read next <code>number</code> bytes (no real parsing, just copying) * * @param number Number of bytes to read */ public byte[] parseBinary(int number) throws ParseException { try { byte []ret = new byte[number]; System.arraycopy(in, pos, ret, 0, number); pos += number; // no more reading possible... return ret; } catch (Exception e) { throw new ParseException(); } } public Date parseDate() throws ParseException { // String dateString = parseText(); if (dateString != null && dateString.length() > 1) try { return new SimpleDateFormat("yyyy-MM-ddTHH:mm:ss".substring(0, dateString.length())).parse(dateString); } catch (java.text.ParseException e) { throw new ParseException(); } return null; } private byte []in; private int stop; private int pos; // Next byte to parse private byte encoding; // Encoding used for text private String targetEncoding = MP3File.DEF_ASCII_ENCODING; }