/* based on a combination of codes written by T.Shimizu which in turn were
 * based on IJG software, so: 
 *
 * Copyright (C) 1991, 1992, Thomas G. Lane.
 * Part of the Independent JPEG Group's software.
 * See the file Copyright for more details.
 *
 * Copyright (c) 1993 Brian C. Smith, The Regents of the University
 * of California
 * All rights reserved.
 * 
 * Copyright (c) 1994 Kongji Huang and Brian C. Smith.
 * Cornell University
 * All rights reserved.
 * 
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose, without fee, and without written agreement is
 * hereby granted, provided that the above copyright notice and the following
 * two paragraphs appear in all copies of this software.
 * 
 * IN NO EVENT SHALL CORNELL UNIVERSITY BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF CORNELL
 * UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * CORNELL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND CORNELL UNIVERSITY HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 * we could add more but that seems enough for now
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "fppjpeg.h"
#include "mcu.h"
#include "io.h"
#include "predictor.h"
#include "defs.h"
#include "ana_structures.h"
 extern	struct sym_desc sym[];

#define RST0    0xD0	/* RST0 marker code */

 int inputBufferOffset;       /* Offset of current byte */
 /* use M.Kubo's errors, define them here */
 int DecompError;
 /* the JPEG marker codes */
 typedef enum {
      M_SOF0 = 0xc0,
      M_SOF1 = 0xc1,
      M_SOF2 = 0xc2,
      M_SOF3 = 0xc3,

      M_SOF5 = 0xc5,
      M_SOF6 = 0xc6,
      M_SOF7 = 0xc7,

      M_JPG = 0xc8,
      M_SOF9 = 0xc9,
      M_SOF10 = 0xca,
      M_SOF11 = 0xcb,

      M_SOF13 = 0xcd,
      M_SOF14 = 0xce,
      M_SOF15 = 0xcf,

      M_DHT = 0xc4,

      M_DAC = 0xcc,

      M_RST0 = 0xd0,
      M_RST1 = 0xd1,
      M_RST2 = 0xd2,
      M_RST3 = 0xd3,
      M_RST4 = 0xd4,
      M_RST5 = 0xd5,
      M_RST6 = 0xd6,
      M_RST7 = 0xd7,

      M_SOI = 0xd8,
      M_EOI = 0xd9,
      M_SOS = 0xda,
      M_DQT = 0xdb,
      M_DNL = 0xdc,
      M_DRI = 0xdd,
      M_DHP = 0xde,
      M_EXP = 0xdf,

      M_APP0 = 0xe0,
      M_APP15 = 0xef,

      M_JPG0 = 0xf0,
      M_JPG13 = 0xfd,
      M_COM = 0xfe,

      M_TEM = 0x01,

      M_ERROR = 0x100
} JpegMarker;

static unsigned int bitMask[] = {  0xffffffff, 0x7fffffff, 0x3fffffff, 0x1fffffff,
                            0x0fffffff, 0x07ffffff, 0x03ffffff, 0x01ffffff,
                            0x00ffffff, 0x007fffff, 0x003fffff, 0x001fffff,
                            0x000fffff, 0x0007ffff, 0x0003ffff, 0x0001ffff,
                            0x0000ffff, 0x00007fff, 0x00003fff, 0x00001fff,
                            0x00000fff, 0x000007ff, 0x000003ff, 0x000001ff,
                            0x000000ff, 0x0000007f, 0x0000003f, 0x0000001f,
                            0x0000000f, 0x00000007, 0x00000003, 0x00000001};

static long getBuffer;		/* current bit-extraction buffer */
static int bitsLeft;		/* # of unused bits in it */
#define BITS_PER_LONG	(8*sizeof(long))
#define MIN_GET_BITS  (BITS_PER_LONG-7)	   /* max value for long getBuffer */
/*
 * bmask[n] is mask for n rightmost bits
 */
static int bmask[] = {0x0000,
	 0x0001, 0x0003, 0x0007, 0x000F,
	 0x001F, 0x003F, 0x007F, 0x00FF,
	 0x01FF, 0x03FF, 0x07FF, 0x0FFF,
	 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF};
 /* -----------------------------------------------------------------------*/
/*
 *--------------------------------------------------------------
 *
 * FillBitBuffer --
 *
 *	Load up the bit buffer with at least nbits
 *	Process any stuffed bytes at this time.
 *
 * Results:
 *	None
 *
 * Side effects:
 *	The bitwise global variables are updated.
 *
 *--------------------------------------------------------------
 */
static void
FillBitBuffer (int nbits,unsigned char *inputBuffer, int numInputBytes)
{
    int c, c2;

    while (bitsLeft < MIN_GET_BITS) {
	c = GetJpegChar ();

	/*
	 * If it's 0xFF, check and discard stuffed zero byte
	 */
	if (c == 0xFF) {
	    c2 = GetJpegChar ();

	    if (c2 != 0) {

		/*
		 * Oops, it's actually a marker indicating end of
		 * compressed data.  Better put it back for use later.
		 */
		UnGetJpegChar (c2);
		UnGetJpegChar (c);

		/*
		 * There should be enough bits still left in the data
		 * segment; if so, just break out of the while loop.
		 */
		if (bitsLeft >= nbits)
		    break;

		/*
		 * Uh-oh.  Corrupted data: stuff zeroes into the data
		 * stream, since this sometimes occurs when we are on the
		 * last show_bits(8) during decoding of the Huffman
		 * segment.
		 */
		c = 0;
	    }
	}
	/*
	 * OK, load c into getBuffer
	 */
	getBuffer = (getBuffer << 8) | c;
	bitsLeft += 8;
    }
}

/* Macros to make things go at some speed! */
/* NB: parameter to get_bits should be simple variable, not expression */

#define show_bits(nbits,rv,inputBuffer, numInputBytes) {		\
    if (bitsLeft < nbits) FillBitBuffer(nbits, inputBuffer, numInputBytes);\
    rv = (getBuffer >> (bitsLeft-(nbits))) & bmask[nbits];		\
}

#define show_bits8(rv,inputBuffer, numInputBytes) {     		\
	if (bitsLeft < 8) FillBitBuffer(8,inputBuffer, numInputBytes);  \
	rv = (getBuffer >> (bitsLeft-8)) & 0xff;			\
}

#define flush_bits(nbits) {						\
	bitsLeft -= (nbits);						\
}

#define get_bits(nbits,rv,inputBuffer, numInputBytes) { 		\
	if (bitsLeft < nbits) FillBitBuffer(nbits,inputBuffer, numInputBytes);\
	rv = ((getBuffer >> (bitsLeft -= (nbits)))) & bmask[nbits];	\
}

#define get_bit(rv,inputBuffer, numInputBytes) {			\
	if (!bitsLeft) FillBitBuffer(1,inputBuffer, numInputBytes);     \
	rv = (getBuffer >> (--bitsLeft)) & 1;	 			\
}


/* The word-per-sample format always puts the LSB first. */
#define PUTPPMSAMPLE(ptr,v)			\
	{ register int val_ = v;		\
	  *ptr++ = (char) (val_ & 0xFF);	\
	  *ptr++ = (char) ((val_ >> 8) & 0xFF);	\
	}

/*
 *--------------------------------------------------------------
 *
 * HuffDecode --
 *
 *	Taken from Figure F.16: extract next coded symbol from
 *	input stream.  This should becode a macro.
 *
 * Results:
 *	Next coded symbol
 *
 * Side effects:
 *	Bitstream is parsed.
 *
 *--------------------------------------------------------------
 */
#define HuffDecode(htbl,rv,inputBuffer, numInputBytes)			\
{									\
    int l, code, temp;							\
									\
    /*									\
     * If the huffman code is less than 8 bits, we can use the fast	\
     * table lookup to get its value.  It's more than 8 bits about	\
     * 3-4% of the time.						\
     */									\
    show_bits8(code, inputBuffer, numInputBytes);			\
    if (htbl->numbits[code]) {						\
	flush_bits(htbl->numbits[code]);				\
	rv=htbl->value[code];						\
    }  else {								\
	flush_bits(8);							\
	l = 8;								\
	while (code > htbl->maxcode[l]) {				\
	    get_bit(temp, inputBuffer, numInputBytes);	        	\
	    code = (code << 1) | temp;					\
	    l++;							\
	}								\
									\
	/*								\
	 * With garbage input we may reach the sentinel value l = 17.	\
	 */								\
									\
	if (l > 16) {							\
	    fprintf (stderr, "Corrupt JPEG data: bad Huffman code\n");  \
            fflush(stdout);                                             \
	    rv = 0;		/* fake a zero as the safest result */	\
                                                                        \
	    /*                                                          \ 
	     * add by M.Kubo (2001-Aug-02)                              \
	     */                                                         \
	    DecompError = 1;                                      \
	     return;                                                    \
	} else {							\
	    rv = htbl->huffval[htbl->valptr[l] +			\
		((int)(code - htbl->mincode[l]))];			\
	}								\
    }									\
}

/*
 *--------------------------------------------------------------
 *
 * HuffExtend --
 *
 *	Code and table for Figure F.12: extend sign bit
 *
 * Results:
 *	The extended value.
 *
 * Side effects:
 *	None.
 *
 *--------------------------------------------------------------
 */
static int extendTest[16] =	/* entry n is 2**(n-1) */
{0, 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080,
 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000};

static int extendOffset[16] =	/* entry n is (-1 << n) + 1 */
{0, ((-1) << 1) + 1, ((-1) << 2) + 1, ((-1) << 3) + 1, ((-1) << 4) + 1,
 ((-1) << 5) + 1, ((-1) << 6) + 1, ((-1) << 7) + 1, ((-1) << 8) + 1,
 ((-1) << 9) + 1, ((-1) << 10) + 1, ((-1) << 11) + 1, ((-1) << 12) + 1,
 ((-1) << 13) + 1, ((-1) << 14) + 1, ((-1) << 15) + 1};

#define HuffExtend(x,s) {					\
    if ((x) < extendTest[s]) {					\
	(x) += extendOffset[s];					\
    }								\
}

/*
 *--------------------------------------------------------------
 *
 * FixHuffTbl --
 *
 *      Compute derived values for a Huffman table one the DHT marker
 *      has been processed.  This generates both the encoding and
 *      decoding tables.
 *
 * Results:
 *      None.
 *
 * Side effects:
 *      None.
 *
 *--------------------------------------------------------------
 */
static void
FixHuffTbl (htbl)
    HuffmanTable *htbl;
{
    int p, i, l, lastp, si;
    char huffsize[257];
    Ushort huffcode[257];
    Ushort code;
    int size;
    int value, ll, ul;

    /*
     * Figure C.1: make table of Huffman code length for each symbol
     * Note that this is in code-length order.
     */
    p = 0;
    for (l = 1; l <= 16; l++) {
        for (i = 1; i <= (int)htbl->bits[l]; i++)
            huffsize[p++] = (char)l;
    }
    huffsize[p] = 0;
    lastp = p;


    /*
     * Figure C.2: generate the codes themselves
     * Note that this is in code-length order.
     */
    code = 0;
    si = huffsize[0];
    p = 0;
    while (huffsize[p]) {
        while (((int)huffsize[p]) == si) {
            huffcode[p++] = code;
            code++;
        }
        code <<= 1;
        si++;
    }

    /*
     * Figure C.3: generate encoding tables
     * These are code and size indexed by symbol value
     * Set any codeless symbols to have code length 0; this allows
     * EmitBits to detect any attempt to emit such symbols.
     */
    MEMSET(htbl->ehufsi, 0, sizeof(htbl->ehufsi));

    for (p = 0; p < lastp; p++) {
        htbl->ehufco[htbl->huffval[p]] = huffcode[p];
        htbl->ehufsi[htbl->huffval[p]] = huffsize[p];
    }

    /*
     * Figure F.15: generate decoding tables
     */
    p = 0;
    for (l = 1; l <= 16; l++) {
        if (htbl->bits[l]) {
            htbl->valptr[l] = p;
            htbl->mincode[l] = huffcode[p];
            p += htbl->bits[l];
            htbl->maxcode[l] = huffcode[p - 1];
        } else {
            htbl->maxcode[l] = -1;
        }
    }

    /*
     * We put in this value to ensure HuffDecode terminates.
     */
    htbl->maxcode[17] = 0xFFFFFL;

    /*
     * Build the numbits, value lookup tables.
     * These table allow us to gather 8 bits from the bits stream,
     * and immediately lookup the size and value of the huffman codes.
     * If size is zero, it means that more than 8 bits are in the huffman
     * code (this happens about 3-4% of the time).
     */
    bzero (htbl->numbits, sizeof(htbl->numbits));
    for (p=0; p<lastp; p++) {
        size = huffsize[p];
        if (size <= 8) {
            value = htbl->huffval[p];
            code = huffcode[p];
            ll = code << (8-size);
            if (size < 8) {
                ul = ll | bitMask[24+size];
            } else {
                ul = ll;
            }
            for (i=ll; i<=ul; i++) {
                htbl->numbits[i] = size;
                htbl->value[i] = value;
            }
        }
    }
}
/*
 *--------------------------------------------------------------
 *
 * HuffDecoderInit --
 *
 *	Initialize for a Huffman-compressed scan.
 *	This is invoked after reading the SOS marker.
 *
 * Results:
 *	None
 *
 * Side effects:
 *	None.
 *
 *--------------------------------------------------------------
 */
static void 
HuffDecoderInit (dcPtr)
    DecompressInfo *dcPtr;
{
    short ci;
    JpegComponentInfo *compptr;

    /*
     * Initialize static variables
     */
    bitsLeft = 0;

    for (ci = 0; ci < dcPtr->compsInScan; ci++) {
	compptr = dcPtr->curCompInfo[ci];
	/*
	 * Make sure requested tables are present
	 */
	if (dcPtr->dcHuffTblPtrs[compptr->dcTblNo] == NULL) { 
	    fprintf (stderr, "Error: Use of undefined Huffman table\n");
	    //	    exit(1);

	    /*
	     * add by M.Kubo (2001-Aug-02)
	     */
	    DecompError = 1;
	    return;
	}

	/*
	 * Compute derived values for Huffman tables.
	 * We may do this more than once for same table, but it's not a
	 * big deal
	 */
	FixHuffTbl (dcPtr->dcHuffTblPtrs[compptr->dcTblNo]);
    }

    /*
     * Initialize restart stuff
     */
    dcPtr->restartInRows = (dcPtr->restartInterval)/(dcPtr->imageWidth);
    dcPtr->restartRowsToGo = dcPtr->restartInRows;
    dcPtr->nextRestartNum = 0;
}

/*
 *--------------------------------------------------------------
 *
 * ProcessRestart --
 *
 *	Check for a restart marker & resynchronize decoder.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	BitStream is parsed, bit buffer is reset, etc.
 *
 *--------------------------------------------------------------
 */
static void 
ProcessRestart (DecompressInfo *dcPtr, unsigned char *inputBuffer, int numInputBytes)
{
    int c, nbytes;
    short ci;

    /*
     * Throw away any unused bits remaining in bit buffer
     */
    nbytes = bitsLeft / 8;
    bitsLeft = 0;

    /*
     * Scan for next JPEG marker
     */
    do {
	do {			/* skip any non-FF bytes */
	    nbytes++;
	    c = GetJpegChar ();
	} while (c != 0xFF);
	do {			/* skip any duplicate FFs */
	    /*
	     * we don't increment nbytes here since extra FFs are legal
	     */
	    c = GetJpegChar ();
	} while (c == 0xFF);
    } while (c == 0);		/* repeat if it was a stuffed FF/00 */

    if (c != (RST0 + dcPtr->nextRestartNum)) {

	/*
	 * Uh-oh, the restart markers have been messed up too.
	 * Just bail out.
	 */
	printf ("Error: Corrupt JPEG data.  Exiting...\n");
	DecompError = -1;
	return;
    }

    /*
     * Update restart state
     */
    dcPtr->restartRowsToGo = dcPtr->restartInRows;
    dcPtr->nextRestartNum = (dcPtr->nextRestartNum + 1) & 7;
}

/*
 *--------------------------------------------------------------
 *
 * DecodeFirstRow --
 *
 *	Decode the first raster line of samples at the start of 
 *      the scan and at the beginning of each restart interval.
 *	This includes modifying the component value so the real
 *      value, not the difference is returned.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	Bitstream is parsed.
 *
 *--------------------------------------------------------------
 */
static void DecodeFirstRow(DecompressInfo *dcPtr,MCU *curRowBuf,unsigned char *inputBuffer,
   int numInputBytes)
{
    register short curComp,ci;
    register int s,col,compsInScan,numCOL;
    register JpegComponentInfo *compptr;
    int Pr,Pt,d;
    HuffmanTable *dctbl;

    Pr=dcPtr->dataPrecision;
    Pt=dcPtr->Pt;
    compsInScan=dcPtr->compsInScan;
    numCOL=dcPtr->imageWidth;

    //printf("Pr, Pt = %d, %d\n", Pr, Pt);
    /*
     * the start of the scan or at the beginning of restart interval.
     */

        ci = dcPtr->MCUmembership[0];
        compptr = dcPtr->curCompInfo[ci];
        dctbl = dcPtr->dcHuffTblPtrs[compptr->dcTblNo];

        /*
         * Section F.2.2.1: decode the difference
         */
        HuffDecode (dctbl,s,inputBuffer, numInputBytes);
	if (DecompError) return;

        if (s) {
           get_bits(s,d,inputBuffer, numInputBytes);
           HuffExtend(d,s);
           } else {
           d = 0;
        }

        /* 
         * Add the predictor to the difference.
         */
        curRowBuf[0][0]=d+(1<<(Pr-Pt-1));

    /*
     * the rest of the first row
     */

    for (col=1; col<numCOL; col++) {

            /*
             * Section F.2.2.1: decode the difference
             */
            HuffDecode (dctbl,s,inputBuffer, numInputBytes);
	    if (DecompError) return;

            if (s) {
	      get_bits(s,d,inputBuffer, numInputBytes);
	      HuffExtend(d,s);
	    } else {
	      d = 0;
            }
            /* 
             * Add the predictor to the difference.
             */
            curRowBuf[col][0]=d+curRowBuf[col-1][0];
    }
    if (dcPtr->restartInRows) {
      (dcPtr->restartRowsToGo)--;
    }
}

/*
 *--------------------------------------------------------------
 *
 * DecodeImage --
 *
 *      Decode the input stream. This includes modifying
 *      the component value so the real value, not the
 *      difference is returned.
 *
 * Results:
 *      None.
 *
 * Side effects:
 *      Bitstream is parsed.
 *
 * modified to remove components, just have one component for Solar B
 * note that there is no checking for size of output yet
 *--------------------------------------------------------------
 */
static void
DecodeImage(DecompressInfo *dcPtr, unsigned char *inputBuffer, int numInputBytes,
    short *outputBuffer, int numOutputBytes)
{
    register int s,d,col,row,i;
    register short ci;
    HuffmanTable *dctbl;
    JpegComponentInfo *compptr;
    int predictor;
    int numCOL,numROW,compsInScan;
    MCU *prevRowBuf,*curRowBuf;
    int imagewidth,Pt,psv;
    int outputBufferOffset;

    numCOL=imagewidth=dcPtr->imageWidth;
    numROW=dcPtr->imageHeight;
    compsInScan=dcPtr->compsInScan;
    Pt=dcPtr->Pt;
    psv=dcPtr->Ss;
    prevRowBuf=mcuROW2;
    curRowBuf=mcuROW1;
    
    /*
     * Define numOutputBytes and outputBuffer
     *      by T.Shimizu
     */

    outputBufferOffset =0;

    /*
     * Decode the first row of image. Output the row and
     * turn this row into a previous row for later predictor
     * calculation.
     */  
    
    DecodeFirstRow(dcPtr,curRowBuf,inputBuffer, numInputBytes);
    if (DecompError) return;

    /*
     * Write decompressed data into outputBuffer
     *    by T.Shimizu
     */

      for (i = 0; i < numCOL; i++){
	outputBuffer[i]= (short) curRowBuf[i][0];
      }
      outputBufferOffset++;
          
    /*
     * PmPutRow(curRowBuf,compsInScan,numCOL,Pt);
     */
    swap(MCU *,prevRowBuf,curRowBuf);
    /* just get the table address once */
    ci = dcPtr->MCUmembership[0];
    compptr = dcPtr->curCompInfo[ci];
    dctbl = dcPtr->dcHuffTblPtrs[compptr->dcTblNo];

    for (row=1; row<numROW; row++) {
      
      /*
       * Account for restart interval, process restart marker if needed.
       */
      if (dcPtr->restartInRows) {
	if (dcPtr->restartRowsToGo == 0) {
	  ProcessRestart (dcPtr,inputBuffer, numInputBytes);
	  if (DecompError) return;

	  
	  /*
	   * Reset predictors at restart.
	   */
	  DecodeFirstRow(dcPtr,curRowBuf,inputBuffer, numInputBytes);
	  if (DecompError) return;
	  
	  /*
	   * Write decompressed data into outputBuffer
	   *     by T.Shimizu
	   */
	  for (i = 0; i < numCOL; i++){
	    outputBuffer[i+outputBufferOffset*numCOL]= (short) curRowBuf[i][0];
	  }
	  outputBufferOffset++;
	  
	  /*
	    PmPutRow(curRowBuf,compsInScan,numCOL,Pt);
	  */
	  swap(MCU *,prevRowBuf,curRowBuf);
	  continue;
	}
	dcPtr->restartRowsToGo--;
      }
      
      /*
       * The upper neighbors are predictors for the first column.
       */
	
	/*
	 * Section F.2.2.1: decode the difference
	 */
            HuffDecode (dctbl,s,inputBuffer, numInputBytes);
	    if (DecompError) return;
	    
            if (s) {
	      get_bits(s,d,inputBuffer, numInputBytes);
	      HuffExtend(d,s);
	    } else {
	      d = 0;
            }
	    
            curRowBuf[0][0]=d+prevRowBuf[0][0];
      
      /*
       * For the rest of the column on this row, predictor
       * calculations are base on PSV. 
       */
      for (col=1; col<numCOL; col++) {
	  
	  /*
	   * Section F.2.2.1: decode the difference
	   */
	  HuffDecode (dctbl,s,inputBuffer, numInputBytes);
	  if (DecompError) return;

	  if (s) {
	    get_bits(s,d,inputBuffer, numInputBytes);
	    HuffExtend(d,s);
	  } else {
	    d = 0;
	  }
	  QuickPredict(col,0,curRowBuf,prevRowBuf,
		       psv,&predictor);
	  
	  curRowBuf[col][0]=d+predictor;
      }

      /*
       * Write decompressed data into outputBuffer
       *     by T.Shimizu
       */
      for (i = 0; i < numCOL; i++){
	outputBuffer[i+outputBufferOffset*numCOL]= (short) curRowBuf[i][0];
        }
      outputBufferOffset++;
      
      /*
	PmPutRow(curRowBuf,compsInScan,numCOL,Pt);
      */
      swap(MCU *,prevRowBuf,curRowBuf);
      
    }
}


 /* -----------------------------------------------------------------------*/
/*
 *--------------------------------------------------------------
 *
 * DecoderStructInit --
 *
 *	Initalize the rest of the fields in the decompression
 *	structure.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	None.
 *
 *--------------------------------------------------------------
 */
static void
DecoderStructInit (dcPtr)
    DecompressInfo *dcPtr;

{
    short ci,i;
    JpegComponentInfo *compPtr;
    char *buf1,*buf2;
    int mcuSize;

    /*
     * Prepare array describing MCU composition
     */
    if (dcPtr->compsInScan == 1) {
	dcPtr->MCUmembership[0] = 0;
    } else {
	short ci;

	if (dcPtr->compsInScan > 4) {
	    fprintf (stderr, "Too many components for interleaved scan");
	    //	    exit(1);	    
	    /*
	     * add by M.Kubo (2001-Aug-02)
	     */
	    DecompError = 1;
	    return;
	}

	for (ci = 0; ci < dcPtr->compsInScan; ci++) {
            dcPtr->MCUmembership[ci] = ci;
	}
    }

    /*
     * Initialize mucROW1 and mcuROW2 which buffer two rows of
     * pixels for predictor calculation.
     */

    if ((mcuROW1 = (MCU *)malloc(dcPtr->imageWidth*sizeof(MCU)))==NULL) {
       fprintf(stderr,"Not enough memory for mcuROW1\n");
    }
    if ((mcuROW2 = (MCU *)malloc(dcPtr->imageWidth*sizeof(MCU)))==NULL) {
       fprintf(stderr,"Not enough memory for mcuROW2\n");
    }

    mcuSize=dcPtr->compsInScan * sizeof(ComponentType);
    if ((buf1 = (char *)malloc(dcPtr->imageWidth*mcuSize))==NULL) {
       fprintf(stderr,"Not enough memory for buf1\n");
    }
    if ((buf2 = (char *)malloc(dcPtr->imageWidth*mcuSize))==NULL) {
       fprintf(stderr,"Not enough memory for buf2\n");
    }

    for (i=0;i<dcPtr->imageWidth;i++) {
        mcuROW1[i]=(MCU)(buf1+i*mcuSize);
        mcuROW2[i]=(MCU)(buf2+i*mcuSize);
    }
}


/*
 *--------------------------------------------------------------
 *
 * Get2bytes --
 *
 *	Get a 2-byte unsigned integer (e.g., a marker parameter length
 *	field)
 *
 * Results:
 *	Next two byte of input as an integer.
 *
 * Side effects:
 *	Bitstream is parsed.
 *
 *--------------------------------------------------------------
 */
static Uint
Get2bytes (char *inputBuffer, int numInputBytes)
{
    int a;
    a = GetJpegChar();
    return (a << 8) + GetJpegChar();
}
/*
 *--------------------------------------------------------------
 *
 * GetDht --
 *
 *	Process a DHT marker
 *
 * Results:
 *	None
 *
 * Side effects:
 *	A huffman table is read.
 *	Exits on error.
 *
 *--------------------------------------------------------------
 */
static void
GetDht (DecompressInfo *dcPtr, unsigned char *inputBuffer, int numInputBytes)
{
    int length;
    unsigned char bits[17];
    unsigned char huffval[256];
    int i, index, count;
    HuffmanTable **htblptr;

    length = Get2bytes (inputBuffer, numInputBytes) - 2;

    while (length) {
	index = GetJpegChar();

	bits[0] = 0;
	count = 0;
	for (i = 1; i <= 16; i++) {
	    bits[i] = GetJpegChar();
	    count += bits[i];
	}

	if (count > 256) {
	    fprintf (stderr, "Bogus DHT counts");
	    DecompError = 1;
	    return;
	}

	for (i = 0; i < count; i++)
	    huffval[i] = GetJpegChar();

	length -= 1 + 16 + count;

	if (index & 0x10) {	/* AC table definition */
           fprintf(stderr,"Huffman table for lossless JPEG is not defined.\n");
	} else {		/* DC table definition */
	    htblptr = &dcPtr->dcHuffTblPtrs[index];
	}

	if (index < 0 || index >= 4) {
	    fprintf (stderr, "Bogus DHT index %d", index);
	    DecompError = 1;
	    return;
	}

	if (*htblptr == NULL) {
	    *htblptr = (HuffmanTable *) malloc (sizeof (HuffmanTable));
             if (*htblptr==NULL) {
                fprintf(stderr,"Can't malloc HuffmanTable\n");
                DecompError = -1;
		return;
             }
	}

	MEMCPY((*htblptr)->bits, bits, sizeof ((*htblptr)->bits));
	MEMCPY((*htblptr)->huffval, huffval, sizeof ((*htblptr)->huffval));
    }
}

/*
 *--------------------------------------------------------------
 *
 * GetDri --
 *
 *	Process a DRI marker
 *
 * Results:
 *	None
 *
 * Side effects:
 *	Exits on error.
 *	Bitstream is parsed.
 *
 *--------------------------------------------------------------
 */
static void
GetDri (DecompressInfo *dcPtr,unsigned char *inputBuffer, int numInputBytes)
{
    if (Get2bytes (inputBuffer, numInputBytes) != 4) {
	fprintf (stderr, "Bogus length in DRI");
	DecompError = 1;
	return;
    }

    dcPtr->restartInterval = (Ushort) Get2bytes (inputBuffer, numInputBytes);
}

/*
 *--------------------------------------------------------------
 *
 * GetApp0 --
 *
 *	Process an APP0 marker.
 *
 * Results:
 *	None
 *
 * Side effects:
 *	Bitstream is parsed
 *
 *--------------------------------------------------------------
 */
static void
GetApp0 (DecompressInfo *dcPtr, unsigned char *inputBuffer, int numInputBytes)
{
    int length;

    length = Get2bytes (inputBuffer, numInputBytes) - 2;
    while (length-- > 0)	/* skip any remaining data */
	(void)GetJpegChar();
}

/*
 *--------------------------------------------------------------
 *
 * GetSof --
 *
 *	Process a SOFn marker
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	Bitstream is parsed
 *	Exits on error
 *	dcPtr structure is filled in
 *
 *--------------------------------------------------------------
 */
static void
GetSof (DecompressInfo *dcPtr, int code, unsigned char *inputBuffer, int numInputBytes)
{
    int length;
    short ci;
    int c;
    JpegComponentInfo *compptr;

    length = Get2bytes (inputBuffer, numInputBytes);

    dcPtr->dataPrecision = GetJpegChar();
    dcPtr->imageHeight = Get2bytes (inputBuffer, numInputBytes);
    dcPtr->imageWidth = Get2bytes (inputBuffer, numInputBytes);
    dcPtr->numComponents = GetJpegChar();
    //printf("ny, ny, nc = %d, %d, %d, nbits = %d\n", dcPtr->imageHeight, dcPtr->imageWidth,
    //	dcPtr->numComponents, dcPtr->dataPrecision);

    /*
     * We don't support files in which the image height is initially
     * specified as 0 and is later redefined by DNL.  As long as we
     * have to check that, might as well have a general sanity check.
     */
    if ((dcPtr->imageHeight <= 0 ) ||
	(dcPtr->imageWidth <= 0) || 
	(dcPtr->numComponents <= 0)) {
	fprintf (stderr, "Empty JPEG image (DNL not supported)");
	DecompError = 1;
	return;
    }

    if ((dcPtr->dataPrecision<MinPrecisionBits) ||
        (dcPtr->dataPrecision>MaxPrecisionBits)) {
	fprintf (stderr, "Unsupported JPEG data precision");
	DecompError = 1;
	return;
    }

    if (length != (dcPtr->numComponents * 3 + 8)) {
	fprintf (stderr, "Bogus SOF length");
	DecompError = 1;
	return;
    }

    dcPtr->compInfo = (JpegComponentInfo *) malloc
	(dcPtr->numComponents * sizeof (JpegComponentInfo));

    for (ci = 0; ci < dcPtr->numComponents; ci++) {
	compptr = &dcPtr->compInfo[ci];
	compptr->componentIndex = ci;
	compptr->componentId = GetJpegChar();
	c = GetJpegChar();
	compptr->hSampFactor = (c >> 4) & 15;
	compptr->vSampFactor = (c) & 15;
	/* for Solar B we always want these to be 1, so catch this
	problem here */
	if ((compptr->hSampFactor != 1) || (compptr->vSampFactor != 1)) {
	  fprintf (stderr, "Error: JPEG downsampling is not supported.\n");
	  DecompError = 1;
	  return;
	}

        (void) GetJpegChar();   /* skip Tq */
    }
}
/*
 *--------------------------------------------------------------
 *
 * GetSos --
 *
 *	Process a SOS marker
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	Bitstream is parsed.
 *
 *--------------------------------------------------------------
 */
static void
GetSos (DecompressInfo *dcPtr, unsigned char *inputBuffer, int numInputBytes)
{
    int length;
    int i, ci, n, c, cc;
    JpegComponentInfo *compptr;

    length = Get2bytes (inputBuffer, numInputBytes);

    /* 
     * Get the number of image components.
     */
    n = GetJpegChar();
    dcPtr->compsInScan = n;
    if (n != 1) {
      /* Solar B doesn't have components */
      fprintf (stderr, "n components = %d\n", n);	
      DecompError = 1;
      return;
    }
    length -= 3;

    if (length != (n * 2 + 3) || n < 1 || n > 4) {
	fprintf (stderr, "Bogus SOS length");
	DecompError = 1;
	return;
    }


    for (i = 0; i < n; i++) {
	cc = GetJpegChar();
	c = GetJpegChar();
	length -= 2;

	for (ci = 0; ci < dcPtr->numComponents; ci++)
	    if (cc == dcPtr->compInfo[ci].componentId) {
		break;
	    }

	if (ci >= dcPtr->numComponents) {
	    fprintf (stderr, "Invalid component number in SOS");	
	    DecompError = 1;
	    return;
	}

	compptr = &dcPtr->compInfo[ci];
	dcPtr->curCompInfo[i] = compptr;
	compptr->dcTblNo = (c >> 4) & 15;
    }

    /*
     * Get the PSV, skip Se, and get the point transform parameter.
     */
    dcPtr->Ss = GetJpegChar(); 
    (void)GetJpegChar();
    c = GetJpegChar(); 
    dcPtr->Pt = c & 0x0F;
}

/*
 *--------------------------------------------------------------
 *
 * GetSoi --
 *
 *	Process an SOI marker
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	Bitstream is parsed.
 *
 *--------------------------------------------------------------
 */
static void
GetSoi (dcPtr)
    DecompressInfo *dcPtr;
{

    /*
     * Reset all parameters that are defined to be reset by SOI
     */
    dcPtr->restartInterval = 0;
}

 /* -----------------------------------------------------------------------*/
/*
 *--------------------------------------------------------------
 *
 * NextMarker --
 *
 *      Find the next JPEG marker Note that the output might not
 *	be a valid marker code but it will never be 0 or FF
 *
 * Results:
 *	The marker found.
 *
 * Side effects:
 *	Bitstream is parsed.
 *
 *--------------------------------------------------------------
 */
static int
NextMarker (unsigned char *inputBuffer, int numInputBytes)
{
    int c;

    do {
	/* skip any non-FF bytes */
	do {
	    c = GetJpegChar();
	} while (c != 0xFF);
	/*
	 * skip any duplicate FFs without incrementing nbytes, since
	 * extra FFs are legal
	 */
	do {
	    c = GetJpegChar();
	} while (c == 0xFF);
    } while (c == 0);		/* repeat if it was a stuffed FF/00 */

    return c;
}
/*
 *--------------------------------------------------------------
 *
 * ProcessTables --
 *
 *	Scan and process JPEG markers that can appear in any order
 *	Return when an SOI, EOI, SOFn, or SOS is found
 *	return a zero if an error
 *
 * Results:
 *	The marker found.
 *
 * Side effects:
 *	Bitstream is parsed.
 *
 *--------------------------------------------------------------
 */
static JpegMarker
ProcessTables (DecompressInfo *dcPtr,unsigned char *inputBuffer, int numInputBytes)
{
    int c;

    while (1) {
	c = NextMarker (inputBuffer, numInputBytes);
	//printf("c = %d\n", c);

	switch (c) {
	case M_SOF0:
	case M_SOF1:
	case M_SOF2:
	case M_SOF3:
	case M_SOF5:
	case M_SOF6:
	case M_SOF7:
	case M_JPG:
	case M_SOF9:
	case M_SOF10:
	case M_SOF11:
	case M_SOF13:
	case M_SOF14:
	case M_SOF15:
	case M_SOI:
	case M_EOI:
	case M_SOS:
	    return ((JpegMarker)c);

	case M_DHT:
	    //printf("M_DHT\n");
	    GetDht (dcPtr,inputBuffer, numInputBytes);
	    if (DecompError) return 0;
	    break;

	case M_DQT:
	    //printf("M_DQT\n");
            fprintf(stderr,"Not a lossless JPEG file.\n");
	    break;

	case M_DRI:
	    //printf("M_DRI\n");
	    GetDri (dcPtr,inputBuffer, numInputBytes);
	    if (DecompError) return 0;
	    break;

	case M_APP0:
	    //printf("M_APP0\n");
	    GetApp0 (dcPtr,inputBuffer, numInputBytes);
	    break;

	case M_RST0:		/* these are all parameterless */
	case M_RST1:
	case M_RST2:
	case M_RST3:
	case M_RST4:
	case M_RST5:
	case M_RST6:
	case M_RST7:
	case M_TEM:
	    printf ("Warning: unexpected marker 0x%02x", c);
	    break;

	default:		/* must be DNL, DHP, EXP, APPn, JPGn, COM,
				 * or RESn, just skip over */
	{
	  int length = Get2bytes (inputBuffer, numInputBytes) - 2;
	  while (length--)  GetJpegChar();
	}
	    break;
	}
    }
}
/*
 *--------------------------------------------------------------
 *
 * ReadFileHeader --
 *
 *	Initialize and read the file header (everything through
 *	the SOF marker).
 *
 * Results:
 *	None
 *
 * Side effects:
 *	Exit on error.
 *
 *--------------------------------------------------------------
 */
static void
ReadFileHeader (DecompressInfo *dcPtr, unsigned char *inputBuffer, int numInputBytes)
{
    int c, c2;
    
    /* get the SOI */
    c = NextMarker (inputBuffer, numInputBytes);
    if (c != M_SOI) { DecompError = 1;  return; }

    GetSoi (dcPtr);		/* OK, process SOI */

    /*
     * Process markers until SOF
     */
    c = ProcessTables (dcPtr, inputBuffer, numInputBytes);

    switch (c) {
    case M_SOF0:
    case M_SOF1:
    case M_SOF3:
	GetSof (dcPtr, c, inputBuffer, numInputBytes);
	if (DecompError) return;
	break;

    default:
	fprintf (stderr, "Unsupported SOF marker type 0x%02x", c);
	break;
    }
}
 /* -----------------------------------------------------------------------*/
/*
 *--------------------------------------------------------------
 *
 * ReadScanHeader --
 *
 *	Read the start of a scan (everything through the SOS marker).
 *
 * Results:
 *	0 if find SOS, 1 if find EOI or error
 *
 * Side effects:
 *	Bitstream is parsed.
 *
 *--------------------------------------------------------------
 */
static int
ReadScanHeader (DecompressInfo *dcPtr, unsigned char *inputBuffer, int numInputBytes)
{
    int c;

    /*
     * Process markers until SOS or EOI
     */
    c = ProcessTables (dcPtr, inputBuffer, numInputBytes);

    switch (c) {
    case M_SOS:
	GetSos (dcPtr, inputBuffer, numInputBytes);
	if (DecompError) return 1;
	return 0;

    case M_EOI:
	return 1;

    default:
	fprintf (stderr, "Unexpected marker 0x%02x", c);
	break;
    }
    return 1;
}
 /* -----------------------------------------------------------------------*/
static int fpp_decomp(int cmode, char *inputBuffer, int numInputBytes,
	char *outputBuffer, int numOutputBytes)
{
  /* cmode is the caller's take on the type of compression, we really only
  care if it indicates 0 (for no compression). Otherwise we get it from the
  SOF. */
  int dpcm_flag;
  DecompressInfo dcInfo;
  DecompError = 0;
  switch (cmode) {
    case 0:
      /* this shouldn't be called for a non-compressed case, but later we'll
      do a courtesy copy if it happens to be */
      bcopy(inputBuffer, outputBuffer, numInputBytes);
      printf("data is not compressed\n");  return 0;
    case 3:
      dpcm_flag = 1;
      break;
    case 7:
      dpcm_flag = 0;
      break;
    default:
      printf("illegal compression mode for FPP %d\n", cmode);
      DecompError = 1;
      return 1;
  }

  if (dpcm_flag) {
    inputBufferOffset = 0;
    bzero(&dcInfo, sizeof(dcInfo));

    /* Read the JPEG File header, up to scan header, and initialize all
    the variables in the decompression information structure. */

    ReadFileHeader (&dcInfo, inputBuffer, numInputBytes);
    //printf("mark 1\n");
    if (DecompError) return DecompError;

    /* Solar B data just has one scan */
    if (ReadScanHeader (&dcInfo, inputBuffer, numInputBytes)) {
	  printf ("no SOS found in file\n");
	  DecompError = 1;
    } 
    //printf("mark 2\n");
    if (DecompError) return DecompError;

    DecoderStructInit(&dcInfo);
    //printf("mark 3\n");
    if (DecompError) return DecompError;

    /* and now decode the Huffman table */
    HuffDecoderInit(&dcInfo);
    //printf("mark 4\n");
    if (DecompError) return DecompError;

    DecodeImage(&dcInfo,inputBuffer,numInputBytes,(short *)outputBuffer,numOutputBytes);
    //printf("mark 5\n");
    if (DecompError) return DecompError;

    free(mcuROW1[0]); free(mcuROW1);
    free(mcuROW2[0]); free(mcuROW2);
  } else {
    if ( epic_decode(inputBuffer, numInputBytes, (short *)outputBuffer, numOutputBytes))
      { printf("error in epic_decode\n"); return 1; }
  }
  return 0;
  
}
 /* -----------------------------------------------------------------------*/
int ana_fppdecomp(narg,ps)
 int narg, ps[];
 /* a function, digests an array containing FPP image data
 image = fppdecomp(array, comptype, nx, ny) where comptype is the FPP compression type
 this is for testing the decompression codes */
 {
 int comptype, n, nout, nx, ny, dim[8], nd, stat, result_sym, iq, type;
 char *pin;
 int *pout;
 struct	ahead	*h;
 if (int_arg_stat(ps[1], &comptype) != 1) return -1;
 iq = ps[0];
 n = get_p_c(&iq, &pin);
 if (int_arg_stat(ps[2], &nx) != 1) return -1;
 if (int_arg_stat(ps[3], &ny) != 1) return -1;
 dim[0] = nx;  dim[1] = ny;  nout = nx * ny;
 //if (comptype == 13) type = 2; else type = 1;
 type = 1;
 result_sym = array_scratch(type, 2, dim);         /* for the result */
 h = (struct ahead *) sym[result_sym].spec.array.ptr;
 pout = (int *) ((char *)h + sizeof(struct ahead));
 bzero(pout, nx*ny*2);
//  if (comptype == 13) {
//    if (stat = DpcmDecomp(pin, n, pout, nout)) {
//      printf("DpcmDecomp error %d\n", stat);  return 2;
//    }
//  } else {
   if (stat = fpp_decomp(comptype, pin, n, (char *) pout, nout)) {
     printf("FPPDECOMP error %d\n", stat);  return 2;
   }
// }
 
 return result_sym;
 }
 /* -----------------------------------------------------------------------*/
 
