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