gifcodec.cpp
上传用户:zhongxx05
上传日期:2007-06-06
资源大小:33641k
文件大小:42k
源码类别:

Symbian

开发平台:

C/C++

  1. /* ***** BEGIN LICENSE BLOCK ***** 
  2.  * Version: RCSL 1.0/RPSL 1.0 
  3.  *  
  4.  * Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved. 
  5.  *      
  6.  * The contents of this file, and the files included with this file, are 
  7.  * subject to the current version of the RealNetworks Public Source License 
  8.  * Version 1.0 (the "RPSL") available at 
  9.  * http://www.helixcommunity.org/content/rpsl unless you have licensed 
  10.  * the file under the RealNetworks Community Source License Version 1.0 
  11.  * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl, 
  12.  * in which case the RCSL will apply. You may also obtain the license terms 
  13.  * directly from RealNetworks.  You may not use this file except in 
  14.  * compliance with the RPSL or, if you have a valid RCSL with RealNetworks 
  15.  * applicable to this file, the RCSL.  Please see the applicable RPSL or 
  16.  * RCSL for the rights, obligations and limitations governing use of the 
  17.  * contents of the file.  
  18.  *  
  19.  * This file is part of the Helix DNA Technology. RealNetworks is the 
  20.  * developer of the Original Code and owns the copyrights in the portions 
  21.  * it created. 
  22.  *  
  23.  * This file, and the files included with this file, is distributed and made 
  24.  * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
  25.  * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
  26.  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS 
  27.  * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
  28.  * 
  29.  * Technology Compatibility Kit Test Suite(s) Location: 
  30.  *    http://www.helixcommunity.org/content/tck 
  31.  * 
  32.  * Contributor(s): 
  33.  *  
  34.  * ***** END LICENSE BLOCK ***** */ 
  35. // system
  36. #include <hlxclib/memory.h>
  37. #include <string.h>
  38. // include
  39. #include "hxtypes.h"
  40. #include "hxcom.h"
  41. // pnmisc
  42. #include "baseobj.h"
  43. #include "unkimp.h"
  44. // pxcomlib
  45. #include "glist.h"
  46. // pxgiflib
  47. #include "gifimage.h"
  48. #include "gifcodec.h"
  49. // pndebug
  50. #include "hxheap.h"
  51. #ifdef _DEBUG
  52. #undef HX_THIS_FILE
  53. static char HX_THIS_FILE[] = __FILE__;
  54. #endif
  55. BEGIN_INTERFACE_LIST(CGIFCodec)
  56. END_INTERFACE_LIST
  57. CGIFCodec::CGIFCodec()
  58. {
  59.     ResetParse();
  60.     ResetDecompress();
  61. };
  62. CGIFCodec::~CGIFCodec()
  63. {
  64.     TermParse();
  65.     TermDecompress();
  66. };
  67. void CGIFCodec::ResetParse()
  68. {
  69.     m_ulParseState           = kStateConstructed;
  70.     m_pParseBuffer           = NULL;
  71.     m_ulParseBufferLength    = 0;
  72.     m_pSegment               = NULL;
  73.     m_ulDelayTimeSum         = 0;
  74.     m_ulNumSegmentsAllocated = 0;
  75.     m_ulNumSegments          = 0;
  76.     m_ulNumImages            = 0;
  77.     m_ulCurSegIndex          = 0;
  78.     m_ulCurSegOffset         = 0;
  79.     m_ulLoopCount            = 1;
  80. }
  81. void CGIFCodec::ResetDecompress()
  82. {
  83.     m_cLSD.m_ulLogicalScreenWidth     = 0;
  84.     m_cLSD.m_ulLogicalScreenHeight    = 0;
  85.     m_cLSD.m_bGlobalColorTablePresent = FALSE;
  86.     m_cLSD.m_ulOriginalColorBits      = 0;
  87.     m_cLSD.m_bColorsSorted            = FALSE;
  88.     m_cLSD.m_ulColorTableBits         = 0;
  89.     m_cLSD.m_ulColorTableNumEntries   = 0;
  90.     m_cLSD.m_ulBackgroundColorIndex   = 0;
  91.     m_cLSD.m_ulPixelAspectRatio       = 0;
  92.     m_cLSD.m_fPixelAspectRatio        = 0.0F;
  93.     m_bIsGIF89a                       = FALSE;
  94.     m_pucGlobalColorMap               = NULL;
  95.     m_ulNumImages                     = 0;
  96.     m_pImageHeaderSize                = NULL;
  97.     m_pCompressedBufferSize           = NULL;
  98.     m_pImage                          = NULL;
  99.     m_ulCurrentImageIndex             = 0;
  100.     m_bNeedPacket                     = TRUE;
  101.     m_ulState                         = kStateConstructed;
  102.     m_bValid                          = TRUE;
  103.     m_ulLoopCount                     = 1;
  104. }
  105. void CGIFCodec::TermParse()
  106. {
  107.     if (m_pSegment)
  108.     {
  109.         delete [] m_pSegment;
  110.         m_pSegment = NULL;
  111.     }
  112.     ResetParse();
  113. }
  114. void CGIFCodec::TermDecompress()
  115. {
  116.     if (m_pucGlobalColorMap)
  117.     {
  118.         delete [] m_pucGlobalColorMap;
  119.         m_pucGlobalColorMap = NULL;
  120.     }
  121.     if (m_pImageHeaderSize)
  122.     {
  123.         delete [] m_pImageHeaderSize;
  124.         m_pImageHeaderSize = NULL;
  125.     }
  126.     if (m_pCompressedBufferSize)
  127.     {
  128.         delete [] m_pCompressedBufferSize;
  129.         m_pCompressedBufferSize = NULL;
  130.     }
  131.     if (m_pImage)
  132.     {
  133.         delete [] m_pImage;
  134.         m_pImage = NULL;
  135.     }
  136.     ResetDecompress();
  137. }
  138. UINT32 CGIFCodec::GetMaxNumPackets(BYTE* pBuf, UINT32 ulLen)
  139. {
  140.     UINT32 ulNumPackets = 0;
  141.     if (pBuf && ulLen)
  142.     {
  143.         BYTE* pBufLimit = pBuf + ulLen;
  144.         if (pBuf[0] == 'G' && pBuf[1] == 'I' && pBuf[2] == 'F' &&
  145.             pBuf[3] == '8' && pBuf[5] == 'a')
  146.         {
  147.             // Advance past the signature
  148.             pBuf += 6;
  149.             // Parse the logical screen descriptor
  150.             LogicalScreenDescriptor cLSD;
  151.             ParseLogicalScreenDescriptor(pBuf, cLSD);
  152.             pBuf += 7;
  153.             // Skip the color table
  154.             if (cLSD.m_bGlobalColorTablePresent == TRUE)
  155.             {
  156.                 // Advance that number of bytes
  157.                 pBuf += (UINT32) (cLSD.m_ulColorTableNumEntries * 3);
  158.             }
  159.             // We count this as the first packet
  160.             ulNumPackets++;
  161.             // Loop through the GIF blocks - we know that the max number
  162.             // of packets would be if each GIF block were its own packet,
  163.             // so we simply need to count the GIF blocks
  164.             while (pBuf < pBufLimit)
  165.             {
  166.                 if (pBuf[0] == kImageDescriptor)
  167.                 {
  168.                     // Skip the Image Descriptor marker
  169.                     pBuf++;
  170.                     // Parse the image descriptor struct
  171.                     CGIFImage::ImageDescriptor cID;
  172.                     CGIFImage::ParseImageDescriptor(pBuf, cID);
  173.                     pBuf += 9;
  174.                     // If a local color table IS present, then skip it
  175.                     if (cID.m_bLocalColorTablePresent == TRUE)
  176.                     {
  177.                         pBuf += cID.m_ulLocalColorTableNumEntries * 3;
  178.                     }
  179.                     // Skip the minimum LZW code size
  180.                     pBuf++;
  181.                     // We count the image descriptor as a packet
  182.                     ulNumPackets++;
  183.                     // Now skip the LZW blocks
  184.                     UINT32 ulBlockSize = 0;
  185.                     do
  186.                     {
  187.                         // Get the block size
  188.                         ulBlockSize = *pBuf++;
  189.                         // Skip that amount of bytes
  190.                         pBuf += ulBlockSize;
  191.                         // Count this as a packet
  192.                         ulNumPackets++;
  193.                     }
  194.                     while (ulBlockSize);
  195.                 }
  196.                 else if (pBuf[0] == kExtension)
  197.                 {
  198.                     // Skip the extension marker and type
  199.                     pBuf += 2;
  200.                     // Count the blocks in this extension
  201.                     UINT32 ulBlockSize = 0;
  202.                     do
  203.                     {
  204.                         // Get the block size
  205.                         ulBlockSize = *pBuf++;
  206.                         // Skip that amount of bytes
  207.                         pBuf += ulBlockSize;
  208.                         // Count this as a packet
  209.                         ulNumPackets++;
  210.                     }
  211.                     while (ulBlockSize);
  212.                 }
  213.                 else if (pBuf[0] == kTrailer)
  214.                 {
  215.                     // We found a GIF trailer - we should be at the end of the file
  216.                     pBuf++;
  217.                     // Go ahead and count it as a packet
  218.                     ulNumPackets++;
  219.                 }
  220.                 else
  221.                 {
  222.                     // Sometimes extra 0 blocks get stuck in GIFs. Check for them
  223.                     // here - if the current byte is 0, then it's OK. If it's not,
  224.                     // then we've gotten lost somewhere.
  225.                     if (pBuf[0] == 0x00)
  226.                     {
  227.                         pBuf++;
  228.                     }
  229.                     else
  230.                     {
  231.                         // Something is wrong with the GIF file.
  232.                         break;
  233.                     }
  234.                 }
  235.             }
  236.         }
  237.     }
  238.     return ulNumPackets;
  239. }
  240. HX_RESULT CGIFCodec::InitParseWireFormat(BYTE *pBuffer, UINT32 ulLen)
  241. {
  242.     /* Check for input error conditions */
  243.     if (pBuffer == NULL || ulLen == 0)
  244.     {
  245.         return HXR_INVALID_PARAMETER;
  246.     }
  247.     /* Check state */
  248.     if (m_ulParseState != kStateConstructed)
  249.     {
  250.         return HXR_UNEXPECTED;
  251.     }
  252.     /* Save copy of the buffer pointer and length */
  253.     m_pParseBuffer        = pBuffer;
  254.     m_ulParseBufferLength = ulLen;
  255.     /*
  256.      * We have to make a pass through the image to determine the mark points.
  257.      * Will store these mark points (BYTE pointers) in cMarkList. The first
  258.      * mark point is, of course, the beginning of the file.
  259.      */
  260.     GList cMarkList;
  261.     cMarkList.PushBack((void *) m_pParseBuffer);
  262.     /* Get local copy of buffer */
  263.     BYTE  *pBuf      = m_pParseBuffer;
  264.     BYTE  *pBufLimit = pBuf + m_ulParseBufferLength;
  265.     /* Check the signature */
  266.     if (pBuf[0] != 'G' || pBuf[1] != 'I' || pBuf[2] != 'F')
  267.     {
  268.         return HXR_INVALID_OPERATION;
  269.     }
  270.     pBuf += 3;
  271.     /* Check the version */
  272.     if (pBuf[0] == '8' && pBuf[1] == '9' && pBuf[2] == 'a')
  273.     {
  274.         m_bIsGIF89a = TRUE;
  275.     }
  276.     else if (pBuf[0] == '8' && pBuf[1] == '7' && pBuf[2] == 'a')
  277.     {
  278.         m_bIsGIF89a = FALSE;
  279.     }
  280.     else
  281.     {
  282.         return HXR_INVALID_OPERATION;
  283.     }
  284.     pBuf += 3;
  285.     /* Get the logical screen descriptor */
  286.     ParseLogicalScreenDescriptor(pBuf, m_cLSD);
  287.     pBuf += 7;
  288.     /* Skip the color table */
  289.     if (m_cLSD.m_bGlobalColorTablePresent == TRUE)
  290.     {
  291.         /* Calculate the number of bytes for the global color table */
  292.         UINT32 ulNumBytes = m_cLSD.m_ulColorTableNumEntries * 3;
  293.         /* Advance that number of bytes */
  294.         pBuf += ulNumBytes;
  295.     }
  296.     /*
  297.      * Parse the file and enter marks in the mark list. We're looking for:
  298.      *    a) Beginnings of GCEs and IDs (although if a ID immediately follows
  299.      *       a GCE, we only mark the beginning of the GCE;
  300.      *    b) Beginnings of LZW data for each image.
  301.      */
  302.     BOOL bMarkImageDescriptor = TRUE;
  303.     m_ulDelayTimeSum          = 0;
  304.     m_ulNumImages             = 0;
  305.     while (pBuf < pBufLimit)
  306.     {
  307.         if (pBuf[0] == kImageDescriptor)
  308.         {
  309.             /*
  310.              * We've found an Image Descriptor (ID). If m_bMarkImageDescriptor is
  311.              * FALSE, then this ID is one that immediately followed a GCE, so we
  312.              * DON'T mark it. If m_bMarkImageDescriptor is TRUE, this is an 
  313.              * ID that was NOT preceded by a GCE - these usually happen in GIF87a's.
  314.              */
  315.             if (bMarkImageDescriptor == TRUE)
  316.             {
  317.                 cMarkList.PushBack((void *) pBuf);
  318.             }
  319.             else
  320.             {
  321.                 bMarkImageDescriptor = TRUE;
  322.             }
  323.             /* Skip the Image Descriptor marker */
  324.             pBuf++;
  325.             /*
  326.              * Whether we mark it or not, we still have to parse it to find out
  327.              * whether or not a local color table is present.
  328.              */
  329.             CGIFImage::ImageDescriptor cID;
  330.             CGIFImage::ParseImageDescriptor(pBuf, cID);
  331.             pBuf += 9;
  332.             // We make sure this frame's dimensions are within the dimensions
  333.             // of the logical screen. If they are not, then we are probably
  334.             // dealing with a corrupt GIF. That's really really bad, cause we probably
  335.             // can't trust any of the data. Therefore, we will simply fail out of
  336.             // parsing and rely on the app above us to do the right thing.
  337.             if (cID.m_ulImageLeft + cID.m_ulImageWidth  > m_cLSD.m_ulLogicalScreenWidth ||
  338.                 cID.m_ulImageTop  + cID.m_ulImageHeight > m_cLSD.m_ulLogicalScreenHeight)
  339.             {
  340.                 return HXR_FAIL;
  341.             }
  342.             /* If a local color table IS present, then skip it */
  343.             if (cID.m_bLocalColorTablePresent == TRUE)
  344.             {
  345.                 pBuf += cID.m_ulLocalColorTableNumEntries * 3;
  346.             }
  347.             /* Now we should be at the beginning of LZW data, so mark this pointer */
  348.             cMarkList.PushBack((void *) pBuf);
  349.             /* Skip the minimum LZW code size */
  350.             UINT32 ulInitialCodeSize = *pBuf++;
  351.             if (ulInitialCodeSize > 12)
  352.             {
  353.                 // Code size can't be any bigger than 12. If we
  354.                 // do get one bigger than that, then we're dealing
  355.                 // with a corrupt file here.
  356.                 return HXR_FAIL;
  357.             }
  358.             /* Now skip the LZW blocks */
  359.             SkipBlocks(pBuf, pBufLimit);
  360.             // Check to see if we went past the end of the buffer
  361.             if (pBuf >= pBufLimit)
  362.             {
  363.                 // This is really really bad if we get here. That almost certainly
  364.                 // means the GIF is corrupt, cause we were happily parsing LZW blocks
  365.                 // and went off the end of the file. In reality it probably means that
  366.                 // the GIF was corrupt earlier. We will simply fail here. We cannot
  367.                 // reliably parse any of this image.
  368.                 return HXR_FAIL;
  369.             }
  370.             /* We've just seen an image */
  371.             m_ulNumImages++;
  372.         }
  373.         else if (pBuf[0] == kExtension)
  374.         {
  375.             /* This is an extension, but what type? */
  376.             switch(pBuf[1])
  377.             {
  378.                 case kGraphicControlExtension:
  379.                     /* We've found a GCE - mark it but don't mark the ID */
  380.                     cMarkList.PushBack((void *) pBuf);
  381.                     bMarkImageDescriptor = FALSE;
  382.                     pBuf                += 2;
  383.                     UINT32 ulBlockSize;
  384.                     do
  385.                     {
  386.                         /* Get the block size */
  387.                         ulBlockSize = *pBuf++;
  388.                         /* Initialize the GCE */
  389.                         CGIFImage::GraphicControlExtension cGCE;
  390.                         if (ulBlockSize >= 4)
  391.                         {
  392.                             CGIFImage::ParseGraphicControlExtension(pBuf, cGCE);
  393.                             /* Add the delay time */
  394.                             m_ulDelayTimeSum += cGCE.m_ulDelayTime * 10;
  395.                         }
  396.                         /* Advance by the block size */
  397.                         pBuf += ulBlockSize;
  398.                     }
  399.                     while (ulBlockSize > 0);
  400.                     break;
  401.                 case kCommentExtension:
  402.                 case kPlainTextExtension:
  403.                     pBuf += 2;
  404.                     SkipBlocks(pBuf, pBufLimit);
  405.                     break;
  406.                 case kApplicationExtension:
  407.                     ParseApplicationExtension(pBuf);
  408.                     break;
  409.                 default:
  410.                     // An extension we don't know - just try to
  411.                     // pass it through
  412.                     pBuf += 2;
  413.                     SkipBlocks(pBuf, pBufLimit);
  414.                     break;
  415.             }
  416.         }
  417.         else if (pBuf[0] == kTrailer)
  418.         {
  419.             /* We found a GIF trailer - we should be at the end of the file */
  420.             cMarkList.PushBack((void *) pBuf);
  421.     break;
  422.         }
  423.         else
  424.         {
  425.             // Sometimes extra 0 blocks get stuck in GIFs. Check for them
  426.             // here - if the current byte is 0, then it's OK. If it's not,
  427.             // then we've gotten lost somewhere.
  428.             if (pBuf[0] == 0x00)
  429.             {
  430.                 pBuf++;
  431.             }
  432.             else
  433.             {
  434.                 // Something is wrong with the GIF file.
  435. //
  436. // XXXMEH - instead of returning an error, we will
  437. // be lax and just break here. This will have the effect
  438. // of potentially sending garbage GIFs down to the
  439. // client. The upside is that there are a lot of 
  440. // non-standard GIFs out there that will display in
  441. // browsers and this will allow them to be displayed.
  442. break;
  443.             }
  444.         }
  445.     }
  446.     /* The last mark is, of course, the end of the file. */
  447.     cMarkList.PushBack((void *) pBufLimit);
  448.     /*
  449.      * Now we convert our list to a more usable array of ParseSegment's. First
  450.      * we compute the number of segments, which is one less than the number
  451.      * of marks.
  452.      */
  453.     m_ulNumSegmentsAllocated = cMarkList.Size() - 1;
  454.     if (m_ulNumSegmentsAllocated == 0 || m_ulNumSegmentsAllocated > cMarkList.Size())
  455.     {
  456.         return HXR_UNEXPECTED;
  457.     }
  458.     /* Allocate memory for the segment array */
  459.     if (m_pSegment)
  460.     {
  461.         delete [] m_pSegment;
  462.         m_pSegment = NULL;
  463.     }
  464.     m_pSegment = new ParseSegment [m_ulNumSegmentsAllocated];
  465.     if (!m_pSegment)
  466.     {
  467.         return HXR_OUTOFMEMORY;
  468.     }
  469.     /*
  470.      * Now run through the list of marks, computing segments. Note that
  471.      * if the mark in the marklist is an extension not necessary for 
  472.      * deompression, we do not make it into a segment.
  473.      */
  474.     m_ulNumSegments         = 0;
  475.     GListIterator itr       = cMarkList.Begin();
  476.     BYTE         *pLastMark = (BYTE *) *itr;
  477.     itr++;
  478.     do
  479.     {
  480.         BYTE *pCurMark = (BYTE *) *itr;
  481.         /*
  482.          * Filter out all unwanted extensions. We don't send application, 
  483.          * comment, or plain text extensions. We also don't send the GIF
  484.          * Trailer
  485.          */
  486.         if (!((pLastMark[0] == kExtension && (pLastMark[1] == kApplicationExtension ||
  487.                                               pLastMark[1] == kCommentExtension     ||
  488.                                               pLastMark[1] == kPlainTextExtension)) ||
  489.                pLastMark[0] == kTrailer))
  490.         {
  491.             m_pSegment[m_ulNumSegments].pMark  = pLastMark;
  492.             m_pSegment[m_ulNumSegments].ulSize = pCurMark - pLastMark;
  493.             m_ulNumSegments++;
  494.         }
  495.         pLastMark = pCurMark;
  496.         itr++;
  497.     }
  498.     while (itr != cMarkList.End());
  499.     /* Now we're done with the list */
  500.     cMarkList.EraseAll();
  501.     /* Set the state */
  502.     m_ulParseState = kStateParseInitialized;
  503.     return HXR_OK;
  504. }
  505. UINT32 CGIFCodec::GetDelayTime(UINT32 i)
  506. {
  507.     if (i >= m_ulNumImages || m_bIsGIF89a == FALSE)
  508.     {
  509.         return 0;
  510.     }
  511.     UINT32        ulDelay;
  512.     ParseSegment *pSeg = &m_pSegment[1 + (i << 1)];
  513.     if (pSeg->pMark[0] == kExtension && pSeg->pMark[1] == kGraphicControlExtension)
  514.     {
  515.         CGIFImage::GraphicControlExtension cGCE;
  516.         CGIFImage::ParseGraphicControlExtension(pSeg->pMark + 3, cGCE);
  517.         ulDelay = cGCE.m_ulDelayTime;
  518.         if (ulDelay == 0)
  519.         {
  520.             ulDelay = 1;
  521.         }
  522.     }
  523.     else
  524.     {
  525.         ulDelay = 0;
  526.     }
  527.     return ulDelay;
  528. }
  529. UINT32 CGIFCodec::GetImageDataSize(UINT32 i)
  530. {
  531.     if (i >= m_ulNumImages)
  532.     {
  533.         return 0;
  534.     }
  535.     return m_pSegment[2 + (i << 1)].ulSize;
  536. }
  537. HX_RESULT CGIFCodec::GetPacketBufferLength(UINT32 &rulLen)
  538. {
  539.     /* Check state */
  540.     if (m_ulParseState != kStateParseInitialized &&
  541.         m_ulParseState != kStateParseInProgress)
  542.     {
  543.         return HXR_UNEXPECTED;
  544.     }
  545.     /* Is this our first time here? */
  546.     if (m_ulParseState == kStateParseInitialized)
  547.     {
  548.         /* This is the first time here - we need to find the header length */
  549.         UINT32 ulLen = 8                    +  /* Container header size, num images */
  550.                        8 * m_ulNumImages    +  /* Image header size and compressed data size */
  551.                        m_pSegment[0].ulSize;   /* Container header */
  552.         /*
  553.          * Add the individual image header sizes - these are the segments which
  554.          * begin with either an Image Descriptor or a GCE.
  555.          */
  556.         UINT32 i;
  557.         for (i = 0; i < m_ulNumSegments; i++)
  558.         {
  559.             BYTE *pMark = m_pSegment[i].pMark;
  560.             if ( pMark[0] == kImageDescriptor ||
  561.                 (pMark[0] == kExtension && pMark[1] == kGraphicControlExtension))
  562.             {
  563.                 ulLen += m_pSegment[i].ulSize;
  564.             }
  565.         }
  566.         /* Set the initial segment for data packet parsing */
  567.         m_ulCurSegIndex  = 2;
  568.         m_ulCurSegOffset = 0;
  569.         /* We have our length */
  570.         rulLen = ulLen;
  571.     }
  572.     else
  573.     {
  574.         /* This is NOT the first time here - we need to find the data packet length */
  575.         BYTE  *pBufStart = m_pSegment[m_ulCurSegIndex].pMark;
  576.         BYTE  *pBuf      = pBufStart + m_ulCurSegOffset;
  577.         UINT32 ulSize    = 0;
  578.         /* If we are at the beginning of a LZW segment, we need to skip the min code size */
  579.         if (m_ulCurSegOffset == 0)
  580.         {
  581.             pBuf++;
  582.             ulSize++;
  583.         }
  584.         /* Advance through the blocks, until we reach the ideal packet size */
  585.         UINT32 ulBlockSize;
  586.         do
  587.         {
  588.             ulBlockSize = *pBuf;
  589.             ulSize     += ulBlockSize + 1;
  590.             pBuf       += ulBlockSize + 1;
  591.         }
  592.         while (ulBlockSize > 0 && ulSize < kIdealPacketSize);
  593.         /*
  594.          * Make a check to see if what's left over is not less than the
  595.          * minimum packet size. If it IS less than the minimum packet size,
  596.          * then go ahead and get the rest of it.
  597.          */
  598.         UINT32 ulBytesLeftInSegment = pBufStart + m_pSegment[m_ulCurSegIndex].ulSize - pBuf;
  599.         if (ulBytesLeftInSegment > 0 && ulBytesLeftInSegment < kMinimumPacketSize)
  600.         {
  601.             ulSize += ulBytesLeftInSegment;
  602.         }
  603.         /* Now we have our length */
  604.         rulLen = ulSize;
  605.     }
  606.     return HXR_OK;
  607. }
  608. UINT32 CGIFCodec::ComputeLZWDataSize(BYTE *pLZW)
  609. {
  610.     /* Skip the minimum code size */
  611.     pLZW++;
  612.     /* Run through blocks, adding up sizes */
  613.     UINT32 ulSum = 0;
  614.     UINT32 ulBlockSize;
  615.     do
  616.     {
  617.         ulBlockSize = *pLZW++;
  618.         ulSum      += ulBlockSize;
  619.         pLZW       += ulBlockSize;
  620.     }
  621.     while (ulBlockSize > 0);
  622.     return ulSum;
  623. }
  624. HX_RESULT CGIFCodec::GetPacketBuffer(BYTE *pBuffer, UINT32 ulLen, BOOL &rbFirstInImage)
  625. {
  626.     /* Check for input error conditions */
  627.     if (pBuffer == NULL || ulLen == 0)
  628.     {
  629.         return HXR_INVALID_PARAMETER;
  630.     }
  631.     /* Check state */
  632.     if (m_ulParseState != kStateParseInitialized &&
  633.         m_ulParseState != kStateParseInProgress)
  634.     {
  635.         return HXR_UNEXPECTED;
  636.     }
  637.     /* Is this our first time here? */
  638.     if (m_ulParseState == kStateParseInitialized)
  639.     {
  640.         /* Conainer header size */
  641.         Pack32(m_pSegment[0].ulSize, pBuffer);
  642.         pBuffer += 4;
  643.         /* Number of Images */
  644.         Pack32(m_ulNumImages,      pBuffer);
  645.         pBuffer += 4;
  646.         /* Individual image parameters */
  647.         UINT32 i;
  648.         for (i = 0; i < m_ulNumImages; i++)
  649.         {
  650.             /* Individual image header size */
  651.             Pack32(m_pSegment[1 + (i << 1)].ulSize, pBuffer);
  652.             pBuffer += 4;
  653.             /* Individual image compressed data size */
  654.             Pack32(ComputeLZWDataSize(m_pSegment[2 + (i << 1)].pMark), pBuffer);
  655.             pBuffer += 4;
  656.         }
  657.         /* Copy container header */
  658.         memcpy(pBuffer, m_pSegment[0].pMark, m_pSegment[0].ulSize); /* Flawfinder: ignore */
  659.         pBuffer += m_pSegment[0].ulSize;
  660.         /* Copy each individual image header */
  661.         for (i = 0; i < m_ulNumImages; i++)
  662.         {
  663.             ParseSegment *pSegment = &m_pSegment[1 + (i << 1)];
  664.             memcpy(pBuffer, pSegment->pMark, pSegment->ulSize); /* Flawfinder: ignore */
  665.             pBuffer += pSegment->ulSize;
  666.         }
  667.         /* Clear the flag */
  668.         rbFirstInImage = FALSE;
  669.         /* Set the new state */
  670.         m_ulParseState = kStateParseInProgress;
  671.     }
  672.     else
  673.     {
  674.         /* Copy the data packet */
  675.         memcpy(pBuffer, /* Flawfinder: ignore */
  676.                m_pSegment[m_ulCurSegIndex].pMark + m_ulCurSegOffset,
  677.                ulLen);
  678.         /* Was this the first packet for one of the images? */
  679.         if (m_ulCurSegOffset == 0)
  680.         {
  681.             rbFirstInImage = TRUE;
  682.         }
  683.         else
  684.         {
  685.             rbFirstInImage = FALSE;
  686.         }
  687.         /* Check to see if we're done with this segment */
  688.         if (m_ulCurSegOffset + ulLen >= m_pSegment[m_ulCurSegIndex].ulSize)
  689.         {
  690.             m_ulCurSegIndex += 2;
  691.             m_ulCurSegOffset = 0;
  692.         }
  693.         else
  694.         {
  695.             m_ulCurSegOffset += ulLen;
  696.         }
  697.         /* Check to see if we finished */
  698.         if (m_ulCurSegIndex >= m_ulNumSegments)
  699.         {
  700.             m_ulParseState = kStateParseFinished;
  701.         }
  702.     }
  703.     return HXR_OK;
  704. }
  705. void CGIFCodec::ParseLogicalScreenDescriptor(BYTE *pBuffer, LogicalScreenDescriptor &cLSD)
  706. {
  707.     /* Read Logical Screen Descriptor */
  708.     cLSD.m_ulLogicalScreenWidth     =  (pBuffer[1] << 8) | pBuffer[0];
  709.     cLSD.m_ulLogicalScreenHeight    =  (pBuffer[3] << 8) | pBuffer[2];
  710.     cLSD.m_bGlobalColorTablePresent =  (pBuffer[4] & 0x80 ? TRUE : FALSE);
  711.     cLSD.m_ulOriginalColorBits      = ((pBuffer[4] & 0x70) >> 4) + 1;
  712.     cLSD.m_bColorsSorted            =  (pBuffer[4] & 0x08 ? TRUE : FALSE);
  713.     cLSD.m_ulColorTableBits         =  (pBuffer[4] & 0x07) + 1;
  714.     cLSD.m_ulColorTableNumEntries   = 1 << cLSD.m_ulColorTableBits;
  715.     cLSD.m_ulBackgroundColorIndex   =   pBuffer[5];
  716.     cLSD.m_ulPixelAspectRatio       =   pBuffer[6];
  717.     cLSD.m_fPixelAspectRatio        = (cLSD.m_ulPixelAspectRatio + 15.0F) / 64.0F;
  718. }
  719. HX_RESULT CGIFCodec::ParseContainerHeader(BYTE * &pBuffer)
  720. {
  721.     /* Verify the signature */
  722.     if (pBuffer[0] != 'G' || pBuffer[1] != 'I' || pBuffer[2] != 'F')
  723.     {
  724.         return HXR_INVALID_OPERATION;
  725.     }
  726.     pBuffer += 3;
  727.     /* Get the version */
  728.     if (pBuffer[0] == '8' && pBuffer[1] == '9' && pBuffer[2] == 'a')
  729.     {
  730.         m_bIsGIF89a = TRUE;
  731.     }
  732.     else if (pBuffer[0] == '8' && pBuffer[1] == '7' && pBuffer[2] == 'a')
  733.     {
  734.         m_bIsGIF89a = FALSE;
  735.     }
  736.     else
  737.     {
  738.         return HXR_INVALID_OPERATION;
  739.     }
  740.     pBuffer += 3;
  741.     /* Read the Logical Screen Descriptor */
  742.     ParseLogicalScreenDescriptor(pBuffer, m_cLSD);
  743.     pBuffer += 7;
  744.     /* Read the colortable if present */
  745.     if (m_cLSD.m_bGlobalColorTablePresent == TRUE)
  746.     {
  747.         /* Allocate space for the global color table */
  748.         if (m_pucGlobalColorMap)
  749.         {
  750.             delete [] m_pucGlobalColorMap;
  751.             m_pucGlobalColorMap = NULL;
  752.         }
  753.         UINT32 ulColorTableBytes = m_cLSD.m_ulColorTableNumEntries * 3;
  754.         m_pucGlobalColorMap = new BYTE [ulColorTableBytes];
  755.         if (!m_pucGlobalColorMap)
  756.         {
  757.             return HXR_OUTOFMEMORY;
  758.         }
  759.         /* Copy the global color table */
  760.         memcpy(m_pucGlobalColorMap, pBuffer, ulColorTableBytes); /* Flawfinder: ignore */
  761.         /* Advance the pointer */
  762.         pBuffer += ulColorTableBytes;
  763.         /* Loop through the images, setting the global color map */
  764.         UINT32 i;
  765.         for (i = 0; i < m_ulNumImages; i++)
  766.         {
  767.             m_pImage[i].SetGlobalColorMap(m_cLSD.m_ulColorTableNumEntries,
  768.                                           m_pucGlobalColorMap);
  769.         }
  770.     }
  771.     // Reset the delay time sum
  772.     m_ulDelayTimeSum = 0;
  773.     /* Here we loop through looking for Image Descriptors or Graphic Control Extensions */
  774.     HX_RESULT retVal;
  775.     UINT32    ulImageNum = 0;
  776.     for (;;)
  777.     {
  778.         UINT32 ulMarker = *pBuffer;
  779.         switch(ulMarker)
  780.         {
  781.             case kImageDescriptor:
  782.                 retVal = m_pImage[ulImageNum].InitDecompress(pBuffer, m_pImageHeaderSize[ulImageNum]);
  783.                 if (retVal != HXR_OK)
  784.                 {
  785.                     return retVal;
  786.                 }
  787.                 retVal = m_pImage[ulImageNum].SetCompressedBufferSize(m_pCompressedBufferSize[ulImageNum]);
  788.                 if (retVal != HXR_OK)
  789.                 {
  790.                     return retVal;
  791.                 }
  792.                 pBuffer += m_pImageHeaderSize[ulImageNum];
  793.                 ulImageNum++;
  794.                 break;
  795.             case kExtension:
  796.                 if (pBuffer[1] == kGraphicControlExtension)
  797.                 {
  798.                     retVal = m_pImage[ulImageNum].InitDecompress(pBuffer, m_pImageHeaderSize[ulImageNum]);
  799.                     if (retVal != HXR_OK)
  800.                     {
  801.                         return retVal;
  802.                     }
  803.                     // Add the delay time to the delay time sum
  804.                     m_ulDelayTimeSum += m_pImage[ulImageNum].GetDelayTime() * 10;
  805.                     retVal = m_pImage[ulImageNum].SetCompressedBufferSize(m_pCompressedBufferSize[ulImageNum]);
  806.                     if (retVal != HXR_OK)
  807.                     {
  808.                         return retVal;
  809.                     }
  810.                     pBuffer += m_pImageHeaderSize[ulImageNum];
  811.                     ulImageNum++;
  812.                 }
  813.                 else if (pBuffer[1] == kApplicationExtension)
  814.                 {
  815.                     ParseApplicationExtension(pBuffer);
  816.                 }
  817.                 else
  818.                 {
  819.                     /* Skip the extension marker and type */
  820.                     pBuffer += 2;
  821.                     /* Now skip the extension itself */
  822.                     SkipBlocks(pBuffer);
  823.                 }
  824.                 break;
  825.             case kTrailer:
  826.             default:
  827.                 /* Something went wrong */
  828.                 return HXR_INVALID_OPERATION;
  829.                 break;
  830.         }
  831.         /* If we've gotten all intialized all images, then we're done */
  832.         if (ulImageNum >= m_ulNumImages)
  833.         {
  834.             break;
  835.         }
  836.     }
  837.     return HXR_OK;
  838. }
  839. void CGIFCodec::SkipBlocks(BYTE * &pBuffer, BYTE* pBufLimit)
  840. {
  841.     // If pBufLimit is NULL, then we won't use it at all.
  842.     // If pBufLimit is not NULL, then we will make sure
  843.     // we don't go past the end of the buffer
  844.     UINT32 ulBlockSize;
  845.     do
  846.     {
  847.         /* Get the block size */
  848.         ulBlockSize = *pBuffer++;
  849.         /* Skip that amount of bytes */
  850.         pBuffer += ulBlockSize;
  851.     }
  852.     while (ulBlockSize > 0 &&
  853.            (!pBufLimit || (pBufLimit && pBuffer < pBufLimit)));
  854. }
  855. HX_RESULT CGIFCodec::InitDecompress(BYTE *pBuffer, UINT32 ulLen)
  856. {
  857.     /* Check for input error conditions */
  858.     if (pBuffer == NULL || ulLen == 0)
  859.     {
  860.         return HXR_INVALID_PARAMETER;
  861.     }
  862.     /* Check the state */
  863.     if (m_ulState != kStateConstructed)
  864.     {
  865.         return HXR_UNEXPECTED;
  866.     }
  867.     /* Get the master header length */
  868.     UINT32 ulHeaderLength = UnPack32(pBuffer);
  869.     pBuffer += 4;
  870.     /* Get the number of images */
  871.     m_ulNumImages = UnPack32(pBuffer);
  872.     pBuffer += 4;
  873.     if (m_ulNumImages == 0)
  874.     {
  875.         return HXR_UNEXPECTED;
  876.     }
  877.     /* Allocate array of images */
  878.     if (m_pImage)
  879.     {
  880.         delete [] m_pImage;
  881.         m_pImage = NULL;
  882.     }
  883.     m_pImage = new CGIFImage [m_ulNumImages];
  884.     if (!m_pImage)
  885.     {
  886.         return HXR_OUTOFMEMORY;
  887.     }
  888.     /* Allocate array for image header sizes */
  889.     if (m_pImageHeaderSize)
  890.     {
  891.         delete [] m_pImageHeaderSize;
  892.         m_pImageHeaderSize = NULL;
  893.     }
  894.     m_pImageHeaderSize = new UINT32 [m_ulNumImages];
  895.     if (!m_pImageHeaderSize)
  896.     {
  897.         if (m_pImage)
  898.         {
  899.             delete [] m_pImage;
  900.             m_pImage = NULL;
  901.         }
  902.         return HXR_OUTOFMEMORY;
  903.     }
  904.     /* Allocate array for image header sizes */
  905.     if (m_pCompressedBufferSize)
  906.     {
  907.         delete [] m_pCompressedBufferSize;
  908.         m_pCompressedBufferSize = NULL;
  909.     }
  910.     m_pCompressedBufferSize = new UINT32 [m_ulNumImages];
  911.     if (!m_pCompressedBufferSize)
  912.     {
  913.         if (m_pImage)
  914.         {
  915.             delete [] m_pImage;
  916.             m_pImage = NULL;
  917.         }
  918.         if (m_pImageHeaderSize)
  919.         {
  920.             delete [] m_pImageHeaderSize;
  921.             m_pImageHeaderSize = NULL;
  922.         }
  923.         return HXR_OUTOFMEMORY;
  924.     }
  925.     /* Now set the compressed buffer size for each image */
  926.     HX_RESULT retVal;
  927.     UINT32    i;
  928.     for (i = 0; i < m_ulNumImages; i++)
  929.     {
  930.         /* Get the image header size */
  931.         m_pImageHeaderSize[i] = UnPack32(pBuffer);
  932.         pBuffer += 4;
  933.         /* Get a compressed buffer size */
  934.         m_pCompressedBufferSize[i] = UnPack32(pBuffer);
  935.         pBuffer += 4;
  936.     }
  937.     /* Now parse the container header */
  938.     retVal = ParseContainerHeader(pBuffer);
  939.     if (retVal != HXR_OK)
  940.     {
  941.         if (m_pImage)
  942.         {
  943.             delete [] m_pImage;
  944.             m_pImage = NULL;
  945.         }
  946.         if (m_pImageHeaderSize)
  947.         {
  948.             delete [] m_pImageHeaderSize;
  949.             m_pImageHeaderSize = NULL;
  950.         }
  951.         return retVal;
  952.     }
  953.     /* Set the current image */
  954.     m_ulCurrentImageIndex = 0;
  955.     /* Set the new state */
  956.     m_ulState = kStateDecoInitialized;
  957.     return HXR_OK;
  958. }
  959. HX_RESULT CGIFCodec::Decompress(BYTE *pBuffer, UINT32 ulLen, BOOL bNewImage)
  960. {
  961.     /* Check for input error conditions */
  962.     if (pBuffer == NULL || ulLen == 0)
  963.     {
  964.         return HXR_INVALID_PARAMETER;
  965.     }
  966.     /* Check the state */
  967.     if (m_ulState != kStateDecoInitialized && m_ulState != kStateDecoInProgress)
  968.     {
  969.         return HXR_UNEXPECTED;
  970.     }
  971.     /* Check to see if the we lost a packet on this image */
  972.     if (m_pImage[m_ulCurrentImageIndex].GetValid() == FALSE)
  973.     {
  974.         /* This image was declared invalid due to a lost packet */
  975.         if (bNewImage == FALSE)
  976.         {
  977.             // We're still on the same image, so we can't do anything
  978.             return HXR_OK;
  979.         }
  980.         // We've moved on to a new image, so we can begin decompressing again
  981.         m_ulCurrentImageIndex++;
  982.     }
  983.     /* All we have to do is pass this data on to the current image */
  984.     HX_RESULT retVal = m_pImage[m_ulCurrentImageIndex].Decompress(pBuffer, ulLen);
  985.     if (retVal != HXR_OK)
  986.     {
  987.         return retVal;
  988.     }
  989.     /* Set the state */
  990.     m_ulState = kStateDecoInProgress;
  991.     /* Are we finished with this image? */
  992.     if (m_pImage[m_ulCurrentImageIndex].Finished() == TRUE)
  993.     {
  994.         /* Move on to the next image */
  995.         m_ulCurrentImageIndex++;
  996.         /* If we've done all images, then we're done */
  997.         if (m_ulCurrentImageIndex >= m_ulNumImages)
  998.         {
  999.             m_ulState = kStateDecoFinished;
  1000.         }
  1001.     }
  1002.     return HXR_OK;
  1003. }
  1004. INT32 CGIFCodec::ComputeStartingImageIndex(INT32 lCurIndex, INT32 lDesiredIndex)
  1005. {
  1006.     // Does the buffer currently hold any image now?
  1007.     INT32 lStartIndex;
  1008.     INT32 lBaseIndex;
  1009.     if (lCurIndex == -1 || lCurIndex > lDesiredIndex)
  1010.     {
  1011.         // The buffer doesn't have anything in it now, so we must build
  1012.         // from the last full screen image before or equal to ulImgIndex
  1013.         // all the way back to 0.
  1014.         lBaseIndex = 0;
  1015.     }
  1016.     else
  1017.     {
  1018.         // The buffer currently has a valid image in it, so we only need
  1019.         // to go back to the first full screen image greater than lCurIndex.
  1020.         lBaseIndex = lCurIndex + 1;
  1021.     }
  1022.     // Find the index of the first image we need to do
  1023.     for (lStartIndex = lDesiredIndex; lStartIndex >= lBaseIndex; lStartIndex--)
  1024.     {
  1025.         if (m_pImage[lStartIndex].GetImageWidth()  == m_cLSD.m_ulLogicalScreenWidth &&
  1026.             m_pImage[lStartIndex].GetImageHeight() == m_cLSD.m_ulLogicalScreenHeight)
  1027.         {
  1028.             break;
  1029.         }
  1030.     }
  1031.     if (lStartIndex < lBaseIndex)
  1032.     {
  1033.         lStartIndex = 0;
  1034.     }
  1035.     return lStartIndex;
  1036. }
  1037. HX_RESULT CGIFCodec::GetIndexImage(INT32 lCurIndex, UINT32 ulImgIndex, BYTE *pBuffer, UINT32 ulWidth, UINT32 ulHeight,
  1038.                                    UINT32 ulPadWidth, BOOL bRowsInverted)
  1039. {
  1040.     // Check for input error
  1041.     if (lCurIndex < -1 || lCurIndex >= (INT32) m_ulNumImages || ulImgIndex >= m_ulNumImages ||
  1042.         pBuffer == NULL || ulWidth == 0 || ulHeight == 0 || ulPadWidth == 0)
  1043.     {
  1044.         return HXR_INVALID_PARAMETER;
  1045.     }
  1046.     // Since frames of a GIF can be dependent upon prior frames, we need to
  1047.     // determine which frame we need to go back to
  1048.     INT32 lStartIndex = ComputeStartingImageIndex(lCurIndex, (INT32) ulImgIndex);
  1049.     // Now do the images from lStartIndex to ulImgIndex
  1050.     INT32 i;
  1051.     for (i = lStartIndex; i <= (INT32) ulImgIndex; i++)
  1052.     {
  1053.         HX_RESULT retVal = m_pImage[i].GetIndexImage(pBuffer, ulWidth, ulHeight,
  1054.                                                      ulPadWidth, bRowsInverted);
  1055.         if (retVal != HXR_OK)
  1056.         {
  1057.             return retVal;
  1058.         }
  1059.     }
  1060.     return HXR_OK;
  1061. }
  1062. HX_RESULT CGIFCodec::GetRGBImage(INT32 lCurIndex, UINT32 ulImgIndex, BYTE *pBuffer, UINT32 ulWidth, UINT32 ulHeight, UINT32 ulPadWidth,
  1063.                                  UINT32 ulBytesPerPixel, BOOL bRowsInverted, BOOL bRGBOrdering, BYTE ucBackRed, BYTE ucBackGreen, BYTE ucBackBlue,
  1064.                                  BYTE ucBackAlpha)
  1065. {
  1066.     // Check for input error
  1067.     if (lCurIndex < -1 || lCurIndex >= (INT32) m_ulNumImages || ulImgIndex >= m_ulNumImages ||
  1068.         pBuffer == NULL || ulWidth == 0 || ulHeight == 0 || ulPadWidth == 0 || ulBytesPerPixel == 0)
  1069.     {
  1070.         return HXR_INVALID_PARAMETER;
  1071.     }
  1072.     // Since frames of a GIF can be dependent upon prior frames, we need to
  1073.     // determine which frame we need to go back to
  1074.     INT32 lStartIndex = ComputeStartingImageIndex(lCurIndex, (INT32) ulImgIndex);
  1075.     // Now do the images from lStartIndex to ulImgIndex
  1076.     INT32 i;
  1077.     for (i = lStartIndex; i <= (INT32) ulImgIndex; i++)
  1078.     {
  1079.         HX_RESULT retVal = m_pImage[i].GetRGBImage(pBuffer, ulWidth, ulHeight, ulPadWidth,
  1080.                                                    ulBytesPerPixel, bRowsInverted, bRGBOrdering,
  1081.                                                    ucBackRed, ucBackGreen, ucBackBlue, ucBackAlpha);
  1082.         if (retVal != HXR_OK)
  1083.         {
  1084.             return retVal;
  1085.         }
  1086.     }
  1087.     return HXR_OK;
  1088. }
  1089. HX_RESULT CGIFCodec::GetRGBImageEx(INT32 lCurIndex, UINT32 ulImgIndex, BYTE *pBuffer, UINT32 ulWidth, UINT32 ulHeight,
  1090.                                    UINT32 ulPadWidth, UINT32 ulBytesPerPixel, BOOL bRowsInverted, BOOL bRGBOrdering,
  1091.                                    UINT32 ulBgColor, BOOL bMediaOpacity, UINT32 ulMediaOpacity,
  1092.                                    BOOL bChromaKey, UINT32 ulChromaKey, UINT32 ulChromaKeyTol, UINT32 ulChromaKeyOpacity)
  1093. {
  1094.     HX_RESULT retVal = HXR_OK;
  1095.     if (lCurIndex >= -1 && lCurIndex < (INT32) m_ulNumImages &&
  1096.         ulImgIndex < m_ulNumImages && pBuffer && ulWidth && ulHeight &&
  1097.         ulPadWidth && ulBytesPerPixel)
  1098.     {
  1099.         // Since frames of a GIF can be dependent upon prior frames, we need to
  1100.         // determine which frame we need to go back to
  1101.         INT32 lStartIndex = ComputeStartingImageIndex(lCurIndex, (INT32) ulImgIndex);
  1102.         // Now do the images from lStartIndex to ulImgIndex
  1103.         INT32 i = 0;
  1104.         for (i = lStartIndex; i <= (INT32) ulImgIndex; i++)
  1105.         {
  1106.             retVal = m_pImage[i].GetRGBImageEx(pBuffer, ulWidth, ulHeight, ulPadWidth,
  1107.                                                ulBytesPerPixel, bRowsInverted, bRGBOrdering,
  1108.                                                ulBgColor, bMediaOpacity, ulMediaOpacity,
  1109.                                                bChromaKey, ulChromaKey, ulChromaKeyTol, ulChromaKeyOpacity);
  1110.             if (FAILED(retVal))
  1111.             {
  1112.                 break;
  1113.             }
  1114.         }
  1115.     }
  1116.     else
  1117.     {
  1118.         retVal = HXR_INVALID_PARAMETER;
  1119.     }
  1120.     return retVal;
  1121. }
  1122. HX_RESULT CGIFCodec::GetRGB32(UINT32 ulImageNum, BYTE *pBuffer, UINT32 ulRowStride, BOOL bRowsInverted)
  1123. {
  1124.     HX_RESULT retVal = HXR_OK;
  1125.     if (pBuffer)
  1126.     {
  1127.         if (ulImageNum < m_ulNumImages && m_pImage)
  1128.         {
  1129.             retVal = m_pImage[ulImageNum].GetRGB32(pBuffer, ulRowStride, bRowsInverted);
  1130.         }
  1131.         else
  1132.         {
  1133.             retVal = HXR_UNEXPECTED;
  1134.         }
  1135.     }
  1136.     else
  1137.     {
  1138.         retVal = HXR_INVALID_PARAMETER;
  1139.     }
  1140.     return retVal;
  1141. }
  1142. void CGIFCodec::PacketLost()
  1143. {
  1144.     // Clear the valid flag for the current image
  1145.     m_pImage[m_ulCurrentImageIndex].SetValid(FALSE);
  1146.     // Set the finished flag for this image
  1147.     m_pImage[m_ulCurrentImageIndex].SetFinished();
  1148. }
  1149. BOOL CGIFCodec::LocalColorMapsPresent()
  1150. {
  1151.     UINT32 i;
  1152.     for (i = 0; i < m_ulNumImages; i++)
  1153.     {
  1154.         if (m_pImage[i].LocalColorMapPresent())
  1155.         {
  1156.             return TRUE;
  1157.         }
  1158.     }
  1159.     return FALSE;
  1160. }
  1161. void CGIFCodec::ParseApplicationExtension(BYTE * &pBuf)
  1162. {
  1163.     pBuf += 2; // skip the extension introducer and the application extension label
  1164.     // The next block should always be 11 bytes - 8 bytes for application identifier
  1165.     // and 3 bytes for the application authentication code. If it's not then just
  1166.     // skip these blocks
  1167.     if (pBuf[0] == 11)
  1168.     {
  1169.         // Now we check to see if this is a NETSCAPE2.0 application extension.
  1170.         // If it is, then it contains the loop count for the animation.
  1171.         if (!strncmp((const char *) pBuf + 1, "NETSCAPE2.0", 11))
  1172.         {
  1173.             // Yep, we've got a NETSCAPE2.0 application extension,
  1174.             // so attempt to extract the loop count
  1175.             if (pBuf[12] == 0x03 && pBuf[13] == 0x01 && pBuf[16] == 0x00)
  1176.             {
  1177.                 UINT32 ulCount = (pBuf[15] << 8) | pBuf[14];
  1178.                 if (ulCount == 0)
  1179.                 {
  1180.                     m_ulLoopCount = 0;
  1181.                 }
  1182.                 else
  1183.                 {
  1184.                     m_ulLoopCount = ulCount + 1;
  1185.                 }
  1186.                 pBuf += 17;
  1187.             }
  1188.             else
  1189.             {
  1190.                 SkipBlocks(pBuf);
  1191.             }
  1192.         }
  1193.         else
  1194.         {
  1195.             SkipBlocks(pBuf);
  1196.         }
  1197.     }
  1198.     else
  1199.     {
  1200.         SkipBlocks(pBuf);
  1201.     }
  1202. }