mirror of
https://github.com/jezhiggins/arabica
synced 2025-01-02 06:20:38 +01:00
5a339ca613
cannot propagate through the COM boundary. ErrorHandlerAdaptor now caches reported errors until the parse has completed, then reports them to ErrorHandler afterwards. This ensures that throw exceptions propogate as expected.
988 lines
38 KiB
C++
988 lines
38 KiB
C++
#ifndef ARABICA_SAX_MSXML2_H
|
|
#define ARABICA_SAX_MSXML2_H
|
|
//---------------------------------------------------------------------------
|
|
// A SAX2 wrapper class for MSXML component.
|
|
//
|
|
// $Id$
|
|
//
|
|
// Changes:
|
|
// 21-Jul-2002 Major tweaks to use #include <header> rather then
|
|
// #import <type_library>. The latter is sensitive to
|
|
// the exact name/version of the library provided by
|
|
// Microsoft and various options provided to the type
|
|
// library reader. (Found the issue when I attempted
|
|
// to build with MSXML4 rather then MSXML3.) [kas]
|
|
//
|
|
// 31-Jul-2002 Created the default PROGID define. M$. in their
|
|
// wisdom, removed the version independent IDs starting
|
|
// in version 4.0 of the MSXML library. Saves a lot of
|
|
// 'DLL hell' problems but creates others for maintainers.
|
|
// The initialization code will now try the 4.0 ID and
|
|
// then the older (version independant) name. [kas]
|
|
//
|
|
//
|
|
// Known issues:
|
|
// 1. The destructor (~msxml2_wrapper) should release the COM
|
|
// interfaces. It doesn't because of problem 2.
|
|
//
|
|
// 2. The classes don't handle non-initialization well. Failure
|
|
// to get the COM interfaces during instance construction will
|
|
// cause a crash at some later point.
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
#include <SAX/ArabicaConfig.h>
|
|
#include <SAX/XMLReader.h>
|
|
#include <SAX/InputSource.h>
|
|
#include <SAX/SAXParseException.h>
|
|
#include <SAX/SAXNotRecognizedException.h>
|
|
#include <SAX/SAXNotSupportedException.h>
|
|
#include <SAX/ext/LexicalHandler.h>
|
|
#include <SAX/ext/DeclHandler.h>
|
|
#include <SAX/helpers/PropertyNames.h>
|
|
#include <SAX/helpers/StringAdaptor.h>
|
|
#include <iostream>
|
|
|
|
// Include the MSXML definitions.
|
|
#include <msxml2.h>
|
|
|
|
// Declare the ProgID used in the version dependent MSXML 4.0 library
|
|
// up here rather then buried somewhere in the code.
|
|
#define MSXML_PROGID_NAME "Msxml2.SAXXMLReader.4.0"
|
|
|
|
//
|
|
// Declare the 'smart pointer' type to simplify COM handling.
|
|
#include <comdef.h>
|
|
_COM_SMARTPTR_TYPEDEF(ISAXXMLReader, __uuidof(ISAXXMLReader));
|
|
|
|
namespace SAX
|
|
{
|
|
|
|
/**
|
|
* use this as COMInitializer_type if you call
|
|
* CoInitialize/CoInitializeEx in your own code
|
|
*/
|
|
class COMExternalInitializer
|
|
{
|
|
public:
|
|
COMExternalInitializer() { }
|
|
~COMExternalInitializer() { }
|
|
}; // COMExternalInitializer
|
|
|
|
class COMSingleThreadInitializer
|
|
{
|
|
public:
|
|
COMSingleThreadInitializer() { ::CoInitialize(NULL); }
|
|
~COMSingleThreadInitializer() { ::CoUninitialize(); }
|
|
}; // COMSingleThreadInitializer
|
|
|
|
#if(_WIN32_WINNT >= 0x0400 ) || defined(_WIN32_DCOM)
|
|
class COMMultiThreadInitializer
|
|
{
|
|
public:
|
|
COMMultiThreadInitializer() { ::CoInitializeEx(NULL, COINIT_MULTITHREADED); }
|
|
~COMMultiThreadInitializer() { ::CoUninitialize(); }
|
|
};
|
|
#endif
|
|
|
|
template<class string_type,
|
|
class COMInitializer_type = COMSingleThreadInitializer,
|
|
class string_adaptor_type = SAX::default_string_adaptor<string_type> >
|
|
class msxml2_wrapper : public SAX::basic_XMLReader<string_type>
|
|
{
|
|
public:
|
|
typedef string_type stringT;
|
|
typedef string_adaptor_type string_adaptorT;
|
|
typedef SAX::basic_EntityResolver<stringT> entityResolverT;
|
|
typedef SAX::basic_DTDHandler<stringT> dtdHandlerT;
|
|
typedef SAX::basic_ContentHandler<stringT> contentHandlerT;
|
|
typedef SAX::basic_DeclHandler<stringT> declHandlerT;
|
|
typedef SAX::basic_LexicalHandler<stringT> lexicalHandlerT;
|
|
typedef SAX::basic_InputSource<stringT> inputSourceT;
|
|
typedef SAX::basic_Locator<stringT> locatorT;
|
|
typedef SAX::basic_ErrorHandler<stringT> errorHandlerT;
|
|
typedef COMInitializer_type COMInitializerT;
|
|
|
|
msxml2_wrapper();
|
|
virtual ~msxml2_wrapper();
|
|
|
|
/////////////////////////////////////////////////
|
|
// Configuration
|
|
virtual bool getFeature(const stringT& name) const;
|
|
virtual void setFeature(const stringT& name, bool value);
|
|
|
|
/////////////////////////////////////////////////
|
|
// Event Handlers
|
|
/* MSXML does not use EntityResolver currently */
|
|
virtual void setEntityResolver(SAX::basic_EntityResolver<stringT>& resolver) { }
|
|
virtual SAX::basic_EntityResolver<stringT>* getEntityResolver() const { return 0; }
|
|
virtual void setDTDHandler(SAX::basic_DTDHandler<stringT>& handler) { dtdHandler_.setDTDHandler(handler); }
|
|
virtual SAX::basic_DTDHandler<stringT>* getDTDHandler() const { return dtdHandler_.getDTDHandler(); }
|
|
virtual void setContentHandler(SAX::basic_ContentHandler<stringT>& handler) { contentHandler_.setContentHandler(handler); }
|
|
virtual SAX::basic_ContentHandler<stringT>* getContentHandler() const { return contentHandler_.getContentHandler(); }
|
|
virtual void setErrorHandler(SAX::basic_ErrorHandler<stringT>& handler);
|
|
virtual SAX::basic_ErrorHandler<stringT>* getErrorHandler() const;
|
|
|
|
//////////////////////////////////////////////////
|
|
// Parsing
|
|
virtual void parse(SAX::basic_InputSource<stringT>& input);
|
|
|
|
protected:
|
|
virtual std::auto_ptr<SAX::basic_XMLReader<stringT>::PropertyBase> doGetProperty(const stringT& name);
|
|
virtual void doSetProperty(const stringT& name, std::auto_ptr<SAX::basic_XMLReader<stringT>::PropertyBase> value);
|
|
|
|
private:
|
|
//////////////////////////////////////////////////////
|
|
// COM interface -> C++ interface adaptors
|
|
class LocatorAdaptor : public SAX::basic_Locator<stringT>
|
|
{
|
|
public:
|
|
LocatorAdaptor() : locator_(0) { }
|
|
LocatorAdaptor(ISAXLocator __RPC_FAR* locator) : locator_(0) { setLocator(locator); }
|
|
~LocatorAdaptor() { setLocator(0); }
|
|
|
|
stringT getPublicId() const
|
|
{
|
|
if(!locator_)
|
|
return stringT();
|
|
|
|
const wchar_t* pwchPublicId;
|
|
locator_->getPublicId(&pwchPublicId);
|
|
stringT publicId(SA_.makeStringT(pwchPublicId));
|
|
return publicId;
|
|
} // getPublicId
|
|
|
|
stringT getSystemId() const
|
|
{
|
|
if(!locator_)
|
|
return stringT();
|
|
|
|
const wchar_t* pwchSystemId;
|
|
locator_->getSystemId(&pwchSystemId);
|
|
stringT systemId(SA_.makeStringT(pwchSystemId));
|
|
return systemId;
|
|
} // getSystemId
|
|
|
|
int getLineNumber() const
|
|
{
|
|
if(!locator_)
|
|
return -1;
|
|
|
|
int lineNumber;
|
|
locator_->getLineNumber(&lineNumber);
|
|
return lineNumber;
|
|
} // getLineNumber
|
|
|
|
int getColumnNumber() const
|
|
{
|
|
if(!locator_)
|
|
return -1;
|
|
|
|
int columnNumber;
|
|
locator_->getColumnNumber(&columnNumber);
|
|
return columnNumber;
|
|
} // getColumnNumber
|
|
|
|
void setLocator(ISAXLocator __RPC_FAR* locator)
|
|
{
|
|
locator_ = locator;
|
|
// no need to AddRef or Release as the ISAXLocator points to the MSXML instance
|
|
// and we'll clean that up properly anyway
|
|
} // setLocator
|
|
|
|
private:
|
|
ISAXLocator __RPC_FAR *locator_;
|
|
string_adaptorT SA_;
|
|
}; // class LocatorAdaptor
|
|
|
|
class DTDHandlerAdaptor : public ISAXDTDHandler
|
|
{
|
|
public:
|
|
DTDHandlerAdaptor() : dtdHandler_(0) { }
|
|
~DTDHandlerAdaptor() { }
|
|
|
|
void setDTDHandler(SAX::basic_DTDHandler<stringT>& handler) { dtdHandler_ = &handler; }
|
|
SAX::basic_DTDHandler<stringT>* getDTDHandler() const { return dtdHandler_; }
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE notationDecl(
|
|
/* [in] */ const wchar_t *pwchName,
|
|
/* [in] */ int cchName,
|
|
/* [in] */ const wchar_t *pwchPublicId,
|
|
/* [in] */ int cchPublicId,
|
|
/* [in] */ const wchar_t *pwchSystemId,
|
|
/* [in] */ int cchSystemId)
|
|
{
|
|
if(dtdHandler_)
|
|
dtdHandler_->notationDecl(SA_.makeStringT(pwchName, cchName),
|
|
SA_.makeStringT(pwchPublicId, cchPublicId),
|
|
SA_.makeStringT(pwchSystemId, cchSystemId));
|
|
return S_OK;
|
|
} // notationDecl
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE unparsedEntityDecl(
|
|
/* [in] */ const wchar_t *pwchName,
|
|
/* [in] */ int cchName,
|
|
/* [in] */ const wchar_t *pwchPublicId,
|
|
/* [in] */ int cchPublicId,
|
|
/* [in] */ const wchar_t *pwchSystemId,
|
|
/* [in] */ int cchSystemId,
|
|
/* [in] */ const wchar_t *pwchNotationName,
|
|
/* [in] */ int cchNotationName)
|
|
{
|
|
if(dtdHandler_)
|
|
dtdHandler_->unparsedEntityDecl(SA_.makeStringT(pwchName, cchName),
|
|
SA_.makeStringT(pwchPublicId, cchPublicId),
|
|
SA_.makeStringT(pwchSystemId, cchSystemId),
|
|
SA_.makeStringT(pwchNotationName, cchNotationName));
|
|
return S_OK;
|
|
} // unparsedEntityDecl
|
|
|
|
// satify COM interface even if we're not a COM object
|
|
long __stdcall QueryInterface(const struct _GUID &riid,void **ppvObject) { return 0; }
|
|
unsigned long __stdcall AddRef() { return 0; }
|
|
unsigned long __stdcall Release() { return 0; }
|
|
|
|
private:
|
|
SAX::basic_DTDHandler<stringT>* dtdHandler_;
|
|
string_adaptorT SA_;
|
|
}; // class DTDHandlerAdaptor
|
|
|
|
class ContentHandlerAdaptor : public ISAXContentHandler
|
|
{
|
|
public:
|
|
ContentHandlerAdaptor() : contentHandler_(0) { }
|
|
~ContentHandlerAdaptor() { }
|
|
|
|
void setContentHandler(SAX::basic_ContentHandler<stringT>& handler) { contentHandler_ = &handler; }
|
|
SAX::basic_ContentHandler<stringT>* getContentHandler() const { return contentHandler_; }
|
|
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE putDocumentLocator(
|
|
/* [in] */ ISAXLocator *pLocator)
|
|
{
|
|
locator_.setLocator(pLocator);
|
|
if(contentHandler_) contentHandler_->setDocumentLocator(locator_);
|
|
return S_OK;
|
|
} // putDocumentLocation
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE startDocument( void)
|
|
{
|
|
if(contentHandler_) contentHandler_->startDocument();
|
|
return S_OK;
|
|
} // startDocument
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE endDocument( void)
|
|
{
|
|
if(contentHandler_) contentHandler_->endDocument();
|
|
return S_OK;
|
|
} // endDocument
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE startPrefixMapping(
|
|
/* [in] */ const wchar_t *pwchPrefix,
|
|
/* [in] */ int cchPrefix,
|
|
/* [in] */ const wchar_t *pwchUri,
|
|
/* [in] */ int cchUri)
|
|
|
|
{
|
|
if(contentHandler_)
|
|
contentHandler_->startPrefixMapping(SA_.makeStringT(pwchPrefix, cchPrefix),
|
|
SA_.makeStringT(pwchUri, cchUri));
|
|
return S_OK;
|
|
} // startPrefixMapping
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE endPrefixMapping(
|
|
/* [in] */ const wchar_t *pwchPrefix,
|
|
/* [in] */ int cchPrefix)
|
|
{
|
|
if(contentHandler_) contentHandler_->endPrefixMapping(SA_.makeStringT(pwchPrefix, cchPrefix));
|
|
return S_OK;
|
|
} // endPrefixMapping
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE startElement(
|
|
/* [in] */ const wchar_t *pwchNamespaceUri,
|
|
/* [in] */ int cchNamespaceUri,
|
|
/* [in] */ const wchar_t *pwchLocalName,
|
|
/* [in] */ int cchLocalName,
|
|
/* [in] */ const wchar_t *pwchQName,
|
|
/* [in] */ int cchQName,
|
|
/* [in] */ ISAXAttributes *pAttributes)
|
|
{
|
|
if(contentHandler_)
|
|
{
|
|
AttributesAdaptor attrs(pAttributes);
|
|
contentHandler_->startElement(SA_.makeStringT(pwchNamespaceUri, cchNamespaceUri),
|
|
SA_.makeStringT(pwchLocalName, cchLocalName),
|
|
SA_.makeStringT(pwchQName, cchQName),
|
|
attrs);
|
|
} // if ...
|
|
return S_OK;
|
|
} // startElement
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE endElement(
|
|
/* [in] */ const wchar_t *pwchNamespaceUri,
|
|
/* [in] */ int cchNamespaceUri,
|
|
/* [in] */ const wchar_t *pwchLocalName,
|
|
/* [in] */ int cchLocalName,
|
|
/* [in] */ const wchar_t *pwchQName,
|
|
/* [in] */ int cchQName)
|
|
{
|
|
if(contentHandler_)
|
|
contentHandler_->endElement(SA_.makeStringT(pwchNamespaceUri, cchNamespaceUri),
|
|
SA_.makeStringT(pwchLocalName, cchLocalName),
|
|
SA_.makeStringT(pwchQName, cchQName));
|
|
return S_OK;
|
|
} // endElement
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE characters(
|
|
/* [in] */ const wchar_t *pwchChars,
|
|
/* [in] */ int cchChars)
|
|
{
|
|
if(contentHandler_) contentHandler_->characters(SA_.makeStringT(pwchChars, cchChars));
|
|
return S_OK;
|
|
} // characters
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE ignorableWhitespace(
|
|
/* [in] */ const wchar_t *pwchChars,
|
|
/* [in] */ int cchChars)
|
|
{
|
|
if(contentHandler_)
|
|
contentHandler_->ignorableWhitespace(SA_.makeStringT(pwchChars, cchChars));
|
|
return S_OK;
|
|
} // ignorableWhitespace
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE processingInstruction(
|
|
/* [in] */ const wchar_t *pwchTarget,
|
|
/* [in] */ int cchTarget,
|
|
/* [in] */ const wchar_t *pwchData,
|
|
/* [in] */ int cchData)
|
|
{
|
|
if(contentHandler_)
|
|
contentHandler_->processingInstruction(SA_.makeStringT(pwchTarget, cchTarget),
|
|
SA_.makeStringT(pwchData, cchData));
|
|
return S_OK;
|
|
} // processingInstruction
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE skippedEntity(
|
|
/* [in] */ const wchar_t *pwchName,
|
|
/* [in] */ int cchName)
|
|
{
|
|
if(contentHandler_)
|
|
contentHandler_->skippedEntity(SA_.makeStringT(pwchName, cchName));
|
|
return S_OK;
|
|
} // skippedEntity
|
|
|
|
// satisfy COM interface even if we're not a COM object
|
|
long __stdcall QueryInterface(const struct _GUID &riid,void **ppvObject) { return 0; }
|
|
unsigned long __stdcall AddRef() { return 0; }
|
|
unsigned long __stdcall Release() { return 0; }
|
|
|
|
private:
|
|
////////////////////////////////////////////////
|
|
// member varaibles
|
|
SAX::basic_ContentHandler<stringT>* contentHandler_;
|
|
LocatorAdaptor locator_;
|
|
string_adaptorT SA_;
|
|
|
|
//////////////////////////////////////////////////////
|
|
// COM interface -> C++ interface adaptors
|
|
class AttributesAdaptor : public SAX::basic_Attributes<stringT>
|
|
{
|
|
public:
|
|
AttributesAdaptor(ISAXAttributes __RPC_FAR *pAttributes) : attributes_(pAttributes) { }
|
|
~AttributesAdaptor() { }
|
|
|
|
/////////////////////////
|
|
// indexed access
|
|
virtual int getLength() const
|
|
{
|
|
int length;
|
|
attributes_->getLength(&length);
|
|
return length;
|
|
} // getLength
|
|
|
|
virtual stringT getURI(unsigned int index) const
|
|
{
|
|
const wchar_t* pwchUri;
|
|
int cchUri;
|
|
HRESULT hr = attributes_->getURI(index, &pwchUri, &cchUri);
|
|
if (FAILED(hr))
|
|
return stringT();
|
|
stringT uri(SA_.makeStringT(pwchUri, cchUri));
|
|
return uri;
|
|
} // getURI
|
|
|
|
virtual stringT getLocalName(unsigned int index) const
|
|
{
|
|
const wchar_t* pwchLocalName;
|
|
int cchLocalName;
|
|
HRESULT hr = attributes_->getLocalName(index, &pwchLocalName, &cchLocalName);
|
|
if (FAILED(hr))
|
|
return stringT();
|
|
stringT localName(SA_.makeStringT(pwchLocalName, cchLocalName));
|
|
return localName;
|
|
} // getLocalName
|
|
|
|
virtual stringT getQName(unsigned int index) const
|
|
{
|
|
const wchar_t* pwchQName;
|
|
int cchQName;
|
|
HRESULT hr = attributes_->getQName(index, &pwchQName, &cchQName);
|
|
if (FAILED(hr))
|
|
return stringT();
|
|
stringT qName(SA_.makeStringT(pwchQName, cchQName));
|
|
return qName;
|
|
} // getQName
|
|
|
|
virtual stringT getType(unsigned int index) const
|
|
{
|
|
const wchar_t* pwchType;
|
|
int cchType;
|
|
HRESULT hr = attributes_->getType(index, &pwchType, &cchType);
|
|
if (FAILED(hr))
|
|
return stringT();
|
|
stringT type(SA_.makeStringT(pwchType, cchType));
|
|
return type;
|
|
} // getType
|
|
|
|
virtual stringT getValue(unsigned int index) const
|
|
{
|
|
const wchar_t* pwchValue;
|
|
int cchValue;
|
|
HRESULT hr = attributes_->getValue(index, &pwchValue, &cchValue);
|
|
if (FAILED(hr))
|
|
return stringT();
|
|
stringT value(SA_.makeStringT(pwchValue, cchValue));
|
|
return value;
|
|
} // getValue
|
|
|
|
/////////////////////////
|
|
// name based query
|
|
virtual int getIndex(const stringT& uri, const stringT& localName) const
|
|
{
|
|
int index = -1;
|
|
std::wstring wUri(SA_.asStdWString(uri));
|
|
std::wstring wLocalName(SA_.asStdWString(localName));
|
|
HRESULT hr = attributes_->getIndexFromName(wUri.data(), static_cast<int>(wUri.length()),
|
|
wLocalName.data(), static_cast<int>(wLocalName.length()),
|
|
&index);
|
|
return index;
|
|
} // getIndex
|
|
|
|
virtual int getIndex(const stringT& qName) const
|
|
{
|
|
int index = -1;
|
|
std::wstring wQName(SA_.asStdWString(qName));
|
|
attributes_->getIndexFromQName(wQName.data(), static_cast<int>(wQName.length()), &index);
|
|
return index;
|
|
} // getIndex
|
|
|
|
virtual stringT getType(const stringT& uri, const stringT& localName) const
|
|
{
|
|
const wchar_t* pwchType;
|
|
int cchType;
|
|
std::wstring wUri(SA_.asStdWString(uri));
|
|
std::wstring wLocalName(SA_.asStdWString(localName));
|
|
HRESULT hr = attributes_->getTypeFromName(wUri.data(), static_cast<int>(wUri.length()),
|
|
wLocalName.data(), static_cast<int>(wLocalName.length()),
|
|
&pwchType, &cchType);
|
|
if (FAILED(hr))
|
|
return stringT();
|
|
stringT type(SA_.makeStringT(pwchType, cchType));
|
|
return type;
|
|
} // getType
|
|
|
|
virtual stringT getType(const stringT& qName) const
|
|
{
|
|
const wchar_t* pwchType;
|
|
int cchType;
|
|
std::wstring wQName(SA_.asStdWString(qName));
|
|
HRESULT hr = attributes_->getTypeFromQName(wQName.data(), static_cast<int>(wQName.length()),
|
|
&pwchType, &cchType);
|
|
if (FAILED(hr))
|
|
return stringT();
|
|
stringT type(SA_.makeStringT(pwchType, cchType));
|
|
return type;
|
|
} // getType
|
|
|
|
virtual stringT getValue(const stringT& uri, const stringT& localName) const
|
|
{
|
|
const wchar_t* pwchValue;
|
|
int cchValue;
|
|
std::wstring wUri(SA_.asStdWString(uri));
|
|
std::wstring wLocalName(SA_.asStdWString(localName));
|
|
HRESULT hr = attributes_->getValueFromName(wUri.data(), static_cast<int>(wUri.length()),
|
|
wLocalName.data(), static_cast<int>(wLocalName.length()),
|
|
&pwchValue, &cchValue);
|
|
if (FAILED(hr))
|
|
return stringT();
|
|
stringT value(SA_.makeStringT(pwchValue, cchValue));
|
|
return value;
|
|
} // getValue
|
|
|
|
virtual stringT getValue(const stringT& qname) const
|
|
{
|
|
const wchar_t* pwchValue;
|
|
int cchValue;
|
|
std::wstring wQName(SA_.asStdWString(qname));
|
|
HRESULT hr = attributes_->getValueFromQName(wQName.data(), static_cast<int>(wQName.length()),
|
|
&pwchValue, &cchValue);
|
|
if (FAILED(hr))
|
|
return stringT();
|
|
stringT value(SA_.makeStringT(pwchValue, cchValue));
|
|
return value;
|
|
} // getValue
|
|
|
|
private:
|
|
ISAXAttributes __RPC_FAR *attributes_;
|
|
string_adaptorT SA_;
|
|
|
|
AttributesAdaptor();
|
|
}; // class AttributesAdaptor
|
|
}; // class ContentHandlerAdaptor
|
|
|
|
class ErrorHandlerAdaptor : public ISAXErrorHandler
|
|
{
|
|
public:
|
|
ErrorHandlerAdaptor() : errorHandler_(0),
|
|
bWarning_(false), bError_(false), bFatal_(false),
|
|
eWarning_("none"), eError_("none"), eFatal_("none")
|
|
{ }
|
|
virtual ~ErrorHandlerAdaptor() { }
|
|
|
|
void setErrorHandler(SAX::basic_ErrorHandler<stringT>& handler) { errorHandler_ = &handler; }
|
|
SAX::basic_ErrorHandler<stringT>* getErrorHandler() const { return errorHandler_; }
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE error(
|
|
/* [in] */ ISAXLocator *pLocator,
|
|
/* [in] */ const wchar_t *pwchErrorMessage,
|
|
/* [in] */ HRESULT hrErrorCode)
|
|
{
|
|
bError_ = true;
|
|
stringT errorMsg(SA_.makeStringT(pwchErrorMessage));
|
|
eError_ = SAXParseExceptionT(SA_.asStdString(errorMsg), LocatorAdaptor(pLocator));
|
|
return S_OK;
|
|
} // error
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE fatalError(
|
|
/* [in] */ ISAXLocator *pLocator,
|
|
/* [in] */ const wchar_t *pwchErrorMessage,
|
|
/* [in] */ HRESULT hrErrorCode)
|
|
{
|
|
bFatal_ = true;
|
|
stringT errorMsg(SA_.makeStringT(pwchErrorMessage));
|
|
eFatal_ = SAXParseExceptionT(SA_.asStdString(errorMsg), LocatorAdaptor(pLocator));
|
|
return S_FALSE;
|
|
} // fatalError
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE ignorableWarning(
|
|
/* [in] */ ISAXLocator *pLocator,
|
|
/* [in] */ const wchar_t *pwchErrorMessage,
|
|
/* [in] */ HRESULT hrErrorCode)
|
|
{
|
|
bWarning_ = true;
|
|
stringT errorMsg(SA_.makeStringT(pwchErrorMessage));
|
|
eWarning_ = SAXParseExceptionT(SA_.asStdString(errorMsg), LocatorAdaptor(pLocator));
|
|
return S_OK;
|
|
} // ignorableWarning
|
|
|
|
void report()
|
|
{
|
|
if(!errorHandler_)
|
|
return;
|
|
|
|
bool bWarning = bWarning_;
|
|
bool bError = bError_;
|
|
bool bFatal = bFatal_;
|
|
|
|
bWarning_ = bError_ = bFatal_ = false;
|
|
|
|
if(bFatal)
|
|
errorHandler_->fatalError(eFatal_);
|
|
if(bError)
|
|
errorHandler_->error(eError_);
|
|
if(bWarning)
|
|
errorHandler_->warning(eWarning_);
|
|
} // report
|
|
|
|
// satisfy COM interface even if we're not a COM object
|
|
long __stdcall QueryInterface(const struct _GUID &riid,void **ppvObject) { return 0; }
|
|
unsigned long __stdcall AddRef() { return 0; }
|
|
unsigned long __stdcall Release() { return 0; }
|
|
|
|
private:
|
|
typedef SAX::basic_SAXParseException<stringT> SAXParseExceptionT;
|
|
bool bWarning_;
|
|
bool bError_;
|
|
bool bFatal_;
|
|
SAXParseExceptionT eWarning_;
|
|
SAXParseExceptionT eError_;
|
|
SAXParseExceptionT eFatal_;
|
|
|
|
SAX::basic_ErrorHandler<stringT>* errorHandler_;
|
|
string_adaptorT SA_;
|
|
}; // class ErrorHandlerAdaptor
|
|
|
|
class LexicalHandlerAdaptor : public ISAXLexicalHandler
|
|
{
|
|
public:
|
|
LexicalHandlerAdaptor() : lexicalHandler_(0) { }
|
|
virtual ~LexicalHandlerAdaptor() { }
|
|
|
|
void setLexicalHandler(SAX::basic_LexicalHandler<stringT>& handler) { lexicalHandler_ = &handler; }
|
|
SAX::basic_LexicalHandler<stringT>* getLexicalHandler() const { return lexicalHandler_; }
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE startDTD(
|
|
/* [in] */ const wchar_t *pwchName,
|
|
/* [in] */ int cchName,
|
|
/* [in] */ const wchar_t *pwchPublicId,
|
|
/* [in] */ int cchPublicId,
|
|
/* [in] */ const wchar_t *pwchSystemId,
|
|
/* [in] */ int cchSystemId)
|
|
{
|
|
if(lexicalHandler_)
|
|
lexicalHandler_->startDTD(SA_.makeStringT(pwchName, cchName),
|
|
SA_.makeStringT(pwchPublicId, cchPublicId),
|
|
SA_.makeStringT(pwchSystemId, cchSystemId));
|
|
return S_OK;
|
|
} // startDTD
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE endDTD( void)
|
|
{
|
|
if(lexicalHandler_)
|
|
lexicalHandler_->endDTD();
|
|
return S_OK;
|
|
} // endDTD
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE startEntity(
|
|
/* [in] */ const wchar_t *pwchName,
|
|
/* [in] */ int cchName)
|
|
{
|
|
if(lexicalHandler_)
|
|
lexicalHandler_->startEntity(SA_.makeStringT(pwchName, cchName));
|
|
return S_OK;
|
|
} // startEntity
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE endEntity(
|
|
/* [in] */ const wchar_t *pwchName,
|
|
/* [in] */ int cchName)
|
|
{
|
|
if(lexicalHandler_)
|
|
lexicalHandler_->endEntity(SA_.makeStringT(pwchName, cchName));
|
|
return S_OK;
|
|
} // endEntity
|
|
|
|
virtual HRESULT __stdcall startCDATA()
|
|
{
|
|
if(lexicalHandler_)
|
|
lexicalHandler_->startCDATA();
|
|
return S_OK;
|
|
} // startCDATA
|
|
|
|
virtual HRESULT __stdcall endCDATA()
|
|
{
|
|
if(lexicalHandler_)
|
|
lexicalHandler_->endCDATA();
|
|
return S_OK;
|
|
} // endCDATA
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE comment(
|
|
/* [in] */ const wchar_t *pwchChars,
|
|
/* [in] */ int cchChars)
|
|
{
|
|
if(lexicalHandler_)
|
|
lexicalHandler_->comment(SA_.makeStringT(pwchChars, cchChars));
|
|
return S_OK;
|
|
} // comment
|
|
|
|
// satisfy COM interface even if we're not a COM object
|
|
long __stdcall QueryInterface(const struct _GUID &riid,void **ppvObject)
|
|
{
|
|
// we have to implement this, because we pass this as an IUnknown but it needs an
|
|
// ISAXLexicalHandler interface
|
|
if(riid == __uuidof(ISAXLexicalHandler))
|
|
*ppvObject = this;
|
|
return 0;
|
|
} // QueryInterface
|
|
unsigned long __stdcall AddRef() { return 0; }
|
|
unsigned long __stdcall Release() { return 0; }
|
|
|
|
private:
|
|
SAX::basic_LexicalHandler<stringT>* lexicalHandler_;
|
|
string_adaptorT SA_;
|
|
}; // class LexicalHandlerAdaptor
|
|
|
|
class DeclHandlerAdaptor : public ISAXDeclHandler
|
|
{
|
|
public:
|
|
DeclHandlerAdaptor() : declHandler_(0) { }
|
|
virtual ~DeclHandlerAdaptor() { }
|
|
|
|
void setDeclHandler(SAX::basic_DeclHandler<stringT>& handler) { declHandler_ = &handler; }
|
|
SAX::basic_DeclHandler<stringT>* getDeclHandler() const { return declHandler_; }
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE elementDecl(
|
|
/* [in] */ const wchar_t *pwchName,
|
|
/* [in] */ int cchName,
|
|
/* [in] */ const wchar_t *pwchModel,
|
|
/* [in] */ int cchModel)
|
|
{
|
|
if(declHandler_)
|
|
declHandler_->elementDecl(SA_.makeStringT(pwchName, cchName),
|
|
SA_.makeStringT(pwchModel, cchModel));
|
|
return S_OK;
|
|
} // elementDecl
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE attributeDecl(
|
|
/* [in] */ const wchar_t *pwchElementName,
|
|
/* [in] */ int cchElementName,
|
|
/* [in] */ const wchar_t *pwchAttributeName,
|
|
/* [in] */ int cchAttributeName,
|
|
/* [in] */ const wchar_t *pwchType,
|
|
/* [in] */ int cchType,
|
|
/* [in] */ const wchar_t *pwchValueDefault,
|
|
/* [in] */ int cchValueDefault,
|
|
/* [in] */ const wchar_t *pwchValue,
|
|
/* [in] */ int cchValue)
|
|
{
|
|
if(declHandler_)
|
|
declHandler_->attributeDecl(SA_.makeStringT(pwchElementName, cchElementName),
|
|
SA_.makeStringT(pwchAttributeName, cchAttributeName),
|
|
SA_.makeStringT(pwchType, cchType),
|
|
SA_.makeStringT(pwchValueDefault, cchValueDefault),
|
|
SA_.makeStringT(pwchValue, cchValue));
|
|
return S_OK;
|
|
} // attributeDecl
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE internalEntityDecl(
|
|
/* [in] */ const wchar_t *pwchName,
|
|
/* [in] */ int cchName,
|
|
/* [in] */ const wchar_t *pwchValue,
|
|
/* [in] */ int cchValue)
|
|
{
|
|
if(declHandler_)
|
|
declHandler_->internalEntityDecl(SA_.makeStringT(pwchName, cchName),
|
|
SA_.makeStringT(pwchValue, cchValue));
|
|
return S_OK;
|
|
} // internalEntityDecl
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE externalEntityDecl(
|
|
/* [in] */ const wchar_t *pwchName,
|
|
/* [in] */ int cchName,
|
|
/* [in] */ const wchar_t *pwchPublicId,
|
|
/* [in] */ int cchPublicId,
|
|
/* [in] */ const wchar_t *pwchSystemId,
|
|
/* [in] */ int cchSystemId)
|
|
{
|
|
if(declHandler_)
|
|
declHandler_->externalEntityDecl(SA_.makeStringT(pwchName, cchName),
|
|
SA_.makeStringT(pwchPublicId, cchPublicId),
|
|
SA_.makeStringT(pwchSystemId, cchSystemId));
|
|
return S_OK;
|
|
} // externalEntityDecl
|
|
|
|
// satisfy COM interface even if we're not a COM object
|
|
long __stdcall QueryInterface(const struct _GUID &riid,void **ppvObject)
|
|
{
|
|
// we have to implement this, because we pass this as an IUnknown but it needs an
|
|
// ISAXDeclHandler interface
|
|
if(riid == __uuidof(ISAXDeclHandler))
|
|
*ppvObject = reinterpret_cast<void*>(this);
|
|
return 0;
|
|
} // QueryInterface
|
|
|
|
unsigned long __stdcall AddRef() { return 0; }
|
|
unsigned long __stdcall Release() { return 0; }
|
|
|
|
private:
|
|
SAX::basic_DeclHandler<stringT>* declHandler_;
|
|
string_adaptorT SA_;
|
|
}; // class DeclHandlerAdaptor
|
|
|
|
class StreamAdaptor : public ISequentialStream
|
|
{
|
|
public:
|
|
StreamAdaptor(SAX::basic_InputSource<stringT>& source) :
|
|
source_(source)
|
|
{
|
|
} // StreamAdaptor
|
|
|
|
virtual HRESULT __stdcall Read(void* pv, ULONG cb, ULONG* pcbRead)
|
|
{
|
|
source_.getByteStream()->read(reinterpret_cast<char*>(pv), cb);
|
|
*pcbRead = source_.getByteStream()->gcount();
|
|
return S_OK;
|
|
} // Read
|
|
|
|
virtual HRESULT __stdcall Write(const void __RPC_FAR *pv, ULONG cb, ULONG __RPC_FAR *pcbWritten)
|
|
{
|
|
return S_FALSE;
|
|
} // Write
|
|
|
|
// satisfy COM interface even if we're not a COM object
|
|
long __stdcall QueryInterface(const struct _GUID &riid,void **ppvObject)
|
|
{
|
|
// we have to implement this, because we pass this as an IUnknown but it needs an
|
|
// IStream interface
|
|
if(riid == __uuidof(ISequentialStream))
|
|
{
|
|
*ppvObject = reinterpret_cast<void*>(this);
|
|
return S_OK;
|
|
} // if ...
|
|
return E_NOINTERFACE;
|
|
} // QueryInterface
|
|
|
|
unsigned long __stdcall AddRef() { return 1; }
|
|
unsigned long __stdcall Release() { return 1; }
|
|
|
|
private:
|
|
SAX::basic_InputSource<stringT>& source_;
|
|
}; // StreamAdaptor
|
|
|
|
|
|
//////////////////////////////////////////////////////
|
|
// member variables
|
|
COMInitializer_type init;
|
|
DTDHandlerAdaptor dtdHandler_;
|
|
ContentHandlerAdaptor contentHandler_;
|
|
ErrorHandlerAdaptor errorHandler_;
|
|
LexicalHandlerAdaptor lexicalHandler_;
|
|
DeclHandlerAdaptor declHandler_;
|
|
|
|
ISAXXMLReaderPtr reader_;
|
|
string_adaptorT SA_;
|
|
SAX::PropertyNames<stringT, string_adaptorT> properties_;
|
|
}; // class msxml
|
|
|
|
template<class stringT, class COMInitializerT, class string_adaptorT>
|
|
msxml2_wrapper<stringT, COMInitializerT, string_adaptorT>::msxml2_wrapper()
|
|
{
|
|
|
|
reader_.CreateInstance(MSXML_PROGID_NAME);
|
|
if (reader_.GetInterfacePtr() == NULL)
|
|
{
|
|
std::cerr << "MSXML SAX Reader 4.0 not instanciated, trying older versions."
|
|
<< std::endl << std::flush;
|
|
reader_.CreateInstance(__uuidof(ISAXXMLReader));
|
|
if (reader_.GetInterfacePtr() == NULL)
|
|
{
|
|
std::cerr << "MSXML SAX Reader (pre-4.0) not instanciated."
|
|
<< std::endl << std::flush;
|
|
exit(1);
|
|
}
|
|
}
|
|
reader_.AddRef();
|
|
reader_->putContentHandler(&contentHandler_);
|
|
reader_->putErrorHandler(&errorHandler_);
|
|
reader_->putDTDHandler(&dtdHandler_);
|
|
|
|
VARIANT wrapper;
|
|
wrapper.vt = VT_UNKNOWN;
|
|
wrapper.punkVal = static_cast<ISAXLexicalHandler*>(&lexicalHandler_);
|
|
reader_->putProperty(L"http://xml.org/sax/properties/lexical-handler", wrapper);
|
|
wrapper.punkVal = static_cast<ISAXDeclHandler*>(&declHandler_);
|
|
reader_->putProperty(L"http://xml.org/sax/properties/declaration-handler", wrapper);
|
|
} // msxml2_wrapper
|
|
|
|
template<class stringT, class COMInitializerT, class string_adaptorT>
|
|
msxml2_wrapper<stringT, COMInitializerT, string_adaptorT>::~msxml2_wrapper()
|
|
{
|
|
} // ~msxml2_wrapper
|
|
|
|
template<class stringT, class COMInitializerT, class string_adaptorT>
|
|
bool msxml2_wrapper<stringT, COMInitializerT, string_adaptorT>::getFeature(const stringT& name) const
|
|
{
|
|
VARIANT_BOOL feature;
|
|
std::wstring wName(SA_.asStdWString(name));
|
|
reader_->getFeature(wName.c_str(), &feature);
|
|
return (feature == VARIANT_TRUE) ? true : false;
|
|
} // msxml2_wrapper::getFeature
|
|
|
|
template<class stringT, class COMInitializerT, class string_adaptorT>
|
|
void msxml2_wrapper<stringT, COMInitializerT, string_adaptorT>::setFeature(const stringT& name, bool value)
|
|
{
|
|
std::wstring wName(SA_.asStdWString(name));
|
|
reader_->putFeature(wName.c_str(), value);
|
|
} // setFeature
|
|
|
|
template<class stringT, class COMInitializerT, class string_adaptorT>
|
|
void msxml2_wrapper<stringT, COMInitializerT, string_adaptorT>::setErrorHandler(SAX::basic_ErrorHandler<stringT>& handler)
|
|
{
|
|
errorHandler_.setErrorHandler(handler);
|
|
} // setErrorHandler
|
|
|
|
template<class stringT, class COMInitializerT, class string_adaptorT>
|
|
SAX::basic_ErrorHandler<stringT>* msxml2_wrapper<stringT, COMInitializerT, string_adaptorT>::getErrorHandler() const
|
|
{
|
|
return errorHandler_.getErrorHandler();
|
|
} // getErrorHandler
|
|
|
|
template<class stringT, class COMInitializerT, class string_adaptorT>
|
|
#ifndef ARABICA_VS6_WORKAROUND
|
|
std::auto_ptr<typename SAX::basic_XMLReader<stringT>::PropertyBase> msxml2_wrapper<stringT, COMInitializerT, string_adaptorT>::doGetProperty(const stringT& name)
|
|
#else
|
|
std::auto_ptr<SAX::basic_XMLReader<stringT>::PropertyBase> msxml2_wrapper<stringT, COMInitializerT, string_adaptorT>::doGetProperty(const stringT& name)
|
|
#endif
|
|
{
|
|
if(name == properties_.lexicalHandler)
|
|
{
|
|
Property<SAX::basic_LexicalHandler<stringT>*>* prop = new Property<SAX::basic_LexicalHandler<stringT>*>(lexicalHandler_.getLexicalHandler());
|
|
return std::auto_ptr<SAX::basic_XMLReader<stringT>::PropertyBase>(prop);
|
|
}
|
|
if(name == properties_.declHandler)
|
|
{
|
|
Property<SAX::basic_DeclHandler<stringT>*>* prop = new Property<SAX::basic_DeclHandler<stringT>*>(declHandler_.getDeclHandler());
|
|
return std::auto_ptr<SAX::basic_XMLReader<stringT>::PropertyBase>(prop);
|
|
}
|
|
throw SAX::SAXNotRecognizedException("Property not recognized ");
|
|
} // doGetProperty
|
|
|
|
template<class stringT, class COMInitializerT, class string_adaptorT>
|
|
void msxml2_wrapper<stringT, COMInitializerT, string_adaptorT>::doSetProperty(const stringT& name, std::auto_ptr<SAX::basic_XMLReader<stringT>::PropertyBase> value)
|
|
{
|
|
if(name == properties_.lexicalHandler)
|
|
{
|
|
Property<SAX::basic_LexicalHandler<stringT>&>* prop = dynamic_cast<Property<SAX::basic_LexicalHandler<stringT>&>*>(value.get());
|
|
|
|
if(!prop)
|
|
throw std::bad_cast("Property LexicalHandler is wrong type, should be SAX::LexicalHandler&");
|
|
|
|
lexicalHandler_.setLexicalHandler(prop->get());
|
|
return;
|
|
} // if ...
|
|
if(name == properties_.declHandler)
|
|
{
|
|
Property<SAX::basic_DeclHandler<stringT>&>* prop = dynamic_cast<Property<SAX::basic_DeclHandler<stringT>&>*>(value.get());
|
|
|
|
if(!prop)
|
|
throw std::bad_cast("Property DeclHandler is wrong type, should be SAX::DeclHandler&");
|
|
|
|
declHandler_.setDeclHandler(prop->get());
|
|
return;
|
|
} // if ...
|
|
throw SAX::SAXNotRecognizedException("Property not recognized ");
|
|
} // doSetProperty
|
|
|
|
template<class stringT, class COMInitializerT, class string_adaptorT>
|
|
void msxml2_wrapper<stringT, COMInitializerT, string_adaptorT>::parse(SAX::basic_InputSource<stringT>& source)
|
|
{
|
|
if(source.getByteStream() == 0)
|
|
{
|
|
std::wstring wSysId(SA_.asStdWString(source.getSystemId()));
|
|
reader_->parseURL(wSysId.c_str());
|
|
}
|
|
else
|
|
{
|
|
StreamAdaptor sa(source);
|
|
VARIANT wrapper;
|
|
wrapper.vt = VT_UNKNOWN;
|
|
wrapper.punkVal = static_cast<ISequentialStream*>(&sa);
|
|
reader_->parse(wrapper);
|
|
} // if ...
|
|
errorHandler_.report();
|
|
} // parse
|
|
|
|
} // namespace SAX
|
|
|
|
#endif
|
|
// end of file
|
|
|