This source file includes following definitions.
- invalidNBits
- tooMuchData
- notEnoughData
- invalidCode
- invalidTableSize
- unexpectedEndOfTable
- tableTooLong
- invalidTableEntry
- hufLength
- hufCode
- outputBits
- getBits
- hufCanonicalCodeTable
- hufFreeDecTable
- outputCode
- sendCode
- countFrequencies
- writeUInt
- readUInt
- hufCompress
- hufUncompress
#include <ImfHuf.h>
#include <ImfInt64.h>
#include <ImfAutoArray.h>
#include "Iex.h"
#include <string.h>
#include <assert.h>
#include <algorithm>
using namespace std;
using namespace Iex;
namespace Imf {
namespace {
const int HUF_ENCBITS = 16;
const int HUF_DECBITS = 14;
const int HUF_ENCSIZE = (1 << HUF_ENCBITS) + 1;
const int HUF_DECSIZE = 1 << HUF_DECBITS;
const int HUF_DECMASK = HUF_DECSIZE - 1;
struct HufDec
{
int len:8;
int lit:24;
int * p;
};
void
invalidNBits ()
{
throw InputExc ("Error in header for Huffman-encoded data "
"(invalid number of bits).");
}
void
tooMuchData ()
{
throw InputExc ("Error in Huffman-encoded data "
"(decoded data are longer than expected).");
}
void
notEnoughData ()
{
throw InputExc ("Error in Huffman-encoded data "
"(decoded data are shorter than expected).");
}
void
invalidCode ()
{
throw InputExc ("Error in Huffman-encoded data "
"(invalid code).");
}
void
invalidTableSize ()
{
throw InputExc ("Error in Huffman-encoded data "
"(invalid code table size).");
}
void
unexpectedEndOfTable ()
{
throw InputExc ("Error in Huffman-encoded data "
"(unexpected end of code table data).");
}
void
tableTooLong ()
{
throw InputExc ("Error in Huffman-encoded data "
"(code table is longer than expected).");
}
void
invalidTableEntry ()
{
throw InputExc ("Error in Huffman-encoded data "
"(invalid code table entry).");
}
inline Int64
hufLength (Int64 code)
{
return code & 63;
}
inline Int64
hufCode (Int64 code)
{
return code >> 6;
}
inline void
outputBits (int nBits, Int64 bits, Int64 &c, int &lc, char *&out)
{
c <<= nBits;
lc += nBits;
c |= bits;
while (lc >= 8)
*out++ = (c >> (lc -= 8));
}
inline Int64
getBits (int nBits, Int64 &c, int &lc, const char *&in)
{
while (lc < nBits)
{
c = (c << 8) | *(unsigned char *)(in++);
lc += 8;
}
lc -= nBits;
return (c >> lc) & ((1 << nBits) - 1);
}
void
hufCanonicalCodeTable (Int64 hcode[HUF_ENCSIZE])
{
Int64 n[59];
for (int i = 0; i <= 58; ++i)
n[i] = 0;
for (int i = 0; i < HUF_ENCSIZE; ++i)
n[hcode[i]] += 1;
Int64 c = 0;
for (int i = 58; i > 0; --i)
{
Int64 nc = ((c + n[i]) >> 1);
n[i] = c;
c = nc;
}
for (int i = 0; i < HUF_ENCSIZE; ++i)
{
int l = hcode[i];
if (l > 0)
hcode[i] = l | (n[l]++ << 6);
}
}
struct FHeapCompare
{
bool operator () (Int64 *a, Int64 *b) {return *a > *b;}
};
void
hufBuildEncTable
(Int64* frq,
int* im,
int* iM)
{
AutoArray <int, HUF_ENCSIZE> hlink;
AutoArray <Int64 *, HUF_ENCSIZE> fHeap;
*im = 0;
while (!frq[*im])
(*im)++;
int nf = 0;
for (int i = *im; i < HUF_ENCSIZE; i++)
{
hlink[i] = i;
if (frq[i])
{
fHeap[nf] = &frq[i];
nf++;
*iM = i;
}
}
(*iM)++;
frq[*iM] = 1;
fHeap[nf] = &frq[*iM];
nf++;
make_heap (&fHeap[0], &fHeap[nf], FHeapCompare());
AutoArray <Int64, HUF_ENCSIZE> scode;
memset (scode, 0, sizeof (Int64) * HUF_ENCSIZE);
while (nf > 1)
{
int mm = fHeap[0] - frq;
pop_heap (&fHeap[0], &fHeap[nf], FHeapCompare());
--nf;
int m = fHeap[0] - frq;
pop_heap (&fHeap[0], &fHeap[nf], FHeapCompare());
frq[m ] += frq[mm];
push_heap (&fHeap[0], &fHeap[nf], FHeapCompare());
for (int j = m; true; j = hlink[j])
{
scode[j]++;
assert (scode[j] <= 58);
if (hlink[j] == j)
{
hlink[j] = mm;
break;
}
}
for (int j = mm; true; j = hlink[j])
{
scode[j]++;
assert (scode[j] <= 58);
if (hlink[j] == j)
break;
}
}
hufCanonicalCodeTable (scode);
memcpy (frq, scode, sizeof (Int64) * HUF_ENCSIZE);
}
const int SHORT_ZEROCODE_RUN = 59;
const int LONG_ZEROCODE_RUN = 63;
const int SHORTEST_LONG_RUN = 2 + LONG_ZEROCODE_RUN - SHORT_ZEROCODE_RUN;
const int LONGEST_LONG_RUN = 255 + SHORTEST_LONG_RUN;
void
hufPackEncTable
(const Int64* hcode,
int im,
int iM,
char** pcode)
{
char *p = *pcode;
Int64 c = 0;
int lc = 0;
for (; im <= iM; im++)
{
int l = hufLength (hcode[im]);
if (l == 0)
{
int zerun = 1;
while ((im < iM) && (zerun < LONGEST_LONG_RUN))
{
if (hufLength (hcode[im+1]) > 0 )
break;
im++;
zerun++;
}
if (zerun >= 2)
{
if (zerun >= SHORTEST_LONG_RUN)
{
outputBits (6, LONG_ZEROCODE_RUN, c, lc, p);
outputBits (8, zerun - SHORTEST_LONG_RUN, c, lc, p);
}
else
{
outputBits (6, SHORT_ZEROCODE_RUN + zerun - 2, c, lc, p);
}
continue;
}
}
outputBits (6, l, c, lc, p);
}
if (lc > 0)
*p++ = (unsigned char) (c << (8 - lc));
*pcode = p;
}
void
hufUnpackEncTable
(const char** pcode,
int ni,
int im,
int iM,
Int64* hcode)
{
memset (hcode, 0, sizeof (Int64) * HUF_ENCSIZE);
const char *p = *pcode;
Int64 c = 0;
int lc = 0;
for (; im <= iM; im++)
{
if (p - *pcode > ni)
unexpectedEndOfTable();
Int64 l = hcode[im] = getBits (6, c, lc, p);
if (l == (Int64) LONG_ZEROCODE_RUN)
{
if (p - *pcode > ni)
unexpectedEndOfTable();
int zerun = getBits (8, c, lc, p) + SHORTEST_LONG_RUN;
if (im + zerun > iM + 1)
tableTooLong();
while (zerun--)
hcode[im++] = 0;
im--;
}
else if (l >= (Int64) SHORT_ZEROCODE_RUN)
{
int zerun = l - SHORT_ZEROCODE_RUN + 2;
if (im + zerun > iM + 1)
tableTooLong();
while (zerun--)
hcode[im++] = 0;
im--;
}
}
*pcode = (char *) p;
hufCanonicalCodeTable (hcode);
}
void
hufClearDecTable
(HufDec * hdecod)
{
memset (hdecod, 0, sizeof (HufDec) * HUF_DECSIZE);
}
void
hufBuildDecTable
(const Int64* hcode,
int im,
int iM,
HufDec * hdecod)
{
for (; im <= iM; im++)
{
Int64 c = hufCode (hcode[im]);
int l = hufLength (hcode[im]);
if (c >> l)
{
invalidTableEntry();
}
if (l > HUF_DECBITS)
{
HufDec *pl = hdecod + (c >> (l - HUF_DECBITS));
if (pl->len)
{
invalidTableEntry();
}
pl->lit++;
if (pl->p)
{
int *p = pl->p;
pl->p = new int [pl->lit];
for (int i = 0; i < pl->lit - 1; ++i)
pl->p[i] = p[i];
delete [] p;
}
else
{
pl->p = new int [1];
}
pl->p[pl->lit - 1]= im;
}
else if (l)
{
HufDec *pl = hdecod + (c << (HUF_DECBITS - l));
for (Int64 i = 1 << (HUF_DECBITS - l); i > 0; i--, pl++)
{
if (pl->len || pl->p)
{
invalidTableEntry();
}
pl->len = l;
pl->lit = im;
}
}
}
}
void
hufFreeDecTable (HufDec *hdecod)
{
for (int i = 0; i < HUF_DECSIZE; i++)
{
if (hdecod[i].p)
{
delete [] hdecod[i].p;
hdecod[i].p = 0;
}
}
}
inline void
outputCode (Int64 code, Int64 &c, int &lc, char *&out)
{
outputBits (hufLength (code), hufCode (code), c, lc, out);
}
inline void
sendCode (Int64 sCode, int runCount, Int64 runCode,
Int64 &c, int &lc, char *&out)
{
static const int RLMIN = 32;
if (runCount > RLMIN)
{
outputCode (sCode, c, lc, out);
outputCode (runCode, c, lc, out);
outputBits (8, runCount, c, lc, out);
}
else
{
while (runCount-- >= 0)
outputCode (sCode, c, lc, out);
}
}
int
hufEncode
(const Int64* hcode,
const unsigned short* in,
const int ni,
int rlc,
char* out)
{
char *outStart = out;
Int64 c = 0;
int lc = 0;
int s = in[0];
int cs = 0;
for (int i = 1; i < ni; i++)
{
if (s == in[i] && cs < 255)
{
cs++;
}
else
{
sendCode (hcode[s], cs, hcode[rlc], c, lc, out);
cs=0;
}
s = in[i];
}
sendCode (hcode[s], cs, hcode[rlc], c, lc, out);
if (lc)
*out = (c << (8 - lc)) & 0xff;
return (out - outStart) * 8 + lc;
}
#define getChar(c, lc, in) \
{ \
c = (c << 8) | *(unsigned char *)(in++); \
lc += 8; \
}
#define getCode(po, rlc, c, lc, in, out, oe) \
{ \
if (po == rlc) \
{ \
if (lc < 8) \
getChar(c, lc, in); \
\
lc -= 8; \
\
unsigned char cs = (c >> lc); \
\
if (out + cs > oe) \
tooMuchData(); \
\
unsigned short s = out[-1]; \
\
while (cs-- > 0) \
*out++ = s; \
} \
else if (out < oe) \
{ \
*out++ = po; \
} \
else \
{ \
tooMuchData(); \
} \
}
void
hufDecode
(const Int64 * hcode,
const HufDec * hdecod,
const char* in,
int ni,
int rlc,
int no,
unsigned short* out)
{
Int64 c = 0;
int lc = 0;
unsigned short * outb = out;
unsigned short * oe = out + no;
const char * ie = in + (ni + 7) / 8;
while (in < ie)
{
getChar (c, lc, in);
while (lc >= HUF_DECBITS)
{
const HufDec pl = hdecod[(c >> (lc-HUF_DECBITS)) & HUF_DECMASK];
if (pl.len)
{
lc -= pl.len;
getCode (pl.lit, rlc, c, lc, in, out, oe);
}
else
{
if (!pl.p)
invalidCode();
int j;
for (j = 0; j < pl.lit; j++)
{
int l = hufLength (hcode[pl.p[j]]);
while (lc < l && in < ie)
getChar (c, lc, in);
if (lc >= l)
{
if (hufCode (hcode[pl.p[j]]) ==
((c >> (lc - l)) & ((Int64(1) << l) - 1)))
{
lc -= l;
getCode (pl.p[j], rlc, c, lc, in, out, oe);
break;
}
}
}
if (j == pl.lit)
invalidCode();
}
}
}
int i = (8 - ni) & 7;
c >>= i;
lc -= i;
while (lc > 0)
{
const HufDec pl = hdecod[(c << (HUF_DECBITS - lc)) & HUF_DECMASK];
if (pl.len)
{
lc -= pl.len;
getCode (pl.lit, rlc, c, lc, in, out, oe);
}
else
{
invalidCode();
}
}
if (out - outb != no)
notEnoughData ();
}
void
countFrequencies (Int64 freq[HUF_ENCSIZE],
const unsigned short data[],
int n)
{
for (int i = 0; i < HUF_ENCSIZE; ++i)
freq[i] = 0;
for (int i = 0; i < n; ++i)
++freq[data[i]];
}
void
writeUInt (char buf[4], unsigned int i)
{
unsigned char *b = (unsigned char *) buf;
b[0] = i;
b[1] = i >> 8;
b[2] = i >> 16;
b[3] = i >> 24;
}
unsigned int
readUInt (const char buf[4])
{
const unsigned char *b = (const unsigned char *) buf;
return ( b[0] & 0x000000ff) |
((b[1] << 8) & 0x0000ff00) |
((b[2] << 16) & 0x00ff0000) |
((b[3] << 24) & 0xff000000);
}
}
int
hufCompress (const unsigned short raw[],
int nRaw,
char compressed[])
{
if (nRaw == 0)
return 0;
AutoArray <Int64, HUF_ENCSIZE> freq;
countFrequencies (freq, raw, nRaw);
int im, iM;
hufBuildEncTable (freq, &im, &iM);
char *tableStart = compressed + 20;
char *tableEnd = tableStart;
hufPackEncTable (freq, im, iM, &tableEnd);
int tableLength = tableEnd - tableStart;
char *dataStart = tableEnd;
int nBits = hufEncode (freq, raw, nRaw, iM, dataStart);
int dataLength = (nBits + 7) / 8;
writeUInt (compressed, im);
writeUInt (compressed + 4, iM);
writeUInt (compressed + 8, tableLength);
writeUInt (compressed + 12, nBits);
writeUInt (compressed + 16, 0);
return dataStart + dataLength - compressed;
}
void
hufUncompress (const char compressed[],
int nCompressed,
unsigned short raw[],
int nRaw)
{
if (nCompressed == 0)
{
if (nRaw != 0)
notEnoughData();
return;
}
int im = readUInt (compressed);
int iM = readUInt (compressed + 4);
int nBits = readUInt (compressed + 12);
if (im < 0 || im >= HUF_ENCSIZE || iM < 0 || iM >= HUF_ENCSIZE)
invalidTableSize();
const char *ptr = compressed + 20;
AutoArray <Int64, HUF_ENCSIZE> freq;
AutoArray <HufDec, HUF_DECSIZE> hdec;
hufClearDecTable (hdec);
hufUnpackEncTable (&ptr, nCompressed - (ptr - compressed), im, iM, freq);
try
{
if (nBits > 8 * (nCompressed - (ptr - compressed)))
invalidNBits();
hufBuildDecTable (freq, im, iM, hdec);
hufDecode (freq, hdec, ptr, nBits, iM, nRaw, raw);
}
catch (...)
{
hufFreeDecTable (hdec);
throw;
}
hufFreeDecTable (hdec);
}
}