text: // DOM-IGNORE-BEGIN
  /*******************************************************************************
  * Copyright (C) 2020 Microchip Technology Inc. and its subsidiaries.
  *
  * Subject to your compliance with these terms, you may use Microchip software
  * and any derivatives exclusively with Microchip products. It is your
  * responsibility to comply with third party license terms applicable to your
  * use of third party software (including open source software) that may
  * accompany Microchip software.
  *
  * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER
  * EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED
  * WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A
  * PARTICULAR PURPOSE.
  *
  * IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE,
  * INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND
  * WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS
  * BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE
  * FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN
  * ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
  * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
  *******************************************************************************/
  // DOM-IGNORE-END
  
  
  #include "gfx/legato/image/jpeg/legato_imagedecoder_jpeg_common.h"
  
  #include "gfx/legato/memory/legato_memory.h"
  #include "gfx/legato/common/legato_rect.h"
  
  void jpeg_idct_islow (short *inbuf, uint16_t *quantptr);
  
  
  static void JPEG_Seek(JPEGDECODER* decoder, long offset, int whence)
  {
      if(whence == 0)
      {
          decoder->fileIndex = offset;
      }
      else if(whence == 1)
      {
          decoder->fileIndex += offset;
      }
  }
  
  /*static size_t JPEG_Read(void *ptr, size_t size, size_t n, JPEGDECODER* decoder)
  {
      size_t count = 0;
      uint8_t* pFile;
      uint8_t* bptr;
  
      pFile = (uint8_t*)decoder->pImageFile->header.dataAddress;
      bptr = (uint8_t *)ptr;
  
      for(count = 0; count < size * n; ++count)
      {
          bptr[count] = (uint8_t) pFile[decoder->fileIndex];
          ++decoder->fileIndex;
      }
      return count;
  }*/
  
  
  void JPEG_vResetDecoder(JPEGDECODER *decoder)
  {
      uint16_t wIndex;
      uint8_t *pbptr = (uint8_t*)decoder;
      for(wIndex = 0; wIndex < sizeof(JPEGDECODER); wIndex++)
      {
          pbptr[wIndex] = 0;
      }
  }
  
  /*******************************************************************************
  Function:       uint16_t JPEG_wReadWord(GFXU_ImageAsset *pfile)
  
  Precondition:   None
  
  Overview:       This function reads and returns a single word obtained as
                  Higher byte first followed by lower byte
  
  Input:          Image file
  
  Output:         One word
  *******************************************************************************/
  static uint16_t JPEG_wReadWord(JPEGDECODER *decoder)
  {
      uint8_t btemp;
      uint16_t wData;
  
      decoder->readPtr(&btemp, sizeof(btemp), 1, decoder);
      wData = btemp;
      decoder->readPtr(&btemp, sizeof(btemp), 1, decoder);
      wData = (wData << 8) | btemp;
  
      return wData;
  }
  
  /*******************************************************************************
  Function:       uint8_t JPEG_bReadByte(GFXU_ImageAsset *pfile)
  
  Precondition:   None
  
  Overview:       This function reads and returns a single byte from the file
  
  Input:          Image file
  
  Output:         One byte
  *******************************************************************************/
  static uint8_t JPEG_bReadByte(JPEGDECODER *decoder)
  {
      uint8_t bData;
  
      decoder->readPtr(&bData, sizeof(bData), 1, decoder);
  
      return bData;
  }
  
  /*******************************************************************************
  Function:       uint8_t JPEG_bReadHeader(JPEGDECODER *pJpegDecoder)
  
  Precondition:   None
  
  Overview:       This function reads the JPEG file header and
                  fills the data structure
  
  Input:          JPEGDECODER
  
  Output:         Error code - '0' means no error
  *******************************************************************************/
  uint8_t JPEG_bReadHeader(JPEGDECODER *pJpegDecoder)
  {
      leBool blSOSOver = 0;
      while(pJpegDecoder->fileIndex * sizeof(uint8_t)
      < pJpegDecoder->pImageFile->header.size)
      {
          uint8_t btemp, bcount, bsection;
          uint16_t wSegLen, wOffset;
  
          if(blSOSOver == 1)
          {
              if(pJpegDecoder->bChannels == 1)
              {
                  pJpegDecoder->bBlocksInOnePass = 1;
                  pJpegDecoder->bSubSampleType = JPEG_SAMPLE_1x1;
              }
              else if(pJpegDecoder->bChannels == 3)
              {
                  if((pJpegDecoder->abChannelHSampFactor[0] == 1 && pJpegDecoder->abChannelVSampFactor[0] == 1) &&
                  (pJpegDecoder->abChannelHSampFactor[1] == 1 && pJpegDecoder->abChannelVSampFactor[1] == 1) &&
                  (pJpegDecoder->abChannelHSampFactor[2] == 1 && pJpegDecoder->abChannelVSampFactor[2] == 1))
                  {
                      pJpegDecoder->bBlocksInOnePass = 3;
                      pJpegDecoder->abChannelMap[0] = 0;
                      pJpegDecoder->abChannelMap[1] = 1;
                      pJpegDecoder->abChannelMap[2] = 2;
                      pJpegDecoder->bSubSampleType = JPEG_SAMPLE_1x1;
                  }
                  else if((pJpegDecoder->abChannelHSampFactor[0] == 1 && pJpegDecoder->abChannelVSampFactor[0] == 2) &&
                  (pJpegDecoder->abChannelHSampFactor[1] == 1 && pJpegDecoder->abChannelVSampFactor[1] == 1) &&
                  (pJpegDecoder->abChannelHSampFactor[2] == 1 && pJpegDecoder->abChannelVSampFactor[2] == 1))
                  {
                      pJpegDecoder->bBlocksInOnePass = 4;
                      pJpegDecoder->abChannelMap[0] = 0;
                      pJpegDecoder->abChannelMap[1] = 0;
                      pJpegDecoder->abChannelMap[2] = 1;
                      pJpegDecoder->abChannelMap[3] = 2;
                      pJpegDecoder->bSubSampleType = JPEG_SAMPLE_1x2;
                  }
                  else if((pJpegDecoder->abChannelHSampFactor[0] == 2 && pJpegDecoder->abChannelVSampFactor[0] == 1) &&
                  (pJpegDecoder->abChannelHSampFactor[1] == 1 && pJpegDecoder->abChannelVSampFactor[1] == 1) &&
                  (pJpegDecoder->abChannelHSampFactor[2] == 1 && pJpegDecoder->abChannelVSampFactor[2] == 1))
                  {
                      pJpegDecoder->bBlocksInOnePass = 4;
                      pJpegDecoder->abChannelMap[0] = 0;
                      pJpegDecoder->abChannelMap[1] = 0;
                      pJpegDecoder->abChannelMap[2] = 1;
                      pJpegDecoder->abChannelMap[3] = 2;
                      pJpegDecoder->bSubSampleType = JPEG_SAMPLE_2x1;
                  }
                  else if((pJpegDecoder->abChannelHSampFactor[0] == 2 && pJpegDecoder->abChannelVSampFactor[0] == 2) &&
                  (pJpegDecoder->abChannelHSampFactor[1] == 1 && pJpegDecoder->abChannelVSampFactor[1] == 1) &&
                  (pJpegDecoder->abChannelHSampFactor[2] == 1 && pJpegDecoder->abChannelVSampFactor[2] == 1))
                  {
                      pJpegDecoder->bBlocksInOnePass = 6;
                      pJpegDecoder->abChannelMap[0] = 0;
                      pJpegDecoder->abChannelMap[1] = 0;
                      pJpegDecoder->abChannelMap[2] = 0;
                      pJpegDecoder->abChannelMap[3] = 0;
                      pJpegDecoder->abChannelMap[4] = 1;
                      pJpegDecoder->abChannelMap[5] = 2;
                      pJpegDecoder->bSubSampleType = JPEG_SAMPLE_2x2;
                  }
                  else
                  {
                      JPEG_SendError(100);
                  }
              }
              return 0;
          }
  
          pJpegDecoder->readPtr(&btemp, sizeof(btemp), 1, pJpegDecoder);
  
          if(btemp != 0xFF)
          {
              continue;
          }
  
          pJpegDecoder->readPtr(&bsection, sizeof(bsection), 1, pJpegDecoder);
          switch(bsection)
          {
              case SOI:
              case TEM:
              case EOI:
              case RST0:
              case RST1:
              case RST2:
              case RST3:
              case RST4:
              case RST5:
              case RST6:
              case RST7: break;
  
              case SOF0: /* Start of frame */
                  wSegLen = JPEG_wReadWord(pJpegDecoder);
                  if(wSegLen <= 8)
                  {
                      JPEG_SendError(100);
                      break;
                  }
                  pJpegDecoder->bDataBits = JPEG_bReadByte(pJpegDecoder);
                  pJpegDecoder->wHeight   = JPEG_wReadWord(pJpegDecoder);
                  pJpegDecoder->wWidth    = JPEG_wReadWord(pJpegDecoder);
                  pJpegDecoder->bChannels = JPEG_bReadByte(pJpegDecoder);
                  if(wSegLen < 8 + (pJpegDecoder->bChannels * 3))
                  {
                      JPEG_SendError(100);
                      break;
                  }
                  for(bcount = 0; bcount < pJpegDecoder->bChannels; bcount++)
                  {
                      pJpegDecoder->abChannelType[bcount] = JPEG_bReadByte(pJpegDecoder);
                      btemp = JPEG_bReadByte(pJpegDecoder);
                      pJpegDecoder->abChannelHSampFactor[bcount] = btemp >> 4;
                      pJpegDecoder->abChannelVSampFactor[bcount] = btemp & 0x0F;
                      pJpegDecoder->abChannelQuantTableMap[bcount] = JPEG_bReadByte(pJpegDecoder);
                  }
                  break;
  
              case APP0: /* Start of Application */
                  wSegLen = JPEG_wReadWord(pJpegDecoder);
                  if(wSegLen < 16)
                  {
                      JPEG_SendError(100);
                      break;
                  }
                  else
                  {
                      unsigned char buf[5];
                      pJpegDecoder->readPtr(buf, sizeof(buf[0]), 5, pJpegDecoder);
                      if(buf[0] == 'J' && buf[1] == 'F' && buf[2] == 'I' && buf[3] == 'F' && buf[4] == '\0')
                      {
                          pJpegDecoder->blJFIF = 1;
                      }
                  }
                  pJpegDecoder->bMajorRev = JPEG_bReadByte(pJpegDecoder);
                  pJpegDecoder->bMinorRev = JPEG_bReadByte(pJpegDecoder);
                  if(pJpegDecoder->bMajorRev != 1)
                  {
                      JPEG_SendError(100);
                      break;
                  }
                  /* Ignore other bytes in this segment */
                  break;
  
              case DRI: /* Start of Quantization table */
                  wSegLen = JPEG_wReadWord(pJpegDecoder);
                  if(wSegLen == 4)
                  {
                      pJpegDecoder->wRestartInterval = JPEG_wReadWord(pJpegDecoder);
                  }
                  break;
  
              case DQT: /* Start of Quantization table */
                  wSegLen = JPEG_wReadWord(pJpegDecoder);
                  if(wSegLen < 67)
                  {
                      JPEG_SendError(100);
                      break;
                  }
  
                  do
                  {
                      uint8_t bQTableIndex, bCounter;
  
                      btemp = JPEG_bReadByte(pJpegDecoder);
                      bQTableIndex = btemp & 0x0F;
                      pJpegDecoder->blQuantUses16bits |= (btemp >> 4);
  
                      for(bCounter = 0; bCounter < 64; bCounter++)
                      {
                          uint8_t bData1, bData2 = 0;
                          if(pJpegDecoder->blQuantUses16bits == 0)
                          {
                              pJpegDecoder->readPtr(&bData1, sizeof(uint8_t), 1, pJpegDecoder);
                              pJpegDecoder->awQuantTable[bQTableIndex][abZigzag[bCounter]] = bData1;
                          }
                          else
                          {
                              pJpegDecoder->readPtr(&bData1, sizeof(uint8_t), 1, pJpegDecoder);
                              pJpegDecoder->readPtr(&bData2, sizeof(uint8_t), 1, pJpegDecoder);
                              pJpegDecoder->awQuantTable[bQTableIndex][abZigzag[bCounter]] = (((uint16_t)bData1) << 8) + (uint16_t)bData2;
                          }
                      }
                      wSegLen -= (pJpegDecoder->blQuantUses16bits == 0)? 65: 129; /* Table length + information byte */
                  } while(wSegLen >= 67);
                  break;
  
              case DHT: /* Start of Huffmann table */
                  wSegLen = JPEG_wReadWord(pJpegDecoder);
                  if(wSegLen < 19)
                  {
                      JPEG_SendError(100);
                      break;
                  }
  
                  do
                  {
                      uint8_t bHTableIndex, bCounter;
                      uint16_t wNumOfSymbols;
                      uint8_t blIsAc;
                      uint8_t *pbLenTable, *pbSymTable;
  
                      btemp = JPEG_bReadByte(pJpegDecoder);
                      bHTableIndex = btemp & 0x0F;
                      blIsAc = (btemp >> 4) & 0x01;
  
                      if(blIsAc == 0)
                      {
                          pbLenTable = (uint8_t*)&pJpegDecoder->abHuffDcSymLen[bHTableIndex][0];
                          pbSymTable = (uint8_t*)&pJpegDecoder->abHuffDcSymbol[bHTableIndex][0];
                      }
                      else
                      {
                          pbLenTable = (uint8_t*)&pJpegDecoder->abHuffAcSymLen[bHTableIndex][0];
                          pbSymTable = (uint8_t*)&pJpegDecoder->abHuffAcSymbol[bHTableIndex][0];
                      }
  
                      pJpegDecoder->readPtr(pbLenTable, sizeof(uint8_t), 16, pJpegDecoder);
  
                      for(bCounter = 0, wNumOfSymbols = 0; bCounter < 16; bCounter++)
                      {
                          wNumOfSymbols += pbLenTable[bCounter];
                      }
  
                      wSegLen -= 17; /* This table length + information byte */
  
                      if(wSegLen < wNumOfSymbols || (blIsAc == 1 && wNumOfSymbols > 256) || (blIsAc == 0 && wNumOfSymbols > 16))
                      {
                          JPEG_SendError(100);
                          break;
                      }
  
                      pJpegDecoder->readPtr(pbSymTable, sizeof(uint8_t), wNumOfSymbols, pJpegDecoder);
                      wSegLen -= wNumOfSymbols; /* This table length + information byte */
                      pJpegDecoder->bHuffTables++;
                  } while(wSegLen >= 19);
                  break;
  
              case SOS: /* Start of Scan parameters */
                  wSegLen = JPEG_wReadWord(pJpegDecoder);
                  if(wSegLen < 3)
                  {
                      JPEG_SendError(100);
                      break;
                  }
  
                  btemp = JPEG_bReadByte(pJpegDecoder);
                  wOffset = wSegLen - (3 + (btemp << 1));
  
                  if(pJpegDecoder->bChannels != btemp || wSegLen < 3 + (btemp << 1))
                  {
                      JPEG_SendError(100);
                      break;
                  }
                  else
                  {
                      uint8_t bCounter, bChannelId = 0xFF;
  
                      for(bCounter = 0; bCounter < pJpegDecoder->bChannels; bCounter++)
                      {
                          uint8_t bindex;
  
                          btemp = JPEG_bReadByte(pJpegDecoder);
                          for(bindex = 0; bindex < MAX_CHANNELS; bindex++)
                          {
                              if(pJpegDecoder->abChannelType[bindex] == btemp)
                              {
                                  bChannelId = bindex;
                                  break;
                              }
                          }
  
                          if(bChannelId < MAX_CHANNELS)
                          {
                              btemp = JPEG_bReadByte(pJpegDecoder);
                              pJpegDecoder->abChannelHuffAcTableMap[bChannelId] = btemp & 0x0F;
                              pJpegDecoder->abChannelHuffDcTableMap[bChannelId] = btemp >> 4;
                          }
                      }
                      JPEG_Seek(pJpegDecoder, wOffset, 1);
                  }
                  blSOSOver = 1;
                  break;
  
              default: /* Any other segment with length */
                  wSegLen = JPEG_wReadWord(pJpegDecoder);
                  if(wSegLen < 2)
                  {
                      JPEG_SendError(100);
                      break;
                  }
                  JPEG_Seek(pJpegDecoder, wSegLen - 2, 1);
          }
      }
      return (pJpegDecoder->blJFIF == 1) ? 0 : 1;
  }
  
  /*******************************************************************************
  Function:       uint8_t JPEG_bGenerateHuffmanTables(JPEGDECODER *pJpegDecoder)
  
  Precondition:   None
  
  Overview:       This function generated the table required for Huffman decoding
                  from the data read from the header
  
  Input:          JPEGDECODER
  
  Output:         Error code - '0' means no error
  *******************************************************************************/
  uint8_t JPEG_bGenerateHuffmanTables(JPEGDECODER *pJpegDecoder)
  {
      uint8_t bLength, bTable;
  
      for(bTable = 0; bTable < pJpegDecoder->bHuffTables / 2; bTable++)
      {
          pJpegDecoder->awHuffAcSymStart[bTable][0] = 0;
          pJpegDecoder->awHuffDcSymStart[bTable][0] = 0;
  
          for(bLength = 1; bLength < 16; bLength++)
          {
              pJpegDecoder->awHuffAcSymStart[bTable][bLength] = (pJpegDecoder->awHuffAcSymStart[bTable][bLength - 1] + pJpegDecoder->abHuffAcSymLen[bTable][bLength - 1]) << 1;
              pJpegDecoder->awHuffDcSymStart[bTable][bLength] = (pJpegDecoder->awHuffDcSymStart[bTable][bLength - 1] + pJpegDecoder->abHuffDcSymLen[bTable][bLength - 1]) << 1;
          }
      }
      return 0;
  }
  
  /*******************************************************************************
  Function:       uint8_t JPEG_bGet1Bit(JPEGDECODER *pJpegDecoder)
  
  Precondition:   None
  
  Overview:       This function returns 1 bit as the lsb of the returned byte.
                  It automatically fills the buffer if it becomes empty.
                  It also converts 0xFF00 into 0.
  
  Input:          JPEGDECODER
  
  Output:         One bit
  *******************************************************************************/
  static uint8_t JPEG_bGet1Bit(JPEGDECODER *pJpegDecoder)
  {
      uint8_t bBit = 0;
  
      if(pJpegDecoder->wBufferIndex >= pJpegDecoder->wBufferLen)
      {
          pJpegDecoder->wBufferLen = pJpegDecoder->readPtr(&pJpegDecoder->abDataBuffer[0], sizeof(uint8_t), MAX_DATA_BUF_LEN, pJpegDecoder);
          while(pJpegDecoder->abDataBuffer[pJpegDecoder->wBufferLen - 1] == 0xFF)
          {
              pJpegDecoder->wBufferLen--;
              JPEG_Seek(pJpegDecoder, -1, 1);
          }
          pJpegDecoder->wBufferIndex = 0;
      }
  
      while(pJpegDecoder->bBitsAvailable == 0) /* Be very careful to touch this part of code! You must know exactly what you are doing */
      {
          pJpegDecoder->bBitsAvailable = 16;
          pJpegDecoder->wWorkBits = pJpegDecoder->abDataBuffer[pJpegDecoder->wBufferIndex++];
          pJpegDecoder->wWorkBits = (pJpegDecoder->wWorkBits << 8) + pJpegDecoder->abDataBuffer[pJpegDecoder->wBufferIndex++];
          if(pJpegDecoder->wBufferIndex > pJpegDecoder->wBufferLen) /* wBufferIndex need not be even because of the below condition */
          {
              pJpegDecoder->bBitsAvailable = 8;
          }
          else if((pJpegDecoder->wWorkBits & 0x00FF) == 0x00FF)
          {
              pJpegDecoder->bBitsAvailable = 8;
              pJpegDecoder->wBufferIndex--;
          }
          else if(pJpegDecoder->wWorkBits >= 0xFF00)
          {
              if(pJpegDecoder->wWorkBits == 0xFF00)
              {
                  pJpegDecoder->bBitsAvailable = 8;
              }
          }
      }
  
      bBit = (pJpegDecoder->wWorkBits & 0x8000)? 0x01: 0;
  
      pJpegDecoder->wWorkBits <<= 1;
      pJpegDecoder->bBitsAvailable--;
  
      return bBit;
  }
  
  /*******************************************************************************
  Function:       uint16_t JPEG_wGetBits(JPEGDECODER *pJpegDecoder, uint8_t bLen)
  
  Precondition:   None
  
  Overview:       This function returns bLen number of bits as the lsb of the
                  returned word and it automatically fills the buffer
                  if it becomes empty.
  
  Input:          JPEGDECODER, Number of bits
  
  Output:         Requested number of bits
  *******************************************************************************/
  static uint16_t JPEG_wGetBits(JPEGDECODER *pJpegDecoder, uint8_t bLen)
  {
      uint16_t wVal = 0;
  
      wVal = pJpegDecoder->bFirstBit = JPEG_bGet1Bit(pJpegDecoder);
      bLen--;
  
      while(bLen)
      {
          wVal = (wVal << 1) + JPEG_bGet1Bit(pJpegDecoder);
          bLen--;
      }
  
      return wVal;
  }
  
  /*******************************************************************************
  Function:       uint16_t JPEG_wGetRestartWord(JPEGDECODER *pJpegDecoder)
  
  Precondition:   File pointer must point to the restart word
  
  Overview:       Returns the restart word
  
  Input:          JPEGDECODER
  
  Output:         Restart word
  *******************************************************************************/
  static uint16_t JPEG_wGetRestartWord(JPEGDECODER *pJpegDecoder)
  {
      uint16_t wRestartWord;
      while((pJpegDecoder->bBitsAvailable & 0x07) != 0) /* This is to clearoff wnwanted bits to go to fresh byte */
      {
          JPEG_bGet1Bit(pJpegDecoder);
      }
      wRestartWord = JPEG_wGetBits(pJpegDecoder, 16);
      return(wRestartWord);
  }
  
  /*******************************************************************************
  Function:       int16_t JPEG_sGetBitsValue(JPEGDECODER *pJpegDecoder, uint8_t bLen)
  
  Precondition:   None
  
  Overview:       Returns the signed value of the bLen bits of data
  
  Input:          JPEGDECODER, Number of bits
  
  Output:         Signed number
  *******************************************************************************/
  static int16_t JPEG_sGetBitsValue(JPEGDECODER *pJpegDecoder, uint8_t bLen)
  {
      uint16_t wVal = 0;
  
      if(bLen != 0)
      {
          wVal = JPEG_wGetBits(pJpegDecoder, bLen);
          if(pJpegDecoder->bFirstBit == 0)
          {
              wVal = ~(wVal | (0xFFFF << bLen));
              return ((int16_t)wVal * -1);
          }
      }
      return (int16_t)wVal;
  }
  
  /*******************************************************************************
  Function:       uint8_t JPEG_bGetNextHuffByte(JPEGDECODER *pJpegDecoder)
  
  Precondition:   File pointer must point to the Huffman data
  
  Overview:       Returns the Huffman decoded data
  
  Input:          JPEGDECODER
  
  Output:         Huffman decoded data
  *******************************************************************************/
  static uint8_t JPEG_bGetNextHuffByte(JPEGDECODER *pJpegDecoder)
  {
      uint8_t bBits, bSymbol = 0;
      uint16_t wBitPattern = 0, wSymbolOffset = 0;
  
      for(bBits = 0; bBits < 16; bBits++)
      {
          uint8_t bSymbols;
          uint16_t wDiff;
  
          wBitPattern = (wBitPattern << 1) + JPEG_bGet1Bit(pJpegDecoder);
          bSymbols = pJpegDecoder->pbCurrentHuffSymLenTable[bBits];
          if(bSymbols == 0)
          {
              continue;
          }
  
          wDiff = wBitPattern - pJpegDecoder->pwCurrentHuffSymStartTable[bBits];
          if(wDiff < bSymbols)
          {
              bSymbol = pJpegDecoder->pbCurrentHuffSymbolTable[wSymbolOffset + wDiff];
              break;
          }
          wSymbolOffset += bSymbols;
      }
      return bSymbol;
  }
  
  #define range_limit(x) (x<0)?0:(x>0xFF)?0xFF:x
  /*******************************************************************************
  Function:       uint8_t JPEG_bDecodeOneBlock(JPEGDECODER *pJpegDecoder)
  
  Precondition:   File pointer must point to a new block of data
  
  Overview:       Decodes the 8x8 pixel values of all the channels
                  (A multiple of 8x8 block if subsampling is used)
  
  Input:          JPEGDECODER
  
  Output:         Error code - '0' means no error
  *******************************************************************************/
  uint8_t JPEG_bDecodeOneBlock(JPEGDECODER *pJpegDecoder)
  {
      uint8_t bBlock, bCounter;
  
  
      for(bBlock = 0; bBlock < pJpegDecoder->bBlocksInOnePass; bBlock++)
      {
          uint8_t bByteCount, bHuffbyte;
  
          if((pJpegDecoder->wRestartInterval > 0) && (pJpegDecoder->wBlockNumber == pJpegDecoder->wRestartInterval * pJpegDecoder->bBlocksInOnePass))
          {
              uint16_t wRestartWord = JPEG_wGetRestartWord(pJpegDecoder);
              if(wRestartWord < 0xFFD0 || wRestartWord > 0xFFD7)
              {
                  JPEG_SendError(100);
              }
              for(bCounter = 0; bCounter < MAX_CHANNELS; bCounter++)
              {
                  pJpegDecoder->asPrevDcValue[bCounter] = 0;
              }
              pJpegDecoder->wBlockNumber = 0;
          }
  
          for(bCounter = 0; bCounter < 64; bCounter++)
          {
              pJpegDecoder->asOneBlock[bBlock][bCounter] = 0;
          }
  
          pJpegDecoder->pwCurrentQuantTable = &pJpegDecoder->awQuantTable[pJpegDecoder->abChannelQuantTableMap[pJpegDecoder->abChannelMap[bBlock]]][0];
  
          /* Decode DC value */
          bByteCount = 0;
          pJpegDecoder->pbCurrentHuffSymLenTable = &pJpegDecoder->abHuffDcSymLen[pJpegDecoder->abChannelHuffDcTableMap[pJpegDecoder->abChannelMap[bBlock]]][0];
          pJpegDecoder->pbCurrentHuffSymbolTable = &pJpegDecoder->abHuffDcSymbol[pJpegDecoder->abChannelHuffDcTableMap[pJpegDecoder->abChannelMap[bBlock]]][0];
          pJpegDecoder->pwCurrentHuffSymStartTable = &pJpegDecoder->awHuffDcSymStart[pJpegDecoder->abChannelHuffDcTableMap[pJpegDecoder->abChannelMap[bBlock]]][0];
          bHuffbyte = JPEG_bGetNextHuffByte(pJpegDecoder);
          pJpegDecoder->asOneBlock[bBlock][0] = JPEG_sGetBitsValue(pJpegDecoder, bHuffbyte & 0x0F) + pJpegDecoder->asPrevDcValue[pJpegDecoder->abChannelMap[bBlock]];
          pJpegDecoder->asPrevDcValue[pJpegDecoder->abChannelMap[bBlock]] = pJpegDecoder->asOneBlock[bBlock][0];
  
          /* Decode AC value */
          bByteCount = 1;
          pJpegDecoder->pbCurrentHuffSymLenTable = &pJpegDecoder->abHuffAcSymLen[pJpegDecoder->abChannelHuffAcTableMap[pJpegDecoder->abChannelMap[bBlock]]][0];
          pJpegDecoder->pbCurrentHuffSymbolTable = &pJpegDecoder->abHuffAcSymbol[pJpegDecoder->abChannelHuffAcTableMap[pJpegDecoder->abChannelMap[bBlock]]][0];
          pJpegDecoder->pwCurrentHuffSymStartTable = &pJpegDecoder->awHuffAcSymStart[pJpegDecoder->abChannelHuffAcTableMap[pJpegDecoder->abChannelMap[bBlock]]][0];
          while(bByteCount < 64)
          {
              bHuffbyte = JPEG_bGetNextHuffByte(pJpegDecoder);
              bByteCount += (bHuffbyte >> 4);
              if(bHuffbyte == 0 /* EOB */)
              {
                  break;
              }
              if(bByteCount > 63)
              {
                  JPEG_SendError(100);
              }
              pJpegDecoder->asOneBlock[bBlock][abZigzag[bByteCount++]] = JPEG_sGetBitsValue(pJpegDecoder, bHuffbyte & 0x0F);
          }
          pJpegDecoder->wBlockNumber++;
          jpeg_idct_islow(&pJpegDecoder->asOneBlock[bBlock][0],pJpegDecoder->pwCurrentQuantTable);
      }
  
      return 0;
  }
  
  #define JPEG_WRITE_TO_DISPLAY
  /*******************************************************************************
  Function:       void JPEG_vInitDisplay(JPEGDECODER *pJpegDecoder)
  
  Precondition:   None
  
  Overview:       Initializes the (x, y) co-ordinates to (0, 0)
  
  Input:          JPEGDECODER
  
  Output:         None
  *******************************************************************************/
  void JPEG_vInitDisplay(JPEGDECODER *pJpegDecoder)
  {
      pJpegDecoder->wPrevX = 0;
      pJpegDecoder->wPrevY = 0;
  }
  
  /*******************************************************************************
  Function:       uint8_t JPEG_bPaintOneBlock(JPEGDECODER *pJpegDecoder)
  
  Precondition:   One block - 8x8 pixel data of all channels must be decoded
  
  Overview:       Displays one 8x8 on the screen
                  (A multiple of 8x8 block if subsampling is used)
  
  Input:          JPEGDECODER
  
  Output:         Error code - '0' means no error
  *******************************************************************************/
  uint8_t JPEG_bPaintOneBlock(JPEGDECODER *pJpegDecoder)
  {
      static uint16_t wX, wY, wX2, psCxIndex;
      static uint8_t r,g,b;
      static short *psY,*psCb,*psCr;
      static int32_t s1,s2,s3;
      static uint8_t bBlock, bOffsetY[2] = {0,8}, bOffsetX[4] = {0,8,0,8}, bCbCrOffset[4] = {0,4,32,36};
      static uint16_t wXPos, wYPos,wYPos2;
      static uint8_t shiftX, shiftY;
      static lePoint pnt;
      static leColor color;
      leRect drawRect;
  
      if(pJpegDecoder->bSubSampleType == JPEG_SAMPLE_1x1)
      {
          shiftX = 8;
          shiftY = 8;
  
          lePixelBufferCreate(shiftX,
                              shiftY,
                              LE_COLOR_MODE_RGB_888,
                              NULL,
                              &pJpegDecoder->pixelBlockBuffer);
  
          pJpegDecoder->pixelBlockBuffer.pixels = LE_MALLOC(pJpegDecoder->pixelBlockBuffer.buffer_length);
  
          psY = &pJpegDecoder->asOneBlock[0][0];
          psCb = &pJpegDecoder->asOneBlock[1][0];
          psCr = &pJpegDecoder->asOneBlock[2][0];
  
          for(wY = 0; wY < 8; wY++)
          {
              for(wX = 0; wX < 8; wX++)
              {
                  s1 = ((*psY) + 128)*128, s2 = (*psCb), s3 = (*psCr);
                  r = range_limit((s1 + 180*s3)>>7);
                  g = range_limit((s1 - 44*s2 - 91*s3)>>7);
                  b = range_limit((s1 + 227*s2)>>7);
  
  //              IMG_vSetColor(r, g, b);
  //              IMG_vPixelArray(wX + (wY<<3));
  //                pixel[wX + (wY<<3)] = GFX_RGBConvert(r, g, b);
  
                  color = r << 16 | g << 8 | b;
  
                  pnt.x = wX;
                  pnt.y = wY; //(wY << 3);
  
                  lePixelBufferSet_Unsafe(&pJpegDecoder->pixelBlockBuffer,
                                          pnt.x,
                                          pnt.y,
                                          color);
  
                  psY++; psCb++; psCr++;
              }
          }
      }
      else if(pJpegDecoder->bSubSampleType == JPEG_SAMPLE_1x2)
      {
          shiftX = 8;
          shiftY = 16;
  
          lePixelBufferCreate(shiftX,
                              shiftY,
                              LE_COLOR_MODE_RGB_888,
                              NULL,
                              &pJpegDecoder->pixelBlockBuffer);
  
          pJpegDecoder->pixelBlockBuffer.pixels = LE_MALLOC(pJpegDecoder->pixelBlockBuffer.buffer_length);
  
          for(bBlock = 0; bBlock < 2; bBlock++)
          {
              psY = &pJpegDecoder->asOneBlock[bBlock][0];
              psCb = &pJpegDecoder->asOneBlock[2][bBlock<<5];
              psCr = &pJpegDecoder->asOneBlock[3][bBlock<<5];
  
              for(wY = 0; wY < 8; wY++)
              {
                  for(wX = 0; wX < 8; wX++)
                  {
                      s1 = ((*psY) + 128)*128;
                      s2 = psCb[(wY>>1)*8+wX];
                      s3 = psCr[(wY>>1)*8+wX];
                      r = range_limit((s1 + 180*s3)>>7);
                      g = range_limit((s1 - 44*s2 - 91*s3)>>7);
                      b = range_limit((s1 + 227*s2)>>7);
                      //pixel[wX + ((bOffsetY[bBlock] + wY)<<3)] = GFX_RGBConvert(r, g, b);
  
                      color = r << 16 | g << 8 | b;
  
                      pnt.x = wX;
                      pnt.y = ((bOffsetY[bBlock] + wY) << 3);
  
                      lePixelBufferSet_Unsafe(&pJpegDecoder->pixelBlockBuffer,
                                              pnt.x,
                                              pnt.y,
                                              color);
  
                      psY++;
                  }
              }
          }
      }
      else if(pJpegDecoder->bSubSampleType == JPEG_SAMPLE_2x1)
      {
          shiftX = 16;
          shiftY = 8;
  
          lePixelBufferCreate(shiftX,
                              shiftY,
                              LE_COLOR_MODE_RGB_888,
                              NULL,
                              &pJpegDecoder->pixelBlockBuffer);
  
          pJpegDecoder->pixelBlockBuffer.pixels = LE_MALLOC(pJpegDecoder->pixelBlockBuffer.buffer_length);
  
          for(bBlock = 0; bBlock < 2; bBlock++)
          {
              psY = &pJpegDecoder->asOneBlock[bBlock][0];
              psCb = &pJpegDecoder->asOneBlock[2][bBlock<<2];
              psCr = &pJpegDecoder->asOneBlock[3][bBlock<<2];
  
              for(wY = 0; wY < 8; wY++)
              {
                  for(wX = 0; wX < 8; wX++)
                  {
                      s1 = ((*psY) + 128)*128;
                      s2 = psCb[(wY*8)+(wX>>1)];
                      s3 = psCr[(wY*8)+(wX>>1)];
                      r = range_limit((s1 + 180*s3)>>7);
                      g = range_limit((s1 - 44*s2 - 91*s3)>>7);
                      b = range_limit((s1 + 227*s2)>>7);
  //                    pixel[bOffsetX[bBlock] + wX + (wY<<4)] = GFX_RGBConvert(r, g, b);
  
                      color = r << 16 | g << 8 | b;
  
                      pnt.x = bOffsetX[bBlock] + wX;
                      pnt.y = (wY << 4);
  
                      lePixelBufferSet_Unsafe(&pJpegDecoder->pixelBlockBuffer,
                                              pnt.x,
                                              pnt.y,
                                              color);
  
                      psY++;
                  }
              }
          }
      }
      else if(pJpegDecoder->bSubSampleType == JPEG_SAMPLE_2x2)
      {
          shiftX = 16;
          shiftY = 16;
  
          lePixelBufferCreate(shiftX,
                              shiftY,
                              LE_COLOR_MODE_RGB_888,
                              NULL,
                              &pJpegDecoder->pixelBlockBuffer);
  
          pJpegDecoder->pixelBlockBuffer.pixels = LE_MALLOC(pJpegDecoder->pixelBlockBuffer.buffer_length);
  
          for(bBlock = 0; bBlock < 4; bBlock++)
          {
              wXPos = bOffsetX[bBlock];
              wYPos = bOffsetY[bBlock>>1];
  
              psY = &pJpegDecoder->asOneBlock[bBlock][0];
              psCb = &pJpegDecoder->asOneBlock[4][bCbCrOffset[bBlock]];
              psCr = &pJpegDecoder->asOneBlock[5][bCbCrOffset[bBlock]];
  
              for(wY = 0; wY < 8; wY++)
              {
                  wYPos2 = wYPos + wY;
  
                  for(wX = 0; wX < 4; wX++)
                  {
                      psCxIndex = (wY>>1)*8 + wX;
                      s2 = psCb[psCxIndex];
                      s3 = psCr[psCxIndex];
  
                      for(wX2 = 0; wX2 < 2; wX2++)
                      {
                          s1 = ((*psY++) + 128)*128;
                          r = range_limit((s1 + 180*s3)>>7);
                          g = range_limit((s1 - 44*s2 - 91*s3)>>7);
                          b = range_limit((s1 + 227*s2)>>7);
                          //pixel[wXPos + (wX<<1) + wX2 + (wYPos2<<4)] = GFX_RGBConvert(r, g, b);
  
                          color = r << 16 | g << 8 | b;
  
                          pnt.x = wXPos + (wX<<1) + wX2;
                          pnt.y = wYPos2;
  
                          lePixelBufferSet_Unsafe(&pJpegDecoder->pixelBlockBuffer,
                                                  pnt.x,
                                                  pnt.y,
                                                  color);
                      }
                  }
              }
          }
      }
  
      drawRect.x = pJpegDecoder->wPrevX + pJpegDecoder->wDrawX;
      drawRect.y = pJpegDecoder->wPrevY + pJpegDecoder->wDrawY;
      drawRect.width = shiftX;
      drawRect.height = shiftY;
  
      if(leRectIntersects(&drawRect, &pJpegDecoder->clipRect) == LE_TRUE)
      {
          pJpegDecoder->blitPtr(pJpegDecoder,
                                &pJpegDecoder->pixelBlockBuffer,
                                0,
                                0,
                                shiftX,
                                shiftY,
                                pJpegDecoder->wPrevX + pJpegDecoder->wDrawX,
                                pJpegDecoder->wPrevY + pJpegDecoder->wDrawY,
                                pJpegDecoder->globalAlpha);
      }
  
      pJpegDecoder->wPrevX += shiftX;
  
      if (pJpegDecoder->wPrevX >= pJpegDecoder->wWidth + pJpegDecoder->wStartX)
      {
          pJpegDecoder->wPrevX = pJpegDecoder->wStartX;
          pJpegDecoder->wPrevY += shiftY;
      }
  
      LE_FREE(pJpegDecoder->pixelBlockBuffer.pixels);
  
      return 0;
  }
  
  int8_t JPEG_bInterpretResourceHeader(leImage* img)
  {
      JPEGDECODER JPEG_JpegDecoder;
  
      if (img == NULL)
          return -1;
  
      JPEG_vResetDecoder(&JPEG_JpegDecoder);
      JPEG_JpegDecoder.pImageFile = img;
  
      if(JPEG_bReadHeader(&JPEG_JpegDecoder) != 0)
      {
          return(1);
      }
  
      return 0;
  }
  