32#include "SaxParserWrapper.h"
36#include <libxml/parser.h>
37#include <libxml/xmlstring.h>
43#include "BESInternalError.h"
44#include "BESInternalFatalError.h"
45#include "BESSyntaxUserError.h"
46#include "BESForbiddenError.h"
47#include "BESNotFoundError.h"
50#include "XMLHelpers.h"
56#define NCML_PARSER_USE_SAX2_NAMESPACES 1
64#if NCML_PARSER_USE_SAX2_NAMESPACES
65static const int SAX2_NAMESPACE_ATTRIBUTE_ARRAY_STRIDE = 5;
66static int toXMLAttributeMapWithNamespaces(
XMLAttributeMap& attrMap,
const xmlChar** attributes,
int num_attributes)
69 for (
int i = 0; i < num_attributes; ++i) {
72 attributes += SAX2_NAMESPACE_ATTRIBUTE_ARRAY_STRIDE;
75 return num_attributes;
79static int toXMLAttributeMapNoNamespaces(
XMLAttributeMap& attrMap,
const xmlChar** attrs)
83 while (attrs && *attrs != NULL)
86 attr.localname = XMLUtil::xmlCharToString(*attrs);
87 attr.value = XMLUtil::xmlCharToString(*(attrs+1));
114#define BEGIN_SAFE_PARSER_BLOCK(argName) { \
115 SaxParserWrapper* _spw_ = static_cast<SaxParserWrapper*>(argName); \
116 if (_spw_->isExceptionState()) \
124 SaxParser& parser = _spw_->getParser(); \
125 parser.setParseLineNumber(_spw_->getCurrentParseLine());
128#define END_SAFE_PARSER_BLOCK } \
129 catch (BESError& theErr) \
131 BESDEBUG("ncml", "Caught BESError&, deferring..." << endl); \
132 BESInternalError _badness_("ParseError: " + theErr.get_message() , theErr.get_file(), theErr.get_line());\
133 _spw_->deferException(_badness_); \
135 catch (std::exception& ex) \
137 BESDEBUG("ncml", "Caught std::exception&, wrapping and deferring..." << endl); \
138 BESInternalError _badness_("ParseError: " + string(ex.what()), __FILE__, __LINE__);\
139 _spw_->deferException(_badness_); \
143 BESDEBUG("ncml", "Caught unknown (...) exception: deferring default error." << endl); \
144 BESInternalError _badness_("SaxParserWrapper:: Unknown Exception Type: ", __FILE__, __LINE__); \
145 _spw_->deferException(_badness_); \
153static void ncmlStartDocument(
void* userData)
155 BEGIN_SAFE_PARSER_BLOCK(userData)
157 parser.onStartDocument();
159 END_SAFE_PARSER_BLOCK
162static void ncmlEndDocument(
void* userData)
164 BEGIN_SAFE_PARSER_BLOCK(userData)
166 parser.onEndDocument();
168 END_SAFE_PARSER_BLOCK
171#if !NCML_PARSER_USE_SAX2_NAMESPACES
173static void ncmlStartElement(
void * userData,
174 const xmlChar * name,
175 const xmlChar ** attrs)
178 BEGIN_SAFE_PARSER_BLOCK(1)
180 string nameS =
XMLUtil::xmlCharToString(name);
182 toXMLAttributeMapNoNamespaces(map, attrs);
185 parser.onStartElement(nameS, map);
187 END_SAFE_PARSER_BLOCK
190static
void ncmlEndElement(
void * userData,
191 const xmlChar * name)
193 BEGIN_SAFE_PARSER_BLOCK(1)
195 string nameS =
XMLUtil::xmlCharToString(name);
196 parser.onEndElement(nameS);
198 END_SAFE_PARSER_BLOCK
202#if NCML_PARSER_USE_SAX2_NAMESPACES
204void ncmlSax2StartElementNs(
void *userData,
const xmlChar *localname,
const xmlChar *prefix,
const xmlChar *URI,
205 int nb_namespaces,
const xmlChar **namespaces,
int nb_attributes,
int ,
206 const xmlChar **attributes)
209 BEGIN_SAFE_PARSER_BLOCK(userData)
211 BESDEBUG(
"ncml",
"SaxParserWrapper::ncmlSax2StartElementNs() - localname:" << localname << endl);
214 toXMLAttributeMapWithNamespaces(attrMap, attributes, nb_attributes);
220 string localnameString = XMLUtil::xmlCharToString(localname);
221 string prefixString = XMLUtil::xmlCharToString(prefix);
222 string uriString = XMLUtil::xmlCharToString(URI);
224 parser.onStartElementWithNamespace(
231 END_SAFE_PARSER_BLOCK
235void ncmlSax2EndElementNs(
void *userData,
const xmlChar *localname,
const xmlChar *prefix,
const xmlChar *URI)
237 BEGIN_SAFE_PARSER_BLOCK(userData)
239 string localnameString = XMLUtil::xmlCharToString(localname);
240 string prefixString = XMLUtil::xmlCharToString(prefix);
241 string uriString = XMLUtil::xmlCharToString(URI);
242 parser.onEndElementWithNamespace(localnameString, prefixString, uriString);
244 END_SAFE_PARSER_BLOCK
248static void ncmlCharacters(
void* userData,
const xmlChar* content,
int len)
250 BEGIN_SAFE_PARSER_BLOCK(userData)
255 string characters(
"");
256 characters.reserve(len);
257 const xmlChar* contentEnd = content+len;
258 while(content != contentEnd)
260 characters += (
const char)(*content++);
263 parser.onCharacters(characters);
265 END_SAFE_PARSER_BLOCK
268static void ncmlWarning(
void* userData,
const char* msg, ...)
270 BEGIN_SAFE_PARSER_BLOCK(userData)
272 BESDEBUG(
"ncml",
"SaxParserWrapper::ncmlWarning() - msg:" << msg << endl);
277 unsigned int len =
sizeof(buffer);
278 vsnprintf(buffer, len, msg, args);
280 parser.onParseWarning(
string(buffer));
282 END_SAFE_PARSER_BLOCK
285static void ncmlFatalError(
void* userData,
const char* msg, ...)
287 BEGIN_SAFE_PARSER_BLOCK(userData)
289 BESDEBUG(
"ncml",
"SaxParserWrapper::ncmlFatalError() - msg:" << msg << endl);
294 unsigned int len =
sizeof(buffer);
295 vsnprintf(buffer, len, msg, args);
297 parser.onParseError(
string(buffer));
299 END_SAFE_PARSER_BLOCK
306 _parser(parser), _handler(), _state(NOT_PARSING), _errorMsg(
""), _errorType(0), _errorFile(
""), _errorLine(-1)
310SaxParserWrapper::~SaxParserWrapper()
313 _state = NOT_PARSING;
322 if (_state == PARSING) {
323 throw BESInternalError(
"Parse called again while already in parse.", __FILE__, __LINE__);
331 bool success = xmlSAXUserParseFile(&_handler,
this, ncmlFilename.c_str());
339 _state = NOT_PARSING;
357 _state = NOT_PARSING;
359 switch (_errorType) {
360 case BES_INTERNAL_ERROR:
363 case BES_INTERNAL_FATAL_ERROR:
366 case BES_SYNTAX_USER_ERROR:
369 case BES_FORBIDDEN_ERROR:
372 case BES_NOT_FOUND_ERROR:
384 return xmlSAX2GetLineNumber(_context);
393static void setAllHandlerCBToNulls(xmlSAXHandler& h)
395 h.internalSubset = 0;
397 h.hasInternalSubset = 0;
398 h.hasExternalSubset = 0;
405 h.unparsedEntityDecl = 0;
406 h.setDocumentLocator = 0;
413 h.ignorableWhitespace = 0;
414 h.processingInstruction = 0;
419 h.getParameterEntity = 0;
421 h.externalSubset = 0;
426 h.startElementNs = 0;
431void SaxParserWrapper::setupParser()
437 xmlSAXVersion(&_handler, 2);
441 setAllHandlerCBToNulls(_handler);
444 _handler.startDocument = ncmlStartDocument;
445 _handler.endDocument = ncmlEndDocument;
446 _handler.warning = ncmlWarning;
447 _handler.error = ncmlFatalError;
448 _handler.fatalError = ncmlFatalError;
449 _handler.characters = ncmlCharacters;
452#if NCML_PARSER_USE_SAX2_NAMESPACES
453 _handler.startElement = 0;
454 _handler.endElement = 0;
455 _handler.startElementNs = ncmlSax2StartElementNs;
456 _handler.endElementNs = ncmlSax2EndElementNs;
458 _handler.startElement = ncmlStartElement;
459 _handler.endElement = ncmlEndElement;
460 _handler.startElementNs = 0;
461 _handler.endElementNs = 0;
466void SaxParserWrapper::cleanupParser() noexcept
Base exception class for the BES with basic string message.
unsigned int get_line() const
get the line number where the exception was thrown
unsigned int get_bes_error_type() const
Return the return code for this error class.
std::string get_file() const
get the file name where the exception was thrown
std::string get_message() const
get the error message for this exception
error thrown if the BES is not allowed to access the resource requested
exception thrown if internal error encountered
exception thrown if an internal error is found and is fatal to the BES
error thrown if the resource requested cannot be found
error thrown if there is a user syntax error in the request or any other user error
bool parse(const std::string &ncmlFilename)
Do a SAX parse of the ncmlFilename and pass the calls to wrapper parser.
bool isExceptionState() const
void deferException(BESError &theErr)
The remaining calls are for the internals of the parser, but need to be public.
int getCurrentParseLine() const
Interface class for the wrapper between libxml C SAX parser and our NCMLParser.
void addAttribute(const XMLAttribute &attribute)
void fromSAX2Namespaces(const xmlChar **pNamespaces, int numNamespaces)
NcML Parser for adding/modifying/removing metadata (attributes) to existing local datasets using NcML...
void fromSAX2NamespaceAttributes(const xmlChar **chunkOfFivePointers)