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