/*  #########################################################################
These routines to apply the H-compress decompression algorithm to a 2-D Fits
image were written by R. White at the STScI and were obtained from the STScI at
http://www.stsci.edu/software/hcompress.html

This source file is a concatination of the following sources files in the
original distribution 
  hinv.c 
  hsmooth.c 
  undigitize.c 
  decode.c 
  dodecode.c 
  qtree_decode.c 
  qread.c 
  bit_input.c


The following modifications have been made to the original code:

  - commented out redundant "include" statements
  - added the nextchar global variable 
  - changed all the 'extern' declarations to 'static', since all the routines are in
    the same source file
  - changed the first parameter in decode (and in lower level routines from a file stream
    to a char array
  - modified the myread routine, and lower level byte reading routines,  to copy 
    the input bytes to a char array, instead of reading them from a file stream
  - changed the function declarations to the more modern ANSI C style
  - changed calls to printf and perror to call the CFITSIO ffpmsg routine
  - replace "exit" statements with "return" statements

 ############################################################################  */
 
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include "fitsio2.h"

/* WDP added test to see if min and max are already defined */
#ifndef min
#define min(a,b)        (((a)<(b))?(a):(b))
#endif
#ifndef max
#define max(a,b)        (((a)>(b))?(a):(b))
#endif

#define input_nybble(infile)	input_nbits(infile,4)

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();
static int input_bit(unsigned char *infile);
static int input_nbits(unsigned char *infile, int n);

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);
static int  myread(unsigned char *file, char buffer[], int n);

/* ---------------------------------------------------------------------- */
int fits_hdecompress(unsigned char *input, int smooth, int *a, int *ny, int *nx, 
                     int *scale, int *status)
{
  /* 
     decompress the input byte stream using the H-compress algorithm
  
   input  - input array of compressed bytes
   a - pre-allocated array to hold the output uncompressed image
   nx - returned X axis size
   ny - returned Y axis size

 NOTE: the nx and ny dimensions as defined within this code are reversed from
 the usual FITS notation.  ny is the fastest varying dimension, which is
 usually considered the X axis in the FITS image display

  */
int stat;

  if (*status > 0) return(*status);

	/* decode the input array */

	stat = decode(input, a, nx, ny, scale);
        *status = stat;
	if (stat) return(*status);
	
	/*
	 * Un-Digitize
	 */
	undigitize(a, *nx, *ny, *scale);

	/*
	 * Inverse H-transform
	 */
	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)
{
  /* 
     decompress the input byte stream using the H-compress algorithm
  
   input  - input array of compressed bytes
   a - pre-allocated array to hold the output uncompressed image
   nx - returned X axis size
   ny - returned Y axis size

 NOTE: the nx and ny dimensions as defined within this code are reversed from
 the usual FITS notation.  ny is the fastest varying dimension, which is
 usually considered the X axis in the FITS image display

  */
  int stat, *iarray, ii, nval;

  if (*status > 0) return(*status);

	/* decode the input array */

	stat = decode64(input, a, nx, ny, scale);
        *status = stat;
	if (stat) return(*status);
	
	/*
	 * Un-Digitize
	 */
	undigitize64(a, *nx, *ny, *scale);

	/*
	 * Inverse H-transform
	 */
	stat = hinv64(a, *nx, *ny, smooth, *scale);

        *status = stat;
	
         /* pack the I*8 values back into an I*4 array */
        iarray = (int *) a;
	nval = (*nx) * (*ny);

	for (ii = 0; ii < nval; ii++)
	   iarray[ii] = (int) a[ii];	

  return(*status);
}

/*  ############################################################################  */
/*  ############################################################################  */

/* Copyright (c) 1993 Association of Universities for Research 
 * in Astronomy. All rights reserved. Produced under National   
 * Aeronautics and Space Administration Contract No. NAS5-26555.
 */
/* hinv.c   Inverse H-transform of NX x NY integer image
 *
 * Programmer: R. White		Date: 23 July 1993
 */

/*  ############################################################################  */
static int 
hinv(int a[], int nx, int ny, int smooth ,int scale)
/*
int smooth;    0 for no smoothing, else smooth during inversion 
int scale;     used if smoothing is specified 
*/
{
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;

	/*
	 * log2n is log2 of max(nx,ny) rounded up to next power of 2
	 */
	nmax = (nx>ny) ? nx : ny;
	log2n = (int) (log((float) nmax)/log(2.0)+0.5);
	if ( nmax > (1<<log2n) ) {
		log2n += 1;
	}
	/*
	 * get temporary storage for shuffling elements
	 */  
	tmp = (int *) malloc(((nmax+1)/2)*sizeof(int));
	if (tmp == (int *) NULL) {
		ffpmsg("hinv: insufficient memory");
		return(DATA_DECOMPRESSION_ERR);
	}
	/*
	 * set up masks, rounding parameters
	 */
	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;
	/*
	 * round h0 to multiple of bit2
	 */
	a[0] = (a[0] + ((a[0] >= 0) ? prnd2 : nrnd2)) & mask2;
	/*
	 * do log2n expansions
	 *
	 * We're indexing a as a 2-D array with dimensions (nx,ny).
	 */
	nxtop = 1;
	nytop = 1;
	nxf = nx;
	nyf = ny;
	c = 1<<log2n;
	for (k = log2n-1; k>=0; k--) {
		/*
		 * this somewhat cryptic code generates the sequence
		 * ntop[k-1] = (ntop[k]+1)/2, where ntop[log2n] = n
		 */
		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; }
		/*
		 * double shift and fix nrnd0 (because prnd0=0) on last pass
		 */
		if (k == 0) {
			nrnd0 = 0;
			shift = 2;
		}
		/*
		 * unshuffle in each dimension to interleave coefficients
		 */
		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);
		}
		/*
		 * smooth by interpolating coefficients if SMOOTH != 0
		 */
		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;				/* s00 is index of a[i,j]	*/
			s10 = s00+ny;			/* s10 is index of a[i+1,j]	*/
			for (j = 0; j<nytop-oddy; j += 2) {
				h0 = a[s00  ];
				hx = a[s10  ];
				hy = a[s00+1];
				hc = a[s10+1];
				/*
				 * round hx and hy to multiple of bit1, hc to multiple of bit0
				 * h0 is already a multiple of bit2
				 */
				hx = (hx + ((hx >= 0) ? prnd1 : nrnd1)) & mask1;
				hy = (hy + ((hy >= 0) ? prnd1 : nrnd1)) & mask1;
				hc = (hc + ((hc >= 0) ? prnd0 : nrnd0)) & mask0;
				/*
				 * propagate bit0 of hc to hx,hy
				 */
				lowbit0 = hc & bit0;
				hx = (hx >= 0) ? (hx - lowbit0) : (hx + lowbit0);
				hy = (hy >= 0) ? (hy - lowbit0) : (hy + lowbit0);
				/*
				 * Propagate bits 0 and 1 of hc,hx,hy to h0.
				 * This could be simplified if we assume h0>0, but then
				 * the inversion would not be lossless for images with
				 * negative pixels.
				 */
				lowbit1 = (hc ^ hx ^ hy) & bit1;
				h0 = (h0 >= 0)
					? (h0 + lowbit0 - lowbit1)
					: (h0 + ((lowbit0 == 0) ? lowbit1 : (lowbit0-lowbit1)));
				/*
				 * Divide sums by 2 (4 last time)
				 */
				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) {
				/*
				 * do last element in row if row length is odd
				 * s00+1, s10+1 are off edge
				 */
				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) {
			/*
			 * do last row if column length is odd
			 * s10, s10+1 are off edge
			 */
			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) {
				/*
				 * do corner element if both row and column lengths are odd
				 * s00+1, s10, s10+1 are off edge
				 */
				h0 = a[s00  ];
				a[s00  ] = h0 >> shift;
			}
		}
		/*
		 * divide all the masks and rounding values by 2
		 */
		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 smooth;    0 for no smoothing, else smooth during inversion 
int scale;     used if smoothing is specified 
*/
{
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;

	/*
	 * log2n is log2 of max(nx,ny) rounded up to next power of 2
	 */
	nmax = (nx>ny) ? nx : ny;
	log2n = (int) (log((float) nmax)/log(2.0)+0.5);
	if ( nmax > (1<<log2n) ) {
		log2n += 1;
	}
	/*
	 * get temporary storage for shuffling elements
	 */  
	tmp = (LONGLONG *) malloc(((nmax+1)/2)*sizeof(LONGLONG));
	if (tmp == (LONGLONG *) NULL) {
		ffpmsg("hinv64: insufficient memory");
		return(DATA_DECOMPRESSION_ERR);
	}
	/*
	 * set up masks, rounding parameters
	 */
	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;
	/*
	 * round h0 to multiple of bit2
	 */
	a[0] = (a[0] + ((a[0] >= 0) ? prnd2 : nrnd2)) & mask2;
	/*
	 * do log2n expansions
	 *
	 * We're indexing a as a 2-D array with dimensions (nx,ny).
	 */
	nxtop = 1;
	nytop = 1;
	nxf = nx;
	nyf = ny;
	c = 1<<log2n;
	for (k = log2n-1; k>=0; k--) {
		/*
		 * this somewhat cryptic code generates the sequence
		 * ntop[k-1] = (ntop[k]+1)/2, where ntop[log2n] = n
		 */
		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; }
		/*
		 * double shift and fix nrnd0 (because prnd0=0) on last pass
		 */
		if (k == 0) {
			nrnd0 = 0;
			shift = 2;
		}
		/*
		 * unshuffle in each dimension to interleave coefficients
		 */
		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);
		}
		/*
		 * smooth by interpolating coefficients if SMOOTH != 0
		 */
		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;				/* s00 is index of a[i,j]	*/
			s10 = s00+ny;			/* s10 is index of a[i+1,j]	*/
			for (j = 0; j<nytop-oddy; j += 2) {
				h0 = a[s00  ];
				hx = a[s10  ];
				hy = a[s00+1];
				hc = a[s10+1];
				/*
				 * round hx and hy to multiple of bit1, hc to multiple of bit0
				 * h0 is already a multiple of bit2
				 */
				hx = (hx + ((hx >= 0) ? prnd1 : nrnd1)) & mask1;
				hy = (hy + ((hy >= 0) ? prnd1 : nrnd1)) & mask1;
				hc = (hc + ((hc >= 0) ? prnd0 : nrnd0)) & mask0;
				/*
				 * propagate bit0 of hc to hx,hy
				 */
				lowbit0 = hc & bit0;
				hx = (hx >= 0) ? (hx - lowbit0) : (hx + lowbit0);
				hy = (hy >= 0) ? (hy - lowbit0) : (hy + lowbit0);
				/*
				 * Propagate bits 0 and 1 of hc,hx,hy to h0.
				 * This could be simplified if we assume h0>0, but then
				 * the inversion would not be lossless for images with
				 * negative pixels.
				 */
				lowbit1 = (hc ^ hx ^ hy) & bit1;
				h0 = (h0 >= 0)
					? (h0 + lowbit0 - lowbit1)
					: (h0 + ((lowbit0 == 0) ? lowbit1 : (lowbit0-lowbit1)));
				/*
				 * Divide sums by 2 (4 last time)
				 */
				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) {
				/*
				 * do last element in row if row length is odd
				 * s00+1, s10+1 are off edge
				 */
				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) {
			/*
			 * do last row if column length is odd
			 * s10, s10+1 are off edge
			 */
			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) {
				/*
				 * do corner element if both row and column lengths are odd
				 * s00+1, s10, s10+1 are off edge
				 */
				h0 = a[s00  ];
				a[s00  ] = h0 >> shift;
			}
		}
		/*
		 * divide all the masks and rounding values by 2
		 */
		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 a[];	 array to shuffle					
int n;		 number of elements to shuffle	
int n2;		 second dimension					
int tmp[];	 scratch storage					
*/
{
int i;
int nhalf;
int *p1, *p2, *pt;
 
	/*
	 * copy 2nd half of array to tmp
	 */
	nhalf = (n+1)>>1;
	pt = tmp;
	p1 = &a[n2*nhalf];				/* pointer to a[i]			*/
	for (i=nhalf; i<n; i++) {
		*pt = *p1;
		p1 += n2;
		pt += 1;
	}
	/*
	 * distribute 1st half of array to even elements
	 */
	p2 = &a[ n2*(nhalf-1) ];		/* pointer to a[i]			*/
	p1 = &a[(n2*(nhalf-1))<<1];		/* pointer to a[2*i]		*/
	for (i=nhalf-1; i >= 0; i--) {
		*p1 = *p2;
		p2 -= n2;
		p1 -= (n2+n2);
	}
	/*
	 * now distribute 2nd half of array (in tmp) to odd elements
	 */
	pt = tmp;
	p1 = &a[n2];					/* pointer to a[i]			*/
	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[])
/*
LONGLONG a[];	 array to shuffle					
int n;		 number of elements to shuffle	
int n2;		 second dimension					
LONGLONG tmp[];	 scratch storage					
*/
{
int i;
int nhalf;
LONGLONG *p1, *p2, *pt;
 
	/*
	 * copy 2nd half of array to tmp
	 */
	nhalf = (n+1)>>1;
	pt = tmp;
	p1 = &a[n2*nhalf];				/* pointer to a[i]			*/
	for (i=nhalf; i<n; i++) {
		*pt = *p1;
		p1 += n2;
		pt += 1;
	}
	/*
	 * distribute 1st half of array to even elements
	 */
	p2 = &a[ n2*(nhalf-1) ];		/* pointer to a[i]			*/
	p1 = &a[(n2*(nhalf-1))<<1];		/* pointer to a[2*i]		*/
	for (i=nhalf-1; i >= 0; i--) {
		*p1 = *p2;
		p2 -= n2;
		p1 -= (n2+n2);
	}
	/*
	 * now distribute 2nd half of array (in tmp) to odd elements
	 */
	pt = tmp;
	p1 = &a[n2];					/* pointer to a[i]			*/
	for (i=1; i<n; i += 2) {
		*p1 = *pt;
		p1 += (n2+n2);
		pt += 1;
	}
}

/*  ############################################################################  */
/*  ############################################################################  */

/* Copyright (c) 1993 Association of Universities for Research 
 * in Astronomy. All rights reserved. Produced under National   
 * Aeronautics and Space Administration Contract No. NAS5-26555.
 */
/* hsmooth.c	Smooth H-transform image by adjusting coefficients toward
 *				interpolated values
 *
 * Programmer: R. White		Date: 13 April 1992
 */

/*  ############################################################################  */
static void 
hsmooth(int a[], int nxtop, int nytop, int ny, int scale)
/*
int a[];			 array of H-transform coefficients		
int nxtop,nytop;	 size of coefficient block to use			
int ny;				 actual 1st dimension of array			
int scale;			 truncation scale factor that was used	
*/
{
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;

	/*
	 * Maximum change in coefficients is determined by scale factor.
	 * Since we rounded during division (see digitize.c), the biggest
	 * permitted change is scale/2.
	 */
	smax = (scale >> 1);
	if (smax <= 0) return;
	ny2 = ny << 1;
	/*
	 * We're indexing a as a 2-D array with dimensions (nxtop,ny) of which
	 * only (nxtop,nytop) are used.  The coefficients on the edge of the
	 * array are not adjusted (which is why the loops below start at 2
	 * instead of 0 and end at nxtop-2 instead of nxtop.)
	 */
	/*
	 * Adjust x difference hx
	 */
	for (i = 2; i<nxtop-2; i += 2) {
		s00 = ny*i;				/* s00 is index of a[i,j]	*/
		s10 = s00+ny;			/* s10 is index of a[i+1,j]	*/
		for (j = 0; j<nytop; j += 2) {
			/*
			 * hp is h0 (mean value) in next x zone, hm is h0 in previous x zone
			 */
			hm = a[s00-ny2];
			h0 = a[s00];
			hp = a[s00+ny2];
			/*
			 * diff = 8 * hx slope that would match h0 in neighboring zones
			 */
			diff = hp-hm;
			/*
			 * monotonicity constraints on diff
			 */
			dmax = max( min( (hp-h0), (h0-hm) ), 0 ) << 2;
			dmin = min( max( (hp-h0), (h0-hm) ), 0 ) << 2;
			/*
			 * if monotonicity would set slope = 0 then don't change hx.
			 * note dmax>=0, dmin<=0.
			 */
			if (dmin < dmax) {
				diff = max( min(diff, dmax), dmin);
				/*
				 * Compute change in slope limited to range +/- smax.
				 * Careful with rounding negative numbers when using
				 * shift for divide by 8.
				 */
				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;
		}
	}
	/*
	 * Adjust y difference hy
	 */
	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;
		}
	}
	/*
	 * Adjust curvature difference hc
	 */
	for (i = 2; i<nxtop-2; i += 2) {
		s00 = ny*i+2;
		s10 = s00+ny;
		for (j = 2; j<nytop-2; j += 2) {
			/*
			 * ------------------    y
			 * | hmp |    | hpp |    |
			 * ------------------    |
			 * |     | h0 |     |    |
			 * ------------------    -------x
			 * | hmm |    | hpm |
			 * ------------------
			 */
			hmm = a[s00-ny2-2];
			hpm = a[s00+ny2-2];
			hmp = a[s00-ny2+2];
			hpp = a[s00+ny2+2];
			h0  = a[s00];
			/*
			 * diff = 64 * hc value that would match h0 in neighboring zones
			 */
			diff = hpp + hmm - hmp - hpm;
			/*
			 * 2 times x,y slopes in this zone
			 */
			hx2 = a[s10  ]<<1;
			hy2 = a[s00+1]<<1;
			/*
			 * monotonicity constraints on diff
			 */
			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 monotonicity would set slope = 0 then don't change hc.
			 * note dmax>=0, dmin<=0.
			 */
			if (dmin < dmax) {
				diff = max( min(diff, dmax), dmin);
				/*
				 * Compute change in slope limited to range +/- smax.
				 * Careful with rounding negative numbers when using
				 * shift for divide by 64.
				 */
				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)
/*
LONGLONG a[];			 array of H-transform coefficients		
int nxtop,nytop;	 size of coefficient block to use			
int ny;				 actual 1st dimension of array			
int scale;			 truncation scale factor that was used	
*/
{
int i, j;
int ny2, s10, s00;
LONGLONG hm, h0, hp, hmm, hpm, hmp, hpp, hx2, hy2, diff, dmax, dmin, s, smax, m1, m2;

	/*
	 * Maximum change in coefficients is determined by scale factor.
	 * Since we rounded during division (see digitize.c), the biggest
	 * permitted change is scale/2.
	 */
	smax = (scale >> 1);
	if (smax <= 0) return;
	ny2 = ny << 1;
	/*
	 * We're indexing a as a 2-D array with dimensions (nxtop,ny) of which
	 * only (nxtop,nytop) are used.  The coefficients on the edge of the
	 * array are not adjusted (which is why the loops below start at 2
	 * instead of 0 and end at nxtop-2 instead of nxtop.)
	 */
	/*
	 * Adjust x difference hx
	 */
	for (i = 2; i<nxtop-2; i += 2) {
		s00 = ny*i;				/* s00 is index of a[i,j]	*/
		s10 = s00+ny;			/* s10 is index of a[i+1,j]	*/
		for (j = 0; j<nytop; j += 2) {
			/*
			 * hp is h0 (mean value) in next x zone, hm is h0 in previous x zone
			 */
			hm = a[s00-ny2];
			h0 = a[s00];
			hp = a[s00+ny2];
			/*
			 * diff = 8 * hx slope that would match h0 in neighboring zones
			 */
			diff = hp-hm;
			/*
			 * monotonicity constraints on diff
			 */
			dmax = max( min( (hp-h0), (h0-hm) ), 0 ) << 2;
			dmin = min( max( (hp-h0), (h0-hm) ), 0 ) << 2;
			/*
			 * if monotonicity would set slope = 0 then don't change hx.
			 * note dmax>=0, dmin<=0.
			 */
			if (dmin < dmax) {
				diff = max( min(diff, dmax), dmin);
				/*
				 * Compute change in slope limited to range +/- smax.
				 * Careful with rounding negative numbers when using
				 * shift for divide by 8.
				 */
				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;
		}
	}
	/*
	 * Adjust y difference hy
	 */
	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;
		}
	}
	/*
	 * Adjust curvature difference hc
	 */
	for (i = 2; i<nxtop-2; i += 2) {
		s00 = ny*i+2;
		s10 = s00+ny;
		for (j = 2; j<nytop-2; j += 2) {
			/*
			 * ------------------    y
			 * | hmp |    | hpp |    |
			 * ------------------    |
			 * |     | h0 |     |    |
			 * ------------------    -------x
			 * | hmm |    | hpm |
			 * ------------------
			 */
			hmm = a[s00-ny2-2];
			hpm = a[s00+ny2-2];
			hmp = a[s00-ny2+2];
			hpp = a[s00+ny2+2];
			h0  = a[s00];
			/*
			 * diff = 64 * hc value that would match h0 in neighboring zones
			 */
			diff = hpp + hmm - hmp - hpm;
			/*
			 * 2 times x,y slopes in this zone
			 */
			hx2 = a[s10  ]<<1;
			hy2 = a[s00+1]<<1;
			/*
			 * monotonicity constraints on diff
			 */
			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 monotonicity would set slope = 0 then don't change hc.
			 * note dmax>=0, dmin<=0.
			 */
			if (dmin < dmax) {
				diff = max( min(diff, dmax), dmin);
				/*
				 * Compute change in slope limited to range +/- smax.
				 * Careful with rounding negative numbers when using
				 * shift for divide by 64.
				 */
				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;
		}
	}
}


/*  ############################################################################  */
/*  ############################################################################  */
/* Copyright (c) 1993 Association of Universities for Research 
 * in Astronomy. All rights reserved. Produced under National   
 * Aeronautics and Space Administration Contract No. NAS5-26555.
 */
/* undigitize.c		undigitize H-transform
 *
 * Programmer: R. White		Date: 9 May 1991
 */

/*  ############################################################################  */
static void
undigitize(int a[], int nx, int ny, int scale)
{
int *p;

	/*
	 * multiply by scale
	 */
	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;

	/*
	 * multiply by scale
	 */
	if (scale <= 1) return;
	scale64 = (LONGLONG) scale;   /* use a 64-bit int for efficiency in the big loop */
	
	for (p=a; p <= &a[nx*ny-1]; p++) *p = (*p)*scale64;
}

/*  ############################################################################  */
/*  ############################################################################  */
/* Copyright (c) 1993 Association of Universities for Research 
 * in Astronomy. All rights reserved. Produced under National   
 * Aeronautics and Space Administration Contract No. NAS5-26555.
 */
/* decode.c		read codes from infile and construct array
 *
 * Programmer: R. White		Date: 2 February 1994
 */


static char code_magic[2] = { (char)0xDD, (char)0x99 };

/*  ############################################################################  */
static int decode(unsigned char *infile, int *a, int *nx, int *ny, int *scale)
/*
char *infile;				 input file							
int  *a;				 address of output array [nx][ny]		
int  *nx,*ny;				 size of output array					
int  *scale;				 scale factor for digitization		
*/
{
LONGLONG sumall;
int nel, stat;
unsigned char nbitplanes[3];
char tmagic[2];

	/* initialize the byte read position to the beginning of the array */;
	nextchar = 0;
	
	/*
	 * File starts either with special 2-byte magic code or with
	 * FITS keyword "SIMPLE  ="
	 */
	qread(infile, tmagic, sizeof(tmagic));
	/*
	 * check for correct magic code value
	 */
	if (memcmp(tmagic,code_magic,sizeof(code_magic)) != 0) {
		ffpmsg("bad file format");
		return(DATA_DECOMPRESSION_ERR);
	}
	*nx =readint(infile);				/* x size of image			*/
	*ny =readint(infile);				/* y size of image			*/
	*scale=readint(infile);				/* scale factor for digitization	*/
	
	nel = (*nx) * (*ny);

	/* sum of all pixels	*/
	sumall=readlonglong(infile);
	/* # bits in quadrants	*/

	qread(infile, (char *) nbitplanes, sizeof(nbitplanes));

	stat = dodecode(infile, a, *nx, *ny, nbitplanes);
	/*
	 * put sum of all pixels back into pixel 0
	 */
	a[0] = (int) sumall;
	return(stat);
}
/*  ############################################################################  */
static int decode64(unsigned char *infile, LONGLONG *a, int *nx, int *ny, int *scale)
/*
char *infile;				 input file							
LONGLONG  *a;				 address of output array [nx][ny]		
int  *nx,*ny;				 size of output array					
int  *scale;				 scale factor for digitization		
*/
{
int nel, stat;
LONGLONG sumall;
unsigned char nbitplanes[3];
char tmagic[2];

	/* initialize the byte read position to the beginning of the array */;
	nextchar = 0;
	
	/*
	 * File starts either with special 2-byte magic code or with
	 * FITS keyword "SIMPLE  ="
	 */
	qread(infile, tmagic, sizeof(tmagic));
	/*
	 * check for correct magic code value
	 */
	if (memcmp(tmagic,code_magic,sizeof(code_magic)) != 0) {
		ffpmsg("bad file format");
		return(DATA_DECOMPRESSION_ERR);
	}
	*nx =readint(infile);				/* x size of image			*/
	*ny =readint(infile);				/* y size of image			*/
	*scale=readint(infile);				/* scale factor for digitization	*/
	
	nel = (*nx) * (*ny);

	/* sum of all pixels	*/
	sumall=readlonglong(infile);
	/* # bits in quadrants	*/

	qread(infile, (char *) nbitplanes, sizeof(nbitplanes));

	stat = dodecode64(infile, a, *nx, *ny, nbitplanes);
	/*
	 * put sum of all pixels back into pixel 0
	 */
	a[0] = sumall;

	return(stat);
}


/*  ############################################################################  */
/*  ############################################################################  */
/* Copyright (c) 1993 Association of Universities for Research 
 * in Astronomy. All rights reserved. Produced under National   
 * Aeronautics and Space Administration Contract No. NAS5-26555.
 */
/* dodecode.c	Decode stream of characters on infile and return array
 *
 * This version encodes the different quadrants separately
 *
 * Programmer: R. White		Date: 9 May 1991
 */

/*  ############################################################################  */
static int
dodecode(unsigned char *infile, int a[], int nx, int ny, unsigned char nbitplanes[3])

/* int a[];					 			
   int nx,ny;					 Array dimensions are [nx][ny]		
   unsigned char nbitplanes[3];		 Number of bit planes in quadrants
*/
{
int i, nel, nx2, ny2, stat;

	nel = nx*ny;
	nx2 = (nx+1)/2;
	ny2 = (ny+1)/2;

	/*
	 * initialize a to zero
	 */
	for (i=0; i<nel; i++) a[i] = 0;
	/*
	 * Initialize bit input
	 */
	start_inputing_bits();
	/*
	 * read bit planes for each quadrant
	 */
	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);
	
	/*
	 * make sure there is an EOF symbol (nybble=0) at end
	 */
	if (input_nybble(infile) != 0) {
		ffpmsg("dodecode: bad bit plane values");
		return(DATA_DECOMPRESSION_ERR);
	}
	/*
	 * now get the sign bits
	 * Re-initialize bit input
	 */
	start_inputing_bits();
	for (i=0; i<nel; i++) {
		if (a[i] != 0) {
			if (input_bit(infile) != 0) a[i] = -a[i];
		}
	}
	return(0);
}
/*  ############################################################################  */
static int
dodecode64(unsigned char *infile, LONGLONG a[], int nx, int ny, unsigned char nbitplanes[3])

/* LONGLONG a[];					 			
   int nx,ny;					 Array dimensions are [nx][ny]		
   unsigned char nbitplanes[3];		 Number of bit planes in quadrants
*/
{
int i, nel, nx2, ny2, stat;

	nel = nx*ny;
	nx2 = (nx+1)/2;
	ny2 = (ny+1)/2;

	/*
	 * initialize a to zero
	 */
	for (i=0; i<nel; i++) a[i] = 0;
	/*
	 * Initialize bit input
	 */
	start_inputing_bits();
	/*
	 * read bit planes for each quadrant
	 */
	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);
	
	/*
	 * make sure there is an EOF symbol (nybble=0) at end
	 */
	if (input_nybble(infile) != 0) {
		ffpmsg("dodecode64: bad bit plane values");
		return(DATA_DECOMPRESSION_ERR);
	}
	/*
	 * now get the sign bits
	 * Re-initialize bit input
	 */
	start_inputing_bits();
	for (i=0; i<nel; i++) {
		if (a[i] != 0) {
			if (input_bit(infile) != 0) a[i] = -a[i];
		}
	}
	return(0);
}

/*  ############################################################################  */
/*  ############################################################################  */
/* Copyright (c) 1993 Association of Universities for Research 
 * in Astronomy. All rights reserved. Produced under National   
 * Aeronautics and Space Administration Contract No. NAS5-26555.
 */
/* qtree_decode.c	Read stream of codes from infile and construct bit planes
 *					in quadrant of 2-D array using binary quadtree coding
 *
 * Programmer: R. White		Date: 7 May 1991
 */

/*  ############################################################################  */
static int
qtree_decode(unsigned char *infile, int a[], int n, int nqx, int nqy, int nbitplanes)

/*
char *infile;
int a[];				 a is 2-D array with dimensions (n,n)	
int n;					 length of full row in a				
int nqx;				 partial length of row to decode		
int nqy;				 partial length of column (<=n)		
int nbitplanes;				 number of bitplanes to decode		
*/
{
int log2n, k, bit, b, nqmax;
int nx,ny,nfx,nfy,c;
int nqx2, nqy2;
unsigned char *scratch;

	/*
	 * log2n is log2 of max(nqx,nqy) rounded up to next power of 2
	 */
	nqmax = (nqx>nqy) ? nqx : nqy;
	log2n = (int) (log((float) nqmax)/log(2.0)+0.5);
	if (nqmax > (1<<log2n)) {
		log2n += 1;
	}
	/*
	 * allocate scratch array for working space
	 */
	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);
	}
	/*
	 * now decode each bit plane, starting at the top
	 * A is assumed to be initialized to zero
	 */
	for (bit = nbitplanes-1; bit >= 0; bit--) {
		/*
		 * Was bitplane was quadtree-coded or written directly?
		 */
		b = input_nybble(infile);

		if(b == 0) {
			/*
			 * bit map was written directly
			 */
			read_bdirect(infile,a,n,nqx,nqy,scratch,bit);
		} else if (b != 0xf) {
			ffpmsg("qtree_decode: bad format code");
			return(DATA_DECOMPRESSION_ERR);
		} else {
			/*
			 * bitmap was quadtree-coded, do log2n expansions
			 *
			 * read first code
			 */
			scratch[0] = input_huffman(infile);
			/*
			 * now do log2n expansions, reading codes from file as necessary
			 */
			nx = 1;
			ny = 1;
			nfx = nqx;
			nfy = nqy;
			c = 1<<log2n;
			for (k = 1; k<log2n; k++) {
				/*
				 * this somewhat cryptic code generates the sequence
				 * n[k-1] = (n[k]+1)/2 where n[log2n]=nqx or nqy
				 */
				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);
			}
			/*
			 * now copy last set of 4-bit codes to bitplane bit of array a
			 */
			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)

/*
char *infile;
LONGLONG a[];				 a is 2-D array with dimensions (n,n)	
int n;					 length of full row in a				
int nqx;				 partial length of row to decode		
int nqy;				 partial length of column (<=n)		
int nbitplanes;				 number of bitplanes to decode		
*/
{
int log2n, k, bit, b, nqmax;
int nx,ny,nfx,nfy,c;
int nqx2, nqy2;
unsigned char *scratch;

	/*
	 * log2n is log2 of max(nqx,nqy) rounded up to next power of 2
	 */
	nqmax = (nqx>nqy) ? nqx : nqy;
	log2n = (int) (log((float) nqmax)/log(2.0)+0.5);
	if (nqmax > (1<<log2n)) {
		log2n += 1;
	}
	/*
	 * allocate scratch array for working space
	 */
	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);
	}
	/*
	 * now decode each bit plane, starting at the top
	 * A is assumed to be initialized to zero
	 */
	for (bit = nbitplanes-1; bit >= 0; bit--) {
		/*
		 * Was bitplane was quadtree-coded or written directly?
		 */
		b = input_nybble(infile);

		if(b == 0) {
			/*
			 * bit map was written directly
			 */
			read_bdirect64(infile,a,n,nqx,nqy,scratch,bit);
		} else if (b != 0xf) {
			ffpmsg("qtree_decode64: bad format code");
			return(DATA_DECOMPRESSION_ERR);
		} else {
			/*
			 * bitmap was quadtree-coded, do log2n expansions
			 *
			 * read first code
			 */
			scratch[0] = input_huffman(infile);
			/*
			 * now do log2n expansions, reading codes from file as necessary
			 */
			nx = 1;
			ny = 1;
			nfx = nqx;
			nfy = nqy;
			c = 1<<log2n;
			for (k = 1; k<log2n; k++) {
				/*
				 * this somewhat cryptic code generates the sequence
				 * n[k-1] = (n[k]+1)/2 where n[log2n]=nqx or nqy
				 */
				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);
			}
			/*
			 * now copy last set of 4-bit codes to bitplane bit of array a
			 */
			qtree_bitins64(scratch,nqx,nqy,a,n,bit);
		}
	}
	free(scratch);
	return(0);
}


/*  ############################################################################  */
/*
 * do one quadtree expansion step on array a[(nqx+1)/2,(nqy+1)/2]
 * results put into b[nqx,nqy] (which may be the same as a)
 */
static void
qtree_expand(unsigned char *infile, unsigned char a[], int nx, int ny, unsigned char b[])
{
int i;

	/*
	 * first copy a to b, expanding each 4-bit value
	 */
	qtree_copy(a,nx,ny,b,ny);
	/*
	 * now read new 4-bit values into b for each non-zero element
	 */
	for (i = nx*ny-1; i >= 0; i--) {
		if (b[i] != 0) b[i] = input_huffman(infile);
	}
}

/*  ############################################################################  */
/*
 * copy 4-bit values from a[(nx+1)/2,(ny+1)/2] to b[nx,ny], expanding
 * each value to 2x2 pixels
 * a,b may be same array
 */
static void
qtree_copy(unsigned char a[], int nx, int ny, unsigned char b[], int n)
/*   int n;		declared y dimension of b */
{
int i, j, k, nx2, ny2;
int s00, s10;

	/*
	 * first copy 4-bit values to b
	 * start at end in case a,b are same array
	 */
	nx2 = (nx+1)/2;
	ny2 = (ny+1)/2;
	k = ny2*(nx2-1)+ny2-1;			/* k   is index of a[i,j]			*/
	for (i = nx2-1; i >= 0; i--) {
		s00 = 2*(n*i+ny2-1);		/* s00 is index of b[2*i,2*j]		*/
		for (j = ny2-1; j >= 0; j--) {
			b[s00] = a[k];
			k -= 1;
			s00 -= 2;
		}
	}
	/*
	 * now expand each 2x2 block
	 */
	for (i = 0; i<nx-1; i += 2) {
		s00 = n*i;					/* s00 is index of b[i,j]	*/
		s10 = s00+n;				/* s10 is index of b[i+1,j]	*/
		for (j = 0; j<ny-1; j += 2) {
			b[s10+1] =  b[s00]     & 1;
			b[s10  ] = (b[s00]>>1) & 1;
			b[s00+1] = (b[s00]>>2) & 1;
			b[s00  ] = (b[s00]>>3) & 1;
			s00 += 2;
			s10 += 2;
		}
		if (j < ny) {
			/*
			 * row size is odd, do last element in row
			 * s00+1, s10+1 are off edge
			 */
			b[s10  ] = (b[s00]>>1) & 1;
			b[s00  ] = (b[s00]>>3) & 1;
		}
	}
	if (i < nx) {
		/*
		 * column size is odd, do last row
		 * s10, s10+1 are off edge
		 */
		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) {
			/*
			 * both row and column size are odd, do corner element
			 * s00+1, s10, s10+1 are off edge
			 */
			b[s00  ] = (b[s00]>>3) & 1;
		}
	}
}

/*  ############################################################################  */
/*
 * Copy 4-bit values from a[(nx+1)/2,(ny+1)/2] to b[nx,ny], expanding
 * each value to 2x2 pixels and inserting into bitplane BIT of B.
 * A,B may NOT be same array (it wouldn't make sense to be inserting
 * bits into the same array anyway.)
 */
static void
qtree_bitins(unsigned char a[], int nx, int ny, int b[], int n, int bit)
/*
   int n;		declared y dimension of b
*/
{
int i, j, k;
int s00, s10;

	/*
	 * expand each 2x2 block
	 */
	k = 0;							/* k   is index of a[i/2,j/2]	*/
	for (i = 0; i<nx-1; i += 2) {
		s00 = n*i;					/* s00 is index of b[i,j]		*/
		s10 = s00+n;				/* s10 is index of b[i+1,j]		*/
		for (j = 0; j<ny-1; j += 2) {
			b[s10+1] |= ( a[k]     & 1) << bit;
			b[s10  ] |= ((a[k]>>1) & 1) << bit;
			b[s00+1] |= ((a[k]>>2) & 1) << bit;
			b[s00  ] |= ((a[k]>>3) & 1) << bit;
			s00 += 2;
			s10 += 2;
			k += 1;
		}
		if (j < ny) {
			/*
			 * row size is odd, do last element in row
			 * s00+1, s10+1 are off edge
			 */
			b[s10  ] |= ((a[k]>>1) & 1) << bit;
			b[s00  ] |= ((a[k]>>3) & 1) << bit;
			k += 1;
		}
	}
	if (i < nx) {
		/*
		 * column size is odd, do last row
		 * s10, s10+1 are off edge
		 */
		s00 = n*i;
		for (j = 0; j<ny-1; j += 2) {
			b[s00+1] |= ((a[k]>>2) & 1) << bit;
			b[s00  ] |= ((a[k]>>3) & 1) << bit;
			s00 += 2;
			k += 1;
		}
		if (j < ny) {
			/*
			 * both row and column size are odd, do corner element
			 * s00+1, s10, s10+1 are off edge
			 */
			b[s00  ] |= ((a[k]>>3) & 1) << bit;
			k += 1;
		}
	}
}
/*  ############################################################################  */
/*
 * Copy 4-bit values from a[(nx+1)/2,(ny+1)/2] to b[nx,ny], expanding
 * each value to 2x2 pixels and inserting into bitplane BIT of B.
 * A,B may NOT be same array (it wouldn't make sense to be inserting
 * bits into the same array anyway.)
 */
static void
qtree_bitins64(unsigned char a[], int nx, int ny, LONGLONG b[], int n, int bit)
/*
   int n;		declared y dimension of b
*/
{
int i, j, k;
int s00, s10;

	/*
	 * expand each 2x2 block
	 */
	k = 0;							/* k   is index of a[i/2,j/2]	*/
	for (i = 0; i<nx-1; i += 2) {
		s00 = n*i;					/* s00 is index of b[i,j]		*/
		s10 = s00+n;				/* s10 is index of b[i+1,j]		*/
		for (j = 0; j<ny-1; j += 2) {
			b[s10+1] |= ((LONGLONG) ( a[k]     & 1)) << bit;
			b[s10  ] |= ((((LONGLONG)a[k])>>1) & 1) << bit;
			b[s00+1] |= ((((LONGLONG)a[k])>>2) & 1) << bit;
			b[s00  ] |= ((((LONGLONG)a[k])>>3) & 1) << bit;
			s00 += 2;
			s10 += 2;
			k += 1;
		}
		if (j < ny) {
			/*
			 * row size is odd, do last element in row
			 * s00+1, s10+1 are off edge
			 */
			b[s10  ] |= ((((LONGLONG)a[k])>>1) & 1) << bit;
			b[s00  ] |= ((((LONGLONG)a[k])>>3) & 1) << bit;
			k += 1;
		}
	}
	if (i < nx) {
		/*
		 * column size is odd, do last row
		 * s10, s10+1 are off edge
		 */
		s00 = n*i;
		for (j = 0; j<ny-1; j += 2) {
			b[s00+1] |= ((((LONGLONG)a[k])>>2) & 1) << bit;
			b[s00  ] |= ((((LONGLONG)a[k])>>3) & 1) << bit;
			s00 += 2;
			k += 1;
		}
		if (j < ny) {
			/*
			 * both row and column size are odd, do corner element
			 * s00+1, s10, s10+1 are off edge
			 */
			b[s00  ] |= ((((LONGLONG)a[k])>>3) & 1) << bit;
			k += 1;
		}
	}
}

/*  ############################################################################  */
static void
read_bdirect(unsigned char *infile, int a[], int n, int nqx, int nqy, unsigned char scratch[], int bit)
{
int i;

	/*
	 * read bit image packed 4 pixels/nybble
	 */
	for (i = 0; i < ((nqx+1)/2) * ((nqy+1)/2); i++) {
		scratch[i] = input_nybble(infile);
	}
	/*
	 * insert in bitplane BIT of image A
	 */
	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)
{
int i;

	/*
	 * read bit image packed 4 pixels/nybble
	 */
	for (i = 0; i < ((nqx+1)/2) * ((nqy+1)/2); i++) {
		scratch[i] = input_nybble(infile);
	}
	/*
	 * insert in bitplane BIT of image A
	 */
	qtree_bitins64(scratch,nqx,nqy,a,n,bit);
}

/*  ############################################################################  */
/*
 * Huffman decoding for fixed codes
 *
 * Coded values range from 0-15
 *
 * Huffman code values (hex):
 *
 *	3e, 00, 01, 08, 02, 09, 1a, 1b,
 *	03, 1c, 0a, 1d, 0b, 1e, 3f, 0c
 *
 * and number of bits in each code:
 *
 *	6,  3,  3,  4,  3,  4,  5,  5,
 *	3,  5,  4,  5,  4,  5,  6,  4
 */
static int input_huffman(unsigned char *infile)
{
int c;

	/*
	 * get first 3 bits to start
	 */
	c = input_nbits(infile,3);
	if (c < 4) {
		/*
		 * this is all we need
		 * return 1,2,4,8 for c=0,1,2,3
		 */
		return(1<<c);
	}
	/*
	 * get the next bit
	 */
	c = input_bit(infile) | (c<<1);
	if (c < 13) {
		/*
		 * OK, 4 bits is enough
		 */
		switch (c) {
			case  8 : return(3);
			case  9 : return(5);
			case 10 : return(10);
			case 11 : return(12);
			case 12 : return(15);
		}
	}
	/*
	 * get yet another bit
	 */
	c = input_bit(infile) | (c<<1);
	if (c < 31) {
		/*
		 * OK, 5 bits is enough
		 */
		switch (c) {
			case 26 : return(6);
			case 27 : return(7);
			case 28 : return(9);
			case 29 : return(11);
			case 30 : return(13);
		}
	}
	/*
	 * need the 6th bit
	 */
	c = input_bit(infile) | (c<<1);
	if (c == 62) {
		return(0);
	} else {
		return(14);
	}
}

/*  ############################################################################  */
/*  ############################################################################  */
/* Copyright (c) 1993 Association of Universities for Research 
 * in Astronomy. All rights reserved. Produced under National   
 * Aeronautics and Space Administration Contract No. NAS5-26555.
 */
/* qread.c	Read binary data
 *
 * Programmer: R. White		Date: 11 March 1991
 */

static int readint(unsigned char *infile)
{
int a,i;
unsigned char b[4];

	/* Read integer A one byte at a time from infile.
	 *
	 * This is portable from Vax to Sun since it eliminates the
	 * need for byte-swapping.
	 */
	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];

	/* Read integer A one byte at a time from infile.
	 *
	 * This is portable from Vax to Sun since it eliminates the
	 * need for byte-swapping.
	 */
	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 *infile,char *a, int n)
{
/*
	if(myread(infile, a, n) != n) {
		perror("qread");
		exit(-1);

	}
*/
	myread(infile, a, n);
}

/*  ############################################################################  */
static int myread(unsigned char *file, char buffer[], int n)
{
    /*
     * read n bytes from file into buffer
     * returns number of bytes read (=n) if successful, <=0 if not
     *
     * this version is for VMS C: each read may return
     * fewer than n bytes, so multiple reads may be needed
     * to fill the buffer.
     *
     * I think this is unnecessary for Sun Unix, but it won't hurt
     * either, so I'll leave it in.
     */
/*    int nread, total;  */

    /* keep reading until we've read n bytes */
/*
    total = 0;
    while ( (nread = fread(&buffer[total], 1, n-total, file)) > 0) {
	total += nread;
	if (total==n) return(total);
    }
*/

    memcpy(buffer, &file[nextchar], n);
    nextchar += n;
    
    return(n);
}

/*  ############################################################################  */
/*  ############################################################################  */
/* Copyright (c) 1993 Association of Universities for Research
 * in Astronomy. All rights reserved. Produced under National
 * Aeronautics and Space Administration Contract No. NAS5-26555.
 */

/* BIT INPUT ROUTINES */

/* THE BIT BUFFER */

static int buffer2;			/* Bits waiting to be input	*/
static int bits_to_go;			/* Number of bits still in buffer */


/* INITIALIZE BIT INPUT */

/*  ############################################################################  */
static void start_inputing_bits()
{
	/*
	 * Buffer starts out with no bits in it
	 */
	bits_to_go = 0;
}


/*  ############################################################################  */
/* INPUT A BIT */

static int input_bit(unsigned char *infile)
{
	if (bits_to_go == 0) {			/* Read the next byte if no	*/
		/* buffer2 = getc(infile); */	/* bits are left in buffer	*/

		buffer2 = infile[nextchar];
		nextchar++;
		
	/*	if (buffer2 == EOF) {  */
			/*
			 * end of file is an error for this application
			 */
/*
			fprintf(stderr, "input_bit: unexpected end-of-file\n");
			exit(-1);
		}
*/
		bits_to_go = 8;
	}
	/*
	 * Return the next bit
	 */
	bits_to_go -= 1;
	return((buffer2>>bits_to_go) & 1);
}


/*  ############################################################################  */
/* INPUT N BITS (N must be <= 8) */

static int input_nbits(unsigned char *infile, int n)
{
int c;

	if (bits_to_go < n) {
		/*
		 * need another byte's worth of bits
		 */
		buffer2 <<= 8;

/*		c = getc(infile);  */

		c = infile[nextchar];
		nextchar++;
		
/*		if (c == EOF) { */
			/*
			 * end of file is an error for this application
			 */
/*
			fprintf(stderr, "input_nbits: unexpected end-of-file\n");
			exit(-1);
		}
*/
		buffer2 |= c;
		bits_to_go += 8;
	}
	/*
	 * now pick off the first n bits
	 */
	bits_to_go -= n;
	return( (buffer2>>bits_to_go) & ((1<<n)-1) );
}
