diff options
Diffstat (limited to 'CPP/Common/MyXml.cpp')
-rwxr-xr-x | CPP/Common/MyXml.cpp | 209 |
1 files changed, 209 insertions, 0 deletions
diff --git a/CPP/Common/MyXml.cpp b/CPP/Common/MyXml.cpp new file mode 100755 index 00000000..1d5d836a --- /dev/null +++ b/CPP/Common/MyXml.cpp @@ -0,0 +1,209 @@ +// MyXml.cpp + +#include "StdAfx.h" + +#include "MyXml.h" + +static bool IsValidChar(char c) +{ + return + c >= 'a' && c <= 'z' || + c >= 'A' && c <= 'Z' || + c >= '0' && c <= '9' || + c == '-'; +} + +static bool IsSpaceChar(char c) +{ + return (c == ' ' || c == '\t' || c == 0x0D || c == 0x0A); +} + +#define SKEEP_SPACES(s, pos) while (IsSpaceChar(s[pos])) pos++; + +static bool ReadProperty(const AString &s, int &pos, CXmlProp &prop) +{ + prop.Name.Empty(); + prop.Value.Empty(); + for (; pos < s.Length(); pos++) + { + char c = s[pos]; + if (!IsValidChar(c)) + break; + prop.Name += c; + } + + if (prop.Name.IsEmpty()) + return false; + + SKEEP_SPACES(s, pos); + if (s[pos++] != '=') + return false; + + SKEEP_SPACES(s, pos); + if (s[pos++] != '\"') + return false; + + while (pos < s.Length()) + { + char c = s[pos++]; + if (c == '\"') + return true; + prop.Value += c; + } + return false; +} + +int CXmlItem::FindProperty(const AString &propName) const +{ + for (int i = 0; i < Props.Size(); i++) + if (Props[i].Name == propName) + return i; + return -1; +} + +AString CXmlItem::GetPropertyValue(const AString &propName) const +{ + int index = FindProperty(propName); + if (index >= 0) + return Props[index].Value; + return AString(); +} + +bool CXmlItem::IsTagged(const AString &tag) const +{ + return (IsTag && Name == tag); +} + +int CXmlItem::FindSubTag(const AString &tag) const +{ + for (int i = 0; i < SubItems.Size(); i++) + if (SubItems[i].IsTagged(tag)) + return i; + return -1; +} + +AString CXmlItem::GetSubString() const +{ + if (SubItems.Size() == 1) + { + const CXmlItem &item = SubItems[0]; + if (!item.IsTag) + return item.Name; + } + return AString(); +} + +AString CXmlItem::GetSubStringForTag(const AString &tag) const +{ + int index = FindSubTag(tag); + if (index >= 0) + return SubItems[index].GetSubString(); + return AString(); +} + +bool CXmlItem::ParseItems(const AString &s, int &pos, int numAllowedLevels) +{ + if (numAllowedLevels == 0) + return false; + SubItems.Clear(); + AString finishString = "</"; + for (;;) + { + SKEEP_SPACES(s, pos); + + if (s.Mid(pos, finishString.Length()) == finishString) + return true; + + CXmlItem item; + if (!item.ParseItem(s, pos, numAllowedLevels - 1)) + return false; + SubItems.Add(item); + } +} + +bool CXmlItem::ParseItem(const AString &s, int &pos, int numAllowedLevels) +{ + SKEEP_SPACES(s, pos); + + int pos2 = s.Find('<', pos); + if (pos2 < 0) + return false; + if (pos2 != pos) + { + IsTag = false; + Name += s.Mid(pos, pos2 - pos); + pos = pos2; + return true; + } + IsTag = true; + + pos++; + SKEEP_SPACES(s, pos); + + for (; pos < s.Length(); pos++) + { + char c = s[pos]; + if (!IsValidChar(c)) + break; + Name += c; + } + if (Name.IsEmpty() || pos == s.Length()) + return false; + + int posTemp = pos; + for (;;) + { + SKEEP_SPACES(s, pos); + if (s[pos] == '/') + { + pos++; + // SKEEP_SPACES(s, pos); + return (s[pos++] == '>'); + } + if (s[pos] == '>') + { + if (!ParseItems(s, ++pos, numAllowedLevels)) + return false; + AString finishString = AString("</") + Name + AString(">"); + if (s.Mid(pos, finishString.Length()) != finishString) + return false; + pos += finishString.Length(); + return true; + } + if (posTemp == pos) + return false; + + CXmlProp prop; + if (!ReadProperty(s, pos, prop)) + return false; + Props.Add(prop); + posTemp = pos; + } +} + +bool SkeepHeader(const AString &s, int &pos, const AString &startString, const AString &endString) +{ + SKEEP_SPACES(s, pos); + if (s.Mid(pos, startString.Length()) == startString) + { + pos = s.Find(endString, pos); + if (pos < 0) + return false; + pos += endString.Length(); + SKEEP_SPACES(s, pos); + } + return true; +} + +bool CXml::Parse(const AString &s) +{ + int pos = 0; + if (!SkeepHeader(s, pos, "<?xml", "?>")) + return false; + if (!SkeepHeader(s, pos, "<!DOCTYPE", ">")) + return false; + if (!Root.ParseItem(s, pos, 1000)) + return false; + SKEEP_SPACES(s, pos); + return (pos == s.Length() && Root.IsTag); +} |