mirror of
https://github.com/jezhiggins/arabica
synced 2024-12-27 21:58:30 +01:00
1050 lines
40 KiB
C++
1050 lines
40 KiB
C++
#ifndef ARABICA_SAX_MSXML2_H
|
|
#define ARABICA_SAX_MSXML2_H
|
|
//---------------------------------------------------------------------------
|
|
// A SAX2 wrapper class for MSXML component.
|
|
//---------------------------------------------------------------------------
|
|
|
|
#include <SAX/ArabicaConfig.hpp>
|
|
#include <SAX/XMLReader.hpp>
|
|
#include <SAX/InputSource.hpp>
|
|
#include <SAX/SAXParseException.hpp>
|
|
#include <SAX/SAXNotRecognizedException.hpp>
|
|
#include <SAX/SAXNotSupportedException.hpp>
|
|
#include <Arabica/StringAdaptor.hpp>
|
|
#include <iostream>
|
|
#include <Arabica/getparam.hpp>
|
|
|
|
// Include the MSXML definitions.
|
|
#include <msxml2.h>
|
|
|
|
//
|
|
// Declare the 'smart pointer' type to simplify COM handling.
|
|
#include <comdef.h>
|
|
_COM_SMARTPTR_TYPEDEF(ISAXXMLReader, __uuidof(ISAXXMLReader));
|
|
|
|
#if defined(_MSC_VER)
|
|
# pragma warning( push )
|
|
# pragma warning( disable : 6031 )
|
|
#endif
|
|
|
|
namespace Arabica
|
|
{
|
|
namespace SAX
|
|
{
|
|
|
|
struct COMInitializer_tag { };
|
|
|
|
/**
|
|
* use this as COMInitializer_type if you call
|
|
* CoInitialize/CoInitializeEx in your own code
|
|
*/
|
|
class COMExternalInitializer : public COMInitializer_tag
|
|
{
|
|
public:
|
|
COMExternalInitializer() { }
|
|
~COMExternalInitializer() { }
|
|
}; // COMExternalInitializer
|
|
|
|
class COMSingleThreadInitializer : public COMInitializer_tag
|
|
{
|
|
public:
|
|
COMSingleThreadInitializer() { ::CoInitialize(NULL); }
|
|
~COMSingleThreadInitializer() { ::CoUninitialize(); }
|
|
}; // COMSingleThreadInitializer
|
|
|
|
#if(_WIN32_WINNT >= 0x0400 ) || defined(_WIN32_DCOM)
|
|
class COMMultiThreadInitializer : public COMInitializer_tag
|
|
{
|
|
public:
|
|
COMMultiThreadInitializer() { ::CoInitializeEx(NULL, COINIT_MULTITHREADED); }
|
|
~COMMultiThreadInitializer() { ::CoUninitialize(); }
|
|
};
|
|
#endif
|
|
|
|
template<class string_type,
|
|
class T0 = Arabica::nil_t,
|
|
class T1 = Arabica::nil_t>
|
|
class msxml2_wrapper :
|
|
public SAX::XMLReaderInterface<string_type,
|
|
typename Arabica::get_string_adaptor<string_type, T0, T1>::type>
|
|
{
|
|
public:
|
|
typedef SAX::XMLReaderInterface<string_type, typename Arabica::get_param<Arabica::string_adaptor_tag,
|
|
Arabica::default_string_adaptor<string_type>,
|
|
T0,
|
|
T1>::type> XMLReaderT;
|
|
typedef typename XMLReaderT::string_adaptor string_adaptor;
|
|
typedef typename Arabica::get_param<COMInitializer_tag,
|
|
COMSingleThreadInitializer,
|
|
T1,
|
|
T0>::type COMInitializer_type;
|
|
|
|
typedef SAX::EntityResolver<string_type, string_adaptor> entityResolverT;
|
|
typedef SAX::DTDHandler<string_type, string_adaptor> dtdHandlerT;
|
|
typedef SAX::ContentHandler<string_type, string_adaptor> contentHandlerT;
|
|
typedef SAX::DeclHandler<string_type, string_adaptor> declHandlerT;
|
|
typedef SAX::LexicalHandler<string_type, string_adaptor> lexicalHandlerT;
|
|
typedef SAX::InputSource<string_type, string_adaptor> inputSourceT;
|
|
typedef SAX::Locator<string_type, string_adaptor> locatorT;
|
|
typedef SAX::ErrorHandler<string_type, string_adaptor> errorHandlerT;
|
|
typedef SAX::Attributes<string_type, string_adaptor> attributesT;
|
|
|
|
msxml2_wrapper();
|
|
virtual ~msxml2_wrapper();
|
|
|
|
/////////////////////////////////////////////////
|
|
// Configuration
|
|
virtual bool getFeature(const string_type& name) const;
|
|
virtual void setFeature(const string_type& name, bool value);
|
|
|
|
/////////////////////////////////////////////////
|
|
// Event Handlers
|
|
/* MSXML does not use EntityResolver currently */
|
|
virtual void setEntityResolver(entityResolverT& resolver) { }
|
|
virtual entityResolverT* getEntityResolver() const { return 0; }
|
|
virtual void setDTDHandler(dtdHandlerT& handler) { dtdHandler_.setDTDHandler(handler); }
|
|
virtual dtdHandlerT* getDTDHandler() const { return dtdHandler_.getDTDHandler(); }
|
|
virtual void setContentHandler(contentHandlerT& handler) { contentHandler_.setContentHandler(handler); }
|
|
virtual contentHandlerT* getContentHandler() const { return contentHandler_.getContentHandler(); }
|
|
virtual void setErrorHandler(errorHandlerT& handler);
|
|
virtual errorHandlerT* getErrorHandler() const { return errorHandler_.getErrorHandler(); }
|
|
virtual void setDeclHandler(declHandlerT& handler) { declHandler_.setDeclHandler(handler); }
|
|
virtual declHandlerT* getDeclHandler() const { return declHandler_.getDeclHandler(); }
|
|
virtual void setLexicalHandler(lexicalHandlerT& handler) { lexicalHandler_.setLexicalHandler(handler); }
|
|
virtual lexicalHandlerT* getLexicalHandler() const { return lexicalHandler_.getLexicalHandler(); }
|
|
|
|
//////////////////////////////////////////////////
|
|
// Parsing
|
|
virtual void parse(inputSourceT& input);
|
|
|
|
private:
|
|
//////////////////////////////////////////////////////
|
|
// COM interface -> C++ interface adaptors
|
|
class LocatorAdaptor : public locatorT
|
|
{
|
|
public:
|
|
LocatorAdaptor() : locator_(0) { }
|
|
LocatorAdaptor(ISAXLocator __RPC_FAR* locator) : locator_(0) { setLocator(locator); }
|
|
~LocatorAdaptor() { setLocator(0); }
|
|
|
|
string_type getPublicId() const
|
|
{
|
|
if(!locator_)
|
|
return string_type();
|
|
|
|
const wchar_t* pwchPublicId;
|
|
locator_->getPublicId(&pwchPublicId);
|
|
string_type publicId(string_adaptor::construct_from_utf16(pwchPublicId));
|
|
return publicId;
|
|
} // getPublicId
|
|
|
|
string_type getSystemId() const
|
|
{
|
|
if(!locator_)
|
|
return string_type();
|
|
|
|
const wchar_t* pwchSystemId;
|
|
locator_->getSystemId(&pwchSystemId);
|
|
string_type systemId(string_adaptor::construct_from_utf16(pwchSystemId));
|
|
return systemId;
|
|
} // getSystemId
|
|
|
|
size_t getLineNumber() const
|
|
{
|
|
if(!locator_)
|
|
return -1;
|
|
|
|
int lineNumber;
|
|
locator_->getLineNumber(&lineNumber);
|
|
return lineNumber;
|
|
} // getLineNumber
|
|
|
|
size_t 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_;
|
|
}; // class LocatorAdaptor
|
|
|
|
class DTDHandlerAdaptor : public ISAXDTDHandler
|
|
{
|
|
public:
|
|
DTDHandlerAdaptor() : dtdHandler_(0) { }
|
|
~DTDHandlerAdaptor() { }
|
|
|
|
void setDTDHandler(dtdHandlerT& handler) { dtdHandler_ = &handler; }
|
|
dtdHandlerT* 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(string_adaptor::construct_from_utf16(pwchName, cchName),
|
|
string_adaptor::construct_from_utf16(pwchPublicId, cchPublicId),
|
|
string_adaptor::construct_from_utf16(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(string_adaptor::construct_from_utf16(pwchName, cchName),
|
|
string_adaptor::construct_from_utf16(pwchPublicId, cchPublicId),
|
|
string_adaptor::construct_from_utf16(pwchSystemId, cchSystemId),
|
|
string_adaptor::construct_from_utf16(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:
|
|
dtdHandlerT* dtdHandler_;
|
|
}; // class DTDHandlerAdaptor
|
|
|
|
class ErrorHandlerAdaptor : public ISAXErrorHandler
|
|
{
|
|
public:
|
|
ErrorHandlerAdaptor() : errorHandler_(0),
|
|
bWarning_(false), bError_(false), bFatal_(false),
|
|
eWarning_("none"), eError_("none"), eFatal_("none")
|
|
{ }
|
|
virtual ~ErrorHandlerAdaptor() { }
|
|
|
|
void setErrorHandler(errorHandlerT& handler) { errorHandler_ = &handler; }
|
|
errorHandlerT* getErrorHandler() const { return errorHandler_; }
|
|
|
|
void setSupplementaryMessage(const std::exception& supplementary)
|
|
{
|
|
supplementary_ = supplementary.what();
|
|
} // setSupplementaryMessage
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE error(
|
|
/* [in] */ ISAXLocator *pLocator,
|
|
/* [in] */ const wchar_t *pwchErrorMessage,
|
|
/* [in] */ HRESULT hrErrorCode)
|
|
{
|
|
bError_ = true;
|
|
eError_ = SAXParseExceptionT(formatError(pwchErrorMessage), LocatorAdaptor(pLocator));
|
|
return S_OK;
|
|
} // error
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE fatalError(
|
|
/* [in] */ ISAXLocator *pLocator,
|
|
/* [in] */ const wchar_t *pwchErrorMessage,
|
|
/* [in] */ HRESULT hrErrorCode)
|
|
{
|
|
bFatal_ = true;
|
|
eFatal_ = SAXParseExceptionT(formatError(pwchErrorMessage), LocatorAdaptor(pLocator));
|
|
return S_FALSE;
|
|
} // fatalError
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE ignorableWarning(
|
|
/* [in] */ ISAXLocator *pLocator,
|
|
/* [in] */ const wchar_t *pwchErrorMessage,
|
|
/* [in] */ HRESULT hrErrorCode)
|
|
{
|
|
bWarning_ = true;
|
|
eWarning_ = SAXParseExceptionT(formatError(pwchErrorMessage), 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:
|
|
std::string formatError(const wchar_t *pwchErrorMessage) const
|
|
{
|
|
std::string errorMsg = string_adaptor::asStdString((string_adaptor::construct_from_utf16(pwchErrorMessage)));
|
|
if(!supplementary_.empty())
|
|
errorMsg += ": " + supplementary_;
|
|
return errorMsg;
|
|
} // formatError
|
|
|
|
ErrorHandlerAdaptor(const ErrorHandlerAdaptor&);
|
|
|
|
typedef SAX::SAXParseException<string_type, string_adaptor> SAXParseExceptionT;
|
|
bool bWarning_;
|
|
bool bError_;
|
|
bool bFatal_;
|
|
SAXParseExceptionT eWarning_;
|
|
SAXParseExceptionT eError_;
|
|
SAXParseExceptionT eFatal_;
|
|
std::string supplementary_;
|
|
|
|
errorHandlerT* errorHandler_;
|
|
}; // class ErrorHandlerAdaptor
|
|
|
|
class ContentHandlerAdaptor : public ISAXContentHandler
|
|
{
|
|
public:
|
|
ContentHandlerAdaptor(ErrorHandlerAdaptor& eh) : contentHandler_(0), eh_(eh) { }
|
|
~ContentHandlerAdaptor() { }
|
|
|
|
void setContentHandler(contentHandlerT& handler) { contentHandler_ = &handler; }
|
|
contentHandlerT* getContentHandler() const { return contentHandler_; }
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE putDocumentLocator(
|
|
/* [in] */ ISAXLocator *pLocator)
|
|
{
|
|
locator_.setLocator(pLocator);
|
|
if(contentHandler_)
|
|
try {
|
|
contentHandler_->setDocumentLocator(locator_);
|
|
}
|
|
catch(const std::exception& e) {
|
|
eh_.setSupplementaryMessage(e);
|
|
throw;
|
|
} // catch
|
|
catch(...) {
|
|
throw;
|
|
}
|
|
return S_OK;
|
|
} // putDocumentLocation
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE startDocument( void)
|
|
{
|
|
if(contentHandler_)
|
|
try {
|
|
contentHandler_->startDocument();
|
|
}
|
|
catch(const std::exception& e) {
|
|
eh_.setSupplementaryMessage(e);
|
|
throw;
|
|
} // catch
|
|
catch(...) {
|
|
throw;
|
|
}
|
|
return S_OK;
|
|
} // startDocument
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE endDocument( void)
|
|
{
|
|
if(contentHandler_)
|
|
try {
|
|
contentHandler_->endDocument();
|
|
}
|
|
catch(const std::exception& e) {
|
|
eh_.setSupplementaryMessage(e);
|
|
throw;
|
|
} // catch
|
|
catch(...) {
|
|
throw;
|
|
}
|
|
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_)
|
|
try {
|
|
contentHandler_->startPrefixMapping(string_adaptor::construct_from_utf16(pwchPrefix, cchPrefix),
|
|
string_adaptor::construct_from_utf16(pwchUri, cchUri));
|
|
}
|
|
catch(const std::exception& e) {
|
|
eh_.setSupplementaryMessage(e);
|
|
throw;
|
|
} // catch
|
|
catch(...) {
|
|
throw;
|
|
}
|
|
return S_OK;
|
|
} // startPrefixMapping
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE endPrefixMapping(
|
|
/* [in] */ const wchar_t *pwchPrefix,
|
|
/* [in] */ int cchPrefix)
|
|
{
|
|
if(contentHandler_)
|
|
try {
|
|
contentHandler_->endPrefixMapping(string_adaptor::construct_from_utf16(pwchPrefix, cchPrefix));
|
|
}
|
|
catch(const std::exception& e) {
|
|
eh_.setSupplementaryMessage(e);
|
|
throw;
|
|
} // catch
|
|
catch(...) {
|
|
throw;
|
|
}
|
|
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_)
|
|
{
|
|
try {
|
|
AttributesAdaptor attrs(pAttributes);
|
|
contentHandler_->startElement(string_adaptor::construct_from_utf16(pwchNamespaceUri, cchNamespaceUri),
|
|
string_adaptor::construct_from_utf16(pwchLocalName, cchLocalName),
|
|
string_adaptor::construct_from_utf16(pwchQName, cchQName),
|
|
attrs);
|
|
}
|
|
catch(const std::exception& e) {
|
|
eh_.setSupplementaryMessage(e);
|
|
throw;
|
|
} // catch
|
|
catch(...) {
|
|
throw;
|
|
}
|
|
} // 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_)
|
|
try {
|
|
contentHandler_->endElement(string_adaptor::construct_from_utf16(pwchNamespaceUri, cchNamespaceUri),
|
|
string_adaptor::construct_from_utf16(pwchLocalName, cchLocalName),
|
|
string_adaptor::construct_from_utf16(pwchQName, cchQName));
|
|
}
|
|
catch(const std::exception& e) {
|
|
eh_.setSupplementaryMessage(e);
|
|
throw;
|
|
} // catch
|
|
catch(...) {
|
|
throw;
|
|
}
|
|
return S_OK;
|
|
} // endElement
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE characters(
|
|
/* [in] */ const wchar_t *pwchChars,
|
|
/* [in] */ int cchChars)
|
|
{
|
|
if(contentHandler_)
|
|
try {
|
|
contentHandler_->characters(string_adaptor::construct_from_utf16(pwchChars, cchChars));
|
|
}
|
|
catch(const std::exception& e) {
|
|
eh_.setSupplementaryMessage(e);
|
|
throw;
|
|
} // catch
|
|
catch(...) {
|
|
throw;
|
|
}
|
|
return S_OK;
|
|
} // characters
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE ignorableWhitespace(
|
|
/* [in] */ const wchar_t *pwchChars,
|
|
/* [in] */ int cchChars)
|
|
{
|
|
if(contentHandler_)
|
|
try {
|
|
contentHandler_->ignorableWhitespace(string_adaptor::construct_from_utf16(pwchChars, cchChars));
|
|
}
|
|
catch(const std::exception& e) {
|
|
eh_.setSupplementaryMessage(e);
|
|
throw;
|
|
} // catch
|
|
catch(...) {
|
|
throw;
|
|
}
|
|
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_)
|
|
try {
|
|
contentHandler_->processingInstruction(string_adaptor::construct_from_utf16(pwchTarget, cchTarget),
|
|
string_adaptor::construct_from_utf16(pwchData, cchData));
|
|
}
|
|
catch(const std::exception& e) {
|
|
eh_.setSupplementaryMessage(e);
|
|
throw;
|
|
} // catch
|
|
catch(...) {
|
|
throw;
|
|
}
|
|
return S_OK;
|
|
} // processingInstruction
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE skippedEntity(
|
|
/* [in] */ const wchar_t *pwchName,
|
|
/* [in] */ int cchName)
|
|
{
|
|
if(contentHandler_)
|
|
try {
|
|
contentHandler_->skippedEntity(string_adaptor::construct_from_utf16(pwchName, cchName));
|
|
}
|
|
catch(const std::exception& e) {
|
|
eh_.setSupplementaryMessage(e);
|
|
throw;
|
|
} // catch
|
|
catch(...) {
|
|
throw;
|
|
}
|
|
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
|
|
contentHandlerT* contentHandler_;
|
|
ErrorHandlerAdaptor& eh_;
|
|
LocatorAdaptor locator_;
|
|
|
|
//////////////////////////////////////////////////////
|
|
// COM interface -> C++ interface adaptors
|
|
class AttributesAdaptor : public attributesT
|
|
{
|
|
public:
|
|
AttributesAdaptor(ISAXAttributes __RPC_FAR *pAttributes) : attributes_(pAttributes) { }
|
|
~AttributesAdaptor() { }
|
|
|
|
/////////////////////////
|
|
// indexed access
|
|
virtual int getLength() const
|
|
{
|
|
int length;
|
|
attributes_->getLength(&length);
|
|
return length;
|
|
} // getLength
|
|
|
|
virtual string_type getURI(unsigned int index) const
|
|
{
|
|
const wchar_t* pwchUri;
|
|
int cchUri;
|
|
HRESULT hr = attributes_->getURI(index, &pwchUri, &cchUri);
|
|
if (FAILED(hr))
|
|
return string_type();
|
|
string_type uri(string_adaptor::construct_from_utf16(pwchUri, cchUri));
|
|
return uri;
|
|
} // getURI
|
|
|
|
virtual string_type getLocalName(unsigned int index) const
|
|
{
|
|
const wchar_t* pwchLocalName;
|
|
int cchLocalName;
|
|
HRESULT hr = attributes_->getLocalName(index, &pwchLocalName, &cchLocalName);
|
|
if (FAILED(hr))
|
|
return string_type();
|
|
string_type localName(string_adaptor::construct_from_utf16(pwchLocalName, cchLocalName));
|
|
return localName;
|
|
} // getLocalName
|
|
|
|
virtual string_type getQName(unsigned int index) const
|
|
{
|
|
const wchar_t* pwchQName;
|
|
int cchQName;
|
|
HRESULT hr = attributes_->getQName(index, &pwchQName, &cchQName);
|
|
if (FAILED(hr))
|
|
return string_type();
|
|
string_type qName(string_adaptor::construct_from_utf16(pwchQName, cchQName));
|
|
return qName;
|
|
} // getQName
|
|
|
|
virtual string_type getType(unsigned int index) const
|
|
{
|
|
const wchar_t* pwchType;
|
|
int cchType;
|
|
HRESULT hr = attributes_->getType(index, &pwchType, &cchType);
|
|
if (FAILED(hr))
|
|
return string_type();
|
|
string_type type(string_adaptor::construct_from_utf16(pwchType, cchType));
|
|
return type;
|
|
} // getType
|
|
|
|
virtual string_type getValue(unsigned int index) const
|
|
{
|
|
const wchar_t* pwchValue;
|
|
int cchValue;
|
|
HRESULT hr = attributes_->getValue(index, &pwchValue, &cchValue);
|
|
if (FAILED(hr))
|
|
return string_type();
|
|
string_type value(string_adaptor::construct_from_utf16(pwchValue, cchValue));
|
|
return value;
|
|
} // getValue
|
|
|
|
/////////////////////////
|
|
// name based query
|
|
virtual int getIndex(const string_type& uri, const string_type& localName) const
|
|
{
|
|
int index = -1;
|
|
std::wstring wUri(string_adaptor::asStdWString(uri));
|
|
std::wstring wLocalName(string_adaptor::asStdWString(localName));
|
|
HRESULT hr = attributes_->getIndexFromName(wUri.data(), static_cast<int>(wUri.length()),
|
|
wLocalName.data(), static_cast<int>(wLocalName.length()),
|
|
&index);
|
|
if (FAILED(hr))
|
|
{
|
|
index = -1;
|
|
}
|
|
return index;
|
|
} // getIndex
|
|
|
|
virtual int getIndex(const string_type& qName) const
|
|
{
|
|
int index = -1;
|
|
std::wstring wQName(string_adaptor::asStdWString(qName));
|
|
HRESULT hr = attributes_->getIndexFromQName(wQName.data(), static_cast<int>(wQName.length()), &index);
|
|
if (FAILED(hr))
|
|
{
|
|
index = -1;
|
|
}
|
|
return index;
|
|
} // getIndex
|
|
|
|
virtual string_type getType(const string_type& uri, const string_type& localName) const
|
|
{
|
|
const wchar_t* pwchType;
|
|
int cchType;
|
|
std::wstring wUri(string_adaptor::asStdWString(uri));
|
|
std::wstring wLocalName(string_adaptor::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 string_type();
|
|
string_type type(string_adaptor::construct_from_utf16(pwchType, cchType));
|
|
return type;
|
|
} // getType
|
|
|
|
virtual string_type getType(const string_type& qName) const
|
|
{
|
|
const wchar_t* pwchType;
|
|
int cchType;
|
|
std::wstring wQName(string_adaptor::asStdWString(qName));
|
|
HRESULT hr = attributes_->getTypeFromQName(wQName.data(), static_cast<int>(wQName.length()),
|
|
&pwchType, &cchType);
|
|
if (FAILED(hr))
|
|
return string_type();
|
|
string_type type(string_adaptor::construct_from_utf16(pwchType, cchType));
|
|
return type;
|
|
} // getType
|
|
|
|
virtual string_type getValue(const string_type& uri, const string_type& localName) const
|
|
{
|
|
const wchar_t* pwchValue;
|
|
int cchValue;
|
|
std::wstring wUri(string_adaptor::asStdWString(uri));
|
|
std::wstring wLocalName(string_adaptor::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 string_type();
|
|
string_type value(string_adaptor::construct_from_utf16(pwchValue, cchValue));
|
|
return value;
|
|
} // getValue
|
|
|
|
virtual string_type getValue(const string_type& qname) const
|
|
{
|
|
const wchar_t* pwchValue;
|
|
int cchValue;
|
|
std::wstring wQName(string_adaptor::asStdWString(qname));
|
|
HRESULT hr = attributes_->getValueFromQName(wQName.data(), static_cast<int>(wQName.length()),
|
|
&pwchValue, &cchValue);
|
|
if (FAILED(hr))
|
|
return string_type();
|
|
string_type value(string_adaptor::construct_from_utf16(pwchValue, cchValue));
|
|
return value;
|
|
} // getValue
|
|
|
|
private:
|
|
ISAXAttributes __RPC_FAR *attributes_;
|
|
|
|
AttributesAdaptor();
|
|
}; // class AttributesAdaptor
|
|
}; // class ContentHandlerAdaptor
|
|
|
|
class LexicalHandlerAdaptor : public ISAXLexicalHandler
|
|
{
|
|
public:
|
|
LexicalHandlerAdaptor() : lexicalHandler_(0) { }
|
|
virtual ~LexicalHandlerAdaptor() { }
|
|
|
|
void setLexicalHandler(lexicalHandlerT& handler) { lexicalHandler_ = &handler; }
|
|
lexicalHandlerT* 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(string_adaptor::construct_from_utf16(pwchName, cchName),
|
|
string_adaptor::construct_from_utf16(pwchPublicId, cchPublicId),
|
|
string_adaptor::construct_from_utf16(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(string_adaptor::construct_from_utf16(pwchName, cchName));
|
|
return S_OK;
|
|
} // startEntity
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE endEntity(
|
|
/* [in] */ const wchar_t *pwchName,
|
|
/* [in] */ int cchName)
|
|
{
|
|
if(lexicalHandler_)
|
|
lexicalHandler_->endEntity(string_adaptor::construct_from_utf16(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(string_adaptor::construct_from_utf16(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:
|
|
lexicalHandlerT* lexicalHandler_;
|
|
}; // class LexicalHandlerAdaptor
|
|
|
|
class DeclHandlerAdaptor : public ISAXDeclHandler
|
|
{
|
|
public:
|
|
DeclHandlerAdaptor() : declHandler_(0) { }
|
|
virtual ~DeclHandlerAdaptor() { }
|
|
|
|
void setDeclHandler(declHandlerT& handler) { declHandler_ = &handler; }
|
|
declHandlerT* 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(string_adaptor::construct_from_utf16(pwchName, cchName),
|
|
string_adaptor::construct_from_utf16(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(string_adaptor::construct_from_utf16(pwchElementName, cchElementName),
|
|
string_adaptor::construct_from_utf16(pwchAttributeName, cchAttributeName),
|
|
string_adaptor::construct_from_utf16(pwchType, cchType),
|
|
string_adaptor::construct_from_utf16(pwchValueDefault, cchValueDefault),
|
|
string_adaptor::construct_from_utf16(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(string_adaptor::construct_from_utf16(pwchName, cchName),
|
|
string_adaptor::construct_from_utf16(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(string_adaptor::construct_from_utf16(pwchName, cchName),
|
|
string_adaptor::construct_from_utf16(pwchPublicId, cchPublicId),
|
|
string_adaptor::construct_from_utf16(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:
|
|
declHandlerT* declHandler_;
|
|
}; // class DeclHandlerAdaptor
|
|
|
|
class StreamAdaptor : public ISequentialStream
|
|
{
|
|
public:
|
|
StreamAdaptor(inputSourceT& source) :
|
|
source_(source)
|
|
{
|
|
} // StreamAdaptor
|
|
|
|
virtual HRESULT __stdcall Read(void* pv, ULONG cb, ULONG* pcbRead)
|
|
{
|
|
source_.getByteStream()->read(reinterpret_cast<char*>(pv), cb);
|
|
*pcbRead = static_cast<ULONG>(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:
|
|
inputSourceT& source_;
|
|
}; // StreamAdaptor
|
|
|
|
|
|
//////////////////////////////////////////////////////
|
|
// member variables
|
|
COMInitializer_type init;
|
|
DTDHandlerAdaptor dtdHandler_;
|
|
ErrorHandlerAdaptor errorHandler_;
|
|
ContentHandlerAdaptor contentHandler_;
|
|
LexicalHandlerAdaptor lexicalHandler_;
|
|
DeclHandlerAdaptor declHandler_;
|
|
|
|
ISAXXMLReaderPtr reader_;
|
|
}; // class msxml
|
|
|
|
template<class string_type, class T0, class T1>
|
|
msxml2_wrapper<string_type, T0, T1>::msxml2_wrapper() :
|
|
init(),
|
|
dtdHandler_(),
|
|
errorHandler_(),
|
|
contentHandler_(errorHandler_),
|
|
lexicalHandler_(),
|
|
declHandler_(),
|
|
reader_()
|
|
{
|
|
reader_.CreateInstance("Msxml2.SAXXMLReader.6.0");
|
|
if(reader_.GetInterfacePtr() == 0)
|
|
reader_.CreateInstance("Msxml2.SAXXMLReader.5.0");
|
|
if(reader_.GetInterfacePtr() == 0)
|
|
reader_.CreateInstance("Msxml2.SAXXMLReader.4.0");
|
|
if(reader_.GetInterfacePtr() == 0)
|
|
reader_.CreateInstance("Msxml2.SAXXMLReader.3.0");
|
|
if(reader_.GetInterfacePtr() == 0)
|
|
reader_.CreateInstance(__uuidof(ISAXXMLReader));
|
|
|
|
if(reader_.GetInterfacePtr() == 0)
|
|
throw SAXException("MSXML SAX Reader (pre-4.0) could not be instantiated");
|
|
|
|
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 string_type, class T0, class T1>
|
|
msxml2_wrapper<string_type, T0, T1>::~msxml2_wrapper()
|
|
{
|
|
if(reader_.GetInterfacePtr())
|
|
reader_.Release();
|
|
} // ~msxml2_wrapper
|
|
|
|
template<class string_type, class T0, class T1>
|
|
bool msxml2_wrapper<string_type, T0, T1>::getFeature(const string_type& name) const
|
|
{
|
|
VARIANT_BOOL feature;
|
|
std::wstring wName(string_adaptor::asStdWString(name));
|
|
reader_->getFeature(wName.c_str(), &feature);
|
|
return (feature == VARIANT_TRUE) ? true : false;
|
|
} // msxml2_wrapper::getFeature
|
|
|
|
template<class string_type, class T0, class T1>
|
|
void msxml2_wrapper<string_type, T0, T1>::setFeature(const string_type& name, bool value)
|
|
{
|
|
std::wstring wName(string_adaptor::asStdWString(name));
|
|
reader_->putFeature(wName.c_str(), value);
|
|
} // setFeature
|
|
|
|
template<class string_type, class T0, class T1>
|
|
void msxml2_wrapper<string_type, T0, T1>::setErrorHandler(errorHandlerT& handler)
|
|
{
|
|
errorHandler_.setErrorHandler(handler);
|
|
} // setErrorHandler
|
|
|
|
template<class string_type, class T0, class T1>
|
|
void msxml2_wrapper<string_type, T0, T1>::parse(inputSourceT& source)
|
|
{
|
|
if(source.getByteStream() == 0)
|
|
{
|
|
std::wstring wSysId(string_adaptor::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
|
|
} // namespace Arabica
|
|
|
|
#if defined(_MSC_VER)
|
|
# pragma warning( pop )
|
|
#endif
|
|
|
|
#endif
|
|
// end of file
|
|
|