/*
* 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.io.Closeable;
import java.io.IOException;
import java.nio.ByteOrder;
import sun.misc.Unsafe;
/**
* Wrapper of native memory block
* <p>
* Caution: No index range check
* </p>
*
* @author aqd
*/
public class NativeBuffer implements Closeable, LargeBuffer {
private static final Unsafe unsafe = Memory.unsafe;
private final Closeable source;
private final long base;
private final long length;
private final long limit;
private long pointer;
private boolean swapped;
private boolean closed;
/**
* Create a wrapper of native memory block at certain address
*
* @param source Source to be used for information and closed on {@link NativeBuffer#close}, may be null
* @param address Starting address of the memory block (be careful of alignment!)
* @param length Length of the memory block, starting from {@code address}
*/
public NativeBuffer(Closeable source, long address, long length) {
this.source = source;
this.base = address;
this.length = length;
this.limit = address + length;
//
this.pointer = address;
this.swapped = false;
}
@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 += relativePosition;
}
@Override
public final long position() {
return this.pointer - this.base;
}
@Override
public final void position(long absolutePosition) {
this.pointer = this.base + absolutePosition;
}
@Override
public final boolean getBoolean() {
boolean value = unsafe.getByte(this.pointer) != (byte) 0;
this.pointer += 1;
return value;
}
@Override
public final byte getByte() {
byte value = unsafe.getByte(this.pointer);
this.pointer += 1;
return value;
}
@Override
public final short getShort() {
short value = unsafe.getShort(this.pointer);
this.pointer += 2;
return this.swapped ? Short.reverseBytes(value) : value;
}
@Override
public final int getInt() {
int value = unsafe.getInt(this.pointer);
this.pointer += 4;
return this.swapped ? Integer.reverseBytes(value) : value;
}
@Override
public final long getLong() {
long value = unsafe.getLong(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(unsafe.getInt(this.pointer)))
: unsafe.getFloat(this.pointer);
this.pointer += 4;
return value;
}
@Override
public final double getDouble() {
double value = this.swapped
? Double.longBitsToDouble(Long.reverseBytes(unsafe.getLong(this.pointer)))
: unsafe.getDouble(this.pointer);
this.pointer += 8;
return value;
}
@Override
public final short getUByte() {
byte value = unsafe.getByte(this.pointer);
this.pointer += 1;
return (short) (value & 0xFF);
}
@Override
public final int getUShort() {
short value = unsafe.getShort(this.pointer);
this.pointer += 2;
return (this.swapped ? Short.reverseBytes(value) : value) & 0xFFFF;
}
@Override
public final long getUInt() {
int value = unsafe.getInt(this.pointer);
this.pointer += 4;
return (this.swapped ? Integer.reverseBytes(value) : value) & 0xFFFFFFFFL;
}
@Override
public final void getData(byte[] data) {
unsafe.copyMemory(null, this.pointer, data, Unsafe.ARRAY_BYTE_BASE_OFFSET, data.length);
this.pointer += data.length;
}
@Override
public final boolean getBooleanAt(long offset) {
return unsafe.getByte(this.pointer + offset) != (byte) 0;
}
@Override
public final byte getByteAt(long offset) {
return unsafe.getByte(this.pointer + offset);
}
@Override
public final short getShortAt(long offset) {
short value = unsafe.getShort(this.pointer + offset);
return this.swapped ? Short.reverseBytes(value) : value;
}
@Override
public final int getIntAt(long offset) {
int value = unsafe.getInt(this.pointer + offset);
return this.swapped ? Integer.reverseBytes(value) : value;
}
@Override
public final long getLongAt(long offset) {
long value = unsafe.getLong(this.pointer + offset);
return this.swapped ? Long.reverseBytes(value) : value;
}
@Override
public final float getFloatAt(long offset) {
return this.swapped
? Float.intBitsToFloat(Integer.reverseBytes(unsafe.getInt(this.pointer + offset)))
: unsafe.getFloat(this.pointer + offset);
}
@Override
public final double getDoubleAt(long offset) {
return this.swapped
? Double.longBitsToDouble(Long.reverseBytes(unsafe.getLong(this.pointer + offset)))
: unsafe.getDouble(this.pointer + offset);
}
@Override
public final short getUByteAt(long offset) {
return (short) (unsafe.getByte(this.pointer + offset) & 0xFF);
}
@Override
public final int getUShortAt(long offset) {
short value = unsafe.getShort(this.pointer + offset);
return (this.swapped ? Short.reverseBytes(value) : value) & 0xFFFF;
}
@Override
public final long getUIntAt(long offset) {
int value = unsafe.getInt(this.pointer + offset);
return (this.swapped ? Integer.reverseBytes(value) : value) & 0xFFFFFFFFL;
}
@Override
public final void getDataAt(long offset, byte[] data) {
unsafe.copyMemory(null, this.pointer + offset, data, Unsafe.ARRAY_BYTE_BASE_OFFSET, data.length);
}
@Override
public final void putBoolean(boolean val) {
unsafe.putByte(this.pointer, val ? (byte) 1 : (byte) 0);
this.pointer += 1;
}
@Override
public final void putByte(byte val) {
unsafe.putByte(this.pointer, val);
this.pointer += 1;
}
@Override
public final void putShort(short val) {
unsafe.putShort(this.pointer, this.swapped ? Short.reverseBytes(val) : val);
this.pointer += 2;
}
@Override
public final void putInt(int val) {
unsafe.putInt(this.pointer, this.swapped ? Integer.reverseBytes(val) : val);
this.pointer += 4;
}
@Override
public final void putLong(long val) {
unsafe.putLong(this.pointer, this.swapped ? Long.reverseBytes(val) : val);
this.pointer += 8;
}
@Override
public final void putFloat(float val) {
if (this.swapped) {
unsafe.putInt(this.pointer, Integer.reverseBytes(Float.floatToIntBits(val)));
} else {
unsafe.putFloat(this.pointer, val);
}
this.pointer += 4;
}
@Override
public final void putDouble(double val) {
if (this.swapped) {
unsafe.putLong(this.pointer, Long.reverseBytes(Double.doubleToLongBits(val)));
} else {
unsafe.putDouble(this.pointer, val);
}
this.pointer += 8;
}
@Override
public final void putData(byte[] data) {
unsafe.copyMemory(data, Unsafe.ARRAY_BYTE_BASE_OFFSET, null, this.pointer, data.length);
this.pointer += data.length;
}
@Override
public final void putBooleanAt(long offset, boolean val) {
unsafe.putByte(this.pointer + offset, val ? (byte) 1 : (byte) 0);
}
@Override
public final void putByteAt(long offset, byte val) {
unsafe.putByte(this.pointer + offset, val);
}
@Override
public final void putShortAt(long offset, short val) {
unsafe.putShort(this.pointer + offset, this.swapped ? Short.reverseBytes(val) : val);
}
@Override
public final void putIntAt(long offset, int val) {
unsafe.putInt(this.pointer + offset, this.swapped ? Integer.reverseBytes(val) : val);
}
@Override
public final void putLongAt(long offset, long val) {
unsafe.putLong(this.pointer + offset, this.swapped ? Long.reverseBytes(val) : val);
}
@Override
public final void putFloatAt(long offset, float val) {
if (this.swapped) {
unsafe.putInt(this.pointer + offset, Integer.reverseBytes(Float.floatToIntBits(val)));
} else {
unsafe.putFloat(this.pointer + offset, val);
}
}
@Override
public final void putDoubleAt(long offset, double val) {
if (this.swapped) {
unsafe.putLong(this.pointer + offset, Long.reverseBytes(Double.doubleToLongBits(val)));
} else {
unsafe.putDouble(this.pointer + offset, val);
}
}
@Override
public final void putDataAt(long offset, byte[] data) {
unsafe.copyMemory(data, Unsafe.ARRAY_BYTE_BASE_OFFSET, null, this.pointer + offset, data.length);
}
@Override
public final Long find(long limit, byte[] needle) {
long address = NativeString.memmem(this.pointer, limit, needle);
if (address == 0L) {
return null;
} else {
return address - this.pointer;
}
}
@Override
public final Long find(long offset, long limit, byte[] needle) {
long address = NativeString.memmem(this.pointer + offset, limit, needle);
if (address == 0L) {
return null;
} else {
return address - this.pointer;
}
}
@Override
public final void close() {
if (this.closed) {
return;
}
try {
if (this.source != null) {
this.source.close();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
this.closed = true;
}
}
@Override
public final String toString() {
return "nbuf_" + this.source;
}
@Override
protected final void finalize() throws Throwable {
this.close();
super.finalize();
}
}