View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.imaging.mylzw;
18  
19  import java.io.FilterOutputStream;
20  import java.io.IOException;
21  import java.io.OutputStream;
22  import java.nio.ByteOrder;
23  
24  final class MyBitOutputStream extends FilterOutputStream {
25  
26      private final ByteOrder byteOrder;
27      private int bitsInCache;
28      private int bitCache;
29      private int bytesWritten;
30  
31      MyBitOutputStream(final OutputStream os, final ByteOrder byteOrder) {
32          super(os);
33          this.byteOrder = byteOrder;
34      }
35  
36      private void actualWrite(final int value) throws IOException {
37          out.write(value);
38          bytesWritten++;
39      }
40  
41      public void flushCache() throws IOException {
42          if (bitsInCache > 0) {
43              final int bitMask = (1 << bitsInCache) - 1;
44              int b = bitMask & bitCache;
45  
46              if (byteOrder == ByteOrder.BIG_ENDIAN) {
47                  // MSB, so write from left
48                  b <<= 8 - bitsInCache; // left align fragment.
49              }
50              out.write(b);
51          }
52  
53          bitsInCache = 0;
54          bitCache = 0;
55      }
56  
57      public int getBytesWritten() {
58          return bytesWritten + (bitsInCache > 0 ? 1 : 0);
59      }
60  
61      @Override
62      public void write(final int value) throws IOException {
63          writeBits(value, 8);
64      }
65  
66      // TODO: in and out streams CANNOT accurately read/write 32bits at a time,
67      // as int will overflow. should have used a long
68      public void writeBits(int value, final int sampleBits) throws IOException {
69          final int sampleMask = (1 << sampleBits) - 1;
70          value &= sampleMask;
71  
72          if (byteOrder == ByteOrder.BIG_ENDIAN) {
73              // MSB, so add to right
74              bitCache = bitCache << sampleBits | value;
75          } else {
76              // LSB, so add to left
77              bitCache |= value << bitsInCache;
78          }
79          bitsInCache += sampleBits;
80  
81          while (bitsInCache >= 8) {
82              if (byteOrder == ByteOrder.BIG_ENDIAN) {
83                  // MSB, so write from left
84                  final int b = 0xff & bitCache >> bitsInCache - 8;
85                  actualWrite(b);
86              } else {
87                  // LSB, so write from right
88                  final int b = 0xff & bitCache;
89                  actualWrite(b);
90  
91                  bitCache >>= 8;
92              }
93              bitsInCache -= 8;
94              final int remainderMask = (1 << bitsInCache) - 1; // unnecessary
95              bitCache &= remainderMask; // unnecessary
96          }
97  
98      }
99  
100 }