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

com.github.azbh111.utils.java.lang.io.CharSequenceInputStream Maven / Gradle / Ivy

package com.github.azbh111.utils.java.lang.io;

import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.*;

/**
 * 源自guava org.apache.commons.io.input.CharSequenceInputStream
 */
public class CharSequenceInputStream extends InputStream {
    private static final int BUFFER_SIZE = 2048;
    private static final int NO_MARK = -1;
    private final CharsetEncoder encoder;
    private final CharBuffer cbuf;
    private final ByteBuffer bbuf;
    private int mark_cbuf;
    private int mark_bbuf;

    public CharSequenceInputStream(CharSequence cs, Charset charset, int bufferSize) {
        this.encoder = charset.newEncoder().onMalformedInput(CodingErrorAction.REPLACE).onUnmappableCharacter(CodingErrorAction.REPLACE);
        float maxBytesPerChar = this.encoder.maxBytesPerChar();
        if ((float) bufferSize < maxBytesPerChar) {
            throw new IllegalArgumentException("Buffer size " + bufferSize + " is less than maxBytesPerChar " + maxBytesPerChar);
        } else {
            this.bbuf = ByteBuffer.allocate(bufferSize);
            this.bbuf.flip();
            this.cbuf = CharBuffer.wrap(cs);
            this.mark_cbuf = -1;
            this.mark_bbuf = -1;
        }
    }

    public CharSequenceInputStream(CharSequence cs, String charset, int bufferSize) {
        this(cs, Charset.forName(charset), bufferSize);
    }

    public CharSequenceInputStream(CharSequence cs, Charset charset) {
        this(cs, (Charset) charset, 2048);
    }

    public CharSequenceInputStream(CharSequence cs, String charset) {
        this(cs, (String) charset, 2048);
    }

    private void fillBuffer() throws CharacterCodingException {
        this.bbuf.compact();
        CoderResult result = this.encoder.encode(this.cbuf, this.bbuf, true);
        if (result.isError()) {
            result.throwException();
        }

        this.bbuf.flip();
    }

    @Override
    public int read(byte[] b, int off, int len) throws IOException {
        if (b == null) {
            throw new NullPointerException("Byte array is null");
        } else if (len >= 0 && off + len <= b.length) {
            if (len == 0) {
                return 0;
            } else if (!this.bbuf.hasRemaining() && !this.cbuf.hasRemaining()) {
                return -1;
            } else {
                int bytesRead = 0;

                while (len > 0) {
                    if (this.bbuf.hasRemaining()) {
                        int chunk = Math.min(this.bbuf.remaining(), len);
                        this.bbuf.get(b, off, chunk);
                        off += chunk;
                        len -= chunk;
                        bytesRead += chunk;
                    } else {
                        this.fillBuffer();
                        if (!this.bbuf.hasRemaining() && !this.cbuf.hasRemaining()) {
                            break;
                        }
                    }
                }

                return bytesRead == 0 && !this.cbuf.hasRemaining() ? -1 : bytesRead;
            }
        } else {
            throw new IndexOutOfBoundsException("Array Size=" + b.length + ", offset=" + off + ", length=" + len);
        }
    }

    @Override
    public int read() throws IOException {
        do {
            if (this.bbuf.hasRemaining()) {
                return this.bbuf.get() & 255;
            }

            this.fillBuffer();
        } while (this.bbuf.hasRemaining() || this.cbuf.hasRemaining());

        return -1;
    }

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

    @Override
    public long skip(long n) throws IOException {
        long skipped;
        for (skipped = 0L; n > 0L && this.available() > 0; ++skipped) {
            this.read();
            --n;
        }

        return skipped;
    }

    @Override
    public int available() throws IOException {
        return this.bbuf.remaining() + this.cbuf.remaining();
    }

    @Override
    public void close() throws IOException {
    }

    public synchronized void mark(int readlimit) {
        this.mark_cbuf = this.cbuf.position();
        this.mark_bbuf = this.bbuf.position();
        this.cbuf.mark();
        this.bbuf.mark();
    }

    @Override
    public synchronized void reset() throws IOException {
        if (this.mark_cbuf != -1) {
            if (this.cbuf.position() != 0) {
                this.encoder.reset();
                this.cbuf.rewind();
                this.bbuf.rewind();
                this.bbuf.limit(0);

                while (this.cbuf.position() < this.mark_cbuf) {
                    this.bbuf.rewind();
                    this.bbuf.limit(0);
                    this.fillBuffer();
                }
            }

            if (this.cbuf.position() != this.mark_cbuf) {
                throw new IllegalStateException("Unexpected CharBuffer postion: actual=" + this.cbuf.position() + " expected=" + this.mark_cbuf);
            }

            this.bbuf.position(this.mark_bbuf);
            this.mark_cbuf = -1;
            this.mark_bbuf = -1;
        }

    }

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




© 2015 - 2024 Weber Informatics LLC | Privacy Policy