OSDN Git Service

Add new source files
[armadillo/armadillo1.git] / src / jp / sfjp / armadillo / io / BitInputStream.java
1 package jp.sfjp.armadillo.io;
2
3 import java.io.*;
4
5 /**
6  * A bit-by-bit readable InputStream.
7  */
8 public final class BitInputStream extends FilterInputStream {
9
10     private static final int INT_BITSIZE = 32;
11     private static final int INPUT_BITSIZE = 8;
12
13     private boolean closed;
14     private int buffer;
15     private int remaining;
16     private boolean eof;
17
18     public BitInputStream(InputStream is) {
19         super(is);
20         this.closed = false;
21         this.buffer = 0;
22         this.remaining = 0;
23         this.eof = false;
24     }
25
26     private void ensureOpen() throws IOException {
27         if (closed)
28             throw new IOException("stream closed");
29     }
30
31     /**
32      * Reads the bits that specified length.
33      * Reads bits of int from the lower bit,
34      * and writes it into the higher bit of this stream.
35      * @param b int value
36      * @param bitLength bit length to write
37      * @throws IOException
38      * @throws IllegalArgumentException
39      */
40     public int readBits(int bitLength) throws IOException {
41         ensureOpen();
42         if (bitLength < 1 || 32 < bitLength)
43             throw new IllegalArgumentException("bit length: " + bitLength);
44         if (remaining < bitLength) {
45             fillBuffer(bitLength);
46             if (remaining == 0)
47                 return -1;
48             else if (remaining < bitLength)
49                 throw new IOException("requred=" + bitLength + ", remaining=" + remaining);
50         }
51         int value = buffer >>> (INT_BITSIZE - bitLength);
52         remaining -= bitLength;
53         buffer <<= bitLength;
54         return value;
55     }
56
57     /**
58      * Reads a bit.
59      * @return a bit value, or <code>-1</code> if stream has already reached EOF
60      * @throws IOException
61      */
62     public int readBit() throws IOException {
63         return readBits(1);
64     }
65
66     /**
67      * Prefetches bits from InputStream.
68      * @param bitLength bit length to read
69      * @return a value of bits, or <code>-1</code> if stream has already reached EOF
70      * @throws IOException 
71      */
72     public int prefetchBits(int bitLength) throws IOException {
73         ensureOpen();
74         if (bitLength > INT_BITSIZE)
75             throw new IllegalArgumentException("overflow: " + bitLength);
76         if (remaining < bitLength)
77             fillBuffer(bitLength);
78         return buffer >>> (INT_BITSIZE - bitLength);
79     }
80
81     /**
82      * Prefetches bits from InputStream.
83      * @return an octet, or <code>-1</code> if stream has already reached EOF
84      * @throws IOException
85      */
86     public int prefetch() throws IOException {
87         return prefetchBits(INPUT_BITSIZE);
88     }
89
90     /**
91      * Fills the buffer.
92      * When the buffer has already filled enough, it does nothing.
93      * @param requiredSize a bit size to need, not a fill size
94      * @throws IOException
95      */
96     private void fillBuffer(int requiredSize) throws IOException {
97         assert requiredSize >= 1 && requiredSize <= INT_BITSIZE;
98         while (!eof && remaining < requiredSize) {
99             int b = super.read();
100             if (b == -1) {
101                 eof = true;
102                 return;
103             }
104             b <<= (INT_BITSIZE - INPUT_BITSIZE - remaining);
105             assert (buffer | b) == buffer + b;
106             buffer |= b;
107             remaining += INPUT_BITSIZE;
108         }
109     }
110
111     /**
112      * Clears buffer.
113      */
114     public void clearBuffer() {
115         this.buffer = 0;
116         this.remaining = 0;
117     }
118
119     /**
120      * Gets the value of buffer.
121      * @return
122      */
123     public int getBuffer() {
124         return buffer;
125     }
126
127     /**
128      * Gets the number of available bits.
129      * @return
130      */
131     public int getRemaining() {
132         return remaining;
133     }
134
135     /**
136      * Tests whether this stream has already reached EOF or not.
137      * @return <code>true</code> if this stream has already reached EOF, otherwise <code>false</code>
138      */
139     public boolean isEOF() {
140         return eof;
141     }
142
143     @Override
144     public int read() throws IOException {
145         return readBits(8);
146     }
147
148     @Override
149     public void close() throws IOException {
150         ensureOpen();
151         closed = true;
152         super.close();
153     }
154
155 }