Compare commits

..

No commits in common. "master" and "1.1.0" have entirely different histories.

18 changed files with 59 additions and 149 deletions

8
README
View File

@ -1,4 +1,4 @@
libStreamedXML http://www.lwithers.me.uk/projects/libStreamedXML/ libStreamedXML
======================================================================== ========================================================================
(c)2006, Laurence Withers, <l@lwithers.me.uk>. (c)2006, Laurence Withers, <l@lwithers.me.uk>.
Released under the GNU GPLv2. See file COPYING or Released under the GNU GPLv2. See file COPYING or
@ -11,8 +11,4 @@ To build: ./make.sh
To install: ./make.sh install To install: ./make.sh install
(you might want to set PREFIX, by default it's /usr/local) (you might want to set PREFIX, by default it's /usr/local)
Dependencies @TODO@
------------
libutf8++
http://www.lwithers.me.uk/projects/libutf8++/

View File

@ -64,7 +64,6 @@ OUTPUT_DIRS="obj html"
# none no special processing happens before each file # none no special processing happens before each file
# C #line directives are inserted before each file # C #line directives are inserted before each file
# and VERSION, VERMAJOR etc. are #defined # and VERSION, VERMAJOR etc. are #defined
# Ch Like C, but for header files (no VERSION #defines)
# #
make_monolithic() { make_monolithic() {
if [ $# -ne 2 ] if [ $# -ne 2 ]
@ -83,9 +82,6 @@ make_monolithic() {
then then
HASHLINE=1 HASHLINE=1
VERDEFINE=1 VERDEFINE=1
elif [ "$2" == "Ch" ]
then
HASHLINE=1
elif [ "$2" == "none" ] elif [ "$2" == "none" ]
then then
HASHLINE=0 # dummy command HASHLINE=0 # dummy command
@ -265,7 +261,7 @@ else
targets="$@" targets="$@"
fi fi
for func in ${targets} for func in "${targets}"
do do
case ${func} in case ${func} in
clean) clean)

1
scripts/.gitignore vendored
View File

@ -1,6 +1,5 @@
build.c++.app build.c++.app
build.c++.lib build.c++.lib
build.c++.qtapp
build.c++.tests build.c++.tests
build.c.app build.c.app
build.c.lib build.c.lib

View File

@ -5,7 +5,3 @@
*/ */
#endif #endif
/* options for text editors
kate: replace-trailing-space-save true; space-indent true; tab-width 4;
vim: expandtab:ts=4:sw=4
*/

View File

@ -177,9 +177,8 @@ public:
/*! \brief Entity reference. /*! \brief Entity reference.
\param name The name of the entity being referred to. \param name The name of the entity being referred to.
\param[out] value The expanded text. \returns The expanded text.
\retval true if the entity is valid. \throws UnknownEntity if the entity is unknown.
\retval false if the entity is not valid.
This function is called whenever an entity reference is encountered, This function is called whenever an entity reference is encountered,
and \a expandEntities is \a true in your parser. The five standard and \a expandEntities is \a true in your parser. The five standard
@ -187,18 +186,12 @@ public:
but anything else will be passed to this function. but anything else will be passed to this function.
*/ */
virtual bool entityRef(const std::wstring& name, std::wstring& value) virtual std::wstring entityRef(const std::wstring& name)
{ {
(void)name; throw UnknownEntity(name);
(void)value;
return false;
} }
}; };
}; };
/* options for text editors
kate: replace-trailing-space-save true; space-indent true; tab-width 4;
vim: expandtab:ts=4:sw=4
*/

View File

@ -62,7 +62,3 @@ void Decoder::restart()
} }
/* options for text editors
kate: replace-trailing-space-save true; space-indent true; tab-width 4;
vim: expandtab:ts=4:sw=4
*/

View File

@ -70,7 +70,3 @@ private:
} }
/* options for text editors
kate: replace-trailing-space-save true; space-indent true; tab-width 4;
vim: expandtab:ts=4:sw=4
*/

View File

@ -8,14 +8,14 @@ namespace lsx {
Exception::Exception(const std::wstring& reason, int line, int col) Exception::Exception(const std::wstring& reason)
: reason(reason), line(line), col(col) : reason(reason)
{ {
} }
const char* Exception::what() const throw() const char* Exception::what()
{ {
if(utf8Reason.empty()) utf8Reason = utf8::encode(reason, true); if(utf8Reason.empty()) utf8Reason = utf8::encode(reason, true);
return utf8Reason.c_str(); return utf8Reason.c_str();
@ -23,46 +23,39 @@ const char* Exception::what() const throw()
NotWellFormed::NotWellFormed(const std::wstring& error, int line, int col) NotWellFormed::NotWellFormed(const std::wstring& error)
: Exception(format(error, line, col), line, col), error(error) : Exception(format(error)), error(error)
{ {
} }
std::wstring NotWellFormed::format(const std::wstring& error, int line, int col) std::wstring NotWellFormed::format(const std::wstring& error)
{ {
std::wostringstream ost; std::wostringstream ost;
ost << L"Streamed XML is not well formed:" ost << L"Streamed XML is not well formed:\n"
<< L"\n line : " << line + 1 << error;
<< L"\n column: " << col + 1
<< L"\n reason: " << error;
return ost.str(); return ost.str();
} }
UnknownEntity::UnknownEntity(const std::wstring& name, int line, int col) UnknownEntity::UnknownEntity(const std::wstring& name)
: Exception(format(name, line, col), line, col), name(name) : Exception(format(name)), name(name)
{ {
} }
std::wstring UnknownEntity::format(const std::wstring& name, int line, int col) std::wstring UnknownEntity::format(const std::wstring& name)
{ {
std::wostringstream ost; std::wostringstream ost;
ost << L"Encountered an unknown entity in the Streamed XML:" ost << L"Encountered an unknown entity named '"
<< L"\n line : " << line + 1 << name
<< L"\n column: " << col + 1 << L"' in the Streamed XML.";
<< L"\n name : " << name;
return ost.str(); return ost.str();
} }
} }
/* options for text editors
kate: replace-trailing-space-save true; space-indent true; tab-width 4;
vim: expandtab:ts=4:sw=4
*/

View File

@ -14,38 +14,30 @@ This class is the base class of all exceptions. It simply provides a mechanism f
message; more specific details must be stored in base classes. message; more specific details must be stored in base classes.
*/ */
class Exception : public std::exception { class Exception {
public: public:
/*! \brief Constructor. /*! \brief Constructor.
\param reason Reason for the exception. \param reason Reason for the exception.
\param line Line number of input (starting from 0).
\param col Column of input (starting from 0).
The constructor simply stores the reason for the exception, which may be later accessed for The constructor simply stores the reason for the exception, which may be later accessed for
reporting to the user. reporting to the user.
*/ */
Exception(const std::wstring& reason, int line, int col); Exception(const std::wstring& reason);
/// Destructor. /// Destructor.
virtual ~Exception() throw() virtual ~Exception() throw()
{ } { }
/// Find what caused the error. /// Find what caused the error.
virtual const char* what() const throw(); virtual const char* what();
/// Reason for the exception. /// Reason for the exception.
const std::wstring reason; const std::wstring reason;
/// Line on which the exception occurred (starting from 0).
const int line;
/// Column on which the exception occurred (starting from 0).
const int col;
private: private:
mutable std::string utf8Reason; std::string utf8Reason;
}; };
@ -53,20 +45,18 @@ private:
/// Thrown when XML is not well formed. /// Thrown when XML is not well formed.
class NotWellFormed : public Exception { class NotWellFormed : public Exception {
private: private:
static std::wstring format(const std::wstring& error, int line, int col); static std::wstring format(const std::wstring& error);
public: public:
/*! \brief Constructor. /*! \brief Constructor.
\param error Reason for the error. \param error Reason for the error.
\param line Line on which the exception occurred.
\param col Column on which the exception occurred.
The constructor will store the reason for the error. It will also prepare a suitable message The constructor will store the reason for the error. It will also prepare a suitable message
for the Exception base class. for the Exception base class.
*/ */
NotWellFormed(const std::wstring& error, int line, int col); NotWellFormed(const std::wstring& error);
/// Destructor. /// Destructor.
virtual ~NotWellFormed() throw() virtual ~NotWellFormed() throw()
@ -81,20 +71,18 @@ public:
/// Thrown when an unknown entity is referred to. /// Thrown when an unknown entity is referred to.
class UnknownEntity : public Exception { class UnknownEntity : public Exception {
private: private:
static std::wstring format(const std::wstring& name, int line, int col); static std::wstring format(const std::wstring& name);
public: public:
/*! \brief Constructor. /*! \brief Constructor.
\param name Name of the unknown entity. \param name Name of the unknown entity.
\param line Line on which the exception occurred.
\param col Column on which the exception occurred.
The constructor will store the name of the unknown entity. It will also prepare a suitable The constructor will store the name of the unknown entity. It will also prepare a suitable
message for the Exception base class. message for the Exception base class.
*/ */
UnknownEntity(const std::wstring& name, int line, int col); UnknownEntity(const std::wstring& name);
/// Destructor. /// Destructor.
virtual ~UnknownEntity() throw() virtual ~UnknownEntity() throw()
@ -107,7 +95,3 @@ public:
} }
/* options for text editors
kate: replace-trailing-space-save true; space-indent true; tab-width 4;
vim: expandtab:ts=4:sw=4
*/

View File

@ -22,7 +22,3 @@ class UnknownEntity;
} }
/* options for text editors
kate: replace-trailing-space-save true; space-indent true; tab-width 4;
vim: expandtab:ts=4:sw=4
*/

View File

@ -37,8 +37,6 @@ void Parser::reset()
skipNextNewline = false; skipNextNewline = false;
state = StateNone; state = StateNone;
restartCount = 0; restartCount = 0;
line = 0;
col = 0;
} }
@ -61,7 +59,7 @@ void Parser::feedChar(wchar_t ch)
#define ERROR(_reason) do { \ #define ERROR(_reason) do { \
state = StateError; \ state = StateError; \
throw NotWellFormed(_reason, line, col); \ throw NotWellFormed(_reason); \
}while(0) }while(0)
if(ch == xmlRestartMarker[restartCount]) { if(ch == xmlRestartMarker[restartCount]) {
if(++restartCount == 11) { if(++restartCount == 11) {
@ -86,15 +84,11 @@ void Parser::feedChar(wchar_t ch)
skipNextNewline = true; skipNextNewline = true;
ch = L'\n'; ch = L'\n';
c = ClassWhitespace; c = ClassWhitespace;
++line;
col = 0;
goto doBuffer; goto doBuffer;
case 0x2028: case 0x2028:
ch = L'\n'; ch = L'\n';
c = ClassWhitespace; c = ClassWhitespace;
++line;
col = 0;
break; break;
case L' ': case L' ':
@ -107,8 +101,6 @@ void Parser::feedChar(wchar_t ch)
if(skipNextNewline) return; if(skipNextNewline) return;
ch = L'\n'; ch = L'\n';
c = ClassWhitespace; c = ClassWhitespace;
++line;
col = 0;
break; break;
case L':': case L':':
@ -163,26 +155,26 @@ doBuffer:
break; break;
case ClassOpenTag: case ClassOpenTag:
state = StateOpen;
if(!buffer.empty()) callback->whiteSpace(buffer); if(!buffer.empty()) callback->whiteSpace(buffer);
state = StateOpen;
buffer.clear(); buffer.clear();
break; break;
case ClassEntity: case ClassEntity:
if(expandEntities) { if(expandEntities) {
if(!elementDepth) ERROR(L"Entities cannot appear at stream level."); if(!elementDepth) ERROR(L"Entities cannot appear at stream level.");
state = StateEntity;
if(!buffer.empty()) callback->whiteSpace(buffer); if(!buffer.empty()) callback->whiteSpace(buffer);
buffer.clear(); buffer.clear();
parsingAttr = false; parsingAttr = false;
state = StateEntity;
break; break;
} }
// fall through // fall through
default: default:
if(!elementDepth) ERROR(L"Content cannot appear at stream level."); if(!elementDepth) ERROR(L"Content cannot appear at stream level.");
state = StateData;
if(!buffer.empty()) callback->whiteSpace(buffer); if(!buffer.empty()) callback->whiteSpace(buffer);
state = StateData;
buffer = ch; buffer = ch;
break; break;
} }
@ -191,16 +183,16 @@ doBuffer:
case StateData: case StateData:
switch(c) { switch(c) {
case ClassOpenTag: case ClassOpenTag:
state = StateOpen;
callback->content(buffer); callback->content(buffer);
buffer.clear(); buffer.clear();
state = StateOpen;
break; break;
case ClassEntity: case ClassEntity:
state = StateEntity;
callback->content(buffer); callback->content(buffer);
buffer.clear(); buffer.clear();
parsingAttr = false; parsingAttr = false;
state = StateEntity;
break; break;
default: default:
@ -225,9 +217,9 @@ doBuffer:
case StateCDATA2: case StateCDATA2:
if(ch == L'>') { if(ch == L'>') {
state = StateNone;
callback->cdata(buffer); callback->cdata(buffer);
buffer.clear(); buffer.clear();
state = StateNone;
} else if(ch == L']') { } else if(ch == L']') {
buffer += ch; buffer += ch;
} else { } else {
@ -298,9 +290,9 @@ doBuffer:
case StatePI2: case StatePI2:
if(ch != L'>') ERROR(L"Invalid target for PI"); if(ch != L'>') ERROR(L"Invalid target for PI");
else { else {
state = StateNone;
callback->PI(buffer2, L""); callback->PI(buffer2, L"");
buffer.clear(); buffer.clear();
state = StateNone;
} }
break; break;
@ -311,15 +303,12 @@ doBuffer:
case StatePI3: case StatePI3:
if(ch == L'>') { if(ch == L'>') {
state = StateNone;
callback->PI(buffer2, buffer); callback->PI(buffer2, buffer);
buffer.clear(); buffer.clear();
} else if(ch == '?') { state = StateNone;
buffer += L'?';
} else { } else {
buffer += L'?'; buffer += L'?';
buffer += ch; buffer += ch;
state = StatePIData;
} }
break; break;
@ -354,15 +343,14 @@ doBuffer:
else { else {
buffer += L'-'; buffer += L'-';
buffer += ch; buffer += ch;
state = StateComment;
} }
break; break;
case StateComment3: case StateComment3:
if(ch != L'>') ERROR(L"`--' not valid in comments"); if(ch != L'>') ERROR(L"`--' not valid in comments");
state = StateNone;
callback->comment(buffer); callback->comment(buffer);
buffer.clear(); buffer.clear();
state = StateNone;
break; break;
case StateElemName: case StateElemName:
@ -382,10 +370,10 @@ doBuffer:
switch(ch) { switch(ch) {
case L'>': case L'>':
elemStack.push_back(buffer); elemStack.push_back(buffer);
state = StateNone;
buffer.clear();
callback->element(buffer, elemAttrs); callback->element(buffer, elemAttrs);
state = StateNone;
++elementDepth; ++elementDepth;
buffer.clear();
break; break;
case L'/': case L'/':
@ -412,9 +400,9 @@ doBuffer:
switch(ch) { switch(ch) {
case L'>': case L'>':
elemStack.push_back(elemName); elemStack.push_back(elemName);
state = StateNone;
buffer.clear();
callback->element(elemName, elemAttrs); callback->element(elemName, elemAttrs);
buffer.clear();
state = StateNone;
++elementDepth; ++elementDepth;
break; break;
@ -474,10 +462,10 @@ doBuffer:
if(ch == L'/') { if(ch == L'/') {
state = StateNeedClose; state = StateNeedClose;
} else if(ch == L'>') { } else if(ch == L'>') {
state = StateNone;
buffer.clear();
callback->element(elemName, elemAttrs); callback->element(elemName, elemAttrs);
elemStack.push_back(elemName); elemStack.push_back(elemName);
buffer.clear();
state = StateNone;
++elementDepth; ++elementDepth;
} else ERROR(L"Invalid character after attribute."); } else ERROR(L"Invalid character after attribute.");
break; break;
@ -486,10 +474,10 @@ doBuffer:
case StateNeedClose: case StateNeedClose:
if(ch != L'>') ERROR(L"Stray `/' in open tag."); if(ch != L'>') ERROR(L"Stray `/' in open tag.");
state = StateNone;
buffer.clear();
callback->element(elemName, elemAttrs); callback->element(elemName, elemAttrs);
callback->closeTag(elemName); callback->closeTag(elemName);
buffer.clear();
state = StateNone;
break; break;
case StateClose: case StateClose:
@ -513,9 +501,9 @@ doBuffer:
if(ch != L'>') ERROR(L"Invalid character in close tag name."); if(ch != L'>') ERROR(L"Invalid character in close tag name.");
if(elemStack.back() != buffer) ERROR(L"Mismatched close tag."); if(elemStack.back() != buffer) ERROR(L"Mismatched close tag.");
elemStack.pop_back(); elemStack.pop_back();
state = StateNone;
buffer.clear();
callback->closeTag(buffer); callback->closeTag(buffer);
buffer.clear();
state = StateNone;
--elementDepth; --elementDepth;
} }
break; break;
@ -525,9 +513,9 @@ doBuffer:
if(ch != L'>') ERROR(L"Invalid data in close tag."); if(ch != L'>') ERROR(L"Invalid data in close tag.");
if(elemStack.back() != elemName) ERROR(L"Mismatched close tag."); if(elemStack.back() != elemName) ERROR(L"Mismatched close tag.");
elemStack.pop_back(); elemStack.pop_back();
state = StateNone;
buffer.clear();
callback->closeTag(elemName); callback->closeTag(elemName);
buffer.clear();
state = StateNone;
--elementDepth; --elementDepth;
break; break;
@ -578,7 +566,6 @@ doBuffer:
break; break;
} }
#undef ERROR #undef ERROR
++col;
} }
@ -590,16 +577,9 @@ std::wstring Parser::entityRef(const std::wstring& ent)
if(ent == L"apos") return L"'"; if(ent == L"apos") return L"'";
if(ent == L"lt") return L"<"; if(ent == L"lt") return L"<";
if(ent == L"gt") return L">"; if(ent == L"gt") return L">";
return callback->entityRef(ent);
std::wstring result;
if(callback->entityRef(ent, result)) return result;
throw UnknownEntity(ent, line, col);
} }
} }
/* options for text editors
kate: replace-trailing-space-save true; space-indent true; tab-width 4;
vim: expandtab:ts=4:sw=4
*/

View File

@ -120,9 +120,6 @@ private:
bool skipNextNewline; bool skipNextNewline;
int elementDepth, xmlCount, restartCount; int elementDepth, xmlCount, restartCount;
// for reporting errors
int line, col;
public: public:
/*! \brief Constructor. /*! \brief Constructor.
@ -224,7 +221,3 @@ public:
} }
/* options for text editors
kate: replace-trailing-space-save true; space-indent true; tab-width 4;
vim: expandtab:ts=4:sw=4
*/

View File

@ -14,7 +14,3 @@
#include <sstream> #include <sstream>
#include <utf8> #include <utf8>
#include <stdint.h> #include <stdint.h>
/* options for text editors
kate: replace-trailing-space-save true; space-indent true; tab-width 4;
vim: expandtab:ts=4:sw=4
*/

View File

@ -8,7 +8,3 @@
// Below are all the includes used throughout the library. // Below are all the includes used throughout the library.
/* options for text editors
kate: replace-trailing-space-save true; space-indent true; tab-width 4;
vim: expandtab:ts=4:sw=4
*/

View File

@ -31,7 +31,7 @@ then
echo " Compiling" echo " Compiling"
SONAME="${libStreamedXML_BASE}.so.${SOMAJOR}.${SOMINOR}" SONAME="${libStreamedXML_BASE}.so.${SOMAJOR}.${SOMINOR}"
do_cmd ${CXX} ${CFLAGS} -Iobj -shared -fpic -o "${libStreamedXML}" \ do_cmd ${CXX} ${CFLAGS} -shared -fpic -o "${libStreamedXML}" \
-Wl,-soname,${SONAME} \ -Wl,-soname,${SONAME} \
${SRC} ${SO_EXTRA} || return 1 ${SRC} ${SO_EXTRA} || return 1

View File

@ -9,7 +9,7 @@ MONOLITHIC_TESTS="src/libStreamedXML/build.lib src/libStreamedXML/build.monolith
if [ -z "${libStreamedXML_MONOLITHIC}" ] if [ -z "${libStreamedXML_MONOLITHIC}" ]
then then
MONOLITHIC_SOURCE="$(echo src/libStreamedXML/{TopHeader,ForwardDeclare,Exceptions,Callback,Parser,Decoder,BottomHeader}.h)" MONOLITHIC_SOURCE="$(echo src/libStreamedXML/{TopHeader,ForwardDeclare,Exceptions,Callback,Parser,Decoder,BottomHeader}.h)"
make_monolithic ${HDR} Ch || return 1 make_monolithic ${HDR} C || return 1
MONOLITHIC_SOURCE="$(echo src/libStreamedXML/{TopSource,Exceptions,Parser,Decoder}.cpp)" MONOLITHIC_SOURCE="$(echo src/libStreamedXML/{TopSource,Exceptions,Parser,Decoder}.cpp)"
make_monolithic ${SRC} C || return 1 make_monolithic ${SRC} C || return 1

View File

@ -11,7 +11,7 @@
# be bumped on a binary-incompatible release. They are both single # be bumped on a binary-incompatible release. They are both single
# integers. # integers.
SOMAJOR=0 SOMAJOR=0
SOMINOR=1 SOMINOR=0
# SOMICRO is bumped every time there is a binary-compatible release. # SOMICRO is bumped every time there is a binary-compatible release.
SOMICRO=3 SOMICRO=0

View File

@ -11,8 +11,8 @@
# expected to be in 'major.minor.micro' format. It can optionally be # expected to be in 'major.minor.micro' format. It can optionally be
# suffixed with a string. # suffixed with a string.
VERMAJOR=1 VERMAJOR=1
VERMINOR=2 VERMINOR=1
VERMICRO=8 VERMICRO=0
VEREXTRA="" VEREXTRA=""
# kate: replace-trailing-space-save true; space-indent true; tab-width 4; # kate: replace-trailing-space-save true; space-indent true; tab-width 4;