gifcodec.cpp
上传用户:dangjiwu
上传日期:2013-07-19
资源大小:42019k
文件大小:43k
源码类别:

Symbian

开发平台:

Visual C++

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