From 7610d4361ce279f498ccb4f4a2f424758efc1016 Mon Sep 17 00:00:00 2001 From: Ykkrosh Date: Sun, 22 Mar 2009 20:51:35 +0000 Subject: [PATCH] # Started using libxml2 This was SVN commit r6763. --- build/premake/premake.lua | 6 + source/tools/atlas/AtlasObject/AtlasObject.h | 6 +- .../atlas/AtlasObject/AtlasObjectXML.cpp | 146 +++++++++--------- .../CustomControls/Windows/AtlasWindow.cpp | 7 +- .../tools/atlas/AtlasUI/Misc/DLLInterface.cpp | 18 ++- 5 files changed, 105 insertions(+), 78 deletions(-) diff --git a/build/premake/premake.lua b/build/premake/premake.lua index 28166e6e80..b7f819d9d6 100755 --- a/build/premake/premake.lua +++ b/build/premake/premake.lua @@ -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", diff --git a/source/tools/atlas/AtlasObject/AtlasObject.h b/source/tools/atlas/AtlasObject/AtlasObject.h index 755ad14df2..a256c2c639 100644 --- a/source/tools/atlas/AtlasObject/AtlasObject.h +++ b/source/tools/atlas/AtlasObject/AtlasObject.h @@ -8,6 +8,7 @@ #define INCLUDED_ATLASOBJECT #include // for wchar_t +#include ////////////////////////////////////////////////////////////////////////// // 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); } diff --git a/source/tools/atlas/AtlasObject/AtlasObjectXML.cpp b/source/tools/atlas/AtlasObject/AtlasObjectXML.cpp index 20cfd95096..23804f9dbd 100644 --- a/source/tools/atlas/AtlasObject/AtlasObjectXML.cpp +++ b/source/tools/atlas/AtlasObject/AtlasObjectXML.cpp @@ -4,6 +4,7 @@ #include #include +#include #ifdef _MSC_VER # ifndef NDEBUG @@ -27,6 +28,8 @@ #include #include +#include + 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 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(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(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 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(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; } diff --git a/source/tools/atlas/AtlasUI/CustomControls/Windows/AtlasWindow.cpp b/source/tools/atlas/AtlasUI/CustomControls/Windows/AtlasWindow.cpp index 9b78d95d17..a7b52eecb7 100644 --- a/source/tools/atlas/AtlasUI/CustomControls/Windows/AtlasWindow.cpp +++ b/source/tools/atlas/AtlasUI/CustomControls/Windows/AtlasWindow.cpp @@ -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(); diff --git a/source/tools/atlas/AtlasUI/Misc/DLLInterface.cpp b/source/tools/atlas/AtlasUI/Misc/DLLInterface.cpp index 4f9f233701..705516392d 100644 --- a/source/tools/atlas/AtlasUI/Misc/DLLInterface.cpp +++ b/source/tools/atlas/AtlasUI/Misc/DLLInterface.cpp @@ -22,6 +22,12 @@ #include "wx/debugrpt.h" #include "wx/file.h" +#include + +#ifndef LIBXML_THREAD_ENABLED +#error libxml2 must have threading support enabled +#endif + #ifdef __WXGTK__ #include #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 }