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

Symbian

开发平台:

Visual C++

  1. /* ***** BEGIN LICENSE BLOCK *****
  2.  * Source last modified: $Id: smlffpln.cpp,v 1.3.8.1 2004/07/09 01:57:20 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. #define INITGUID
  50. #include <string.h>
  51. #include <ctype.h>
  52. #include <time.h>
  53. #include "smlffpln.ver"
  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 "hxengin.h"
  61. #include "hxplugn.h"
  62. #include "hxpends.h"
  63. #include "hxasm.h"
  64. #include "hxprefs.h"
  65. #include "hxvsrc.h"  /*IHXFileViewSource*/
  66. #include "chxfgbuf.h" /*CHXFragmentedBuffer */
  67. #include "hxmon.h"
  68. #include "hxerror.h"
  69. #include "hxstack.h"
  70. #include "hxslist.h"
  71. #include "hxstring.h"
  72. #include "chxpckts.h"
  73. #include "hxurl.h"
  74. #include "hxver.h"
  75. #include "verutil.h"
  76. #include "perplex.h"
  77. #include "xmlreslt.h"
  78. #include "smlpkt.h"
  79. #include "smlffpln.h"
  80. #if defined(HELIX_FEATURE_VIEWSOURCE)
  81. #include "escsmil.h" /* CEscapeSMIL */
  82. #include "shadvsrc.h" /* CShadowViewSource */
  83. #endif /* #if defined(HELIX_FEATURE_VIEWSOURCE) */
  84. #include "hxheap.h"
  85. #ifdef _DEBUG
  86. #undef HX_THIS_FILE
  87. static const char HX_THIS_FILE[] = __FILE__;
  88. #endif
  89. #ifdef _AIX
  90. #include "dllpath.h"
  91. ENABLE_MULTILOAD_DLLACCESS_PATHS(Smlffplin);
  92. #endif
  93. //#define DUMPFILEFORMATOUTPUT 1
  94. static const UINT32 FileChunkSize = 10000; //XXXBAB adjust
  95. static const UINT32 MaxPacketSize = 1000;
  96. #define XML_BAD_ATTRIBUTE_NAME "SMIL Parse Error: Error in attribute name"
  97. #define XML_BAD_TAG_NAME "SMIL Parse Error: Bad Tag Name"
  98. #define XML_MISSING_ATTRIBUTE_VALUE "SMIL Parse Error: Attribute value is missing"
  99. #define XML_NO_CLOSE_QUOTE "SMIL Parse Error: No closing quote"
  100. #define XML_MISSING_SPACE "SMIL Parse Error: Missing space"
  101. /****************************************************************************
  102.  * 
  103.  *  Function:
  104.  * 
  105.  * HXCreateInstance()
  106.  * 
  107.  *  Purpose:
  108.  * 
  109.  * Function implemented by all plugin DLL's to create an instance of 
  110.  * any of the objects supported by the DLL. This method is similar to 
  111.  * Window's CoCreateInstance() in its purpose, except that it only 
  112.  * creates objects from this plugin DLL.
  113.  *
  114.  * NOTE: Aggregation is never used. Therefore and outer unknown is
  115.  * not passed to this function, and you do not need to code for this
  116.  * situation.
  117.  * 
  118.  */
  119. STDAPI ENTRYPOINT(HXCreateInstance)
  120. (
  121.     IUnknown**  /*OUT*/ ppIUnknown
  122. )
  123. {
  124.     *ppIUnknown = (IUnknown*)(IHXPlugin*)new CSmilFileFormat();
  125.     if (*ppIUnknown)
  126.     {
  127. (*ppIUnknown)->AddRef();
  128. return HXR_OK;
  129.     }
  130.     return HXR_OUTOFMEMORY;
  131. }
  132. /****************************************************************************
  133.  * 
  134.  *  Function:
  135.  * 
  136.  * CanUnload2()
  137.  * 
  138.  *  Purpose:
  139.  * 
  140.  * Function implemented by all plugin DLL's if it returns HXR_OK 
  141.  * then the pluginhandler can unload the DLL
  142.  *
  143.  */
  144. STDAPI ENTRYPOINT(CanUnload2)(void)
  145. {
  146.     return (CHXBaseCountingObject::ObjectsActive() > 0 ? HXR_FAIL : HXR_OK );
  147. }
  148. const char* const CSmilFileFormat::zm_pDescription    = "RealNetworks SMIL File Format Plugin";
  149. const char* const CSmilFileFormat::zm_pCopyright      = HXVER_COPYRIGHT;
  150. const char* const CSmilFileFormat::zm_pMoreInfoURL    = HXVER_MOREINFO;
  151. const char* const CSmilFileFormat::zm_pFileMimeTypes[]  = {"application/smil", NULL};
  152. // /NOTE: here's what's sent as stream mime types; if there is no default
  153. // namespace, then the file is treated as a SMIL 1.0 document and sent to
  154. // our old renderer.   If the default namespace is unrecognized, then we
  155. // send "application/smil" and let the 2.0 or later SMIL renderer parse the
  156. // namespace in the smil file data and, if it recognizes it (e.g., the SMIL
  157. // renderer is a SMIL 3.0 renderer and the namespace is SMIL 3.0 but this
  158. // file format is of the SMIL 2.0 timeframe), then it plays it.  If the
  159. // renderer doesn't recognize the namespace, it tries to auto upgrade with
  160. // the following as the AU mime-type request: "application/smil.[namespace]"
  161. // and the AU server then looks for a component (maybe not even an RN one)
  162. // that can handle this type of SMIL file.
  163. const char* const CSmilFileFormat::zm_pStreamMimeTypes[]  =  {
  164. // /The following are SMIL 1.0 stream mime types that will be handled
  165. // by SMIL 1.0-exclusive players (e.g., RealPlayer 8):
  166. "application/rma-driver", // /Beta-1, SMIL 1.0 stream
  167. "application/vnd.rn-rmadriver", // /SMIL 1.0 strm (no dflt namespace)
  168. // /The following is SMIL 1.0 Rec default namespace:
  169. // "http://www.w3.org/TR/REC-smil"
  170. "application/smil",
  171. // /The following is SMIL 2.0 Candidate Rec (i.e., pre SMIL 2.0 W3C Rec
  172. // status) default namespace:
  173. // "http://www.w3.org/2000/SMIL20/CR/Language"
  174. // The following is SMIL 2.0 Proposed Rec default namespace:
  175. // "http://www.w3.org/2001/SMIL20/PR/Language"
  176. // Both CR and PR use this stream mime type:
  177. "application/smil",
  178. // /The following is the SMIL 2.0 Recommendation namespace
  179. // "http://www.w3.org/2001/SMIL20/Language",
  180. "application/smil",
  181. // /We'll use this for any unrecognized SMIL file version (and note:
  182. // this is probably going to always be the same as the SMIL20 mime
  183. // type; the renderer will do all the work of deciding whether or not
  184. // to auto upgrade if it doesn't recognize the default namespace):
  185. "application/smil",
  186. NULL};
  187. const char* const CSmilFileFormat::zm_pFileExtensions[] = {"smi", "smil", NULL};
  188. const char* const CSmilFileFormat::zm_pFileOpenNames[]  = {"SMIL File Format (*.smi,*.smil)", NULL};
  189. CSmilFileFormat::CSmilFileFormat()
  190.     : m_lRefCount(0)
  191.     , m_pContext(0)
  192.     , m_pFileObject(0)
  193.     , m_pFFResponse(0)
  194.     , m_bHeaderSent(FALSE)
  195.     , m_bChannelInit(FALSE)
  196.     , m_bSentFirstChannel(FALSE)
  197.     , m_bSourceInit(FALSE)
  198.     , m_ulCurrentTime(0)
  199.     , m_state(Ready)
  200.     , m_pRequest(0)
  201.     , m_pCommonClassFactory(0)
  202.     , m_ulPacketCount(0)
  203.     , m_ulCurrentPacket(0)
  204.     , m_ulStreamVersion(0)
  205.     , m_ulContentVersion(0)
  206.     , m_pCurrentPacketData(NULL)
  207.     , m_fileState(InContent)
  208.     , m_smilFileVersion(SMILFileVersionSmil10)
  209.     , m_pArrayOfPackets(0)
  210.     , m_bLogErrors(FALSE)
  211.     , m_pStartOfFile(NULL)
  212. {
  213. };
  214. CSmilFileFormat::~CSmilFileFormat()
  215. {
  216.     Close();
  217. }
  218. /************************************************************************
  219.  *  Method:
  220.  *    IHXPlugin::InitPlugin
  221.  *  Purpose:
  222.  *    Initializes the plugin for use. This interface must always be
  223.  *    called before any other method is called. This is primarily needed 
  224.  *    so that the plugin can have access to the context for creation of
  225.  *    IHXBuffers and IMalloc.
  226.  */
  227. STDMETHODIMP CSmilFileFormat::InitPlugin(IUnknown* /*IN*/ pContext)
  228. {
  229.     m_pContext = pContext;
  230.     m_pContext->AddRef();
  231.     m_pContext->QueryInterface(IID_IHXCommonClassFactory,
  232.      (void**)&m_pCommonClassFactory);
  233.     return HXR_OK;
  234. }
  235. /************************************************************************
  236.  *  Method:
  237.  *    IHXPlugin::GetPluginInfo
  238.  *  Purpose:
  239.  *    Returns the basic information about this plugin. Including:
  240.  *
  241.  *    bLoadMultiple whether or not this plugin DLL can be loaded
  242.  * multiple times. All File Formats must set
  243.  * this value to TRUE.
  244.  *    pDescription which is used in about UIs (can be NULL)
  245.  *    pCopyright which is used in about UIs (can be NULL)
  246.  *    pMoreInfoURL which is used in about UIs (can be NULL)
  247.  */
  248. STDMETHODIMP CSmilFileFormat::GetPluginInfo
  249. (
  250.     REF(BOOL)     /*OUT*/ bLoadMultiple,
  251.     REF(const char*)/*OUT*/ pDescription,
  252.     REF(const char*)/*OUT*/ pCopyright,
  253.     REF(const char*)/*OUT*/ pMoreInfoURL,
  254.     REF(ULONG32)    /*OUT*/ ulVersionNumber
  255. )
  256. {
  257.     bLoadMultiple = TRUE;   // Must be true for file formats.
  258.     pDescription    = (const char*) zm_pDescription;
  259.     pCopyright     = (const char*) zm_pCopyright;
  260.     pMoreInfoURL    = (const char*) zm_pMoreInfoURL;
  261.     ulVersionNumber = TARVER_ULONG32_VERSION;
  262.     return HXR_OK;
  263. }
  264. /************************************************************************
  265.  *  Method:
  266.  *    IHXPlugin::GetObjFileFormatInfo
  267.  *  Purpose:
  268.  *    If this object is a file format object this method returns
  269.  *    information vital to the instantiation of file format plugins.
  270.  *    If this object is not a file format object, it should return
  271.  *    HXR_UNEXPECTED.
  272.  */
  273. STDMETHODIMP CSmilFileFormat::GetFileFormatInfo
  274. (
  275.     REF(const char**) /*OUT*/ pFileMimeTypes,
  276.     REF(const char**) /*OUT*/ pFileExtensions,
  277.     REF(const char**) /*OUT*/ pFileOpenNames
  278. )
  279. {
  280.     pFileMimeTypes  = (const char**) zm_pFileMimeTypes;
  281.     pFileExtensions = (const char**) zm_pFileExtensions;
  282.     pFileOpenNames  = (const char**) zm_pFileOpenNames;
  283.     return HXR_OK;
  284. }
  285. // *** IUnknown methods ***
  286. /////////////////////////////////////////////////////////////////////////
  287. //  Method:
  288. // IUnknown::QueryInterface
  289. //  Purpose:
  290. // Implement this to export the interfaces supported by your 
  291. // object.
  292. //
  293. STDMETHODIMP CSmilFileFormat::QueryInterface(REFIID riid, void** ppvObj)
  294. {
  295.     if (IsEqualIID(riid, IID_IUnknown))
  296.     {
  297. AddRef();
  298. *ppvObj = this;
  299. return HXR_OK;
  300.     }
  301.     else if (IsEqualIID(riid, IID_IHXPlugin))
  302.     {
  303. AddRef();
  304. *ppvObj = (IHXPlugin*)this;
  305. return HXR_OK;
  306.     }
  307.     else if (IsEqualIID(riid, IID_IHXFileFormatObject))
  308.     {
  309. AddRef();
  310. *ppvObj = (IHXFileFormatObject*)this;
  311. return HXR_OK;
  312.     }
  313.     else if (IsEqualIID(riid, IID_IHXFileResponse))
  314.     {
  315. AddRef();
  316. *ppvObj = (IHXFileResponse*)this;
  317. return HXR_OK;
  318.     }
  319.     else if (IsEqualIID(riid, IID_IHXPendingStatus))
  320.     {
  321. AddRef();
  322. *ppvObj = (IHXPendingStatus*)this;
  323. return HXR_OK;
  324.     }
  325.     else if (IsEqualIID(riid, IID_IHXInterruptSafe))
  326.     {
  327. AddRef();
  328. *ppvObj = (IHXInterruptSafe*)this;
  329. return HXR_OK;
  330.     }
  331.     else if (IsEqualIID(riid, IID_IHXThreadSafeMethods))
  332.     {
  333. AddRef();
  334. *ppvObj = (IHXThreadSafeMethods*)this;
  335. return HXR_OK;
  336.     }
  337. #if defined(HELIX_FEATURE_VIEWSOURCE)
  338.     else if ( IsEqualIID(riid, IID_IHXFileViewSource) )
  339.     {
  340. CShadowViewSource* pVsrc = new CShadowViewSource(m_pContext, 
  341.     (IUnknown*)(IHXPlugin*)this);
  342. if ( pVsrc == NULL )
  343. {
  344.     return HXR_FAIL;
  345. }
  346. return pVsrc->QueryInterface(riid, ppvObj);
  347.     }
  348. #endif /* #if defined(HELIX_FEATURE_VIEWSOURCE) */
  349.     *ppvObj = NULL;
  350.     return HXR_NOINTERFACE;
  351. }
  352. /////////////////////////////////////////////////////////////////////////
  353. //  Method:
  354. // IUnknown::AddRef
  355. //  Purpose:
  356. // Everyone usually implements this the same... feel free to use
  357. // this implementation.
  358. //
  359. STDMETHODIMP_(ULONG32) CSmilFileFormat::AddRef()
  360. {
  361.     return InterlockedIncrement(&m_lRefCount);
  362. }
  363. /////////////////////////////////////////////////////////////////////////
  364. //  Method:
  365. // IUnknown::Release
  366. //  Purpose:
  367. // Everyone usually implements this the same... feel free to use
  368. // this implementation.
  369. //
  370. STDMETHODIMP_(ULONG32) CSmilFileFormat::Release()
  371. {
  372.     if (InterlockedDecrement(&m_lRefCount) > 0)
  373.     {
  374.         return m_lRefCount;
  375.     }
  376.     delete this;
  377.     return 0;
  378. }
  379. // *** IHXFileFormatObject methods ***
  380. STDMETHODIMP CSmilFileFormat::InitFileFormat
  381. (
  382.     IHXRequest* /*IN*/ pRequest, 
  383.     IHXFormatResponse* /*IN*/ pFormatResponse,
  384.     IHXFileObject* /*IN*/  pFileObject
  385. )
  386. {
  387.     HX_RESULT ret = HXR_OK;
  388.     m_pRequest    = pRequest;
  389.     m_pFFResponse = pFormatResponse;
  390.     m_pFileObject = pFileObject;
  391.     m_pRequest->AddRef();
  392.     m_pFFResponse->AddRef();
  393.     m_pFileObject->AddRef();
  394.     // set stream and content versions
  395.     m_ulStreamVersion = HX_ENCODE_PROD_VERSION(STREAM_MAJOR_VER,
  396.        STREAM_MINOR_VER,
  397.        STREAM_RELEASE,
  398.        STREAM_BUILD);
  399.     m_ulContentVersion = HX_ENCODE_PROD_VERSION(CONTENT_MAJOR_VER,
  400. CONTENT_MINOR_VER,
  401. CONTENT_RELEASE,
  402. CONTENT_BUILD);
  403.     
  404.     if ( m_pArrayOfPackets )
  405.     {
  406. int s = m_pArrayOfPackets->GetSize();
  407. for ( int i = s; i > 0; --i )
  408. {
  409.     PacketData* pckt = (PacketData*)(*m_pArrayOfPackets)[i-1];
  410.     HX_RELEASE(pckt->pBuffer);
  411.     HX_DELETE(pckt);
  412.     (*m_pArrayOfPackets)[i-1] = NULL;
  413. }
  414. HX_DELETE(m_pArrayOfPackets);
  415.     }
  416.     m_pArrayOfPackets = new CHXPtrArray;
  417.     if ( m_pCurrentPacketData )
  418.     {
  419. HX_RELEASE(m_pCurrentPacketData->pBuffer);
  420. HX_DELETE(m_pCurrentPacketData);
  421.     }
  422.     m_ulCurrentBufferPos = 0;
  423.     m_ulCurrentPacket = 0;
  424.     // This file format is not a container type, so it only supports one
  425.     // stream and therefore one header, but before we do that, we want to
  426.     // make sure the file object is initialized; we can't actually return
  427.     // the header count until the file init is done... (See InitDone).
  428.     m_state = InitPending;
  429.     // Note, we need to pass ourself to the FileObject, because this is its
  430.     // first opportunity to know that we implement the IHXFileResponse
  431.     // interface it will call for completed pending operations
  432.     return m_pFileObject->Init( HX_FILE_READ, this);
  433. }
  434. STDMETHODIMP CSmilFileFormat::Close()
  435. {
  436.     HX_RELEASE(m_pContext);
  437.     if (m_pFileObject)
  438.     {
  439. m_pFileObject->Close();
  440. HX_RELEASE(m_pFileObject);
  441.     }
  442.     if ( m_pArrayOfPackets )
  443.     {
  444. int s = m_pArrayOfPackets->GetSize();
  445. for ( int i = s; i > 0; --i )
  446. {
  447.     PacketData* pckt = (PacketData*)(*m_pArrayOfPackets)[i-1];
  448.     HX_RELEASE(pckt->pBuffer);
  449.     HX_DELETE(pckt);
  450.     (*m_pArrayOfPackets)[i-1] = NULL;
  451.     m_pArrayOfPackets->RemoveAt(i-1);
  452. }
  453. HX_DELETE(m_pArrayOfPackets);
  454.     }
  455.     if ( m_pCurrentPacketData )
  456.     {
  457. HX_RELEASE(m_pCurrentPacketData->pBuffer);
  458. m_pCurrentPacketData->pNumPos = NULL;
  459. HX_DELETE(m_pCurrentPacketData);
  460.     }
  461.     HX_RELEASE(m_pFFResponse);
  462.     HX_RELEASE(m_pRequest);
  463.     HX_RELEASE(m_pCommonClassFactory);
  464.     HX_RELEASE(m_pStartOfFile);
  465.     return HXR_OK;
  466. }
  467. /////////////////////////////////////////////////////////////////////////
  468. //  Method:
  469. // IHXFileFormatObject::GetFileHeader
  470. //  Purpose:
  471. // Called by controller to ask the file format for the number of
  472. // headers in the file. The file format should call the 
  473. // IHXFileFormatSession::HeaderCountReady() for the IHXFileFormat-
  474. // Session object that was passed in during initialization, when the
  475. // header count is available.
  476. //
  477. STDMETHODIMP CSmilFileFormat::GetFileHeader()
  478. {
  479.     // If we are not ready then something has gone wrong
  480.     if (m_state != Ready) return HXR_UNEXPECTED;
  481.     IHXValues* pHeader = 0;
  482.     if (HXR_OK != m_pCommonClassFactory->CreateInstance(CLSID_IHXValues,
  483.     (void**)&pHeader))
  484.     {
  485. return HXR_UNEXPECTED;
  486.     }
  487.     pHeader->SetPropertyULONG32("StreamCount", 1);
  488.     m_pFFResponse->FileHeaderReady(HXR_OK, pHeader);
  489.     HX_RELEASE(pHeader);
  490.     return HXR_OK;
  491. }
  492. /////////////////////////////////////////////////////////////////////////
  493. //  Method:
  494. // IHXFileFormatObject::GetStreamHeader
  495. //  Purpose:
  496. // Called by controller to ask the file format for the header for
  497. // a particular stream in the file. The file format should call 
  498. // IHXFileFormatSession::StreamHeaderReady() for IHXFileFormatSession
  499. // object that was passed in during initialization, when the header
  500. // is available.
  501. //
  502. STDMETHODIMP CSmilFileFormat::GetStreamHeader(UINT16 unStreamNumber)
  503. {
  504.     // If we are not ready then something has gone wrong
  505.     if (m_state != Ready) return HXR_UNEXPECTED;
  506.     IHXBuffer* pASM = 0;
  507.     char pBook[256]; /* Flawfinder: ignore */
  508.     IHXValues* pHeader = 0;
  509.     IHXBuffer* pBuffer = 0;
  510.     if (HXR_OK != m_pCommonClassFactory->CreateInstance(CLSID_IHXValues,
  511.     (void**)&pHeader))
  512.     {
  513. return HXR_UNEXPECTED;
  514.     }
  515.     if (HXR_OK != m_pCommonClassFactory->CreateInstance(CLSID_IHXBuffer,
  516.     (void**)&pBuffer))
  517.     {
  518. return HXR_UNEXPECTED;
  519.     }
  520.     BOOL bBeta1Player = ::IsBeta1Player(m_pRequest);
  521.     HX_RESULT pnrver = GetSMILFileVersion();
  522.     if (HXR_OK != pnrver  ||
  523. SMILFileVersionSmil10 == m_smilFileVersion)
  524.     {
  525. if(bBeta1Player)
  526. {
  527.     pBuffer->Set((const BYTE*)
  528.    zm_pStreamMimeTypes[SMILFileVersionSmilBeta10],
  529.    strlen(zm_pStreamMimeTypes[SMILFileVersionSmilBeta10])+1);
  530. }
  531. else
  532. {
  533.     pBuffer->Set(
  534.    (const BYTE*)zm_pStreamMimeTypes[SMILFileVersionSmil10],
  535.    strlen(zm_pStreamMimeTypes[SMILFileVersionSmil10])+1);
  536. }
  537.     }
  538.     else if (SMILFileVersionSmil10Strict == m_smilFileVersion)
  539.     {
  540. // /Send strictly-declared SMIL 1.0 streams to the SMIL 2.0 renderer
  541. pBuffer->Set((const BYTE*)
  542.        zm_pStreamMimeTypes[SMILFileVersionSmil10Strict],
  543.        strlen(zm_pStreamMimeTypes[SMILFileVersionSmil10Strict])+1);
  544.     }
  545.     else if (SMILFileVersionSmil20PreRec == m_smilFileVersion)
  546.     {
  547. pBuffer->Set((const BYTE*)
  548.        zm_pStreamMimeTypes[SMILFileVersionSmil20PreRec],
  549.        strlen(zm_pStreamMimeTypes[SMILFileVersionSmil20PreRec])+1);
  550.     }
  551.     else if (SMILFileVersionSmil20 == m_smilFileVersion)
  552.     {
  553. pBuffer->Set((const BYTE*)
  554. zm_pStreamMimeTypes[SMILFileVersionSmil20],
  555. strlen(zm_pStreamMimeTypes[SMILFileVersionSmil20])+1);
  556.     }
  557.     else // /Too high a version number as far as this ff is concerned:
  558.     // /XXXEH: should we use the namespace (if there is one) to determine
  559.     // the mime type and, if there is one, send it and let the player deal
  560.     // with the auto update (if needed)?  Or, should we encourage server
  561.     // (hence smil ff) updating by just not serving the stream?  That's
  562.     // what I'm doing here:
  563.     {
  564. pBuffer->Set((const BYTE*)
  565. zm_pStreamMimeTypes[SMILFileVersionUnknown],
  566. strlen(zm_pStreamMimeTypes[SMILFileVersionUnknown])+1);
  567.     }
  568.     pHeader->SetPropertyCString("MimeType", pBuffer);
  569.     HX_RELEASE(pBuffer);
  570.     pHeader->SetPropertyULONG32("StreamNumber", unStreamNumber);
  571.     //XXXEH- removed 20000 (20sec) duration that BAB put in "to avoid problem
  572.     // in core" in 1998(?).  0 milliseconds seems to work fine now (3/2000):
  573.     pHeader->SetPropertyULONG32("Duration", 0);
  574.     pHeader->SetPropertyULONG32("PreRoll", 1000);   //XXXBAB 'cause Rahul told me to
  575.     pHeader->SetPropertyULONG32("AvgBitRate", 1000);
  576.     pHeader->SetPropertyULONG32("StreamVersion", m_ulStreamVersion);
  577.     pHeader->SetPropertyULONG32("ContentVersion", m_ulContentVersion);
  578.     //
  579.     // set ASM rule book
  580.     //
  581.     sprintf(pBook, "TimestampDelivery=TRUE,priority=10;"); /* Flawfinder: ignore */
  582.     if(HXR_OK == m_pCommonClassFactory->CreateInstance(CLSID_IHXBuffer,
  583.     (void**)&pASM))
  584.     {
  585. pASM->Set((BYTE*)pBook, strlen(pBook)+1);
  586. pHeader->SetPropertyCString("ASMRuleBook", pASM);
  587. HX_RELEASE(pASM);
  588.     }
  589.     m_bHeaderSent = TRUE;
  590.     m_pFFResponse->StreamHeaderReady(HXR_OK, pHeader);
  591.     HX_RELEASE(pHeader);
  592.     return HXR_OK;
  593. }
  594. /////////////////////////////////////////////////////////////////////////
  595. //  Method:
  596. // IHXFileFormatObject::GetPacket
  597. //  Purpose:
  598. // Called by controller to ask the file format for the next packet
  599. // for a particular stream in the file. The file format should call 
  600. // IHXFileFormatSession::PacketReady() for the IHXFileFormatSession
  601. // object that was passed in during initialization, when the packet
  602. // is available.
  603. //
  604. STDMETHODIMP CSmilFileFormat::GetPacket(UINT16 unStreamNumber)
  605. {
  606.     HX_RESULT result = HXR_OK;
  607.     // If we are not ready then something has gone wrong
  608.     if (m_state != Ready) return HXR_UNEXPECTED;
  609.     if (!m_bHeaderSent)
  610.     {
  611.         return HXR_UNEXPECTED;
  612.     }
  613.     IHXPacket* pPacket = NULL;
  614.     result = m_pCommonClassFactory->CreateInstance(CLSID_IHXPacket,
  615. (void**)&pPacket);
  616.     if( SUCCEEDED(result) )
  617.     {
  618. if(m_ulCurrentPacket >= m_ulPacketCount)
  619. {
  620.     m_pFFResponse->StreamDone(unStreamNumber);
  621. }
  622. else
  623. {
  624.     PacketData* pckt = (PacketData*)(*m_pArrayOfPackets)[m_ulCurrentPacket++];
  625.     
  626.     if ( pckt->pNumPos )
  627.     {
  628. char buf[10]; /* Flawfinder: ignore */
  629. sprintf(buf, "%u", m_ulPacketCount); /* Flawfinder: ignore */
  630. HX_ASSERT(strlen(buf) < 7);
  631. strncpy(pckt->pNumPos, buf, strlen(buf)); /* Flawfinder: ignore */
  632. pckt->pNumPos = NULL;
  633.     }
  634. #ifdef DUMPFILEFORMATOUTPUT
  635.     FILE* stream = fopen( "C:\PacketData.smil", "a" );
  636.     fprintf( stream, "%sn", (const char*)pckt->pBuffer->GetBuffer());
  637.     fclose( stream );
  638. #endif
  639.     pPacket->Set(pckt->pBuffer, 0, unStreamNumber, HX_ASM_SWITCH_ON, 0);
  640.     m_pFFResponse->PacketReady(HXR_OK, pPacket);
  641. }
  642.     }
  643.     HX_RELEASE(pPacket);
  644.     return result;
  645. }
  646. /////////////////////////////////////////////////////////////////////////
  647. //  Method:
  648. // IHXFileFormatObject::Seek
  649. //  Purpose:
  650. // Called by controller to tell the file format to seek to the 
  651. // nearest packet to the requested offset. The file format should 
  652. // call IHXFileFormatSession::SeekDone() for the IHXFileFormat-
  653. // Session object that was passed in during initialization, when 
  654. // the seek has completed.
  655. //
  656. STDMETHODIMP CSmilFileFormat::Seek(ULONG32 ulOffset)
  657. {
  658.     m_pFFResponse->SeekDone(HXR_OK);
  659.     return HXR_OK;
  660. }
  661. /////////////////////////////////////////////////////////////////////////
  662. //  Method:
  663. //    IHXFileResponse::InitDone
  664. //  Purpose:
  665. //    Notification interface provided by users of the IHXFileObject
  666. //    interface. This method is called by the IHXFileObject when the
  667. //    initialization of the file is complete, and the Mime type is
  668. //    available for the request file. If the URL is not valid for the
  669. //    file system, the status HXR_FAILED should be returned,
  670. //    with a mime type of NULL. If the URL is valid but the mime type
  671. //    is unknown, then the status HXR_OK should be returned with
  672. //    a mime type of NULL.
  673. //
  674. STDMETHODIMP CSmilFileFormat::InitDone
  675. (
  676.     HX_RESULT status
  677. )
  678. {
  679.     HX_RESULT rc = HXR_OK;
  680.     // If we are not ready then something has gone wrong
  681.     if (m_state != InitPending) return HXR_UNEXPECTED;
  682.     // Now it's time to read the file
  683.     m_state = ReadPending;
  684.     if (status != HXR_OK)
  685.     {
  686. rc = m_pFFResponse->InitDone(status);
  687.     }
  688.     else
  689.     {
  690. // check to see if we have logged an error for this file
  691. // in the last hour.  If we have we will not log an error.
  692. UpdateErrorCaching();
  693. rc = m_pFileObject->Read(FileChunkSize);
  694.     }
  695.     return rc;
  696. }
  697. HX_RESULT CSmilFileFormat::UpdateErrorCaching()
  698. {
  699.     IHXValues* pRequestHeaders = NULL;
  700.     UINT32 ulID = 0, ulSes = 0;
  701.  
  702.     IHXRegistry* pReg = NULL;
  703.     m_pContext->QueryInterface(IID_IHXRegistry, (void**)&pReg);
  704.     
  705.     HX_RESULT ret = m_pRequest->GetRequestHeaders(pRequestHeaders);
  706.     if (!pRequestHeaders)
  707.     {
  708. // succeeds even when there are no request headers.
  709. ret = HXR_FAIL;
  710.     }
  711.  
  712.     if (SUCCEEDED(ret))
  713.     {
  714. IHXBuffer* pID = NULL;
  715. ret = pRequestHeaders->GetPropertyCString("ConnID", pID);
  716. if (SUCCEEDED(ret) && pID) 
  717. {
  718.     ulID = atoi((char*)pID->GetBuffer());
  719. }
  720. HX_RELEASE(pID);
  721.     }
  722.     
  723.     if (SUCCEEDED(ret))
  724.     {
  725. IHXBuffer* pSes = NULL;
  726. if (SUCCEEDED(pRequestHeaders->GetPropertyCString("SessionNumber", pSes)))
  727. {
  728.     ulSes = atoi((char*)pSes->GetBuffer());
  729. }
  730. else
  731. {
  732.     // assume 0
  733.     ulSes = 0;
  734. }
  735. HX_RELEASE(pSes);
  736.     }
  737.     IHXBuffer* pURL = NULL;
  738.     if (SUCCEEDED(ret))
  739.     {
  740. const char form[] = "client.%u.session.%u.URL";
  741. char pRegkey[sizeof(form) + 20]; /* Flawfinder: ignore */
  742. sprintf(pRegkey, form, ulID, ulSes); /* Flawfinder: ignore */
  743. ret = pReg->GetStrByName(pRegkey, pURL);
  744.     }
  745.     char* buf = NULL;
  746.     const char regtemp[] = "server.smilerrorlog.";
  747.     if ( SUCCEEDED(ret) )
  748.     {
  749.        buf = new char[sizeof(regtemp) + pURL->GetSize()];
  750.        if (!buf)
  751.        {
  752.    ret = HXR_OUTOFMEMORY;
  753.        }
  754.     }
  755.     if (SUCCEEDED(ret))
  756.     {
  757. strcpy(buf, regtemp); /* Flawfinder: ignore */
  758. char* pos = buf + sizeof(regtemp) - 1;
  759. const char* url = (const char*)pURL->GetBuffer();
  760. // escape the '.'s
  761. while (*url && pos < buf + sizeof(regtemp) + pURL->GetSize())
  762. {
  763.     if (*url == '.' || *url == '/')
  764.     {
  765. *pos++ = '%';
  766. ++url;
  767.     }
  768.     else
  769.     {
  770. *pos++ = *url++;
  771.     }
  772. }
  773. *pos = '';
  774.     }
  775.     if (SUCCEEDED(ret))
  776.     {
  777. INT32 lTime = 0;
  778. INT32 lNow = time(NULL);
  779. if (SUCCEEDED(pReg->GetIntByName(buf, lTime)))
  780. {
  781.     if ((lNow - lTime) > 3600)
  782.     {
  783. m_bLogErrors = TRUE;
  784. ret = pReg->SetIntByName(buf, lNow);
  785.     }
  786.     else
  787.     {
  788. m_bLogErrors = FALSE;
  789.     }
  790. }
  791. else
  792. {
  793.     m_bLogErrors = TRUE;
  794.     pReg->AddInt(buf, lNow);
  795. }
  796.     }
  797.     HX_RELEASE(pReg);
  798.     HX_RELEASE(pRequestHeaders);
  799.     HX_VECTOR_DELETE(buf);
  800.     HX_RELEASE(pURL);
  801.     return ret;
  802. }
  803. /////////////////////////////////////////////////////////////////////////
  804. //  Method:
  805. // IHXFileResponse::CloseDone
  806. //  Purpose:
  807. // Notification interface provided by users of the IHXFileObject
  808. // interface. This method is called by the IHXFileObject when the
  809. // close of the file is complete.
  810. //
  811. STDMETHODIMP CSmilFileFormat::CloseDone(HX_RESULT status)
  812. {
  813.     return HXR_OK;
  814. }
  815. /////////////////////////////////////////////////////////////////////////
  816. //  Method:
  817. // IHXFileResponse::ReadDone
  818. //  Purpose:
  819. // Notification interface provided by users of the IHXFileObject
  820. // interface. This method is called by the IHXFileObject when the
  821. // last read from the file is complete and a buffer is available.
  822. //
  823. STDMETHODIMP CSmilFileFormat::ReadDone
  824. (
  825.     HX_RESULT status,
  826.     IHXBuffer* pBuffer
  827. )
  828. {
  829.     HX_RESULT result = HXR_OK;
  830.     if ( SUCCEEDED(status) )
  831.     {
  832. HX_ASSERT(pBuffer);
  833. // /For determining what type file this is (via namespace URI), we'll
  834. // hold onto the first pBuffer for later when we handle stream header:
  835. if (!m_pStartOfFile)
  836. {
  837.     pBuffer->AddRef();
  838.     m_pStartOfFile = pBuffer;
  839. }
  840. BreakUpBuffer(pBuffer);
  841. // recurse...
  842. m_pFileObject->Read(FileChunkSize);
  843.     }
  844.     else
  845.     {
  846. // check see if we have a packet that needs added to the array.
  847. if ( m_pCurrentPacketData )
  848. {
  849.     UCHAR* pCb = m_pCurrentPacketData->pBuffer->GetBuffer();
  850.     pCb[m_ulCurrentBufferPos++] = '"';
  851.     pCb[m_ulCurrentBufferPos++] = ')';
  852.     pCb[m_ulCurrentBufferPos++] = '';
  853.     m_pCurrentPacketData->pBuffer->SetSize(m_ulCurrentBufferPos);
  854.     m_pArrayOfPackets->Add((void*)m_pCurrentPacketData);
  855.     m_pCurrentPacketData = NULL;
  856.     m_ulCurrentBufferPos = 0;
  857. }
  858. // finished reading, calculate the number of packets to send:
  859. m_ulPacketCount = m_ulCurrentPacket;
  860. m_ulCurrentPacket = 0;
  861. m_state = Ready;
  862. m_pFFResponse->InitDone(result);
  863.     }
  864.     return result;
  865. }
  866. /////////////////////////////////////////////////////////////////////////
  867. //  Method:
  868. // GetSMILFileVersion
  869. //  Purpose:
  870. // This Function will break the buffer into packets.
  871. //
  872. // This function maintains a state, such that multiple buffers should
  873. // Be able to be passed into it at any point...
  874. //
  875. HX_RESULT 
  876. CSmilFileFormat::GetSMILFileVersion()
  877. {
  878.     HX_RESULT pnreslt = HXR_OK;
  879.     const char* pSmilTag = NULL;
  880.     const char* pCloseOfSmilTag = NULL;
  881.     const char* pXmlns = NULL;
  882.     const char* pXmlnsOpenQuotationMark = NULL;
  883.     const char* pBuf = NULL;
  884.     ULONG32 ulBufLen = 0;
  885.     const char* pEqualsSign = NULL;
  886.     const char* pTmp = NULL;
  887.     char* pTmp2 = NULL;
  888.     char* pszStartOfFile = NULL;
  889.     ULONG32 ulCount = 0;
  890.     LONG32 lNumCommentsOpen = 0;
  891.     if (!m_pStartOfFile)
  892.     {
  893. pnreslt = HXR_BUFFERTOOSMALL;
  894. goto cleanup;
  895.     }
  896.     // /Fixes PR 59282: m_pStartOfFile is not necessarily NULL-terminated,
  897.     // so we have to limit our access of it to the size of the buffer (duh!):
  898.     ulBufLen = m_pStartOfFile->GetSize();
  899.     pBuf = (const char*)m_pStartOfFile->GetBuffer();
  900.     if (!pBuf  ||  !ulBufLen)
  901.     {
  902. pnreslt = HXR_BUFFERTOOSMALL;
  903. goto cleanup;
  904.     }
  905.     pszStartOfFile = new char[ulBufLen+1];
  906.     if (!pszStartOfFile)
  907.     {
  908. pnreslt = HXR_OUTOFMEMORY;
  909. goto cleanup;
  910.     }
  911.     // /Now, walk through and copy each character from non-NULL terminated buf:
  912.     pTmp = pBuf; 
  913.     pTmp2 = pszStartOfFile;
  914.     while (*pTmp  &&  ulCount<ulBufLen)
  915.     {
  916. *pTmp2 = *pTmp;
  917. pTmp++;
  918. pTmp2++;
  919. ulCount++;
  920.     }
  921.     pszStartOfFile[ulCount] = ''; // /NULL-terminate it.
  922.     // /Now, let's walk through the start of pszStartOfFile looking for
  923.     // namespace declaration(s) inside the <smil ...> tag, and make sure that
  924.     // the smil tag is NOT inside of a comment:
  925.     pTmp = pszStartOfFile;
  926.     while (*pTmp)
  927.     {
  928. if (0==strncmp(pTmp, "<!--", 4) )
  929. {
  930.     lNumCommentsOpen++;
  931.     pTmp+=4;
  932. }
  933. else if (0==strncmp(pTmp, "-->", 3) )
  934. {
  935.     lNumCommentsOpen--;
  936.     pTmp+=3;
  937. }
  938. else if (lNumCommentsOpen<=0  &&  0==strncmp(pTmp, "<smil", 5) )
  939. {
  940.     pSmilTag = pTmp; // /We found the smil tag outside of a comment.
  941.     break;
  942. }
  943. else
  944. {
  945.     pTmp++;
  946. }
  947.     }
  948.     if (!pSmilTag  ||  ulBufLen-(pSmilTag-pszStartOfFile) < 6) // /6==min size: "<smil>"
  949.     {
  950. // /There had better be a <smil...> tag!
  951. pnreslt = HXR_UNEXPECTED;
  952. goto cleanup;
  953.     }
  954.     pCloseOfSmilTag = strchr(pSmilTag, '>');
  955.     // /Add 6 so that we don't allow "<smilxmlns ..." (which is invalid):
  956.     pXmlns = strstr(pSmilTag+6, "xmlns");
  957.     if (pXmlns  &&  isspace(*(pXmlns-1)) ) // /"xmlns" must follow a space.
  958.     {
  959. pEqualsSign = strchr(pXmlns, '=');
  960. if (pEqualsSign)
  961. {
  962.     pXmlnsOpenQuotationMark = strchr(pXmlns, '"');
  963. }
  964.     }
  965.     if (pXmlns  &&   pEqualsSign  &&  pXmlnsOpenQuotationMark  &&
  966.     (!pCloseOfSmilTag  ||  pXmlns<pCloseOfSmilTag))
  967.     {
  968. BOOL bIsValidNamespaceDeclaration = TRUE;
  969. // /First, make sure there is nothing but whitespace between
  970. // the "xmlns" and the '=' as well as between the '=' and the
  971. // quotation mark:
  972. char* pTmp = (char*)(pXmlns + strlen("xmlns"));
  973. while (pTmp<pEqualsSign)
  974. {
  975.     if (!isspace(*pTmp))
  976.     {
  977. bIsValidNamespaceDeclaration = FALSE;
  978. break;
  979.     }
  980.     pTmp++;
  981. }
  982. pTmp = (char*)(pEqualsSign+1);
  983. while(pTmp<pXmlnsOpenQuotationMark)
  984. {
  985.     if (!isspace(*pTmp))
  986.     {
  987. bIsValidNamespaceDeclaration = FALSE;
  988. break;
  989.     }
  990.     pTmp++;
  991. }
  992. if (bIsValidNamespaceDeclaration)
  993. {
  994.     // /Note: SMIL 1.0 namespace is default and is:
  995.     // "http://www.w3.org/TR/REC-smil".  Note that if this is
  996.     // tagged (first) with a SMIL 1.0 namespace followed by
  997.     // another namespace, then this is a 1.0 file and we'll let
  998.     // the 1.0 renderer get it and do what it can with the 2.0
  999.     // stuff (namely ignore it):
  1000.     const char* pSMIL10Namespace = strstr(pXmlnsOpenQuotationMark,
  1001.     "http://www.w3.org/TR/REC-smil"");
  1002.     // /This in the final SMIL 2.0 rec:
  1003.     const char* pSMIL20Namespace = strstr(pXmlnsOpenQuotationMark,
  1004.     "http://www.w3.org/2001/SMIL20/Language"");
  1005.     const char* pSMIL20NamespaceCandidateRec = strstr(
  1006.     pXmlnsOpenQuotationMark,
  1007.     "http://www.w3.org/2000/SMIL20/CR/Language"");
  1008.     // /Fixes PR 55749: allow new PR namespace:
  1009.     const char* pSMIL20NamespaceProposedRec = strstr(
  1010.     pXmlnsOpenQuotationMark,
  1011.     "http://www.w3.org/2001/SMIL20/PR/Language"");
  1012.     const char* pSMIL20NamespaceLastCall = strstr(
  1013.     pXmlnsOpenQuotationMark,
  1014.     "http://www.w3.org/TR/REC-smil/2000/SMIL20/LC/"");
  1015.     // /If the SMIL 1.0 namespace is declared prior to any other
  1016.     // version of SMIL's namespace, then this is a SMIL 1.0 doc:
  1017.     if (pSMIL10Namespace  &&  (!pSMIL20Namespace  ||
  1018.     pSMIL10Namespace < pSMIL20Namespace)  &&
  1019.     (!pSMIL20NamespaceCandidateRec  ||
  1020.     pSMIL10Namespace < pSMIL20NamespaceCandidateRec)  &&
  1021.     (!pSMIL20NamespaceProposedRec  ||
  1022.     pSMIL10Namespace < pSMIL20NamespaceProposedRec)  &&
  1023.     (!pSMIL20NamespaceLastCall  ||
  1024.     pSMIL10Namespace < pSMIL20NamespaceLastCall) )
  1025.     {
  1026. m_smilFileVersion = SMILFileVersionSmil10Strict;
  1027.     }
  1028.     else if (pSMIL20NamespaceCandidateRec  &&  (!pSMIL20Namespace  ||
  1029.     pSMIL20NamespaceCandidateRec < pSMIL20Namespace))
  1030.     {
  1031. m_smilFileVersion = SMILFileVersionSmil20PreRec;
  1032.     }
  1033.     else if (pSMIL20NamespaceProposedRec  &&  (!pSMIL20Namespace ||
  1034.     pSMIL20NamespaceProposedRec < pSMIL20Namespace))
  1035.     {
  1036. m_smilFileVersion = SMILFileVersionSmil20PreRec;
  1037.     }
  1038.     // /Treat both LC (Last Call) and CR (Candidate Rec) as "PreRec":
  1039.     else if (pSMIL20NamespaceLastCall  &&  (!pSMIL20Namespace  ||
  1040.     pSMIL20NamespaceLastCall < pSMIL20Namespace))
  1041.     {
  1042. m_smilFileVersion = SMILFileVersionSmil20PreRec;
  1043.     }
  1044.     else if (pSMIL20Namespace)
  1045.     {
  1046. m_smilFileVersion = SMILFileVersionSmil20;
  1047.     }
  1048.     else
  1049.     {
  1050. m_smilFileVersion = SMILFileVersionUnknown;
  1051.     }
  1052. }
  1053.     }
  1054. cleanup:
  1055.     if (pszStartOfFile)
  1056.     {
  1057. HX_VECTOR_DELETE(pszStartOfFile);
  1058.     }
  1059.     return pnreslt;
  1060. }
  1061. /////////////////////////////////////////////////////////////////////////
  1062. //  Method:
  1063. // BreakUpBuffer
  1064. //  Purpose:
  1065. // This Function will break the buffer into packets.
  1066. //
  1067. // This function maintains a state, such that multiple buffers should
  1068. // Be able to be passed into it at any point...
  1069. //
  1070. // XXX  jhug
  1071. // This doesn't allow text between tags... Future versions of SMIL might
  1072. // support this... this will need a bit of a modification.
  1073. HX_RESULT 
  1074. CSmilFileFormat::BreakUpBuffer(IHXBuffer* pBuffer)
  1075. {
  1076.     // walk through the buffer and escape all "s
  1077.     // also forget about all white space and comments...
  1078.     // also break the buffer up into packets for easy access.
  1079.     HX_RESULT result = HXR_OK;
  1080.     UCHAR* pCb = NULL;
  1081.     if ( m_pCurrentPacketData )
  1082.     {
  1083. pCb = m_pCurrentPacketData->pBuffer->GetBuffer();
  1084.     }
  1085.     const UCHAR* pData = pBuffer->GetBuffer();
  1086.     UINT32 ulSize = pBuffer->GetSize();
  1087.     for ( UINT32 ulPos = 0; ulPos < ulSize && pData[ulPos]; ++ulPos )
  1088.     {
  1089. // three for the end of the packet structure, and 1 in case we have 
  1090. // to escape a char...
  1091. if ( m_ulCurrentBufferPos >= MaxPacketSize - 4 ) 
  1092. {
  1093.     pCb[m_ulCurrentBufferPos++] = '"';
  1094.     pCb[m_ulCurrentBufferPos++] = ')';
  1095.     pCb[m_ulCurrentBufferPos++] = '';
  1096.     m_pCurrentPacketData->pBuffer->SetSize(m_ulCurrentBufferPos);
  1097.     m_pArrayOfPackets->Add((void*)m_pCurrentPacketData);
  1098.     m_pCurrentPacketData = NULL;
  1099.     m_ulCurrentBufferPos = 0;
  1100.     pCb = NULL;
  1101. }
  1102. if ( !m_pCurrentPacketData )
  1103. {
  1104.     m_pCurrentPacketData = new PacketData;
  1105.     if ( m_pCurrentPacketData == NULL )
  1106.     {
  1107. result = HXR_OUTOFMEMORY;
  1108.     }
  1109.     else
  1110.     {
  1111. m_pCurrentPacketData->pBuffer = NULL;
  1112. m_pCurrentPacketData->pNumPos = NULL;
  1113. result = m_pCommonClassFactory->CreateInstance(CLSID_IHXBuffer, 
  1114. (void**)&m_pCurrentPacketData->pBuffer);
  1115.     }
  1116.     if ( SUCCEEDED(result) )
  1117.     {
  1118. result = m_pCurrentPacketData->pBuffer->SetSize(MaxPacketSize);
  1119.     }
  1120.     if ( SUCCEEDED(result) )
  1121.     {
  1122. pCb = m_pCurrentPacketData->pBuffer->GetBuffer();
  1123. //memset(pCb, 0xef, MaxPacketSize);
  1124. sprintf((char*)pCb, "(smil-document (ver %s)(npkt %ld)"
  1125.     "(ttlpkt 0     )(doc "", 
  1126.     RMA_DRIVER_VERSION, ++m_ulCurrentPacket);
  1127. m_ulCurrentBufferPos = strlen((char*)pCb);
  1128. // back up to the begining of the total number position.
  1129. // 13 is position back in header...
  1130. m_pCurrentPacketData->pNumPos = (char*)pCb + 
  1131.     m_ulCurrentBufferPos - 13; 
  1132.     }
  1133. }
  1134. if ( FAILED(result) )
  1135. {
  1136.     break;
  1137. }
  1138. switch ( m_fileState )
  1139. {
  1140. case InContent:
  1141.     {
  1142. if ( pData[ulPos] == '"' )
  1143. {
  1144.     pCb[m_ulCurrentBufferPos++] = '\';
  1145.     pCb[m_ulCurrentBufferPos++] = '"';
  1146. }
  1147. else if ( pData[ulPos] == '\' )
  1148. {
  1149.     pCb[m_ulCurrentBufferPos++] = '\';
  1150.     pCb[m_ulCurrentBufferPos++] = '"';
  1151. }
  1152. else if ( pData[ulPos] == '<' )
  1153. {
  1154.     if ( pData[ulPos+1] == '!' )
  1155.     {
  1156. if ( pData[ulPos+2] == '-'
  1157.     && pData[ulPos+3] == '-' )
  1158. {
  1159.     ulPos += 3;
  1160.     m_fileState = InComment;
  1161. }
  1162. else if ( pData[ulPos+2] == '[' && 
  1163.   pData[ulPos+3] == 'C' &&
  1164.   pData[ulPos+4] == 'D' &&
  1165.   pData[ulPos+5] == 'A' &&
  1166.   pData[ulPos+6] == 'T' &&
  1167.   pData[ulPos+7] == 'A' &&
  1168.   pData[ulPos+8] == '[' )
  1169. {
  1170.     pCb[m_ulCurrentBufferPos++] = pData[ulPos++];
  1171.     pCb[m_ulCurrentBufferPos++] = pData[ulPos++];
  1172.     pCb[m_ulCurrentBufferPos++] = pData[ulPos++];
  1173.     pCb[m_ulCurrentBufferPos++] = pData[ulPos++];
  1174.     pCb[m_ulCurrentBufferPos++] = pData[ulPos++];
  1175.     pCb[m_ulCurrentBufferPos++] = pData[ulPos++];
  1176.     pCb[m_ulCurrentBufferPos++] = pData[ulPos];
  1177.     m_fileState = InCDATA;
  1178. }
  1179. else if ( pData[ulPos+2] == 'D' && 
  1180.   pData[ulPos+3] == 'O' &&
  1181.   pData[ulPos+4] == 'C' &&
  1182.   pData[ulPos+5] == 'T' &&
  1183.   pData[ulPos+6] == 'Y' &&
  1184.   pData[ulPos+7] == 'P' &&
  1185.   pData[ulPos+8] == 'E' )
  1186. {
  1187.     pCb[m_ulCurrentBufferPos++] = pData[ulPos++];
  1188.     pCb[m_ulCurrentBufferPos++] = pData[ulPos++];
  1189.     pCb[m_ulCurrentBufferPos++] = pData[ulPos++];
  1190.     pCb[m_ulCurrentBufferPos++] = pData[ulPos++];
  1191.     pCb[m_ulCurrentBufferPos++] = pData[ulPos++];
  1192.     pCb[m_ulCurrentBufferPos++] = pData[ulPos++];
  1193.     pCb[m_ulCurrentBufferPos++] = pData[ulPos];
  1194.     m_fileState = InDTD;
  1195. }
  1196.     }
  1197.     else
  1198.     {
  1199. pCb[m_ulCurrentBufferPos++] = pData[ulPos];
  1200. m_fileState = InTagName;
  1201.     }
  1202. }
  1203. // preserve all lines so line number error reporting is
  1204. // accurate
  1205. else if ( isspace(pData[ulPos]) && pData[ulPos] != 'n'  &&
  1206. pData[ulPos] != 'r')
  1207. {
  1208.     //continue...
  1209. }
  1210. //If we find rx where x is not n, then keep it else let
  1211. // the next char (n) be kept in the next iteration of
  1212. // this loop.  This accomodates Mac-authored 'r'-only
  1213. // text.  Think Different (pain is "different").
  1214. else if (isspace(pData[ulPos])  &&  ('r' == pData[ulPos]  &&
  1215. (ulPos+1 < ulSize  &&  pData[ulPos+1])  &&
  1216. 'n' == pData[ulPos+1]) )
  1217. {
  1218.     //continue...
  1219. }
  1220. else
  1221. {
  1222.     if ('r' == pData[ulPos])
  1223.     {
  1224. pCb[m_ulCurrentBufferPos++] = 'n';
  1225.     }
  1226.     else
  1227.     {
  1228. pCb[m_ulCurrentBufferPos++] = pData[ulPos];
  1229.     }
  1230. }
  1231.     }
  1232.     break;
  1233. case InDTD:
  1234.     {
  1235. if ( pData[ulPos] == '[' )
  1236. {
  1237.     m_fileState = InDTDMarkup;
  1238. }
  1239. else if ( pData[ulPos] == '>' )
  1240. {
  1241.     m_fileState = InContent;
  1242. }
  1243. else if ( pData[ulPos] == '"' )
  1244. {
  1245.     pCb[m_ulCurrentBufferPos++] = '\';
  1246. }
  1247. else if ( pData[ulPos] == '\' )
  1248. {
  1249.     pCb[m_ulCurrentBufferPos++] = '\';
  1250. }
  1251. pCb[m_ulCurrentBufferPos++] = pData[ulPos];
  1252.     }
  1253.     break;
  1254. case InDTDMarkup:
  1255.     {
  1256. if ( pData[ulPos] == ']' )
  1257. {
  1258.     m_fileState = InDTD;
  1259. }
  1260. else if ( pData[ulPos] == '"' )
  1261. {
  1262.     pCb[m_ulCurrentBufferPos++] = '\';
  1263. }
  1264. else if ( pData[ulPos] == '\' )
  1265. {
  1266.     pCb[m_ulCurrentBufferPos++] = '\';
  1267. }
  1268. pCb[m_ulCurrentBufferPos++] = pData[ulPos];
  1269.     }
  1270.     break;
  1271. case InCDATA:
  1272.     {
  1273. if ( pData[ulPos] == ']' && pData[ulPos+1] == ']' && pData[ulPos+2] == '>' )
  1274. {
  1275.     pCb[m_ulCurrentBufferPos++] = pData[ulPos++];
  1276.     m_fileState = InContent;
  1277. }
  1278. else if ( pData[ulPos] == '"' )
  1279. {
  1280.     pCb[m_ulCurrentBufferPos++] = '\';
  1281. }
  1282. else if ( pData[ulPos] == '\' )
  1283. {
  1284.     pCb[m_ulCurrentBufferPos++] = '\';
  1285. }
  1286. pCb[m_ulCurrentBufferPos++] = pData[ulPos];
  1287.     }
  1288.     break;
  1289. case InTagName:
  1290.     {
  1291. // go to first white space
  1292. // let's escape " and  even though they are ilegal.
  1293. if ( isspace(pData[ulPos]) )
  1294. {
  1295.     m_fileState = InBeginAttributeName;
  1296. }
  1297. else if ( pData[ulPos] == '>' )
  1298. {
  1299.     m_fileState = InContent;
  1300. }
  1301. else if ( pData[ulPos] == '"' )
  1302. {
  1303.     ReportError(HXR_XML_GENERALERROR, XML_BAD_TAG_NAME);
  1304.     pCb[m_ulCurrentBufferPos++] = '\';
  1305. }
  1306. else if ( pData[ulPos] == '\' )
  1307. {
  1308.     ReportError(HXR_XML_GENERALERROR, XML_BAD_TAG_NAME);
  1309.     pCb[m_ulCurrentBufferPos++] = '\';
  1310. }
  1311. pCb[m_ulCurrentBufferPos++] = pData[ulPos];
  1312.     }
  1313.     break;
  1314. case InTag:
  1315.     {
  1316. if ( pData[ulPos] == '>' || (pData[ulPos] == '/' && 
  1317.     pData[ulPos+1] == '>'))
  1318. {
  1319.     pCb[m_ulCurrentBufferPos++] = pData[ulPos];
  1320.     m_fileState = InContent;
  1321. }
  1322. else
  1323. {
  1324.     // grab the first char... keep it and switch states.
  1325.     // it should be a space... but if it isn't we will
  1326.     // not complain because the renderer accepts no 
  1327.     // space.
  1328.     pCb[m_ulCurrentBufferPos++] = pData[ulPos];
  1329.     m_fileState = InBeginAttributeName;
  1330.     if (!isspace(pData[ulPos]))
  1331.     {
  1332. ReportError(HXR_XML_GENERALERROR,
  1333. XML_MISSING_SPACE);
  1334.     }
  1335. }
  1336.     }
  1337.     break;
  1338. case InBeginAttributeName:
  1339.     {
  1340. if ( isspace(pData[ulPos]) )
  1341. {
  1342.     // preserve all lines so line numbers in error messages
  1343.     // are accurate
  1344.     if (pData[ulPos] == 'n'  ||  ('r' == pData[ulPos]  &&
  1345.     ulPos+1 < ulSize  &&  'n' != pData[ulPos+1]) )
  1346.     {
  1347. if ('r' == pData[ulPos])
  1348. {
  1349.     pCb[m_ulCurrentBufferPos++] = 'n';
  1350. }
  1351. else
  1352. {
  1353.     pCb[m_ulCurrentBufferPos++] = pData[ulPos];
  1354. }
  1355.     }
  1356.     // continue...
  1357. }
  1358. else if ( pData[ulPos] == '=' )
  1359. {
  1360.     ReportError(HXR_XML_GENERALERROR, 
  1361.      XML_BAD_ATTRIBUTE_NAME);
  1362.     m_fileState = InBeginAttributeValue;
  1363.     pCb[m_ulCurrentBufferPos++] = pData[ulPos];
  1364. }
  1365. else if ( pData[ulPos] == '>' || (pData[ulPos] == '/' 
  1366.     && pData[ulPos+1] == '>'))
  1367. {
  1368.     m_fileState = InContent;
  1369.     pCb[m_ulCurrentBufferPos++] = pData[ulPos];
  1370. }
  1371. else
  1372. {
  1373.     m_fileState = InAttributeName;
  1374.     pCb[m_ulCurrentBufferPos++] = pData[ulPos];
  1375. }
  1376.     }
  1377.     break;
  1378. case InAttributeName:
  1379.     {
  1380. if ( isspace(pData[ulPos]) )
  1381. {
  1382.     m_fileState = InEndAttributeName;
  1383.     pCb[m_ulCurrentBufferPos++] = pData[ulPos];
  1384. }
  1385. else if ( pData[ulPos] == '=' )
  1386. {
  1387.     m_fileState = InBeginAttributeValue;
  1388.     pCb[m_ulCurrentBufferPos++] = pData[ulPos];
  1389. }
  1390. else if ( pData[ulPos] == '>' )
  1391. {
  1392.     ReportError(HXR_XML_GENERALERROR, 
  1393.      XML_MISSING_ATTRIBUTE_VALUE);
  1394.     m_fileState = InContent;
  1395.     pCb[m_ulCurrentBufferPos++] = pData[ulPos];
  1396. }
  1397. else if (pData[ulPos] == ''' || pData[ulPos] == '"')
  1398. {
  1399.     ReportError(HXR_XML_GENERALERROR, 
  1400.      XML_BAD_ATTRIBUTE_NAME);
  1401.     m_cQuote = pData[ulPos];
  1402.     if (m_cQuote == '"')
  1403.     {
  1404. pCb[m_ulCurrentBufferPos++] = '\';
  1405.     }
  1406.     pCb[m_ulCurrentBufferPos++] = pData[ulPos];
  1407.     m_fileState = InAttributeValue;
  1408. }
  1409. else
  1410. {
  1411.     pCb[m_ulCurrentBufferPos++] = pData[ulPos];
  1412. }
  1413.     }
  1414.     break;
  1415. case InEndAttributeName:
  1416.     {
  1417. if ( isspace(pData[ulPos]) )
  1418. {
  1419.     // preserve all lines so line numbers in error messages
  1420.     // are accurate
  1421.     if (pData[ulPos] == 'n'  ||  ('r' == pData[ulPos]  &&
  1422.     ulPos+1 < ulSize  &&  'n' != pData[ulPos+1]) )
  1423.     {
  1424. if ('r' == pData[ulPos])
  1425. {
  1426.     pCb[m_ulCurrentBufferPos++] = 'n';
  1427. }
  1428. else
  1429. {
  1430.     pCb[m_ulCurrentBufferPos++] = pData[ulPos];
  1431. }
  1432.     }
  1433.     // continue..
  1434. }
  1435. else if ( pData[ulPos] == '=' )
  1436. {
  1437.     m_fileState = InBeginAttributeValue;
  1438.     pCb[m_ulCurrentBufferPos++] = pData[ulPos];
  1439. }
  1440. else if ( pData[ulPos] == '>' )
  1441. {
  1442.     ReportError(HXR_XML_GENERALERROR, 
  1443.      XML_MISSING_ATTRIBUTE_VALUE);
  1444.     // illegal.
  1445.     m_fileState = InContent;
  1446.     pCb[m_ulCurrentBufferPos++] = pData[ulPos];
  1447. }
  1448. else
  1449. {
  1450.     // hmm. we got a non whitespace before the =
  1451.     // push a ' ' on so the render will get this error.
  1452.     pCb[m_ulCurrentBufferPos++] = ' ';
  1453.     //First, let's see if we have a ["] or a [']
  1454.     // (i.e., an attribute value start) in which
  1455.     // case the author must have forgotten to
  1456.     // put an '=' between the name/value pair.
  1457.     // In this case, we need to keep the renderers
  1458.     // from firing off an error with old bad content,
  1459.     // so we pretend we're in the "InAttributeValue"
  1460.     // state:
  1461.     if ( pData[ulPos] == ''' )
  1462.     {
  1463. ReportError(HXR_XML_GENERALERROR, 
  1464. XML_BAD_ATTRIBUTE_NAME);
  1465. m_cQuote = pData[ulPos];
  1466. m_fileState = InAttributeValue;
  1467.     }
  1468.     else if ( pData[ulPos] == '"' )
  1469.     {
  1470. ReportError(HXR_XML_GENERALERROR,
  1471. XML_BAD_ATTRIBUTE_NAME);
  1472. m_cQuote = pData[ulPos];
  1473. pCb[m_ulCurrentBufferPos++] = '\';
  1474. m_fileState = InAttributeValue;
  1475.     }
  1476.     else
  1477.     {
  1478. ReportError(HXR_XML_BADATTRIBUTE, 
  1479. XML_BAD_ATTRIBUTE_NAME);
  1480. // lets go back to the attribute name state.
  1481. m_fileState = InAttributeName;
  1482.     }
  1483.     //Push the character back on so the renderer
  1484.     // can deal with it:
  1485.     pCb[m_ulCurrentBufferPos++] = pData[ulPos];
  1486. }
  1487.     }
  1488.     break;
  1489. case InBeginAttributeValue:
  1490.     {
  1491. if ( isspace(pData[ulPos]) )
  1492. {
  1493.     // preserve all lines so line numbers in error messages
  1494.     // are accurate
  1495.     if (pData[ulPos] == 'n'  ||  ('r' == pData[ulPos]  &&
  1496.     ulPos+1 < ulSize  &&  'n' != pData[ulPos+1]) )
  1497.     {
  1498. if ('r' == pData[ulPos])
  1499. {
  1500.     pCb[m_ulCurrentBufferPos++] = 'n';
  1501. }
  1502. else
  1503. {
  1504.     pCb[m_ulCurrentBufferPos++] = pData[ulPos];
  1505. }
  1506.     }
  1507.     // continue...
  1508. }
  1509. else if ( pData[ulPos] == ''' )
  1510. {
  1511.     m_cQuote = pData[ulPos];
  1512.     m_fileState = InAttributeValue;
  1513.     pCb[m_ulCurrentBufferPos++] = pData[ulPos];
  1514. }
  1515. else if ( pData[ulPos] == '"' )
  1516. {
  1517.     m_cQuote = pData[ulPos];
  1518.     pCb[m_ulCurrentBufferPos++] = '\';
  1519.     pCb[m_ulCurrentBufferPos++] = '"';
  1520.     m_fileState = InAttributeValue;
  1521. }
  1522. else if ( pData[ulPos] == '>' )
  1523. {
  1524.     ReportError(HXR_XML_GENERALERROR,
  1525.      XML_MISSING_ATTRIBUTE_VALUE);
  1526.     m_fileState = InContent;
  1527.     pCb[m_ulCurrentBufferPos++] = pData[ulPos];
  1528. }
  1529.     }
  1530.     break;
  1531. case InAttributeValue:
  1532.     {
  1533. if ( pData[ulPos] == m_cQuote )
  1534. {
  1535.     if ( m_cQuote == '"' )
  1536.     {
  1537. pCb[m_ulCurrentBufferPos++] = '\';
  1538.     }
  1539.     m_fileState = InTag;
  1540. }
  1541. else if ( pData[ulPos] == '"' )
  1542. {
  1543.     pCb[m_ulCurrentBufferPos++] = '\';
  1544. }
  1545. else if ( pData[ulPos] == '\' )
  1546. {
  1547.     pCb[m_ulCurrentBufferPos++] = '\';
  1548. }
  1549. pCb[m_ulCurrentBufferPos++] = pData[ulPos];
  1550.     }
  1551.     break;
  1552. case InComment:
  1553.     {
  1554. if ( pData[ulPos] == '-' && pData[ulPos+1] == '-' &&
  1555.     pData[ulPos+2] == '>' )
  1556. {
  1557.     m_fileState = InContent;
  1558.     ulPos += 2;
  1559. }
  1560. // preserve all lines so line numbers in error messages
  1561. // are accurate
  1562. else if (pData[ulPos] == 'n'  ||  ('r' == pData[ulPos]  &&
  1563.     ulPos+1 < ulSize  &&  'n' != pData[ulPos+1]) )
  1564. {
  1565.     if ('r' == pData[ulPos])
  1566.     {
  1567. pCb[m_ulCurrentBufferPos++] = 'n';
  1568.     }
  1569.     else
  1570.     {
  1571. pCb[m_ulCurrentBufferPos++] = pData[ulPos];
  1572.     }
  1573. }
  1574. // else continue...
  1575.     }
  1576.     break;
  1577. default:
  1578.     HX_ASSERT(FALSE);
  1579. }
  1580.     }
  1581.     return result;
  1582. }
  1583. HX_RESULT CSmilFileFormat::ReportError(HX_RESULT result, 
  1584.        const char* errStr)
  1585. {
  1586.     if ( m_bLogErrors )
  1587.     {
  1588. IHXErrorMessages* pLog = NULL;
  1589. m_pContext->QueryInterface(IID_IHXErrorMessages, 
  1590. (void**)&pLog);
  1591. pLog->Report(HXLOG_ERR, result, 0, errStr,
  1592.     "http://www.real.com");
  1593. HX_RELEASE(pLog);
  1594.     }
  1595.     return HXR_OK;
  1596. }
  1597. /////////////////////////////////////////////////////////////////////////
  1598. //  Method:
  1599. // IHXFileResponse::WriteDone
  1600. //  Purpose:
  1601. // Notification interface provided by users of the IHXFileObject
  1602. // interface. This method is called by the IHXFileObject when the
  1603. // last write to the file is complete.
  1604. //
  1605. STDMETHODIMP CSmilFileFormat::WriteDone(HX_RESULT status)
  1606. {
  1607.     // We don't ever write, so we don't expect to get this...
  1608.     return HXR_UNEXPECTED;
  1609. }
  1610. /////////////////////////////////////////////////////////////////////////
  1611. //  Method:
  1612. // IHXFileResponse::SeekDone
  1613. //  Purpose:
  1614. // Notification interface provided by users of the IHXFileObject
  1615. // interface. This method is called by the IHXFileObject when the
  1616. // last seek in the file is complete.
  1617. //
  1618. STDMETHODIMP CSmilFileFormat::SeekDone(HX_RESULT status)
  1619. {
  1620.     HX_RESULT result = HXR_OK;
  1621.     return result;
  1622. }
  1623. /************************************************************************
  1624.  * Method:
  1625.  *     IHXPendingStatus::GetStatus
  1626.  * Purpose:
  1627.  *     Called by the user to get the current pending status from an object
  1628.  */
  1629. STDMETHODIMP
  1630. CSmilFileFormat::GetStatus
  1631. (
  1632.     REF(UINT16) uStatusCode, 
  1633.     REF(IHXBuffer*) pStatusDesc, 
  1634.     REF(UINT16) ulPercentDone
  1635. )
  1636. {
  1637.     HX_RESULT hResult = HXR_OK;
  1638.     IHXPendingStatus* pFileSystemStatus = NULL;
  1639.     // asking status information from the file system object
  1640.     if (m_pFileObject)
  1641.     {
  1642. if (HXR_OK == m_pFileObject->QueryInterface(IID_IHXPendingStatus,(void**)&pFileSystemStatus))
  1643. {
  1644.     hResult = pFileSystemStatus->GetStatus(uStatusCode, pStatusDesc, ulPercentDone);
  1645.     pFileSystemStatus->Release();
  1646.     return hResult;
  1647. }
  1648.     }
  1649.     // by default
  1650.     uStatusCode = HX_STATUS_READY;
  1651.     pStatusDesc = NULL;
  1652.     ulPercentDone = 0;
  1653.  
  1654.     return hResult;
  1655. }
  1656. /************************************************************************
  1657.  * Method:
  1658.  *     IHXThreadSafeMethods::IsThreadSafe
  1659.  */
  1660. STDMETHODIMP_(UINT32)
  1661. CSmilFileFormat::IsThreadSafe()
  1662. {
  1663.     return HX_THREADSAFE_METHOD_FF_GETPACKET |
  1664. HX_THREADSAFE_METHOD_FSR_READDONE;
  1665. }