View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   * http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.commons.compress.utils;
20  
21  import static org.junit.jupiter.api.Assertions.assertEquals;
22  import static org.junit.jupiter.api.Assertions.assertThrows;
23  
24  import java.io.ByteArrayInputStream;
25  import java.io.IOException;
26  import java.nio.ByteOrder;
27  
28  import org.junit.jupiter.api.Test;
29  
30  public class BitInputStreamTest {
31  
32      private ByteArrayInputStream getStream() {
33          return new ByteArrayInputStream(new byte[] { (byte) 0xF8, // 11111000
34                  0x40, // 01000000
35                  0x01, // 00000001
36                  0x2F }); // 00101111
37      }
38  
39      @Test
40      public void testAlignWithByteBoundaryWhenAtBoundary() throws Exception {
41          try (BitInputStream bis = new BitInputStream(getStream(), ByteOrder.LITTLE_ENDIAN)) {
42              assertEquals(0xF8, bis.readBits(8));
43              bis.alignWithByteBoundary();
44              assertEquals(0, bis.readBits(4));
45          }
46      }
47  
48      @Test
49      public void testAlignWithByteBoundaryWhenNotAtBoundary() throws Exception {
50          try (BitInputStream bis = new BitInputStream(getStream(), ByteOrder.LITTLE_ENDIAN)) {
51              assertEquals(0x08, bis.readBits(4));
52              assertEquals(4, bis.bitsCached());
53              bis.alignWithByteBoundary();
54              assertEquals(0, bis.bitsCached());
55              assertEquals(0, bis.readBits(4));
56          }
57      }
58  
59      @Test
60      public void testAvailableWithCache() throws Exception {
61          try (BitInputStream bis = new BitInputStream(getStream(), ByteOrder.LITTLE_ENDIAN)) {
62              assertEquals(0x08, bis.readBits(4));
63              assertEquals(28, bis.bitsAvailable());
64          }
65      }
66  
67      @Test
68      public void testAvailableWithoutCache() throws Exception {
69          try (BitInputStream bis = new BitInputStream(getStream(), ByteOrder.LITTLE_ENDIAN)) {
70              assertEquals(32, bis.bitsAvailable());
71          }
72      }
73  
74      @Test
75      public void testBigEndianWithOverflow() throws Exception {
76          final ByteArrayInputStream in = new ByteArrayInputStream(new byte[] { 87, // 01010111
77                  45, // 00101101
78                  66, // 01000010
79                  15, // 00001111
80                  90, // 01011010
81                  29, // 00011101
82                  88, // 01011000
83                  61, // 00111101
84                  33, // 00100001
85                  74 // 01001010
86          });
87          try (BitInputStream bin = new BitInputStream(in, ByteOrder.BIG_ENDIAN)) {
88              assertEquals(10, // 01010
89                      bin.readBits(5));
90              assertEquals(8274274654740644818L, // 111-00101101-01000010-00001111-01011010-00011101-01011000-00111101-0010
91                      bin.readBits(63));
92              assertEquals(330, // 0001-01001010
93                      bin.readBits(12));
94              assertEquals(-1, bin.readBits(1));
95          }
96      }
97  
98      @Test
99      public void testClearBitCache() throws IOException {
100         try (BitInputStream bis = new BitInputStream(getStream(), ByteOrder.LITTLE_ENDIAN)) {
101             assertEquals(0x08, bis.readBits(4));
102             bis.clearBitCache();
103             assertEquals(0, bis.readBits(1));
104         }
105     }
106 
107     @Test
108     public void testEOF() throws IOException {
109         try (BitInputStream bis = new BitInputStream(getStream(), ByteOrder.LITTLE_ENDIAN)) {
110             assertEquals(0x2f0140f8, bis.readBits(30));
111             assertEquals(-1, bis.readBits(3));
112         }
113     }
114 
115     /**
116      * @see "https://issues.apache.org/jira/browse/COMPRESS-363"
117      */
118     @Test
119     public void testLittleEndianWithOverflow() throws Exception {
120         final ByteArrayInputStream in = new ByteArrayInputStream(new byte[] { 87, // 01010111
121                 45, // 00101101
122                 66, // 01000010
123                 15, // 00001111
124                 90, // 01011010
125                 29, // 00011101
126                 88, // 01011000
127                 61, // 00111101
128                 33, // 00100001
129                 74 // 01001010
130         });
131         try (BitInputStream bin = new BitInputStream(in, ByteOrder.LITTLE_ENDIAN)) {
132             assertEquals(23, // 10111
133                     bin.readBits(5));
134             assertEquals(714595605644185962L, // 0001-00111101-01011000-00011101-01011010-00001111-01000010-00101101-010
135                     bin.readBits(63));
136             assertEquals(1186, // 01001010-0010
137                     bin.readBits(12));
138             assertEquals(-1, bin.readBits(1));
139         }
140     }
141 
142     @Test
143     public void testReading17BitsInBigEndian() throws IOException {
144         try (BitInputStream bis = new BitInputStream(getStream(), ByteOrder.BIG_ENDIAN)) {
145             // 1-11110000-10000000
146             assertEquals(0x0001f080, bis.readBits(17));
147         }
148     }
149 
150     @Test
151     public void testReading17BitsInLittleEndian() throws IOException {
152         try (BitInputStream bis = new BitInputStream(getStream(), ByteOrder.LITTLE_ENDIAN)) {
153             assertEquals(0x000140f8, bis.readBits(17));
154         }
155     }
156 
157     @Test
158     public void testReading24BitsInBigEndian() throws IOException {
159         try (BitInputStream bis = new BitInputStream(getStream(), ByteOrder.BIG_ENDIAN)) {
160             assertEquals(0x00f84001, bis.readBits(24));
161         }
162     }
163 
164     @Test
165     public void testReading24BitsInLittleEndian() throws IOException {
166         try (BitInputStream bis = new BitInputStream(getStream(), ByteOrder.LITTLE_ENDIAN)) {
167             assertEquals(0x000140f8, bis.readBits(24));
168         }
169     }
170 
171     @Test
172     public void testReading30BitsInBigEndian() throws IOException {
173         try (BitInputStream bis = new BitInputStream(getStream(), ByteOrder.BIG_ENDIAN)) {
174             // 111110-00010000-00000000-01001011
175             assertEquals(0x3e10004b, bis.readBits(30));
176         }
177     }
178 
179     @Test
180     public void testReading30BitsInLittleEndian() throws IOException {
181         try (BitInputStream bis = new BitInputStream(getStream(), ByteOrder.LITTLE_ENDIAN)) {
182             assertEquals(0x2f0140f8, bis.readBits(30));
183         }
184     }
185 
186     @Test
187     public void testReading31BitsInBigEndian() throws IOException {
188         try (BitInputStream bis = new BitInputStream(getStream(), ByteOrder.BIG_ENDIAN)) {
189             // 1111100-00100000-00000000-10010111
190             assertEquals(0x7c200097, bis.readBits(31));
191         }
192     }
193 
194     @Test
195     public void testReading31BitsInLittleEndian() throws IOException {
196         try (BitInputStream bis = new BitInputStream(getStream(), ByteOrder.LITTLE_ENDIAN)) {
197             assertEquals(0x2f0140f8, bis.readBits(31));
198         }
199     }
200 
201     @Test
202     public void testShouldNotAllowReadingOfANegativeAmountOfBits() throws IOException {
203         try (BitInputStream bis = new BitInputStream(getStream(), ByteOrder.LITTLE_ENDIAN)) {
204             assertThrows(IOException.class, () -> bis.readBits(-1));
205         }
206     }
207 
208     @Test
209     public void testShouldNotAllowReadingOfMoreThan63BitsAtATime() throws IOException {
210         try (BitInputStream bis = new BitInputStream(getStream(), ByteOrder.LITTLE_ENDIAN)) {
211             assertThrows(IOException.class, () -> bis.readBits(64));
212         }
213     }
214 
215 }