// 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 SKIP_SPACES(s) while (IsSpaceChar(*s)) s++; int CXmlItem::FindProp(const AString &propName) const throw() { FOR_VECTOR (i, Props) if (Props[i].Name == propName) return i; return -1; } AString CXmlItem::GetPropVal(const AString &propName) const { int index = FindProp(propName); if (index >= 0) return Props[index].Value; return AString(); } bool CXmlItem::IsTagged(const AString &tag) const throw() { return (IsTag && Name == tag); } int CXmlItem::FindSubTag(const AString &tag) const throw() { FOR_VECTOR (i, SubItems) 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(); } const AString * CXmlItem::GetSubStringPtr() const throw() { if (SubItems.Size() == 1) { const CXmlItem &item = SubItems[0]; if (!item.IsTag) return &item.Name; } return NULL; } AString CXmlItem::GetSubStringForTag(const AString &tag) const { int index = FindSubTag(tag); if (index >= 0) return SubItems[index].GetSubString(); return AString(); } const char * CXmlItem::ParseItem(const char *s, int numAllowedLevels) { SKIP_SPACES(s); const char *beg = s; for (;;) { char c; c = *s; if (c == 0 || c == '<') break; s++; c = *s; if (c == 0 || c == '<') break; s++; } if (*s == 0) return NULL; if (s != beg) { IsTag = false; Name.SetFrom(beg, (unsigned)(s - beg)); return s; } IsTag = true; s++; SKIP_SPACES(s); beg = s; for (;; s++) if (!IsValidChar(*s)) break; if (s == beg || *s == 0) return NULL; Name.SetFrom(beg, (unsigned)(s - beg)); for (;;) { beg = s; SKIP_SPACES(s); if (*s == '/') { s++; // SKIP_SPACES(s); if (*s != '>') return NULL; return s + 1; } if (*s == '>') { s++; if (numAllowedLevels == 0) return NULL; SubItems.Clear(); for (;;) { SKIP_SPACES(s); if (s[0] == '<' && s[1] == '/') break; CXmlItem &item = SubItems.AddNew(); s = item.ParseItem(s, numAllowedLevels - 1); if (!s) return NULL; } s += 2; unsigned len = Name.Len(); for (unsigned i = 0; i < len; i++) if (s[i] != Name[i]) return NULL; s += len; if (s[0] != '>') return NULL; return s + 1; } if (beg == s) return NULL; // ReadProperty CXmlProp &prop = Props.AddNew(); beg = s; for (;; s++) { char c = *s; if (!IsValidChar(c)) break; } if (s == beg) return NULL; prop.Name.SetFrom(beg, (unsigned)(s - beg)); SKIP_SPACES(s); if (*s != '=') return NULL; s++; SKIP_SPACES(s); if (*s != '\"') return NULL; s++; beg = s; for (;;) { char c = *s; if (c == 0) return NULL; if (c == '\"') break; s++; } prop.Value.SetFrom(beg, (unsigned)(s - beg)); s++; } } static const char * SkipHeader(const char *s, const char *startString, const char *endString) { SKIP_SPACES(s); if (IsString1PrefixedByString2(s, startString)) { s = strstr(s, endString); if (!s) return NULL; s += strlen(endString); } return s; } void CXmlItem::AppendTo(AString &s) const { if (IsTag) s += '<'; s += Name; if (IsTag) { FOR_VECTOR (i, Props) { const CXmlProp &prop = Props[i]; s += ' '; s += prop.Name; s += '='; s += '\"'; s += prop.Value; s += '\"'; } s += '>'; } FOR_VECTOR (i, SubItems) { const CXmlItem &item = SubItems[i]; if (i != 0 && !SubItems[i - 1].IsTag) s += ' '; item.AppendTo(s); } if (IsTag) { s += '<'; s += '/'; s += Name; s += '>'; } } bool CXml::Parse(const char *s) { s = SkipHeader(s, ""); if (!s) return false; s = SkipHeader(s, ""); if (!s) return false; s = Root.ParseItem(s, 1000); if (!s || !Root.IsTag) return false; SKIP_SPACES(s); return *s == 0; } /* void CXml::AppendTo(AString &s) const { Root.AppendTo(s); } */