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, const char* savefile)
\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 m_savefilename = savefile;
\r
90 m_savefilename = file;
\r
92 doc = xmlParseFile(file); // TODO error checking!
\r
98 context = xmlXPathNewContext(doc);
\r
103 bool XmlTagBuilder::SaveXmlDoc(void)
\r
105 return SaveXmlDoc(m_savefilename.c_str());
\r
108 bool XmlTagBuilder::SaveXmlDoc(const char* file)
\r
110 /* Writes the XML document
\r
112 returns TRUE if the document was saved successfully or FALSE when saving failed
\r
115 xmlSaveNoEmptyTags = 1;
\r
117 if(xmlSaveFile(file, doc) != -1)
\r
124 bool XmlTagBuilder::AddShaderNode(const char* shader, TextureType textureType, NodeShaderType nodeShaderType)
\r
126 /* Adds a shader node
\r
128 char* shader - the name of the shader or texture (without trailing .tga or something)
\r
130 returns TRUE if the node was added successfully or FALSE when failed
\r
133 xmlNodeSetPtr nodePtr = NULL;
\r
134 xmlXPathObjectPtr xpathPtr = NULL;
\r
136 switch(textureType)
\r
139 xpathPtr = XpathEval("/root/stock");
\r
142 xpathPtr = XpathEval("/root/custom");
\r
146 nodePtr = xpathPtr->nodesetval;
\r
150 if(!xmlXPathNodeSetIsEmpty(nodePtr))
\r
152 xmlNodePtr newnode, newtext;
\r
153 xmlNodePtr nodeParent = nodePtr->nodeTab[0];
\r
155 // create a new node and set the node attribute (shader path)
\r
156 switch(nodeShaderType)
\r
159 newnode = xmlNewNode(NULL, (xmlChar*)"shader");
\r
162 newnode = xmlNewNode(NULL, (xmlChar*)"texture");
\r
165 newnode = xmlDocCopyNode(newnode, doc, 1);
\r
166 xmlSetProp(newnode, (xmlChar*)"path", (xmlChar*)shader);
\r
167 xmlNodeSetContent(newnode, (xmlChar*)"\n ");
\r
169 if(nodePtr->nodeTab[0]->children->next == NULL) // there are no shaders yet
\r
172 newtext = xmlNewText((xmlChar*)" ");
\r
173 xmlAddChild(nodeParent->children, newtext);
\r
175 // add the new node
\r
176 xmlAddNextSibling(nodeParent->children, newnode);
\r
178 // append a new line
\r
179 newtext = xmlNewText((xmlChar*)"\n ");
\r
180 xmlAddNextSibling(nodeParent->children->next, newtext);
\r
183 xmlAddNextSibling(nodeParent->children, newnode);
\r
185 // append a new line and spaces
\r
186 newtext = xmlNewText((xmlChar*)"\n ");
\r
187 xmlAddNextSibling(nodeParent->children->next, newtext);
\r
190 xmlXPathFreeObject(xpathPtr);
\r
193 xmlXPathFreeObject(xpathPtr);
\r
198 bool XmlTagBuilder::DeleteShaderNode(const char* shader)
\r
200 /* Deletes a shader node
\r
202 char* shader - the name of the shader or texture (without trailing .tga or something)
\r
204 returns TRUE if the node was deleted successfully or FALSE when failed
\r
208 char* expression = GetTagsXpathExpression(buffer, shader, EMPTY);
\r
209 xmlXPathObjectPtr xpathPtr = XpathEval(expression);
\r
211 xmlNodeSetPtr nodePtr;
\r
213 nodePtr = xpathPtr->nodesetval;
\r
217 if(!xmlXPathNodeSetIsEmpty(nodePtr))
\r
219 xmlNodePtr ptrContent = nodePtr->nodeTab[0];
\r
220 xmlNodePtr ptrWhitespace = nodePtr->nodeTab[0]->prev;
\r
223 xmlUnlinkNode(ptrContent);
\r
224 xmlFreeNode(ptrContent);
\r
226 // delete leading whitespace node
\r
227 xmlUnlinkNode(ptrWhitespace);
\r
228 xmlFreeNode(ptrWhitespace);
\r
229 xmlXPathFreeObject(xpathPtr);
\r
232 xmlXPathFreeObject(xpathPtr);
\r
236 bool XmlTagBuilder::CheckShaderTag(const char* shader)
\r
238 /* Checks whether there exists an entry for a shader/texture with at least one tag
\r
240 char* shader - the name of the shader or texture (without trailing .tga or something)
\r
242 returns TRUE if the shader is already stored in the XML tag file and has at least one tag
\r
245 // build the XPath expression to search for
\r
247 strcpy(buffer, "/root/*/*[@path='");
\r
248 strcat(buffer, shader);
\r
249 strcat(buffer, "']");
\r
251 char* expression = buffer;
\r
253 xmlXPathObjectPtr xpathPtr = XpathEval(expression);
\r
254 xmlNodeSetPtr nodePtr;
\r
256 nodePtr = xpathPtr->nodesetval;
\r
260 if(!xmlXPathNodeSetIsEmpty(nodePtr))
\r
262 xmlXPathFreeObject(xpathPtr);
\r
265 xmlXPathFreeObject(xpathPtr);
\r
270 bool XmlTagBuilder::CheckShaderTag(const char* shader, const char* content)
\r
272 /* Checks whether a tag with content already exists
\r
274 char* shader - the name of the shader or texture (without trailing .tga or something)
\r
275 char* content - the node content (a tag name)
\r
277 returns TRUE if the tag with content already exists or FALSE if not
\r
280 // build the XPath expression to search for
\r
281 // example expression: "/stock/*[@path='textures/alpha/barb_wire'][child::tag='Alpha']";
\r
284 strcpy(buffer, "/root/*/*[@path='");
\r
285 strcat(buffer, shader);
\r
286 strcat(buffer, "'][child::tag='");
\r
287 strcat(buffer, content);
\r
288 strcat(buffer, "']");
\r
290 char* expression = buffer;
\r
292 xmlXPathObjectPtr xpathPtr = XpathEval(expression);
\r
293 xmlNodeSetPtr nodePtr;
\r
295 nodePtr = xpathPtr->nodesetval;
\r
299 if(!xmlXPathNodeSetIsEmpty(nodePtr))
\r
301 xmlXPathFreeObject(xpathPtr);
\r
304 xmlXPathFreeObject(xpathPtr);
\r
309 bool XmlTagBuilder::AddShaderTag(const char* shader, const char* content, NodeTagType nodeTagType)
\r
311 /* Adds a tag node to an existing shader/texture node if there's no tag with the same content yet
\r
313 char* shader - the name of the shader or texture (without trailing .tga or something)
\r
314 char* content - the node content (a tag name)
\r
316 returns TRUE if the node was added successfully or FALSE when failed
\r
319 // build the XPath expression
\r
321 char* expression = GetTagsXpathExpression(buffer, shader, EMPTY);
\r
323 xmlXPathObjectPtr xpathPtr = XpathEval(expression);
\r
324 xmlNodeSetPtr nodePtr;
\r
326 nodePtr = xpathPtr->nodesetval;
\r
330 if(!xmlXPathNodeSetIsEmpty(nodePtr)) // node was found
\r
332 xmlNodePtr newnode = xmlNewNode(NULL, (xmlChar*)"tag");
\r
333 xmlNodePtr nodeParent = nodePtr->nodeTab[0];
\r
334 newnode = xmlDocCopyNode(newnode, doc, 1);
\r
335 xmlNodeSetContent(newnode, (xmlChar*)content);
\r
337 if(nodePtr->nodeTab[0]->children->next == NULL) // shader node has NO children
\r
340 xmlNodePtr newtext = xmlNewText((xmlChar*)" ");
\r
341 xmlAddChild(nodeParent->children, newtext);
\r
344 xmlAddNextSibling(nodeParent->children, newnode);
\r
346 // append a new line + spaces
\r
347 newtext = xmlNewText((xmlChar*)"\n ");
\r
348 xmlAddNextSibling(nodeParent->children->next, newtext);
\r
349 } else { // shader node has children already - the new node will be the first sibling
\r
350 xmlAddNextSibling(nodeParent->children, newnode);
\r
351 xmlNodePtr newtext = xmlNewText((xmlChar*)"\n ");
\r
352 xmlAddNextSibling(nodeParent->children->next, newtext);
\r
354 xmlXPathFreeObject(xpathPtr);
\r
357 xmlXPathFreeObject(xpathPtr);
\r
362 //int XmlTagBuilder::RenameShaderTag(const char* oldtag, const char* newtag)
\r
363 int XmlTagBuilder::RenameShaderTag(const char* oldtag, CopiedString newtag)
\r
365 /* Replaces tag node contents
\r
367 char* oldtag - the <tag></tag> node content that sould be changed
\r
368 char* newtag - the new <tag></tag> node content
\r
370 returns the number of renamed shaders
\r
375 // build the XPath expression
\r
376 char expression[256];
\r
377 strcpy(expression, "/root/*/*[child::tag='");
\r
378 strcat(expression, oldtag);
\r
379 strcat(expression, "']/*");
\r
381 xmlXPathObjectPtr result = xmlXPathEvalExpression((xmlChar*)expression, context);
\r
384 xmlNodeSetPtr nodePtr = result->nodesetval;
\r
386 for(int i = 0; i < nodePtr->nodeNr; i++)
\r
388 xmlNodePtr ptrContent = nodePtr->nodeTab[i];
\r
389 char* content = (char*)xmlNodeGetContent(ptrContent);
\r
391 if(strcmp(content, oldtag) == 0) // found a node with old content?
\r
393 xmlNodeSetContent(ptrContent, (xmlChar*)newtag.c_str());
\r
399 xmlXPathFreeObject(result);// CHANGED
\r
403 bool XmlTagBuilder::DeleteShaderTag(const char* shader, const char* tag)
\r
405 /* Deletes a child node of a shader
\r
407 char* shader - the name of the shader or texture (without trailing .tga or something)
\r
408 char* tag - the tag being deleted
\r
410 returns TRUE if the node was deleted successfully or FALSE when failed
\r
414 char* expression = GetTagsXpathExpression(buffer, shader, TAG);
\r
415 xmlXPathObjectPtr xpathPtr = XpathEval(expression);
\r
416 xmlNodeSetPtr nodePtr;
\r
418 nodePtr = xpathPtr->nodesetval;
\r
422 if(!xmlXPathNodeSetIsEmpty(nodePtr))
\r
424 for(int i = 0; i < nodePtr->nodeNr; i++)
\r
426 xmlNodePtr ptrContent = nodePtr->nodeTab[i];
\r
427 char* content = (char*)(xmlChar*)xmlNodeGetContent(ptrContent);
\r
429 if(strcmp(content, tag) == 0) // find the node
\r
431 xmlNodePtr ptrWhitespace = nodePtr->nodeTab[i]->prev;
\r
433 xmlUnlinkNode(ptrContent);
\r
434 xmlFreeNode(ptrContent);
\r
436 // delete leading whitespace node
\r
437 xmlUnlinkNode(ptrWhitespace);
\r
438 xmlFreeNode(ptrWhitespace);
\r
439 xmlXPathFreeObject(xpathPtr);
\r
444 xmlXPathFreeObject(xpathPtr);
\r
448 bool XmlTagBuilder::DeleteTag(const char* tag)
\r
450 /* Deletes a tag from all shaders
\r
452 char* tag - the tag being deleted from all shaders
\r
454 returns TRUE if the tag was deleted successfully or FALSE when failed
\r
457 char expression[256];
\r
458 strcpy(expression, "/root/*/*[child::tag='");
\r
459 strcat(expression, tag);
\r
460 strcat(expression, "']");
\r
462 std::set<CopiedString> dellist;
\r
463 TagSearch(expression, dellist);
\r
464 std::set<CopiedString>::iterator iter;
\r
466 for(iter = dellist.begin(); iter != dellist.end(); iter++)
\r
468 DeleteShaderTag(iter->c_str(), tag);
\r
475 void XmlTagBuilder::GetShaderTags(const char* shader, std::vector<CopiedString>& tags)
\r
477 /* Gets the tags from a shader
\r
479 char* shader - the name of the shader
\r
481 returns a vector containing the tags
\r
486 if(shader == NULL) // get all tags from all shaders
\r
488 expression = "/root/*/*/tag";
\r
491 expression = GetTagsXpathExpression(buffer, shader, TAG);
\r
494 xmlXPathObjectPtr xpathPtr = XpathEval(expression);
\r
495 xmlNodeSetPtr nodePtr;
\r
497 nodePtr = xpathPtr->nodesetval;
\r
501 if(!xmlXPathNodeSetIsEmpty(nodePtr))
\r
503 for(int i = 0; i < nodePtr->nodeNr; i++)
\r
505 tags.push_back((CopiedString)(char*)xmlNodeGetContent(nodePtr->nodeTab[i]));
\r
508 xmlXPathFreeObject(xpathPtr);
\r
511 void XmlTagBuilder::GetUntagged(std::set<CopiedString>& shaders)
\r
513 /* Gets all textures and shaders listed in the xml file that don't have any tag
\r
515 returns a set containing the shaders (with path)
\r
518 char* expression = "/root/*/*[not(child::tag)]";
\r
520 xmlXPathObjectPtr xpathPtr = XpathEval(expression);
\r
521 xmlNodeSetPtr nodePtr;
\r
523 nodePtr = xpathPtr->nodesetval;
\r
527 if(!xmlXPathNodeSetIsEmpty(nodePtr))
\r
531 for(int i = 0; i < nodePtr->nodeNr; i++)
\r
533 ptr = nodePtr->nodeTab[i];
\r
534 shaders.insert((char*)xmlGetProp(ptr, (xmlChar*)"path"));
\r
538 xmlXPathFreeObject(xpathPtr);
\r
541 void XmlTagBuilder::GetAllTags(std::set<CopiedString>& tags)
\r
543 /* Gets a list of all tags that are used (assigned to any shader)
\r
545 returns a set containing all used tags
\r
548 char* expression = "/root/*/*/tag";
\r
550 xmlXPathObjectPtr xpathPtr = XpathEval(expression);
\r
551 xmlNodeSetPtr nodePtr;
\r
553 nodePtr = xpathPtr->nodesetval;
\r
557 if(!xmlXPathNodeSetIsEmpty(nodePtr))
\r
559 for(int i = 0; i < nodePtr->nodeNr; i++)
\r
561 tags.insert((CopiedString)(char*)xmlNodeGetContent(nodePtr->nodeTab[i]));
\r
565 xmlXPathFreeObject(xpathPtr);
\r
568 void XmlTagBuilder::TagSearch(const char* expression, std::set<CopiedString>& paths)
\r
570 /* Searches shaders by tags
\r
572 char* expression - the XPath expression to search
\r
574 returns a set containing the found shaders
\r
577 xmlXPathObjectPtr xpathPtr = XpathEval(expression);
\r
578 xmlNodeSetPtr nodePtr;
\r
580 nodePtr = xpathPtr->nodesetval;
\r
584 if(!xmlXPathNodeSetIsEmpty(nodePtr))
\r
587 xmlChar* xmlattrib;
\r
588 for(int i = 0; i < nodePtr->nodeNr; i++)
\r
590 ptr = nodePtr->nodeTab[i];
\r
591 xmlattrib = xmlGetProp(ptr, (xmlChar*)"path");
\r
592 paths.insert((CopiedString)(char*)xmlattrib);
\r
595 xmlXPathFreeObject(xpathPtr);
\r