/*
* This is free and unencumbered software released into the public domain.
*
* Anyone is free to copy, modify, publish, use, compile, sell, or
* distribute this software, either in source code form or as a compiled
* binary, for any purpose, commercial or non-commercial, and by any
* means.
*
* In jurisdictions that recognize copyright laws, the author or authors
* of this software dedicate any and all copyright interest in the
* software to the public domain. We make this dedication for the benefit
* of the public at large and to the detriment of our heirs and
* successors. We intend this dedication to be an overt act of
* relinquishment in perpetuity of all present and future rights to this
* software under copyright law.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* For more information, please refer to <http://unlicense.org/>
*/
package jxtn.core.unix;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Objects;
/**
* Wrapper of a single Java array
*
* @author aqd
*/
public class ArrayBuffer implements LargeBuffer {
private final byte[] source;
private final int base;
private final int length;
private int pointer;
private int limit;
private boolean swapped;
public ArrayBuffer(byte[] source, int offset, int length) {
if (offset < 0 || offset > source.length) {
throw new IllegalArgumentException("offset=" + offset);
}
if (length < 0 || offset + length > source.length) {
throw new IllegalArgumentException("length=" + length);
}
this.source = Objects.requireNonNull(source);
this.base = offset;
this.length = length;
//
this.pointer = offset;
this.limit = offset + length;
}
@Override
public final ByteOrder order() {
if (this.swapped) {
return ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN
? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN;
} else {
return ByteOrder.nativeOrder();
}
}
@Override
public final void order(ByteOrder newOrder) {
this.swapped = newOrder != ByteOrder.nativeOrder();
}
@Override
public final boolean hasRemaining() {
return this.limit > this.pointer;
}
@Override
public final long remaining() {
return this.limit - this.pointer;
}
@Override
public final long length() {
return this.length;
}
@Override
public final void move(long relativePosition) {
this.pointer += (int) relativePosition;
}
@Override
public final long position() {
return this.pointer - this.base;
}
@Override
public final void position(long absolutePosition) {
this.pointer = this.base + (int) absolutePosition;
}
@Override
public final boolean getBoolean() {
boolean value = getBoolean(this.source, this.pointer);
this.pointer += 1;
return value;
}
@Override
public final byte getByte() {
byte value = this.source[this.pointer];
this.pointer += 1;
return value;
}
@Override
public final short getShort() {
short value = getShort(this.source, this.pointer);
this.pointer += 2;
return this.swapped ? Short.reverseBytes(value) : value;
}
@Override
public final int getInt() {
int value = getInt(this.source, this.pointer);
this.pointer += 4;
return this.swapped ? Integer.reverseBytes(value) : value;
}
@Override
public final long getLong() {
long value = getLong(this.source, this.pointer);
this.pointer += 8;
return this.swapped ? Long.reverseBytes(value) : value;
}
@Override
public final float getFloat() {
float value = this.swapped
? Float.intBitsToFloat(Integer.reverseBytes(getInt(this.source, this.pointer)))
: getFloat(this.source, this.pointer);
this.pointer += 4;
return value;
}
@Override
public final double getDouble() {
double value = this.swapped
? Double.longBitsToDouble(Long.reverseBytes(getLong(this.source, this.pointer)))
: getDouble(this.source, this.pointer);
this.pointer += 8;
return value;
}
@Override
public final short getUByte() {
byte value = this.source[this.pointer];
this.pointer += 1;
return (short) (value & 0xFF);
}
@Override
public final int getUShort() {
short value = getShort(this.source, this.pointer);
this.pointer += 2;
return (this.swapped ? Short.reverseBytes(value) : value) & 0xFFFF;
}
@Override
public final long getUInt() {
int value = getInt(this.source, this.pointer);
this.pointer += 4;
return (this.swapped ? Integer.reverseBytes(value) : value) & 0xFFFFFFFFL;
}
@Override
public final void getData(byte[] data) {
System.arraycopy(this.source, this.pointer, data, 0, data.length);
this.pointer += data.length;
}
@Override
public final boolean getBooleanAt(long offset) {
return getBoolean(this.source, this.pointer + (int) offset);
}
@Override
public final byte getByteAt(long offset) {
return this.source[this.pointer + (int) offset];
}
@Override
public final short getShortAt(long offset) {
short value = getShort(this.source, this.pointer + (int) offset);
return this.swapped ? Short.reverseBytes(value) : value;
}
@Override
public final int getIntAt(long offset) {
int value = getInt(this.source, this.pointer + (int) offset);
return this.swapped ? Integer.reverseBytes(value) : value;
}
@Override
public final long getLongAt(long offset) {
long value = getLong(this.source, this.pointer + (int) offset);
return this.swapped ? Long.reverseBytes(value) : value;
}
@Override
public final float getFloatAt(long offset) {
return this.swapped
? Float.intBitsToFloat(Integer.reverseBytes(getInt(this.source, this.pointer + (int) offset)))
: getFloat(this.source, this.pointer + (int) offset);
}
@Override
public final double getDoubleAt(long offset) {
return this.swapped
? Double.longBitsToDouble(Long.reverseBytes(getLong(this.source, this.pointer + (int) offset)))
: getDouble(this.source, this.pointer + (int) offset);
}
@Override
public final short getUByteAt(long offset) {
return (short) (this.source[this.pointer + (int) offset] & 0xFF);
}
@Override
public final int getUShortAt(long offset) {
short value = getShort(this.source, this.pointer + (int) offset);
return (this.swapped ? Short.reverseBytes(value) : value) & 0xFFFF;
}
@Override
public final long getUIntAt(long offset) {
int value = getInt(this.source, this.pointer + (int) offset);
return (this.swapped ? Integer.reverseBytes(value) : value) & 0xFFFFFFFFL;
}
@Override
public final void getDataAt(long offset, byte[] data) {
System.arraycopy(this.source, this.pointer + (int) offset, data, 0, data.length);
}
@Override
public final void putBoolean(boolean val) {
putBoolean(this.source, this.pointer, val);
this.pointer += 1;
}
@Override
public final void putByte(byte val) {
this.source[this.pointer] = val;
this.pointer += 1;
}
@Override
public final void putShort(short val) {
putShort(this.source, this.pointer, this.swapped ? Short.reverseBytes(val) : val);
this.pointer += 2;
}
@Override
public final void putInt(int val) {
putInt(this.source, this.pointer, this.swapped ? Integer.reverseBytes(val) : val);
this.pointer += 4;
}
@Override
public final void putLong(long val) {
putLong(this.source, this.pointer, this.swapped ? Long.reverseBytes(val) : val);
this.pointer += 8;
}
@Override
public final void putFloat(float val) {
if (this.swapped) {
putInt(this.source, this.pointer, Integer.reverseBytes(Float.floatToIntBits(val)));
} else {
putFloat(this.source, this.pointer, val);
}
this.pointer += 4;
}
@Override
public final void putDouble(double val) {
if (this.swapped) {
putLong(this.source, this.pointer, Long.reverseBytes(Double.doubleToLongBits(val)));
} else {
putDouble(this.source, this.pointer, val);
}
this.pointer += 8;
}
@Override
public final void putData(byte[] data) {
System.arraycopy(data, 0, this.source, this.pointer, data.length);
this.pointer += data.length;
}
@Override
public final void putBooleanAt(long offset, boolean val) {
putBoolean(this.source, this.pointer + (int) offset, val);
}
@Override
public final void putByteAt(long offset, byte val) {
this.source[this.pointer + (int) offset] = val;
}
@Override
public final void putShortAt(long offset, short val) {
putShort(this.source, this.pointer + (int) offset, this.swapped ? Short.reverseBytes(val) : val);
}
@Override
public final void putIntAt(long offset, int val) {
putInt(this.source, this.pointer + (int) offset, this.swapped ? Integer.reverseBytes(val) : val);
}
@Override
public final void putLongAt(long offset, long val) {
putLong(this.source, this.pointer + (int) offset, this.swapped ? Long.reverseBytes(val) : val);
}
@Override
public final void putFloatAt(long offset, float val) {
if (this.swapped) {
putInt(this.source, this.pointer + (int) offset, Integer.reverseBytes(Float.floatToIntBits(val)));
} else {
putFloat(this.source, this.pointer + (int) offset, val);
}
}
@Override
public final void putDoubleAt(long offset, double val) {
if (this.swapped) {
putLong(this.source, this.pointer + (int) offset, Long.reverseBytes(Double.doubleToLongBits(val)));
} else {
putDouble(this.source, this.pointer + (int) offset, val);
}
}
@Override
public final void putDataAt(long offset, byte[] data) {
System.arraycopy(data, 0, this.source, this.pointer + (int) offset, data.length);
}
@Override
public final Long find(long limit, byte[] needle) {
int index = indexOf(this.source, this.pointer, (int) limit, needle, 0, needle.length);
if (index < 0) {
return null;
} else {
return (long) (index - this.pointer);
}
}
@Override
public final Long find(long offset, long limit, byte[] needle) {
int index = indexOf(this.source, this.pointer + (int) offset, (int) limit, needle, 0, needle.length);
if (index < 0) {
return null;
} else {
return (long) (index - this.pointer);
}
}
public final ByteBuffer toByteBuffer() {
ByteBuffer buffer = ByteBuffer.wrap(this.source, this.base, this.length);
buffer.position((int) this.position());
buffer.order(this.order());
return buffer;
}
private static boolean getBoolean(byte[] b, int off) {
return b[off] != 0;
}
private static short getShort(byte[] b, int off) {
return (short) ((b[off + 0] & 0xFF) |
(b[off + 1] << 8));
}
private static int getInt(byte[] b, int off) {
return ((b[off + 0] & 0xFF)) |
((b[off + 1] & 0xFF) << 8) |
((b[off + 2] & 0xFF) << 16) |
((b[off + 3]) << 24);
}
private static float getFloat(byte[] b, int off) {
return Float.intBitsToFloat(getInt(b, off));
}
private static long getLong(byte[] b, int off) {
return ((b[off + 0] & 0xFFL)) |
((b[off + 1] & 0xFFL) << 8) |
((b[off + 2] & 0xFFL) << 16) |
((b[off + 3] & 0xFFL) << 24) |
((b[off + 4] & 0xFFL) << 32) |
((b[off + 5] & 0xFFL) << 40) |
((b[off + 6] & 0xFFL) << 48) |
(((long) b[off + 7]) << 56);
}
private static double getDouble(byte[] b, int off) {
return Double.longBitsToDouble(getLong(b, off));
}
private static void putBoolean(byte[] b, int off, boolean val) {
b[off] = (byte) (val ? 1 : 0);
}
private static void putShort(byte[] b, int off, short val) {
b[off + 1] = (byte) (val);
b[off] = (byte) (val >>> 8);
}
private static void putInt(byte[] b, int off, int val) {
b[off + 0] = (byte) (val);
b[off + 1] = (byte) (val >>> 8);
b[off + 2] = (byte) (val >>> 16);
b[off + 3] = (byte) (val >>> 24);
}
private static void putFloat(byte[] b, int off, float val) {
putInt(b, off, Float.floatToIntBits(val));
}
private static void putLong(byte[] b, int off, long val) {
b[off + 0] = (byte) (val);
b[off + 1] = (byte) (val >>> 8);
b[off + 2] = (byte) (val >>> 16);
b[off + 3] = (byte) (val >>> 24);
b[off + 4] = (byte) (val >>> 32);
b[off + 5] = (byte) (val >>> 40);
b[off + 6] = (byte) (val >>> 48);
b[off + 7] = (byte) (val >>> 56);
}
private static void putDouble(byte[] b, int off, double val) {
putLong(b, off, Double.doubleToLongBits(val));
}
private static int indexOf(
byte[] source, int sourceOffset, int sourceCount,
byte[] target, int targetOffset, int targetCount) {
if (targetCount == 0) {
return sourceOffset;
}
byte first = target[targetOffset];
int max = sourceOffset + (sourceCount - targetCount);
for (int i = sourceOffset; i <= max; i++) {
if (source[i] != first) {
while (++i <= max && source[i] != first) {
}
}
if (i <= max) {
int j = i + 1;
int end = j + targetCount - 1;
for (int k = targetOffset + 1; j < end && source[j] == target[k]; j++, k++) {
}
if (j == end) {
return i;
}
}
}
return -1;
}
}