Files
simgear/simgear/xml/easyxml.cxx
2016-07-03 23:41:07 +01:00

335 lines
7.0 KiB
C++
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* \file easyxml.cxx - implementation of EasyXML interfaces.
* Written by David Megginson, 2000-2001
* This file is in the Public Domain, and comes with NO WARRANTY of any kind.
*/
#ifdef HAVE_CONFIG_H
# include <simgear_config.h>
#endif
#include <simgear/compiler.h>
#include <string.h> // strcmp()
#include "easyxml.hxx"
#ifdef SYSTEM_EXPAT
# include <expat.h>
#else
# include "sg_expat.h"
#endif
#include <fstream>
#include <iostream>
#include <simgear/misc/sgstream.hxx>
#include <simgear/misc/sg_path.hxx>
using std::ifstream;
using std::istream;
using std::string;
////////////////////////////////////////////////////////////////////////
// Implementation of XMLAttributes.
////////////////////////////////////////////////////////////////////////
XMLAttributes::XMLAttributes ()
{
}
XMLAttributes::~XMLAttributes ()
{
}
int
XMLAttributes::findAttribute (const char * name) const
{
int s = size();
for (int i = 0; i < s; i++) {
if (strcmp(name, getName(i)) == 0)
return i;
}
return -1;
}
bool
XMLAttributes::hasAttribute (const char * name) const
{
return (findAttribute(name) != -1);
}
const char *
XMLAttributes::getValue (const char * name) const
{
int pos = findAttribute(name);
if (pos >= 0)
return getValue(pos);
else
return 0;
}
////////////////////////////////////////////////////////////////////////
// Implementation of XMLAttributesDefault.
////////////////////////////////////////////////////////////////////////
XMLAttributesDefault::XMLAttributesDefault ()
{
}
XMLAttributesDefault::XMLAttributesDefault (const XMLAttributes &atts)
{
int s = atts.size();
for (int i = 0; i < s; i++)
addAttribute(atts.getName(i), atts.getValue(i));
}
XMLAttributesDefault::~XMLAttributesDefault ()
{
}
int
XMLAttributesDefault::size () const
{
return _atts.size() / 2;
}
const char *
XMLAttributesDefault::getName (int i) const
{
return _atts[i*2].c_str();
}
const char *
XMLAttributesDefault::getValue (int i) const
{
return _atts[i*2+1].c_str();
}
void
XMLAttributesDefault::addAttribute (const char * name, const char * value)
{
_atts.push_back(name);
_atts.push_back(value);
}
void
XMLAttributesDefault::setName (int i, const char * name)
{
_atts[i*2] = name;
}
void
XMLAttributesDefault::setValue (int i, const char * name)
{
_atts[i*2+1] = name;
}
void
XMLAttributesDefault::setValue (const char * name, const char * value)
{
int pos = findAttribute(name);
if (pos >= 0) {
setName(pos, name);
setValue(pos, value);
} else {
addAttribute(name, value);
}
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void XMLVisitor::savePosition(void)
{
if (parser) {
column = XML_GetCurrentColumnNumber(parser);
line = XML_GetCurrentLineNumber(parser);
}
}
////////////////////////////////////////////////////////////////////////
// Attribute list wrapper for Expat.
////////////////////////////////////////////////////////////////////////
int
ExpatAtts::size () const
{
int s = 0;
for (int i = 0; _atts[i] != 0; i += 2)
s++;
return s;
}
const char *
ExpatAtts::getName (int i) const
{
return _atts[i*2];
}
const char *
ExpatAtts::getValue (int i) const
{
return _atts[i*2+1];
}
const char *
ExpatAtts::getValue (const char * name) const
{
return XMLAttributes::getValue(name);
}
////////////////////////////////////////////////////////////////////////
// Static callback functions for Expat.
////////////////////////////////////////////////////////////////////////
#define VISITOR (*((XMLVisitor *)userData))
static void
start_element (void * userData, const char * name, const char ** atts)
{
VISITOR.savePosition();
VISITOR.startElement(name, ExpatAtts(atts));
}
static void
end_element (void * userData, const char * name)
{
VISITOR.savePosition();
VISITOR.endElement(name);
}
static void
character_data (void * userData, const char * s, int len)
{
VISITOR.savePosition();
VISITOR.data(s, len);
}
static void
processing_instruction (void * userData,
const char * target,
const char * data)
{
VISITOR.savePosition();
VISITOR.pi(target, data);
}
#undef VISITOR
////////////////////////////////////////////////////////////////////////
// Implementation of XMLReader.
////////////////////////////////////////////////////////////////////////
void
readXML (istream &input, XMLVisitor &visitor, const string &path)
{
XML_Parser parser = XML_ParserCreate(0);
XML_SetUserData(parser, &visitor);
XML_SetElementHandler(parser, start_element, end_element);
XML_SetCharacterDataHandler(parser, character_data);
XML_SetProcessingInstructionHandler(parser, processing_instruction);
visitor.setParser(parser);
visitor.setPath(path);
visitor.startXML();
char buf[16384];
while (!input.eof()) {
// FIXME: get proper error string from system
if (!input.good()) {
sg_io_exception ex ("Problem reading file",
sg_location(path,
XML_GetCurrentLineNumber(parser),
XML_GetCurrentColumnNumber(parser)),
"SimGear XML Parser");
visitor.setParser(0);
XML_ParserFree(parser);
throw ex;
}
input.read(buf,16384);
if (!XML_Parse(parser, buf, input.gcount(), false)) {
sg_io_exception ex (XML_ErrorString(XML_GetErrorCode(parser)),
sg_location(path,
XML_GetCurrentLineNumber(parser),
XML_GetCurrentColumnNumber(parser)),
"SimGear XML Parser");
visitor.setParser(0);
XML_ParserFree(parser);
throw ex;
}
}
// Verify end of document.
if (!XML_Parse(parser, buf, 0, true)) {
sg_io_exception ex (XML_ErrorString(XML_GetErrorCode(parser)),
sg_location(path,
XML_GetCurrentLineNumber(parser),
XML_GetCurrentColumnNumber(parser)),
"SimGear XML Parser");
visitor.setParser(0);
XML_ParserFree(parser);
throw ex;
}
visitor.setParser(0);
XML_ParserFree(parser);
visitor.endXML();
}
void
readXML (const SGPath &path, XMLVisitor &visitor)
{
sg_ifstream input(path);
if (input.good()) {
try {
readXML(input, visitor, path.utf8Str());
} catch (sg_io_exception &) {
input.close();
throw;
} catch (sg_throwable &) {
input.close();
throw;
}
} else {
throw sg_io_exception("Failed to open file", sg_location(path),
"SimGear XML Parser");
}
input.close();
}
void
readXML (const char *buf, const int size, XMLVisitor &visitor)
{
XML_Parser parser = XML_ParserCreate(0);
XML_SetUserData(parser, &visitor);
XML_SetElementHandler(parser, start_element, end_element);
XML_SetCharacterDataHandler(parser, character_data);
XML_SetProcessingInstructionHandler(parser, processing_instruction);
visitor.startXML();
if (!XML_Parse(parser, buf, size, false)) {
sg_io_exception ex (XML_ErrorString(XML_GetErrorCode(parser)),
sg_location("In-memory XML buffer",
XML_GetCurrentLineNumber(parser),
XML_GetCurrentColumnNumber(parser)),
"SimGear XML Parser");
XML_ParserFree(parser);
throw ex;
}
XML_ParserFree(parser);
visitor.endXML();
}
// end of easyxml.cxx