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

com.ebmwebsourcing.easycommons.stream.ReaderInputStream Maven / Gradle / Ivy

/****************************************************************************
 * Copyright (c) 2010-2012, EBM WebSourcing - All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the University of California, Berkeley nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ****************************************************************************/
 
package com.ebmwebsourcing.easycommons.stream;

import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;

public class ReaderInputStream extends InputStream {
    /**
     * The initial {@link Reader}.
     */
    private Reader reader;

    /**
     * As a buffer reads from a Reader is bigger than a buffer reads from an
     * InputStream, we need to keep characters read from the Reader and not
     * returned to the client. They are stored in this buffer.
     * 
     */
    private byte[] internalBuffer = null;

    private int internalBufferPos = 0;

    /**
     * The constructor.
     * 
     * @param reader
     *            The Reader to wrap. Not null.
     */
    public ReaderInputStream(final Reader reader) {
        if (reader == null) {
            throw new IllegalArgumentException("Reader cannot be null.");
        }
        this.reader = reader;
    }

    /**
     * Returns available bytes in the internal buffer incremented by one if the
     * reader is ready (see {@link Reader#ready()}).
     * 
     * @see java.io.InputStream#available()
     */
    @Override
    public int available() throws IOException {

        if (this.reader.ready()) {
            // A next read on the reader can be done withoutto be blocked.
            // We do the read to check if a character is available or EOF is
            // expected
            final int availableChar = this.reader.read();
            if (availableChar != -1) {
                // We push the read character in the internal buffer
                if (this.internalBuffer != null) {
                    final byte[] newBuffer = new byte[this.internalBuffer.length + 1];
                    System.arraycopy(this.internalBuffer, 0, newBuffer, 0,
                            this.internalBuffer.length);
                    newBuffer[newBuffer.length - 1] = (byte) availableChar;
                    this.internalBuffer = newBuffer;
                } else {
                    this.internalBuffer = new String(new char[] { (char) availableChar })
                            .getBytes();
                    this.internalBufferPos = 0;
                }
            }
        }
        return this.internalBuffer == null ? 0
                : (this.internalBuffer.length - this.internalBufferPos);
    }

    @Override
    public void close() throws IOException {
        this.reader.close();
    }

    @Override
    public boolean markSupported() {
        return false;
    }

    @Override
    public int read() throws IOException {
        byte[] buffer = new byte[1];
        int nbByteRead = this.read(buffer);
        if (nbByteRead != 1) {
            throw new IOException("No byte read.");
        }
        return buffer[0];
    }

    @Override
    public int read(final byte[] cbuf) throws IOException {
        return this.read(cbuf, 0, cbuf.length);
    }

    @Override
    public int read(final byte[] cbuf, final int off, final int len) throws IOException {
        return this.localRead(cbuf, off, len, false);
    }

    @Override
    public long skip(long n) throws IOException, IllegalArgumentException {
        if (n > Long.MAX_VALUE) {
            throw new IllegalArgumentException("Only value lesser " + Integer.MAX_VALUE
                    + "are accepted.");
        }
        return this.localRead(null, 0, (int) n, true);
    }

    private int localRead(final byte[] buf, final int off, final int len, final boolean skip)
            throws IOException {

        int remainingLen = len;
        int offset = off;

        // First we read from the internal buffer
        int bytesToReadInInternalBuffer = this.internalBuffer == null ? 0 : Math.min(len,
                this.internalBuffer.length - this.internalBufferPos);
        if (bytesToReadInInternalBuffer > 0) {
            if (!skip) {
                System.arraycopy(this.internalBuffer, this.internalBufferPos, buf, offset,
                        bytesToReadInInternalBuffer);
            }
            remainingLen -= bytesToReadInInternalBuffer;
            this.internalBufferPos += bytesToReadInInternalBuffer;
        }

        if (remainingLen > 0) {
            offset += bytesToReadInInternalBuffer;
            // We must complete the provided buffer with bytes read from the
            // reader
            final char[] cbuf = new char[remainingLen];
            int charRead = this.reader.read(cbuf, 0, remainingLen);
            if (charRead == -1) {
                // EOF: No more character in the reader
                if (len == remainingLen) {
                    // No bytes available --> EOF
                    return -1;
                } else {
                    // Few characters bytes have read from the internal buffer
                    return len - remainingLen;
                }
            } else {
                this.internalBuffer = new String(cbuf, 0, charRead).getBytes();
                this.internalBufferPos = 0;
                bytesToReadInInternalBuffer = Math.min(remainingLen, charRead);
                if (!skip) {
                    System.arraycopy(this.internalBuffer, 0, buf, offset,
                            bytesToReadInInternalBuffer);
                }
                this.internalBufferPos += bytesToReadInInternalBuffer;

                // Now the provided buffer should be full
                return bytesToReadInInternalBuffer;
            }

        } else {
            // No more bytes to read, the provided buffer is full
            return len;
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy