#include <stdio.h>
#include <math.h>
#include "tap.h"

#define FIX_0_298631336  ((long)  2446)
#define FIX_0_390180644  ((long)  3196)
#define FIX_0_541196100  ((long)  4433)
#define FIX_0_765366865  ((long)  6270)
#define FIX_0_899976223  ((long)  7373)
#define FIX_1_175875602  ((long)  9633)
#define FIX_1_501321110  ((long)  12299)
#define FIX_1_847759065  ((long)  15137)
#define FIX_1_961570560  ((long)  16069)
#define FIX_2_053119869  ((long)  16819)
#define FIX_2_562915447  ((long)  20995)
#define FIX_3_072711026  ((long)  25172)

#define NEXTWORD(x)     ((*(x)->data << 8) | (*((x)->data + 1)))
#define DESCALE(x,n)    (((x) + ((long)1 << ((n) - 1))) >> n)

#define GETDWORD(x)		( (x)[0] | (((x)[1])<<8) | (((x)[2])<<16) | (((x)[3])<<24) )
#define GETWORD(x)		( (x)[0] | (((x)[1])<<8) )

#define SOF0            0xc0
#define SOF1            0xc1
#define DHT             0xc4
#define SOI             0xd8
#define EOI             0xd9
#define SOS             0xda
#define DQT             0xdb
#define DRI             0xdd
#define APP0            0xe0
#define APP1			0xe1
#define COM             0xfe

#define SOF0_DEFINED    0x01
#define DHT_DEFINED     0x02
#define SOI_DEFINED     0x04
#define SOS_DEFINED     0x08
#define DQT_DEFINED     0x10
#define APP0_DEFINED    0x20
#define DRI_DEFINED     0x40

#define JFIF_OK         0x3F


typedef struct HUFFMAN_NODE
{
   long index;
   int code, length;
} HUFFMAN_NODE;


typedef struct DECODER_DATA
{
   unsigned char *data_start;       /* buffered JPG data block */
   unsigned char *data;             /* pointer to actual data */

   int bits;                        /* number of bits available to be read */
   int byte;                        /* current byte read */
   int width, height;               /* size of the image */

   int components;                  /* number of image pixel components */
   HUFFMAN_NODE huffman_node[1024]; /* huffman decoding entries */
   int dequant[128];                /* dequantization tables */
   int huffman_y, huffman_cbcr;     /* for tables handling */
   int samples_y;                   /* y sampling factor */
   int quant_y, quant_cbcr;         /* quantization table indexes */
   int ac_y, ac_cbcr;               /* AC y/cbcr table indexes */
   int dc_y, dc_cbcr;               /* DC y/cbcr table indexes */
   int flags;                       /* Various decoding flags */
} DECODER_DATA;



/* next_bit:
 *  Returns next bit from decoding data stream.
 */
inline unsigned long next_bit(DECODER_DATA *dec)
{
   long seg_len;
   
   dec->bits--;
   if (dec->bits < 0) {
      dec->bits = 7;
      dec->byte = *(++dec->data);
      if (dec->byte == 0xff) {
         dec->data++;
      }
   }
   return (long)((dec->byte & (1 << dec->bits)) ? 1 : 0);
}



/* get_bits:
 *  Reads a sequence of bits from the buffered data stream. Used to get the
 *  representation of a number, given its category (by JPEG standard).
 */
inline int get_bits(DECODER_DATA *dec, int category)
{
   unsigned int i;
   int result = 0;

   for (i=0; i<category; i++)
      result = (result << 1) | next_bit(dec);

   /* adjust sign of the value by category */
   if (result >= (1 << (category - 1)))
      return result;
   else
      return result - ((1 << category) - 1);
}



/* huffman_decode:
 *  Decodes a huffman encoded value from JPG file.
 */
inline int huffman_decode(DECODER_DATA *dec, HUFFMAN_NODE *node)
{
   int i, j, found = -1;
   long val;

   if (*dec->data == 0xff)
      if (*(dec->data + 1) >= 0xd0 && *(dec->data + 1) <= 0xd7) {
         val = (1 << dec->bits) - 1;
         if ((dec->byte & val) == val)
            return -2;
      }

   val = 0;
   for (i=1; i<=16; i++) {
      val = (val << 1) | next_bit(dec);
      for (j=0; j<256; j++) {
         if (node[j].length > i) break;
         if ((node[j].length == i) &&
             (node[j].index == val)) {
            found = j;
            break;
         }
      }
      if (found > -1) break;
   }
   if (found == -1) return -1;

   return node[found].code;
}



/* zigzag_reorder:
 *  Reorders coefficients following the zigzag scan path.
 */
static void zigzag_reorder(int *coefs)
{
   int i, temp[64],
      scan[64] = {  0, 1, 5, 6,14,15,27,28,
                    2, 4, 7,13,16,26,29,42,
                    3, 8,12,17,25,30,41,43,
                    9,11,18,24,31,40,44,53,
                   10,19,23,32,39,45,52,54,
                   20,22,33,38,46,51,55,60,
                   21,34,37,47,50,56,59,61,
                   35,36,48,49,57,58,62,63 };
                  
   for (i=0; i<64; i++) temp[i] = coefs[scan[i]];
   for (i=0; i<64; i++) coefs[i] = temp[i];
}



/* do_idct:
 *  Calculates the inverse discrete cosine transform; based on code by the
 *  Independent JPEG Group. This method uses integer fixed point math.
 */
static void do_idct(int *data, int *dequant)
{
   long tmp0, tmp1, tmp2, tmp3,
        tmp10, tmp11, tmp12, tmp13,
        z1, z2, z3, z4, z5;
   int *inptr, *wsptr, *dqptr, *outptr;
   int i, workspace[64], temp;
   
   /* Pass 1 */

   inptr = data;
   dqptr = dequant;
   wsptr = workspace;
   for (i=8; i>0; i--) {
      if (inptr[8] == 0 && inptr[16] == 0 && inptr[24] == 0 &&
          inptr[32] == 0 && inptr[40] == 0 && inptr[48] == 0 &&
          inptr[56] == 0) {
         /* AC terms all zero */
         temp = (inptr[0] * dqptr[0]) << 2;

         wsptr[0] = temp;
         wsptr[8] = temp;
         wsptr[16] = temp;
         wsptr[24] = temp;
         wsptr[32] = temp;
         wsptr[40] = temp;
         wsptr[48] = temp;
         wsptr[56] = temp;

         inptr++;
         wsptr++;
         dqptr++;
         continue;
      }

      z2 = inptr[16] * dqptr[16];
      z3 = inptr[48] * dqptr[48];
      z1 = (z2 + z3) * FIX_0_541196100;
      tmp2 = z1 + (z3 * (- FIX_1_847759065));
      tmp3 = z1 + (z2 * FIX_0_765366865);
      z2 = inptr[0] * dqptr[0];
      z3 = inptr[32] * dqptr[32];
      tmp0 = (z2 + z3) << 13;
      tmp1 = (z2 - z3) << 13;

      tmp10 = tmp0 + tmp3;
      tmp13 = tmp0 - tmp3;
      tmp11 = tmp1 + tmp2;
      tmp12 = tmp1 - tmp2;

      tmp0 = inptr[56] * dqptr[56];
      tmp1 = inptr[40] * dqptr[40];
      tmp2 = inptr[24] * dqptr[24];
      tmp3 = inptr[8] * dqptr[8];
      z1 = tmp0 + tmp3;
      z2 = tmp1 + tmp2;
      z3 = tmp0 + tmp2;
      z4 = tmp1 + tmp3;
      z5 = (z3 + z4) * FIX_1_175875602;
      tmp0 *= FIX_0_298631336;
      tmp1 *= FIX_2_053119869;
      tmp2 *= FIX_3_072711026;
      tmp3 *= FIX_1_501321110;
      z1 *= (- FIX_0_899976223);
      z2 *= (- FIX_2_562915447);
      z3 *= (- FIX_1_961570560);
      z4 *= (- FIX_0_390180644);
      z3 += z5;
      z4 += z5;
      
      tmp0 += z1 + z3;
      tmp1 += z2 + z4;
      tmp2 += z2 + z3;
      tmp3 += z1 + z4;

      /* Temp output */
      wsptr[0]  = (int) DESCALE(tmp10 + tmp3, 11);
      wsptr[56] = (int) DESCALE(tmp10 - tmp3, 11);
      wsptr[8]  = (int) DESCALE(tmp11 + tmp2, 11);
      wsptr[48] = (int) DESCALE(tmp11 - tmp2, 11);
      wsptr[16] = (int) DESCALE(tmp12 + tmp1, 11);
      wsptr[40] = (int) DESCALE(tmp12 - tmp1, 11);
      wsptr[24] = (int) DESCALE(tmp13 + tmp0, 11);
      wsptr[32] = (int) DESCALE(tmp13 - tmp0, 11);

      inptr++;
      dqptr++;
      wsptr++;
   }
   
   /* Pass 2 */

   wsptr = workspace;
   outptr = data;
   for (i=0; i<8; i++) {
      z2 = (long) wsptr[2];
      z3 = (long) wsptr[6];
      z1 = (z2 + z3) * FIX_0_541196100;
      tmp2 = z1 + (z3 * (- FIX_1_847759065));
      tmp3 = z1 + (z2 * FIX_0_765366865);
      tmp0 = ((long) wsptr[0] + (long) wsptr[4]) << 13;
      tmp1 = ((long) wsptr[0] - (long) wsptr[4]) << 13;

      tmp10 = tmp0 + tmp3;
      tmp13 = tmp0 - tmp3;
      tmp11 = tmp1 + tmp2;
      tmp12 = tmp1 - tmp2;
      
      tmp0 = (long) wsptr[7];
      tmp1 = (long) wsptr[5];
      tmp2 = (long) wsptr[3];
      tmp3 = (long) wsptr[1];

      z1 = tmp0 + tmp3;
      z2 = tmp1 + tmp2;
      z3 = tmp0 + tmp2;
      z4 = tmp1 + tmp3;
      z5 = (z3 + z4) * FIX_1_175875602;

      tmp0 *= FIX_0_298631336;
      tmp1 *= FIX_2_053119869;
      tmp2 *= FIX_3_072711026;
      tmp3 *= FIX_1_501321110;
      z1 *= (- FIX_0_899976223);
      z2 *= (- FIX_2_562915447);
      z3 *= (- FIX_1_961570560);
      z4 *= (- FIX_0_390180644);
      z3 += z5;
      z4 += z5;

      tmp0 += z1 + z3;
      tmp1 += z2 + z4;
      tmp2 += z2 + z3;
      tmp3 += z1 + z4;

      /* Final output */
      outptr[0] = (int) DESCALE(tmp10 + tmp3, 18) + 128;
      outptr[7] = (int) DESCALE(tmp10 - tmp3, 18) + 128;
      outptr[1] = (int) DESCALE(tmp11 + tmp2, 18) + 128;
      outptr[6] = (int) DESCALE(tmp11 - tmp2, 18) + 128;
      outptr[2] = (int) DESCALE(tmp12 + tmp1, 18) + 128;
      outptr[5] = (int) DESCALE(tmp12 - tmp1, 18) + 128;
      outptr[3] = (int) DESCALE(tmp13 + tmp0, 18) + 128;
      outptr[4] = (int) DESCALE(tmp13 - tmp0, 18) + 128;

      outptr += 8;
      wsptr += 8;
   }
}



/* read_dht:
 *  Reads AC/DC huffman table(s) from jpeg data.
 */
static int read_dht(DECODER_DATA *dec)
{
   int bit_len[16];
   int table_class, table_id, i, j;
   unsigned int seg_len, count, val, table, index;

   dec->data++;
   seg_len = NEXTWORD(dec);
   dec->data += 2;
   count = 2;
   
   do {
      table_id = *dec->data & 0x1;
      table_class = (*dec->data & 0x10) >> 4;
      table = (table_class << 9) | (table_id << 8);
      dec->data++;
      count++;

      for (i=0; i<16; i++, count++)
         bit_len[i] = *dec->data++;

      val = 0;
      index = -1;
      for (i=0; i<16; i++) {
         for (j=0; j<bit_len[i]; j++) {
            index++;
            count++;
            dec->huffman_node[table | index].code = *dec->data++;
            dec->huffman_node[table | index].index = val;
            dec->huffman_node[table | index].length = i + 1;
            val++;
         }
         val <<= 1;
      }
   } while (count < seg_len);

   return 0;
}



/* read_sof0:
 *  Basically reads more image informations.
 */
static int read_sof0(DECODER_DATA *dec)
{
   unsigned char comps;
   int i;
   word length;

	dec->data+=1;
	length = NEXTWORD(dec);
	
   dec->data += 2;
   if (*dec->data != 8)
      /* Only 8 bits/sample supported */
      return 2;
   dec->data++;
   
   dec->height = NEXTWORD(dec);
   dec->data += 2;
   dec->width = NEXTWORD(dec);
   dec->data += 2;

   comps = *dec->data++;
   for (i=0; i<comps; i++) {
      switch (*dec->data) {

         case 1:
            dec->data++;
            dec->samples_y = (*dec->data & 0xf) * (*dec->data >> 4);
            dec->data++;
            dec->quant_y = *dec->data++;
            break;

         case 2:
         case 3:
            /* Skips cbcr samples (we don't care) */
            dec->data += 2;
            dec->quant_cbcr = *dec->data++;
            break;

      }
   }

   return 0;
}



/* read_dqt:
 *  Reads dequantization table(s).
 */
static int read_dqt(DECODER_DATA *dec)
{
   unsigned int seg_len, count;
   int i, qt_num;
   
   dec->data++;
   seg_len = NEXTWORD(dec);
   dec->data += 2;
   count = 2;

   do {
      if ((qt_num = (*dec->data & 0xf)) > 1)
         /* Illegal dequantization table number */
         return 1;
      if (*dec->data & 0xf0)
         /* Only 8 bit dequantization table precision supported */
         return 1;
      dec->data++;
      count++;
      for (i=0; i<64; i++, count++)
         dec->dequant[(qt_num << 6) | i] = *dec->data++;
      zigzag_reorder(dec->dequant + (qt_num << 6));
   } while (count < seg_len);
   
   return 0;
}
         


/* read_sos:
 *  Reads final image informations before decoding.
 */
static int read_sos(DECODER_DATA *dec)
{
   int i;
   
   dec->data += 3;
   
   dec->components = *dec->data++;

   if ((dec->components != 1) && (dec->components != 3))
      /* Only 1 or 3 components supported */
      return 2;

   for (i=0; i<dec->components; i++) {
      switch (*dec->data) {

         case 1:
            dec->data++;
            dec->ac_y = *dec->data & 0xf;
            dec->dc_y = *dec->data >> 4;
            dec->data++;
            break;

         case 2:
         case 3:
            dec->data++;
            dec->ac_cbcr = *dec->data & 0xf;
            dec->dc_cbcr = *dec->data >> 4;
            dec->data++;
            break;

         default:
            return 3;
      }
   }
   /* Skip next 3 bytes */
   dec->data += 3;

   return 0;
}



/* read_app0:
 *  Reads JFIF format data segment.
 */
static int read_app0(DECODER_DATA *dec)
{
   int skip;

   dec->data++;
   
   if (NEXTWORD(dec) < 16)
      /* Segment length too short */
      return 1;
//   TAP_Print("length = %d\r\n");
   
   dec->data += 2;

//	TAP_Print("%s\r\n", dec->data );
   if (strcmp(dec->data, "JFIF"))
   {
      return 1;
   }

   dec->data += 5;

//  TAP_Print("ext : %x\r\n", dec->data[0] );


   if (*dec->data != 1)
   {
      /* Only JFIF version 1.x supported */
      return 1;
   }
   dec->data += 7;

   /* Skips thumbnail */
   skip = (*dec->data) * (*(dec->data + 1));
   dec->data += 2 + (skip * 3);

   return 0;
}


static int read_app1(DECODER_DATA *dec)
{
	int i;
	dword ifdOffset;
	word fieldCount;
	byte *startP;
	dword mainStartOffset = 0;

//	TAP_Print("APP1\r\n");

	dec->data++;

	if (NEXTWORD(dec) < 16)
	  return 1;

//	TAP_Print("length = %d\r\n", NEXTWORD(dec) );
	dec->data += NEXTWORD(dec);
	dec->data_start = dec->data;
	return 0;

/*		
	dec->data += 2;

//	TAP_Print("%s\r\n", dec->data );	// Exif
	if (strcmp(dec->data, "Exif"))
	{
	  return 1;
	}

	dec->data += 6;		// Exif\0\0
	startP = dec->data;
	dec->data += 4;		// 0x49492A00

	ifdOffset = GETDWORD(dec->data);	// maybe 0x00000008

	while( ifdOffset )	// if next IFD exist	( Thumbnail IFD )
	{
		dec->data = startP + ifdOffset;
		ifdOffset = 0;
	
		fieldCount = GETWORD(dec->data);
		dec->data += 2;
		while( fieldCount-- )
		{
			word tag, type;
			dword count, value;

			tag		= GETWORD( dec->data );	dec->data += 2;
			type 	= GETWORD( dec->data );	dec->data += 2;
			count	= GETDWORD( dec->data );	dec->data += 4;
			value	= GETDWORD( dec->data );	dec->data += 4;
//			TAP_Print(" tag = %x, type = %d, count = %d, value = %x\r\n", tag, type, count, value );
			if( tag == 0x201 )	// offset of jpeg
			{
				mainStartOffset = value;
			}
			ef( tag == 0x202 )	// size of jpeg
			{
				mainStartOffset += value;
			}
		}

		ifdOffset = GETDWORD( dec->data );
		dec->data += 4;
//		TAP_Print("next offset = %d\r\n", ifdOffset );
		
	}

	dec->data_start = startP + mainStartOffset;
	dec->data = startP + mainStartOffset;

    return 0;
*/    
}



/* decode_block:
 *  Decodes a 8x8 block of pixel components; core algorithm.
 */
static int decode_block(DECODER_DATA *dec, int *dat, int dc, int ac, int qt, int *old_dc)
{
	int temp[64];
	int data, num_zeros, num_bits;
	int i, val, coef;
	HUFFMAN_NODE *dc_node, *ac_node;

	dc_node = dec->huffman_node + (dc << 8);
	ac_node = dec->huffman_node + (ac << 8) + 512;

	/* First step: huffman-decode 1 DC coefficient */
	data = huffman_decode(dec, dc_node);
	*old_dc += get_bits(dec, data & 0xf);
	dat[0] = *old_dc;

	coef = 1;
	do {
	  /* Second step: huffman-decode 63 AC coefficients */
	  data = huffman_decode(dec, ac_node);
	  if (data == -2) data = 0;
	  else if (data == -1) {
	     /* Bad block */
	     for (i=0; i<64; i++) dat[i] = 0;
	     for (i=0; i<8; i++) dat[(i<<3)|i] = 255;
	     for (i=0; i<8; i++) dat[(i<<3)|(7-i)] = 255;
	     return 1;
	  }
	  num_zeros = data >> 4;
	  num_bits = data & 0xf;
	  val = get_bits(dec, num_bits);

	  /* Third step: run length decoding */
	  if ((num_zeros == 0) && (num_bits == 0)) {         /* end of block */
	     for (i=coef; i<64; i++)
	        dat[i] = 0;
	     break;
	  }
	  else if ((num_zeros == 15) && (num_bits == 0)) {   /* 16 zeros RLE */
	     for (i=0; i<16; i++)
	        dat[coef + i] = 0;
	     coef += 16;
	  }
	  else {                                   /* normal zero run length */
	     for (i=0; i<num_zeros && coef<64; i++)
	        dat[coef++] = 0;
	     if (coef >= 64) break;

	     dat[coef++] = val;
	  }
	} while (coef < 64);

	/* Fourth step: zig-zag reordering */
	zigzag_reorder(dat);

	/* Fifth step: dequantization and inverse discrete cosine transform */
	do_idct(dat, dec->dequant + (qt << 6));

	return 0;
}


#define _R(y,u,v) (0x2568*(y)			   + 0x3343*(u)) /0x2000
#define _G(y,u,v) (0x2568*(y) - 0x0c92*(v) - 0x1a1e*(u)) /0x2000
#define _B(y,u,v) (0x2568*(y) + 0x40cf*(v)) 			 /0x2000

#define _S(a)		(a)>255 ? 255 : (a)<0 ? 0 : (a)

#define YUV2RGB( y, v, u, r, g, b ) \
{\
    signed int uu, vv;\
	uu = (int)(u) - 128;\
	vv = (int)(v) - 128;\
	r = _S(_R(y,uu,vv));\
	g = _S(_G(y,uu,vv));\
	b = _S(_B(y,uu,vv));\
}

#define putpixel_lc( bmp, xx, yy, y, cb, cr ) \
{\
   byte r, g, b;\
   YUV2RGB( y, cb, cr, r, g, b );\
   bmp[dec.width*(yy)+(xx)] = RGB8888( r, g, b );\
}

static int __jw, __jh;
#define DECODE_PERCALL	500

static word *_decodeBuf = NULL;

word *decode_jpg( void *data, int start )
{
   static DECODER_DATA dec;
   static int dc_y, dc_cb, dc_cr;
   static int x, y, hue;
   dword decodeBlockCound = 0;
//   static int startTick;
   
   int y1[64], y2[64], y3[64], y4[64], cb[64], cr[64];
   int i, j;

    if( start )
    {
//		startTick = TAP_GetTick();
       memset(&dec, 0, sizeof(dec));

       dec.data_start = (unsigned char *)data;
       dec.data = dec.data_start;

       /*
        *  Scans the jpg data for markers, until the SOS marker is found.
        */
       do {
          if (*dec.data++ == 0xff) {
             switch (*dec.data) {

                case SOF0:
                case SOF1:
                   dec.flags |= SOF0_DEFINED;
                   read_sof0(&dec);
                   break;

                case DHT:
                   dec.flags |= DHT_DEFINED;
                   read_dht(&dec);
                   break;

                case SOI:
                   dec.flags |= SOI_DEFINED;
                   dec.data++;
                   break;

                case SOS:
                   dec.flags |= SOS_DEFINED;
                   read_sos(&dec);
                   break;

                case DQT:
                   dec.flags |= DQT_DEFINED;
                   read_dqt(&dec);
                   break;

                case DRI:
                   dec.flags |= DRI_DEFINED;
                   dec.data += 5;
                   break;

                case APP0:
                   dec.flags |= APP0_DEFINED;
                   read_app0(&dec);
                   break;

                case APP1:
                   read_app1(&dec);
                   break;


                case COM:
                   dec.data++;
                   i = NEXTWORD(&dec);
                   dec.data += i;
                   break;

             }
          }
       /*
        *  Continue scanning for 10000 bytes (more than enough for a header eh?)
        *  or until all the proper markers have been found.
        */
       } while ((dec.data <= dec.data_start + 10000) && !(dec.flags & SOS_DEFINED));

	   dec.width = (dec.width+15)/16*16;
	   dec.height = dec.height;

//	   TAP_Print("width = %d, height = %d\r\n", dec.width, dec.height );

       __jw = dec.width;
       __jh = dec.height;
       
       _decodeBuf = TAP_MemAlloc( dec.width * ((dec.height+15)/16*16) * 2 );
       if (!_decodeBuf)
          return NULL;

       x = y = 0;
       dc_y = dc_cb = dc_cr = 0;
       dec.bits = 8;
       dec.byte = *dec.data;
	   return (word *)1;
    }

    if( y >= dec.height)
        return NULL;

   switch(dec.components) {

      case 3:
         /*
          *  Image has three components (1 for luminance and 2 for chrominance);
          *  this means it's a colored image.
          */
         switch(dec.samples_y) {

            case 4:
               do {
                  /* 1st case:
                   *  chrominance is taken every two pixels (horizontally and
                   *  vertically), and luminance for every pixel.
                   */
                  decode_block(&dec, y1, dec.dc_y, dec.ac_y, dec.quant_y, &dc_y);
                  decode_block(&dec, y2, dec.dc_y, dec.ac_y, dec.quant_y, &dc_y);
                  decode_block(&dec, y3, dec.dc_y, dec.ac_y, dec.quant_y, &dc_y);
                  decode_block(&dec, y4, dec.dc_y, dec.ac_y, dec.quant_y, &dc_y);
                  decode_block(&dec, cb, dec.dc_cbcr, dec.ac_cbcr, dec.quant_cbcr, &dc_cb);
                  decode_block(&dec, cr, dec.dc_cbcr, dec.ac_cbcr, dec.quant_cbcr, &dc_cr);
                  for (i=0; i<8; i++) for (j=0; j<8; j++)
                     putpixel_lc(_decodeBuf, x + j, y + i,
                              y1[(i << 3) | j],
                              cb[((i >> 1) << 3) | (j >> 1)],
                              cr[((i >> 1) << 3) | (j >> 1)]);
                  for (i=0; i<8; i++) for (j=0; j<8; j++)
                     putpixel_lc(_decodeBuf, x + 8 + j, y + i,
                              y2[(i << 3) | j],
                              cb[((i >> 1) << 3) | ((j >> 1) + 4)],
                              cr[((i >> 1) << 3) | ((j >> 1) + 4)]);
                  for (i=0; i<8; i++) for (j=0; j<8; j++)
                     putpixel_lc(_decodeBuf, x + j, y + 8 + i,
                              y3[(i << 3) | j],
                              cb[(((i >> 1) + 4) << 3) | (j >> 1)],
                              cr[(((i >> 1) + 4) << 3) | (j >> 1)]);
                  for (i=0; i<8; i++) for (j=0; j<8; j++)
                     putpixel_lc(_decodeBuf, x + 8 + j, y + 8 + i,
                              y4[(i << 3) | j],
                              cb[(((i >> 1) + 4) << 3) | ((j >> 1) + 4)],
                              cr[(((i >> 1) + 4) << 3) | ((j >> 1) + 4)]);
                  x += 16;
                  if (x >= dec.width) {
                     x = 0;
                     y += 16;
                     if (dec.flags & DRI_DEFINED) {
                        dc_y = dc_cb = dc_cr = 0;
                        dec.data += 2;
                        dec.bits = 0;
                     }
                  }

				  decodeBlockCound++;
				  if( decodeBlockCound == DECODE_PERCALL )
					 break;
				  

               } while (y < dec.height);
               break;

            case 2:
               do {
                  /* 2nd case:
                   *  chrominance is taken every two pixels (only horizontally)
                   *  and luminance every pixel.
                   */
                  decode_block(&dec, y1, dec.dc_y, dec.ac_y, dec.quant_y, &dc_y);
                  decode_block(&dec, y2, dec.dc_y, dec.ac_y, dec.quant_y, &dc_y);
                  decode_block(&dec, cb, dec.dc_cbcr, dec.ac_cbcr, dec.quant_cbcr, &dc_cb);
                  decode_block(&dec, cr, dec.dc_cbcr, dec.ac_cbcr, dec.quant_cbcr, &dc_cr);
                  for (i=0; i<8; i++) for (j=0; j<8; j++)
                     putpixel_lc(_decodeBuf, x + j, y + i,
                              y1[(i << 3) | j],
                              cb[(i << 3) | (j >> 1)],
                              cr[(i << 3) | (j >> 1)]);
                  for (i=0; i<8; i++) for (j=0; j<8; j++)
                     putpixel_lc(_decodeBuf, x + 8 + j, y + i,
                              y2[(i << 3) | j],
                              cb[(i << 3) | ((j >> 1) + 4)],
                              cr[(i << 3) | ((j >> 1) + 4)]);
                  x += 16;
                  if (x >= dec.width) {
                     x = 0;
                     y += 8;
                     if (dec.flags & DRI_DEFINED) {
                        dc_y = dc_cb = dc_cr = 0;
                        dec.data += 2;
                        dec.bits = 0;
                     }
                  }
				  decodeBlockCound++;
				  if( decodeBlockCound == DECODE_PERCALL )
					 break;

               } while (y < dec.height);
               break;

            case 1:
               do {
                  /* 3rd case:
                   *  chrominance and luminance are taken every pixel.
                   */
                  decode_block(&dec, y1, dec.dc_y, dec.ac_y, dec.quant_y, &dc_y);
                  decode_block(&dec, cb, dec.dc_cbcr, dec.ac_cbcr, dec.quant_cbcr, &dc_cb);
                  decode_block(&dec, cr, dec.dc_cbcr, dec.ac_cbcr, dec.quant_cbcr, &dc_cr);
                  for (i=0; i<8; i++) for (j=0; j<8; j++)
                     putpixel_lc(_decodeBuf, x + j, y + i,
                              y1[(i << 3) | j],
                              cb[(i << 3) | j],
                              cr[(i << 3) | j]);
                  x += 8;
                  if (x >= dec.width) {
                     x = 0;
                     y += 8;
                     if (dec.flags & DRI_DEFINED) {
                        dc_y = dc_cb = dc_cr = 0;
                        dec.data += 2;
                        dec.bits = 0;
                     }
                  }
				  decodeBlockCound++;
				  if( decodeBlockCound == DECODE_PERCALL )
					 break;

               } while (y < dec.height);
               break;
         }
		 break;

      case 1:
         /*
          *  Image has just one component (luminance) taken every pixel; we
          *  have a grayscaled picture.
          */
         do {
            decode_block(&dec, y1, dec.dc_y, dec.ac_y, dec.quant_y, &dc_y);
            for (i=0; i<8; i++) for (j=0; j<8; j++) {
               putpixel_lc(_decodeBuf, x + j, y + i, y1[(i << 3) | j], 0, 0 );
            }
            x += 8;
            if (x >= dec.width) {
               x = 0;
               y += 8;
               if (dec.flags & DRI_DEFINED) {
                  dc_y = 0;
                  dec.data += 2;
                  dec.bits = 0;
               }
            }
			decodeBlockCound++;
			if( decodeBlockCound == DECODE_PERCALL )
				break;

         } while (y < dec.height);
         break;
   }

    if( y >= dec.height)
    {
//		TAP_Print("decode time : %d\r\n", TAP_GetTick() - startTick );
       return _decodeBuf;
    }

    return NULL;
}



byte *load_jpg( char *filename, int *width, int *height )
{
    long size;
    unsigned char *data;
    TYPE_File *file;

    file = TAP_Hdd_Fopen( filename );
    if( file == NULL )
        return NULL;

    size = TAP_Hdd_Flen( file );

    data = (unsigned char *)TAP_MemAlloc( size );
    if (!data)
        return NULL;

    TAP_Hdd_Fread( data, size, 1, file );
    TAP_Hdd_Fclose( file );

	if( decode_jpg( data, 1 ) == NULL )
	{
		TAP_MemFree( data );
		return NULL;
	}
	*width = __jw;
	*height = __jh;
    return data;
}

void free_jpg( void )
{
	if( _decodeBuf )
	{
		TAP_MemFree( _decodeBuf );
		_decodeBuf = NULL;
	}
}
