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.formats.tiff.itu_t4;
18  
19  import java.io.OutputStream;
20  import java.util.Arrays;
21  
22  import org.apache.commons.imaging.common.Allocator;
23  
24  /**
25   * Output stream writing to a byte array, and capable of writing 1 bit at a time, starting from the most significant bit.
26   */
27  final class BitArrayOutputStream extends OutputStream {
28      private byte[] buffer;
29      private int bytesWritten;
30      private int cache;
31      private int cacheMask = 0x80;
32  
33      BitArrayOutputStream() {
34          buffer = new byte[16];
35      }
36  
37      BitArrayOutputStream(final int size) {
38          buffer = Allocator.byteArray(size);
39      }
40  
41      @Override
42      public void close() {
43          flush();
44      }
45  
46      @Override
47      public void flush() {
48          if (cacheMask != 0x80) {
49              writeByte(cache);
50              cache = 0;
51              cacheMask = 0x80;
52          }
53      }
54  
55      public int getBitsAvailableInCurrentByte() {
56          int count = 0;
57          for (int mask = cacheMask; mask != 0; mask >>>= 1) {
58              ++count;
59          }
60          return count;
61      }
62  
63      public int size() {
64          return bytesWritten;
65      }
66  
67      public byte[] toByteArray() {
68          flush();
69          if (bytesWritten == buffer.length) {
70              return buffer;
71          }
72          return Arrays.copyOf(buffer, bytesWritten);
73      }
74  
75      @Override
76      public void write(final int b) {
77          flush();
78          writeByte(b);
79      }
80  
81      public void writeBit(final int bit) {
82          if (bit != 0) {
83              cache |= cacheMask;
84          }
85          cacheMask >>>= 1;
86          if (cacheMask == 0) {
87              flush();
88          }
89      }
90  
91      private void writeByte(final int b) {
92          if (bytesWritten >= buffer.length) {
93              final byte[] bigger = Allocator.byteArray(buffer.length * 2);
94              System.arraycopy(buffer, 0, bigger, 0, bytesWritten);
95              buffer = bigger;
96          }
97          buffer[bytesWritten++] = (byte) b;
98      }
99  }