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

org.apache.sshd.common.util.buffer.ByteArrayBuffer Maven / Gradle / Ivy

Go to download

This artifact provides a single jar that contains all classes required to use remote EJB and JMS, including all dependencies. It is intended for use by those not using maven, maven users should just import the EJB and JMS BOM's instead (shaded JAR's cause lots of problems with maven, as it is very easy to inadvertently end up with different versions on classes on the class path).

There is a newer version: 34.0.0.Final
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package org.apache.sshd.common.util.buffer;

import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.Objects;
import java.util.function.IntUnaryOperator;

import org.apache.sshd.common.util.GenericUtils;
import org.apache.sshd.common.util.NumberUtils;
import org.apache.sshd.common.util.Readable;
import org.apache.sshd.common.util.ValidateUtils;

/**
 * Provides an implementation of {@link Buffer} using a backing byte array
 *
 * @author Apache MINA SSHD Project
 */
public class ByteArrayBuffer extends Buffer {
    /**
     * Initial default allocated buffer size if none specified
     */
    public static final int DEFAULT_SIZE = 256;

    private byte[] data;
    private int rpos;
    private int wpos;

    /**
     * Allocates a buffer for writing purposes with {@value #DEFAULT_SIZE} bytes
     */
    public ByteArrayBuffer() {
        this(DEFAULT_SIZE, false);
    }

    /**
     * Allocates a buffer for writing purposes
     *
     * @param size Initial buffer size - Note: it is rounded to the closest power of 2 that is greater or
     *             equal to it.
     * @see        #ByteArrayBuffer(int, boolean)
     */
    public ByteArrayBuffer(int size) {
        this(size, true);
    }

    /**
     * Allocates a buffer for writing purposes
     *
     * @param size     Initial buffer size
     * @param roundOff Whether to round it to closest power of 2 that is greater or equal to the specified size
     */
    public ByteArrayBuffer(int size, boolean roundOff) {
        this(new byte[roundOff ? BufferUtils.getNextPowerOf2(size) : size], false);
    }

    /**
     * Wraps data bytes for reading
     *
     * @param data Data bytes to read from
     * @see        #ByteArrayBuffer(byte[], boolean)
     */
    public ByteArrayBuffer(byte[] data) {
        this(data, 0, data.length, true);
    }

    /**
     * @param data Data bytes to use
     * @param read Whether the data bytes are for reading or writing
     */
    public ByteArrayBuffer(byte[] data, boolean read) {
        this(data, 0, data.length, read);
    }

    /**
     * Wraps data bytes for reading
     *
     * @param data Data bytes to read from
     * @param off  Offset to read from
     * @param len  Available bytes from given offset
     * @see        #ByteArrayBuffer(byte[], int, int, boolean)
     */
    public ByteArrayBuffer(byte[] data, int off, int len) {
        this(data, off, len, true);
    }

    /**
     * @param data Data bytes to use
     * @param off  Offset to read/write (according to read parameter)
     * @param len  Available bytes from given offset
     * @param read Whether the data bytes are for reading or writing
     */
    public ByteArrayBuffer(byte[] data, int off, int len, boolean read) {
        if ((off < 0) || (len < 0)) {
            throw new IndexOutOfBoundsException("Invalid offset(" + off + ")/length(" + len + ")");
        }
        this.data = data;
        this.rpos = off;
        this.wpos = (read ? len : 0) + off;
    }

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

    @Override
    public void rpos(int rpos) {
        this.rpos = rpos;
    }

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

    @Override
    public void wpos(int wpos) {
        if (wpos > this.wpos) {
            ensureCapacity(wpos - this.wpos);
        }
        this.wpos = wpos;
    }

    @Override
    public int available() {
        return wpos - rpos;
    }

    @Override
    public int capacity() {
        return data.length - wpos;
    }

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

    @Override
    public byte[] getBytesConsumed() {
        byte[] consumed = new byte[rpos];
        System.arraycopy(data, 0, consumed, 0, rpos);
        return consumed;
    }

    @Override
    public byte rawByte(int pos) {
        return data[pos];
    }

    @Override
    public long rawUInt(int pos) {
        return BufferUtils.getUInt(data, pos, Integer.BYTES);
    }

    @Override
    public void compact() {
        int avail = available();
        if (avail > 0) {
            System.arraycopy(data, rpos, data, 0, avail);
        }
        wpos -= rpos;
        rpos = 0;
    }

    @Override
    public Buffer clear(boolean wipeData) {
        rpos = 0;
        wpos = 0;

        if (wipeData) {
            Arrays.fill(data, (byte) 0);
        }

        return this;
    }

    @Override
    public byte getByte() {
        ensureAvailable(Byte.BYTES);
        return data[rpos++];
    }

    @Override
    public void putByte(byte b) {
        ensureCapacity(Byte.BYTES);
        data[wpos++] = b;
    }

    @Override
    public int putBuffer(Readable buffer, boolean expand) {
        int required = expand ? buffer.available() : Math.min(buffer.available(), capacity());
        ensureCapacity(required);
        buffer.getRawBytes(data, wpos, required);
        wpos += required;
        return required;
    }

    @Override
    public void putBuffer(ByteBuffer buffer) {
        int required = buffer.remaining();
        ensureCapacity(required + Integer.SIZE);
        putUInt(required);
        buffer.get(data, wpos, required);
        wpos += required;
    }

    @Override
    public void putRawBytes(byte[] d, int off, int len) {
        ValidateUtils.checkTrue(len >= 0, "Negative raw bytes length: %d", len);
        ensureCapacity(len);
        System.arraycopy(d, off, data, wpos, len);
        wpos += len;
    }

    @Override
    public String getString(Charset charset) {
        Objects.requireNonNull(charset, "No charset specified");

        int reqLen = getInt();
        int len = ensureAvailable(reqLen);
        String s = new String(data, rpos, len, charset);
        rpos += len;
        return s;
    }

    @Override
    public void getRawBytes(byte[] buf, int off, int len) {
        ensureAvailable(len);
        copyRawBytes(0, buf, off, len);
        rpos += len;
    }

    @Override
    protected void copyRawBytes(int offset, byte[] buf, int pos, int len) {
        if ((offset < 0) || (pos < 0) || (len < 0)) {
            throw new IndexOutOfBoundsException(
                    "Invalid offset(" + offset + ")/position(" + pos + ")/length(" + len + ") required");
        }
        System.arraycopy(data, rpos + offset, buf, pos, len);
    }

    @Override
    public Buffer ensureCapacity(int capacity, IntUnaryOperator growthFactor) {
        ValidateUtils.checkTrue(capacity >= 0, "Negative capacity requested: %d", capacity);

        int maxSize = size();
        int curPos = wpos();
        int remaining = maxSize - curPos;
        if (remaining < capacity) {
            int minimum = curPos + capacity;
            int actual = growthFactor.applyAsInt(minimum);
            if (actual < minimum) {
                throw new IllegalStateException(
                        "ensureCapacity(" + capacity + ") actual (" + actual + ") below min. (" + minimum + ")");
            }
            byte[] tmp = new byte[actual];
            System.arraycopy(data, 0, tmp, 0, data.length);
            data = tmp;
        }

        return this;
    }

    @Override
    protected int size() {
        return data.length;
    }

    /**
     * Creates a compact buffer (i.e., one that starts at offset zero) containing a copy of the original data
     *
     * @param  data The original data buffer
     * @return      A {@link ByteArrayBuffer} containing a copy of the original data starting at zero read
     *              position
     * @see         #getCompactClone(byte[], int, int)
     */
    public static ByteArrayBuffer getCompactClone(byte[] data) {
        return getCompactClone(data, 0, NumberUtils.length(data));
    }

    /**
     * Creates a compact buffer (i.e., one that starts at offset zero) containing a copy of the original data
     *
     * @param  data   The original data buffer
     * @param  offset The offset of the valid data in the buffer
     * @param  len    The size (in bytes) of of the valid data in the buffer
     * @return        A {@link ByteArrayBuffer} containing a copy of the original data starting at zero read
     *                position
     */
    public static ByteArrayBuffer getCompactClone(byte[] data, int offset, int len) {
        byte[] clone = (len > 0) ? new byte[len] : GenericUtils.EMPTY_BYTE_ARRAY;
        if (len > 0) {
            System.arraycopy(data, offset, clone, 0, len);
        }

        return new ByteArrayBuffer(clone, true);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy