/* * Copyright (C) 2011 in-somnia * * This file is part of JAAD. * * JAAD 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 3 of the * License, or (at your option) any later version. * * JAAD 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, see <http://www.gnu.org/licenses/>. */ package net.sourceforge.jaad.aac.syntax; import net.sourceforge.jaad.aac.AACException; public class BitStream { private static final int WORD_BITS = 32; private static final int WORD_BYTES = 4; private static final int BYTE_MASK = 0xff; private byte[] buffer; private int pos; //offset in the buffer array private int cache; //current 4 bytes, that are read from the buffer protected int bitsCached; //remaining bits in current cache protected int position; //number of total bits read public BitStream() { } public BitStream(byte[] data) { setData(data); } public void destroy() { reset(); buffer = null; } public final void setData(byte[] data) { //make the buffer size an integer number of words final int size = WORD_BYTES*((data.length+WORD_BYTES-1)/WORD_BYTES); //only reallocate if needed if(buffer==null||buffer.length!=size) buffer = new byte[size]; System.arraycopy(data, 0, buffer, 0, data.length); reset(); } public void byteAlign() throws AACException { final int toFlush = bitsCached&7; if(toFlush>0) skipBits(toFlush); } public final void reset() { pos = 0; bitsCached = 0; cache = 0; position = 0; } public int getPosition() { return position; } public int getBitsLeft() { return 8*(buffer.length-pos)+bitsCached; } /** * Reads the next four bytes. * @param peek if true, the stream pointer will not be increased */ protected int readCache(boolean peek) throws AACException { int i; if(pos>buffer.length-WORD_BYTES) throw new AACException("end of stream", true); else i = ((buffer[pos]&BYTE_MASK)<<24) |((buffer[pos+1]&BYTE_MASK)<<16) |((buffer[pos+2]&BYTE_MASK)<<8) |(buffer[pos+3]&BYTE_MASK); if(!peek) pos += WORD_BYTES; return i; } public int readBits(int n) throws AACException { int result; if(bitsCached>=n) { bitsCached -= n; result = (cache>>bitsCached)&maskBits(n); position += n; } else { position += n; final int c = cache&maskBits(bitsCached); final int left = n-bitsCached; cache = readCache(false); bitsCached = WORD_BITS-left; result = ((cache>>bitsCached)&maskBits(left))|(c<<left); } return result; } public int readBit() throws AACException { int i; if(bitsCached>0) { bitsCached--; i = (cache>>(bitsCached))&1; position++; } else { cache = readCache(false); bitsCached = WORD_BITS-1; position++; i = (cache>>bitsCached)&1; } return i; } public boolean readBool() throws AACException { return (readBit()&0x1)!=0; } public int peekBits(int n) throws AACException { int ret; if(bitsCached>=n) { ret = (cache>>(bitsCached-n))&maskBits(n); } else { //old cache final int c = cache&maskBits(bitsCached); n -= bitsCached; //read next & combine ret = ((readCache(true)>>WORD_BITS-n)&maskBits(n))|(c<<n); } return ret; } public int peekBit() throws AACException { int ret; if(bitsCached>0) { ret = (cache>>(bitsCached-1))&1; } else { final int word = readCache(true); ret = (word>>WORD_BITS-1)&1; } return ret; } public void skipBits(int n) throws AACException { position += n; if(n<=bitsCached) { bitsCached -= n; } else { n -= bitsCached; while(n>=WORD_BITS) { n -= WORD_BITS; readCache(false); } if(n>0) { cache = readCache(false); bitsCached = WORD_BITS-n; } else { cache = 0; bitsCached = 0; } } } public void skipBit() throws AACException { position++; if(bitsCached>0) { bitsCached--; } else { cache = readCache(false); bitsCached = WORD_BITS-1; } } public int maskBits(int n) { int i; if(n==32) i = -1; else i = (1<<n)-1; return i; } }