summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2014-12-03 20:30:46 +0100
committerSven Gothel <[email protected]>2014-12-03 20:30:46 +0100
commit9e13e8c78ed69bb7afcd49abe8bf69340dc06223 (patch)
tree956c8bb0ab085e7325aa18400681be7612224dae
parentca4f075aeed16331f0b806ea564ca3d492039336 (diff)
Bug 1106 - Bitstream: Simplify 'msbFirst' case for bulk operations / Add setting of stream position (optional)
- Add setting position entry, optionally supported, e.g. ByteBufferStream and ByteArrayStream - Remove 'msbFirst' parameter on all 'bulk' read/write operations. These methods use LSB-first always, allowing proper stream access of data w/ different bit-sizes. Data is now read/write as little-endian and swapped accordingly. Optimizations are adopted for LSB-first operations. This change removes API confusion/bugs: - removes one decision (parameter) - removes the data reversion case - removes bugs w/ different bit-sizes
-rwxr-xr-xmake/scripts/runtest.sh16
-rw-r--r--src/java/com/jogamp/common/util/Bitstream.java555
-rw-r--r--src/junit/com/jogamp/common/util/TestBitstream00.java132
-rw-r--r--src/junit/com/jogamp/common/util/TestBitstream01.java164
-rw-r--r--src/junit/com/jogamp/common/util/TestBitstream02.java14
-rw-r--r--src/junit/com/jogamp/common/util/TestBitstream03.java21
-rw-r--r--src/junit/com/jogamp/common/util/TestBitstream04.java20
7 files changed, 595 insertions, 327 deletions
diff --git a/make/scripts/runtest.sh b/make/scripts/runtest.sh
index ed8cb8d..d19e016 100755
--- a/make/scripts/runtest.sh
+++ b/make/scripts/runtest.sh
@@ -56,7 +56,7 @@ rm -f $LOG
#D_ARGS="-Djogamp.debug.Lock -Djogamp.debug.Lock.TraceLock"
#D_ARGS="-Djogamp.debug.Lock.TraceLock"
#D_ARGS="-Djogamp.debug.IOUtil"
-D_ARGS="-Djogamp.debug.ByteBufferInputStream"
+#D_ARGS="-Djogamp.debug.ByteBufferInputStream"
#D_ARGS="-Djogamp.debug.Bitstream"
#D_ARGS="-Djogamp.debug=all"
@@ -106,11 +106,13 @@ function onetest() {
#onetest com.jogamp.common.util.TestValueConversion 2>&1 | tee -a $LOG
#onetest com.jogamp.common.util.TestSyncRingBuffer01 $*
#onetest com.jogamp.common.util.TestLFRingBuffer01 $*
-#onetest com.jogamp.common.util.TestBitstream00 2>&1 | tee -a $LOG
-#onetest com.jogamp.common.util.TestBitstream01 2>&1 | tee -a $LOG
-#onetest com.jogamp.common.util.TestBitstream02 2>&1 | tee -a $LOG
-#onetest com.jogamp.common.util.TestBitstream03 2>&1 | tee -a $LOG
-#onetest com.jogamp.common.util.TestBitstream04 2>&1 | tee -a $LOG
+
+onetest com.jogamp.common.util.TestBitstream00 2>&1 | tee -a $LOG
+onetest com.jogamp.common.util.TestBitstream01 2>&1 | tee -a $LOG
+onetest com.jogamp.common.util.TestBitstream02 2>&1 | tee -a $LOG
+onetest com.jogamp.common.util.TestBitstream03 2>&1 | tee -a $LOG
+onetest com.jogamp.common.util.TestBitstream04 2>&1 | tee -a $LOG
+
#onetest com.jogamp.common.net.TestUrisWithAssetHandler 2>&1 | tee -a $LOG
#onetest com.jogamp.common.net.TestUriQueryProps 2>&1 | tee -a $LOG
#onetest com.jogamp.common.net.TestUri01 2>&1 | tee -a $LOG
@@ -124,7 +126,7 @@ function onetest() {
#onetest com.jogamp.common.nio.TestPointerBufferEndian 2>&1 | tee -a $LOG
#onetest com.jogamp.common.nio.TestStructAccessorEndian 2>&1 | tee -a $LOG
#onetest com.jogamp.common.nio.TestByteBufferInputStream 2>&1 | tee -a $LOG
-onetest com.jogamp.common.nio.TestByteBufferOutputStream 2>&1 | tee -a $LOG
+#onetest com.jogamp.common.nio.TestByteBufferOutputStream 2>&1 | tee -a $LOG
#onetest com.jogamp.common.nio.TestByteBufferCopyStream 2>&1 | tee -a $LOG
#onetest com.jogamp.common.os.TestElfReader01 2>&1 | tee -a $LOG
#onetest com.jogamp.gluegen.PCPPTest 2>&1 | tee -a $LOG
diff --git a/src/java/com/jogamp/common/util/Bitstream.java b/src/java/com/jogamp/common/util/Bitstream.java
index a242faf..e75d820 100644
--- a/src/java/com/jogamp/common/util/Bitstream.java
+++ b/src/java/com/jogamp/common/util/Bitstream.java
@@ -91,6 +91,28 @@ public class Bitstream<T> {
long position();
/**
+ * Sets this stream's position.
+ * <p>
+ * A set mark is cleared if &gt; new position.
+ * </p>
+ * <p>
+ * Returns {@link Bitstream#EOS} is end-of-stream is reached,
+ * otherwise the new position.
+ * </p>
+ * <p>
+ * Known supporting implementation is {@link ByteBufferStream} and {@link ByteArrayStream}.
+ * </p>
+ *
+ * @param newPosition The new positive position.
+ *
+ * @return The new set position or {@link Bitstream#EOS} if end-of-stream is reached.
+ *
+ * @throws UnsupportedOperationException if not supported, i.e. {@link ByteInputStream} or {@link ByteOutputStream}
+ * @throws IllegalArgumentException If the {@code newPosition} is negative
+ */
+ long position(long newPosition) throws UnsupportedOperationException, IllegalArgumentException;
+
+ /**
* It is implementation dependent, whether backward skip giving a negative number is supported or not.
* @param n number of bytes to skip
* @return actual skipped bytes
@@ -99,9 +121,9 @@ public class Bitstream<T> {
long skip(final long n) throws IOException;
/**
- * Set <i>markpos</i> to current position, allowing the stream to be {@link #reset()}.
- * @param readLimit
- * @throws UnsupportedOperationException is not supported, i.e. if stream is not an {@link #canInput() input stream}.
+ * Set {@code markpos} to current position, allowing the stream to be {@link #reset()}.
+ * @param readlimit maximum number of bytes able to read before invalidating the {@code markpos}.
+ * @throws UnsupportedOperationException if not supported, i.e. if stream is not an {@link #canInput() input stream}.
*/
void mark(final int readLimit) throws UnsupportedOperationException;
@@ -110,7 +132,7 @@ public class Bitstream<T> {
* <p>
* <i>markpos</i> is kept, hence {@link #reset()} can be called multiple times.
* </p>
- * @throws UnsupportedOperationException is not supported, i.e. if stream is not an {@link #canInput() input stream}.
+ * @throws UnsupportedOperationException if not supported, i.e. if stream is not an {@link #canInput() input stream}.
* @throws IllegalStateException if <i>markpos</i> has not been set via {@link #mark(int)} or reset operation failed.
* @throws IOException if reset operation failed.
*/
@@ -123,7 +145,7 @@ public class Bitstream<T> {
* otherwise the resulting value.
* </p>
* @throws IOException
- * @throws UnsupportedOperationException is not supported, i.e. if stream is not an {@link #canInput() input stream}.
+ * @throws UnsupportedOperationException if not supported, i.e. if stream is not an {@link #canInput() input stream}.
*/
int read() throws UnsupportedOperationException, IOException;
@@ -134,7 +156,7 @@ public class Bitstream<T> {
* otherwise the written value.
* </p>
* @throws IOException
- * @throws UnsupportedOperationException is not supported, i.e. if stream is not an {@link #canOutput() output stream}.
+ * @throws UnsupportedOperationException if not supported, i.e. if stream is not an {@link #canOutput() output stream}.
*/
int write(final byte val) throws UnsupportedOperationException, IOException;
}
@@ -183,6 +205,18 @@ public class Bitstream<T> {
public long position() { return pos; }
@Override
+ public long position(final long newPosition) throws UnsupportedOperationException, IllegalArgumentException {
+ if( newPosition >= media.length ) {
+ return Bitstream.EOS;
+ }
+ pos = (int)newPosition;
+ if( posMark > pos ) {
+ posMark = -1;
+ }
+ return pos;
+ }
+
+ @Override
public long skip(final long n) {
final long skip;
if( n >= 0 ) {
@@ -220,7 +254,7 @@ public class Bitstream<T> {
}
if( DEBUG ) {
if( EOS != r ) {
- System.err.println("u8["+(pos-1)+"] -> "+toHexBinString(r, 8));
+ System.err.println("u8["+(pos-1)+"] -> "+toHexBinString(true, r, 8));
} else {
System.err.println("u8["+(pos-0)+"] -> EOS");
}
@@ -239,7 +273,7 @@ public class Bitstream<T> {
}
if( DEBUG ) {
if( EOS != r ) {
- System.err.println("u8["+(pos-1)+"] <- "+toHexBinString(r, 8));
+ System.err.println("u8["+(pos-1)+"] <- "+toHexBinString(true, r, 8));
} else {
System.err.println("u8["+(pos-0)+"] <- EOS");
}
@@ -292,6 +326,19 @@ public class Bitstream<T> {
public long position() { return pos; }
@Override
+ public long position(final long newPosition) throws UnsupportedOperationException, IllegalArgumentException {
+ if( newPosition >= media.limit() ) {
+ return Bitstream.EOS;
+ }
+ media.position((int)newPosition);
+ pos = (int)newPosition;
+ if( posMark > pos ) {
+ posMark = -1;
+ }
+ return pos;
+ }
+
+ @Override
public long skip(final long n) {
final long skip;
if( n >= 0 ) {
@@ -330,7 +377,7 @@ public class Bitstream<T> {
}
if( DEBUG ) {
if( EOS != r ) {
- System.err.println("u8["+(pos-1)+"] -> "+toHexBinString(r, 8));
+ System.err.println("u8["+(pos-1)+"] -> "+toHexBinString(true, r, 8));
} else {
System.err.println("u8["+(pos-0)+"] -> EOS");
}
@@ -349,7 +396,7 @@ public class Bitstream<T> {
}
if( DEBUG ) {
if( EOS != r ) {
- System.err.println("u8["+(pos-1)+"] <- "+toHexBinString(r, 8));
+ System.err.println("u8["+(pos-1)+"] <- "+toHexBinString(true, r, 8));
} else {
System.err.println("u8["+(pos-0)+"] <- EOS");
}
@@ -411,6 +458,11 @@ public class Bitstream<T> {
public long position() { return pos; }
@Override
+ public long position(final long newPosition) throws UnsupportedOperationException, IllegalArgumentException {
+ throw new UnsupportedOperationException("N/a for "+getClass().getCanonicalName());
+ }
+
+ @Override
public long skip(final long n) throws IOException {
final long skip = media.skip(n);
pos += skip;
@@ -438,7 +490,7 @@ public class Bitstream<T> {
final int r = media.read();
if(DEBUG) {
if( EOS != r ) {
- System.err.println("u8["+pos+"] -> "+toHexBinString(r, 8));
+ System.err.println("u8["+pos+"] -> "+toHexBinString(true, r, 8));
} else {
System.err.println("u8["+pos+"] -> EOS");
}
@@ -505,6 +557,11 @@ public class Bitstream<T> {
public long position() { return pos; }
@Override
+ public long position(final long newPosition) throws UnsupportedOperationException, IllegalArgumentException {
+ throw new UnsupportedOperationException("N/a for "+getClass().getCanonicalName());
+ }
+
+ @Override
public long skip(final long n) throws IOException {
long i = n;
while(i > 0) {
@@ -539,7 +596,7 @@ public class Bitstream<T> {
final int r = 0xff & val;
media.write(r);
if(DEBUG) {
- System.err.println("u8["+pos+"] <- "+toHexBinString(r, 8));
+ System.err.println("u8["+pos+"] <- "+toHexBinString(true, r, 8));
}
pos++;
return r;
@@ -685,8 +742,8 @@ public class Bitstream<T> {
public final boolean canOutput() { return null != bytes ? bytes.canOutput() : false; }
/**
- * Set <i>markpos</i> to current position, allowing the stream to be {@link #reset()}.
- * @param readLimit
+ * Set {@code markpos} to current position, allowing the stream to be {@link #reset()}.
+ * @param readlimit maximum number of bytes able to read before invalidating the {@code markpos}.
* @throws IllegalStateException if not in input mode or stream closed
*/
public final void mark(final int readLimit) throws IllegalStateException {
@@ -779,46 +836,68 @@ public class Bitstream<T> {
}
/**
+ * Sets this stream's bit position.
+ * <p>
+ * A set mark is cleared.
+ * </p>
+ * <p>
+ * Returns {@link Bitstream#EOS} is end-of-stream is reached,
+ * otherwise the new position.
+ * </p>
+ * <p>
+ * Known supporting implementation is {@link ByteBufferStream} and {@link ByteArrayStream}.
+ * </p>
+ *
+ * @param newPosition The new positive position.
+ *
+ * @return The new set position or {@link Bitstream#EOS} if end-of-stream is reached.
+ *
+ * @throws UnsupportedOperationException if not supported, i.e. {@link ByteInputStream} or {@link ByteOutputStream}
+ * @throws IllegalArgumentException If the {@code newPosition} is negative
+ * @throws IOException if read error occurs or EOS is reached and {@link #setThrowIOExceptionOnEOF(boolean)} is set to true.
+ * @throws IllegalStateException
+ */
+ public final long position(final long newPosition) throws UnsupportedOperationException, IllegalArgumentException, IllegalStateException, IOException {
+ if( 0 > newPosition ) {
+ throw new IllegalArgumentException("new position not positive: "+newPosition);
+ }
+ bytes.position(0); // throws UnsupportedOperationException
+ resetLocal();
+ if( newPosition > skip(newPosition) ) {
+ return EOS;
+ }
+ return newPosition;
+ }
+
+ /**
* @param msbFirst if true incoming stream bit order is MSB to LSB, otherwise LSB to MSB.
* @return the read bit or {@link #EOS} if end-of-stream is reached.
* @throws IOException
* @throws IllegalStateException if not in input mode or stream closed
*/
- public final int readBit(final boolean msbFirst) throws IllegalStateException, IOException {
+ public final int readBit(final boolean msbFirst) throws UnsupportedOperationException, IllegalStateException, IOException {
if( outputMode || null == bytes ) {
throw new IllegalStateException("not in input-mode: "+this);
}
- if( msbFirst ) {
- // MSB
- if ( 0 < bitCount ) {
- bitCount--;
+ if ( 0 < bitCount ) {
+ bitCount--;
+ if( msbFirst ) {
return ( bitBuffer >>> bitCount ) & 0x01;
} else {
- bitBuffer = bytes.read();
- if( EOS == bitBuffer ) {
- if( throwIOExceptionOnEOF ) {
- throw new IOException("EOS "+this);
- }
- return EOS;
- } else {
- bitCount=7;
- return bitBuffer >>> 7;
- }
+ return ( bitBuffer >>> ( 7 - bitCount ) ) & 0x01;
}
} else {
- // LSB
- if ( 0 < bitCount ) {
- bitCount--;
- return ( bitBuffer >>> ( 7 - bitCount ) ) & 0x01;
+ bitBuffer = bytes.read();
+ if( EOS == bitBuffer ) {
+ if( throwIOExceptionOnEOF ) {
+ throw new IOException("EOS "+this);
+ }
+ return EOS;
} else {
- bitBuffer = bytes.read();
- if( EOS == bitBuffer ) {
- if( throwIOExceptionOnEOF ) {
- throw new IOException("EOS "+this);
- }
- return EOS;
+ bitCount=7;
+ if( msbFirst ) {
+ return bitBuffer >>> 7;
} else {
- bitCount=7;
return bitBuffer & 0x01;
}
}
@@ -836,36 +915,25 @@ public class Bitstream<T> {
if( !outputMode || null == bytes ) {
throw new IllegalStateException("not in output-mode: "+this);
}
- if( msbFirst ) {
- // MSB
- if ( 0 < bitCount ) {
- bitCount--;
+ if ( 0 < bitCount ) {
+ bitCount--;
+ if( msbFirst ) {
bitBuffer |= ( 0x01 & bit ) << bitCount;
- if( 0 == bitCount ) {
- final int r = bytes.write((byte)bitBuffer);
- if( throwIOExceptionOnEOF && EOS == r ) {
- throw new IOException("EOS "+this);
- }
- return r;
- }
} else {
- bitCount = 7;
- bitBuffer = ( 0x01 & bit ) << 7;
- }
- } else {
- // LSB
- if ( 0 < bitCount ) {
- bitCount--;
bitBuffer |= ( 0x01 & bit ) << ( 7 - bitCount );
- if( 0 == bitCount ) {
- final int r = bytes.write((byte)bitBuffer);
- if( throwIOExceptionOnEOF && EOS == r ) {
- throw new IOException("EOS "+this);
- }
- return r;
+ }
+ if( 0 == bitCount ) {
+ final int r = bytes.write((byte)bitBuffer);
+ if( throwIOExceptionOnEOF && EOS == r ) {
+ throw new IOException("EOS "+this);
}
+ return r;
+ }
+ } else {
+ bitCount = 7;
+ if( msbFirst ) {
+ bitBuffer = ( 0x01 & bit ) << 7;
} else {
- bitCount = 7;
bitBuffer = 0x01 & bit;
}
}
@@ -877,7 +945,7 @@ public class Bitstream<T> {
*
* @param n number of bits to skip
* @return actual skipped bits
- * @throws IOException
+ * @throws IOException if read error occurs or EOS is reached and {@link #setThrowIOExceptionOnEOF(boolean)} is set to true.
* @throws IllegalStateException if closed
*/
public long skip(final long n) throws IllegalStateException, IOException {
@@ -939,85 +1007,96 @@ public class Bitstream<T> {
return nX - notReadBits;
}
} else {
- // FIXME: Backward skip
+ // Zero skip or backward skip
+ // FIXME: Backward skip n < 0
return 0;
}
}
+ private static final boolean useFastPathStream = true;
+ private static final boolean useFastPathTypes = true;
+
/**
- * Return incoming bits as read via {@link #readBit(boolean)}.
+ * Return incoming bits as read via {@link #readBit(boolean)} LSB-first as little-endian.
* <p>
- * The incoming bits are stored in MSB-first order, i.e. first on highest position and last bit on lowest position.
- * Hence reading w/ <i>lsbFirst</i>, the bit order will be reversed!
+ * The incoming bit order is from low- to most-significant-bit, maintaining bit LSB-first order.
* </p>
- * @param msbFirst if true incoming stream bit order is MSB to LSB, otherwise LSB to MSB.
* @param n number of bits, maximum 31 bits
* @return the read bits from 0-n in the given order or {@link #EOS}.
* @throws IllegalStateException if not in input mode or stream closed
* @throws IllegalArgumentException if n > 31
* @throws IOException
*/
- public int readBits31(final boolean msbFirst, final int n) throws IllegalArgumentException, IOException {
+ public int readBits31(final int n) throws IllegalArgumentException, IOException {
if( 31 < n ) {
throw new IllegalArgumentException("n > 31: "+n);
}
if( outputMode || null == bytes ) {
throw new IllegalStateException("not in input-mode: "+this);
}
- if( !msbFirst || 0 == n ) {
- // Slow path
- int r = 0;
- int c = n;
- while(--c >= 0) {
- final int b = readBit(msbFirst);
- if( EOS == b ) {
- return EOS;
- }
- r |= b << c;
- }
- return r;
+ if( 0 == n ) {
+ return 0;
} else {
- // fast path: MSB
- int c = n;
- final int n1 = Math.min(c, bitCount); // remaining portion
- int r;
- if( 0 < n1 ) {
- final int m1 = ( 1 << n1 ) - 1;
- bitCount -= n1;
- c -= n1;
- r = ( m1 & ( bitBuffer >>> bitCount ) ) << c;
- if( 0 == c ) {
- return r;
+ if( !useFastPathStream ) {
+ // Slow path
+ int r = 0;
+ for(int i=0; i < n; i++) {
+ final int b = readBit(false /* msbFirst */);
+ if( EOS == b ) {
+ if( throwIOExceptionOnEOF ) {
+ throw new IOException("EOS "+this);
+ }
+ return EOS;
+ }
+ r |= b << i;
}
+ return r;
} else {
- r = 0;
- }
- assert( 0 == bitCount );
- do {
- bitBuffer = bytes.read();
- if( EOS == bitBuffer ) {
- if( throwIOExceptionOnEOF ) {
- throw new IOException("EOS "+this);
+ // fast path
+ int c = n;
+ final int n1 = Math.min(n, bitCount); // remaining portion
+ int r;
+ if( 0 < n1 ) {
+ final int m1 = ( 1 << n1 ) - 1;
+ final int s1 = 7 - bitCount + 1; // LSBfirst: right-shift to new bits
+ bitCount -= n1;
+ c -= n1;
+ // MSBfirst: r = ( m1 & ( bitBuffer >>> bitCount ) ) << c;
+ r = ( m1 & ( bitBuffer >>> s1 ) ); // LSBfirst
+ if( 0 == c ) {
+ return r;
}
- return EOS;
+ } else {
+ r = 0;
}
- final int n2 = Math.min(c, 8); // full portion
- final int m2 = ( 1 << n2 ) - 1;
- bitCount = 8 - n2;
- c -= n2;
- r |= ( m2 & ( bitBuffer >>> bitCount ) ) << c;
- } while ( 0 < c );
- return r;
+ assert( 0 == bitCount );
+ int s = n1; // LSBfirst: left shift for additional elements
+ do {
+ bitBuffer = bytes.read();
+ if( EOS == bitBuffer ) {
+ if( throwIOExceptionOnEOF ) {
+ throw new IOException("EOS "+this);
+ }
+ return EOS;
+ }
+ final int n2 = Math.min(c, 8); // full portion
+ final int m2 = ( 1 << n2 ) - 1;
+ bitCount = 8 - n2;
+ c -= n2;
+ // MSBfirst: r |= ( m2 & ( bitBuffer >>> bitCount ) ) << c;
+ r |= ( m2 & bitBuffer ) << s; // LSBfirst on new bits
+ s += n2;
+ } while ( 0 < c );
+ return r;
+ }
}
}
/**
- * Write the given bits via {@link #writeBit(boolean, int)}.
+ * Write the given bits via {@link #writeBit(boolean, int)} LSB-first as little-endian.
* <p>
- * The given bits are scanned from LSB-first order.
- * Hence reading w/ <i>msbFirst</i>, the bit order will be reversed!
+ * The outgoing bit order is from low- to most-significant-bit, maintaining bit LSB-first order.
* </p>
- * @param msbFirst if true incoming stream bit order is MSB to LSB, otherwise LSB to MSB.
* @param n number of bits, maximum 31 bits
* @param bits the bits to write
* @return the written bits or {@link #EOS}.
@@ -1025,76 +1104,81 @@ public class Bitstream<T> {
* @throws IllegalArgumentException if n > 31
* @throws IOException
*/
- public int writeBits31(final boolean msbFirst, final int n, final int bits) throws IllegalStateException, IllegalArgumentException, IOException {
+ public int writeBits31(final int n, final int bits) throws IllegalStateException, IllegalArgumentException, IOException {
if( 31 < n ) {
throw new IllegalArgumentException("n > 31: "+n);
}
if( !outputMode || null == bytes ) {
throw new IllegalStateException("not in output-mode: "+this);
}
- if( !msbFirst || 0 == n ) {
- // Slow path
- int c = n;
- while(--c >= 0) {
- final int b = writeBit(msbFirst, ( bits >>> c ) & 0x1);
- if( EOS == b ) {
- return EOS;
- }
- }
- } else {
- // fast path: MSB
- int c = n;
- final int n1 = Math.min(c, bitCount); // remaining portion
- if( 0 < n1 ) {
- final int m1 = ( 1 << n1 ) - 1;
- bitCount -= n1;
- c -= n1;
- bitBuffer |= ( m1 & ( bits >> c ) ) << bitCount;
- if( 0 == bitCount ) {
- if( EOS == bytes.write((byte)bitBuffer) ) {
- if( throwIOExceptionOnEOF ) {
- throw new IOException("EOS "+this);
- }
+ if( 0 < n ) {
+ if( !useFastPathStream ) {
+ // Slow path
+ for(int i=0; i < n; i++) {
+ final int b = writeBit(false /* msbFirst */, ( bits >>> i ) & 0x1);
+ if( EOS == b ) {
return EOS;
}
}
- if( 0 == c ) {
- return bits;
- }
- }
- assert( 0 == bitCount );
- do {
- final int n2 = Math.min(c, 8); // full portion
- final int m2 = ( 1 << n2 ) - 1;
- bitCount = 8 - n2;
- c -= n2;
- bitBuffer = ( m2 & ( bits >> c ) ) << bitCount;
- if( 0 == bitCount ) {
- if( EOS == bytes.write((byte)bitBuffer) ) {
- if( throwIOExceptionOnEOF ) {
- throw new IOException("EOS "+this);
+ } else {
+ // fast path
+ int c = n;
+ final int n1 = Math.min(n, bitCount); // remaining portion
+ if( 0 < n1 ) {
+ final int m1 = ( 1 << n1 ) - 1;
+ final int s1 = 7 - bitCount + 1; // LSBfirst: left-shift to free bit-pos
+ bitCount -= n1;
+ c -= n1;
+ // MSBfirst: bitBuffer |= ( m1 & ( bits >>> c ) ) << bitCount;
+ bitBuffer |= ( m1 & bits ) << s1 ; // LSBfirst
+ if( 0 == bitCount ) {
+ if( EOS == bytes.write((byte)bitBuffer) ) {
+ if( throwIOExceptionOnEOF ) {
+ throw new IOException("EOS "+this);
+ }
+ return EOS;
}
- return EOS;
+ }
+ if( 0 == c ) {
+ return bits;
}
}
- } while ( 0 < c );
+ assert( 0 == bitCount );
+ int s = n1; // LSBfirst: left shift for additional elements
+ do {
+ final int n2 = Math.min(c, 8); // full portion
+ final int m2 = ( 1 << n2 ) - 1;
+ bitCount = 8 - n2;
+ c -= n2;
+ // MSBfirst: bitBuffer = ( m2 & ( bits >>> c ) ) << bitCount;
+ bitBuffer = ( m2 & ( bits >>> s ) ); // LSBfirst
+ s += n2;
+ if( 0 == bitCount ) {
+ if( EOS == bytes.write((byte)bitBuffer) ) {
+ if( throwIOExceptionOnEOF ) {
+ throw new IOException("EOS "+this);
+ }
+ return EOS;
+ }
+ }
+ } while ( 0 < c );
+ }
}
return bits;
}
/**
- * Return incoming <code>uint8_t</code> as read via {@link #readBits31(boolean, int)}.
+ * Return incoming <code>uint8_t</code> as read via {@link #readBits31(int)}.
* <p>
* In case of a <code>int8_t</code> 2-complement signed value, simply cast the result to <code>byte</code>
* after checking for {@link #EOS}.
* </p>
- * @param msbFirst if true incoming stream bit order is MSB to LSB, otherwise LSB to MSB.
* @return {@link #EOS} or the 8bit unsigned value within the lower bits.
* @throws IllegalStateException if not in input mode or stream closed
* @throws IOException
*/
- public final int readUInt8(final boolean msbFirst) throws IllegalStateException, IOException {
- if( 0 == bitCount && msbFirst ) {
+ public final int readUInt8() throws IllegalStateException, IOException {
+ if( 0 == bitCount && useFastPathTypes ) {
// fast path
if( outputMode || null == bytes ) {
throw new IllegalStateException("not in input-mode: "+this);
@@ -1105,19 +1189,18 @@ public class Bitstream<T> {
}
return r;
} else {
- return readBits31(msbFirst, 8);
+ return readBits31(8);
}
}
/**
- * Write the given 8 bits via {@link #writeBits31(boolean, int, int)}.
- * @param msbFirst if true incoming stream bit order is MSB to LSB, otherwise LSB to MSB.
+ * Write the given 8 bits via {@link #writeBits31(int, int)}.
* @return {@link #EOS} or the written 8bit value.
* @throws IllegalStateException if not in output mode or stream closed
* @throws IOException
*/
- public final int writeInt8(final boolean msbFirst, final byte int8) throws IllegalStateException, IOException {
- if( 0 == bitCount && msbFirst ) {
+ public final int writeInt8(final byte int8) throws IllegalStateException, IOException {
+ if( 0 == bitCount && useFastPathTypes ) {
// fast path
if( !outputMode || null == bytes ) {
throw new IllegalStateException("not in output-mode: "+this);
@@ -1128,25 +1211,24 @@ public class Bitstream<T> {
}
return r;
} else {
- return this.writeBits31(msbFirst, 8, int8);
+ return this.writeBits31(8, int8);
}
}
/**
- * Return incoming <code>uint16_t</code> as read via {@link #readBits31(boolean, int)}
- * and swap bytes if !bigEndian.
+ * Return incoming <code>uint16_t</code> as read via {@link #readBits31(int)} LSB-first as little-endian,
+ * hence bytes are swapped if bigEndian.
* <p>
* In case of a <code>int16_t</code> 2-complement signed value, simply cast the result to <code>short</code>
* after checking for {@link #EOS}.
* </p>
- * @param msbFirst if true incoming stream bit order is MSB to LSB, otherwise LSB to MSB.
- * @param bigEndian if false, swap incoming bytes to little-endian, otherwise leave them as big-endian.
+ * @param bigEndian if true, swap incoming bytes to little-endian, otherwise leave them as little-endian.
* @return {@link #EOS} or the 16bit unsigned value within the lower bits.
* @throws IllegalStateException if not in input mode or stream closed
* @throws IOException
*/
- public final int readUInt16(final boolean msbFirst, final boolean bigEndian) throws IllegalStateException, IOException {
- if( 0 == bitCount && msbFirst ) {
+ public final int readUInt16(final boolean bigEndian) throws IllegalStateException, IOException {
+ if( 0 == bitCount && useFastPathTypes ) {
// fast path
if( outputMode || null == bytes ) {
throw new IllegalStateException("not in input-mode: "+this);
@@ -1164,21 +1246,21 @@ public class Bitstream<T> {
return b2 << 8 | b1;
}
} else {
- final int i16 = readBits31(msbFirst, 16);
+ final int i16 = readBits31(16);
if( EOS == i16 ) {
return EOS;
} else if( bigEndian ) {
- return i16;
- } else {
final int b1 = 0xff & ( i16 >>> 8 );
final int b2 = 0xff & i16;
return b2 << 8 | b1;
+ } else {
+ return i16;
}
}
}
/**
- * Return incoming <code>uint16_t</code> value and swap bytes if !bigEndian.
+ * Return incoming <code>uint16_t</code> value and swap bytes according to bigEndian.
* <p>
* In case of a <code>int16_t</code> 2-complement signed value, simply cast the result to <code>short</code>.
* </p>
@@ -1199,16 +1281,15 @@ public class Bitstream<T> {
}
/**
- * Write the given 16 bits via {@link #writeBits31(boolean, int, int)},
- * while swapping bytes if !bigEndian beforehand.
- * @param msbFirst if true incoming stream bit order is MSB to LSB, otherwise LSB to MSB.
- * @param bigEndian if false, swap given bytes to little-endian, otherwise leave them as big-endian.
+ * Write the given 16 bits via {@link #writeBits31(int, int)} LSB-first as little-endian,
+ * hence bytes are swapped if bigEndian.
+ * @param bigEndian if true, swap given bytes to little-endian, otherwise leave them as little-endian.
* @return {@link #EOS} or the written 16bit value.
* @throws IllegalStateException if not in output mode or stream closed
* @throws IOException
*/
- public final int writeInt16(final boolean msbFirst, final boolean bigEndian, final short int16) throws IllegalStateException, IOException {
- if( 0 == bitCount && msbFirst ) {
+ public final int writeInt16(final boolean bigEndian, final short int16) throws IllegalStateException, IOException {
+ if( 0 == bitCount && useFastPathTypes ) {
// fast path
if( !outputMode || null == bytes ) {
throw new IllegalStateException("not in output-mode: "+this);
@@ -1233,29 +1314,28 @@ public class Bitstream<T> {
}
return EOS;
} else if( bigEndian ) {
- return writeBits31(msbFirst, 16, int16);
- } else {
final int b1 = 0xff & ( int16 >>> 8 );
final int b2 = 0xff & int16;
- return writeBits31(msbFirst, 16, b2 << 8 | b1);
+ return writeBits31(16, b2 << 8 | b1);
+ } else {
+ return writeBits31(16, int16);
}
}
/**
- * Return incoming <code>uint32_t</code> as read via {@link #readBits31(boolean, int)}
- * and swap bytes if !bigEndian.
+ * Return incoming <code>uint32_t</code> as read via {@link #readBits31(int)} LSB-first as little-endian,
+ * hence bytes are swapped if bigEndian.
* <p>
* In case of a <code>int32_t</code> 2-complement signed value, simply cast the result to <code>int</code>
* after checking for {@link #EOS}.
* </p>
- * @param msbFirst if true incoming stream bit order is MSB to LSB, otherwise LSB to MSB.
- * @param bigEndian if false, swap incoming bytes to little-endian, otherwise leave them as big-endian.
+ * @param bigEndian if true, swap incoming bytes to little-endian, otherwise leave them as little-endian.
* @return {@link #EOS} or the 32bit unsigned value within the lower bits.
* @throws IllegalStateException if not in input mode or stream closed
* @throws IOException
*/
- public final long readUInt32(final boolean msbFirst, final boolean bigEndian) throws IllegalStateException, IOException {
- if( 0 == bitCount && msbFirst ) {
+ public final long readUInt32(final boolean bigEndian) throws IllegalStateException, IOException {
+ if( 0 == bitCount && useFastPathTypes ) {
// fast path
if( outputMode || null == bytes ) {
throw new IllegalStateException("not in input-mode: "+this);
@@ -1275,24 +1355,24 @@ public class Bitstream<T> {
return 0xffffffffL & ( b4 << 24 | b3 << 16 | b2 << 8 | b1 );
}
} else {
- final int i16a = readBits31(msbFirst, 16);
- final int i16b = EOS != i16a ? readBits31(msbFirst, 16) : EOS;
+ final int i16a = readBits31(16);
+ final int i16b = EOS != i16a ? readBits31(16) : EOS;
if( EOS == i16b ) {
return EOS;
} else if( bigEndian ) {
- return 0xffffffffL & ( i16a << 16 | i16b );
- } else {
- final int b1 = 0xff & ( i16a >>> 8 );
- final int b2 = 0xff & i16a;
- final int b3 = 0xff & ( i16b >>> 8 );
- final int b4 = 0xff & i16b;
+ final int b1 = 0xff & ( i16b >>> 8 );
+ final int b2 = 0xff & i16b;
+ final int b3 = 0xff & ( i16a >>> 8 );
+ final int b4 = 0xff & i16a;
return 0xffffffffL & ( b4 << 24 | b3 << 16 | b2 << 8 | b1 );
+ } else {
+ return 0xffffffffL & ( i16b << 16 | i16a );
}
}
}
/**
- * Return incoming <code>uint32_t</code> and swap bytes if !bigEndian.
+ * Return incoming <code>uint32_t</code> and swap bytes according to bigEndian.
* <p>
* In case of a <code>int32_t</code> 2-complement signed value, simply cast the result to <code>int</code>.
* </p>
@@ -1314,16 +1394,15 @@ public class Bitstream<T> {
}
/**
- * Write the given 32 bits via {@link #writeBits31(boolean, int, int)},
- * while swapping bytes if !bigEndian beforehand.
- * @param msbFirst if true incoming stream bit order is MSB to LSB, otherwise LSB to MSB.
- * @param bigEndian if false, swap given bytes to little-endian, otherwise leave them as little-endian.
+ * Write the given 32 bits via {@link #writeBits31(int, int)} LSB-first as little-endian,
+ * hence bytes are swapped if bigEndian.
+ * @param bigEndian if true, swap given bytes to little-endian, otherwise leave them as little-endian.
* @return {@link #EOS} or the written 32bit value.
* @throws IllegalStateException if not in output mode or stream closed
* @throws IOException
*/
- public final int writeInt32(final boolean msbFirst, final boolean bigEndian, final int int32) throws IllegalStateException, IOException {
- if( 0 == bitCount && msbFirst ) {
+ public final int writeInt32(final boolean bigEndian, final int int32) throws IllegalStateException, IOException {
+ if( 0 == bitCount && useFastPathTypes ) {
// fast path
if( !outputMode || null == bytes ) {
throw new IllegalStateException("not in output-mode: "+this);
@@ -1358,21 +1437,21 @@ public class Bitstream<T> {
}
return EOS;
} else if( bigEndian ) {
- final int hi = 0x0000ffff & ( int32 >>> 16 );
- final int lo = 0x0000ffff & int32 ;
- if( EOS != writeBits31(msbFirst, 16, hi) ) {
- if( EOS != writeBits31(msbFirst, 16, lo) ) {
+ final int p1 = 0xff & ( int32 >>> 24 );
+ final int p2 = 0xff & ( int32 >>> 16 );
+ final int p3 = 0xff & ( int32 >>> 8 );
+ final int p4 = 0xff & int32 ;
+ if( EOS != writeBits31(16, p2 << 8 | p1) ) {
+ if( EOS != writeBits31(16, p4 << 8 | p3) ) {
return int32;
}
}
return EOS;
} else {
- final int p1 = 0xff & ( int32 >>> 24 );
- final int p2 = 0xff & ( int32 >>> 16 );
- final int p3 = 0xff & ( int32 >>> 8 );
- final int p4 = 0xff & int32 ;
- if( EOS != writeBits31(msbFirst, 16, p4 << 8 | p3) ) {
- if( EOS != writeBits31(msbFirst, 16, p2 << 8 | p1) ) {
+ final int hi = 0x0000ffff & ( int32 >>> 16 );
+ final int lo = 0x0000ffff & int32 ;
+ if( EOS != writeBits31(16, lo) ) {
+ if( EOS != writeBits31(16, hi) ) {
return int32;
}
}
@@ -1429,22 +1508,52 @@ public class Bitstream<T> {
bpos = bytes.position();
}
return String.format("%s, pos %d [byteP %d, bitCnt %d], bitbuf %s",
- mode, position(), bpos, bitCount, toHexBinString(bitBuffer, 8));
+ mode, position(), bpos, bitCount, toHexBinString(true, bitBuffer, 8));
}
private static final String strZeroPadding= "0000000000000000000000000000000000000000000000000000000000000000"; // 64
- public static String toBinString(final int v, final int bitCount) {
+ public static String toBinString(final boolean msbFirst, final int v, final int bitCount) {
if( 0 == bitCount ) {
return "";
}
- final int mask = (int) ( ( 1L << bitCount ) - 1L );
- final String s0 = Integer.toBinaryString( mask & v );
- return strZeroPadding.substring(0, bitCount-s0.length())+s0;
+ if( msbFirst ) {
+ final int mask = (int) ( ( 1L << bitCount ) - 1L );
+ final String s0 = Integer.toBinaryString( mask & v );
+ return strZeroPadding.substring(0, bitCount-s0.length())+s0;
+ } else {
+ final char[] c = new char[32];
+ for(int i=0; i<bitCount; i++) {
+ c[i] = 0 != ( v & ( 1 << i ) ) ? '1' : '0';
+ }
+ final String s0 = new String(c, 0, bitCount);
+ return s0+strZeroPadding.substring(0, bitCount-s0.length());
+ }
}
- public static String toHexBinString(final int v, final int bitCount) {
+ public static String toHexBinString(final boolean msbFirst, final int v, final int bitCount) {
final int nibbles = 0 == bitCount ? 2 : ( bitCount + 3 ) / 4;
- return String.format("[%0"+nibbles+"X, %s]", v, toBinString(v, bitCount));
+ return String.format("[0x%0"+nibbles+"X, msbFirst %b, %s]", v, msbFirst, toBinString(msbFirst, v, bitCount));
+ }
+ public static final String toHexBinString(final boolean msbFirst, final byte[] data, final int offset, final int len) {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("[");
+ for(int i=0; i<len; i++) {
+ final int v = 0xFF & data[offset+i];
+ sb.append(toHexBinString(msbFirst, v, 8)).append(", ");
+ }
+ sb.append("]");
+ return sb.toString();
}
+ public static final String toHexBinString(final boolean msbFirst, final ByteBuffer data, final int offset, final int len) {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("[");
+ for(int i=0; i<len; i++) {
+ final int v = 0xFF & data.get(offset+i);
+ sb.append(toHexBinString(msbFirst, v, 8)).append(", ");
+ }
+ sb.append("]");
+ return sb.toString();
+ }
+
public static void checkBounds(final byte[] sb, final int offset, final int remaining) throws IndexOutOfBoundsException {
if( offset + remaining > sb.length ) {
throw new IndexOutOfBoundsException("Buffer of size "+sb.length+" cannot hold offset "+offset+" + remaining "+remaining);
diff --git a/src/junit/com/jogamp/common/util/TestBitstream00.java b/src/junit/com/jogamp/common/util/TestBitstream00.java
index fa9c75d..920363b 100644
--- a/src/junit/com/jogamp/common/util/TestBitstream00.java
+++ b/src/junit/com/jogamp/common/util/TestBitstream00.java
@@ -129,6 +129,138 @@ public class TestBitstream00 extends SingletonJunitCase {
}
}
+ @Test
+ public void test10ReadWrite_13() throws UnsupportedOperationException, IllegalStateException, IOException {
+ // H->L : 00000011 00000010 00000001 000000110000001000000001
+ // H->L rev: 10000000 01000000 11000000 100000000100000011000000
+ //
+ // L->H : 00000001 00000010 00000011 000000010000001000000011
+ // L->H rev: 11000000 01000000 10000000 110000000100000010000000
+ test10ReadWrite1_31Impl(8, 8, 8, 0x030201, "000000110000001000000001");
+
+ // H->L: 00011 000010 00001 0001100001000001
+ // L->H: 10000 010000 11000 1000001000011000
+ test10ReadWrite1_31Impl(5, 6, 5, 0x1841, "0001100001000001");
+ }
+ void test10ReadWrite1_31Impl(final int c1, final int c2, final int c3, final int v, final String vStrHigh2LowExp)
+ throws UnsupportedOperationException, IllegalStateException, IOException
+ {
+ // final Bitstream<ByteBuffer> source = new Bitstream<ByteBuffer>();
+ final int bitCount = c1+c2+c3;
+ final int byteCount = ( bitCount + 7 ) / 8;
+ final String vStrHigh2Low0 = Bitstream.toBinString(true, v, bitCount);
+ System.err.printf("test10ReadWrite31 bits %d:%d:%d = %d = %d bytes%n",
+ c1, c2, c3, bitCount, byteCount);
+ System.err.printf("test10ReadWrite31 %s%n", Bitstream.toHexBinString(true, v, bitCount));
+ System.err.printf("test10ReadWrite31 %s%n", Bitstream.toHexBinString(false, v, bitCount));
+ Assert.assertEquals(vStrHigh2LowExp, vStrHigh2Low0);
+
+ final ByteBuffer bbRead = ByteBuffer.allocate(byteCount);
+ for(int i=0; i<byteCount; i++) {
+ final int b = ( v >>> 8*i ) & 0xff;
+ bbRead.put(i, (byte) b);
+ System.err.printf("testBytes[%d]: %s%n", i, Bitstream.toHexBinString(true, b, 8));
+ }
+ final Bitstream.ByteBufferStream bbsRead = new Bitstream.ByteBufferStream(bbRead);
+ final Bitstream<ByteBuffer> bsRead = new Bitstream<ByteBuffer>(bbsRead, false /* outputMode */);
+
+ String vStrHigh2Low1C1 = "";
+ String vStrHigh2Low1C2 = "";
+ String vStrHigh2Low1C3 = "";
+ String vStrHigh2Low1 = "";
+ {
+ bsRead.mark(byteCount);
+ System.err.println("readBit (msbFirst false): ");
+ int b;
+ int i=0;
+ String vStrHigh2Low1T = ""; // OK for LSB, MSB segmented
+ while( Bitstream.EOS != ( b = bsRead.readBit(false /* msbFirst */) ) ) {
+ vStrHigh2Low1T = b + vStrHigh2Low1T;
+ if(i < c1) {
+ vStrHigh2Low1C1 = b + vStrHigh2Low1C1;
+ } else if(i < c1+c2) {
+ vStrHigh2Low1C2 = b + vStrHigh2Low1C2;
+ } else {
+ vStrHigh2Low1C3 = b + vStrHigh2Low1C3;
+ }
+ i++;
+ }
+ vStrHigh2Low1 = vStrHigh2Low1C3 + vStrHigh2Low1C2 + vStrHigh2Low1C1;
+ System.err.printf("readBit.1 %s, 0x%s%n", vStrHigh2Low1C1, Integer.toHexString(Integer.valueOf(vStrHigh2Low1C1, 2)));
+ System.err.printf("readBit.2 %s, 0x%s%n", vStrHigh2Low1C2, Integer.toHexString(Integer.valueOf(vStrHigh2Low1C2, 2)));
+ System.err.printf("readBit.3 %s, 0x%s%n", vStrHigh2Low1C3, Integer.toHexString(Integer.valueOf(vStrHigh2Low1C3, 2)));
+ System.err.printf("readBit.T %s, ok %b%n%n", vStrHigh2Low1T, vStrHigh2LowExp.equals(vStrHigh2Low1T));
+ System.err.printf("readBit.X %s, ok %b%n%n", vStrHigh2Low1, vStrHigh2LowExp.equals(vStrHigh2Low1));
+ bsRead.reset();
+ }
+
+ {
+ String vStrHigh2Low3T = ""; // OK for LSB, MSB segmented
+ System.err.println("readBits32: ");
+ final int b = bsRead.readBits31(bitCount);
+ vStrHigh2Low3T = Bitstream.toBinString(true, b, bitCount);
+ System.err.printf("readBits31.T %s, ok %b, %s%n%n", vStrHigh2Low3T, vStrHigh2LowExp.equals(vStrHigh2Low3T), Bitstream.toHexBinString(true, b, bitCount));
+ bsRead.reset();
+ }
+
+ String vStrHigh2Low2 = "";
+ {
+ System.err.println("readBits32: ");
+ final int bC1 = bsRead.readBits31(c1);
+ System.err.printf("readBits31.1 %s%n", Bitstream.toHexBinString(true, bC1, c1));
+ final int bC2 = bsRead.readBits31(c2);
+ System.err.printf("readBits31.2 %s%n", Bitstream.toHexBinString(true, bC2, c2));
+ final int bC3 = bsRead.readBits31(c3);
+ System.err.printf("readBits31.3 %s%n", Bitstream.toHexBinString(true, bC3, c3));
+ final int b = bC3 << (c1+c2) | bC2 << c1 | bC1;
+ vStrHigh2Low2 = Bitstream.toBinString(true, b, bitCount);
+ System.err.printf("readBits31.X %s, ok %b, %s%n%n", vStrHigh2Low2, vStrHigh2LowExp.equals(vStrHigh2Low2), Bitstream.toHexBinString(true, b, bitCount));
+ bsRead.reset();
+ }
+
+ Assert.assertEquals(vStrHigh2LowExp, vStrHigh2Low1);
+ Assert.assertEquals(vStrHigh2LowExp, vStrHigh2Low2);
+
+ boolean ok = true;
+ {
+ final ByteBuffer bbWrite = ByteBuffer.allocate(byteCount);
+ final Bitstream.ByteBufferStream bbsWrite = new Bitstream.ByteBufferStream(bbWrite);
+ final Bitstream<ByteBuffer> bsWrite = new Bitstream<ByteBuffer>(bbsWrite, true /* outputMode */);
+ {
+ int b;
+ while( Bitstream.EOS != ( b = bsRead.readBit(false)) ) {
+ bsWrite.writeBit(false, b);
+ }
+ }
+ bsRead.reset();
+ for(int i=0; i<byteCount; i++) {
+ final int bR = bbWrite.get(i);
+ final int bW = bbWrite.get(i);
+ System.err.printf("readWriteBit [%d]: read %s, write %s, ok %b%n",
+ i, Bitstream.toHexBinString(true, bR, 8), Bitstream.toHexBinString(true, bW, 8), bR==bW);
+ ok = ok && bR==bW;
+ }
+ Assert.assertTrue(ok);
+ }
+ {
+ final ByteBuffer bbWrite = ByteBuffer.allocate(byteCount);
+ final Bitstream.ByteBufferStream bbsWrite = new Bitstream.ByteBufferStream(bbWrite);
+ final Bitstream<ByteBuffer> bsWrite = new Bitstream<ByteBuffer>(bbsWrite, true /* outputMode */);
+ {
+ bsWrite.writeBits31(bitCount, bsRead.readBits31(bitCount));
+ }
+ bsRead.reset();
+ for(int i=0; i<byteCount; i++) {
+ final int bR = bbWrite.get(i);
+ final int bW = bbWrite.get(i);
+ System.err.printf("readWriteBits31[%d]: read %s, write %s, ok %b%n",
+ i, Bitstream.toHexBinString(true, bR, 8), Bitstream.toHexBinString(true, bW, 8), bR==bW);
+ ok = ok && bR==bW;
+ }
+ Assert.assertTrue(ok);
+ }
+ }
+
public static void main(final String args[]) throws IOException {
final String tstname = TestBitstream00.class.getName();
org.junit.runner.JUnitCore.main(tstname);
diff --git a/src/junit/com/jogamp/common/util/TestBitstream01.java b/src/junit/com/jogamp/common/util/TestBitstream01.java
index 99116e6..49931a3 100644
--- a/src/junit/com/jogamp/common/util/TestBitstream01.java
+++ b/src/junit/com/jogamp/common/util/TestBitstream01.java
@@ -48,44 +48,67 @@ import org.junit.runners.MethodSorters;
* <li>{@link Bitstream#mark(int)}</li>
* <li>{@link Bitstream#reset()}</li>
* <li>{@link Bitstream#flush()}</li>
- * <li>{@link Bitstream#readBits31(boolean, int)}</li>
- * <li>{@link Bitstream#writeBits31(boolean, int, int)}</li>
+ * <li>{@link Bitstream#readBits31(int)}</li>
+ * <li>{@link Bitstream#writeBits31(int, int)}</li>
* </ul>
*/
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class TestBitstream01 extends SingletonJunitCase {
- Bitstream<ByteBuffer> getTestStream(final boolean msbFirst, final int preBits, final int skipBits, final int postBits) throws IOException {
- final int byteCount = ( preBits + skipBits + postBits + 7 ) / 8;
+ Bitstream<ByteBuffer> getTestStream(final boolean msbFirstData, final boolean msbFirstWrite,
+ final int preBits, final int skipBits, final int postBits) throws IOException {
+ final int bitCount = preBits+skipBits+postBits;
+ final int byteCount = ( bitCount + 7 ) / 8;
final ByteBuffer bbTest = ByteBuffer.allocate(byteCount);
final Bitstream.ByteBufferStream bbsTest = new Bitstream.ByteBufferStream(bbTest);
final Bitstream<ByteBuffer> bsTest = new Bitstream<ByteBuffer>(bbsTest, true /* outputMode */);
final String sTest0;
- if( msbFirst ) {
+ if( msbFirstData ) {
sTest0 = testStringMSB.substring(0, preBits+skipBits+postBits);
} else {
sTest0 = testStringLSB.substring(0, preBits+skipBits+postBits);
}
- for(int i=0; i<preBits+skipBits+postBits; i++) {
- final int bit = Integer.valueOf(sTest0.substring(i, i+1));
- bsTest.writeBit(msbFirst, bit);
+ if( msbFirstData == msbFirstWrite ) {
+ for(int i=0; i<bitCount; i++) {
+ final int bit = Integer.valueOf(sTest0.substring(i, i+1));
+ bsTest.writeBit(msbFirstWrite, bit);
+ }
+ } else {
+ for(int i=bitCount-1; i >= 0; i--) {
+ final int bit = Integer.valueOf(sTest0.substring(i, i+1));
+ bsTest.writeBit(msbFirstWrite, bit);
+ }
}
+ System.err.printf("TestData: msbFirst[data %b, write %b], bits[pre %d, skip %d, post %d = %d]: <%s>%n",
+ msbFirstData, msbFirstWrite, preBits, skipBits, postBits, bitCount, sTest0);
Assert.assertEquals(preBits+skipBits+postBits, bsTest.position());
bsTest.setStream(bsTest.getSubStream(), false /* outputMode */); // switch to input-mode, implies flush()
+ dumpData("TestData: ", bsTest.getSubStream(), 0, bsTest.getSubStream().limit());
return bsTest;
}
- String getTestStreamResultAsString(final boolean msbFirst, final int preBits, final int skipBits, final int postBits) {
+ String getTestStreamResultAsString(final boolean msbFirstData, final boolean msbFirstAssemble,
+ final int preBits, final int skipBits, final int postBits) {
final String pre, post;
- if( msbFirst ) {
- pre = testStringMSB.substring(0, preBits);
- post = testStringMSB.substring(preBits+skipBits, preBits+skipBits+postBits);
+ if( msbFirstData ) {
+ if( msbFirstAssemble ) {
+ pre = testStringMSB.substring(0, preBits);
+ post = testStringMSB.substring(preBits+skipBits, preBits+skipBits+postBits);
+ } else {
+ pre = testStringMSB.substring(postBits+skipBits, preBits+skipBits+postBits);
+ post = testStringMSB.substring(0, postBits);
+ }
} else {
- pre = testStringLSB.substring(0, preBits);
- post = testStringLSB.substring(preBits+skipBits, preBits+skipBits+postBits);
+ if( msbFirstAssemble ) {
+ pre = testStringLSB.substring(0, preBits);
+ post = testStringLSB.substring(preBits+skipBits, preBits+skipBits+postBits);
+ } else {
+ pre = testStringMSB.substring(postBits+skipBits, preBits+skipBits+postBits);
+ post = testStringMSB.substring(0, postBits);
+ }
}
- final String r = pre + post;
- System.err.println("Test: <"+pre+"> + <"+post+"> = <"+r+">");
+ final String r = msbFirstAssemble ? pre + post : post + pre;
+ System.err.println("ResultExp: <"+pre+"> + <"+post+"> = <"+r+">");
return r;
}
@@ -155,9 +178,8 @@ public class TestBitstream01 extends SingletonJunitCase {
// prepare bitstream
System.err.println("Prepare bitstream");
- final Bitstream<ByteBuffer> bsTest = getTestStream(msbFirst, preBits, skipBits, postBits);
- dumpData("Test", bsTest.getSubStream(), 0, bsTest.getSubStream().limit());
- final String sTest = getTestStreamResultAsString(msbFirst, preBits, skipBits, postBits);
+ final Bitstream<ByteBuffer> bsTest = getTestStream(msbFirst, msbFirst, preBits, skipBits, postBits);
+ final String sTest = getTestStreamResultAsString(msbFirst, true, preBits, skipBits, postBits);
// init copy-bitstream
final int byteCount = ( totalBits + 7 ) / 8;
@@ -219,50 +241,48 @@ public class TestBitstream01 extends SingletonJunitCase {
}
@Test
- public void test03BulkBitsMSBFirst() throws IOException {
- testBulkBitsImpl(true);
- }
- @Test
- public void test04BulkBitsLSBFirst() throws IOException {
- testBulkBitsImpl(false);
- }
- void testBulkBitsImpl(final boolean msbFirst) throws IOException {
- testBulkBitsImpl(msbFirst, 0, 0, 1);
- testBulkBitsImpl(msbFirst, 0, 0, 3);
- testBulkBitsImpl(msbFirst, 0, 0, 8);
- testBulkBitsImpl(msbFirst, 0, 0, 10);
- testBulkBitsImpl(msbFirst, 0, 0, 30);
- testBulkBitsImpl(msbFirst, 0, 0, 31);
-
- testBulkBitsImpl(msbFirst, 3, 0, 3);
- testBulkBitsImpl(msbFirst, 8, 0, 3);
- testBulkBitsImpl(msbFirst, 9, 0, 3);
-
- testBulkBitsImpl(msbFirst, 0, 1, 1);
- testBulkBitsImpl(msbFirst, 0, 1, 3);
- testBulkBitsImpl(msbFirst, 0, 2, 8);
- testBulkBitsImpl(msbFirst, 0, 8, 10);
- testBulkBitsImpl(msbFirst, 0, 12, 20);
- testBulkBitsImpl(msbFirst, 0, 23, 9);
- testBulkBitsImpl(msbFirst, 0, 1, 31);
-
- testBulkBitsImpl(msbFirst, 1, 1, 1);
- testBulkBitsImpl(msbFirst, 2, 1, 3);
- testBulkBitsImpl(msbFirst, 7, 2, 8);
- testBulkBitsImpl(msbFirst, 8, 8, 8);
- testBulkBitsImpl(msbFirst, 15, 12, 5);
- testBulkBitsImpl(msbFirst, 16, 11, 5);
+ public void test03BulkBits() throws IOException {
+ testBulkBitsImpl(0, 0, 1);
+ testBulkBitsImpl(0, 0, 3);
+ testBulkBitsImpl(0, 0, 8);
+ testBulkBitsImpl(0, 0, 10);
+ testBulkBitsImpl(0, 0, 30);
+ testBulkBitsImpl(0, 0, 31);
+
+ testBulkBitsImpl(3, 0, 3);
+ testBulkBitsImpl(8, 0, 3);
+ testBulkBitsImpl(9, 0, 3);
+ testBulkBitsImpl(5, 0, 6);
+ testBulkBitsImpl(5, 0, 8);
+
+ testBulkBitsImpl(0, 1, 1);
+ testBulkBitsImpl(3, 6, 4);
+
+ testBulkBitsImpl(0, 1, 3);
+ testBulkBitsImpl(0, 2, 8);
+ testBulkBitsImpl(0, 8, 10);
+ testBulkBitsImpl(0, 12, 20);
+ testBulkBitsImpl(0, 23, 9);
+ testBulkBitsImpl(0, 1, 31);
+
+ testBulkBitsImpl(1, 1, 1);
+ testBulkBitsImpl(2, 1, 3);
+ testBulkBitsImpl(7, 2, 8);
+ testBulkBitsImpl(8, 8, 8);
+ testBulkBitsImpl(15, 12, 5);
+ testBulkBitsImpl(16, 11, 5);
+ testBulkBitsImpl(5, 6, 5);
+ testBulkBitsImpl(5, 6, 8);
}
- void testBulkBitsImpl(final boolean msbFirst, final int preBits, final int skipBits, final int postBits) throws IOException {
+ void testBulkBitsImpl(final int preBits, final int skipBits, final int postBits) throws IOException {
final int totalBits = preBits+skipBits+postBits;
- System.err.println("XXX TestBulkBits: msbFirst "+msbFirst+", preBits "+preBits+", skipBits "+skipBits+", postBits "+postBits+", totalBits "+totalBits);
+ System.err.println("XXX TestBulkBits: preBits "+preBits+", skipBits "+skipBits+", postBits "+postBits+", totalBits "+totalBits);
// prepare bitstream
System.err.println("Prepare bitstream");
- final Bitstream<ByteBuffer> bsTest = getTestStream(msbFirst, preBits, skipBits, postBits);
- dumpData("Test", bsTest.getSubStream(), 0, bsTest.getSubStream().limit());
- final String sTest = getTestStreamResultAsString(msbFirst, preBits, skipBits, postBits);
+ final Bitstream<ByteBuffer> bsTest = getTestStream(true, false, preBits, skipBits, postBits);
+ final String sTest = getTestStreamResultAsString(true, false, preBits, skipBits, postBits);
// init copy-bitstream
final int byteCount = ( totalBits + 7 ) / 8;
@@ -273,18 +293,18 @@ public class TestBitstream01 extends SingletonJunitCase {
// read-bitstream .. and copy bits while reading
System.err.println("Reading bitstream: "+bsTest);
{
- final int readBitsPre = bsTest.readBits31(msbFirst, preBits);
- Assert.assertEquals(readBitsPre, bsCopy.writeBits31(msbFirst, preBits, readBitsPre));
+ final int readBitsPre = bsTest.readBits31(preBits);
+ Assert.assertEquals(readBitsPre, bsCopy.writeBits31(preBits, readBitsPre));
final int skippedReadBits = (int) bsTest.skip(skipBits);
final int skippedBitsCopy = (int) bsCopy.skip(skipBits);
- final int readBitsPost = bsTest.readBits31(msbFirst, postBits);
- Assert.assertEquals(readBitsPost, bsCopy.writeBits31(msbFirst, postBits, readBitsPost));
- final String sReadPre = toBinaryString(readBitsPre, preBits);
- final String sReadPost = toBinaryString(readBitsPost, postBits);
- final String sRead = sReadPre + sReadPost;
- System.err.println("Read.Test: <"+sReadPre+"> + <"+sReadPost+"> = <"+sRead+">");
+ final int readBitsPost = bsTest.readBits31(postBits);
+ Assert.assertEquals(readBitsPost, bsCopy.writeBits31(postBits, readBitsPost));
+ final String sReadPreLo = toBinaryString(readBitsPre, preBits);
+ final String sReadPostHi = toBinaryString(readBitsPost, postBits);
+ final String sRead = sReadPostHi + sReadPreLo;
+ System.err.println("Read.Test: <"+sReadPreLo+"> + <"+sReadPostHi+"> = <"+sRead+">");
Assert.assertEquals(skipBits, skippedReadBits);
Assert.assertEquals(sTest, sRead);
@@ -298,15 +318,15 @@ public class TestBitstream01 extends SingletonJunitCase {
System.err.println("Reading copy-bitstream: "+bsCopy);
Assert.assertEquals(0, bsCopy.position());
{
- final int copyBitsPre = bsCopy.readBits31(msbFirst, preBits);
+ final int copyBitsPre = bsCopy.readBits31(preBits);
final int skippedCopyBits = (int) bsCopy.skip(skipBits);
- final int copyBitsPost = bsCopy.readBits31(msbFirst, postBits);
- final String sCopyPre = toBinaryString(copyBitsPre, preBits);
- final String sCopyPost = toBinaryString(copyBitsPost, postBits);
- final String sCopy = sCopyPre + sCopyPost;
- System.err.println("Copy.Test: <"+sCopyPre+"> + <"+sCopyPost+"> = <"+sCopy+">");
+ final int copyBitsPost = bsCopy.readBits31(postBits);
+ final String sCopyPreLo = toBinaryString(copyBitsPre, preBits);
+ final String sCopyPostHi = toBinaryString(copyBitsPost, postBits);
+ final String sCopy = sCopyPostHi + sCopyPreLo;
+ System.err.println("Copy.Test: <"+sCopyPreLo+"> + <"+sCopyPostHi+"> = <"+sCopy+">");
Assert.assertEquals(skipBits, skippedCopyBits);
Assert.assertEquals(sTest, sCopy);
@@ -317,7 +337,7 @@ public class TestBitstream01 extends SingletonJunitCase {
@Test
public void test05ErrorHandling() throws IOException {
// prepare bitstream
- final Bitstream<ByteBuffer> bsTest = getTestStream(false, 0, 0, 0);
+ final Bitstream<ByteBuffer> bsTest = getTestStream(false, false, 0, 0, 0);
System.err.println("01a: "+bsTest);
bsTest.close();
System.err.println("01b: "+bsTest);
diff --git a/src/junit/com/jogamp/common/util/TestBitstream02.java b/src/junit/com/jogamp/common/util/TestBitstream02.java
index 3fb4cce..16904a2 100644
--- a/src/junit/com/jogamp/common/util/TestBitstream02.java
+++ b/src/junit/com/jogamp/common/util/TestBitstream02.java
@@ -71,17 +71,17 @@ public class TestBitstream02 extends SingletonJunitCase {
final Bitstream.ByteBufferStream bbs = new Bitstream.ByteBufferStream(bb);
final Bitstream<ByteBuffer> bs = new Bitstream<ByteBuffer>(bbs, false /* outputMode */);
{
- final byte r8 = (byte) bs.readUInt8(true /* msbFirst */);
+ final byte r8 = (byte) bs.readUInt8();
System.err.println("Read8.1 "+r8+", "+toHexBinaryString(r8, 8));
Assert.assertEquals(val8, r8);
}
// Test with written bitstream value
bs.setStream(bs.getSubStream(), true /* outputMode */);
- bs.writeInt8(true /* msbFirst */, val8);
+ bs.writeInt8(val8);
bs.setStream(bs.getSubStream(), false /* outputMode */); // switch to input-mode, implies flush()
{
- final byte r8 = (byte) bs.readUInt8(true /* msbFirst */);
+ final byte r8 = (byte) bs.readUInt8();
System.err.println("Read8.2 "+r8+", "+toHexBinaryString(r8, 8));
Assert.assertEquals(val8, r8);
}
@@ -114,12 +114,12 @@ public class TestBitstream02 extends SingletonJunitCase {
// Test with written bitstream value
final Bitstream.ByteBufferStream bbs = new Bitstream.ByteBufferStream(bb);
final Bitstream<ByteBuffer> bs = new Bitstream<ByteBuffer>(bbs, true /* outputMode */);
- bs.writeBits31(true /* msbFirst */, preBits, 0);
- bs.writeInt8(true /* msbFirst */, val8);
+ bs.writeBits31(preBits, 0);
+ bs.writeInt8(val8);
bs.setStream(bs.getSubStream(), false /* outputMode */); // switch to input-mode, implies flush()
- final int rPre = (short) bs.readBits31(true /* msbFirst */, preBits);
- final byte r8 = (byte) bs.readUInt8(true /* msbFirst */);
+ final int rPre = (short) bs.readBits31(preBits);
+ final byte r8 = (byte) bs.readUInt8();
System.err.println("ReadPre "+rPre+", "+toBinaryString(rPre, preBits));
System.err.println("Read8 "+r8+", "+toHexBinaryString(r8, 8));
Assert.assertEquals(val8, r8);
diff --git a/src/junit/com/jogamp/common/util/TestBitstream03.java b/src/junit/com/jogamp/common/util/TestBitstream03.java
index 4dfb3d7..a6129d8 100644
--- a/src/junit/com/jogamp/common/util/TestBitstream03.java
+++ b/src/junit/com/jogamp/common/util/TestBitstream03.java
@@ -47,8 +47,8 @@ import org.junit.runners.MethodSorters;
* Test {@link Bitstream} w/ int16 read/write access w/ semantics
* as well as with aligned and unaligned access.
* <ul>
- * <li>{@link Bitstream#readUInt16(boolean, boolean)}</li>
- * <li>{@link Bitstream#writeInt16(boolean, boolean, short)}</li>
+ * <li>{@link Bitstream#readUInt16(boolean)}</li>
+ * <li>{@link Bitstream#writeInt16(boolean, short)}</li>
* </ul>
*/
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@@ -78,21 +78,23 @@ public class TestBitstream03 extends SingletonJunitCase {
final boolean bigEndian = ByteOrder.BIG_ENDIAN == bb.order();
System.err.println("XXX Test01Int16BitsAligned: byteOrder "+byteOrder+" (bigEndian "+bigEndian+"), value "+val16+", "+toHexBinaryString(val16, 16));
bb.putShort(0, val16);
+ dumpData("TestData.1: ", bb, 0, 2);
final Bitstream.ByteBufferStream bbs = new Bitstream.ByteBufferStream(bb);
final Bitstream<ByteBuffer> bs = new Bitstream<ByteBuffer>(bbs, false /* outputMode */);
{
- final short r16 = (short) bs.readUInt16(true /* msbFirst */, bigEndian);
+ final short r16 = (short) bs.readUInt16(bigEndian);
System.err.println("Read16.1 "+r16+", "+toHexBinaryString(r16, 16));
Assert.assertEquals(val16, r16);
}
// Test with written bitstream value
bs.setStream(bs.getSubStream(), true /* outputMode */);
- bs.writeInt16(true /* msbFirst */, bigEndian, val16);
+ bs.writeInt16(bigEndian, val16);
bs.setStream(bs.getSubStream(), false /* outputMode */); // switch to input-mode, implies flush()
+ dumpData("TestData.2: ", bb, 0, 2);
{
- final short r16 = (short) bs.readUInt16(true /* msbFirst */, bigEndian);
+ final short r16 = (short) bs.readUInt16(bigEndian);
System.err.println("Read16.2 "+r16+", "+toHexBinaryString(r16, 16));
Assert.assertEquals(val16, r16);
}
@@ -135,12 +137,13 @@ public class TestBitstream03 extends SingletonJunitCase {
// Test with written bitstream value
final Bitstream.ByteBufferStream bbs = new Bitstream.ByteBufferStream(bb);
final Bitstream<ByteBuffer> bs = new Bitstream<ByteBuffer>(bbs, true /* outputMode */);
- bs.writeBits31(true /* msbFirst */, preBits, 0);
- bs.writeInt16(true /* msbFirst */, bigEndian, val16);
+ bs.writeBits31(preBits, 0);
+ bs.writeInt16(bigEndian, val16);
bs.setStream(bs.getSubStream(), false /* outputMode */); // switch to input-mode, implies flush()
+ dumpData("TestData.1: ", bb, 0, byteCount);
- final int rPre = (short) bs.readBits31(true /* msbFirst */, preBits);
- final short r16 = (short) bs.readUInt16(true /* msbFirst */, bigEndian);
+ final int rPre = (short) bs.readBits31(preBits);
+ final short r16 = (short) bs.readUInt16(bigEndian);
System.err.println("ReadPre "+rPre+", "+toBinaryString(rPre, preBits));
System.err.println("Read16 "+r16+", "+toHexBinaryString(r16, 16));
Assert.assertEquals(val16, r16);
diff --git a/src/junit/com/jogamp/common/util/TestBitstream04.java b/src/junit/com/jogamp/common/util/TestBitstream04.java
index 277510e..47be38d 100644
--- a/src/junit/com/jogamp/common/util/TestBitstream04.java
+++ b/src/junit/com/jogamp/common/util/TestBitstream04.java
@@ -47,8 +47,8 @@ import org.junit.runners.MethodSorters;
* Test {@link Bitstream} w/ int32 read/write access w/ semantics
* as well as with aligned and unaligned access.
* <ul>
- * <li>{@link Bitstream#readUInt32(boolean, boolean)}</li>
- * <li>{@link Bitstream#writeInt32(boolean, boolean, int)}</li>
+ * <li>{@link Bitstream#readUInt32(boolean)}</li>
+ * <li>{@link Bitstream#writeInt32(boolean, int)}</li>
* </ul>
*/
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@@ -82,11 +82,12 @@ public class TestBitstream04 extends SingletonJunitCase {
System.err.println("XXX Test01Int32BitsAligned: "+val32+", "+val32_hs);
bb.putInt(0, val32);
+ dumpData("TestData.1: ", bb, 0, 4);
final Bitstream.ByteBufferStream bbs = new Bitstream.ByteBufferStream(bb);
final Bitstream<ByteBuffer> bs = new Bitstream<ByteBuffer>(bbs, false /* outputMode */);
{
- final long uint32_l = bs.readUInt32(true /* msbFirst */, bigEndian);
+ final long uint32_l = bs.readUInt32(bigEndian);
final int int32_l = (int)uint32_l;
final String uint32_l_hs = toHexString(uint32_l);
final int uint32_i = Bitstream.uint32LongToInt(uint32_l);
@@ -99,10 +100,11 @@ public class TestBitstream04 extends SingletonJunitCase {
// Test with written bitstream value
bs.setStream(bs.getSubStream(), true /* outputMode */);
- bs.writeInt32(true /* msbFirst */, bigEndian, val32);
+ bs.writeInt32(bigEndian, val32);
bs.setStream(bs.getSubStream(), false /* outputMode */); // switch to input-mode, implies flush()
+ dumpData("TestData.2: ", bb, 0, 4);
{
- final long uint32_l = bs.readUInt32(true /* msbFirst */, bigEndian);
+ final long uint32_l = bs.readUInt32(bigEndian);
final int int32_l = (int)uint32_l;
final String uint32_l_hs = toHexString(uint32_l);
final int uint32_i = Bitstream.uint32LongToInt(uint32_l);
@@ -154,12 +156,12 @@ public class TestBitstream04 extends SingletonJunitCase {
// Test with written bitstream value
final Bitstream.ByteBufferStream bbs = new Bitstream.ByteBufferStream(bb);
final Bitstream<ByteBuffer> bs = new Bitstream<ByteBuffer>(bbs, true /* outputMode */);
- bs.writeBits31(true /* msbFirst */, preBits, 0);
- bs.writeInt32(true /* msbFirst */, bigEndian, val32);
+ bs.writeBits31(preBits, 0);
+ bs.writeInt32(bigEndian, val32);
bs.setStream(bs.getSubStream(), false /* outputMode */); // switch to input-mode, implies flush()
- final int rPre = bs.readBits31(true /* msbFirst */, preBits);
- final long uint32_l = bs.readUInt32(true /* msbFirst */, bigEndian);
+ final int rPre = bs.readBits31(preBits);
+ final long uint32_l = bs.readUInt32(bigEndian);
final int int32_l = (int)uint32_l;
final String uint32_l_hs = toHexString(uint32_l);
final int uint32_i = Bitstream.uint32LongToInt(uint32_l);