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.
|
||||
byte[] bytes = new byte[text.length*2];
|
||||
for(int i=0; i<text.length; i++) {
|
||||
bytes[2*i] = (byte) ((text[i] & 0xFF00)>>8);
|
||||
bytes[2*i+1] = (byte) (text[i] & 0x00FF);
|
||||
bytes[2*i] = (byte) (text[i] >> 8);
|
||||
bytes[2*i+1] = (byte) text[i];
|
||||
}
|
||||
|
||||
return bytes;
|
||||
@ -754,7 +754,7 @@ public class Sys {
|
||||
|
||||
|
||||
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 {
|
||||
|
||||
URLConnection connection = resource.openConnection();
|
||||
@ -764,7 +764,6 @@ public class Sys {
|
||||
JarURLConnection jarURLConnection = (JarURLConnection) connection;
|
||||
|
||||
JarFile jarFile = jarURLConnection.getJarFile();
|
||||
String fileResource = jarURLConnection.getEntryName();
|
||||
|
||||
Enumeration<JarEntry> entries = jarFile.entries();
|
||||
|
||||
@ -773,8 +772,8 @@ public class Sys {
|
||||
JarEntry jarEntry = entries.nextElement();
|
||||
String name = jarEntry.getName();
|
||||
|
||||
if (name.startsWith(fileResource) && // make sure it's at least the correct package
|
||||
isValid(name)) {
|
||||
if (name.startsWith(searchLocation) && // make sure it's at least the correct package
|
||||
isValid(name)) {
|
||||
|
||||
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
|
||||
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('.'));
|
||||
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;
|
||||
|
||||
/**
|
||||
* This is intel/amd/arm arch!
|
||||
*
|
||||
* arm is technically bi-endian
|
||||
*/
|
||||
public class LittleEndian {
|
||||
// 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);
|
||||
}
|
||||
|
||||
|
||||
public static final byte[] toBytes(char x) {
|
||||
return new byte[] {(byte) (x >> 8),
|
||||
(byte) (x >> 0)
|
||||
return new byte[] {(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)}.
|
||||
*
|
||||
* @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) {
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
@ -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
|
||||
*/
|
||||
public final int canReadInt (ByteBuf buffer) {
|
||||
public final int canReadInt(ByteBuf buffer) {
|
||||
int startIndex = buffer.readerIndex();
|
||||
try {
|
||||
int remaining = buffer.readableBytes();
|
||||
@ -56,7 +67,7 @@ public class OptimizeUtilsByteBuf {
|
||||
*
|
||||
* 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 result = b & 0x7F;
|
||||
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
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
public final int writeInt (ByteBuf buffer, int value, boolean optimizePositive) {
|
||||
if (!optimizePositive) value = (value << 1) ^ (value >> 31);
|
||||
public final int writeInt(ByteBuf buffer, int value, boolean optimizePositive) {
|
||||
if (!optimizePositive) {
|
||||
value = value << 1 ^ value >> 31;
|
||||
}
|
||||
if (value >>> 7 == 0) {
|
||||
buffer.writeByte((byte)value);
|
||||
buffer.writeByte((byte) value);
|
||||
return 1;
|
||||
}
|
||||
if (value >>> 14 == 0) {
|
||||
buffer.writeByte((byte)((value & 0x7F) | 0x80));
|
||||
buffer.writeByte((byte)(value >>> 7));
|
||||
buffer.writeByte((byte) (value & 0x7F | 0x80));
|
||||
buffer.writeByte((byte) (value >>> 7));
|
||||
return 2;
|
||||
}
|
||||
if (value >>> 21 == 0) {
|
||||
buffer.writeByte((byte)((value & 0x7F) | 0x80));
|
||||
buffer.writeByte((byte)(value >>> 7 | 0x80));
|
||||
buffer.writeByte((byte)(value >>> 14));
|
||||
buffer.writeByte((byte) (value & 0x7F | 0x80));
|
||||
buffer.writeByte((byte) (value >>> 7 | 0x80));
|
||||
buffer.writeByte((byte) (value >>> 14));
|
||||
return 3;
|
||||
}
|
||||
if (value >>> 28 == 0) {
|
||||
buffer.writeByte((byte)((value & 0x7F) | 0x80));
|
||||
buffer.writeByte((byte)(value >>> 7 | 0x80));
|
||||
buffer.writeByte((byte)(value >>> 14 | 0x80));
|
||||
buffer.writeByte((byte)(value >>> 21));
|
||||
buffer.writeByte((byte) (value & 0x7F | 0x80));
|
||||
buffer.writeByte((byte) (value >>> 7 | 0x80));
|
||||
buffer.writeByte((byte) (value >>> 14 | 0x80));
|
||||
buffer.writeByte((byte) (value >>> 21));
|
||||
return 4;
|
||||
}
|
||||
buffer.writeByte((byte)((value & 0x7F) | 0x80));
|
||||
buffer.writeByte((byte)(value >>> 7 | 0x80));
|
||||
buffer.writeByte((byte)(value >>> 14 | 0x80));
|
||||
buffer.writeByte((byte)(value >>> 21 | 0x80));
|
||||
buffer.writeByte((byte)(value >>> 28));
|
||||
buffer.writeByte((byte) (value & 0x7F | 0x80));
|
||||
buffer.writeByte((byte) (value >>> 7 | 0x80));
|
||||
buffer.writeByte((byte) (value >>> 14 | 0x80));
|
||||
buffer.writeByte((byte) (value >>> 21 | 0x80));
|
||||
buffer.writeByte((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
|
||||
* @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;
|
||||
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;
|
||||
}
|
||||
|
||||
@ -147,9 +176,10 @@ public class OptimizeUtilsByteBuf {
|
||||
*
|
||||
* 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();
|
||||
long result = b & 0x7F;
|
||||
if ((b & 0x80) != 0) {
|
||||
@ -163,19 +193,19 @@ public class OptimizeUtilsByteBuf {
|
||||
result |= (b & 0x7F) << 21;
|
||||
if ((b & 0x80) != 0) {
|
||||
b = buffer.readByte();
|
||||
result |= (long)(b & 0x7F) << 28;
|
||||
result |= (long) (b & 0x7F) << 28;
|
||||
if ((b & 0x80) != 0) {
|
||||
b = buffer.readByte();
|
||||
result |= (long)(b & 0x7F) << 35;
|
||||
result |= (long) (b & 0x7F) << 35;
|
||||
if ((b & 0x80) != 0) {
|
||||
b = buffer.readByte();
|
||||
result |= (long)(b & 0x7F) << 42;
|
||||
result |= (long) (b & 0x7F) << 42;
|
||||
if ((b & 0x80) != 0) {
|
||||
b = buffer.readByte();
|
||||
result |= (long)(b & 0x7F) << 49;
|
||||
result |= (long) (b & 0x7F) << 49;
|
||||
if ((b & 0x80) != 0) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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).
|
||||
* @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 (ByteBuf buffer, long value, boolean optimizePositive) {
|
||||
if (!optimizePositive) value = (value << 1) ^ (value >> 63);
|
||||
public final int writeLong(ByteBuf buffer, long value, boolean optimizePositive) {
|
||||
if (!optimizePositive) {
|
||||
value = value << 1 ^ value >> 63;
|
||||
}
|
||||
if (value >>> 7 == 0) {
|
||||
buffer.writeByte((byte)value);
|
||||
buffer.writeByte((byte) value);
|
||||
return 1;
|
||||
}
|
||||
if (value >>> 14 == 0) {
|
||||
buffer.writeByte((byte)((value & 0x7F) | 0x80));
|
||||
buffer.writeByte((byte)(value >>> 7));
|
||||
buffer.writeByte((byte) (value & 0x7F | 0x80));
|
||||
buffer.writeByte((byte) (value >>> 7));
|
||||
return 2;
|
||||
}
|
||||
if (value >>> 21 == 0) {
|
||||
buffer.writeByte((byte)((value & 0x7F) | 0x80));
|
||||
buffer.writeByte((byte)(value >>> 7 | 0x80));
|
||||
buffer.writeByte((byte)(value >>> 14));
|
||||
buffer.writeByte((byte) (value & 0x7F | 0x80));
|
||||
buffer.writeByte((byte) (value >>> 7 | 0x80));
|
||||
buffer.writeByte((byte) (value >>> 14));
|
||||
return 3;
|
||||
}
|
||||
if (value >>> 28 == 0) {
|
||||
buffer.writeByte((byte)((value & 0x7F) | 0x80));
|
||||
buffer.writeByte((byte)(value >>> 7 | 0x80));
|
||||
buffer.writeByte((byte)(value >>> 14 | 0x80));
|
||||
buffer.writeByte((byte)(value >>> 21));
|
||||
buffer.writeByte((byte) (value & 0x7F | 0x80));
|
||||
buffer.writeByte((byte) (value >>> 7 | 0x80));
|
||||
buffer.writeByte((byte) (value >>> 14 | 0x80));
|
||||
buffer.writeByte((byte) (value >>> 21));
|
||||
return 4;
|
||||
}
|
||||
if (value >>> 35 == 0) {
|
||||
buffer.writeByte((byte)((value & 0x7F) | 0x80));
|
||||
buffer.writeByte((byte)(value >>> 7 | 0x80));
|
||||
buffer.writeByte((byte)(value >>> 14 | 0x80));
|
||||
buffer.writeByte((byte)(value >>> 21 | 0x80));
|
||||
buffer.writeByte((byte)(value >>> 28));
|
||||
buffer.writeByte((byte) (value & 0x7F | 0x80));
|
||||
buffer.writeByte((byte) (value >>> 7 | 0x80));
|
||||
buffer.writeByte((byte) (value >>> 14 | 0x80));
|
||||
buffer.writeByte((byte) (value >>> 21 | 0x80));
|
||||
buffer.writeByte((byte) (value >>> 28));
|
||||
return 5;
|
||||
}
|
||||
if (value >>> 42 == 0) {
|
||||
buffer.writeByte((byte)((value & 0x7F) | 0x80));
|
||||
buffer.writeByte((byte)(value >>> 7 | 0x80));
|
||||
buffer.writeByte((byte)(value >>> 14 | 0x80));
|
||||
buffer.writeByte((byte)(value >>> 21 | 0x80));
|
||||
buffer.writeByte((byte)(value >>> 28 | 0x80));
|
||||
buffer.writeByte((byte)(value >>> 35));
|
||||
buffer.writeByte((byte) (value & 0x7F | 0x80));
|
||||
buffer.writeByte((byte) (value >>> 7 | 0x80));
|
||||
buffer.writeByte((byte) (value >>> 14 | 0x80));
|
||||
buffer.writeByte((byte) (value >>> 21 | 0x80));
|
||||
buffer.writeByte((byte) (value >>> 28 | 0x80));
|
||||
buffer.writeByte((byte) (value >>> 35));
|
||||
return 6;
|
||||
}
|
||||
if (value >>> 49 == 0) {
|
||||
buffer.writeByte((byte)((value & 0x7F) | 0x80));
|
||||
buffer.writeByte((byte)(value >>> 7 | 0x80));
|
||||
buffer.writeByte((byte)(value >>> 14 | 0x80));
|
||||
buffer.writeByte((byte)(value >>> 21 | 0x80));
|
||||
buffer.writeByte((byte)(value >>> 28 | 0x80));
|
||||
buffer.writeByte((byte)(value >>> 35 | 0x80));
|
||||
buffer.writeByte((byte)(value >>> 42));
|
||||
buffer.writeByte((byte) (value & 0x7F | 0x80));
|
||||
buffer.writeByte((byte) (value >>> 7 | 0x80));
|
||||
buffer.writeByte((byte) (value >>> 14 | 0x80));
|
||||
buffer.writeByte((byte) (value >>> 21 | 0x80));
|
||||
buffer.writeByte((byte) (value >>> 28 | 0x80));
|
||||
buffer.writeByte((byte) (value >>> 35 | 0x80));
|
||||
buffer.writeByte((byte) (value >>> 42));
|
||||
return 7;
|
||||
}
|
||||
if (value >>> 56 == 0) {
|
||||
buffer.writeByte((byte)((value & 0x7F) | 0x80));
|
||||
buffer.writeByte((byte)(value >>> 7 | 0x80));
|
||||
buffer.writeByte((byte)(value >>> 14 | 0x80));
|
||||
buffer.writeByte((byte)(value >>> 21 | 0x80));
|
||||
buffer.writeByte((byte)(value >>> 28 | 0x80));
|
||||
buffer.writeByte((byte)(value >>> 35 | 0x80));
|
||||
buffer.writeByte((byte)(value >>> 42 | 0x80));
|
||||
buffer.writeByte((byte)(value >>> 49));
|
||||
buffer.writeByte((byte) (value & 0x7F | 0x80));
|
||||
buffer.writeByte((byte) (value >>> 7 | 0x80));
|
||||
buffer.writeByte((byte) (value >>> 14 | 0x80));
|
||||
buffer.writeByte((byte) (value >>> 21 | 0x80));
|
||||
buffer.writeByte((byte) (value >>> 28 | 0x80));
|
||||
buffer.writeByte((byte) (value >>> 35 | 0x80));
|
||||
buffer.writeByte((byte) (value >>> 42 | 0x80));
|
||||
buffer.writeByte((byte) (value >>> 49));
|
||||
return 8;
|
||||
}
|
||||
buffer.writeByte((byte)((value & 0x7F) | 0x80));
|
||||
buffer.writeByte((byte)(value >>> 7 | 0x80));
|
||||
buffer.writeByte((byte)(value >>> 14 | 0x80));
|
||||
buffer.writeByte((byte)(value >>> 21 | 0x80));
|
||||
buffer.writeByte((byte)(value >>> 28 | 0x80));
|
||||
buffer.writeByte((byte)(value >>> 35 | 0x80));
|
||||
buffer.writeByte((byte)(value >>> 42 | 0x80));
|
||||
buffer.writeByte((byte)(value >>> 49 | 0x80));
|
||||
buffer.writeByte((byte)(value >>> 56));
|
||||
buffer.writeByte((byte) (value & 0x7F | 0x80));
|
||||
buffer.writeByte((byte) (value >>> 7 | 0x80));
|
||||
buffer.writeByte((byte) (value >>> 14 | 0x80));
|
||||
buffer.writeByte((byte) (value >>> 21 | 0x80));
|
||||
buffer.writeByte((byte) (value >>> 28 | 0x80));
|
||||
buffer.writeByte((byte) (value >>> 35 | 0x80));
|
||||
buffer.writeByte((byte) (value >>> 42 | 0x80));
|
||||
buffer.writeByte((byte) (value >>> 49 | 0x80));
|
||||
buffer.writeByte((byte) (value >>> 56));
|
||||
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
|
||||
*/
|
||||
public final int canReadLong (ByteBuf buffer) {
|
||||
public final int canReadLong(ByteBuf buffer) {
|
||||
int position = buffer.readerIndex();
|
||||
try {
|
||||
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;
|
||||
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.PrintStream;
|
||||
import java.io.Reader;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.Charset;
|
||||
import java.security.CodeSource;
|
||||
import java.security.ProtectionDomain;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
@ -18,11 +15,14 @@ import org.fusesource.jansi.AnsiConsole;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import dorkbox.util.OS;
|
||||
import dorkbox.util.Sys;
|
||||
import dorkbox.util.bytes.ByteBuffer2Fast;
|
||||
import dorkbox.util.bytes.ByteBuffer2;
|
||||
import dorkbox.util.bytes.ByteBuffer2Poolable;
|
||||
import dorkbox.util.input.posix.UnixTerminal;
|
||||
import dorkbox.util.input.unsupported.UnsupportedTerminal;
|
||||
import dorkbox.util.input.windows.WindowsTerminal;
|
||||
import dorkbox.util.objectPool.ObjectPool;
|
||||
import dorkbox.util.objectPool.ObjectPoolFactory;
|
||||
import dorkbox.util.objectPool.ObjectPoolHolder;
|
||||
|
||||
public class InputConsole {
|
||||
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 inputLockLine = new Object();
|
||||
|
||||
private ThreadLocal<ByteBuffer2Fast> threadBufferForRead = new ThreadLocal<ByteBuffer2Fast>();
|
||||
private CopyOnWriteArrayList<ByteBuffer2Fast> threadBuffersForRead = new CopyOnWriteArrayList<ByteBuffer2Fast>();
|
||||
|
||||
ThreadLocal<Integer> indexOfStringForReadChar = new ThreadLocal<Integer>() {
|
||||
@Override
|
||||
protected Integer initialValue() {
|
||||
return -1;
|
||||
}
|
||||
};
|
||||
|
||||
private final ObjectPool<ByteBuffer2> pool = ObjectPoolFactory.create(new ByteBuffer2Poolable());
|
||||
private ThreadLocal<ObjectPoolHolder<ByteBuffer2>> threadBufferForRead = new ThreadLocal<ObjectPoolHolder<ByteBuffer2>>();
|
||||
private CopyOnWriteArrayList<ObjectPoolHolder<ByteBuffer2>> threadBuffersForRead = new CopyOnWriteArrayList<ObjectPoolHolder<ByteBuffer2>>();
|
||||
|
||||
private volatile int readChar = -1;
|
||||
|
||||
private final boolean unsupported;
|
||||
|
||||
private final Terminal terminal;
|
||||
private Reader reader;
|
||||
private final String encoding;
|
||||
|
||||
|
||||
|
||||
private InputConsole() {
|
||||
Logger logger = InputConsole.logger;
|
||||
boolean unsupported = false;
|
||||
|
||||
String type = System.getProperty(TerminalType.TYPE, TerminalType.AUTO).toLowerCase();
|
||||
if ("dumb".equals(System.getenv("TERM"))) {
|
||||
@ -141,48 +126,42 @@ public class InputConsole {
|
||||
|
||||
logger.debug("Creating terminal; type={}", type);
|
||||
|
||||
Terminal t;
|
||||
|
||||
String encoding = Encoding.get();
|
||||
Terminal t;
|
||||
try {
|
||||
if (type.equals(TerminalType.UNIX)) {
|
||||
t = new UnixTerminal();
|
||||
t = new UnixTerminal(encoding);
|
||||
}
|
||||
else if (type.equals(TerminalType.WIN) || type.equals(TerminalType.WINDOWS)) {
|
||||
t = new WindowsTerminal();
|
||||
}
|
||||
else if (type.equals(TerminalType.NONE) || type.equals(TerminalType.OFF) || type.equals(TerminalType.FALSE)) {
|
||||
t = new UnsupportedTerminal();
|
||||
unsupported = true;
|
||||
t = new UnsupportedTerminal(encoding);
|
||||
} else {
|
||||
if (isIDEAutoDetect()) {
|
||||
logger.debug("Terminal is in UNSUPPORTED (best guess). Unable to support single key input. Only line input available.");
|
||||
t = new UnsupportedTerminal();
|
||||
unsupported = true;
|
||||
t = new UnsupportedTerminal(encoding);
|
||||
} else {
|
||||
if (OS.isWindows()) {
|
||||
t = new WindowsTerminal();
|
||||
} else {
|
||||
t = new UnixTerminal();
|
||||
t = new UnixTerminal(encoding);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
logger.error("Failed to construct terminal, falling back to unsupported");
|
||||
t = new UnsupportedTerminal();
|
||||
unsupported = true;
|
||||
t = new UnsupportedTerminal(encoding);
|
||||
}
|
||||
|
||||
InputStream in;
|
||||
|
||||
try {
|
||||
t.init();
|
||||
in = t.wrapInIfNeeded(System.in);
|
||||
}
|
||||
catch (Throwable e) {
|
||||
logger.error("Terminal initialization failed, falling back to unsupported");
|
||||
t = new UnsupportedTerminal();
|
||||
unsupported = true;
|
||||
in = System.in;
|
||||
t = new UnsupportedTerminal(encoding);
|
||||
|
||||
try {
|
||||
t.init();
|
||||
@ -191,17 +170,10 @@ public class InputConsole {
|
||||
}
|
||||
}
|
||||
|
||||
this.encoding = this.encoding != null ? this.encoding : getEncoding();
|
||||
this.reader = new InputStreamReader(in, this.encoding);
|
||||
t.setEchoEnabled(true);
|
||||
|
||||
if (unsupported) {
|
||||
this.reader = new BufferedReader(this.reader);
|
||||
}
|
||||
|
||||
this.unsupported = unsupported;
|
||||
this.terminal = t;
|
||||
|
||||
logger.debug("Created Terminal: {}", this.terminal);
|
||||
logger.debug("Created Terminal: {} ({}x{})", this.terminal.getClass().getSimpleName(), t.getWidth(), t.getHeight());
|
||||
}
|
||||
|
||||
// called when the JVM is shutting down.
|
||||
@ -237,9 +209,9 @@ public class InputConsole {
|
||||
/** return null if no data */
|
||||
private final char[] readLine0() {
|
||||
if (this.threadBufferForRead.get() == null) {
|
||||
ByteBuffer2Fast buffer = ByteBuffer2Fast.allocate(0);
|
||||
this.threadBufferForRead.set(buffer);
|
||||
this.threadBuffersForRead.add(buffer);
|
||||
ObjectPoolHolder<ByteBuffer2> holder = this.pool.take();
|
||||
this.threadBufferForRead.set(holder);
|
||||
this.threadBuffersForRead.add(holder);
|
||||
}
|
||||
|
||||
synchronized (this.inputLockLine) {
|
||||
@ -250,33 +222,28 @@ public class InputConsole {
|
||||
}
|
||||
}
|
||||
|
||||
ByteBuffer2Fast stringBuffer = this.threadBufferForRead.get();
|
||||
int len = stringBuffer.position();
|
||||
ObjectPoolHolder<ByteBuffer2> objectPoolHolder = this.threadBufferForRead.get();
|
||||
ByteBuffer2 buffer = objectPoolHolder.getValue();
|
||||
int len = buffer.position();
|
||||
if (len == 0) {
|
||||
return emptyLine;
|
||||
}
|
||||
|
||||
char[] chars = new char[len/2]; // because 2 chars is 1 bytes
|
||||
stringBuffer.getChars(0, len, chars, 0);
|
||||
buffer.rewind();
|
||||
char[] readChars = buffer.readChars(len/2); // java always stores chars in 2 bytes
|
||||
|
||||
// dump the chars in the buffer (safer for passwords, etc)
|
||||
stringBuffer.clear();
|
||||
stringBuffer.putBytes(new byte[0]);
|
||||
buffer.clearSecure();
|
||||
|
||||
this.threadBuffersForRead.remove(objectPoolHolder);
|
||||
this.pool.release(objectPoolHolder);
|
||||
this.threadBufferForRead.set(null);
|
||||
this.threadBuffersForRead.remove(stringBuffer); // TODO: use object pool!
|
||||
|
||||
return chars;
|
||||
return readChars;
|
||||
}
|
||||
|
||||
/** return null if no data */
|
||||
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.
|
||||
boolean echoEnabled = this.terminal.isEchoEnabled();
|
||||
this.terminal.setEchoEnabled(false);
|
||||
@ -288,51 +255,15 @@ public class InputConsole {
|
||||
|
||||
/** return -1 if no data */
|
||||
private final int read0() {
|
||||
// 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
|
||||
if (this.unsupported) {
|
||||
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);
|
||||
}
|
||||
synchronized (this.inputLockSingle) {
|
||||
try {
|
||||
this.inputLockSingle.wait();
|
||||
} catch (InterruptedException e) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
// 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() {
|
||||
Logger logger2 = logger;
|
||||
|
||||
// if we are eclipse/etc, we MUST do this per line! (per character DOESN'T work.)
|
||||
// char readers will get looped for the WHOLE string, so reading by char will work,
|
||||
// it just waits until \n until it triggers
|
||||
if (this.unsupported) {
|
||||
BufferedReader reader = (BufferedReader) this.reader;
|
||||
String line = null;
|
||||
char[] readLine = null;
|
||||
final boolean ansiEnabled = Ansi.isEnabled();
|
||||
Ansi ansi = Ansi.ansi();
|
||||
PrintStream out = AnsiConsole.out;
|
||||
|
||||
try {
|
||||
while ((line = reader.readLine()) != null) {
|
||||
readLine = line.toCharArray();
|
||||
int typedChar;
|
||||
char asChar;
|
||||
|
||||
// notify everyone waiting for a line of text.
|
||||
synchronized (this.inputLockSingle) {
|
||||
if (readLine.length > 0) {
|
||||
this.readChar = readLine[0];
|
||||
} else {
|
||||
this.readChar = -1;
|
||||
}
|
||||
this.inputLockSingle.notifyAll();
|
||||
}
|
||||
synchronized (this.inputLockLine) {
|
||||
byte[] charToBytes = Sys.charToBytes(readLine);
|
||||
// don't type ; in a bash shell, it quits everything
|
||||
// \n is replaced by \r in unix terminal?
|
||||
while ((typedChar = this.terminal.read()) != -1) {
|
||||
asChar = (char) typedChar;
|
||||
|
||||
for (ByteBuffer2Fast buffer : this.threadBuffersForRead) {
|
||||
buffer.clear();
|
||||
buffer.putBytes(charToBytes);
|
||||
}
|
||||
|
||||
this.inputLockLine.notifyAll();
|
||||
}
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
ignored.printStackTrace();
|
||||
if (logger2.isTraceEnabled()) {
|
||||
logger2.trace("READ: {} ({})", asChar, typedChar);
|
||||
}
|
||||
}
|
||||
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
|
||||
// \n is replaced by \r in unix terminal?
|
||||
while ((typedChar = this.reader.read()) != -1) {
|
||||
char asChar = (char) typedChar;
|
||||
// if we type a backspace key, swallow it + previous in READLINE. READCHAR will have it passed.
|
||||
if (typedChar == '\b') {
|
||||
int position = 0;
|
||||
|
||||
if (logger2.isTraceEnabled()) {
|
||||
logger2.trace("READ: {} ({})", asChar, typedChar);
|
||||
}
|
||||
// clear ourself + one extra.
|
||||
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.
|
||||
synchronized (this.inputLockSingle) {
|
||||
this.readChar = typedChar;
|
||||
this.inputLockSingle.notifyAll();
|
||||
}
|
||||
if (length > 1) {
|
||||
char charAt = buffer.readChar(length-2);
|
||||
amtToOverwrite += getPrintableCharacters(charAt);
|
||||
|
||||
// if we type a backspace key, swallow it + previous in READLINE. READCHAR will have it passed.
|
||||
if (typedChar == 127) {
|
||||
int position = 0;
|
||||
// delete last item in our buffer
|
||||
length -= 2;
|
||||
buffer.setPosition(length);
|
||||
|
||||
// clear ourself + one extra.
|
||||
if (ansiEnabled) {
|
||||
for (ByteBuffer2Fast buffer : this.threadBuffersForRead) {
|
||||
// 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
|
||||
|
||||
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();
|
||||
// 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.readChar(i);
|
||||
position += getPrintableCharacters(charAt);
|
||||
}
|
||||
|
||||
position++;
|
||||
}
|
||||
|
||||
// read-line will ignore backspace
|
||||
continue;
|
||||
}
|
||||
char[] overwrite = new char[amtToOverwrite];
|
||||
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)
|
||||
if (asChar == '\n') {
|
||||
synchronized (this.inputLockLine) {
|
||||
this.inputLockLine.notifyAll();
|
||||
}
|
||||
} else if (asChar != '\r') {
|
||||
// only append if we are not a new line.
|
||||
for (ByteBuffer2Fast buffer : this.threadBuffersForRead) {
|
||||
buffer.putChar(asChar);
|
||||
}
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
} 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
|
||||
*/
|
||||
|
@ -1,7 +1,6 @@
|
||||
package dorkbox.util.input;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
public abstract class Terminal {
|
||||
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 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
|
||||
*/
|
||||
package dorkbox.util.input;
|
||||
package dorkbox.util.input.posix;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
@ -1,6 +1,7 @@
|
||||
package dorkbox.util.input.posix;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import com.sun.jna.Native;
|
||||
@ -18,10 +19,15 @@ public class UnixTerminal extends Terminal {
|
||||
private volatile TermiosStruct termInfoDefault = new TermiosStruct();
|
||||
private volatile TermiosStruct termInfo = new TermiosStruct();
|
||||
|
||||
private Reader reader;
|
||||
|
||||
private PosixTerminalControl term;
|
||||
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);
|
||||
|
||||
// save off the defaults
|
||||
@ -54,7 +60,6 @@ public class UnixTerminal extends Terminal {
|
||||
// t->c_cc[VMIN] = 1;
|
||||
// t->c_cc[VTIME] = 0;
|
||||
|
||||
|
||||
if (this.term.tcgetattr(0, this.termInfo) !=0) {
|
||||
throw new IOException("Failed to get terminal info");
|
||||
}
|
||||
@ -86,7 +91,7 @@ public class UnixTerminal extends Terminal {
|
||||
* used after calling this method.
|
||||
*/
|
||||
@Override
|
||||
public void restore() throws IOException {
|
||||
public final void restore() throws IOException {
|
||||
if (this.term.tcsetattr(0, PosixTerminalControl.TCSANOW, this.termInfoDefault) != 0) {
|
||||
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.
|
||||
*/
|
||||
@Override
|
||||
public int getWidth() {
|
||||
public final int getWidth() {
|
||||
if (this.term.ioctl(0, PosixTerminalControl.TIOCGWINSZ, this.windowSizeBuffer) != 0) {
|
||||
return DEFAULT_WIDTH;
|
||||
}
|
||||
@ -109,7 +114,7 @@ public class UnixTerminal extends Terminal {
|
||||
* Returns number of rows in the terminal.
|
||||
*/
|
||||
@Override
|
||||
public int getHeight() {
|
||||
public final int getHeight() {
|
||||
if (this.term.ioctl(0, PosixTerminalControl.TIOCGWINSZ, this.windowSizeBuffer) != 0) {
|
||||
return DEFAULT_HEIGHT;
|
||||
}
|
||||
@ -119,7 +124,7 @@ public class UnixTerminal extends Terminal {
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void setEchoEnabled(final boolean enabled) {
|
||||
public final synchronized void setEchoEnabled(final boolean enabled) {
|
||||
// have to reget them, since flags change everything
|
||||
if (this.term.tcgetattr(0, this.termInfo) !=0) {
|
||||
this.logger.error("Failed to get terminal info");
|
||||
@ -139,29 +144,38 @@ public class UnixTerminal extends Terminal {
|
||||
super.setEchoEnabled(enabled);
|
||||
}
|
||||
|
||||
public void disableInterruptCharacter() {
|
||||
// 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");
|
||||
}
|
||||
// public final void disableInterruptCharacter() {
|
||||
// // 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] = 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
|
||||
|
||||
if (this.term.tcsetattr(0, PosixTerminalControl.TCSANOW, this.termInfo) != 0) {
|
||||
this.logger.error("Can not set terminal flags");
|
||||
}
|
||||
}
|
||||
|
||||
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");
|
||||
@Override
|
||||
public final int read() {
|
||||
try {
|
||||
return this.reader.read();
|
||||
} catch (IOException ignored) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,30 +1,91 @@
|
||||
package dorkbox.util.input.unsupported;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
|
||||
import dorkbox.util.bytes.ByteBuffer2;
|
||||
import dorkbox.util.input.Terminal;
|
||||
import dorkbox.util.input.posix.InputStreamReader;
|
||||
|
||||
public class UnsupportedTerminal extends Terminal {
|
||||
public UnsupportedTerminal() {
|
||||
// setAnsiSupported(false);
|
||||
setEchoEnabled(true);
|
||||
|
||||
private final ByteBuffer2 buffer = new ByteBuffer2(8, -1);
|
||||
|
||||
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
|
||||
public void init() throws IOException {
|
||||
public final void init() throws IOException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restore() {
|
||||
public final void restore() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWidth() {
|
||||
public final int getWidth() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHeight() {
|
||||
public final int getHeight() {
|
||||
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.
|
||||
*/
|
||||
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;
|
||||
|
||||
|
@ -8,11 +8,11 @@
|
||||
*/
|
||||
package dorkbox.util.input.windows;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.FileInputStream;
|
||||
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 dorkbox.util.input.Terminal;
|
||||
@ -26,34 +26,26 @@ import dorkbox.util.input.Terminal;
|
||||
* url=/library/en-us/dllproc/base/getconsolemode.asp">GetConsoleMode</a> to
|
||||
* disable character echoing.
|
||||
* <p/>
|
||||
* <p>
|
||||
* 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
|
||||
* @since 2.0 (customized)
|
||||
*/
|
||||
public class WindowsTerminal extends Terminal
|
||||
{
|
||||
public static final String DIRECT_CONSOLE = WindowsTerminal.class.getName() + ".directConsole";
|
||||
|
||||
private int originalMode;
|
||||
public class WindowsTerminal extends Terminal {
|
||||
private volatile int originalMode;
|
||||
private final PrintStream out;
|
||||
|
||||
public WindowsTerminal() {
|
||||
this.out = System.out;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() throws IOException {
|
||||
public final void init() throws IOException {
|
||||
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.
|
||||
*/
|
||||
@Override
|
||||
public void restore() throws IOException {
|
||||
public final void restore() throws IOException {
|
||||
// restore the old console mode
|
||||
WindowsSupport.setConsoleMode(this.originalMode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWidth() {
|
||||
public final int getWidth() {
|
||||
int w = WindowsSupport.getWindowsTerminalWidth();
|
||||
return w < 1 ? DEFAULT_WIDTH : w;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHeight() {
|
||||
public final int getHeight() {
|
||||
int h = WindowsSupport.getWindowsTerminalHeight();
|
||||
return h < 1 ? DEFAULT_HEIGHT : h;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEchoEnabled(final boolean enabled) {
|
||||
// Must set these four modes at the same time to make it work fine.
|
||||
if (enabled) {
|
||||
WindowsSupport.setConsoleMode(WindowsSupport.getConsoleMode() |
|
||||
ConsoleMode.ENABLE_ECHO_INPUT.code |
|
||||
ConsoleMode.ENABLE_LINE_INPUT.code |
|
||||
ConsoleMode.ENABLE_PROCESSED_INPUT.code |
|
||||
ConsoleMode.ENABLE_WINDOW_INPUT.code);
|
||||
public final int read() {
|
||||
int input = readInput();
|
||||
|
||||
if (isEchoEnabled()) {
|
||||
char asChar = (char) input;
|
||||
if (asChar == '\n') {
|
||||
this.out.println();
|
||||
} 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() &
|
||||
~(ConsoleMode.ENABLE_LINE_INPUT.code |
|
||||
ConsoleMode.ENABLE_ECHO_INPUT.code |
|
||||
ConsoleMode.ENABLE_PROCESSED_INPUT.code |
|
||||
ConsoleMode.ENABLE_WINDOW_INPUT.code));
|
||||
}
|
||||
super.setEchoEnabled(enabled);
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
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
|
||||
public InputStream wrapInIfNeeded(InputStream in) throws IOException {
|
||||
if (isSystemIn(in)) {
|
||||
return new InputStream() {
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
return WindowsSupport.readByte();
|
||||
if (events != null) {
|
||||
for (int i = 0; i < events.length; i++ ) {
|
||||
KEY_EVENT_RECORD keyEvent = events[i].keyEvent;
|
||||
//Log.trace(keyEvent.keyDown? "KEY_DOWN" : "KEY_UP", "key code:", keyEvent.keyCode, "char:", (long)keyEvent.uchar);
|
||||
if (keyEvent.keyDown) {
|
||||
if (keyEvent.uchar > 0) {
|
||||
char uchar = keyEvent.uchar;
|
||||
if (uchar == '\r') {
|
||||
// we purposefully swallow input after \r, and substitute it with \n
|
||||
return '\n';
|
||||
}
|
||||
|
||||
return uchar;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
} else {
|
||||
return in;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
this.logger.error("Windows console input error: ", e);
|
||||
}
|
||||
|
||||
return false;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
@ -104,10 +104,10 @@ class FastObjectPool<T> implements ObjectPool<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void release(ObjectPoolHolder<T> object) throws InterruptedException {
|
||||
this.lock.lockInterruptibly();
|
||||
|
||||
public void release(ObjectPoolHolder<T> object) {
|
||||
try {
|
||||
this.lock.lockInterruptibly();
|
||||
|
||||
int localValue = this.releasePointer;
|
||||
//long index = ((localValue & mask) * INDEXSCALE ) + BASE;
|
||||
long index = ((localValue & this.mask)<<this.ASHIFT ) + this.BASE;
|
||||
@ -120,6 +120,7 @@ class FastObjectPool<T> implements ObjectPool<T> {
|
||||
else {
|
||||
throw new IllegalArgumentException("Invalid reference passed");
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
finally {
|
||||
this.lock.unlock();
|
||||
|
@ -9,5 +9,5 @@ public interface ObjectPool<T> {
|
||||
/**
|
||||
* 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;
|
||||
|
||||
public class ObjectPoolFactory<T> {
|
||||
public class 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) {
|
||||
if (Sys.isAndroid) {
|
||||
// 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
|
||||
*/
|
||||
public void activate(T t);
|
||||
public void activate(T object);
|
||||
|
||||
/**
|
||||
* 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
|
||||
public void release(ObjectPoolHolder<T> object) throws InterruptedException {
|
||||
public void release(ObjectPoolHolder<T> object) {
|
||||
if (object.state.compareAndSet(USED, FREE)) {
|
||||
this.queue.offer(object);
|
||||
this.poolableObject.passivate(object.getValue());
|
||||
|
@ -21,10 +21,6 @@ import dorkbox.util.OS;
|
||||
*/
|
||||
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 executableName = null;
|
||||
private String executableDirectory = null;
|
||||
@ -56,9 +52,9 @@ public class ShellProcessBuilder {
|
||||
}
|
||||
|
||||
public ShellProcessBuilder(InputStream in, PrintStream out, PrintStream err) {
|
||||
outputStream = out;
|
||||
errorStream = err;
|
||||
inputStream = in;
|
||||
this.outputStream = out;
|
||||
this.errorStream = err;
|
||||
this.inputStream = in;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -71,19 +67,19 @@ public class ShellProcessBuilder {
|
||||
}
|
||||
|
||||
public final ShellProcessBuilder addArgument(String argument) {
|
||||
arguments.add(argument);
|
||||
this.arguments.add(argument);
|
||||
return this;
|
||||
}
|
||||
|
||||
public final ShellProcessBuilder addArguments(String... paths) {
|
||||
for (String path : paths) {
|
||||
arguments.add(path);
|
||||
this.arguments.add(path);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public final ShellProcessBuilder addArguments(List<String> paths) {
|
||||
arguments.addAll(paths);
|
||||
this.arguments.addAll(paths);
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -106,39 +102,39 @@ public class ShellProcessBuilder {
|
||||
|
||||
public void start() {
|
||||
// if no executable, then use the command shell
|
||||
if (executableName == null) {
|
||||
if (this.executableName == null) {
|
||||
if (OS.isWindows()) {
|
||||
// windows
|
||||
executableName = "cmd";
|
||||
arguments.add(0, "/c");
|
||||
this.executableName = "cmd";
|
||||
this.arguments.add(0, "/c");
|
||||
|
||||
} else {
|
||||
// *nix
|
||||
executableName = "/bin/bash";
|
||||
File file = new File(executableName);
|
||||
this.executableName = "/bin/bash";
|
||||
File file = new File(this.executableName);
|
||||
if (!file.canExecute()) {
|
||||
executableName = "/bin/sh";
|
||||
this.executableName = "/bin/sh";
|
||||
}
|
||||
arguments.add(0, "-c");
|
||||
this.arguments.add(0, "-c");
|
||||
}
|
||||
} else if (workingDirectory != null) {
|
||||
if (!workingDirectory.endsWith("/") && !workingDirectory.endsWith("\\")) {
|
||||
workingDirectory += File.separator;
|
||||
} else if (this.workingDirectory != null) {
|
||||
if (!this.workingDirectory.endsWith("/") && !this.workingDirectory.endsWith("\\")) {
|
||||
this.workingDirectory += File.separator;
|
||||
}
|
||||
}
|
||||
|
||||
if (executableDirectory != null) {
|
||||
if (!executableDirectory.endsWith("/") && !executableDirectory.endsWith("\\")) {
|
||||
executableDirectory += File.separator;
|
||||
if (this.executableDirectory != null) {
|
||||
if (!this.executableDirectory.endsWith("/") && !this.executableDirectory.endsWith("\\")) {
|
||||
this.executableDirectory += File.separator;
|
||||
}
|
||||
|
||||
executableName = executableDirectory + executableName;
|
||||
this.executableName = this.executableDirectory + this.executableName;
|
||||
}
|
||||
|
||||
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(" ")) {
|
||||
// individual arguments MUST be in their own element in order to
|
||||
// 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)
|
||||
// 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 (OS.isWindows()) {
|
||||
// >NUL on windows
|
||||
@ -165,22 +161,22 @@ public class ShellProcessBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
if (debugInfo) {
|
||||
errorStream.print("Executing: ");
|
||||
if (this.debugInfo) {
|
||||
this.errorStream.print("Executing: ");
|
||||
Iterator<String> iterator = argumentsList.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
String s = iterator.next();
|
||||
errorStream.print(s);
|
||||
this.errorStream.print(s);
|
||||
if (iterator.hasNext()) {
|
||||
errorStream.print(" ");
|
||||
this.errorStream.print(" ");
|
||||
}
|
||||
}
|
||||
errorStream.print(OS.LINE_SEPARATOR);
|
||||
this.errorStream.print(OS.LINE_SEPARATOR);
|
||||
}
|
||||
|
||||
ProcessBuilder processBuilder = new ProcessBuilder(argumentsList);
|
||||
if (workingDirectory != null) {
|
||||
processBuilder.directory(new File(workingDirectory));
|
||||
if (this.workingDirectory != null) {
|
||||
processBuilder.directory(new File(this.workingDirectory));
|
||||
}
|
||||
|
||||
// combine these so output is properly piped to null.
|
||||
@ -189,23 +185,23 @@ public class ShellProcessBuilder {
|
||||
}
|
||||
|
||||
try {
|
||||
process = processBuilder.start();
|
||||
this.process = processBuilder.start();
|
||||
} catch (Exception ex) {
|
||||
errorStream.println("There was a problem executing the program. Details:\n");
|
||||
ex.printStackTrace(errorStream);
|
||||
this.errorStream.println("There was a problem executing the program. Details:\n");
|
||||
ex.printStackTrace(this.errorStream);
|
||||
|
||||
if (process != null) {
|
||||
if (this.process != null) {
|
||||
try {
|
||||
process.destroy();
|
||||
process = null;
|
||||
this.process.destroy();
|
||||
this.process = null;
|
||||
} catch (Exception e) {
|
||||
errorStream.println("Error destroying process: \n");
|
||||
e.printStackTrace(errorStream);
|
||||
this.errorStream.println("Error destroying process: \n");
|
||||
e.printStackTrace(this.errorStream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (process != null) {
|
||||
if (this.process != null) {
|
||||
ProcessProxy writeToProcess_input;
|
||||
ProcessProxy readFromProcess_output;
|
||||
ProcessProxy readFromProcess_error;
|
||||
@ -218,7 +214,7 @@ public class ShellProcessBuilder {
|
||||
|
||||
// readers (read process -> write console)
|
||||
// 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;
|
||||
}
|
||||
// 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.
|
||||
*/
|
||||
// readers (read process -> write console)
|
||||
readFromProcess_output = new ProcessProxy("Process Reader: " + executableName, process.getInputStream(), outputStream);
|
||||
if (errorStream != outputStream) {
|
||||
readFromProcess_error = new ProcessProxy("Process Reader: " + executableName, process.getErrorStream(), errorStream);
|
||||
readFromProcess_output = new ProcessProxy("Process Reader: " + this.executableName, this.process.getInputStream(), this.outputStream);
|
||||
if (this.errorStream != this.outputStream) {
|
||||
readFromProcess_error = new ProcessProxy("Process Reader: " + this.executableName, this.process.getErrorStream(), this.errorStream);
|
||||
} else {
|
||||
processBuilder.redirectErrorStream(true);
|
||||
readFromProcess_error = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (inputStream != null) {
|
||||
if (this.inputStream != null) {
|
||||
/**
|
||||
* Proxy System.in from the user's window to the spawned 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 {
|
||||
writeToProcess_input = null;
|
||||
}
|
||||
@ -254,10 +250,10 @@ public class ShellProcessBuilder {
|
||||
Thread hook = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (debugInfo) {
|
||||
errorStream.println("Terminating process: " + executableName);
|
||||
if (ShellProcessBuilder.this.debugInfo) {
|
||||
ShellProcessBuilder.this.errorStream.println("Terminating process: " + ShellProcessBuilder.this.executableName);
|
||||
}
|
||||
process.destroy();
|
||||
ShellProcessBuilder.this.process.destroy();
|
||||
}
|
||||
}
|
||||
);
|
||||
@ -273,10 +269,10 @@ public class ShellProcessBuilder {
|
||||
}
|
||||
|
||||
try {
|
||||
process.waitFor();
|
||||
this.process.waitFor();
|
||||
|
||||
@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)
|
||||
if (writeToProcess_input != null) {
|
||||
@ -294,7 +290,7 @@ public class ShellProcessBuilder {
|
||||
|
||||
// forcibly terminate the process when it's streams have closed.
|
||||
// this is for cleanup ONLY, not to actually do anything.
|
||||
process.destroy();
|
||||
this.process.destroy();
|
||||
} catch (InterruptedException e) {
|
||||
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