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.compress.compressors.deflate64;
18  
19  import static org.junit.jupiter.api.Assertions.assertEquals;
20  import static org.junit.jupiter.api.Assertions.assertThrows;
21  import static org.junit.jupiter.api.Assertions.fail;
22  
23  import java.io.ByteArrayInputStream;
24  import java.util.Arrays;
25  
26  import org.junit.jupiter.api.Test;
27  
28  public class HuffmanDecoderTest {
29      @Test
30      public void testDecodeFixedHuffmanBlockWithMemoryLookup() throws Exception {
31          final byte[] data = {
32                  // |--- binary filling ---|76543210
33                  0b11111111111111111111111111110011, // final block + fixed huffman + H
34                  0b00000000000000000000000001001000, // H + e
35                  0b11111111111111111111111111001101, // e + l
36                  0b11111111111111111111111111001001, // l + l
37                  0b11111111111111111111111111001001, // l + o
38                  0b00000000000000000000000001010111, // o + ' '
39                  0b00000000000000000000000000001000, // ' ' + W
40                  0b11111111111111111111111111001111, // W + o
41                  0b00000000000000000000000000101111, // o + r
42                  0b11111111111111111111111111001010, // r + l
43                  0b00000000000000000000000001001001, // l + d
44                  0b11111111111111111111111111100001, // d + '\n'
45                  0b00000000000000000000000000100010, // '\n' + <len>
46                  0b11111111111111111111111110000110, // <len> + offset <001> + dist6
47                  0b00000000000000000000000000001101, // dist6 + offset <11> + end of block (000000)
48                  0b11111111111111111111111111111000 // end of block (0000) + garbage
49          };
50  
51          final HuffmanDecoder decoder = new HuffmanDecoder(new ByteArrayInputStream(data));
52          final byte[] result = new byte[100];
53          final int len = decoder.decode(result);
54  
55          assertEquals(48, len);
56          assertEquals("Hello World\nHello World\nHello World\nHello World\n", new String(result, 0, len));
57      }
58  
59      @Test
60      public void testDecodeFixedHuffmanBlockWithMemoryLookupInExactBuffer() throws Exception {
61          final byte[] data = {
62                  // |--- binary filling ---|76543210
63                  0b11111111111111111111111111110011, // final block + fixed huffman + H
64                  0b00000000000000000000000001001000, // H + e
65                  0b11111111111111111111111111001101, // e + l
66                  0b11111111111111111111111111001001, // l + l
67                  0b11111111111111111111111111001001, // l + o
68                  0b00000000000000000000000001010111, // o + ' '
69                  0b00000000000000000000000000001000, // ' ' + W
70                  0b11111111111111111111111111001111, // W + o
71                  0b00000000000000000000000000101111, // o + r
72                  0b11111111111111111111111111001010, // r + l
73                  0b00000000000000000000000001001001, // l + d
74                  0b11111111111111111111111111100001, // d + '\n'
75                  0b00000000000000000000000000100010, // '\n' + <len>
76                  0b11111111111111111111111110000110, // <len> + offset <001> + dist6
77                  0b00000000000000000000000000001101, // dist6 + offset <11> + end of block (000000)
78                  0b11111111111111111111111111111000 // end of block (0000) + garbage
79          };
80  
81          final HuffmanDecoder decoder = new HuffmanDecoder(new ByteArrayInputStream(data));
82          final byte[] result = new byte[48];
83          int len;
84  
85          len = decoder.decode(result);
86          assertEquals(48, len);
87          assertEquals("Hello World\nHello World\nHello World\nHello World\n", new String(result, 0, len));
88  
89          len = decoder.decode(result);
90          assertEquals(-1, len);
91      }
92  
93      @Test
94      public void testDecodeFixedHuffmanBlockWithMemoryLookupInSmallBuffer() throws Exception {
95          final byte[] data = {
96                  // |--- binary filling ---|76543210
97                  0b11111111111111111111111111110011, // final block + fixed huffman + H
98                  0b00000000000000000000000001001000, // H + e
99                  0b11111111111111111111111111001101, // e + l
100                 0b11111111111111111111111111001001, // l + l
101                 0b11111111111111111111111111001001, // l + o
102                 0b00000000000000000000000001010111, // o + ' '
103                 0b00000000000000000000000000001000, // ' ' + W
104                 0b11111111111111111111111111001111, // W + o
105                 0b00000000000000000000000000101111, // o + r
106                 0b11111111111111111111111111001010, // r + l
107                 0b00000000000000000000000001001001, // l + d
108                 0b11111111111111111111111111100001, // d + '\n'
109                 0b00000000000000000000000000100010, // '\n' + <len>
110                 0b11111111111111111111111110000110, // <len> + offset <001> + dist6
111                 0b00000000000000000000000000001101, // dist6 + offset <11> + end of block (000000)
112                 0b11111111111111111111111111111000 // end of block (0000) + garbage
113         };
114 
115         final HuffmanDecoder decoder = new HuffmanDecoder(new ByteArrayInputStream(data));
116         final byte[] result = new byte[30];
117         int len;
118 
119         len = decoder.decode(result);
120         assertEquals(30, len);
121         assertEquals("Hello World\nHello World\nHello ", new String(result, 0, len));
122 
123         len = decoder.decode(result);
124         assertEquals(18, len);
125         assertEquals("World\nHello World\n", new String(result, 0, len));
126     }
127 
128     @Test
129     public void testDecodeSimpleFixedHuffmanBlock() throws Exception {
130         final byte[] data = {
131                 // |--- binary filling ---|76543210
132                 0b11111111111111111111111111110011, // final block + fixed huffman + H
133                 0b00000000000000000000000001001000, // H + e
134                 0b11111111111111111111111111001101, // e + l
135                 0b11111111111111111111111111001001, // l + l
136                 0b11111111111111111111111111001001, // l + o
137                 0b00000000000000000000000001010111, // o + ' '
138                 0b00000000000000000000000000001000, // ' ' + W
139                 0b11111111111111111111111111001111, // W + o
140                 0b00000000000000000000000000101111, // o + r
141                 0b11111111111111111111111111001010, // r + l
142                 0b00000000000000000000000001001001, // l + d
143                 0b00000000000000000000000000000001, // d + end of block
144                 0b11111111111111111111111111111100 // end of block (00) + garbage
145         };
146 
147         final HuffmanDecoder decoder = new HuffmanDecoder(new ByteArrayInputStream(data));
148         final byte[] result = new byte[100];
149         final int len = decoder.decode(result);
150 
151         assertEquals(11, len);
152         assertEquals("Hello World", new String(result, 0, len));
153     }
154 
155     @Test
156     public void testDecodeSimpleFixedHuffmanBlockToSmallBuffer() throws Exception {
157         final byte[] data = {
158                 // |--- binary filling ---|76543210
159                 0b11111111111111111111111111110011, // final block + fixed huffman + H
160                 0b00000000000000000000000001001000, // H + e
161                 0b11111111111111111111111111001101, // e + l
162                 0b11111111111111111111111111001001, // l + l
163                 0b11111111111111111111111111001001, // l + o
164                 0b00000000000000000000000001010111, // o + ' '
165                 0b00000000000000000000000000001000, // ' ' + W
166                 0b11111111111111111111111111001111, // W + o
167                 0b00000000000000000000000000101111, // o + r
168                 0b11111111111111111111111111001010, // r + l
169                 0b00000000000000000000000001001001, // l + d
170                 0b00000000000000000000000000000001, // d + end of block
171                 0b11111111111111111111111111111100 // end of block (00) + garbage
172         };
173 
174         final HuffmanDecoder decoder = new HuffmanDecoder(new ByteArrayInputStream(data));
175         final byte[] result = new byte[10];
176         int len;
177         len = decoder.decode(result);
178         assertEquals(10, len);
179         assertEquals("Hello Worl", new String(result, 0, len));
180         len = decoder.decode(result);
181         assertEquals(1, len);
182         assertEquals("d", new String(result, 0, len));
183     }
184 
185     @Test
186     public void testDecodeUncompressedBlock() throws Exception {
187         final byte[] data = { 0b1, // end of block + no compression mode
188                 11, 0, -12, -1, // len & ~len
189                 'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd' };
190 
191         final HuffmanDecoder decoder = new HuffmanDecoder(new ByteArrayInputStream(data));
192         final byte[] result = new byte[100];
193         final int len = decoder.decode(result);
194 
195         assertEquals(11, len);
196         assertEquals("Hello World", new String(result, 0, len));
197     }
198 
199     @Test
200     public void testDecodeUncompressedBlockWithInvalidLenNLenValue() throws Exception {
201         final byte[] data = { 0b1, // end of block + no compression mode
202                 11, 0, -12, -2, // len & ~len
203                 'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd' };
204 
205         final HuffmanDecoder decoder = new HuffmanDecoder(new ByteArrayInputStream(data));
206         final byte[] result = new byte[100];
207         final IllegalStateException e = assertThrows(IllegalStateException.class, () -> {
208             final int len = decoder.decode(result);
209             fail("Should have failed but returned " + len + " entries: " + Arrays.toString(Arrays.copyOf(result, len)));
210         });
211         assertEquals("Illegal LEN / NLEN values", e.getMessage());
212     }
213 }