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