📄 inputbitstream.java
字号:
} /** Feeds 16 more bits into {@link #current}, assuming that {@link #fill} is less than 16. * * <p>This method will never throw an {@link EOFException}—simply, it will refill less than 16 bits. * * @return {@link #fill}. */ private final int refill() throws IOException { if ( ASSERTS ) assert fill < 16; if ( avail > 1 ) { // If there is a byte in the buffer, we use it directly. avail -= 2; current = current << 16 | ( buffer[ pos++ ] & 0xFF ) << 8 | buffer[ pos++ ] & 0xFF; return fill += 16; } try{ current = ( current << 8 ) | read(); fill += 8; current = ( current << 8 ) | read(); fill += 8; } catch( EOFException dontCare ) {} return fill; } /** Reads bits from the bit buffer, possibly refilling it. * * <P>This method is the basic mean for extracting bits from the underlying stream. * * <P>You cannot read more than {@link #fill} bits with this method (unless {@link #fill} is 0, * and <code>len</code> is nonzero, in which case the buffer will be refilled for you with 8 bits), and if you * read exactly {@link #fill} bits the buffer will be empty afterwards. In particular, * there will never be 8 bits in the buffer. * * <P>The bit buffer stores its content in the lower {@link #fill} bits. The content * of the remaining bits is undefined. * * <P>This method updates {@link #readBits}. * * @param len the number of bits to read. * @return the bits read (in the <strong>lower</strong> positions). * @throws AssertionError if one tries to read more bits than available in the buffer and assertions are enabled. */ private final int readFromCurrent( final int len ) throws IOException { if ( len == 0 ) return 0; if ( fill == 0 ) { current = read(); fill = 8; } if ( ASSERTS ) assert len <= fill : len + " bit(s) requested, " + fill + " available"; readBits += len; return current >>> ( fill -= len ) & ( 1 << len ) - 1; } /** Aligns the stream. * * After a call to this function, the stream is byte aligned. Bits that have been * read to align are discarded. */ public void align() { if ( ( fill & 7 ) == 0 ) return; readBits += fill & 7; fill &= ~7; } /** Reads a sequence of bits. * * Bits will be read in the natural way: the first bit is bit 7 of the * first byte, the eightth bit is bit 0 of the first byte, the ninth bit is * bit 7 of the second byte and so on. * * @param bits an array of bytes to store the result. * @param len the number of bits to read. */ public void read( final byte[] bits, int len ) throws IOException { if ( ASSERTS ) assert fill < 32 : fill + " >= " + 32; if ( len <= fill ) { if ( len <= 8 ) { bits[ 0 ] = (byte)( readFromCurrent( len ) << 8 - len ); return; } else if ( len <= 16 ){ bits[ 0 ] = (byte)( readFromCurrent( 8 ) ); bits[ 1 ] = (byte)( readFromCurrent( len - 8 ) << 16 - len ); return; } else if ( len <= 24 ) { bits[ 0 ] = (byte)( readFromCurrent( 8 ) ); bits[ 1 ] = (byte)( readFromCurrent( 8 ) ); bits[ 2 ] = (byte)( readFromCurrent( len - 16 ) << 24 - len ); return; } else { bits[ 0 ] = (byte)( readFromCurrent( 8 ) ); bits[ 1 ] = (byte)( readFromCurrent( 8 ) ); bits[ 2 ] = (byte)( readFromCurrent( 8 ) ); bits[ 3 ] = (byte)( readFromCurrent( len - 24 ) << 32 - len ); return; } } else { int i, j = 0, b; if ( fill >= 24 ) { bits[ j++ ] = (byte)( readFromCurrent( 8 ) ); bits[ j++ ] = (byte)( readFromCurrent( 8 ) ); bits[ j++ ] = (byte)( readFromCurrent( 8 ) ); len -= 24; } else if ( fill >= 16 ) { bits[ j++ ] = (byte)( readFromCurrent( 8 ) ); bits[ j++ ] = (byte)( readFromCurrent( 8 ) ); len -= 16; } else if ( fill >= 8 ) { bits[ j++ ] = (byte)( readFromCurrent( 8 ) ); len -= 8; } final int shift = fill; if ( shift != 0 ) { bits[ j ] = (byte)( readFromCurrent( shift ) << 8 - shift ); len -= shift; i = len >> 3; while( i-- != 0 ) { b = read(); bits[ j ] |= ( b & 0xFF ) >>> shift; bits[ ++j ] = (byte)( b << 8 - shift ); } } else { i = len >> 3; while( i-- != 0 ) bits[ j++ ] = (byte)read(); } readBits += len & ~7; len &= 7; if ( len != 0 ) { if ( shift == 0 ) bits[ j ] = 0; // We must zero the next byte before OR'ing stuff in if ( len <= 8 - shift ) { bits[ j ] |= (byte)( readFromCurrent( len ) << 8 - shift - len ); } else { bits[ j ] |= (byte)( readFromCurrent( 8 - shift ) ); bits[ j + 1 ] = (byte)( readFromCurrent( len + shift - 8 ) << 16 - shift - len ); } } } } /** Reads a bit. * * @return the next bit from the stream. */ public int readBit() throws IOException { return readFromCurrent( 1 ); } /** Reads a fixed number of bits into an integer. * * @param len a bit length. * @return an integer whose lower <code>len</code> bits are taken from the stream; the rest is zeroed. */ public int readInt( int len ) throws IOException { int i, x = 0; if ( len < 0 || len > 32 ) throw new IllegalArgumentException( "You cannot read " + len + " bits into an integer." ); if ( fill < 16 ) refill(); if ( len <= fill ) return readFromCurrent( len ); len -= fill; x = readFromCurrent( fill ); i = len >> 3; while( i-- != 0 ) x = x << 8 | read(); readBits += len & ~7; len &= 7; return ( x << len ) | readFromCurrent( len ); } /** Reads a fixed number of bits into a long. * * @param len a bit length. * @return a long whose lower <code>len</code> bits are taken from the stream; the rest is zeroed. */ public long readLong( int len ) throws IOException { int i; long x = 0; if ( len < 0 || len > 64 ) throw new IllegalArgumentException( "You cannot read " + len + " bits into a long." ); if ( fill < 16 ) refill(); if ( len <= fill ) return readFromCurrent( len ); len -= fill; x = readFromCurrent( fill ); i = len >> 3; while( i-- != 0 ) x = x << 8 | read(); readBits += len & ~7; len &= 7; return ( x << len ) | readFromCurrent( len ); } /** Skips the given number of bits. * * @param n the number of bits to skip. * @return the actual number of skipped bits. */ public long skip( long n ) throws IOException { if ( n <= fill ) { if ( n < 0 ) throw new IllegalArgumentException( "Negative bit skip value: " + n ); fill -= n; readBits += n; return n; } else { final long prevReadBits = readBits; n -= fill; readBits += fill; fill = 0; long nb = n >> 3; // TODO: A real evaluation of the usefulness of this block of code if ( buffer != null && nb > avail && nb < avail + buffer.length ) { /* If we can skip by simply filling the buffer and skipping some bytes, we do it. Usually the next block has already been fetched by a read-ahead logic. */ readBits += ( avail + 1 ) << 3; n -= ( avail + 1 ) << 3; nb -= avail + 1; position += pos + avail; pos = avail = 0; read(); } if ( nb <= avail ) { // We skip bytes directly inside the buffer. pos += (int)nb; avail -= (int)nb; readBits += n & ~7; } else { // No way, we have to pass the byte skip to the underlying stream. n -= avail << 3; readBits += avail << 3; final long toSkip = nb - avail; // ALERT: the semantics of skip is flawed--this should be somehow fixed. final long skipped = is.skip( toSkip ); if ( skipped < toSkip ) throw new IOException( "skip() has skipped " + skipped + " instead of " + toSkip + " bytes" ); position += ( avail + pos ) + skipped; pos = 0; avail = 0; readBits += skipped << 3; if ( skipped != toSkip ) return readBits - prevReadBits; } final int residual = (int)( n & 7 ); if ( residual != 0 ) { current = read(); fill = 8 - residual; readBits += residual; } return readBits - prevReadBits; } } /** Sets this stream bit position, if it is based on a {@link RepositionableStream} or on a {@link java.nio.channels.FileChannel}. * * <P>Given an underlying stream that implements {@link * RepositionableStream} or that can provide a {@link * java.nio.channels.FileChannel} via the <code>getChannel()</code> method, * a call to this method has the same semantics of a {@link #flush()}, * followed by a call to {@link * java.nio.channels.FileChannel#position(long) position(position / 8)} on * the byte stream, followed by a {@link #skip(long) skip(position % 8)}. * * @param position the new position expressed as a bit offset. * @throws UnsupportedOperationException if the underlying byte stream does not implement * {@link RepositionableStream} and if the channel it returns is not a {@link java.nio.channels.FileChannel}. * @see FileChannel#position(long) */ public void position( final long position ) throws IOException { if ( position < 0 ) throw new IllegalArgumentException( "Illegal position: " + position ); /*if ( wrapping ) { final long bitDelta = ( pos << 3 ) - position; if ( bitDelta >= 0 && bitDelta <= fill ) { //System.err.println( "Bit positioning... position: " + position + " this.position: " + this.position + " pos: " + pos + " bitDelta: " + bitDelta + " fill: " + fill ); fill = (int)bitDelta; //System.err.println( "Post: " + position + " fill: " + fill ); return; } pos = (int)( position >> 3 ); avail = buffer.length - pos; fill = 0; final int residual = (int)( position & 7 ); if ( residual != 0 ) { current = read(); fill = 8 - residual; } return; }*/ final long bitDelta = ( ( this.position + pos ) << 3 ) - position; if ( bitDelta >= 0 && bitDelta <= fill ) { //System.err.println( "Bit positioning... position: " + position + " this.position: " + this.position + " pos: " + pos + " bitDelta: " + bitDelta + " fill: " + fill ); fill = (int)bitDelta; //System.err.println( "Post: " + position + " fill: " + fill ); return; } final long delta = ( position >> 3 ) - ( this.position + pos ); if ( DEBUG ) System.err.println( this + ".position(" + position + "); curr: " + this.position + " delta: " + delta + " pos: " + pos + " avail: " + avail ); // TODO: check for delta < number of bits in current if ( delta <= avail && delta >= - pos ) { // We can reposition just by moving into the buffer. avail -= delta; pos += delta; fill = 0; if ( DEBUG ) System.err.println( this + ": moved internally; pos: " + pos + " avail: " + avail ); } else if ( repositionableStream != null ) { flush(); repositionableStream.position( this.position = position >> 3 ); } else if ( fileChannel != null ) { flush(); fileChannel.position( this.position = position >> 3 );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -