mirror of https://github.com/KLayout/klayout.git
WIP
This commit is contained in:
parent
971ef3ff72
commit
c8bc64a90e
|
|
@ -45,6 +45,7 @@ SOURCES = \
|
||||||
tlUnitTest.cc \
|
tlUnitTest.cc \
|
||||||
tlInt128Support.cc \
|
tlInt128Support.cc \
|
||||||
tlXMLParser.cc \
|
tlXMLParser.cc \
|
||||||
|
tlXMLReader.cc \
|
||||||
tlXMLWriter.cc \
|
tlXMLWriter.cc \
|
||||||
tlThreadedWorkers.cc \
|
tlThreadedWorkers.cc \
|
||||||
tlThreads.cc \
|
tlThreads.cc \
|
||||||
|
|
@ -113,6 +114,7 @@ HEADERS = \
|
||||||
tlInt128Support.h \
|
tlInt128Support.h \
|
||||||
tlDefs.h \
|
tlDefs.h \
|
||||||
tlXMLParser.h \
|
tlXMLParser.h \
|
||||||
|
tlXMLReader.h \
|
||||||
tlXMLWriter.h \
|
tlXMLWriter.h \
|
||||||
tlThreadedWorkers.h \
|
tlThreadedWorkers.h \
|
||||||
tlThreads.h \
|
tlThreads.h \
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,913 @@
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
KLayout Layout Viewer
|
||||||
|
Copyright (C) 2006-2024 Matthias Koefferlein
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "tlXMLReader.h"
|
||||||
|
#include "tlXMLParser.h"
|
||||||
|
#include "tlString.h"
|
||||||
|
#include "tlLog.h"
|
||||||
|
#include "tlAssert.h"
|
||||||
|
#include "tlProgress.h"
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#if defined(HAVE_EXPAT)
|
||||||
|
|
||||||
|
#include <expat.h>
|
||||||
|
|
||||||
|
namespace tl
|
||||||
|
{
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------
|
||||||
|
// SourcePrivateData implementation
|
||||||
|
|
||||||
|
class XMLSourcePrivateData
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
XMLSourcePrivateData (tl::InputStream *stream)
|
||||||
|
: mp_stream_holder (stream),
|
||||||
|
m_has_error (false)
|
||||||
|
{
|
||||||
|
mp_stream = stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
XMLSourcePrivateData (tl::InputStream *stream, const std::string &progress_message)
|
||||||
|
: mp_stream_holder (stream),
|
||||||
|
mp_progress (new AbsoluteProgress (progress_message, 100)),
|
||||||
|
m_has_error (false)
|
||||||
|
{
|
||||||
|
mp_stream = stream;
|
||||||
|
mp_progress->set_format (tl::to_string (tr ("%.0f MB")));
|
||||||
|
mp_progress->set_unit (1024 * 1024);
|
||||||
|
}
|
||||||
|
|
||||||
|
XMLSourcePrivateData (tl::InputStream &stream)
|
||||||
|
: m_has_error (false)
|
||||||
|
{
|
||||||
|
mp_stream = &stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
XMLSourcePrivateData (tl::InputStream &stream, const std::string &progress_message)
|
||||||
|
: mp_progress (new AbsoluteProgress (progress_message, 100)),
|
||||||
|
m_has_error (false)
|
||||||
|
{
|
||||||
|
mp_stream = &stream;
|
||||||
|
mp_progress->set_format (tl::to_string (tr ("%.0f MB")));
|
||||||
|
mp_progress->set_unit (1024 * 1024);
|
||||||
|
}
|
||||||
|
|
||||||
|
int read (char *data, size_t n)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
|
||||||
|
if (mp_progress.get ()) {
|
||||||
|
mp_progress->set (mp_stream->pos ());
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t n0 = n;
|
||||||
|
for (const char *rd = 0; n > 0 && (rd = mp_stream->get (1)) != 0; --n) {
|
||||||
|
*data++ = *rd;
|
||||||
|
}
|
||||||
|
|
||||||
|
return int (n0 - n);
|
||||||
|
|
||||||
|
} catch (tl::Exception &ex) {
|
||||||
|
m_error = ex.msg ();
|
||||||
|
m_has_error = true;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool has_error () const
|
||||||
|
{
|
||||||
|
return m_has_error;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string &error_msg () const
|
||||||
|
{
|
||||||
|
return m_error;
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset ()
|
||||||
|
{
|
||||||
|
mp_stream->reset ();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unique_ptr<tl::InputStream> mp_stream_holder;
|
||||||
|
tl::InputStream *mp_stream;
|
||||||
|
std::unique_ptr<tl::AbsoluteProgress> mp_progress;
|
||||||
|
bool m_has_error;
|
||||||
|
std::string m_error;
|
||||||
|
};
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------
|
||||||
|
// XMLSource implementation
|
||||||
|
|
||||||
|
XMLSource::XMLSource ()
|
||||||
|
: mp_source (0)
|
||||||
|
{
|
||||||
|
// .. nothing yet ..
|
||||||
|
}
|
||||||
|
|
||||||
|
XMLSource::~XMLSource ()
|
||||||
|
{
|
||||||
|
delete mp_source;
|
||||||
|
mp_source = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
XMLSource::reset ()
|
||||||
|
{
|
||||||
|
mp_source->reset ();
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------
|
||||||
|
// XMLStringSource implementation
|
||||||
|
|
||||||
|
XMLStringSource::XMLStringSource (const std::string &string)
|
||||||
|
: m_copy (string)
|
||||||
|
{
|
||||||
|
set_source (new XMLSourcePrivateData (new tl::InputStream (new tl::InputMemoryStream (m_copy.c_str (), string.size ()))));
|
||||||
|
}
|
||||||
|
|
||||||
|
XMLStringSource::XMLStringSource (const char *cp)
|
||||||
|
{
|
||||||
|
set_source (new XMLSourcePrivateData (new tl::InputStream (new tl::InputMemoryStream (cp, strlen (cp)))));
|
||||||
|
}
|
||||||
|
|
||||||
|
XMLStringSource::XMLStringSource (const char *cp, size_t len)
|
||||||
|
{
|
||||||
|
set_source (new XMLSourcePrivateData (new tl::InputStream (new tl::InputMemoryStream (cp, len))));
|
||||||
|
}
|
||||||
|
|
||||||
|
XMLStringSource::~XMLStringSource ()
|
||||||
|
{
|
||||||
|
// .. nothing yet ..
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------
|
||||||
|
// XMLFileSource implementation
|
||||||
|
|
||||||
|
XMLFileSource::XMLFileSource (const std::string &path, const std::string &progress_message)
|
||||||
|
{
|
||||||
|
set_source (new XMLSourcePrivateData (new tl::InputStream (path), progress_message));
|
||||||
|
}
|
||||||
|
|
||||||
|
XMLFileSource::XMLFileSource (const std::string &path)
|
||||||
|
{
|
||||||
|
set_source (new XMLSourcePrivateData (new tl::InputStream (path)));
|
||||||
|
}
|
||||||
|
|
||||||
|
XMLFileSource::~XMLFileSource ()
|
||||||
|
{
|
||||||
|
// .. nothing yet ..
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------
|
||||||
|
// XMLStreamSource implementation
|
||||||
|
|
||||||
|
XMLStreamSource::XMLStreamSource (tl::InputStream &s, const std::string &progress_message)
|
||||||
|
{
|
||||||
|
set_source (new XMLSourcePrivateData (s, progress_message));
|
||||||
|
}
|
||||||
|
|
||||||
|
XMLStreamSource::XMLStreamSource (tl::InputStream &s)
|
||||||
|
{
|
||||||
|
set_source (new XMLSourcePrivateData (s));
|
||||||
|
}
|
||||||
|
|
||||||
|
XMLStreamSource::~XMLStreamSource ()
|
||||||
|
{
|
||||||
|
// .. nothing yet ..
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------
|
||||||
|
// XMLParser implementation
|
||||||
|
|
||||||
|
void XMLCALL start_element_handler (void *user_data, const XML_Char *name, const XML_Char **atts);
|
||||||
|
void XMLCALL end_element_handler (void *user_data, const XML_Char *name);
|
||||||
|
void XMLCALL cdata_handler (void *user_data, const XML_Char *s, int len);
|
||||||
|
|
||||||
|
static std::string get_lname (const std::string &name)
|
||||||
|
{
|
||||||
|
size_t colon = name.find (':');
|
||||||
|
if (colon != std::string::npos) {
|
||||||
|
return std::string (name, colon + 1, name.size () - colon - 1);
|
||||||
|
} else {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class XMLParserPrivateData
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
XMLParserPrivateData ()
|
||||||
|
: mp_struct_handler (0)
|
||||||
|
{
|
||||||
|
mp_parser = XML_ParserCreate ("UTF-8");
|
||||||
|
tl_assert (mp_parser != NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
~XMLParserPrivateData ()
|
||||||
|
{
|
||||||
|
if (mp_parser != NULL) {
|
||||||
|
XML_ParserFree (mp_parser);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void start_element (const std::string &name)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
// TODO: Provide namespace URI?
|
||||||
|
mp_struct_handler->start_element (std::string (), get_lname (name), name);
|
||||||
|
} catch (tl::Exception &ex) {
|
||||||
|
error (ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void end_element (const std::string &name)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
// TODO: Provide namespace URI?
|
||||||
|
mp_struct_handler->end_element (std::string (), get_lname (name), name);
|
||||||
|
} catch (tl::Exception &ex) {
|
||||||
|
error (ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cdata (const std::string &cdata)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
mp_struct_handler->characters (cdata);
|
||||||
|
} catch (tl::Exception &ex) {
|
||||||
|
error (ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void parse (tl::XMLSource &source, XMLStructureHandler &struct_handler)
|
||||||
|
{
|
||||||
|
m_has_error = false;
|
||||||
|
mp_struct_handler = &struct_handler;
|
||||||
|
|
||||||
|
// Just in case we want to reuse it ...
|
||||||
|
XML_ParserReset (mp_parser, NULL);
|
||||||
|
XML_SetUserData (mp_parser, (void *) this);
|
||||||
|
XML_SetElementHandler (mp_parser, start_element_handler, end_element_handler);
|
||||||
|
XML_SetCharacterDataHandler (mp_parser, cdata_handler);
|
||||||
|
|
||||||
|
const int chunk = 65536;
|
||||||
|
char buffer [chunk];
|
||||||
|
|
||||||
|
int n;
|
||||||
|
|
||||||
|
do {
|
||||||
|
|
||||||
|
n = source.source ()->read (buffer, chunk);
|
||||||
|
if (n < 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
XML_Status status = XML_Parse (mp_parser, buffer, n, n < chunk /*is final*/);
|
||||||
|
if (status == XML_STATUS_ERROR) {
|
||||||
|
m_has_error = true;
|
||||||
|
m_error = XML_ErrorString (XML_GetErrorCode (mp_parser));
|
||||||
|
m_error_line = XML_GetErrorLineNumber (mp_parser);
|
||||||
|
m_error_column = XML_GetErrorColumnNumber (mp_parser);
|
||||||
|
}
|
||||||
|
|
||||||
|
} while (n == chunk && !m_has_error);
|
||||||
|
}
|
||||||
|
|
||||||
|
void check_error ()
|
||||||
|
{
|
||||||
|
if (m_has_error) {
|
||||||
|
throw tl::XMLLocatedException (m_error, m_error_line, m_error_column);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void error (tl::Exception &ex)
|
||||||
|
{
|
||||||
|
m_has_error = true;
|
||||||
|
m_error_line = XML_GetCurrentLineNumber (mp_parser);
|
||||||
|
m_error_column = XML_GetCurrentColumnNumber (mp_parser);
|
||||||
|
m_error = ex.msg ();
|
||||||
|
}
|
||||||
|
|
||||||
|
XML_Parser mp_parser;
|
||||||
|
XMLStructureHandler *mp_struct_handler;
|
||||||
|
bool m_has_error;
|
||||||
|
std::string m_error;
|
||||||
|
int m_error_line, m_error_column;
|
||||||
|
};
|
||||||
|
|
||||||
|
void start_element_handler (void *user_data, const XML_Char *name, const XML_Char ** /*atts*/)
|
||||||
|
{
|
||||||
|
XMLParserPrivateData *d = reinterpret_cast<XMLParserPrivateData *> (user_data);
|
||||||
|
d->start_element (std::string (name));
|
||||||
|
}
|
||||||
|
|
||||||
|
void end_element_handler (void *user_data, const XML_Char *name)
|
||||||
|
{
|
||||||
|
XMLParserPrivateData *d = reinterpret_cast<XMLParserPrivateData *> (user_data);
|
||||||
|
d->end_element (std::string (name));
|
||||||
|
}
|
||||||
|
|
||||||
|
void cdata_handler (void *user_data, const XML_Char *s, int len)
|
||||||
|
{
|
||||||
|
XMLParserPrivateData *d = reinterpret_cast<XMLParserPrivateData *> (user_data);
|
||||||
|
d->cdata (std::string (s, size_t (len)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
XMLParser::XMLParser ()
|
||||||
|
: mp_data (new XMLParserPrivateData ())
|
||||||
|
{
|
||||||
|
// .. nothing yet ..
|
||||||
|
}
|
||||||
|
|
||||||
|
XMLParser::~XMLParser ()
|
||||||
|
{
|
||||||
|
delete mp_data;
|
||||||
|
mp_data = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
XMLParser::parse (XMLSource &source, XMLStructureHandler &struct_handler)
|
||||||
|
{
|
||||||
|
mp_data->parse (source, struct_handler);
|
||||||
|
|
||||||
|
// throws an exception if there is an error
|
||||||
|
mp_data->check_error ();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
XMLParser::is_available ()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif defined(HAVE_QT)
|
||||||
|
|
||||||
|
#include <QFile>
|
||||||
|
#include <QIODevice>
|
||||||
|
#include <QXmlContentHandler>
|
||||||
|
|
||||||
|
namespace tl
|
||||||
|
{
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------
|
||||||
|
// A SAX handler for the Qt implementation
|
||||||
|
|
||||||
|
class SAXHandler
|
||||||
|
: public QXmlDefaultHandler
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SAXHandler (XMLStructureHandler *sh);
|
||||||
|
|
||||||
|
virtual bool characters (const QString &ch);
|
||||||
|
virtual bool endElement (const QString &namespaceURI, const QString &localName, const QString &qName);
|
||||||
|
virtual bool startElement (const QString &namespaceURI, const QString &localName, const QString &qName, const QXmlAttributes &atts);
|
||||||
|
virtual bool error (const QXmlParseException &exception);
|
||||||
|
virtual bool fatalError (const QXmlParseException &exception);
|
||||||
|
virtual bool warning (const QXmlParseException &exception);
|
||||||
|
virtual QString errorString () const;
|
||||||
|
|
||||||
|
void setDocumentLocator (QXmlLocator *locator);
|
||||||
|
|
||||||
|
const tl::XMLLocatedException *exception () const
|
||||||
|
{
|
||||||
|
return m_error.get ();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
QXmlLocator *mp_locator;
|
||||||
|
XMLStructureHandler *mp_struct_handler;
|
||||||
|
std::unique_ptr<tl::XMLLocatedException> m_error;
|
||||||
|
std::string m_error_string;
|
||||||
|
};
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------------------------------------------
|
||||||
|
// trureHandler implementation
|
||||||
|
|
||||||
|
SAXHandler::SAXHandler (XMLStructureHandler *sh)
|
||||||
|
: QXmlDefaultHandler (), mp_locator (0), mp_struct_handler (sh)
|
||||||
|
{
|
||||||
|
// .. nothing yet ..
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SAXHandler::setDocumentLocator (QXmlLocator *locator)
|
||||||
|
{
|
||||||
|
mp_locator = locator;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
SAXHandler::startElement (const QString &qs_uri, const QString &qs_lname, const QString &qs_qname, const QXmlAttributes & /*atts*/)
|
||||||
|
{
|
||||||
|
std::string uri (tl::to_string (qs_uri));
|
||||||
|
std::string lname (tl::to_string (qs_lname));
|
||||||
|
std::string qname (tl::to_string (qs_qname));
|
||||||
|
|
||||||
|
try {
|
||||||
|
mp_struct_handler->start_element (uri, lname, qname);
|
||||||
|
} catch (tl::XMLException &ex) {
|
||||||
|
m_error_string = ex.raw_msg ();
|
||||||
|
return false;
|
||||||
|
} catch (tl::Exception &ex) {
|
||||||
|
m_error_string = ex.msg ();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// successful
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
SAXHandler::endElement (const QString &qs_uri, const QString &qs_lname, const QString &qs_qname)
|
||||||
|
{
|
||||||
|
std::string uri (tl::to_string (qs_uri));
|
||||||
|
std::string lname (tl::to_string (qs_lname));
|
||||||
|
std::string qname (tl::to_string (qs_qname));
|
||||||
|
|
||||||
|
try {
|
||||||
|
mp_struct_handler->end_element (uri, lname, qname);
|
||||||
|
} catch (tl::XMLException &ex) {
|
||||||
|
m_error_string = ex.raw_msg ();
|
||||||
|
return false;
|
||||||
|
} catch (tl::Exception &ex) {
|
||||||
|
m_error_string = ex.msg ();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// successful
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
SAXHandler::characters (const QString &t)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
mp_struct_handler->characters (tl::to_string (t));
|
||||||
|
} catch (tl::XMLException &ex) {
|
||||||
|
m_error_string = ex.raw_msg ();
|
||||||
|
return false;
|
||||||
|
} catch (tl::Exception &ex) {
|
||||||
|
m_error_string = ex.msg ();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// successful
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString
|
||||||
|
SAXHandler::errorString () const
|
||||||
|
{
|
||||||
|
return tl::to_qstring (m_error_string);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
SAXHandler::error (const QXmlParseException &ex)
|
||||||
|
{
|
||||||
|
m_error.reset (new tl::XMLLocatedException (tl::to_string (ex.message ()), ex.lineNumber (), ex.columnNumber ()));
|
||||||
|
// stop reading
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
SAXHandler::fatalError (const QXmlParseException &ex)
|
||||||
|
{
|
||||||
|
m_error.reset (new tl::XMLLocatedException (tl::to_string (ex.message ()), ex.lineNumber (), ex.columnNumber ()));
|
||||||
|
// stop reading
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
SAXHandler::warning (const QXmlParseException &ex)
|
||||||
|
{
|
||||||
|
tl::XMLLocatedException lex (tl::to_string (ex.message ()), ex.lineNumber (), ex.columnNumber ());
|
||||||
|
tl::warn << lex.msg ();
|
||||||
|
// continue
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------
|
||||||
|
// SourcePrivateData implementation
|
||||||
|
|
||||||
|
class XMLSourcePrivateData
|
||||||
|
: public QXmlInputSource
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
XMLSourcePrivateData ()
|
||||||
|
: QXmlInputSource ()
|
||||||
|
{
|
||||||
|
// .. nothing yet ..
|
||||||
|
}
|
||||||
|
|
||||||
|
XMLSourcePrivateData (QIODevice *dev)
|
||||||
|
: QXmlInputSource (dev)
|
||||||
|
{
|
||||||
|
// .. nothing yet ..
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------
|
||||||
|
// XMLSource implementation
|
||||||
|
|
||||||
|
XMLSource::XMLSource ()
|
||||||
|
: mp_source (0)
|
||||||
|
{
|
||||||
|
// .. nothing yet ..
|
||||||
|
}
|
||||||
|
|
||||||
|
XMLSource::~XMLSource ()
|
||||||
|
{
|
||||||
|
delete mp_source;
|
||||||
|
mp_source = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
XMLSource::reset ()
|
||||||
|
{
|
||||||
|
mp_source->reset ();
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------
|
||||||
|
// XMLStringSource implementation
|
||||||
|
|
||||||
|
XMLStringSource::XMLStringSource (const std::string &string)
|
||||||
|
{
|
||||||
|
XMLSourcePrivateData *source = new XMLSourcePrivateData ();
|
||||||
|
source->setData (QByteArray (string.c_str ()));
|
||||||
|
set_source (source);
|
||||||
|
}
|
||||||
|
|
||||||
|
XMLStringSource::XMLStringSource (const char *cp)
|
||||||
|
{
|
||||||
|
XMLSourcePrivateData *source = new XMLSourcePrivateData ();
|
||||||
|
source->setData (QByteArray (cp));
|
||||||
|
set_source (source);
|
||||||
|
}
|
||||||
|
|
||||||
|
XMLStringSource::XMLStringSource (const char *cp, size_t len)
|
||||||
|
{
|
||||||
|
XMLSourcePrivateData *source = new XMLSourcePrivateData ();
|
||||||
|
source->setData (QByteArray (cp, int (len)));
|
||||||
|
set_source (source);
|
||||||
|
}
|
||||||
|
|
||||||
|
XMLStringSource::~XMLStringSource ()
|
||||||
|
{
|
||||||
|
// .. nothing yet ..
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------
|
||||||
|
// StreamIODevice definition and implementation
|
||||||
|
|
||||||
|
class StreamIODevice
|
||||||
|
: public QIODevice
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
StreamIODevice (tl::InputStream &stream)
|
||||||
|
: mp_stream (&stream),
|
||||||
|
mp_progress (0),
|
||||||
|
m_has_error (false)
|
||||||
|
{
|
||||||
|
open (QIODevice::ReadOnly);
|
||||||
|
}
|
||||||
|
|
||||||
|
StreamIODevice (tl::InputStream &stream, const std::string &progress_message)
|
||||||
|
: mp_stream (&stream),
|
||||||
|
mp_progress (new AbsoluteProgress (progress_message, 100)),
|
||||||
|
m_has_error (false)
|
||||||
|
{
|
||||||
|
mp_progress->set_format (tl::to_string (tr ("%.0f MB")));
|
||||||
|
mp_progress->set_unit (1024 * 1024);
|
||||||
|
open (QIODevice::ReadOnly);
|
||||||
|
}
|
||||||
|
|
||||||
|
StreamIODevice (const std::string &path)
|
||||||
|
: mp_stream_holder (new tl::InputStream (path)),
|
||||||
|
mp_progress (0),
|
||||||
|
m_has_error (false)
|
||||||
|
{
|
||||||
|
mp_stream = mp_stream_holder.get ();
|
||||||
|
open (QIODevice::ReadOnly);
|
||||||
|
}
|
||||||
|
|
||||||
|
StreamIODevice (const std::string &path, const std::string &progress_message)
|
||||||
|
: mp_stream_holder (new tl::InputStream (path)),
|
||||||
|
mp_progress (new AbsoluteProgress (progress_message, 100)),
|
||||||
|
m_has_error (false)
|
||||||
|
{
|
||||||
|
mp_stream = mp_stream_holder.get ();
|
||||||
|
mp_progress->set_format (tl::to_string (tr ("%.0f MB")));
|
||||||
|
mp_progress->set_unit (1024 * 1024);
|
||||||
|
open (QIODevice::ReadOnly);
|
||||||
|
}
|
||||||
|
|
||||||
|
~StreamIODevice ()
|
||||||
|
{
|
||||||
|
if (mp_progress) {
|
||||||
|
delete mp_progress;
|
||||||
|
mp_progress = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool isSequential () const
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
qint64 writeData (const char *, qint64)
|
||||||
|
{
|
||||||
|
tl_assert (false);
|
||||||
|
}
|
||||||
|
|
||||||
|
qint64 readData (char *data, qint64 n)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
|
||||||
|
if (mp_progress) {
|
||||||
|
mp_progress->set (mp_stream->pos ());
|
||||||
|
}
|
||||||
|
|
||||||
|
qint64 n0 = n;
|
||||||
|
for (const char *rd = 0; n > 0 && (rd = mp_stream->get (1)) != 0; ) {
|
||||||
|
// NOTE: we skip CR to compensate for Windows CRLF line terminators (issue #419).
|
||||||
|
if (*rd != '\r') {
|
||||||
|
*data++ = *rd;
|
||||||
|
--n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n0 == n) {
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
return n0 - n;
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (tl::Exception &ex) {
|
||||||
|
setErrorString (tl::to_qstring (ex.msg ()));
|
||||||
|
m_has_error = true;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool has_error () const
|
||||||
|
{
|
||||||
|
return m_has_error;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
tl::InputStream *mp_stream;
|
||||||
|
std::unique_ptr<tl::InputStream> mp_stream_holder;
|
||||||
|
tl::AbsoluteProgress *mp_progress;
|
||||||
|
bool m_has_error;
|
||||||
|
};
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------
|
||||||
|
// XMLFileSource implementation
|
||||||
|
|
||||||
|
class XMLStreamSourcePrivateData
|
||||||
|
: public XMLSourcePrivateData
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
XMLStreamSourcePrivateData (StreamIODevice *io)
|
||||||
|
: XMLSourcePrivateData (io), mp_io (io)
|
||||||
|
{
|
||||||
|
// .. nothing yet ..
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void fetchData ()
|
||||||
|
{
|
||||||
|
QXmlInputSource::fetchData ();
|
||||||
|
|
||||||
|
// This feature is actually missing in the original implementation: throw an exception on error
|
||||||
|
if (mp_io->has_error ()) {
|
||||||
|
throw tl::Exception (tl::to_string (mp_io->errorString ()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unique_ptr<StreamIODevice> mp_io;
|
||||||
|
};
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------
|
||||||
|
// XMLFileSource implementation
|
||||||
|
|
||||||
|
XMLFileSource::XMLFileSource (const std::string &path, const std::string &progress_message)
|
||||||
|
{
|
||||||
|
set_source (new XMLStreamSourcePrivateData (new StreamIODevice (path, progress_message)));
|
||||||
|
}
|
||||||
|
|
||||||
|
XMLFileSource::XMLFileSource (const std::string &path)
|
||||||
|
{
|
||||||
|
set_source (new XMLStreamSourcePrivateData (new StreamIODevice (path)));
|
||||||
|
}
|
||||||
|
|
||||||
|
XMLFileSource::~XMLFileSource ()
|
||||||
|
{
|
||||||
|
// .. nothing yet ..
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------
|
||||||
|
// XMLStreamSource implementation
|
||||||
|
|
||||||
|
XMLStreamSource::XMLStreamSource (tl::InputStream &s, const std::string &progress_message)
|
||||||
|
{
|
||||||
|
set_source (new XMLStreamSourcePrivateData (new StreamIODevice (s, progress_message)));
|
||||||
|
}
|
||||||
|
|
||||||
|
XMLStreamSource::XMLStreamSource (tl::InputStream &s)
|
||||||
|
{
|
||||||
|
set_source (new XMLStreamSourcePrivateData (new StreamIODevice (s)));
|
||||||
|
}
|
||||||
|
|
||||||
|
XMLStreamSource::~XMLStreamSource ()
|
||||||
|
{
|
||||||
|
// .. nothing yet ..
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------
|
||||||
|
// XMLParser implementation
|
||||||
|
|
||||||
|
class XMLParserPrivateData
|
||||||
|
: public QXmlSimpleReader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
XMLParserPrivateData () : QXmlSimpleReader () { }
|
||||||
|
};
|
||||||
|
|
||||||
|
XMLParser::XMLParser ()
|
||||||
|
: mp_data (new XMLParserPrivateData ())
|
||||||
|
{
|
||||||
|
// .. nothing yet ..
|
||||||
|
}
|
||||||
|
|
||||||
|
XMLParser::~XMLParser ()
|
||||||
|
{
|
||||||
|
delete mp_data;
|
||||||
|
mp_data = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
XMLParser::parse (XMLSource &source, XMLStructureHandler &struct_handler)
|
||||||
|
{
|
||||||
|
SAXHandler handler (&struct_handler);
|
||||||
|
|
||||||
|
mp_data->setContentHandler (&handler);
|
||||||
|
mp_data->setErrorHandler (&handler);
|
||||||
|
|
||||||
|
bool result = mp_data->parse (source.source (), false /*=not incremental*/);
|
||||||
|
if (! result && handler.exception ()) {
|
||||||
|
throw tl::XMLLocatedException (*handler.exception ());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
XMLParser::is_available ()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
namespace tl
|
||||||
|
{
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------
|
||||||
|
// XMLSource implementation
|
||||||
|
|
||||||
|
XMLSource::XMLSource ()
|
||||||
|
: mp_source (0)
|
||||||
|
{
|
||||||
|
// .. nothing yet ..
|
||||||
|
}
|
||||||
|
|
||||||
|
XMLSource::~XMLSource ()
|
||||||
|
{
|
||||||
|
// .. nothing yet ..
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
XMLSource::reset ()
|
||||||
|
{
|
||||||
|
// .. nothing yet ..
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------
|
||||||
|
// XMLStringSource implementation
|
||||||
|
|
||||||
|
XMLStringSource::XMLStringSource (const std::string &)
|
||||||
|
{
|
||||||
|
tl_assert (false);
|
||||||
|
}
|
||||||
|
|
||||||
|
XMLStringSource::XMLStringSource (const char *)
|
||||||
|
{
|
||||||
|
tl_assert (false);
|
||||||
|
}
|
||||||
|
|
||||||
|
XMLStringSource::XMLStringSource (const char *, size_t)
|
||||||
|
{
|
||||||
|
tl_assert (false);
|
||||||
|
}
|
||||||
|
|
||||||
|
XMLStringSource::~XMLStringSource ()
|
||||||
|
{
|
||||||
|
// .. nothing yet ..
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------
|
||||||
|
// XMLFileSource implementation
|
||||||
|
|
||||||
|
XMLFileSource::XMLFileSource (const std::string &, const std::string &)
|
||||||
|
{
|
||||||
|
tl_assert (false);
|
||||||
|
}
|
||||||
|
|
||||||
|
XMLFileSource::XMLFileSource (const std::string &)
|
||||||
|
{
|
||||||
|
tl_assert (false);
|
||||||
|
}
|
||||||
|
|
||||||
|
XMLFileSource::~XMLFileSource ()
|
||||||
|
{
|
||||||
|
// .. nothing yet ..
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------
|
||||||
|
// XMLStreamSource implementation
|
||||||
|
|
||||||
|
XMLStreamSource::XMLStreamSource (tl::InputStream &, const std::string &)
|
||||||
|
{
|
||||||
|
tl_assert (false);
|
||||||
|
}
|
||||||
|
|
||||||
|
XMLStreamSource::XMLStreamSource (tl::InputStream &)
|
||||||
|
{
|
||||||
|
tl_assert (false);
|
||||||
|
}
|
||||||
|
|
||||||
|
XMLStreamSource::~XMLStreamSource ()
|
||||||
|
{
|
||||||
|
// .. nothing yet ..
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------
|
||||||
|
// XMLParser implementation
|
||||||
|
|
||||||
|
XMLParser::XMLParser ()
|
||||||
|
: mp_data (0)
|
||||||
|
{
|
||||||
|
// .. nothing yet ..
|
||||||
|
}
|
||||||
|
|
||||||
|
XMLParser::~XMLParser ()
|
||||||
|
{
|
||||||
|
// .. nothing yet ..
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
XMLParser::parse (XMLSource &, XMLStructureHandler &)
|
||||||
|
{
|
||||||
|
tl_assert (false);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
XMLParser::is_available ()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,215 @@
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
KLayout Layout Viewer
|
||||||
|
Copyright (C) 2006-2024 Matthias Koefferlein
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef HDR_tlXMLReader
|
||||||
|
#define HDR_tlXMLReader
|
||||||
|
|
||||||
|
#include "tlCommon.h"
|
||||||
|
|
||||||
|
#include <list>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "tlAssert.h"
|
||||||
|
#include "tlInternational.h"
|
||||||
|
#include "tlString.h"
|
||||||
|
#include "tlStream.h"
|
||||||
|
|
||||||
|
class QIODevice;
|
||||||
|
|
||||||
|
namespace tl
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* NOTE: This XML parser package also supports a ProtocolBuffer flavor.
|
||||||
|
* This allows binding the same scheme to efficient binary PB format.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class ProtocolBufferReaderBase;
|
||||||
|
class ProtocolBufferWriterBase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A basic XML parser error exception class
|
||||||
|
*/
|
||||||
|
|
||||||
|
class TL_PUBLIC XMLException : public tl::Exception
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
XMLException (const char *msg)
|
||||||
|
: Exception (tl::to_string (tr ("XML parser error: %s")).c_str ()),
|
||||||
|
m_msg (msg)
|
||||||
|
{
|
||||||
|
// .. nothing yet ..
|
||||||
|
}
|
||||||
|
|
||||||
|
XMLException (const std::string &msg)
|
||||||
|
: Exception (fmt (-1, -1).c_str (), msg.c_str ()),
|
||||||
|
m_msg (msg)
|
||||||
|
{
|
||||||
|
// .. nothing yet ..
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Raw (unprefixed) message of the XML parser
|
||||||
|
*/
|
||||||
|
const std::string &
|
||||||
|
raw_msg () const
|
||||||
|
{
|
||||||
|
return m_msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
XMLException (const std::string &msg, int line, int column)
|
||||||
|
: Exception (fmt (line, column).c_str (), msg.c_str (), line, column),
|
||||||
|
m_msg (msg)
|
||||||
|
{
|
||||||
|
// .. nothing yet ..
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string m_msg;
|
||||||
|
|
||||||
|
static std::string fmt (int line, int /*column*/)
|
||||||
|
{
|
||||||
|
if (line < 0) {
|
||||||
|
return tl::to_string (tr ("XML parser error: %s")).c_str ();
|
||||||
|
} else {
|
||||||
|
return tl::to_string (tr ("XML parser error: %s in line %d, column %d")).c_str ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A XML parser error exception class that additionally provides line and column information
|
||||||
|
*/
|
||||||
|
|
||||||
|
class TL_PUBLIC XMLLocatedException : public XMLException
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
XMLLocatedException (const std::string &msg, int line, int column)
|
||||||
|
: XMLException (msg, line, column),
|
||||||
|
m_line (line), m_column (column)
|
||||||
|
{
|
||||||
|
// .. nothing yet ..
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Line number information of the exception
|
||||||
|
*/
|
||||||
|
int line () const
|
||||||
|
{
|
||||||
|
return m_line;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Column number information of the exception
|
||||||
|
*/
|
||||||
|
int column () const
|
||||||
|
{
|
||||||
|
return m_column;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
int m_line;
|
||||||
|
int m_column;
|
||||||
|
};
|
||||||
|
|
||||||
|
// The opaque source type
|
||||||
|
class XMLSourcePrivateData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A generic XML text source class
|
||||||
|
*
|
||||||
|
* This class is the base class providing input for
|
||||||
|
* the Qt XML parser and basically maps to a QXmlInputSource object
|
||||||
|
* for compatibility with the "libparsifal" branch.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class TL_PUBLIC XMLSource
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
XMLSource ();
|
||||||
|
~XMLSource ();
|
||||||
|
|
||||||
|
XMLSourcePrivateData *source ()
|
||||||
|
{
|
||||||
|
return mp_source;
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset ();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void set_source (XMLSourcePrivateData *source)
|
||||||
|
{
|
||||||
|
mp_source = source;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
XMLSourcePrivateData *mp_source;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A specialization of XMLSource to receive a string
|
||||||
|
*/
|
||||||
|
|
||||||
|
class TL_PUBLIC XMLStringSource : public XMLSource
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
XMLStringSource (const std::string &string);
|
||||||
|
XMLStringSource (const char *cp);
|
||||||
|
XMLStringSource (const char *cp, size_t len);
|
||||||
|
~XMLStringSource ();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string m_copy;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A specialization of XMLSource to receive from a file
|
||||||
|
*/
|
||||||
|
|
||||||
|
class TL_PUBLIC XMLFileSource : public XMLSource
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
XMLFileSource (const std::string &path);
|
||||||
|
XMLFileSource (const std::string &path, const std::string &progress_message);
|
||||||
|
~XMLFileSource ();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A generic stream source class
|
||||||
|
*
|
||||||
|
* This class implements a XML parser source from a tl::InputStream
|
||||||
|
*/
|
||||||
|
|
||||||
|
class TL_PUBLIC XMLStreamSource : public XMLSource
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
XMLStreamSource (tl::InputStream &stream);
|
||||||
|
XMLStreamSource (tl::InputStream &stream, const std::string &progress_message);
|
||||||
|
~XMLStreamSource ();
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace tl
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
@ -20,16 +20,14 @@
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "tlProtocolBufferStruct.h"
|
#include "tlXMLParser.h"
|
||||||
|
#include "tlProtocolBuffer.h"
|
||||||
#include "tlUnitTest.h"
|
#include "tlUnitTest.h"
|
||||||
#include "tlFileUtils.h"
|
#include "tlFileUtils.h"
|
||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
// @@@
|
|
||||||
// Missing: all kind of variants (uint8_t, ...), float
|
|
||||||
|
|
||||||
// Basic tests of reader and writer
|
// Basic tests of reader and writer
|
||||||
TEST (1_BasicTypes)
|
TEST (1_BasicTypes)
|
||||||
{
|
{
|
||||||
|
|
@ -205,20 +203,20 @@ struct Root {
|
||||||
const Child &get_child () const { return m_child; }
|
const Child &get_child () const { return m_child; }
|
||||||
};
|
};
|
||||||
|
|
||||||
static tl::PBElementList child_struct ("Child",
|
static tl::XMLElementList child_struct ("Child",
|
||||||
tl::pb_make_member (&Child::txt, "txt", 1) +
|
tl::make_member (&Child::txt, "txt#1") +
|
||||||
tl::pb_make_member (&Child::d, "d", 2) +
|
tl::make_member (&Child::d, "d#2") +
|
||||||
tl::pb_make_element (&Child::begin_children, &Child::end_children, &Child::add_child, "children", 3, &child_struct)
|
tl::make_element (&Child::begin_children, &Child::end_children, &Child::add_child, "children#3", &child_struct)
|
||||||
);
|
);
|
||||||
|
|
||||||
static tl::PBStruct<Root> structure ("pbtest-struct", 88888888,
|
static tl::XMLStruct<Root> structure ("pbtest-struct#88888888",
|
||||||
tl::pb_make_member (&Root::begin_subs, &Root::end_subs, &Root::add_sub, "sub", 1) +
|
tl::make_member (&Root::begin_subs, &Root::end_subs, &Root::add_sub, "sub#1") +
|
||||||
tl::pb_make_member (&Root::begin_isubs, &Root::end_isubs, &Root::add_isub, "isub", 2) +
|
tl::make_member (&Root::begin_isubs, &Root::end_isubs, &Root::add_isub, "isub#2") +
|
||||||
tl::pb_make_element (&Root::begin_children, &Root::end_children, &Root::add_child, "children", 3, &child_struct) +
|
tl::make_element (&Root::begin_children, &Root::end_children, &Root::add_child, "children#3", &child_struct) +
|
||||||
tl::pb_make_element (&Root::get_child, &Root::set_child, "child", 4, &child_struct) +
|
tl::make_element (&Root::get_child, &Root::set_child, "child#4", &child_struct) +
|
||||||
tl::pb_make_member (&Root::m, "m", 5) +
|
tl::make_member (&Root::m, "m#5") +
|
||||||
tl::pb_make_member (&Root::get_mi, &Root::set_mi, "mi", 6) +
|
tl::make_member (&Root::get_mi, &Root::set_mi, "mi#6") +
|
||||||
tl::pb_make_member (&Root::b, "b", 7)
|
tl::make_member (&Root::b, "b#7")
|
||||||
);
|
);
|
||||||
|
|
||||||
static void build_struct (Root &root)
|
static void build_struct (Root &root)
|
||||||
|
|
@ -405,10 +403,13 @@ struct TestClassEnumConverter
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void from_string (const std::string &, TestClass::enum_type) const { }
|
||||||
|
std::string to_string (TestClass::enum_type) const { return std::string (); }
|
||||||
};
|
};
|
||||||
|
|
||||||
tl::PBStruct<TestClass> tc_structure ("pbtest-tc", 1,
|
tl::XMLStruct<TestClass> tc_structure ("pbtest-tc#1",
|
||||||
tl::pb_make_member (&TestClass::e, "e", 2, TestClassEnumConverter ())
|
tl::make_member (&TestClass::e, "e#2", TestClassEnumConverter ())
|
||||||
);
|
);
|
||||||
|
|
||||||
TEST (101_Converter)
|
TEST (101_Converter)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue