xref: /trunk/main/tools/source/communi/parser.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 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_tools.hxx"
30 
31 #include <stdio.h>
32 #include <tools/stream.hxx>
33 #include <tools/fsys.hxx>
34 
35 #include "tools/iparser.hxx"
36 #include "tools/geninfo.hxx"
37 
38 
39 
40 //
41 // class InformationParser
42 //
43 
44 #define cKeyLevelChar '\t'
45 
46 /*****************************************************************************/
47 InformationParser::InformationParser( sal_Bool bReplace )
48 /*****************************************************************************/
49 				: bRecover( sal_False ),
50 				sOldLine( "" ),
51 				bReplaceVariables( bReplace ),
52 				nLevel( 0 ),
53 				sUPD( "" ),
54 				sVersion( "" ),
55 				pActStream( NULL ),
56 				nErrorCode( 0 ),
57 				nErrorLine( 0 ),
58 				sErrorText( "" ),
59 				nActLine( 0 )
60 {
61 }
62 
63 /*****************************************************************************/
64 InformationParser::~InformationParser()
65 /*****************************************************************************/
66 {
67 }
68 
69 /*****************************************************************************/
70 ByteString &InformationParser::ReadLine()
71 /*****************************************************************************/
72 {
73 	ByteString sLine;
74 
75 	if ( bRecover ) {
76 		bRecover = sal_False;
77 	}
78 	else {
79 		 if ( !pActStream->IsEof()) {
80 			pActStream->ReadLine( sLine );
81             xub_StrLen nStart = 0;
82             xub_StrLen nEnd = sLine.Len();
83             sal_Bool bCopy = sal_False;
84             while ( nStart < nEnd && ( sLine.GetChar( nStart ) == ' ' || sLine.GetChar( nStart ) == 0x09 ) )
85             {
86                 nStart++;
87                 bCopy = sal_True;
88             }
89 
90             while ( nStart < nEnd && ( sLine.GetChar( nEnd-1 ) == ' ' || sLine.GetChar( nEnd-1 ) == 0x09 ) )
91             {
92                 nEnd--;
93                 bCopy = sal_True;
94             }
95 
96             if ( bCopy )
97                 sLine = sLine.Copy( nStart, nEnd - nStart );
98 
99 			if (( sLine.GetChar( 0 ) == '#' ) || ( !sLine.Len())) {
100 				if ( sCurrentComment.Len())
101 					sCurrentComment += "\n";
102 				sCurrentComment += sLine;
103 				return ReadLine();
104 			}
105 			else {
106 				if ( bReplaceVariables ) {
107 					sLine.SearchAndReplaceAll( "%UPD", sUPD );
108 					sLine.SearchAndReplaceAll( "%VERSION", sVersion );
109 				}
110 			}
111 		}
112         else {
113 			if ( nLevel ) {
114             	sLine = "}";
115 	            fprintf( stdout, "Reached EOF parsing %s. Suplying extra '}'\n",ByteString( sStreamName, gsl_getSystemTextEncoding()).GetBuffer() );
116 	//	        nErrorCode = IP_UNEXPECTED_EOF;
117 	//	        nErrorLine = nActLine;
118 			}
119 			else
120 				sLine = "";
121         }
122 
123 		sOldLine = sLine;
124 		nActLine++;
125 	}
126 
127 	return sOldLine;
128 }
129 
130 /*****************************************************************************/
131 GenericInformation *InformationParser::ReadKey(
132 									GenericInformationList *pExistingList )
133 /*****************************************************************************/
134 {
135 	// this method has no error handling yet, but it works very fast.
136 	// it is used to create whole informations and sub informations in
137 	// a simple data format in memory, readed in a configuration file with
138 	// following format:
139 
140 	/*
141 
142 	key [value]
143 	{
144 		key [value]
145 		key [value]
146 		{
147 			key [value]
148 			...
149 			...
150 		}
151 	}
152 	key [value]
153 	...
154 	...
155 
156 	*/
157 
158 	GenericInformation *pInfo = NULL;
159 
160 	ByteString sLine( ReadLine());
161 	ByteString sKey;
162 	ByteString sValue;
163 	ByteString sComment( sCurrentComment );
164 	sCurrentComment = "";
165 
166 	// key separated from value by tab?
167 	sal_uInt16 nWSPos = sLine.Search( ' ' );
168 	if ( sLine.Search( '\t' ) < nWSPos ) {
169 		nWSPos = sLine.Search( '\t' );
170 		sLine.SearchAndReplace( "\t", " " );
171 	}
172 
173 	if ( sLine.GetTokenCount( ' ' ) > 1 ) {
174 		sKey = sLine.GetToken( 0, ' ' );
175 		sValue = sLine.Copy( sKey.Len() + 1 );
176 		while (( sValue.Search( ' ' ) == 0 ) || ( sValue.Search( '\t' ) == 0 )) {
177 			sValue.Erase( 0, 1 );
178 		}
179 	}
180 	else
181 		sKey=sLine;
182 
183 	if ( bReplaceVariables && !nLevel ) {
184 		sUPD = sKey.Copy( sKey.Len() - 3 );
185 		sVersion = sKey;
186 	}
187 
188 	if ( ReadLine() == "{" ) {
189 		nLevel++;
190 		GenericInformationList *pSubList = new GenericInformationList();
191 		while ( ReadLine() != "}" ) {
192 			Recover();
193 			ReadKey( pSubList );
194 		}
195 		nLevel--;
196 		pInfo = new GenericInformation( sKey, sValue,
197 						pExistingList, pSubList );
198 		pInfo->SetComment( sComment );
199 	}
200 	else {
201 		Recover();
202         if ( !sKey.Equals( "}" ) && !sKey.Equals( "{" ) )
203         {
204 		    pInfo = new GenericInformation( sKey, sValue, pExistingList );
205 		    pInfo->SetComment( sComment );
206         }
207 	}
208 
209 	return pInfo;
210 }
211 
212 /*****************************************************************************/
213 void InformationParser::Recover()
214 /*****************************************************************************/
215 {
216 	bRecover = sal_True;
217 }
218 
219 /*****************************************************************************/
220 sal_Bool InformationParser::Save( SvStream &rOutStream,
221 			      const GenericInformationList *pSaveList,
222 			      sal_uInt16 level, sal_Bool bStripped )
223 /*****************************************************************************/
224 {
225 	sal_uInt16 i;
226 	sal_uIntPtr nInfoListCount;
227 	ByteString sTmpStr;
228 	GenericInformation *pGenericInfo;
229 	GenericInformationList *pGenericInfoList;
230 
231  	static ByteString aKeyLevel;
232     aKeyLevel.Expand( level, cKeyLevelChar );
233 
234 	for ( nInfoListCount = 0; nInfoListCount < pSaveList->Count(); nInfoListCount++) {
235 	    // Key-Value Paare schreiben
236     	pGenericInfo = pSaveList->GetObject( nInfoListCount );
237     	sTmpStr = "";
238         if ( !bStripped && level )
239         	sTmpStr.Append( aKeyLevel.GetBuffer(), level );
240 
241         if ( !bStripped )
242 		    for ( i = 0; i < pGenericInfo->GetComment().GetTokenCount( '\n' ); i++ ) {
243 			    sTmpStr += pGenericInfo->GetComment().GetToken( i, '\n' );
244 			    sTmpStr += "\n";
245                 if ( level )
246         	        sTmpStr.Append( aKeyLevel.GetBuffer(), level );
247 		    }
248 
249     	sTmpStr += pGenericInfo->GetBuffer();
250     	sTmpStr += ' ';
251     	sTmpStr += pGenericInfo->GetValue();
252     	if ( !rOutStream.WriteLine( sTmpStr ) )
253       		return sal_False;
254 
255     	// wenn vorhanden, bearbeite recursive die Sublisten
256     	if (( pGenericInfoList = pGenericInfo->GetSubList() ) != NULL ) {
257       		// oeffnende Klammer
258       		sTmpStr = "";
259             if ( !bStripped && level )
260         	    sTmpStr.Append( aKeyLevel.GetBuffer(), level );
261       		sTmpStr += '{';
262       		if ( !rOutStream.WriteLine( sTmpStr ) )
263 				return sal_False;
264       		// recursiv die sublist abarbeiten
265       		if ( !Save( rOutStream, pGenericInfoList, level+1, bStripped ) )
266     			return sal_False;
267       			// schliessende Klammer
268       		sTmpStr = "";
269             if ( !bStripped && level )
270         	    sTmpStr.Append( aKeyLevel.GetBuffer(), level );
271       		sTmpStr += '}';
272       		if ( !rOutStream.WriteLine( sTmpStr ) )
273 				return sal_False;
274     	}
275   	}
276   	return sal_True;
277 }
278 
279 /*****************************************************************************/
280 GenericInformationList *InformationParser::Execute(
281 								SvStream &rSourceStream,
282 								GenericInformationList *pExistingList )
283 /*****************************************************************************/
284 {
285 	GenericInformationList *pList;
286 	if ( pExistingList )
287 		pList = pExistingList;
288 	else
289 		pList = new GenericInformationList();
290 
291 	pActStream = &rSourceStream;
292 
293 	// read all infos out of current file
294 	while( !rSourceStream.IsEof()) {
295 		nLevel = 0;
296 		ReadKey( pList );
297 	}
298 
299 	return pList;
300 }
301 
302 /*****************************************************************************/
303 GenericInformationList *InformationParser::Execute( SvMemoryStream &rSourceStream,
304 						    GenericInformationList *pExistingList )
305 /*****************************************************************************/
306 {
307   	sStreamName = UniString( "Memory", gsl_getSystemTextEncoding());
308   	return Execute( (SvStream &)rSourceStream, pExistingList );
309 }
310 
311 /*****************************************************************************/
312 GenericInformationList *InformationParser::Execute(
313 								SvFileStream &rSourceStream,
314 								GenericInformationList *pExistingList )
315 /*****************************************************************************/
316 {
317 	if ( !rSourceStream.IsOpen())
318 		return NULL;
319 	sStreamName = rSourceStream.GetFileName();
320 	return Execute( (SvStream &)rSourceStream, pExistingList );
321 }
322 
323 /*****************************************************************************/
324 GenericInformationList *InformationParser::Execute( UniString &rSourceFile,
325 								GenericInformationList *pExistingList )
326 /*****************************************************************************/
327 {
328 	DirEntry aDirEntry( rSourceFile );
329 	if ( !aDirEntry.Exists())
330 		return NULL;
331 
332 	GenericInformationList *pList;
333 	if ( pExistingList )
334 		pList = pExistingList;
335 	else
336 		pList = new GenericInformationList();
337 
338 	// reset status
339 	nErrorCode = 0;
340 	nErrorLine = 0;
341 	nActLine = 0;
342 
343 	SvFileStream aActStream;
344 	aActStream.Open( rSourceFile, STREAM_READ );
345 	if( aActStream.GetError())
346 		return NULL;
347 
348 	pActStream = &aActStream;
349 	if ( !Execute( aActStream, pList )) {
350 		delete pList;
351 		pList = NULL;
352 	}
353 
354 	// close the stream
355 	aActStream.Close();
356  	pActStream = NULL;
357 
358 	if ( !nErrorCode )
359 		return pList;
360 
361 	return NULL;
362 }
363 
364 /*****************************************************************************/
365 GenericInformationList *InformationParser::Execute( Dir &rDir,
366 								GenericInformationList *pExistingList )
367 /*****************************************************************************/
368 {
369 	GenericInformationList *pList;
370 
371 	if ( pExistingList )
372 		pList = pExistingList;
373 	else
374 		pList = new GenericInformationList();
375 
376 	for ( sal_uInt16 i = 0; i < rDir.Count(); i++ ) {
377 
378 		// execute this dir
379 		UniString sNextFile( rDir[i].GetFull());
380 		GenericInformationList *pSubList = Execute( sNextFile );
381 
382 		if ( !pSubList ) {
383 			// any errors ?
384 			delete pList;
385 			return NULL;
386 		}
387 
388 		// create new info and insert it into list
389 		ByteString sFileKey( rDir[i].GetName(), RTL_TEXTENCODING_UTF8 );
390 		new GenericInformation(
391 											sFileKey,
392 											ByteString( "" ),
393 											pList, pSubList );
394 	}
395 
396 	return pList;
397 }
398 
399 /*****************************************************************************/
400 sal_Bool InformationParser::Save( SvFileStream &rSourceStream,
401 			      const GenericInformationList *pSaveList )
402 /*****************************************************************************/
403 {
404 	if ( !rSourceStream.IsOpen() || !Save( (SvStream &)rSourceStream, pSaveList, 0, sal_False ))
405     {
406         printf( "ERROR saving file \"%s\"\n",ByteString( rSourceStream.GetFileName(), gsl_getSystemTextEncoding()).GetBuffer() );
407 		return sal_False;
408     }
409 
410 	return sal_True;
411 }
412 
413 /*****************************************************************************/
414 sal_Bool InformationParser::Save( SvMemoryStream &rSourceStream,
415 			      const GenericInformationList *pSaveList )
416 /*****************************************************************************/
417 {
418     Time a;
419     sal_Bool bRet = Save( (SvStream &)rSourceStream, pSaveList, 0, sal_True );
420     Time b;
421     b = b - a;
422     return bRet;
423 }
424 
425 /*****************************************************************************/
426 sal_Bool InformationParser::Save( const UniString &rSourceFile,
427 			      const GenericInformationList *pSaveList )
428 /*****************************************************************************/
429 {
430   SvFileStream *pOutFile = new SvFileStream( rSourceFile, STREAM_STD_WRITE | STREAM_TRUNC );
431 
432   if ( !Save( *pOutFile, pSaveList )) {
433     delete pOutFile;
434     return sal_False;
435   }
436   delete pOutFile;
437   return sal_True;
438 }
439 
440 /*****************************************************************************/
441 sal_uInt16 InformationParser::GetErrorCode()
442 /*****************************************************************************/
443 {
444 	return nErrorCode;
445 }
446 
447 /*****************************************************************************/
448 ByteString &InformationParser::GetErrorText()
449 /*****************************************************************************/
450 {
451   //	sErrorText = pActStream->GetFileName();
452     sErrorText = ByteString( sStreamName, gsl_getSystemTextEncoding());
453 	sErrorText += ByteString( " (" );
454 	sErrorText += ByteString::CreateFromInt64(nErrorLine);
455 	sErrorText += ByteString( "): " );
456 
457 	switch ( nErrorCode ) {
458 	case IP_NO_ERROR:
459 		sErrorText += ByteString( "Keine Fehler aufgetereten" );
460 		break;
461 	case IP_UNEXPECTED_EOF:
462 		sErrorText += ByteString( "Ung�ltiges Dateiende!" );
463 		break;
464 	}
465 
466 	return sErrorText;
467 }
468 
469 
470