annotate src/win32/7zip/7z/CPP/Common/MyXml.cpp @ 1:f9f4f1b99eed

importing src directory
author Robert McIntyre <rlm@mit.edu>
date Sat, 03 Mar 2012 10:31:27 -0600
parents
children
rev   line source
rlm@1 1 // MyXml.cpp
rlm@1 2
rlm@1 3 #include "StdAfx.h"
rlm@1 4
rlm@1 5 #include "MyXml.h"
rlm@1 6
rlm@1 7 static bool IsValidChar(char c)
rlm@1 8 {
rlm@1 9 return
rlm@1 10 c >= 'a' && c <= 'z' ||
rlm@1 11 c >= 'A' && c <= 'Z' ||
rlm@1 12 c >= '0' && c <= '9' ||
rlm@1 13 c == '-';
rlm@1 14 }
rlm@1 15
rlm@1 16 static bool IsSpaceChar(char c)
rlm@1 17 {
rlm@1 18 return (c == ' ' || c == '\t' || c == 0x0D || c == 0x0A);
rlm@1 19 }
rlm@1 20
rlm@1 21 #define SKEEP_SPACES(s, pos) while (IsSpaceChar(s[pos])) pos++;
rlm@1 22
rlm@1 23 static bool ReadProperty(const AString &s, int &pos, CXmlProp &prop)
rlm@1 24 {
rlm@1 25 prop.Name.Empty();
rlm@1 26 prop.Value.Empty();
rlm@1 27 for (; pos < s.Length(); pos++)
rlm@1 28 {
rlm@1 29 char c = s[pos];
rlm@1 30 if (!IsValidChar(c))
rlm@1 31 break;
rlm@1 32 prop.Name += c;
rlm@1 33 }
rlm@1 34
rlm@1 35 if (prop.Name.IsEmpty())
rlm@1 36 return false;
rlm@1 37
rlm@1 38 SKEEP_SPACES(s, pos);
rlm@1 39 if (s[pos++] != '=')
rlm@1 40 return false;
rlm@1 41
rlm@1 42 SKEEP_SPACES(s, pos);
rlm@1 43 if (s[pos++] != '\"')
rlm@1 44 return false;
rlm@1 45
rlm@1 46 while (pos < s.Length())
rlm@1 47 {
rlm@1 48 char c = s[pos++];
rlm@1 49 if (c == '\"')
rlm@1 50 return true;
rlm@1 51 prop.Value += c;
rlm@1 52 }
rlm@1 53 return false;
rlm@1 54 }
rlm@1 55
rlm@1 56 int CXmlItem::FindProperty(const AString &propName) const
rlm@1 57 {
rlm@1 58 for (int i = 0; i < Props.Size(); i++)
rlm@1 59 if (Props[i].Name == propName)
rlm@1 60 return i;
rlm@1 61 return -1;
rlm@1 62 }
rlm@1 63
rlm@1 64 AString CXmlItem::GetPropertyValue(const AString &propName) const
rlm@1 65 {
rlm@1 66 int index = FindProperty(propName);
rlm@1 67 if (index >= 0)
rlm@1 68 return Props[index].Value;
rlm@1 69 return AString();
rlm@1 70 }
rlm@1 71
rlm@1 72 bool CXmlItem::IsTagged(const AString &tag) const
rlm@1 73 {
rlm@1 74 return (IsTag && Name == tag);
rlm@1 75 }
rlm@1 76
rlm@1 77 int CXmlItem::FindSubTag(const AString &tag) const
rlm@1 78 {
rlm@1 79 for (int i = 0; i < SubItems.Size(); i++)
rlm@1 80 if (SubItems[i].IsTagged(tag))
rlm@1 81 return i;
rlm@1 82 return -1;
rlm@1 83 }
rlm@1 84
rlm@1 85 AString CXmlItem::GetSubString() const
rlm@1 86 {
rlm@1 87 if (SubItems.Size() == 1)
rlm@1 88 {
rlm@1 89 const CXmlItem &item = SubItems[0];
rlm@1 90 if (!item.IsTag)
rlm@1 91 return item.Name;
rlm@1 92 }
rlm@1 93 return AString();
rlm@1 94 }
rlm@1 95
rlm@1 96 AString CXmlItem::GetSubStringForTag(const AString &tag) const
rlm@1 97 {
rlm@1 98 int index = FindSubTag(tag);
rlm@1 99 if (index >= 0)
rlm@1 100 return SubItems[index].GetSubString();
rlm@1 101 return AString();
rlm@1 102 }
rlm@1 103
rlm@1 104 bool CXmlItem::ParseItems(const AString &s, int &pos, int numAllowedLevels)
rlm@1 105 {
rlm@1 106 if (numAllowedLevels == 0)
rlm@1 107 return false;
rlm@1 108 SubItems.Clear();
rlm@1 109 AString finishString = "</";
rlm@1 110 for (;;)
rlm@1 111 {
rlm@1 112 SKEEP_SPACES(s, pos);
rlm@1 113
rlm@1 114 if (s.Mid(pos, finishString.Length()) == finishString)
rlm@1 115 return true;
rlm@1 116
rlm@1 117 CXmlItem item;
rlm@1 118 if (!item.ParseItem(s, pos, numAllowedLevels - 1))
rlm@1 119 return false;
rlm@1 120 SubItems.Add(item);
rlm@1 121 }
rlm@1 122 }
rlm@1 123
rlm@1 124 bool CXmlItem::ParseItem(const AString &s, int &pos, int numAllowedLevels)
rlm@1 125 {
rlm@1 126 SKEEP_SPACES(s, pos);
rlm@1 127
rlm@1 128 int pos2 = s.Find('<', pos);
rlm@1 129 if (pos2 < 0)
rlm@1 130 return false;
rlm@1 131 if (pos2 != pos)
rlm@1 132 {
rlm@1 133 IsTag = false;
rlm@1 134 Name += s.Mid(pos, pos2 - pos);
rlm@1 135 pos = pos2;
rlm@1 136 return true;
rlm@1 137 }
rlm@1 138 IsTag = true;
rlm@1 139
rlm@1 140 pos++;
rlm@1 141 SKEEP_SPACES(s, pos);
rlm@1 142
rlm@1 143 for (; pos < s.Length(); pos++)
rlm@1 144 {
rlm@1 145 char c = s[pos];
rlm@1 146 if (!IsValidChar(c))
rlm@1 147 break;
rlm@1 148 Name += c;
rlm@1 149 }
rlm@1 150 if (Name.IsEmpty() || pos == s.Length())
rlm@1 151 return false;
rlm@1 152
rlm@1 153 int posTemp = pos;
rlm@1 154 for (;;)
rlm@1 155 {
rlm@1 156 SKEEP_SPACES(s, pos);
rlm@1 157 if (s[pos] == '/')
rlm@1 158 {
rlm@1 159 pos++;
rlm@1 160 // SKEEP_SPACES(s, pos);
rlm@1 161 return (s[pos++] == '>');
rlm@1 162 }
rlm@1 163 if (s[pos] == '>')
rlm@1 164 {
rlm@1 165 if (!ParseItems(s, ++pos, numAllowedLevels))
rlm@1 166 return false;
rlm@1 167 AString finishString = AString("</") + Name + AString(">");
rlm@1 168 if (s.Mid(pos, finishString.Length()) != finishString)
rlm@1 169 return false;
rlm@1 170 pos += finishString.Length();
rlm@1 171 return true;
rlm@1 172 }
rlm@1 173 if (posTemp == pos)
rlm@1 174 return false;
rlm@1 175
rlm@1 176 CXmlProp prop;
rlm@1 177 if (!ReadProperty(s, pos, prop))
rlm@1 178 return false;
rlm@1 179 Props.Add(prop);
rlm@1 180 posTemp = pos;
rlm@1 181 }
rlm@1 182 }
rlm@1 183
rlm@1 184 bool SkeepHeader(const AString &s, int &pos, const AString &startString, const AString &endString)
rlm@1 185 {
rlm@1 186 SKEEP_SPACES(s, pos);
rlm@1 187 if (s.Mid(pos, startString.Length()) == startString)
rlm@1 188 {
rlm@1 189 pos = s.Find(endString, pos);
rlm@1 190 if (pos < 0)
rlm@1 191 return false;
rlm@1 192 pos += endString.Length();
rlm@1 193 SKEEP_SPACES(s, pos);
rlm@1 194 }
rlm@1 195 return true;
rlm@1 196 }
rlm@1 197
rlm@1 198 bool CXml::Parse(const AString &s)
rlm@1 199 {
rlm@1 200 int pos = 0;
rlm@1 201 if (!SkeepHeader(s, pos, "<?xml", "?>"))
rlm@1 202 return false;
rlm@1 203 if (!SkeepHeader(s, pos, "<!DOCTYPE", ">"))
rlm@1 204 return false;
rlm@1 205 if (!Root.ParseItem(s, pos, 1000))
rlm@1 206 return false;
rlm@1 207 SKEEP_SPACES(s, pos);
rlm@1 208 return (pos == s.Length() && Root.IsTag);
rlm@1 209 }