1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.commons.compress.archivers.zip;
21
22 import java.io.EOFException;
23 import java.io.IOException;
24 import java.io.InputStream;
25
26 import org.apache.commons.compress.utils.IOUtils;
27 import org.apache.commons.lang3.ArrayFill;
28
29
30
31
32
33
34 final class BinaryTree {
35
36
37 private static final int UNDEFINED = -1;
38
39
40 private static final int NODE = -2;
41
42
43
44
45 static BinaryTree decode(final InputStream inputStream, final int totalNumberOfValues) throws IOException {
46 if (totalNumberOfValues < 0) {
47 throw new IllegalArgumentException("totalNumberOfValues must be bigger than 0, is " + totalNumberOfValues);
48 }
49
50 final int size = inputStream.read() + 1;
51 if (size == 0) {
52 throw new IOException("Cannot read the size of the encoded tree, unexpected end of stream");
53 }
54
55 final byte[] encodedTree = IOUtils.readRange(inputStream, size);
56 if (encodedTree.length != size) {
57 throw new EOFException();
58 }
59
60
61 int maxLength = 0;
62
63 final int[] originalBitLengths = new int[totalNumberOfValues];
64 int pos = 0;
65 for (final byte b : encodedTree) {
66
67 final int numberOfValues = ((b & 0xF0) >> 4) + 1;
68 if (pos + numberOfValues > totalNumberOfValues) {
69 throw new IOException("Number of values exceeds given total number of values");
70 }
71 final int bitLength = (b & 0x0F) + 1;
72
73 for (int j = 0; j < numberOfValues; j++) {
74 originalBitLengths[pos++] = bitLength;
75 }
76
77 maxLength = Math.max(maxLength, bitLength);
78 }
79
80 final int oBitLengths = originalBitLengths.length;
81
82 final int[] permutation = new int[oBitLengths];
83 for (int k = 0; k < permutation.length; k++) {
84 permutation[k] = k;
85 }
86
87 int c = 0;
88 final int[] sortedBitLengths = new int[oBitLengths];
89 for (int k = 0; k < oBitLengths; k++) {
90
91 for (int l = 0; l < oBitLengths; l++) {
92
93 if (originalBitLengths[l] == k) {
94
95 sortedBitLengths[c] = k;
96
97
98 permutation[c] = l;
99
100 c++;
101 }
102 }
103 }
104
105
106 int code = 0;
107 int codeIncrement = 0;
108 int lastBitLength = 0;
109
110 final int[] codes = new int[totalNumberOfValues];
111
112 for (int i = totalNumberOfValues - 1; i >= 0; i--) {
113 code += codeIncrement;
114 if (sortedBitLengths[i] != lastBitLength) {
115 lastBitLength = sortedBitLengths[i];
116 codeIncrement = 1 << 16 - lastBitLength;
117 }
118 codes[permutation[i]] = code;
119 }
120
121
122 final BinaryTree tree = new BinaryTree(maxLength);
123
124 for (int k = 0; k < codes.length; k++) {
125 final int bitLength = originalBitLengths[k];
126 if (bitLength > 0) {
127 tree.addLeaf(0, Integer.reverse(codes[k] << 16), bitLength, k);
128 }
129 }
130
131 return tree;
132 }
133
134
135
136
137 private final int[] tree;
138
139 BinaryTree(final int depth) {
140 if (depth < 0 || depth > 30) {
141 throw new IllegalArgumentException("depth must be bigger than 0 and not bigger than 30" + " but is " + depth);
142 }
143 tree = ArrayFill.fill(new int[(int) ((1L << depth + 1) - 1)], UNDEFINED);
144 }
145
146
147
148
149
150
151
152
153
154 public void addLeaf(final int node, final int path, final int depth, final int value) {
155 if (depth == 0) {
156
157 if (tree[node] != UNDEFINED) {
158 throw new IllegalArgumentException("Tree value at index " + node + " has already been assigned (" + tree[node] + ")");
159 }
160 tree[node] = value;
161 } else {
162
163 tree[node] = NODE;
164
165
166 final int nextChild = 2 * node + 1 + (path & 1);
167 addLeaf(nextChild, path >>> 1, depth - 1, value);
168 }
169 }
170
171
172
173
174
175
176
177
178 public int read(final BitStream stream) throws IOException {
179 int currentIndex = 0;
180
181 while (true) {
182 final int bit = stream.nextBit();
183 if (bit == -1) {
184 return -1;
185 }
186
187 final int childIndex = 2 * currentIndex + 1 + bit;
188 final int value = tree[childIndex];
189 if (value == NODE) {
190
191 currentIndex = childIndex;
192 } else if (value != UNDEFINED) {
193 return value;
194 } else {
195 throw new IOException("The child " + bit + " of node at index " + currentIndex + " is not defined");
196 }
197 }
198 }
199 }