extras:types:CountryCode: re-introducing functionality removed by a7d522a3822bbe30235...
[sdk] / extras / XMLParser.ec
1 import "ecere"
2
3 #define MAX_TAG_LEN  2048
4
5 enum WordStatus
6 {
7    None,
8    Normal,
9    Quoted
10 };
11
12 static WordStatus GetKeyWordEx(char ** input, char * keyWord, int maxSize, bool treatEqual)
13 {
14    char * string = *input;
15    char ch;
16    int c = 0;
17    bool quoted = false, start = true, wasQuoted = false;
18
19    for(; (ch = *string); string++)
20    {
21       if(!quoted && wasQuoted)
22          break;
23
24       if((ch == ' ' || ch == '\t') && !quoted) 
25       {
26          if(!start) break;
27       }
28       else
29       {
30          if(!quoted && ((ch == ',' || (treatEqual && ch == '=')) || ch == '>') )
31             break;
32          else if(ch == '\"' /*|| ch == '\''*/)
33          {
34             quoted ^= true;
35             wasQuoted = true;
36             start = false;
37          }
38          else if(ch != '\r' && ch != '\n')
39          {
40             if(c < maxSize) 
41                keyWord[c++] = ch;
42             start = false;
43          }
44       }
45    }
46    for(;*string == '>' || *string == ',' || *string == ' ' || *string == '=' || *string == '\t' || *string == '\r' || *string == '\n'; string++);
47    keyWord[c] = '\0';
48    *input = string;
49    return (c > 0) ? (wasQuoted ? Quoted : Normal) : None;
50 }
51
52 static WordStatus GetKeyWord(char ** input, char * keyWord, int maxSize)
53 {
54    return GetKeyWordEx(input, keyWord, maxSize, true);
55 }
56
57 #define CHARBUFSIZE  65536
58
59 class XMLParser
60 {
61    virtual void ProcessKeyword(char * keyWord);
62    virtual void ProcessCharacterData(char * data);
63
64    char keyWord[1024];
65    char * string;
66    int xmlDepth;
67    bool closingTag;
68    bool openingTag;
69
70    bool GetWord()
71    {
72       if(string && string[0])
73       {
74          GetKeyWord(&string, keyWord, sizeof(keyWord));
75          return true;
76       }
77       return false;
78    }
79
80    bool Parse(char * inputString, int count)
81    {
82       bool insideTag = false;
83       char tag[MAX_TAG_LEN];
84       int tagLen;
85       bool commented = false;
86       byte lastCh = ' ';
87       int stringPos;
88       byte characterData[CHARBUFSIZE];
89       int charLen = 0;
90       int oldDepth = xmlDepth;
91       
92       closingTag = false;
93       
94       // Preparse to check for completeness
95       for(stringPos = 0; stringPos < count; stringPos++)
96       {
97          byte ch = inputString[stringPos];
98       
99          if(commented)
100          {
101             if((ch == '-' && tagLen < 2) || (ch == '>' && tagLen == 2))
102             {
103                if(!strcmp(tag,  "-->"))
104                {
105                   commented = false;
106                }
107             }
108          }
109          else if(insideTag)
110          {
111             if(ch == '/' && lastCh == '<')
112                closingTag = true;
113
114             if(ch == '<')
115             {
116                insideTag++;
117             }
118             else if(ch == '>')
119             {
120                if(closingTag)
121                   xmlDepth--;
122                else if(lastCh != '?' && lastCh != '/')
123                   xmlDepth++;
124                insideTag--;
125                closingTag = false;
126             }
127             
128             if(!strcmp(tag, "!--"))
129             {
130                commented = true;
131                insideTag = false;
132             }
133          }
134          else
135          {
136             if(ch == '<')
137             {
138                insideTag = true;
139             }
140          }
141          lastCh = ch;
142       }
143       if(xmlDepth > 1 || insideTag || commented)
144       {
145          xmlDepth = oldDepth;
146          return false;
147       }
148
149       xmlDepth = oldDepth;
150       commented = false;
151       lastCh = ' ';
152       charLen = 0;
153       insideTag = false;
154       closingTag = false;
155       openingTag = false;
156
157       // Parse entire file
158       for(stringPos = 0; stringPos < count; stringPos++)
159       {
160          byte ch = inputString[stringPos];
161       
162          if(commented)
163          {
164             if((ch == '-' && tagLen < 2) || (ch == '>' && tagLen == 2))
165             {
166                tag[tagLen++] = ch;
167                tag[tagLen] = '\0';
168                if(!strcmp(tag,  "-->"))
169                {
170                   commented = false;
171                }
172             }
173             else
174                tagLen = 0;
175          }
176          else if(insideTag)
177          {
178             if(ch == '/' && lastCh == '<')
179                closingTag = true;
180             if(ch == '<')
181             {
182                insideTag++;
183                openingTag = true;
184             }
185             else if(ch == '>')
186             {
187                if(closingTag)
188                   xmlDepth--;
189                else if(lastCh != '?' && lastCh != '/')
190                   xmlDepth++;
191                else
192                {
193                   closingTag = true;
194                   openingTag = true;
195                }
196
197                insideTag--;
198                if(!insideTag)
199                {
200                   tag[tagLen] = '\0';
201                   insideTag = false;
202
203                   string = tag;
204
205                   if(GetKeyWord(&string, keyWord, sizeof(keyWord)))
206                   {
207                      ProcessKeyword(keyWord);
208                   }
209                }
210                else
211                {
212                   tag[tagLen++] = ch;
213                   tag[tagLen] = '\0';
214                }
215                closingTag = false;
216             }
217             else if(ch != '/' || lastCh != '<')
218             {
219                tag[tagLen++] = ch;
220                tag[tagLen] = '\0';
221             }
222             else
223                openingTag = false;
224             if(!strcmp(tag, "!--"))
225             {
226                commented = true;
227                insideTag = false;
228                tagLen = 0;
229                tag[tagLen] = '\0';
230             }
231          }
232          else
233          {
234             if(ch == '<' || charLen == CHARBUFSIZE - 1)
235             {
236                ProcessCharacterData(characterData);
237                charLen = 0;               
238             }
239             if(ch == '<')
240             {
241                openingTag = true;
242                insideTag = true;
243                tagLen = 0;
244             }
245             else
246             {
247                characterData[charLen++] = ch;
248                characterData[charLen] = 0;
249             }
250          }
251          lastCh = ch;
252       }
253       return true;
254    }
255 }