blob: f751ff7c1affe3fba4891d6403e8c663ceecd712 [file] [log] [blame]
package org.eclipse.swt.internal.image;
/*
* (c) Copyright IBM Corp. 2000, 2001.
* All Rights Reserved
*/
public class PngHuffmanTable {
CodeLengthInfo[] codeLengthInfo;
int[] codeValues;
static final int MAX_CODE_LENGTH = 15;
static final int BAD_CODE = 0xFFFFFFF;
PngHuffmanTable (int[] lengths) {
super();
initialize(lengths);
generateTable(lengths);
}
private void initialize(int[] lengths) {
codeValues = new int[lengths.length];
for (int i = 0; i < codeValues.length; i++) {
codeValues[i] = i;
}
// minCodesByLength[n] : The smallest Huffman code of length n + 1.
// maxCodesByLength[n] : The largest Huffman code of length n + 1.
// indexesByLength[n] : Index into the values array. First value with a code of length n + 1.
codeLengthInfo = new CodeLengthInfo[MAX_CODE_LENGTH];
for (int i = 0; i < MAX_CODE_LENGTH; i++) {
codeLengthInfo[i] = new CodeLengthInfo();
codeLengthInfo[i].length = i;
codeLengthInfo[i].baseIndex = 0;
codeLengthInfo[i].min = BAD_CODE;
codeLengthInfo[i].max = -1;
}
}
private void generateTable(int[] lengths) {
// Sort the values. Primary key is code size. Secondary key is value.
for (int i = 0; i < lengths.length - 1; i++) {
for (int j = i + 1; j < lengths.length; j++) {
if (lengths[j] < lengths[i]
|| (lengths[j] == lengths[i]
&& codeValues[j] < codeValues[i]))
{
int tmp;
tmp = lengths[j];
lengths[j] = lengths[i];
lengths[i] = tmp;
tmp = codeValues[j];
codeValues[j] = codeValues[i];
codeValues[i] = tmp;
}
}
}
// These values in these arrays correspond to the elements of the
// "values" array. The Huffman code for codeValues[N] is codes[N]
// and the length of the code is lengths[N].
int[] codes = new int[lengths.length];
int lastLength = 0;
int code = 0;
for (int i = 0; i < lengths.length; i++) {
while (lastLength != lengths[i]) {
lastLength++;
code <<= 1;
}
if (lastLength != 0) {
codes[i] = code;
code++;
}
}
int last = 0;
for (int i = 0; i < lengths.length; i++) {
if (last != lengths[i]) {
last = lengths[i];
codeLengthInfo[last - 1].baseIndex = i;
codeLengthInfo[last - 1].min = codes[i];
}
if (last != 0) codeLengthInfo[last - 1].max = codes[i];
}
}
int getNextValue(PngDecodingDataStream stream) {
int code = stream.getNextIdatBit();
int codelength = 0;
// Here we are taking advantage of the fact that 1 bits are used as
// a prefix to the longer codeValues.
while (code > codeLengthInfo[codelength].max && codelength < MAX_CODE_LENGTH) {
code = ((code << 1) | stream.getNextIdatBit());
codelength++;
}
if (codelength >= MAX_CODE_LENGTH) stream.error();
// Now we have a Huffman code of length (codelength + 1) that
// is somewhere in the range
// minCodesByLength[codelength]..maxCodesByLength[codelength].
// This code is the (offset + 1)'th code of (codelength + 1);
int offset = code - codeLengthInfo[codelength].min;
// indexesByLength[codelength] is the first code of length (codelength + 1)
// so now we can look up the value for the Huffman code in the table.
int index = codeLengthInfo[codelength].baseIndex + offset;
return codeValues[index];
}
class CodeValuePair {
int value;
int code;
}
class CodeLengthInfo {
int length;
int max;
int min;
int baseIndex;
}
}