| /******************************************************************************* |
| * Copyright (c) 2000, 2007 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.swt.internal.image; |
| |
| |
| import java.io.*; |
| |
| final class LEDataInputStream extends InputStream { |
| int position; |
| InputStream in; |
| |
| /** |
| * The byte array containing the bytes to read. |
| */ |
| protected byte[] buf; |
| |
| /** |
| * The current position within the byte array <code>buf</code>. A value |
| * equal to buf.length indicates no bytes available. A value of |
| * 0 indicates the buffer is full. |
| */ |
| protected int pos; |
| |
| |
| public LEDataInputStream(InputStream input) { |
| this(input, 512); |
| } |
| |
| public LEDataInputStream(InputStream input, int bufferSize) { |
| this.in = input; |
| if (bufferSize > 0) { |
| buf = new byte[bufferSize]; |
| pos = bufferSize; |
| } |
| else throw new IllegalArgumentException(); |
| } |
| |
| public void close() throws IOException { |
| buf = null; |
| if (in != null) { |
| in.close(); |
| in = null; |
| } |
| } |
| |
| /** |
| * Answer how many bytes were read. |
| */ |
| public int getPosition() { |
| return position; |
| } |
| |
| /** |
| * Answers how many bytes are available for reading without blocking |
| */ |
| public int available() throws IOException { |
| if (buf == null) throw new IOException(); |
| return (buf.length - pos) + in.available(); |
| } |
| |
| /** |
| * Answer the next byte of the input stream. |
| */ |
| public int read() throws IOException { |
| if (buf == null) throw new IOException(); |
| if (pos < buf.length) { |
| position++; |
| return (buf[pos++] & 0xFF); |
| } |
| int c = in.read(); |
| if (c != -1) position++; |
| return c; |
| } |
| |
| /** |
| * Don't imitate the JDK behaviour of reading a random number |
| * of bytes when you can actually read them all. |
| */ |
| public int read(byte b[], int off, int len) throws IOException { |
| int read = 0, count; |
| while (read != len && (count = readData(b, off, len - read)) != -1) { |
| off += count; |
| read += count; |
| } |
| position += read; |
| if (read == 0 && read != len) return -1; |
| return read; |
| } |
| |
| /** |
| * Reads at most <code>length</code> bytes from this LEDataInputStream and |
| * stores them in byte array <code>buffer</code> starting at <code>offset</code>. |
| * <p> |
| * Answer the number of bytes actually read or -1 if no bytes were read and |
| * end of stream was encountered. This implementation reads bytes from |
| * the pushback buffer first, then the target stream if more bytes are required |
| * to satisfy <code>count</code>. |
| * </p> |
| * @param buffer the byte array in which to store the read bytes. |
| * @param offset the offset in <code>buffer</code> to store the read bytes. |
| * @param length the maximum number of bytes to store in <code>buffer</code>. |
| * |
| * @return int the number of bytes actually read or -1 if end of stream. |
| * |
| * @exception java.io.IOException if an IOException occurs. |
| */ |
| private int readData(byte[] buffer, int offset, int length) throws IOException { |
| if (buf == null) throw new IOException(); |
| if (offset < 0 || offset > buffer.length || |
| length < 0 || (length > buffer.length - offset)) { |
| throw new ArrayIndexOutOfBoundsException(); |
| } |
| |
| int cacheCopied = 0; |
| int newOffset = offset; |
| |
| // Are there pushback bytes available? |
| int available = buf.length - pos; |
| if (available > 0) { |
| cacheCopied = (available >= length) ? length : available; |
| System.arraycopy(buf, pos, buffer, newOffset, cacheCopied); |
| newOffset += cacheCopied; |
| pos += cacheCopied; |
| } |
| |
| // Have we copied enough? |
| if (cacheCopied == length) return length; |
| |
| int inCopied = in.read(buffer, newOffset, length - cacheCopied); |
| |
| if (inCopied > 0) return inCopied + cacheCopied; |
| if (cacheCopied == 0) return inCopied; |
| return cacheCopied; |
| } |
| |
| /** |
| * Answer an integer comprised of the next |
| * four bytes of the input stream. |
| */ |
| public int readInt() throws IOException { |
| byte[] buf = new byte[4]; |
| read(buf); |
| return ((buf[3] & 0xFF) << 24) | |
| ((buf[2] & 0xFF) << 16) | |
| ((buf[1] & 0xFF) << 8) | |
| (buf[0] & 0xFF); |
| } |
| |
| /** |
| * Answer a short comprised of the next |
| * two bytes of the input stream. |
| */ |
| public short readShort() throws IOException { |
| byte[] buf = new byte[2]; |
| read(buf); |
| return (short)(((buf[1] & 0xFF) << 8) | (buf[0] & 0xFF)); |
| } |
| |
| /** |
| * Push back the entire content of the given buffer <code>b</code>. |
| * <p> |
| * The bytes are pushed so that they would be read back b[0], b[1], etc. |
| * If the push back buffer cannot handle the bytes copied from <code>b</code>, |
| * an IOException will be thrown and no byte will be pushed back. |
| * </p> |
| * |
| * @param b the byte array containing bytes to push back into the stream |
| * |
| * @exception java.io.IOException if the pushback buffer is too small |
| */ |
| public void unread(byte[] b) throws IOException { |
| int length = b.length; |
| if (length > pos) throw new IOException(); |
| position -= length; |
| pos -= length; |
| System.arraycopy(b, 0, buf, pos, length); |
| } |
| } |