Sorted out exception handling in MSXML ContentHandler wrapper so that it no longer corrupts the stack

This commit is contained in:
jez 2010-05-21 09:56:18 +01:00
parent b8ea5e1f64
commit 94b834ff30
4 changed files with 235 additions and 113 deletions

View file

@ -268,33 +268,156 @@ class msxml2_wrapper :
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() : contentHandler_(0) { }
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_) contentHandler_->setDocumentLocator(locator_);
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_) contentHandler_->startDocument();
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_) contentHandler_->endDocument();
if(contentHandler_)
try {
contentHandler_->endDocument();
}
catch(const std::exception& e) {
eh_.setSupplementaryMessage(e);
throw;
} // catch
catch(...) {
throw;
}
return S_OK;
} // endDocument
@ -304,10 +427,19 @@ class msxml2_wrapper :
/* [in] */ const wchar_t *pwchUri,
/* [in] */ int cchUri)
{
{
if(contentHandler_)
contentHandler_->startPrefixMapping(string_adaptor::construct_from_utf16(pwchPrefix, cchPrefix),
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
@ -315,7 +447,17 @@ class msxml2_wrapper :
/* [in] */ const wchar_t *pwchPrefix,
/* [in] */ int cchPrefix)
{
if(contentHandler_) contentHandler_->endPrefixMapping(string_adaptor::construct_from_utf16(pwchPrefix, 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
@ -330,11 +472,20 @@ class msxml2_wrapper :
{
if(contentHandler_)
{
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);
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
@ -348,9 +499,18 @@ class msxml2_wrapper :
/* [in] */ int cchQName)
{
if(contentHandler_)
contentHandler_->endElement(string_adaptor::construct_from_utf16(pwchNamespaceUri, cchNamespaceUri),
string_adaptor::construct_from_utf16(pwchLocalName, cchLocalName),
string_adaptor::construct_from_utf16(pwchQName, cchQName));
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
@ -358,7 +518,17 @@ class msxml2_wrapper :
/* [in] */ const wchar_t *pwchChars,
/* [in] */ int cchChars)
{
if(contentHandler_) contentHandler_->characters(string_adaptor::construct_from_utf16(pwchChars, 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
@ -367,7 +537,16 @@ class msxml2_wrapper :
/* [in] */ int cchChars)
{
if(contentHandler_)
contentHandler_->ignorableWhitespace(string_adaptor::construct_from_utf16(pwchChars, cchChars));
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
@ -378,17 +557,35 @@ class msxml2_wrapper :
/* [in] */ int cchData)
{
if(contentHandler_)
contentHandler_->processingInstruction(string_adaptor::construct_from_utf16(pwchTarget, cchTarget),
string_adaptor::construct_from_utf16(pwchData, cchData));
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)
/* [in] */ int cchName)
{
if(contentHandler_)
contentHandler_->skippedEntity(string_adaptor::construct_from_utf16(pwchName, cchName));
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
@ -401,6 +598,7 @@ class msxml2_wrapper :
////////////////////////////////////////////////
// member varaibles
contentHandlerT* contentHandler_;
ErrorHandlerAdaptor& eh_;
LocatorAdaptor locator_;
//////////////////////////////////////////////////////
@ -559,87 +757,6 @@ class msxml2_wrapper :
}; // 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(errorHandlerT& handler) { errorHandler_ = &handler; }
errorHandlerT* getErrorHandler() const { return errorHandler_; }
virtual HRESULT STDMETHODCALLTYPE error(
/* [in] */ ISAXLocator *pLocator,
/* [in] */ const wchar_t *pwchErrorMessage,
/* [in] */ HRESULT hrErrorCode)
{
bError_ = true;
string_type errorMsg(string_adaptor::construct_from_utf16(pwchErrorMessage));
eError_ = SAXParseExceptionT(string_adaptor::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;
string_type errorMsg(string_adaptor::construct_from_utf16(pwchErrorMessage));
eFatal_ = SAXParseExceptionT(string_adaptor::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;
string_type errorMsg(string_adaptor::construct_from_utf16(pwchErrorMessage));
eWarning_ = SAXParseExceptionT(string_adaptor::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::SAXParseException<string_type, string_adaptor> SAXParseExceptionT;
bool bWarning_;
bool bError_;
bool bFatal_;
SAXParseExceptionT eWarning_;
SAXParseExceptionT eError_;
SAXParseExceptionT eFatal_;
errorHandlerT* errorHandler_;
}; // class ErrorHandlerAdaptor
class LexicalHandlerAdaptor : public ISAXLexicalHandler
{
public:
@ -859,8 +976,8 @@ class msxml2_wrapper :
// member variables
COMInitializer_type init;
DTDHandlerAdaptor dtdHandler_;
ContentHandlerAdaptor contentHandler_;
ErrorHandlerAdaptor errorHandler_;
ContentHandlerAdaptor contentHandler_;
LexicalHandlerAdaptor lexicalHandler_;
DeclHandlerAdaptor declHandler_;
@ -869,7 +986,15 @@ class msxml2_wrapper :
}; // class msxml
template<class string_type, class T0, class T1>
msxml2_wrapper<string_type, T0, T1>::msxml2_wrapper()
msxml2_wrapper<string_type, T0, T1>::msxml2_wrapper() :
init(),
dtdHandler_(),
errorHandler_(),
contentHandler_(errorHandler_),
lexicalHandler_(),
declHandler_(),
reader_(),
properties_()
{
reader_.CreateInstance("Msxml2.SAXXMLReader.6.0");
if(reader_.GetInterfacePtr() == 0)

View file

@ -83,7 +83,7 @@ public:
virtual void characters(const std::string& ch)
{
verifyNoCharacterData(ch, "xsl:apply-templates");
verifyNoCharacterData(ch, "xsl:apply-templates");
} // characters
private:

View file

@ -67,7 +67,7 @@ public:
virtual void characters(const std::string& ch)
{
verifyNoCharacterData(ch, "xsl:sort");
verifyNoCharacterData(ch, "xsl:sort");
} // characters
private:

View file

@ -92,12 +92,9 @@ std::map<std::string, std::string> gatherAttributes(const std::string& parentEle
void verifyNoCharacterData(const std::string& ch,
const std::string& name)
{
bool ok = true;
for(std::string::const_iterator i = ch.begin(), e = ch.end(); ok && i != e; ++i)
ok = Arabica::XML::is_space(*i);
if(!ok)
throw SAX::SAXException(name + " element can not contain character data.");
for(std::string::const_iterator i = ch.begin(), e = ch.end(); i != e; ++i)
if(!Arabica::XML::is_space(*i))
throw SAX::SAXException(name + " element can not contain character data.");
} // verifyNoCharacterContent
} // namespace XSLT