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