#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include "fitsio2.h"
#ifndef min
#define min(a,b) (((a)<(b))?(a):(b))
#endif
#ifndef max
#define max(a,b) (((a)>(b))?(a):(b))
#endif
static long nextchar;
static int decode(unsigned char *infile, int *a, int *nx, int *ny, int *scale);
static int decode64(unsigned char *infile, LONGLONG *a, int *nx, int *ny, int *scale);
static int hinv(int a[], int nx, int ny, int smooth ,int scale);
static int hinv64(LONGLONG a[], int nx, int ny, int smooth ,int scale);
static void undigitize(int a[], int nx, int ny, int scale);
static void undigitize64(LONGLONG a[], int nx, int ny, int scale);
static void unshuffle(int a[], int n, int n2, int tmp[]);
static void unshuffle64(LONGLONG a[], int n, int n2, LONGLONG tmp[]);
static void hsmooth(int a[], int nxtop, int nytop, int ny, int scale);
static void hsmooth64(LONGLONG a[], int nxtop, int nytop, int ny, int scale);
static void qread(unsigned char *infile,char *a, int n);
static int readint(unsigned char *infile);
static LONGLONG readlonglong(unsigned char *infile);
static int dodecode(unsigned char *infile, int a[], int nx, int ny, unsigned char nbitplanes[3]);
static int dodecode64(unsigned char *infile, LONGLONG a[], int nx, int ny, unsigned char nbitplanes[3]);
static int qtree_decode(unsigned char *infile, int a[], int n, int nqx, int nqy, int nbitplanes);
static int qtree_decode64(unsigned char *infile, LONGLONG a[], int n, int nqx, int nqy, int nbitplanes);
static void start_inputing_bits(void);
static int input_bit(unsigned char *infile);
static int input_nbits(unsigned char *infile, int n);
static int input_nybble(unsigned char *infile);
static int input_nnybble(unsigned char *infile, int n, unsigned char *array);
static void qtree_expand(unsigned char *infile, unsigned char a[], int nx, int ny, unsigned char b[]);
static void qtree_bitins(unsigned char a[], int nx, int ny, int b[], int n, int bit);
static void qtree_bitins64(unsigned char a[], int nx, int ny, LONGLONG b[], int n, int bit);
static void qtree_copy(unsigned char a[], int nx, int ny, unsigned char b[], int n);
static void read_bdirect(unsigned char *infile, int a[], int n, int nqx, int nqy, unsigned char scratch[], int bit);
static void read_bdirect64(unsigned char *infile, LONGLONG a[], int n, int nqx, int nqy, unsigned char scratch[], int bit);
static int input_huffman(unsigned char *infile);
int fits_hdecompress(unsigned char *input, int smooth, int *a, int *ny, int *nx,
int *scale, int *status)
{
int stat;
if (*status > 0) return(*status);
FFLOCK;
stat = decode(input, a, nx, ny, scale);
FFUNLOCK;
*status = stat;
if (stat) return(*status);
undigitize(a, *nx, *ny, *scale);
stat = hinv(a, *nx, *ny, smooth, *scale);
*status = stat;
return(*status);
}
int fits_hdecompress64(unsigned char *input, int smooth, LONGLONG *a, int *ny, int *nx,
int *scale, int *status)
{
int stat, *iarray, ii, nval;
if (*status > 0) return(*status);
FFLOCK;
stat = decode64(input, a, nx, ny, scale);
FFUNLOCK;
*status = stat;
if (stat) return(*status);
undigitize64(a, *nx, *ny, *scale);
stat = hinv64(a, *nx, *ny, smooth, *scale);
*status = stat;
iarray = (int *) a;
nval = (*nx) * (*ny);
for (ii = 0; ii < nval; ii++)
iarray[ii] = (int) a[ii];
return(*status);
}
static int
hinv(int a[], int nx, int ny, int smooth ,int scale)
{
int nmax, log2n, i, j, k;
int nxtop,nytop,nxf,nyf,c;
int oddx,oddy;
int shift, bit0, bit1, bit2, mask0, mask1, mask2,
prnd0, prnd1, prnd2, nrnd0, nrnd1, nrnd2, lowbit0, lowbit1;
int h0, hx, hy, hc;
int s10, s00;
int *tmp;
nmax = (nx>ny) ? nx : ny;
log2n = (int) (log((float) nmax)/log(2.0)+0.5);
if ( nmax > (1<<log2n) ) {
log2n += 1;
}
tmp = (int *) malloc(((nmax+1)/2)*sizeof(int));
if (tmp == (int *) NULL) {
ffpmsg("hinv: insufficient memory");
return(DATA_DECOMPRESSION_ERR);
}
shift = 1;
bit0 = 1 << (log2n - 1);
bit1 = bit0 << 1;
bit2 = bit0 << 2;
mask0 = -bit0;
mask1 = mask0 << 1;
mask2 = mask0 << 2;
prnd0 = bit0 >> 1;
prnd1 = bit1 >> 1;
prnd2 = bit2 >> 1;
nrnd0 = prnd0 - 1;
nrnd1 = prnd1 - 1;
nrnd2 = prnd2 - 1;
a[0] = (a[0] + ((a[0] >= 0) ? prnd2 : nrnd2)) & mask2;
nxtop = 1;
nytop = 1;
nxf = nx;
nyf = ny;
c = 1<<log2n;
for (k = log2n-1; k>=0; k--) {
c = c>>1;
nxtop = nxtop<<1;
nytop = nytop<<1;
if (nxf <= c) { nxtop -= 1; } else { nxf -= c; }
if (nyf <= c) { nytop -= 1; } else { nyf -= c; }
if (k == 0) {
nrnd0 = 0;
shift = 2;
}
for (i = 0; i<nxtop; i++) {
unshuffle(&a[ny*i],nytop,1,tmp);
}
for (j = 0; j<nytop; j++) {
unshuffle(&a[j],nxtop,ny,tmp);
}
if (smooth) hsmooth(a,nxtop,nytop,ny,scale);
oddx = nxtop % 2;
oddy = nytop % 2;
for (i = 0; i<nxtop-oddx; i += 2) {
s00 = ny*i;
s10 = s00+ny;
for (j = 0; j<nytop-oddy; j += 2) {
h0 = a[s00 ];
hx = a[s10 ];
hy = a[s00+1];
hc = a[s10+1];
hx = (hx + ((hx >= 0) ? prnd1 : nrnd1)) & mask1;
hy = (hy + ((hy >= 0) ? prnd1 : nrnd1)) & mask1;
hc = (hc + ((hc >= 0) ? prnd0 : nrnd0)) & mask0;
lowbit0 = hc & bit0;
hx = (hx >= 0) ? (hx - lowbit0) : (hx + lowbit0);
hy = (hy >= 0) ? (hy - lowbit0) : (hy + lowbit0);
lowbit1 = (hc ^ hx ^ hy) & bit1;
h0 = (h0 >= 0)
? (h0 + lowbit0 - lowbit1)
: (h0 + ((lowbit0 == 0) ? lowbit1 : (lowbit0-lowbit1)));
a[s10+1] = (h0 + hx + hy + hc) >> shift;
a[s10 ] = (h0 + hx - hy - hc) >> shift;
a[s00+1] = (h0 - hx + hy - hc) >> shift;
a[s00 ] = (h0 - hx - hy + hc) >> shift;
s00 += 2;
s10 += 2;
}
if (oddy) {
h0 = a[s00 ];
hx = a[s10 ];
hx = ((hx >= 0) ? (hx+prnd1) : (hx+nrnd1)) & mask1;
lowbit1 = hx & bit1;
h0 = (h0 >= 0) ? (h0 - lowbit1) : (h0 + lowbit1);
a[s10 ] = (h0 + hx) >> shift;
a[s00 ] = (h0 - hx) >> shift;
}
}
if (oddx) {
s00 = ny*i;
for (j = 0; j<nytop-oddy; j += 2) {
h0 = a[s00 ];
hy = a[s00+1];
hy = ((hy >= 0) ? (hy+prnd1) : (hy+nrnd1)) & mask1;
lowbit1 = hy & bit1;
h0 = (h0 >= 0) ? (h0 - lowbit1) : (h0 + lowbit1);
a[s00+1] = (h0 + hy) >> shift;
a[s00 ] = (h0 - hy) >> shift;
s00 += 2;
}
if (oddy) {
h0 = a[s00 ];
a[s00 ] = h0 >> shift;
}
}
bit2 = bit1;
bit1 = bit0;
bit0 = bit0 >> 1;
mask1 = mask0;
mask0 = mask0 >> 1;
prnd1 = prnd0;
prnd0 = prnd0 >> 1;
nrnd1 = nrnd0;
nrnd0 = prnd0 - 1;
}
free(tmp);
return(0);
}
static int
hinv64(LONGLONG a[], int nx, int ny, int smooth ,int scale)
{
int nmax, log2n, i, j, k;
int nxtop,nytop,nxf,nyf,c;
int oddx,oddy;
int shift;
LONGLONG mask0, mask1, mask2, prnd0, prnd1, prnd2, bit0, bit1, bit2;
LONGLONG nrnd0, nrnd1, nrnd2, lowbit0, lowbit1;
LONGLONG h0, hx, hy, hc;
int s10, s00;
LONGLONG *tmp;
nmax = (nx>ny) ? nx : ny;
log2n = (int) (log((float) nmax)/log(2.0)+0.5);
if ( nmax > (1<<log2n) ) {
log2n += 1;
}
tmp = (LONGLONG *) malloc(((nmax+1)/2)*sizeof(LONGLONG));
if (tmp == (LONGLONG *) NULL) {
ffpmsg("hinv64: insufficient memory");
return(DATA_DECOMPRESSION_ERR);
}
shift = 1;
bit0 = ((LONGLONG) 1) << (log2n - 1);
bit1 = bit0 << 1;
bit2 = bit0 << 2;
mask0 = -bit0;
mask1 = mask0 << 1;
mask2 = mask0 << 2;
prnd0 = bit0 >> 1;
prnd1 = bit1 >> 1;
prnd2 = bit2 >> 1;
nrnd0 = prnd0 - 1;
nrnd1 = prnd1 - 1;
nrnd2 = prnd2 - 1;
a[0] = (a[0] + ((a[0] >= 0) ? prnd2 : nrnd2)) & mask2;
nxtop = 1;
nytop = 1;
nxf = nx;
nyf = ny;
c = 1<<log2n;
for (k = log2n-1; k>=0; k--) {
c = c>>1;
nxtop = nxtop<<1;
nytop = nytop<<1;
if (nxf <= c) { nxtop -= 1; } else { nxf -= c; }
if (nyf <= c) { nytop -= 1; } else { nyf -= c; }
if (k == 0) {
nrnd0 = 0;
shift = 2;
}
for (i = 0; i<nxtop; i++) {
unshuffle64(&a[ny*i],nytop,1,tmp);
}
for (j = 0; j<nytop; j++) {
unshuffle64(&a[j],nxtop,ny,tmp);
}
if (smooth) hsmooth64(a,nxtop,nytop,ny,scale);
oddx = nxtop % 2;
oddy = nytop % 2;
for (i = 0; i<nxtop-oddx; i += 2) {
s00 = ny*i;
s10 = s00+ny;
for (j = 0; j<nytop-oddy; j += 2) {
h0 = a[s00 ];
hx = a[s10 ];
hy = a[s00+1];
hc = a[s10+1];
hx = (hx + ((hx >= 0) ? prnd1 : nrnd1)) & mask1;
hy = (hy + ((hy >= 0) ? prnd1 : nrnd1)) & mask1;
hc = (hc + ((hc >= 0) ? prnd0 : nrnd0)) & mask0;
lowbit0 = hc & bit0;
hx = (hx >= 0) ? (hx - lowbit0) : (hx + lowbit0);
hy = (hy >= 0) ? (hy - lowbit0) : (hy + lowbit0);
lowbit1 = (hc ^ hx ^ hy) & bit1;
h0 = (h0 >= 0)
? (h0 + lowbit0 - lowbit1)
: (h0 + ((lowbit0 == 0) ? lowbit1 : (lowbit0-lowbit1)));
a[s10+1] = (h0 + hx + hy + hc) >> shift;
a[s10 ] = (h0 + hx - hy - hc) >> shift;
a[s00+1] = (h0 - hx + hy - hc) >> shift;
a[s00 ] = (h0 - hx - hy + hc) >> shift;
s00 += 2;
s10 += 2;
}
if (oddy) {
h0 = a[s00 ];
hx = a[s10 ];
hx = ((hx >= 0) ? (hx+prnd1) : (hx+nrnd1)) & mask1;
lowbit1 = hx & bit1;
h0 = (h0 >= 0) ? (h0 - lowbit1) : (h0 + lowbit1);
a[s10 ] = (h0 + hx) >> shift;
a[s00 ] = (h0 - hx) >> shift;
}
}
if (oddx) {
s00 = ny*i;
for (j = 0; j<nytop-oddy; j += 2) {
h0 = a[s00 ];
hy = a[s00+1];
hy = ((hy >= 0) ? (hy+prnd1) : (hy+nrnd1)) & mask1;
lowbit1 = hy & bit1;
h0 = (h0 >= 0) ? (h0 - lowbit1) : (h0 + lowbit1);
a[s00+1] = (h0 + hy) >> shift;
a[s00 ] = (h0 - hy) >> shift;
s00 += 2;
}
if (oddy) {
h0 = a[s00 ];
a[s00 ] = h0 >> shift;
}
}
bit2 = bit1;
bit1 = bit0;
bit0 = bit0 >> 1;
mask1 = mask0;
mask0 = mask0 >> 1;
prnd1 = prnd0;
prnd0 = prnd0 >> 1;
nrnd1 = nrnd0;
nrnd0 = prnd0 - 1;
}
free(tmp);
return(0);
}
static void
unshuffle(int a[], int n, int n2, int tmp[])
{
int i;
int nhalf;
int *p1, *p2, *pt;
nhalf = (n+1)>>1;
pt = tmp;
p1 = &a[n2*nhalf];
for (i=nhalf; i<n; i++) {
*pt = *p1;
p1 += n2;
pt += 1;
}
p2 = &a[ n2*(nhalf-1) ];
p1 = &a[(n2*(nhalf-1))<<1];
for (i=nhalf-1; i >= 0; i--) {
*p1 = *p2;
p2 -= n2;
p1 -= (n2+n2);
}
pt = tmp;
p1 = &a[n2];
for (i=1; i<n; i += 2) {
*p1 = *pt;
p1 += (n2+n2);
pt += 1;
}
}
static void
unshuffle64(LONGLONG a[], int n, int n2, LONGLONG tmp[])
{
int i;
int nhalf;
LONGLONG *p1, *p2, *pt;
nhalf = (n+1)>>1;
pt = tmp;
p1 = &a[n2*nhalf];
for (i=nhalf; i<n; i++) {
*pt = *p1;
p1 += n2;
pt += 1;
}
p2 = &a[ n2*(nhalf-1) ];
p1 = &a[(n2*(nhalf-1))<<1];
for (i=nhalf-1; i >= 0; i--) {
*p1 = *p2;
p2 -= n2;
p1 -= (n2+n2);
}
pt = tmp;
p1 = &a[n2];
for (i=1; i<n; i += 2) {
*p1 = *pt;
p1 += (n2+n2);
pt += 1;
}
}
static void
hsmooth(int a[], int nxtop, int nytop, int ny, int scale)
{
int i, j;
int ny2, s10, s00, diff, dmax, dmin, s, smax;
int hm, h0, hp, hmm, hpm, hmp, hpp, hx2, hy2;
int m1,m2;
smax = (scale >> 1);
if (smax <= 0) return;
ny2 = ny << 1;
for (i = 2; i<nxtop-2; i += 2) {
s00 = ny*i;
s10 = s00+ny;
for (j = 0; j<nytop; j += 2) {
hm = a[s00-ny2];
h0 = a[s00];
hp = a[s00+ny2];
diff = hp-hm;
dmax = max( min( (hp-h0), (h0-hm) ), 0 ) << 2;
dmin = min( max( (hp-h0), (h0-hm) ), 0 ) << 2;
if (dmin < dmax) {
diff = max( min(diff, dmax), dmin);
s = diff-(a[s10]<<3);
s = (s>=0) ? (s>>3) : ((s+7)>>3) ;
s = max( min(s, smax), -smax);
a[s10] = a[s10]+s;
}
s00 += 2;
s10 += 2;
}
}
for (i = 0; i<nxtop; i += 2) {
s00 = ny*i+2;
s10 = s00+ny;
for (j = 2; j<nytop-2; j += 2) {
hm = a[s00-2];
h0 = a[s00];
hp = a[s00+2];
diff = hp-hm;
dmax = max( min( (hp-h0), (h0-hm) ), 0 ) << 2;
dmin = min( max( (hp-h0), (h0-hm) ), 0 ) << 2;
if (dmin < dmax) {
diff = max( min(diff, dmax), dmin);
s = diff-(a[s00+1]<<3);
s = (s>=0) ? (s>>3) : ((s+7)>>3) ;
s = max( min(s, smax), -smax);
a[s00+1] = a[s00+1]+s;
}
s00 += 2;
s10 += 2;
}
}
for (i = 2; i<nxtop-2; i += 2) {
s00 = ny*i+2;
s10 = s00+ny;
for (j = 2; j<nytop-2; j += 2) {
hmm = a[s00-ny2-2];
hpm = a[s00+ny2-2];
hmp = a[s00-ny2+2];
hpp = a[s00+ny2+2];
h0 = a[s00];
diff = hpp + hmm - hmp - hpm;
hx2 = a[s10 ]<<1;
hy2 = a[s00+1]<<1;
m1 = min(max(hpp-h0,0)-hx2-hy2, max(h0-hpm,0)+hx2-hy2);
m2 = min(max(h0-hmp,0)-hx2+hy2, max(hmm-h0,0)+hx2+hy2);
dmax = min(m1,m2) << 4;
m1 = max(min(hpp-h0,0)-hx2-hy2, min(h0-hpm,0)+hx2-hy2);
m2 = max(min(h0-hmp,0)-hx2+hy2, min(hmm-h0,0)+hx2+hy2);
dmin = max(m1,m2) << 4;
if (dmin < dmax) {
diff = max( min(diff, dmax), dmin);
s = diff-(a[s10+1]<<6);
s = (s>=0) ? (s>>6) : ((s+63)>>6) ;
s = max( min(s, smax), -smax);
a[s10+1] = a[s10+1]+s;
}
s00 += 2;
s10 += 2;
}
}
}
static void
hsmooth64(LONGLONG a[], int nxtop, int nytop, int ny, int scale)
{
int i, j;
int ny2, s10, s00;
LONGLONG hm, h0, hp, hmm, hpm, hmp, hpp, hx2, hy2, diff, dmax, dmin, s, smax, m1, m2;
smax = (scale >> 1);
if (smax <= 0) return;
ny2 = ny << 1;
for (i = 2; i<nxtop-2; i += 2) {
s00 = ny*i;
s10 = s00+ny;
for (j = 0; j<nytop; j += 2) {
hm = a[s00-ny2];
h0 = a[s00];
hp = a[s00+ny2];
diff = hp-hm;
dmax = max( min( (hp-h0), (h0-hm) ), 0 ) << 2;
dmin = min( max( (hp-h0), (h0-hm) ), 0 ) << 2;
if (dmin < dmax) {
diff = max( min(diff, dmax), dmin);
s = diff-(a[s10]<<3);
s = (s>=0) ? (s>>3) : ((s+7)>>3) ;
s = max( min(s, smax), -smax);
a[s10] = a[s10]+s;
}
s00 += 2;
s10 += 2;
}
}
for (i = 0; i<nxtop; i += 2) {
s00 = ny*i+2;
s10 = s00+ny;
for (j = 2; j<nytop-2; j += 2) {
hm = a[s00-2];
h0 = a[s00];
hp = a[s00+2];
diff = hp-hm;
dmax = max( min( (hp-h0), (h0-hm) ), 0 ) << 2;
dmin = min( max( (hp-h0), (h0-hm) ), 0 ) << 2;
if (dmin < dmax) {
diff = max( min(diff, dmax), dmin);
s = diff-(a[s00+1]<<3);
s = (s>=0) ? (s>>3) : ((s+7)>>3) ;
s = max( min(s, smax), -smax);
a[s00+1] = a[s00+1]+s;
}
s00 += 2;
s10 += 2;
}
}
for (i = 2; i<nxtop-2; i += 2) {
s00 = ny*i+2;
s10 = s00+ny;
for (j = 2; j<nytop-2; j += 2) {
hmm = a[s00-ny2-2];
hpm = a[s00+ny2-2];
hmp = a[s00-ny2+2];
hpp = a[s00+ny2+2];
h0 = a[s00];
diff = hpp + hmm - hmp - hpm;
hx2 = a[s10 ]<<1;
hy2 = a[s00+1]<<1;
m1 = min(max(hpp-h0,0)-hx2-hy2, max(h0-hpm,0)+hx2-hy2);
m2 = min(max(h0-hmp,0)-hx2+hy2, max(hmm-h0,0)+hx2+hy2);
dmax = min(m1,m2) << 4;
m1 = max(min(hpp-h0,0)-hx2-hy2, min(h0-hpm,0)+hx2-hy2);
m2 = max(min(h0-hmp,0)-hx2+hy2, min(hmm-h0,0)+hx2+hy2);
dmin = max(m1,m2) << 4;
if (dmin < dmax) {
diff = max( min(diff, dmax), dmin);
s = diff-(a[s10+1]<<6);
s = (s>=0) ? (s>>6) : ((s+63)>>6) ;
s = max( min(s, smax), -smax);
a[s10+1] = a[s10+1]+s;
}
s00 += 2;
s10 += 2;
}
}
}
static void
undigitize(int a[], int nx, int ny, int scale)
{
int *p;
if (scale <= 1) return;
for (p=a; p <= &a[nx*ny-1]; p++) *p = (*p)*scale;
}
static void
undigitize64(LONGLONG a[], int nx, int ny, int scale)
{
LONGLONG *p, scale64;
if (scale <= 1) return;
scale64 = (LONGLONG) scale;
for (p=a; p <= &a[nx*ny-1]; p++) *p = (*p)*scale64;
}
static char code_magic[2] = { (char)0xDD, (char)0x99 };
static int decode(unsigned char *infile, int *a, int *nx, int *ny, int *scale)
{
LONGLONG sumall;
int stat;
unsigned char nbitplanes[3];
char tmagic[2];
;
nextchar = 0;
qread(infile, tmagic, sizeof(tmagic));
if (memcmp(tmagic,code_magic,sizeof(code_magic)) != 0) {
ffpmsg("bad file format");
return(DATA_DECOMPRESSION_ERR);
}
*nx =readint(infile);
*ny =readint(infile);
*scale=readint(infile);
sumall=readlonglong(infile);
qread(infile, (char *) nbitplanes, sizeof(nbitplanes));
stat = dodecode(infile, a, *nx, *ny, nbitplanes);
a[0] = (int) sumall;
return(stat);
}
static int decode64(unsigned char *infile, LONGLONG *a, int *nx, int *ny, int *scale)
{
int stat;
LONGLONG sumall;
unsigned char nbitplanes[3];
char tmagic[2];
;
nextchar = 0;
qread(infile, tmagic, sizeof(tmagic));
if (memcmp(tmagic,code_magic,sizeof(code_magic)) != 0) {
ffpmsg("bad file format");
return(DATA_DECOMPRESSION_ERR);
}
*nx =readint(infile);
*ny =readint(infile);
*scale=readint(infile);
sumall=readlonglong(infile);
qread(infile, (char *) nbitplanes, sizeof(nbitplanes));
stat = dodecode64(infile, a, *nx, *ny, nbitplanes);
a[0] = sumall;
return(stat);
}
static int
dodecode(unsigned char *infile, int a[], int nx, int ny, unsigned char nbitplanes[3])
{
int i, nel, nx2, ny2, stat;
nel = nx*ny;
nx2 = (nx+1)/2;
ny2 = (ny+1)/2;
for (i=0; i<nel; i++) a[i] = 0;
start_inputing_bits();
stat = qtree_decode(infile, &a[0], ny, nx2, ny2, nbitplanes[0]);
if (stat) return(stat);
stat = qtree_decode(infile, &a[ny2], ny, nx2, ny/2, nbitplanes[1]);
if (stat) return(stat);
stat = qtree_decode(infile, &a[ny*nx2], ny, nx/2, ny2, nbitplanes[1]);
if (stat) return(stat);
stat = qtree_decode(infile, &a[ny*nx2+ny2], ny, nx/2, ny/2, nbitplanes[2]);
if (stat) return(stat);
if (input_nybble(infile) != 0) {
ffpmsg("dodecode: bad bit plane values");
return(DATA_DECOMPRESSION_ERR);
}
start_inputing_bits();
for (i=0; i<nel; i++) {
if (a[i]) {
if (input_bit(infile)) a[i] = -a[i];
}
}
return(0);
}
static int
dodecode64(unsigned char *infile, LONGLONG a[], int nx, int ny, unsigned char nbitplanes[3])
{
int i, nel, nx2, ny2, stat;
nel = nx*ny;
nx2 = (nx+1)/2;
ny2 = (ny+1)/2;
for (i=0; i<nel; i++) a[i] = 0;
start_inputing_bits();
stat = qtree_decode64(infile, &a[0], ny, nx2, ny2, nbitplanes[0]);
if (stat) return(stat);
stat = qtree_decode64(infile, &a[ny2], ny, nx2, ny/2, nbitplanes[1]);
if (stat) return(stat);
stat = qtree_decode64(infile, &a[ny*nx2], ny, nx/2, ny2, nbitplanes[1]);
if (stat) return(stat);
stat = qtree_decode64(infile, &a[ny*nx2+ny2], ny, nx/2, ny/2, nbitplanes[2]);
if (stat) return(stat);
if (input_nybble(infile) != 0) {
ffpmsg("dodecode64: bad bit plane values");
return(DATA_DECOMPRESSION_ERR);
}
start_inputing_bits();
for (i=0; i<nel; i++) {
if (a[i]) {
if (input_bit(infile) != 0) a[i] = -a[i];
}
}
return(0);
}
static int
qtree_decode(unsigned char *infile, int a[], int n, int nqx, int nqy, int nbitplanes)
{
int log2n, k, bit, b, nqmax;
int nx,ny,nfx,nfy,c;
int nqx2, nqy2;
unsigned char *scratch;
nqmax = (nqx>nqy) ? nqx : nqy;
log2n = (int) (log((float) nqmax)/log(2.0)+0.5);
if (nqmax > (1<<log2n)) {
log2n += 1;
}
nqx2=(nqx+1)/2;
nqy2=(nqy+1)/2;
scratch = (unsigned char *) malloc(nqx2*nqy2);
if (scratch == (unsigned char *) NULL) {
ffpmsg("qtree_decode: insufficient memory");
return(DATA_DECOMPRESSION_ERR);
}
for (bit = nbitplanes-1; bit >= 0; bit--) {
b = input_nybble(infile);
if(b == 0) {
read_bdirect(infile,a,n,nqx,nqy,scratch,bit);
} else if (b != 0xf) {
ffpmsg("qtree_decode: bad format code");
return(DATA_DECOMPRESSION_ERR);
} else {
scratch[0] = input_huffman(infile);
nx = 1;
ny = 1;
nfx = nqx;
nfy = nqy;
c = 1<<log2n;
for (k = 1; k<log2n; k++) {
c = c>>1;
nx = nx<<1;
ny = ny<<1;
if (nfx <= c) { nx -= 1; } else { nfx -= c; }
if (nfy <= c) { ny -= 1; } else { nfy -= c; }
qtree_expand(infile,scratch,nx,ny,scratch);
}
qtree_bitins(scratch,nqx,nqy,a,n,bit);
}
}
free(scratch);
return(0);
}
static int
qtree_decode64(unsigned char *infile, LONGLONG a[], int n, int nqx, int nqy, int nbitplanes)
{
int log2n, k, bit, b, nqmax;
int nx,ny,nfx,nfy,c;
int nqx2, nqy2;
unsigned char *scratch;
nqmax = (nqx>nqy) ? nqx : nqy;
log2n = (int) (log((float) nqmax)/log(2.0)+0.5);
if (nqmax > (1<<log2n)) {
log2n += 1;
}
nqx2=(nqx+1)/2;
nqy2=(nqy+1)/2;
scratch = (unsigned char *) malloc(nqx2*nqy2);
if (scratch == (unsigned char *) NULL) {
ffpmsg("qtree_decode64: insufficient memory");
return(DATA_DECOMPRESSION_ERR);
}
for (bit = nbitplanes-1; bit >= 0; bit--) {
b = input_nybble(infile);
if(b == 0) {
read_bdirect64(infile,a,n,nqx,nqy,scratch,bit);
} else if (b != 0xf) {
ffpmsg("qtree_decode64: bad format code");
return(DATA_DECOMPRESSION_ERR);
} else {
scratch[0] = input_huffman(infile);
nx = 1;
ny = 1;
nfx = nqx;
nfy = nqy;
c = 1<<log2n;
for (k = 1; k<log2n; k++) {
c = c>>1;
nx = nx<<1;
ny = ny<<1;
if (nfx <= c) { nx -= 1; } else { nfx -= c; }
if (nfy <= c) { ny -= 1; } else { nfy -= c; }
qtree_expand(infile,scratch,nx,ny,scratch);
}
qtree_bitins64(scratch,nqx,nqy,a,n,bit);
}
}
free(scratch);
return(0);
}
static void
qtree_expand(unsigned char *infile, unsigned char a[], int nx, int ny, unsigned char b[])
{
int i;
qtree_copy(a,nx,ny,b,ny);
for (i = nx*ny-1; i >= 0; i--) {
if (b[i]) b[i] = input_huffman(infile);
}
}
static void
qtree_copy(unsigned char a[], int nx, int ny, unsigned char b[], int n)
{
int i, j, k, nx2, ny2;
int s00, s10;
nx2 = (nx+1)/2;
ny2 = (ny+1)/2;
k = ny2*(nx2-1)+ny2-1;
for (i = nx2-1; i >= 0; i--) {
s00 = 2*(n*i+ny2-1);
for (j = ny2-1; j >= 0; j--) {
b[s00] = a[k];
k -= 1;
s00 -= 2;
}
}
for (i = 0; i<nx-1; i += 2) {
s00 = n*i;
s10 = s00+n;
for (j = 0; j<ny-1; j += 2) {
switch (b[s00]) {
case(0):
b[s10+1] = 0;
b[s10 ] = 0;
b[s00+1] = 0;
b[s00 ] = 0;
break;
case(1):
b[s10+1] = 1;
b[s10 ] = 0;
b[s00+1] = 0;
b[s00 ] = 0;
break;
case(2):
b[s10+1] = 0;
b[s10 ] = 1;
b[s00+1] = 0;
b[s00 ] = 0;
break;
case(3):
b[s10+1] = 1;
b[s10 ] = 1;
b[s00+1] = 0;
b[s00 ] = 0;
break;
case(4):
b[s10+1] = 0;
b[s10 ] = 0;
b[s00+1] = 1;
b[s00 ] = 0;
break;
case(5):
b[s10+1] = 1;
b[s10 ] = 0;
b[s00+1] = 1;
b[s00 ] = 0;
break;
case(6):
b[s10+1] = 0;
b[s10 ] = 1;
b[s00+1] = 1;
b[s00 ] = 0;
break;
case(7):
b[s10+1] = 1;
b[s10 ] = 1;
b[s00+1] = 1;
b[s00 ] = 0;
break;
case(8):
b[s10+1] = 0;
b[s10 ] = 0;
b[s00+1] = 0;
b[s00 ] = 1;
break;
case(9):
b[s10+1] = 1;
b[s10 ] = 0;
b[s00+1] = 0;
b[s00 ] = 1;
break;
case(10):
b[s10+1] = 0;
b[s10 ] = 1;
b[s00+1] = 0;
b[s00 ] = 1;
break;
case(11):
b[s10+1] = 1;
b[s10 ] = 1;
b[s00+1] = 0;
b[s00 ] = 1;
break;
case(12):
b[s10+1] = 0;
b[s10 ] = 0;
b[s00+1] = 1;
b[s00 ] = 1;
break;
case(13):
b[s10+1] = 1;
b[s10 ] = 0;
b[s00+1] = 1;
b[s00 ] = 1;
break;
case(14):
b[s10+1] = 0;
b[s10 ] = 1;
b[s00+1] = 1;
b[s00 ] = 1;
break;
case(15):
b[s10+1] = 1;
b[s10 ] = 1;
b[s00+1] = 1;
b[s00 ] = 1;
break;
}
s00 += 2;
s10 += 2;
}
if (j < ny) {
b[s10 ] = (b[s00]>>1) & 1;
b[s00 ] = (b[s00]>>3) & 1;
}
}
if (i < nx) {
s00 = n*i;
for (j = 0; j<ny-1; j += 2) {
b[s00+1] = (b[s00]>>2) & 1;
b[s00 ] = (b[s00]>>3) & 1;
s00 += 2;
}
if (j < ny) {
b[s00 ] = (b[s00]>>3) & 1;
}
}
}
static void
qtree_bitins(unsigned char a[], int nx, int ny, int b[], int n, int bit)
{
int i, j, k;
int s00;
int plane_val;
plane_val = 1 << bit;
k = 0;
for (i = 0; i<nx-1; i += 2) {
s00 = n*i;
for (j = 0; j<ny-1; j += 2) {
switch (a[k]) {
case(0):
break;
case(1):
b[s00+n+1] |= plane_val;
break;
case(2):
b[s00+n ] |= plane_val;
break;
case(3):
b[s00+n+1] |= plane_val;
b[s00+n ] |= plane_val;
break;
case(4):
b[s00+1] |= plane_val;
break;
case(5):
b[s00+n+1] |= plane_val;
b[s00+1] |= plane_val;
break;
case(6):
b[s00+n ] |= plane_val;
b[s00+1] |= plane_val;
break;
case(7):
b[s00+n+1] |= plane_val;
b[s00+n ] |= plane_val;
b[s00+1] |= plane_val;
break;
case(8):
b[s00 ] |= plane_val;
break;
case(9):
b[s00+n+1] |= plane_val;
b[s00 ] |= plane_val;
break;
case(10):
b[s00+n ] |= plane_val;
b[s00 ] |= plane_val;
break;
case(11):
b[s00+n+1] |= plane_val;
b[s00+n ] |= plane_val;
b[s00 ] |= plane_val;
break;
case(12):
b[s00+1] |= plane_val;
b[s00 ] |= plane_val;
break;
case(13):
b[s00+n+1] |= plane_val;
b[s00+1] |= plane_val;
b[s00 ] |= plane_val;
break;
case(14):
b[s00+n ] |= plane_val;
b[s00+1] |= plane_val;
b[s00 ] |= plane_val;
break;
case(15):
b[s00+n+1] |= plane_val;
b[s00+n ] |= plane_val;
b[s00+1] |= plane_val;
b[s00 ] |= plane_val;
break;
}
s00 += 2;
k += 1;
}
if (j < ny) {
switch (a[k]) {
case(0):
break;
case(1):
break;
case(2):
b[s00+n ] |= plane_val;
break;
case(3):
b[s00+n ] |= plane_val;
break;
case(4):
break;
case(5):
break;
case(6):
b[s00+n ] |= plane_val;
break;
case(7):
b[s00+n ] |= plane_val;
break;
case(8):
b[s00 ] |= plane_val;
break;
case(9):
b[s00 ] |= plane_val;
break;
case(10):
b[s00+n ] |= plane_val;
b[s00 ] |= plane_val;
break;
case(11):
b[s00+n ] |= plane_val;
b[s00 ] |= plane_val;
break;
case(12):
b[s00 ] |= plane_val;
break;
case(13):
b[s00 ] |= plane_val;
break;
case(14):
b[s00+n ] |= plane_val;
b[s00 ] |= plane_val;
break;
case(15):
b[s00+n ] |= plane_val;
b[s00 ] |= plane_val;
break;
}
k += 1;
}
}
if (i < nx) {
s00 = n*i;
for (j = 0; j<ny-1; j += 2) {
switch (a[k]) {
case(0):
break;
case(1):
break;
case(2):
break;
case(3):
break;
case(4):
b[s00+1] |= plane_val;
break;
case(5):
b[s00+1] |= plane_val;
break;
case(6):
b[s00+1] |= plane_val;
break;
case(7):
b[s00+1] |= plane_val;
break;
case(8):
b[s00 ] |= plane_val;
break;
case(9):
b[s00 ] |= plane_val;
break;
case(10):
b[s00 ] |= plane_val;
break;
case(11):
b[s00 ] |= plane_val;
break;
case(12):
b[s00+1] |= plane_val;
b[s00 ] |= plane_val;
break;
case(13):
b[s00+1] |= plane_val;
b[s00 ] |= plane_val;
break;
case(14):
b[s00+1] |= plane_val;
b[s00 ] |= plane_val;
break;
case(15):
b[s00+1] |= plane_val;
b[s00 ] |= plane_val;
break;
}
s00 += 2;
k += 1;
}
if (j < ny) {
switch (a[k]) {
case(0):
break;
case(1):
break;
case(2):
break;
case(3):
break;
case(4):
break;
case(5):
break;
case(6):
break;
case(7):
break;
case(8):
b[s00 ] |= plane_val;
break;
case(9):
b[s00 ] |= plane_val;
break;
case(10):
b[s00 ] |= plane_val;
break;
case(11):
b[s00 ] |= plane_val;
break;
case(12):
b[s00 ] |= plane_val;
break;
case(13):
b[s00 ] |= plane_val;
break;
case(14):
b[s00 ] |= plane_val;
break;
case(15):
b[s00 ] |= plane_val;
break;
}
k += 1;
}
}
}
static void
qtree_bitins64(unsigned char a[], int nx, int ny, LONGLONG b[], int n, int bit)
{
int i, j, k;
int s00;
LONGLONG plane_val;
plane_val = ((LONGLONG) 1) << bit;
k = 0;
for (i = 0; i<nx-1; i += 2) {
s00 = n*i;
for (j = 0; j<ny-1; j += 2) {
switch (a[k]) {
case(0):
break;
case(1):
b[s00+n+1] |= plane_val;
break;
case(2):
b[s00+n ] |= plane_val;
break;
case(3):
b[s00+n+1] |= plane_val;
b[s00+n ] |= plane_val;
break;
case(4):
b[s00+1] |= plane_val;
break;
case(5):
b[s00+n+1] |= plane_val;
b[s00+1] |= plane_val;
break;
case(6):
b[s00+n ] |= plane_val;
b[s00+1] |= plane_val;
break;
case(7):
b[s00+n+1] |= plane_val;
b[s00+n ] |= plane_val;
b[s00+1] |= plane_val;
break;
case(8):
b[s00 ] |= plane_val;
break;
case(9):
b[s00+n+1] |= plane_val;
b[s00 ] |= plane_val;
break;
case(10):
b[s00+n ] |= plane_val;
b[s00 ] |= plane_val;
break;
case(11):
b[s00+n+1] |= plane_val;
b[s00+n ] |= plane_val;
b[s00 ] |= plane_val;
break;
case(12):
b[s00+1] |= plane_val;
b[s00 ] |= plane_val;
break;
case(13):
b[s00+n+1] |= plane_val;
b[s00+1] |= plane_val;
b[s00 ] |= plane_val;
break;
case(14):
b[s00+n ] |= plane_val;
b[s00+1] |= plane_val;
b[s00 ] |= plane_val;
break;
case(15):
b[s00+n+1] |= plane_val;
b[s00+n ] |= plane_val;
b[s00+1] |= plane_val;
b[s00 ] |= plane_val;
break;
}
s00 += 2;
k += 1;
}
if (j < ny) {
switch (a[k]) {
case(0):
break;
case(1):
break;
case(2):
b[s00+n ] |= plane_val;
break;
case(3):
b[s00+n ] |= plane_val;
break;
case(4):
break;
case(5):
break;
case(6):
b[s00+n ] |= plane_val;
break;
case(7):
b[s00+n ] |= plane_val;
break;
case(8):
b[s00 ] |= plane_val;
break;
case(9):
b[s00 ] |= plane_val;
break;
case(10):
b[s00+n ] |= plane_val;
b[s00 ] |= plane_val;
break;
case(11):
b[s00+n ] |= plane_val;
b[s00 ] |= plane_val;
break;
case(12):
b[s00 ] |= plane_val;
break;
case(13):
b[s00 ] |= plane_val;
break;
case(14):
b[s00+n ] |= plane_val;
b[s00 ] |= plane_val;
break;
case(15):
b[s00+n ] |= plane_val;
b[s00 ] |= plane_val;
break;
}
k += 1;
}
}
if (i < nx) {
s00 = n*i;
for (j = 0; j<ny-1; j += 2) {
switch (a[k]) {
case(0):
break;
case(1):
break;
case(2):
break;
case(3):
break;
case(4):
b[s00+1] |= plane_val;
break;
case(5):
b[s00+1] |= plane_val;
break;
case(6):
b[s00+1] |= plane_val;
break;
case(7):
b[s00+1] |= plane_val;
break;
case(8):
b[s00 ] |= plane_val;
break;
case(9):
b[s00 ] |= plane_val;
break;
case(10):
b[s00 ] |= plane_val;
break;
case(11):
b[s00 ] |= plane_val;
break;
case(12):
b[s00+1] |= plane_val;
b[s00 ] |= plane_val;
break;
case(13):
b[s00+1] |= plane_val;
b[s00 ] |= plane_val;
break;
case(14):
b[s00+1] |= plane_val;
b[s00 ] |= plane_val;
break;
case(15):
b[s00+1] |= plane_val;
b[s00 ] |= plane_val;
break;
}
s00 += 2;
k += 1;
}
if (j < ny) {
switch (a[k]) {
case(0):
break;
case(1):
break;
case(2):
break;
case(3):
break;
case(4):
break;
case(5):
break;
case(6):
break;
case(7):
break;
case(8):
b[s00 ] |= plane_val;
break;
case(9):
b[s00 ] |= plane_val;
break;
case(10):
b[s00 ] |= plane_val;
break;
case(11):
b[s00 ] |= plane_val;
break;
case(12):
b[s00 ] |= plane_val;
break;
case(13):
b[s00 ] |= plane_val;
break;
case(14):
b[s00 ] |= plane_val;
break;
case(15):
b[s00 ] |= plane_val;
break;
}
k += 1;
}
}
}
static void
read_bdirect(unsigned char *infile, int a[], int n, int nqx, int nqy, unsigned char scratch[], int bit)
{
input_nnybble(infile, ((nqx+1)/2) * ((nqy+1)/2), scratch);
qtree_bitins(scratch,nqx,nqy,a,n,bit);
}
static void
read_bdirect64(unsigned char *infile, LONGLONG a[], int n, int nqx, int nqy, unsigned char scratch[], int bit)
{
input_nnybble(infile, ((nqx+1)/2) * ((nqy+1)/2), scratch);
qtree_bitins64(scratch,nqx,nqy,a,n,bit);
}
static int input_huffman(unsigned char *infile)
{
int c;
c = input_nbits(infile,3);
if (c < 4) {
return(1<<c);
}
c = input_bit(infile) | (c<<1);
if (c < 13) {
switch (c) {
case 8 : return(3);
case 9 : return(5);
case 10 : return(10);
case 11 : return(12);
case 12 : return(15);
}
}
c = input_bit(infile) | (c<<1);
if (c < 31) {
switch (c) {
case 26 : return(6);
case 27 : return(7);
case 28 : return(9);
case 29 : return(11);
case 30 : return(13);
}
}
c = input_bit(infile) | (c<<1);
if (c == 62) {
return(0);
} else {
return(14);
}
}
static int readint(unsigned char *infile)
{
int a,i;
unsigned char b[4];
for (i=0; i<4; i++) qread(infile,(char *) &b[i],1);
a = b[0];
for (i=1; i<4; i++) a = (a<<8) + b[i];
return(a);
}
static LONGLONG readlonglong(unsigned char *infile)
{
int i;
LONGLONG a;
unsigned char b[8];
for (i=0; i<8; i++) qread(infile,(char *) &b[i],1);
a = b[0];
for (i=1; i<8; i++) a = (a<<8) + b[i];
return(a);
}
static void qread(unsigned char *file, char buffer[], int n)
{
memcpy(buffer, &file[nextchar], n);
nextchar += n;
}
static int buffer2;
static int bits_to_go;
static void start_inputing_bits(void)
{
bits_to_go = 0;
}
static int input_bit(unsigned char *infile)
{
if (bits_to_go == 0) {
buffer2 = infile[nextchar];
nextchar++;
bits_to_go = 8;
}
bits_to_go -= 1;
return((buffer2>>bits_to_go) & 1);
}
static int input_nbits(unsigned char *infile, int n)
{
static int mask[9] = {0, 1, 3, 7, 15, 31, 63, 127, 255};
if (bits_to_go < n) {
buffer2 = (buffer2<<8) | (int) infile[nextchar];
nextchar++;
bits_to_go += 8;
}
bits_to_go -= n;
return( (buffer2>>bits_to_go) & (*(mask+n)) );
}
static int input_nybble(unsigned char *infile)
{
if (bits_to_go < 4) {
buffer2 = (buffer2<<8) | (int) infile[nextchar];
nextchar++;
bits_to_go += 8;
}
bits_to_go -= 4;
return( (buffer2>>bits_to_go) & 15 );
}
static int input_nnybble(unsigned char *infile, int n, unsigned char array[])
{
int ii, kk, shift1, shift2;
if (n == 1) {
array[0] = input_nybble(infile);
return(0);
}
if (bits_to_go == 8) {
nextchar--;
bits_to_go = 0;
}
shift1 = bits_to_go + 4;
shift2 = bits_to_go;
kk = 0;
if (bits_to_go == 0)
{
for (ii = 0; ii < n/2; ii++) {
buffer2 = (buffer2<<8) | (int) infile[nextchar];
nextchar++;
array[kk] = (int) ((buffer2>>4) & 15);
array[kk + 1] = (int) ((buffer2) & 15);
kk += 2;
}
}
else
{
for (ii = 0; ii < n/2; ii++) {
buffer2 = (buffer2<<8) | (int) infile[nextchar];
nextchar++;
array[kk] = (int) ((buffer2>>shift1) & 15);
array[kk + 1] = (int) ((buffer2>>shift2) & 15);
kk += 2;
}
}
if (ii * 2 != n) {
array[n-1] = input_nybble(infile);
}
return( (buffer2>>bits_to_go) & 15 );
}