* Marker | Binary | Type | Description |
* 00..7F | 0xxxxxxx | +TINY_INT | Integer 0 to 127 |
* 80..8F | 1000xxxx | TINY_TEXT | |
@@ -54,7 +55,8 @@
* A0..AF | 1010xxxx | TINY_MAP | |
* B0..BF | 1011xxxx | TINY_STRUCT | |
* C0 | 11000000 | NULL | |
- * C1 | 11000001 | FLOAT_64 | 64-bit floating point number (double) |
+ * C1 | 11000001 | FLOAT_64 | 64-bit floating point number
+ * (double) |
* C2 | 11000010 | FALSE | Boolean false |
* C3 | 11000011 | TRUE | Boolean true |
* C4..C7 | 110001xx | RESERVED | |
@@ -62,34 +64,48 @@
* C9 | 11001001 | INT_8 | 16-bit signed integer |
* CA | 11001010 | INT_8 | 32-bit signed integer |
* CB | 11001011 | INT_8 | 64-bit signed integer |
- * CC | 11001100 | BYTES_8 | Byte string (fewer than 28 bytes) |
- * CD | 11001101 | BYTES_16 | Byte string (fewer than 216 bytes) |
- * CE | 11001110 | BYTES_32 | Byte string (fewer than 232 bytes) |
+ * CC | 11001100 | BYTES_8 | Byte string (fewer than 28
+ * bytes) |
+ * CD | 11001101 | BYTES_16 | Byte string (fewer than 216
+ * bytes) |
+ * CE | 11001110 | BYTES_32 | Byte string (fewer than 232
+ * bytes) |
* CF | 11001111 | RESERVED | |
- * D0 | 11010000 | TEXT_8 | UTF-8 encoded text string (fewer than 28 bytes) |
- * D1 | 11010001 | TEXT_16 | UTF-8 encoded text string (fewer than 216 bytes) |
- * D2 | 11010010 | TEXT_32 | UTF-8 encoded text string (fewer than 232 bytes) |
+ * D0 | 11010000 | TEXT_8 | UTF-8 encoded text string (fewer than
+ * 28 bytes) |
+ * D1 | 11010001 | TEXT_16 | UTF-8 encoded text string (fewer than
+ * 216 bytes) |
+ * D2 | 11010010 | TEXT_32 | UTF-8 encoded text string (fewer than
+ * 232 bytes) |
* D3 | 11010011 | RESERVED | |
- * D4 | 11010100 | LIST_8 | List (fewer than 28 items) |
- * D5 | 11010101 | LIST_16 | List (fewer than 216 items) |
- * D6 | 11010110 | LIST_32 | List (fewer than 232 items) |
+ * D4 | 11010100 | LIST_8 | List (fewer than 28
+ * items) |
+ * D5 | 11010101 | LIST_16 | List (fewer than 216
+ * items) |
+ * D6 | 11010110 | LIST_32 | List (fewer than 232
+ * items) |
* D7 | 11010111 | RESERVED | |
- * D8 | 11011000 | MAP_8 | Map (fewer than 28 key:value pairs) |
- * D9 | 11011001 | MAP_16 | Map (fewer than 216 key:value pairs) |
- * DA | 11011010 | MAP_32 | Map (fewer than 232 key:value pairs) |
+ * D8 | 11011000 | MAP_8 | Map (fewer than 28 key:value
+ * pairs) |
+ * D9 | 11011001 | MAP_16 | Map (fewer than 216 key:value
+ * pairs) |
+ * DA | 11011010 | MAP_32 | Map (fewer than 232 key:value
+ * pairs) |
* DB | 11011011 | RESERVED | |
- * DC | 11011100 | STRUCT_8 | Structure (fewer than 28 fields) |
- * DD | 11011101 | STRUCT_16 | Structure (fewer than 216 fields) |
- * DE | 11011110 | STRUCT_32 | Structure (fewer than 232 fields) |
+ * DC | 11011100 | STRUCT_8 | Structure (fewer than 28
+ * fields) |
+ * DD | 11011101 | STRUCT_16 | Structure (fewer than 216
+ * fields) |
+ * DE | 11011110 | STRUCT_32 | Structure (fewer than 232
+ * fields) |
* DF | 11011111 | RESERVED | |
* E0..EF | 1110xxxx | RESERVED | |
* F0..FF | 1111xxxx | -TINY_INT | Integer -1 to -16 |
*
- *
*/
public class PackStream
{
-
+
public static final byte TINY_TEXT = (byte) 0x80;
public static final byte TINY_LIST = (byte) 0x90;
public static final byte TINY_MAP = (byte) 0xA0;
@@ -143,11 +159,11 @@ public class PackStream
public static final byte RESERVED_EE = (byte) 0xEE;
public static final byte RESERVED_EF = (byte) 0xEF;
- private static final long PLUS_2_TO_THE_31 = 2147483648L;
- private static final long PLUS_2_TO_THE_15 = 32768L;
- private static final long PLUS_2_TO_THE_7 = 128L;
- private static final long MINUS_2_TO_THE_4 = -16L;
- private static final long MINUS_2_TO_THE_7 = -128L;
+ private static final long PLUS_2_TO_THE_31 = 2147483648L;
+ private static final long PLUS_2_TO_THE_15 = 32768L;
+ private static final long PLUS_2_TO_THE_7 = 128L;
+ private static final long MINUS_2_TO_THE_4 = -16L;
+ private static final long MINUS_2_TO_THE_7 = -128L;
private static final long MINUS_2_TO_THE_15 = -32768L;
private static final long MINUS_2_TO_THE_31 = -2147483648L;
@@ -155,7 +171,9 @@ public class PackStream
private static final int DEFAULT_BUFFER_CAPACITY = 8192;
- private PackStream() {}
+ private PackStream()
+ {
+ }
public static class Packer
{
@@ -189,53 +207,53 @@ public void packRaw( byte[] data ) throws IOException
public void packNull() throws IOException
{
out.ensure( 1 )
- .put( NULL );
+ .put( NULL );
}
public void pack( boolean value ) throws IOException
{
out.ensure( 1 )
- .put( value ? TRUE : FALSE );
+ .put( value ? TRUE : FALSE );
}
public void pack( long value ) throws IOException
{
- if ( value >= MINUS_2_TO_THE_4 && value < PLUS_2_TO_THE_7)
+ if ( value >= MINUS_2_TO_THE_4 && value < PLUS_2_TO_THE_7 )
{
out.ensure( 1 )
- .put( (byte) value );
+ .put( (byte) value );
}
else if ( value >= MINUS_2_TO_THE_7 && value < MINUS_2_TO_THE_4 )
{
out.ensure( 2 )
- .put( INT_8 )
- .put( (byte) value );
+ .put( INT_8 )
+ .put( (byte) value );
}
else if ( value >= MINUS_2_TO_THE_15 && value < PLUS_2_TO_THE_15 )
{
out.ensure( 3 )
- .put( INT_16 )
- .putShort( (short) value );
+ .put( INT_16 )
+ .putShort( (short) value );
}
else if ( value >= MINUS_2_TO_THE_31 && value < PLUS_2_TO_THE_31 )
{
out.ensure( 5 )
- .put( INT_32 )
- .putInt( (int) value );
+ .put( INT_32 )
+ .putInt( (int) value );
}
else
{
out.ensure( 9 )
- .put( INT_64 )
- .putLong( value );
+ .put( INT_64 )
+ .putLong( value );
}
}
public void pack( double value ) throws IOException
{
out.ensure( 9 )
- .put( FLOAT_64 )
- .putDouble( value );
+ .put( FLOAT_64 )
+ .putDouble( value );
}
public void pack( byte[] values ) throws IOException
@@ -327,20 +345,20 @@ public void packBytesHeader( int size ) throws IOException
if ( size <= Byte.MAX_VALUE )
{
out.ensure( 2 )
- .put( BYTES_8 )
- .put( (byte) size );
+ .put( BYTES_8 )
+ .put( (byte) size );
}
else if ( size <= Short.MAX_VALUE )
{
out.ensure( 3 )
- .put( BYTES_16 )
- .putShort( (short) size );
+ .put( BYTES_16 )
+ .putShort( (short) size );
}
else
{
out.ensure( 5 )
- .put( BYTES_32 )
- .putInt( size );
+ .put( BYTES_32 )
+ .putInt( size );
}
}
@@ -349,25 +367,25 @@ public void packTextHeader( int size ) throws IOException
if ( size < 0x10 )
{
out.ensure( 1 )
- .put( (byte) (TINY_TEXT | size) );
+ .put( (byte) (TINY_TEXT | size) );
}
else if ( size <= Byte.MAX_VALUE )
{
out.ensure( 2 )
- .put( TEXT_8 )
- .put( (byte) size );
+ .put( TEXT_8 )
+ .put( (byte) size );
}
else if ( size <= Short.MAX_VALUE )
{
out.ensure( 3 )
- .put( TEXT_16 )
- .putShort( (short) size );
+ .put( TEXT_16 )
+ .putShort( (short) size );
}
else
{
out.ensure( 5 )
- .put( TEXT_32 )
- .putInt( size );
+ .put( TEXT_32 )
+ .putInt( size );
}
}
@@ -376,25 +394,25 @@ public void packListHeader( int size ) throws IOException
if ( size < 0x10 )
{
out.ensure( 1 )
- .put( (byte) (TINY_LIST | size) );
+ .put( (byte) (TINY_LIST | size) );
}
else if ( size <= Byte.MAX_VALUE )
{
out.ensure( 2 )
- .put( LIST_8 )
- .put( (byte) size );
+ .put( LIST_8 )
+ .put( (byte) size );
}
else if ( size <= Short.MAX_VALUE )
{
out.ensure( 3 )
- .put( LIST_16 )
- .putShort( (short) size );
+ .put( LIST_16 )
+ .putShort( (short) size );
}
else
{
out.ensure( 5 )
- .put( LIST_32 )
- .putInt( size );
+ .put( LIST_32 )
+ .putInt( size );
}
}
@@ -403,25 +421,25 @@ public void packMapHeader( int size ) throws IOException
if ( size < 0x10 )
{
out.ensure( 1 )
- .put( (byte) (TINY_MAP | size) );
+ .put( (byte) (TINY_MAP | size) );
}
else if ( size <= Byte.MAX_VALUE )
{
out.ensure( 2 )
- .put( MAP_8 )
- .put( (byte) size );
+ .put( MAP_8 )
+ .put( (byte) size );
}
else if ( size <= Short.MAX_VALUE )
{
out.ensure( 3 )
- .put( MAP_16 )
- .putShort( (short) size );
+ .put( MAP_16 )
+ .putShort( (short) size );
}
else
{
out.ensure( 5 )
- .put( MAP_32 )
- .putInt( size );
+ .put( MAP_32 )
+ .putInt( size );
}
}
@@ -430,22 +448,22 @@ public void packStructHeader( int size, char signature ) throws IOException
if ( size < 0x10 )
{
out.ensure( 2 )
- .put( (byte) (TINY_STRUCT | size) )
- .put( (byte) signature );
+ .put( (byte) (TINY_STRUCT | size) )
+ .put( (byte) signature );
}
else if ( size <= Byte.MAX_VALUE )
{
out.ensure( 3 )
- .put( STRUCT_8 )
- .put( (byte) size )
- .put( (byte) signature );
+ .put( STRUCT_8 )
+ .put( (byte) size )
+ .put( (byte) signature );
}
else if ( size <= Short.MAX_VALUE )
{
out.ensure( 4 )
- .put( STRUCT_16 )
- .putShort( (short) size )
- .put( (byte) signature );
+ .put( STRUCT_16 )
+ .putShort( (short) size )
+ .put( (byte) signature );
}
else
{
@@ -479,7 +497,7 @@ public Unpacker( PackInput in )
public Unpacker reset( ReadableByteChannel ch )
{
- ((BufferedChannelInput)in).reset( ch );
+ ((BufferedChannelInput) in).reset( ch );
return this;
}
@@ -488,6 +506,9 @@ public boolean hasNext() throws IOException
return in.remaining() > 0 || in.attempt( 1 );
}
+ // TODO: This currently returns the number of fields in the struct. In 99% of cases we will look at the struct
+ // signature to determine how to read it, suggest we make that what we return here,
+ // and have the number of fields available through some alternate optional mechanism.
public long unpackStructHeader() throws IOException
{
final byte markerByte = in.ensure( 1 ).get();
@@ -495,11 +516,14 @@ public long unpackStructHeader() throws IOException
final byte markerLowNibble = (byte) (markerByte & 0x0F);
if ( markerHighNibble == TINY_STRUCT ) { return markerLowNibble; }
- switch(markerByte)
+ switch ( markerByte )
{
- case STRUCT_8: return unpackUINT8();
- case STRUCT_16: return unpackUINT16();
- default: throw new Unexpected( "Expected a struct, but got: " + toHexString( markerByte ));
+ case STRUCT_8:
+ return unpackUINT8();
+ case STRUCT_16:
+ return unpackUINT16();
+ default:
+ throw new Unexpected( "Expected a struct, but got: " + toHexString( markerByte ) );
}
}
@@ -512,15 +536,19 @@ public long unpackListHeader() throws IOException
{
final byte markerByte = in.ensure( 1 ).get();
final byte markerHighNibble = (byte) (markerByte & 0xF0);
- final byte markerLowNibble = (byte) (markerByte & 0x0F);
+ final byte markerLowNibble = (byte) (markerByte & 0x0F);
if ( markerHighNibble == TINY_LIST ) { return markerLowNibble; }
- switch(markerByte)
+ switch ( markerByte )
{
- case LIST_8: return unpackUINT8();
- case LIST_16: return unpackUINT16();
- case LIST_32: return unpackUINT32();
- default: throw new Unexpected( "Expected a list, but got: " + toHexString( markerByte ));
+ case LIST_8:
+ return unpackUINT8();
+ case LIST_16:
+ return unpackUINT16();
+ case LIST_32:
+ return unpackUINT32();
+ default:
+ throw new Unexpected( "Expected a list, but got: " + toHexString( markerByte ) );
}
}
@@ -531,42 +559,51 @@ public long unpackMapHeader() throws IOException
final byte markerLowNibble = (byte) (markerByte & 0x0F);
if ( markerHighNibble == TINY_MAP ) { return markerLowNibble; }
- switch(markerByte)
+ switch ( markerByte )
{
- case MAP_8: return unpackUINT8();
- case MAP_16: return unpackUINT16();
- case MAP_32: return unpackUINT32();
- default: throw new Unexpected( "Expected a map, but got: " + toHexString( markerByte ));
+ case MAP_8:
+ return unpackUINT8();
+ case MAP_16:
+ return unpackUINT16();
+ case MAP_32:
+ return unpackUINT32();
+ default:
+ throw new Unexpected( "Expected a map, but got: " + toHexString( markerByte ) );
}
}
public long unpackLong() throws IOException
{
final byte markerByte = in.ensure( 1 ).get();
- if ( markerByte >= MINUS_2_TO_THE_4) { return markerByte; }
- switch(markerByte)
- {
- case INT_8: return in.ensure( 1 ).get();
- case INT_16: return in.ensure( 2 ).getShort();
- case INT_32: return in.ensure( 4 ).getInt();
- case INT_64: return in.ensure( 8 ).getLong();
- default: throw new Unexpected( "Expected an integer, but got: " + toHexString( markerByte ));
+ if ( markerByte >= MINUS_2_TO_THE_4 ) { return markerByte; }
+ switch ( markerByte )
+ {
+ case INT_8:
+ return in.ensure( 1 ).get();
+ case INT_16:
+ return in.ensure( 2 ).getShort();
+ case INT_32:
+ return in.ensure( 4 ).getInt();
+ case INT_64:
+ return in.ensure( 8 ).getLong();
+ default:
+ throw new Unexpected( "Expected an integer, but got: " + toHexString( markerByte ) );
}
}
public double unpackDouble() throws IOException
{
final byte markerByte = in.ensure( 1 ).get();
- if(markerByte == FLOAT_64)
+ if ( markerByte == FLOAT_64 )
{
return in.ensure( 8 ).getDouble();
}
- throw new Unexpected( "Expected a double, but got: " + toHexString( markerByte ));
+ throw new Unexpected( "Expected a double, but got: " + toHexString( markerByte ) );
}
public String unpackString() throws IOException
{
- return new String(unpackUtf8(), UTF_8);
+ return new String( unpackUtf8(), UTF_8 );
}
public byte[] unpackUtf8() throws IOException
@@ -576,10 +613,12 @@ public byte[] unpackUtf8() throws IOException
final byte markerLowNibble = (byte) (markerByte & 0x0F);
if ( markerHighNibble == TINY_TEXT ) { return unpackBytes( markerLowNibble ); }
- switch(markerByte)
+ switch ( markerByte )
{
- case TEXT_8: return unpackBytes( unpackUINT8() );
- case TEXT_16: return unpackBytes( unpackUINT16() );
+ case TEXT_8:
+ return unpackBytes( unpackUINT8() );
+ case TEXT_16:
+ return unpackBytes( unpackUINT16() );
case TEXT_32:
{
long size = unpackUINT32();
@@ -592,18 +631,22 @@ public byte[] unpackUtf8() throws IOException
throw new Overflow( "TEXT_32 too long for Java" );
}
}
- default: throw new Unexpected( "Expected a string, but got: " + toHexString( markerByte & 0xFF ));
+ default:
+ throw new Unexpected( "Expected a string, but got: " + toHexString( markerByte & 0xFF ) );
}
}
public boolean unpackBoolean() throws IOException
{
final byte markerByte = in.ensure( 1 ).get();
- switch(markerByte)
+ switch ( markerByte )
{
- case TRUE: return true;
- case FALSE: return false;
- default: throw new Unexpected( "Expected a boolean, but got: " + toHexString( markerByte & 0xFF ));
+ case TRUE:
+ return true;
+ case FALSE:
+ return false;
+ default:
+ throw new Unexpected( "Expected a boolean, but got: " + toHexString( markerByte & 0xFF ) );
}
}
@@ -774,22 +817,25 @@ private long unpackUINT32() throws IOException
private byte[] unpackBytes( int size ) throws IOException
{
- if ( size == 0 ) return EMPTY_BYTE_ARRAY;
+ if ( size == 0 )
+ {
+ return EMPTY_BYTE_ARRAY;
+ }
byte[] heapBuffer = new byte[size];
int index = 0;
- while(index < size)
+ while ( index < size )
{
int toRead = Math.min( in.remaining(), size - index );
in.get( heapBuffer, index, toRead );
index += toRead;
- if(in.remaining() == 0 && index < size)
+ if ( in.remaining() == 0 && index < size )
{
in.attemptUpTo( size - index );
- if(in.remaining() == 0)
+ if ( in.remaining() == 0 )
{
throw new EndOfStream( "Expected " + (size - index) + " bytes available, " +
- "but no more bytes accessible from underlying stream." );
+ "but no more bytes accessible from underlying stream." );
}
}
}
@@ -798,7 +844,10 @@ private byte[] unpackBytes( int size ) throws IOException
private List