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

com.wizzardo.tools.io.BlockInputStream Maven / Gradle / Ivy

package com.wizzardo.tools.io;

import java.io.IOException;
import java.io.InputStream;
import java.io.PushbackInputStream;
import java.util.Arrays;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * @author Moxa
 */
public class BlockInputStream extends InputStream {

    private PushbackInputStream in;
    private byte[] buffer, dynamicBuffer;
    private boolean close = false;
    private byte[] separator;
    private boolean wait = true;
    private int findedIndex = -1;
    private int offset = 0;
    private int r, endimg, buffered;
    private BoyerMoore bm;
    private long blockLength = 0;
    private long limit = 0;
    private long totalRead = 0;
    private ProgressListener progressListener;

    public BlockInputStream(InputStream in, byte[] separator) {
        this.separator = Arrays.copyOf(separator, separator.length);
        this.in = new PushbackInputStream(in, 1024 * 50);
        buffer = new byte[separator.length];
        bm = new BoyerMoore(separator);
    }

    public BlockInputStream(InputStream in, byte[] separator, long limit) {
        this(in, separator);
        this.limit = limit;
    }

    public BlockInputStream(InputStream in, byte[] separator, long limit, ProgressListener progressListener) {
        this(in, separator, limit);
        this.progressListener = progressListener;
    }

    public InputStream getInputStream() throws IOException {
        if (!wait) {
            throw new IllegalStateException("this method can be executed only between blocks");
        }
        if (dynamicBuffer != null) {
            in.unread(dynamicBuffer, offset, dynamicBuffer.length - offset);
        }
        return in;
    }

    public boolean hasNext() throws IOException {
        if (limitReached()) {
            return false;
        }
        return dynamicBuffer != null || ready();
    }

    public void next() {
        wait = false;
        blockLength = 0;
    }

    @Override
    public int read() throws IOException {
        if (limitReached()) {
            return -1;
        }

        byte[] bytes = new byte[1];
        int r = read(bytes);
        if (r == 0)
            return -1;

        return bytes[0] & 0xff;
    }

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

    private boolean limitReached() {
        return dynamicBuffer == null && limit > 0 && totalRead >= limit;
    }

    public int read(byte[] b, int off, int l) throws IOException {
        if (limitReached()) {
            return -1;
        }
        if (l < separator.length) {
            throw new IllegalArgumentException("byte array MUST be bigger then separator");
        }
        if (wait) {
            return -1;
        }
        if (dynamicBuffer != null) {
            int k = dynamicBuffer.length - offset;
            if (k >= l) {
                System.arraycopy(dynamicBuffer, offset, b, off, l);
                offset += l;
                if (offset == dynamicBuffer.length) {
                    dynamicBuffer = null;
                    offset = 0;
                }
                r = l;
            } else {
                System.arraycopy(dynamicBuffer, offset, b, off, k);
                dynamicBuffer = null;
                offset = 0;
                r = k;
            }
        } else {
            if (buffered > 0) {
                System.arraycopy(buffer, 0, b, off, buffered);
                r = in.read(b, buffered + off, l - buffered);
                if (r != -1) {
                    r += buffered;
                    totalRead += r;
                } else {
                    r = buffered;
                }
                buffered = 0;
            } else {
                if (ready()) {
                    r = in.read(b, off, l);
                    totalRead += r;
                } else {
                    r = -1;
                }
            }
        }

        if (progressListener != null) {
            if (totalRead != limit)
                progressListener.setProgress((int) (totalRead * 100f / limit));
            else
                progressListener.setProgress(100);
        }

        if (r != -1) {
            findedIndex = bm.search(b, off, r);
            if (findedIndex != -1) {
                wait = true;
                int length = r - findedIndex - separator.length + off;
                if (length != 0) {
                    dynamicBuffer = new byte[length];
                    System.arraycopy(b, findedIndex + separator.length, dynamicBuffer, 0, dynamicBuffer.length);
                }
                blockLength += findedIndex;
                return findedIndex - off;
            } else {
                endimg = isEnding(b, r, separator);
                if (endimg != -1) {
                    buffered = r - endimg;
                    System.arraycopy(b, endimg, buffer, 0, buffered);
                    blockLength += endimg;
                    return endimg;
                } else {
                    blockLength += r;
                    return r;
                }
            }
        }
        return -1;
    }

    public long getBlockLength() {
        return blockLength;
    }

    public void close() throws IOException {
        in.close();
        close = true;
        in = null;
    }

    public static int isEnding(byte[] b, int length, byte[] endsWith) {
        int i = length - endsWith.length;
        if (i < 0) {
            i = 0;
        }
        outer:
        for (; i < length; i++) {
            int j = 0;
            while (j < endsWith.length && j + i < length && b[i + j] == endsWith[j]) {
                j++;
            }
            if (j + i == length) {
                return i;
            }
        }
        return -1;
    }

    private int endOfBlock(byte[] b, int offset, int length) {
        int i = offset;
        if (i < 0) {
            i = 0;
        }
        outer:
        while (i <= length - separator.length) {
            int j = 0;
            while (j < separator.length && b[i + j] == separator[j]) {
                j++;
            }
            if (j == separator.length) {
                return i;
            }
            i++;
        }
        return -1;
    }

    public boolean ready() throws IOException {
        if (!close && (dynamicBuffer == null || limit > 0 && totalRead < limit)) {
            long wait = 0;
            int r;
            while ((r = in.read()) == -1 && wait < 500) {
                try {
                    Thread.sleep(1);
                } catch (InterruptedException ex) {
                    Logger.getLogger(BlockInputStream.class.getName()).log(Level.SEVERE, null, ex);
                }
                wait++;
            }
            if (r == -1) {
                return false;
            }
            in.unread(r);
            return true;
        } else {
            return false;
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy