-/*\r
-Copyright (C) 2006, Stefan Greven.\r
-All Rights Reserved.\r
-\r
-This file is part of GtkRadiant.\r
-\r
-GtkRadiant is free software; you can redistribute it and/or modify\r
-it under the terms of the GNU General Public License as published by\r
-the Free Software Foundation; either version 2 of the License, or\r
-(at your option) any later version.\r
-\r
-GtkRadiant is distributed in the hope that it will be useful,\r
-but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
-GNU General Public License for more details.\r
-\r
-You should have received a copy of the GNU General Public License\r
-along with GtkRadiant; if not, write to the Free Software\r
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\r
-*/\r
-\r
-#include "xmltextags.h"\r
-\r
-#include <string>\r
-\r
-#include "qerplugin.h"\r
-#include "stream/stringstream.h"\r
-\r
-XmlTagBuilder::XmlTagBuilder()\r
-{\r
-}\r
-\r
-XmlTagBuilder::~XmlTagBuilder()\r
-{\r
- // clean up\r
- xmlFreeDoc(doc);\r
- xmlXPathFreeContext(context);\r
-}\r
-\r
-bool XmlTagBuilder::CreateXmlDocument()\r
-{\r
- /* Creates an XML file\r
-\r
- returns TRUE if the file was created successfully or FALSE when failed\r
- */\r
-\r
- xmlTextWriterPtr writer;\r
-\r
- writer = xmlNewTextWriterDoc(&doc, 0);\r
-\r
- // begin a new UTF-8 formatted xml document\r
- xmlTextWriterStartDocument(writer, NULL, "UTF-8", NULL);\r
-\r
- // create the root node with stock and custom elements\r
- xmlTextWriterStartElement(writer, (xmlChar*)"root");\r
- xmlTextWriterWriteString(writer, (xmlChar*)"\n ");\r
- xmlTextWriterStartElement(writer, (xmlChar*)"stock");\r
- xmlTextWriterWriteString(writer, (xmlChar*)"\n ");\r
- xmlTextWriterEndElement(writer);\r
- xmlTextWriterWriteString(writer, (xmlChar*)"\n ");\r
- xmlTextWriterStartElement(writer, (xmlChar*)"custom");\r
- xmlTextWriterWriteString(writer, (xmlChar*)"\n ");\r
- xmlTextWriterEndElement(writer);\r
- xmlTextWriterWriteString(writer, (xmlChar*)"\n");\r
- xmlTextWriterEndElement(writer);\r
-\r
- // end of the xml document\r
- xmlTextWriterEndDocument(writer);\r
- xmlFreeTextWriter(writer);\r
-\r
- if(!doc)\r
- {\r
- return false;\r
- } else {\r
- context = xmlXPathNewContext(doc);\r
- return true;\r
- }\r
-}\r
-\r
-bool XmlTagBuilder::OpenXmlDoc(const char* file, const char* savefile)\r
-{\r
- /* Reads a XML document from a file\r
-\r
- returns TRUE if the document was read successfully or FALSE when failed\r
- */\r
-\r
- if(savefile)\r
- m_savefilename = savefile;\r
- else\r
- m_savefilename = file;\r
- \r
- doc = xmlParseFile(file); // TODO error checking!\r
-\r
- if(!doc)\r
- {\r
- return false;\r
- } else {\r
- context = xmlXPathNewContext(doc);\r
- return true;\r
- }\r
-}\r
-\r
-bool XmlTagBuilder::SaveXmlDoc(void)\r
-{\r
- return SaveXmlDoc(m_savefilename.c_str());\r
-}\r
-\r
-bool XmlTagBuilder::SaveXmlDoc(const char* file)\r
-{\r
- /* Writes the XML document\r
-\r
- returns TRUE if the document was saved successfully or FALSE when saving failed\r
- */\r
- \r
- xmlSaveNoEmptyTags = 1;\r
-\r
- if(xmlSaveFile(file, doc) != -1)\r
- {\r
- return true;\r
- }\r
- return false;\r
-}\r
-\r
-bool XmlTagBuilder::AddShaderNode(const char* shader, TextureType textureType, NodeShaderType nodeShaderType)\r
-{\r
- /* Adds a shader node\r
-\r
- char* shader - the name of the shader or texture (without trailing .tga or something)\r
-\r
- returns TRUE if the node was added successfully or FALSE when failed\r
- */\r
-\r
- xmlNodeSetPtr nodePtr = NULL;\r
- xmlXPathObjectPtr xpathPtr = NULL;\r
- \r
- switch(textureType)\r
- {\r
- case STOCK:\r
- xpathPtr = XpathEval("/root/stock");\r
- break;\r
- case CUSTOM:\r
- xpathPtr = XpathEval("/root/custom");\r
- };\r
- \r
- if(xpathPtr)\r
- nodePtr = xpathPtr->nodesetval;\r
- else\r
- return false;\r
-\r
- if(!xmlXPathNodeSetIsEmpty(nodePtr))\r
- {\r
- xmlNodePtr newnode, newtext;\r
- xmlNodePtr nodeParent = nodePtr->nodeTab[0];\r
-\r
- // create a new node and set the node attribute (shader path)\r
- switch(nodeShaderType)\r
- {\r
- case SHADER:\r
- newnode = xmlNewNode(NULL, (xmlChar*)"shader");\r
- break;\r
- case TEXTURE:\r
- newnode = xmlNewNode(NULL, (xmlChar*)"texture");\r
- };\r
-\r
- newnode = xmlDocCopyNode(newnode, doc, 1);\r
- xmlSetProp(newnode, (xmlChar*)"path", (xmlChar*)shader);\r
- xmlNodeSetContent(newnode, (xmlChar*)"\n ");\r
-\r
- if(nodePtr->nodeTab[0]->children->next == NULL) // there are no shaders yet\r
- {\r
- // add spaces\r
- newtext = xmlNewText((xmlChar*)" ");\r
- xmlAddChild(nodeParent->children, newtext);\r
-\r
- // add the new node\r
- xmlAddNextSibling(nodeParent->children, newnode);\r
-\r
- // append a new line\r
- newtext = xmlNewText((xmlChar*)"\n ");\r
- xmlAddNextSibling(nodeParent->children->next, newtext);\r
- } else {\r
- // add the node\r
- xmlAddNextSibling(nodeParent->children, newnode);\r
-\r
- // append a new line and spaces\r
- newtext = xmlNewText((xmlChar*)"\n ");\r
- xmlAddNextSibling(nodeParent->children->next, newtext);\r
- }\r
- \r
- xmlXPathFreeObject(xpathPtr);\r
- return true;\r
- } else {\r
- xmlXPathFreeObject(xpathPtr);\r
- return false;\r
- }\r
-}\r
-\r
-bool XmlTagBuilder::DeleteShaderNode(const char* shader)\r
-{\r
- /* Deletes a shader node\r
-\r
- char* shader - the name of the shader or texture (without trailing .tga or something)\r
-\r
- returns TRUE if the node was deleted successfully or FALSE when failed\r
- */\r
-\r
- char buffer[256];\r
- char* expression = GetTagsXpathExpression(buffer, shader, EMPTY);\r
- xmlXPathObjectPtr xpathPtr = XpathEval(expression);\r
- \r
- xmlNodeSetPtr nodePtr;\r
- if(xpathPtr)\r
- nodePtr = xpathPtr->nodesetval;\r
- else\r
- return false;\r
-\r
- if(!xmlXPathNodeSetIsEmpty(nodePtr))\r
- {\r
- xmlNodePtr ptrContent = nodePtr->nodeTab[0];\r
- xmlNodePtr ptrWhitespace = nodePtr->nodeTab[0]->prev;\r
-\r
- // delete the node\r
- xmlUnlinkNode(ptrContent);\r
- xmlFreeNode(ptrContent);\r
-\r
- // delete leading whitespace node\r
- xmlUnlinkNode(ptrWhitespace);\r
- xmlFreeNode(ptrWhitespace);\r
- xmlXPathFreeObject(xpathPtr);\r
- return true;\r
- }\r
- xmlXPathFreeObject(xpathPtr);\r
- return false;\r
-}\r
-\r
-bool XmlTagBuilder::CheckShaderTag(const char* shader)\r
-{\r
- /* Checks whether there exists an entry for a shader/texture with at least one tag\r
-\r
- char* shader - the name of the shader or texture (without trailing .tga or something)\r
-\r
- returns TRUE if the shader is already stored in the XML tag file and has at least one tag\r
- */\r
-\r
- // build the XPath expression to search for\r
- char buffer[256];\r
- strcpy(buffer, "/root/*/*[@path='");\r
- strcat(buffer, shader);\r
- strcat(buffer, "']");\r
-\r
- char* expression = buffer;\r
-\r
- xmlXPathObjectPtr xpathPtr = XpathEval(expression);\r
- xmlNodeSetPtr nodePtr;\r
- if(xpathPtr)\r
- nodePtr = xpathPtr->nodesetval;\r
- else\r
- return false;\r
-\r
- if(!xmlXPathNodeSetIsEmpty(nodePtr))\r
- {\r
- xmlXPathFreeObject(xpathPtr);\r
- return true;\r
- } else {\r
- xmlXPathFreeObject(xpathPtr);\r
- return false;\r
- }\r
-}\r
-\r
-bool XmlTagBuilder::CheckShaderTag(const char* shader, const char* content)\r
-{\r
- /* Checks whether a tag with content already exists\r
-\r
- char* shader - the name of the shader or texture (without trailing .tga or something)\r
- char* content - the node content (a tag name)\r
-\r
- returns TRUE if the tag with content already exists or FALSE if not\r
- */\r
-\r
- // build the XPath expression to search for\r
- // example expression: "/stock/*[@path='textures/alpha/barb_wire'][child::tag='Alpha']";\r
-\r
- char buffer[256];\r
- strcpy(buffer, "/root/*/*[@path='");\r
- strcat(buffer, shader);\r
- strcat(buffer, "'][child::tag='");\r
- strcat(buffer, content);\r
- strcat(buffer, "']");\r
-\r
- char* expression = buffer;\r
-\r
- xmlXPathObjectPtr xpathPtr = XpathEval(expression);\r
- xmlNodeSetPtr nodePtr;\r
- if(xpathPtr)\r
- nodePtr = xpathPtr->nodesetval;\r
- else\r
- return false;\r
-\r
- if(!xmlXPathNodeSetIsEmpty(nodePtr))\r
- {\r
- xmlXPathFreeObject(xpathPtr);\r
- return true;\r
- } else {\r
- xmlXPathFreeObject(xpathPtr);\r
- return false;\r
- }\r
-}\r
-\r
-bool XmlTagBuilder::AddShaderTag(const char* shader, const char* content, NodeTagType nodeTagType)\r
-{\r
- /* Adds a tag node to an existing shader/texture node if there's no tag with the same content yet\r
-\r
- char* shader - the name of the shader or texture (without trailing .tga or something)\r
- char* content - the node content (a tag name)\r
-\r
- returns TRUE if the node was added successfully or FALSE when failed\r
- */\r
-\r
- // build the XPath expression\r
- char buffer[256];\r
- char* expression = GetTagsXpathExpression(buffer, shader, EMPTY);\r
- \r
- xmlXPathObjectPtr xpathPtr = XpathEval(expression);\r
- xmlNodeSetPtr nodePtr;\r
- if(xpathPtr)\r
- nodePtr = xpathPtr->nodesetval;\r
- else\r
- return false;\r
-\r
- if(!xmlXPathNodeSetIsEmpty(nodePtr)) // node was found\r
- {\r
- xmlNodePtr newnode = xmlNewNode(NULL, (xmlChar*)"tag");\r
- xmlNodePtr nodeParent = nodePtr->nodeTab[0];\r
- newnode = xmlDocCopyNode(newnode, doc, 1);\r
- xmlNodeSetContent(newnode, (xmlChar*)content);\r
-\r
- if(nodePtr->nodeTab[0]->children->next == NULL) // shader node has NO children\r
- {\r
- // add spaces\r
- xmlNodePtr newtext = xmlNewText((xmlChar*)" ");\r
- xmlAddChild(nodeParent->children, newtext);\r
-\r
- // add new node\r
- xmlAddNextSibling(nodeParent->children, newnode);\r
-\r
- // append a new line + spaces\r
- newtext = xmlNewText((xmlChar*)"\n ");\r
- xmlAddNextSibling(nodeParent->children->next, newtext);\r
- } else { // shader node has children already - the new node will be the first sibling\r
- xmlAddNextSibling(nodeParent->children, newnode);\r
- xmlNodePtr newtext = xmlNewText((xmlChar*)"\n ");\r
- xmlAddNextSibling(nodeParent->children->next, newtext);\r
- }\r
- xmlXPathFreeObject(xpathPtr);\r
- return true;\r
- } else {\r
- xmlXPathFreeObject(xpathPtr);\r
- return false;\r
- }\r
-}\r
-\r
-//int XmlTagBuilder::RenameShaderTag(const char* oldtag, const char* newtag)\r
-int XmlTagBuilder::RenameShaderTag(const char* oldtag, CopiedString newtag)\r
-{\r
- /* Replaces tag node contents\r
-\r
- char* oldtag - the <tag></tag> node content that sould be changed\r
- char* newtag - the new <tag></tag> node content\r
-\r
- returns the number of renamed shaders\r
- */\r
-\r
- int num = 0;\r
-\r
- // build the XPath expression\r
- char expression[256];\r
- strcpy(expression, "/root/*/*[child::tag='");\r
- strcat(expression, oldtag);\r
- strcat(expression, "']/*");\r
-\r
- xmlXPathObjectPtr result = xmlXPathEvalExpression((xmlChar*)expression, context);\r
- if(!result)\r
- return 0;\r
- xmlNodeSetPtr nodePtr = result->nodesetval;\r
-\r
- for(int i = 0; i < nodePtr->nodeNr; i++)\r
- {\r
- xmlNodePtr ptrContent = nodePtr->nodeTab[i];\r
- char* content = (char*)xmlNodeGetContent(ptrContent);\r
-\r
- if(strcmp(content, oldtag) == 0) // found a node with old content?\r
- {\r
- xmlNodeSetContent(ptrContent, (xmlChar*)newtag.c_str());\r
- num++;\r
- }\r
- }\r
-\r
- SaveXmlDoc();\r
- xmlXPathFreeObject(result);// CHANGED\r
- return num;\r
-}\r
-\r
-bool XmlTagBuilder::DeleteShaderTag(const char* shader, const char* tag)\r
-{\r
- /* Deletes a child node of a shader\r
-\r
- char* shader - the name of the shader or texture (without trailing .tga or something)\r
- char* tag - the tag being deleted\r
-\r
- returns TRUE if the node was deleted successfully or FALSE when failed\r
- */\r
-\r
- char buffer[256];\r
- char* expression = GetTagsXpathExpression(buffer, shader, TAG);\r
- xmlXPathObjectPtr xpathPtr = XpathEval(expression);\r
- xmlNodeSetPtr nodePtr;\r
- if(xpathPtr)\r
- nodePtr = xpathPtr->nodesetval;\r
- else\r
- return false;\r
-\r
- if(!xmlXPathNodeSetIsEmpty(nodePtr))\r
- {\r
- for(int i = 0; i < nodePtr->nodeNr; i++)\r
- {\r
- xmlNodePtr ptrContent = nodePtr->nodeTab[i];\r
- char* content = (char*)(xmlChar*)xmlNodeGetContent(ptrContent);\r
-\r
- if(strcmp(content, tag) == 0) // find the node\r
- {\r
- xmlNodePtr ptrWhitespace = nodePtr->nodeTab[i]->prev;\r
- // delete the node\r
- xmlUnlinkNode(ptrContent);\r
- xmlFreeNode(ptrContent);\r
-\r
- // delete leading whitespace node\r
- xmlUnlinkNode(ptrWhitespace);\r
- xmlFreeNode(ptrWhitespace);\r
- xmlXPathFreeObject(xpathPtr);\r
- return true;\r
- }\r
- }\r
- }\r
- xmlXPathFreeObject(xpathPtr);\r
- return false;\r
-}\r
-\r
-bool XmlTagBuilder::DeleteTag(const char* tag)\r
-{\r
- /* Deletes a tag from all shaders\r
-\r
- char* tag - the tag being deleted from all shaders\r
-\r
- returns TRUE if the tag was deleted successfully or FALSE when failed\r
- */\r
-\r
- char expression[256];\r
- strcpy(expression, "/root/*/*[child::tag='");\r
- strcat(expression, tag);\r
- strcat(expression, "']");\r
-\r
- std::set<CopiedString> dellist;\r
- TagSearch(expression, dellist);\r
- std::set<CopiedString>::iterator iter;\r
-\r
- for(iter = dellist.begin(); iter != dellist.end(); iter++)\r
- {\r
- DeleteShaderTag(iter->c_str(), tag);\r
- }\r
- SaveXmlDoc();\r
-\r
- return true;\r
-}\r
-\r
-void XmlTagBuilder::GetShaderTags(const char* shader, std::vector<CopiedString>& tags)\r
-{\r
- /* Gets the tags from a shader\r
-\r
- char* shader - the name of the shader\r
-\r
- returns a vector containing the tags\r
- */\r
-\r
- char* expression;\r
-\r
- if(shader == NULL) // get all tags from all shaders\r
- {\r
- expression = "/root/*/*/tag";\r
- } else {\r
- char buffer[256];\r
- expression = GetTagsXpathExpression(buffer, shader, TAG);\r
- }\r
-\r
- xmlXPathObjectPtr xpathPtr = XpathEval(expression);\r
- xmlNodeSetPtr nodePtr;\r
- if(xpathPtr)\r
- nodePtr = xpathPtr->nodesetval;\r
- else\r
- return;\r
-\r
- if(!xmlXPathNodeSetIsEmpty(nodePtr))\r
- {\r
- for(int i = 0; i < nodePtr->nodeNr; i++)\r
- {\r
- tags.push_back((CopiedString)(char*)xmlNodeGetContent(nodePtr->nodeTab[i]));\r
- }\r
- }\r
- xmlXPathFreeObject(xpathPtr);\r
-}\r
-\r
-void XmlTagBuilder::GetUntagged(std::set<CopiedString>& shaders)\r
-{\r
- /* Gets all textures and shaders listed in the xml file that don't have any tag\r
-\r
- returns a set containing the shaders (with path)\r
- */\r
-\r
- char* expression = "/root/*/*[not(child::tag)]";\r
-\r
- xmlXPathObjectPtr xpathPtr = XpathEval(expression);\r
- xmlNodeSetPtr nodePtr;\r
- if(xpathPtr)\r
- nodePtr = xpathPtr->nodesetval;\r
- else\r
- return;\r
- \r
- if(!xmlXPathNodeSetIsEmpty(nodePtr))\r
- {\r
- xmlNodePtr ptr;\r
-\r
- for(int i = 0; i < nodePtr->nodeNr; i++)\r
- {\r
- ptr = nodePtr->nodeTab[i];\r
- shaders.insert((char*)xmlGetProp(ptr, (xmlChar*)"path"));\r
- }\r
- }\r
- \r
- xmlXPathFreeObject(xpathPtr);\r
-}\r
-\r
-void XmlTagBuilder::GetAllTags(std::set<CopiedString>& tags)\r
-{\r
- /* Gets a list of all tags that are used (assigned to any shader)\r
-\r
- returns a set containing all used tags\r
- */\r
-\r
- char* expression = "/root/*/*/tag";\r
-\r
- xmlXPathObjectPtr xpathPtr = XpathEval(expression);\r
- xmlNodeSetPtr nodePtr;\r
- if(xpathPtr)\r
- nodePtr = xpathPtr->nodesetval;\r
- else\r
- return;\r
- \r
- if(!xmlXPathNodeSetIsEmpty(nodePtr))\r
- {\r
- for(int i = 0; i < nodePtr->nodeNr; i++)\r
- {\r
- tags.insert((CopiedString)(char*)xmlNodeGetContent(nodePtr->nodeTab[i]));\r
- }\r
- }\r
- \r
- xmlXPathFreeObject(xpathPtr);\r
-}\r
-\r
-void XmlTagBuilder::TagSearch(const char* expression, std::set<CopiedString>& paths)\r
-{\r
- /* Searches shaders by tags\r
-\r
- char* expression - the XPath expression to search\r
-\r
- returns a set containing the found shaders\r
- */\r
-\r
- xmlXPathObjectPtr xpathPtr = XpathEval(expression);\r
- xmlNodeSetPtr nodePtr;\r
- if(xpathPtr)\r
- nodePtr = xpathPtr->nodesetval;\r
- else\r
- return;\r
-\r
- if(!xmlXPathNodeSetIsEmpty(nodePtr))\r
- {\r
- xmlNodePtr ptr;\r
- xmlChar* xmlattrib;\r
- for(int i = 0; i < nodePtr->nodeNr; i++)\r
- {\r
- ptr = nodePtr->nodeTab[i];\r
- xmlattrib = xmlGetProp(ptr, (xmlChar*)"path");\r
- paths.insert((CopiedString)(char*)xmlattrib);\r
- }\r
- }\r
- xmlXPathFreeObject(xpathPtr);\r
-}\r
-\r
+/*
+Copyright (C) 2006, Stefan Greven.
+All Rights Reserved.
+
+This file is part of GtkRadiant.
+
+GtkRadiant is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+GtkRadiant 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GtkRadiant; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "xmltextags.h"
+
+#include <string>
+
+#include "qerplugin.h"
+#include "stream/stringstream.h"
+
+XmlTagBuilder::XmlTagBuilder()
+{
+}
+
+XmlTagBuilder::~XmlTagBuilder()
+{
+ // clean up
+ xmlFreeDoc(doc);
+ xmlXPathFreeContext(context);
+}
+
+bool XmlTagBuilder::CreateXmlDocument()
+{
+ /* Creates an XML file
+
+ returns TRUE if the file was created successfully or FALSE when failed
+ */
+
+ xmlTextWriterPtr writer;
+
+ writer = xmlNewTextWriterDoc(&doc, 0);
+
+ // begin a new UTF-8 formatted xml document
+ xmlTextWriterStartDocument(writer, NULL, "UTF-8", NULL);
+
+ // create the root node with stock and custom elements
+ xmlTextWriterStartElement(writer, (xmlChar*)"root");
+ xmlTextWriterWriteString(writer, (xmlChar*)"\n ");
+ xmlTextWriterStartElement(writer, (xmlChar*)"stock");
+ xmlTextWriterWriteString(writer, (xmlChar*)"\n ");
+ xmlTextWriterEndElement(writer);
+ xmlTextWriterWriteString(writer, (xmlChar*)"\n ");
+ xmlTextWriterStartElement(writer, (xmlChar*)"custom");
+ xmlTextWriterWriteString(writer, (xmlChar*)"\n ");
+ xmlTextWriterEndElement(writer);
+ xmlTextWriterWriteString(writer, (xmlChar*)"\n");
+ xmlTextWriterEndElement(writer);
+
+ // end of the xml document
+ xmlTextWriterEndDocument(writer);
+ xmlFreeTextWriter(writer);
+
+ if(!doc)
+ {
+ return false;
+ } else {
+ context = xmlXPathNewContext(doc);
+ return true;
+ }
+}
+
+bool XmlTagBuilder::OpenXmlDoc(const char* file, const char* savefile)
+{
+ /* Reads a XML document from a file
+
+ returns TRUE if the document was read successfully or FALSE when failed
+ */
+
+ if(savefile)
+ m_savefilename = savefile;
+ else
+ m_savefilename = file;
+
+ doc = xmlParseFile(file); // TODO error checking!
+
+ if(!doc)
+ {
+ return false;
+ } else {
+ context = xmlXPathNewContext(doc);
+ return true;
+ }
+}
+
+bool XmlTagBuilder::SaveXmlDoc(void)
+{
+ return SaveXmlDoc(m_savefilename.c_str());
+}
+
+bool XmlTagBuilder::SaveXmlDoc(const char* file)
+{
+ /* Writes the XML document
+
+ returns TRUE if the document was saved successfully or FALSE when saving failed
+ */
+
+ xmlSaveNoEmptyTags = 1;
+
+ if(xmlSaveFile(file, doc) != -1)
+ {
+ return true;
+ }
+ return false;
+}
+
+bool XmlTagBuilder::AddShaderNode(const char* shader, TextureType textureType, NodeShaderType nodeShaderType)
+{
+ /* Adds a shader node
+
+ char* shader - the name of the shader or texture (without trailing .tga or something)
+
+ returns TRUE if the node was added successfully or FALSE when failed
+ */
+
+ xmlNodeSetPtr nodePtr = NULL;
+ xmlXPathObjectPtr xpathPtr = NULL;
+
+ switch(textureType)
+ {
+ case STOCK:
+ xpathPtr = XpathEval("/root/stock");
+ break;
+ case CUSTOM:
+ xpathPtr = XpathEval("/root/custom");
+ };
+
+ if(xpathPtr)
+ nodePtr = xpathPtr->nodesetval;
+ else
+ return false;
+
+ if(!xmlXPathNodeSetIsEmpty(nodePtr))
+ {
+ xmlNodePtr newnode, newtext;
+ xmlNodePtr nodeParent = nodePtr->nodeTab[0];
+
+ // create a new node and set the node attribute (shader path)
+ switch(nodeShaderType)
+ {
+ case SHADER:
+ newnode = xmlNewNode(NULL, (xmlChar*)"shader");
+ break;
+ case TEXTURE:
+ newnode = xmlNewNode(NULL, (xmlChar*)"texture");
+ };
+
+ newnode = xmlDocCopyNode(newnode, doc, 1);
+ xmlSetProp(newnode, (xmlChar*)"path", (xmlChar*)shader);
+ xmlNodeSetContent(newnode, (xmlChar*)"\n ");
+
+ if(nodePtr->nodeTab[0]->children->next == NULL) // there are no shaders yet
+ {
+ // add spaces
+ newtext = xmlNewText((xmlChar*)" ");
+ xmlAddChild(nodeParent->children, newtext);
+
+ // add the new node
+ xmlAddNextSibling(nodeParent->children, newnode);
+
+ // append a new line
+ newtext = xmlNewText((xmlChar*)"\n ");
+ xmlAddNextSibling(nodeParent->children->next, newtext);
+ } else {
+ // add the node
+ xmlAddNextSibling(nodeParent->children, newnode);
+
+ // append a new line and spaces
+ newtext = xmlNewText((xmlChar*)"\n ");
+ xmlAddNextSibling(nodeParent->children->next, newtext);
+ }
+
+ xmlXPathFreeObject(xpathPtr);
+ return true;
+ } else {
+ xmlXPathFreeObject(xpathPtr);
+ return false;
+ }
+}
+
+bool XmlTagBuilder::DeleteShaderNode(const char* shader)
+{
+ /* Deletes a shader node
+
+ char* shader - the name of the shader or texture (without trailing .tga or something)
+
+ returns TRUE if the node was deleted successfully or FALSE when failed
+ */
+
+ char buffer[256];
+ char* expression = GetTagsXpathExpression(buffer, shader, EMPTY);
+ xmlXPathObjectPtr xpathPtr = XpathEval(expression);
+
+ xmlNodeSetPtr nodePtr;
+ if(xpathPtr)
+ nodePtr = xpathPtr->nodesetval;
+ else
+ return false;
+
+ if(!xmlXPathNodeSetIsEmpty(nodePtr))
+ {
+ xmlNodePtr ptrContent = nodePtr->nodeTab[0];
+ xmlNodePtr ptrWhitespace = nodePtr->nodeTab[0]->prev;
+
+ // delete the node
+ xmlUnlinkNode(ptrContent);
+ xmlFreeNode(ptrContent);
+
+ // delete leading whitespace node
+ xmlUnlinkNode(ptrWhitespace);
+ xmlFreeNode(ptrWhitespace);
+ xmlXPathFreeObject(xpathPtr);
+ return true;
+ }
+ xmlXPathFreeObject(xpathPtr);
+ return false;
+}
+
+bool XmlTagBuilder::CheckShaderTag(const char* shader)
+{
+ /* Checks whether there exists an entry for a shader/texture with at least one tag
+
+ char* shader - the name of the shader or texture (without trailing .tga or something)
+
+ returns TRUE if the shader is already stored in the XML tag file and has at least one tag
+ */
+
+ // build the XPath expression to search for
+ char buffer[256];
+ strcpy(buffer, "/root/*/*[@path='");
+ strcat(buffer, shader);
+ strcat(buffer, "']");
+
+ char* expression = buffer;
+
+ xmlXPathObjectPtr xpathPtr = XpathEval(expression);
+ xmlNodeSetPtr nodePtr;
+ if(xpathPtr)
+ nodePtr = xpathPtr->nodesetval;
+ else
+ return false;
+
+ if(!xmlXPathNodeSetIsEmpty(nodePtr))
+ {
+ xmlXPathFreeObject(xpathPtr);
+ return true;
+ } else {
+ xmlXPathFreeObject(xpathPtr);
+ return false;
+ }
+}
+
+bool XmlTagBuilder::CheckShaderTag(const char* shader, const char* content)
+{
+ /* Checks whether a tag with content already exists
+
+ char* shader - the name of the shader or texture (without trailing .tga or something)
+ char* content - the node content (a tag name)
+
+ returns TRUE if the tag with content already exists or FALSE if not
+ */
+
+ // build the XPath expression to search for
+ // example expression: "/stock/*[@path='textures/alpha/barb_wire'][child::tag='Alpha']";
+
+ char buffer[256];
+ strcpy(buffer, "/root/*/*[@path='");
+ strcat(buffer, shader);
+ strcat(buffer, "'][child::tag='");
+ strcat(buffer, content);
+ strcat(buffer, "']");
+
+ char* expression = buffer;
+
+ xmlXPathObjectPtr xpathPtr = XpathEval(expression);
+ xmlNodeSetPtr nodePtr;
+ if(xpathPtr)
+ nodePtr = xpathPtr->nodesetval;
+ else
+ return false;
+
+ if(!xmlXPathNodeSetIsEmpty(nodePtr))
+ {
+ xmlXPathFreeObject(xpathPtr);
+ return true;
+ } else {
+ xmlXPathFreeObject(xpathPtr);
+ return false;
+ }
+}
+
+bool XmlTagBuilder::AddShaderTag(const char* shader, const char* content, NodeTagType nodeTagType)
+{
+ /* Adds a tag node to an existing shader/texture node if there's no tag with the same content yet
+
+ char* shader - the name of the shader or texture (without trailing .tga or something)
+ char* content - the node content (a tag name)
+
+ returns TRUE if the node was added successfully or FALSE when failed
+ */
+
+ // build the XPath expression
+ char buffer[256];
+ char* expression = GetTagsXpathExpression(buffer, shader, EMPTY);
+
+ xmlXPathObjectPtr xpathPtr = XpathEval(expression);
+ xmlNodeSetPtr nodePtr;
+ if(xpathPtr)
+ nodePtr = xpathPtr->nodesetval;
+ else
+ return false;
+
+ if(!xmlXPathNodeSetIsEmpty(nodePtr)) // node was found
+ {
+ xmlNodePtr newnode = xmlNewNode(NULL, (xmlChar*)"tag");
+ xmlNodePtr nodeParent = nodePtr->nodeTab[0];
+ newnode = xmlDocCopyNode(newnode, doc, 1);
+ xmlNodeSetContent(newnode, (xmlChar*)content);
+
+ if(nodePtr->nodeTab[0]->children->next == NULL) // shader node has NO children
+ {
+ // add spaces
+ xmlNodePtr newtext = xmlNewText((xmlChar*)" ");
+ xmlAddChild(nodeParent->children, newtext);
+
+ // add new node
+ xmlAddNextSibling(nodeParent->children, newnode);
+
+ // append a new line + spaces
+ newtext = xmlNewText((xmlChar*)"\n ");
+ xmlAddNextSibling(nodeParent->children->next, newtext);
+ } else { // shader node has children already - the new node will be the first sibling
+ xmlAddNextSibling(nodeParent->children, newnode);
+ xmlNodePtr newtext = xmlNewText((xmlChar*)"\n ");
+ xmlAddNextSibling(nodeParent->children->next, newtext);
+ }
+ xmlXPathFreeObject(xpathPtr);
+ return true;
+ } else {
+ xmlXPathFreeObject(xpathPtr);
+ return false;
+ }
+}
+
+//int XmlTagBuilder::RenameShaderTag(const char* oldtag, const char* newtag)
+int XmlTagBuilder::RenameShaderTag(const char* oldtag, CopiedString newtag)
+{
+ /* Replaces tag node contents
+
+ char* oldtag - the <tag></tag> node content that sould be changed
+ char* newtag - the new <tag></tag> node content
+
+ returns the number of renamed shaders
+ */
+
+ int num = 0;
+
+ // build the XPath expression
+ char expression[256];
+ strcpy(expression, "/root/*/*[child::tag='");
+ strcat(expression, oldtag);
+ strcat(expression, "']/*");
+
+ xmlXPathObjectPtr result = xmlXPathEvalExpression((xmlChar*)expression, context);
+ if(!result)
+ return 0;
+ xmlNodeSetPtr nodePtr = result->nodesetval;
+
+ for(int i = 0; i < nodePtr->nodeNr; i++)
+ {
+ xmlNodePtr ptrContent = nodePtr->nodeTab[i];
+ char* content = (char*)xmlNodeGetContent(ptrContent);
+
+ if(strcmp(content, oldtag) == 0) // found a node with old content?
+ {
+ xmlNodeSetContent(ptrContent, (xmlChar*)newtag.c_str());
+ num++;
+ }
+ }
+
+ SaveXmlDoc();
+ xmlXPathFreeObject(result);// CHANGED
+ return num;
+}
+
+bool XmlTagBuilder::DeleteShaderTag(const char* shader, const char* tag)
+{
+ /* Deletes a child node of a shader
+
+ char* shader - the name of the shader or texture (without trailing .tga or something)
+ char* tag - the tag being deleted
+
+ returns TRUE if the node was deleted successfully or FALSE when failed
+ */
+
+ char buffer[256];
+ char* expression = GetTagsXpathExpression(buffer, shader, TAG);
+ xmlXPathObjectPtr xpathPtr = XpathEval(expression);
+ xmlNodeSetPtr nodePtr;
+ if(xpathPtr)
+ nodePtr = xpathPtr->nodesetval;
+ else
+ return false;
+
+ if(!xmlXPathNodeSetIsEmpty(nodePtr))
+ {
+ for(int i = 0; i < nodePtr->nodeNr; i++)
+ {
+ xmlNodePtr ptrContent = nodePtr->nodeTab[i];
+ char* content = (char*)(xmlChar*)xmlNodeGetContent(ptrContent);
+
+ if(strcmp(content, tag) == 0) // find the node
+ {
+ xmlNodePtr ptrWhitespace = nodePtr->nodeTab[i]->prev;
+ // delete the node
+ xmlUnlinkNode(ptrContent);
+ xmlFreeNode(ptrContent);
+
+ // delete leading whitespace node
+ xmlUnlinkNode(ptrWhitespace);
+ xmlFreeNode(ptrWhitespace);
+ xmlXPathFreeObject(xpathPtr);
+ return true;
+ }
+ }
+ }
+ xmlXPathFreeObject(xpathPtr);
+ return false;
+}
+
+bool XmlTagBuilder::DeleteTag(const char* tag)
+{
+ /* Deletes a tag from all shaders
+
+ char* tag - the tag being deleted from all shaders
+
+ returns TRUE if the tag was deleted successfully or FALSE when failed
+ */
+
+ char expression[256];
+ strcpy(expression, "/root/*/*[child::tag='");
+ strcat(expression, tag);
+ strcat(expression, "']");
+
+ std::set<CopiedString> dellist;
+ TagSearch(expression, dellist);
+ std::set<CopiedString>::iterator iter;
+
+ for(iter = dellist.begin(); iter != dellist.end(); iter++)
+ {
+ DeleteShaderTag(iter->c_str(), tag);
+ }
+ SaveXmlDoc();
+
+ return true;
+}
+
+void XmlTagBuilder::GetShaderTags(const char* shader, std::vector<CopiedString>& tags)
+{
+ /* Gets the tags from a shader
+
+ char* shader - the name of the shader
+
+ returns a vector containing the tags
+ */
+
+ char* expression;
+
+ if(shader == NULL) // get all tags from all shaders
+ {
+ expression = "/root/*/*/tag";
+ } else {
+ char buffer[256];
+ expression = GetTagsXpathExpression(buffer, shader, TAG);
+ }
+
+ xmlXPathObjectPtr xpathPtr = XpathEval(expression);
+ xmlNodeSetPtr nodePtr;
+ if(xpathPtr)
+ nodePtr = xpathPtr->nodesetval;
+ else
+ return;
+
+ if(!xmlXPathNodeSetIsEmpty(nodePtr))
+ {
+ for(int i = 0; i < nodePtr->nodeNr; i++)
+ {
+ tags.push_back((CopiedString)(char*)xmlNodeGetContent(nodePtr->nodeTab[i]));
+ }
+ }
+ xmlXPathFreeObject(xpathPtr);
+}
+
+void XmlTagBuilder::GetUntagged(std::set<CopiedString>& shaders)
+{
+ /* Gets all textures and shaders listed in the xml file that don't have any tag
+
+ returns a set containing the shaders (with path)
+ */
+
+ char* expression = "/root/*/*[not(child::tag)]";
+
+ xmlXPathObjectPtr xpathPtr = XpathEval(expression);
+ xmlNodeSetPtr nodePtr;
+ if(xpathPtr)
+ nodePtr = xpathPtr->nodesetval;
+ else
+ return;
+
+ if(!xmlXPathNodeSetIsEmpty(nodePtr))
+ {
+ xmlNodePtr ptr;
+
+ for(int i = 0; i < nodePtr->nodeNr; i++)
+ {
+ ptr = nodePtr->nodeTab[i];
+ shaders.insert((char*)xmlGetProp(ptr, (xmlChar*)"path"));
+ }
+ }
+
+ xmlXPathFreeObject(xpathPtr);
+}
+
+void XmlTagBuilder::GetAllTags(std::set<CopiedString>& tags)
+{
+ /* Gets a list of all tags that are used (assigned to any shader)
+
+ returns a set containing all used tags
+ */
+
+ char* expression = "/root/*/*/tag";
+
+ xmlXPathObjectPtr xpathPtr = XpathEval(expression);
+ xmlNodeSetPtr nodePtr;
+ if(xpathPtr)
+ nodePtr = xpathPtr->nodesetval;
+ else
+ return;
+
+ if(!xmlXPathNodeSetIsEmpty(nodePtr))
+ {
+ for(int i = 0; i < nodePtr->nodeNr; i++)
+ {
+ tags.insert((CopiedString)(char*)xmlNodeGetContent(nodePtr->nodeTab[i]));
+ }
+ }
+
+ xmlXPathFreeObject(xpathPtr);
+}
+
+void XmlTagBuilder::TagSearch(const char* expression, std::set<CopiedString>& paths)
+{
+ /* Searches shaders by tags
+
+ char* expression - the XPath expression to search
+
+ returns a set containing the found shaders
+ */
+
+ xmlXPathObjectPtr xpathPtr = XpathEval(expression);
+ xmlNodeSetPtr nodePtr;
+ if(xpathPtr)
+ nodePtr = xpathPtr->nodesetval;
+ else
+ return;
+
+ if(!xmlXPathNodeSetIsEmpty(nodePtr))
+ {
+ xmlNodePtr ptr;
+ xmlChar* xmlattrib;
+ for(int i = 0; i < nodePtr->nodeNr; i++)
+ {
+ ptr = nodePtr->nodeTab[i];
+ xmlattrib = xmlGetProp(ptr, (xmlChar*)"path");
+ paths.insert((CopiedString)(char*)xmlattrib);
+ }
+ }
+ xmlXPathFreeObject(xpathPtr);
+}
+