2 Copyright (C) 2006, Stefan Greven.
\r
5 This file is part of GtkRadiant.
\r
7 GtkRadiant is free software; you can redistribute it and/or modify
\r
8 it under the terms of the GNU General Public License as published by
\r
9 the Free Software Foundation; either version 2 of the License, or
\r
10 (at your option) any later version.
\r
12 GtkRadiant is distributed in the hope that it will be useful,
\r
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
15 GNU General Public License for more details.
\r
17 You should have received a copy of the GNU General Public License
\r
18 along with GtkRadiant; if not, write to the Free Software
\r
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
\r
22 #include "xmltextags.h"
\r
26 #include "qerplugin.h"
\r
27 #include "stream/stringstream.h"
\r
29 XmlTagBuilder::XmlTagBuilder()
\r
33 XmlTagBuilder::~XmlTagBuilder()
\r
37 xmlXPathFreeContext(context);
\r
40 bool XmlTagBuilder::CreateXmlDocument()
\r
42 /* Creates an XML file
\r
44 returns TRUE if the file was created successfully or FALSE when failed
\r
47 xmlTextWriterPtr writer;
\r
49 writer = xmlNewTextWriterDoc(&doc, 0);
\r
51 // begin a new UTF-8 formatted xml document
\r
52 xmlTextWriterStartDocument(writer, NULL, "UTF-8", NULL);
\r
54 // create the root node with stock and custom elements
\r
55 xmlTextWriterStartElement(writer, (xmlChar*)"root");
\r
56 xmlTextWriterWriteString(writer, (xmlChar*)"\n ");
\r
57 xmlTextWriterStartElement(writer, (xmlChar*)"stock");
\r
58 xmlTextWriterWriteString(writer, (xmlChar*)"\n ");
\r
59 xmlTextWriterEndElement(writer);
\r
60 xmlTextWriterWriteString(writer, (xmlChar*)"\n ");
\r
61 xmlTextWriterStartElement(writer, (xmlChar*)"custom");
\r
62 xmlTextWriterWriteString(writer, (xmlChar*)"\n ");
\r
63 xmlTextWriterEndElement(writer);
\r
64 xmlTextWriterWriteString(writer, (xmlChar*)"\n");
\r
65 xmlTextWriterEndElement(writer);
\r
67 // end of the xml document
\r
68 xmlTextWriterEndDocument(writer);
\r
69 xmlFreeTextWriter(writer);
\r
75 context = xmlXPathNewContext(doc);
\r
80 bool XmlTagBuilder::OpenXmlDoc(const char* file)
\r
82 /* Reads a XML document from a file
\r
84 returns TRUE if the document was read successfully or FALSE when failed
\r
88 doc = xmlParseFile(file); // TODO error checking!
\r
94 context = xmlXPathNewContext(doc);
\r
99 bool XmlTagBuilder::SaveXmlDoc(void)
\r
101 return SaveXmlDoc(filename.c_str());
\r
104 bool XmlTagBuilder::SaveXmlDoc(const char* file)
\r
106 /* Writes the XML document
\r
108 returns TRUE if the document was saved successfully or FALSE when saving failed
\r
111 xmlSaveNoEmptyTags = 1;
\r
113 if(xmlSaveFile(file, doc) != -1)
\r
120 bool XmlTagBuilder::AddShaderNode(const char* shader, TextureType textureType, NodeShaderType nodeShaderType)
\r
122 /* Adds a shader node
\r
124 char* shader - the name of the shader or texture (without trailing .tga or something)
\r
126 returns TRUE if the node was added successfully or FALSE when failed
\r
129 xmlNodeSetPtr nodePtr = NULL;
\r
130 xmlXPathObjectPtr xpathPtr = NULL;
\r
132 switch(textureType)
\r
135 xpathPtr = XpathEval("/root/stock");
\r
138 xpathPtr = XpathEval("/root/custom");
\r
142 nodePtr = xpathPtr->nodesetval;
\r
146 if(!xmlXPathNodeSetIsEmpty(nodePtr))
\r
148 xmlNodePtr newnode, newtext;
\r
149 xmlNodePtr nodeParent = nodePtr->nodeTab[0];
\r
151 // create a new node and set the node attribute (shader path)
\r
152 switch(nodeShaderType)
\r
155 newnode = xmlNewNode(NULL, (xmlChar*)"shader");
\r
158 newnode = xmlNewNode(NULL, (xmlChar*)"texture");
\r
161 newnode = xmlDocCopyNode(newnode, doc, 1);
\r
162 xmlSetProp(newnode, (xmlChar*)"path", (xmlChar*)shader);
\r
163 xmlNodeSetContent(newnode, (xmlChar*)"\n ");
\r
165 if(nodePtr->nodeTab[0]->children->next == NULL) // there are no shaders yet
\r
168 newtext = xmlNewText((xmlChar*)" ");
\r
169 xmlAddChild(nodeParent->children, newtext);
\r
171 // add the new node
\r
172 xmlAddNextSibling(nodeParent->children, newnode);
\r
174 // append a new line
\r
175 newtext = xmlNewText((xmlChar*)"\n ");
\r
176 xmlAddNextSibling(nodeParent->children->next, newtext);
\r
179 xmlAddNextSibling(nodeParent->children, newnode);
\r
181 // append a new line and spaces
\r
182 newtext = xmlNewText((xmlChar*)"\n ");
\r
183 xmlAddNextSibling(nodeParent->children->next, newtext);
\r
186 xmlXPathFreeObject(xpathPtr);
\r
189 xmlXPathFreeObject(xpathPtr);
\r
194 bool XmlTagBuilder::DeleteShaderNode(const char* shader)
\r
196 /* Deletes a shader node
\r
198 char* shader - the name of the shader or texture (without trailing .tga or something)
\r
200 returns TRUE if the node was deleted successfully or FALSE when failed
\r
204 char* expression = GetTagsXpathExpression(buffer, shader, EMPTY);
\r
205 xmlXPathObjectPtr xpathPtr = XpathEval(expression);
\r
207 xmlNodeSetPtr nodePtr;
\r
209 nodePtr = xpathPtr->nodesetval;
\r
213 if(!xmlXPathNodeSetIsEmpty(nodePtr))
\r
215 xmlNodePtr ptrContent = nodePtr->nodeTab[0];
\r
216 xmlNodePtr ptrWhitespace = nodePtr->nodeTab[0]->prev;
\r
219 xmlUnlinkNode(ptrContent);
\r
220 xmlFreeNode(ptrContent);
\r
222 // delete leading whitespace node
\r
223 xmlUnlinkNode(ptrWhitespace);
\r
224 xmlFreeNode(ptrWhitespace);
\r
225 xmlXPathFreeObject(xpathPtr);
\r
228 xmlXPathFreeObject(xpathPtr);
\r
232 bool XmlTagBuilder::CheckShaderTag(const char* shader)
\r
234 /* Checks whether there exists an entry for a shader/texture with at least one tag
\r
236 char* shader - the name of the shader or texture (without trailing .tga or something)
\r
238 returns TRUE if the shader is already stored in the XML tag file and has at least one tag
\r
241 // build the XPath expression to search for
\r
243 strcpy(buffer, "/root/*/*[@path='");
\r
244 strcat(buffer, shader);
\r
245 strcat(buffer, "']");
\r
247 char* expression = buffer;
\r
249 xmlXPathObjectPtr xpathPtr = XpathEval(expression);
\r
250 xmlNodeSetPtr nodePtr;
\r
252 nodePtr = xpathPtr->nodesetval;
\r
256 if(!xmlXPathNodeSetIsEmpty(nodePtr))
\r
258 xmlXPathFreeObject(xpathPtr);
\r
261 xmlXPathFreeObject(xpathPtr);
\r
266 bool XmlTagBuilder::CheckShaderTag(const char* shader, const char* content)
\r
268 /* Checks whether a tag with content already exists
\r
270 char* shader - the name of the shader or texture (without trailing .tga or something)
\r
271 char* content - the node content (a tag name)
\r
273 returns TRUE if the tag with content already exists or FALSE if not
\r
276 // build the XPath expression to search for
\r
277 // example expression: "/stock/*[@path='textures/alpha/barb_wire'][child::tag='Alpha']";
\r
280 strcpy(buffer, "/root/*/*[@path='");
\r
281 strcat(buffer, shader);
\r
282 strcat(buffer, "'][child::tag='");
\r
283 strcat(buffer, content);
\r
284 strcat(buffer, "']");
\r
286 char* expression = buffer;
\r
288 xmlXPathObjectPtr xpathPtr = XpathEval(expression);
\r
289 xmlNodeSetPtr nodePtr;
\r
291 nodePtr = xpathPtr->nodesetval;
\r
295 if(!xmlXPathNodeSetIsEmpty(nodePtr))
\r
297 xmlXPathFreeObject(xpathPtr);
\r
300 xmlXPathFreeObject(xpathPtr);
\r
305 bool XmlTagBuilder::AddShaderTag(const char* shader, const char* content, NodeTagType nodeTagType)
\r
307 /* Adds a tag node to an existing shader/texture node if there's no tag with the same content yet
\r
309 char* shader - the name of the shader or texture (without trailing .tga or something)
\r
310 char* content - the node content (a tag name)
\r
312 returns TRUE if the node was added successfully or FALSE when failed
\r
315 // build the XPath expression
\r
317 char* expression = GetTagsXpathExpression(buffer, shader, EMPTY);
\r
319 xmlXPathObjectPtr xpathPtr = XpathEval(expression);
\r
320 xmlNodeSetPtr nodePtr;
\r
322 nodePtr = xpathPtr->nodesetval;
\r
326 if(!xmlXPathNodeSetIsEmpty(nodePtr)) // node was found
\r
328 xmlNodePtr newnode = xmlNewNode(NULL, (xmlChar*)"tag");
\r
329 xmlNodePtr nodeParent = nodePtr->nodeTab[0];
\r
330 newnode = xmlDocCopyNode(newnode, doc, 1);
\r
331 xmlNodeSetContent(newnode, (xmlChar*)content);
\r
333 if(nodePtr->nodeTab[0]->children->next == NULL) // shader node has NO children
\r
336 xmlNodePtr newtext = xmlNewText((xmlChar*)" ");
\r
337 xmlAddChild(nodeParent->children, newtext);
\r
340 xmlAddNextSibling(nodeParent->children, newnode);
\r
342 // append a new line + spaces
\r
343 newtext = xmlNewText((xmlChar*)"\n ");
\r
344 xmlAddNextSibling(nodeParent->children->next, newtext);
\r
345 } else { // shader node has children already - the new node will be the first sibling
\r
346 xmlAddNextSibling(nodeParent->children, newnode);
\r
347 xmlNodePtr newtext = xmlNewText((xmlChar*)"\n ");
\r
348 xmlAddNextSibling(nodeParent->children->next, newtext);
\r
350 xmlXPathFreeObject(xpathPtr);
\r
353 xmlXPathFreeObject(xpathPtr);
\r
358 //int XmlTagBuilder::RenameShaderTag(const char* oldtag, const char* newtag)
\r
359 int XmlTagBuilder::RenameShaderTag(const char* oldtag, CopiedString newtag)
\r
361 /* Replaces tag node contents
\r
363 char* oldtag - the <tag></tag> node content that sould be changed
\r
364 char* newtag - the new <tag></tag> node content
\r
366 returns the number of renamed shaders
\r
371 // build the XPath expression
\r
372 char expression[256];
\r
373 strcpy(expression, "/root/*/*[child::tag='");
\r
374 strcat(expression, oldtag);
\r
375 strcat(expression, "']/*");
\r
377 xmlXPathObjectPtr result = xmlXPathEvalExpression((xmlChar*)expression, context);
\r
380 xmlNodeSetPtr nodePtr = result->nodesetval;
\r
382 for(int i = 0; i < nodePtr->nodeNr; i++)
\r
384 xmlNodePtr ptrContent = nodePtr->nodeTab[i];
\r
385 char* content = (char*)xmlNodeGetContent(ptrContent);
\r
387 if(strcmp(content, oldtag) == 0) // found a node with old content?
\r
389 xmlNodeSetContent(ptrContent, (xmlChar*)newtag.c_str());
\r
395 xmlXPathFreeObject(result);// CHANGED
\r
399 bool XmlTagBuilder::DeleteShaderTag(const char* shader, const char* tag)
\r
401 /* Deletes a child node of a shader
\r
403 char* shader - the name of the shader or texture (without trailing .tga or something)
\r
404 char* tag - the tag being deleted
\r
406 returns TRUE if the node was deleted successfully or FALSE when failed
\r
410 char* expression = GetTagsXpathExpression(buffer, shader, TAG);
\r
411 xmlXPathObjectPtr xpathPtr = XpathEval(expression);
\r
412 xmlNodeSetPtr nodePtr;
\r
414 nodePtr = xpathPtr->nodesetval;
\r
418 if(!xmlXPathNodeSetIsEmpty(nodePtr))
\r
420 for(int i = 0; i < nodePtr->nodeNr; i++)
\r
422 xmlNodePtr ptrContent = nodePtr->nodeTab[i];
\r
423 char* content = (char*)(xmlChar*)xmlNodeGetContent(ptrContent);
\r
425 if(strcmp(content, tag) == 0) // find the node
\r
427 xmlNodePtr ptrWhitespace = nodePtr->nodeTab[i]->prev;
\r
429 xmlUnlinkNode(ptrContent);
\r
430 xmlFreeNode(ptrContent);
\r
432 // delete leading whitespace node
\r
433 xmlUnlinkNode(ptrWhitespace);
\r
434 xmlFreeNode(ptrWhitespace);
\r
435 xmlXPathFreeObject(xpathPtr);
\r
440 xmlXPathFreeObject(xpathPtr);
\r
444 bool XmlTagBuilder::DeleteTag(const char* tag)
\r
446 /* Deletes a tag from all shaders
\r
448 char* tag - the tag being deleted from all shaders
\r
450 returns TRUE if the tag was deleted successfully or FALSE when failed
\r
453 char expression[256];
\r
454 strcpy(expression, "/root/*/*[child::tag='");
\r
455 strcat(expression, tag);
\r
456 strcat(expression, "']");
\r
458 std::set<CopiedString> dellist;
\r
459 TagSearch(expression, dellist);
\r
460 std::set<CopiedString>::iterator iter;
\r
462 for(iter = dellist.begin(); iter != dellist.end(); iter++)
\r
464 DeleteShaderTag(iter->c_str(), tag);
\r
471 void XmlTagBuilder::GetShaderTags(const char* shader, std::vector<CopiedString>& tags)
\r
473 /* Gets the tags from a shader
\r
475 char* shader - the name of the shader
\r
477 returns a vector containing the tags
\r
482 if(shader == NULL) // get all tags from all shaders
\r
484 expression = "/root/*/*/tag";
\r
487 expression = GetTagsXpathExpression(buffer, shader, TAG);
\r
490 xmlXPathObjectPtr xpathPtr = XpathEval(expression);
\r
491 xmlNodeSetPtr nodePtr;
\r
493 nodePtr = xpathPtr->nodesetval;
\r
497 if(!xmlXPathNodeSetIsEmpty(nodePtr))
\r
499 for(int i = 0; i < nodePtr->nodeNr; i++)
\r
501 tags.push_back((CopiedString)(char*)xmlNodeGetContent(nodePtr->nodeTab[i]));
\r
504 xmlXPathFreeObject(xpathPtr);
\r
507 void XmlTagBuilder::GetUntagged(std::set<CopiedString>& shaders)
\r
509 /* Gets all textures and shaders listed in the xml file that don't have any tag
\r
511 returns a set containing the shaders (with path)
\r
514 char* expression = "/root/*/*[not(child::tag)]";
\r
516 xmlXPathObjectPtr xpathPtr = XpathEval(expression);
\r
517 xmlNodeSetPtr nodePtr;
\r
519 nodePtr = xpathPtr->nodesetval;
\r
523 if(!xmlXPathNodeSetIsEmpty(nodePtr))
\r
527 for(int i = 0; i < nodePtr->nodeNr; i++)
\r
529 ptr = nodePtr->nodeTab[i];
\r
530 shaders.insert((char*)xmlGetProp(ptr, (xmlChar*)"path"));
\r
534 xmlXPathFreeObject(xpathPtr);
\r
537 void XmlTagBuilder::GetAllTags(std::set<CopiedString>& tags)
\r
539 /* Gets a list of all tags that are used (assigned to any shader)
\r
541 returns a set containing all used tags
\r
544 char* expression = "/root/*/*/tag";
\r
546 xmlXPathObjectPtr xpathPtr = XpathEval(expression);
\r
547 xmlNodeSetPtr nodePtr;
\r
549 nodePtr = xpathPtr->nodesetval;
\r
553 if(!xmlXPathNodeSetIsEmpty(nodePtr))
\r
555 for(int i = 0; i < nodePtr->nodeNr; i++)
\r
557 tags.insert((CopiedString)(char*)xmlNodeGetContent(nodePtr->nodeTab[i]));
\r
561 xmlXPathFreeObject(xpathPtr);
\r
564 void XmlTagBuilder::TagSearch(const char* expression, std::set<CopiedString>& paths)
\r
566 /* Searches shaders by tags
\r
568 char* expression - the XPath expression to search
\r
570 returns a set containing the found shaders
\r
573 xmlXPathObjectPtr xpathPtr = XpathEval(expression);
\r
574 xmlNodeSetPtr nodePtr;
\r
576 nodePtr = xpathPtr->nodesetval;
\r
580 if(!xmlXPathNodeSetIsEmpty(nodePtr))
\r
583 xmlChar* xmlattrib;
\r
584 for(int i = 0; i < nodePtr->nodeNr; i++)
\r
586 ptr = nodePtr->nodeTab[i];
\r
587 xmlattrib = xmlGetProp(ptr, (xmlChar*)"path");
\r
588 paths.insert((CopiedString)(char*)xmlattrib);
\r
591 xmlXPathFreeObject(xpathPtr);
\r