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