/* -------------------------------------------------------------------

   Module Name:	$Source: /delcano/h2/pgf/acis/huff/RCS/huff.c,v $

   Purpose:	Construct and test Huffman table for FITS input

   Assumptions:	Input from 16-bit FITS file

   Part Number:	TBD

   Author:	Peter G. Ford <pgf@space.mit.edu>

   References:	

   Copyright:	Massachusetts Institute of Technology 1996

   $Log: huff.c,v $
 * Revision 1.6  1996/07/29  17:11:14  pgf
 * rename 'last' to 'initval'
 *
 * Revision 1.5  1996/07/29  16:24:27  pgf
 * add 'initval' parameter to compressArray() and uncompressArray()
 *
 * Revision 1.4  1996/07/23  17:15:23  pgf
 * read and write external HUFFTAB in little-endian format
 *
 * Revision 1.3  1996/04/29  17:10:30  pgf
 * add tableId to HUFFTAB and -i flag to caller arguments
 * change previous -i flag to -r
 * change tableOrigin to lowLimit in HUFFTAB
 * add code in readTable() to check for valid lowLimit
 *
 * Revision 1.2  1996/04/27  03:49:17  pgf
 * add -i option and readTable() function to support it
 *
 * Revision 1.1  1996/04/17  21:33:19  pgf
 * Initial revision
 *
   ------------------------------------------------------------------- */

static char rcsid[] = "$Id: huff.c,v 1.6 1996/07/29 17:11:14 pgf Exp $";

/* --------------------------------------------------------------------

   Function:	Construct a pixel histogram from a FITS file.
		Then build a Huffman table and compress the file.
		Finally, decompress the file.
   ------------------------------------------------------------------- */

#include <stdio.h>

typedef struct {		/* Huffman table */
  unsigned tableId;		/* table itentifier */
  unsigned lowLimit;		/* 4093 - zero difference index */
  unsigned tableSize;		/* number of normal entries in table */
  unsigned huffTruncCode;	/* tab[-3]: misc code */
  unsigned huffBadBiasCode;	/* tab[-2]: BAD_BIAS code */
  unsigned huffBadPixelCode;	/* tab[-1]: BAD_PIXEL code */
  unsigned tab[1];		/* code table */
} HUFFTAB;

typedef struct leaf {		/* Element of Huffman tree */
  struct leaf *left;		/* less frequent branch */
  struct leaf *right;		/* more frequent branch */
  unsigned freq;		/* branch frequency */
  int val;			/* leaf value or VAL_ code */
} NODE;

/* --------------------------------------------------------------------
   Pixel masks and special values
   ------------------------------------------------------------------- */
#define	PIXEL_MASK	0xfff		/* pixel value */
#define BAD_PIXEL	0xfff		/* ignore this pixel */
#define BAD_BIAS	0xffe		/* ignore this bias */
#define	HUFF_MASK	0xffffffe0	/* string area of code */
#define	COUNT_MASK	0x1f		/* length of code */
#define	TRUNC_MAX	(32-12-5)	/* max length of spill */

/* --------------------------------------------------------------------
   Special Huffman tree leaf values
   ------------------------------------------------------------------- */

#define	VAL_BADPIX	-1		/* bad pixel leaf val */
#define	VAL_BADBIAS	-2		/* bad bias leaf val */
#define	VAL_MISC	-3		/* out-of-range pixel */
#define	VAL_NONE	-4		/* leaf is a branch */

/* --------------------------------------------------------------------
   Huffman table indices
   ------------------------------------------------------------------- */

#define	HIST_MAX	8187			/* max pixel entries */
#define	HIST_SIZE	8192			/* histogram size */
#define	HIST_MID	(HIST_MAX/2)		/* center of hist[] */
#define	HIST_MISC	(HIST_SIZE+VAL_MISC)	/* hist misc index */
#define	HIST_BADBIAS	(HIST_SIZE+VAL_BADBIAS)	/* hist bad bias index */
#define	HIST_BADPIX	(HIST_SIZE+VAL_BADPIX)	/* hist bad pixel index */

/* --------------------------------------------------------------------
   Routines
   ------------------------------------------------------------------- */

unsigned short *openFits(char *, unsigned *, unsigned *);
unsigned *makeHistFromFile(char *, int, unsigned);
void compressFile(char *, int, char *, HUFFTAB *);
void uncompressFile(char *, int, char *, HUFFTAB *);
HUFFTAB *makeHuffFromFile(char *, int, unsigned, unsigned);
HUFFTAB *readTable(char *);
void makeTableFromTree(unsigned, unsigned, NODE *, unsigned *);
int compareLeafFreqs( NODE **, NODE **);
NODE *makeTreeFromTable(HUFFTAB *);
NODE *addLeafToTree(NODE *, int, unsigned, unsigned);
NODE *makeTreeFromHist(unsigned *, unsigned, unsigned);
void insertSort(NODE **, unsigned);
unsigned compressArray(unsigned short *, unsigned, unsigned *,
  HUFFTAB *, unsigned);
unsigned uncompressArray(unsigned *, unsigned, unsigned short *, unsigned,
  NODE *, unsigned, unsigned);
void writeTable(char *, HUFFTAB *);
void swap4(unsigned *pp, unsigned count);
extern char *malloc(unsigned);

/***********************************************************************
   Main: parse command line arguments, build trees, compress, decompress
 ***********************************************************************/

main(int argc, char *argv[])
{
  unsigned size = HIST_MAX;	/* Huffman table size */
  char *table = NULL;		/* output table file */
  int bswap = 0;		/* =1 to byte-swap FITS pixels */
  int init = 0;			/* =1 to read table from -t */
  int id = 0;			/* table ID for new table */
  unsigned nmisc = 2;		/* number of miscellaneous counts */
  HUFFTAB *huff;		/* Huffman table */

  while (*++argv && **argv == '-')
    if (argv[0][1] == 'b' && ! argv[0][2])
      bswap++;
    else if (argv[0][1] == 'r' && ! argv[0][2])
      init++;
    else if (argv[0][1] == 'i' && (argv[0][2] || argv[1]))
      id = atoi(argv[0][2] ? argv[0]+2 : *++argv);
    else if (argv[0][1] == 'n' && (argv[0][2] || argv[1]))
      size = atoi(argv[0][2] ? argv[0]+2 : *++argv);
    else if (argv[0][1] == 'm' && (argv[0][2] || argv[1]))
      nmisc = atoi(argv[0][2] ? argv[0]+2 : *++argv);
    else if (argv[0][1] == 't' && (argv[0][2] || argv[1]))
      table = argv[0][2] ? argv[0]+2 : *++argv;
    else
      fprintf(stderr, "bad -%c value\n", argv[0][1]), exit(1);

  if (init) {
    huff = readTable(table);
    size = huff->tableSize;
  } else {
    huff = makeHuffFromFile(argv[0], bswap, size, nmisc);
    huff->tableId = id;
    if (table) writeTable(table, huff);
  }
  compressFile(argv[0], bswap, argv[1], huff);
  uncompressFile(argv[0], bswap, argv[1], huff);
  exit(0);
}

/***********************************************************************
   makeHuffFromFile: construct Huffman table from input file
 ***********************************************************************/

HUFFTAB *makeHuffFromFile(char *infile, int bswap, unsigned size,
  unsigned nmisc)
{
  HUFFTAB *huff;
  unsigned len, maxlen = 0, jj, temp;
  int ii;

  huff = (HUFFTAB *)malloc(sizeof(HUFFTAB)+(size-1)*sizeof(unsigned));
  huff->tableSize = size;
  huff->lowLimit = HIST_MID-size/2;
  makeTableFromTree(0, 0,
    makeTreeFromHist(
      makeHistFromFile(infile, bswap, nmisc),
    size, huff->lowLimit),
  huff->tab);
  len = huff->huffTruncCode & COUNT_MASK;
  if (len > TRUNC_MAX) {
    for (len = jj = ii = 1; ii < size; ii++) {
      temp = huff->tab[ii] & COUNT_MASK;
      if (temp <= TRUNC_MAX && temp > len)
        jj = ii, len = temp;
    }
    temp = huff->huffTruncCode;
    huff->huffTruncCode = huff->tab[jj];
    huff->tab[jj] = temp;
    fprintf(stderr,
      "Warning: Huffman table rearranged %d 0x%08x <=> 0x%08x\n",
      jj, huff->huffTruncCode, temp);
  }
  for (ii = -3; ii < (int)size; ii++)
    if (maxlen < (huff->tab[ii] & COUNT_MASK))
      maxlen = huff->tab[ii] & COUNT_MASK;
  fprintf(stderr,
    "Huffman %d code lengths: min %d max %d misc %d badpix %d badbias %d\n",
    size, huff->tab[HIST_MID-huff->lowLimit] & COUNT_MASK, maxlen, len,
    huff->huffBadPixelCode & COUNT_MASK,
    huff->huffBadBiasCode & COUNT_MASK);
  return huff;
}

/* --------------------------------------------------------------------
   makeHistFromFile: construct pixel frequency histogram from 'infile'
   ------------------------------------------------------------------- */
 
unsigned *makeHistFromFile(char *infile, int bswap, unsigned nmisc)
{
  unsigned short *inbuf;
  unsigned *hist, nx, ny, val, last, x, y;
  double sum, sumsq, npix, sqrt(double);
 
  inbuf = openFits(infile, &nx, &ny);
  hist = (unsigned *)malloc(HIST_SIZE*4);
  bzero(hist, HIST_SIZE*4);

  for (npix = sum = sumsq = y = 0; y < ny; y++) {
    if (fread(inbuf, 2, nx, stdin) != nx)
      perror(infile), exit(1);
    if (bswap)
      swab(inbuf, inbuf, 2*nx);
    last = inbuf[0] & PIXEL_MASK;
    if (last == BAD_PIXEL || last == BAD_BIAS)
      last = 0;
    for (x = 1; x < nx; x++)
      if ((val = inbuf[x] & PIXEL_MASK) == BAD_PIXEL)
        hist[HIST_BADPIX]++;
      else if (val == BAD_BIAS)
        hist[HIST_BADBIAS]++;
      else {
        last = val-last+HIST_MID;
        hist[last]++;
        sum += (double)last;
        sumsq += (double)last*(double)last;
        npix++;
        last = val;
      }
  }
  free(inbuf);
  hist[HIST_MISC] = nmisc;
  fprintf(stderr, "%s: input bytes %d bits %dx%dx12 mean %.2f sigma %.2f\n",
    infile, (3*nx*ny)/2, nx, ny, sum/npix, sqrt((sumsq-sum*sum/npix)/npix));
  return hist;
}

/* --------------------------------------------------------------------
   makeTableFromTree: build Huffman table array 'tab' from Huffman tree 'np'
   ------------------------------------------------------------------- */

void makeTableFromTree(unsigned code, unsigned len, NODE *np, unsigned *tab)
{
  if (np == NULL)
    fprintf(stderr, "Error: null leaf pointer in makeTableFromTree\n"),
    exit(1);
  if (np->val == VAL_NONE) {
    makeTableFromTree(code, len+1, np->right, tab);
    makeTableFromTree(code+(1 << len), len+1, np->left, tab);
  } else {
    tab[np->val] = (code << (32-len)) | len;
  }
}

/* --------------------------------------------------------------------
   makeTreeFromHist: build Huffman tree from pixel histogram 'hist'
   ------------------------------------------------------------------- */

NODE *makeTreeFromHist(unsigned *hist, unsigned size, unsigned min)
{
  NODE *nodes[HIST_SIZE], **npp = nodes, *np;
  int ii;

  if (min < 0 || min+size > HIST_MAX)
    fprintf(stderr, "bad -n value: %d\n", size);

  /* allocate a leaf node to each pixel value */
  for (ii = 0; ii < HIST_SIZE; ii++) {
    if (ii < min || (ii >= min+size && ii < HIST_MISC))
      hist[HIST_MISC] += hist[ii];
    else {
      np = *npp++ = (NODE *)malloc(sizeof(NODE));
      np->freq = hist[ii] ? hist[ii] : 1;
      np->val = ii < HIST_MISC ? (ii - min) : (ii - HIST_SIZE);
      np->left = np->right = NULL;
    }
  }
  qsort(nodes, ii = npp-nodes, sizeof(NODE *), compareLeafFreqs);
  /* build branch nodes to connect the leaves */
  for (npp = nodes, np = *npp; ii-- > 1; ) {
    np = (NODE *)malloc(sizeof(NODE));
    np->right = *npp++;
    np->left = *npp;
    np->val = VAL_NONE;
    np->freq = np->right->freq + np->left->freq;
    *npp = np;
    insertSort(npp, ii);
  }
  fprintf(stderr,
    "Pixel frequency: max %d misc %d badpix %d badbias %d\n",
    hist[HIST_MID], hist[HIST_MISC], hist[HIST_BADPIX], hist[HIST_BADBIAS]);
  return np;
}

/* --------------------------------------------------------------------
   compareLeafFreqs: called from qsort() to compare two leaf frequencies
   ------------------------------------------------------------------- */

int compareLeafFreqs( NODE **a, NODE **b)
{
  return a[0]->freq - b[0]->freq;
}

/* --------------------------------------------------------------------
   insertSort: insertion sort of node npp[0] into npp[] array
   ------------------------------------------------------------------- */

void insertSort(NODE **npp, unsigned ii)
{
  NODE *np;
  for (np = npp[0]; ii-- > 1 && np->freq > npp[1]->freq; npp++)
    npp[0] = npp[1];
  npp[0] = np;
}

/***********************************************************************
   compressFile: compress 'infile' to 'outfile' using Huffman table 'huff'
 ***********************************************************************/

void compressFile(char *infile, int bswap, char *outfile, HUFFTAB *huff)
{
  FILE *fp;
  unsigned nx, ny, y, *outbuf, nw;
  unsigned short *inbuf, outlen;

  inbuf = openFits(infile, &nx, &ny);
  outbuf = (unsigned *)malloc((nx+1)*4);

  if ((fp = fopen(outfile, "w")) == NULL)
    perror(outfile), exit(1);

  fwrite(&nx, 1, 4, fp);
  fwrite(&ny, 1, 4, fp);

  for (y = nw = 0; y < ny; y++) {
    fread(inbuf, nx, 2, stdin);
    if (bswap)
      swab(inbuf, inbuf, 2*nx);
    outlen = compressArray(inbuf, nx, outbuf, huff, 0);
    fwrite(&outlen, 1, 2, fp);
    fwrite(outbuf, outlen, 4, fp);
    nw += outlen;
  }
  fclose(fp);
  free(inbuf);
  free(outbuf);
  fprintf(stderr, "%s: compressed to %d bytes (%.2f%%)\n",
    outfile, 4*nw+8, (800.0*nw)/(3*nx*ny));
}

/* --------------------------------------------------------------------
   compressArray: use Huffman table 'huff' to compress 'in' array to 'out'
   ------------------------------------------------------------------- */

unsigned compressArray(
  unsigned short *in,		/* input pixel array */
  unsigned inlen,		/* number of input pixels */
  unsigned *out,		/* output array */
  HUFFTAB  *huff,		/* Huffman table */
  unsigned initval		/* previous pixel value */
)
{
  unsigned *outorg = out;	/* saved output origin */
  unsigned val;			/* input pixel value */
  unsigned code;		/* coded pixel value */
  unsigned bitlen = 12;		/* length of 'code' in bits */
  unsigned acc = 0;		/* output register */
  unsigned bitout = 0;		/* length of 'acc' in bits */
  unsigned trunc;		/* truncated pixel code */
  int      index;		/* Huffman table index */

  /* construct code for truncated pixels */
  trunc = (12 + (huff->huffTruncCode & COUNT_MASK)) |
               ((huff->huffTruncCode & HUFF_MASK) >> 12);

  /* compress the array */
  while (inlen--) {
    if (huff) {
      /* load the next pixel */
      switch (val = *in++ & PIXEL_MASK) {
        case BAD_PIXEL:
          code = huff->huffBadPixelCode;
          break;
        case BAD_BIAS:
          code = huff->huffBadBiasCode;
          break;
        default:
          index = (val+(HIST_MID-huff->lowLimit))-initval;
          initval = val;
          if (index < 0 || index >= huff->tableSize)
            code = trunc | (val << 20);
          else
            code = huff->tab[index];
          break;
      }
      bitlen = code & COUNT_MASK;
      code >>= 32 - bitlen;
    } else
      code = *in++;
   
    /* append 'code' to 'acc' */
    acc |= code << bitout;
    if ((bitout += bitlen ) >= 32) {
      bitout -= 32;
      *out++ = acc;
      acc = code >> (bitlen - bitout);
    }
  }

  /* anything left to save? */
  if (bitout > 0)
    *out++ = acc;

  /* return output word count */
  return out - outorg;
}

/***********************************************************************
   uncompressFile: decompress 'tmpfile' using Huffman tree 'root' and
                   compare the result to the original 'infile'
 ***********************************************************************/

void uncompressFile(char *infile, int bswap, char *tmpfile, HUFFTAB *huff)
{
  FILE *fp;
  NODE *root;
  unsigned nx, ny, x, y, ii, maxlen, *tmpbuf = NULL;
  unsigned short *inbuf, *cmpbuf, tmplen;

  root = makeTreeFromTable(huff);
  inbuf = openFits(infile, &nx, &ny);
  if ((fp = fopen(tmpfile, "r")) == NULL)
    perror(tmpfile), exit(1);
  if (fread(&ii, 4, 1, fp) != 1 || ii != nx)
    fprintf(stderr, "%s: bad x-dim: %d (not %d)\n", tmpfile, ii, nx);
  if (fread(&ii, 4, 1, fp) != 1 || ii != ny)
    fprintf(stderr, "%s: bad y-dim: %d (not %d)\n", tmpfile, ii, ny);
  cmpbuf = (unsigned short *)malloc(nx*2);

  for (y = maxlen = 0; y < ny; y++) {
    if (fread(inbuf, 2, nx, stdin) != nx)
      perror(infile), exit(1);
    if (bswap)
      swab(inbuf, inbuf, nx*2);
    if (fread(&tmplen, 2, 1, fp) != 1)
      perror(tmpfile), exit(1);
    if (tmplen > maxlen) {
      if (tmpbuf) free(tmpbuf);
      tmpbuf = (unsigned *)malloc((maxlen = tmplen)*4);
    }
    if (fread(tmpbuf, 4, tmplen, fp) != tmplen)
      perror(tmpfile), exit(1);
    if (!uncompressArray(tmpbuf, tmplen, cmpbuf, nx, root,
        HIST_MID-huff->lowLimit, 0))
      fprintf(stderr, "%s: decompression fails at line %d\n", tmpfile, y),
      exit(1);
    for (x = 0; x < nx; x++)
      if ((inbuf[x] & PIXEL_MASK) != cmpbuf[x])
        fprintf(stderr, "%s: line %4d col %4d orig %5d unpk %5d\n",
          tmpfile, y, x, inbuf[x], cmpbuf[x]);
  }
  fclose(fp);
  free(inbuf);
  free(tmpbuf);
  free(cmpbuf);
  fprintf(stderr, "%s: uncompressFile was successful\n", tmpfile);
}

/* --------------------------------------------------------------------
   makeTreeFromTable: construct a Huffman tree from Huffman table 'huff'
   ------------------------------------------------------------------- */

NODE *makeTreeFromTable(HUFFTAB *huff)
{
  NODE *root = NULL;
  unsigned tab[HIST_SIZE];
  int ii;

  for (ii = -3; ii < (int)huff->tableSize; ii++)
    root = addLeafToTree(root, ii,
      huff->tab[ii] & HUFF_MASK, huff->tab[ii] & COUNT_MASK);

  bzero(tab, sizeof(tab));
  makeTableFromTree(0, 0, root, tab+3);
  if (bcmp(tab, &huff->huffTruncCode, 4*(huff->tableSize+3)))
    fprintf(stderr, "failed to construct Huffman tree\n");

  return root;
}

/* --------------------------------------------------------------------
   addLeafToTree: add a new leaf to a Huffman tree
   ------------------------------------------------------------------- */

NODE *addLeafToTree(NODE *np, int val, unsigned code, unsigned len)
{
  if (np == NULL) {
    np = (NODE *)malloc(sizeof(NODE));
    np->left = np->right = NULL;
    np->freq = 0;
    np->val = VAL_NONE;
  }

  if (len == 0)
    np->val = val;
  else if (code & (1 << (32 - len))) 
    np->left = addLeafToTree(np->left, val, code, len-1);
  else
    np->right = addLeafToTree(np->right, val, code, len-1);

  return np;
}

/* --------------------------------------------------------------------
   uncompressArray: use Huffman tree 'root' to unpack array 'in' to 'out'
   ------------------------------------------------------------------- */

unsigned uncompressArray(
  unsigned *in,			/* input packed array */
  unsigned inlen,		/* number of input elements */
  unsigned short *out,		/* output array */
  unsigned outlen,		/* maximum length of output */
  NODE *root,			/* Huffman tree */
  unsigned offset,		/* Huffman table zero difference index */
  unsigned initval		/* previous unpacked value */
)
{
  unsigned code;		/* unpacking buffer */
  unsigned bitlen;		/* length of unpacking buffer */
  unsigned temp;		/* scratch */
  NODE *np = root;		/* Huffman tree pointer */

  while (inlen-- > 0) {
    code = *in++;
    bitlen = 32;
    while (bitlen--) {
      np = (code & 1) ? np->left : np->right;
      code >>= 1;
      switch (np->val) {
        case VAL_NONE:
          continue;
        case VAL_BADPIX:
          *out++ = BAD_PIXEL;
          break;
        case VAL_BADBIAS:
          *out++ = BAD_BIAS;
          break;
        case VAL_MISC:
          if (bitlen >= 12) {
            initval = *out++ = code & 0xfff;
            code >>= 12;
            bitlen -= 12;
          } else {
            temp = code;
            if (inlen-- == 0)
              return 0;
            code = *in++;
            initval = *out++ = (temp | (code << bitlen)) & 0xfff;
            bitlen += 20;
            code >>= 32-bitlen;
          }
          break;
        default:
          initval = *out++ = np->val+initval-offset;
          break;
      }
      if (--outlen == 0)
        return inlen == 0;
      np = root;
    }
  }
  return 0;
}

/***********************************************************************
   openFits: open a FITS file using stdin, read its header, return nx,ny
 ***********************************************************************/

unsigned short *openFits(char *infile, unsigned *nx, unsigned *ny)
{
  char hdr[2880];
  int ii, neof, bits = 0;
 
  if (freopen(infile, "r", stdin) == NULL)
    perror(infile), exit(1);

  *nx = *ny = 0;

  do {
    if (fread(hdr, sizeof(hdr), 1, stdin) != 1)
      perror(infile), exit(1);
    for (ii = 0; ii < 2880 && (neof = strncmp(hdr+ii, "END ", 4)); ii += 80) {
      sscanf(hdr+ii, "NAXIS1 = %d", nx);
      sscanf(hdr+ii, "NAXIS2 = %d", ny);
      sscanf(hdr+ii, "BITPIX = %d", &bits);
    }
  } while(neof);

  if (bits != 16 || *nx <= 0 || *ny <= 0)
    fprintf(stderr, "%s: bad FITS header\n", infile), exit(1);

  return (unsigned short *)malloc(*nx*2);
}

/***********************************************************************
   readTable: read Huffman table from file 'file'
 ***********************************************************************/

HUFFTAB *readTable(char *table)
{
  FILE *fp;
  HUFFTAB *huff;
  unsigned size;

  if ((fp = fopen(table, "r")) == NULL || fseek(fp, 0L, 2))
    perror(table), exit(1);
  huff = (HUFFTAB *)malloc(size = ftell(fp));
  if (fseek(fp, 0L, 0) || fread(huff, size, 1, fp) != 1)
    perror(table), exit(1);
  (void)fclose(fp);
  swap4((unsigned *)huff, size/4);
  fprintf(stderr, "%s: id %d size %d low %d\n", table,
    huff->tableId, huff->tableSize, huff->lowLimit);
  if (huff->lowLimit+huff->tableSize >= HIST_MAX)
    fprintf(stderr, "%s: bad lowLimit value\n", table), exit(1);
  return huff;
}

/***********************************************************************
   writeTable: write Huffman table 'huff' to file 'outfile'
 ***********************************************************************/

void writeTable(char *table, HUFFTAB *huff)
{
  FILE *fp;
  unsigned size = sizeof(HUFFTAB)+(huff->tableSize-1)*sizeof(unsigned);

  if ((fp = fopen(table, "w")) == NULL)
    perror(table), exit(1);
  swap4((unsigned *)huff, size/4);
  if (fwrite(huff, size, 1, fp) != 1)
    perror(table), exit(1);
  (void)fclose(fp);
  swap4((unsigned *)huff, size/4);
}

/***********************************************************************
   swap4: perform byte-reversal of 32-bit array
 ***********************************************************************/

void swap4(unsigned *pp, unsigned count)
{
#ifndef mips
#ifndef vax
   while (count-- > 0) {
    int ii = *pp;
    *pp++ = ((ii & 0xff) << 24) | ((ii & 0xff00) << 8) |
            ((ii >> 8) & 0xff00) | ((ii >> 24) & 0xff);
  }
#endif vax
#endif mips
}

/* --------------------------------------------------------------------
   End
   ------------------------------------------------------------------- */

