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

org.cuberact.tools.bytes.ByteData Maven / Gradle / Ivy

package org.cuberact.tools.bytes;

import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.Arrays;

import static org.cuberact.tools.bytes.ByteConst.CR;
import static org.cuberact.tools.bytes.ByteConst.LF;

public final class ByteData extends ABytes {

    private static final int CHUNK_SIZE = 65536;
    private static final int MAX_DATA_SIZE = Integer.MAX_VALUE - 8;

    private final int chunkSize;
    private byte[] data;
    private int size;

    public ByteData() {
        this(CHUNK_SIZE);
    }

    public ByteData(final int chunkSize) {
        this.data = new byte[chunkSize];
        this.chunkSize = chunkSize;
        this.size = 0;
    }

    public ByteData(final byte[] data) {
        this(data, CHUNK_SIZE);
    }

    public ByteData(final byte[] data, final int chunkSize) {
        this.data = data;
        this.size = data.length;
        this.chunkSize = chunkSize;
    }

    public ByteData add(final byte b) {
        addToData(b);
        return this;
    }

    public ByteData add(final byte[] bytes) {
        return add(bytes, bytes.length);
    }

    public ByteData add(final byte[] bytes, final int length) {
        if (bytes.length > 0) {
            for (int i = 0; i < length; i++) {
                addToData(bytes[i]);
            }
        }
        return this;
    }

    public ByteData add(final CharSequence sequence, final Charset charset) {
        if (sequence == null || sequence.length() == 0) return this;
        return add(sequence.toString().getBytes(charset));
    }

    public ByteData add(final Bytes bytes) {
        final int byteSize = bytes.size(); //important, because param byteData can be this (same instance)
        for (int i = 0; i < byteSize; i++) {
            addToData(bytes.get(i));
        }
        return this;
    }

    public ByteData add(final Bytes bytes, final ByteToken token) {
        for (int i = token.from; i <= token.to; i++) {
            addToData(bytes.get(i));
        }
        return this;
    }

    public ByteData add(final ByteInputStream stream, final byte[] separator) {
        while (true) {
            add(readOneByte(stream));
            if (endWith(separator)) {
                return this;
            }
        }
    }

    public ByteData addLine(final ByteInputStream stream) {
        while (true) {
            add(readOneByte(stream));
            if (data[size - 1] == CR) {
                byte nextChar = readOneByte(stream);
                if (nextChar == LF) {
                    add(nextChar);
                } else {
                    stream.repeatLastByte();
                }
                return this;
            } else if (data[size - 1] == LF) {
                return this;
            }
        }
    }

    public ByteData add(final ByteInputStream stream, final int length) {
        for (int i = 0; i < length; i++) {
            addToData(readOneByte(stream));
        }
        return this;
    }

    public ByteData add(final ByteInputStream stream) {
        while (true) {
            try {
                int intValue = stream.read();
                if (intValue == -1) {
                    return this;
                }
                addToData((byte) intValue);
            } catch (IOException e) {
                throw new ByteException(e);
            }
        }
    }

    public ByteData drop(final int byteCount) {
        if (byteCount > 0) {
            size -= byteCount;
            size = size < 0 ? 0 : size;
        }
        return this;
    }

    public ByteData clear() {
        size = 0;
        return this;
    }

    public ByteData align() {
        if (size != data.length) {
            data = Arrays.copyOf(data, size);
        }
        return this;
    }

    @Override
    public byte get(final int index) {
        return data[index];
    }

    @Override
    public int size() {
        return size;
    }

    @Override
    public byte[] toArray() {
        align();
        return data;
    }

    @Override
    public byte[] toArray(final ByteToken token) {
        final int sizeMinusOne = size() - 1;
        final int f = token.from() < 0 ? 0 : token.from();
        final int t = token.to() > sizeMinusOne ? sizeMinusOne : token.to();
        if (f == 0 && t == sizeMinusOne) return toArray();
        return Arrays.copyOfRange(data, f, t + 1);
    }

    private void addToData(final byte b) {
        ensureDataSize();
        data[size++] = b;
    }

    private void ensureDataSize() {
        if (size == data.length) {
            int newSize = data.length + chunkSize;
            if (newSize > MAX_DATA_SIZE) newSize = MAX_DATA_SIZE;
            if (newSize > data.length) {
                byte[] enlarged = new byte[newSize];
                System.arraycopy(data, 0, enlarged, 0, data.length);
                data = enlarged;
            }
            if (chunkSize == 0) throw new ByteException("Chunk size is zero");
            if (size == data.length) throw new ByteException("Ensure data size fail. Too big [" + size + "]");
        }
    }

    private static byte readOneByte(final InputStream inputStream) throws ByteException {
        try {
            int intValue = inputStream.read();
            if (intValue == -1) {
                throw new ByteException("Unexpected end of stream");
            }
            return (byte) intValue;
        } catch (IOException e) {
            throw new ByteException(e);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy