xref: /aosp_15_r20/external/lzma/CPP/Common/MyXml.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
1 // MyXml.cpp
2 
3 #include "StdAfx.h"
4 
5 #include "MyXml.h"
6 #include "StringToInt.h"
7 
IsValidChar(char c)8 static bool IsValidChar(char c)
9 {
10   return
11     (c >= 'a' && c <= 'z') ||
12     (c >= 'A' && c <= 'Z') ||
13     (c >= '0' && c <= '9') ||
14     c == '-';
15 }
16 
IsSpaceChar(char c)17 static bool IsSpaceChar(char c)
18 {
19   return (c == ' ' || c == '\t' || c == 0x0D || c == 0x0A);
20 }
21 
22 #define SKIP_SPACES(s) while (IsSpaceChar(*s)) s++;
23 
FindProp(const char * propName) const24 int CXmlItem::FindProp(const char *propName) const throw()
25 {
26   FOR_VECTOR (i, Props)
27     if (Props[i].Name == propName)
28       return (int)i;
29   return -1;
30 }
31 
GetPropVal(const char * propName) const32 AString CXmlItem::GetPropVal(const char *propName) const
33 {
34   const int index = FindProp(propName);
35   if (index >= 0)
36     return Props[(unsigned)index].Value;
37   return AString();
38 }
39 
IsTagged(const char * tag) const40 bool CXmlItem::IsTagged(const char *tag) const throw()
41 {
42   return (IsTag && Name == tag);
43 }
44 
FindSubTag(const char * tag) const45 int CXmlItem::FindSubTag(const char *tag) const throw()
46 {
47   FOR_VECTOR (i, SubItems)
48     if (SubItems[i].IsTagged(tag))
49       return (int)i;
50   return -1;
51 }
52 
FindSubTag_GetPtr(const char * tag) const53 const CXmlItem *CXmlItem::FindSubTag_GetPtr(const char *tag) const throw()
54 {
55   FOR_VECTOR (i, SubItems)
56   {
57     const CXmlItem *p = &SubItems[i];
58     if (p->IsTagged(tag))
59       return p;
60   }
61   return NULL;
62 }
63 
GetSubString() const64 AString CXmlItem::GetSubString() const
65 {
66   if (SubItems.Size() == 1)
67   {
68     const CXmlItem &item = SubItems[0];
69     if (!item.IsTag)
70       return item.Name;
71   }
72   return AString();
73 }
74 
GetSubStringPtr() const75 const AString * CXmlItem::GetSubStringPtr() const throw()
76 {
77   if (SubItems.Size() == 1)
78   {
79     const CXmlItem &item = SubItems[0];
80     if (!item.IsTag)
81       return &item.Name;
82   }
83   return NULL;
84 }
85 
GetSubStringForTag(const char * tag) const86 AString CXmlItem::GetSubStringForTag(const char *tag) const
87 {
88   const CXmlItem *item = FindSubTag_GetPtr(tag);
89   if (item)
90     return item->GetSubString();
91   return AString();
92 }
93 
ParseItem(const char * s,int numAllowedLevels)94 const char * CXmlItem::ParseItem(const char *s, int numAllowedLevels)
95 {
96   SKIP_SPACES(s)
97 
98   const char *beg = s;
99   for (;;)
100   {
101     char c;
102     c = *s; if (c == 0 || c == '<') break; s++;
103     c = *s; if (c == 0 || c == '<') break; s++;
104   }
105   if (*s == 0)
106     return NULL;
107   {
108     const size_t num = (size_t)(s - beg);
109     if (num)
110     {
111       IsTag = false;
112       Name.SetFrom_Chars_SizeT(beg, num);
113       return s;
114     }
115   }
116 
117   IsTag = true;
118 
119   s++;
120   SKIP_SPACES(s)
121 
122   beg = s;
123   for (;; s++)
124     if (!IsValidChar(*s))
125       break;
126   if (s == beg || *s == 0)
127     return NULL;
128   Name.SetFrom_Chars_SizeT(beg, (size_t)(s - beg));
129 
130   for (;;)
131   {
132     beg = s;
133     SKIP_SPACES(s)
134     if (*s == '/')
135     {
136       s++;
137       // SKIP_SPACES(s)
138       if (*s != '>')
139         return NULL;
140       return s + 1;
141     }
142     if (*s == '>')
143     {
144       s++;
145       if (numAllowedLevels == 0)
146         return NULL;
147       SubItems.Clear();
148       for (;;)
149       {
150         SKIP_SPACES(s)
151         if (s[0] == '<' && s[1] == '/')
152           break;
153         CXmlItem &item = SubItems.AddNew();
154         s = item.ParseItem(s, numAllowedLevels - 1);
155         if (!s)
156           return NULL;
157       }
158 
159       s += 2;
160       const unsigned len = Name.Len();
161       const char *name = Name.Ptr();
162       for (unsigned i = 0; i < len; i++)
163         if (*s++ != *name++)
164           return NULL;
165       // s += len;
166       if (s[0] != '>')
167         return NULL;
168       return s + 1;
169     }
170     if (beg == s)
171       return NULL;
172 
173     // ReadProperty
174     CXmlProp &prop = Props.AddNew();
175 
176     beg = s;
177     for (;; s++)
178     {
179       char c = *s;
180       if (!IsValidChar(c))
181         break;
182     }
183     if (s == beg)
184       return NULL;
185     prop.Name.SetFrom_Chars_SizeT(beg, (size_t)(s - beg));
186 
187     SKIP_SPACES(s)
188     if (*s != '=')
189       return NULL;
190     s++;
191     SKIP_SPACES(s)
192     if (*s != '\"')
193       return NULL;
194     s++;
195 
196     beg = s;
197     for (;;)
198     {
199       char c = *s;
200       if (c == 0)
201         return NULL;
202       if (c == '\"')
203         break;
204       s++;
205     }
206     prop.Value.SetFrom_Chars_SizeT(beg, (size_t)(s - beg));
207     s++;
208   }
209 }
210 
SkipHeader(const char * s,const char * startString,const char * endString)211 static const char * SkipHeader(const char *s, const char *startString, const char *endString)
212 {
213   SKIP_SPACES(s)
214   if (IsString1PrefixedByString2(s, startString))
215   {
216     s = strstr(s, endString);
217     if (!s)
218       return NULL;
219     s += strlen(endString);
220   }
221   return s;
222 }
223 
AppendTo(AString & s) const224 void CXmlItem::AppendTo(AString &s) const
225 {
226   if (IsTag)
227     s += '<';
228   s += Name;
229   if (IsTag)
230   {
231     FOR_VECTOR (i, Props)
232     {
233       const CXmlProp &prop = Props[i];
234       s.Add_Space();
235       s += prop.Name;
236       s += '=';
237       s += '\"';
238       s += prop.Value;
239       s += '\"';
240     }
241     s += '>';
242   }
243   FOR_VECTOR (i, SubItems)
244   {
245     const CXmlItem &item = SubItems[i];
246     if (i != 0 && !SubItems[i - 1].IsTag)
247       s.Add_Space();
248     item.AppendTo(s);
249   }
250   if (IsTag)
251   {
252     s += '<';
253     s += '/';
254     s += Name;
255     s += '>';
256   }
257 }
258 
Parse(const char * s)259 bool CXml::Parse(const char *s)
260 {
261   s = SkipHeader(s, "<?xml",    "?>"); if (!s) return false;
262   s = SkipHeader(s, "<!DOCTYPE", ">"); if (!s) return false;
263 
264   s = Root.ParseItem(s, 1000);
265   if (!s || !Root.IsTag)
266     return false;
267   SKIP_SPACES(s)
268   return *s == 0;
269 }
270 
271 /*
272 void CXml::AppendTo(AString &s) const
273 {
274   Root.AppendTo(s);
275 }
276 */
277 
278 
z7_xml_DecodeString(AString & temp)279 void z7_xml_DecodeString(AString &temp)
280 {
281   char * const beg = temp.GetBuf();
282   char *dest = beg;
283   const char *p = beg;
284   for (;;)
285   {
286     char c = *p++;
287     if (c == 0)
288       break;
289     if (c == '&')
290     {
291       if (p[0] == '#')
292       {
293         const char *end;
294         const UInt32 number = ConvertStringToUInt32(p + 1, &end);
295         if (*end == ';' && number != 0 && number <= 127)
296         {
297           p = end + 1;
298           c = (char)number;
299         }
300       }
301       else if (
302           p[0] == 'a' &&
303           p[1] == 'm' &&
304           p[2] == 'p' &&
305           p[3] == ';')
306       {
307         p += 4;
308       }
309       else if (
310           p[0] == 'l' &&
311           p[1] == 't' &&
312           p[2] == ';')
313       {
314         p += 3;
315         c = '<';
316       }
317       else if (
318           p[0] == 'g' &&
319           p[1] == 't' &&
320           p[2] == ';')
321       {
322         p += 3;
323         c = '>';
324       }
325       else if (
326           p[0] == 'a' &&
327           p[1] == 'p' &&
328           p[2] == 'o' &&
329           p[3] == 's' &&
330           p[4] == ';')
331       {
332         p += 5;
333         c = '\'';
334       }
335       else if (
336           p[0] == 'q' &&
337           p[1] == 'u' &&
338           p[2] == 'o' &&
339           p[3] == 't' &&
340           p[4] == ';')
341       {
342         p += 5;
343         c = '\"';
344       }
345     }
346     *dest++ = c;
347   }
348   temp.ReleaseBuf_SetEnd((unsigned)(dest - beg));
349 }
350