XMLNode.cpp

Go to the documentation of this file.
00001 ////////////////////////////////////////////////////////////////////////////////
00002 //    Scorched3D (c) 2000-2009
00003 //
00004 //    This file is part of Scorched3D.
00005 //
00006 //    Scorched3D is free software; you can redistribute it and/or modify
00007 //    it under the terms of the GNU General Public License as published by
00008 //    the Free Software Foundation; either version 2 of the License, or
00009 //    (at your option) any later version.
00010 //
00011 //    Scorched3D is distributed in the hope that it will be useful,
00012 //    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 //    GNU General Public License for more details.
00015 //
00016 //    You should have received a copy of the GNU General Public License
00017 //    along with Scorched3D; if not, write to the Free Software
00018 //    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019 ////////////////////////////////////////////////////////////////////////////////
00020 
00021 #include <XML/XMLNode.h>
00022 #include <common/Defines.h>
00023 #include <stdlib.h>
00024 #include <stdio.h>
00025 #include <common/NumberParser.h>
00026 
00027 void XMLNode::removeSpecialChars(const std::string &content, std::string &result)
00028 {
00029         result = "";
00030         for (char *c=(char *) content.c_str(); *c; c++)
00031         {
00032                 char newchar = *c;
00033                 if (*c == '\n') result += "&#10;";
00034                 else if (*c < 32 || *c > 126) result += " ";
00035                 else if (*c == '>') result += "&gt;";
00036                 else if (*c == '<') result += "&lt;";
00037                 else if (*c == '\'') result += "&apos;";
00038                 else if (*c == '"') result += "&quot;";
00039                 else if (*c == '&') result += "&amp;";
00040                 else if (*c == '%') result += "&#37;";
00041                 else result += *c;
00042         }
00043 }
00044 
00045 void XMLNode::addSpecialChars(const std::string &content, std::string &result)
00046 {
00047         result = "";
00048         for (char *c=(char *) content.c_str(); *c; c++)
00049         {
00050                 if (*c == '&')
00051                 {
00052                         if (strstr(c, "&gt;") == c) { result += '>'; c+=3; }
00053                         else if (strstr(c, "&lt;") == c) { result += '<'; c+=3; }
00054                         else if (strstr(c, "&apos;") == c) { result += '\''; c+=5; }
00055                         else if (strstr(c, "&quot;") == c) { result += '"'; c+=5; }
00056                         else if (strstr(c, "&amp;") == c) { result += '&'; c+=4; }
00057                         else if (strstr(c, "&#") == c)
00058                         {
00059                                 char *pos = strchr(c, ';');
00060                                 if (pos <= c + 3)
00061                                 {
00062                                         c+=2;
00063                                         result += S3D::formatStringBuffer("%c", atoi(c));
00064                                         *pos = '\0';
00065                                         c = pos + 1;
00066                                 }
00067                         }
00068                         else result += *c;
00069                 }
00070                 else result += *c;
00071         }       
00072 }
00073 
00074 const char *XMLNode::getSpacer(int space)
00075 {
00076         static std::string spacestr;
00077         spacestr = "";
00078 
00079         for (int i=0; i<space; i++) spacestr+="\t";
00080         return spacestr.c_str();
00081 }
00082 
00083 XMLNode::XMLNode(const char *name, const char *content, NodeType type) : 
00084         name_(name), parent_(0), type_(type),
00085         useContentNodes_(false)
00086 {
00087         addContent(content, strlen(content));
00088 }
00089 
00090 XMLNode::XMLNode(const char *name, const std::string &content, NodeType type) : 
00091         name_(name), parent_(0), type_(type),
00092         useContentNodes_(false)
00093 {
00094         addContent(content.c_str(), content.size());
00095 }
00096 
00097 XMLNode::XMLNode(const char *name, const LangString &langStringContent, NodeType type) : 
00098         name_(name), parent_(0), type_(type),
00099         useContentNodes_(false)
00100 {
00101         std::string content;
00102         content = LangStringUtil::convertFromLang(langStringContent);
00103         addContent(content.c_str(), content.size());
00104 }
00105 
00106 XMLNode::XMLNode(const char *name, float content, NodeType type) :
00107         name_(name), parent_(0), type_(type), useContentNodes_(false)
00108 {
00109         char buffer[20];
00110         snprintf(buffer, 20, "%.2f", content);
00111         addContent(buffer, strlen(buffer));
00112 }
00113 
00114 XMLNode::XMLNode(const char *name, int content, NodeType type) :
00115         name_(name), parent_(0), type_(type), useContentNodes_(false)
00116 {
00117         char buffer[20];
00118         snprintf(buffer, 20, "%i", content);
00119         addContent(buffer, strlen(buffer));
00120 }
00121 
00122 XMLNode::XMLNode(const char *name, unsigned int content, NodeType type) :
00123         name_(name), parent_(0), type_(type), useContentNodes_(false)
00124 {
00125         char buffer[20];
00126         snprintf(buffer, 20, "%u", content);
00127         addContent(buffer, strlen(buffer));
00128 }
00129 
00130 XMLNode::XMLNode(const char *name, bool content, NodeType type) :
00131         name_(name), parent_(0), type_(type), useContentNodes_(false)
00132 {
00133         const char *buffer = content?"true":"false";
00134         addContent(buffer, strlen(buffer));
00135 }
00136 
00137 XMLNode::XMLNode(const char *name, fixed content, NodeType type) :
00138         name_(name), parent_(0), type_(type), useContentNodes_(false)
00139 {
00140         const char *buffer = content.asString();
00141         addContent(buffer, strlen(buffer));
00142 }
00143 
00144 XMLNode::XMLNode(const char *name, FixedVector &content, NodeType type) :
00145         name_(name), parent_(0), type_(type), useContentNodes_(false)
00146 {
00147         XMLNode *nodeA = new XMLNode("a");
00148         addChild(nodeA);
00149         XMLNode *nodeB = new XMLNode("b");
00150         addChild(nodeB);
00151         XMLNode *nodeC = new XMLNode("c");
00152         addChild(nodeC);
00153 
00154         const char *buffer = content[0].asString();
00155         nodeA->addContent(buffer, strlen(buffer));
00156 
00157         buffer = content[1].asString();
00158         nodeB->addContent(buffer, strlen(buffer));
00159 
00160         buffer = content[2].asString();
00161         nodeC->addContent(buffer, strlen(buffer));
00162 }
00163 
00164 XMLNode::XMLNode(const char *name, Vector &content, NodeType type) :
00165         name_(name), parent_(0), type_(type), useContentNodes_(false)
00166 {
00167         XMLNode *nodeA = new XMLNode("a");
00168         addChild(nodeA);
00169         XMLNode *nodeB = new XMLNode("b");
00170         addChild(nodeB);
00171         XMLNode *nodeC = new XMLNode("c");
00172         addChild(nodeC);
00173 
00174         char buffer[20];
00175         snprintf(buffer, 20, "%.2f", content[0]);
00176         nodeA->addContent(buffer, strlen(buffer));
00177 
00178         snprintf(buffer, 20, "%.2f", content[1]);
00179         nodeB->addContent(buffer, strlen(buffer));
00180 
00181         snprintf(buffer, 20, "%.2f", content[2]);
00182         nodeC->addContent(buffer, strlen(buffer));
00183 }
00184 
00185 XMLNode::~XMLNode()
00186 {
00187         while (!children_.empty())
00188         {
00189                 XMLNode *node = children_.front();
00190                 children_.pop_front();
00191                 delete node;
00192         }
00193         while (!removedChildren_.empty())
00194         {
00195                 XMLNode *node = removedChildren_.front();
00196                 removedChildren_.pop_front();
00197                 delete node;
00198         }
00199         while (!parameters_.empty())
00200         {
00201                 XMLNode *node = parameters_.front();
00202                 parameters_.pop_front();
00203                 delete node;
00204         }
00205         while (!removedParameters_.empty())
00206         {
00207                 XMLNode *node = removedParameters_.front();
00208                 removedParameters_.pop_front();
00209                 delete node;
00210         }
00211 }
00212 
00213 bool XMLNode::writeToFile(const std::string &filename)
00214 {
00215         FileLines lines;
00216         addNodeToFile(lines, 0);
00217         return lines.writeFile(filename);
00218 }
00219 
00220 void XMLNode::addNodeToFile(FileLines &lines, int spacing)
00221 {
00222         if (type_ == XMLNodeType)
00223         {
00224                 std::string params;
00225                 std::list<XMLNode *>::iterator pitor;
00226                 for (pitor = parameters_.begin();
00227                         pitor != parameters_.end();
00228                         pitor++)
00229                 {
00230                         XMLNode *node = (*pitor);
00231                         DIALOG_ASSERT(node->type_ == XMLParameterType);
00232                         
00233                         std::string oldContent(node->getContent());
00234                         std::string newContent;
00235                         removeSpecialChars(oldContent, newContent);
00236                         
00237                         params += " " + node->name_ + "='" + newContent + "'";
00238                 }
00239 
00240                 if (children_.empty())
00241                 {
00242                         std::string oldContent(getContent());
00243                         std::string newContent;
00244                         removeSpecialChars(oldContent, newContent);
00245                         
00246                         lines.addLine(S3D::formatStringBuffer("%s<%s%s>%s</%s>", 
00247                                 getSpacer(spacing),
00248                                 name_.c_str(), params.c_str(), 
00249                                 newContent.c_str(), name_.c_str()));
00250                 }
00251                 else
00252                 {
00253                         lines.addLine(S3D::formatStringBuffer("%s<%s%s>", 
00254                                 getSpacer(spacing),
00255                                 name_.c_str(), params.c_str()));
00256 
00257                         std::list<XMLNode *>::iterator itor;
00258                         for (itor = children_.begin();
00259                                 itor != children_.end();
00260                                 itor++)
00261                         {
00262                                 XMLNode *node = (*itor);
00263                                 node->addNodeToFile(lines, spacing + 1);
00264                         }
00265 
00266                         lines.addLine(S3D::formatStringBuffer("%s</%s>", 
00267                                 getSpacer(spacing), name_.c_str()));
00268                 }
00269         }
00270         else if (type_ == XMLCommentType)
00271         {
00272                 lines.addLine(S3D::formatStringBuffer("%s<!-- %s -->", 
00273                         getSpacer(spacing), getContent()));
00274         }
00275 }
00276 
00277 bool XMLNode::failChildren()
00278 {
00279         if (useContentNodes_)
00280         {
00281                 std::list<XMLNode *>::iterator itor;
00282                 for (itor = getChildren().begin();
00283                         itor != getChildren().end();
00284                         itor++)
00285                 {
00286                         XMLNode *node = (*itor);
00287                         if (node->getType() == XMLNodeType)
00288                         {
00289                                 node->returnError(S3D::formatStringBuffer("Unrecognised node."));
00290                                 return false;
00291                         }
00292                 }
00293         }
00294         else
00295         {
00296                 if (!children_.empty())
00297                 {
00298                         XMLNode *node = children_.front();
00299                         node->returnError(S3D::formatStringBuffer("Unrecognised node."));
00300                         return false;
00301                 }
00302         }
00303 
00304         return true;
00305 }
00306 
00307 bool XMLNode::failContent()
00308 {
00309         for (const char *c=getContent(); *c; c++)
00310         {
00311                 if (*c != '\n' &&
00312                         *c != '\r' &&
00313                         *c != '\t' &&
00314                         *c != ' ')
00315                 {
00316                         returnError(S3D::formatStringBuffer("Unexpected context : %s", 
00317                                         getContent()));
00318                         return false;
00319                 }
00320         }
00321         return true;
00322 }
00323 
00324 void XMLNode::resurrectRemovedChildren()
00325 {
00326         while (!removedChildren_.empty())
00327         {
00328                 XMLNode *node = removedChildren_.front();
00329                 removedChildren_.pop_front();
00330                 children_.push_back(node);
00331                 
00332                 node->resurrectRemovedChildren();
00333         }
00334         while (!removedParameters_.empty())
00335         {
00336                 XMLNode *node = removedParameters_.front();
00337                 removedParameters_.pop_front();
00338                 parameters_.push_back(node);
00339         }
00340 }
00341 
00342 bool XMLNode::getNamedChild(const char *name, XMLNode *&value,
00343         bool failOnError, bool remove)
00344 {
00345         std::list<XMLNode *>::iterator itor;
00346         for (itor = children_.begin();
00347                 itor != children_.end();
00348                 itor++)
00349         {
00350                 XMLNode *node = (*itor);
00351                 if (strcmp(name, node->getName()) == 0) 
00352                 {
00353                         if (remove)
00354                         {
00355                                 removedChildren_.push_back(node);
00356                                 children_.erase(itor);
00357                         }
00358                         value = node;
00359                         return true;
00360                 }
00361         }
00362 
00363         if (failOnError)
00364         {
00365                 returnError(S3D::formatStringBuffer("Failed to find \"%s\" node", name));
00366         }
00367         return false;
00368 }
00369 
00370 bool XMLNode::getNamedParameter(const char *name, XMLNode *&value,
00371         bool failOnError, bool remove)
00372 {
00373         std::list<XMLNode *>::iterator itor;
00374         for (itor = parameters_.begin();
00375                 itor != parameters_.end();
00376                 itor++)
00377         {
00378                 XMLNode *node = (*itor);
00379                 if (strcmp(name, node->getName()) == 0)
00380                 {
00381                         if (remove)
00382                         {
00383                                 removedParameters_.push_back(node);
00384                                 parameters_.erase(itor);
00385                         }
00386                         value = node;
00387                         return true;
00388                 }
00389         }
00390 
00391         if (failOnError)
00392         {
00393                 returnError(S3D::formatStringBuffer("Failed to find \"%s\" parameter", name));
00394         }
00395         return false;
00396 }
00397 
00398 bool XMLNode::getNamedParameter(const char *name, std::string &value,
00399         bool failOnError, bool remove)
00400 {
00401         XMLNode *node;
00402         if (!getNamedParameter(name, node, failOnError, remove)) return false;
00403         value = node->getContent();
00404         return true;
00405 }
00406 
00407 bool XMLNode::getNamedParameter(const char *name, LangString &value,
00408         bool failOnError, bool remove)
00409 {
00410         XMLNode *node;
00411         if (!getNamedParameter(name, node, failOnError, remove)) return false;
00412         value = LANG_STRING(node->getContent());
00413         return true;
00414 }
00415 
00416 bool XMLNode::getNamedChild(const char *name, LangString &value,
00417         bool failOnError, bool remove)
00418 {
00419         XMLNode *node;
00420         if (!getNamedChild(name, node, failOnError, remove)) return false;
00421         value = LANG_STRING(node->getContent());
00422         return true;
00423 }
00424 
00425 bool XMLNode::getNamedChild(const char *name, std::string &value,
00426         bool failOnError, bool remove)
00427 {
00428         XMLNode *node;
00429         if (!getNamedChild(name, node, failOnError, remove)) return false;
00430         value = node->getContent();
00431         return true;
00432 }
00433 
00434 bool XMLNode::getNamedChild(const char *name, bool &value,
00435         bool failOnError, bool remove)
00436 {
00437         XMLNode *node;
00438         if (!getNamedChild(name, node, failOnError, remove)) return false;
00439 
00440         if (0 == strcmp(node->getContent(), "true")) value = true;
00441         else if (0 == strcmp(node->getContent(), "false")) value = false;
00442         else 
00443         {
00444                 return node->returnError(
00445                         "Failed to parse boolean value (should be true or false)");
00446         }
00447         return true;
00448 }
00449 
00450 bool XMLNode::getNamedChild(const char *name, NumberParser &value,
00451         bool failOnError, bool remove)
00452 {
00453         XMLNode *node;
00454         if (!getNamedChild(name, node, failOnError, remove)) return false;
00455 
00456         if (!value.setExpression(node->getContent()))
00457                         return node->returnError("Failed to parse expression");
00458 
00459         return true;
00460 }
00461 
00462 bool XMLNode::getNamedChild(const char *name, float &value,
00463         bool failOnError, bool remove)
00464 {
00465         XMLNode *node;
00466         if (!getNamedChild(name, node, failOnError, remove)) return false;
00467 
00468         if (sscanf(node->getContent(), "%f", &value) != 1) 
00469                 return node->returnError("Failed to parse float value");
00470         return true;
00471 }
00472 
00473 bool XMLNode::getNamedChild(const char *name, int &value,
00474         bool failOnError, bool remove)
00475 {
00476         XMLNode *node;
00477         if (!getNamedChild(name, node, failOnError, remove)) return false;
00478 
00479         if (sscanf(node->getContent(), "%i", &value) != 1)
00480                 return node->returnError("Failed to parse int value");
00481         return true;
00482 }
00483 
00484 bool XMLNode::getNamedChild(const char *name, unsigned int &value,
00485         bool failOnError, bool remove)
00486 {
00487         XMLNode *node;
00488         if (!getNamedChild(name, node, failOnError, remove)) return false;
00489 
00490         if (sscanf(node->getContent(), "%u", &value) != 1)
00491                 return node->returnError("Failed to parse unsigned int value");
00492         return true;
00493 }
00494 
00495 bool XMLNode::getNamedChild(const char *name, fixed &value,
00496         bool failOnError, bool remove)
00497 {
00498         std::string v;
00499         if (!getNamedChild(name, v, failOnError, remove)) return false;
00500         value = fixed(v.c_str());
00501         return true;
00502 }
00503 
00504 bool XMLNode::getNamedChild(const char *name, FixedVector &value, 
00505         bool failOnError, bool remove)
00506 {
00507         XMLNode *node;
00508         if (!getNamedChild(name, node, failOnError, remove)) return false;
00509 
00510         std::string a, b, c;
00511         if (!node->getNamedChild("A", a, false, true) &&
00512                 !node->getNamedChild("a", a, false, true))
00513         {
00514                 if (failOnError) node->returnError("Failed to find a node");
00515                 return false;
00516         }
00517         if (!node->getNamedChild("B", b, false, true) &&
00518                 !node->getNamedChild("b", b, false, true))
00519         {
00520                 if (failOnError) node->returnError("Failed to find b node");
00521                 return false;
00522         }
00523         if (!node->getNamedChild("C", c, false, true) &&
00524                 !node->getNamedChild("c", c, false, true))
00525         {
00526                 if (failOnError) node->returnError("Failed to find c node");
00527                 return false;
00528         }
00529         if (failOnError && !node->failChildren()) return false;
00530 
00531         value[0] = fixed(a.c_str());
00532         value[1] = fixed(b.c_str());
00533         value[2] = fixed(c.c_str());
00534         return true;
00535 }
00536 
00537 bool XMLNode::getNamedChild(const char *name, Vector &value, 
00538         bool failOnError, bool remove)
00539 {
00540         XMLNode *node;
00541         if (!getNamedChild(name, node, failOnError, remove)) return false;
00542 
00543         Vector tmpValue;
00544         if (!node->getNamedChild("A", tmpValue[0], false, true) &&
00545                 !node->getNamedChild("a", tmpValue[0], false, true))
00546         {
00547                 if (failOnError) node->returnError("Failed to find a node");
00548                 return false;
00549         }
00550         if (!node->getNamedChild("B", tmpValue[1], false, true) &&
00551                 !node->getNamedChild("b", tmpValue[1], false, true))
00552         {
00553                 if (failOnError) node->returnError("Failed to find b node");
00554                 return false;
00555         }
00556         if (!node->getNamedChild("C", tmpValue[2], false, true) &&
00557                 !node->getNamedChild("c", tmpValue[2], false, true))
00558         {
00559                 if (failOnError) node->returnError("Failed to find c node");
00560                 return false;
00561         }
00562         if (failOnError && !node->failChildren()) return false;
00563 
00564         value = tmpValue;
00565         return true;
00566 }
00567 
00568 const char *XMLNode::getContent()
00569 {
00570         if (useContentNodes_ &&
00571                 getType() == XMLNodeType)
00572         {
00573                 static std::string result;
00574 
00575                 result = "";
00576                 std::list<XMLNode *>::iterator itor;
00577                 for (itor = getChildren().begin();
00578                         itor != getChildren().end();
00579                         itor++)
00580                 {
00581                         XMLNode *node = (*itor);
00582                         if (node->getType() == XMLContentType)
00583                         {
00584                                 result += node->content_.c_str();
00585                         }
00586                 }
00587                 return result.c_str();
00588         }
00589         else
00590         {
00591                 return content_.c_str();
00592         }
00593 }
00594 
00595 void XMLNode::setSource(const char *source)
00596 { 
00597         source_ = source; 
00598 }
00599 
00600 void XMLNode::setLine(int line, int col)
00601 {
00602         line_ = line;
00603         col_ = col;
00604 }
00605 
00606 void XMLNode::addChild(XMLNode *node) 
00607 { 
00608         children_.push_back(node); 
00609         node->setUseContentNodes(useContentNodes_);
00610         node->parent_ = this; 
00611         node->source_ = source_; 
00612 }
00613 
00614 void XMLNode::addParameter(XMLNode *node) 
00615 { 
00616         parameters_.push_back(node); 
00617         node->parent_ = this; 
00618         node->source_ = source_; 
00619 }
00620 
00621 void XMLNode::addContent(const char *data, int len)
00622 {
00623         std::string oldContent, newContent;
00624         oldContent.append(data, len);
00625         addSpecialChars(oldContent, newContent);
00626 
00627         if (useContentNodes_)
00628         {
00629                 XMLNode *newNode = 
00630                         new XMLNode("__TEXT__", "", XMLNode::XMLContentType);
00631                 newNode->setLine(line_, col_);
00632                 newNode->content_.append(newContent);
00633                 addChild(newNode);
00634         }
00635         else
00636         {
00637                 content_.append(newContent); 
00638         }
00639 }
00640 
00641 bool XMLNode::returnError(const std::string &error)
00642 {
00643         S3D::dialogMessage("XMLNode",
00644                 S3D::formatStringBuffer("Parse Error, File:%s Line:%i Col:%i Node:%s Error:%s",
00645                 source_.c_str(), line_, col_, getName(), error.c_str()));
00646         return false;
00647 }

Generated on Mon Feb 16 15:14:52 2009 for Scorched3D by  doxygen 1.5.3