OSDN Git Service

Add new source files
[armadillo/armadillo1.git] / src / jp / sfjp / armadillo / io / BitOutputStream.java
1 package jp.sfjp.armadillo.io;
2
3 import java.io.*;
4
5 /**
6  * A bit-by-bit writable OutputStream.
7  */
8 public final class BitOutputStream extends FilterOutputStream {
9
10     private static final int INT_BITSIZE = 32;
11     private static final int OUTPUT_BITSIZE = 8;
12
13     private boolean closed;
14     private int buffer;
15     private int buffered;
16
17     public BitOutputStream(OutputStream out) {
18         super(out);
19         this.closed = false;
20     }
21
22     private void ensureOpen() throws IOException {
23         if (closed)
24             throw new IOException("stream closed");
25     }
26
27     /**
28      * Writes the specified int bit by bit.
29      * Reads bits of int from the lowest bit,
30      * and writes it into the highest bits of this stream.
31      * @param b int value
32      * @param bitLength bit length to write
33      * @throws IOException
34      * @throws IllegalArgumentException
35      */
36     public void writeBits(int b, int bitLength) throws IOException {
37         ensureOpen();
38         if (1 <= bitLength && bitLength <= 16) {
39             if (buffered + bitLength >= INT_BITSIZE)
40                 flushBuffer();
41             int value = b << (INT_BITSIZE - bitLength);
42             value >>>= buffered;
43             buffer |= value;
44             buffered += bitLength;
45         }
46         else if (17 <= bitLength && bitLength <= 32) {
47             writeBits(b >>> 16, bitLength - 16);
48             writeBits(b, 16);
49         }
50         else
51             throw new IllegalArgumentException("value=" + b + ", bit length=" + bitLength);
52     }
53
54     @Override
55     public void write(int b) throws IOException {
56         ensureOpen();
57         writeBits((byte)b, 8);
58     }
59
60     @Override
61     public void write(byte[] b, int off, int len) throws IOException {
62         ensureOpen();
63         for (int i = off; i < off + len; i++)
64             writeBits(b[i], 8);
65     }
66
67     @Override
68     public void flush() throws IOException {
69         ensureOpen();
70         flushBuffer();
71         super.flush();
72     }
73
74     private void flushBuffer() throws IOException {
75         while (buffered >= OUTPUT_BITSIZE) {
76             int value = buffer >>> (INT_BITSIZE - OUTPUT_BITSIZE);
77             super.write(value);
78             buffer <<= OUTPUT_BITSIZE;
79             buffered -= OUTPUT_BITSIZE;
80         }
81     }
82
83     @Override
84     public void close() throws IOException {
85         ensureOpen();
86         try {
87             if (buffered > 0)
88                 buffered += OUTPUT_BITSIZE - 1;
89             flush();
90         }
91         finally {
92             buffer = 0;
93             buffered = 0;
94             closed = true;
95             super.close();
96         }
97     }
98
99 }