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 }
|