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