smlffpln.cpp
上传用户:zhongxx05
上传日期:2007-06-06
资源大小:33641k
文件大小:50k
- /* ***** BEGIN LICENSE BLOCK *****
- * Version: RCSL 1.0/RPSL 1.0
- *
- * Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved.
- *
- * The contents of this file, and the files included with this file, are
- * subject to the current version of the RealNetworks Public Source License
- * Version 1.0 (the "RPSL") available at
- * http://www.helixcommunity.org/content/rpsl unless you have licensed
- * the file under the RealNetworks Community Source License Version 1.0
- * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl,
- * in which case the RCSL will apply. You may also obtain the license terms
- * directly from RealNetworks. You may not use this file except in
- * compliance with the RPSL or, if you have a valid RCSL with RealNetworks
- * applicable to this file, the RCSL. Please see the applicable RPSL or
- * RCSL for the rights, obligations and limitations governing use of the
- * contents of the file.
- *
- * This file is part of the Helix DNA Technology. RealNetworks is the
- * developer of the Original Code and owns the copyrights in the portions
- * it created.
- *
- * This file, and the files included with this file, is distributed and made
- * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- *
- * Technology Compatibility Kit Test Suite(s) Location:
- * http://www.helixcommunity.org/content/tck
- *
- * Contributor(s):
- *
- * ***** END LICENSE BLOCK ***** */
- #define INITGUID
- #include <string.h>
- #include <ctype.h>
- #include <time.h>
- #include "smlffpln.ver"
- #include "hxtypes.h"
- #include "hxcom.h"
- #include "hxcomm.h"
- #include "ihxpckts.h"
- #include "hxfiles.h"
- #include "hxformt.h"
- #include "hxengin.h"
- #include "hxplugn.h"
- #include "hxpends.h"
- #include "hxasm.h"
- #include "hxprefs.h"
- #include "hxvsrc.h" /*IHXFileViewSource*/
- #include "chxfgbuf.h" /*CHXFragmentedBuffer */
- #include "hxmon.h"
- #include "hxerror.h"
- #include "hxstack.h"
- #include "hxslist.h"
- #include "hxstring.h"
- #include "chxpckts.h"
- #include "hxurl.h"
- #include "hxver.h"
- #include "verutil.h"
- #include "perplex.h"
- #include "xmlreslt.h"
- #include "smlpkt.h"
- #include "smlffpln.h"
- #if defined(HELIX_FEATURE_VIEWSOURCE)
- #include "escsmil.h" /* CEscapeSMIL */
- #include "shadvsrc.h" /* CShadowViewSource */
- #endif /* #if defined(HELIX_FEATURE_VIEWSOURCE) */
- #include "hxheap.h"
- #ifdef _DEBUG
- #undef HX_THIS_FILE
- static const char HX_THIS_FILE[] = __FILE__;
- #endif
- #ifdef _AIX
- #include "dllpath.h"
- ENABLE_MULTILOAD_DLLACCESS_PATHS(Smlffplin);
- #endif
- //#define DUMPFILEFORMATOUTPUT 1
- static const UINT32 FileChunkSize = 10000; //XXXBAB adjust
- static const UINT32 MaxPacketSize = 1000;
- #define XML_BAD_ATTRIBUTE_NAME "SMIL Parse Error: Error in attribute name"
- #define XML_BAD_TAG_NAME "SMIL Parse Error: Bad Tag Name"
- #define XML_MISSING_ATTRIBUTE_VALUE "SMIL Parse Error: Attribute value is missing"
- #define XML_NO_CLOSE_QUOTE "SMIL Parse Error: No closing quote"
- #define XML_MISSING_SPACE "SMIL Parse Error: Missing space"
- /****************************************************************************
- *
- * Function:
- *
- * HXCreateInstance()
- *
- * Purpose:
- *
- * Function implemented by all plugin DLL's to create an instance of
- * any of the objects supported by the DLL. This method is similar to
- * Window's CoCreateInstance() in its purpose, except that it only
- * creates objects from this plugin DLL.
- *
- * NOTE: Aggregation is never used. Therefore and outer unknown is
- * not passed to this function, and you do not need to code for this
- * situation.
- *
- */
- STDAPI ENTRYPOINT(HXCreateInstance)
- (
- IUnknown** /*OUT*/ ppIUnknown
- )
- {
- *ppIUnknown = (IUnknown*)(IHXPlugin*)new CSmilFileFormat();
- if (*ppIUnknown)
- {
- (*ppIUnknown)->AddRef();
- return HXR_OK;
- }
- return HXR_OUTOFMEMORY;
- }
- /****************************************************************************
- *
- * Function:
- *
- * CanUnload2()
- *
- * Purpose:
- *
- * Function implemented by all plugin DLL's if it returns HXR_OK
- * then the pluginhandler can unload the DLL
- *
- */
- STDAPI ENTRYPOINT(CanUnload2)(void)
- {
- return (CHXBaseCountingObject::ObjectsActive() > 0 ? HXR_FAIL : HXR_OK );
- }
- const char* const CSmilFileFormat::zm_pDescription = "RealNetworks SMIL File Format Plugin";
- const char* const CSmilFileFormat::zm_pCopyright = HXVER_COPYRIGHT;
- const char* const CSmilFileFormat::zm_pMoreInfoURL = HXVER_MOREINFO;
- const char* const CSmilFileFormat::zm_pFileMimeTypes[] = {"application/smil", NULL};
- // /NOTE: here's what's sent as stream mime types; if there is no default
- // namespace, then the file is treated as a SMIL 1.0 document and sent to
- // our old renderer. If the default namespace is unrecognized, then we
- // send "application/smil" and let the 2.0 or later SMIL renderer parse the
- // namespace in the smil file data and, if it recognizes it (e.g., the SMIL
- // renderer is a SMIL 3.0 renderer and the namespace is SMIL 3.0 but this
- // file format is of the SMIL 2.0 timeframe), then it plays it. If the
- // renderer doesn't recognize the namespace, it tries to auto upgrade with
- // the following as the AU mime-type request: "application/smil.[namespace]"
- // and the AU server then looks for a component (maybe not even an RN one)
- // that can handle this type of SMIL file.
- const char* const CSmilFileFormat::zm_pStreamMimeTypes[] = {
- // /The following are SMIL 1.0 stream mime types that will be handled
- // by SMIL 1.0-exclusive players (e.g., RealPlayer 8):
- "application/rma-driver", // /Beta-1, SMIL 1.0 stream
- "application/vnd.rn-rmadriver", // /SMIL 1.0 strm (no dflt namespace)
- // /The following is SMIL 1.0 Rec default namespace:
- // "http://www.w3.org/TR/REC-smil"
- "application/smil",
- // /The following is SMIL 2.0 Candidate Rec (i.e., pre SMIL 2.0 W3C Rec
- // status) default namespace:
- // "http://www.w3.org/2000/SMIL20/CR/Language"
- // The following is SMIL 2.0 Proposed Rec default namespace:
- // "http://www.w3.org/2001/SMIL20/PR/Language"
- // Both CR and PR use this stream mime type:
- "application/smil",
- // /The following is the SMIL 2.0 Recommendation namespace
- // "http://www.w3.org/2001/SMIL20/Language",
- "application/smil",
- // /We'll use this for any unrecognized SMIL file version (and note:
- // this is probably going to always be the same as the SMIL20 mime
- // type; the renderer will do all the work of deciding whether or not
- // to auto upgrade if it doesn't recognize the default namespace):
- "application/smil",
- NULL};
- const char* const CSmilFileFormat::zm_pFileExtensions[] = {"smi", "smil", NULL};
- const char* const CSmilFileFormat::zm_pFileOpenNames[] = {"SMIL File Format (*.smi,*.smil)", NULL};
- CSmilFileFormat::CSmilFileFormat()
- : m_lRefCount(0)
- , m_pContext(0)
- , m_pFileObject(0)
- , m_pFFResponse(0)
- , m_bHeaderSent(FALSE)
- , m_bChannelInit(FALSE)
- , m_bSentFirstChannel(FALSE)
- , m_bSourceInit(FALSE)
- , m_ulCurrentTime(0)
- , m_state(Ready)
- , m_pRequest(0)
- , m_pCommonClassFactory(0)
- , m_ulPacketCount(0)
- , m_ulCurrentPacket(0)
- , m_ulStreamVersion(0)
- , m_ulContentVersion(0)
- , m_pCurrentPacketData(NULL)
- , m_fileState(InContent)
- , m_smilFileVersion(SMILFileVersionSmil10)
- , m_pArrayOfPackets(0)
- , m_bLogErrors(FALSE)
- , m_pStartOfFile(NULL)
- {
- };
- CSmilFileFormat::~CSmilFileFormat()
- {
- Close();
- }
- /************************************************************************
- * Method:
- * IHXPlugin::InitPlugin
- * Purpose:
- * Initializes the plugin for use. This interface must always be
- * called before any other method is called. This is primarily needed
- * so that the plugin can have access to the context for creation of
- * IHXBuffers and IMalloc.
- */
- STDMETHODIMP CSmilFileFormat::InitPlugin(IUnknown* /*IN*/ pContext)
- {
- m_pContext = pContext;
- m_pContext->AddRef();
- m_pContext->QueryInterface(IID_IHXCommonClassFactory,
- (void**)&m_pCommonClassFactory);
- return HXR_OK;
- }
- /************************************************************************
- * Method:
- * IHXPlugin::GetPluginInfo
- * Purpose:
- * Returns the basic information about this plugin. Including:
- *
- * bLoadMultiple whether or not this plugin DLL can be loaded
- * multiple times. All File Formats must set
- * this value to TRUE.
- * pDescription which is used in about UIs (can be NULL)
- * pCopyright which is used in about UIs (can be NULL)
- * pMoreInfoURL which is used in about UIs (can be NULL)
- */
- STDMETHODIMP CSmilFileFormat::GetPluginInfo
- (
- REF(BOOL) /*OUT*/ bLoadMultiple,
- REF(const char*)/*OUT*/ pDescription,
- REF(const char*)/*OUT*/ pCopyright,
- REF(const char*)/*OUT*/ pMoreInfoURL,
- REF(ULONG32) /*OUT*/ ulVersionNumber
- )
- {
- bLoadMultiple = TRUE; // Must be true for file formats.
- pDescription = (const char*) zm_pDescription;
- pCopyright = (const char*) zm_pCopyright;
- pMoreInfoURL = (const char*) zm_pMoreInfoURL;
- ulVersionNumber = TARVER_ULONG32_VERSION;
- return HXR_OK;
- }
- /************************************************************************
- * Method:
- * IHXPlugin::GetObjFileFormatInfo
- * Purpose:
- * If this object is a file format object this method returns
- * information vital to the instantiation of file format plugins.
- * If this object is not a file format object, it should return
- * HXR_UNEXPECTED.
- */
- STDMETHODIMP CSmilFileFormat::GetFileFormatInfo
- (
- REF(const char**) /*OUT*/ pFileMimeTypes,
- REF(const char**) /*OUT*/ pFileExtensions,
- REF(const char**) /*OUT*/ pFileOpenNames
- )
- {
- pFileMimeTypes = (const char**) zm_pFileMimeTypes;
- pFileExtensions = (const char**) zm_pFileExtensions;
- pFileOpenNames = (const char**) zm_pFileOpenNames;
- return HXR_OK;
- }
- // *** IUnknown methods ***
- /////////////////////////////////////////////////////////////////////////
- // Method:
- // IUnknown::QueryInterface
- // Purpose:
- // Implement this to export the interfaces supported by your
- // object.
- //
- STDMETHODIMP CSmilFileFormat::QueryInterface(REFIID riid, void** ppvObj)
- {
- if (IsEqualIID(riid, IID_IUnknown))
- {
- AddRef();
- *ppvObj = this;
- return HXR_OK;
- }
- else if (IsEqualIID(riid, IID_IHXPlugin))
- {
- AddRef();
- *ppvObj = (IHXPlugin*)this;
- return HXR_OK;
- }
- else if (IsEqualIID(riid, IID_IHXFileFormatObject))
- {
- AddRef();
- *ppvObj = (IHXFileFormatObject*)this;
- return HXR_OK;
- }
- else if (IsEqualIID(riid, IID_IHXFileResponse))
- {
- AddRef();
- *ppvObj = (IHXFileResponse*)this;
- return HXR_OK;
- }
- else if (IsEqualIID(riid, IID_IHXPendingStatus))
- {
- AddRef();
- *ppvObj = (IHXPendingStatus*)this;
- return HXR_OK;
- }
- else if (IsEqualIID(riid, IID_IHXInterruptSafe))
- {
- AddRef();
- *ppvObj = (IHXInterruptSafe*)this;
- return HXR_OK;
- }
- else if (IsEqualIID(riid, IID_IHXThreadSafeMethods))
- {
- AddRef();
- *ppvObj = (IHXThreadSafeMethods*)this;
- return HXR_OK;
- }
- #if defined(HELIX_FEATURE_VIEWSOURCE)
- else if ( IsEqualIID(riid, IID_IHXFileViewSource) )
- {
- CShadowViewSource* pVsrc = new CShadowViewSource(m_pContext,
- (IUnknown*)(IHXPlugin*)this);
- if ( pVsrc == NULL )
- {
- return HXR_FAIL;
- }
- return pVsrc->QueryInterface(riid, ppvObj);
- }
- #endif /* #if defined(HELIX_FEATURE_VIEWSOURCE) */
- *ppvObj = NULL;
- return HXR_NOINTERFACE;
- }
- /////////////////////////////////////////////////////////////////////////
- // Method:
- // IUnknown::AddRef
- // Purpose:
- // Everyone usually implements this the same... feel free to use
- // this implementation.
- //
- STDMETHODIMP_(ULONG32) CSmilFileFormat::AddRef()
- {
- return InterlockedIncrement(&m_lRefCount);
- }
- /////////////////////////////////////////////////////////////////////////
- // Method:
- // IUnknown::Release
- // Purpose:
- // Everyone usually implements this the same... feel free to use
- // this implementation.
- //
- STDMETHODIMP_(ULONG32) CSmilFileFormat::Release()
- {
- if (InterlockedDecrement(&m_lRefCount) > 0)
- {
- return m_lRefCount;
- }
- delete this;
- return 0;
- }
- // *** IHXFileFormatObject methods ***
- STDMETHODIMP CSmilFileFormat::InitFileFormat
- (
- IHXRequest* /*IN*/ pRequest,
- IHXFormatResponse* /*IN*/ pFormatResponse,
- IHXFileObject* /*IN*/ pFileObject
- )
- {
- HX_RESULT ret = HXR_OK;
- m_pRequest = pRequest;
- m_pFFResponse = pFormatResponse;
- m_pFileObject = pFileObject;
- m_pRequest->AddRef();
- m_pFFResponse->AddRef();
- m_pFileObject->AddRef();
- // set stream and content versions
- m_ulStreamVersion = HX_ENCODE_PROD_VERSION(STREAM_MAJOR_VER,
- STREAM_MINOR_VER,
- STREAM_RELEASE,
- STREAM_BUILD);
- m_ulContentVersion = HX_ENCODE_PROD_VERSION(CONTENT_MAJOR_VER,
- CONTENT_MINOR_VER,
- CONTENT_RELEASE,
- CONTENT_BUILD);
-
- if ( m_pArrayOfPackets )
- {
- int s = m_pArrayOfPackets->GetSize();
- for ( int i = s; i > 0; --i )
- {
- PacketData* pckt = (PacketData*)(*m_pArrayOfPackets)[i-1];
- HX_RELEASE(pckt->pBuffer);
- HX_DELETE(pckt);
- (*m_pArrayOfPackets)[i-1] = NULL;
- }
- HX_DELETE(m_pArrayOfPackets);
- }
- m_pArrayOfPackets = new CHXPtrArray;
- if ( m_pCurrentPacketData )
- {
- HX_RELEASE(m_pCurrentPacketData->pBuffer);
- HX_DELETE(m_pCurrentPacketData);
- }
- m_ulCurrentBufferPos = 0;
- m_ulCurrentPacket = 0;
- // This file format is not a container type, so it only supports one
- // stream and therefore one header, but before we do that, we want to
- // make sure the file object is initialized; we can't actually return
- // the header count until the file init is done... (See InitDone).
- m_state = InitPending;
- // Note, we need to pass ourself to the FileObject, because this is its
- // first opportunity to know that we implement the IHXFileResponse
- // interface it will call for completed pending operations
- return m_pFileObject->Init( HX_FILE_READ, this);
- }
- STDMETHODIMP CSmilFileFormat::Close()
- {
- HX_RELEASE(m_pContext);
- if (m_pFileObject)
- {
- m_pFileObject->Close();
- HX_RELEASE(m_pFileObject);
- }
- if ( m_pArrayOfPackets )
- {
- int s = m_pArrayOfPackets->GetSize();
- for ( int i = s; i > 0; --i )
- {
- PacketData* pckt = (PacketData*)(*m_pArrayOfPackets)[i-1];
- HX_RELEASE(pckt->pBuffer);
- HX_DELETE(pckt);
- (*m_pArrayOfPackets)[i-1] = NULL;
- m_pArrayOfPackets->RemoveAt(i-1);
- }
- HX_DELETE(m_pArrayOfPackets);
- }
- if ( m_pCurrentPacketData )
- {
- HX_RELEASE(m_pCurrentPacketData->pBuffer);
- m_pCurrentPacketData->pNumPos = NULL;
- HX_DELETE(m_pCurrentPacketData);
- }
- HX_RELEASE(m_pFFResponse);
- HX_RELEASE(m_pRequest);
- HX_RELEASE(m_pCommonClassFactory);
- HX_RELEASE(m_pStartOfFile);
- return HXR_OK;
- }
- /////////////////////////////////////////////////////////////////////////
- // Method:
- // IHXFileFormatObject::GetFileHeader
- // Purpose:
- // Called by controller to ask the file format for the number of
- // headers in the file. The file format should call the
- // IHXFileFormatSession::HeaderCountReady() for the IHXFileFormat-
- // Session object that was passed in during initialization, when the
- // header count is available.
- //
- STDMETHODIMP CSmilFileFormat::GetFileHeader()
- {
- // If we are not ready then something has gone wrong
- if (m_state != Ready) return HXR_UNEXPECTED;
- IHXValues* pHeader = 0;
- if (HXR_OK != m_pCommonClassFactory->CreateInstance(CLSID_IHXValues,
- (void**)&pHeader))
- {
- return HXR_UNEXPECTED;
- }
- pHeader->SetPropertyULONG32("StreamCount", 1);
- m_pFFResponse->FileHeaderReady(HXR_OK, pHeader);
- HX_RELEASE(pHeader);
- return HXR_OK;
- }
- /////////////////////////////////////////////////////////////////////////
- // Method:
- // IHXFileFormatObject::GetStreamHeader
- // Purpose:
- // Called by controller to ask the file format for the header for
- // a particular stream in the file. The file format should call
- // IHXFileFormatSession::StreamHeaderReady() for IHXFileFormatSession
- // object that was passed in during initialization, when the header
- // is available.
- //
- STDMETHODIMP CSmilFileFormat::GetStreamHeader(UINT16 unStreamNumber)
- {
- // If we are not ready then something has gone wrong
- if (m_state != Ready) return HXR_UNEXPECTED;
- IHXBuffer* pASM = 0;
- char pBook[256]; /* Flawfinder: ignore */
- IHXValues* pHeader = 0;
- IHXBuffer* pBuffer = 0;
- if (HXR_OK != m_pCommonClassFactory->CreateInstance(CLSID_IHXValues,
- (void**)&pHeader))
- {
- return HXR_UNEXPECTED;
- }
- if (HXR_OK != m_pCommonClassFactory->CreateInstance(CLSID_IHXBuffer,
- (void**)&pBuffer))
- {
- return HXR_UNEXPECTED;
- }
- BOOL bBeta1Player = ::IsBeta1Player(m_pRequest);
- HX_RESULT pnrver = GetSMILFileVersion();
- if (HXR_OK != pnrver ||
- SMILFileVersionSmil10 == m_smilFileVersion)
- {
- if(bBeta1Player)
- {
- pBuffer->Set((const BYTE*)
- zm_pStreamMimeTypes[SMILFileVersionSmilBeta10],
- strlen(zm_pStreamMimeTypes[SMILFileVersionSmilBeta10])+1);
- }
- else
- {
- pBuffer->Set(
- (const BYTE*)zm_pStreamMimeTypes[SMILFileVersionSmil10],
- strlen(zm_pStreamMimeTypes[SMILFileVersionSmil10])+1);
- }
- }
- else if (SMILFileVersionSmil10Strict == m_smilFileVersion)
- {
- // /Send strictly-declared SMIL 1.0 streams to the SMIL 2.0 renderer
- pBuffer->Set((const BYTE*)
- zm_pStreamMimeTypes[SMILFileVersionSmil10Strict],
- strlen(zm_pStreamMimeTypes[SMILFileVersionSmil10Strict])+1);
- }
- else if (SMILFileVersionSmil20PreRec == m_smilFileVersion)
- {
- pBuffer->Set((const BYTE*)
- zm_pStreamMimeTypes[SMILFileVersionSmil20PreRec],
- strlen(zm_pStreamMimeTypes[SMILFileVersionSmil20PreRec])+1);
- }
- else if (SMILFileVersionSmil20 == m_smilFileVersion)
- {
- pBuffer->Set((const BYTE*)
- zm_pStreamMimeTypes[SMILFileVersionSmil20],
- strlen(zm_pStreamMimeTypes[SMILFileVersionSmil20])+1);
- }
- else // /Too high a version number as far as this ff is concerned:
- // /XXXEH: should we use the namespace (if there is one) to determine
- // the mime type and, if there is one, send it and let the player deal
- // with the auto update (if needed)? Or, should we encourage server
- // (hence smil ff) updating by just not serving the stream? That's
- // what I'm doing here:
- {
- pBuffer->Set((const BYTE*)
- zm_pStreamMimeTypes[SMILFileVersionUnknown],
- strlen(zm_pStreamMimeTypes[SMILFileVersionUnknown])+1);
- }
- pHeader->SetPropertyCString("MimeType", pBuffer);
- HX_RELEASE(pBuffer);
- pHeader->SetPropertyULONG32("StreamNumber", unStreamNumber);
- //XXXEH- removed 20000 (20sec) duration that BAB put in "to avoid problem
- // in core" in 1998(?). 0 milliseconds seems to work fine now (3/2000):
- pHeader->SetPropertyULONG32("Duration", 0);
- pHeader->SetPropertyULONG32("PreRoll", 1000); //XXXBAB 'cause Rahul told me to
- pHeader->SetPropertyULONG32("AvgBitRate", 1000);
- pHeader->SetPropertyULONG32("StreamVersion", m_ulStreamVersion);
- pHeader->SetPropertyULONG32("ContentVersion", m_ulContentVersion);
- //
- // set ASM rule book
- //
- sprintf(pBook, "TimestampDelivery=TRUE,priority=10;"); /* Flawfinder: ignore */
- if(HXR_OK == m_pCommonClassFactory->CreateInstance(CLSID_IHXBuffer,
- (void**)&pASM))
- {
- pASM->Set((BYTE*)pBook, strlen(pBook)+1);
- pHeader->SetPropertyCString("ASMRuleBook", pASM);
- HX_RELEASE(pASM);
- }
- m_bHeaderSent = TRUE;
- m_pFFResponse->StreamHeaderReady(HXR_OK, pHeader);
- HX_RELEASE(pHeader);
- return HXR_OK;
- }
- /////////////////////////////////////////////////////////////////////////
- // Method:
- // IHXFileFormatObject::GetPacket
- // Purpose:
- // Called by controller to ask the file format for the next packet
- // for a particular stream in the file. The file format should call
- // IHXFileFormatSession::PacketReady() for the IHXFileFormatSession
- // object that was passed in during initialization, when the packet
- // is available.
- //
- STDMETHODIMP CSmilFileFormat::GetPacket(UINT16 unStreamNumber)
- {
- HX_RESULT result = HXR_OK;
- // If we are not ready then something has gone wrong
- if (m_state != Ready) return HXR_UNEXPECTED;
- if (!m_bHeaderSent)
- {
- return HXR_UNEXPECTED;
- }
- IHXPacket* pPacket = NULL;
- result = m_pCommonClassFactory->CreateInstance(CLSID_IHXPacket,
- (void**)&pPacket);
- if( SUCCEEDED(result) )
- {
- if(m_ulCurrentPacket >= m_ulPacketCount)
- {
- m_pFFResponse->StreamDone(unStreamNumber);
- }
- else
- {
- PacketData* pckt = (PacketData*)(*m_pArrayOfPackets)[m_ulCurrentPacket++];
-
- if ( pckt->pNumPos )
- {
- char buf[10]; /* Flawfinder: ignore */
- sprintf(buf, "%u", m_ulPacketCount); /* Flawfinder: ignore */
- HX_ASSERT(strlen(buf) < 7);
- strncpy(pckt->pNumPos, buf, strlen(buf)); /* Flawfinder: ignore */
- pckt->pNumPos = NULL;
- }
- #ifdef DUMPFILEFORMATOUTPUT
- FILE* stream = fopen( "C:\PacketData.smil", "a" );
- fprintf( stream, "%sn", (const char*)pckt->pBuffer->GetBuffer());
- fclose( stream );
- #endif
- pPacket->Set(pckt->pBuffer, 0, unStreamNumber, HX_ASM_SWITCH_ON, 0);
- m_pFFResponse->PacketReady(HXR_OK, pPacket);
- }
- }
- HX_RELEASE(pPacket);
- return result;
- }
- /////////////////////////////////////////////////////////////////////////
- // Method:
- // IHXFileFormatObject::Seek
- // Purpose:
- // Called by controller to tell the file format to seek to the
- // nearest packet to the requested offset. The file format should
- // call IHXFileFormatSession::SeekDone() for the IHXFileFormat-
- // Session object that was passed in during initialization, when
- // the seek has completed.
- //
- STDMETHODIMP CSmilFileFormat::Seek(ULONG32 ulOffset)
- {
- m_pFFResponse->SeekDone(HXR_OK);
- return HXR_OK;
- }
- /////////////////////////////////////////////////////////////////////////
- // Method:
- // IHXFileResponse::InitDone
- // Purpose:
- // Notification interface provided by users of the IHXFileObject
- // interface. This method is called by the IHXFileObject when the
- // initialization of the file is complete, and the Mime type is
- // available for the request file. If the URL is not valid for the
- // file system, the status HXR_FAILED should be returned,
- // with a mime type of NULL. If the URL is valid but the mime type
- // is unknown, then the status HXR_OK should be returned with
- // a mime type of NULL.
- //
- STDMETHODIMP CSmilFileFormat::InitDone
- (
- HX_RESULT status
- )
- {
- HX_RESULT rc = HXR_OK;
- // If we are not ready then something has gone wrong
- if (m_state != InitPending) return HXR_UNEXPECTED;
- // Now it's time to read the file
- m_state = ReadPending;
- if (status != HXR_OK)
- {
- rc = m_pFFResponse->InitDone(status);
- }
- else
- {
- // check to see if we have logged an error for this file
- // in the last hour. If we have we will not log an error.
-
- UpdateErrorCaching();
-
- rc = m_pFileObject->Read(FileChunkSize);
- }
- return rc;
- }
- HX_RESULT CSmilFileFormat::UpdateErrorCaching()
- {
- IHXValues* pRequestHeaders = NULL;
- UINT32 ulID = 0, ulSes = 0;
-
- IHXRegistry* pReg = NULL;
- m_pContext->QueryInterface(IID_IHXRegistry, (void**)&pReg);
-
- HX_RESULT ret = m_pRequest->GetRequestHeaders(pRequestHeaders);
- if (!pRequestHeaders)
- {
- // succeeds even when there are no request headers.
- ret = HXR_FAIL;
- }
-
- if (SUCCEEDED(ret))
- {
- IHXBuffer* pID = NULL;
- ret = pRequestHeaders->GetPropertyCString("ConnID", pID);
- if (SUCCEEDED(ret) && pID)
- {
- ulID = atoi((char*)pID->GetBuffer());
- }
- HX_RELEASE(pID);
- }
-
- if (SUCCEEDED(ret))
- {
- IHXBuffer* pSes = NULL;
- if (SUCCEEDED(pRequestHeaders->GetPropertyCString("SessionNumber", pSes)))
- {
- ulSes = atoi((char*)pSes->GetBuffer());
- }
- else
- {
- // assume 0
- ulSes = 0;
- }
- HX_RELEASE(pSes);
- }
- IHXBuffer* pURL = NULL;
- if (SUCCEEDED(ret))
- {
- const char form[] = "client.%u.session.%u.URL";
- char pRegkey[sizeof(form) + 20]; /* Flawfinder: ignore */
- sprintf(pRegkey, form, ulID, ulSes); /* Flawfinder: ignore */
- ret = pReg->GetStrByName(pRegkey, pURL);
- }
- char* buf = NULL;
- const char regtemp[] = "server.smilerrorlog.";
- if ( SUCCEEDED(ret) )
- {
- buf = new char[sizeof(regtemp) + pURL->GetSize()];
- if (!buf)
- {
- ret = HXR_OUTOFMEMORY;
- }
- }
- if (SUCCEEDED(ret))
- {
- strcpy(buf, regtemp); /* Flawfinder: ignore */
- char* pos = buf + sizeof(regtemp) - 1;
- const char* url = (const char*)pURL->GetBuffer();
- // escape the '.'s
- while (*url && pos < buf + sizeof(regtemp) + pURL->GetSize())
- {
- if (*url == '.' || *url == '/')
- {
- *pos++ = '%';
- ++url;
- }
- else
- {
- *pos++ = *url++;
- }
- }
- *pos = ' ';
- }
- if (SUCCEEDED(ret))
- {
- INT32 lTime = 0;
- INT32 lNow = time(NULL);
- if (SUCCEEDED(pReg->GetIntByName(buf, lTime)))
- {
- if ((lNow - lTime) > 3600)
- {
- m_bLogErrors = TRUE;
- ret = pReg->SetIntByName(buf, lNow);
- }
- else
- {
- m_bLogErrors = FALSE;
- }
- }
- else
- {
- m_bLogErrors = TRUE;
- pReg->AddInt(buf, lNow);
- }
- }
- HX_RELEASE(pReg);
- HX_RELEASE(pRequestHeaders);
- HX_VECTOR_DELETE(buf);
- HX_RELEASE(pURL);
- return ret;
- }
- /////////////////////////////////////////////////////////////////////////
- // Method:
- // IHXFileResponse::CloseDone
- // Purpose:
- // Notification interface provided by users of the IHXFileObject
- // interface. This method is called by the IHXFileObject when the
- // close of the file is complete.
- //
- STDMETHODIMP CSmilFileFormat::CloseDone(HX_RESULT status)
- {
- return HXR_OK;
- }
- /////////////////////////////////////////////////////////////////////////
- // Method:
- // IHXFileResponse::ReadDone
- // Purpose:
- // Notification interface provided by users of the IHXFileObject
- // interface. This method is called by the IHXFileObject when the
- // last read from the file is complete and a buffer is available.
- //
- STDMETHODIMP CSmilFileFormat::ReadDone
- (
- HX_RESULT status,
- IHXBuffer* pBuffer
- )
- {
- HX_RESULT result = HXR_OK;
- if ( SUCCEEDED(status) )
- {
- HX_ASSERT(pBuffer);
- // /For determining what type file this is (via namespace URI), we'll
- // hold onto the first pBuffer for later when we handle stream header:
- if (!m_pStartOfFile)
- {
- pBuffer->AddRef();
- m_pStartOfFile = pBuffer;
- }
- BreakUpBuffer(pBuffer);
- // recurse...
- m_pFileObject->Read(FileChunkSize);
- }
- else
- {
- // check see if we have a packet that needs added to the array.
- if ( m_pCurrentPacketData )
- {
- UCHAR* pCb = m_pCurrentPacketData->pBuffer->GetBuffer();
- pCb[m_ulCurrentBufferPos++] = '"';
- pCb[m_ulCurrentBufferPos++] = ')';
- pCb[m_ulCurrentBufferPos++] = ' ';
- m_pCurrentPacketData->pBuffer->SetSize(m_ulCurrentBufferPos);
- m_pArrayOfPackets->Add((void*)m_pCurrentPacketData);
- m_pCurrentPacketData = NULL;
- m_ulCurrentBufferPos = 0;
- }
- // finished reading, calculate the number of packets to send:
- m_ulPacketCount = m_ulCurrentPacket;
- m_ulCurrentPacket = 0;
- m_state = Ready;
- m_pFFResponse->InitDone(result);
- }
- return result;
- }
- /////////////////////////////////////////////////////////////////////////
- // Method:
- // GetSMILFileVersion
- // Purpose:
- // This Function will break the buffer into packets.
- //
- // This function maintains a state, such that multiple buffers should
- // Be able to be passed into it at any point...
- //
- HX_RESULT
- CSmilFileFormat::GetSMILFileVersion()
- {
- HX_RESULT pnreslt = HXR_OK;
- const char* pSmilTag = NULL;
- const char* pCloseOfSmilTag = NULL;
- const char* pXmlns = NULL;
- const char* pXmlnsOpenQuotationMark = NULL;
- const char* pBuf = NULL;
- ULONG32 ulBufLen = 0;
- const char* pEqualsSign = NULL;
- const char* pTmp = NULL;
- char* pTmp2 = NULL;
- char* pszStartOfFile = NULL;
- ULONG32 ulCount = 0;
- LONG32 lNumCommentsOpen = 0;
- if (!m_pStartOfFile)
- {
- pnreslt = HXR_BUFFERTOOSMALL;
- goto cleanup;
- }
- // /Fixes PR 59282: m_pStartOfFile is not necessarily NULL-terminated,
- // so we have to limit our access of it to the size of the buffer (duh!):
- ulBufLen = m_pStartOfFile->GetSize();
- pBuf = (const char*)m_pStartOfFile->GetBuffer();
- if (!pBuf || !ulBufLen)
- {
- pnreslt = HXR_BUFFERTOOSMALL;
- goto cleanup;
- }
- pszStartOfFile = new char[ulBufLen+1];
- if (!pszStartOfFile)
- {
- pnreslt = HXR_OUTOFMEMORY;
- goto cleanup;
- }
- // /Now, walk through and copy each character from non-NULL terminated buf:
- pTmp = pBuf;
- pTmp2 = pszStartOfFile;
- while (*pTmp && ulCount<ulBufLen)
- {
- *pTmp2 = *pTmp;
- pTmp++;
- pTmp2++;
- ulCount++;
- }
- pszStartOfFile[ulCount] = ' '; // /NULL-terminate it.
- // /Now, let's walk through the start of pszStartOfFile looking for
- // namespace declaration(s) inside the <smil ...> tag, and make sure that
- // the smil tag is NOT inside of a comment:
- pTmp = pszStartOfFile;
- while (*pTmp)
- {
- if (0==strncmp(pTmp, "<!--", 4) )
- {
- lNumCommentsOpen++;
- pTmp+=4;
- }
- else if (0==strncmp(pTmp, "-->", 3) )
- {
- lNumCommentsOpen--;
- pTmp+=3;
- }
- else if (lNumCommentsOpen<=0 && 0==strncmp(pTmp, "<smil", 5) )
- {
- pSmilTag = pTmp; // /We found the smil tag outside of a comment.
- break;
- }
- else
- {
- pTmp++;
- }
- }
- if (!pSmilTag || ulBufLen-(pSmilTag-pszStartOfFile) < 6) // /6==min size: "<smil>"
- {
- // /There had better be a <smil...> tag!
- pnreslt = HXR_UNEXPECTED;
- goto cleanup;
- }
- pCloseOfSmilTag = strchr(pSmilTag, '>');
- // /Add 6 so that we don't allow "<smilxmlns ..." (which is invalid):
- pXmlns = strstr(pSmilTag+6, "xmlns");
- if (pXmlns && isspace(*(pXmlns-1)) ) // /"xmlns" must follow a space.
- {
- pEqualsSign = strchr(pXmlns, '=');
- if (pEqualsSign)
- {
- pXmlnsOpenQuotationMark = strchr(pXmlns, '"');
- }
- }
- if (pXmlns && pEqualsSign && pXmlnsOpenQuotationMark &&
- (!pCloseOfSmilTag || pXmlns<pCloseOfSmilTag))
- {
- BOOL bIsValidNamespaceDeclaration = TRUE;
- // /First, make sure there is nothing but whitespace between
- // the "xmlns" and the '=' as well as between the '=' and the
- // quotation mark:
- char* pTmp = (char*)(pXmlns + strlen("xmlns"));
- while (pTmp<pEqualsSign)
- {
- if (!isspace(*pTmp))
- {
- bIsValidNamespaceDeclaration = FALSE;
- break;
- }
- pTmp++;
- }
- pTmp = (char*)(pEqualsSign+1);
- while(pTmp<pXmlnsOpenQuotationMark)
- {
- if (!isspace(*pTmp))
- {
- bIsValidNamespaceDeclaration = FALSE;
- break;
- }
- pTmp++;
- }
- if (bIsValidNamespaceDeclaration)
- {
- // /Note: SMIL 1.0 namespace is default and is:
- // "http://www.w3.org/TR/REC-smil". Note that if this is
- // tagged (first) with a SMIL 1.0 namespace followed by
- // another namespace, then this is a 1.0 file and we'll let
- // the 1.0 renderer get it and do what it can with the 2.0
- // stuff (namely ignore it):
- const char* pSMIL10Namespace = strstr(pXmlnsOpenQuotationMark,
- "http://www.w3.org/TR/REC-smil"");
- // /This in the final SMIL 2.0 rec:
- const char* pSMIL20Namespace = strstr(pXmlnsOpenQuotationMark,
- "http://www.w3.org/2001/SMIL20/Language"");
- const char* pSMIL20NamespaceCandidateRec = strstr(
- pXmlnsOpenQuotationMark,
- "http://www.w3.org/2000/SMIL20/CR/Language"");
- // /Fixes PR 55749: allow new PR namespace:
- const char* pSMIL20NamespaceProposedRec = strstr(
- pXmlnsOpenQuotationMark,
- "http://www.w3.org/2001/SMIL20/PR/Language"");
- const char* pSMIL20NamespaceLastCall = strstr(
- pXmlnsOpenQuotationMark,
- "http://www.w3.org/TR/REC-smil/2000/SMIL20/LC/"");
- // /If the SMIL 1.0 namespace is declared prior to any other
- // version of SMIL's namespace, then this is a SMIL 1.0 doc:
- if (pSMIL10Namespace && (!pSMIL20Namespace ||
- pSMIL10Namespace < pSMIL20Namespace) &&
- (!pSMIL20NamespaceCandidateRec ||
- pSMIL10Namespace < pSMIL20NamespaceCandidateRec) &&
- (!pSMIL20NamespaceProposedRec ||
- pSMIL10Namespace < pSMIL20NamespaceProposedRec) &&
- (!pSMIL20NamespaceLastCall ||
- pSMIL10Namespace < pSMIL20NamespaceLastCall) )
- {
- m_smilFileVersion = SMILFileVersionSmil10Strict;
- }
- else if (pSMIL20NamespaceCandidateRec && (!pSMIL20Namespace ||
- pSMIL20NamespaceCandidateRec < pSMIL20Namespace))
- {
- m_smilFileVersion = SMILFileVersionSmil20PreRec;
- }
- else if (pSMIL20NamespaceProposedRec && (!pSMIL20Namespace ||
- pSMIL20NamespaceProposedRec < pSMIL20Namespace))
- {
- m_smilFileVersion = SMILFileVersionSmil20PreRec;
- }
- // /Treat both LC (Last Call) and CR (Candidate Rec) as "PreRec":
- else if (pSMIL20NamespaceLastCall && (!pSMIL20Namespace ||
- pSMIL20NamespaceLastCall < pSMIL20Namespace))
- {
- m_smilFileVersion = SMILFileVersionSmil20PreRec;
- }
- else if (pSMIL20Namespace)
- {
- m_smilFileVersion = SMILFileVersionSmil20;
- }
- else
- {
- m_smilFileVersion = SMILFileVersionUnknown;
- }
- }
- }
- cleanup:
- if (pszStartOfFile)
- {
- HX_VECTOR_DELETE(pszStartOfFile);
- }
- return pnreslt;
- }
- /////////////////////////////////////////////////////////////////////////
- // Method:
- // BreakUpBuffer
- // Purpose:
- // This Function will break the buffer into packets.
- //
- // This function maintains a state, such that multiple buffers should
- // Be able to be passed into it at any point...
- //
- // XXX jhug
- // This doesn't allow text between tags... Future versions of SMIL might
- // support this... this will need a bit of a modification.
- HX_RESULT
- CSmilFileFormat::BreakUpBuffer(IHXBuffer* pBuffer)
- {
- // walk through the buffer and escape all "s
- // also forget about all white space and comments...
- // also break the buffer up into packets for easy access.
- HX_RESULT result = HXR_OK;
- UCHAR* pCb = NULL;
- if ( m_pCurrentPacketData )
- {
- pCb = m_pCurrentPacketData->pBuffer->GetBuffer();
- }
- const UCHAR* pData = pBuffer->GetBuffer();
- UINT32 ulSize = pBuffer->GetSize();
- for ( UINT32 ulPos = 0; ulPos < ulSize && pData[ulPos]; ++ulPos )
- {
- // three for the end of the packet structure, and 1 in case we have
- // to escape a char...
- if ( m_ulCurrentBufferPos >= MaxPacketSize - 4 )
- {
- pCb[m_ulCurrentBufferPos++] = '"';
- pCb[m_ulCurrentBufferPos++] = ')';
- pCb[m_ulCurrentBufferPos++] = ' ';
- m_pCurrentPacketData->pBuffer->SetSize(m_ulCurrentBufferPos);
- m_pArrayOfPackets->Add((void*)m_pCurrentPacketData);
- m_pCurrentPacketData = NULL;
- m_ulCurrentBufferPos = 0;
- pCb = NULL;
- }
- if ( !m_pCurrentPacketData )
- {
- m_pCurrentPacketData = new PacketData;
- if ( m_pCurrentPacketData == NULL )
- {
- result = HXR_OUTOFMEMORY;
- }
- else
- {
- m_pCurrentPacketData->pBuffer = NULL;
- m_pCurrentPacketData->pNumPos = NULL;
- result = m_pCommonClassFactory->CreateInstance(CLSID_IHXBuffer,
- (void**)&m_pCurrentPacketData->pBuffer);
- }
- if ( SUCCEEDED(result) )
- {
- result = m_pCurrentPacketData->pBuffer->SetSize(MaxPacketSize);
- }
- if ( SUCCEEDED(result) )
- {
- pCb = m_pCurrentPacketData->pBuffer->GetBuffer();
- //memset(pCb, 0xef, MaxPacketSize);
- sprintf((char*)pCb, "(smil-document (ver %s)(npkt %ld)"
- "(ttlpkt 0 )(doc "",
- RMA_DRIVER_VERSION, ++m_ulCurrentPacket);
- m_ulCurrentBufferPos = strlen((char*)pCb);
- // back up to the begining of the total number position.
- // 13 is position back in header...
- m_pCurrentPacketData->pNumPos = (char*)pCb +
- m_ulCurrentBufferPos - 13;
- }
- }
- if ( FAILED(result) )
- {
- break;
- }
- switch ( m_fileState )
- {
- case InContent:
- {
- if ( pData[ulPos] == '"' )
- {
- pCb[m_ulCurrentBufferPos++] = '\';
- pCb[m_ulCurrentBufferPos++] = '"';
- }
- else if ( pData[ulPos] == '\' )
- {
- pCb[m_ulCurrentBufferPos++] = '\';
- pCb[m_ulCurrentBufferPos++] = '"';
- }
- else if ( pData[ulPos] == '<' )
- {
- if ( pData[ulPos+1] == '!' )
- {
- if ( pData[ulPos+2] == '-'
- && pData[ulPos+3] == '-' )
- {
- ulPos += 3;
- m_fileState = InComment;
- }
- else if ( pData[ulPos+2] == '[' &&
- pData[ulPos+3] == 'C' &&
- pData[ulPos+4] == 'D' &&
- pData[ulPos+5] == 'A' &&
- pData[ulPos+6] == 'T' &&
- pData[ulPos+7] == 'A' &&
- pData[ulPos+8] == '[' )
- {
- pCb[m_ulCurrentBufferPos++] = pData[ulPos++];
- pCb[m_ulCurrentBufferPos++] = pData[ulPos++];
- pCb[m_ulCurrentBufferPos++] = pData[ulPos++];
- pCb[m_ulCurrentBufferPos++] = pData[ulPos++];
- pCb[m_ulCurrentBufferPos++] = pData[ulPos++];
- pCb[m_ulCurrentBufferPos++] = pData[ulPos++];
- pCb[m_ulCurrentBufferPos++] = pData[ulPos];
- m_fileState = InCDATA;
- }
- else if ( pData[ulPos+2] == 'D' &&
- pData[ulPos+3] == 'O' &&
- pData[ulPos+4] == 'C' &&
- pData[ulPos+5] == 'T' &&
- pData[ulPos+6] == 'Y' &&
- pData[ulPos+7] == 'P' &&
- pData[ulPos+8] == 'E' )
- {
- pCb[m_ulCurrentBufferPos++] = pData[ulPos++];
- pCb[m_ulCurrentBufferPos++] = pData[ulPos++];
- pCb[m_ulCurrentBufferPos++] = pData[ulPos++];
- pCb[m_ulCurrentBufferPos++] = pData[ulPos++];
- pCb[m_ulCurrentBufferPos++] = pData[ulPos++];
- pCb[m_ulCurrentBufferPos++] = pData[ulPos++];
- pCb[m_ulCurrentBufferPos++] = pData[ulPos];
- m_fileState = InDTD;
- }
- }
- else
- {
- pCb[m_ulCurrentBufferPos++] = pData[ulPos];
- m_fileState = InTagName;
- }
- }
- // preserve all lines so line number error reporting is
- // accurate
- else if ( isspace(pData[ulPos]) && pData[ulPos] != 'n' &&
- pData[ulPos] != 'r')
- {
- //continue...
- }
- //If we find rx where x is not n, then keep it else let
- // the next char (n) be kept in the next iteration of
- // this loop. This accomodates Mac-authored 'r'-only
- // text. Think Different (pain is "different").
- else if (isspace(pData[ulPos]) && ('r' == pData[ulPos] &&
- (ulPos+1 < ulSize && pData[ulPos+1]) &&
- 'n' == pData[ulPos+1]) )
- {
- //continue...
- }
- else
- {
- if ('r' == pData[ulPos])
- {
- pCb[m_ulCurrentBufferPos++] = 'n';
- }
- else
- {
- pCb[m_ulCurrentBufferPos++] = pData[ulPos];
- }
- }
- }
- break;
- case InDTD:
- {
- if ( pData[ulPos] == '[' )
- {
- m_fileState = InDTDMarkup;
- }
- else if ( pData[ulPos] == '>' )
- {
- m_fileState = InContent;
- }
- else if ( pData[ulPos] == '"' )
- {
- pCb[m_ulCurrentBufferPos++] = '\';
- }
- else if ( pData[ulPos] == '\' )
- {
- pCb[m_ulCurrentBufferPos++] = '\';
- }
- pCb[m_ulCurrentBufferPos++] = pData[ulPos];
- }
- break;
- case InDTDMarkup:
- {
- if ( pData[ulPos] == ']' )
- {
- m_fileState = InDTD;
- }
- else if ( pData[ulPos] == '"' )
- {
- pCb[m_ulCurrentBufferPos++] = '\';
- }
- else if ( pData[ulPos] == '\' )
- {
- pCb[m_ulCurrentBufferPos++] = '\';
- }
- pCb[m_ulCurrentBufferPos++] = pData[ulPos];
- }
- break;
- case InCDATA:
- {
- if ( pData[ulPos] == ']' && pData[ulPos+1] == ']' && pData[ulPos+2] == '>' )
- {
- pCb[m_ulCurrentBufferPos++] = pData[ulPos++];
- m_fileState = InContent;
- }
- else if ( pData[ulPos] == '"' )
- {
- pCb[m_ulCurrentBufferPos++] = '\';
- }
- else if ( pData[ulPos] == '\' )
- {
- pCb[m_ulCurrentBufferPos++] = '\';
- }
- pCb[m_ulCurrentBufferPos++] = pData[ulPos];
- }
- break;
- case InTagName:
- {
- // go to first white space
- // let's escape " and even though they are ilegal.
- if ( isspace(pData[ulPos]) )
- {
- m_fileState = InBeginAttributeName;
- }
- else if ( pData[ulPos] == '>' )
- {
- m_fileState = InContent;
- }
- else if ( pData[ulPos] == '"' )
- {
- ReportError(HXR_XML_GENERALERROR, XML_BAD_TAG_NAME);
- pCb[m_ulCurrentBufferPos++] = '\';
- }
- else if ( pData[ulPos] == '\' )
- {
- ReportError(HXR_XML_GENERALERROR, XML_BAD_TAG_NAME);
- pCb[m_ulCurrentBufferPos++] = '\';
- }
- pCb[m_ulCurrentBufferPos++] = pData[ulPos];
- }
- break;
- case InTag:
- {
- if ( pData[ulPos] == '>' || (pData[ulPos] == '/' &&
- pData[ulPos+1] == '>'))
- {
- pCb[m_ulCurrentBufferPos++] = pData[ulPos];
- m_fileState = InContent;
- }
- else
- {
- // grab the first char... keep it and switch states.
- // it should be a space... but if it isn't we will
- // not complain because the renderer accepts no
- // space.
- pCb[m_ulCurrentBufferPos++] = pData[ulPos];
- m_fileState = InBeginAttributeName;
- if (!isspace(pData[ulPos]))
- {
- ReportError(HXR_XML_GENERALERROR,
- XML_MISSING_SPACE);
- }
- }
- }
- break;
- case InBeginAttributeName:
- {
- if ( isspace(pData[ulPos]) )
- {
- // preserve all lines so line numbers in error messages
- // are accurate
- if (pData[ulPos] == 'n' || ('r' == pData[ulPos] &&
- ulPos+1 < ulSize && 'n' != pData[ulPos+1]) )
- {
- if ('r' == pData[ulPos])
- {
- pCb[m_ulCurrentBufferPos++] = 'n';
- }
- else
- {
- pCb[m_ulCurrentBufferPos++] = pData[ulPos];
- }
- }
- // continue...
- }
- else if ( pData[ulPos] == '=' )
- {
- ReportError(HXR_XML_GENERALERROR,
- XML_BAD_ATTRIBUTE_NAME);
- m_fileState = InBeginAttributeValue;
- pCb[m_ulCurrentBufferPos++] = pData[ulPos];
- }
- else if ( pData[ulPos] == '>' || (pData[ulPos] == '/'
- && pData[ulPos+1] == '>'))
- {
- m_fileState = InContent;
- pCb[m_ulCurrentBufferPos++] = pData[ulPos];
- }
- else
- {
- m_fileState = InAttributeName;
- pCb[m_ulCurrentBufferPos++] = pData[ulPos];
- }
- }
- break;
- case InAttributeName:
- {
- if ( isspace(pData[ulPos]) )
- {
- m_fileState = InEndAttributeName;
- pCb[m_ulCurrentBufferPos++] = pData[ulPos];
- }
- else if ( pData[ulPos] == '=' )
- {
- m_fileState = InBeginAttributeValue;
- pCb[m_ulCurrentBufferPos++] = pData[ulPos];
- }
- else if ( pData[ulPos] == '>' )
- {
- ReportError(HXR_XML_GENERALERROR,
- XML_MISSING_ATTRIBUTE_VALUE);
- m_fileState = InContent;
- pCb[m_ulCurrentBufferPos++] = pData[ulPos];
- }
- else if (pData[ulPos] == ''' || pData[ulPos] == '"')
- {
- ReportError(HXR_XML_GENERALERROR,
- XML_BAD_ATTRIBUTE_NAME);
- m_cQuote = pData[ulPos];
- if (m_cQuote == '"')
- {
- pCb[m_ulCurrentBufferPos++] = '\';
- }
- pCb[m_ulCurrentBufferPos++] = pData[ulPos];
- m_fileState = InAttributeValue;
- }
- else
- {
- pCb[m_ulCurrentBufferPos++] = pData[ulPos];
- }
- }
- break;
- case InEndAttributeName:
- {
- if ( isspace(pData[ulPos]) )
- {
- // preserve all lines so line numbers in error messages
- // are accurate
- if (pData[ulPos] == 'n' || ('r' == pData[ulPos] &&
- ulPos+1 < ulSize && 'n' != pData[ulPos+1]) )
- {
- if ('r' == pData[ulPos])
- {
- pCb[m_ulCurrentBufferPos++] = 'n';
- }
- else
- {
- pCb[m_ulCurrentBufferPos++] = pData[ulPos];
- }
- }
- // continue..
- }
- else if ( pData[ulPos] == '=' )
- {
- m_fileState = InBeginAttributeValue;
- pCb[m_ulCurrentBufferPos++] = pData[ulPos];
- }
- else if ( pData[ulPos] == '>' )
- {
- ReportError(HXR_XML_GENERALERROR,
- XML_MISSING_ATTRIBUTE_VALUE);
- // illegal.
- m_fileState = InContent;
- pCb[m_ulCurrentBufferPos++] = pData[ulPos];
- }
- else
- {
- // hmm. we got a non whitespace before the =
- // push a ' ' on so the render will get this error.
- pCb[m_ulCurrentBufferPos++] = ' ';
- //First, let's see if we have a ["] or a [']
- // (i.e., an attribute value start) in which
- // case the author must have forgotten to
- // put an '=' between the name/value pair.
- // In this case, we need to keep the renderers
- // from firing off an error with old bad content,
- // so we pretend we're in the "InAttributeValue"
- // state:
- if ( pData[ulPos] == ''' )
- {
- ReportError(HXR_XML_GENERALERROR,
- XML_BAD_ATTRIBUTE_NAME);
- m_cQuote = pData[ulPos];
- m_fileState = InAttributeValue;
- }
- else if ( pData[ulPos] == '"' )
- {
- ReportError(HXR_XML_GENERALERROR,
- XML_BAD_ATTRIBUTE_NAME);
- m_cQuote = pData[ulPos];
- pCb[m_ulCurrentBufferPos++] = '\';
- m_fileState = InAttributeValue;
- }
- else
- {
- ReportError(HXR_XML_BADATTRIBUTE,
- XML_BAD_ATTRIBUTE_NAME);
- // lets go back to the attribute name state.
- m_fileState = InAttributeName;
- }
- //Push the character back on so the renderer
- // can deal with it:
- pCb[m_ulCurrentBufferPos++] = pData[ulPos];
- }
- }
- break;
- case InBeginAttributeValue:
- {
- if ( isspace(pData[ulPos]) )
- {
- // preserve all lines so line numbers in error messages
- // are accurate
- if (pData[ulPos] == 'n' || ('r' == pData[ulPos] &&
- ulPos+1 < ulSize && 'n' != pData[ulPos+1]) )
- {
- if ('r' == pData[ulPos])
- {
- pCb[m_ulCurrentBufferPos++] = 'n';
- }
- else
- {
- pCb[m_ulCurrentBufferPos++] = pData[ulPos];
- }
- }
- // continue...
- }
- else if ( pData[ulPos] == ''' )
- {
- m_cQuote = pData[ulPos];
- m_fileState = InAttributeValue;
- pCb[m_ulCurrentBufferPos++] = pData[ulPos];
- }
- else if ( pData[ulPos] == '"' )
- {
- m_cQuote = pData[ulPos];
- pCb[m_ulCurrentBufferPos++] = '\';
- pCb[m_ulCurrentBufferPos++] = '"';
- m_fileState = InAttributeValue;
- }
- else if ( pData[ulPos] == '>' )
- {
- ReportError(HXR_XML_GENERALERROR,
- XML_MISSING_ATTRIBUTE_VALUE);
- m_fileState = InContent;
- pCb[m_ulCurrentBufferPos++] = pData[ulPos];
- }
- }
- break;
- case InAttributeValue:
- {
- if ( pData[ulPos] == m_cQuote )
- {
- if ( m_cQuote == '"' )
- {
- pCb[m_ulCurrentBufferPos++] = '\';
- }
- m_fileState = InTag;
- }
- else if ( pData[ulPos] == '"' )
- {
- pCb[m_ulCurrentBufferPos++] = '\';
- }
- else if ( pData[ulPos] == '\' )
- {
- pCb[m_ulCurrentBufferPos++] = '\';
- }
- pCb[m_ulCurrentBufferPos++] = pData[ulPos];
- }
- break;
- case InComment:
- {
- if ( pData[ulPos] == '-' && pData[ulPos+1] == '-' &&
- pData[ulPos+2] == '>' )
- {
- m_fileState = InContent;
- ulPos += 2;
- }
- // preserve all lines so line numbers in error messages
- // are accurate
- else if (pData[ulPos] == 'n' || ('r' == pData[ulPos] &&
- ulPos+1 < ulSize && 'n' != pData[ulPos+1]) )
- {
- if ('r' == pData[ulPos])
- {
- pCb[m_ulCurrentBufferPos++] = 'n';
- }
- else
- {
- pCb[m_ulCurrentBufferPos++] = pData[ulPos];
- }
- }
- // else continue...
- }
- break;
- default:
- HX_ASSERT(FALSE);
- }
- }
- return result;
- }
- HX_RESULT CSmilFileFormat::ReportError(HX_RESULT result,
- const char* errStr)
- {
- if ( m_bLogErrors )
- {
- IHXErrorMessages* pLog = NULL;
- m_pContext->QueryInterface(IID_IHXErrorMessages,
- (void**)&pLog);
- pLog->Report(HXLOG_ERR, result, 0, errStr,
- "http://www.real.com");
- HX_RELEASE(pLog);
- }
- return HXR_OK;
- }
- /////////////////////////////////////////////////////////////////////////
- // Method:
- // IHXFileResponse::WriteDone
- // Purpose:
- // Notification interface provided by users of the IHXFileObject
- // interface. This method is called by the IHXFileObject when the
- // last write to the file is complete.
- //
- STDMETHODIMP CSmilFileFormat::WriteDone(HX_RESULT status)
- {
- // We don't ever write, so we don't expect to get this...
- return HXR_UNEXPECTED;
- }
- /////////////////////////////////////////////////////////////////////////
- // Method:
- // IHXFileResponse::SeekDone
- // Purpose:
- // Notification interface provided by users of the IHXFileObject
- // interface. This method is called by the IHXFileObject when the
- // last seek in the file is complete.
- //
- STDMETHODIMP CSmilFileFormat::SeekDone(HX_RESULT status)
- {
- HX_RESULT result = HXR_OK;
- return result;
- }
- /************************************************************************
- * Method:
- * IHXPendingStatus::GetStatus
- * Purpose:
- * Called by the user to get the current pending status from an object
- */
- STDMETHODIMP
- CSmilFileFormat::GetStatus
- (
- REF(UINT16) uStatusCode,
- REF(IHXBuffer*) pStatusDesc,
- REF(UINT16) ulPercentDone
- )
- {
- HX_RESULT hResult = HXR_OK;
- IHXPendingStatus* pFileSystemStatus = NULL;
- // asking status information from the file system object
- if (m_pFileObject)
- {
- if (HXR_OK == m_pFileObject->QueryInterface(IID_IHXPendingStatus,(void**)&pFileSystemStatus))
- {
- hResult = pFileSystemStatus->GetStatus(uStatusCode, pStatusDesc, ulPercentDone);
- pFileSystemStatus->Release();
- return hResult;
- }
- }
- // by default
- uStatusCode = HX_STATUS_READY;
- pStatusDesc = NULL;
- ulPercentDone = 0;
-
- return hResult;
- }
- /************************************************************************
- * Method:
- * IHXThreadSafeMethods::IsThreadSafe
- */
- STDMETHODIMP_(UINT32)
- CSmilFileFormat::IsThreadSafe()
- {
- return HX_THREADSAFE_METHOD_FF_GETPACKET |
- HX_THREADSAFE_METHOD_FSR_READDONE;
- }