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

Symbian

开发平台:

C/C++

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