![JAR search and dependency download from the Maven repository](/logo.png)
com.neovisionaries.ws.client.ByteArray Maven / Gradle / Ivy
/*
* Copyright (C) 2015 Neo Visionaries Inc.
*
* Licensed 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 com.neovisionaries.ws.client;
import java.nio.ByteBuffer;
/**
* Expandable byte array with byte-basis and bit-basis operations.
*/
class ByteArray
{
private static final int ADDITIONAL_BUFFER_SIZE = 1024;
// The buffer.
private ByteBuffer mBuffer;
// The current length.
private int mLength;
/**
* Constructor with initial capacity.
*
* @param capacity
* Initial capacity for the internal buffer.
*/
public ByteArray(int capacity)
{
mBuffer = ByteBuffer.allocate(capacity);
mLength = 0;
}
/**
* Constructor with initial data. The length of the data is used
* as the initial capacity of the internal buffer.
*
* @param data
* Initial data.
*/
public ByteArray(byte[] data)
{
mBuffer = ByteBuffer.wrap(data);
mLength = data.length;
}
/**
* The length of the data.
*/
public int length()
{
return mLength;
}
/**
* Get a byte at the index.
*/
public byte get(int index) throws IndexOutOfBoundsException
{
if (index < 0 || mLength <= index)
{
// Bad index.
throw new IndexOutOfBoundsException(
String.format("Bad index: index=%d, length=%d", index, mLength));
}
return mBuffer.get(index);
}
/**
* Expand the size of the internal buffer.
*/
private void expandBuffer(int newBufferSize)
{
// Allocate a new buffer.
ByteBuffer newBuffer = ByteBuffer.allocate(newBufferSize);
// Copy the content of the current buffer to the new buffer.
int oldPosition = mBuffer.position();
mBuffer.position(0);
newBuffer.put(mBuffer);
newBuffer.position(oldPosition);
// Replace the buffers.
mBuffer = newBuffer;
}
/**
* Add a byte at the current position.
*/
public void put(int data)
{
// If the buffer is small.
if (mBuffer.capacity() < (mLength + 1))
{
expandBuffer(mLength + ADDITIONAL_BUFFER_SIZE);
}
mBuffer.put((byte)data);
++mLength;
}
/**
* Add data at the current position.
*
* @param source
* Source data.
*/
public void put(byte[] source)
{
// If the buffer is small.
if (mBuffer.capacity() < (mLength + source.length))
{
expandBuffer(mLength + source.length + ADDITIONAL_BUFFER_SIZE);
}
mBuffer.put(source);
mLength += source.length;
}
/**
* Add data at the current position.
*
* @param source
* Source data.
*
* @param index
* The index in the source data. Data from the index is copied.
*
* @param length
* The length of data to copy.
*/
public void put(byte[] source, int index, int length)
{
// If the buffer is small.
if (mBuffer.capacity() < (mLength + length))
{
expandBuffer(mLength + length + ADDITIONAL_BUFFER_SIZE);
}
mBuffer.put(source, index, length);
mLength += length;
}
/**
* Add data at the current position.
*
* @param source
* Source data.
*
* @param index
* The index in the source data. Data from the index is copied.
*
* @param length
* The length of data to copy.
*/
public void put(ByteArray source, int index, int length)
{
put(source.mBuffer.array(), index, length);
}
/**
* Convert to a byte array (byte[]
).
*/
public byte[] toBytes()
{
return toBytes(0);
}
public byte[] toBytes(int beginIndex)
{
return toBytes(beginIndex, length());
}
public byte[] toBytes(int beginIndex, int endIndex)
{
int len = endIndex - beginIndex;
if (len < 0 || beginIndex < 0 || mLength < endIndex)
{
throw new IllegalArgumentException(
String.format("Bad range: beginIndex=%d, endIndex=%d, length=%d",
beginIndex, endIndex, mLength));
}
byte[] bytes = new byte[len];
if (len != 0)
{
System.arraycopy(mBuffer.array(), beginIndex, bytes, 0, len);
}
return bytes;
}
public void clear()
{
mBuffer.clear();
mBuffer.position(0);
mLength = 0;
}
public void shrink(int size)
{
if (mBuffer.capacity() <= size)
{
return;
}
int endIndex = mLength;
int beginIndex = mLength - size;
byte[] bytes = toBytes(beginIndex, endIndex);
mBuffer = ByteBuffer.wrap(bytes);
mBuffer.position(bytes.length);
mLength = bytes.length;
}
public boolean getBit(int bitIndex)
{
int index = bitIndex / 8;
int shift = bitIndex % 8;
int value = get(index);
// Return true if the bit pointed to by bitIndex is set.
return ((value & (1 << shift)) != 0);
}
public int getBits(int bitIndex, int nBits)
{
int number = 0;
int weight = 1;
// Convert consecutive bits into a number.
for (int i = 0; i < nBits; ++i, weight *= 2)
{
// getBit() returns true if the bit is set.
if (getBit(bitIndex + i))
{
number += weight;
}
}
return number;
}
public int getHuffmanBits(int bitIndex, int nBits)
{
int number = 0;
int weight = 1;
// Convert consecutive bits into a number.
//
// Note that 'i' is initialized by 'nBits - 1', not by 1.
// This is because "3.1.1. Packing into bytes" in RFC 1951
// says as follows:
//
// Huffman codes are packed starting with the most
// significant bit of the code.
//
for (int i = nBits - 1; 0 <= i; --i, weight *= 2)
{
// getBit() returns true if the bit is set.
if (getBit(bitIndex + i))
{
number += weight;
}
}
return number;
}
public boolean readBit(int[] bitIndex)
{
boolean result = getBit(bitIndex[0]);
++bitIndex[0];
return result;
}
public int readBits(int[] bitIndex, int nBits)
{
int number = getBits(bitIndex[0], nBits);
bitIndex[0] += nBits;
return number;
}
public void setBit(int bitIndex, boolean bit)
{
int index = bitIndex / 8;
int shift = bitIndex % 8;
int value = get(index);
if (bit)
{
value |= (1 << shift);
}
else
{
value &= ~(1 << shift);
}
mBuffer.put(index, (byte)value);
}
public void clearBit(int bitIndex)
{
setBit(bitIndex, false);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy