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");
|
||||
end
|
||||
|
||||
if options["aoe3ed"] then
|
||||
tinsert(package.defines, "USE_AOE3ED")
|
||||
end
|
||||
|
||||
-- Platform Specifics
|
||||
if OS == "windows" then
|
||||
|
||||
@ -638,6 +642,7 @@ function setup_atlas_packages()
|
||||
""
|
||||
},{ -- include
|
||||
},{ -- extern_libs
|
||||
"libxml2",
|
||||
"xerces",
|
||||
"wxwidgets"
|
||||
},{ -- extra_params
|
||||
@ -723,6 +728,7 @@ function setup_atlas_packages()
|
||||
"boost",
|
||||
"devil",
|
||||
--"ffmpeg", -- disabled for now because it causes too many build difficulties
|
||||
"libxml2",
|
||||
"spidermonkey",
|
||||
"wxwidgets",
|
||||
"xerces",
|
||||
|
@ -8,6 +8,7 @@
|
||||
#define INCLUDED_ATLASOBJECT
|
||||
|
||||
#include <wchar.h> // for wchar_t
|
||||
#include <string>
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Mostly-private bits:
|
||||
@ -142,8 +143,9 @@ namespace AtlasObject
|
||||
// Returns AtObj() on failure - test with AtObj::defined()
|
||||
AtObj LoadFromXML(const wchar_t* filename);
|
||||
|
||||
// Returns false on failure
|
||||
bool SaveToXML(AtObj& obj, const wchar_t* filename);
|
||||
// Returns UTF-8-encoded XML document string.
|
||||
// Returns empty string on failure.
|
||||
std::string SaveToXML(AtObj& obj);
|
||||
|
||||
AtObj TrimEmptyChildren(AtObj& obj);
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <assert.h>
|
||||
|
||||
#include <memory>
|
||||
#include <fstream>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# ifndef NDEBUG
|
||||
@ -27,6 +28,8 @@
|
||||
#include <xercesc/sax/SAXParseException.hpp>
|
||||
#include <xercesc/sax/ErrorHandler.hpp>
|
||||
|
||||
#include <libxml/parser.h>
|
||||
|
||||
XERCES_CPP_NAMESPACE_USE
|
||||
|
||||
class XercesInitialiser
|
||||
@ -96,6 +99,45 @@ private:
|
||||
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
|
||||
// a file) with some proper logging/reporting system
|
||||
|
||||
@ -219,106 +261,64 @@ static AtSmartPtr<AtNode> ConvertNode(DOMElement* element)
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
||||
// 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->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)
|
||||
{
|
||||
// Test for attribute nodes (whose names start with @)
|
||||
if (it->first.length() && it->first[0] == '@')
|
||||
{
|
||||
XMLString::transcode(it->first.c_str()+1, tempStr, 255);
|
||||
node->setAttributeNode(BuildDOMAttr(doc, tempStr, it->second));
|
||||
assert(it->second);
|
||||
assert(it->second->children.empty());
|
||||
xmlNewProp(node, (const xmlChar*)it->first.c_str()+1, toXmlChar(it->second->value));
|
||||
}
|
||||
else
|
||||
{
|
||||
XMLString::transcode(it->first.c_str(), tempStr, 255);
|
||||
node->appendChild(BuildDOMNode(doc, tempStr, it->second));
|
||||
if (node == NULL) // first node in the document - needs to be made the root node
|
||||
{
|
||||
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)
|
||||
{
|
||||
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);
|
||||
|
||||
try
|
||||
{
|
||||
std::auto_ptr<DOMDocument> doc (impl->createDocument());
|
||||
doc->appendChild(BuildDOMNode(doc.get(), rootName, firstChild));
|
||||
xmlDocPtr doc = xmlNewDoc((const xmlChar*)"1.0");
|
||||
BuildDOMNode(doc, NULL, obj.p);
|
||||
|
||||
LocalFileFormatTarget formatTarget (StrConv<XMLCh>(filename).c_str());
|
||||
writer->writeNode(&formatTarget, *doc);
|
||||
}
|
||||
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;
|
||||
}
|
||||
xmlChar* buf;
|
||||
int size;
|
||||
xmlDocDumpFormatMemoryEnc(doc, &buf, &size, "utf-8", 1);
|
||||
|
||||
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());
|
||||
// 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();
|
||||
|
||||
|
@ -22,6 +22,12 @@
|
||||
#include "wx/debugrpt.h"
|
||||
#include "wx/file.h"
|
||||
|
||||
#include <libxml/parser.h>
|
||||
|
||||
#ifndef LIBXML_THREAD_ENABLED
|
||||
#error libxml2 must have threading support enabled
|
||||
#endif
|
||||
|
||||
#ifdef __WXGTK__
|
||||
#include <X11/Xlib.h>
|
||||
#endif
|
||||
@ -85,6 +91,10 @@ ATLASDLLIMPEXP void Atlas_SetMessagePasser(MessagePasser* passer)
|
||||
|
||||
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;
|
||||
#ifdef __WXMSW__
|
||||
wxEntry(g_Module);
|
||||
@ -99,7 +109,8 @@ ATLASDLLIMPEXP void Atlas_StartWindow(const wchar_t* type)
|
||||
}
|
||||
#endif
|
||||
int argc = 1;
|
||||
char *argv[] = {"atlas", NULL};
|
||||
char atlas[] = "atlas";
|
||||
char *argv[] = {atlas, NULL};
|
||||
wxEntry(argc, argv);
|
||||
#endif
|
||||
}
|
||||
@ -161,9 +172,11 @@ public:
|
||||
#define MAYBE(t) if (g_InitialWindowType == _T(#t)) frame = new t(NULL); else
|
||||
MAYBE(ActorEditor)
|
||||
MAYBE(ActorViewer)
|
||||
MAYBE(ArchiveViewer)
|
||||
MAYBE(ColourTester)
|
||||
#ifdef USE_AOE3ED
|
||||
MAYBE(ArchiveViewer)
|
||||
MAYBE(FileConverter)
|
||||
#endif
|
||||
#undef MAYBE
|
||||
// else
|
||||
if (g_InitialWindowType == _T("ScenarioEditor"))
|
||||
@ -278,6 +291,7 @@ private:
|
||||
#else
|
||||
// Figure out what goes for "default browser" on unix/linux/whatever
|
||||
// open an xterm perhaps? :)
|
||||
(void)dir;
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user