1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24
25 #include <parse.hxx>
26
27 #include <string.h>
28 #include <iostream>
29 #include <xmlelem.hxx>
30
31 #if (_MSC_VER >=1400)
32 #pragma warning(disable:4365)
33 #endif
34
35 #ifdef UNX
36 #define strnicmp strncasecmp
37 #endif
38
39
40
41 // NOT FULLY DEFINED SERVICES
42
43
44
45 #define AssertionOf(x) \
46 {if (!(x)) {std::cerr << "Assertion failed: " << #x << __FILE__ << __LINE__ << std::endl; exit(3); }}
47
48
49
X2CParser(XmlElement & o_rDocumentData)50 X2CParser::X2CParser( XmlElement & o_rDocumentData )
51 : // sFileName,
52 nFileLine(0),
53 pDocumentData(&o_rDocumentData),
54 // sWord,
55 text(0)
56 {
57 }
58
~X2CParser()59 X2CParser::~X2CParser()
60 {
61 }
62
63
64 bool
LoadFile(const char * i_sFilename)65 X2CParser::LoadFile( const char * i_sFilename )
66 {
67 sFileName = i_sFilename;
68 nFileLine = 1;
69
70 // Load file:
71 if ( ! LoadXmlFile( aFile, i_sFilename ) )
72 return false;
73
74 // Test correct end:
75 const char * pLastTag = strrchr(aFile.operator const char *(),'<');
76 if (pLastTag == 0)
77 return false;
78 if ( strnicmp(pLastTag+2, pDocumentData->Name().str(), pDocumentData->Name().l()) != 0
79 || strnicmp(pLastTag, "</", 2) != 0 )
80 return false;
81 if (strchr(pLastTag,'>') == 0)
82 return false;
83 return true;
84 }
85
86 void
Parse()87 X2CParser::Parse()
88 {
89 // Parse:
90 text = aFile.operator const char *();
91
92 Parse_XmlDeclaration();
93 Parse_Doctype();
94
95 // skip XML comment
96 Goto('<');
97 if ( IsText("<!--") )
98 Goto_And_Pass('>');
99
100 pDocumentData->Parse(*this);
101 }
102
103 bool
Parse(const char * i_sFilename)104 X2CParser::Parse( const char * i_sFilename )
105 {
106 bool ret = LoadFile(i_sFilename);
107 if (ret)
108 Parse();
109 return ret;
110 }
111
112 void
Parse_XmlDeclaration()113 X2CParser::Parse_XmlDeclaration()
114 {
115 Goto('<');
116 if ( IsText("<?xml") )
117 {
118 Goto_And_Pass('>');
119 }
120 }
121
122 void
Parse_Doctype()123 X2CParser::Parse_Doctype()
124 {
125 Goto('<');
126 if ( IsText("<!DOCTYPE") )
127 Goto_And_Pass('>');
128 }
129
130 void
Parse_Sequence(DynamicList<XmlElement> & o_rElements,const Simstr & i_sElementName)131 X2CParser::Parse_Sequence( DynamicList<XmlElement> & o_rElements,
132 const Simstr & i_sElementName )
133 {
134 CheckAndPassBeginTag(i_sElementName.str());
135
136 unsigned int i_max = o_rElements.size();
137 for (unsigned i = 0; i < i_max; ++i)
138 {
139 o_rElements[i]->Parse(*this);
140 } // end for
141
142 CheckAndPassEndTag(i_sElementName.str());
143 }
144
145 void
Parse_FreeChoice(DynamicList<XmlElement> & o_rElements)146 X2CParser::Parse_FreeChoice( DynamicList<XmlElement> & o_rElements )
147 {
148 unsigned nSize = o_rElements.size();
149
150 for ( bool bBreak = false; !bBreak; )
151 {
152 bBreak = true;
153 for ( unsigned i = 0; i < nSize; ++i )
154 {
155 Goto('<');
156 if ( IsBeginTag(o_rElements[i]->Name().str()) )
157 {
158 o_rElements[i]->Parse(*this);
159 bBreak = false;
160 break;
161 }
162 } // end for i
163 } // end for !bBreak
164 }
165
166 void
Parse_List(ListElement & o_rListElem)167 X2CParser::Parse_List( ListElement & o_rListElem )
168 {
169
170 for ( Goto('<'); IsBeginTag(o_rListElem.Name().str()); Goto('<') )
171 {
172 XmlElement * pNew = o_rListElem.Create_and_Add_NewElement();
173 pNew->Parse(*this);
174 }
175 }
176
177 void
Parse_Text(Simstr & o_sText,const Simstr & i_sElementName,bool i_bReverseName)178 X2CParser::Parse_Text( Simstr & o_sText,
179 const Simstr & i_sElementName,
180 bool i_bReverseName )
181 {
182
183 if ( ! CheckAndPassBeginTag(i_sElementName.str()) )
184 return;
185
186 // Add new Element
187 GetTextTill( o_sText, '<', i_bReverseName );
188 o_sText.remove_trailing_blanks();
189
190 CheckAndPassEndTag(i_sElementName.str());
191 }
192
193 void
Parse_MultipleText(List<Simstr> & o_rTexts,const Simstr & i_sElementName,bool i_bReverseName)194 X2CParser::Parse_MultipleText( List<Simstr> & o_rTexts,
195 const Simstr & i_sElementName,
196 bool i_bReverseName )
197 {
198 for ( Goto('<'); IsBeginTag(i_sElementName.str()); Goto('<') )
199 {
200 Simstr sNew;
201 Parse_Text(sNew, i_sElementName, i_bReverseName);
202 if (sNew.l() > 0)
203 o_rTexts.push_back(sNew);
204 }
205 }
206
207 void
Parse_SglAttr(Simstr & o_sAttrValue,const Simstr & i_sElementName,const Simstr & i_sAttrName)208 X2CParser::Parse_SglAttr( Simstr & o_sAttrValue,
209 const Simstr & i_sElementName,
210 const Simstr & i_sAttrName )
211 {
212 Goto('<');
213 if ( !IsBeginTag(i_sElementName.str()) )
214 SyntaxError("unexpected element");
215 Move( i_sElementName.l() + 1 );
216
217 Pass_White();
218 if (*text == '>')
219 SyntaxError("no attribute found, where one was expected");
220 Simstr sAttrName;
221 Get_Attribute(o_sAttrValue, sAttrName);
222 if (sAttrName != i_sAttrName)
223 SyntaxError("unknown attribute found");
224 Pass_White();
225 if (strncmp(text,"/>",2) != 0)
226 SyntaxError("missing \"/>\" at end of empty element");
227 Move(2);
228 }
229
230 void
Parse_MultipleAttr(List<Simstr> & o_rAttrValues,const Simstr & i_sElementName,const List<Simstr> & i_rAttrNames)231 X2CParser::Parse_MultipleAttr( List<Simstr> & o_rAttrValues,
232 const Simstr & i_sElementName,
233 const List<Simstr> & i_rAttrNames )
234 {
235 Goto('<');
236 if ( !IsBeginTag(i_sElementName.str()) )
237 SyntaxError("unexpected element");
238 Move( i_sElementName.l() + 1 );
239 Simstr sAttrName;
240 Simstr sAttrValue;
241 unsigned nSize = i_rAttrNames.size();
242 unsigned i;
243
244 for ( Pass_White(); *text != '/'; Pass_White() )
245 {
246
247 Get_Attribute(sAttrValue, sAttrName);
248
249 for ( i = 0; i < nSize; ++i )
250 {
251 if ( i_rAttrNames[i] == sAttrName )
252 {
253 o_rAttrValues[i] = sAttrValue;
254 break;
255 }
256 }
257 if (i == nSize)
258 SyntaxError("unknown attribute found");
259 }
260 Move(2);
261 }
262
263
264 void
Get_Attribute(Simstr & o_rAttrValue,Simstr & o_rAttrName)265 X2CParser::Get_Attribute( Simstr & o_rAttrValue,
266 Simstr & o_rAttrName )
267 {
268 GetTextTill( o_rAttrName, '=');
269
270 while (*(++text) != '"')
271 {
272 if (*text == '\0')
273 SyntaxError("unexpected end of file");
274 }
275
276 ++text;
277 GetTextTill( o_rAttrValue, '"');
278 ++text;
279 }
280
281 bool
IsText(const char * i_sComparedText)282 X2CParser::IsText( const char * i_sComparedText )
283 {
284 return strnicmp( text, i_sComparedText, strlen(i_sComparedText) ) == 0;
285 }
286
287 bool
IsBeginTag(const char * i_sTagName)288 X2CParser::IsBeginTag( const char * i_sTagName )
289 {
290 return strnicmp( text+1, i_sTagName, strlen(i_sTagName) ) == 0
291 && *text == '<';
292 }
293
294 bool
IsEndTag(const char * i_sTagName)295 X2CParser::IsEndTag( const char * i_sTagName )
296 {
297 return strnicmp( text+2, i_sTagName, strlen(i_sTagName) ) == 0
298 && strnicmp( text, "</", 2 ) == 0;
299 }
300
301 void
Goto(char i_cNext)302 X2CParser::Goto( char i_cNext )
303 {
304 while (*text != i_cNext)
305 {
306 TestCurChar();
307 ++text;
308 }
309 }
310
311 void
Goto_And_Pass(char i_cNext)312 X2CParser::Goto_And_Pass( char i_cNext )
313 {
314 Goto(i_cNext);
315 ++text;
316 }
317
318 void
Move(int i_nForward)319 X2CParser::Move( int i_nForward )
320 {
321 text += i_nForward;
322 }
323
324 void
Pass_White()325 X2CParser::Pass_White()
326 {
327 while (*text <= 32)
328 {
329 TestCurChar();
330 ++text;
331 }
332 }
333
334 void
GetTextTill(Simstr & o_rText,char i_cEnd,bool i_bReverseName)335 X2CParser::GetTextTill( Simstr & o_rText,
336 char i_cEnd,
337 bool i_bReverseName )
338 {
339 char * pResult = &sWord[0];
340 char * pSet;
341
342 for ( pSet = pResult;
343 *text != i_cEnd;
344 ++text )
345 {
346 TestCurChar();
347 *pSet++ = *text;
348 }
349
350 while ( *pResult < 33 && *pResult > 0 )
351 ++pResult;
352 while ( pSet > pResult ? *(pSet-1) < 33 : false )
353 pSet--;
354 *pSet = '\0';
355
356
357 if (i_bReverseName)
358 {
359 const unsigned int nMaxLen = 1000;
360 if (strlen(pResult) < nMaxLen)
361 {
362 char * sBreak = strrchr(pResult,'.');
363 if (sBreak != 0)
364 {
365 static char sScope[nMaxLen+10];
366 static char sName[nMaxLen+10];
367
368 unsigned nScopeLen = sBreak - pResult;
369 strncpy ( sScope, pResult, nScopeLen ); // STRNCPY SAFE HERE
370 sScope[nScopeLen] = '\0';
371 strcpy( sName, sBreak + 1 ); // STRCPY SAFE HERE
372 strcat( sName, " in " ); // STRCAT SAFE HERE
373 strcat( sName, sScope ); // STRCAT SAFE HERE
374
375 o_rText = sName;
376 return;
377 }
378 }
379 } // endif (i_bReverseName)
380
381 o_rText = &sWord[0];
382 }
383
384 bool
CheckAndPassBeginTag(const char * i_sElementName)385 X2CParser::CheckAndPassBeginTag( const char * i_sElementName )
386 {
387 bool ret = true;
388 Goto('<');
389 if ( ! IsBeginTag(i_sElementName) )
390 SyntaxError( "unexpected element");
391 if (IsAbsoluteEmpty())
392 ret = false;
393 Goto_And_Pass('>');
394 if (ret)
395 Pass_White();
396 return ret;
397 }
398
399 void
CheckAndPassEndTag(const char * i_sElementName)400 X2CParser::CheckAndPassEndTag( const char * i_sElementName )
401 {
402 Pass_White();
403 if ( !IsEndTag(i_sElementName) )
404 SyntaxError("missing or not matching end tag");
405 Goto_And_Pass('>');
406 }
407
408 bool
IsAbsoluteEmpty() const409 X2CParser::IsAbsoluteEmpty() const
410 {
411 const char * pEnd = strchr(text+1, '>');
412 if (pEnd != 0)
413 {
414 if ( *(pEnd-1) == '/' )
415 {
416 const char * pAttr = strchr(text+1, '"');
417 if (pAttr == 0)
418 return true;
419 else if ( (pAttr-text) > (pEnd-text) )
420 return true;
421 }
422 }
423 return false;
424 }
425
426 void
SyntaxError(const char * i_sText)427 X2CParser::SyntaxError( const char * i_sText )
428 {
429 std::cerr
430 << "Syntax error "
431 << i_sText
432 << " in file: "
433 << sFileName.str()
434 << " in line "
435 << nFileLine
436 << "."
437 << std::endl;
438
439 exit(3);
440 }
441
442 void
TestCurChar()443 X2CParser::TestCurChar()
444 {
445 // if (*text == '\0')
446 // SyntaxError("unexpected end of file");
447 // else
448
449 if (*text == '\n')
450 nFileLine++;
451 }
452
453
454