⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rewindableinputstream.java

📁 电子地图服务器,搭建自己的地图服务
💻 JAVA
📖 第 1 页 / 共 2 页
字号:
//
// Borrowed from org.apache.xerces.impl.XMLEntityManager,
// slightly modified and commented out. -AK
//
// This class wraps the byte inputstreams we're presented with.
// We need it because java.io.InputStreams don't provide
// functionality to reread processed bytes, and they have a habit
// of reading more than one character when you call their read()
// methods.  This means that, once we discover the true (declared)
// encoding of a document, we can neither backtrack to read the
// whole doc again nor start reading where we are with a new
// reader.
//
// This class allows rewinding an inputStream by allowing a mark
// to be set, and the stream reset to that position.  <strong>The
// class assumes that it needs to read one character per
// invocation when it's read() method is inovked, but uses the
// underlying InputStream's read(char[], offset length) method--it
// won't buffer data read this way!</strong>
//
// @task TODO: How about implementing an ability to completely
//             disable buffering performed by this stream?
//             It is very unlikely that someone will read data from
//             the stream byte by byte with <code>read()</code>
//             method, but if they do, the whole content will
//             be unconditionally stored in internal buffer, resulting
//             in additional (and most probably vain) memory impact.
//
// @author Neil Graham, IBM
// @author Glenn Marcy, IBM
//
package org.geoserver.ows.util;

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


public class RewindableInputStream extends InputStream {
    /**
     * Default buffer size before we've finished with the XMLDecl:
     * I think the name should be left unchanged to give a hint for
     * possible use of this class :)
     */
    public static final int DEFAULT_XMLDECL_BUFFER_SIZE = 64;

    /**
     * Tells whether <code>read(byte[], int, int)</code> method
     * is allowed to read multiple bytes beyond the internal buffer
     * (<code>true</code>) or not (<code>true</code> is the default)
     */
    protected boolean fMayReadChunks;

    /**
     * Source input stream we are wrapping with rewindable one.
     */
    protected InputStream fInputStream;

    /**
     * Internal buffer of bytes already read from source input stream.
     * Allows to access the same byte more than once.
     */
    protected byte[] fData;

    /**
     * Position in the stream that to which stream pointer can be reset
     * with <code>rewind</code> method invocation.
     */
    protected int fStartOffset;

    /**
     * Position where the end of underlying stream was encountered. Potentially
     * in <code>RewindableInputStream</code> instance stream's "end" could be
     * reached more than once, so it is a good thing to know where original
     * stream ended to avoid <code>IOExceptions</code>.
     */
    protected int fEndOffset;

    /**
     * Offset of the next byte to be read from the stream relative to
     * the beginning of the stream (and <code>fData</code> array as well)
     */
    protected int fOffset;

    /**
     * Number of read bytes currently stored in <code>fData</code> buffer.
     * Size of the buffer itself can be greater than this value, obviously.
     */
    protected int fLength;

    /**
     * Offset of the "marked" position in the stream relative to its beginning.
     */
    protected int fMark;

    /**
     * Creates new <code>RewindableInputStream</code> object with internal
     * buffer of default size and default value of chunked reading flag (which
     * is _currently_ <code>true</code>).
     *
     * @param  is  InputStream that needs basic reset/rewind functionality.
     */
    public RewindableInputStream(InputStream is) {
        this(is, true, DEFAULT_XMLDECL_BUFFER_SIZE);
    }

    /**
     * Creates new RewindableInputStream with internal buffer of specified size
     * and no chunk reading beyound the buffer limits allowed.
     *
     * @param  is  InputStream that needs some reset/rewind functionality.
     *
     * @param  chunkedMode  See the <code>RewindableInputStream(InputStream,
     *                      boolean, int)</code> constructor description.
     */
    public RewindableInputStream(InputStream is, boolean chunkedMode) {
        this(is, chunkedMode, DEFAULT_XMLDECL_BUFFER_SIZE);
    }

    /**
     * Primary constructor that allows to specify all parameters exlicitly
     * affecting class work (initial size of the internal buffer and
     * chunk read mode).
     *
     * @param  is  InputStream that needs some reset/rewind functionality.
     *
     * @param  chunkedMode
     *
     *         Initial value of <code>fMayReadChunks</code> flag which determines
     *         whether multiple bytes can be read from the underlying stream in
     *         single reading operation or not. This value can be changed using
     *         <code>setChunkedMode</code> (or its aliases). For specific
     *         purpose of inferring encoding/charset of XML document typical
     *         usage policy is to disable chunked reads while obtaining XML
     *         declaration and then enable it to speed up reading the rest of
     *         document.
     *
     * @param  initialSize  Initial size of the internal buffer array.
     */
    public RewindableInputStream(InputStream is, boolean chunkedMode, int initialSize) {
        if (0 >= initialSize) {
            initialSize = DEFAULT_XMLDECL_BUFFER_SIZE;
        }

        fData = new byte[initialSize];

        fInputStream = is;
        fStartOffset = 0;
        fMayReadChunks = chunkedMode;
        fEndOffset = -1;
        fOffset = 0;
        fLength = 0;
        fMark = 0;
    }

    /**
     * Sets the position somewhere in the stream to which the stream pointer
     * will be reset after <code>rewind</code> invocation. By default this
     * position is the beginning of the stream.
     *
     * @param  offset  New value for "fStartOffset".
     */
    public void setStartOffset(int offset) {
        fStartOffset = offset;
    }

    /**
     * Allows to change the behavior of the stream regarding chunked reading
     * at runtime. If you allowed chunked reading and then read some data from
     * the stream, you better forget about <code>reset</code>ting or
     * <code>rewind</code>ing it after that.
     *
     * @param  chunkedMode  New value for <code>fMayReadChunks</code>.
     */
    public void setChunkedMode(boolean chunkedMode) {
        fMayReadChunks = chunkedMode;
    }

    /**
     * More conscious alias for <code>setChunkedMode(true)</code>. While last
     * method is a general purpose mutator, code may look a bit more clear if
     * you use specialized methods to enable/disable chunk read mode.
     */
    public void enableChunkedMode() {
        fMayReadChunks = true;
    }

    /**
     * More conscious alias for <code>setChunkedMode(false)</code>. While last
     * method is a general purpose mutator, code may look a bit more clear if
     * you use specialized methods to enable/disable chunk read mode.
     */
    public void disableChunkedMode() {
        fMayReadChunks = false;
    }

    /**
     * Quickly reset stream pointer to the beginning of the stream or to
     * position which offset was specified during the last
     * <code>setStartOffset</code> call.
     */
    public void rewind() {
        fOffset = fStartOffset;
    }

    /**
     * Reads next byte from this stream. This byte is either being read from
     * underlying InputStream or taken from the internal buffer in case it was
     * already read at some point before.
     *
     * @return Next byte of data or <code>-1</code> if end of stream is reached.
     *
     * @throws IOException in case of any I/O errors.
     */
    public int read() throws IOException {
        int b = 0;

        // Byte to be read is already in out buffer, simply returning it
        if (fOffset < fLength) {
            return fData[fOffset++] & 0xff;
        }

        /*
         * End of the stream is reached.
         * I also believe that in certain cases fOffset can point to the
         * position after the end of stream, for example, after invalid
         * `setStartOffset()` call followed by `rewind()`.
         * This situation is not handled currently.
         */
        if (fOffset == fEndOffset) {
            return -1;
        }

        /*
         * Ok, we should actually read data from underlying stream, but
         * first it will be good to check if buffer array should be
         * expanded. Each time buffer size is doubled.
         */
        if (fOffset == fData.length) {
            byte[] newData = new byte[fOffset << 1];
            System.arraycopy(fData, 0, newData, 0, fOffset);
            fData = newData;
        }

        // Reading byte from the underlying stream, storing it in buffer and
        // then returning it.
        b = fInputStream.read();

        if (b == -1) {
            fEndOffset = fOffset;

            return -1;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -