import IE bookmarks and convert into XBEL format bookmark file

svn path=/trunk/; revision=8964
This commit is contained in:
Martin Fuchs 2004-04-04 16:04:34 +00:00
parent 4eb5cb108b
commit 776c1e9696
16 changed files with 929 additions and 131 deletions

View file

@ -31,6 +31,7 @@ exe explorer :
taskbar/startmenu.cpp
taskbar/taskbar.cpp
taskbar/traynotify.cpp
taskbar/favorites.cpp
desktop/desktop.cpp
# utility/splitpath.c
utility/dragdropimpl.cpp

View file

@ -99,6 +99,7 @@ OBJECTS = \
startmenu.o \
traynotify.o \
quicklaunch.o \
favorites.o \
searchprogram.o \
settings.o \
i386-stub-win32.o \

View file

@ -68,6 +68,7 @@ OBJECTS = \
startmenu.o \
traynotify.o \
quicklaunch.o \
favorites.o \
searchprogram.o \
settings.o \
i386-stub-win32.o \

View file

@ -39,6 +39,7 @@ CPP_SRCS = \
taskbar/startmenu.cpp \
taskbar/traynotify.cpp \
taskbar/quicklaunch.cpp \
taskbar/favorites.cpp \
dialogs/searchprogram.cpp \
dialogs/settings.cpp

View file

@ -3,7 +3,7 @@
<tr>
<td><address style="align: right;"><small>
ROS Explorer Source Code Documentation
<br>generated on 28.03.2004 by <a href="http://www.doxygen.org/index.html">
<br>generated on 04.04.2004 by <a href="http://www.doxygen.org/index.html">
<img src="doxygen.png" alt="doxygen" align="middle" border=0>
</small></address>
</td>

View file

@ -82,27 +82,31 @@ void ExplorerGlobals::init(HINSTANCE hInstance)
}
bool ExplorerGlobals::read_cfg()
void ExplorerGlobals::read_persistent()
{
// read configuration file
_cfg_dir.printf(TEXT("%s\\ReactOS"), (LPCTSTR)SpecialFolderFSPath(CSIDL_APPDATA,0));
_cfg_path.printf(TEXT("%s\\ros-explorer.xml"), _cfg_dir.c_str());
_cfg_path.printf(TEXT("%s\\ros-explorer-cfg.xml"), _cfg_dir.c_str());
if (_cfg.read(_cfg_path))
return true;
if (!_cfg.read(_cfg_path))
_cfg.read(TEXT("explorer-cfg-template.xml"));
if (_cfg.read("explorer-cfg-template.xml"))
return true;
// read bookmarks
_favorites_path.printf(TEXT("%s\\ros-explorer-bookmarks.xml"), _cfg_dir.c_str());
return false;
if (!_favorites.read(_favorites_path)) {
_favorites.import_IE_favorites(0);
_favorites.write(_favorites_path);
}
}
void ExplorerGlobals::write_cfg()
void ExplorerGlobals::write_persistent()
{
// write configuration file
RecursiveCreateDirectory(_cfg_dir);
_cfg.write(_cfg_path);
_favorites.write(_favorites_path);
}
@ -110,7 +114,7 @@ XMLPos ExplorerGlobals::get_cfg()
{
XMLPos pos(&_cfg);
pos.create("explorer-cfg");
pos.smart_create("explorer-cfg");
return pos;
}
@ -119,8 +123,8 @@ XMLPos ExplorerGlobals::get_cfg(const String& name)
{
XMLPos pos(&_cfg);
pos.create("explorer-cfg");
pos.create(name);
pos.smart_create("explorer-cfg");
pos.smart_create(name);
return pos;
}
@ -790,7 +794,7 @@ int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdL
// init common controls library
CommonControlInit usingCmnCtrl;
g_Globals.read_cfg();
g_Globals.read_persistent();
if (startup_desktop) {
g_Globals._desktops.init();
@ -818,7 +822,7 @@ int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdL
int ret = explorer_main(hInstance, lpCmdLine, nShowCmd);
// write configuration file
g_Globals.write_cfg();
g_Globals.write_persistent();
return ret;
}

View file

@ -554,6 +554,14 @@ SOURCE=.\taskbar\desktopbar.h
# End Source File
# Begin Source File
SOURCE=.\taskbar\favorites.cpp
# End Source File
# Begin Source File
SOURCE=.\taskbar\favorites.h
# End Source File
# Begin Source File
SOURCE=.\notifyhook\notifyhook.h
# End Source File
# Begin Source File

View file

@ -30,6 +30,8 @@
using namespace XMLStorage;
#include "taskbar/favorites.h"
/// management of file types
struct FileTypeInfo {
@ -228,8 +230,8 @@ extern struct ExplorerGlobals
void init(HINSTANCE hInstance);
bool read_cfg();
void write_cfg();
void read_persistent();
void write_persistent();
XMLPos get_cfg();
XMLPos get_cfg(const String& name);
@ -259,6 +261,9 @@ extern struct ExplorerGlobals
XMLDoc _cfg;
String _cfg_dir;
String _cfg_path;
Favorites _favorites;
String _favorites_path;
} g_Globals;

View file

@ -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.MinGW UNICODE=1"
# PROP Cmd_Line "make -f Makefile.MinGW UNICODE=1"
# PROP Rebuild_Opt "clean all"
# PROP Target_File "explorer.exe"
# PROP Bsc_Name ""

View file

@ -460,7 +460,7 @@ FATDrive::FATDrive(LPCTSTR path)
_CacheDty = NULL;
_Caches = 0;
_hDrive = CreateFile(path, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
_hDrive = CreateFile(path, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0);
if (_hDrive != INVALID_HANDLE_VALUE) {
_boot_sector.BytesPerSector = 512;

View file

@ -0,0 +1,292 @@
/*
* Copyright 2004 Martin Fuchs
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
//
// Explorer and Desktop clone
//
// favorites.cpp
//
// Martin Fuchs, 04.04.2004
//
#include "../utility/utility.h"
#include "../explorer.h"
#include "../globals.h"
#include "startmenu.h"
/// read .URL file
bool Bookmark::read_url(LPCTSTR path)
{
char line[BUFFER_LEN];
tifstream in(path);
while(in.good()) {
in.getline(line, BUFFER_LEN);
const char* p = line;
while(isspace(*p))
++p;
const char* keyword = p;
const char* eq = strchr(p, '=');
if (eq) {
const char* cont = eq + 1;
while(isspace(*cont))
++cont;
if (!strnicmp(keyword, "URL", 3))
_url = cont;
else if (!strnicmp(keyword, "IconFile", 8))
_icon_path = cont;
}
}
return true;
}
/// convert XBEL bookmark node
bool Bookmark::read_xbel(const_XMLPos& pos)
{
_url = pos.get("href");
if (!pos.go_down("title"))
return false;
_name = pos->get_content();
pos.back();
return true;
}
BookmarkNode::BookmarkNode(const Bookmark& bm)
: _type(BMNT_BOOKMARK)
{
_pbookmark = new Bookmark(bm);
}
BookmarkNode::BookmarkNode(const BookmarkFolder& bmf)
: _type(BMNT_FOLDER)
{
_pfolder = new BookmarkFolder(bmf);
}
BookmarkNode::BookmarkNode(const BookmarkNode& other)
: _type(other._type)
{
if (_type == BMNT_BOOKMARK)
_pbookmark = new Bookmark(*other._pbookmark);
else
_pfolder = new BookmarkFolder(*other._pfolder);
}
BookmarkNode::~BookmarkNode()
{
if (_type == BMNT_BOOKMARK)
delete _pbookmark;
else
delete _pfolder;
}
/// read bookmark list from XBEL formated XML tree
void BookmarkList::read(const_XMLPos& pos)
{
const XMLNode::Children& children = pos->get_children();
for(XMLNode::Children::const_iterator it=children.begin(); it!=children.end(); ++it) {
const XMLNode& node = **it;
const_XMLPos sub_pos(&node);
if (node == "folder") {
BookmarkFolder new_folder;
if (sub_pos.go_down("title")) {
new_folder._name = sub_pos->get_content();
sub_pos.back();
}
new_folder._bookmarks.read(sub_pos);
push_back(new_folder);
} else if (node == "bookmark") {
Bookmark bookmark;
if (bookmark.read_xbel(sub_pos))
push_back(bookmark);
}
}
}
/// write bookmark list into XBEL formated XML tree
void BookmarkList::write(XMLPos& pos) const
{
for(const_iterator it=begin(); it!=end(); ++it) {
const BookmarkNode& node = *it;
if (node._type == BookmarkNode::BMNT_FOLDER) {
BookmarkFolder& folder = *node._pfolder;
pos.create("folder");
pos.create("title");
pos->set_content(folder._name);
pos.back();
folder._bookmarks.write(pos);
pos.back();
} else { // node._type == BookmarkNode::BMNT_BOOKMARK
Bookmark& bookmark = *node._pbookmark;
if (!bookmark._url.empty()) {
pos.create("bookmark");
pos["href"] = bookmark._url;
pos.create("title");
pos->set_content(bookmark._name);
pos.back();
pos.back();
}
}
}
}
void BookmarkList::import_IE_favorites(ShellDirectory& dir, HWND hwnd)
{
TCHAR path[MAX_PATH], ext[_MAX_EXT];
dir.smart_scan(SCAN_FILESYSTEM);
for(Entry*entry=dir._down; entry; entry=entry->_next) {
if (entry->_shell_attribs & SFGAO_HIDDEN) // hide files like "desktop.ini"
continue;
String name;
if (entry->_etype == ET_SHELL)
name = dir._folder.get_name(static_cast<ShellEntry*>(entry)->_pidl);
else
name = entry->_display_name;
if (entry->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
BookmarkFolder new_folder;
new_folder._name = name;
if (entry->_etype == ET_SHELL) {
ShellDirectory new_dir(dir._folder, static_cast<ShellEntry*>(entry)->_pidl, hwnd);
new_folder._bookmarks.import_IE_favorites(new_dir, hwnd);
} else {
entry->get_path(path);
ShellDirectory new_dir(GetDesktopFolder(), path, hwnd);
new_folder._bookmarks.import_IE_favorites(new_dir, hwnd);
}
push_back(new_folder);
} else {
Bookmark bookmark;
bookmark._name = name;
entry->get_path(path);
_tsplitpath(path, NULL, NULL, NULL, ext);
if (!_tcsicmp(ext, TEXT(".url"))) {
bookmark.read_url(path);
push_back(bookmark);
} else {
///@todo read shell links
assert(0);
}
}
}
}
/// read XBEL bookmark file
bool Favorites::read(LPCTSTR path)
{
XMLDoc xbel;
if (!xbel.read(path))
return false;
const_XMLPos pos(&xbel);
if (!pos.go_down("xbel"))
return false;
super::read(pos);
pos.back();
return true;
}
/// write XBEL bookmark file
void Favorites::write(LPCTSTR path) const
{
XMLDoc xbel;
XMLPos pos(&xbel);
pos.create("xbel");
super::write(pos);
pos.back();
xbel.write(path, XMLNode::FORMAT_SMART, XMLHeader("1.0", "UTF-8", "<!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\">"));
}
/// import Internet Explorer bookmarks from Favorites folder
bool Favorites::import_IE_favorites(HWND hwnd)
{
WaitCursor wait;
StartMenuShellDirs dirs;
try {
dirs.push_back(ShellDirectory(GetDesktopFolder(), SpecialFolderPath(CSIDL_COMMON_FAVORITES, hwnd), hwnd));
dirs.push_back(ShellDirectory(GetDesktopFolder(), SpecialFolderPath(CSIDL_FAVORITES, hwnd), hwnd));
} catch(COMException&) {
}
for(StartMenuShellDirs::iterator it=dirs.begin(); it!=dirs.end(); ++it) {
StartMenuDirectory& smd = *it;
ShellDirectory& dir = smd._dir;
try {
super::import_IE_favorites(dir, hwnd);
} catch(COMException&) {
}
}
return true;
}

View file

@ -0,0 +1,87 @@
/*
* Copyright 2004 Martin Fuchs
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
//
// Explorer and Desktop clone
//
// favorites.h
//
// Martin Fuchs, 04.04.2004
//
struct Bookmark
{
Bookmark() : _icon_idx(0) {}
String _name;
String _url;
String _description;
String _icon_path;
int _icon_idx;
bool read_url(LPCTSTR path);
bool read_xbel(const_XMLPos& pos);
};
struct BookmarkFolder;
struct BookmarkNode
{
BookmarkNode(const Bookmark& bm);
BookmarkNode(const BookmarkFolder& bmf);
BookmarkNode(const BookmarkNode& other);
~BookmarkNode();
enum BOOKMARKNODE_TYPE {
BMNT_BOOKMARK, BMNT_FOLDER
};
BOOKMARKNODE_TYPE _type;
union {
Bookmark* _pbookmark;
BookmarkFolder* _pfolder;
};
};
struct BookmarkList : public list<BookmarkNode>
{
void import_IE_favorites(struct ShellDirectory& dir, HWND hwnd);
void read(const_XMLPos& pos);
void write(XMLPos& pos) const;
};
struct BookmarkFolder
{
String _name;
String _description;
BookmarkList _bookmarks;
};
struct Favorites : public BookmarkList
{
typedef BookmarkList super;
bool read(LPCTSTR path);
void write(LPCTSTR path) const;
bool import_IE_favorites(HWND hwnd);
};

View file

@ -1616,7 +1616,7 @@ int StartMenuHandler::Command(int id, int code)
break;
case IDC_FAVORITES:
CreateSubmenu(id, CSIDL_FAVORITES, ResString(IDS_FAVORITES));
CreateSubmenu(id, CSIDL_COMMON_FAVORITES, CSIDL_FAVORITES, ResString(IDS_FAVORITES));
break;
case IDC_BROWSE:

View file

@ -259,11 +259,11 @@ void NotifyArea::write_config()
// write notification icon settings to XML configuration file
XMLPos pos = g_Globals.get_cfg();
pos.create("desktopbar");
pos.smart_create("desktopbar");
XMLBoolRef(pos, "options", "show-clock") = _hwndClock!=0;
pos.back();
pos.create("notify-icons");
pos.smart_create("notify-icons");
XMLBoolRef(pos, "options", "hide-inactive") = _hide_inactive;
XMLBoolRef(pos, "options", "show-hidden") = _show_hidden;
@ -272,7 +272,7 @@ void NotifyArea::write_config()
NotifyIconConfig& cfg = *it;
// search for the corresponding node using the original name
pos.create("icon", "name", cfg._name);
pos.smart_create("icon", "name", cfg._name);
// refresh unique name
cfg.create_name();
@ -293,7 +293,7 @@ void NotifyArea::show_clock(bool flag)
if (vis != flag) {
if (flag) {
// create clock window
// smart_create clock window
_hwndClock = ClockWindow::Create(_hwnd);
if (_hwndClock) {

View file

@ -54,6 +54,34 @@ bool XMLPos::go(const char* path)
}
/// read XML stream into XML tree below _pos
XML_Status XMLReader::read(std::istream& in)
{
XML_Status status = XML_STATUS_OK;
while(in.good() && status==XML_STATUS_OK) {
char* buffer = (char*) XML_GetBuffer(_parser, BUFFER_LEN);
in.read(buffer, BUFFER_LEN);
status = XML_ParseBuffer(_parser, in.gcount(), false);
}
if (status != XML_STATUS_ERROR)
status = XML_ParseBuffer(_parser, 0, true);
/*
if (status == XML_STATUS_ERROR)
cerr << get_error_string();
*/
_pos->append_trailing(_content.c_str(), _content.length());
_content.erase();
return status;
}
/// store XML version and encoding into XML reader
void XMLCALL XMLReader::XML_XmlDeclHandler(void* userData, const XML_Char* version, const XML_Char* encoding, int standalone)
{
@ -65,12 +93,31 @@ void XMLCALL XMLReader::XML_XmlDeclHandler(void* userData, const XML_Char* versi
}
}
/// notifications about XML tag start
/// notifications about XML start tag
void XMLCALL XMLReader::XML_StartElementHandler(void* userData, const XML_Char* name, const XML_Char** atts)
{
XMLReader* pThis = (XMLReader*) userData;
XMLNode* node = new XMLNode(String_from_XML_Char(name));
// search for end of first line
const char* s = pThis->_content.c_str();
const char* p = s;
const char* e = p + pThis->_content.length();
for(; p<e; ++p)
if (*p == '\n') {
++p;
break;
}
if (p != s)
pThis->_pos->append_trailing(s, p-s);
std::string leading;
if (p != e)
leading.assign(p, e-p);
XMLNode* node = new XMLNode(String_from_XML_Char(name), leading);
pThis->_pos.add_down(node);
@ -81,17 +128,41 @@ void XMLCALL XMLReader::XML_StartElementHandler(void* userData, const XML_Char*
(*node)[String_from_XML_Char(attr_name)] = String_from_XML_Char(attr_value);
}
pThis->_in_tag = true;
pThis->_in_node = true;
pThis->_content.erase();
}
/// notifications about XML tag end
/// notifications about XML end tag
void XMLCALL XMLReader::XML_EndElementHandler(void* userData, const XML_Char* name)
{
XMLReader* pThis = (XMLReader*) userData;
// search for end of first line
const char* s = pThis->_content.c_str();
const char* p = s;
const char* e = p + pThis->_content.length();
for(; p<e; ++p)
if (*p == '\n') {
++p;
break;
}
if (p != s)
pThis->_pos->append_content(s, p-s);
std::string leading;
if (p != e)
leading.assign(p, e-p);
if (leading.empty())
pThis->_pos->_end_leading = leading;
pThis->_pos.back();
pThis->_in_tag = false;
pThis->_in_node = false;
pThis->_content.erase();
}
/// store content, white space and comments
@ -99,14 +170,11 @@ void XMLCALL XMLReader::XML_DefaultHandler(void* userData, const XML_Char* s, in
{
XMLReader* pThis = (XMLReader*) userData;
if (pThis->_in_tag)
pThis->_pos->append_content(s, len);
else
pThis->_pos->append_trailing(s, len);
pThis->_content.append(s, len);
}
std::string XMLString(LPCTSTR s)
std::string EncodeXMLString(LPCTSTR s)
{
TCHAR buffer[BUFFER_LEN];
LPTSTR o = buffer;
@ -132,22 +200,46 @@ std::string XMLString(LPCTSTR s)
return get_utf8(buffer, o-buffer);
}
String DecodeXMLString(LPCTSTR s)
{
TCHAR buffer[BUFFER_LEN];
LPTSTR o = buffer;
for(LPCTSTR p=s; *p; ++p)
if (*p == '&') {
if (!_tcsnicmp(p+1, TEXT("amp;"), 4)) {
*o++ = '&';
p += 4;
} else if (!_tcsnicmp(p+1, TEXT("lt;"), 3)) {
*o++ = '<';
p += 3;
} else if (!_tcsnicmp(p+1, TEXT("gt;"), 3)) {
*o++ = '>';
p += 3;
} else
*o++ = *p;
} else
*o++ = *p;
return String(buffer, o-buffer);
}
/// write node with children tree to output stream using original white space
void XMLNode::write_worker(std::ostream& out, WRITE_MODE mode, int indent) const
void XMLNode::write_worker(std::ostream& out, int indent) const
{
out << '<' << XMLString(*this);
out << _leading << '<' << EncodeXMLString(*this);
for(AttributeMap::const_iterator it=_attributes.begin(); it!=_attributes.end(); ++it)
out << ' ' << XMLString(it->first) << "=\"" << XMLString(it->second) << "\"";
out << ' ' << EncodeXMLString(it->first) << "=\"" << EncodeXMLString(it->second) << "\"";
if (!_children.empty() || !_content.empty()) {
out << '>' << _content;
for(Children::const_iterator it=_children.begin(); it!=_children.end(); ++it)
(*it)->write_worker(out, mode, indent+1);
(*it)->write_worker(out, indent+1);
out << "</" << XMLString(*this) << '>';
out << _end_leading << "</" << EncodeXMLString(*this) << '>';
} else
out << "/>";
@ -156,81 +248,73 @@ void XMLNode::write_worker(std::ostream& out, WRITE_MODE mode, int indent) const
/// pretty print node with children tree to output stream
void XMLNode::pretty_write_worker(std::ostream& out, WRITE_MODE mode, int indent) const
void XMLNode::pretty_write_worker(std::ostream& out, int indent) const
{
for(int i=indent; i--; )
out << XML_INDENT_SPACE;
out << '<' << XMLString(*this);
out << '<' << EncodeXMLString(*this);
for(AttributeMap::const_iterator it=_attributes.begin(); it!=_attributes.end(); ++it)
out << ' ' << XMLString(it->first) << "=\"" << XMLString(it->second) << "\"";
out << ' ' << EncodeXMLString(it->first) << "=\"" << EncodeXMLString(it->second) << "\"";
if (!_children.empty() || !_content.empty()) {
out << ">\n";
for(Children::const_iterator it=_children.begin(); it!=_children.end(); ++it)
(*it)->pretty_write_worker(out, mode, indent+1);
(*it)->pretty_write_worker(out, indent+1);
for(int i=indent; i--; )
out << XML_INDENT_SPACE;
out << "</" << XMLString(*this) << ">\n";
out << "</" << EncodeXMLString(*this) << ">\n";
} else
out << "/>\n";
}
/// write node with children tree to output stream using smart formating
bool XMLNode::smart_write_worker(std::ostream& out, int indent, bool next_format) const
void XMLNode::smart_write_worker(std::ostream& out, int indent) const
{
bool format_pre, format_mid, format_post;
format_pre = next_format;
format_mid = _content.empty();
format_post = _trailing.empty();
if (format_pre)
if (_leading.empty())
for(int i=indent; i--; )
out << XML_INDENT_SPACE;
else
out << _leading;
out << '<' << XMLString(*this);
out << '<' << EncodeXMLString(*this);
for(AttributeMap::const_iterator it=_attributes.begin(); it!=_attributes.end(); ++it)
out << ' ' << XMLString(it->first) << "=\"" << XMLString(it->second) << "\"";
out << ' ' << EncodeXMLString(it->first) << "=\"" << EncodeXMLString(it->second) << "\"";
if (!_children.empty() || !_content.empty()) {
out << '>';
if (format_mid)
if (_content.empty())
out << '\n';
else
out << _content;
Children::const_iterator it = _children.begin();
if (it != _children.end()) {
next_format = (*it)->_content.empty() && (*it)->_trailing.empty();
if (it != _children.end())
for(; it!=_children.end(); ++it)
next_format = (*it)->smart_write_worker(out, indent+1, next_format);
}
(*it)->smart_write_worker(out, indent+1);
if (next_format)
if (_end_leading.empty())
for(int i=indent; i--; )
out << XML_INDENT_SPACE;
else
out << _end_leading;
out << "</" << XMLString(*this) << '>';
out << "</" << EncodeXMLString(*this) << '>';
} else
out << "/>";
if (format_post)
if (_trailing.empty())
out << '\n';
else
out << _trailing;
return format_post;
}

View file

@ -47,7 +47,7 @@
#include <windows.h> // for LPCTSTR
#ifdef UNICODE
#define _UNICODE
#define _UNICODE
#endif
#include <tchar.h>
@ -202,11 +202,74 @@ inline std::string get_utf8(const String& s)
return get_utf8(s.c_str(), s.length());
}
extern std::string XMLString(LPCTSTR s);
extern std::string EncodeXMLString(LPCTSTR s);
extern String DecodeXMLString(LPCTSTR s);
#ifdef __GNUC__
#include <ext/stdio_filebuf.h>
typedef __gnu_cxx::stdio_filebuf<char> STDIO_FILEBUF;
#else
typedef std::filebuf STDIO_FILEBUF;
#endif
struct tifstream : public std::istream
{
typedef std::istream super;
tifstream(LPCTSTR path)
: super(&_buf),
_pfile(_tfopen(path, TEXT("r"))),
#ifdef __GNUC__
_buf(_pfile, ios::in)
#else
_buf(_pfile)
#endif
{
}
~tifstream()
{
if (_pfile)
fclose(_pfile);
}
protected:
FILE* _pfile;
STDIO_FILEBUF _buf;
};
struct tofstream : public std::ostream
{
typedef std::ostream super;
tofstream(LPCTSTR path)
: super(&_buf),
_pfile(_tfopen(path, TEXT("w"))),
#ifdef __GNUC__
_buf(_pfile, ios::out)
#else
_buf(_pfile)
#endif
{
}
~tofstream()
{
flush();
if (_pfile)
fclose(_pfile);
}
protected:
FILE* _pfile;
STDIO_FILEBUF _buf;
};
// write XML files with 2 spaces indenting
#define XML_INDENT_SPACE " "
#define XML_INDENT_SPACE " "
#ifdef XML_UNICODE // Are XML_Char strings UTF-16 encoded?
@ -279,6 +342,7 @@ struct XMLNode : public String
// access to protected class members for XMLPos and XMLReader
friend struct XMLPos;
friend struct const_XMLPos;
friend struct XMLReader;
XMLNode(const String& name)
@ -286,9 +350,17 @@ struct XMLNode : public String
{
}
XMLNode(const String& name, const std::string& leading)
: String(name),
_leading(leading)
{
}
XMLNode(const XMLNode& other)
: _attributes(other._attributes),
_leading(other._leading),
_content(other._content),
_end_leading(other._end_leading),
_trailing(other._trailing)
{
for(Children::const_iterator it=other._children.begin(); it!=other._children.end(); ++it)
@ -312,7 +384,9 @@ struct XMLNode : public String
_attributes = other._attributes;
_leading = other._leading;
_content = other._content;
_end_leading = other._end_leading;
_trailing = other._trailing;
return *this;
@ -401,10 +475,24 @@ struct XMLNode : public String
return _children;
}
String get_content() const
{
String ret;
assign_utf8(ret, _content.c_str());
return DecodeXMLString(ret);
}
void set_content(const String& s)
{
_content.assign(EncodeXMLString(s));
}
enum WRITE_MODE {
FORMAT_SMART = 0, /// preserve original white space and comments if present; pretty print otherwise
FORMAT_ORIGINAL = 1, /// write XML stream preserving original white space and comments
FORMAT_PRETTY = 2 /// pretty print node to stream without preserving original white space
FORMAT_PRETTY = 2 /// pretty print node to stream without preserving original white space
};
/// write node with children tree to output stream
@ -412,15 +500,15 @@ struct XMLNode : public String
{
switch(mode) {
case FORMAT_PRETTY:
pretty_write_worker(out, mode, indent);
pretty_write_worker(out, indent);
break;
case FORMAT_ORIGINAL:
write_worker(out, mode, indent);
write_worker(out, indent);
break;
default: // FORMAT_SMART
smart_write_worker(out, indent, _content.empty() && _trailing.empty());
smart_write_worker(out, indent);
}
return out;
@ -430,8 +518,10 @@ protected:
Children _children;
AttributeMap _attributes;
std::string _content;
std::string _trailing;
std::string _leading;
std::string _content;
std::string _end_leading;
std::string _trailing;
XMLNode* get_first_child() const
{
@ -488,10 +578,10 @@ protected:
void append_content(const char* s, int l)
{
if (_children.empty())
//if (_children.empty())
_content.append(s, l);
else
_children.back()->_content.append(s, l);
//else
// _children.back()->_content.append(s, l);
}
void append_trailing(const char* s, int l)
@ -502,9 +592,9 @@ protected:
_children.back()->_trailing.append(s, l);
}
void write_worker(std::ostream& out, WRITE_MODE mode, int indent) const;
void pretty_write_worker(std::ostream& out, WRITE_MODE mode, int indent) const;
bool smart_write_worker(std::ostream& out, int indent, bool next_format) const;
void write_worker(std::ostream& out, int indent) const;
void pretty_write_worker(std::ostream& out, int indent) const;
void smart_write_worker(std::ostream& out, int indent) const;
};
@ -606,6 +696,104 @@ protected:
};
/// read only iterator access to children nodes with name filtering
struct const_XMLChildrenFilter
{
const_XMLChildrenFilter(const XMLNode::Children& children, const String& name)
: _begin(children.begin(), children.end(), name),
_end(children.end(), children.end(), name)
{
}
const_XMLChildrenFilter(const XMLNode* node, const String& name)
: _begin(node->get_children().begin(), node->get_children().end(), name),
_end(node->get_children().end(), node->get_children().end(), name)
{
}
struct const_iterator
{
typedef XMLNode::Children::const_iterator BaseIterator;
const_iterator(BaseIterator begin, BaseIterator end, const String& filter_name)
: _cur(begin),
_end(end),
_filter_name(filter_name)
{
search_next();
}
operator BaseIterator()
{
return _cur;
}
const XMLNode* operator*() const
{
return *_cur;
}
XMLNode* operator*()
{
return *_cur;
}
const_iterator& operator++()
{
++_cur;
search_next();
return *this;
}
const_iterator operator++(int)
{
const_iterator ret = *this;
++_cur;
search_next();
return ret;
}
bool operator==(const BaseIterator& other) const
{
return _cur == other;
}
bool operator!=(const BaseIterator& other) const
{
return _cur != other;
}
protected:
BaseIterator _cur;
BaseIterator _end;
String _filter_name;
void search_next()
{
while(_cur!=_end && **_cur!=_filter_name)
++_cur;
}
};
const_iterator begin()
{
return _begin;
}
const_iterator end()
{
return _end;
}
protected:
const_iterator _begin;
const_iterator _end;
};
/// iterator for XML trees
struct XMLPos
{
@ -622,8 +810,8 @@ struct XMLPos
}
/// access to current node
operator XMLNode*() {return _cur;}
operator const XMLNode*() const {return _cur;}
operator XMLNode*() {return _cur;}
const XMLNode* operator->() const {return _cur;}
XMLNode* operator->() {return _cur;}
@ -632,8 +820,8 @@ struct XMLPos
XMLNode& operator*() {return *_cur;}
/// attribute access
String& operator[](const String& attr_name) {return (*_cur)[attr_name];}
template<typename T> String get(const T& attr_name) const {return (*_cur)[attr_name];}
String& operator[](const String& attr_name) {return (*_cur)[attr_name];}
/// insert children when building tree
void add_down(XMLNode* child)
@ -680,8 +868,14 @@ struct XMLPos
/// move X-Path like to position in XML tree
bool go(const char* path);
/// create node if not already existing and move to it
/// create node and move to it
void create(const String& name)
{
add_down(new XMLNode(name));
}
/// create node if not already existing and move to it
void smart_create(const String& name)
{
XMLNode* node = _cur->find_first(name);
@ -692,7 +886,7 @@ struct XMLPos
}
/// search matching child node identified by key name and an attribute value
void create(const String& name, const String& attr_name, const String& attr_value)
void smart_create(const String& name, const String& attr_name, const String& attr_value)
{
XMLNode* node = _cur->find_first(name, attr_name, attr_value);
@ -718,8 +912,14 @@ struct XMLPos
return false;
}
/// create node if not already existing and move to it
/// create node and move to it
void create(const char* name)
{
add_down(new XMLNode(name));
}
/// create node if not already existing and move to it
void smart_create(const char* name)
{
XMLNode* node = _cur->find_first(name);
@ -731,7 +931,7 @@ struct XMLPos
/// search matching child node identified by key name and an attribute value
template<typename T, typename U>
void create(const char* name, const T& attr_name, const U& attr_value)
void smart_create(const char* name, const T& attr_name, const U& attr_value)
{
XMLNode* node = _cur->find_first(name, attr_name, attr_value);
@ -759,6 +959,97 @@ protected:
};
/// iterator for XML trees
struct const_XMLPos
{
const_XMLPos(const XMLNode* root)
: _root(root),
_cur(root)
{
}
const_XMLPos(const const_XMLPos& other)
: _root(other._root),
_cur(other._cur)
{ // don't copy _stack
}
/// access to current node
operator const XMLNode*() const {return _cur;}
const XMLNode* operator->() const {return _cur;}
const XMLNode& operator*() const {return *_cur;}
/// attribute access
template<typename T> String get(const T& attr_name) const {return _cur->get(attr_name);}
/// go back to previous position
bool back()
{
if (!_stack.empty()) {
_cur = _stack.top();
_stack.pop();
return true;
} else
return false;
}
/// go down to first child
bool go_down()
{
const XMLNode* node = _cur->get_first_child();
if (node) {
go_to(node);
return true;
} else
return false;
}
/// search for child and go down
bool go_down(const String& name)
{
XMLNode* node = _cur->find_first(name);
if (node) {
go_to(node);
return true;
} else
return false;
}
/// move X-Path like to position in XML tree
bool go(const char* path);
#ifdef UNICODE
/// search for child and go down
bool go_down(const char* name)
{
XMLNode* node = _cur->find_first(name);
if (node) {
go_to(node);
return true;
} else
return false;
}
#endif
protected:
const XMLNode* _root;
const XMLNode* _cur;
std::stack<const XMLNode*> _stack;
/// go to specified node
void go_to(const XMLNode* child)
{
_stack.push(_cur);
_cur = child;
}
};
struct XMLBool
{
XMLBool(bool value)
@ -789,6 +1080,11 @@ struct XMLBool
return _value;
}
bool operator!() const
{
return !_value;
}
operator LPCTSTR() const
{
return _value? TEXT("TRUE"): TEXT("FALSE");
@ -798,7 +1094,7 @@ protected:
bool _value;
private:
void operator=(const XMLBool&); // disallow assignment operations
void operator=(const XMLBool&); // disallow assignment operations
};
struct XMLBoolRef
@ -815,6 +1111,11 @@ struct XMLBoolRef
return !_tcsicmp(_ref, TEXT("TRUE"));
}
bool operator!() const
{
return _tcsicmp(_ref, TEXT("TRUE"))? true: false;
}
XMLBoolRef& operator=(bool value)
{
assign(value);
@ -833,7 +1134,7 @@ struct XMLBoolRef
}
protected:
String& _ref;
String& _ref;
};
@ -875,10 +1176,10 @@ struct XMLNumber
}
protected:
int _value;
int _value;
private:
void operator=(const XMLBool&); // disallow assignment operations
void operator=(const XMLBool&); // disallow assignment operations
};
struct XMLNumberRef
@ -911,7 +1212,7 @@ struct XMLNumberRef
}
protected:
String& _ref;
String& _ref;
};
@ -931,7 +1232,7 @@ struct XMLReader
XML_SetElementHandler(_parser, XML_StartElementHandler, XML_EndElementHandler);
XML_SetDefaultHandler(_parser, XML_DefaultHandler);
_in_tag = false;
_in_node = false;
}
~XMLReader()
@ -939,28 +1240,7 @@ struct XMLReader
XML_ParserFree(_parser);
}
XML_Status read(std::istream& in)
{
XML_Status status = XML_STATUS_OK;
while(in.good() && status==XML_STATUS_OK) {
char* buffer = (char*) XML_GetBuffer(_parser, BUFFER_LEN);
in.read(buffer, BUFFER_LEN);
status = XML_ParseBuffer(_parser, in.gcount(), false);
}
if (status != XML_STATUS_ERROR)
status = XML_ParseBuffer(_parser, 0, true);
/*
if (status == XML_STATUS_ERROR)
cerr << path << get_error_string();
*/
return status;
}
XML_Status read(std::istream& in);
std::string get_position() const
{
@ -986,9 +1266,11 @@ struct XMLReader
protected:
XMLPos _pos;
XML_Parser _parser;
std::string _xml_version;
std::string _encoding;
bool _in_tag;
std::string _xml_version;
std::string _encoding;
std::string _content;
bool _in_node;
static void XMLCALL XML_XmlDeclHandler(void* userData, const XML_Char* version, const XML_Char* encoding, int standalone);
static void XMLCALL XML_StartElementHandler(void* userData, const XML_Char* name, const XML_Char** atts);
@ -997,6 +1279,29 @@ protected:
};
struct XMLHeader : public std::string
{
XMLHeader(const std::string& xml_version="1.0", const std::string& encoding="UTF-8", const std::string& doctype="")
: _version(xml_version),
_encoding(encoding),
_doctype(doctype)
{
}
void print(std::ostream& out) const
{
out << "<?xml version=\"" << _version << "\" encoding=\"" << _encoding << "\"?>\n";
if (!_doctype.empty())
out << _doctype << '\n';
}
std::string _version;
std::string _encoding;
std::string _doctype;
};
struct XMLDoc : public XMLNode
{
XMLDoc()
@ -1004,7 +1309,7 @@ struct XMLDoc : public XMLNode
{
}
XMLDoc(const std::string& path)
XMLDoc(LPCTSTR path)
: XMLNode("")
{
read(path);
@ -1012,23 +1317,33 @@ struct XMLDoc : public XMLNode
std::istream& read(std::istream& in)
{
XMLReader(this).read(in);
XMLReader reader(this);
/*XML_Status status = */reader.read(in);
/*
if (status == XML_STATUS_ERROR)
cerr << reader.get_error_string();
*/
return in;
}
bool read(const std::string& path)
bool read(LPCTSTR path)
{
std::ifstream in(path.c_str());
tifstream in(path);
XMLReader reader(this);
return XMLReader(this).read(in) != XML_STATUS_ERROR;
XML_Status status = reader.read(in);
/*
if (status == XML_STATUS_ERROR)
cerr << path << reader.get_error_string();
*/
return status != XML_STATUS_ERROR;
}
/// write XML stream preserving previous white space and comments
std::ostream& write(std::ostream& out, WRITE_MODE mode=FORMAT_SMART,
const std::string& xml_version="1.0", const std::string& encoding="UTF-8") const
std::ostream& write(std::ostream& out, WRITE_MODE mode=FORMAT_SMART, const XMLHeader& header=XMLHeader()) const
{
out << "<?xml version=\"" << xml_version << "\" encoding=\"" << encoding << "\"?>\n";
header.print(out);
if (!_children.empty())
_children.front()->write(out);
@ -1042,17 +1357,16 @@ struct XMLDoc : public XMLNode
return write(out, FORMAT_PRETTY);
}
void write(const std::string& path, WRITE_MODE mode=FORMAT_SMART,
const std::string& xml_version="1.0", const std::string& encoding="UTF-8") const
void write(LPCTSTR path, WRITE_MODE mode=FORMAT_SMART, const XMLHeader& header=XMLHeader()) const
{
std::ofstream out(path.c_str());
tofstream out(path);
write(out, mode, xml_version, encoding);
write(out, mode, header);
}
void write_formating(const std::string& path) const
void write_formating(LPCTSTR path) const
{
std::ofstream out(path.c_str());
tofstream out(path);
write_formating(out);
}