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

org.codehaus.swizzle.stream.PushbackInputStream Maven / Gradle / Ivy

There is a newer version: 10.0.0-M3
Show newest version
/**
 *  Licensed 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 org.codehaus.swizzle.stream;

import java.util.LinkedList;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.io.InputStream;
import java.io.IOException;

public class PushbackInputStream extends InputStream implements PushbackBuffer {
    private final InputStream delegate;
    private final LinkedList pushbackBuffers = new LinkedList();

    private byte[] markBuffer;
    private int markCount;

    public PushbackInputStream() {
        this(null);
    }

    public PushbackInputStream(InputStream delegate) {
        this.delegate = delegate;
    }

    public InputStream getDelegate() {
        return delegate;
    }

    public int read() throws IOException {
        int next = -1;

        // first check the pushback buffer
        for (Iterator iterator = pushbackBuffers.iterator(); iterator.hasNext();) {
            PushbackBuffer buffer = iterator.next();
            if (buffer.hasNext()) {
                next = buffer.next();
                break;
            }
            iterator.remove();
        }

        // if we didn't get a byte from the pushback buffer, get the next byte internally
        if (next == -1) {
            next = getNextByte();
        }

        // before returning the byte, add it to the mark buffer
        if (next != -1) {
            addToMarkBuffer((byte) next);
        }

        return next;
    }

    protected int getNextByte() throws IOException {
        if (delegate != null) {
            return delegate.read();
        }
        return -1;
    }

    /**
     * Add a byte to the mark buffer if mark is active
     */
    protected void addToMarkBuffer(byte b) {
        // if there is no mark we are done
        if (markBuffer == null) {
            return;
        }

        // growBuffer if necessary
        if (markCount >= markBuffer.length) {
            byte[] oldBuf = markBuffer;
            markBuffer = new byte[oldBuf.length * 2];

            System.arraycopy(oldBuf, 0, markBuffer, 0, oldBuf.length);
        }

        // add byte
        markBuffer[markCount++] = b;
    }

    public boolean markSupported() {
        return true;
    }

    /**
     * Activate mark/reset buffer.
     * This will release any previous marks.
     * @param readlimit suggested mark buffer size
     */
    public void mark(int readlimit) {
        markBuffer = new byte[readlimit];
    }

    /**
     * Release current mark/reset buffer.
     */
    public void unmark() {
        markBuffer = null;
        markCount = 0;
    }

    /**
     * Push the mark/reset buffer onto the pushback buffer, and release the mark
     */
    public void reset() {
        if (markCount > 0) {
            pushbackBuffers.addFirst(new PushbackBuffer(markBuffer, 0, markCount));
        }
        unmark();
    }

    public void unread(byte[] bytes) {
        unread(bytes, 0, bytes.length);
    }

    public void unread(byte[] bytes, int off, int len) {
        pushbackBuffers.addFirst(new PushbackBuffer(bytes, off, len));
    }

    public byte[] getBuffer() {
        int size = 0;
        for (PushbackBuffer buffer : pushbackBuffers) {
            size += buffer.size();
        }

        int off = 0;
        byte[] out = new byte[size];
        for (PushbackBuffer buffer : pushbackBuffers) {
            off += buffer.copyBuffer(out, off);
        }
        return out;
    }

    private static class PushbackBuffer {
        private final byte[] buf;
        private int pos;
        private final int end;

        private PushbackBuffer(byte[] buf, int off, int len) {
            if (buf == null) throw new NullPointerException("buf is null");
            if (off < 0) throw new IllegalArgumentException("pos is negative");
            if (len < 0) throw new IllegalArgumentException("len is negative");
            if (off + len > buf.length) throw new IllegalArgumentException("off + len is greater then buf size");
            this.buf = buf;
            this.pos = off;
            this.end = off + len;
        }

        public boolean hasNext() {
            return pos < end;
        }

        public byte next() {
            if (!hasNext()) {
                throw new NoSuchElementException();
            }
            return buf[pos++];
        }

        public int size() {
            return Math.max(end - pos, 0);
        }

        public int copyBuffer(byte[] outBuf, int off) {
            int size = size();
            System.arraycopy(buf, pos, outBuf, off, size);
            return size;
        }

        public String toString() {
            return new String(buf, pos, end - pos);
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy