| /* java.util.zip.StreamManipulator | |
| Copyright (C) 2001 Free Software Foundation, Inc. | |
| This file is part of GNU Classpath. | |
| GNU Classpath 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 2, or (at your option) | |
| any later version. | |
| GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the | |
| Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | |
| 02110-1301 USA. | |
| Linking this library statically or dynamically with other modules is | |
| making a combined work based on this library. Thus, the terms and | |
| conditions of the GNU General Public License cover the whole | |
| combination. | |
| As a special exception, the copyright holders of this library give you | |
| permission to link this library with independent modules to produce an | |
| executable, regardless of the license terms of these independent | |
| modules, and to copy and distribute the resulting executable under | |
| terms of your choice, provided that you also meet, for each linked | |
| independent module, the terms and conditions of the license of that | |
| module. An independent module is a module which is not derived from | |
| or based on this library. If you modify this library, you may extend | |
| this exception to your version of the library, but you are not | |
| obligated to do so. If you do not wish to do so, delete this | |
| exception statement from your version. */ | |
| package java.util.zip; | |
| /** | |
| * This class allows us to retrieve a specified amount of bits from | |
| * the input buffer, as well as copy big byte blocks. | |
| * | |
| * It uses an int buffer to store up to 31 bits for direct | |
| * manipulation. This guarantees that we can get at least 16 bits, | |
| * but we only need at most 15, so this is all safe. | |
| * | |
| * There are some optimizations in this class, for example, you must | |
| * never peek more then 8 bits more than needed, and you must first | |
| * peek bits before you may drop them. This is not a general purpose | |
| * class but optimized for the behaviour of the Inflater. | |
| * | |
| * @author John Leuner, Jochen Hoenicke | |
| */ | |
| class StreamManipulator | |
| { | |
| private byte[] window; | |
| private int window_start = 0; | |
| private int window_end = 0; | |
| private int buffer = 0; | |
| private int bits_in_buffer = 0; | |
| /** | |
| * Get the next n bits but don't increase input pointer. n must be | |
| * less or equal 16 and if you if this call succeeds, you must drop | |
| * at least n-8 bits in the next call. | |
| * | |
| * @return the value of the bits, or -1 if not enough bits available. */ | |
| public final int peekBits(int n) | |
| { | |
| if (bits_in_buffer < n) | |
| { | |
| if (window_start == window_end) | |
| return -1; | |
| buffer |= (window[window_start++] & 0xff | |
| | (window[window_start++] & 0xff) << 8) << bits_in_buffer; | |
| bits_in_buffer += 16; | |
| } | |
| return buffer & ((1 << n) - 1); | |
| } | |
| /* Drops the next n bits from the input. You should have called peekBits | |
| * with a bigger or equal n before, to make sure that enough bits are in | |
| * the bit buffer. | |
| */ | |
| public final void dropBits(int n) | |
| { | |
| buffer >>>= n; | |
| bits_in_buffer -= n; | |
| } | |
| /** | |
| * Gets the next n bits and increases input pointer. This is equivalent | |
| * to peekBits followed by dropBits, except for correct error handling. | |
| * @return the value of the bits, or -1 if not enough bits available. | |
| */ | |
| public final int getBits(int n) | |
| { | |
| int bits = peekBits(n); | |
| if (bits >= 0) | |
| dropBits(n); | |
| return bits; | |
| } | |
| /** | |
| * Gets the number of bits available in the bit buffer. This must be | |
| * only called when a previous peekBits() returned -1. | |
| * @return the number of bits available. | |
| */ | |
| public final int getAvailableBits() | |
| { | |
| return bits_in_buffer; | |
| } | |
| /** | |
| * Gets the number of bytes available. | |
| * @return the number of bytes available. | |
| */ | |
| public final int getAvailableBytes() | |
| { | |
| return window_end - window_start + (bits_in_buffer >> 3); | |
| } | |
| /** | |
| * Skips to the next byte boundary. | |
| */ | |
| public void skipToByteBoundary() | |
| { | |
| buffer >>= (bits_in_buffer & 7); | |
| bits_in_buffer &= ~7; | |
| } | |
| public final boolean needsInput() { | |
| return window_start == window_end; | |
| } | |
| /* Copies length bytes from input buffer to output buffer starting | |
| * at output[offset]. You have to make sure, that the buffer is | |
| * byte aligned. If not enough bytes are available, copies fewer | |
| * bytes. | |
| * @param length the length to copy, 0 is allowed. | |
| * @return the number of bytes copied, 0 if no byte is available. | |
| */ | |
| public int copyBytes(byte[] output, int offset, int length) | |
| { | |
| if (length < 0) | |
| throw new IllegalArgumentException("length negative"); | |
| if ((bits_in_buffer & 7) != 0) | |
| /* bits_in_buffer may only be 0 or 8 */ | |
| throw new IllegalStateException("Bit buffer is not aligned!"); | |
| int count = 0; | |
| while (bits_in_buffer > 0 && length > 0) | |
| { | |
| output[offset++] = (byte) buffer; | |
| buffer >>>= 8; | |
| bits_in_buffer -= 8; | |
| length--; | |
| count++; | |
| } | |
| if (length == 0) | |
| return count; | |
| int avail = window_end - window_start; | |
| if (length > avail) | |
| length = avail; | |
| System.arraycopy(window, window_start, output, offset, length); | |
| window_start += length; | |
| if (((window_start - window_end) & 1) != 0) | |
| { | |
| /* We always want an even number of bytes in input, see peekBits */ | |
| buffer = (window[window_start++] & 0xff); | |
| bits_in_buffer = 8; | |
| } | |
| return count + length; | |
| } | |
| public StreamManipulator() | |
| { | |
| } | |
| public void reset() | |
| { | |
| window_start = window_end = buffer = bits_in_buffer = 0; | |
| } | |
| public void setInput(byte[] buf, int off, int len) | |
| { | |
| if (window_start < window_end) | |
| throw new IllegalStateException | |
| ("Old input was not completely processed"); | |
| int end = off + len; | |
| /* We want to throw an ArrayIndexOutOfBoundsException early. The | |
| * check is very tricky: it also handles integer wrap around. | |
| */ | |
| if (0 > off || off > end || end > buf.length) | |
| throw new ArrayIndexOutOfBoundsException(); | |
| if ((len & 1) != 0) | |
| { | |
| /* We always want an even number of bytes in input, see peekBits */ | |
| buffer |= (buf[off++] & 0xff) << bits_in_buffer; | |
| bits_in_buffer += 8; | |
| } | |
| window = buf; | |
| window_start = off; | |
| window_end = end; | |
| } | |
| } |