Explorer: update XMLStorage library and remove Expat dependency

svn path=/trunk/; revision=23397
This commit is contained in:
Martin Fuchs 2006-07-31 23:21:55 +00:00
parent 4a89b0422d
commit 350cddb3d6
16 changed files with 1282 additions and 474 deletions

View file

@ -7,8 +7,6 @@
import rc-mingw ;
EXPAT_INC = [ modules.peek : EXPAT_INC ] ;
exe explorer :
explorer.cpp
explorer_intres.rc
@ -44,7 +42,7 @@ exe explorer :
dialogs/settings.cpp
i386-stub-win32.c
: <define>WIN32 <define>_WIN32_IE=0x0600 <define>_WIN32_WINNT=0x0501 <define>WINVER=0x0500
<include>. <include>$(EXPAT_INC)
<include>.
# only for GCC: <cxxflags>-fexceptions <cxxflags>-Wall <cxxflags>-Wno-unused-value
<find-shared-library>gdi32
<find-shared-library>ole32
@ -53,8 +51,6 @@ exe explorer :
<find-shared-library>wsock32
<find-shared-library>oleaut32
<find-shared-library>msimg32
# <find-shared-library>expat
<linkflags>notifyhook.dll
<linkflags>libexpat.dll
;

View file

@ -10,7 +10,7 @@ CC = gcc
CXX = g++
LINK = g++
CFLAGS = -DWIN32 -DROSSHELL -D_WIN32_IE=0x0600 -D_WIN32_WINNT=0x0501 -DWINVER=0x0500 -fexceptions -Wall -I. -I$(EXPAT_INC)
CFLAGS = -DWIN32 -DROSSHELL -D_WIN32_IE=0x0600 -D_WIN32_WINNT=0x0501 -DWINVER=0x0500 -fexceptions -Wall -I.
RCFLAGS = -DWIN32 -DROSSHELL -D__WINDRES__
LFLAGS = -Wl,--subsystem,windows
@ -68,7 +68,8 @@ OBJECTS = \
searchprogram.o \
settings.o \
i386-stub-win32.o \
xmlstorage.o
xmlstorage.o \
xs-native.o
LIBS = gdi32 comctl32 msimg32 ole32 uuid
DELAYIMPORTS = oleaut32 wsock32
@ -78,7 +79,7 @@ all: precomp.h.gch $(TARGET)
precomp.h.gch: *.h utility/*.h shell/*.h desktop/*.h
$(CXX) $(CFLAGS) precomp.h
$(TARGET): $(OBJECTS) $(PROGRAM)$(RES_SUFFIX) notifyhook.dll libexpat.dll
$(TARGET): $(OBJECTS) $(PROGRAM)$(RES_SUFFIX) notifyhook.dll
$(LINK) $(LFLAGS) -o $@ $^ $(addprefix -l,$(LIBS)) $(addprefix -l,$(DELAYIMPORTS))
$(PROGRAM)$(RES_SUFFIX): explorer_intres.rc res/*.bmp res/*.ico

View file

@ -17,15 +17,14 @@ TARGET_INSTALLDIR := .
TARGET_CFLAGS := \
-D__USE_W32API -DWIN32 -D_ROS_ \
-D_WIN32_IE=0x0600 -D_WIN32_WINNT=0x0501 -DWINVER=0x0500 \
-DUNICODE -fexceptions -Wall -g \
-I../../../include/expat
-DUNICODE -fexceptions -Wall -g
TARGET_CPPFLAGS := $(TARGET_CFLAGS)
TARGET_RCFLAGS := -D__USE_W32API -DWIN32 -D_ROS_ -D__WINDRES__
TARGET_SDKLIBS := \
gdi32.a user32.a comctl32.a ole32.a oleaut32.a shell32.a expat.a \
gdi32.a user32.a comctl32.a ole32.a oleaut32.a shell32.a \
notifyhook.a ws2_32.a msimg32.a
TARGET_GCCLIBS := stdc++ uuid
@ -53,7 +52,8 @@ TARGET_OBJECTS := \
utility/window.o \
utility/dragdropimpl.o \
utility/shellbrowserimpl.o \
utility/xmlstorage.o
utility/xmlstorage.o \
utility/xs-native.o
TARGET_CPPAPP := yes

View file

@ -9,7 +9,7 @@ CXX = g++
LINK = g++
# -D_NO_ALPHABLEND for builds without msimg32.dll dependency
CFLAGS = -DWIN32 -D_WIN32_IE=0x0600 -D_WIN32_WINNT=0x0501 -DWINVER=0x0500 -fexceptions -Wall -I. -I$(EXPAT_INC)
CFLAGS = -DWIN32 -D_WIN32_IE=0x0600 -D_WIN32_WINNT=0x0501 -DWINVER=0x0500 -fexceptions -Wall -I.
RCFLAGS = -DWIN32 -D__WINDRES__
LFLAGS = -Wl,--subsystem,windows
@ -75,14 +75,15 @@ OBJECTS = \
searchprogram.o \
settings.o \
i386-stub-win32.o \
xmlstorage.o
xmlstorage.o \
xs-native.o
LIBS = gdi32 comctl32 msimg32 ole32 uuid
DELAYIMPORTS = oleaut32 wsock32
all: $(TARGET)
$(TARGET): $(OBJECTS) $(PROGRAM)$(RES_SUFFIX) notifyhook.dll libexpat.dll
$(TARGET): $(OBJECTS) $(PROGRAM)$(RES_SUFFIX) notifyhook.dll
$(LINK) $(LFLAGS) -o $@ $^ $(addprefix -l,$(LIBS)) $(addprefix -l,$(DELAYIMPORTS))
$(PROGRAM)$(RES_SUFFIX): $(PROGRAM)_intres.rc res/*.bmp res/*.ico

View file

@ -6,7 +6,7 @@ MODULE = explorer.exe
APPMODE = gui
IMPORTS = shell32 comctl32 msimg32 ole32 user32 gdi32 kernel32 advapi32 oleaut32
EXTRADEFS = -D__WINE__ -D_WIN32_IE=0x0600 -D_WIN32_WINNT=0x0501 -DWINVER=0x0500 -D__MINGW32__ -DCINTERFACE
EXTRA_OBJS = notifyhook.dll libexpat.dll
EXTRA_OBJS = notifyhook.dll
EXTRALIBS = $(LIBUUID)
C_SRCS = \
@ -22,6 +22,8 @@ CPP_SRCS = \
utility/dragdropimpl.cpp \
utility/shellbrowserimpl.cpp \
utility/xmlstorage.cpp \
utility/xmlstorage.cpp \
utility/xs-native.cpp
shell/entries.cpp \
shell/winfs.cpp \
shell/unixfs.cpp \

View file

@ -10,7 +10,7 @@ CC = gcc
CXX = g++
LINK = g++
CFLAGS = -DWIN32 -D_WIN32_IE=0x0600 -D_WIN32_WINNT=0x0501 -DWINVER=0x0500 -fexceptions -Wall -I. -I$(EXPAT_INC)
CFLAGS = -DWIN32 -D_WIN32_IE=0x0600 -D_WIN32_WINNT=0x0501 -DWINVER=0x0500 -fexceptions -Wall -I.
RCFLAGS = -DWIN32 -D__WINDRES__
LFLAGS = -Wl,--subsystem,windows
@ -76,7 +76,8 @@ OBJECTS = \
searchprogram.o \
settings.o \
i386-stub-win32.o \
xmlstorage.o
xmlstorage.o \
xs-native.o
LIBS = gdi32 comctl32 msimg32 ole32 uuid
DELAYIMPORTS = oleaut32 wsock32
@ -86,7 +87,7 @@ all: precomp.h.gch $(TARGET)
precomp.h.gch: *.h utility/*.h shell/*.h desktop/*.h
$(CXX) $(CFLAGS) precomp.h
$(TARGET): $(OBJECTS) $(PROGRAM)$(RES_SUFFIX) notifyhook.dll libexpat.dll
$(TARGET): $(OBJECTS) $(PROGRAM)$(RES_SUFFIX) notifyhook.dll
$(LINK) $(LFLAGS) -o $@ $^ $(addprefix -l,$(LIBS)) $(addprefix -l,$(DELAYIMPORTS))
$(PROGRAM)$(RES_SUFFIX): explorer_intres.rc res/*.bmp res/*.ico

View file

@ -1,22 +0,0 @@
Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd
and Clark Cooper
Copyright (c) 2001, 2002, 2003 Expat maintainers.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View file

@ -1,5 +1,5 @@
/*
* Copyright 2003, 2004, 2005 Martin Fuchs
* Copyright 2003, 2004, 2005, 2006 Martin Fuchs
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -94,9 +94,9 @@ void ExplorerGlobals::read_persistent()
_cfg_path.printf(TEXT("%s\\ros-explorer-cfg.xml"), _cfg_dir.c_str());
if (!_cfg.read(_cfg_path)) {
if (_cfg._last_error != XML_ERROR_NO_ELEMENTS)
MessageBox(_hwndDesktop, String(_cfg._last_error_msg.c_str()),
TEXT("ROS Explorer - reading user settings"), MB_OK);
//if (_cfg._last_error != XML_ERROR_NO_ELEMENTS)
MessageBox(_hwndDesktop, _cfg._errors.str(),
TEXT("ROS Explorer - reading user settings"), MB_OK);
_cfg.read(TEXT("explorer-cfg-template.xml"));
}

View file

@ -310,6 +310,10 @@ SOURCE=.\utility\xmlstorage.cpp
SOURCE=.\utility\xmlstorage.h
# End Source File
# Begin Source File
SOURCE=".\utility\xs-native.cpp"
# End Source File
# End Group
# Begin Group "resources"

View file

@ -22,7 +22,6 @@
<library>ole32</library>
<library>oleaut32</library>
<library>shell32</library>
<library>expat</library>
<library>notifyhook</library>
<pch>precomp.h</pch>
<directory name="desktop">
@ -65,6 +64,7 @@
<file>dragdropimpl.cpp</file>
<file>shellbrowserimpl.cpp</file>
<file>xmlstorage.cpp</file>
<file>xs-native.cpp</file>
</directory>
<file>explorer.cpp</file>
<file>i386-stub-win32.c</file>

View file

@ -45,7 +45,7 @@ CFG=make_explorer - Win32 bjam
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Cmd_Line "msdevfilt -gcc -pipe "perl d:\tools\gSTLFilt.pl" make -f Makefile-precomp UNICODE=0"
# PROP Cmd_Line "msdevfilt -gcc -pipe "perl d:\tools\gSTLFilt.pl" mingw32-make.exe -f Makefile-precomp UNICODE=0"
# PROP Rebuild_Opt "clean all"
# PROP Target_File "explorer.exe"
# PROP Bsc_Name ""
@ -66,7 +66,7 @@ CFG=make_explorer - Win32 bjam
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Cmd_Line "msdevfilt -gcc -pipe "perl d:\tools\gSTLFilt.pl" make -f Makefile-precomp UNICODE=0 DEBUG=1"
# PROP Cmd_Line "msdevfilt -gcc -pipe "perl d:\tools\gSTLFilt.pl" mingw32-make.exe -f Makefile-precomp UNICODE=0 DEBUG=1"
# PROP Rebuild_Opt "clean all"
# PROP Target_File "explorer.exe"
# PROP Bsc_Name "msdevfilt -gcc -pipe "perl d:\tools\gSTLFilt.pl" make -f Makefile.MinGW UNICODE=0 DEBUG=1"
@ -87,7 +87,7 @@ CFG=make_explorer - Win32 bjam
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "UDebug"
# PROP Intermediate_Dir "UDebug"
# PROP Cmd_Line "msdevfilt -gcc -pipe "perl d:\tools\gSTLFilt.pl" make -f Makefile.MinGW UNICODE=1 DEBUG=1"
# PROP Cmd_Line "msdevfilt -gcc -pipe "perl d:\tools\gSTLFilt.pl" mingw32-make.exe -f Makefile.MinGW UNICODE=1 DEBUG=1"
# PROP Rebuild_Opt "clean all"
# PROP Target_File "explorer.exe"
# PROP Bsc_Name ""
@ -108,7 +108,7 @@ CFG=make_explorer - Win32 bjam
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "URelease"
# PROP Intermediate_Dir "URelease"
# PROP Cmd_Line "msdevfilt -gcc make -f Makefile-precomp UNICODE=1"
# PROP Cmd_Line "msdevfilt -gcc mingw32-make.exe -f Makefile-precomp UNICODE=1"
# PROP Rebuild_Opt "clean all"
# PROP Target_File "explorer.exe"
# PROP Bsc_Name ""

View file

@ -1,5 +1,5 @@
/*
* Copyright 2004 Martin Fuchs
* Copyright 2004, 2006 Martin Fuchs
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -426,12 +426,10 @@ bool Favorites::read(LPCTSTR path)
{
XMLDoc xbel;
if (!xbel.read(path))
if (xbel._last_error == XML_ERROR_NO_ELEMENTS)
return false;
else
MessageBox(g_Globals._hwndDesktop, String(xbel._last_error_msg.c_str()),
TEXT("ROS Explorer - reading bookmark file"), MB_OK);
if (!xbel.read(path)) {
MessageBox(g_Globals._hwndDesktop, xbel._errors.str(),
TEXT("ROS Explorer - reading bookmark file"), MB_OK);
}
const_XMLPos pos(&xbel);
@ -455,9 +453,9 @@ void Favorites::write(LPCTSTR path) const
super::write(pos);
pos.back();
xbel._header._doctype = "<!DOCTYPE xbel"
" PUBLIC \"+//IDN python.org//DTD XML Bookmark Exchange Language 1.0//EN//XML\"\n"
" \"http://www.python.org/topics/xml/dtds/xbel-1.0.dtd\">";
xbel._format._doctype._name = "xbel";
xbel._format._doctype._public = "+//IDN python.org//DTD XML Bookmark Exchange Language 1.0//EN//XML";
xbel._format._doctype._system = "http://www.python.org/topics/xml/dtds/xbel-1.0.dtd";
xbel.write(path);
}

View file

@ -416,7 +416,7 @@ LRESULT StartMenu::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam)
int new_id = ButtonHitTest(pt);
if (new_id > 0 && new_id != _selected_id)
if (new_id>0 && new_id!=_selected_id)
SelectButton(new_id);
_last_mouse_pos = lparam;
@ -707,13 +707,13 @@ bool StartMenu::Navigate(int step)
for(;;) {
idx += step;
if ((int)_buttons.size() <= 1 && (idx<0 || idx>(int)_buttons.size()))
if (_buttons.size()<=1 && (idx<0 || idx>(int)_buttons.size()))
break;
if (idx<0)
if (idx < 0)
idx += _buttons.size();
if (idx>(int)_buttons.size())
if (idx > (int)_buttons.size())
idx -= _buttons.size()+1;
if (SelectButtonIndex(idx, false))

View file

@ -36,8 +36,8 @@
*/
#ifndef _NO_COMMENT
#define _NO_COMMENT // no #pragma comment(lib, ...) statements in .lib files
#ifndef XS_NO_COMMENT
#define XS_NO_COMMENT // no #pragma comment(lib, ...) statements in .lib files
#endif
//#include "xmlstorage.h"
@ -46,6 +46,7 @@
// work around GCC's wide string constant bug
#ifdef __GNUC__
const LPCXSSTR XMLStorage::XS_EMPTY = XS_EMPTY_STR;
const LPCXSSTR XMLStorage::XS_TRUE = XS_TRUE_STR;
const LPCXSSTR XMLStorage::XS_FALSE = XS_FALSE_STR;
const LPCXSSTR XMLStorage::XS_INTFMT = XS_INTFMT_STR;
@ -57,7 +58,7 @@ namespace XMLStorage {
/// remove escape characters from zero terminated string
static std::string unescape(const char* s, char b='"', char e='"')
static std::string unescape(const char* s, char b, char e)
{
const char* end = s + strlen(s);
@ -74,8 +75,13 @@ static std::string unescape(const char* s, char b='"', char e='"')
return std::string(s, end-s);
}
inline std::string unescape(const char* s)
{
return unescape(s, '"', '"');
}
/// remove escape characters from string with specified length
static std::string unescape(const char* s, int l, char b='"', char e='"')
static std::string unescape(const char* s, size_t l, char b, char e)
{
const char* end = s + l;
@ -92,6 +98,11 @@ static std::string unescape(const char* s, int l, char b='"', char e='"')
return std::string(s, end-s);
}
inline std::string unescape(const char* s, size_t l)
{
return unescape(s, l, '"', '"');
}
/// move XPath like to position in XML tree
bool XMLPos::go(const char* path)
@ -205,7 +216,7 @@ XMLNode* XMLNode::create_relative(const char* path)
if (slash == path)
return NULL;
int l = slash? slash-path: strlen(path);
size_t l = slash? slash-path: strlen(path);
std::string comp(path, l);
path += l;
@ -270,46 +281,106 @@ XMLNode* XMLNode::create_relative(const char* path)
std::string EncodeXMLString(const XS_String& str)
{
LPCXSSTR s = str.c_str();
LPXSSTR buffer = (LPXSSTR)alloca(6*sizeof(XS_CHAR)*XS_len(s)); // worst case "&quot;" / "&apos;"
LPXSSTR o = buffer;
size_t l = XS_len(s);
for(LPCXSSTR p=s; *p; ++p)
switch(*p) {
case '&':
*o++ = '&'; *o++ = 'a'; *o++ = 'm'; *o++ = 'p'; *o++ = ';';
break;
if (l <= BUFFER_LEN) {
LPXSSTR buffer = (LPXSSTR)alloca(6*sizeof(XS_CHAR)*XS_len(s)); // worst case "&quot;" / "&apos;"
LPXSSTR o = buffer;
case '<':
*o++ = '&'; *o++ = 'l'; *o++ = 't'; *o++ = ';';
break;
for(LPCXSSTR p=s; *p; ++p)
switch(*p) {
case '&':
*o++ = '&'; *o++ = 'a'; *o++ = 'm'; *o++ = 'p'; *o++ = ';';
break;
case '>':
*o++ = '&'; *o++ = 'g'; *o++ = 't'; *o++ = ';';
break;
case '<':
*o++ = '&'; *o++ = 'l'; *o++ = 't'; *o++ = ';';
break;
case '"':
*o++ = '&'; *o++ = 'q'; *o++ = 'u'; *o++ = 'o'; *o++ = 't'; *o++ = ';';
break;
case '>':
*o++ = '&'; *o++ = 'g'; *o++ = 't'; *o++ = ';';
break;
case '\'':
*o++ = '&'; *o++ = 'a'; *o++ = 'p'; *o++ = 'o'; *o++ = 's'; *o++ = ';';
break;
case '"':
*o++ = '&'; *o++ = 'q'; *o++ = 'u'; *o++ = 'o'; *o++ = 't'; *o++ = ';';
break;
default:
if ((unsigned)*p<20 && *p!='\t' && *p!='\r' && *p!='\n') {
char b[16];
sprintf(b, "&%d;", (unsigned)*p);
for(const char*q=b; *q; )
*o++ = *q++;
} else
*o++ = *p;
}
case '\'':
*o++ = '&'; *o++ = 'a'; *o++ = 'p'; *o++ = 'o'; *o++ = 's'; *o++ = ';';
break;
default:
if ((unsigned)*p<20 && *p!='\t' && *p!='\r' && *p!='\n') {
char b[16];
sprintf(b, "&%d;", (unsigned)*p);
for(const char*q=b; *q; )
*o++ = *q++;
} else
*o++ = *p;
}
#ifdef XS_STRING_UTF8
return XS_String(buffer, o-buffer);
return XS_String(buffer, o-buffer);
#else
return get_utf8(buffer, o-buffer);
return get_utf8(buffer, o-buffer);
#endif
} else { // l > BUFFER_LEN
// encode the whole string in a CDATA section
std::string ret = "<![CDATA[";
#ifdef XS_STRING_UTF8
ret += str;
#else
ret += get_utf8(str);
#endif
ret += "]]>";
return ret;
/* alternative code using ostringstream (beware: quite slow)
#include <sstream>
std::ostringstream out;
LPCXSSTR s = str.c_str();
for(LPCXSSTR p=s; *p; ++p)
switch(*p) {
case '&':
out << "&amp;";
break;
case '<':
out << "&lt;";
break;
case '>':
out << "&gt;";
break;
case '"':
out << "&quot;";
break;
case '\'':
out << "&apos;";
break;
default:
if ((unsigned)*p<20 && *p!='\t' *p!='\r' && *p!='\n')
out << "&" << (unsigned)*p << ";";
else
out << *p;
}
#ifdef XS_STRING_UTF8
return XS_String(out.str());
#else
return get_utf8(out.str());
#endif
*/
}
}
/// decode XML string literals
@ -338,6 +409,16 @@ XS_String DecodeXMLString(const XS_String& str)
p += 5;
} else
*o++ = *p;
} else if (*p=='<' && !XS_nicmp(p+1,XS_TEXT("!CDATA["),7)) {
p += 9;
LPCXSSTR e = XS_strstr(p, XS_TEXT("]]>"));
if (e) {
size_t l = e - p;
memcpy(o, p, l);
o += l;
p += 3;
} else
*o++ = *p;
} else
*o++ = *p;
@ -367,8 +448,28 @@ void XMLNode::write_worker(std::ostream& out, int indent) const
}
/// print node without any white space
void XMLNode::plain_write_worker(std::ostream& out) const
{
out << '<' << EncodeXMLString(*this);
for(AttributeMap::const_iterator it=_attributes.begin(); it!=_attributes.end(); ++it)
out << ' ' << EncodeXMLString(it->first) << "=\"" << EncodeXMLString(it->second) << "\"";
if (!_children.empty()/*@@ || !_content.empty()*/) {
out << ">";
for(Children::const_iterator it=_children.begin(); it!=_children.end(); ++it)
(*it)->plain_write_worker(out);
out << "</" << EncodeXMLString(*this) << ">";
} else
out << "/>";
}
/// pretty print node with children tree to output stream
void XMLNode::pretty_write_worker(std::ostream& out, int indent) const
void XMLNode::pretty_write_worker(std::ostream& out, const XMLFormat& format, int indent) const
{
for(int i=indent; i--; )
out << XML_INDENT_SPACE;
@ -378,23 +479,23 @@ void XMLNode::pretty_write_worker(std::ostream& out, int indent) const
for(AttributeMap::const_iterator it=_attributes.begin(); it!=_attributes.end(); ++it)
out << ' ' << EncodeXMLString(it->first) << "=\"" << EncodeXMLString(it->second) << "\"";
if (!_children.empty() || !_content.empty()) {
out << ">\n";
if (!_children.empty()/*@@ || !_content.empty()*/) {
out << '>' << format._endl;
for(Children::const_iterator it=_children.begin(); it!=_children.end(); ++it)
(*it)->pretty_write_worker(out, indent+1);
(*it)->pretty_write_worker(out, format, indent+1);
for(int i=indent; i--; )
out << XML_INDENT_SPACE;
out << "</" << EncodeXMLString(*this) << ">\n";
out << "</" << EncodeXMLString(*this) << '>' << format._endl;
} else
out << "/>\n";
out << "/>" << format._endl;
}
/// write node with children tree to output stream using smart formating
void XMLNode::smart_write_worker(std::ostream& out, int indent) const
void XMLNode::smart_write_worker(std::ostream& out, const XMLFormat& format, int indent) const
{
if (_leading.empty())
for(int i=indent; i--; )
@ -413,7 +514,7 @@ void XMLNode::smart_write_worker(std::ostream& out, int indent) const
out << '>';
if (_content.empty())
out << '\n';
out << format._endl;
else
out << _content;
@ -421,7 +522,7 @@ void XMLNode::smart_write_worker(std::ostream& out, int indent) const
if (it != _children.end()) {
for(; it!=_children.end(); ++it)
(*it)->smart_write_worker(out, indent+1);
(*it)->smart_write_worker(out, format, indent+1);
if (_end_leading.empty())
for(int i=indent; i--; )
@ -435,181 +536,150 @@ void XMLNode::smart_write_worker(std::ostream& out, int indent) const
}
if (_trailing.empty())
out << '\n';
out << format._endl;
else
out << _trailing;
}
/// read XML stream into XML tree below _pos
XML_Status XMLReaderBase::read()
std::ostream& operator<<(std::ostream& out, const XMLError& err)
{
XML_Status status = XML_STATUS_OK;
out << err._systemId << "(" << err._line << ") [column " << err._column << "] : "
<< err._message;
do {
char* buffer = (char*) XML_GetBuffer(_parser, BUFFER_LEN);
size_t l = read_buffer(buffer, BUFFER_LEN);
if ((int)l < 0)
break;
status = XML_ParseBuffer(_parser, l, false);
} while(status == XML_STATUS_OK);
if (status != XML_STATUS_ERROR)
status = XML_ParseBuffer(_parser, 0, true);
finish_read();
return status;
return out;
}
/// return current parser position as string
std::string XMLReaderBase::get_position() const
void DocType::parse(const char* p)
{
int line = XML_GetCurrentLineNumber(_parser);
int column = XML_GetCurrentColumnNumber(_parser);
while(isspace((unsigned char)*p)) ++p;
const char* start = p;
while(isxmlsym(*p)) ++p;
_name.assign(start, p-start);
while(isspace((unsigned char)*p)) ++p;
start = p;
while(isxmlsym(*p)) ++p;
std::string keyword(p, p-start); // "PUBLIC" or "SYSTEM"
while(isspace((unsigned char)*p)) ++p;
if (*p=='"' || *p=='\'') {
char delim = *p;
start = ++p;
while(*p && *p!=delim) ++p;
if (*p == delim)
_public.assign(start, p++-start);
} else
_public.erase();
while(isspace((unsigned char)*p)) ++p;
if (*p=='"' || *p=='\'') {
char delim = *p;
start = ++p;
while(*p && *p!=delim) ++p;
if (*p == delim)
_system.assign(start, p++-start);
} else
_system.erase();
}
void XMLFormat::print_header(std::ostream& out, bool lf) const
{
out << "<?xml version=\"" << _version << "\" encoding=\"" << _encoding << "\"";
if (_standalone != -1)
out << " standalone=\"yes\"";
out << "?>";
if (lf)
out << _endl;
if (!_doctype.empty()) {
out << "<!DOCTYPE " << _doctype._name;
if (!_doctype._public.empty()) {
out << " PUBLIC " << _doctype._public;
if (lf)
out << _endl;
out << " " << _doctype._system;
} else if (!_doctype._system.empty())
out << " SYSTEM " << _doctype._system;
out << "?>";
if (lf)
out << _endl;
}
for(StyleSheetList::const_iterator it=_stylesheets.begin(); it!=_stylesheets.end(); ++it) {
it->print(out);
if (lf)
out << _endl;
}
/* if (!_additional.empty()) {
out << _additional;
if (lf)
out << _endl;
} */
}
void StyleSheet::print(std::ostream& out) const
{
out << "<?xml-stylesheet"
" href=\"" << _href << "\""
" type=\"" << _type << "\"";
if (!_title.empty())
out << " title=\"" << _title << "\"";
if (!_media.empty())
out << " media=\"" << _media << "\"";
if (!_charset.empty())
out << " charset=\"" << _charset << "\"";
if (_alternate)
out << " alternate=\"yes\"";
out << "?>";
}
/// return formated error message
std::string XMLError::str() const
{
std::ostringstream out;
out << "(" << line << ") : [column " << column << "]";
out << *this;
return out.str();
}
#ifdef XMLNODE_LOCATION
XMLLocation XMLReaderBase::get_location() const
{
int line = XML_GetCurrentLineNumber(_parser);
int column = XML_GetCurrentColumnNumber(_parser);
return XMLLocation(_display_path, line, column);
}
std::string XMLLocation::str() const
/// return merged error strings
XS_String XMLErrorList::str() const
{
std::ostringstream out;
if (_pdisplay_path)
out << _pdisplay_path;
out << "(" << _line << ") : [column " << _column << "]";
return out.str();
}
#endif
/// return current error code from Expat
XML_Error XMLReaderBase::get_error_code() const
{
return XML_GetErrorCode(_parser);
}
/// store XML version and encoding into XML reader
void XMLCALL XMLReaderBase::XML_XmlDeclHandler(void* userData, const XML_Char* version, const XML_Char* encoding, int standalone)
{
XMLReaderBase* pReader = (XMLReaderBase*) userData;
pReader->XmlDeclHandler(version, encoding, standalone);
}
/// notifications about XML start tag
void XMLCALL XMLReaderBase::XML_StartElementHandler(void* userData, const XML_Char* name, const XML_Char** atts)
{
XMLReaderBase* pReader = (XMLReaderBase*) userData;
XMLNode::AttributeMap attributes;
while(*atts) {
const XML_Char* attr_name = *atts++;
const XML_Char* attr_value = *atts++;
attributes[String_from_XML_Char(attr_name)] = String_from_XML_Char(attr_value);
}
pReader->StartElementHandler(String_from_XML_Char(name), attributes);
}
/// notifications about XML end tag
void XMLCALL XMLReaderBase::XML_EndElementHandler(void* userData, const XML_Char* name)
{
XMLReaderBase* pReader = (XMLReaderBase*) userData;
pReader->EndElementHandler();
}
/// store content, white space and comments
void XMLCALL XMLReaderBase::XML_DefaultHandler(void* userData, const XML_Char* s, int len)
{
XMLReaderBase* pReader = (XMLReaderBase*) userData;
pReader->DefaultHandler(s, len);
}
/// return error strings for Expat errors
std::string XMLReaderBase::get_error_string() const
{
XML_Error error = XML_GetErrorCode(_parser);
switch(error) {
case XML_ERROR_NONE: return "XML_ERROR_NONE";
case XML_ERROR_NO_MEMORY: return "XML_ERROR_NO_MEMORY";
case XML_ERROR_SYNTAX: return "XML_ERROR_SYNTAX";
case XML_ERROR_NO_ELEMENTS: return "XML_ERROR_NO_ELEMENTS";
case XML_ERROR_INVALID_TOKEN: return "XML_ERROR_INVALID_TOKEN";
case XML_ERROR_UNCLOSED_TOKEN: return "XML_ERROR_UNCLOSED_TOKEN";
case XML_ERROR_PARTIAL_CHAR: return "XML_ERROR_PARTIAL_CHAR";
case XML_ERROR_TAG_MISMATCH: return "XML_ERROR_TAG_MISMATCH";
case XML_ERROR_DUPLICATE_ATTRIBUTE: return "XML_ERROR_DUPLICATE_ATTRIBUTE";
case XML_ERROR_JUNK_AFTER_DOC_ELEMENT: return "XML_ERROR_JUNK_AFTER_DOC_ELEMENT";
case XML_ERROR_PARAM_ENTITY_REF: return "XML_ERROR_PARAM_ENTITY_REF";
case XML_ERROR_UNDEFINED_ENTITY: return "XML_ERROR_UNDEFINED_ENTITY";
case XML_ERROR_RECURSIVE_ENTITY_REF: return "XML_ERROR_RECURSIVE_ENTITY_REF";
case XML_ERROR_ASYNC_ENTITY: return "XML_ERROR_ASYNC_ENTITY";
case XML_ERROR_BAD_CHAR_REF: return "XML_ERROR_BAD_CHAR_REF";
case XML_ERROR_BINARY_ENTITY_REF: return "XML_ERROR_BINARY_ENTITY_REF";
case XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF: return "XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF";
case XML_ERROR_MISPLACED_XML_PI: return "XML_ERROR_MISPLACED_XML_PI";
case XML_ERROR_UNKNOWN_ENCODING: return "XML_ERROR_UNKNOWN_ENCODING";
case XML_ERROR_INCORRECT_ENCODING: return "XML_ERROR_INCORRECT_ENCODING";
case XML_ERROR_UNCLOSED_CDATA_SECTION: return "XML_ERROR_UNCLOSED_CDATA_SECTION";
case XML_ERROR_EXTERNAL_ENTITY_HANDLING: return "XML_ERROR_EXTERNAL_ENTITY_HANDLING";
case XML_ERROR_NOT_STANDALONE: return "XML_ERROR_NOT_STANDALONE";
case XML_ERROR_UNEXPECTED_STATE: return "XML_ERROR_UNEXPECTED_STATE";
case XML_ERROR_ENTITY_DECLARED_IN_PE: return "XML_ERROR_ENTITY_DECLARED_IN_PE";
case XML_ERROR_FEATURE_REQUIRES_XML_DTD: return "XML_ERROR_FEATURE_REQUIRES_XML_DTD";
case XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING: return "XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING";
case XML_ERROR_UNBOUND_PREFIX: return "XML_ERROR_UNBOUND_PREFIX";
// EXPAT version >= 1.95.8
#if XML_MAJOR_VERSION>1 || (XML_MAJOR_VERSION==1 && XML_MINOR_VERSION>95) || (XML_MAJOR_VERSION==1 && XML_MINOR_VERSION==95 && XML_MICRO_VERSION>7)
case XML_ERROR_UNDECLARING_PREFIX: return "XML_ERROR_UNDECLARING_PREFIX";
case XML_ERROR_INCOMPLETE_PE: return "XML_ERROR_INCOMPLETE_PE";
case XML_ERROR_XML_DECL: return "XML_ERROR_XML_DECL";
case XML_ERROR_TEXT_DECL: return "XML_ERROR_TEXT_DECL";
case XML_ERROR_PUBLICID: return "XML_ERROR_PUBLICID";
case XML_ERROR_SUSPENDED: return "XML_ERROR_SUSPENDED";
case XML_ERROR_NOT_SUSPENDED: return "XML_ERROR_NOT_SUSPENDED";
case XML_ERROR_ABORTED: return "XML_ERROR_ABORTED";
case XML_ERROR_FINISHED: return "XML_ERROR_FINISHED";
case XML_ERROR_SUSPEND_PE: return "XML_ERROR_SUSPEND_PE";
#endif
#if XML_MAJOR_VERSION>=2
/* Added in 2.0. */
case XML_ERROR_RESERVED_PREFIX_XML: return "XML_ERROR_RESERVED_PREFIX_XML";
case XML_ERROR_RESERVED_PREFIX_XMLNS: return "XML_ERROR_RESERVED_PREFIX_XMLNS";
case XML_ERROR_RESERVED_NAMESPACE_URI: return "XML_ERROR_RESERVED_NAMESPACE_URI";
#endif
}
std::ostringstream out;
out << "XML parser error #" << error;
for(const_iterator it=begin(); it!=end(); ++it)
out << *it << std::endl;
return out.str();
}
@ -627,13 +697,15 @@ void XMLReaderBase::finish_read()
/// store XML version and encoding into XML reader
void XMLReaderBase::XmlDeclHandler(const XML_Char* version, const XML_Char* encoding, int standalone)
void XMLReaderBase::XmlDeclHandler(const char* version, const char* encoding, int standalone)
{
if (version)
_xml_version = version;
_format._version = version;
if (encoding)
_encoding = encoding;
_format._encoding = encoding;
_format._standalone = standalone;
}
@ -657,7 +729,8 @@ void XMLReaderBase::StartElementHandler(const XS_String& name, const XMLNode::At
_pos->_content.append(s, p-s);
else if (_last_tag == TAG_END)
_pos->_trailing.append(s, p-s);
// else TAG_NONE -> don't store white space in root node
else // TAG_NONE at root node
p = s;
} else
_pos->_children.back()->_trailing.append(s, p-s);
@ -712,13 +785,20 @@ void XMLReaderBase::EndElementHandler()
_content.erase();
}
#if defined(XS_USE_XERCES) || defined(XS_USE_EXPAT)
/// store content, white space and comments
void XMLReaderBase::DefaultHandler(const XML_Char* s, int len)
{
#if defined(XML_UNICODE) || defined(XS_USE_XERCES)
_content.append(String_from_XML_Char(s, len));
#else
_content.append(s, len);
#endif
}
#endif
XS_String XMLWriter::s_empty_attr;
} // namespace XMLStorage

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,438 @@
//
// XML storage classes
//
// xs-native.cpp
//
// Copyright (c) 2006 Martin Fuchs <martin-fuchs@gmx.net>
//
/*
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef XS_NO_COMMENT
#define XS_NO_COMMENT // no #pragma comment(lib, ...) statements in .lib files to enable static linking
#endif
//#include "xmlstorage.h"
#include <precomp.h>
#if !defined(XS_USE_EXPAT) && !defined(XS_USE_XERCES)
namespace XMLStorage {
XMLReaderBase::~XMLReaderBase()
{
}
/// read XML stream into XML tree below _pos
void XMLReaderBase::read()
{
if (!parse()) {
XMLError error;
error._message = "XML parsing error";
//error._line = ;
//error._column = ;
_errors.push_back(error);
}
finish_read();
}
struct Buffer
{
Buffer()
{
_buffer = (char*) malloc(BUFFER_LEN);
_len = BUFFER_LEN;
reset();
}
~Buffer()
{
free(_buffer);
}
void reset()
{
_wptr = _buffer;
_buffer_str.erase();
}
void append(char c)
{
size_t wpos = _wptr-_buffer;
if (wpos >= _len) {
_len <<= 1;
_buffer = (char*) realloc(_buffer, _len);
_wptr = _buffer + wpos;
}
*_wptr++ = c;
}
const std::string& str(bool utf8) // returns UTF-8 encoded buffer content
{
if (utf8)
_buffer_str.assign(_buffer, _wptr-_buffer);
else
_buffer_str = get_utf8(_buffer, _wptr-_buffer);
return _buffer_str;
}
size_t len() const
{
return _wptr - _buffer;
}
bool has_CDEnd() const
{
//if (_wptr-_buffer < 3)
// return false;
return !strncmp(_wptr-3, "]]>", 3);
}
XS_String get_tag() const
{
const char* p = _buffer_str.c_str();
if (*p == '<')
++p;
if (*p == '/')
++p;
const char* q = p;
if (*q == '?')
++q;
while(isxmlsym(*q))
++q;
#ifdef XS_STRING_UTF8
return XS_String(p, q-p);
#else
XS_String tag;
assign_utf8(tag, p, q-p);
return tag;
#endif
}
/// read attributes and values
void get_attributes(XMLNode::AttributeMap& attributes) const
{
const char* p = _buffer_str.c_str();
// find end of tag name
if (*p == '<')
++p;
if (*p == '/')
++p;
else if (*p == '?')
++p;
while(isxmlsym(*p))
++p;
// read attributes from buffer
while(*p && *p!='>' && *p!='/') {
while(isspace((unsigned char)*p))
++p;
const char* attr_name = p;
while(isxmlsym(*p))
++p;
if (*p != '=')
break; //@TODO error handling
size_t attr_len = p - attr_name;
if (*++p!='"' && *p!='\'')
break; //@TODO error handling
char delim = *p;
const char* value = ++p;
while(*p && *p!=delim)
++p;
size_t value_len = p - value;
if (*p)
++p; // '"'
#ifdef XS_STRING_UTF8
XS_String name_str(attr_name, attr_len);
XS_String value_str(value, value_len);
#else
XS_String name_str, value_str;
assign_utf8(name_str, attr_name, attr_len);
assign_utf8(value_str, value, value_len);
#endif
attributes[name_str] = DecodeXMLString(value_str);
}
}
protected:
char* _buffer;
char* _wptr;
size_t _len;
std::string _buffer_str; // UF-8 encoded
};
bool XMLReaderBase::parse()
{
Buffer buffer;
int c = get();
bool in_comment = false;
while(c != EOF) {
if (in_comment || c=='<') {
buffer.append(c);
// read start or end tag
for(;;) {
c = get();
if (c == EOF)
break;
buffer.append(c);
if (c == '>')
break;
}
const std::string& b = buffer.str(_utf8);
const char* str = b.c_str();
if (in_comment || !strncmp(str+1, "!--", 3)) {
// XML comment
DefaultHandler(b);
if (strcmp(str+b.length()-3, "-->"))
in_comment = true;
else
in_comment = false;
c = get();
} else if (str[1] == '/') {
// end tag
/*@TODO error handling
const XS_String& tag = buffer.get_tag();
if (tag != last_opened_tag) {
ERROR
}
*/
EndElementHandler();
c = get();
} else if (str[1] == '?') {
// XML declaration
const XS_String& tag = buffer.get_tag();
if (tag == "?xml") {
XMLNode::AttributeMap attributes;
buffer.get_attributes(attributes);
const std::string& version = attributes.get("version");
const std::string& encoding = attributes.get("encoding");
int standalone;
XMLNode::AttributeMap::const_iterator found = // const_cast for ISO C++ compatibility error of GCC
const_cast<const XMLNode::AttributeMap&>(attributes).find("standalone");
if (found != attributes.end())
standalone = !XS_icmp(found->second.c_str(), XS_TEXT("yes"));
else
standalone = -1;
XmlDeclHandler(version.empty()?NULL:version.c_str(), encoding.empty()?NULL:encoding.c_str(), standalone);
if (!encoding.empty() && !_stricmp(encoding.c_str(), "utf-8"))
_utf8 = true;
c = eat_endl();
} else if (tag == "?xml-stylesheet") {
XMLNode::AttributeMap attributes;
buffer.get_attributes(attributes);
StyleSheet stylesheet(attributes.get("href"), attributes.get("type"), !XS_icmp(attributes.get("alternate"), XS_TEXT("yes")));
stylesheet._title = attributes.get("title");
stylesheet._media = attributes.get("media");
stylesheet._charset = attributes.get("charset");
_format._stylesheets.push_back(stylesheet);
c = eat_endl();
} else {
DefaultHandler(b);
c = get();
}
} else if (str[1] == '!') {
if (!strncmp(str+2, "DOCTYPE ", 8)) {
_format._doctype.parse(str+10);
c = eat_endl();
} else if (!strncmp(str+2, "[CDATA[", 7)) {
// parse <![CDATA[ ... ]]> strings
while(!buffer.has_CDEnd()) {
c = get();
if (c == EOF)
break;
buffer.append(c);
}
DefaultHandler(buffer.str(_utf8));
c = get();
}
} else {
// start tag
const XS_String& tag = buffer.get_tag();
if (!tag.empty()) {
XMLNode::AttributeMap attributes;
buffer.get_attributes(attributes);
StartElementHandler(tag, attributes);
if (str[b.length()-2] == '/')
EndElementHandler();
}
c = get();
}
} else {
buffer.append(c);
// read white space
for(;;) {
// check for the encoding of the first line end
if (!_endl_defined)
if (c == '\n') {
_format._endl = "\n";
_endl_defined = true;
} else if (c == '\r') {
_format._endl = "\r\n";
_endl_defined = true;
}
c = get();
if (c == EOF)
break;
if (c == '<')
break;
buffer.append(c);
}
DefaultHandler(buffer.str(_utf8));
}
buffer.reset();
}
return true;
}
int XMLReaderBase::eat_endl()
{
int c = get();
if (c == '\r')
c = get();
if (c == '\n')
c = get();
return c;
}
/// return current parser position as string
std::string XMLReaderBase::get_position() const
{
/*@TODO display parser position in case of errors
int line = XML_GetCurrentLineNumber(_parser);
int column = XML_GetCurrentColumnNumber(_parser);
std::ostringstream out;
out << "(" << line << ") : [column " << column << "]";
return out.str();
*/
return "";
}
#ifdef XMLNODE_LOCATION
XMLLocation XMLReaderBase::get_location() const
{
return XMLLocation(); //@TODO XMLLocation for XS-native
}
std::string XMLLocation::str() const
{
return ""; //TODO
}
#endif
/// store content, white space and comments
void XMLReaderBase::DefaultHandler(const std::string& s)
{
_content.append(s);
}
} // namespace XMLStorage
#endif // !defined(XS_USE_EXPAT) && !defined(XS_USE_XERCES)