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