xref: /trunk/main/xml2cmp/source/xcd/parse.cxx (revision ab595ff6)
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