All Downloads are FREE. Search and download functionalities are using the official Maven repository.

java.io.PushbackInputStream Maven / Gradle / Ivy

Go to download

JVM AOT compiler currently generating JavaScript, C++, Haxe, with initial focus on Kotlin and games.

The newest version!
/*
 *  Licensed to the Apache Software Foundation (ASF) under one or more
 *  contributor license agreements.  See the NOTICE file distributed with
 *  this work for additional information regarding copyright ownership.
 *  The ASF licenses this file to You under the Apache License, Version 2.0
 *  (the "License"); you may not use this file except in compliance with
 *  the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package java.io;

import com.jtransc.JTranscArrays;

import java.util.Arrays;

/**
 * Wraps an existing {@link InputStream} and adds functionality to "push back"
 * bytes that have been read, so that they can be read again. Parsers may find
 * this useful. The number of bytes which may be pushed back can be specified
 * during construction. If the buffer of pushed back bytes is empty, bytes are
 * read from the underlying input stream.
 */
public class PushbackInputStream extends FilterInputStream {
    /**
     * The buffer that contains pushed-back bytes.
     */
    protected byte[] buf;

    /**
     * The current position within {@code buf}. A value equal to
     * {@code buf.length} indicates that no bytes are available. A value of 0
     * indicates that the buffer is full.
     */
    protected int pos;

    /**
     * Constructs a new {@code PushbackInputStream} with the specified input
     * stream as source. The size of the pushback buffer is set to the default
     * value of 1 byte.
     *
     * 

Warning: passing a null source creates an invalid * {@code PushbackInputStream}. All read operations on such a stream will * fail. * * @param in * the source input stream. */ public PushbackInputStream(InputStream in) { super(in); buf = (in == null) ? null : new byte[1]; pos = 1; } /** * Constructs a new {@code PushbackInputStream} with {@code in} as source * input stream. The size of the pushback buffer is set to {@code size}. * *

Warning: passing a null source creates an invalid * {@code PushbackInputStream}. All read operations on such a stream will * fail. * * @param in * the source input stream. * @param size * the size of the pushback buffer. * @throws IllegalArgumentException * if {@code size} is negative. */ public PushbackInputStream(InputStream in, int size) { super(in); if (size <= 0) { throw new IllegalArgumentException("size <= 0"); } buf = (in == null) ? null : new byte[size]; pos = size; } @Override public int available() throws IOException { if (buf == null) { throw new IOException(); } return buf.length - pos + in.available(); } /** * Closes this stream. This implementation closes the source stream * and releases the pushback buffer. * * @throws IOException * if an error occurs while closing this stream. */ @Override public void close() throws IOException { if (in != null) { in.close(); in = null; buf = null; } } /** * Indicates whether this stream supports the {@code mark(int)} and * {@code reset()} methods. {@code PushbackInputStream} does not support * them, so it returns {@code false}. * * @return always {@code false}. * @see #mark(int) * @see #reset() */ @Override public boolean markSupported() { return false; } /** * Reads a single byte from this stream and returns it as an integer in the * range from 0 to 255. If the pushback buffer does not contain any * available bytes then a byte from the source input stream is returned. * Blocks until one byte has been read, the end of the source stream is * detected or an exception is thrown. * * @return the byte read or -1 if the end of the source stream has been * reached. * @throws IOException * if this stream is closed or an I/O error occurs while reading * from this stream. */ @Override public int read() throws IOException { if (buf == null) { throw new IOException(); } // Is there a pushback byte available? if (pos < buf.length) { return (buf[pos++] & 0xFF); } // Assume read() in the InputStream will return low-order byte or -1 // if end of stream. return in.read(); } /** * Reads up to {@code byteCount} bytes from this stream and stores them in * the byte array {@code buffer} starting at {@code byteOffset}. Bytes are read * from the pushback buffer first, then from the source stream if more bytes * are required. Blocks until {@code byteCount} bytes have been read, the end of * the source stream is detected or an exception is thrown. Returns the number of bytes read, * or -1 if the end of the source stream has been reached. * * @throws IndexOutOfBoundsException * if {@code byteOffset < 0 || byteCount < 0 || byteOffset + byteCount > buffer.length}. * @throws IOException * if this stream is closed or another I/O error occurs while * reading from this stream. * @throws NullPointerException * if {@code buffer == null}. */ @Override public int read(byte[] buffer, int byteOffset, int byteCount) throws IOException { if (buf == null) { throw streamClosed(); } JTranscArrays.checkOffsetAndCount(buffer.length, byteOffset, byteCount); int copiedBytes = 0, copyLength = 0, newOffset = byteOffset; // Are there pushback bytes available? if (pos < buf.length) { copyLength = (buf.length - pos >= byteCount) ? byteCount : buf.length - pos; System.arraycopy(buf, pos, buffer, newOffset, copyLength); newOffset += copyLength; copiedBytes += copyLength; // Use up the bytes in the local buffer pos += copyLength; } // Have we copied enough? if (copyLength == byteCount) { return byteCount; } int inCopied = in.read(buffer, newOffset, byteCount - copiedBytes); if (inCopied > 0) { return inCopied + copiedBytes; } if (copiedBytes == 0) { return inCopied; } return copiedBytes; } private IOException streamClosed() throws IOException { throw new IOException("PushbackInputStream is closed"); } /** * Skips {@code byteCount} bytes in this stream. This implementation skips bytes * in the pushback buffer first and then in the source stream if necessary. * * @return the number of bytes actually skipped. * @throws IOException * if this stream is closed or another I/O error occurs. */ @Override public long skip(long byteCount) throws IOException { if (in == null) { throw streamClosed(); } if (byteCount <= 0) { return 0; } int numSkipped = 0; if (pos < buf.length) { numSkipped += (byteCount < buf.length - pos) ? byteCount : buf.length - pos; pos += numSkipped; } if (numSkipped < byteCount) { numSkipped += in.skip(byteCount - numSkipped); } return numSkipped; } /** * Pushes all the bytes in {@code buffer} back to this stream. The bytes are * pushed back in such a way that the next byte read from this stream is * buffer[0], then buffer[1] and so on. *

* If this stream's internal pushback buffer cannot store the entire * contents of {@code buffer}, an {@code IOException} is thrown. Parts of * {@code buffer} may have already been copied to the pushback buffer when * the exception is thrown. * * @param buffer * the buffer containing the bytes to push back to this stream. * @throws IOException * if the free space in the internal pushback buffer is not * sufficient to store the contents of {@code buffer}. */ public void unread(byte[] buffer) throws IOException { unread(buffer, 0, buffer.length); } /** * Pushes a subset of the bytes in {@code buffer} back to this stream. The * subset is defined by the start position {@code offset} within * {@code buffer} and the number of bytes specified by {@code length}. The * bytes are pushed back in such a way that the next byte read from this * stream is {@code buffer[offset]}, then {@code buffer[1]} and so on. *

* If this stream's internal pushback buffer cannot store the selected * subset of {@code buffer}, an {@code IOException} is thrown. Parts of * {@code buffer} may have already been copied to the pushback buffer when * the exception is thrown. * * @param buffer * the buffer containing the bytes to push back to this stream. * @param offset * the index of the first byte in {@code buffer} to push back. * @param length * the number of bytes to push back. * @throws IndexOutOfBoundsException * if {@code offset < 0} or {@code length < 0}, or if * {@code offset + length} is greater than the length of * {@code buffer}. * @throws IOException * if the free space in the internal pushback buffer is not * sufficient to store the selected contents of {@code buffer}. */ public void unread(byte[] buffer, int offset, int length) throws IOException { if (length > pos) { throw new IOException("Pushback buffer full"); } JTranscArrays.checkOffsetAndCount(buffer.length, offset, length); if (buf == null) { throw streamClosed(); } System.arraycopy(buffer, offset, buf, pos - length, length); pos = pos - length; } /** * Pushes the specified byte {@code oneByte} back to this stream. Only the * least significant byte of the integer {@code oneByte} is pushed back. * This is done in such a way that the next byte read from this stream is * {@code (byte) oneByte}. *

* If this stream's internal pushback buffer cannot store the byte, an * {@code IOException} is thrown. * * @param oneByte * the byte to push back to this stream. * @throws IOException * if this stream is closed or the internal pushback buffer is * full. */ public void unread(int oneByte) throws IOException { if (buf == null) { throw new IOException(); } if (pos == 0) { throw new IOException("Pushback buffer full"); } buf[--pos] = (byte) oneByte; } /** * Marks the current position in this stream. Setting a mark is not * supported in this class; this implementation does nothing. * * @param readlimit * the number of bytes that can be read from this stream before * the mark is invalidated; this parameter is ignored. */ @Override public void mark(int readlimit) { } /** * Resets this stream to the last marked position. Resetting the stream is * not supported in this class; this implementation always throws an * {@code IOException}. * * @throws IOException * if this method is called. */ @Override public void reset() throws IOException { throw new IOException(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy