forked from 0ad/0ad
# Started using libxml2
This was SVN commit r6763.
This commit is contained in:
parent
6768858cf1
commit
7610d4361c
@ -601,6 +601,10 @@ function setup_atlas_package(package_name, target_type, rel_source_dirs, rel_inc
|
|||||||
package_setup_pch(nil, "precompiled.h", "precompiled.cpp");
|
package_setup_pch(nil, "precompiled.h", "precompiled.cpp");
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if options["aoe3ed"] then
|
||||||
|
tinsert(package.defines, "USE_AOE3ED")
|
||||||
|
end
|
||||||
|
|
||||||
-- Platform Specifics
|
-- Platform Specifics
|
||||||
if OS == "windows" then
|
if OS == "windows" then
|
||||||
|
|
||||||
@ -638,6 +642,7 @@ function setup_atlas_packages()
|
|||||||
""
|
""
|
||||||
},{ -- include
|
},{ -- include
|
||||||
},{ -- extern_libs
|
},{ -- extern_libs
|
||||||
|
"libxml2",
|
||||||
"xerces",
|
"xerces",
|
||||||
"wxwidgets"
|
"wxwidgets"
|
||||||
},{ -- extra_params
|
},{ -- extra_params
|
||||||
@ -723,6 +728,7 @@ function setup_atlas_packages()
|
|||||||
"boost",
|
"boost",
|
||||||
"devil",
|
"devil",
|
||||||
--"ffmpeg", -- disabled for now because it causes too many build difficulties
|
--"ffmpeg", -- disabled for now because it causes too many build difficulties
|
||||||
|
"libxml2",
|
||||||
"spidermonkey",
|
"spidermonkey",
|
||||||
"wxwidgets",
|
"wxwidgets",
|
||||||
"xerces",
|
"xerces",
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#define INCLUDED_ATLASOBJECT
|
#define INCLUDED_ATLASOBJECT
|
||||||
|
|
||||||
#include <wchar.h> // for wchar_t
|
#include <wchar.h> // for wchar_t
|
||||||
|
#include <string>
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
// Mostly-private bits:
|
// Mostly-private bits:
|
||||||
@ -142,8 +143,9 @@ namespace AtlasObject
|
|||||||
// Returns AtObj() on failure - test with AtObj::defined()
|
// Returns AtObj() on failure - test with AtObj::defined()
|
||||||
AtObj LoadFromXML(const wchar_t* filename);
|
AtObj LoadFromXML(const wchar_t* filename);
|
||||||
|
|
||||||
// Returns false on failure
|
// Returns UTF-8-encoded XML document string.
|
||||||
bool SaveToXML(AtObj& obj, const wchar_t* filename);
|
// Returns empty string on failure.
|
||||||
|
std::string SaveToXML(AtObj& obj);
|
||||||
|
|
||||||
AtObj TrimEmptyChildren(AtObj& obj);
|
AtObj TrimEmptyChildren(AtObj& obj);
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
# ifndef NDEBUG
|
# ifndef NDEBUG
|
||||||
@ -27,6 +28,8 @@
|
|||||||
#include <xercesc/sax/SAXParseException.hpp>
|
#include <xercesc/sax/SAXParseException.hpp>
|
||||||
#include <xercesc/sax/ErrorHandler.hpp>
|
#include <xercesc/sax/ErrorHandler.hpp>
|
||||||
|
|
||||||
|
#include <libxml/parser.h>
|
||||||
|
|
||||||
XERCES_CPP_NAMESPACE_USE
|
XERCES_CPP_NAMESPACE_USE
|
||||||
|
|
||||||
class XercesInitialiser
|
class XercesInitialiser
|
||||||
@ -96,6 +99,45 @@ private:
|
|||||||
T* data;
|
T* data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// UTF conversion code adapted from http://www.unicode.org/Public/PROGRAMS/CVTUTF/ConvertUTF.c
|
||||||
|
static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
|
||||||
|
class toXmlChar
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
toXmlChar(const std::wstring& str)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < str.length(); ++i)
|
||||||
|
{
|
||||||
|
unsigned short bytesToWrite;
|
||||||
|
wchar_t ch = str[i];
|
||||||
|
|
||||||
|
if (ch < 0x80) bytesToWrite = 1;
|
||||||
|
else if (ch < 0x800) bytesToWrite = 2;
|
||||||
|
else if (ch < 0x10000) bytesToWrite = 3;
|
||||||
|
else if (ch < 0x110000) bytesToWrite = 4;
|
||||||
|
else bytesToWrite = 3, ch = 0xFFFD; // replacement character
|
||||||
|
|
||||||
|
char buf[4];
|
||||||
|
char* target = &buf[bytesToWrite];
|
||||||
|
switch (bytesToWrite)
|
||||||
|
{
|
||||||
|
case 4: *--target = ((ch | 0x80) & 0xBF); ch >>= 6;
|
||||||
|
case 3: *--target = ((ch | 0x80) & 0xBF); ch >>= 6;
|
||||||
|
case 2: *--target = ((ch | 0x80) & 0xBF); ch >>= 6;
|
||||||
|
case 1: *--target = (ch | firstByteMark[bytesToWrite]);
|
||||||
|
}
|
||||||
|
data += std::string(buf, bytesToWrite);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
operator const xmlChar*()
|
||||||
|
{
|
||||||
|
return (const xmlChar*)data.c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string data;
|
||||||
|
};
|
||||||
|
|
||||||
// TODO: replace most of the asserts below (e.g. for when it fails to load
|
// TODO: replace most of the asserts below (e.g. for when it fails to load
|
||||||
// a file) with some proper logging/reporting system
|
// a file) with some proper logging/reporting system
|
||||||
|
|
||||||
@ -219,106 +261,64 @@ static AtSmartPtr<AtNode> ConvertNode(DOMElement* element)
|
|||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Build a DOM node from a given AtNode
|
// Build a DOM node from a given AtNode
|
||||||
static DOMAttr* BuildDOMAttr(DOMDocument* doc, const XMLCh* name, AtNode::Ptr p)
|
static void BuildDOMNode(xmlDocPtr doc, xmlNodePtr node, AtNode::Ptr p)
|
||||||
{
|
{
|
||||||
assert(p); // attributes must contain some data
|
|
||||||
assert(p->children.size() == 0); // attributes mustn't contain nested data
|
|
||||||
|
|
||||||
if (!p || p->children.size() != 0)
|
|
||||||
{
|
|
||||||
// Oops - invalid data
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
DOMAttr* attr = doc->createAttribute(name);
|
|
||||||
|
|
||||||
attr->setValue(StrConv<XMLCh>(p->value).c_str());
|
|
||||||
|
|
||||||
return attr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Build a DOM node from a given AtNode
|
|
||||||
static DOMNode* BuildDOMNode(DOMDocument* doc, const XMLCh* name, AtNode::Ptr p)
|
|
||||||
{
|
|
||||||
DOMElement* node = doc->createElement(name);
|
|
||||||
|
|
||||||
if (p)
|
if (p)
|
||||||
{
|
{
|
||||||
if (p->value.length())
|
if (p->value.length())
|
||||||
node->setTextContent(StrConv<XMLCh>(p->value).c_str());
|
xmlNodeAddContent(node, toXmlChar(p->value));
|
||||||
|
|
||||||
XMLCh tempStr[256]; // urgh, nasty fixed-size buffer
|
|
||||||
for (AtNode::child_maptype::const_iterator it = p->children.begin(); it != p->children.end(); ++it)
|
for (AtNode::child_maptype::const_iterator it = p->children.begin(); it != p->children.end(); ++it)
|
||||||
{
|
{
|
||||||
// Test for attribute nodes (whose names start with @)
|
// Test for attribute nodes (whose names start with @)
|
||||||
if (it->first.length() && it->first[0] == '@')
|
if (it->first.length() && it->first[0] == '@')
|
||||||
{
|
{
|
||||||
XMLString::transcode(it->first.c_str()+1, tempStr, 255);
|
assert(it->second);
|
||||||
node->setAttributeNode(BuildDOMAttr(doc, tempStr, it->second));
|
assert(it->second->children.empty());
|
||||||
|
xmlNewProp(node, (const xmlChar*)it->first.c_str()+1, toXmlChar(it->second->value));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
XMLString::transcode(it->first.c_str(), tempStr, 255);
|
if (node == NULL) // first node in the document - needs to be made the root node
|
||||||
node->appendChild(BuildDOMNode(doc, tempStr, it->second));
|
{
|
||||||
|
xmlNodePtr root = xmlNewNode(NULL, (const xmlChar*)it->first.c_str());
|
||||||
|
xmlDocSetRootElement(doc, root);
|
||||||
|
BuildDOMNode(doc, root, it->second);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
xmlNodePtr child = xmlNewChild(node, NULL, (const xmlChar*)it->first.c_str(), NULL);
|
||||||
|
BuildDOMNode(doc, child, it->second);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return node;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AtlasObject::SaveToXML(AtObj& obj, const wchar_t* filename)
|
std::string AtlasObject::SaveToXML(AtObj& obj)
|
||||||
{
|
{
|
||||||
XercesInitialiser::enable();
|
|
||||||
|
|
||||||
// Why does it take so much work just to create a standard DOMWriter? :-(
|
|
||||||
XMLCh domFeatures[100] = { 0 };
|
|
||||||
XMLString::transcode("LS", domFeatures, 99); // maybe "LS" means "load/save", but I really don't know
|
|
||||||
DOMImplementation* impl = DOMImplementationRegistry::getDOMImplementation(domFeatures);
|
|
||||||
DOMWriter* writer = ((DOMImplementationLS*)impl)->createDOMWriter();
|
|
||||||
|
|
||||||
if (writer->canSetFeature(XMLUni::fgDOMWRTDiscardDefaultContent, true))
|
|
||||||
writer->setFeature(XMLUni::fgDOMWRTDiscardDefaultContent, true);
|
|
||||||
|
|
||||||
if (writer->canSetFeature(XMLUni::fgDOMWRTFormatPrettyPrint, true))
|
|
||||||
writer->setFeature(XMLUni::fgDOMWRTFormatPrettyPrint, true);
|
|
||||||
|
|
||||||
|
|
||||||
// Find the root element of the object:
|
|
||||||
|
|
||||||
if (!obj.p || obj.p->children.size() != 1)
|
if (!obj.p || obj.p->children.size() != 1)
|
||||||
{
|
{
|
||||||
assert(! "SaveToXML: root must only have one child");
|
assert(! "SaveToXML: root must only have one child");
|
||||||
return false;
|
return "";
|
||||||
}
|
}
|
||||||
XMLCh rootName[255];
|
|
||||||
XMLString::transcode(obj.p->children.begin()->first.c_str(), rootName, 255);
|
|
||||||
AtNode::Ptr firstChild (obj.p->children.begin()->second);
|
AtNode::Ptr firstChild (obj.p->children.begin()->second);
|
||||||
|
|
||||||
try
|
xmlDocPtr doc = xmlNewDoc((const xmlChar*)"1.0");
|
||||||
{
|
BuildDOMNode(doc, NULL, obj.p);
|
||||||
std::auto_ptr<DOMDocument> doc (impl->createDocument());
|
|
||||||
doc->appendChild(BuildDOMNode(doc.get(), rootName, firstChild));
|
|
||||||
|
|
||||||
LocalFileFormatTarget formatTarget (StrConv<XMLCh>(filename).c_str());
|
xmlChar* buf;
|
||||||
writer->writeNode(&formatTarget, *doc);
|
int size;
|
||||||
}
|
xmlDocDumpFormatMemoryEnc(doc, &buf, &size, "utf-8", 1);
|
||||||
catch (const XMLException& e) {
|
|
||||||
char* message = XMLString::transcode(e.getMessage());
|
|
||||||
assert(! "XML exception - maybe failed while writing the file");
|
|
||||||
XMLString::release(&message);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
catch (const DOMException& e) {
|
|
||||||
char* message = XMLString::transcode(e.msg);
|
|
||||||
assert(! "DOM exception");
|
|
||||||
XMLString::release(&message);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
writer->release();
|
std::string ret((const char*)buf, size);
|
||||||
|
|
||||||
return true;
|
xmlFree(buf);
|
||||||
|
xmlFreeDoc(doc);
|
||||||
|
|
||||||
|
// TODO: handle errors better
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -263,7 +263,12 @@ bool AtlasWindow::SaveChanges(bool forceSaveAs)
|
|||||||
AtObj file (ExportData());
|
AtObj file (ExportData());
|
||||||
// TODO: Make sure it succeeded. Back up .xml file in case it didn't.
|
// TODO: Make sure it succeeded. Back up .xml file in case it didn't.
|
||||||
|
|
||||||
AtlasObject::SaveToXML(file, GetCurrentFilename().GetFullPath());
|
std::string xml = AtlasObject::SaveToXML(file);
|
||||||
|
wxCHECK(!xml.empty(), false);
|
||||||
|
|
||||||
|
wxFile outfile (GetCurrentFilename().GetFullPath(), wxFile::write);
|
||||||
|
outfile.Write(xml.c_str(), xml.length());
|
||||||
|
outfile.Close();
|
||||||
|
|
||||||
sig_FileSaved();
|
sig_FileSaved();
|
||||||
|
|
||||||
|
@ -22,6 +22,12 @@
|
|||||||
#include "wx/debugrpt.h"
|
#include "wx/debugrpt.h"
|
||||||
#include "wx/file.h"
|
#include "wx/file.h"
|
||||||
|
|
||||||
|
#include <libxml/parser.h>
|
||||||
|
|
||||||
|
#ifndef LIBXML_THREAD_ENABLED
|
||||||
|
#error libxml2 must have threading support enabled
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef __WXGTK__
|
#ifdef __WXGTK__
|
||||||
#include <X11/Xlib.h>
|
#include <X11/Xlib.h>
|
||||||
#endif
|
#endif
|
||||||
@ -85,6 +91,10 @@ ATLASDLLIMPEXP void Atlas_SetMessagePasser(MessagePasser* passer)
|
|||||||
|
|
||||||
ATLASDLLIMPEXP void Atlas_StartWindow(const wchar_t* type)
|
ATLASDLLIMPEXP void Atlas_StartWindow(const wchar_t* type)
|
||||||
{
|
{
|
||||||
|
// Initialise libxml2
|
||||||
|
// (If we're executed from the game instead, it has the responsibility to initialise libxml2)
|
||||||
|
xmlInitParser();
|
||||||
|
|
||||||
g_InitialWindowType = type;
|
g_InitialWindowType = type;
|
||||||
#ifdef __WXMSW__
|
#ifdef __WXMSW__
|
||||||
wxEntry(g_Module);
|
wxEntry(g_Module);
|
||||||
@ -99,7 +109,8 @@ ATLASDLLIMPEXP void Atlas_StartWindow(const wchar_t* type)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
int argc = 1;
|
int argc = 1;
|
||||||
char *argv[] = {"atlas", NULL};
|
char atlas[] = "atlas";
|
||||||
|
char *argv[] = {atlas, NULL};
|
||||||
wxEntry(argc, argv);
|
wxEntry(argc, argv);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@ -161,9 +172,11 @@ public:
|
|||||||
#define MAYBE(t) if (g_InitialWindowType == _T(#t)) frame = new t(NULL); else
|
#define MAYBE(t) if (g_InitialWindowType == _T(#t)) frame = new t(NULL); else
|
||||||
MAYBE(ActorEditor)
|
MAYBE(ActorEditor)
|
||||||
MAYBE(ActorViewer)
|
MAYBE(ActorViewer)
|
||||||
MAYBE(ArchiveViewer)
|
|
||||||
MAYBE(ColourTester)
|
MAYBE(ColourTester)
|
||||||
|
#ifdef USE_AOE3ED
|
||||||
|
MAYBE(ArchiveViewer)
|
||||||
MAYBE(FileConverter)
|
MAYBE(FileConverter)
|
||||||
|
#endif
|
||||||
#undef MAYBE
|
#undef MAYBE
|
||||||
// else
|
// else
|
||||||
if (g_InitialWindowType == _T("ScenarioEditor"))
|
if (g_InitialWindowType == _T("ScenarioEditor"))
|
||||||
@ -278,6 +291,7 @@ private:
|
|||||||
#else
|
#else
|
||||||
// Figure out what goes for "default browser" on unix/linux/whatever
|
// Figure out what goes for "default browser" on unix/linux/whatever
|
||||||
// open an xterm perhaps? :)
|
// open an xterm perhaps? :)
|
||||||
|
(void)dir;
|
||||||
return false;
|
return false;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user