pxgifff.cpp
Upload User: zhongxx05
Upload Date: 2007-06-06
Package Size: 33641k
Code Size: 51k
Category:

Symbian

Development Platform:

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 <stdio.h>
  37. #include <stdlib.h>
  38. #include <string.h>
  39. // include
  40. #include "hxtypes.h"
  41. #include "hxcom.h"
  42. #include "hxcomm.h"
  43. #include "ihxpckts.h"
  44. #include "hxfiles.h"
  45. #include "hxformt.h"
  46. #include "hxplugn.h"
  47. #include "hxver.h"
  48. #include "hxerror.h"
  49. #include "hxxres.h"
  50. #include "hxxrsmg.h"
  51. #include "ihxfgbuf.h"
  52. #include "hxvsrc.h"
  53. #include "hxengin.h"
  54. #ifdef _MACINTOSH
  55. #include <ctype.h>
  56. #endif
  57. // pncont
  58. #include "hxstring.h"
  59. #include "hxslist.h"
  60. #include "chxpckts.h"
  61. #include "chxfgbuf.h"
  62. // pnmisc
  63. #include "hxurl.h"
  64. #include "unkimp.h"
  65. #include "baseobj.h"
  66. #ifdef _AIX
  67. #include "dllpath.h"
  68. ENABLE_MULTILOAD_DLLACCESS_PATHS(Pxgifff);
  69. #endif
  70. // pxcomlib
  71. #include "gstring.h"
  72. #include "pxutil.h"
  73. #include "pxcolor.h"
  74. #include "parseurl.h"
  75. #include "buffutil.h"
  76. // pxgiflib
  77. #include "lzw.h"
  78. #include "gifimage.h"
  79. #include "gifcodec.h"
  80. // coreres
  81. #include "pixres.h"
  82. // pxgifff
  83. #if defined(HELIX_FEATURE_VIEWSOURCE)
  84. #include "gifvsrc.h"
  85. #endif /* #if defined(HELIX_FEATURE_VIEWSOURCE) */
  86. #include "pxgifff.h"
  87. #include "giffdll.ver"
  88. // pndebug
  89. #include "errdbg.h"
  90. #include "hxheap.h"
  91. #ifdef _DEBUG
  92. #undef HX_THIS_FILE
  93. static const char HX_THIS_FILE[] = __FILE__;
  94. #endif
  95. #define BASE_GIFSTREAM_VERSION    HX_ENCODE_PROD_VERSION(0, 0, 0, 0)
  96. #define MEDREP_GIFSTREAM_VERSION  HX_ENCODE_PROD_VERSION(0, 1, 0, 0)
  97. const char * const CGIFFileFormat::m_pszDescription       = "Helix GIF File Format Plugin";
  98. const char * const CGIFFileFormat::m_pszCopyright         = HXVER_COPYRIGHT;
  99. const char * const CGIFFileFormat::m_pszMoreInfoURL       = HXVER_MOREINFO;
  100. const char * const CGIFFileFormat::m_ppszFileMimeTypes[]  = {"image/gif", NULL};
  101. const char * const CGIFFileFormat::m_ppszFileExtensions[] = {"gif", NULL};
  102. const char * const CGIFFileFormat::m_ppszFileOpenNames[]  = {"GIF File Format (*.gif)", NULL};
  103. const char * const CGIFFileFormat::m_pszStreamMimeType    = "application/vnd.rn-gifstream2";
  104. const char * const CGIFFileFormat::m_pszBadStreamMimeType = "application/vnd.rn-gifstream3";
  105. const UINT32 CGIFFileFormat::m_ulContentVersion     = HX_ENCODE_PROD_VERSION(0, 0, 0, 0);
  106. const UINT32 CGIFFileFormat::m_ulStreamVersion      = BASE_GIFSTREAM_VERSION;
  107. #ifdef _WINDOWS
  108. extern HINSTANCE g_hInstance;
  109. #endif
  110. CGIFFileFormat::CGIFFileFormat()
  111. {
  112.     m_lRefCount            = 0;
  113.     m_pContext             = NULL;
  114.     m_pFileObject          = NULL;
  115.     m_pFileStat            = NULL;
  116.     m_pFormatResponse      = NULL;
  117.     m_pCommonClassFactory  = NULL;
  118.     m_pError               = NULL;
  119.     m_ulBitRate            = 0;
  120.     m_ulPreroll            = 0;
  121.     m_ulDuration           = 0;
  122.     m_pURL                 = NULL;
  123.     m_pRequestURL          = NULL;
  124.     m_ulSeekTime           = 0;
  125.     m_ucTarget             = kTargetBrowser;
  126.     m_ucURLType            = kURLTypeNormal;
  127.     m_lCurrentTime         = 0;
  128.     m_plImageStartTime     = NULL;
  129.     m_lCurImgIndex         = 0;
  130.     m_ulState              = kStateConstructed;
  131.     m_ulFileSize           = 0;
  132.     m_pGIFCodec            = NULL;
  133.     m_bReliable            = FALSE;
  134.     m_ulNumBytesRead       = 0;
  135.     m_pFileBuffer          = NULL;
  136.     m_pFragFileBuffer      = NULL;
  137.     m_ppPacket             = NULL;
  138.     m_ulNumPackets         = 0;
  139.     m_ulCurrentPacketIndex = 0;
  140.     m_bParseFailed         = FALSE;
  141.     m_pMediaRepeatStr      = NULL;
  142. }
  143. CGIFFileFormat::~CGIFFileFormat()
  144.     Close();
  145. }
  146. STDMETHODIMP CGIFFileFormat::QueryInterface(REFIID riid, void **ppvObj)
  147. {
  148.     if (IsEqualIID(riid, IID_IUnknown))
  149.     {
  150.         AddRef();
  151.         *ppvObj = (IUnknown *) (IHXPlugin *) this;
  152.         return HXR_OK;
  153.     }
  154.     else if (IsEqualIID(riid, IID_IHXPlugin))
  155.     {
  156.         AddRef();
  157.         *ppvObj = (IHXPlugin *) this;
  158.         return HXR_OK;
  159.     }
  160.     else if (IsEqualIID(riid, IID_IHXFileFormatObject))
  161.     {
  162.         AddRef();
  163.         *ppvObj = (IHXFileFormatObject *) this;
  164.         return HXR_OK;
  165.     }
  166.     else if (IsEqualIID(riid, IID_IHXFileResponse))
  167.     {
  168.         AddRef();
  169.         *ppvObj = (IHXFileResponse *) this;
  170.         return HXR_OK;
  171.     }
  172.     else if (IsEqualIID(riid, IID_IHXFileStatResponse))
  173.     {
  174.         AddRef();
  175.         *ppvObj = (IHXFileStatResponse *) this;
  176.         return HXR_OK;
  177.     }
  178. #if defined(HELIX_FEATURE_VIEWSOURCE)
  179.     else if (IsEqualIID(riid, IID_IHXFileViewSource))
  180.     {
  181. CGIFViewSource* pVsrc = new CGIFViewSource(m_pContext,
  182. (IUnknown*)(IHXPlugin*)this);
  183. if ( pVsrc == NULL )
  184. {
  185.     return HXR_FAIL;
  186. }
  187. return pVsrc->QueryInterface(riid, ppvObj);
  188.     }
  189. #endif /* #if defined(HELIX_FEATURE_VIEWSOURCE) */
  190.     else if (IsEqualIID(riid, IID_IHXThreadSafeMethods))
  191.     {
  192. AddRef();
  193. *ppvObj = (IHXThreadSafeMethods*)this;
  194. return HXR_OK;
  195.     }
  196.     *ppvObj = NULL;
  197.     return HXR_NOINTERFACE;
  198. }
  199. STDMETHODIMP_(UINT32) CGIFFileFormat::AddRef()
  200. {
  201.     return InterlockedIncrement(&m_lRefCount);
  202. }
  203. STDMETHODIMP_(UINT32) CGIFFileFormat::Release()
  204. {
  205.     if (InterlockedDecrement(&m_lRefCount) > 0)
  206.     {
  207.         return m_lRefCount;
  208.     }
  209.     delete this;
  210.     return 0;
  211. }
  212. STDMETHODIMP CGIFFileFormat::GetPluginInfo(REF(BOOL)        bMultipleLoad,
  213.                                            REF(const char*) pDescription,
  214.                                            REF(const char*) pCopyright,
  215.                                            REF(const char*) pMoreInfoURL,
  216.                                            REF(ULONG32)     ulVersionNumber)
  217. {
  218.     bMultipleLoad   = TRUE;   // Must be true for file formats.
  219.     pDescription    = m_pszDescription;
  220.     pCopyright      = m_pszCopyright;
  221.     pMoreInfoURL    = m_pszMoreInfoURL;
  222.     ulVersionNumber = TARVER_ULONG32_VERSION;
  223.     return HXR_OK;
  224. }
  225. STDMETHODIMP CGIFFileFormat::GetFileFormatInfo(REF(const char **) rppszFileMimeTypes,
  226.                                                REF(const char **) rppszFileExtensions,
  227.                                                REF(const char **) rppszFileOpenNames)
  228. {
  229.     rppszFileMimeTypes  = (const char**) m_ppszFileMimeTypes;
  230.     rppszFileExtensions = (const char**) m_ppszFileExtensions;
  231.     rppszFileOpenNames  = (const char**) m_ppszFileOpenNames;
  232.     return HXR_OK;
  233. }
  234. STDMETHODIMP CGIFFileFormat::InitPlugin(IUnknown *pContext)
  235. {
  236.     // Check for input error
  237.     if (pContext == NULL)
  238.     {
  239.         return HXR_INVALID_PARAMETER;
  240.     }
  241.     // Save a copy of the context
  242.     m_pContext = pContext;
  243.     m_pContext->AddRef();
  244.     // Get an IHXCommonClassFactory interface from the context
  245.     HX_RELEASE(m_pCommonClassFactory);
  246.     HX_RESULT retVal = m_pContext->QueryInterface(IID_IHXCommonClassFactory, (void **) &m_pCommonClassFactory);
  247.     if (retVal != HXR_OK)
  248.     {
  249.         HX_RELEASE(m_pContext);
  250.         return HXR_NOINTERFACE;
  251.     }
  252.     // Get the IHXErrorMessages interface
  253.     // It's OK if TLC doesn't support it.
  254.     HX_RELEASE(m_pError);
  255.     m_pContext->QueryInterface(IID_IHXErrorMessages, (void **) &m_pError);
  256.     return HXR_OK;
  257. }
  258. STDMETHODIMP CGIFFileFormat::InitFileFormat(IHXRequest        *pRequest,
  259.                                             IHXFormatResponse *pFormatResponse,
  260.                                             IHXFileObject     *pFileObject)
  261. {
  262. #ifdef XXXMEH_DEBUG_LOG
  263.     const char* pszURLDbg = NULL;
  264.     pRequest->GetURL(pszURLDbg);
  265.     DEBUG_OUTF("pxgifff.log", (s, "0x%08x::InitFileFormat(): %sn", this, pszURLDbg));
  266. #endif
  267.     // Check for input error
  268.     if (pRequest == NULL || pFormatResponse == NULL || pFileObject == NULL)
  269.     {
  270.         return HXR_INVALID_PARAMETER;
  271.     }
  272.     // Check state
  273.     if (m_ulState != kStateConstructed)
  274.     {
  275.         return HXR_UNEXPECTED;
  276.     }
  277.     // Save a copy of the IHXFormatResponse
  278.     m_pFormatResponse = pFormatResponse;
  279.     m_pFormatResponse->AddRef();
  280.     // Get the URL string from the IHXRequest object
  281.     const char *pszURL = NULL;
  282.     HX_RESULT   retVal = pRequest->GetURL(pszURL);
  283.     if (retVal != HXR_OK)
  284.     {
  285.         return m_pFormatResponse->InitDone(retVal);
  286.     }
  287.     if (pszURL)
  288.     {
  289.         HX_DELETE(m_pRequestURL);
  290.         m_pRequestURL = new CHXString(pszURL);
  291.     }
  292.     // Create an IHXValues object to hold the param name/value pairs
  293.     IHXValues *pValues = NULL;
  294.     retVal = m_pCommonClassFactory->CreateInstance(CLSID_IHXValues, (void**) &pValues);
  295.     if (FAILED(retVal))
  296.     {
  297.         return m_pFormatResponse->InitDone(retVal);
  298.     }
  299.     // Now add the following parameters to the IHXValues. These
  300.     // parameters could have come as URL-encoded parameters or as
  301.     // parameters in the request headers. These parameters will be
  302.     // added as CString properties to the IHXValues.
  303.     AddURLOrRequestParam(pRequest, "bitrate",                 m_pContext, pValues);
  304.     AddURLOrRequestParam(pRequest, "duration",                m_pContext, pValues);
  305.     AddURLOrRequestParam(pRequest, "preroll",                 m_pContext, pValues);
  306.     AddURLOrRequestParam(pRequest, "url",                     m_pContext, pValues);
  307.     AddURLOrRequestParam(pRequest, "target",                  m_pContext, pValues);
  308.     AddURLOrRequestParam(pRequest, "bgcolor",                 m_pContext, pValues);
  309.     AddURLOrRequestParam(pRequest, "reliable",                m_pContext, pValues);
  310.     AddURLOrRequestParam(pRequest, "mediaRepeat",             m_pContext, pValues);
  311.     // Set the bitrate
  312.     retVal = ExtractValueUINT32(pValues, "bitrate", kDefaultBitRate, m_ulBitRate);
  313.     if (retVal != HXR_OK)
  314.     {
  315.         HX_RELEASE(pValues);
  316.         ReportError(IDS_ERR_GIF_BADBITRATE);
  317.         return m_pFormatResponse->InitDone(retVal);
  318.     }
  319.     // Set the duration
  320.     retVal = ExtractValueTime(pValues, "duration", kDefaultDuration, m_ulDuration);
  321.     if (retVal != HXR_OK)
  322.     {
  323.         HX_RELEASE(pValues);
  324.         ReportError(IDS_ERR_GIF_BADDURATION);
  325.         return m_pFormatResponse->InitDone(retVal);
  326.     }
  327.     // Set the preroll
  328.     retVal = ExtractValueTime(pValues, "preroll", 0, m_ulPreroll);
  329.     if (retVal != HXR_OK)
  330.     {
  331.         HX_RELEASE(pValues);
  332.         ReportError(IDS_ERR_GIF_BADPREROLL);
  333.         return m_pFormatResponse->InitDone(retVal);
  334.     }
  335.     // Set the URL
  336.     CHXString cTmp;
  337.     retVal = ExtractValueString(pValues, "url", NULL, cTmp);
  338.     if (retVal != HXR_OK)
  339.     {
  340.         HX_RELEASE(pValues);
  341.         ReportError(IDS_ERR_GIF_BADURL);
  342.         return m_pFormatResponse->InitDone(retVal);
  343.     }
  344.     if (cTmp.GetLength() > 0)
  345.     {
  346.         HX_DELETE(m_pURL);
  347.         m_pURL = new CHXString((const char*) cTmp);
  348.     }
  349.     CHXString cTarget;
  350.     retVal = ExtractValueString(pValues, "target", "_browser", cTarget);
  351.     if (retVal != HXR_OK)
  352.     {
  353.         HX_RELEASE(pValues);
  354.         ReportError(IDS_ERR_GIF_BADTARGET);
  355.         return m_pFormatResponse->InitDone(retVal);
  356.     }
  357.     retVal = ExtractValueColor(pValues, "bgcolor", 0x00FFFFFF, m_ulBackgroundColor);
  358.     if (retVal != HXR_OK)
  359.     {
  360.         HX_RELEASE(pValues);
  361.         ReportError(IDS_ERR_GIF_BADBGCOLOR);
  362.         return m_pFormatResponse->InitDone(retVal);
  363.     }
  364.     retVal = ExtractValueBOOL(pValues, "reliable", FALSE, m_bReliable);
  365.     if (retVal != HXR_OK)
  366.     {
  367.         HX_RELEASE(pValues);
  368.         ReportError(IDS_ERR_GIF_BADRELFLAG);
  369.         return m_pFormatResponse->InitDone(retVal);
  370.     }
  371.     // Get the media repeat string
  372.     pValues->GetPropertyCString("mediaRepeat", m_pMediaRepeatStr);
  373.     // Release the IHXValues object
  374.     HX_RELEASE(pValues);
  375.     // Check url encoded bitrate
  376.     if (!m_ulBitRate)
  377.     {
  378.         ReportError(IDS_ERR_GIF_BITRATEZERO);
  379.         return m_pFormatResponse->InitDone(retVal);
  380.     }
  381.     // Check target string
  382.     if (cTarget == "_player")
  383.     {
  384.         m_ucTarget = kTargetPlayer;
  385.     }
  386.     else if (cTarget == "_browser")
  387.     {
  388.         m_ucTarget = kTargetBrowser;
  389.     }
  390.     else
  391.     {
  392.         ReportError(IDS_ERR_GIF_ILLEGALTARGET);
  393.         return m_pFormatResponse->InitDone(retVal);
  394.     }
  395.     // Set some defaults
  396.     m_ucURLType  = kURLTypeNormal;
  397.     m_ulSeekTime = 0;
  398.     // Check the URL if present
  399.     if (m_pURL && m_pURL->GetLength() > 0)
  400.     {
  401.         // Check to see if it's a command
  402.         if (m_pURL->Left(8) == "command:")
  403.         {
  404.             // Yes it is a command. Make sure it's either seek, pause, or play
  405.             if (*m_pURL == "command:pause()")
  406.             {
  407.                 m_ucURLType = kURLTypeCommandPause;
  408.             }
  409.             else if (*m_pURL == "command:play()")
  410.             {
  411.                 m_ucURLType = kURLTypeCommandPlay;
  412.             }
  413.             else if (*m_pURL == "command:stop()")
  414.             {
  415.                 m_ucURLType = kURLTypeCommandStop;
  416.             }
  417.             else if (m_pURL->Mid(8,5) == "seek(" &&
  418.                      m_pURL->Right(1) == ")")
  419.             {
  420.                 m_ucURLType = kURLTypeCommandSeek;
  421.                 // Make sure there's a valid seek time
  422.                 CHXString cSeekStr   = m_pURL->Mid(13, m_pURL->GetLength() - 14);
  423.                 BOOL bRet = ConvertTimeStringToULONG32((char*) (const char*) cSeekStr,
  424.                                                        cSeekStr.GetLength(),
  425.                                                        m_ulSeekTime);
  426.                 if (bRet == FALSE)
  427.                 {
  428.                     ReportError(IDS_ERR_GIF_BADTIMEFORMAT);
  429.                     return m_pFormatResponse->InitDone(retVal);
  430.                 }
  431.             }
  432.             else
  433.             {
  434.                 ReportError(IDS_ERR_GIF_UNKPLAYERCOMMAND);
  435.                 return m_pFormatResponse->InitDone(retVal);
  436.             }
  437.         }
  438.     }
  439.     // Reconcile the URL and the target
  440.     if (m_ucTarget == kTargetBrowser && m_ucURLType != kURLTypeNormal)
  441.     {
  442.         ReportError(IDS_ERR_GIF_NOTARGETBROWSER);
  443.         return m_pFormatResponse->InitDone(retVal);
  444.     }
  445.     // Save a copy of the file object
  446.     m_pFileObject = pFileObject;
  447.     m_pFileObject->AddRef();
  448.     // Set the new state
  449.     m_ulState = kStateFileInit;
  450.     // Init the file object - see InitDone for response
  451.     return m_pFileObject->Init(HX_FILE_READ | HX_FILE_BINARY, this);
  452. }
  453. STDMETHODIMP CGIFFileFormat::InitDone(HX_RESULT status)
  454. {
  455. #ifdef XXXMEH_DEBUG_LOG
  456.     DEBUG_OUTF("pxgifff.log", (s, "0x%08x::InitDone(0x%08x)n", this, status));
  457. #endif
  458.     // Check state
  459.     if (m_ulState != kStateFileInit)
  460.     {
  461.         return HXR_UNEXPECTED;
  462.     }
  463.     // Check for input error
  464.     if (status != HXR_OK)
  465.     {
  466.         return m_pFormatResponse->InitDone(status);
  467.     }
  468.     // Now we must get the IHXFileStat interface from the IHXFileObject
  469.     HX_RELEASE(m_pFileStat);
  470.     HX_RESULT retVal = m_pFileObject->QueryInterface(IID_IHXFileStat, (void **) &m_pFileStat);
  471.     if (retVal != HXR_OK)
  472.     {
  473.         return m_pFormatResponse->InitDone(retVal);
  474.     }
  475.     // Set the new state
  476.     m_ulState = kStateFileStat;
  477.     // Now we find out how big is the file
  478.     return m_pFileStat->Stat(this);
  479. }
  480. STDMETHODIMP CGIFFileFormat::StatDone(HX_RESULT status, UINT32 ulSize, UINT32 ulCreationTime,
  481.                                       UINT32 ulAccessTime, UINT32 ulModificationTime, UINT32 ulMode)
  482. {
  483. #ifdef XXXMEH_DEBUG_LOG
  484.     DEBUG_OUTF("pxgifff.log", (s, "0x%08x::StatDone(0x%08x,%lu,,,,)n", this, status, ulSize));
  485. #endif
  486.     HX_RESULT retVal = HXR_OK;
  487.     if (m_ulState == kStateFileStat)
  488.     {
  489.         if (SUCCEEDED(status))
  490.         {
  491.             // Set the file size
  492.             m_ulFileSize = ulSize;
  493.             // Now we no longer need the IHXFileStat interface
  494.             HX_RELEASE(m_pFileStat);
  495.             // Create an IHXFragmentedBuffer to hold the file
  496.             CHXFragmentedBuffer* pTmp = NULL;
  497.             retVal                     = CHXFragmentedBuffer::CreateObject(&pTmp);
  498.             if (SUCCEEDED(retVal))
  499.             {
  500.                 HX_RELEASE(m_pFragFileBuffer);
  501.                 retVal = pTmp->QueryInterface(IID_IHXFragmentedBuffer, (void**) &m_pFragFileBuffer);
  502.                 if (SUCCEEDED(retVal))
  503.                 {
  504.                     // Set the new state
  505.                     m_ulState        = kStateFileRead;
  506.                     // Clear the bytes read counter
  507.                     m_ulNumBytesRead = 0;
  508.                     // Now we read, 2k at a time
  509.                     retVal           = m_pFileObject->Read(2048);
  510.                 }
  511.                 else
  512.                 {
  513.                     retVal = m_pFormatResponse->InitDone(retVal);
  514.                 }
  515.             }
  516.             else
  517.             {
  518.                 retVal = m_pFormatResponse->InitDone(retVal);
  519.             }
  520.         }
  521.         else
  522.         {
  523.             retVal = m_pFormatResponse->InitDone(status);
  524.         }
  525.     }
  526.     else
  527.     {
  528.         retVal = HXR_UNEXPECTED;
  529.     }
  530.     return retVal;
  531. }
  532. STDMETHODIMP CGIFFileFormat::ReadDone(HX_RESULT status, IHXBuffer *pBuffer)
  533. {
  534. #ifdef XXXMEH_DEBUG_LOG
  535.     UINT32 ulSize = (SUCCEEDED(status) && pBuffer ? pBuffer->GetSize() : 0);
  536.     DEBUG_OUTF("pxgifff.log", (s, "0x%08x::ReadDone(0x%08x,0x%08x): pBuffer->GetSize() = %lun",
  537.                this, status, pBuffer, ulSize));
  538. #endif
  539.     HX_RESULT retVal = HXR_OK;
  540.     if (m_ulState == kStateFileRead)
  541.     {
  542.         if (SUCCEEDED(status))
  543.         {
  544.             // Append the buffer to the fragmented buffer
  545.             retVal = m_pFragFileBuffer->Append(pBuffer, 0, pBuffer->GetSize());
  546.             if (SUCCEEDED(retVal))
  547.             {
  548.                 // Update the number of bytes read
  549.                 m_ulNumBytesRead += pBuffer->GetSize();
  550.                 // Have we read all we were supposed to?
  551.                 if (m_ulFileSize > 0 && m_ulNumBytesRead >= m_ulFileSize)
  552.                 {
  553.                     retVal = ParseFile();
  554.                     if (SUCCEEDED(retVal))
  555.                     {
  556.                         // Set the new state
  557.                         m_ulState = kStateInitialized;
  558.                     }
  559.                     else
  560.                     {
  561.                         m_bParseFailed = TRUE;
  562.                         const char* pszStr = (m_pRequestURL ? (const char*) *m_pRequestURL : NULL);
  563.                         ReportError(IDS_ERR_GIF_CORRUPTFILE, pszStr);
  564.                         retVal = HXR_OK;
  565.                         // Set the new state
  566.                         m_ulState = kStateInitialized;
  567.                     }
  568.                     // Tell the response interface we're ready
  569.                     retVal = m_pFormatResponse->InitDone(retVal);
  570.                 }
  571.                 else
  572.                 {
  573.                     // No, either we haven't read enough or we don't
  574.                     // know how big the file really is. Either way,
  575.                     // we need to do another read.
  576.                     retVal = m_pFileObject->Read(2048);
  577.                 }
  578.             }
  579.         }
  580.         else
  581.         {
  582.             // We might have gotten here if we didn't know the file size
  583.             // and we're reading until we got an error. Therefore, if
  584.             // we're here AND we've read some bytes OK, then we'll try
  585.             // parsing the file. If we have NOT read any bytes successfully,
  586.             // then we'll fail
  587.             //
  588.             if (m_ulNumBytesRead > 0)
  589.             {
  590.                 retVal = ParseFile();
  591.                 if (SUCCEEDED(retVal))
  592.                 {
  593.                     // Set the new state
  594.                     m_ulState = kStateInitialized;
  595.                 }
  596.                 else
  597.                 {
  598.                     m_bParseFailed = TRUE;
  599.                     const char* pszStr = (m_pRequestURL ? (const char*) *m_pRequestURL : NULL);
  600.                     ReportError(IDS_ERR_GIF_CORRUPTFILE, pszStr);
  601.                     retVal = HXR_OK;
  602.                     // Set the new state
  603.                     m_ulState = kStateInitialized;
  604.                 }
  605.             }
  606.             else
  607.             {
  608.                 retVal = status;
  609.             }
  610.             retVal = m_pFormatResponse->InitDone(retVal);
  611.         }
  612.     }
  613.     else
  614.     {
  615.         retVal = HXR_UNEXPECTED;
  616.     }
  617.     return retVal;
  618. }
  619. STDMETHODIMP CGIFFileFormat::GetFileHeader()
  620. {
  621. #ifdef XXXMEH_DEBUG_LOG
  622.     DEBUG_OUTF("pxgifff.log", (s, "0x%08x::GetFileHeader()n", this));
  623. #endif
  624.     // Check the state
  625.     if (m_ulState != kStateInitialized)
  626.     {
  627.         return HXR_UNEXPECTED;
  628.     }
  629.     // Create an IHXValues object
  630.     IHXValues *pHeader = NULL;
  631.     HX_RESULT   retVal  = m_pCommonClassFactory->CreateInstance(CLSID_IHXValues, (void **) &pHeader);
  632.     if (retVal != HXR_OK)
  633.     {
  634.         m_pFormatResponse->FileHeaderReady(retVal, NULL);
  635.     }
  636.     // Set the StreamCount propery - we always only have 1 stream
  637.     pHeader->SetPropertyULONG32("StreamCount", 1);
  638.     pHeader->SetPropertyULONG32("IsRealDataType", 1);
  639.     // Set the width and height
  640.     if (m_pGIFCodec)
  641.     {
  642.         pHeader->SetPropertyULONG32("Width",  m_pGIFCodec->GetLogicalScreenWidth());
  643.         pHeader->SetPropertyULONG32("Height", m_pGIFCodec->GetLogicalScreenHeight());
  644.     }
  645.     // Set the new state
  646.     m_ulState = kStateFileHeaderSent;
  647.     // Inform the response interface that we have the file header
  648.     retVal = m_pFormatResponse->FileHeaderReady(HXR_OK, pHeader);
  649.     // Release our reference on the IHXValues object
  650.     HX_RELEASE(pHeader);
  651.     return retVal;
  652. }
  653. STDMETHODIMP CGIFFileFormat::GetStreamHeader(UINT16 usStreamNum)
  654. {
  655. #ifdef XXXMEH_DEBUG_LOG
  656.     DEBUG_OUTF("pxgifff.log", (s, "0x%08x::GetStreamHeader(%u)n", this, usStreamNum));
  657. #endif
  658.     // Check the state
  659.     if (m_ulState != kStateFileHeaderSent)
  660.     {
  661.         return HXR_UNEXPECTED;
  662.     }
  663.     // Check for input error
  664.     if (usStreamNum != 0)
  665.     {
  666.         return m_pFormatResponse->StreamHeaderReady(HXR_FAIL, NULL);
  667.     }
  668.     UINT32 ulPreDataBytes = 0;
  669.     if (m_pGIFCodec && !m_bParseFailed)
  670.     {
  671.         // Resolve the minimum duration with the requested duration.
  672.         //
  673.         // Here's the rule: if the duration was not specified (i.e. - the
  674.         // duration is equal to the default, then take the duration that's
  675.         // in the GIF file, as long as it HAS some duration
  676.         if (m_ulDuration == kDefaultDuration &&
  677.             m_pGIFCodec->IsGIF89a()          &&
  678.             m_pGIFCodec->GetDelayTimeSum() > 0)
  679.         {
  680.             m_ulDuration = m_pGIFCodec->GetDelayTimeSum();
  681.         }
  682.         // Allocate space for the array of scheduling times
  683.         INT32 lNumImages = (INT32) m_pGIFCodec->GetNumImages();
  684.         HX_VECTOR_DELETE(m_plImageStartTime);
  685.         m_plImageStartTime = new INT32 [lNumImages];
  686.         if (!m_plImageStartTime)
  687.         {
  688.             return m_pFormatResponse->StreamHeaderReady(HXR_FAIL, NULL);
  689.         }
  690.         // Initially we fill these times with the time the image has to be displayed
  691.         INT32 i;
  692.         INT32 lRunningSum = 0;
  693.         for (i = 0; i < lNumImages; i++)
  694.         {
  695.             m_plImageStartTime[i] = lRunningSum;
  696.             lRunningSum          += (INT32) m_pGIFCodec->GetDelayTime(i) * 10;
  697.         }
  698.         // Now we go from last image to first, adjusting times
  699.         UINT32 ulTotalBytesToSend = 0;
  700.         INT32  lLastStartTime     = m_plImageStartTime[lNumImages - 1];
  701.         for (i = m_pGIFCodec->GetNumImages() - 1; i >= 0; i--)
  702.         {
  703.             INT32 lTransmitSize   = m_pGIFCodec->GetImageDataSize(i);    // Actual bytes to transmit
  704.             INT32 lOverheadSize   = ((lTransmitSize / 500) + 1) * 24;    // This is an estimate of packet overhead
  705.             INT32 lTransmitTime   = ((lTransmitSize + lOverheadSize) * 8000 / m_ulBitRate) + 1; // transmit time in milliseconds
  706.             if (lLastStartTime < m_plImageStartTime[i])
  707.             {
  708.                 m_plImageStartTime[i]  = lLastStartTime - lTransmitTime;
  709.             }
  710.             else
  711.             {
  712.                 m_plImageStartTime[i] -= lTransmitTime;
  713.             }
  714.             lLastStartTime = m_plImageStartTime[i];
  715.             ulTotalBytesToSend += (UINT32) lTransmitSize;
  716.         }
  717.         // Now the min preroll should be the negative of the first start time
  718.         if (m_plImageStartTime[0] >= 0)
  719.         {
  720.             return m_pFormatResponse->StreamHeaderReady(HXR_FAIL, NULL);
  721.         }
  722.         UINT32 ulMinPreroll = (UINT32) -m_plImageStartTime[0];
  723.         // Resolve this with the requested preroll
  724.         if (m_ulPreroll < ulMinPreroll)
  725.         {
  726.             m_ulPreroll = ulMinPreroll;
  727.         }
  728.         // Compute predata bytes
  729.         ulPreDataBytes = m_ulBitRate * m_ulPreroll / 8000;
  730.         if (ulPreDataBytes > ulTotalBytesToSend)
  731.         {
  732.             ulPreDataBytes = ulTotalBytesToSend;
  733.         }
  734.     }
  735.     // Create an IHXValues object
  736.     IHXValues *pStreamHeader = NULL;
  737.     HX_RESULT retVal = m_pCommonClassFactory->CreateInstance(CLSID_IHXValues, (void **) &pStreamHeader);
  738.     if (retVal != HXR_OK)
  739.     {
  740.         return m_pFormatResponse->StreamHeaderReady(retVal, NULL);
  741.     }
  742.     // Set the mime type
  743.     char* pszStreamMimeType = (char*) m_pszStreamMimeType;
  744.     if (m_bParseFailed)
  745.     {
  746.         pszStreamMimeType = (char*) m_pszBadStreamMimeType;
  747.     }
  748.     // Create buffer to hold MIME type
  749.     IHXBuffer *pMimeType = NULL;
  750.     retVal = PXUtilities::CreateStringBuffer(pszStreamMimeType,
  751.                                              m_pContext,
  752.                                              pMimeType);
  753.     if (retVal != HXR_OK)
  754.     {
  755.         HX_RELEASE(pStreamHeader);
  756.         return m_pFormatResponse->StreamHeaderReady(retVal, NULL);
  757.     }
  758.     // Generate an ASM rule book
  759.     char szASMRuleBook[256]; /* Flawfinder: ignore */
  760.     if (m_bReliable)
  761.     {
  762.         sprintf(szASMRuleBook, "AverageBandwidth=%ld,Priority=10;", m_ulBitRate); /* Flawfinder: ignore */
  763.     }
  764.     else
  765.     {
  766.         sprintf(szASMRuleBook, /* Flawfinder: ignore */
  767.                 "AverageBandwidth=%ld,Priority=5;AverageBandwidth=%ld,Priority=9;",
  768.                 m_ulBitRate, 0);
  769.     }
  770.     // Create buffer to hold ASM rules
  771.     IHXBuffer *pASMRuleBook = NULL;
  772.     retVal = PXUtilities::CreateStringBuffer((const char*) szASMRuleBook,
  773.                                              m_pContext,
  774.                                              pASMRuleBook);
  775.     if (retVal != HXR_OK)
  776.     {
  777.         HX_RELEASE(pStreamHeader);
  778.         HX_RELEASE(pMimeType);
  779.         return m_pFormatResponse->StreamHeaderReady(retVal, NULL);
  780.     }
  781.     // Create buffer to hold intrinsic duration type string
  782.     const char* pszIntrinsicDur = NULL;
  783.     if (m_pGIFCodec->GetNumImages()    == 1 &&
  784.         m_pGIFCodec->GetDelayTimeSum() == 0)
  785.     {
  786.         pszIntrinsicDur = "intrinsicDurationDiscrete";
  787.     }
  788.     else
  789.     {
  790.         pszIntrinsicDur = "intrinsicDurationContinuous";
  791.     }
  792.     IHXBuffer* pIntrinsicDur = NULL;
  793.     retVal = PXUtilities::CreateStringBuffer(pszIntrinsicDur,
  794.                                              m_pContext,
  795.                                              pIntrinsicDur);
  796.     if (retVal != HXR_OK)
  797.     {
  798.         HX_RELEASE(pStreamHeader);
  799.         HX_RELEASE(pMimeType);
  800.         HX_RELEASE(pASMRuleBook);
  801.         return m_pFormatResponse->StreamHeaderReady(retVal, NULL);
  802.     }
  803.     // Create buffer to hold opaque data
  804.     IHXBuffer *pOpaqueData = NULL;
  805.     retVal = m_pCommonClassFactory->CreateInstance(CLSID_IHXBuffer, (void **) &pOpaqueData);
  806.     if (retVal != HXR_OK)
  807.     {
  808.         HX_RELEASE(pStreamHeader);
  809.         HX_RELEASE(pMimeType);
  810.         HX_RELEASE(pASMRuleBook);
  811.         HX_RELEASE(pIntrinsicDur);
  812.         return m_pFormatResponse->StreamHeaderReady(retVal, NULL);
  813.     }
  814.     // Fill in the Header with the parameters
  815.     pStreamHeader->SetPropertyULONG32("StreamNumber",          0);
  816.     pStreamHeader->SetPropertyULONG32("MaxBitRate",            m_ulBitRate);
  817.     pStreamHeader->SetPropertyULONG32("AvgBitRate",            m_ulBitRate);
  818.     pStreamHeader->SetPropertyULONG32("MaxPacketSize",         600);
  819.     pStreamHeader->SetPropertyULONG32("AvgPacketSize",         500);
  820.     pStreamHeader->SetPropertyULONG32("StartTime",             0);
  821.     pStreamHeader->SetPropertyULONG32("Preroll",               m_ulPreroll);
  822.     pStreamHeader->SetPropertyULONG32("PreData",               ulPreDataBytes);
  823.     pStreamHeader->SetPropertyULONG32("PreDataAtStart",        1);
  824.     pStreamHeader->SetPropertyULONG32("PreRollAtStart",        0);
  825.     pStreamHeader->SetPropertyULONG32("PreDataAfterSeek",      0);
  826.     pStreamHeader->SetPropertyULONG32("PreRollAfterSeek",      1);
  827.     pStreamHeader->SetPropertyULONG32("Duration",              m_ulDuration);
  828.     pStreamHeader->SetPropertyULONG32("ContentVersion",        m_ulContentVersion);
  829.     pStreamHeader->SetPropertyCString("MimeType",              pMimeType);
  830.     pStreamHeader->SetPropertyCString("ASMRuleBook",           pASMRuleBook);
  831.     pStreamHeader->SetPropertyCString("intrinsicDurationType", pIntrinsicDur);
  832.     // The mediaRepeat attribute says whether or not to strip the native
  833.     // repeat value from the media. We need support for mediaRepeat in
  834.     // the GIF renderer for this to work. Therefore, if mediaRepeat specified,
  835.     // then we also need to bump the stream version.
  836.     UINT32 ulStreamVersion = m_ulStreamVersion;
  837.     if (m_pMediaRepeatStr)
  838.     {
  839.         pStreamHeader->SetPropertyCString("mediaRepeat", m_pMediaRepeatStr);
  840.         ulStreamVersion = MEDREP_GIFSTREAM_VERSION;
  841.     }
  842.     // Now set the stream version
  843.     pStreamHeader->SetPropertyULONG32("StreamVersion", ulStreamVersion);
  844.     // Make a renderer flags property
  845.     UINT32 ulRendererFlags = 0;
  846.     if (m_bParseFailed)
  847.     {
  848.         ulRendererFlags |= GIF_RENDERER_FLAG_PARSEFAILED;
  849.         if (m_pGIFCodec)
  850.         {
  851.             pStreamHeader->SetPropertyULONG32("Width",  m_pGIFCodec->GetLogicalScreenWidth());
  852.             pStreamHeader->SetPropertyULONG32("Height", m_pGIFCodec->GetLogicalScreenHeight());
  853.         }
  854.     }
  855.     pStreamHeader->SetPropertyULONG32("RendererFlags", ulRendererFlags);
  856.     // Ask the GIF Codec how big the header is
  857.     UINT32 ulLength = 0;
  858.     if (m_pGIFCodec && !m_bParseFailed)
  859.     {
  860.         retVal = m_pGIFCodec->GetPacketBufferLength(ulLength);
  861.         if (retVal != HXR_OK)
  862.         {
  863.             HX_RELEASE(pMimeType);
  864.             HX_RELEASE(pASMRuleBook);
  865.             HX_RELEASE(pOpaqueData);
  866.             HX_RELEASE(pStreamHeader);
  867.             HX_RELEASE(pIntrinsicDur);
  868.             return m_pFormatResponse->StreamHeaderReady(retVal, NULL);
  869.         }
  870.     }
  871.     // Set the opaque data buffer to this length plus a bit more
  872.     UINT32 ulExtraDataSize = 12 + (m_pURL ? m_pURL->GetLength() : 0) + 1;
  873.     retVal = pOpaqueData->SetSize(ulLength + ulExtraDataSize);
  874.     if (retVal != HXR_OK)
  875.     {
  876.         HX_RELEASE(pMimeType);
  877.         HX_RELEASE(pASMRuleBook);
  878.         HX_RELEASE(pOpaqueData);
  879.         HX_RELEASE(pStreamHeader);
  880.         HX_RELEASE(pIntrinsicDur);
  881.         return m_pFormatResponse->StreamHeaderReady(retVal, NULL);
  882.     }
  883.     // Fill in the non-image-data information
  884.     BYTE *pData = pOpaqueData->GetBuffer();
  885.     Pack8(pData,      m_ucTarget);
  886.     Pack8(pData,      m_ucURLType);
  887.     Pack32(pData,     m_ulSeekTime);
  888.     Pack8(pData,      (BYTE) ((m_ulBackgroundColor & 0x00FF0000) >> 16)); // R
  889.     Pack8(pData,      (BYTE) ((m_ulBackgroundColor & 0x0000FF00) >>  8)); // G
  890.     Pack8(pData,      (BYTE)  (m_ulBackgroundColor & 0x000000FF)       ); // B
  891.     Pack8(pData,      (BYTE) ((m_ulBackgroundColor & 0xFF000000) >> 24)); // A
  892.     CHXString cTmp;
  893.     if (m_pURL)
  894.     {
  895.         cTmp = *m_pURL;
  896.     }
  897.     PackString(pData, cTmp);
  898.     if (m_pGIFCodec && !m_bParseFailed)
  899.     {
  900.         // Get the opaque data
  901.         BOOL bFirstInImage = FALSE;
  902.         retVal = m_pGIFCodec->GetPacketBuffer(pData,
  903.                                               pOpaqueData->GetSize() - ulExtraDataSize,
  904.                                               bFirstInImage);
  905.         if (retVal != HXR_OK)
  906.         {
  907.             HX_RELEASE(pMimeType);
  908.             HX_RELEASE(pASMRuleBook);
  909.             HX_RELEASE(pOpaqueData);
  910.             HX_RELEASE(pStreamHeader);
  911.             HX_RELEASE(pIntrinsicDur);
  912.             return m_pFormatResponse->StreamHeaderReady(retVal, NULL);
  913.         }
  914.     }
  915.     // Set the opaque data buffer property
  916.     pStreamHeader->SetPropertyBuffer("OpaqueData", pOpaqueData);
  917.     // Set the new state
  918.     m_ulState = kStateStreamHeaderSent;
  919.     // Initialize the current image index
  920.     m_lCurImgIndex = -1;
  921.     if (m_pGIFCodec && !m_bParseFailed)
  922.     {
  923.         // Go ahead and collect all the packets and hold them. We do
  924.         // this since if we get a Seek(), we'll need to completely
  925.         // resend all the packets. Ugh.
  926.         retVal = MakeAllPackets();
  927.         if (retVal != HXR_OK)
  928.         {
  929.             HX_RELEASE(pMimeType);
  930.             HX_RELEASE(pASMRuleBook);
  931.             HX_RELEASE(pOpaqueData);
  932.             HX_RELEASE(pStreamHeader);
  933.             HX_RELEASE(pIntrinsicDur);
  934.             return m_pFormatResponse->StreamHeaderReady(retVal, NULL);
  935.         }
  936.     }
  937.     // Now we can tell the response interface that we're done
  938.     m_pFormatResponse->StreamHeaderReady(HXR_OK, pStreamHeader);
  939.     // Release our references
  940.     HX_RELEASE(pStreamHeader);
  941.     HX_RELEASE(pMimeType);
  942.     HX_RELEASE(pASMRuleBook);
  943.     HX_RELEASE(pOpaqueData);
  944.     HX_RELEASE(pIntrinsicDur);
  945.     return HXR_OK;
  946. }
  947. STDMETHODIMP CGIFFileFormat::GetPacket(UINT16 usStreamNum)
  948. {
  949. #ifdef XXXMEH_DEBUG_LOG
  950.     DEBUG_OUTF("pxgifff.log", (s, "0x%08x::GetPacket(%u)n", this, usStreamNum));
  951. #endif
  952.     HX_RESULT retVal = HXR_OK;
  953.     if (m_ulState == kStateStreamHeaderSent)
  954.     {
  955.         if (usStreamNum == 0)
  956.         {
  957.             // Have we sent all the packets?
  958.             if (m_ulCurrentPacketIndex < m_ulNumPackets && !m_bParseFailed)
  959.             {
  960.                 // Get the packet pointer
  961.                 IHXPacket* pPacket = m_ppPacket[m_ulCurrentPacketIndex];
  962.                 // Increment the packet index
  963.                 m_ulCurrentPacketIndex++;
  964.                 // Give the response interface the packet
  965.                 m_pFormatResponse->PacketReady(HXR_OK, pPacket);
  966.             }
  967.             else
  968.             {
  969.                 // Set the state
  970.                 m_ulState = kStateFinished;
  971.                 // Tell the response interface we're done
  972.                 m_pFormatResponse->StreamDone(0);
  973.             }
  974.         }
  975.         else
  976.         {
  977.             retVal = HXR_INVALID_PARAMETER;
  978.         }
  979.     }
  980.     else
  981.     {
  982.         retVal = HXR_UNEXPECTED;
  983.     }
  984.     return retVal;
  985. }
  986. STDMETHODIMP CGIFFileFormat::SeekDone(HX_RESULT status)
  987. {
  988.     return HXR_UNEXPECTED;
  989. }
  990. STDMETHODIMP CGIFFileFormat::Seek(UINT32 ulRequestedTime)
  991. {
  992.     HX_RESULT retVal = HXR_OK;
  993.     // XXXMEH - no matter WHEN we get a Seek(), we have to resend all the
  994.     // packets again, since they are all timestamp 0.
  995.     //
  996.     // So all we need to do is reset the current packet index to 0.
  997.     m_ulCurrentPacketIndex = 0;
  998.     // Set the state
  999.     m_ulState = kStateStreamHeaderSent;
  1000.     // Inform the response interface we're done
  1001.     m_pFormatResponse->SeekDone(HXR_OK);
  1002.     return retVal;
  1003. }
  1004. STDMETHODIMP CGIFFileFormat::Close()
  1005. {
  1006.     if (m_ppPacket && m_ulNumPackets)
  1007.     {
  1008.         for (UINT32 i = 0; i < m_ulNumPackets; i++)
  1009.         {
  1010.             HX_RELEASE(m_ppPacket[i]);
  1011.         }
  1012.         m_ulNumPackets = 0;
  1013.         HX_VECTOR_DELETE(m_ppPacket);
  1014.     }
  1015.     HX_RELEASE(m_pContext);
  1016.     HX_RELEASE(m_pFileObject);
  1017.     HX_RELEASE(m_pFileStat);
  1018.     HX_RELEASE(m_pFormatResponse);
  1019.     HX_RELEASE(m_pCommonClassFactory);
  1020.     HX_RELEASE(m_pError);
  1021.     HX_DELETE(m_pURL);
  1022.     HX_DELETE(m_pRequestURL);
  1023.     HX_RELEASE(m_pFileBuffer);
  1024.     HX_RELEASE(m_pFragFileBuffer);
  1025.     HX_DELETE(m_pGIFCodec);
  1026.     HX_VECTOR_DELETE(m_plImageStartTime);
  1027.     HX_RELEASE(m_pMediaRepeatStr);
  1028.     m_ulBitRate     = 0;
  1029.     m_ulPreroll     = 0;
  1030.     m_ulDuration    = 0;
  1031.     m_lCurrentTime  = 0;
  1032.     m_ulState       = kStateConstructed;
  1033.     m_ulFileSize    = 0;
  1034.     return HXR_OK;
  1035. }
  1036. STDMETHODIMP CGIFFileFormat::CloseDone(HX_RESULT status)
  1037. {
  1038.     return HXR_OK;
  1039. }
  1040. STDMETHODIMP CGIFFileFormat::WriteDone(HX_RESULT status)
  1041. {
  1042.     return HXR_UNEXPECTED;
  1043. }
  1044. void CGIFFileFormat::ReportError(UINT32 ulErrorID, const char* pszArg)
  1045. {
  1046.     // Try to get the string from the resource manager
  1047.     BYTE      ucSeverity = HXLOG_CRIT;
  1048.     HX_RESULT lRMACode   = HXR_FAIL;
  1049.     CHXString cErrStr;
  1050.     HX_RESULT retVal = GetResourceErrorString(ulErrorID, cErrStr);
  1051.     if (retVal != HXR_OK)
  1052.     {
  1053.         switch (ulErrorID)
  1054.         {
  1055.             case IDS_ERR_GIF_BADBITRATE:
  1056.                 cErrStr = ERRSTR_GIF_BADBITRATE;
  1057.                 break;
  1058.             case IDS_ERR_GIF_BADDURATION:
  1059.                 cErrStr = ERRSTR_GIF_BADDURATION;
  1060.                 break;
  1061.             case IDS_ERR_GIF_BADPREROLL:
  1062.                 cErrStr = ERRSTR_GIF_BADPREROLL;
  1063.                 break;
  1064.             case IDS_ERR_GIF_BADURL:
  1065.                 cErrStr = ERRSTR_GIF_BADURL;
  1066.                 break;
  1067.             case IDS_ERR_GIF_BADTARGET:
  1068.                 cErrStr = ERRSTR_GIF_BADTARGET;
  1069.                 break;
  1070.             case IDS_ERR_GIF_BADBGCOLOR:
  1071.                 cErrStr = ERRSTR_GIF_BADBGCOLOR;
  1072.                 break;
  1073.             case IDS_ERR_GIF_BADRELFLAG:
  1074.                 cErrStr = ERRSTR_GIF_BADRELFLAG;
  1075.                 break;
  1076.             case IDS_ERR_GIF_BITRATEZERO:
  1077.                 cErrStr = ERRSTR_GIF_BITRATEZERO;
  1078.                 break;
  1079.             case IDS_ERR_GIF_ILLEGALTARGET:
  1080.                 cErrStr = ERRSTR_GIF_ILLEGALTARGET;
  1081.                 break;
  1082.             case IDS_ERR_GIF_BADTIMEFORMAT:
  1083.                 cErrStr = ERRSTR_GIF_BADTIMEFORMAT;
  1084.                 break;
  1085.             case IDS_ERR_GIF_UNKPLAYERCOMMAND:
  1086.                 cErrStr = ERRSTR_GIF_UNKPLAYERCOMMAND;
  1087.                 break;
  1088.             case IDS_ERR_GIF_NOTARGETBROWSER:
  1089.                 cErrStr = ERRSTR_GIF_NOTARGETBROWSER;
  1090.                 break;
  1091.             case IDS_ERR_GIF_CORRUPTFILE:
  1092.                 cErrStr = ERRSTR_GIF_CORRUPTFILE;
  1093.                 break;
  1094.             default:
  1095.                 cErrStr = ERRSTR_GIF_GENERALERROR;
  1096.                 break;
  1097.         }
  1098.     }
  1099.     if (ulErrorID == IDS_ERR_GIF_CORRUPTFILE)
  1100.     {
  1101.         if (pszArg)
  1102.         {
  1103.             char* pszStr = new char [strlen((const char*) cErrStr) + strlen(pszArg) + 1];
  1104.             if (pszStr)
  1105.             {
  1106.                 sprintf(pszStr, (const char*) cErrStr, pszArg); /* Flawfinder: ignore */
  1107.                 cErrStr = pszStr;
  1108.             }
  1109.             HX_VECTOR_DELETE(pszStr);
  1110.             ucSeverity = HXLOG_DEBUG;
  1111.             lRMACode   = HXR_OK;
  1112.         }
  1113.     }
  1114.  
  1115.     if (m_pError)
  1116.     {
  1117.         m_pError->Report(ucSeverity, lRMACode, 0, (const char*) cErrStr,  NULL);
  1118.     }
  1119. }
  1120. HX_RESULT CGIFFileFormat::GetResourceErrorString(UINT32 ulErrorID, CHXString& rErrorStr)
  1121. {
  1122.     IHXExternalResourceManager* pResMgr = NULL;
  1123.     HX_RESULT retVal = m_pContext->QueryInterface(IID_IHXExternalResourceManager, (void**) &pResMgr);
  1124.     if (retVal != HXR_OK)
  1125.     {
  1126.         return retVal;
  1127.     }
  1128. IHXExternalResourceReader* pResRdr = NULL;
  1129.     retVal = pResMgr->CreateExternalResourceReader(CORE_RESOURCE_SHORT_NAME, pResRdr);
  1130.     if (retVal != HXR_OK)
  1131.     {
  1132.         HX_RELEASE(pResMgr);
  1133.         return retVal;
  1134.     }
  1135. #ifdef _WINDOWS
  1136.     char szDLLPath[1024]; /* Flawfinder: ignore */
  1137.     GetModuleFileName((HMODULE)g_hInstance, szDLLPath, sizeof(szDLLPath));
  1138.     pResRdr->SetDefaultResourceFile(szDLLPath);
  1139. #endif
  1140.     IHXXResource* pRes = pResRdr->GetResource(HX_RT_STRING, ulErrorID);
  1141.     if(!pRes)
  1142.     {
  1143.         HX_RELEASE(pResRdr);
  1144.         HX_RELEASE(pResMgr);
  1145.         return HXR_FAIL;
  1146.     }
  1147.     // Assign the error string to the out parameter
  1148.     rErrorStr = (const char*) pRes->ResourceData();
  1149.     // Release all references
  1150.     HX_RELEASE(pRes);
  1151.     HX_RELEASE(pResRdr);
  1152.     HX_RELEASE(pResMgr);
  1153.     return HXR_OK;
  1154. }
  1155. HX_RESULT CGIFFileFormat::ParseFile()
  1156. {
  1157.     HX_RESULT retVal = HXR_OK;
  1158.     if (m_pFileObject && m_pFragFileBuffer)
  1159.     {
  1160.         // We don't need the file object anymore
  1161.         HX_RELEASE(m_pFileObject);
  1162.         // We need to get an IHXBuffer interface from the IHXFragmentedBuffer
  1163.         HX_RELEASE(m_pFileBuffer);
  1164.         retVal = m_pFragFileBuffer->QueryInterface(IID_IHXBuffer,
  1165.                                                    (void**) &m_pFileBuffer);
  1166.         if (SUCCEEDED(retVal))
  1167.         {
  1168.             // Get the buffer (this causes the initial gather)
  1169.             BYTE* pBuf = m_pFileBuffer->GetBuffer();
  1170.             if (pBuf)
  1171.             {
  1172.                 // Get the size
  1173.                 UINT32 ulBufSize = m_pFileBuffer->GetSize();
  1174.                 // Now we allocate a CGIFCodec
  1175.                 HX_DELETE(m_pGIFCodec);
  1176.                 m_pGIFCodec = new CGIFCodec();
  1177.                 if (m_pGIFCodec)
  1178.                 {
  1179.                     // Initialize the wire format - this verifies this is a GIF
  1180.                     // and sets up for parsing
  1181.                     retVal = m_pGIFCodec->InitParseWireFormat(pBuf, ulBufSize);
  1182.                 }
  1183.                 else
  1184.                 {
  1185.                     retVal = HXR_OUTOFMEMORY;
  1186.                 }
  1187.             }
  1188.             else
  1189.             {
  1190.                 retVal = HXR_FAIL;
  1191.             }
  1192.         }
  1193.         HX_RELEASE(m_pFragFileBuffer);
  1194.     }
  1195.     else
  1196.     {
  1197.         retVal = HXR_UNEXPECTED;
  1198.     }
  1199.     return retVal;
  1200. }
  1201. HX_RESULT CGIFFileFormat::MakeAllPackets()
  1202. {
  1203.     HX_RESULT retVal = HXR_OK;
  1204.     // We don't know how many packets we'll have up front, so we'll put
  1205.     // them on a list and move them to an array when we're done.
  1206.     CHXSimpleList* pList = new CHXSimpleList();
  1207.     if (pList)
  1208.     {
  1209.         // Loop through the packets
  1210.         while (SUCCEEDED(retVal) && !m_pGIFCodec->ParseFinished())
  1211.         {
  1212.             // Ask the CGIF Codec for the next size
  1213.             UINT32 ulLength = 0;
  1214.             retVal          = m_pGIFCodec->GetPacketBufferLength(ulLength);
  1215.             if (SUCCEEDED(retVal))
  1216.             {
  1217.                 // Create buffer to hold the packet
  1218.                 IHXBuffer* pBuffer = NULL;
  1219.                 retVal              = m_pCommonClassFactory->CreateInstance(CLSID_IHXBuffer,
  1220.                                                                             (void**) &pBuffer);
  1221.                 if (SUCCEEDED(retVal))
  1222.                 {
  1223.                     // Set the size of the IHXBuffer
  1224.                     retVal = pBuffer->SetSize(ulLength + 4); // Extra 4 is for flags
  1225.                     if (SUCCEEDED(retVal))
  1226.                     {
  1227.                         // Get the packet from the CGIFCodec
  1228.                         BOOL bFirstInImage = FALSE;
  1229.                         retVal = m_pGIFCodec->GetPacketBuffer(pBuffer->GetBuffer() + 4,
  1230.                                                               pBuffer->GetSize()   - 4,
  1231.                                                               bFirstInImage);
  1232.                         if (SUCCEEDED(retVal))
  1233.                         {
  1234.                             // If this is a new image (and not the very first image), then update
  1235.                             // the current image index and the start time
  1236.                             if (bFirstInImage)
  1237.                             {
  1238.                                 m_lCurImgIndex++;
  1239.                                 if (m_lCurImgIndex >= 0 && m_lCurImgIndex < (INT32) m_pGIFCodec->GetNumImages())
  1240.                                 {
  1241.                                     m_lCurrentTime = m_plImageStartTime[m_lCurImgIndex];
  1242.                                 }
  1243.                                 else
  1244.                                 {
  1245.                                     retVal = HXR_UNEXPECTED;
  1246.                                 }
  1247.                             }
  1248.                             if (SUCCEEDED(retVal))
  1249.                             {
  1250.                                 // Set the flags
  1251.                                 UINT32 ulFlags = 0;
  1252.                                 if (bFirstInImage)
  1253.                                 {
  1254.                                     ulFlags |= 0x01;
  1255.                                 }
  1256.                                 // Put the flags into the packet
  1257.                                 BYTE *pBuf = pBuffer->GetBuffer();
  1258.                                 Pack32(pBuf, ulFlags);
  1259.                                 // Create an IHXPacket
  1260.                                 IHXPacket* pPacket = NULL;
  1261.                                 retVal              = m_pCommonClassFactory->CreateInstance(CLSID_IHXPacket,
  1262.                                                                                             (void**) &pPacket);
  1263.                                 if (SUCCEEDED(retVal))
  1264.                                 {
  1265.                                     INT32 lTimeStamp = m_lCurrentTime;
  1266.                                     if (lTimeStamp < 0)
  1267.                                     {
  1268.                                         lTimeStamp = 0;
  1269.                                     }
  1270.                                     // Fill in the Packet with the relevant data
  1271.                                     // XXX-MEH
  1272.                                     // This is a result of a client core bug which causes
  1273.                                     // the core not to deliver timestamps which are past the duration
  1274.                                     // of the stream. Specifically, it's causing animated GIFs whose
  1275.                                     // duration is set artificially low not to receive all their
  1276.                                     // packets. As a workaround, we set all GIF packet timestamps to 0.
  1277.                                     retVal = pPacket->Set(pBuffer,           // the actual data from the file
  1278.                                                           0,                 // timestamp
  1279.                                                           0,                 // our stream number (always 0)
  1280.                                                           HX_ASM_SWITCH_ON, // yes, we are using ASM (sort of)
  1281.                                                           0);                // always rule 0
  1282.                                     if (SUCCEEDED(retVal))
  1283.                                     {
  1284.                                         // Update the current timestamp
  1285.                                         m_lCurrentTime += ((pBuffer->GetSize() + 24) * 8000 / m_ulBitRate) + 1;
  1286.                                         // AddRef the packet before putting it on the list
  1287.                                         pPacket->AddRef();
  1288.                                         // Put this packet onto the tail of the list
  1289.                                         pList->AddTail((void*) pPacket);
  1290.                                     }
  1291.                                 }
  1292.                                 HX_RELEASE(pPacket);
  1293.                             }
  1294.                         }
  1295.                     }
  1296.                 }
  1297.                 HX_RELEASE(pBuffer);
  1298.             }
  1299.         }
  1300.     }
  1301.     else
  1302.     {
  1303.         retVal = HXR_OUTOFMEMORY;
  1304.     }
  1305.     // Terminate the parsing
  1306.     m_pGIFCodec->TermParse();
  1307.     // Now we can release the GIF codec
  1308.     HX_DELETE(m_pGIFCodec);
  1309.     // Release the file buffer
  1310.     HX_RELEASE(m_pFileBuffer);
  1311.     if (SUCCEEDED(retVal))
  1312.     {
  1313.         // Clear out any existing packets
  1314.         if (m_ppPacket && m_ulNumPackets)
  1315.         {
  1316.             for (UINT32 i = 0; i < m_ulNumPackets; i++)
  1317.             {
  1318.                 HX_RELEASE(m_ppPacket[i]);
  1319.             }
  1320.             m_ulNumPackets = 0;
  1321.             HX_VECTOR_DELETE(m_ppPacket);
  1322.         }
  1323.         // Allocate the array
  1324.         m_ulNumPackets = pList->GetCount();
  1325.         m_ppPacket     = new IHXPacket* [m_ulNumPackets];
  1326.         if (m_ppPacket)
  1327.         {
  1328.             // Run through the list, transferring packet pointers to the array
  1329.             UINT32       i   = 0;
  1330.             LISTPOSITION pos = pList->GetHeadPosition();
  1331.             while (pos)
  1332.             {
  1333.                 // No need to AddRef()/Release() since we know there's only one ref
  1334.                 IHXPacket* pPacket = (IHXPacket*) pList->GetNext(pos);
  1335.                 m_ppPacket[i++]     = pPacket;
  1336.             }
  1337.             // Now we can clear out the list
  1338.             pList->RemoveAll();
  1339.             // Reset the current packet index
  1340.             m_ulCurrentPacketIndex = 0;
  1341.         }
  1342.         else
  1343.         {
  1344.             retVal = HXR_OUTOFMEMORY;
  1345.         }
  1346.     }
  1347.     // Now we can delete the list
  1348.     HX_DELETE(pList);
  1349.     return retVal;
  1350. }
  1351. /************************************************************************
  1352.  * Method:
  1353.  *     IHXThreadSafeMethods::IsThreadSafe
  1354.  */
  1355. STDMETHODIMP_(UINT32)
  1356. CGIFFileFormat::IsThreadSafe()
  1357. {
  1358.     return HX_THREADSAFE_METHOD_FF_GETPACKET |
  1359. HX_THREADSAFE_METHOD_FSR_READDONE;
  1360. }
  1361. HX_RESULT STDAPICALLTYPE CGIFFileFormat::HXCreateInstance(IUnknown** ppIUnknown)
  1362. {
  1363.     HX_RESULT retVal = HXR_OK;
  1364.     if (ppIUnknown)
  1365.     {
  1366.         // Set default
  1367.         *ppIUnknown = NULL;
  1368.         // Create the object
  1369.         CGIFFileFormat* pObj = new CGIFFileFormat();
  1370.         if (pObj)
  1371.         {
  1372.             // QI for IUnknown
  1373.             retVal = pObj->QueryInterface(IID_IUnknown, (void**) ppIUnknown);
  1374.         }
  1375.         else
  1376.         {
  1377.             retVal = HXR_OUTOFMEMORY;
  1378.         }
  1379.         if (FAILED(retVal))
  1380.         {
  1381.             HX_DELETE(pObj);
  1382.         }
  1383.     }
  1384.     else
  1385.     {
  1386.         retVal = HXR_FAIL;
  1387.     }
  1388.     return HXR_OK;
  1389. }