xref: /AOO41X/main/xml2cmp/source/xcd/parse.cxx (revision 8809db7a87f97847b57a57f4cd2b0104b2b83182)
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 
50 X2CParser::X2CParser( XmlElement & o_rDocumentData )
51     :   // sFileName,
52         nFileLine(0),
53         pDocumentData(&o_rDocumentData),
54         // sWord,
55         text(0)
56 {
57 }
58 
59 X2CParser::~X2CParser()
60 {
61 }
62 
63 
64 bool
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
87 X2CParser::Parse()
88 {
89     // Parse:
90     text = aFile.operator const char *();
91 
92     Parse_XmlDeclaration();
93     Parse_Doctype();
94 
95     pDocumentData->Parse(*this);
96 }
97 
98 bool
99 X2CParser::Parse( const char * i_sFilename )
100 {
101     bool ret = LoadFile(i_sFilename);
102     if (ret)
103         Parse();
104     return ret;
105 }
106 
107 void
108 X2CParser::Parse_XmlDeclaration()
109 {
110     Goto('<');
111     if ( IsText("<?xml") )
112     {
113         Goto_And_Pass('>');
114     }
115 }
116 
117 void
118 X2CParser::Parse_Doctype()
119 {
120     Goto('<');
121     if ( IsText("<!DOCTYPE") )
122         Goto_And_Pass('>');
123 }
124 
125 void
126 X2CParser::Parse_Sequence( DynamicList<XmlElement> & o_rElements,
127                            const Simstr &            i_sElementName  )
128 {
129     CheckAndPassBeginTag(i_sElementName.str());
130 
131     unsigned int i_max = o_rElements.size();
132     for (unsigned i = 0; i < i_max; ++i)
133     {
134         o_rElements[i]->Parse(*this);
135     }  // end for
136 
137     CheckAndPassEndTag(i_sElementName.str());
138 }
139 
140 void
141 X2CParser::Parse_FreeChoice( DynamicList<XmlElement> & o_rElements )
142 {
143     unsigned        nSize = o_rElements.size();
144 
145     for ( bool bBreak = false;  !bBreak; )
146     {
147         bBreak = true;
148         for ( unsigned i = 0; i < nSize; ++i )
149         {
150             Goto('<');
151             if ( IsBeginTag(o_rElements[i]->Name().str()) )
152             {
153                 o_rElements[i]->Parse(*this);
154                 bBreak = false;
155                 break;
156             }
157         }   // end for i
158     }   // end for !bBreak
159 }
160 
161 void
162 X2CParser::Parse_List( ListElement &  o_rListElem )
163 {
164 
165     for ( Goto('<'); IsBeginTag(o_rListElem.Name().str()); Goto('<') )
166     {
167         XmlElement * pNew = o_rListElem.Create_and_Add_NewElement();
168         pNew->Parse(*this);
169     }
170 }
171 
172 void
173 X2CParser::Parse_Text( Simstr &         o_sText,
174                        const Simstr &   i_sElementName,
175                        bool             i_bReverseName )
176 {
177 
178     if ( ! CheckAndPassBeginTag(i_sElementName.str()) )
179         return;
180 
181     // Add new Element
182     GetTextTill( o_sText, '<', i_bReverseName );
183     o_sText.remove_trailing_blanks();
184 
185     CheckAndPassEndTag(i_sElementName.str());
186 }
187 
188 void
189 X2CParser::Parse_MultipleText( List<Simstr> &   o_rTexts,
190                                const Simstr &   i_sElementName,
191                                bool             i_bReverseName )
192 {
193     for ( Goto('<'); IsBeginTag(i_sElementName.str()); Goto('<') )
194     {
195         Simstr sNew;
196         Parse_Text(sNew, i_sElementName, i_bReverseName);
197         if (sNew.l() > 0)
198             o_rTexts.push_back(sNew);
199     }
200 }
201 
202 void
203 X2CParser::Parse_SglAttr( Simstr &          o_sAttrValue,
204                           const Simstr &    i_sElementName,
205                           const Simstr &    i_sAttrName )
206 {
207     Goto('<');
208     if ( !IsBeginTag(i_sElementName.str()) )
209         SyntaxError("unexpected element");
210     Move( i_sElementName.l() + 1 );
211 
212     Pass_White();
213     if (*text == '>')
214         SyntaxError("no attribute found, where one was expected");
215     Simstr sAttrName;
216     Get_Attribute(o_sAttrValue, sAttrName);
217     if (sAttrName != i_sAttrName)
218         SyntaxError("unknown attribute found");
219     Pass_White();
220     if (strncmp(text,"/>",2) != 0)
221         SyntaxError("missing \"/>\" at end of empty element");
222     Move(2);
223 }
224 
225 void
226 X2CParser::Parse_MultipleAttr( List<Simstr> &       o_rAttrValues,
227                                const Simstr &       i_sElementName,
228                                const List<Simstr> & i_rAttrNames )
229 {
230     Goto('<');
231     if ( !IsBeginTag(i_sElementName.str()) )
232         SyntaxError("unexpected element");
233     Move( i_sElementName.l() + 1 );
234     Simstr sAttrName;
235     Simstr sAttrValue;
236     unsigned nSize = i_rAttrNames.size();
237     unsigned i;
238 
239     for ( Pass_White(); *text != '/'; Pass_White() )
240     {
241 
242         Get_Attribute(sAttrValue, sAttrName);
243 
244         for ( i = 0; i < nSize; ++i )
245         {
246             if ( i_rAttrNames[i] == sAttrName )
247             {
248                 o_rAttrValues[i] = sAttrValue;
249                 break;
250             }
251         }
252         if (i == nSize)
253             SyntaxError("unknown attribute found");
254     }
255     Move(2);
256 }
257 
258 
259 void
260 X2CParser::Get_Attribute( Simstr & o_rAttrValue,
261                           Simstr & o_rAttrName )
262 {
263     GetTextTill( o_rAttrName, '=');
264 
265     while (*(++text) != '"')
266     {
267         if (*text == '\0')
268             SyntaxError("unexpected end of file");
269     }
270 
271     ++text;
272     GetTextTill( o_rAttrValue, '"');
273     ++text;
274 }
275 
276 bool
277 X2CParser::IsText( const char * i_sComparedText )
278 {
279     return strnicmp( text, i_sComparedText, strlen(i_sComparedText) ) == 0;
280 }
281 
282 bool
283 X2CParser::IsBeginTag( const char * i_sTagName )
284 {
285     return strnicmp( text+1, i_sTagName, strlen(i_sTagName) ) == 0
286            && *text == '<';
287 }
288 
289 bool
290 X2CParser::IsEndTag( const char * i_sTagName )
291 {
292     return strnicmp( text+2, i_sTagName, strlen(i_sTagName) ) == 0
293            && strnicmp( text, "</", 2 ) == 0;
294 }
295 
296 void
297 X2CParser::Goto( char i_cNext )
298 {
299     while (*text != i_cNext)
300     {
301         TestCurChar();
302         ++text;
303     }
304 }
305 
306 void
307 X2CParser::Goto_And_Pass( char i_cNext )
308 {
309     Goto(i_cNext);
310     ++text;
311 }
312 
313 void
314 X2CParser::Move( int i_nForward )
315 {
316     text += i_nForward;
317 }
318 
319 void
320 X2CParser::Pass_White()
321 {
322     while (*text <= 32)
323     {
324         TestCurChar();
325         ++text;
326     }
327 }
328 
329 void
330 X2CParser::GetTextTill( Simstr & o_rText,
331                         char     i_cEnd,
332                         bool     i_bReverseName )
333 {
334     char * pResult = &sWord[0];
335     char * pSet;
336 
337     for ( pSet = pResult;
338           *text != i_cEnd;
339           ++text )
340     {
341         TestCurChar();
342         *pSet++ = *text;
343     }
344 
345     while ( *pResult < 33 && *pResult > 0 )
346         ++pResult;
347     while ( pSet > pResult ? *(pSet-1) < 33 : false )
348         pSet--;
349     *pSet = '\0';
350 
351 
352     if (i_bReverseName)
353     {
354         const unsigned int nMaxLen = 1000;
355         if (strlen(pResult) < nMaxLen)
356         {
357             char * sBreak = strrchr(pResult,'.');
358             if (sBreak != 0)
359             {
360                 static char sScope[nMaxLen+10];
361                 static char sName[nMaxLen+10];
362 
363                 unsigned nScopeLen = sBreak - pResult;
364                 strncpy ( sScope, pResult, nScopeLen ); // STRNCPY SAFE HERE
365                 sScope[nScopeLen] = '\0';
366                 strcpy( sName, sBreak + 1 );            // STRCPY SAFE HERE
367                 strcat( sName, " in " );                // STRCAT SAFE HERE
368                 strcat( sName, sScope );                // STRCAT SAFE HERE
369 
370                 o_rText = sName;
371                 return;
372             }
373         }
374     }   // endif (i_bReverseName)
375 
376     o_rText = &sWord[0];
377 }
378 
379 bool
380 X2CParser::CheckAndPassBeginTag( const char * i_sElementName )
381 {
382     bool ret = true;
383     Goto('<');
384     if ( ! IsBeginTag(i_sElementName) )
385         SyntaxError( "unexpected element");
386     if (IsAbsoluteEmpty())
387         ret = false;
388     Goto_And_Pass('>');
389     if (ret)
390         Pass_White();
391     return ret;
392 }
393 
394 void
395 X2CParser::CheckAndPassEndTag( const char * i_sElementName )
396 {
397     Pass_White();
398     if ( !IsEndTag(i_sElementName) )
399         SyntaxError("missing or not matching end tag");
400     Goto_And_Pass('>');
401 }
402 
403 bool
404 X2CParser::IsAbsoluteEmpty() const
405 {
406     const char * pEnd = strchr(text+1, '>');
407     if (pEnd != 0)
408     {
409         if ( *(pEnd-1) == '/' )
410         {
411             const char * pAttr = strchr(text+1, '"');
412             if (pAttr == 0)
413                 return true;
414             else if ( (pAttr-text) > (pEnd-text) )
415                 return true;
416         }
417     }
418     return false;
419 }
420 
421 void
422 X2CParser::SyntaxError( const char * i_sText )
423 {
424     std::cerr
425          << "Syntax error "
426          << i_sText
427          << " in file: "
428          << sFileName.str()
429          << " in line "
430          << nFileLine
431          << "."
432          << std::endl;
433 
434      exit(3);
435 }
436 
437 void
438 X2CParser::TestCurChar()
439 {
440 //  if (*text == '\0')
441 //      SyntaxError("unexpected end of file");
442 //  else
443 
444     if (*text == '\n')
445         nFileLine++;
446 }
447 
448 
449