1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.apache.commons.imaging.formats.jpeg.segments;
17
18 import static org.apache.commons.imaging.common.BinaryFunctions.readByte;
19
20 import java.io.ByteArrayInputStream;
21 import java.io.IOException;
22 import java.io.InputStream;
23 import java.util.ArrayList;
24 import java.util.Collections;
25 import java.util.List;
26
27 import org.apache.commons.imaging.common.Allocator;
28
29 public final class DhtSegment extends AbstractSegment {
30
31 public static class HuffmanTable {
32
33
34 public final int tableClass;
35 public final int destinationIdentifier;
36 private final int[] huffVal;
37
38
39 private final int[] huffSize = new int[16 * 256];
40 private final int[] huffCode;
41 private final int[] minCode = new int[1 + 16];
42 private final int[] maxCode = new int[1 + 16];
43 private final int[] valPtr = new int[1 + 16];
44
45 HuffmanTable(final int tableClass, final int destinationIdentifier, final int[] bits, final int[] huffVal) {
46 this.tableClass = tableClass;
47 this.destinationIdentifier = destinationIdentifier;
48
49 this.huffVal = huffVal;
50
51
52
53 int k = 0;
54 int i = 1;
55 int j = 1;
56 int lastK = -1;
57 while (true) {
58 if (j > bits[i]) {
59 i++;
60 j = 1;
61 if (i > 16) {
62 huffSize[k] = 0;
63 lastK = k;
64 break;
65 }
66 } else {
67 huffSize[k] = i;
68 k++;
69 j++;
70 }
71 }
72
73
74
75 k = 0;
76 int code = 0;
77 int si = huffSize[0];
78 huffCode = Allocator.intArray(lastK);
79 while (true) {
80 if (k >= lastK) {
81 break;
82 }
83 huffCode[k] = code;
84 code++;
85 k++;
86
87 if (huffSize[k] == si) {
88 continue;
89 }
90 if (huffSize[k] == 0) {
91 break;
92 }
93 do {
94 code <<= 1;
95 si++;
96 } while (huffSize[k] != si);
97 }
98
99
100 i = 0;
101 j = 0;
102 while (true) {
103 i++;
104 if (i > 16) {
105 break;
106 }
107 if (bits[i] == 0) {
108 maxCode[i] = -1;
109 } else {
110 valPtr[i] = j;
111 minCode[i] = huffCode[j];
112 j += bits[i] - 1;
113 maxCode[i] = huffCode[j];
114 j++;
115 }
116 }
117
118 }
119
120 public int getHuffVal(final int i) {
121 return huffVal[i];
122 }
123
124 public int getMaxCode(final int i) {
125 return maxCode[i];
126 }
127
128 public int getMinCode(final int i) {
129 return minCode[i];
130 }
131
132 public int getValPtr(final int i) {
133 return valPtr[i];
134 }
135 }
136
137 public final List<HuffmanTable> huffmanTables;
138
139 public DhtSegment(final int marker, final byte[] segmentData) throws IOException {
140 this(marker, segmentData.length, new ByteArrayInputStream(segmentData));
141 }
142
143 public DhtSegment(final int marker, int length, final InputStream is) throws IOException {
144 super(marker, length);
145
146 final ArrayList<HuffmanTable> huffmanTables = new ArrayList<>();
147 while (length > 0) {
148 final int tableClassAndDestinationId = 0xff & readByte("TableClassAndDestinationId", is, "Not a Valid JPEG File");
149 length--;
150 final int tableClass = tableClassAndDestinationId >> 4 & 0xf;
151 final int destinationIdentifier = tableClassAndDestinationId & 0xf;
152 final int[] bits = new int[1 + 16];
153 int bitsSum = 0;
154 for (int i = 1; i < bits.length; i++) {
155 bits[i] = 0xff & readByte("Li", is, "Not a Valid JPEG File");
156 length--;
157 bitsSum += bits[i];
158 }
159 final int[] huffVal = Allocator.intArray(bitsSum);
160 for (int i = 0; i < bitsSum; i++) {
161 huffVal[i] = 0xff & readByte("Vij", is, "Not a Valid JPEG File");
162 length--;
163 }
164
165 huffmanTables.add(new HuffmanTable(tableClass, destinationIdentifier, bits, huffVal));
166 }
167 this.huffmanTables = Collections.unmodifiableList(huffmanTables);
168 }
169
170 @Override
171 public String getDescription() {
172 return "DHT (" + getSegmentType() + ")";
173 }
174 }