Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*
3 : : * This file is part of the LibreOffice project.
4 : : *
5 : : * This Source Code Form is subject to the terms of the Mozilla Public
6 : : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : : *
9 : : * This file incorporates work covered by the following license notice:
10 : : *
11 : : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : : * contributor license agreements. See the NOTICE file distributed
13 : : * with this work for additional information regarding copyright
14 : : * ownership. The ASF licenses this file to you under the Apache
15 : : * License, Version 2.0 (the "License"); you may not use this file
16 : : * except in compliance with the License. You may obtain a copy of
17 : : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : : */
19 : : #define _CONFIG_CXX
20 : :
21 : : #include <cstddef>
22 : : #include <cstdlib>
23 : : #include <limits>
24 : : #include <new>
25 : : #include <string.h>
26 : :
27 : : #ifdef WNT
28 : : #include "stdlib.h"
29 : : #endif
30 : :
31 : : #include <osl/file.hxx>
32 : : #include <tools/stream.hxx>
33 : : #include <tools/debug.hxx>
34 : : #include <tools/config.hxx>
35 : : #include <osl/security.h>
36 : : #include <rtl/strbuf.hxx>
37 : :
38 : 40684 : struct ImplKeyData
39 : : {
40 : : ImplKeyData* mpNext;
41 : : rtl::OString maKey;
42 : : rtl::OString maValue;
43 : : sal_Bool mbIsComment;
44 : : };
45 : :
46 : 1552 : struct ImplGroupData
47 : : {
48 : : ImplGroupData* mpNext;
49 : : ImplKeyData* mpFirstKey;
50 : : rtl::OString maGroupName;
51 : : sal_uInt16 mnEmptyLines;
52 : : };
53 : :
54 : 1264 : struct ImplConfigData
55 : : {
56 : : ImplGroupData* mpFirstGroup;
57 : : rtl::OUString maFileName;
58 : : sal_uIntPtr mnDataUpdateId;
59 : : sal_uIntPtr mnTimeStamp;
60 : : LineEnd meLineEnd;
61 : : sal_uInt16 mnRefCount;
62 : : sal_Bool mbModified;
63 : : sal_Bool mbRead;
64 : : sal_Bool mbIsUTF8BOM;
65 : : };
66 : :
67 : 632 : static String toUncPath( const String& rPath )
68 : : {
69 : 632 : ::rtl::OUString aFileURL;
70 : :
71 : : // check if rFileName is already a URL; if not make it so
72 [ + + ][ + - ]: 632 : if( rPath.CompareToAscii( "file://", 7 ) == COMPARE_EQUAL )
73 [ + - ]: 316 : aFileURL = rPath;
74 [ + - ][ + - ]: 316 : else if( ::osl::FileBase::getFileURLFromSystemPath( rPath, aFileURL ) != ::osl::FileBase::E_None )
[ - + ]
75 [ # # ]: 0 : aFileURL = rPath;
76 : :
77 [ + - ]: 632 : return aFileURL;
78 : : }
79 : :
80 : 618 : static sal_uIntPtr ImplSysGetConfigTimeStamp( const rtl::OUString& rFileName )
81 : : {
82 : 618 : sal_uIntPtr nTimeStamp = 0;
83 : 618 : ::osl::DirectoryItem aItem;
84 : 618 : ::osl::FileStatus aStatus( osl_FileStatus_Mask_ModifyTime );
85 : :
86 [ + - ][ + - ]: 1236 : if( ::osl::DirectoryItem::get( rFileName, aItem ) == ::osl::FileBase::E_None &&
[ + - ][ + - ]
87 [ + - ]: 618 : aItem.getFileStatus( aStatus ) == ::osl::FileBase::E_None )
88 : : {
89 [ + - ]: 618 : nTimeStamp = aStatus.getModifyTime().Seconds;
90 : : }
91 : :
92 [ + - ]: 618 : return nTimeStamp;
93 : : }
94 : :
95 : 632 : static sal_uInt8* ImplSysReadConfig( const rtl::OUString& rFileName,
96 : : sal_uInt64& rRead, sal_Bool& rbRead, sal_Bool& rbIsUTF8BOM, sal_uIntPtr& rTimeStamp )
97 : : {
98 : 632 : sal_uInt8* pBuf = NULL;
99 : 632 : ::osl::File aFile( rFileName );
100 : :
101 [ + + ][ + - ]: 632 : if( aFile.open( osl_File_OpenFlag_Read ) == ::osl::FileBase::E_None )
102 : : {
103 : 460 : sal_uInt64 nPos = 0;
104 [ + - ][ + - ]: 460 : if( aFile.getSize( nPos ) == ::osl::FileBase::E_None )
105 : : {
106 [ - + ]: 460 : if (nPos > std::numeric_limits< std::size_t >::max()) {
107 [ # # ]: 0 : aFile.close();
108 : 0 : return 0;
109 : : }
110 [ + - ]: 460 : pBuf = new sal_uInt8[static_cast< std::size_t >(nPos)];
111 : 460 : sal_uInt64 nRead = 0;
112 [ + - ][ + - ]: 460 : if( aFile.read( pBuf, nPos, nRead ) == ::osl::FileBase::E_None && nRead == nPos )
[ + - ][ + - ]
113 : : {
114 : : //skip the byte-order-mark 0xEF 0xBB 0xBF, if it was UTF8 files
115 : 460 : unsigned char BOM[3] = {0xEF, 0xBB, 0xBF};
116 [ + + ][ - + ]: 460 : if (nRead > 2 && memcmp(pBuf, BOM, 3) == 0)
117 : : {
118 : 0 : nRead -= 3;
119 [ # # ]: 0 : rtl_moveMemory(pBuf, pBuf + 3, sal::static_int_cast<sal_Size>(nRead * sizeof(sal_uInt8)) );
120 : 0 : rbIsUTF8BOM = sal_True;
121 : : }
122 : :
123 [ + - ]: 460 : rTimeStamp = ImplSysGetConfigTimeStamp( rFileName );
124 : 460 : rbRead = sal_True;
125 : 460 : rRead = nRead;
126 : : }
127 : : else
128 : : {
129 [ # # ]: 0 : delete[] pBuf;
130 : 460 : pBuf = NULL;
131 : : }
132 : : }
133 [ + - ]: 460 : aFile.close();
134 : : }
135 : :
136 [ + - ]: 632 : return pBuf;
137 : : }
138 : :
139 : 158 : static sal_Bool ImplSysWriteConfig( const rtl::OUString& rFileName,
140 : : const sal_uInt8* pBuf, sal_uIntPtr nBufLen, sal_Bool rbIsUTF8BOM, sal_uIntPtr& rTimeStamp )
141 : : {
142 : 158 : sal_Bool bSuccess = sal_False;
143 : 158 : sal_Bool bUTF8BOMSuccess = sal_False;
144 : :
145 : 158 : ::osl::File aFile( rFileName );
146 [ + - ]: 158 : ::osl::FileBase::RC eError = aFile.open( osl_File_OpenFlag_Write | osl_File_OpenFlag_Create );
147 [ + - ]: 158 : if( eError != ::osl::FileBase::E_None )
148 [ + - ]: 158 : eError = aFile.open( osl_File_OpenFlag_Write );
149 [ + - ]: 158 : if( eError == ::osl::FileBase::E_None )
150 : : {
151 : : // truncate
152 [ + - ]: 158 : aFile.setSize( 0 );
153 : : sal_uInt64 nWritten;
154 : :
155 : : //write the the byte-order-mark 0xEF 0xBB 0xBF first , if it was UTF8 files
156 [ - + ]: 158 : if ( rbIsUTF8BOM )
157 : : {
158 : 0 : unsigned char BOM[3] = {0xEF, 0xBB, 0xBF};
159 : : sal_uInt64 nUTF8BOMWritten;
160 [ # # ][ # # ]: 0 : if( aFile.write( BOM, 3, nUTF8BOMWritten ) == ::osl::FileBase::E_None && 3 == nUTF8BOMWritten )
[ # # ][ # # ]
161 : : {
162 : 0 : bUTF8BOMSuccess = sal_True;
163 : : }
164 : : }
165 : :
166 [ + - ][ + - ]: 158 : if( aFile.write( pBuf, nBufLen, nWritten ) == ::osl::FileBase::E_None && nWritten == nBufLen )
[ + - ][ + - ]
167 : : {
168 : 158 : bSuccess = sal_True;
169 : : }
170 [ - + ][ # # ]: 158 : if ( rbIsUTF8BOM ? bSuccess && bUTF8BOMSuccess : bSuccess )
[ # # ][ + - ]
171 : : {
172 [ + - ]: 158 : rTimeStamp = ImplSysGetConfigTimeStamp( rFileName );
173 : : }
174 : : }
175 : :
176 [ - + ][ # # ]: 158 : return rbIsUTF8BOM ? bSuccess && bUTF8BOMSuccess : bSuccess;
[ # # ][ + - ]
177 : : }
178 : :
179 : : namespace {
180 : 21550 : rtl::OString makeOString(const sal_uInt8* p, sal_uInt64 n)
181 : : {
182 [ - + ]: 21550 : if (n > SAL_MAX_INT32)
183 : : {
184 : : #ifdef WNT
185 : : abort();
186 : : #else
187 : 0 : ::std::abort(); //TODO: handle this gracefully
188 : : #endif
189 : : }
190 : : return rtl::OString(
191 : : reinterpret_cast< char const * >(p),
192 : 21550 : sal::static_int_cast< sal_Int32 >(n));
193 : : }
194 : : }
195 : :
196 : 460 : static void ImplMakeConfigList( ImplConfigData* pData,
197 : : const sal_uInt8* pBuf, sal_uInt64 nLen )
198 : : {
199 [ + + ]: 460 : if ( !nLen )
200 : 460 : return;
201 : :
202 : : // Parse buffer and build config list
203 : : sal_uInt64 nStart;
204 : : sal_uInt64 nLineLen;
205 : : sal_uInt64 nNameLen;
206 : : sal_uInt64 nKeyLen;
207 : : sal_uInt64 i;
208 : : const sal_uInt8* pLine;
209 : 302 : ImplKeyData* pPrevKey = NULL;
210 : : ImplKeyData* pKey;
211 : 302 : ImplGroupData* pPrevGroup = NULL;
212 : 302 : ImplGroupData* pGroup = NULL;
213 : 302 : i = 0;
214 [ + + ]: 20588 : while ( i < nLen )
215 : : {
216 : : // Ctrl+Z
217 [ - + ]: 20286 : if ( pBuf[i] == 0x1A )
218 : 0 : break;
219 : :
220 : : // Remove spaces and tabs
221 [ + - ][ - + ]: 20286 : while ( (pBuf[i] == ' ') || (pBuf[i] == '\t') )
[ - + ]
222 : 0 : i++;
223 : :
224 : : // remember line-starts
225 : 20286 : nStart = i;
226 : 20286 : pLine = pBuf+i;
227 : :
228 : : // search line-endings
229 [ + - ][ + - ]: 767718 : while ( (i < nLen) && pBuf[i] && (pBuf[i] != '\r') && (pBuf[i] != '\n') &&
[ + - ][ + + ]
[ + - ][ + + ]
230 : 747432 : (pBuf[i] != 0x1A) )
231 : 747432 : i++;
232 : :
233 : 20286 : nLineLen = i-nStart;
234 : :
235 : : // if Line-ending is found, continue once
236 [ + + ][ + + ]: 20286 : if ( (i+1 < nLen) &&
[ + - ][ - + ]
237 : 39968 : (pBuf[i] != pBuf[i+1]) &&
238 : 34208 : ((pBuf[i+1] == '\r') || (pBuf[i+1] == '\n')) )
239 : 0 : i++;
240 : 20286 : i++;
241 : :
242 : : // evaluate line
243 [ + + ]: 20286 : if ( *pLine == '[' )
244 : : {
245 : 446 : pGroup = new ImplGroupData;
246 : 446 : pGroup->mpNext = NULL;
247 : 446 : pGroup->mpFirstKey = NULL;
248 : 446 : pGroup->mnEmptyLines = 0;
249 [ + + ]: 446 : if ( pPrevGroup )
250 : 288 : pPrevGroup->mpNext = pGroup;
251 : : else
252 : 158 : pData->mpFirstGroup = pGroup;
253 : 446 : pPrevGroup = pGroup;
254 : 446 : pPrevKey = NULL;
255 : 446 : pKey = NULL;
256 : :
257 : : // filter group names
258 : 446 : pLine++;
259 : 446 : nLineLen--;
260 : : // remove spaces and tabs
261 [ + - ][ - + ]: 446 : while ( (*pLine == ' ') || (*pLine == '\t') )
[ - + ]
262 : : {
263 : 0 : nLineLen--;
264 : 0 : pLine++;
265 : : }
266 : 446 : nNameLen = 0;
267 [ + - ][ + + ]: 7916 : while ( (nNameLen < nLineLen) && (pLine[nNameLen] != ']') )
[ + + ]
268 : 7470 : nNameLen++;
269 [ + - ]: 446 : if ( nNameLen )
270 : : {
271 [ + - ][ - + ]: 446 : while ( (pLine[nNameLen-1] == ' ') || (pLine[nNameLen-1] == '\t') )
[ - + ]
272 : 0 : nNameLen--;
273 : : }
274 : 446 : pGroup->maGroupName = makeOString(pLine, nNameLen);
275 : : }
276 : : else
277 : : {
278 [ + + ]: 19840 : if ( nLineLen )
279 : : {
280 : : // If no group exists yet, add to default
281 [ + + ]: 16960 : if ( !pGroup )
282 : : {
283 : 144 : pGroup = new ImplGroupData;
284 : 144 : pGroup->mpNext = NULL;
285 : 144 : pGroup->mpFirstKey = NULL;
286 : 144 : pGroup->mnEmptyLines = 0;
287 [ - + ]: 144 : if ( pPrevGroup )
288 : 0 : pPrevGroup->mpNext = pGroup;
289 : : else
290 : 144 : pData->mpFirstGroup = pGroup;
291 : 144 : pPrevGroup = pGroup;
292 : 144 : pPrevKey = NULL;
293 : : }
294 : :
295 : : // if empty line, append it
296 [ + + ]: 16960 : if ( pPrevKey )
297 : : {
298 [ + + ]: 18962 : while ( pGroup->mnEmptyLines )
299 : : {
300 : 2592 : pKey = new ImplKeyData;
301 : 2592 : pKey->mbIsComment = sal_True;
302 : 2592 : pPrevKey->mpNext = pKey;
303 : 2592 : pPrevKey = pKey;
304 : 2592 : pGroup->mnEmptyLines--;
305 : : }
306 : : }
307 : :
308 : : // Generate new key
309 : 16960 : pKey = new ImplKeyData;
310 : 16960 : pKey->mpNext = NULL;
311 [ + + ]: 16960 : if ( pPrevKey )
312 : 16370 : pPrevKey->mpNext = pKey;
313 : : else
314 : 590 : pGroup->mpFirstKey = pKey;
315 : 16960 : pPrevKey = pKey;
316 [ + + ]: 16960 : if ( pLine[0] == ';' )
317 : : {
318 : 12384 : pKey->maValue = makeOString(pLine, nLineLen);
319 : 12384 : pKey->mbIsComment = sal_True;
320 : : }
321 : : else
322 : : {
323 : 4576 : pKey->mbIsComment = sal_False;
324 : 4576 : nNameLen = 0;
325 [ + - ][ + + ]: 76262 : while ( (nNameLen < nLineLen) && (pLine[nNameLen] != '=') )
[ + + ]
326 : 71686 : nNameLen++;
327 : 4576 : nKeyLen = nNameLen;
328 : : // Remove spaces and tabs
329 [ + - ]: 4576 : if ( nNameLen )
330 : : {
331 [ + - ][ - + ]: 4576 : while ( (pLine[nNameLen-1] == ' ') || (pLine[nNameLen-1] == '\t') )
[ - + ]
332 : 0 : nNameLen--;
333 : : }
334 : 4576 : pKey->maKey = makeOString(pLine, nNameLen);
335 : 4576 : nKeyLen++;
336 [ + + ]: 4576 : if ( nKeyLen < nLineLen )
337 : : {
338 : 4144 : pLine += nKeyLen;
339 : 4144 : nLineLen -= nKeyLen;
340 : : // Remove spaces and tabs
341 [ + - ][ - + ]: 4144 : while ( (*pLine == ' ') || (*pLine == '\t') )
[ - + ]
342 : : {
343 : 0 : nLineLen--;
344 : 0 : pLine++;
345 : : }
346 [ + - ]: 4144 : if ( nLineLen )
347 : : {
348 [ + - ][ - + ]: 4144 : while ( (pLine[nLineLen-1] == ' ') || (pLine[nLineLen-1] == '\t') )
[ - + ]
349 : 0 : nLineLen--;
350 : 4144 : pKey->maValue = makeOString(pLine, nLineLen);
351 : : }
352 : : }
353 : : }
354 : : }
355 : : else
356 : : {
357 : : // Spaces are counted and appended only after key generation,
358 : : // as we want to store spaces even after adding new keys
359 [ + - ]: 2880 : if ( pGroup )
360 : 2880 : pGroup->mnEmptyLines++;
361 : : }
362 : : }
363 : : }
364 : : }
365 : :
366 : 158 : static sal_uInt8* ImplGetConfigBuffer( const ImplConfigData* pData, sal_uIntPtr& rLen )
367 : : {
368 : : sal_uInt8* pWriteBuf;
369 : : sal_uInt8* pBuf;
370 : 158 : sal_uInt8 aLineEndBuf[2] = {0, 0};
371 : : ImplKeyData* pKey;
372 : : ImplGroupData* pGroup;
373 : : unsigned int nBufLen;
374 : : sal_uInt32 nValueLen;
375 : : sal_uInt32 nKeyLen;
376 : : sal_uInt32 nLineEndLen;
377 : :
378 [ - + ]: 158 : if ( pData->meLineEnd == LINEEND_CR )
379 : : {
380 : 0 : aLineEndBuf[0] = _CR;
381 : 0 : nLineEndLen = 1;
382 : : }
383 [ - + ]: 158 : else if ( pData->meLineEnd == LINEEND_LF )
384 : : {
385 : 0 : aLineEndBuf[0] = _LF;
386 : 0 : nLineEndLen = 1;
387 : : }
388 : : else
389 : : {
390 : 158 : aLineEndBuf[0] = _CR;
391 : 158 : aLineEndBuf[1] = _LF;
392 : 158 : nLineEndLen = 2;
393 : : }
394 : :
395 : 158 : nBufLen = 0;
396 : 158 : pGroup = pData->mpFirstGroup;
397 [ + + ]: 316 : while ( pGroup )
398 : : {
399 : : // Don't write empty groups
400 [ + - ]: 158 : if ( pGroup->mpFirstKey )
401 : : {
402 : 158 : nBufLen += pGroup->maGroupName.getLength() + nLineEndLen + 2;
403 : 158 : pKey = pGroup->mpFirstKey;
404 [ + + ]: 948 : while ( pKey )
405 : : {
406 : 790 : nValueLen = pKey->maValue.getLength();
407 [ - + ]: 790 : if ( pKey->mbIsComment )
408 : 0 : nBufLen += nValueLen + nLineEndLen;
409 : : else
410 : 790 : nBufLen += pKey->maKey.getLength() + nValueLen + nLineEndLen + 1;
411 : :
412 : 790 : pKey = pKey->mpNext;
413 : : }
414 : :
415 : : // Write empty lines after each group
416 [ - + ]: 158 : if ( !pGroup->mnEmptyLines )
417 : 0 : pGroup->mnEmptyLines = 1;
418 : 158 : nBufLen += nLineEndLen * pGroup->mnEmptyLines;
419 : : }
420 : :
421 : 158 : pGroup = pGroup->mpNext;
422 : : }
423 : :
424 : : // Output buffer length
425 : 158 : rLen = nBufLen;
426 [ - + ]: 158 : if ( !nBufLen )
427 : : {
428 [ # # ]: 0 : pWriteBuf = new sal_uInt8[nLineEndLen];
429 [ # # ]: 0 : if ( pWriteBuf )
430 : : {
431 : 0 : pWriteBuf[0] = aLineEndBuf[0];
432 [ # # ]: 0 : if ( nLineEndLen == 2 )
433 : 0 : pWriteBuf[1] = aLineEndBuf[1];
434 : 0 : return pWriteBuf;
435 : : }
436 : : else
437 : 0 : return 0;
438 : : }
439 : :
440 : : // Allocate new write buffer (caller frees it)
441 [ + - ]: 158 : pWriteBuf = new sal_uInt8[nBufLen];
442 [ - + ]: 158 : if ( !pWriteBuf )
443 : 0 : return 0;
444 : :
445 : : // fill buffer
446 : 158 : pBuf = pWriteBuf;
447 : 158 : pGroup = pData->mpFirstGroup;
448 [ + + ]: 316 : while ( pGroup )
449 : : {
450 : : // Don't write empty groups
451 [ + - ]: 158 : if ( pGroup->mpFirstKey )
452 : : {
453 : 158 : *pBuf = '['; pBuf++;
454 : 158 : memcpy( pBuf, pGroup->maGroupName.getStr(), pGroup->maGroupName.getLength() );
455 : 158 : pBuf += pGroup->maGroupName.getLength();
456 : 158 : *pBuf = ']'; pBuf++;
457 : 158 : *pBuf = aLineEndBuf[0]; pBuf++;
458 [ + - ]: 158 : if ( nLineEndLen == 2 )
459 : : {
460 : 158 : *pBuf = aLineEndBuf[1]; pBuf++;
461 : : }
462 : 158 : pKey = pGroup->mpFirstKey;
463 [ + + ]: 948 : while ( pKey )
464 : : {
465 : 790 : nValueLen = pKey->maValue.getLength();
466 [ - + ]: 790 : if ( pKey->mbIsComment )
467 : : {
468 [ # # ]: 0 : if ( nValueLen )
469 : : {
470 : 0 : memcpy( pBuf, pKey->maValue.getStr(), nValueLen );
471 : 0 : pBuf += nValueLen;
472 : : }
473 : 0 : *pBuf = aLineEndBuf[0]; pBuf++;
474 [ # # ]: 0 : if ( nLineEndLen == 2 )
475 : : {
476 : 0 : *pBuf = aLineEndBuf[1]; pBuf++;
477 : : }
478 : : }
479 : : else
480 : : {
481 : 790 : nKeyLen = pKey->maKey.getLength();
482 : 790 : memcpy( pBuf, pKey->maKey.getStr(), nKeyLen );
483 : 790 : pBuf += nKeyLen;
484 : 790 : *pBuf = '='; pBuf++;
485 : 790 : memcpy( pBuf, pKey->maValue.getStr(), nValueLen );
486 : 790 : pBuf += nValueLen;
487 : 790 : *pBuf = aLineEndBuf[0]; pBuf++;
488 [ + - ]: 790 : if ( nLineEndLen == 2 )
489 : : {
490 : 790 : *pBuf = aLineEndBuf[1]; pBuf++;
491 : : }
492 : : }
493 : :
494 : 790 : pKey = pKey->mpNext;
495 : : }
496 : :
497 : : // Store empty line after each group
498 : 158 : sal_uInt16 nEmptyLines = pGroup->mnEmptyLines;
499 [ + + ]: 316 : while ( nEmptyLines )
500 : : {
501 : 158 : *pBuf = aLineEndBuf[0]; pBuf++;
502 [ + - ]: 158 : if ( nLineEndLen == 2 )
503 : : {
504 : 158 : *pBuf = aLineEndBuf[1]; pBuf++;
505 : : }
506 : 158 : nEmptyLines--;
507 : : }
508 : : }
509 : :
510 : 158 : pGroup = pGroup->mpNext;
511 : : }
512 : :
513 : 158 : return pWriteBuf;
514 : : }
515 : :
516 : 632 : static void ImplReadConfig( ImplConfigData* pData )
517 : : {
518 : 632 : sal_uIntPtr nTimeStamp = 0;
519 : 632 : sal_uInt64 nRead = 0;
520 : 632 : sal_Bool bRead = sal_False;
521 : 632 : sal_Bool bIsUTF8BOM =sal_False;
522 [ + - ]: 632 : sal_uInt8* pBuf = ImplSysReadConfig( pData->maFileName, nRead, bRead, bIsUTF8BOM, nTimeStamp );
523 : :
524 : : // Read config list from buffer
525 [ + + ]: 632 : if ( pBuf )
526 : : {
527 [ + - ]: 460 : ImplMakeConfigList( pData, pBuf, nRead );
528 [ + - ]: 460 : delete[] pBuf;
529 : : }
530 : 632 : pData->mnTimeStamp = nTimeStamp;
531 : 632 : pData->mbModified = sal_False;
532 [ + + ]: 632 : if ( bRead )
533 : 460 : pData->mbRead = sal_True;
534 [ - + ]: 632 : if ( bIsUTF8BOM )
535 : 0 : pData->mbIsUTF8BOM = sal_True;
536 : 632 : }
537 : :
538 : 158 : static void ImplWriteConfig( ImplConfigData* pData )
539 : : {
540 : : #ifdef DBG_UTIL
541 : : if ( DbgIsAssert() )
542 : : {
543 : : if ( pData->mnTimeStamp != ImplSysGetConfigTimeStamp( pData->maFileName ) )
544 : : {
545 : : OSL_TRACE( "Config overwrites modified configfile:\n %s", rtl::OUStringToOString(pData->maFileName, RTL_TEXTENCODING_UTF8).getStr() );
546 : : }
547 : : }
548 : : #endif
549 : :
550 : : // Read config list from buffer
551 : : sal_uIntPtr nBufLen;
552 [ + - ]: 158 : sal_uInt8* pBuf = ImplGetConfigBuffer( pData, nBufLen );
553 [ + - ]: 158 : if ( pBuf )
554 : : {
555 [ + - ][ + - ]: 158 : if ( ImplSysWriteConfig( pData->maFileName, pBuf, nBufLen, pData->mbIsUTF8BOM, pData->mnTimeStamp ) )
556 : 158 : pData->mbModified = sal_False;
557 [ + - ]: 158 : delete[] pBuf;
558 : : }
559 : : else
560 : 0 : pData->mbModified = sal_False;
561 : 158 : }
562 : :
563 : 632 : static void ImplDeleteConfigData( ImplConfigData* pData )
564 : : {
565 : : ImplKeyData* pTempKey;
566 : : ImplKeyData* pKey;
567 : : ImplGroupData* pTempGroup;
568 : 632 : ImplGroupData* pGroup = pData->mpFirstGroup;
569 [ + + ]: 1408 : while ( pGroup )
570 : : {
571 : 776 : pTempGroup = pGroup->mpNext;
572 : :
573 : : // remove all keys
574 : 776 : pKey = pGroup->mpFirstKey;
575 [ + + ]: 21118 : while ( pKey )
576 : : {
577 : 20342 : pTempKey = pKey->mpNext;
578 [ + - ]: 20342 : delete pKey;
579 : 20342 : pKey = pTempKey;
580 : : }
581 : :
582 : : // remove group and continue
583 [ + - ]: 776 : delete pGroup;
584 : 776 : pGroup = pTempGroup;
585 : : }
586 : :
587 : 632 : pData->mpFirstGroup = NULL;
588 : 632 : }
589 : :
590 : 632 : static ImplConfigData* ImplGetConfigData( const rtl::OUString& rFileName )
591 : : {
592 : : ImplConfigData* pData;
593 : :
594 : 632 : pData = new ImplConfigData;
595 : 632 : pData->maFileName = rFileName;
596 : 632 : pData->mpFirstGroup = NULL;
597 : 632 : pData->mnDataUpdateId = 0;
598 : 632 : pData->meLineEnd = LINEEND_CRLF;
599 : 632 : pData->mnRefCount = 0;
600 : 632 : pData->mbRead = sal_False;
601 : 632 : pData->mbIsUTF8BOM = sal_False;
602 : 632 : ImplReadConfig( pData );
603 : :
604 : 632 : return pData;
605 : : }
606 : :
607 : 632 : static void ImplFreeConfigData( ImplConfigData* pDelData )
608 : : {
609 : 632 : ImplDeleteConfigData( pDelData );
610 [ + - ]: 632 : delete pDelData;
611 : 632 : }
612 : :
613 : 0 : sal_Bool Config::ImplUpdateConfig() const
614 : : {
615 : : // Re-read file if timestamp differs
616 [ # # ]: 0 : if ( mpData->mnTimeStamp != ImplSysGetConfigTimeStamp( maFileName ) )
617 : : {
618 : 0 : ImplDeleteConfigData( mpData );
619 : 0 : ImplReadConfig( mpData );
620 : 0 : mpData->mnDataUpdateId++;
621 : 0 : return sal_True;
622 : : }
623 : : else
624 : 0 : return sal_False;
625 : : }
626 : :
627 : 7456 : ImplGroupData* Config::ImplGetGroup() const
628 : : {
629 [ + + ][ + + ]: 7456 : if ( !mpActGroup || (mnDataUpdateId != mpData->mnDataUpdateId) )
630 : : {
631 : 632 : ImplGroupData* pPrevGroup = NULL;
632 : 632 : ImplGroupData* pGroup = mpData->mpFirstGroup;
633 [ + + ]: 920 : while ( pGroup )
634 : : {
635 [ + + ]: 734 : if ( pGroup->maGroupName.equalsIgnoreAsciiCase(maGroupName) )
636 : 446 : break;
637 : :
638 : 288 : pPrevGroup = pGroup;
639 : 288 : pGroup = pGroup->mpNext;
640 : : }
641 : :
642 : : // Add group if not exists
643 [ + + ]: 632 : if ( !pGroup )
644 : : {
645 : 186 : pGroup = new ImplGroupData;
646 : 186 : pGroup->mpNext = NULL;
647 : 186 : pGroup->mpFirstKey = NULL;
648 : 186 : pGroup->mnEmptyLines = 1;
649 [ - + ]: 186 : if ( pPrevGroup )
650 : 0 : pPrevGroup->mpNext = pGroup;
651 : : else
652 : 186 : mpData->mpFirstGroup = pGroup;
653 : : }
654 : :
655 : : // Always inherit group names and upate cache members
656 : 632 : pGroup->maGroupName = maGroupName;
657 : 632 : ((Config*)this)->mnDataUpdateId = mpData->mnDataUpdateId;
658 : 632 : ((Config*)this)->mpActGroup = pGroup;
659 : : }
660 : :
661 : 7456 : return mpActGroup;
662 : : }
663 : :
664 : 632 : Config::Config( const rtl::OUString& rFileName )
665 : : {
666 : : // Initialize config data
667 [ + - ][ + - ]: 632 : maFileName = toUncPath( rFileName );
[ + - ][ + - ]
[ + - ]
668 [ + - ]: 632 : mpData = ImplGetConfigData( maFileName );
669 : 632 : mpActGroup = NULL;
670 : 632 : mnDataUpdateId = 0;
671 : 632 : mnLockCount = 1;
672 : 632 : mbPersistence = sal_True;
673 : :
674 : : #ifdef DBG_UTIL
675 : : rtl::OStringBuffer aTraceStr(
676 : : RTL_CONSTASCII_STRINGPARAM("Config::Config( "));
677 : : aTraceStr.append(rtl::OUStringToOString(maFileName, RTL_TEXTENCODING_UTF8));
678 : : aTraceStr.append(RTL_CONSTASCII_STRINGPARAM(" )"));
679 : : OSL_TRACE("%s", aTraceStr.getStr());
680 : : #endif
681 : 632 : }
682 : :
683 : 632 : Config::~Config()
684 : : {
685 : : #ifdef DBG_UTIL
686 : : OSL_TRACE( "Config::~Config()" );
687 : : #endif
688 : :
689 [ + - ]: 632 : Flush();
690 : 632 : ImplFreeConfigData( mpData );
691 : 632 : }
692 : :
693 : 632 : void Config::SetGroup(const rtl::OString& rGroup)
694 : : {
695 : : // If group is to be reset, it needs to be updated on next call
696 [ + + ]: 632 : if ( maGroupName != rGroup )
697 : : {
698 : 560 : maGroupName = rGroup;
699 : 560 : mnDataUpdateId = mpData->mnDataUpdateId-1;
700 : : }
701 : 632 : }
702 : :
703 : 0 : void Config::DeleteGroup(const rtl::OString& rGroup)
704 : : {
705 : : // Update config data if necessary
706 [ # # ][ # # ]: 0 : if ( !mnLockCount || !mpData->mbRead )
707 : : {
708 : 0 : ImplUpdateConfig();
709 : 0 : mpData->mbRead = sal_True;
710 : : }
711 : :
712 : 0 : ImplGroupData* pPrevGroup = NULL;
713 : 0 : ImplGroupData* pGroup = mpData->mpFirstGroup;
714 [ # # ]: 0 : while ( pGroup )
715 : : {
716 [ # # ]: 0 : if ( pGroup->maGroupName.equalsIgnoreAsciiCase(rGroup) )
717 : 0 : break;
718 : :
719 : 0 : pPrevGroup = pGroup;
720 : 0 : pGroup = pGroup->mpNext;
721 : : }
722 : :
723 [ # # ]: 0 : if ( pGroup )
724 : : {
725 : : // Remove all keys
726 : : ImplKeyData* pTempKey;
727 : 0 : ImplKeyData* pKey = pGroup->mpFirstKey;
728 [ # # ]: 0 : while ( pKey )
729 : : {
730 : 0 : pTempKey = pKey->mpNext;
731 [ # # ]: 0 : delete pKey;
732 : 0 : pKey = pTempKey;
733 : : }
734 : :
735 : : // Rewire pointers and remove group
736 [ # # ]: 0 : if ( pPrevGroup )
737 : 0 : pPrevGroup->mpNext = pGroup->mpNext;
738 : : else
739 : 0 : mpData->mpFirstGroup = pGroup->mpNext;
740 [ # # ]: 0 : delete pGroup;
741 : :
742 : : // Rewrite config data
743 [ # # ][ # # ]: 0 : if ( !mnLockCount && mbPersistence )
744 : 0 : ImplWriteConfig( mpData );
745 : : else
746 : : {
747 : 0 : mpData->mbModified = sal_True;
748 : : }
749 : :
750 : 0 : mnDataUpdateId = mpData->mnDataUpdateId;
751 : 0 : mpData->mnDataUpdateId++;
752 : : }
753 : 0 : }
754 : :
755 : 288 : rtl::OString Config::GetGroupName(sal_uInt16 nGroup) const
756 : : {
757 : : // Update config data if necessary
758 [ - + ]: 288 : if ( !mnLockCount )
759 : 0 : ImplUpdateConfig();
760 : :
761 : 288 : ImplGroupData* pGroup = mpData->mpFirstGroup;
762 : 288 : sal_uInt16 nGroupCount = 0;
763 : 288 : rtl::OString aGroupName;
764 [ + - ]: 648 : while ( pGroup )
765 : : {
766 [ + + ]: 648 : if ( nGroup == nGroupCount )
767 : : {
768 : 288 : aGroupName = pGroup->maGroupName;
769 : 288 : break;
770 : : }
771 : :
772 : 360 : nGroupCount++;
773 : 360 : pGroup = pGroup->mpNext;
774 : : }
775 : :
776 : 288 : return aGroupName;
777 : : }
778 : :
779 : 360 : sal_uInt16 Config::GetGroupCount() const
780 : : {
781 : : // Update config data if necessary
782 [ - + ]: 360 : if ( !mnLockCount )
783 : 0 : ImplUpdateConfig();
784 : :
785 : 360 : ImplGroupData* pGroup = mpData->mpFirstGroup;
786 : 360 : sal_uInt16 nGroupCount = 0;
787 [ + + ]: 1224 : while ( pGroup )
788 : : {
789 : 864 : nGroupCount++;
790 : 864 : pGroup = pGroup->mpNext;
791 : : }
792 : :
793 : 360 : return nGroupCount;
794 : : }
795 : :
796 : 144 : sal_Bool Config::HasGroup(const rtl::OString& rGroup) const
797 : : {
798 : : // Update config data if necessary
799 [ - + ]: 144 : if ( !mnLockCount )
800 : 0 : ImplUpdateConfig();
801 : :
802 : 144 : ImplGroupData* pGroup = mpData->mpFirstGroup;
803 : 144 : sal_Bool bRet = sal_False;
804 : :
805 [ + + ]: 216 : while( pGroup )
806 : : {
807 [ + + ]: 144 : if( pGroup->maGroupName.equalsIgnoreAsciiCase(rGroup) )
808 : : {
809 : 72 : bRet = sal_True;
810 : 72 : break;
811 : : }
812 : :
813 : 72 : pGroup = pGroup->mpNext;
814 : : }
815 : :
816 : 144 : return bRet;
817 : : }
818 : :
819 : 3110 : rtl::OString Config::ReadKey(const rtl::OString& rKey) const
820 : : {
821 [ + - ]: 3110 : return ReadKey(rKey, rtl::OString());
822 : : }
823 : :
824 : 0 : rtl::OUString Config::ReadKey(const rtl::OString& rKey, rtl_TextEncoding eEncoding) const
825 : : {
826 [ # # ]: 0 : if ( mpData->mbIsUTF8BOM )
827 : 0 : eEncoding = RTL_TEXTENCODING_UTF8;
828 [ # # ]: 0 : return rtl::OStringToOUString(ReadKey(rKey), eEncoding);
829 : : }
830 : :
831 : 3182 : rtl::OString Config::ReadKey(const rtl::OString& rKey, const rtl::OString& rDefault) const
832 : : {
833 : : #ifdef DBG_UTIL
834 : : rtl::OStringBuffer aTraceStr(
835 : : RTL_CONSTASCII_STRINGPARAM("Config::ReadKey( "));
836 : : aTraceStr.append(rKey);
837 : : aTraceStr.append(RTL_CONSTASCII_STRINGPARAM(" ) from "));
838 : : aTraceStr.append(GetGroup());
839 : : aTraceStr.append(RTL_CONSTASCII_STRINGPARAM(" in "));
840 : : aTraceStr.append(rtl::OUStringToOString(maFileName, RTL_TEXTENCODING_UTF8));
841 : : OSL_TRACE("%s", aTraceStr.getStr());
842 : : #endif
843 : :
844 : : // Update config data if necessary
845 [ - + ]: 3182 : if ( !mnLockCount )
846 : 0 : ImplUpdateConfig();
847 : :
848 : : // Search key, return value if found
849 : 3182 : ImplGroupData* pGroup = ImplGetGroup();
850 [ + - ]: 3182 : if ( pGroup )
851 : : {
852 : 3182 : ImplKeyData* pKey = pGroup->mpFirstKey;
853 [ + + ]: 144990 : while ( pKey )
854 : : {
855 [ + + ][ + + ]: 143464 : if ( !pKey->mbIsComment && pKey->maKey.equalsIgnoreAsciiCase(rKey) )
[ + + ]
856 : 1656 : return pKey->maValue;
857 : :
858 : 141808 : pKey = pKey->mpNext;
859 : : }
860 : : }
861 : :
862 : 3182 : return rDefault;
863 : : }
864 : :
865 : 790 : void Config::WriteKey(const rtl::OString& rKey, const rtl::OString& rStr)
866 : : {
867 : : #ifdef DBG_UTIL
868 : : rtl::OStringBuffer aTraceStr(RTL_CONSTASCII_STRINGPARAM("Config::WriteKey( "));
869 : : aTraceStr.append(rKey);
870 : : aTraceStr.append(RTL_CONSTASCII_STRINGPARAM(", "));
871 : : aTraceStr.append(rStr);
872 : : aTraceStr.append(RTL_CONSTASCII_STRINGPARAM(" ) to "));
873 : : aTraceStr.append(GetGroup());
874 : : aTraceStr.append(RTL_CONSTASCII_STRINGPARAM(" in "));
875 : : aTraceStr.append(rtl::OUStringToOString(maFileName, RTL_TEXTENCODING_UTF8));
876 : : OSL_TRACE("%s", aTraceStr.getStr());
877 : : #endif
878 : :
879 : : // Update config data if necessary
880 [ + - ][ - + ]: 790 : if ( !mnLockCount || !mpData->mbRead )
881 : : {
882 : 0 : ImplUpdateConfig();
883 : 0 : mpData->mbRead = sal_True;
884 : : }
885 : :
886 : : // Search key and update value if found
887 : 790 : ImplGroupData* pGroup = ImplGetGroup();
888 [ + - ]: 790 : if ( pGroup )
889 : : {
890 : 790 : ImplKeyData* pPrevKey = NULL;
891 : 790 : ImplKeyData* pKey = pGroup->mpFirstKey;
892 [ + + ]: 2370 : while ( pKey )
893 : : {
894 [ + - ][ - + ]: 1580 : if ( !pKey->mbIsComment && pKey->maKey.equalsIgnoreAsciiCase(rKey) )
[ - + ]
895 : 0 : break;
896 : :
897 : 1580 : pPrevKey = pKey;
898 : 1580 : pKey = pKey->mpNext;
899 : : }
900 : :
901 : : sal_Bool bNewValue;
902 [ + - ]: 790 : if ( !pKey )
903 : : {
904 : 790 : pKey = new ImplKeyData;
905 : 790 : pKey->mpNext = NULL;
906 : 790 : pKey->maKey = rKey;
907 : 790 : pKey->mbIsComment = sal_False;
908 [ + + ]: 790 : if ( pPrevKey )
909 : 632 : pPrevKey->mpNext = pKey;
910 : : else
911 : 158 : pGroup->mpFirstKey = pKey;
912 : 790 : bNewValue = sal_True;
913 : : }
914 : : else
915 : 0 : bNewValue = pKey->maValue != rStr;
916 : :
917 [ + - ]: 790 : if ( bNewValue )
918 : : {
919 : 790 : pKey->maValue = rStr;
920 : :
921 [ # # ][ - + ]: 790 : if ( !mnLockCount && mbPersistence )
922 : 0 : ImplWriteConfig( mpData );
923 : : else
924 : : {
925 : 790 : mpData->mbModified = sal_True;
926 : : }
927 : : }
928 : : }
929 : 790 : }
930 : :
931 : 0 : void Config::DeleteKey(const rtl::OString& rKey)
932 : : {
933 : : // Update config data if necessary
934 [ # # ][ # # ]: 0 : if ( !mnLockCount || !mpData->mbRead )
935 : : {
936 : 0 : ImplUpdateConfig();
937 : 0 : mpData->mbRead = sal_True;
938 : : }
939 : :
940 : : // Search key and update value
941 : 0 : ImplGroupData* pGroup = ImplGetGroup();
942 [ # # ]: 0 : if ( pGroup )
943 : : {
944 : 0 : ImplKeyData* pPrevKey = NULL;
945 : 0 : ImplKeyData* pKey = pGroup->mpFirstKey;
946 [ # # ]: 0 : while ( pKey )
947 : : {
948 [ # # ][ # # ]: 0 : if ( !pKey->mbIsComment && pKey->maKey.equalsIgnoreAsciiCase(rKey) )
[ # # ]
949 : 0 : break;
950 : :
951 : 0 : pPrevKey = pKey;
952 : 0 : pKey = pKey->mpNext;
953 : : }
954 : :
955 [ # # ]: 0 : if ( pKey )
956 : : {
957 : : // Rewire group pointers and delete
958 [ # # ]: 0 : if ( pPrevKey )
959 : 0 : pPrevKey->mpNext = pKey->mpNext;
960 : : else
961 : 0 : pGroup->mpFirstKey = pKey->mpNext;
962 [ # # ]: 0 : delete pKey;
963 : :
964 : : // Rewrite config file
965 [ # # ][ # # ]: 0 : if ( !mnLockCount && mbPersistence )
966 : 0 : ImplWriteConfig( mpData );
967 : : else
968 : : {
969 : 0 : mpData->mbModified = sal_True;
970 : : }
971 : : }
972 : : }
973 : 0 : }
974 : :
975 : 1828 : sal_uInt16 Config::GetKeyCount() const
976 : : {
977 : : #ifdef DBG_UTIL
978 : : rtl::OStringBuffer aTraceStr(
979 : : RTL_CONSTASCII_STRINGPARAM("Config::GetKeyCount()"));
980 : : aTraceStr.append(RTL_CONSTASCII_STRINGPARAM(" from "));
981 : : aTraceStr.append(GetGroup());
982 : : aTraceStr.append(RTL_CONSTASCII_STRINGPARAM(" in "));
983 : : aTraceStr.append(rtl::OUStringToOString(maFileName, RTL_TEXTENCODING_UTF8));
984 : : OSL_TRACE("%s", aTraceStr.getStr());
985 : : #endif
986 : :
987 : : // Update config data if necessary
988 [ - + ]: 1828 : if ( !mnLockCount )
989 : 0 : ImplUpdateConfig();
990 : :
991 : : // Search key and update value
992 : 1828 : sal_uInt16 nCount = 0;
993 : 1828 : ImplGroupData* pGroup = ImplGetGroup();
994 [ + - ]: 1828 : if ( pGroup )
995 : : {
996 : 1828 : ImplKeyData* pKey = pGroup->mpFirstKey;
997 [ + + ]: 98668 : while ( pKey )
998 : : {
999 [ + + ]: 96840 : if ( !pKey->mbIsComment )
1000 : 21600 : nCount++;
1001 : :
1002 : 96840 : pKey = pKey->mpNext;
1003 : : }
1004 : : }
1005 : :
1006 : 1828 : return nCount;
1007 : : }
1008 : :
1009 : 1656 : rtl::OString Config::GetKeyName(sal_uInt16 nKey) const
1010 : : {
1011 : : #ifdef DBG_UTIL
1012 : : rtl::OStringBuffer aTraceStr(
1013 : : RTL_CONSTASCII_STRINGPARAM("Config::GetKeyName( "));
1014 : : aTraceStr.append(static_cast<sal_Int32>(nKey));
1015 : : aTraceStr.append(RTL_CONSTASCII_STRINGPARAM(" ) from "));
1016 : : aTraceStr.append(GetGroup());
1017 : : aTraceStr.append(RTL_CONSTASCII_STRINGPARAM(" in "));
1018 : : aTraceStr.append(rtl::OUStringToOString(
1019 : : maFileName, RTL_TEXTENCODING_UTF8));
1020 : : OSL_TRACE("%s", aTraceStr.getStr());
1021 : : #endif
1022 : :
1023 : : // search key and return name if found
1024 : 1656 : ImplGroupData* pGroup = ImplGetGroup();
1025 [ + - ]: 1656 : if ( pGroup )
1026 : : {
1027 : 1656 : ImplKeyData* pKey = pGroup->mpFirstKey;
1028 [ + - ]: 69696 : while ( pKey )
1029 : : {
1030 [ + + ]: 69696 : if ( !pKey->mbIsComment )
1031 : : {
1032 [ + + ]: 10800 : if ( !nKey )
1033 : 1656 : return pKey->maKey;
1034 : 9144 : nKey--;
1035 : : }
1036 : :
1037 : 68040 : pKey = pKey->mpNext;
1038 : : }
1039 : : }
1040 : :
1041 : 1656 : return rtl::OString();
1042 : : }
1043 : :
1044 : 0 : rtl::OString Config::ReadKey(sal_uInt16 nKey) const
1045 : : {
1046 : : #ifdef DBG_UTIL
1047 : : rtl::OStringBuffer aTraceStr(
1048 : : RTL_CONSTASCII_STRINGPARAM("Config::ReadKey( "));
1049 : : aTraceStr.append(static_cast<sal_Int32>(nKey));
1050 : : aTraceStr.append(RTL_CONSTASCII_STRINGPARAM(" ) from "));
1051 : : aTraceStr.append(GetGroup());
1052 : : aTraceStr.append(RTL_CONSTASCII_STRINGPARAM(" in "));
1053 : : aTraceStr.append(rtl::OUStringToOString(maFileName,
1054 : : RTL_TEXTENCODING_UTF8));
1055 : : OSL_TRACE("%s", aTraceStr.getStr());
1056 : : #endif
1057 : :
1058 : : // Search key and return value if found
1059 : 0 : ImplGroupData* pGroup = ImplGetGroup();
1060 [ # # ]: 0 : if ( pGroup )
1061 : : {
1062 : 0 : ImplKeyData* pKey = pGroup->mpFirstKey;
1063 [ # # ]: 0 : while ( pKey )
1064 : : {
1065 [ # # ]: 0 : if ( !pKey->mbIsComment )
1066 : : {
1067 [ # # ]: 0 : if ( !nKey )
1068 : 0 : return pKey->maValue;
1069 : 0 : nKey--;
1070 : : }
1071 : :
1072 : 0 : pKey = pKey->mpNext;
1073 : : }
1074 : : }
1075 : :
1076 : 0 : return rtl::OString();
1077 : : }
1078 : :
1079 : 790 : void Config::Flush()
1080 : : {
1081 [ + + ][ + - ]: 790 : if ( mpData->mbModified && mbPersistence )
1082 : 158 : ImplWriteConfig( mpData );
1083 : 790 : }
1084 : :
1085 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|