/* * psxmlparser.cpp * * Copyright (C) 2001 Atomic Blue (info@planeshift.it, http://www.atomicblue.org) * * * This program 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 (version 2 of the License) * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #include #include #include #include "util/psxmlparser.h" int psXMLString::FindTag( const char* tagName, int start ) { psString temp("<"); temp+=tagName; return FindSubString( temp, start, XML_CASE_INSENSITIVE ); } size_t psXMLString::FindNextTag( size_t start ) { start++; const char *myData = GetData(); while ( start < Size && myData[start] != '<' ) start++; if ( start < Size ) return start; else return (size_t)-1; } size_t psXMLString::FindMatchingEndTag( int start, const char* tagName ) { char termTag[100]; int end=-1, next; int nest = 1; strcpy(termTag,"/"); strcat(termTag,tagName); while ( nest ) { end = FindTag( termTag, start ); if ( end == -1 ) break; next = FindTag(tagName, start+1); if ( next == -1 || next > end ) { nest--; start = end+1; } else { nest++; start=next+1; } } return end; } size_t psXMLString::GetTagSection(int start, const char* tagName, psXMLString& tagSection) { size_t end = FindMatchingEndTag(start, tagName); if ( end == (size_t)-1 ) tagSection = ""; else GetSubString(tagSection, start, end+strlen(tagName)+3); return tagSection.Length(); } size_t psXMLString::GetWithinTagSection(int start, const char* tagName, psXMLString& tagSection) { size_t end = FindMatchingEndTag( start, tagName ); if ( end == (size_t)-1 ) tagSection = psString(""); else { psXMLTag startTag; GetTag(start, startTag); start+=(int)startTag.Length(); GetSubString(tagSection, start, end); } return tagSection.Length(); } size_t psXMLString::GetWithinTagSection(int start, const char* tagName, csString& value) { psXMLString tagSection; if (GetWithinTagSection(start,tagName,tagSection) > 0) { value = tagSection; } return tagSection.Length(); } size_t psXMLString::GetWithinTagSection(int start, const char* tagName, int& value) { psXMLString tagSection; if (GetWithinTagSection(start,tagName,tagSection) > 0) { value = atoi(tagSection.GetData()); } return tagSection.Length(); } size_t psXMLString::GetWithinTagSection(int start, const char* tagName, double& value) { psXMLString tagSection; if (GetWithinTagSection(start,tagName,tagSection) > 0) { value = atof(tagSection.GetData()); } return tagSection.Length(); } size_t psXMLString::GetTag( int start, psXMLTag& tag ) { psString tmp(">"); int end = FindSubString(tmp, start); if ( end == -1 ) tag.SetAt(0,0); else GetSubString(tag, start, end+1); return tag.Length(); } //------------------------------------------------------------------- void psXMLTag::GetTagParm(const char* parm, csString& value ) { psString param(" "); param.Append(parm); param.Append('='); int start = FindSubString(param, 0, XML_CASE_INSENSITIVE); //Checks to see if the parm is getting mixed up with the tag name. if ( start==1 ) { psString tagName; GetTagName(tagName); start = FindSubString(param,(int)tagName.Length(),XML_CASE_INSENSITIVE); } psString tempStr; value=""; const char *myData = GetData(); while ( start != -1 ) { start += (int)param.Length(); if (start >= (int)Length()) return; // skip whitespace after parm name while (myData[start]==' ') { start++; if (start >= (int)Length()) return; } size_t end = start+1; // parm is at least one char // Determine delimiter, if any char chr; if ( myData[start] == '\"') chr = '\"'; else if ( myData[start] == '[') chr = ']'; else if ( myData[start] == '\'') chr = '\''; else chr = ' '; while ( end < Length() && myData[end]!=chr && myData[end] != '>') end++; GetSubString(tempStr, start+(chr!=' '), end); // Replace any xml code with the correct '&' const char* what = "&"; const char* with = "&"; while (tempStr.FindSubString(what) != -1) tempStr.ReplaceSubString(what,with); what = "'"; with = "'"; while (tempStr.FindSubString(what) != -1) tempStr.ReplaceSubString(what,with); value = tempStr; return; } } void psXMLTag::GetTagParm(const char* parm, int &value ) { psString str; GetTagParm(parm, str); if (str!="") value = atoi(str); else value = -1; } void psXMLTag::GetTagParm(const char* parm, float &value ) { psString str; GetTagParm(parm, str); value = atof(str); } void psXMLTag::GetTagParm(const char* parm, double &value ) { psString str; GetTagParm(parm, str); value = atof(str); } void psXMLTag::GetTagName( psString& str) { size_t i=1; const char *myData = GetData(); while ( i < Size && !isspace(myData[i]) && myData[i] != '>') i++; GetSubString(str, 1,i); } csRef ParseFile(iObjectRegistry* object_reg, const csString & name) { csRef vfs; csRef xml; csRef doc; const char* error; vfs = CS_QUERY_REGISTRY( object_reg, iVFS ); assert(vfs); csRef buff = vfs->ReadFile(name); if (buff == NULL) { Error2("Could not find file: %s", name.GetData()); return NULL; } xml = CS_QUERY_REGISTRY (object_reg, iDocumentSystem); if (!xml) xml = csPtr(new csTinyDocumentSystem); assert(xml); doc = xml->CreateDocument(); assert(doc); error = doc->Parse( buff ); if ( error ) { Error3("Parse error in %s: %s", name.GetData(), error); return NULL; } return doc; } csRef ParseString(const csString & str) { csRef xml; xml = csPtr(new csTinyDocumentSystem); CS_ASSERT(xml != NULL); csRef doc = xml->CreateDocument(); const char* error = doc->Parse(str); if ( error ) { Error3("Error in XML: %s\nString was: %s", error, str.GetData() ); return NULL; } return doc; } csRef ParseString(const csString & str, const csString & topNodeName) { csRef doc = ParseString(str); if (doc == NULL) return NULL; csRef root = doc->GetRoot(); if (root == NULL) return NULL; csRef topNode = root->GetNode(topNodeName); return topNode; } csString EscpXML(const char * str) { csString ret; size_t strLen; ret = ""; if (str != NULL) { strLen = strlen(str); for (size_t i=0; i < strLen; i++) switch (str[i]) { case '\"': ret += """; break; case '\'': ret += "'"; break; case '<' : ret += "<"; break; case '>' : ret += ">"; break; case '&' : ret += "&"; break; default: ret += str[i]; } } return ret; } csString GetNodeXML(csRef node, bool childrenOnly) { psString xml; csRef nodes; csRef attrs; if (!childrenOnly) xml.Format("<%s", node->GetValue()); attrs = node->GetAttributes(); while (attrs->HasNext()) { csRef attr = attrs->Next(); csString escpxml = EscpXML(attr->GetValue()); xml.AppendFmt(" %s=\"%s\"", attr->GetName(), escpxml.GetData() ); } if (!childrenOnly) xml += ">"; nodes = node->GetNodes(); if (nodes->HasNext()) { while (nodes->HasNext()) { csRef child = nodes->Next(); xml += GetNodeXML(child); } } if (!childrenOnly) { xml += node->GetContentsValue(); xml.AppendFmt("", node->GetValue()); } return xml; } void CopyXMLNode(csRef source, csRef target, int mode) { if (mode == 0) { target->RemoveNodes(); target->RemoveAttributes(); } // copy nodes csRef nodeIter = source->GetNodes(); while (nodeIter->HasNext()) { csRef child = nodeIter->Next(); csRef targetChild = target->GetNode(child->GetValue()); if (targetChild==NULL) { targetChild = target->CreateNodeBefore(child->GetType()); if (targetChild == NULL) assert(!"failed to create XML node, you are probably using wrong XML parser (xmlread instead of xmltiny)"); targetChild->SetValue(child->GetValue()); } CopyXMLNode(child, targetChild, mode); } // copy attributes csRef attrIter = source->GetAttributes(); while (attrIter->HasNext()) { csRef attr = attrIter->Next(); csString attrName = attr->GetName(); if (mode==1 || !target->GetAttribute(attrName)) target->SetAttribute(attrName, attr->GetValue()); } }