aboutsummaryrefslogtreecommitdiff
path: root/CPP/Common/MyXml.cpp
diff options
context:
space:
mode:
authorIgor Pavlov <87184205+ip7z@users.noreply.github.com>2021-12-27 00:00:00 +0000
committerIgor Pavlov <87184205+ip7z@users.noreply.github.com>2022-03-18 15:35:13 +0500
commitf19f813537c7aea1c20749c914e756b54a9c3cf5 (patch)
tree816ba62ca7c0fa19f2eb46d9e9d6f7dd7c3a744d /CPP/Common/MyXml.cpp
parent98e06a519b63b81986abe76d28887f6984a7732b (diff)
download7zip-21.07.tar.gz
7zip-21.07.tar.bz2
7zip-21.07.zip
'21.07'21.07
Diffstat (limited to 'CPP/Common/MyXml.cpp')
-rw-r--r--CPP/Common/MyXml.cpp260
1 files changed, 260 insertions, 0 deletions
diff --git a/CPP/Common/MyXml.cpp b/CPP/Common/MyXml.cpp
new file mode 100644
index 0000000..e014518
--- /dev/null
+++ b/CPP/Common/MyXml.cpp
@@ -0,0 +1,260 @@
1// MyXml.cpp
2
3#include "StdAfx.h"
4
5#include "MyXml.h"
6
7static bool IsValidChar(char c)
8{
9 return
10 (c >= 'a' && c <= 'z') ||
11 (c >= 'A' && c <= 'Z') ||
12 (c >= '0' && c <= '9') ||
13 c == '-';
14}
15
16static bool IsSpaceChar(char c)
17{
18 return (c == ' ' || c == '\t' || c == 0x0D || c == 0x0A);
19}
20
21#define SKIP_SPACES(s) while (IsSpaceChar(*s)) s++;
22
23int CXmlItem::FindProp(const char *propName) const throw()
24{
25 FOR_VECTOR (i, Props)
26 if (Props[i].Name == propName)
27 return (int)i;
28 return -1;
29}
30
31AString CXmlItem::GetPropVal(const char *propName) const
32{
33 int index = FindProp(propName);
34 if (index >= 0)
35 return Props[(unsigned)index].Value;
36 return AString();
37}
38
39bool CXmlItem::IsTagged(const char *tag) const throw()
40{
41 return (IsTag && Name == tag);
42}
43
44int CXmlItem::FindSubTag(const char *tag) const throw()
45{
46 FOR_VECTOR (i, SubItems)
47 if (SubItems[i].IsTagged(tag))
48 return (int)i;
49 return -1;
50}
51
52AString CXmlItem::GetSubString() const
53{
54 if (SubItems.Size() == 1)
55 {
56 const CXmlItem &item = SubItems[0];
57 if (!item.IsTag)
58 return item.Name;
59 }
60 return AString();
61}
62
63const AString * CXmlItem::GetSubStringPtr() const throw()
64{
65 if (SubItems.Size() == 1)
66 {
67 const CXmlItem &item = SubItems[0];
68 if (!item.IsTag)
69 return &item.Name;
70 }
71 return NULL;
72}
73
74AString CXmlItem::GetSubStringForTag(const char *tag) const
75{
76 int index = FindSubTag(tag);
77 if (index >= 0)
78 return SubItems[(unsigned)index].GetSubString();
79 return AString();
80}
81
82const char * CXmlItem::ParseItem(const char *s, int numAllowedLevels)
83{
84 SKIP_SPACES(s);
85
86 const char *beg = s;
87 for (;;)
88 {
89 char c;
90 c = *s; if (c == 0 || c == '<') break; s++;
91 c = *s; if (c == 0 || c == '<') break; s++;
92 }
93 if (*s == 0)
94 return NULL;
95 if (s != beg)
96 {
97 IsTag = false;
98 Name.SetFrom(beg, (unsigned)(s - beg));
99 return s;
100 }
101
102 IsTag = true;
103
104 s++;
105 SKIP_SPACES(s);
106
107 beg = s;
108 for (;; s++)
109 if (!IsValidChar(*s))
110 break;
111 if (s == beg || *s == 0)
112 return NULL;
113 Name.SetFrom(beg, (unsigned)(s - beg));
114
115 for (;;)
116 {
117 beg = s;
118 SKIP_SPACES(s);
119 if (*s == '/')
120 {
121 s++;
122 // SKIP_SPACES(s);
123 if (*s != '>')
124 return NULL;
125 return s + 1;
126 }
127 if (*s == '>')
128 {
129 s++;
130 if (numAllowedLevels == 0)
131 return NULL;
132 SubItems.Clear();
133 for (;;)
134 {
135 SKIP_SPACES(s);
136 if (s[0] == '<' && s[1] == '/')
137 break;
138 CXmlItem &item = SubItems.AddNew();
139 s = item.ParseItem(s, numAllowedLevels - 1);
140 if (!s)
141 return NULL;
142 }
143
144 s += 2;
145 unsigned len = Name.Len();
146 for (unsigned i = 0; i < len; i++)
147 if (s[i] != Name[i])
148 return NULL;
149 s += len;
150 if (s[0] != '>')
151 return NULL;
152 return s + 1;
153 }
154 if (beg == s)
155 return NULL;
156
157 // ReadProperty
158 CXmlProp &prop = Props.AddNew();
159
160 beg = s;
161 for (;; s++)
162 {
163 char c = *s;
164 if (!IsValidChar(c))
165 break;
166 }
167 if (s == beg)
168 return NULL;
169 prop.Name.SetFrom(beg, (unsigned)(s - beg));
170
171 SKIP_SPACES(s);
172 if (*s != '=')
173 return NULL;
174 s++;
175 SKIP_SPACES(s);
176 if (*s != '\"')
177 return NULL;
178 s++;
179
180 beg = s;
181 for (;;)
182 {
183 char c = *s;
184 if (c == 0)
185 return NULL;
186 if (c == '\"')
187 break;
188 s++;
189 }
190 prop.Value.SetFrom(beg, (unsigned)(s - beg));
191 s++;
192 }
193}
194
195static const char * SkipHeader(const char *s, const char *startString, const char *endString)
196{
197 SKIP_SPACES(s);
198 if (IsString1PrefixedByString2(s, startString))
199 {
200 s = strstr(s, endString);
201 if (!s)
202 return NULL;
203 s += strlen(endString);
204 }
205 return s;
206}
207
208void CXmlItem::AppendTo(AString &s) const
209{
210 if (IsTag)
211 s += '<';
212 s += Name;
213 if (IsTag)
214 {
215 FOR_VECTOR (i, Props)
216 {
217 const CXmlProp &prop = Props[i];
218 s += ' ';
219 s += prop.Name;
220 s += '=';
221 s += '\"';
222 s += prop.Value;
223 s += '\"';
224 }
225 s += '>';
226 }
227 FOR_VECTOR (i, SubItems)
228 {
229 const CXmlItem &item = SubItems[i];
230 if (i != 0 && !SubItems[i - 1].IsTag)
231 s += ' ';
232 item.AppendTo(s);
233 }
234 if (IsTag)
235 {
236 s += '<';
237 s += '/';
238 s += Name;
239 s += '>';
240 }
241}
242
243bool CXml::Parse(const char *s)
244{
245 s = SkipHeader(s, "<?xml", "?>"); if (!s) return false;
246 s = SkipHeader(s, "<!DOCTYPE", ">"); if (!s) return false;
247
248 s = Root.ParseItem(s, 1000);
249 if (!s || !Root.IsTag)
250 return false;
251 SKIP_SPACES(s);
252 return *s == 0;
253}
254
255/*
256void CXml::AppendTo(AString &s) const
257{
258 Root.AppendTo(s);
259}
260*/