-/*\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 );
+}