📄 smlparse.cpp
字号:
/* ***** 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 ***** */
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include "hxtypes.h"
#include "hxresult.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 "hxupgrd.h"
#include "hxassert.h"
#include "chxpckts.h"
#include "upgrdcol.h"
#include "nptime.h"
#include "smpte.h"
#include "debug.h"
#include "hxstrutl.h"
#include "hxstring.h"
#include "cbqueue.h"
#include "hxslist.h"
#include "hxurl.h"
#include "hxmap.h"
#include "hxstack.h"
#include "hxwintyp.h"
#include "chxxtype.h"
#include "hxparse.h"
#include "hxxml.h"
#include "xmlreslt.h"
#include "looseprs.h"
#include "hxxmlprs.h" //HXXMLParser
#include "sm1elem.h"
#include "sm1time.h"
#include "sm1error.h"
#include "sm1parse.h"
#include "hxmon.h"
#include "debugout.h"
#include "hxheap.h"
#ifdef _DEBUG
#undef HX_THIS_FILE
static const char HX_THIS_FILE[] = __FILE__;
#endif
static const UINT32 MAX_DRIVER_PACKET_SIZE = 1024;
static const UINT32 INITIAL_STREAM1_TIMESTAMP = 1;
static const UINT32 INITIAL_STREAM0_TIMESTAMP = 0;
static const UINT32 MAX_ERROR_LEN = 1024;
static const char* const RN_PREFIX = "rn";
static const char* const RN_TAG_RENDERER_LIST = "rn:renderer-list";
static const char* const RN_TAG_RENDERER = "rn:renderer";
static const char* const SYSTEM_COMPONENT_NAMESPACE = "http://features.real.com/systemComponent";
static const char* const SYSTEM_COMPONENT = "systemComponent";
static const struct smil1ColorTable
{
char* m_pColorName;
UINT8 m_ucRed;
UINT8 m_ucGreen;
UINT8 m_ucBlue;
} Smil1ColorTable[] =
{
{"black", 0x00, 0x00, 0x00},
{"silver", 0xc0, 0xc0, 0xc0},
{"gray", 0x80, 0x80, 0x80},
{"white", 0xff, 0xff, 0xff},
{"maroon", 0x80, 0x00, 0x00},
{"red", 0xff, 0x00, 0x00},
{"purple", 0x80, 0x00, 0x80},
{"fuchsia", 0xff, 0x00, 0xff},
{"green", 0x00, 0x80, 0x00},
{"lime", 0x00, 0xff, 0x00},
{"olive", 0x80, 0x80, 0x00},
{"yellow", 0xff, 0xff, 0x00},
{"navy", 0x00, 0x00, 0x80},
{"blue", 0x00, 0x00, 0xff},
{"teal", 0x00, 0x80, 0x80},
{"aqua", 0x00, 0xff, 0xff},
{0, 0x00, 0x00, 0x00}
};
static const struct smil1TagTable
{
SMIL1NodeTag m_tag;
const char* m_name;
} smil1TagTable[] =
{
{SMILSmil, "smil"},
{SMILMeta, "meta"},
{SMILHead, "head"},
{SMILBody, "body"},
{SMILBasicLayout, "layout"},
{SMILRootLayout, "root-layout"},
{SMILRegion, "region"},
{SMILSwitch, "switch"},
{SMILText, "text"},
{SMILImg, "img"},
{SMILRef, "ref"},
{SMILAudio, "audio"},
{SMILVideo, "video"},
{SMILAnimation, "animation"},
{SMILTextstream, "textstream"},
{SMILAnchor, "anchor"},
{SMILAAnchor, "a"},
{SMILPar, "par"},
{SMILSeq, "seq"},
{SMILRNRendererList, RN_TAG_RENDERER_LIST},
{SMILRendererPreFetch, RN_TAG_RENDERER},
{SMILUnknown, "unknown"}
};
CSmil1Parser::CSmil1Parser(IUnknown* pContext):
m_pContext(pContext),
m_pClassFactory(NULL),
m_pISystemRequired(NULL),
m_pNodeList(0),
m_pNodeListStack(0),
m_pPacketQueue(0),
m_pIDMap(0),
m_pAddGroupMap(0),
m_pSourceUpdateList(0),
m_pRequireTagsMap(0),
m_bNoNamespaces(FALSE),
m_bRNNamespace(FALSE),
m_bIgnoreUnrecognizedElements(TRUE),
m_bSMILRootLayoutAlreadyFound(FALSE),
m_bSMIL10FullCompliance(FALSE),
m_pActiveNamespaceMap(NULL),
m_pNSConflictList(NULL),
m_bTimestampsResolved(FALSE),
m_pCurNode(0),
m_pNodeDependencies(0),
m_pCurrentDependentNode(0),
m_pAnchorStack(0),
m_pCurrentAnchor(0),
m_pEndLayout(0),
m_ulBandwidthPreference(0),
m_ulScreenHeightPreference(0),
m_ulScreenWidthPreference(0),
m_ulScreenDepthPreference(0),
m_pLanguagePreferenceList(0),
m_bCaptionsPreference(FALSE),
m_pOverdubOrCaptionPreference(0),
m_pBasePath(0),
m_pTagAttributeMap(0),
m_bContainsSource(FALSE),
m_pEncoding(0),
m_pTrackHintList(0),
m_pParser(NULL),
m_pResponse(NULL),
m_ulErrorLineNumber(0),
m_ulErrorColumnNumber(0),
m_pErrorText(NULL)
, m_bStoreErrors(FALSE)
, m_pErrors(NULL)
, m_ulPersistentComponentID(0)
, m_elementWithinTag(WithinUnknown)
, m_pVarName(NULL)
, m_ulNextVar(0)
, m_pTimelineElementManager(NULL)
{
if(m_pContext)
{
m_pContext->AddRef();
m_pContext->QueryInterface(IID_IHXCommonClassFactory, (void**)&m_pClassFactory);
}
initRequireTags();
initTagAttributes();
getPreferences();
m_pVarName = new char [256];
m_pTimelineElementManager = new CSmil1TimelineElementManager;
}
CSmil1Parser::~CSmil1Parser()
{
deleteTagAttributes();
HX_DELETE(m_pRequireTagsMap);
if (m_pErrors)
{
int size = m_pErrors->GetSize();
for (int i =0; i < size; ++i)
{
IHXBuffer* pBuf = (IHXBuffer*)(*m_pErrors)[i];
HX_RELEASE(pBuf);
(*m_pErrors)[i] = NULL;
}
HX_DELETE(m_pErrors);
}
if (m_pActiveNamespaceMap != NULL)
{
CHXMapStringToOb::Iterator ndxBuffer = m_pActiveNamespaceMap->Begin();
for (; ndxBuffer != m_pActiveNamespaceMap->End(); ++ndxBuffer)
{
IHXBuffer* pBuffer = (IHXBuffer*)(*ndxBuffer);
HX_RELEASE(pBuffer);
}
HX_DELETE(m_pActiveNamespaceMap);
}
if (m_pNSConflictList != NULL)
{
CHXSimpleList::Iterator ndx = m_pNSConflictList->Begin();
for (; ndx != m_pNSConflictList->End(); ++ndx)
{
SMIL1Namespace* pNS = (SMIL1Namespace*)(*ndx);
HX_DELETE(pNS);
}
HX_DELETE(m_pNSConflictList);
}
HX_DELETE(m_pNodeDependencies);
HX_DELETE(m_pAnchorStack);
HX_VECTOR_DELETE(m_pEncoding);
if(m_pLanguagePreferenceList)
{
CHXSimpleList::Iterator i = m_pLanguagePreferenceList->Begin();
for(; i != m_pLanguagePreferenceList->End(); ++i)
{
char* pLang = (char*)(*i);
delete[] pLang;
}
HX_DELETE(m_pLanguagePreferenceList);
}
HX_DELETE(m_pOverdubOrCaptionPreference);
HX_DELETE(m_pBasePath);
close();
HX_RELEASE(m_pClassFactory);
HX_RELEASE(m_pContext);
HX_VECTOR_DELETE(m_pVarName);
HX_DELETE(m_pTimelineElementManager);
}
void
CSmil1Parser::initRequireTags()
{
//XXXBAB - add required tags here
#if 0
m_pRequireTagsMap = new CHXMapStringToOb;
(*m_pRequireTagsMap)["foo-require"] = 0;
(*m_pRequireTagsMap)["boo-require"] = 0;
#endif
}
void
CSmil1Parser::getPreferences()
{
IHXPreferences* pPrefs = 0;
IHXRegistry* pRegistry = NULL;
m_pContext->QueryInterface(IID_IHXRegistry, (void**)&pRegistry);
if(HXR_OK == m_pContext->QueryInterface(
IID_IHXPreferences, (void**)&pPrefs))
{
IHXBuffer* pBuf = 0;
CHXString strTemp;
strTemp.Format("%s.%s",HXREGISTRY_PREFPROPNAME,"Language");
if(pRegistry && HXR_OK == pRegistry->GetStrByName(strTemp, pBuf))
{
// language preference can be a comma-separated list
const char* pLang = (const char*)pBuf->GetBuffer();
// gonna call strtok, so copy the string...
char* pLangCopy = new_string(pLang);
m_pLanguagePreferenceList = new CHXSimpleList;
char* pTok = strtok(pLangCopy, ",");
while(pTok)
{
char* pLangString = new_string(pTok);
m_pLanguagePreferenceList->AddTail(pLangString);
pTok = strtok(NULL, ",");
}
delete[] pLangCopy;
HX_RELEASE(pBuf);
}
if(HXR_OK == pPrefs->ReadPref("bandwidth", pBuf) ||
// /Fixes PR 84098 (SMIL 1.0 version) on Mac whose player
// registry is case-sensitive and the registry value is
// Bandwidth with a capital B:
HXR_OK == pPrefs->ReadPref("Bandwidth", pBuf))
{
m_ulBandwidthPreference =
(UINT32)atol((const char*)pBuf->GetBuffer());
HX_RELEASE(pBuf);
}
if(HXR_OK == pPrefs->ReadPref("screen_depth", pBuf))
{
m_ulScreenDepthPreference =
(UINT32)atol((const char*)pBuf->GetBuffer());
HX_RELEASE(pBuf);
}
if(HXR_OK == pPrefs->ReadPref("screen_height", pBuf))
{
m_ulScreenHeightPreference =
(UINT32)atol((const char*)pBuf->GetBuffer());
HX_RELEASE(pBuf);
}
if(HXR_OK == pPrefs->ReadPref("screen_width", pBuf))
{
m_ulScreenWidthPreference =
(UINT32)atol((const char*)pBuf->GetBuffer());
HX_RELEASE(pBuf);
}
if(HXR_OK == pPrefs->ReadPref("caption_switch", pBuf))
{
m_bCaptionsPreference =
(UINT32)atol((const char*)pBuf->GetBuffer());
HX_RELEASE(pBuf);
}
if(HXR_OK == pPrefs->ReadPref("overdub_or_caption", pBuf))
{
const char* pStr = (const char*)pBuf->GetBuffer();
m_pOverdubOrCaptionPreference = new_string(pStr);
HX_RELEASE(pBuf);
}
HX_RELEASE(pPrefs);
}
HX_RELEASE(pRegistry);
}
void
CSmil1Parser::close()
{
HX_DELETE(m_pPacketQueue);
HX_DELETE(m_pEndLayout);
HX_DELETE(m_pTrackHintList);
HX_RELEASE(m_pResponse);
HX_RELEASE(m_pErrorText);
if (m_pParser)
{
m_pParser->Close();
HX_RELEASE(m_pParser);
}
HX_RELEASE(m_pISystemRequired);
if(m_pIDMap)
{
CHXMapStringToOb::Iterator i = m_pIDMap->Begin();
for(; i != m_pIDMap->End(); ++i)
{
SMIL1Node* pNode = (SMIL1Node*)(*i);
HX_DELETE(pNode->m_pElement);
}
HX_DELETE(m_pIDMap);
}
if(m_pAddGroupMap)
{
CHXMapLongToObj::Iterator i = m_pAddGroupMap->Begin();
for(; i != m_pAddGroupMap->End(); ++i)
{
CSmil1AddGroup* pAddGroup = (CSmil1AddGroup*)(*i);
delete pAddGroup;
}
HX_DELETE(m_pAddGroupMap);
}
if(m_pSourceUpdateList)
{
CHXSimpleList::Iterator i = m_pSourceUpdateList->Begin();
for(; i != m_pSourceUpdateList->End(); ++i)
{
CSmil1SourceUpdate* pUpdate = (CSmil1SourceUpdate*)(*i);
delete pUpdate;
}
HX_DELETE(m_pSourceUpdateList);
}
if (m_pActiveNamespaceMap)
{
CHXMapStringToOb::Iterator ndxBuffer = m_pActiveNamespaceMap->Begin();
for (; ndxBuffer != m_pActiveNamespaceMap->End(); ++ndxBuffer)
{
IHXBuffer* pBuffer = (IHXBuffer*)(*ndxBuffer);
HX_RELEASE(pBuffer);
}
HX_DELETE(m_pActiveNamespaceMap);
}
if (m_pNSConflictList != NULL)
{
CHXSimpleList::Iterator ndx = m_pNSConflictList->Begin();
for (; ndx != m_pNSConflictList->End(); ++ndx)
{
SMIL1Namespace* pNS = (SMIL1Namespace*)(*ndx);
HX_DELETE(pNS);
}
HX_DELETE(m_pNSConflictList);
}
delete m_pNodeListStack;
if(m_pNodeList)
{
delete m_pNodeList->m_pParentNode;
}
}
HX_RESULT
CSmil1Parser::init(BOOL bStoreErrors)
{
HX_RESULT rc = HXR_OK;
close();
m_pNodeListStack = new CHXStack;
m_pPacketQueue = new CHXSimpleList;
m_pIDMap = new CHXMapStringToOb;
m_pAddGroupMap = new CHXMapLongToObj;
m_bStoreErrors = bStoreErrors;
if (m_bStoreErrors)
{
// XXXJHUG error stuff.
// In the future if there was any reason, we could
// store the errors in the nodes that the errors occurred in.
// for now when we get an error notification, we will
// just call the storeError function which will add
// a new IHXBuffer to this array.. This will also be
// called when problems are found with tags...
// this will save having to walk the tree when it
// is time to dump the errors.
m_pErrors = new CHXPtrArray;
}
SMIL1Node* pRootNode = new SMIL1Node;
pRootNode->m_id = "root";
pRootNode->m_name = "root";
m_pNodeList = new SMIL1NodeList;
pRootNode->m_pNodeList = m_pNodeList;
m_pNodeList->m_pParentNode = pRootNode;
m_pNodeListStack->Push(pRootNode);
#ifdef USE_EXPAT_FOR_SMIL
rc = m_pClassFactory->CreateInstance(CLSID_IHXXMLParser, (void**)&m_pParser);
if (FAILED(rc))
{
// they don't have the parser... use old one?
// Don't QI core for IID_IHXXMLParser; use our own instance.
m_pParser = new HXXMLParser;
if (m_pParser)
{
rc = HXR_OK;
m_pParser->AddRef();
}
else
{
rc = HXR_OUTOFMEMORY;
}
}
HX_RELEASE(pFact);
if (SUCCEEDED(rc))
{
m_pResponse = new CSmil1ParserResponse(this);
m_pResponse->AddRef();
// Expat is created off the CCF.
// In strict mode it requires 100% compliant XML. We will
// create a "loose" version that allows &'s in attribute values.
// (this parser is still MUCH stricter than the original XML parser)
rc = m_pParser->Init(m_pResponse, "iso-8859-1", FALSE);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -