xmlstorage.h
字号:
//
// XML storage classes
//
// xmlstorage.h
//
// Copyright (c) 2004, 2005, 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 _XMLSTORAGE_H
#if _MSC_VER>=1400
#ifndef _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES
#define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1
#define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_COUNT 1
#define _CRT_SECURE_CPP_OVERLOAD_SECURE_NAMES 1
#endif
#endif
#ifndef _NO_EXPAT
//#include "expat.h"
#include <expat/expat.h>
#else
typedef char XML_Char;
enum XML_Status {
XML_STATUS_ERROR = 0,
XML_STATUS_OK = 1
};
enum XML_Error {
XML_ERROR_NONE,
XML_ERROR_FAILURE
};
#endif
#ifdef _MSC_VER
#pragma warning(disable: 4786)
#ifndef _NO_COMMENT
#ifndef _NO_EXPAT
#ifdef XML_STATIC
#ifndef _DEBUG
#pragma comment(lib, "libexpatMT")
#endif
#else
#pragma comment(lib, "libexpat")
#endif
#endif
#ifndef _STRING_DEFINED // _STRING_DEFINED only allowed if using xmlstorage.cpp embedded in the project
#if defined(_DEBUG) && defined(_DLL) // DEBUG version only supported with MSVCRTD
#if _MSC_VER==1400
#pragma comment(lib, "xmlstorage-vc8d")
#else
#pragma comment(lib, "xmlstorage-vc6d")
#endif
#else
#ifdef _DLL
#if _MSC_VER==1400
#pragma comment(lib, "xmlstorage-vc8")
#else
#pragma comment(lib, "xmlstorage-vc6")
#endif
#elif defined(_MT)
#if _MSC_VER==1400
#pragma comment(lib, "xmlstorage-vc8t")
#else
#pragma comment(lib, "xmlstorage-vc6t")
#endif
#else
// -ML is no more supported by VS2005.
#pragma comment(lib, "xmlstorage-vc6l")
#endif
#endif
#endif // _STRING_DEFINED
#endif // _NO_COMMENT
#endif // _MSC_VER
#ifdef UNICODE
#ifndef _UNICODE
#define _UNICODE
#endif
#else
#ifdef _UNICODE
#define UNICODE
#endif
#endif
#include <windows.h> // for LPCTSTR
#include <tchar.h>
#include <malloc.h>
#include <fstream>
#include <sstream>
#include <string>
#include <stack>
#include <list>
#include <map>
#ifndef BUFFER_LEN
#define BUFFER_LEN 2048
#endif
namespace XMLStorage {
#ifndef XS_String
#ifdef XS_STRING_UTF8
#define XS_CHAR char
#define XS_TEXT(x) x
#define LPXSSTR LPSTR
#define LPCXSSTR LPCSTR
#define XS_icmp stricmp
#define XS_nicmp strnicmp
#define XS_toi atoi
#define XS_tod strtod
#define XS_len strlen
#define XS_snprintf snprintf
#define XS_vsnprintf vsnprintf
#else
#define XS_CHAR TCHAR
#define XS_TEXT(x) TEXT(x)
#define LPXSSTR LPTSTR
#define LPCXSSTR LPCTSTR
#define XS_icmp _tcsicmp
#define XS_nicmp _tcsnicmp
#define XS_toi _ttoi
#define XS_tod _tcstod
#define XS_len _tcslen
#define XS_snprintf _sntprintf
#define XS_vsnprintf _vsntprintf
#endif
#ifndef COUNTOF
#if _MSC_VER>=1400
#define COUNTOF _countof
#else
#define COUNTOF(b) (sizeof(b)/sizeof(b[0]))
#endif
#endif
#if defined(_STRING_DEFINED) && !defined(XS_STRING_UTF8)
#define XS_String String
#else // _STRING_DEFINED, !XS_STRING_UTF8
/// string class for TCHAR strings
struct XS_String
#if defined(UNICODE) && !defined(XS_STRING_UTF8)
: public std::wstring
#else
: public std::string
#endif
{
#if defined(UNICODE) && !defined(XS_STRING_UTF8)
typedef std::wstring super;
#else
typedef std::string super;
#endif
XS_String() {}
XS_String(LPCXSSTR s) {if (s) super::assign(s);}
XS_String(LPCXSSTR s, size_t l) : super(s, l) {}
XS_String(const super& other) : super(other) {}
XS_String(const XS_String& other) : super(other) {}
#if defined(UNICODE) && !defined(XS_STRING_UTF8)
XS_String(LPCSTR s) {assign(s);}
XS_String(LPCSTR s, size_t l) {assign(s, l);}
XS_String(const std::string& other) {assign(other.c_str());}
XS_String& operator=(LPCSTR s) {assign(s); return *this;}
void assign(LPCSTR s) {if (s) {size_t bl=strlen(s); LPWSTR b=(LPWSTR)alloca(sizeof(WCHAR)*bl); super::assign(b, MultiByteToWideChar(CP_ACP, 0, s, bl, b, bl));} else erase();}
void assign(LPCSTR s, size_t l) {if (s) {size_t bl=l; LPWSTR b=(LPWSTR)alloca(sizeof(WCHAR)*bl); super::assign(b, MultiByteToWideChar(CP_ACP, 0, s, l, b, bl));} else erase();}
#else
XS_String(LPCWSTR s) {assign(s);}
XS_String(LPCWSTR s, size_t l) {assign(s, l);}
XS_String(const std::wstring& other) {assign(other.c_str());}
XS_String& operator=(LPCWSTR s) {assign(s); return *this;}
#ifdef XS_STRING_UTF8
void assign(const XS_String& s) {assign(s.c_str());}
void assign(LPCWSTR s) {if (s) {size_t bl=wcslen(s); LPSTR b=(LPSTR)alloca(bl); super::assign(b, WideCharToMultiByte(CP_UTF8, 0, s, (int)bl, b, (int)bl, 0, 0));} else erase();}
void assign(LPCWSTR s, size_t l) {size_t bl=l; if (s) {LPSTR b=(LPSTR)alloca(bl); super::assign(b, WideCharToMultiByte(CP_UTF8, 0, s, (int)l, b, (int)bl, 0, 0));} else erase();}
#else // if !UNICODE && !XS_STRING_UTF8
void assign(LPCWSTR s) {if (s) {size_t bl=wcslen(s); LPSTR b=(LPSTR)alloca(bl); super::assign(b, WideCharToMultiByte(CP_ACP, 0, s, (int)bl, b, (int)bl, 0, 0));} else erase();}
void assign(LPCWSTR s, size_t l) {size_t bl=l; if (s) {LPSTR b=(LPSTR)alloca(bl); super::assign(b, WideCharToMultiByte(CP_ACP, 0, s, (int)l, b, (int)bl, 0, 0));} else erase();}
#endif
#endif
XS_String& operator=(LPCXSSTR s) {if (s) super::assign(s); else erase(); return *this;}
XS_String& operator=(const super& s) {super::assign(s); return *this;}
void assign(LPCXSSTR s) {super::assign(s);}
void assign(LPCXSSTR s, size_t l) {super::assign(s, l);}
operator LPCXSSTR() const {return c_str();}
#ifdef XS_STRING_UTF8
operator std::wstring() const {size_t bl=length(); LPWSTR b=(LPWSTR)alloca(sizeof(WCHAR)*bl); return std::wstring(b, MultiByteToWideChar(CP_UTF8, 0, c_str(), bl, b, bl));}
#elif defined(UNICODE)
operator std::string() const {size_t bl=length(); LPSTR b=(LPSTR)alloca(bl); return std::string(b, WideCharToMultiByte(CP_ACP, 0, c_str(), bl, b, bl, 0, 0));}
#else
operator std::wstring() const {size_t bl=length(); LPWSTR b=(LPWSTR)alloca(sizeof(WCHAR)*bl); return std::wstring(b, MultiByteToWideChar(CP_ACP, 0, c_str(), (int)bl, b, (int)bl));}
#endif
XS_String& printf(LPCXSSTR fmt, ...)
{
va_list l;
XS_CHAR b[BUFFER_LEN];
va_start(l, fmt);
super::assign(b, XS_vsnprintf(b, COUNTOF(b), fmt, l));
va_end(l);
return *this;
}
XS_String& vprintf(LPCXSSTR fmt, va_list l)
{
XS_CHAR b[BUFFER_LEN];
super::assign(b, XS_vsnprintf(b, COUNTOF(b), fmt, l));
return *this;
}
XS_String& appendf(LPCXSSTR fmt, ...)
{
va_list l;
XS_CHAR b[BUFFER_LEN];
va_start(l, fmt);
super::append(b, XS_vsnprintf(b, COUNTOF(b), fmt, l));
va_end(l);
return *this;
}
XS_String& vappendf(LPCXSSTR fmt, va_list l)
{
XS_CHAR b[BUFFER_LEN];
super::append(b, XS_vsnprintf(b, COUNTOF(b), fmt, l));
return *this;
}
};
#endif // _STRING_DEFINED, !XS_STRING_UTF8
#endif // XS_String
#ifndef XS_STRING_UTF8
inline void assign_utf8(XS_String& s, const char* str)
{
int lutf8 = (int)strlen(str);
#ifdef UNICODE
LPTSTR buffer = (LPTSTR)alloca(sizeof(TCHAR)*lutf8);
int l = MultiByteToWideChar(CP_UTF8, 0, str, lutf8, buffer, lutf8);
#else
LPWSTR wbuffer = (LPWSTR)alloca(sizeof(WCHAR)*lutf8);
int l = MultiByteToWideChar(CP_UTF8, 0, str, lutf8, wbuffer, lutf8);
int bl=2*l; LPSTR buffer = (LPSTR)alloca(bl);
l = WideCharToMultiByte(CP_ACP, 0, wbuffer, l, buffer, bl, 0, 0);
#endif
s.assign(buffer, l);
}
inline std::string get_utf8(LPCTSTR s, size_t l)
{
#ifdef UNICODE
size_t bl=2*l; LPSTR buffer = (LPSTR)alloca(bl);
l = WideCharToMultiByte(CP_UTF8, 0, s, (int)l, buffer, (int)bl, 0, 0);
#else
LPWSTR wbuffer = (LPWSTR)alloca(sizeof(WCHAR)*l);
l = MultiByteToWideChar(CP_ACP, 0, s, (int)l, wbuffer, (int)l);
size_t bl=2*l; LPSTR buffer = (LPSTR)alloca(bl);
l = WideCharToMultiByte(CP_UTF8, 0, wbuffer, (int)l, buffer, (int)bl, 0, 0);
#endif
return std::string(buffer, l);
}
inline std::string get_utf8(const XS_String& s)
{
return get_utf8(s.c_str(), s.length());
}
#endif // XS_STRING_UTF8
extern std::string EncodeXMLString(const XS_String& str);
extern XS_String DecodeXMLString(const XS_String& str);
#ifdef __GNUC__
#include <ext/stdio_filebuf.h>
typedef __gnu_cxx::stdio_filebuf<char> STDIO_FILEBUF;
#else
typedef std::filebuf STDIO_FILEBUF;
#endif
struct FileHolder
{
FileHolder(LPCTSTR path, LPCTSTR mode)
{
#ifdef __STDC_WANT_SECURE_LIB__ // secure CRT functions using VS 2005
if (_tfopen_s(&_pfile, path, mode) != 0)
_pfile = NULL;
#else
_pfile = _tfopen(path, mode);
#endif
}
~FileHolder()
{
if (_pfile)
fclose(_pfile);
}
protected:
FILE* _pfile;
};
/// input file stream with ANSI/UNICODE file names
struct tifstream : public std::istream, FileHolder
{
typedef std::istream super;
tifstream(LPCTSTR path)
: super(&_buf),
FileHolder(path, TEXT("rb")), // binary mode is important for XMLReader::read_buffer() with MinGW libraries
#ifdef __GNUC__
_buf(_pfile, std::ios::in)
#else
_buf(_pfile)
#endif
{
}
protected:
STDIO_FILEBUF _buf;
};
/// output file stream with ANSI/UNICODE file names
struct tofstream : public std::ostream, FileHolder
{
typedef std::ostream super;
tofstream(LPCTSTR path)
: super(&_buf),
FileHolder(path, TEXT("w")),
#ifdef __GNUC__
_buf(_pfile, std::ios::out)
#else
_buf(_pfile)
#endif
{
}
~tofstream()
{
flush();
}
protected:
STDIO_FILEBUF _buf;
};
// write XML files with 2 spaces indenting
#define XML_INDENT_SPACE " "
#ifdef XML_UNICODE // Are XML_Char strings UTF-16 encoded?
typedef XS_String String_from_XML_Char;
#elif defined(XS_STRING_UTF8)
typedef XS_String String_from_XML_Char;
#else
/// converter from Expat strings to XMLStorage internal strings
struct String_from_XML_Char : public XS_String
{
String_from_XML_Char(const XML_Char* str)
{
assign_utf8(*this, str);
}
};
#endif
#if defined(UNICODE) && !defined(XS_STRING_UTF8)
// optimization for faster UNICODE/ASCII string comparison without temporary A/U conversion
inline bool operator==(const XS_String& s1, const char* s2)
{
LPCWSTR p = s1;
const unsigned char* q = (const unsigned char*)s2;
while(*p && *q)
if (*p++ != *q++)
return false;
return *p == *q;
};
#endif
#ifdef XMLNODE_LOCATION
/// location of XML Node including XML file name
struct XMLLocation
{
XMLLocation()
: _pdisplay_path(NULL),
_line(0),
_column(0)
{
}
XMLLocation(const char* display_path, int line, int column)
: _pdisplay_path(display_path),
_line(line),
_column(column)
{
}
std::string str() const;
protected:
const char* _pdisplay_path; // character pointer for fast reference
int _line;
int _column;
};
#endif
/// in memory representation of an XML node
struct XMLNode : public XS_String
{
#if defined(UNICODE) && !defined(XS_STRING_UTF8)
// optimized read access without temporary A/U conversion when using ASCII attribute names
struct AttributeMap : public std::map<XS_String, XS_String>
{
typedef std::map<XS_String, XS_String> super;
const_iterator find(const char* x) const
{
for(const_iterator it=begin(); it!=end(); ++it)
if (it->first == x)
return it;
return end();
}
const_iterator find(const key_type& x) const
{
return super::find(x);
}
iterator find(const key_type& x)
{
return super::find(x);
}
};
#else
typedef std::map<XS_String, XS_String> AttributeMap;
#endif
/// internal children node list
struct Children : public std::list<XMLNode*>
{
void assign(const Children& other)
{
clear();
for(Children::const_iterator it=other.begin(); it!=other.end(); ++it)
push_back(new XMLNode(**it));
}
void clear()
{
while(!empty()) {
XMLNode* node = back();
pop_back();
node->clear();
delete node;
}
}
};
// access to protected class members for XMLPos and XMLReader
friend struct XMLPos;
friend struct const_XMLPos;
friend struct XMLReaderBase;
XMLNode(const XS_String& name)
: XS_String(name)
{
}
XMLNode(const XS_String& name, const std::string& leading)
: XS_String(name),
_leading(leading)
{
}
XMLNode(const XMLNode& other)
: XS_String(other),
_attributes(other._attributes),
_leading(other._leading),
_content(other._content),
_end_leading(other._end_leading),
_trailing(other._trailing)
#ifdef XMLNODE_LOCATION
, _location(other._location)
#endif
{
for(Children::const_iterator it=other._children.begin(); it!=other._children.end(); ++it)
_children.push_back(new XMLNode(**it));
}
virtual ~XMLNode()
{
while(!_children.empty()) {
delete _children.back();
_children.pop_back();
}
}
void clear()
{
_leading.erase();
_content.erase();
_end_leading.erase();
_trailing.erase();
_attributes.clear();
_children.clear();
XS_String::erase();
}
XMLNode& operator=(const XMLNode& other)
{
_children.assign(other._children);
_attributes = other._attributes;
_leading = other._leading;
_content = other._content;
_end_leading = other._end_leading;
_trailing = other._trailing;
return *this;
}
/// add a new child node
void add_child(XMLNode* child)
{
_children.push_back(child);
}
/// write access to an attribute
void put(const XS_String& attr_name, const XS_String& value)
{
_attributes[attr_name] = value;
}
/// C++ write access to an attribute
XS_String& operator[](const XS_String& attr_name)
{
return _attributes[attr_name];
}
/// read only access to an attribute
template<typename T> XS_String get(const T& attr_name) const
{
AttributeMap::const_iterator found = _attributes.find(attr_name);
if (found != _attributes.end())
return found->second;
else
return XS_String();
}
/// convenient value access in children node
XS_String subvalue(const XS_String& name, const XS_String& attr_name, int n=0) const
{
const XMLNode* node = find(name, n);
if (node)
return node->get(attr_name);
else
return XS_String();
}
/// convenient storage of distinct values in children node
XS_String& subvalue(const XS_String& name, const XS_String& attr_name, int n=0)
{
XMLNode* node = find(name, n);
if (!node) {
node = new XMLNode(name);
add_child(node);
}
return (*node)[attr_name];
}
#if defined(UNICODE) && !defined(XS_STRING_UTF8)
/// convenient value access in children node
XS_String subvalue(const char* name, const char* attr_name, int n=0) const
{
const XMLNode* node = find(name, n);
if (node)
return node->get(attr_name);
else
return XS_String();
}
/// convenient storage of distinct values in children node
XS_String& subvalue(const char* name, const XS_String& attr_name, int n=0)
{
XMLNode* node = find(name, n);
if (!node) {
node = new XMLNode(name);
add_child(node);
}
return (*node)[attr_name];
}
#endif
const Children& get_children() const
{
return _children;
}
Children& get_children()
{
return _children;
}
const AttributeMap& get_attributes() const
{
return _attributes;
}
AttributeMap& get_attributes()
{
return _attributes;
}
XS_String get_content() const
{
#ifdef XS_STRING_UTF8
const XS_String& ret = _content;
#else
XS_String ret;
assign_utf8(ret, _content.c_str());
#endif
return DecodeXMLString(ret.c_str());
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -