Cleaned up ByteBuffer2 as self-growing bytearray structure. Fixed WINDOWS unbuffered input. Fixed UNSUPPORTED unbuffered input. Fixed POSIX unbuffered input
This commit is contained in:
parent
890d73e8aa
commit
227a0d9378
@ -373,8 +373,8 @@ public class Sys {
|
|||||||
// NOTE: this saves the char array in UTF-16 format of bytes.
|
// NOTE: this saves the char array in UTF-16 format of bytes.
|
||||||
byte[] bytes = new byte[text.length*2];
|
byte[] bytes = new byte[text.length*2];
|
||||||
for(int i=0; i<text.length; i++) {
|
for(int i=0; i<text.length; i++) {
|
||||||
bytes[2*i] = (byte) ((text[i] & 0xFF00)>>8);
|
bytes[2*i] = (byte) (text[i] >> 8);
|
||||||
bytes[2*i+1] = (byte) (text[i] & 0x00FF);
|
bytes[2*i+1] = (byte) text[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
return bytes;
|
return bytes;
|
||||||
@ -754,7 +754,7 @@ public class Sys {
|
|||||||
|
|
||||||
|
|
||||||
private static final void findModulesInJar(ClassLoader classLoader, String searchLocation,
|
private static final void findModulesInJar(ClassLoader classLoader, String searchLocation,
|
||||||
Class<? extends Annotation> annotation, URL resource, List<Class<?>> annotatedClasses)
|
Class<? extends Annotation> annotation, URL resource, List<Class<?>> annotatedClasses)
|
||||||
throws IOException, ClassNotFoundException {
|
throws IOException, ClassNotFoundException {
|
||||||
|
|
||||||
URLConnection connection = resource.openConnection();
|
URLConnection connection = resource.openConnection();
|
||||||
@ -764,7 +764,6 @@ public class Sys {
|
|||||||
JarURLConnection jarURLConnection = (JarURLConnection) connection;
|
JarURLConnection jarURLConnection = (JarURLConnection) connection;
|
||||||
|
|
||||||
JarFile jarFile = jarURLConnection.getJarFile();
|
JarFile jarFile = jarURLConnection.getJarFile();
|
||||||
String fileResource = jarURLConnection.getEntryName();
|
|
||||||
|
|
||||||
Enumeration<JarEntry> entries = jarFile.entries();
|
Enumeration<JarEntry> entries = jarFile.entries();
|
||||||
|
|
||||||
@ -773,8 +772,8 @@ public class Sys {
|
|||||||
JarEntry jarEntry = entries.nextElement();
|
JarEntry jarEntry = entries.nextElement();
|
||||||
String name = jarEntry.getName();
|
String name = jarEntry.getName();
|
||||||
|
|
||||||
if (name.startsWith(fileResource) && // make sure it's at least the correct package
|
if (name.startsWith(searchLocation) && // make sure it's at least the correct package
|
||||||
isValid(name)) {
|
isValid(name)) {
|
||||||
|
|
||||||
String classPath = name.replace(File.separatorChar, '.').substring(0, name.lastIndexOf("."));
|
String classPath = name.replace(File.separatorChar, '.').substring(0, name.lastIndexOf("."));
|
||||||
|
|
||||||
@ -795,7 +794,9 @@ public class Sys {
|
|||||||
// class files will not have an entry name, which is reserved for resources only
|
// class files will not have an entry name, which is reserved for resources only
|
||||||
String name = hiveJarURLConnection.getResourceName();
|
String name = hiveJarURLConnection.getResourceName();
|
||||||
|
|
||||||
if (isValid(name)) {
|
if (name.startsWith(searchLocation) && // make sure it's at least the correct package
|
||||||
|
isValid(name)) {
|
||||||
|
|
||||||
String classPath = name.substring(0, name.lastIndexOf('.'));
|
String classPath = name.substring(0, name.lastIndexOf('.'));
|
||||||
classPath = classPath.replace('/', '.');
|
classPath = classPath.replace('/', '.');
|
||||||
|
|
||||||
|
@ -1,120 +0,0 @@
|
|||||||
package dorkbox.util.bytes;
|
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
|
|
||||||
public class BigEndian {
|
|
||||||
// the following are ALL in Big-Endian (big is to the left, first byte is most significant, unsigned bytes)
|
|
||||||
|
|
||||||
/** SHORT to and from bytes */
|
|
||||||
public static class Short_ {
|
|
||||||
public static final short fromBytes(byte[] bytes) {
|
|
||||||
return fromBytes(bytes[0], bytes[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final short fromBytes(byte b0, byte b1) {
|
|
||||||
return (short) ((b0 & 0xFF) << 8 |
|
|
||||||
(b1 & 0xFF) << 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static final byte[] toBytes(short x) {
|
|
||||||
return new byte[] {(byte) (x >> 8),
|
|
||||||
(byte) (x >> 0)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final int fromBytes(ByteBuffer buff) {
|
|
||||||
return fromBytes(buff.get(), buff.get());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** CHAR to and from bytes */
|
|
||||||
public static class Char_ {
|
|
||||||
public static final char fromBytes(byte[] bytes) {
|
|
||||||
return fromBytes(bytes[0], bytes[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final char fromBytes(byte b0, byte b1) {
|
|
||||||
return (char) ((b0 & 0xFF) << 8 |
|
|
||||||
(b1 & 0xFF) << 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static final byte[] toBytes(char x) {
|
|
||||||
return new byte[] {(byte) (x >> 8),
|
|
||||||
(byte) (x >> 0)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final int fromBytes(ByteBuffer buff) {
|
|
||||||
return fromBytes(buff.get(), buff.get());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** INT to and from bytes */
|
|
||||||
public static class Int_ {
|
|
||||||
public static final int fromBytes(byte[] bytes) {
|
|
||||||
return fromBytes(bytes[0], bytes[1], bytes[2], bytes[3]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final int fromBytes(byte b0, byte b1, byte b2, byte b3) {
|
|
||||||
return (b0 & 0xFF) << 24 |
|
|
||||||
(b1 & 0xFF) << 16 |
|
|
||||||
(b2 & 0xFF) << 8 |
|
|
||||||
(b3 & 0xFF) << 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int fromBytes(byte b0, byte b1) {
|
|
||||||
return (b0 & 0xFF) << 24 |
|
|
||||||
(b1 & 0xFF) << 16;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final byte[] toBytes(int x) {
|
|
||||||
return new byte[] {(byte) (x >> 24),
|
|
||||||
(byte) (x >> 16),
|
|
||||||
(byte) (x >> 8),
|
|
||||||
(byte) (x >> 0)
|
|
||||||
} ;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final int fromBytes(ByteBuffer buff) {
|
|
||||||
return fromBytes(buff.get(), buff.get(), buff.get(), buff.get());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** LONG to and from bytes */
|
|
||||||
public static class Long_ {
|
|
||||||
public static final long fromBytes(byte[] bytes) {
|
|
||||||
return fromBytes(bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final long fromBytes(byte b0, byte b1, byte b2, byte b3, byte b4, byte b5, byte b6, byte b7) {
|
|
||||||
return (long) (b0 & 0xFF) << 56 |
|
|
||||||
(long) (b1 & 0xFF) << 48 |
|
|
||||||
(long) (b2 & 0xFF) << 40 |
|
|
||||||
(long) (b3 & 0xFF) << 32 |
|
|
||||||
(long) (b4 & 0xFF) << 24 |
|
|
||||||
(long) (b5 & 0xFF) << 16 |
|
|
||||||
(long) (b6 & 0xFF) << 8 |
|
|
||||||
(long) (b7 & 0xFF) << 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final byte[] toBytes (long x) {
|
|
||||||
return new byte[] {(byte) (x >> 56),
|
|
||||||
(byte) (x >> 48),
|
|
||||||
(byte) (x >> 40),
|
|
||||||
(byte) (x >> 32),
|
|
||||||
(byte) (x >> 24),
|
|
||||||
(byte) (x >> 16),
|
|
||||||
(byte) (x >> 8),
|
|
||||||
(byte) (x >> 0),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final long fromBytes(ByteBuffer buff) {
|
|
||||||
return fromBytes(buff.get(), buff.get(), buff.get(), buff.get(), buff.get(), buff.get(), buff.get(), buff.get());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
@ -1,338 +0,0 @@
|
|||||||
package dorkbox.util.bytes;
|
|
||||||
|
|
||||||
import java.nio.BufferUnderflowException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Cleanroom implementation of a self-growing bytebuffer. NOT SYNCHRONIZED!
|
|
||||||
*/
|
|
||||||
public class ByteBuffer2Fast {
|
|
||||||
|
|
||||||
private byte[] bytes;
|
|
||||||
|
|
||||||
private int position = 0;
|
|
||||||
private int mark = -1;
|
|
||||||
private int limit = 0;
|
|
||||||
|
|
||||||
public static ByteBuffer2Fast wrap(byte[] buffer) {
|
|
||||||
return new ByteBuffer2Fast(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ByteBuffer2Fast allocate(int capacity) {
|
|
||||||
ByteBuffer2Fast byteBuffer2 = new ByteBuffer2Fast(new byte[capacity]);
|
|
||||||
byteBuffer2.clear();
|
|
||||||
return byteBuffer2;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ByteBuffer2Fast() {
|
|
||||||
this(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ByteBuffer2Fast(int size) {
|
|
||||||
this(new byte[size]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ByteBuffer2Fast(byte[] bytes) {
|
|
||||||
this.bytes = bytes;
|
|
||||||
clear();
|
|
||||||
this.position = bytes.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte getByte() {
|
|
||||||
if (this.position > this.limit) {
|
|
||||||
throw new BufferUnderflowException();
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.bytes[this.position++];
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte getByte(int i) {
|
|
||||||
if (i > this.limit) {
|
|
||||||
throw new BufferUnderflowException();
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.bytes[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
public void getBytes(byte[] buffer) {
|
|
||||||
getBytes(buffer, 0, buffer.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void getBytes(byte[] buffer, int length) {
|
|
||||||
getBytes(buffer, 0, length);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void getBytes(byte[] buffer, int offset, int length) {
|
|
||||||
if (this.position + length - offset > this.limit) {
|
|
||||||
throw new BufferUnderflowException();
|
|
||||||
}
|
|
||||||
|
|
||||||
System.arraycopy(this.bytes, this.position, buffer, 0, length-offset);
|
|
||||||
this.position += length-offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* MUST call checkBuffer before calling this!
|
|
||||||
*
|
|
||||||
* NOT PROTECTED
|
|
||||||
*/
|
|
||||||
private final void _put(byte b) {
|
|
||||||
this.bytes[this.position++] = b;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** NOT PROTECTED! */
|
|
||||||
private final void checkBuffer(int threshold) {
|
|
||||||
if (this.bytes.length < threshold) {
|
|
||||||
byte[] t = new byte[threshold];
|
|
||||||
// grow at back of array
|
|
||||||
System.arraycopy(this.bytes, 0, t, 0, this.bytes.length);
|
|
||||||
this.limit = t.length;
|
|
||||||
|
|
||||||
this.bytes = t;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public final void put(ByteBuffer2Fast buffer) {
|
|
||||||
putBytes(buffer.array(), buffer.position, buffer.limit);
|
|
||||||
buffer.position = buffer.limit;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final ByteBuffer2Fast putBytes(byte[] src) {
|
|
||||||
return putBytes(src, 0, src.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
public final ByteBuffer2Fast putBytes(byte[] src, int offset, int length) {
|
|
||||||
checkBuffer(this.position + length - offset);
|
|
||||||
|
|
||||||
System.arraycopy(src, offset, this.bytes, this.position, length);
|
|
||||||
this.position += length;
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final ByteBuffer2Fast putByte(byte b) {
|
|
||||||
checkBuffer(this.position + 1);
|
|
||||||
|
|
||||||
_put(b);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final void putByte(int position, byte b) {
|
|
||||||
this.position = position;
|
|
||||||
putByte(b);
|
|
||||||
}
|
|
||||||
|
|
||||||
public final void putChar(char c) {
|
|
||||||
checkBuffer(this.position + 2);
|
|
||||||
|
|
||||||
putBytes(BigEndian.Char_.toBytes(c));
|
|
||||||
}
|
|
||||||
|
|
||||||
public final char getChar() {
|
|
||||||
return BigEndian.Char_.fromBytes(getByte(), getByte());
|
|
||||||
}
|
|
||||||
|
|
||||||
public final char getChar(int i) {
|
|
||||||
return BigEndian.Char_.fromBytes(getByte(i++), getByte(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void getChars(int srcStart, int srcLength, char[] dest, int destStart) {
|
|
||||||
for (int i=srcStart;i<srcLength;i+=2) {
|
|
||||||
char c = BigEndian.Char_.fromBytes(getByte(i), getByte(i+1));
|
|
||||||
dest[destStart++] = c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public final ByteBuffer2Fast putShort(short x) {
|
|
||||||
checkBuffer(this.position + 2);
|
|
||||||
|
|
||||||
putBytes(BigEndian.Short_.toBytes(x));
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final short getShort() {
|
|
||||||
return BigEndian.Short_.fromBytes(getByte(), getByte());
|
|
||||||
}
|
|
||||||
|
|
||||||
public final short getShort(int i) {
|
|
||||||
return BigEndian.Short_.fromBytes(getByte(i++), getByte(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
public final void putInt(int x) {
|
|
||||||
checkBuffer(this.position + 4);
|
|
||||||
|
|
||||||
putBytes(BigEndian.Int_.toBytes(x));
|
|
||||||
}
|
|
||||||
|
|
||||||
public final int getInt() {
|
|
||||||
return BigEndian.Int_.fromBytes(getByte(), getByte(), getByte(), getByte());
|
|
||||||
}
|
|
||||||
|
|
||||||
public final int getInt(int i) {
|
|
||||||
return BigEndian.Int_.fromBytes(getByte(i++), getByte(i++), getByte(i++), getByte(i++));
|
|
||||||
}
|
|
||||||
|
|
||||||
public final void putLong(long x) {
|
|
||||||
checkBuffer(this.position + 8);
|
|
||||||
|
|
||||||
putBytes(BigEndian.Long_.toBytes(x));
|
|
||||||
}
|
|
||||||
|
|
||||||
public final long getLong() {
|
|
||||||
return BigEndian.Long_.fromBytes(getByte(), getByte(), getByte(), getByte(), getByte(), getByte(), getByte(), getByte());
|
|
||||||
}
|
|
||||||
|
|
||||||
public final long getLong(int i) {
|
|
||||||
return BigEndian.Long_.fromBytes(getByte(i++), getByte(i++), getByte(i++), getByte(i++), getByte(i++), getByte(i++), getByte(i++), getByte(i++));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the backing array of this buffer
|
|
||||||
*/
|
|
||||||
public byte[] array() {
|
|
||||||
return this.bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a copy of the backing array of this buffer
|
|
||||||
*/
|
|
||||||
public final byte[] arrayCopy() {
|
|
||||||
int length = this.bytes.length - this.position;
|
|
||||||
|
|
||||||
byte[] b = new byte[length];
|
|
||||||
System.arraycopy(this.bytes, this.position, b, 0, length);
|
|
||||||
return b;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns this buffer's position.
|
|
||||||
*/
|
|
||||||
public int position() {
|
|
||||||
return this.position;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets this buffer's position.
|
|
||||||
*/
|
|
||||||
public final ByteBuffer2Fast position(int position) {
|
|
||||||
if (position > this.bytes.length || position < 0) {
|
|
||||||
throw new IllegalArgumentException();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.position = position;
|
|
||||||
if (this.mark > position) {
|
|
||||||
this.mark = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the number of elements between the current position and the
|
|
||||||
* limit.
|
|
||||||
*/
|
|
||||||
public final int remaining() {
|
|
||||||
return this.limit - this.position;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tells whether there are any elements between the current position and
|
|
||||||
* the limit.
|
|
||||||
*/
|
|
||||||
public final boolean hasRemaining() {
|
|
||||||
return this.position < this.limit;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets this buffer's limit.
|
|
||||||
*/
|
|
||||||
public final void limit(int limit) {
|
|
||||||
this.limit = limit;
|
|
||||||
if (this.position > limit) {
|
|
||||||
this.position = limit;
|
|
||||||
}
|
|
||||||
if (this.mark > limit) {
|
|
||||||
this.mark = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns this buffer's limit.
|
|
||||||
*/
|
|
||||||
public int limit() {
|
|
||||||
return this.limit;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns this buffer's capacity.
|
|
||||||
*/
|
|
||||||
public int capacity() {
|
|
||||||
return this.bytes.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The bytes between the buffer's current position and its limit, if any, are copied to the beginning of the buffer.
|
|
||||||
* That is, the byte at index p = position() is copied to index zero, the byte at index p + 1 is copied to index one,
|
|
||||||
* and so forth until the byte at index limit() - 1 is copied to index n = limit() - 1 - p. The buffer's position is
|
|
||||||
* then set to n+1 and its limit is set to its capacity. The mark, if defined, is discarded.
|
|
||||||
*
|
|
||||||
* The buffer's position is set to the number of bytes copied, rather than to zero, so that an invocation of this method
|
|
||||||
* can be followed immediately by an invocation of another relative put method.
|
|
||||||
*/
|
|
||||||
public final void compact() {
|
|
||||||
this.mark = -1;
|
|
||||||
System.arraycopy(this.bytes, this.position, this.bytes, 0, remaining());
|
|
||||||
|
|
||||||
position(remaining());
|
|
||||||
limit(capacity());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Readies the buffer for reading.
|
|
||||||
*
|
|
||||||
* Flips this buffer. The limit is set to the current position and then
|
|
||||||
* the position is set to zero. If the mark is defined then it is
|
|
||||||
* discarded.
|
|
||||||
*/
|
|
||||||
public final void flip() {
|
|
||||||
this.limit = this.position;
|
|
||||||
this.position = 0;
|
|
||||||
this.mark = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clears this buffer. The position is set to zero, the limit is set to
|
|
||||||
* the capacity, and the mark is discarded.
|
|
||||||
*/
|
|
||||||
public final void clear() {
|
|
||||||
this.position = 0;
|
|
||||||
this.limit = capacity();
|
|
||||||
this.mark = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Rewinds this buffer. The position is set to zero and the mark is
|
|
||||||
* discarded.
|
|
||||||
*/
|
|
||||||
public final void rewind() {
|
|
||||||
this.position = 0;
|
|
||||||
this.mark = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets this buffer's mark at its position.
|
|
||||||
*/
|
|
||||||
public final void mark() {
|
|
||||||
this.mark = this.position;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Resets this buffer's position to the previously-marked position.
|
|
||||||
*
|
|
||||||
* <p> Invoking this method neither changes nor discards the mark's
|
|
||||||
* value. </p>
|
|
||||||
*/
|
|
||||||
public void reset() {
|
|
||||||
this.position = this.mark;
|
|
||||||
}
|
|
||||||
}
|
|
20
Dorkbox-Util/src/dorkbox/util/bytes/ByteBuffer2Poolable.java
Normal file
20
Dorkbox-Util/src/dorkbox/util/bytes/ByteBuffer2Poolable.java
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
package dorkbox.util.bytes;
|
||||||
|
|
||||||
|
import dorkbox.util.objectPool.PoolableObject;
|
||||||
|
|
||||||
|
public class ByteBuffer2Poolable implements PoolableObject<ByteBuffer2> {
|
||||||
|
@Override
|
||||||
|
public ByteBuffer2 create() {
|
||||||
|
return new ByteBuffer2(8, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void activate(ByteBuffer2 object) {
|
||||||
|
object.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void passivate(ByteBuffer2 object) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,6 +2,11 @@ package dorkbox.util.bytes;
|
|||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is intel/amd/arm arch!
|
||||||
|
*
|
||||||
|
* arm is technically bi-endian
|
||||||
|
*/
|
||||||
public class LittleEndian {
|
public class LittleEndian {
|
||||||
// the following are ALL in Little-Endian (big is to the right, first byte is least significant, unsigned bytes)
|
// the following are ALL in Little-Endian (big is to the right, first byte is least significant, unsigned bytes)
|
||||||
|
|
||||||
@ -24,10 +29,9 @@ public class LittleEndian {
|
|||||||
(b0 & 0xFF) << 0);
|
(b0 & 0xFF) << 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static final byte[] toBytes(char x) {
|
public static final byte[] toBytes(char x) {
|
||||||
return new byte[] {(byte) (x >> 8),
|
return new byte[] {(byte) (x >> 0),
|
||||||
(byte) (x >> 0)
|
(byte) (x >> 8)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,541 +0,0 @@
|
|||||||
package dorkbox.util.bytes;
|
|
||||||
|
|
||||||
public class OptimizeUtils {
|
|
||||||
|
|
||||||
private static final OptimizeUtils instance = new OptimizeUtils();
|
|
||||||
|
|
||||||
public static OptimizeUtils get() {
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
// int
|
|
||||||
|
|
||||||
/**
|
|
||||||
* FROM KRYO
|
|
||||||
*
|
|
||||||
* Returns the number of bytes that would be written with {@link #writeInt(int, boolean)}.
|
|
||||||
*
|
|
||||||
* @param optimizePositive true if you want to optimize the number of bytes needed to write the length value
|
|
||||||
*/
|
|
||||||
public final int intLength (int value, boolean optimizePositive) {
|
|
||||||
if (!optimizePositive) {
|
|
||||||
value = value << 1 ^ value >> 31;
|
|
||||||
}
|
|
||||||
if (value >>> 7 == 0) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if (value >>> 14 == 0) {
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
if (value >>> 21 == 0) {
|
|
||||||
return 3;
|
|
||||||
}
|
|
||||||
if (value >>> 28 == 0) {
|
|
||||||
return 4;
|
|
||||||
}
|
|
||||||
return 5;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* FROM KRYO
|
|
||||||
*
|
|
||||||
* look at buffer, and see if we can read the length of the int off of it. (from the reader index)
|
|
||||||
*/
|
|
||||||
public final boolean canReadInt (ByteBuffer2 buffer) {
|
|
||||||
int position = buffer.position();
|
|
||||||
try {
|
|
||||||
int remaining = buffer.remaining();
|
|
||||||
for (int offset = 0; offset < 32 && remaining > 0; offset += 7, remaining--) {
|
|
||||||
int b = buffer.getByte();
|
|
||||||
if ((b & 0x80) == 0) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
} finally {
|
|
||||||
buffer.position(position);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* FROM KRYO
|
|
||||||
*
|
|
||||||
* look at buffer, and see if we can read the length of the int off of it. (from the reader index)
|
|
||||||
*
|
|
||||||
* @return 0 if we could not read anything, >0 for the number of bytes for the int on the buffer
|
|
||||||
*/
|
|
||||||
public boolean canReadInt (byte[] buffer) {
|
|
||||||
int length = buffer.length;
|
|
||||||
|
|
||||||
if (length >= 5) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
int p = 0;
|
|
||||||
if ((buffer[p++] & 0x80) == 0) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (p == length) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if ((buffer[p++] & 0x80) == 0) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (p == length) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if ((buffer[p++] & 0x80) == 0) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (p == length) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if ((buffer[p++] & 0x80) == 0) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (p == length) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* FROM KRYO
|
|
||||||
*
|
|
||||||
* Reads an int from the buffer that was optimized.
|
|
||||||
*/
|
|
||||||
public final int readInt (ByteBuffer2 buffer, boolean optimizePositive) {
|
|
||||||
int b = buffer.getByte();
|
|
||||||
int result = b & 0x7F;
|
|
||||||
if ((b & 0x80) != 0) {
|
|
||||||
b = buffer.getByte();
|
|
||||||
result |= (b & 0x7F) << 7;
|
|
||||||
if ((b & 0x80) != 0) {
|
|
||||||
b = buffer.getByte();
|
|
||||||
result |= (b & 0x7F) << 14;
|
|
||||||
if ((b & 0x80) != 0) {
|
|
||||||
b = buffer.getByte();
|
|
||||||
result |= (b & 0x7F) << 21;
|
|
||||||
if ((b & 0x80) != 0) {
|
|
||||||
b = buffer.getByte();
|
|
||||||
result |= (b & 0x7F) << 28;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return optimizePositive ? result : result >>> 1 ^ -(result & 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* FROM KRYO
|
|
||||||
*
|
|
||||||
* Reads an int from the buffer that was optimized.
|
|
||||||
*/
|
|
||||||
public int readInt (byte[] buffer, boolean optimizePositive) {
|
|
||||||
int position = 0;
|
|
||||||
int b = buffer[position++];
|
|
||||||
int result = b & 0x7F;
|
|
||||||
if ((b & 0x80) != 0) {
|
|
||||||
b = buffer[position++];
|
|
||||||
result |= (b & 0x7F) << 7;
|
|
||||||
if ((b & 0x80) != 0) {
|
|
||||||
b = buffer[position++];
|
|
||||||
result |= (b & 0x7F) << 14;
|
|
||||||
if ((b & 0x80) != 0) {
|
|
||||||
b = buffer[position++];
|
|
||||||
result |= (b & 0x7F) << 21;
|
|
||||||
if ((b & 0x80) != 0) {
|
|
||||||
b = buffer[position++];
|
|
||||||
result |= (b & 0x7F) << 28;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return optimizePositive ? result : result >>> 1 ^ -(result & 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* FROM KRYO
|
|
||||||
*
|
|
||||||
* Writes the specified int to the buffer using 1 to 5 bytes, depending on the size of the number.
|
|
||||||
*
|
|
||||||
* @param optimizePositive true if you want to optimize the number of bytes needed to write the length value
|
|
||||||
* @return the number of bytes written.
|
|
||||||
*/
|
|
||||||
public final int writeInt (ByteBuffer2 buffer, int value, boolean optimizePositive) {
|
|
||||||
if (!optimizePositive) {
|
|
||||||
value = value << 1 ^ value >> 31;
|
|
||||||
}
|
|
||||||
if (value >>> 7 == 0) {
|
|
||||||
buffer.putByte((byte)value);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if (value >>> 14 == 0) {
|
|
||||||
buffer.putByte((byte)(value & 0x7F | 0x80));
|
|
||||||
buffer.putByte((byte)(value >>> 7));
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
if (value >>> 21 == 0) {
|
|
||||||
buffer.putByte((byte)(value & 0x7F | 0x80));
|
|
||||||
buffer.putByte((byte)(value >>> 7 | 0x80));
|
|
||||||
buffer.putByte((byte)(value >>> 14));
|
|
||||||
return 3;
|
|
||||||
}
|
|
||||||
if (value >>> 28 == 0) {
|
|
||||||
buffer.putByte((byte)(value & 0x7F | 0x80));
|
|
||||||
buffer.putByte((byte)(value >>> 7 | 0x80));
|
|
||||||
buffer.putByte((byte)(value >>> 14 | 0x80));
|
|
||||||
buffer.putByte((byte)(value >>> 21));
|
|
||||||
return 4;
|
|
||||||
}
|
|
||||||
buffer.putByte((byte)(value & 0x7F | 0x80));
|
|
||||||
buffer.putByte((byte)(value >>> 7 | 0x80));
|
|
||||||
buffer.putByte((byte)(value >>> 14 | 0x80));
|
|
||||||
buffer.putByte((byte)(value >>> 21 | 0x80));
|
|
||||||
buffer.putByte((byte)(value >>> 28));
|
|
||||||
return 5;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* FROM KRYO
|
|
||||||
*
|
|
||||||
* Writes the specified int to the buffer using 1 to 5 bytes, depending on the size of the number.
|
|
||||||
*
|
|
||||||
* @param optimizePositive true if you want to optimize the number of bytes needed to write the length value
|
|
||||||
* @return the number of bytes written.
|
|
||||||
*/
|
|
||||||
public int writeInt (byte[] buffer, int value, boolean optimizePositive) {
|
|
||||||
int position = 0;
|
|
||||||
if (!optimizePositive) {
|
|
||||||
value = value << 1 ^ value >> 31;
|
|
||||||
}
|
|
||||||
if (value >>> 7 == 0) {
|
|
||||||
buffer[position++] = (byte)value;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if (value >>> 14 == 0) {
|
|
||||||
buffer[position++] = (byte)(value & 0x7F | 0x80);
|
|
||||||
buffer[position++] = (byte)(value >>> 7);
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
if (value >>> 21 == 0) {
|
|
||||||
buffer[position++] = (byte)(value & 0x7F | 0x80);
|
|
||||||
buffer[position++] = (byte)(value >>> 7 | 0x80);
|
|
||||||
buffer[position++] = (byte)(value >>> 14);
|
|
||||||
return 3;
|
|
||||||
}
|
|
||||||
if (value >>> 28 == 0) {
|
|
||||||
buffer[position++] = (byte)(value & 0x7F | 0x80);
|
|
||||||
buffer[position++] = (byte)(value >>> 7 | 0x80);
|
|
||||||
buffer[position++] = (byte)(value >>> 14 | 0x80);
|
|
||||||
buffer[position++] = (byte)(value >>> 21);
|
|
||||||
return 4;
|
|
||||||
}
|
|
||||||
buffer[position++] = (byte)(value & 0x7F | 0x80);
|
|
||||||
buffer[position++] = (byte)(value >>> 7 | 0x80);
|
|
||||||
buffer[position++] = (byte)(value >>> 14 | 0x80);
|
|
||||||
buffer[position++] = (byte)(value >>> 21 | 0x80);
|
|
||||||
buffer[position++] = (byte)(value >>> 28);
|
|
||||||
return 5;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// long
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the number of bytes that would be written with {@link #writeLong(long, boolean)}.
|
|
||||||
*
|
|
||||||
* @param optimizePositive true if you want to optimize the number of bytes needed to write the length value
|
|
||||||
*/
|
|
||||||
public final int longLength (long value, boolean optimizePositive) {
|
|
||||||
if (!optimizePositive) {
|
|
||||||
value = value << 1 ^ value >> 63;
|
|
||||||
}
|
|
||||||
if (value >>> 7 == 0) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if (value >>> 14 == 0) {
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
if (value >>> 21 == 0) {
|
|
||||||
return 3;
|
|
||||||
}
|
|
||||||
if (value >>> 28 == 0) {
|
|
||||||
return 4;
|
|
||||||
}
|
|
||||||
if (value >>> 35 == 0) {
|
|
||||||
return 5;
|
|
||||||
}
|
|
||||||
if (value >>> 42 == 0) {
|
|
||||||
return 6;
|
|
||||||
}
|
|
||||||
if (value >>> 49 == 0) {
|
|
||||||
return 7;
|
|
||||||
}
|
|
||||||
if (value >>> 56 == 0) {
|
|
||||||
return 8;
|
|
||||||
}
|
|
||||||
return 9;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* FROM KRYO
|
|
||||||
*
|
|
||||||
* Reads a 1-9 byte long.
|
|
||||||
*
|
|
||||||
* @param optimizePositive true if you want to optimize the number of bytes needed to write the length value
|
|
||||||
*/
|
|
||||||
public final long readLong (ByteBuffer2 buffer, boolean optimizePositive) {
|
|
||||||
int b = buffer.getByte();
|
|
||||||
long result = b & 0x7F;
|
|
||||||
if ((b & 0x80) != 0) {
|
|
||||||
b = buffer.getByte();
|
|
||||||
result |= (b & 0x7F) << 7;
|
|
||||||
if ((b & 0x80) != 0) {
|
|
||||||
b = buffer.getByte();
|
|
||||||
result |= (b & 0x7F) << 14;
|
|
||||||
if ((b & 0x80) != 0) {
|
|
||||||
b = buffer.getByte();
|
|
||||||
result |= (b & 0x7F) << 21;
|
|
||||||
if ((b & 0x80) != 0) {
|
|
||||||
b = buffer.getByte();
|
|
||||||
result |= (long)(b & 0x7F) << 28;
|
|
||||||
if ((b & 0x80) != 0) {
|
|
||||||
b = buffer.getByte();
|
|
||||||
result |= (long)(b & 0x7F) << 35;
|
|
||||||
if ((b & 0x80) != 0) {
|
|
||||||
b = buffer.getByte();
|
|
||||||
result |= (long)(b & 0x7F) << 42;
|
|
||||||
if ((b & 0x80) != 0) {
|
|
||||||
b = buffer.getByte();
|
|
||||||
result |= (long)(b & 0x7F) << 49;
|
|
||||||
if ((b & 0x80) != 0) {
|
|
||||||
b = buffer.getByte();
|
|
||||||
result |= (long)b << 56;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!optimizePositive) {
|
|
||||||
result = result >>> 1 ^ -(result & 1);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* FROM KRYO
|
|
||||||
*
|
|
||||||
* Reads a 1-9 byte long.
|
|
||||||
*
|
|
||||||
* @param optimizePositive true if you want to optimize the number of bytes needed to write the length value
|
|
||||||
*/
|
|
||||||
public long readLong (byte[] buffer, boolean optimizePositive) {
|
|
||||||
int position = 0;
|
|
||||||
int b = buffer[position++];
|
|
||||||
long result = b & 0x7F;
|
|
||||||
if ((b & 0x80) != 0) {
|
|
||||||
b = buffer[position++];
|
|
||||||
result |= (b & 0x7F) << 7;
|
|
||||||
if ((b & 0x80) != 0) {
|
|
||||||
b = buffer[position++];
|
|
||||||
result |= (b & 0x7F) << 14;
|
|
||||||
if ((b & 0x80) != 0) {
|
|
||||||
b = buffer[position++];
|
|
||||||
result |= (b & 0x7F) << 21;
|
|
||||||
if ((b & 0x80) != 0) {
|
|
||||||
b = buffer[position++];
|
|
||||||
result |= (long)(b & 0x7F) << 28;
|
|
||||||
if ((b & 0x80) != 0) {
|
|
||||||
b = buffer[position++];
|
|
||||||
result |= (long)(b & 0x7F) << 35;
|
|
||||||
if ((b & 0x80) != 0) {
|
|
||||||
b = buffer[position++];
|
|
||||||
result |= (long)(b & 0x7F) << 42;
|
|
||||||
if ((b & 0x80) != 0) {
|
|
||||||
b = buffer[position++];
|
|
||||||
result |= (long)(b & 0x7F) << 49;
|
|
||||||
if ((b & 0x80) != 0) {
|
|
||||||
b = buffer[position++];
|
|
||||||
result |= (long)b << 56;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!optimizePositive) {
|
|
||||||
result = result >>> 1 ^ -(result & 1);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* FROM KRYO
|
|
||||||
*
|
|
||||||
* Writes a 1-9 byte long.
|
|
||||||
*
|
|
||||||
* @param optimizePositive If true, small positive numbers will be more efficient (1 byte) and small negative numbers will be
|
|
||||||
* inefficient (9 bytes).
|
|
||||||
* @return the number of bytes written.
|
|
||||||
*/
|
|
||||||
public final int writeLong (ByteBuffer2 buffer, long value, boolean optimizePositive) {
|
|
||||||
if (!optimizePositive) {
|
|
||||||
value = value << 1 ^ value >> 63;
|
|
||||||
}
|
|
||||||
if (value >>> 7 == 0) {
|
|
||||||
buffer.putByte((byte)value);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if (value >>> 14 == 0) {
|
|
||||||
buffer.putByte((byte)(value & 0x7F | 0x80));
|
|
||||||
buffer.putByte((byte)(value >>> 7));
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
if (value >>> 21 == 0) {
|
|
||||||
buffer.putByte((byte)(value & 0x7F | 0x80));
|
|
||||||
buffer.putByte((byte)(value >>> 7 | 0x80));
|
|
||||||
buffer.putByte((byte)(value >>> 14));
|
|
||||||
return 3;
|
|
||||||
}
|
|
||||||
if (value >>> 28 == 0) {
|
|
||||||
buffer.putByte((byte)(value & 0x7F | 0x80));
|
|
||||||
buffer.putByte((byte)(value >>> 7 | 0x80));
|
|
||||||
buffer.putByte((byte)(value >>> 14 | 0x80));
|
|
||||||
buffer.putByte((byte)(value >>> 21));
|
|
||||||
return 4;
|
|
||||||
}
|
|
||||||
if (value >>> 35 == 0) {
|
|
||||||
buffer.putByte((byte)(value & 0x7F | 0x80));
|
|
||||||
buffer.putByte((byte)(value >>> 7 | 0x80));
|
|
||||||
buffer.putByte((byte)(value >>> 14 | 0x80));
|
|
||||||
buffer.putByte((byte)(value >>> 21 | 0x80));
|
|
||||||
buffer.putByte((byte)(value >>> 28));
|
|
||||||
return 5;
|
|
||||||
}
|
|
||||||
if (value >>> 42 == 0) {
|
|
||||||
buffer.putByte((byte)(value & 0x7F | 0x80));
|
|
||||||
buffer.putByte((byte)(value >>> 7 | 0x80));
|
|
||||||
buffer.putByte((byte)(value >>> 14 | 0x80));
|
|
||||||
buffer.putByte((byte)(value >>> 21 | 0x80));
|
|
||||||
buffer.putByte((byte)(value >>> 28 | 0x80));
|
|
||||||
buffer.putByte((byte)(value >>> 35));
|
|
||||||
return 6;
|
|
||||||
}
|
|
||||||
if (value >>> 49 == 0) {
|
|
||||||
buffer.putByte((byte)(value & 0x7F | 0x80));
|
|
||||||
buffer.putByte((byte)(value >>> 7 | 0x80));
|
|
||||||
buffer.putByte((byte)(value >>> 14 | 0x80));
|
|
||||||
buffer.putByte((byte)(value >>> 21 | 0x80));
|
|
||||||
buffer.putByte((byte)(value >>> 28 | 0x80));
|
|
||||||
buffer.putByte((byte)(value >>> 35 | 0x80));
|
|
||||||
buffer.putByte((byte)(value >>> 42));
|
|
||||||
return 7;
|
|
||||||
}
|
|
||||||
if (value >>> 56 == 0) {
|
|
||||||
buffer.putByte((byte)(value & 0x7F | 0x80));
|
|
||||||
buffer.putByte((byte)(value >>> 7 | 0x80));
|
|
||||||
buffer.putByte((byte)(value >>> 14 | 0x80));
|
|
||||||
buffer.putByte((byte)(value >>> 21 | 0x80));
|
|
||||||
buffer.putByte((byte)(value >>> 28 | 0x80));
|
|
||||||
buffer.putByte((byte)(value >>> 35 | 0x80));
|
|
||||||
buffer.putByte((byte)(value >>> 42 | 0x80));
|
|
||||||
buffer.putByte((byte)(value >>> 49));
|
|
||||||
return 8;
|
|
||||||
}
|
|
||||||
buffer.putByte((byte)(value & 0x7F | 0x80));
|
|
||||||
buffer.putByte((byte)(value >>> 7 | 0x80));
|
|
||||||
buffer.putByte((byte)(value >>> 14 | 0x80));
|
|
||||||
buffer.putByte((byte)(value >>> 21 | 0x80));
|
|
||||||
buffer.putByte((byte)(value >>> 28 | 0x80));
|
|
||||||
buffer.putByte((byte)(value >>> 35 | 0x80));
|
|
||||||
buffer.putByte((byte)(value >>> 42 | 0x80));
|
|
||||||
buffer.putByte((byte)(value >>> 49 | 0x80));
|
|
||||||
buffer.putByte((byte)(value >>> 56));
|
|
||||||
return 9;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* FROM KRYO
|
|
||||||
*
|
|
||||||
* look at buffer, and see if we can read the length of the long off of it (from the reader index).
|
|
||||||
*/
|
|
||||||
public final boolean canReadLong (ByteBuffer2 buffer) {
|
|
||||||
int position = buffer.position();
|
|
||||||
try {
|
|
||||||
int remaining = buffer.remaining();
|
|
||||||
for (int offset = 0; offset < 64 && remaining > 0; offset += 7, remaining--) {
|
|
||||||
int b = buffer.getByte();
|
|
||||||
if ((b & 0x80) == 0) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
} finally {
|
|
||||||
buffer.position(position);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean canReadLong (byte[] buffer) {
|
|
||||||
int limit = buffer.length;
|
|
||||||
|
|
||||||
if (limit >= 9) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
int p = 0;
|
|
||||||
if ((buffer[p++] & 0x80) == 0) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (p == limit) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if ((buffer[p++] & 0x80) == 0) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (p == limit) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if ((buffer[p++] & 0x80) == 0) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (p == limit) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if ((buffer[p++] & 0x80) == 0) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (p == limit) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if ((buffer[p++] & 0x80) == 0) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (p == limit) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if ((buffer[p++] & 0x80) == 0) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (p == limit) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if ((buffer[p++] & 0x80) == 0) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (p == limit) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if ((buffer[p++] & 0x80) == 0) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (p == limit) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
284
Dorkbox-Util/src/dorkbox/util/bytes/OptimizeUtilsByteArray.java
Normal file
284
Dorkbox-Util/src/dorkbox/util/bytes/OptimizeUtilsByteArray.java
Normal file
@ -0,0 +1,284 @@
|
|||||||
|
package dorkbox.util.bytes;
|
||||||
|
|
||||||
|
public class OptimizeUtilsByteArray {
|
||||||
|
|
||||||
|
private static final OptimizeUtilsByteArray instance = new OptimizeUtilsByteArray();
|
||||||
|
|
||||||
|
public static OptimizeUtilsByteArray get() {
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
private OptimizeUtilsByteArray() {
|
||||||
|
}
|
||||||
|
|
||||||
|
// int
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FROM KRYO
|
||||||
|
*
|
||||||
|
* Returns the number of bytes that would be written with {@link #writeInt(int, boolean)}.
|
||||||
|
*
|
||||||
|
* @param optimizePositive true if you want to optimize the number of bytes needed to write the length value
|
||||||
|
*/
|
||||||
|
public final int intLength (int value, boolean optimizePositive) {
|
||||||
|
return ByteBuffer2.intLength(value, optimizePositive);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FROM KRYO
|
||||||
|
*
|
||||||
|
* look at buffer, and see if we can read the length of the int off of it. (from the reader index)
|
||||||
|
*
|
||||||
|
* @return 0 if we could not read anything, >0 for the number of bytes for the int on the buffer
|
||||||
|
*/
|
||||||
|
public boolean canReadInt(byte[] buffer) {
|
||||||
|
int length = buffer.length;
|
||||||
|
|
||||||
|
if (length >= 5) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
int p = 0;
|
||||||
|
if ((buffer[p++] & 0x80) == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (p == length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ((buffer[p++] & 0x80) == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (p == length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ((buffer[p++] & 0x80) == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (p == length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ((buffer[p++] & 0x80) == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (p == length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FROM KRYO
|
||||||
|
*
|
||||||
|
* Reads an int from the buffer that was optimized.
|
||||||
|
*/
|
||||||
|
public int readInt (byte[] buffer, boolean optimizePositive) {
|
||||||
|
int position = 0;
|
||||||
|
int b = buffer[position++];
|
||||||
|
int result = b & 0x7F;
|
||||||
|
if ((b & 0x80) != 0) {
|
||||||
|
b = buffer[position++];
|
||||||
|
result |= (b & 0x7F) << 7;
|
||||||
|
if ((b & 0x80) != 0) {
|
||||||
|
b = buffer[position++];
|
||||||
|
result |= (b & 0x7F) << 14;
|
||||||
|
if ((b & 0x80) != 0) {
|
||||||
|
b = buffer[position++];
|
||||||
|
result |= (b & 0x7F) << 21;
|
||||||
|
if ((b & 0x80) != 0) {
|
||||||
|
b = buffer[position++];
|
||||||
|
result |= (b & 0x7F) << 28;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return optimizePositive ? result : result >>> 1 ^ -(result & 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FROM KRYO
|
||||||
|
*
|
||||||
|
* Writes the specified int to the buffer using 1 to 5 bytes, depending on the size of the number.
|
||||||
|
*
|
||||||
|
* @param optimizePositive true if you want to optimize the number of bytes needed to write the length value
|
||||||
|
* @return the number of bytes written.
|
||||||
|
*/
|
||||||
|
public int writeInt (byte[] buffer, int value, boolean optimizePositive) {
|
||||||
|
int position = 0;
|
||||||
|
if (!optimizePositive) {
|
||||||
|
value = value << 1 ^ value >> 31;
|
||||||
|
}
|
||||||
|
if (value >>> 7 == 0) {
|
||||||
|
buffer[position++] = (byte)value;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (value >>> 14 == 0) {
|
||||||
|
buffer[position++] = (byte)(value & 0x7F | 0x80);
|
||||||
|
buffer[position++] = (byte)(value >>> 7);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
if (value >>> 21 == 0) {
|
||||||
|
buffer[position++] = (byte)(value & 0x7F | 0x80);
|
||||||
|
buffer[position++] = (byte)(value >>> 7 | 0x80);
|
||||||
|
buffer[position++] = (byte)(value >>> 14);
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
if (value >>> 28 == 0) {
|
||||||
|
buffer[position++] = (byte)(value & 0x7F | 0x80);
|
||||||
|
buffer[position++] = (byte)(value >>> 7 | 0x80);
|
||||||
|
buffer[position++] = (byte)(value >>> 14 | 0x80);
|
||||||
|
buffer[position++] = (byte)(value >>> 21);
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
buffer[position++] = (byte)(value & 0x7F | 0x80);
|
||||||
|
buffer[position++] = (byte)(value >>> 7 | 0x80);
|
||||||
|
buffer[position++] = (byte)(value >>> 14 | 0x80);
|
||||||
|
buffer[position++] = (byte)(value >>> 21 | 0x80);
|
||||||
|
buffer[position++] = (byte)(value >>> 28);
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// long
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of bytes that would be written with {@link #writeLong(long, boolean)}.
|
||||||
|
*
|
||||||
|
* @param optimizePositive true if you want to optimize the number of bytes needed to write the length value
|
||||||
|
*/
|
||||||
|
public final int longLength (long value, boolean optimizePositive) {
|
||||||
|
if (!optimizePositive) {
|
||||||
|
value = value << 1 ^ value >> 63;
|
||||||
|
}
|
||||||
|
if (value >>> 7 == 0) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (value >>> 14 == 0) {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
if (value >>> 21 == 0) {
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
if (value >>> 28 == 0) {
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
if (value >>> 35 == 0) {
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
if (value >>> 42 == 0) {
|
||||||
|
return 6;
|
||||||
|
}
|
||||||
|
if (value >>> 49 == 0) {
|
||||||
|
return 7;
|
||||||
|
}
|
||||||
|
if (value >>> 56 == 0) {
|
||||||
|
return 8;
|
||||||
|
}
|
||||||
|
return 9;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FROM KRYO
|
||||||
|
*
|
||||||
|
* Reads a 1-9 byte long.
|
||||||
|
*
|
||||||
|
* @param optimizePositive true if you want to optimize the number of bytes needed to write the length value
|
||||||
|
*/
|
||||||
|
public long readLong (byte[] buffer, boolean optimizePositive) {
|
||||||
|
int position = 0;
|
||||||
|
int b = buffer[position++];
|
||||||
|
long result = b & 0x7F;
|
||||||
|
if ((b & 0x80) != 0) {
|
||||||
|
b = buffer[position++];
|
||||||
|
result |= (b & 0x7F) << 7;
|
||||||
|
if ((b & 0x80) != 0) {
|
||||||
|
b = buffer[position++];
|
||||||
|
result |= (b & 0x7F) << 14;
|
||||||
|
if ((b & 0x80) != 0) {
|
||||||
|
b = buffer[position++];
|
||||||
|
result |= (b & 0x7F) << 21;
|
||||||
|
if ((b & 0x80) != 0) {
|
||||||
|
b = buffer[position++];
|
||||||
|
result |= (long)(b & 0x7F) << 28;
|
||||||
|
if ((b & 0x80) != 0) {
|
||||||
|
b = buffer[position++];
|
||||||
|
result |= (long)(b & 0x7F) << 35;
|
||||||
|
if ((b & 0x80) != 0) {
|
||||||
|
b = buffer[position++];
|
||||||
|
result |= (long)(b & 0x7F) << 42;
|
||||||
|
if ((b & 0x80) != 0) {
|
||||||
|
b = buffer[position++];
|
||||||
|
result |= (long)(b & 0x7F) << 49;
|
||||||
|
if ((b & 0x80) != 0) {
|
||||||
|
b = buffer[position++];
|
||||||
|
result |= (long)b << 56;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!optimizePositive) {
|
||||||
|
result = result >>> 1 ^ -(result & 1);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean canReadLong (byte[] buffer) {
|
||||||
|
int limit = buffer.length;
|
||||||
|
|
||||||
|
if (limit >= 9) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
int p = 0;
|
||||||
|
if ((buffer[p++] & 0x80) == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (p == limit) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ((buffer[p++] & 0x80) == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (p == limit) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ((buffer[p++] & 0x80) == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (p == limit) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ((buffer[p++] & 0x80) == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (p == limit) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ((buffer[p++] & 0x80) == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (p == limit) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ((buffer[p++] & 0x80) == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (p == limit) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ((buffer[p++] & 0x80) == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (p == limit) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ((buffer[p++] & 0x80) == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (p == limit) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@ -17,14 +17,25 @@ public class OptimizeUtilsByteBuf {
|
|||||||
*
|
*
|
||||||
* Returns the number of bytes that would be written with {@link #writeInt(int, boolean)}.
|
* Returns the number of bytes that would be written with {@link #writeInt(int, boolean)}.
|
||||||
*
|
*
|
||||||
* @param optimizePositive true if you want to optimize the number of bytes needed to write the length value
|
* @param optimizePositive
|
||||||
|
* true if you want to optimize the number of bytes needed to write the length value
|
||||||
*/
|
*/
|
||||||
public final int intLength (int value, boolean optimizePositive) {
|
public final int intLength(int value, boolean optimizePositive) {
|
||||||
if (!optimizePositive) value = (value << 1) ^ (value >> 31);
|
if (!optimizePositive) {
|
||||||
if (value >>> 7 == 0) return 1;
|
value = value << 1 ^ value >> 31;
|
||||||
if (value >>> 14 == 0) return 2;
|
}
|
||||||
if (value >>> 21 == 0) return 3;
|
if (value >>> 7 == 0) {
|
||||||
if (value >>> 28 == 0) return 4;
|
return 1;
|
||||||
|
}
|
||||||
|
if (value >>> 14 == 0) {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
if (value >>> 21 == 0) {
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
if (value >>> 28 == 0) {
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
return 5;
|
return 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -35,7 +46,7 @@ public class OptimizeUtilsByteBuf {
|
|||||||
*
|
*
|
||||||
* @return 0 if we could not read anything, >0 for the number of bytes for the int on the buffer
|
* @return 0 if we could not read anything, >0 for the number of bytes for the int on the buffer
|
||||||
*/
|
*/
|
||||||
public final int canReadInt (ByteBuf buffer) {
|
public final int canReadInt(ByteBuf buffer) {
|
||||||
int startIndex = buffer.readerIndex();
|
int startIndex = buffer.readerIndex();
|
||||||
try {
|
try {
|
||||||
int remaining = buffer.readableBytes();
|
int remaining = buffer.readableBytes();
|
||||||
@ -56,7 +67,7 @@ public class OptimizeUtilsByteBuf {
|
|||||||
*
|
*
|
||||||
* Reads an int from the buffer that was optimized.
|
* Reads an int from the buffer that was optimized.
|
||||||
*/
|
*/
|
||||||
public final int readInt (ByteBuf buffer, boolean optimizePositive) {
|
public final int readInt(ByteBuf buffer, boolean optimizePositive) {
|
||||||
int b = buffer.readByte();
|
int b = buffer.readByte();
|
||||||
int result = b & 0x7F;
|
int result = b & 0x7F;
|
||||||
if ((b & 0x80) != 0) {
|
if ((b & 0x80) != 0) {
|
||||||
@ -75,70 +86,88 @@ public class OptimizeUtilsByteBuf {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return optimizePositive ? result : ((result >>> 1) ^ -(result & 1));
|
return optimizePositive ? result : result >>> 1 ^ -(result & 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* FROM KRYO
|
* FROM KRYO
|
||||||
*
|
*
|
||||||
* Writes the specified int to the buffer using 1 to 5 bytes, depending on the size of the number.
|
* Writes the specified int to the buffer using 1 to 5 bytes, depending on the size of the number.
|
||||||
*
|
*
|
||||||
* @param optimizePositive true if you want to optimize the number of bytes needed to write the length value
|
* @param optimizePositive
|
||||||
|
* true if you want to optimize the number of bytes needed to write the length value
|
||||||
* @return the number of bytes written.
|
* @return the number of bytes written.
|
||||||
*/
|
*/
|
||||||
public final int writeInt (ByteBuf buffer, int value, boolean optimizePositive) {
|
public final int writeInt(ByteBuf buffer, int value, boolean optimizePositive) {
|
||||||
if (!optimizePositive) value = (value << 1) ^ (value >> 31);
|
if (!optimizePositive) {
|
||||||
|
value = value << 1 ^ value >> 31;
|
||||||
|
}
|
||||||
if (value >>> 7 == 0) {
|
if (value >>> 7 == 0) {
|
||||||
buffer.writeByte((byte)value);
|
buffer.writeByte((byte) value);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if (value >>> 14 == 0) {
|
if (value >>> 14 == 0) {
|
||||||
buffer.writeByte((byte)((value & 0x7F) | 0x80));
|
buffer.writeByte((byte) (value & 0x7F | 0x80));
|
||||||
buffer.writeByte((byte)(value >>> 7));
|
buffer.writeByte((byte) (value >>> 7));
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
if (value >>> 21 == 0) {
|
if (value >>> 21 == 0) {
|
||||||
buffer.writeByte((byte)((value & 0x7F) | 0x80));
|
buffer.writeByte((byte) (value & 0x7F | 0x80));
|
||||||
buffer.writeByte((byte)(value >>> 7 | 0x80));
|
buffer.writeByte((byte) (value >>> 7 | 0x80));
|
||||||
buffer.writeByte((byte)(value >>> 14));
|
buffer.writeByte((byte) (value >>> 14));
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
if (value >>> 28 == 0) {
|
if (value >>> 28 == 0) {
|
||||||
buffer.writeByte((byte)((value & 0x7F) | 0x80));
|
buffer.writeByte((byte) (value & 0x7F | 0x80));
|
||||||
buffer.writeByte((byte)(value >>> 7 | 0x80));
|
buffer.writeByte((byte) (value >>> 7 | 0x80));
|
||||||
buffer.writeByte((byte)(value >>> 14 | 0x80));
|
buffer.writeByte((byte) (value >>> 14 | 0x80));
|
||||||
buffer.writeByte((byte)(value >>> 21));
|
buffer.writeByte((byte) (value >>> 21));
|
||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
buffer.writeByte((byte)((value & 0x7F) | 0x80));
|
buffer.writeByte((byte) (value & 0x7F | 0x80));
|
||||||
buffer.writeByte((byte)(value >>> 7 | 0x80));
|
buffer.writeByte((byte) (value >>> 7 | 0x80));
|
||||||
buffer.writeByte((byte)(value >>> 14 | 0x80));
|
buffer.writeByte((byte) (value >>> 14 | 0x80));
|
||||||
buffer.writeByte((byte)(value >>> 21 | 0x80));
|
buffer.writeByte((byte) (value >>> 21 | 0x80));
|
||||||
buffer.writeByte((byte)(value >>> 28));
|
buffer.writeByte((byte) (value >>> 28));
|
||||||
return 5;
|
return 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// long
|
// long
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the number of bytes that would be written with {@link #writeLong(long, boolean)}.
|
* Returns the number of bytes that would be written with {@link #writeLong(long, boolean)}.
|
||||||
*
|
*
|
||||||
* @param optimizePositive true if you want to optimize the number of bytes needed to write the length value
|
* @param optimizePositive
|
||||||
|
* true if you want to optimize the number of bytes needed to write the length value
|
||||||
*/
|
*/
|
||||||
public final int longLength (long value, boolean optimizePositive) {
|
public final int longLength(long value, boolean optimizePositive) {
|
||||||
if (!optimizePositive) value = (value << 1) ^ (value >> 63);
|
if (!optimizePositive) {
|
||||||
if (value >>> 7 == 0) return 1;
|
value = value << 1 ^ value >> 63;
|
||||||
if (value >>> 14 == 0) return 2;
|
}
|
||||||
if (value >>> 21 == 0) return 3;
|
if (value >>> 7 == 0) {
|
||||||
if (value >>> 28 == 0) return 4;
|
return 1;
|
||||||
if (value >>> 35 == 0) return 5;
|
}
|
||||||
if (value >>> 42 == 0) return 6;
|
if (value >>> 14 == 0) {
|
||||||
if (value >>> 49 == 0) return 7;
|
return 2;
|
||||||
if (value >>> 56 == 0) return 8;
|
}
|
||||||
|
if (value >>> 21 == 0) {
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
if (value >>> 28 == 0) {
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
if (value >>> 35 == 0) {
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
if (value >>> 42 == 0) {
|
||||||
|
return 6;
|
||||||
|
}
|
||||||
|
if (value >>> 49 == 0) {
|
||||||
|
return 7;
|
||||||
|
}
|
||||||
|
if (value >>> 56 == 0) {
|
||||||
|
return 8;
|
||||||
|
}
|
||||||
return 9;
|
return 9;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,9 +176,10 @@ public class OptimizeUtilsByteBuf {
|
|||||||
*
|
*
|
||||||
* Reads a 1-9 byte long.
|
* Reads a 1-9 byte long.
|
||||||
*
|
*
|
||||||
* @param optimizePositive true if you want to optimize the number of bytes needed to write the length value
|
* @param optimizePositive
|
||||||
|
* true if you want to optimize the number of bytes needed to write the length value
|
||||||
*/
|
*/
|
||||||
public final long readLong (ByteBuf buffer, boolean optimizePositive) {
|
public final long readLong(ByteBuf buffer, boolean optimizePositive) {
|
||||||
int b = buffer.readByte();
|
int b = buffer.readByte();
|
||||||
long result = b & 0x7F;
|
long result = b & 0x7F;
|
||||||
if ((b & 0x80) != 0) {
|
if ((b & 0x80) != 0) {
|
||||||
@ -163,19 +193,19 @@ public class OptimizeUtilsByteBuf {
|
|||||||
result |= (b & 0x7F) << 21;
|
result |= (b & 0x7F) << 21;
|
||||||
if ((b & 0x80) != 0) {
|
if ((b & 0x80) != 0) {
|
||||||
b = buffer.readByte();
|
b = buffer.readByte();
|
||||||
result |= (long)(b & 0x7F) << 28;
|
result |= (long) (b & 0x7F) << 28;
|
||||||
if ((b & 0x80) != 0) {
|
if ((b & 0x80) != 0) {
|
||||||
b = buffer.readByte();
|
b = buffer.readByte();
|
||||||
result |= (long)(b & 0x7F) << 35;
|
result |= (long) (b & 0x7F) << 35;
|
||||||
if ((b & 0x80) != 0) {
|
if ((b & 0x80) != 0) {
|
||||||
b = buffer.readByte();
|
b = buffer.readByte();
|
||||||
result |= (long)(b & 0x7F) << 42;
|
result |= (long) (b & 0x7F) << 42;
|
||||||
if ((b & 0x80) != 0) {
|
if ((b & 0x80) != 0) {
|
||||||
b = buffer.readByte();
|
b = buffer.readByte();
|
||||||
result |= (long)(b & 0x7F) << 49;
|
result |= (long) (b & 0x7F) << 49;
|
||||||
if ((b & 0x80) != 0) {
|
if ((b & 0x80) != 0) {
|
||||||
b = buffer.readByte();
|
b = buffer.readByte();
|
||||||
result |= (long)b << 56;
|
result |= (long) b << 56;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -184,91 +214,95 @@ public class OptimizeUtilsByteBuf {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!optimizePositive) result = (result >>> 1) ^ -(result & 1);
|
if (!optimizePositive) {
|
||||||
|
result = result >>> 1 ^ -(result & 1);
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* FROM KRYO
|
* FROM KRYO
|
||||||
*
|
*
|
||||||
* Writes a 1-9 byte long.
|
* Writes a 1-9 byte long.
|
||||||
*
|
*
|
||||||
* @param optimizePositive If true, small positive numbers will be more efficient (1 byte) and small negative numbers will be
|
* @param optimizePositive
|
||||||
* inefficient (9 bytes).
|
* If true, small positive numbers will be more efficient (1 byte) and small negative numbers will be
|
||||||
|
* inefficient (9 bytes).
|
||||||
* @return the number of bytes written.
|
* @return the number of bytes written.
|
||||||
*/
|
*/
|
||||||
public final int writeLong (ByteBuf buffer, long value, boolean optimizePositive) {
|
public final int writeLong(ByteBuf buffer, long value, boolean optimizePositive) {
|
||||||
if (!optimizePositive) value = (value << 1) ^ (value >> 63);
|
if (!optimizePositive) {
|
||||||
|
value = value << 1 ^ value >> 63;
|
||||||
|
}
|
||||||
if (value >>> 7 == 0) {
|
if (value >>> 7 == 0) {
|
||||||
buffer.writeByte((byte)value);
|
buffer.writeByte((byte) value);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if (value >>> 14 == 0) {
|
if (value >>> 14 == 0) {
|
||||||
buffer.writeByte((byte)((value & 0x7F) | 0x80));
|
buffer.writeByte((byte) (value & 0x7F | 0x80));
|
||||||
buffer.writeByte((byte)(value >>> 7));
|
buffer.writeByte((byte) (value >>> 7));
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
if (value >>> 21 == 0) {
|
if (value >>> 21 == 0) {
|
||||||
buffer.writeByte((byte)((value & 0x7F) | 0x80));
|
buffer.writeByte((byte) (value & 0x7F | 0x80));
|
||||||
buffer.writeByte((byte)(value >>> 7 | 0x80));
|
buffer.writeByte((byte) (value >>> 7 | 0x80));
|
||||||
buffer.writeByte((byte)(value >>> 14));
|
buffer.writeByte((byte) (value >>> 14));
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
if (value >>> 28 == 0) {
|
if (value >>> 28 == 0) {
|
||||||
buffer.writeByte((byte)((value & 0x7F) | 0x80));
|
buffer.writeByte((byte) (value & 0x7F | 0x80));
|
||||||
buffer.writeByte((byte)(value >>> 7 | 0x80));
|
buffer.writeByte((byte) (value >>> 7 | 0x80));
|
||||||
buffer.writeByte((byte)(value >>> 14 | 0x80));
|
buffer.writeByte((byte) (value >>> 14 | 0x80));
|
||||||
buffer.writeByte((byte)(value >>> 21));
|
buffer.writeByte((byte) (value >>> 21));
|
||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
if (value >>> 35 == 0) {
|
if (value >>> 35 == 0) {
|
||||||
buffer.writeByte((byte)((value & 0x7F) | 0x80));
|
buffer.writeByte((byte) (value & 0x7F | 0x80));
|
||||||
buffer.writeByte((byte)(value >>> 7 | 0x80));
|
buffer.writeByte((byte) (value >>> 7 | 0x80));
|
||||||
buffer.writeByte((byte)(value >>> 14 | 0x80));
|
buffer.writeByte((byte) (value >>> 14 | 0x80));
|
||||||
buffer.writeByte((byte)(value >>> 21 | 0x80));
|
buffer.writeByte((byte) (value >>> 21 | 0x80));
|
||||||
buffer.writeByte((byte)(value >>> 28));
|
buffer.writeByte((byte) (value >>> 28));
|
||||||
return 5;
|
return 5;
|
||||||
}
|
}
|
||||||
if (value >>> 42 == 0) {
|
if (value >>> 42 == 0) {
|
||||||
buffer.writeByte((byte)((value & 0x7F) | 0x80));
|
buffer.writeByte((byte) (value & 0x7F | 0x80));
|
||||||
buffer.writeByte((byte)(value >>> 7 | 0x80));
|
buffer.writeByte((byte) (value >>> 7 | 0x80));
|
||||||
buffer.writeByte((byte)(value >>> 14 | 0x80));
|
buffer.writeByte((byte) (value >>> 14 | 0x80));
|
||||||
buffer.writeByte((byte)(value >>> 21 | 0x80));
|
buffer.writeByte((byte) (value >>> 21 | 0x80));
|
||||||
buffer.writeByte((byte)(value >>> 28 | 0x80));
|
buffer.writeByte((byte) (value >>> 28 | 0x80));
|
||||||
buffer.writeByte((byte)(value >>> 35));
|
buffer.writeByte((byte) (value >>> 35));
|
||||||
return 6;
|
return 6;
|
||||||
}
|
}
|
||||||
if (value >>> 49 == 0) {
|
if (value >>> 49 == 0) {
|
||||||
buffer.writeByte((byte)((value & 0x7F) | 0x80));
|
buffer.writeByte((byte) (value & 0x7F | 0x80));
|
||||||
buffer.writeByte((byte)(value >>> 7 | 0x80));
|
buffer.writeByte((byte) (value >>> 7 | 0x80));
|
||||||
buffer.writeByte((byte)(value >>> 14 | 0x80));
|
buffer.writeByte((byte) (value >>> 14 | 0x80));
|
||||||
buffer.writeByte((byte)(value >>> 21 | 0x80));
|
buffer.writeByte((byte) (value >>> 21 | 0x80));
|
||||||
buffer.writeByte((byte)(value >>> 28 | 0x80));
|
buffer.writeByte((byte) (value >>> 28 | 0x80));
|
||||||
buffer.writeByte((byte)(value >>> 35 | 0x80));
|
buffer.writeByte((byte) (value >>> 35 | 0x80));
|
||||||
buffer.writeByte((byte)(value >>> 42));
|
buffer.writeByte((byte) (value >>> 42));
|
||||||
return 7;
|
return 7;
|
||||||
}
|
}
|
||||||
if (value >>> 56 == 0) {
|
if (value >>> 56 == 0) {
|
||||||
buffer.writeByte((byte)((value & 0x7F) | 0x80));
|
buffer.writeByte((byte) (value & 0x7F | 0x80));
|
||||||
buffer.writeByte((byte)(value >>> 7 | 0x80));
|
buffer.writeByte((byte) (value >>> 7 | 0x80));
|
||||||
buffer.writeByte((byte)(value >>> 14 | 0x80));
|
buffer.writeByte((byte) (value >>> 14 | 0x80));
|
||||||
buffer.writeByte((byte)(value >>> 21 | 0x80));
|
buffer.writeByte((byte) (value >>> 21 | 0x80));
|
||||||
buffer.writeByte((byte)(value >>> 28 | 0x80));
|
buffer.writeByte((byte) (value >>> 28 | 0x80));
|
||||||
buffer.writeByte((byte)(value >>> 35 | 0x80));
|
buffer.writeByte((byte) (value >>> 35 | 0x80));
|
||||||
buffer.writeByte((byte)(value >>> 42 | 0x80));
|
buffer.writeByte((byte) (value >>> 42 | 0x80));
|
||||||
buffer.writeByte((byte)(value >>> 49));
|
buffer.writeByte((byte) (value >>> 49));
|
||||||
return 8;
|
return 8;
|
||||||
}
|
}
|
||||||
buffer.writeByte((byte)((value & 0x7F) | 0x80));
|
buffer.writeByte((byte) (value & 0x7F | 0x80));
|
||||||
buffer.writeByte((byte)(value >>> 7 | 0x80));
|
buffer.writeByte((byte) (value >>> 7 | 0x80));
|
||||||
buffer.writeByte((byte)(value >>> 14 | 0x80));
|
buffer.writeByte((byte) (value >>> 14 | 0x80));
|
||||||
buffer.writeByte((byte)(value >>> 21 | 0x80));
|
buffer.writeByte((byte) (value >>> 21 | 0x80));
|
||||||
buffer.writeByte((byte)(value >>> 28 | 0x80));
|
buffer.writeByte((byte) (value >>> 28 | 0x80));
|
||||||
buffer.writeByte((byte)(value >>> 35 | 0x80));
|
buffer.writeByte((byte) (value >>> 35 | 0x80));
|
||||||
buffer.writeByte((byte)(value >>> 42 | 0x80));
|
buffer.writeByte((byte) (value >>> 42 | 0x80));
|
||||||
buffer.writeByte((byte)(value >>> 49 | 0x80));
|
buffer.writeByte((byte) (value >>> 49 | 0x80));
|
||||||
buffer.writeByte((byte)(value >>> 56));
|
buffer.writeByte((byte) (value >>> 56));
|
||||||
return 9;
|
return 9;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -279,7 +313,7 @@ public class OptimizeUtilsByteBuf {
|
|||||||
*
|
*
|
||||||
* @return 0 if we could not read anything, >0 for the number of bytes for the long on the buffer
|
* @return 0 if we could not read anything, >0 for the number of bytes for the long on the buffer
|
||||||
*/
|
*/
|
||||||
public final int canReadLong (ByteBuf buffer) {
|
public final int canReadLong(ByteBuf buffer) {
|
||||||
int position = buffer.readerIndex();
|
int position = buffer.readerIndex();
|
||||||
try {
|
try {
|
||||||
int remaining = buffer.readableBytes();
|
int remaining = buffer.readableBytes();
|
||||||
|
38
Dorkbox-Util/src/dorkbox/util/input/Encoding.java
Normal file
38
Dorkbox-Util/src/dorkbox/util/input/Encoding.java
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
package dorkbox.util.input;
|
||||||
|
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
|
||||||
|
public class Encoding {
|
||||||
|
/**
|
||||||
|
* Get the default encoding. Will first look at the LC_CTYPE environment variable, then the input.encoding
|
||||||
|
* system property, then the default charset according to the JVM.
|
||||||
|
*
|
||||||
|
* @return The default encoding to use when none is specified.
|
||||||
|
*/
|
||||||
|
public static String get() {
|
||||||
|
// LC_CTYPE is usually in the form en_US.UTF-8
|
||||||
|
String envEncoding = extractEncodingFromCtype(System.getenv("LC_CTYPE"));
|
||||||
|
if (envEncoding != null) {
|
||||||
|
return envEncoding;
|
||||||
|
}
|
||||||
|
return System.getProperty("input.encoding", Charset.defaultCharset().name());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses the LC_CTYPE value to extract the encoding according to the POSIX standard, which says that the LC_CTYPE
|
||||||
|
* environment variable may be of the format <code>[language[_territory][.codeset][@modifier]]</code>
|
||||||
|
*
|
||||||
|
* @param ctype The ctype to parse, may be null
|
||||||
|
* @return The encoding, if one was present, otherwise null
|
||||||
|
*/
|
||||||
|
private static String extractEncodingFromCtype(String ctype) {
|
||||||
|
if (ctype != null && ctype.indexOf('.') > 0) {
|
||||||
|
String encodingAndModifier = ctype.substring(ctype.indexOf('.') + 1);
|
||||||
|
if (encodingAndModifier.indexOf('@') > 0) {
|
||||||
|
return encodingAndModifier.substring(0, encodingAndModifier.indexOf('@'));
|
||||||
|
}
|
||||||
|
return encodingAndModifier;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
@ -1,14 +1,11 @@
|
|||||||
package dorkbox.util.input;
|
package dorkbox.util.input;
|
||||||
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.PrintStream;
|
import java.io.PrintStream;
|
||||||
import java.io.Reader;
|
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.nio.charset.Charset;
|
|
||||||
import java.security.CodeSource;
|
import java.security.CodeSource;
|
||||||
import java.security.ProtectionDomain;
|
import java.security.ProtectionDomain;
|
||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
@ -18,11 +15,14 @@ import org.fusesource.jansi.AnsiConsole;
|
|||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
|
||||||
import dorkbox.util.OS;
|
import dorkbox.util.OS;
|
||||||
import dorkbox.util.Sys;
|
import dorkbox.util.bytes.ByteBuffer2;
|
||||||
import dorkbox.util.bytes.ByteBuffer2Fast;
|
import dorkbox.util.bytes.ByteBuffer2Poolable;
|
||||||
import dorkbox.util.input.posix.UnixTerminal;
|
import dorkbox.util.input.posix.UnixTerminal;
|
||||||
import dorkbox.util.input.unsupported.UnsupportedTerminal;
|
import dorkbox.util.input.unsupported.UnsupportedTerminal;
|
||||||
import dorkbox.util.input.windows.WindowsTerminal;
|
import dorkbox.util.input.windows.WindowsTerminal;
|
||||||
|
import dorkbox.util.objectPool.ObjectPool;
|
||||||
|
import dorkbox.util.objectPool.ObjectPoolFactory;
|
||||||
|
import dorkbox.util.objectPool.ObjectPoolHolder;
|
||||||
|
|
||||||
public class InputConsole {
|
public class InputConsole {
|
||||||
private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(InputConsole.class);
|
private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(InputConsole.class);
|
||||||
@ -108,30 +108,15 @@ public class InputConsole {
|
|||||||
private final Object inputLockSingle = new Object();
|
private final Object inputLockSingle = new Object();
|
||||||
private final Object inputLockLine = new Object();
|
private final Object inputLockLine = new Object();
|
||||||
|
|
||||||
private ThreadLocal<ByteBuffer2Fast> threadBufferForRead = new ThreadLocal<ByteBuffer2Fast>();
|
private final ObjectPool<ByteBuffer2> pool = ObjectPoolFactory.create(new ByteBuffer2Poolable());
|
||||||
private CopyOnWriteArrayList<ByteBuffer2Fast> threadBuffersForRead = new CopyOnWriteArrayList<ByteBuffer2Fast>();
|
private ThreadLocal<ObjectPoolHolder<ByteBuffer2>> threadBufferForRead = new ThreadLocal<ObjectPoolHolder<ByteBuffer2>>();
|
||||||
|
private CopyOnWriteArrayList<ObjectPoolHolder<ByteBuffer2>> threadBuffersForRead = new CopyOnWriteArrayList<ObjectPoolHolder<ByteBuffer2>>();
|
||||||
ThreadLocal<Integer> indexOfStringForReadChar = new ThreadLocal<Integer>() {
|
|
||||||
@Override
|
|
||||||
protected Integer initialValue() {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
private volatile int readChar = -1;
|
private volatile int readChar = -1;
|
||||||
|
|
||||||
private final boolean unsupported;
|
|
||||||
|
|
||||||
private final Terminal terminal;
|
private final Terminal terminal;
|
||||||
private Reader reader;
|
|
||||||
private final String encoding;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private InputConsole() {
|
private InputConsole() {
|
||||||
Logger logger = InputConsole.logger;
|
Logger logger = InputConsole.logger;
|
||||||
boolean unsupported = false;
|
|
||||||
|
|
||||||
String type = System.getProperty(TerminalType.TYPE, TerminalType.AUTO).toLowerCase();
|
String type = System.getProperty(TerminalType.TYPE, TerminalType.AUTO).toLowerCase();
|
||||||
if ("dumb".equals(System.getenv("TERM"))) {
|
if ("dumb".equals(System.getenv("TERM"))) {
|
||||||
@ -141,48 +126,42 @@ public class InputConsole {
|
|||||||
|
|
||||||
logger.debug("Creating terminal; type={}", type);
|
logger.debug("Creating terminal; type={}", type);
|
||||||
|
|
||||||
Terminal t;
|
|
||||||
|
String encoding = Encoding.get();
|
||||||
|
Terminal t;
|
||||||
try {
|
try {
|
||||||
if (type.equals(TerminalType.UNIX)) {
|
if (type.equals(TerminalType.UNIX)) {
|
||||||
t = new UnixTerminal();
|
t = new UnixTerminal(encoding);
|
||||||
}
|
}
|
||||||
else if (type.equals(TerminalType.WIN) || type.equals(TerminalType.WINDOWS)) {
|
else if (type.equals(TerminalType.WIN) || type.equals(TerminalType.WINDOWS)) {
|
||||||
t = new WindowsTerminal();
|
t = new WindowsTerminal();
|
||||||
}
|
}
|
||||||
else if (type.equals(TerminalType.NONE) || type.equals(TerminalType.OFF) || type.equals(TerminalType.FALSE)) {
|
else if (type.equals(TerminalType.NONE) || type.equals(TerminalType.OFF) || type.equals(TerminalType.FALSE)) {
|
||||||
t = new UnsupportedTerminal();
|
t = new UnsupportedTerminal(encoding);
|
||||||
unsupported = true;
|
|
||||||
} else {
|
} else {
|
||||||
if (isIDEAutoDetect()) {
|
if (isIDEAutoDetect()) {
|
||||||
logger.debug("Terminal is in UNSUPPORTED (best guess). Unable to support single key input. Only line input available.");
|
logger.debug("Terminal is in UNSUPPORTED (best guess). Unable to support single key input. Only line input available.");
|
||||||
t = new UnsupportedTerminal();
|
t = new UnsupportedTerminal(encoding);
|
||||||
unsupported = true;
|
|
||||||
} else {
|
} else {
|
||||||
if (OS.isWindows()) {
|
if (OS.isWindows()) {
|
||||||
t = new WindowsTerminal();
|
t = new WindowsTerminal();
|
||||||
} else {
|
} else {
|
||||||
t = new UnixTerminal();
|
t = new UnixTerminal(encoding);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e) {
|
catch (Exception e) {
|
||||||
logger.error("Failed to construct terminal, falling back to unsupported");
|
logger.error("Failed to construct terminal, falling back to unsupported");
|
||||||
t = new UnsupportedTerminal();
|
t = new UnsupportedTerminal(encoding);
|
||||||
unsupported = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
InputStream in;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
t.init();
|
t.init();
|
||||||
in = t.wrapInIfNeeded(System.in);
|
|
||||||
}
|
}
|
||||||
catch (Throwable e) {
|
catch (Throwable e) {
|
||||||
logger.error("Terminal initialization failed, falling back to unsupported");
|
logger.error("Terminal initialization failed, falling back to unsupported");
|
||||||
t = new UnsupportedTerminal();
|
t = new UnsupportedTerminal(encoding);
|
||||||
unsupported = true;
|
|
||||||
in = System.in;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
t.init();
|
t.init();
|
||||||
@ -191,17 +170,10 @@ public class InputConsole {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.encoding = this.encoding != null ? this.encoding : getEncoding();
|
t.setEchoEnabled(true);
|
||||||
this.reader = new InputStreamReader(in, this.encoding);
|
|
||||||
|
|
||||||
if (unsupported) {
|
|
||||||
this.reader = new BufferedReader(this.reader);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.unsupported = unsupported;
|
|
||||||
this.terminal = t;
|
this.terminal = t;
|
||||||
|
logger.debug("Created Terminal: {} ({}x{})", this.terminal.getClass().getSimpleName(), t.getWidth(), t.getHeight());
|
||||||
logger.debug("Created Terminal: {}", this.terminal);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// called when the JVM is shutting down.
|
// called when the JVM is shutting down.
|
||||||
@ -237,9 +209,9 @@ public class InputConsole {
|
|||||||
/** return null if no data */
|
/** return null if no data */
|
||||||
private final char[] readLine0() {
|
private final char[] readLine0() {
|
||||||
if (this.threadBufferForRead.get() == null) {
|
if (this.threadBufferForRead.get() == null) {
|
||||||
ByteBuffer2Fast buffer = ByteBuffer2Fast.allocate(0);
|
ObjectPoolHolder<ByteBuffer2> holder = this.pool.take();
|
||||||
this.threadBufferForRead.set(buffer);
|
this.threadBufferForRead.set(holder);
|
||||||
this.threadBuffersForRead.add(buffer);
|
this.threadBuffersForRead.add(holder);
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized (this.inputLockLine) {
|
synchronized (this.inputLockLine) {
|
||||||
@ -250,33 +222,28 @@ public class InputConsole {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ByteBuffer2Fast stringBuffer = this.threadBufferForRead.get();
|
ObjectPoolHolder<ByteBuffer2> objectPoolHolder = this.threadBufferForRead.get();
|
||||||
int len = stringBuffer.position();
|
ByteBuffer2 buffer = objectPoolHolder.getValue();
|
||||||
|
int len = buffer.position();
|
||||||
if (len == 0) {
|
if (len == 0) {
|
||||||
return emptyLine;
|
return emptyLine;
|
||||||
}
|
}
|
||||||
|
|
||||||
char[] chars = new char[len/2]; // because 2 chars is 1 bytes
|
buffer.rewind();
|
||||||
stringBuffer.getChars(0, len, chars, 0);
|
char[] readChars = buffer.readChars(len/2); // java always stores chars in 2 bytes
|
||||||
|
|
||||||
// dump the chars in the buffer (safer for passwords, etc)
|
// dump the chars in the buffer (safer for passwords, etc)
|
||||||
stringBuffer.clear();
|
buffer.clearSecure();
|
||||||
stringBuffer.putBytes(new byte[0]);
|
|
||||||
|
|
||||||
|
this.threadBuffersForRead.remove(objectPoolHolder);
|
||||||
|
this.pool.release(objectPoolHolder);
|
||||||
this.threadBufferForRead.set(null);
|
this.threadBufferForRead.set(null);
|
||||||
this.threadBuffersForRead.remove(stringBuffer); // TODO: use object pool!
|
|
||||||
|
|
||||||
return chars;
|
return readChars;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** return null if no data */
|
/** return null if no data */
|
||||||
private final char[] readLinePassword0() {
|
private final char[] readLinePassword0() {
|
||||||
if (this.threadBufferForRead.get() == null) {
|
|
||||||
ByteBuffer2Fast buffer = ByteBuffer2Fast.allocate(0);
|
|
||||||
this.threadBufferForRead.set(buffer);
|
|
||||||
this.threadBuffersForRead.add(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
// don't bother in an IDE. it won't work.
|
// don't bother in an IDE. it won't work.
|
||||||
boolean echoEnabled = this.terminal.isEchoEnabled();
|
boolean echoEnabled = this.terminal.isEchoEnabled();
|
||||||
this.terminal.setEchoEnabled(false);
|
this.terminal.setEchoEnabled(false);
|
||||||
@ -288,51 +255,15 @@ public class InputConsole {
|
|||||||
|
|
||||||
/** return -1 if no data */
|
/** return -1 if no data */
|
||||||
private final int read0() {
|
private final int read0() {
|
||||||
// if we are reading data (because we are in IDE mode), we want to return ALL
|
synchronized (this.inputLockSingle) {
|
||||||
// the chars of the line!
|
try {
|
||||||
|
this.inputLockSingle.wait();
|
||||||
// so, readChar is REALLY the index at which we return letters (until the whole string is returned
|
} catch (InterruptedException e) {
|
||||||
if (this.unsupported) {
|
return -1;
|
||||||
int readerCount = this.indexOfStringForReadChar.get();
|
|
||||||
|
|
||||||
if (readerCount == -1) {
|
|
||||||
// we have to wait for more data.
|
|
||||||
synchronized (this.inputLockLine) {
|
|
||||||
try {
|
|
||||||
this.inputLockLine.wait();
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
readerCount = 0;
|
|
||||||
this.indexOfStringForReadChar.set(0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// EACH thread will have it's own count!
|
|
||||||
ByteBuffer2Fast stringBuffer = this.threadBufferForRead.get();
|
|
||||||
|
|
||||||
if (readerCount == stringBuffer.position()) {
|
|
||||||
this.indexOfStringForReadChar.set(-1);
|
|
||||||
return '\n';
|
|
||||||
} else {
|
|
||||||
this.indexOfStringForReadChar.set(readerCount+1);
|
|
||||||
}
|
|
||||||
|
|
||||||
char c = stringBuffer.getChar(readerCount);
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// we can read like normal.
|
|
||||||
synchronized (this.inputLockSingle) {
|
|
||||||
try {
|
|
||||||
this.inputLockSingle.wait();
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return this.readChar;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return this.readChar;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -351,163 +282,98 @@ public class InputConsole {
|
|||||||
private final void run() {
|
private final void run() {
|
||||||
Logger logger2 = logger;
|
Logger logger2 = logger;
|
||||||
|
|
||||||
// if we are eclipse/etc, we MUST do this per line! (per character DOESN'T work.)
|
final boolean ansiEnabled = Ansi.isEnabled();
|
||||||
// char readers will get looped for the WHOLE string, so reading by char will work,
|
Ansi ansi = Ansi.ansi();
|
||||||
// it just waits until \n until it triggers
|
PrintStream out = AnsiConsole.out;
|
||||||
if (this.unsupported) {
|
|
||||||
BufferedReader reader = (BufferedReader) this.reader;
|
|
||||||
String line = null;
|
|
||||||
char[] readLine = null;
|
|
||||||
|
|
||||||
try {
|
int typedChar;
|
||||||
while ((line = reader.readLine()) != null) {
|
char asChar;
|
||||||
readLine = line.toCharArray();
|
|
||||||
|
|
||||||
// notify everyone waiting for a line of text.
|
// don't type ; in a bash shell, it quits everything
|
||||||
synchronized (this.inputLockSingle) {
|
// \n is replaced by \r in unix terminal?
|
||||||
if (readLine.length > 0) {
|
while ((typedChar = this.terminal.read()) != -1) {
|
||||||
this.readChar = readLine[0];
|
asChar = (char) typedChar;
|
||||||
} else {
|
|
||||||
this.readChar = -1;
|
|
||||||
}
|
|
||||||
this.inputLockSingle.notifyAll();
|
|
||||||
}
|
|
||||||
synchronized (this.inputLockLine) {
|
|
||||||
byte[] charToBytes = Sys.charToBytes(readLine);
|
|
||||||
|
|
||||||
for (ByteBuffer2Fast buffer : this.threadBuffersForRead) {
|
if (logger2.isTraceEnabled()) {
|
||||||
buffer.clear();
|
logger2.trace("READ: {} ({})", asChar, typedChar);
|
||||||
buffer.putBytes(charToBytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.inputLockLine.notifyAll();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Exception ignored) {
|
|
||||||
ignored.printStackTrace();
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else {
|
|
||||||
// from a 'regular' console
|
|
||||||
try {
|
|
||||||
final boolean ansiEnabled = Ansi.isEnabled();
|
|
||||||
Ansi ansi = Ansi.ansi();
|
|
||||||
PrintStream out = AnsiConsole.out;
|
|
||||||
|
|
||||||
int typedChar;
|
// notify everyone waiting for a character.
|
||||||
|
synchronized (this.inputLockSingle) {
|
||||||
|
if (this.terminal.wasSequence() && typedChar == '\n') {
|
||||||
|
// don't want to forward \n if it was a part of a sequence in the unsupported terminal
|
||||||
|
// the JIT will short-cut this out if we are not the unsupported terminal
|
||||||
|
} else {
|
||||||
|
this.readChar = typedChar;
|
||||||
|
this.inputLockSingle.notifyAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// don't type ; in a bash shell, it quits everything
|
// if we type a backspace key, swallow it + previous in READLINE. READCHAR will have it passed.
|
||||||
// \n is replaced by \r in unix terminal?
|
if (typedChar == '\b') {
|
||||||
while ((typedChar = this.reader.read()) != -1) {
|
int position = 0;
|
||||||
char asChar = (char) typedChar;
|
|
||||||
|
|
||||||
if (logger2.isTraceEnabled()) {
|
// clear ourself + one extra.
|
||||||
logger2.trace("READ: {} ({})", asChar, typedChar);
|
if (ansiEnabled) {
|
||||||
}
|
for (ObjectPoolHolder<ByteBuffer2> objectPoolHolder : this.threadBuffersForRead) {
|
||||||
|
ByteBuffer2 buffer = objectPoolHolder.getValue();
|
||||||
|
// size of the buffer BEFORE our backspace was typed
|
||||||
|
int length = buffer.position();
|
||||||
|
int amtToOverwrite = 2 * 2; // backspace is always 2 chars (^?) * 2 because it's bytes
|
||||||
|
|
||||||
// notify everyone waiting for a character.
|
if (length > 1) {
|
||||||
synchronized (this.inputLockSingle) {
|
char charAt = buffer.readChar(length-2);
|
||||||
this.readChar = typedChar;
|
amtToOverwrite += getPrintableCharacters(charAt);
|
||||||
this.inputLockSingle.notifyAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
// if we type a backspace key, swallow it + previous in READLINE. READCHAR will have it passed.
|
// delete last item in our buffer
|
||||||
if (typedChar == 127) {
|
length -= 2;
|
||||||
int position = 0;
|
buffer.setPosition(length);
|
||||||
|
|
||||||
// clear ourself + one extra.
|
// now figure out where the cursor is really at.
|
||||||
if (ansiEnabled) {
|
// this is more memory friendly than buf.toString.length
|
||||||
for (ByteBuffer2Fast buffer : this.threadBuffersForRead) {
|
for (int i=0;i<length;i+=2) {
|
||||||
// size of the buffer BEFORE our backspace was typed
|
charAt = buffer.readChar(i);
|
||||||
int length = buffer.position();
|
position += getPrintableCharacters(charAt);
|
||||||
int amtToOverwrite = 2 * 2; // backspace is always 2 chars (^?) * 2 because it's bytes
|
|
||||||
|
|
||||||
if (length > 1) {
|
|
||||||
char charAt = buffer.getChar(length-2);
|
|
||||||
amtToOverwrite += getPrintableCharacters(charAt);
|
|
||||||
|
|
||||||
// delete last item in our buffer
|
|
||||||
length -= 2;
|
|
||||||
buffer.position(length);
|
|
||||||
|
|
||||||
// now figure out where the cursor is really at.
|
|
||||||
// this is more memory friendly than buf.toString.length
|
|
||||||
for (int i=0;i<length;i+=2) {
|
|
||||||
charAt = buffer.getChar(i);
|
|
||||||
position += getPrintableCharacters(charAt);
|
|
||||||
}
|
|
||||||
|
|
||||||
position++;
|
|
||||||
}
|
|
||||||
|
|
||||||
char[] overwrite = new char[amtToOverwrite];
|
|
||||||
char c = ' ';
|
|
||||||
for (int i=0;i<amtToOverwrite;i++) {
|
|
||||||
overwrite[i] = c;
|
|
||||||
}
|
|
||||||
|
|
||||||
// move back however many, over write, then go back again
|
|
||||||
out.print(ansi.cursorToColumn(position));
|
|
||||||
out.print(overwrite);
|
|
||||||
out.print(ansi.cursorToColumn(position));
|
|
||||||
out.flush();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
position++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// read-line will ignore backspace
|
char[] overwrite = new char[amtToOverwrite];
|
||||||
continue;
|
char c = ' ';
|
||||||
}
|
for (int i=0;i<amtToOverwrite;i++) {
|
||||||
|
overwrite[i] = c;
|
||||||
|
}
|
||||||
|
|
||||||
// ignoring \r, because \n is ALWAYS the last character in a new line sequence. (even for windows)
|
// move back however many, over write, then go back again
|
||||||
if (asChar == '\n') {
|
out.print(ansi.cursorToColumn(position));
|
||||||
synchronized (this.inputLockLine) {
|
out.print(overwrite);
|
||||||
this.inputLockLine.notifyAll();
|
out.print(ansi.cursorToColumn(position));
|
||||||
}
|
out.flush();
|
||||||
} else if (asChar != '\r') {
|
|
||||||
// only append if we are not a new line.
|
|
||||||
for (ByteBuffer2Fast buffer : this.threadBuffersForRead) {
|
|
||||||
buffer.putChar(asChar);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (IOException ignored) {
|
|
||||||
|
// read-line will ignore backspace
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ignoring \r, because \n is ALWAYS the last character in a new line sequence. (even for windows)
|
||||||
|
if (asChar == '\n') {
|
||||||
|
synchronized (this.inputLockLine) {
|
||||||
|
this.inputLockLine.notifyAll();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// our windows console PREVENTS us from returning '\r' (it truncates '\r\n', and returns just '\n')
|
||||||
|
|
||||||
|
// only append if we are not a new line.
|
||||||
|
for (ObjectPoolHolder<ByteBuffer2> objectPoolHolder : this.threadBuffersForRead) {
|
||||||
|
ByteBuffer2 buffer = objectPoolHolder.getValue();
|
||||||
|
buffer.writeChar(asChar);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the default encoding. Will first look at the LC_CTYPE environment variable, then the input.encoding
|
|
||||||
* system property, then the default charset according to the JVM.
|
|
||||||
*
|
|
||||||
* @return The default encoding to use when none is specified.
|
|
||||||
*/
|
|
||||||
public static String getEncoding() {
|
|
||||||
// LC_CTYPE is usually in the form en_US.UTF-8
|
|
||||||
String envEncoding = extractEncodingFromCtype(System.getenv("LC_CTYPE"));
|
|
||||||
if (envEncoding != null) {
|
|
||||||
return envEncoding;
|
|
||||||
}
|
|
||||||
return System.getProperty("input.encoding", Charset.defaultCharset().name());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parses the LC_CTYPE value to extract the encoding according to the POSIX standard, which says that the LC_CTYPE
|
|
||||||
* environment variable may be of the format <code>[language[_territory][.codeset][@modifier]]</code>
|
|
||||||
*
|
|
||||||
* @param ctype The ctype to parse, may be null
|
|
||||||
* @return The encoding, if one was present, otherwise null
|
|
||||||
*/
|
|
||||||
static String extractEncodingFromCtype(String ctype) {
|
|
||||||
if (ctype != null && ctype.indexOf('.') > 0) {
|
|
||||||
String encodingAndModifier = ctype.substring(ctype.indexOf('.') + 1);
|
|
||||||
if (encodingAndModifier.indexOf('@') > 0) {
|
|
||||||
return encodingAndModifier.substring(0, encodingAndModifier.indexOf('@'));
|
|
||||||
}
|
|
||||||
return encodingAndModifier;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* try to guess if we are running inside an IDE
|
* try to guess if we are running inside an IDE
|
||||||
*/
|
*/
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package dorkbox.util.input;
|
package dorkbox.util.input;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
|
||||||
|
|
||||||
public abstract class Terminal {
|
public abstract class Terminal {
|
||||||
protected final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(getClass());
|
protected final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(getClass());
|
||||||
@ -60,7 +59,15 @@ public abstract class Terminal {
|
|||||||
public abstract int getWidth();
|
public abstract int getWidth();
|
||||||
public abstract int getHeight();
|
public abstract int getHeight();
|
||||||
|
|
||||||
public InputStream wrapInIfNeeded(InputStream in) throws IOException {
|
/**
|
||||||
return in;
|
* @return a character from whatever underlying input method the terminal has available.
|
||||||
|
*/
|
||||||
|
public abstract int read();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Only needed for unsupported character input.
|
||||||
|
*/
|
||||||
|
public boolean wasSequence() {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
*
|
*
|
||||||
* http://www.opensource.org/licenses/bsd-license.php
|
* http://www.opensource.org/licenses/bsd-license.php
|
||||||
*/
|
*/
|
||||||
package dorkbox.util.input;
|
package dorkbox.util.input.posix;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
@ -1,6 +1,7 @@
|
|||||||
package dorkbox.util.input.posix;
|
package dorkbox.util.input.posix;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.Reader;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
import com.sun.jna.Native;
|
import com.sun.jna.Native;
|
||||||
@ -18,10 +19,15 @@ public class UnixTerminal extends Terminal {
|
|||||||
private volatile TermiosStruct termInfoDefault = new TermiosStruct();
|
private volatile TermiosStruct termInfoDefault = new TermiosStruct();
|
||||||
private volatile TermiosStruct termInfo = new TermiosStruct();
|
private volatile TermiosStruct termInfo = new TermiosStruct();
|
||||||
|
|
||||||
|
private Reader reader;
|
||||||
|
|
||||||
private PosixTerminalControl term;
|
private PosixTerminalControl term;
|
||||||
private ByteBuffer windowSizeBuffer = ByteBuffer.allocate(8);
|
private ByteBuffer windowSizeBuffer = ByteBuffer.allocate(8);
|
||||||
|
|
||||||
public UnixTerminal() throws Exception {
|
|
||||||
|
public UnixTerminal(String encoding) throws Exception {
|
||||||
|
this.reader = new InputStreamReader(System.in, encoding);
|
||||||
|
|
||||||
this.term = (PosixTerminalControl) Native.loadLibrary("c", PosixTerminalControl.class);
|
this.term = (PosixTerminalControl) Native.loadLibrary("c", PosixTerminalControl.class);
|
||||||
|
|
||||||
// save off the defaults
|
// save off the defaults
|
||||||
@ -54,7 +60,6 @@ public class UnixTerminal extends Terminal {
|
|||||||
// t->c_cc[VMIN] = 1;
|
// t->c_cc[VMIN] = 1;
|
||||||
// t->c_cc[VTIME] = 0;
|
// t->c_cc[VTIME] = 0;
|
||||||
|
|
||||||
|
|
||||||
if (this.term.tcgetattr(0, this.termInfo) !=0) {
|
if (this.term.tcgetattr(0, this.termInfo) !=0) {
|
||||||
throw new IOException("Failed to get terminal info");
|
throw new IOException("Failed to get terminal info");
|
||||||
}
|
}
|
||||||
@ -86,7 +91,7 @@ public class UnixTerminal extends Terminal {
|
|||||||
* used after calling this method.
|
* used after calling this method.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void restore() throws IOException {
|
public final void restore() throws IOException {
|
||||||
if (this.term.tcsetattr(0, PosixTerminalControl.TCSANOW, this.termInfoDefault) != 0) {
|
if (this.term.tcsetattr(0, PosixTerminalControl.TCSANOW, this.termInfoDefault) != 0) {
|
||||||
throw new IOException("Can not reset terminal to defaults");
|
throw new IOException("Can not reset terminal to defaults");
|
||||||
}
|
}
|
||||||
@ -96,7 +101,7 @@ public class UnixTerminal extends Terminal {
|
|||||||
* Returns number of columns in the terminal.
|
* Returns number of columns in the terminal.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public int getWidth() {
|
public final int getWidth() {
|
||||||
if (this.term.ioctl(0, PosixTerminalControl.TIOCGWINSZ, this.windowSizeBuffer) != 0) {
|
if (this.term.ioctl(0, PosixTerminalControl.TIOCGWINSZ, this.windowSizeBuffer) != 0) {
|
||||||
return DEFAULT_WIDTH;
|
return DEFAULT_WIDTH;
|
||||||
}
|
}
|
||||||
@ -109,7 +114,7 @@ public class UnixTerminal extends Terminal {
|
|||||||
* Returns number of rows in the terminal.
|
* Returns number of rows in the terminal.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public int getHeight() {
|
public final int getHeight() {
|
||||||
if (this.term.ioctl(0, PosixTerminalControl.TIOCGWINSZ, this.windowSizeBuffer) != 0) {
|
if (this.term.ioctl(0, PosixTerminalControl.TIOCGWINSZ, this.windowSizeBuffer) != 0) {
|
||||||
return DEFAULT_HEIGHT;
|
return DEFAULT_HEIGHT;
|
||||||
}
|
}
|
||||||
@ -119,7 +124,7 @@ public class UnixTerminal extends Terminal {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void setEchoEnabled(final boolean enabled) {
|
public final synchronized void setEchoEnabled(final boolean enabled) {
|
||||||
// have to reget them, since flags change everything
|
// have to reget them, since flags change everything
|
||||||
if (this.term.tcgetattr(0, this.termInfo) !=0) {
|
if (this.term.tcgetattr(0, this.termInfo) !=0) {
|
||||||
this.logger.error("Failed to get terminal info");
|
this.logger.error("Failed to get terminal info");
|
||||||
@ -139,29 +144,38 @@ public class UnixTerminal extends Terminal {
|
|||||||
super.setEchoEnabled(enabled);
|
super.setEchoEnabled(enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void disableInterruptCharacter() {
|
// public final void disableInterruptCharacter() {
|
||||||
// have to re-get them, since flags change everything
|
// // have to re-get them, since flags change everything
|
||||||
if (this.term.tcgetattr(0, this.termInfo) !=0) {
|
// if (this.term.tcgetattr(0, this.termInfo) !=0) {
|
||||||
this.logger.error("Failed to get terminal info");
|
// this.logger.error("Failed to get terminal info");
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
|
// this.termInfo.c_cc[PosixTerminalControl.VINTR] = 0; // interrupt disabled
|
||||||
|
//
|
||||||
|
// if (this.term.tcsetattr(0, PosixTerminalControl.TCSANOW, this.termInfo) != 0) {
|
||||||
|
// this.logger.error("Can not set terminal flags");
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public final void enableInterruptCharacter() {
|
||||||
|
// // have to re-get them, since flags change everything
|
||||||
|
// if (this.term.tcgetattr(0, this.termInfo) !=0) {
|
||||||
|
// this.logger.error("Failed to get terminal info");
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// this.termInfo.c_cc[PosixTerminalControl.VINTR] = 3; // interrupt is ctrl-c
|
||||||
|
//
|
||||||
|
// if (this.term.tcsetattr(0, PosixTerminalControl.TCSANOW, this.termInfo) != 0) {
|
||||||
|
// this.logger.error("Can not set terminal flags");
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
this.termInfo.c_cc[PosixTerminalControl.VINTR] = 0; // interrupt disabled
|
@Override
|
||||||
|
public final int read() {
|
||||||
if (this.term.tcsetattr(0, PosixTerminalControl.TCSANOW, this.termInfo) != 0) {
|
try {
|
||||||
this.logger.error("Can not set terminal flags");
|
return this.reader.read();
|
||||||
}
|
} catch (IOException ignored) {
|
||||||
}
|
return -1;
|
||||||
|
|
||||||
public void enableInterruptCharacter() {
|
|
||||||
// have to re-get them, since flags change everything
|
|
||||||
if (this.term.tcgetattr(0, this.termInfo) !=0) {
|
|
||||||
this.logger.error("Failed to get terminal info");
|
|
||||||
}
|
|
||||||
|
|
||||||
this.termInfo.c_cc[PosixTerminalControl.VINTR] = 3; // interrupt is ctrl-c
|
|
||||||
|
|
||||||
if (this.term.tcsetattr(0, PosixTerminalControl.TCSANOW, this.termInfo) != 0) {
|
|
||||||
this.logger.error("Can not set terminal flags");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,30 +1,91 @@
|
|||||||
package dorkbox.util.input.unsupported;
|
package dorkbox.util.input.unsupported;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import dorkbox.util.bytes.ByteBuffer2;
|
||||||
import dorkbox.util.input.Terminal;
|
import dorkbox.util.input.Terminal;
|
||||||
|
import dorkbox.util.input.posix.InputStreamReader;
|
||||||
|
|
||||||
public class UnsupportedTerminal extends Terminal {
|
public class UnsupportedTerminal extends Terminal {
|
||||||
public UnsupportedTerminal() {
|
|
||||||
// setAnsiSupported(false);
|
private final ByteBuffer2 buffer = new ByteBuffer2(8, -1);
|
||||||
setEchoEnabled(true);
|
|
||||||
|
private BufferedReader reader;
|
||||||
|
private String readLine = null;
|
||||||
|
private char[] line;
|
||||||
|
|
||||||
|
private ThreadLocal<Integer> indexOfStringForReadChar = new ThreadLocal<Integer>() {
|
||||||
|
@Override
|
||||||
|
protected Integer initialValue() {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public UnsupportedTerminal(String encoding) {
|
||||||
|
this.reader = new BufferedReader(new InputStreamReader(System.in, encoding));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init() throws IOException {
|
public final void init() throws IOException {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void restore() {
|
public final void restore() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getWidth() {
|
public final int getWidth() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getHeight() {
|
public final int getHeight() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final int read() {
|
||||||
|
// if we are reading data (because we are in IDE mode), we want to return ALL
|
||||||
|
// the chars of the line!
|
||||||
|
|
||||||
|
// so, readChar is REALLY the index at which we return letters (until the whole string is returned)
|
||||||
|
int readerCount = this.indexOfStringForReadChar.get();
|
||||||
|
|
||||||
|
if (readerCount == -1) {
|
||||||
|
|
||||||
|
// we have to wait for more data.
|
||||||
|
try {
|
||||||
|
this.readLine = this.reader.readLine();
|
||||||
|
} catch (IOException e) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.line = this.readLine.toCharArray();
|
||||||
|
this.buffer.clear();
|
||||||
|
for (char c : this.line) {
|
||||||
|
this.buffer.writeChar(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
readerCount = 0;
|
||||||
|
this.indexOfStringForReadChar.set(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// EACH thread will have it's own count!
|
||||||
|
if (readerCount == this.buffer.position()) {
|
||||||
|
this.indexOfStringForReadChar.set(-1);
|
||||||
|
return '\n';
|
||||||
|
} else {
|
||||||
|
this.indexOfStringForReadChar.set(readerCount+2); // because 2 bytes per char in java
|
||||||
|
}
|
||||||
|
|
||||||
|
char c = this.buffer.readChar(readerCount);
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final boolean wasSequence() {
|
||||||
|
return this.line.length > 0;
|
||||||
|
}
|
||||||
}
|
}
|
@ -46,22 +46,8 @@ public enum ConsoleMode {
|
|||||||
* discarded by ReadFile or ReadConsole, even when this mode is enabled.
|
* discarded by ReadFile or ReadConsole, even when this mode is enabled.
|
||||||
*/
|
*/
|
||||||
ENABLE_MOUSE_INPUT(16),
|
ENABLE_MOUSE_INPUT(16),
|
||||||
|
;
|
||||||
|
|
||||||
/**
|
|
||||||
* When enabled, text entered in a console window will be inserted at the
|
|
||||||
* current cursor location and all text following that location will not be
|
|
||||||
* overwritten. When disabled, all following text will be overwritten. An OR
|
|
||||||
* operation must be performed with this flag and the ENABLE_EXTENDED_FLAGS
|
|
||||||
* flag to enable this functionality.
|
|
||||||
*/
|
|
||||||
ENABLE_PROCESSED_OUTPUT(1),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This flag enables the user to use the mouse to select and edit text. To
|
|
||||||
* enable this option, use the OR to combine this flag with
|
|
||||||
* ENABLE_EXTENDED_FLAGS.
|
|
||||||
*/
|
|
||||||
ENABLE_WRAP_AT_EOL_OUTPUT(2),;
|
|
||||||
|
|
||||||
public final int code;
|
public final int code;
|
||||||
|
|
||||||
|
@ -8,11 +8,11 @@
|
|||||||
*/
|
*/
|
||||||
package dorkbox.util.input.windows;
|
package dorkbox.util.input.windows;
|
||||||
|
|
||||||
import java.io.FileDescriptor;
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.PrintStream;
|
||||||
|
|
||||||
|
import org.fusesource.jansi.internal.Kernel32.INPUT_RECORD;
|
||||||
|
import org.fusesource.jansi.internal.Kernel32.KEY_EVENT_RECORD;
|
||||||
import org.fusesource.jansi.internal.WindowsSupport;
|
import org.fusesource.jansi.internal.WindowsSupport;
|
||||||
|
|
||||||
import dorkbox.util.input.Terminal;
|
import dorkbox.util.input.Terminal;
|
||||||
@ -26,34 +26,26 @@ import dorkbox.util.input.Terminal;
|
|||||||
* url=/library/en-us/dllproc/base/getconsolemode.asp">GetConsoleMode</a> to
|
* url=/library/en-us/dllproc/base/getconsolemode.asp">GetConsoleMode</a> to
|
||||||
* disable character echoing.
|
* disable character echoing.
|
||||||
* <p/>
|
* <p/>
|
||||||
* <p>
|
* @since 2.0 (customized)
|
||||||
* By default, the {@link #wrapInIfNeeded(java.io.InputStream)} method will attempt
|
|
||||||
* to test to see if the specified {@link InputStream} is {@link System#in} or a wrapper
|
|
||||||
* around {@link FileDescriptor#in}, and if so, will bypass the character reading to
|
|
||||||
* directly invoke the readc() method in the JNI library. This is so the class
|
|
||||||
* can read special keys (like arrow keys) which are otherwise inaccessible via
|
|
||||||
* the {@link System#in} stream. Using JNI reading can be bypassed by setting
|
|
||||||
* the <code>jline.WindowsTerminal.directConsole</code> system property
|
|
||||||
* to <code>false</code>.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
|
|
||||||
* @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
|
|
||||||
* @since 2.0
|
|
||||||
*/
|
*/
|
||||||
public class WindowsTerminal extends Terminal
|
public class WindowsTerminal extends Terminal {
|
||||||
{
|
private volatile int originalMode;
|
||||||
public static final String DIRECT_CONSOLE = WindowsTerminal.class.getName() + ".directConsole";
|
private final PrintStream out;
|
||||||
|
|
||||||
private int originalMode;
|
|
||||||
|
|
||||||
public WindowsTerminal() {
|
public WindowsTerminal() {
|
||||||
|
this.out = System.out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init() throws IOException {
|
public final void init() throws IOException {
|
||||||
this.originalMode = WindowsSupport.getConsoleMode();
|
this.originalMode = WindowsSupport.getConsoleMode();
|
||||||
WindowsSupport.setConsoleMode(this.originalMode & ~ConsoleMode.ENABLE_ECHO_INPUT.code);
|
|
||||||
|
// Must set these four modes at the same time to make it work fine.
|
||||||
|
WindowsSupport.setConsoleMode(this.originalMode |
|
||||||
|
ConsoleMode.ENABLE_LINE_INPUT.code |
|
||||||
|
ConsoleMode.ENABLE_ECHO_INPUT.code |
|
||||||
|
ConsoleMode.ENABLE_PROCESSED_INPUT.code |
|
||||||
|
ConsoleMode.ENABLE_WINDOW_INPUT.code);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -62,69 +54,71 @@ public class WindowsTerminal extends Terminal
|
|||||||
* used after calling this method.
|
* used after calling this method.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void restore() throws IOException {
|
public final void restore() throws IOException {
|
||||||
// restore the old console mode
|
// restore the old console mode
|
||||||
WindowsSupport.setConsoleMode(this.originalMode);
|
WindowsSupport.setConsoleMode(this.originalMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getWidth() {
|
public final int getWidth() {
|
||||||
int w = WindowsSupport.getWindowsTerminalWidth();
|
int w = WindowsSupport.getWindowsTerminalWidth();
|
||||||
return w < 1 ? DEFAULT_WIDTH : w;
|
return w < 1 ? DEFAULT_WIDTH : w;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getHeight() {
|
public final int getHeight() {
|
||||||
int h = WindowsSupport.getWindowsTerminalHeight();
|
int h = WindowsSupport.getWindowsTerminalHeight();
|
||||||
return h < 1 ? DEFAULT_HEIGHT : h;
|
return h < 1 ? DEFAULT_HEIGHT : h;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setEchoEnabled(final boolean enabled) {
|
public final int read() {
|
||||||
// Must set these four modes at the same time to make it work fine.
|
int input = readInput();
|
||||||
if (enabled) {
|
|
||||||
WindowsSupport.setConsoleMode(WindowsSupport.getConsoleMode() |
|
if (isEchoEnabled()) {
|
||||||
ConsoleMode.ENABLE_ECHO_INPUT.code |
|
char asChar = (char) input;
|
||||||
ConsoleMode.ENABLE_LINE_INPUT.code |
|
if (asChar == '\n') {
|
||||||
ConsoleMode.ENABLE_PROCESSED_INPUT.code |
|
this.out.println();
|
||||||
ConsoleMode.ENABLE_WINDOW_INPUT.code);
|
} else {
|
||||||
|
this.out.print(asChar);
|
||||||
|
}
|
||||||
|
// have to flush, otherwise we'll never see the chars on screen
|
||||||
|
this.out.flush();
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
WindowsSupport.setConsoleMode(WindowsSupport.getConsoleMode() &
|
return input;
|
||||||
~(ConsoleMode.ENABLE_LINE_INPUT.code |
|
|
||||||
ConsoleMode.ENABLE_ECHO_INPUT.code |
|
|
||||||
ConsoleMode.ENABLE_PROCESSED_INPUT.code |
|
|
||||||
ConsoleMode.ENABLE_WINDOW_INPUT.code));
|
|
||||||
}
|
|
||||||
super.setEchoEnabled(enabled);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private final int readInput() {
|
||||||
|
// this HOOKS the input event, and prevents it from going to the console "proper"
|
||||||
|
try {
|
||||||
|
INPUT_RECORD[] events = null;
|
||||||
|
while (true) {
|
||||||
|
// we ALWAYS read until we have an event we care about!
|
||||||
|
events = WindowsSupport.readConsoleInput(1);
|
||||||
|
|
||||||
@Override
|
if (events != null) {
|
||||||
public InputStream wrapInIfNeeded(InputStream in) throws IOException {
|
for (int i = 0; i < events.length; i++ ) {
|
||||||
if (isSystemIn(in)) {
|
KEY_EVENT_RECORD keyEvent = events[i].keyEvent;
|
||||||
return new InputStream() {
|
//Log.trace(keyEvent.keyDown? "KEY_DOWN" : "KEY_UP", "key code:", keyEvent.keyCode, "char:", (long)keyEvent.uchar);
|
||||||
@Override
|
if (keyEvent.keyDown) {
|
||||||
public int read() throws IOException {
|
if (keyEvent.uchar > 0) {
|
||||||
return WindowsSupport.readByte();
|
char uchar = keyEvent.uchar;
|
||||||
|
if (uchar == '\r') {
|
||||||
|
// we purposefully swallow input after \r, and substitute it with \n
|
||||||
|
return '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
return uchar;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
} else {
|
} catch (IOException e) {
|
||||||
return in;
|
this.logger.error("Windows console input error: ", e);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isSystemIn(final InputStream in) throws IOException {
|
|
||||||
if (in == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else if (in == System.in) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else if (in instanceof FileInputStream && ((FileInputStream) in).getFD() == FileDescriptor.in) {
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -104,10 +104,10 @@ class FastObjectPool<T> implements ObjectPool<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void release(ObjectPoolHolder<T> object) throws InterruptedException {
|
public void release(ObjectPoolHolder<T> object) {
|
||||||
this.lock.lockInterruptibly();
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
this.lock.lockInterruptibly();
|
||||||
|
|
||||||
int localValue = this.releasePointer;
|
int localValue = this.releasePointer;
|
||||||
//long index = ((localValue & mask) * INDEXSCALE ) + BASE;
|
//long index = ((localValue & mask) * INDEXSCALE ) + BASE;
|
||||||
long index = ((localValue & this.mask)<<this.ASHIFT ) + this.BASE;
|
long index = ((localValue & this.mask)<<this.ASHIFT ) + this.BASE;
|
||||||
@ -120,6 +120,7 @@ class FastObjectPool<T> implements ObjectPool<T> {
|
|||||||
else {
|
else {
|
||||||
throw new IllegalArgumentException("Invalid reference passed");
|
throw new IllegalArgumentException("Invalid reference passed");
|
||||||
}
|
}
|
||||||
|
} catch (InterruptedException e) {
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
this.lock.unlock();
|
this.lock.unlock();
|
||||||
|
@ -9,5 +9,5 @@ public interface ObjectPool<T> {
|
|||||||
/**
|
/**
|
||||||
* Return object to the pool
|
* Return object to the pool
|
||||||
*/
|
*/
|
||||||
public void release(ObjectPoolHolder<T> object) throws InterruptedException;
|
public void release(ObjectPoolHolder<T> object);
|
||||||
}
|
}
|
||||||
|
@ -2,11 +2,22 @@ package dorkbox.util.objectPool;
|
|||||||
|
|
||||||
import dorkbox.util.Sys;
|
import dorkbox.util.Sys;
|
||||||
|
|
||||||
public class ObjectPoolFactory<T> {
|
public class ObjectPoolFactory {
|
||||||
|
|
||||||
private ObjectPoolFactory() {
|
private ObjectPoolFactory() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a pool with the max number of available processors as the pool size (padded by 2x as many).
|
||||||
|
*/
|
||||||
|
public static <T> ObjectPool<T> create(PoolableObject<T> poolableObject) {
|
||||||
|
return create(poolableObject, Runtime.getRuntime().availableProcessors() * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a pool of the specified size
|
||||||
|
*/
|
||||||
public static <T> ObjectPool<T> create(PoolableObject<T> poolableObject, int size) {
|
public static <T> ObjectPool<T> create(PoolableObject<T> poolableObject, int size) {
|
||||||
if (Sys.isAndroid) {
|
if (Sys.isAndroid) {
|
||||||
// unfortunately, unsafe is not available in android
|
// unfortunately, unsafe is not available in android
|
||||||
|
@ -10,10 +10,10 @@ public interface PoolableObject<T> {
|
|||||||
/**
|
/**
|
||||||
* invoked on every instance that is borrowed from the pool
|
* invoked on every instance that is borrowed from the pool
|
||||||
*/
|
*/
|
||||||
public void activate(T t);
|
public void activate(T object);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* invoked on every instance that is returned to the pool
|
* invoked on every instance that is returned to the pool
|
||||||
*/
|
*/
|
||||||
public void passivate(T t);
|
public void passivate(T object);
|
||||||
}
|
}
|
||||||
|
@ -76,7 +76,7 @@ class SlowObjectPool<T> implements ObjectPool<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void release(ObjectPoolHolder<T> object) throws InterruptedException {
|
public void release(ObjectPoolHolder<T> object) {
|
||||||
if (object.state.compareAndSet(USED, FREE)) {
|
if (object.state.compareAndSet(USED, FREE)) {
|
||||||
this.queue.offer(object);
|
this.queue.offer(object);
|
||||||
this.poolableObject.passivate(object.getValue());
|
this.poolableObject.passivate(object.getValue());
|
||||||
|
@ -21,10 +21,6 @@ import dorkbox.util.OS;
|
|||||||
*/
|
*/
|
||||||
public class ShellProcessBuilder {
|
public class ShellProcessBuilder {
|
||||||
|
|
||||||
// TODO: see http://mark.koli.ch/2009/12/uac-prompt-from-java-createprocess-error740-the-requested-operation-requires-elevation.html
|
|
||||||
// for more information on copying files in windows with UAC protections.
|
|
||||||
// maybe we want to hook into our launcher executor so that we can "auto elevate" commands?
|
|
||||||
|
|
||||||
private String workingDirectory = null;
|
private String workingDirectory = null;
|
||||||
private String executableName = null;
|
private String executableName = null;
|
||||||
private String executableDirectory = null;
|
private String executableDirectory = null;
|
||||||
@ -56,9 +52,9 @@ public class ShellProcessBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public ShellProcessBuilder(InputStream in, PrintStream out, PrintStream err) {
|
public ShellProcessBuilder(InputStream in, PrintStream out, PrintStream err) {
|
||||||
outputStream = out;
|
this.outputStream = out;
|
||||||
errorStream = err;
|
this.errorStream = err;
|
||||||
inputStream = in;
|
this.inputStream = in;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -71,19 +67,19 @@ public class ShellProcessBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public final ShellProcessBuilder addArgument(String argument) {
|
public final ShellProcessBuilder addArgument(String argument) {
|
||||||
arguments.add(argument);
|
this.arguments.add(argument);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final ShellProcessBuilder addArguments(String... paths) {
|
public final ShellProcessBuilder addArguments(String... paths) {
|
||||||
for (String path : paths) {
|
for (String path : paths) {
|
||||||
arguments.add(path);
|
this.arguments.add(path);
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final ShellProcessBuilder addArguments(List<String> paths) {
|
public final ShellProcessBuilder addArguments(List<String> paths) {
|
||||||
arguments.addAll(paths);
|
this.arguments.addAll(paths);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,39 +102,39 @@ public class ShellProcessBuilder {
|
|||||||
|
|
||||||
public void start() {
|
public void start() {
|
||||||
// if no executable, then use the command shell
|
// if no executable, then use the command shell
|
||||||
if (executableName == null) {
|
if (this.executableName == null) {
|
||||||
if (OS.isWindows()) {
|
if (OS.isWindows()) {
|
||||||
// windows
|
// windows
|
||||||
executableName = "cmd";
|
this.executableName = "cmd";
|
||||||
arguments.add(0, "/c");
|
this.arguments.add(0, "/c");
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// *nix
|
// *nix
|
||||||
executableName = "/bin/bash";
|
this.executableName = "/bin/bash";
|
||||||
File file = new File(executableName);
|
File file = new File(this.executableName);
|
||||||
if (!file.canExecute()) {
|
if (!file.canExecute()) {
|
||||||
executableName = "/bin/sh";
|
this.executableName = "/bin/sh";
|
||||||
}
|
}
|
||||||
arguments.add(0, "-c");
|
this.arguments.add(0, "-c");
|
||||||
}
|
}
|
||||||
} else if (workingDirectory != null) {
|
} else if (this.workingDirectory != null) {
|
||||||
if (!workingDirectory.endsWith("/") && !workingDirectory.endsWith("\\")) {
|
if (!this.workingDirectory.endsWith("/") && !this.workingDirectory.endsWith("\\")) {
|
||||||
workingDirectory += File.separator;
|
this.workingDirectory += File.separator;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (executableDirectory != null) {
|
if (this.executableDirectory != null) {
|
||||||
if (!executableDirectory.endsWith("/") && !executableDirectory.endsWith("\\")) {
|
if (!this.executableDirectory.endsWith("/") && !this.executableDirectory.endsWith("\\")) {
|
||||||
executableDirectory += File.separator;
|
this.executableDirectory += File.separator;
|
||||||
}
|
}
|
||||||
|
|
||||||
executableName = executableDirectory + executableName;
|
this.executableName = this.executableDirectory + this.executableName;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<String> argumentsList = new ArrayList<String>();
|
List<String> argumentsList = new ArrayList<String>();
|
||||||
argumentsList.add(executableName);
|
argumentsList.add(this.executableName);
|
||||||
|
|
||||||
for (String arg : arguments) {
|
for (String arg : this.arguments) {
|
||||||
if (arg.contains(" ")) {
|
if (arg.contains(" ")) {
|
||||||
// individual arguments MUST be in their own element in order to
|
// individual arguments MUST be in their own element in order to
|
||||||
// be processed properly (this is how it works on the command line!)
|
// be processed properly (this is how it works on the command line!)
|
||||||
@ -154,7 +150,7 @@ public class ShellProcessBuilder {
|
|||||||
|
|
||||||
// if we don't want output... TODO: i think we want to "exec" (this calls exec -c, which calls our program)
|
// if we don't want output... TODO: i think we want to "exec" (this calls exec -c, which calls our program)
|
||||||
// this code as well, since calling it directly won't work
|
// this code as well, since calling it directly won't work
|
||||||
boolean pipeToNull = errorStream == null || outputStream == null;
|
boolean pipeToNull = this.errorStream == null || this.outputStream == null;
|
||||||
if (pipeToNull) {
|
if (pipeToNull) {
|
||||||
if (OS.isWindows()) {
|
if (OS.isWindows()) {
|
||||||
// >NUL on windows
|
// >NUL on windows
|
||||||
@ -165,22 +161,22 @@ public class ShellProcessBuilder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (debugInfo) {
|
if (this.debugInfo) {
|
||||||
errorStream.print("Executing: ");
|
this.errorStream.print("Executing: ");
|
||||||
Iterator<String> iterator = argumentsList.iterator();
|
Iterator<String> iterator = argumentsList.iterator();
|
||||||
while (iterator.hasNext()) {
|
while (iterator.hasNext()) {
|
||||||
String s = iterator.next();
|
String s = iterator.next();
|
||||||
errorStream.print(s);
|
this.errorStream.print(s);
|
||||||
if (iterator.hasNext()) {
|
if (iterator.hasNext()) {
|
||||||
errorStream.print(" ");
|
this.errorStream.print(" ");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
errorStream.print(OS.LINE_SEPARATOR);
|
this.errorStream.print(OS.LINE_SEPARATOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
ProcessBuilder processBuilder = new ProcessBuilder(argumentsList);
|
ProcessBuilder processBuilder = new ProcessBuilder(argumentsList);
|
||||||
if (workingDirectory != null) {
|
if (this.workingDirectory != null) {
|
||||||
processBuilder.directory(new File(workingDirectory));
|
processBuilder.directory(new File(this.workingDirectory));
|
||||||
}
|
}
|
||||||
|
|
||||||
// combine these so output is properly piped to null.
|
// combine these so output is properly piped to null.
|
||||||
@ -189,23 +185,23 @@ public class ShellProcessBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
process = processBuilder.start();
|
this.process = processBuilder.start();
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
errorStream.println("There was a problem executing the program. Details:\n");
|
this.errorStream.println("There was a problem executing the program. Details:\n");
|
||||||
ex.printStackTrace(errorStream);
|
ex.printStackTrace(this.errorStream);
|
||||||
|
|
||||||
if (process != null) {
|
if (this.process != null) {
|
||||||
try {
|
try {
|
||||||
process.destroy();
|
this.process.destroy();
|
||||||
process = null;
|
this.process = null;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
errorStream.println("Error destroying process: \n");
|
this.errorStream.println("Error destroying process: \n");
|
||||||
e.printStackTrace(errorStream);
|
e.printStackTrace(this.errorStream);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (process != null) {
|
if (this.process != null) {
|
||||||
ProcessProxy writeToProcess_input;
|
ProcessProxy writeToProcess_input;
|
||||||
ProcessProxy readFromProcess_output;
|
ProcessProxy readFromProcess_output;
|
||||||
ProcessProxy readFromProcess_error;
|
ProcessProxy readFromProcess_error;
|
||||||
@ -218,7 +214,7 @@ public class ShellProcessBuilder {
|
|||||||
|
|
||||||
// readers (read process -> write console)
|
// readers (read process -> write console)
|
||||||
// have to keep the output buffers from filling in the target process.
|
// have to keep the output buffers from filling in the target process.
|
||||||
readFromProcess_output = new ProcessProxy("Process Reader: " + executableName, process.getInputStream(), nullOutputStream);
|
readFromProcess_output = new ProcessProxy("Process Reader: " + this.executableName, this.process.getInputStream(), nullOutputStream);
|
||||||
readFromProcess_error = null;
|
readFromProcess_error = null;
|
||||||
}
|
}
|
||||||
// we want to pipe our input/output from process to ourselves
|
// we want to pipe our input/output from process to ourselves
|
||||||
@ -228,21 +224,21 @@ public class ShellProcessBuilder {
|
|||||||
* to the user's window. This is important or the spawned process could block.
|
* to the user's window. This is important or the spawned process could block.
|
||||||
*/
|
*/
|
||||||
// readers (read process -> write console)
|
// readers (read process -> write console)
|
||||||
readFromProcess_output = new ProcessProxy("Process Reader: " + executableName, process.getInputStream(), outputStream);
|
readFromProcess_output = new ProcessProxy("Process Reader: " + this.executableName, this.process.getInputStream(), this.outputStream);
|
||||||
if (errorStream != outputStream) {
|
if (this.errorStream != this.outputStream) {
|
||||||
readFromProcess_error = new ProcessProxy("Process Reader: " + executableName, process.getErrorStream(), errorStream);
|
readFromProcess_error = new ProcessProxy("Process Reader: " + this.executableName, this.process.getErrorStream(), this.errorStream);
|
||||||
} else {
|
} else {
|
||||||
processBuilder.redirectErrorStream(true);
|
processBuilder.redirectErrorStream(true);
|
||||||
readFromProcess_error = null;
|
readFromProcess_error = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inputStream != null) {
|
if (this.inputStream != null) {
|
||||||
/**
|
/**
|
||||||
* Proxy System.in from the user's window to the spawned process
|
* Proxy System.in from the user's window to the spawned process
|
||||||
*/
|
*/
|
||||||
// writer (read console -> write process)
|
// writer (read console -> write process)
|
||||||
writeToProcess_input = new ProcessProxy("Process Writer: " + executableName, inputStream, process.getOutputStream());
|
writeToProcess_input = new ProcessProxy("Process Writer: " + this.executableName, this.inputStream, this.process.getOutputStream());
|
||||||
} else {
|
} else {
|
||||||
writeToProcess_input = null;
|
writeToProcess_input = null;
|
||||||
}
|
}
|
||||||
@ -254,10 +250,10 @@ public class ShellProcessBuilder {
|
|||||||
Thread hook = new Thread(new Runnable() {
|
Thread hook = new Thread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if (debugInfo) {
|
if (ShellProcessBuilder.this.debugInfo) {
|
||||||
errorStream.println("Terminating process: " + executableName);
|
ShellProcessBuilder.this.errorStream.println("Terminating process: " + ShellProcessBuilder.this.executableName);
|
||||||
}
|
}
|
||||||
process.destroy();
|
ShellProcessBuilder.this.process.destroy();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@ -273,10 +269,10 @@ public class ShellProcessBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
process.waitFor();
|
this.process.waitFor();
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
int exitValue = process.exitValue();
|
int exitValue = this.process.exitValue();
|
||||||
|
|
||||||
// wait for the READER threads to die (meaning their streams have closed/EOF'd)
|
// wait for the READER threads to die (meaning their streams have closed/EOF'd)
|
||||||
if (writeToProcess_input != null) {
|
if (writeToProcess_input != null) {
|
||||||
@ -294,7 +290,7 @@ public class ShellProcessBuilder {
|
|||||||
|
|
||||||
// forcibly terminate the process when it's streams have closed.
|
// forcibly terminate the process when it's streams have closed.
|
||||||
// this is for cleanup ONLY, not to actually do anything.
|
// this is for cleanup ONLY, not to actually do anything.
|
||||||
process.destroy();
|
this.process.destroy();
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
Thread.currentThread().interrupt();
|
Thread.currentThread().interrupt();
|
||||||
}
|
}
|
||||||
|
766
Dorkbox-Util/test/dorkbox/util/ByteBuffer2Test.java
Normal file
766
Dorkbox-Util/test/dorkbox/util/ByteBuffer2Test.java
Normal file
@ -0,0 +1,766 @@
|
|||||||
|
package dorkbox.util;
|
||||||
|
|
||||||
|
import java.lang.reflect.Array;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import dorkbox.util.bytes.ByteBuffer2;
|
||||||
|
|
||||||
|
public class ByteBuffer2Test {
|
||||||
|
|
||||||
|
|
||||||
|
static public void assertArrayEquals(Object object1, Object object2) {
|
||||||
|
Assert.assertEquals(arrayToList(object1), arrayToList(object2));
|
||||||
|
}
|
||||||
|
|
||||||
|
static public Object arrayToList(Object array) {
|
||||||
|
if (array == null || !array.getClass().isArray()) {
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
ArrayList<Object> list = new ArrayList<Object>(Array.getLength(array));
|
||||||
|
for (int i = 0, n = Array.getLength(array); i < n; i++) {
|
||||||
|
list.add(arrayToList(Array.get(array, i)));
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testWriteBytes() {
|
||||||
|
ByteBuffer2 buffer = new ByteBuffer2(512);
|
||||||
|
buffer.writeBytes(new byte[] {11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26});
|
||||||
|
buffer.writeBytes(new byte[] {31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46});
|
||||||
|
buffer.writeByte(51);
|
||||||
|
buffer.writeBytes(new byte[] {52,53,54,55,56,57,58});
|
||||||
|
buffer.writeByte(61);
|
||||||
|
buffer.writeByte(62);
|
||||||
|
buffer.writeByte(63);
|
||||||
|
buffer.writeByte(64);
|
||||||
|
buffer.writeByte(65);
|
||||||
|
|
||||||
|
assertArrayEquals(new byte[] {11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,31,32,33,34,35,36,37,38,39,40,41,42,
|
||||||
|
43,44,45,46,51,52,53,54,55,56,57,58,61,62,63,64,65}, buffer.toBytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testStrings() {
|
||||||
|
runStringTest(new ByteBuffer2(4096));
|
||||||
|
runStringTest(new ByteBuffer2(897));
|
||||||
|
|
||||||
|
ByteBuffer2 write = new ByteBuffer2(21);
|
||||||
|
String value = "abcdef\u00E1\u00E9\u00ED\u00F3\u00FA\u1234";
|
||||||
|
write.writeString(value);
|
||||||
|
ByteBuffer2 read = new ByteBuffer2(write.toBytes());
|
||||||
|
assertArrayEquals(value, read.readString());
|
||||||
|
|
||||||
|
runStringTest(127);
|
||||||
|
runStringTest(256);
|
||||||
|
runStringTest(1024 * 1023);
|
||||||
|
runStringTest(1024 * 1024);
|
||||||
|
runStringTest(1024 * 1025);
|
||||||
|
runStringTest(1024 * 1026);
|
||||||
|
runStringTest(1024 * 1024 * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void runStringTest(ByteBuffer2 write) {
|
||||||
|
String value1 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ\rabcdefghijklmnopqrstuvwxyz\n1234567890\t\"!`?'.,;:()[]{}<>|/@\\^$-%+=#_&~*";
|
||||||
|
String value2 = "abcdef\u00E1\u00E9\u00ED\u00F3\u00FA\u1234";
|
||||||
|
|
||||||
|
write.writeString("");
|
||||||
|
write.writeString("1");
|
||||||
|
write.writeString("22");
|
||||||
|
write.writeString("uno");
|
||||||
|
write.writeString("dos");
|
||||||
|
write.writeString("tres");
|
||||||
|
write.writeString(null);
|
||||||
|
write.writeString(value1);
|
||||||
|
write.writeString(value2);
|
||||||
|
for (int i = 0; i < 127; i++) {
|
||||||
|
write.writeString(String.valueOf((char) i));
|
||||||
|
}
|
||||||
|
for (int i = 0; i < 127; i++) {
|
||||||
|
write.writeString(String.valueOf((char) i) + "abc");
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteBuffer2 read = new ByteBuffer2(write.toBytes());
|
||||||
|
Assert.assertEquals("", read.readString());
|
||||||
|
Assert.assertEquals("1", read.readString());
|
||||||
|
Assert.assertEquals("22", read.readString());
|
||||||
|
Assert.assertEquals("uno", read.readString());
|
||||||
|
Assert.assertEquals("dos", read.readString());
|
||||||
|
Assert.assertEquals("tres", read.readString());
|
||||||
|
Assert.assertEquals(null, read.readString());
|
||||||
|
Assert.assertEquals(value1, read.readString());
|
||||||
|
Assert.assertEquals(value2, read.readString());
|
||||||
|
for (int i = 0; i < 127; i++) {
|
||||||
|
Assert.assertEquals(String.valueOf((char) i), read.readString());
|
||||||
|
}
|
||||||
|
for (int i = 0; i < 127; i++) {
|
||||||
|
Assert.assertEquals(String.valueOf((char) i) + "abc", read.readString());
|
||||||
|
}
|
||||||
|
|
||||||
|
read.rewind();
|
||||||
|
|
||||||
|
Assert.assertEquals("", read.readStringBuilder().toString());
|
||||||
|
Assert.assertEquals("1", read.readStringBuilder().toString());
|
||||||
|
Assert.assertEquals("22", read.readStringBuilder().toString());
|
||||||
|
Assert.assertEquals("uno", read.readStringBuilder().toString());
|
||||||
|
Assert.assertEquals("dos", read.readStringBuilder().toString());
|
||||||
|
Assert.assertEquals("tres", read.readStringBuilder().toString());
|
||||||
|
Assert.assertEquals(null, read.readStringBuilder());
|
||||||
|
Assert.assertEquals(value1, read.readStringBuilder().toString());
|
||||||
|
Assert.assertEquals(value2, read.readStringBuilder().toString());
|
||||||
|
for (int i = 0; i < 127; i++) {
|
||||||
|
Assert.assertEquals(String.valueOf((char) i), read.readStringBuilder().toString());
|
||||||
|
}
|
||||||
|
for (int i = 0; i < 127; i++) {
|
||||||
|
Assert.assertEquals(String.valueOf((char) i) + "abc", read.readStringBuilder().toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void runStringTest(int length) {
|
||||||
|
ByteBuffer2 write = new ByteBuffer2(1024, -1);
|
||||||
|
|
||||||
|
StringBuilder buffer = new StringBuilder();
|
||||||
|
for (int i = 0; i < length; i++) {
|
||||||
|
buffer.append((char) i);
|
||||||
|
}
|
||||||
|
|
||||||
|
String value = buffer.toString();
|
||||||
|
write.writeString(value);
|
||||||
|
write.writeString(value);
|
||||||
|
|
||||||
|
ByteBuffer2 read = new ByteBuffer2(write.toBytes());
|
||||||
|
Assert.assertEquals(value, read.readString());
|
||||||
|
Assert.assertEquals(value, read.readStringBuilder().toString());
|
||||||
|
|
||||||
|
write.clear();
|
||||||
|
write.writeString(buffer);
|
||||||
|
write.writeString(buffer);
|
||||||
|
read = new ByteBuffer2(write.toBytes());
|
||||||
|
Assert.assertEquals(value, read.readStringBuilder().toString());
|
||||||
|
Assert.assertEquals(value, read.readString());
|
||||||
|
|
||||||
|
if (length <= 127) {
|
||||||
|
write.clear();
|
||||||
|
write.writeAscii(value);
|
||||||
|
write.writeAscii(value);
|
||||||
|
read = new ByteBuffer2(write.toBytes());
|
||||||
|
Assert.assertEquals(value, read.readStringBuilder().toString());
|
||||||
|
Assert.assertEquals(value, read.readString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCanReadInt() {
|
||||||
|
ByteBuffer2 write = new ByteBuffer2();
|
||||||
|
|
||||||
|
ByteBuffer2 read = new ByteBuffer2(write.toBytes());
|
||||||
|
Assert.assertEquals(false, read.canReadInt());
|
||||||
|
|
||||||
|
write = new ByteBuffer2(4);
|
||||||
|
write.writeInt(400, true);
|
||||||
|
|
||||||
|
read = new ByteBuffer2(write.toBytes());
|
||||||
|
Assert.assertEquals(true, read.canReadInt());
|
||||||
|
read.setPosition(read.capacity());
|
||||||
|
Assert.assertEquals(false, read.canReadInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInts() {
|
||||||
|
runIntTest(new ByteBuffer2(4096));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void runIntTest(ByteBuffer2 write) {
|
||||||
|
write.writeInt(0);
|
||||||
|
write.writeInt(63);
|
||||||
|
write.writeInt(64);
|
||||||
|
write.writeInt(127);
|
||||||
|
write.writeInt(128);
|
||||||
|
write.writeInt(8192);
|
||||||
|
write.writeInt(16384);
|
||||||
|
write.writeInt(2097151);
|
||||||
|
write.writeInt(1048575);
|
||||||
|
write.writeInt(134217727);
|
||||||
|
write.writeInt(268435455);
|
||||||
|
write.writeInt(134217728);
|
||||||
|
write.writeInt(268435456);
|
||||||
|
write.writeInt(-2097151);
|
||||||
|
write.writeInt(-1048575);
|
||||||
|
write.writeInt(-134217727);
|
||||||
|
write.writeInt(-268435455);
|
||||||
|
write.writeInt(-134217728);
|
||||||
|
write.writeInt(-268435456);
|
||||||
|
Assert.assertEquals(1, write.writeInt(0, true));
|
||||||
|
Assert.assertEquals(1, write.writeInt(0, false));
|
||||||
|
Assert.assertEquals(1, write.writeInt(63, true));
|
||||||
|
Assert.assertEquals(1, write.writeInt(63, false));
|
||||||
|
Assert.assertEquals(1, write.writeInt(64, true));
|
||||||
|
Assert.assertEquals(2, write.writeInt(64, false));
|
||||||
|
Assert.assertEquals(1, write.writeInt(127, true));
|
||||||
|
Assert.assertEquals(2, write.writeInt(127, false));
|
||||||
|
Assert.assertEquals(2, write.writeInt(128, true));
|
||||||
|
Assert.assertEquals(2, write.writeInt(128, false));
|
||||||
|
Assert.assertEquals(2, write.writeInt(8191, true));
|
||||||
|
Assert.assertEquals(2, write.writeInt(8191, false));
|
||||||
|
Assert.assertEquals(2, write.writeInt(8192, true));
|
||||||
|
Assert.assertEquals(3, write.writeInt(8192, false));
|
||||||
|
Assert.assertEquals(2, write.writeInt(16383, true));
|
||||||
|
Assert.assertEquals(3, write.writeInt(16383, false));
|
||||||
|
Assert.assertEquals(3, write.writeInt(16384, true));
|
||||||
|
Assert.assertEquals(3, write.writeInt(16384, false));
|
||||||
|
Assert.assertEquals(3, write.writeInt(2097151, true));
|
||||||
|
Assert.assertEquals(4, write.writeInt(2097151, false));
|
||||||
|
Assert.assertEquals(3, write.writeInt(1048575, true));
|
||||||
|
Assert.assertEquals(3, write.writeInt(1048575, false));
|
||||||
|
Assert.assertEquals(4, write.writeInt(134217727, true));
|
||||||
|
Assert.assertEquals(4, write.writeInt(134217727, false));
|
||||||
|
Assert.assertEquals(4, write.writeInt(268435455, true));
|
||||||
|
Assert.assertEquals(5, write.writeInt(268435455, false));
|
||||||
|
Assert.assertEquals(4, write.writeInt(134217728, true));
|
||||||
|
Assert.assertEquals(5, write.writeInt(134217728, false));
|
||||||
|
Assert.assertEquals(5, write.writeInt(268435456, true));
|
||||||
|
Assert.assertEquals(5, write.writeInt(268435456, false));
|
||||||
|
Assert.assertEquals(1, write.writeInt(-64, false));
|
||||||
|
Assert.assertEquals(5, write.writeInt(-64, true));
|
||||||
|
Assert.assertEquals(2, write.writeInt(-65, false));
|
||||||
|
Assert.assertEquals(5, write.writeInt(-65, true));
|
||||||
|
Assert.assertEquals(2, write.writeInt(-8192, false));
|
||||||
|
Assert.assertEquals(5, write.writeInt(-8192, true));
|
||||||
|
Assert.assertEquals(3, write.writeInt(-1048576, false));
|
||||||
|
Assert.assertEquals(5, write.writeInt(-1048576, true));
|
||||||
|
Assert.assertEquals(4, write.writeInt(-134217728, false));
|
||||||
|
Assert.assertEquals(5, write.writeInt(-134217728, true));
|
||||||
|
Assert.assertEquals(5, write.writeInt(-134217729, false));
|
||||||
|
Assert.assertEquals(5, write.writeInt(-134217729, true));
|
||||||
|
|
||||||
|
ByteBuffer2 read = new ByteBuffer2(write.toBytes());
|
||||||
|
Assert.assertEquals(0, read.readInt());
|
||||||
|
Assert.assertEquals(63, read.readInt());
|
||||||
|
Assert.assertEquals(64, read.readInt());
|
||||||
|
Assert.assertEquals(127, read.readInt());
|
||||||
|
Assert.assertEquals(128, read.readInt());
|
||||||
|
Assert.assertEquals(8192, read.readInt());
|
||||||
|
Assert.assertEquals(16384, read.readInt());
|
||||||
|
Assert.assertEquals(2097151, read.readInt());
|
||||||
|
Assert.assertEquals(1048575, read.readInt());
|
||||||
|
Assert.assertEquals(134217727, read.readInt());
|
||||||
|
Assert.assertEquals(268435455, read.readInt());
|
||||||
|
Assert.assertEquals(134217728, read.readInt());
|
||||||
|
Assert.assertEquals(268435456, read.readInt());
|
||||||
|
Assert.assertEquals(-2097151, read.readInt());
|
||||||
|
Assert.assertEquals(-1048575, read.readInt());
|
||||||
|
Assert.assertEquals(-134217727, read.readInt());
|
||||||
|
Assert.assertEquals(-268435455, read.readInt());
|
||||||
|
Assert.assertEquals(-134217728, read.readInt());
|
||||||
|
Assert.assertEquals(-268435456, read.readInt());
|
||||||
|
Assert.assertEquals(true, read.canReadInt());
|
||||||
|
Assert.assertEquals(true, read.canReadInt());
|
||||||
|
Assert.assertEquals(true, read.canReadInt());
|
||||||
|
Assert.assertEquals(0, read.readInt(true));
|
||||||
|
Assert.assertEquals(0, read.readInt(false));
|
||||||
|
Assert.assertEquals(63, read.readInt(true));
|
||||||
|
Assert.assertEquals(63, read.readInt(false));
|
||||||
|
Assert.assertEquals(64, read.readInt(true));
|
||||||
|
Assert.assertEquals(64, read.readInt(false));
|
||||||
|
Assert.assertEquals(127, read.readInt(true));
|
||||||
|
Assert.assertEquals(127, read.readInt(false));
|
||||||
|
Assert.assertEquals(128, read.readInt(true));
|
||||||
|
Assert.assertEquals(128, read.readInt(false));
|
||||||
|
Assert.assertEquals(8191, read.readInt(true));
|
||||||
|
Assert.assertEquals(8191, read.readInt(false));
|
||||||
|
Assert.assertEquals(8192, read.readInt(true));
|
||||||
|
Assert.assertEquals(8192, read.readInt(false));
|
||||||
|
Assert.assertEquals(16383, read.readInt(true));
|
||||||
|
Assert.assertEquals(16383, read.readInt(false));
|
||||||
|
Assert.assertEquals(16384, read.readInt(true));
|
||||||
|
Assert.assertEquals(16384, read.readInt(false));
|
||||||
|
Assert.assertEquals(2097151, read.readInt(true));
|
||||||
|
Assert.assertEquals(2097151, read.readInt(false));
|
||||||
|
Assert.assertEquals(1048575, read.readInt(true));
|
||||||
|
Assert.assertEquals(1048575, read.readInt(false));
|
||||||
|
Assert.assertEquals(134217727, read.readInt(true));
|
||||||
|
Assert.assertEquals(134217727, read.readInt(false));
|
||||||
|
Assert.assertEquals(268435455, read.readInt(true));
|
||||||
|
Assert.assertEquals(268435455, read.readInt(false));
|
||||||
|
Assert.assertEquals(134217728, read.readInt(true));
|
||||||
|
Assert.assertEquals(134217728, read.readInt(false));
|
||||||
|
Assert.assertEquals(268435456, read.readInt(true));
|
||||||
|
Assert.assertEquals(268435456, read.readInt(false));
|
||||||
|
Assert.assertEquals(-64, read.readInt(false));
|
||||||
|
Assert.assertEquals(-64, read.readInt(true));
|
||||||
|
Assert.assertEquals(-65, read.readInt(false));
|
||||||
|
Assert.assertEquals(-65, read.readInt(true));
|
||||||
|
Assert.assertEquals(-8192, read.readInt(false));
|
||||||
|
Assert.assertEquals(-8192, read.readInt(true));
|
||||||
|
Assert.assertEquals(-1048576, read.readInt(false));
|
||||||
|
Assert.assertEquals(-1048576, read.readInt(true));
|
||||||
|
Assert.assertEquals(-134217728, read.readInt(false));
|
||||||
|
Assert.assertEquals(-134217728, read.readInt(true));
|
||||||
|
Assert.assertEquals(-134217729, read.readInt(false));
|
||||||
|
Assert.assertEquals(-134217729, read.readInt(true));
|
||||||
|
Assert.assertEquals(false, read.canReadInt());
|
||||||
|
|
||||||
|
Random random = new Random();
|
||||||
|
for (int i = 0; i < 10000; i++) {
|
||||||
|
int value = random.nextInt();
|
||||||
|
write.clear();
|
||||||
|
write.writeInt(value);
|
||||||
|
write.writeInt(value, true);
|
||||||
|
write.writeInt(value, false);
|
||||||
|
read.setBuffer(write.toBytes());
|
||||||
|
Assert.assertEquals(value, read.readInt());
|
||||||
|
Assert.assertEquals(value, read.readInt(true));
|
||||||
|
Assert.assertEquals(value, read.readInt(false));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLongs() {
|
||||||
|
runLongTest(new ByteBuffer2(4096));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void runLongTest(ByteBuffer2 write) {
|
||||||
|
write.writeLong(0);
|
||||||
|
write.writeLong(63);
|
||||||
|
write.writeLong(64);
|
||||||
|
write.writeLong(127);
|
||||||
|
write.writeLong(128);
|
||||||
|
write.writeLong(8192);
|
||||||
|
write.writeLong(16384);
|
||||||
|
write.writeLong(2097151);
|
||||||
|
write.writeLong(1048575);
|
||||||
|
write.writeLong(134217727);
|
||||||
|
write.writeLong(268435455);
|
||||||
|
write.writeLong(134217728);
|
||||||
|
write.writeLong(268435456);
|
||||||
|
write.writeLong(-2097151);
|
||||||
|
write.writeLong(-1048575);
|
||||||
|
write.writeLong(-134217727);
|
||||||
|
write.writeLong(-268435455);
|
||||||
|
write.writeLong(-134217728);
|
||||||
|
write.writeLong(-268435456);
|
||||||
|
Assert.assertEquals(1, write.writeLong(0, true));
|
||||||
|
Assert.assertEquals(1, write.writeLong(0, false));
|
||||||
|
Assert.assertEquals(1, write.writeLong(63, true));
|
||||||
|
Assert.assertEquals(1, write.writeLong(63, false));
|
||||||
|
Assert.assertEquals(1, write.writeLong(64, true));
|
||||||
|
Assert.assertEquals(2, write.writeLong(64, false));
|
||||||
|
Assert.assertEquals(1, write.writeLong(127, true));
|
||||||
|
Assert.assertEquals(2, write.writeLong(127, false));
|
||||||
|
Assert.assertEquals(2, write.writeLong(128, true));
|
||||||
|
Assert.assertEquals(2, write.writeLong(128, false));
|
||||||
|
Assert.assertEquals(2, write.writeLong(8191, true));
|
||||||
|
Assert.assertEquals(2, write.writeLong(8191, false));
|
||||||
|
Assert.assertEquals(2, write.writeLong(8192, true));
|
||||||
|
Assert.assertEquals(3, write.writeLong(8192, false));
|
||||||
|
Assert.assertEquals(2, write.writeLong(16383, true));
|
||||||
|
Assert.assertEquals(3, write.writeLong(16383, false));
|
||||||
|
Assert.assertEquals(3, write.writeLong(16384, true));
|
||||||
|
Assert.assertEquals(3, write.writeLong(16384, false));
|
||||||
|
Assert.assertEquals(3, write.writeLong(2097151, true));
|
||||||
|
Assert.assertEquals(4, write.writeLong(2097151, false));
|
||||||
|
Assert.assertEquals(3, write.writeLong(1048575, true));
|
||||||
|
Assert.assertEquals(3, write.writeLong(1048575, false));
|
||||||
|
Assert.assertEquals(4, write.writeLong(134217727, true));
|
||||||
|
Assert.assertEquals(4, write.writeLong(134217727, false));
|
||||||
|
Assert.assertEquals(4, write.writeLong(268435455l, true));
|
||||||
|
Assert.assertEquals(5, write.writeLong(268435455l, false));
|
||||||
|
Assert.assertEquals(4, write.writeLong(134217728l, true));
|
||||||
|
Assert.assertEquals(5, write.writeLong(134217728l, false));
|
||||||
|
Assert.assertEquals(5, write.writeLong(268435456l, true));
|
||||||
|
Assert.assertEquals(5, write.writeLong(268435456l, false));
|
||||||
|
Assert.assertEquals(1, write.writeLong(-64, false));
|
||||||
|
Assert.assertEquals(9, write.writeLong(-64, true));
|
||||||
|
Assert.assertEquals(2, write.writeLong(-65, false));
|
||||||
|
Assert.assertEquals(9, write.writeLong(-65, true));
|
||||||
|
Assert.assertEquals(2, write.writeLong(-8192, false));
|
||||||
|
Assert.assertEquals(9, write.writeLong(-8192, true));
|
||||||
|
Assert.assertEquals(3, write.writeLong(-1048576, false));
|
||||||
|
Assert.assertEquals(9, write.writeLong(-1048576, true));
|
||||||
|
Assert.assertEquals(4, write.writeLong(-134217728, false));
|
||||||
|
Assert.assertEquals(9, write.writeLong(-134217728, true));
|
||||||
|
Assert.assertEquals(5, write.writeLong(-134217729, false));
|
||||||
|
Assert.assertEquals(9, write.writeLong(-134217729, true));
|
||||||
|
|
||||||
|
ByteBuffer2 read = new ByteBuffer2(write.toBytes());
|
||||||
|
Assert.assertEquals(0, read.readLong());
|
||||||
|
Assert.assertEquals(63, read.readLong());
|
||||||
|
Assert.assertEquals(64, read.readLong());
|
||||||
|
Assert.assertEquals(127, read.readLong());
|
||||||
|
Assert.assertEquals(128, read.readLong());
|
||||||
|
Assert.assertEquals(8192, read.readLong());
|
||||||
|
Assert.assertEquals(16384, read.readLong());
|
||||||
|
Assert.assertEquals(2097151, read.readLong());
|
||||||
|
Assert.assertEquals(1048575, read.readLong());
|
||||||
|
Assert.assertEquals(134217727, read.readLong());
|
||||||
|
Assert.assertEquals(268435455, read.readLong());
|
||||||
|
Assert.assertEquals(134217728, read.readLong());
|
||||||
|
Assert.assertEquals(268435456, read.readLong());
|
||||||
|
Assert.assertEquals(-2097151, read.readLong());
|
||||||
|
Assert.assertEquals(-1048575, read.readLong());
|
||||||
|
Assert.assertEquals(-134217727, read.readLong());
|
||||||
|
Assert.assertEquals(-268435455, read.readLong());
|
||||||
|
Assert.assertEquals(-134217728, read.readLong());
|
||||||
|
Assert.assertEquals(-268435456, read.readLong());
|
||||||
|
Assert.assertEquals(0, read.readLong(true));
|
||||||
|
Assert.assertEquals(0, read.readLong(false));
|
||||||
|
Assert.assertEquals(63, read.readLong(true));
|
||||||
|
Assert.assertEquals(63, read.readLong(false));
|
||||||
|
Assert.assertEquals(64, read.readLong(true));
|
||||||
|
Assert.assertEquals(64, read.readLong(false));
|
||||||
|
Assert.assertEquals(127, read.readLong(true));
|
||||||
|
Assert.assertEquals(127, read.readLong(false));
|
||||||
|
Assert.assertEquals(128, read.readLong(true));
|
||||||
|
Assert.assertEquals(128, read.readLong(false));
|
||||||
|
Assert.assertEquals(8191, read.readLong(true));
|
||||||
|
Assert.assertEquals(8191, read.readLong(false));
|
||||||
|
Assert.assertEquals(8192, read.readLong(true));
|
||||||
|
Assert.assertEquals(8192, read.readLong(false));
|
||||||
|
Assert.assertEquals(16383, read.readLong(true));
|
||||||
|
Assert.assertEquals(16383, read.readLong(false));
|
||||||
|
Assert.assertEquals(16384, read.readLong(true));
|
||||||
|
Assert.assertEquals(16384, read.readLong(false));
|
||||||
|
Assert.assertEquals(2097151, read.readLong(true));
|
||||||
|
Assert.assertEquals(2097151, read.readLong(false));
|
||||||
|
Assert.assertEquals(1048575, read.readLong(true));
|
||||||
|
Assert.assertEquals(1048575, read.readLong(false));
|
||||||
|
Assert.assertEquals(134217727, read.readLong(true));
|
||||||
|
Assert.assertEquals(134217727, read.readLong(false));
|
||||||
|
Assert.assertEquals(268435455, read.readLong(true));
|
||||||
|
Assert.assertEquals(268435455, read.readLong(false));
|
||||||
|
Assert.assertEquals(134217728, read.readLong(true));
|
||||||
|
Assert.assertEquals(134217728, read.readLong(false));
|
||||||
|
Assert.assertEquals(268435456, read.readLong(true));
|
||||||
|
Assert.assertEquals(268435456, read.readLong(false));
|
||||||
|
Assert.assertEquals(-64, read.readLong(false));
|
||||||
|
Assert.assertEquals(-64, read.readLong(true));
|
||||||
|
Assert.assertEquals(-65, read.readLong(false));
|
||||||
|
Assert.assertEquals(-65, read.readLong(true));
|
||||||
|
Assert.assertEquals(-8192, read.readLong(false));
|
||||||
|
Assert.assertEquals(-8192, read.readLong(true));
|
||||||
|
Assert.assertEquals(-1048576, read.readLong(false));
|
||||||
|
Assert.assertEquals(-1048576, read.readLong(true));
|
||||||
|
Assert.assertEquals(-134217728, read.readLong(false));
|
||||||
|
Assert.assertEquals(-134217728, read.readLong(true));
|
||||||
|
Assert.assertEquals(-134217729, read.readLong(false));
|
||||||
|
Assert.assertEquals(-134217729, read.readLong(true));
|
||||||
|
|
||||||
|
Random random = new Random();
|
||||||
|
for (int i = 0; i < 10000; i++) {
|
||||||
|
long value = random.nextLong();
|
||||||
|
write.clear();
|
||||||
|
write.writeLong(value);
|
||||||
|
write.writeLong(value, true);
|
||||||
|
write.writeLong(value, false);
|
||||||
|
read.setBuffer(write.toBytes());
|
||||||
|
Assert.assertEquals(value, read.readLong());
|
||||||
|
Assert.assertEquals(value, read.readLong(true));
|
||||||
|
Assert.assertEquals(value, read.readLong(false));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testShorts() {
|
||||||
|
runShortTest(new ByteBuffer2(4096));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void runShortTest(ByteBuffer2 write) {
|
||||||
|
write.writeShort(0);
|
||||||
|
write.writeShort(63);
|
||||||
|
write.writeShort(64);
|
||||||
|
write.writeShort(127);
|
||||||
|
write.writeShort(128);
|
||||||
|
write.writeShort(8192);
|
||||||
|
write.writeShort(16384);
|
||||||
|
write.writeShort(32767);
|
||||||
|
write.writeShort(-63);
|
||||||
|
write.writeShort(-64);
|
||||||
|
write.writeShort(-127);
|
||||||
|
write.writeShort(-128);
|
||||||
|
write.writeShort(-8192);
|
||||||
|
write.writeShort(-16384);
|
||||||
|
write.writeShort(-32768);
|
||||||
|
|
||||||
|
ByteBuffer2 read = new ByteBuffer2(write.toBytes());
|
||||||
|
Assert.assertEquals(0, read.readShort());
|
||||||
|
Assert.assertEquals(63, read.readShort());
|
||||||
|
Assert.assertEquals(64, read.readShort());
|
||||||
|
Assert.assertEquals(127, read.readShort());
|
||||||
|
Assert.assertEquals(128, read.readShort());
|
||||||
|
Assert.assertEquals(8192, read.readShort());
|
||||||
|
Assert.assertEquals(16384, read.readShort());
|
||||||
|
Assert.assertEquals(32767, read.readShort());
|
||||||
|
Assert.assertEquals(-63, read.readShort());
|
||||||
|
Assert.assertEquals(-64, read.readShort());
|
||||||
|
Assert.assertEquals(-127, read.readShort());
|
||||||
|
Assert.assertEquals(-128, read.readShort());
|
||||||
|
Assert.assertEquals(-8192, read.readShort());
|
||||||
|
Assert.assertEquals(-16384, read.readShort());
|
||||||
|
Assert.assertEquals(-32768, read.readShort());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFloats() {
|
||||||
|
runFloatTest(new ByteBuffer2(4096));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void runFloatTest(ByteBuffer2 write) {
|
||||||
|
write.writeFloat(0);
|
||||||
|
write.writeFloat(63);
|
||||||
|
write.writeFloat(64);
|
||||||
|
write.writeFloat(127);
|
||||||
|
write.writeFloat(128);
|
||||||
|
write.writeFloat(8192);
|
||||||
|
write.writeFloat(16384);
|
||||||
|
write.writeFloat(32767);
|
||||||
|
write.writeFloat(-63);
|
||||||
|
write.writeFloat(-64);
|
||||||
|
write.writeFloat(-127);
|
||||||
|
write.writeFloat(-128);
|
||||||
|
write.writeFloat(-8192);
|
||||||
|
write.writeFloat(-16384);
|
||||||
|
write.writeFloat(-32768);
|
||||||
|
Assert.assertEquals(1, write.writeFloat(0, 1000, true));
|
||||||
|
Assert.assertEquals(1, write.writeFloat(0, 1000, false));
|
||||||
|
Assert.assertEquals(3, write.writeFloat(63, 1000, true));
|
||||||
|
Assert.assertEquals(3, write.writeFloat(63, 1000, false));
|
||||||
|
Assert.assertEquals(3, write.writeFloat(64, 1000, true));
|
||||||
|
Assert.assertEquals(3, write.writeFloat(64, 1000, false));
|
||||||
|
Assert.assertEquals(3, write.writeFloat(127, 1000, true));
|
||||||
|
Assert.assertEquals(3, write.writeFloat(127, 1000, false));
|
||||||
|
Assert.assertEquals(3, write.writeFloat(128, 1000, true));
|
||||||
|
Assert.assertEquals(3, write.writeFloat(128, 1000, false));
|
||||||
|
Assert.assertEquals(4, write.writeFloat(8191, 1000, true));
|
||||||
|
Assert.assertEquals(4, write.writeFloat(8191, 1000, false));
|
||||||
|
Assert.assertEquals(4, write.writeFloat(8192, 1000, true));
|
||||||
|
Assert.assertEquals(4, write.writeFloat(8192, 1000, false));
|
||||||
|
Assert.assertEquals(4, write.writeFloat(16383, 1000, true));
|
||||||
|
Assert.assertEquals(4, write.writeFloat(16383, 1000, false));
|
||||||
|
Assert.assertEquals(4, write.writeFloat(16384, 1000, true));
|
||||||
|
Assert.assertEquals(4, write.writeFloat(16384, 1000, false));
|
||||||
|
Assert.assertEquals(4, write.writeFloat(32767, 1000, true));
|
||||||
|
Assert.assertEquals(4, write.writeFloat(32767, 1000, false));
|
||||||
|
Assert.assertEquals(3, write.writeFloat(-64, 1000, false));
|
||||||
|
Assert.assertEquals(5, write.writeFloat(-64, 1000, true));
|
||||||
|
Assert.assertEquals(3, write.writeFloat(-65, 1000, false));
|
||||||
|
Assert.assertEquals(5, write.writeFloat(-65, 1000, true));
|
||||||
|
Assert.assertEquals(4, write.writeFloat(-8192, 1000, false));
|
||||||
|
Assert.assertEquals(5, write.writeFloat(-8192, 1000, true));
|
||||||
|
|
||||||
|
float delta = 0.00000001f;
|
||||||
|
ByteBuffer2 read = new ByteBuffer2(write.toBytes());
|
||||||
|
Assert.assertEquals(read.readFloat(), 0f, delta);
|
||||||
|
Assert.assertEquals(read.readFloat(), 63f, delta);
|
||||||
|
Assert.assertEquals(read.readFloat(), 64f, delta);
|
||||||
|
Assert.assertEquals(read.readFloat(), 127f, delta);
|
||||||
|
Assert.assertEquals(read.readFloat(), 128f, delta);
|
||||||
|
Assert.assertEquals(read.readFloat(), 8192f, delta);
|
||||||
|
Assert.assertEquals(read.readFloat(), 16384f, delta);
|
||||||
|
Assert.assertEquals(read.readFloat(), 32767f, delta);
|
||||||
|
Assert.assertEquals(read.readFloat(), -63f, delta);
|
||||||
|
Assert.assertEquals(read.readFloat(), -64f, delta);
|
||||||
|
Assert.assertEquals(read.readFloat(), -127f, delta);
|
||||||
|
Assert.assertEquals(read.readFloat(), -128f, delta);
|
||||||
|
Assert.assertEquals(read.readFloat(), -8192f, delta);
|
||||||
|
Assert.assertEquals(read.readFloat(), -16384f, delta);
|
||||||
|
Assert.assertEquals(read.readFloat(), -32768f, delta);
|
||||||
|
Assert.assertEquals(read.readFloat(1000, true), 0f, delta);
|
||||||
|
Assert.assertEquals(read.readFloat(1000, false), 0f, delta);
|
||||||
|
Assert.assertEquals(read.readFloat(1000, true), 63f, delta);
|
||||||
|
Assert.assertEquals(read.readFloat(1000, false), 63f, delta);
|
||||||
|
Assert.assertEquals(read.readFloat(1000, true), 64f, delta);
|
||||||
|
Assert.assertEquals(read.readFloat(1000, false), 64f, delta);
|
||||||
|
Assert.assertEquals(read.readFloat(1000, true), 127f, delta);
|
||||||
|
Assert.assertEquals(read.readFloat(1000, false), 127f, delta);
|
||||||
|
Assert.assertEquals(read.readFloat(1000, true), 128f, delta);
|
||||||
|
Assert.assertEquals(read.readFloat(1000, false), 128f, delta);
|
||||||
|
Assert.assertEquals(read.readFloat(1000, true), 8191f, delta);
|
||||||
|
Assert.assertEquals(read.readFloat(1000, false), 8191f, delta);
|
||||||
|
Assert.assertEquals(read.readFloat(1000, true), 8192f, delta);
|
||||||
|
Assert.assertEquals(read.readFloat(1000, false), 8192f, delta);
|
||||||
|
Assert.assertEquals(read.readFloat(1000, true), 16383f, delta);
|
||||||
|
Assert.assertEquals(read.readFloat(1000, false), 16383f, delta);
|
||||||
|
Assert.assertEquals(read.readFloat(1000, true), 16384f, delta);
|
||||||
|
Assert.assertEquals(read.readFloat(1000, false), 16384f, delta);
|
||||||
|
Assert.assertEquals(read.readFloat(1000, true), 32767f, delta);
|
||||||
|
Assert.assertEquals(read.readFloat(1000, false), 32767f, delta);
|
||||||
|
Assert.assertEquals(read.readFloat(1000, false), -64f, delta);
|
||||||
|
Assert.assertEquals(read.readFloat(1000, true), -64f, delta);
|
||||||
|
Assert.assertEquals(read.readFloat(1000, false), -65f, delta);
|
||||||
|
Assert.assertEquals(read.readFloat(1000, true), -65f, delta);
|
||||||
|
Assert.assertEquals(read.readFloat(1000, false), -8192f, delta);
|
||||||
|
Assert.assertEquals(read.readFloat(1000, true), -8192f, delta);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDoubles() {
|
||||||
|
runDoubleTest(new ByteBuffer2(4096));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void runDoubleTest(ByteBuffer2 write) {
|
||||||
|
write.writeDouble(0);
|
||||||
|
write.writeDouble(63);
|
||||||
|
write.writeDouble(64);
|
||||||
|
write.writeDouble(127);
|
||||||
|
write.writeDouble(128);
|
||||||
|
write.writeDouble(8192);
|
||||||
|
write.writeDouble(16384);
|
||||||
|
write.writeDouble(32767);
|
||||||
|
write.writeDouble(-63);
|
||||||
|
write.writeDouble(-64);
|
||||||
|
write.writeDouble(-127);
|
||||||
|
write.writeDouble(-128);
|
||||||
|
write.writeDouble(-8192);
|
||||||
|
write.writeDouble(-16384);
|
||||||
|
write.writeDouble(-32768);
|
||||||
|
Assert.assertEquals(1, write.writeDouble(0, 1000, true));
|
||||||
|
Assert.assertEquals(1, write.writeDouble(0, 1000, false));
|
||||||
|
Assert.assertEquals(3, write.writeDouble(63, 1000, true));
|
||||||
|
Assert.assertEquals(3, write.writeDouble(63, 1000, false));
|
||||||
|
Assert.assertEquals(3, write.writeDouble(64, 1000, true));
|
||||||
|
Assert.assertEquals(3, write.writeDouble(64, 1000, false));
|
||||||
|
Assert.assertEquals(3, write.writeDouble(127, 1000, true));
|
||||||
|
Assert.assertEquals(3, write.writeDouble(127, 1000, false));
|
||||||
|
Assert.assertEquals(3, write.writeDouble(128, 1000, true));
|
||||||
|
Assert.assertEquals(3, write.writeDouble(128, 1000, false));
|
||||||
|
Assert.assertEquals(4, write.writeDouble(8191, 1000, true));
|
||||||
|
Assert.assertEquals(4, write.writeDouble(8191, 1000, false));
|
||||||
|
Assert.assertEquals(4, write.writeDouble(8192, 1000, true));
|
||||||
|
Assert.assertEquals(4, write.writeDouble(8192, 1000, false));
|
||||||
|
Assert.assertEquals(4, write.writeDouble(16383, 1000, true));
|
||||||
|
Assert.assertEquals(4, write.writeDouble(16383, 1000, false));
|
||||||
|
Assert.assertEquals(4, write.writeDouble(16384, 1000, true));
|
||||||
|
Assert.assertEquals(4, write.writeDouble(16384, 1000, false));
|
||||||
|
Assert.assertEquals(4, write.writeDouble(32767, 1000, true));
|
||||||
|
Assert.assertEquals(4, write.writeDouble(32767, 1000, false));
|
||||||
|
Assert.assertEquals(3, write.writeDouble(-64, 1000, false));
|
||||||
|
Assert.assertEquals(9, write.writeDouble(-64, 1000, true));
|
||||||
|
Assert.assertEquals(3, write.writeDouble(-65, 1000, false));
|
||||||
|
Assert.assertEquals(9, write.writeDouble(-65, 1000, true));
|
||||||
|
Assert.assertEquals(4, write.writeDouble(-8192, 1000, false));
|
||||||
|
Assert.assertEquals(9, write.writeDouble(-8192, 1000, true));
|
||||||
|
write.writeDouble(1.23456d);
|
||||||
|
|
||||||
|
double delta = 0.00000001D;
|
||||||
|
ByteBuffer2 read = new ByteBuffer2(write.toBytes());
|
||||||
|
Assert.assertEquals(read.readDouble(), 0d, delta);
|
||||||
|
Assert.assertEquals(read.readDouble(), 63d, delta);
|
||||||
|
Assert.assertEquals(read.readDouble(), 64d, delta);
|
||||||
|
Assert.assertEquals(read.readDouble(), 127d, delta);
|
||||||
|
Assert.assertEquals(read.readDouble(), 128d, delta);
|
||||||
|
Assert.assertEquals(read.readDouble(), 8192d, delta);
|
||||||
|
Assert.assertEquals(read.readDouble(), 16384d, delta);
|
||||||
|
Assert.assertEquals(read.readDouble(), 32767d, delta);
|
||||||
|
Assert.assertEquals(read.readDouble(), -63d, delta);
|
||||||
|
Assert.assertEquals(read.readDouble(), -64d, delta);
|
||||||
|
Assert.assertEquals(read.readDouble(), -127d, delta);
|
||||||
|
Assert.assertEquals(read.readDouble(), -128d, delta);
|
||||||
|
Assert.assertEquals(read.readDouble(), -8192d, delta);
|
||||||
|
Assert.assertEquals(read.readDouble(), -16384d, delta);
|
||||||
|
Assert.assertEquals(read.readDouble(), -32768d, delta);
|
||||||
|
Assert.assertEquals(read.readDouble(1000, true), 0d, delta);
|
||||||
|
Assert.assertEquals(read.readDouble(1000, false), 0d, delta);
|
||||||
|
Assert.assertEquals(read.readDouble(1000, true), 63d, delta);
|
||||||
|
Assert.assertEquals(read.readDouble(1000, false), 63d, delta);
|
||||||
|
Assert.assertEquals(read.readDouble(1000, true), 64d, delta);
|
||||||
|
Assert.assertEquals(read.readDouble(1000, false), 64d, delta);
|
||||||
|
Assert.assertEquals(read.readDouble(1000, true), 127d, delta);
|
||||||
|
Assert.assertEquals(read.readDouble(1000, false), 127d, delta);
|
||||||
|
Assert.assertEquals(read.readDouble(1000, true), 128d, delta);
|
||||||
|
Assert.assertEquals(read.readDouble(1000, false), 128d, delta);
|
||||||
|
Assert.assertEquals(read.readDouble(1000, true), 8191d, delta);
|
||||||
|
Assert.assertEquals(read.readDouble(1000, false), 8191d, delta);
|
||||||
|
Assert.assertEquals(read.readDouble(1000, true), 8192d, delta);
|
||||||
|
Assert.assertEquals(read.readDouble(1000, false), 8192d, delta);
|
||||||
|
Assert.assertEquals(read.readDouble(1000, true), 16383d, delta);
|
||||||
|
Assert.assertEquals(read.readDouble(1000, false), 16383d, delta);
|
||||||
|
Assert.assertEquals(read.readDouble(1000, true), 16384d, delta);
|
||||||
|
Assert.assertEquals(read.readDouble(1000, false), 16384d, delta);
|
||||||
|
Assert.assertEquals(read.readDouble(1000, true), 32767d, delta);
|
||||||
|
Assert.assertEquals(read.readDouble(1000, false), 32767d, delta);
|
||||||
|
Assert.assertEquals(read.readDouble(1000, false), -64d, delta);
|
||||||
|
Assert.assertEquals(read.readDouble(1000, true), -64d, delta);
|
||||||
|
Assert.assertEquals(read.readDouble(1000, false), -65d, delta);
|
||||||
|
Assert.assertEquals(read.readDouble(1000, true), -65d, delta);
|
||||||
|
Assert.assertEquals(read.readDouble(1000, false), -8192d, delta);
|
||||||
|
Assert.assertEquals(read.readDouble(1000, true), -8192d, delta);
|
||||||
|
Assert.assertEquals(1.23456d, read.readDouble(), delta);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBooleans() {
|
||||||
|
runBooleanTest(new ByteBuffer2(4096));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void runBooleanTest(ByteBuffer2 write) {
|
||||||
|
for (int i = 0; i < 100; i++) {
|
||||||
|
write.writeBoolean(true);
|
||||||
|
write.writeBoolean(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteBuffer2 read = new ByteBuffer2(write.toBytes());
|
||||||
|
for (int i = 0; i < 100; i++) {
|
||||||
|
Assert.assertEquals(true, read.readBoolean());
|
||||||
|
Assert.assertEquals(false, read.readBoolean());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testChars() {
|
||||||
|
runCharTest(new ByteBuffer2(4096));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void runCharTest(ByteBuffer2 write) {
|
||||||
|
write.writeChar((char) 0);
|
||||||
|
write.writeChar((char) 63);
|
||||||
|
write.writeChar((char) 64);
|
||||||
|
write.writeChar((char) 127);
|
||||||
|
write.writeChar((char) 128);
|
||||||
|
write.writeChar((char) 8192);
|
||||||
|
write.writeChar((char) 16384);
|
||||||
|
write.writeChar((char) 32767);
|
||||||
|
write.writeChar((char) 65535);
|
||||||
|
|
||||||
|
ByteBuffer2 read = new ByteBuffer2(write.toBytes());
|
||||||
|
Assert.assertEquals(0, read.readChar());
|
||||||
|
Assert.assertEquals(63, read.readChar());
|
||||||
|
Assert.assertEquals(64, read.readChar());
|
||||||
|
Assert.assertEquals(127, read.readChar());
|
||||||
|
Assert.assertEquals(128, read.readChar());
|
||||||
|
Assert.assertEquals(8192, read.readChar());
|
||||||
|
Assert.assertEquals(16384, read.readChar());
|
||||||
|
Assert.assertEquals(32767, read.readChar());
|
||||||
|
Assert.assertEquals(65535, read.readChar());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInputWithOffset() throws Exception {
|
||||||
|
final byte[] buf = new byte[30];
|
||||||
|
final ByteBuffer2 in = new ByteBuffer2(buf);
|
||||||
|
in.skip(20);
|
||||||
|
Assert.assertEquals(10, in.remaining());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSmallBuffers() throws Exception {
|
||||||
|
ByteBuffer buf = ByteBuffer.allocate(1024);
|
||||||
|
|
||||||
|
ByteBuffer2 testOutput = new ByteBuffer2(buf.array());
|
||||||
|
testOutput.writeBytes(new byte[512]);
|
||||||
|
testOutput.writeBytes(new byte[512]);
|
||||||
|
|
||||||
|
ByteBuffer2 testInputs = new ByteBuffer2();
|
||||||
|
buf.flip();
|
||||||
|
|
||||||
|
testInputs.setBuffer(buf.array());
|
||||||
|
byte[] toRead = new byte[512];
|
||||||
|
testInputs.readBytes(toRead);
|
||||||
|
|
||||||
|
testInputs.readBytes(toRead);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user