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

Symbian

开发平台:

Visual C++

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