Update ooo320-m1
[ooovba.git] / tools / source / generic / config.cxx
blobe6740750c00e11705b14968426c794a1cbef0f0b
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: config.cxx,v $
10 * $Revision: 1.18 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_tools.hxx"
34 #define _CONFIG_CXX
36 #include <cstddef>
37 #include <cstdlib>
38 #include <limits>
39 #include <new>
40 #include <string.h>
42 #ifdef WNT
43 #include "stdlib.h"
44 #endif
45 #include <osl/file.hxx>
46 #include <tools/stream.hxx>
47 #include <tools/debug.hxx>
48 #include <tools/config.hxx>
49 #include <osl/security.h>
51 #define MAXBUFLEN 1024 // Fuer Buffer bei VOS-Funktionen
53 // -----------------
54 // - ImplConfigData -
55 // -----------------
57 struct ImplKeyData
59 ImplKeyData* mpNext;
60 ByteString maKey;
61 ByteString maValue;
62 BOOL mbIsComment;
65 struct ImplGroupData
67 ImplGroupData* mpNext;
68 ImplKeyData* mpFirstKey;
69 ByteString maGroupName;
70 USHORT mnEmptyLines;
73 struct ImplConfigData
75 ImplGroupData* mpFirstGroup;
76 XubString maFileName;
77 ULONG mnDataUpdateId;
78 ULONG mnTimeStamp;
79 LineEnd meLineEnd;
80 USHORT mnRefCount;
81 BOOL mbModified;
82 BOOL mbRead;
83 BOOL mbIsUTF8BOM;
86 // =======================================================================
88 static ByteString& getEmptyByteString()
90 static ByteString aEmpty;
91 return aEmpty;
94 // =======================================================================
96 static String toUncPath( const String& rPath )
98 ::rtl::OUString aFileURL;
100 // check if rFileName is already a URL; if not make it so
101 if( rPath.CompareToAscii( "file://", 7 ) == COMPARE_EQUAL )
102 aFileURL = rPath;
103 else if( ::osl::FileBase::getFileURLFromSystemPath( rPath, aFileURL ) != ::osl::FileBase::E_None )
104 aFileURL = rPath;
106 return aFileURL;
109 static ULONG ImplSysGetConfigTimeStamp( const XubString& rFileName )
111 ULONG nTimeStamp = 0;
112 ::osl::DirectoryItem aItem;
113 ::osl::FileStatus aStatus( osl_FileStatus_Mask_ModifyTime );
115 int nError = 0;
116 if( ( nError = ::osl::DirectoryItem::get( rFileName, aItem ) ) == ::osl::FileBase::E_None &&
117 aItem.getFileStatus( aStatus ) == ::osl::FileBase::E_None )
119 nTimeStamp = aStatus.getModifyTime().Seconds;
122 return nTimeStamp;
125 // -----------------------------------------------------------------------
127 static BYTE* ImplSysReadConfig( const XubString& rFileName,
128 sal_uInt64& rRead, BOOL& rbRead, BOOL& rbIsUTF8BOM, ULONG& rTimeStamp )
130 BYTE* pBuf = NULL;
131 ::osl::File aFile( rFileName );
133 if( aFile.open( osl_File_OpenFlag_Read ) == ::osl::FileBase::E_None )
135 sal_uInt64 nPos = 0, nRead = 0;
136 if( aFile.getSize( nPos ) == ::osl::FileBase::E_None )
138 if (nPos > std::numeric_limits< std::size_t >::max()) {
139 aFile.close();
140 return 0;
142 pBuf = new BYTE[static_cast< std::size_t >(nPos)];
143 if( aFile.read( pBuf, nPos, nRead ) == ::osl::FileBase::E_None && nRead == nPos )
145 //skip the byte-order-mark 0xEF 0xBB 0xBF, if it was UTF8 files
146 unsigned char BOM[3] = {0xEF, 0xBB, 0xBF};
147 if (nRead > 2 && memcmp(pBuf, BOM, 3) == 0)
149 nRead -= 3;
150 rtl_moveMemory(pBuf, pBuf + 3, sal::static_int_cast<sal_Size>(nRead * sizeof(BYTE)) );
151 rbIsUTF8BOM = TRUE;
154 rTimeStamp = ImplSysGetConfigTimeStamp( rFileName );
155 rbRead = TRUE;
156 rRead = nRead;
158 else
160 delete[] pBuf;
161 pBuf = NULL;
164 aFile.close();
167 return pBuf;
170 // -----------------------------------------------------------------------
172 static BOOL ImplSysWriteConfig( const XubString& rFileName,
173 const BYTE* pBuf, ULONG nBufLen, BOOL rbIsUTF8BOM, ULONG& rTimeStamp )
175 BOOL bSuccess = FALSE;
176 BOOL bUTF8BOMSuccess = FALSE;
178 ::osl::File aFile( rFileName );
179 ::osl::FileBase::RC eError = aFile.open( osl_File_OpenFlag_Write | osl_File_OpenFlag_Create );
180 if( eError != ::osl::FileBase::E_None )
181 eError = aFile.open( osl_File_OpenFlag_Write );
182 if( eError == ::osl::FileBase::E_None )
184 // truncate
185 aFile.setSize( 0 );
186 sal_uInt64 nWritten;
188 //write the the byte-order-mark 0xEF 0xBB 0xBF first , if it was UTF8 files
189 if ( rbIsUTF8BOM )
191 unsigned char BOM[3] = {0xEF, 0xBB, 0xBF};
192 sal_uInt64 nUTF8BOMWritten;
193 if( aFile.write( BOM, 3, nUTF8BOMWritten ) == ::osl::FileBase::E_None && 3 == nUTF8BOMWritten )
195 bUTF8BOMSuccess = TRUE;
199 if( aFile.write( pBuf, nBufLen, nWritten ) == ::osl::FileBase::E_None && nWritten == nBufLen )
201 bSuccess = TRUE;
203 if ( rbIsUTF8BOM ? bSuccess && bUTF8BOMSuccess : bSuccess )
205 rTimeStamp = ImplSysGetConfigTimeStamp( rFileName );
209 return rbIsUTF8BOM ? bSuccess && bUTF8BOMSuccess : bSuccess;
212 // -----------------------------------------------------------------------
214 static String ImplMakeConfigName( const XubString* pFileName,
215 const XubString* pPathName )
217 ::rtl::OUString aFileName;
218 ::rtl::OUString aPathName;
219 if ( pFileName )
221 #ifdef UNX
222 aFileName = ::rtl::OUString::createFromAscii( "." );
223 aFileName += *pFileName;
224 aFileName += ::rtl::OUString::createFromAscii( "rc" );
225 #else
226 aFileName = *pFileName;
227 aFileName += ::rtl::OUString::createFromAscii( ".ini" );
228 #endif
230 else
232 #ifdef UNX
233 aFileName = ::rtl::OUString::createFromAscii( ".sversionrc" );
234 #else
235 aFileName = ::rtl::OUString::createFromAscii( "sversion.ini" );
236 #endif
239 // #88208# in case pPathName is set but empty and pFileName is set
240 // and not empty just return the filename; on the default case
241 // prepend default path as usual
242 if ( pPathName && pPathName->Len() )
243 aPathName = toUncPath( *pPathName );
244 else if( pPathName && pFileName && pFileName->Len() )
245 return aFileName;
246 else
248 oslSecurity aSec = osl_getCurrentSecurity();
249 osl_getConfigDir( aSec, &aPathName.pData );
250 osl_freeSecurityHandle( aSec );
253 ::rtl::OUString aName( aPathName );
254 aName += ::rtl::OUString::createFromAscii( "/" );
255 aName += aFileName;
257 return aName;
260 // -----------------------------------------------------------------------
262 namespace {
264 ByteString makeByteString(BYTE const * p, sal_uInt64 n) {
265 if (n > STRING_MAXLEN) {
266 #ifdef WNT
267 abort();
268 #else
269 ::std::abort(); //TODO: handle this gracefully
270 #endif
272 return ByteString(
273 reinterpret_cast< char const * >(p),
274 sal::static_int_cast< xub_StrLen >(n));
279 static void ImplMakeConfigList( ImplConfigData* pData,
280 const BYTE* pBuf, sal_uInt64 nLen )
282 // kein Buffer, keine Daten
283 if ( !nLen )
284 return;
286 // Buffer parsen und Liste zusammenbauen
287 sal_uInt64 nStart;
288 sal_uInt64 nLineLen;
289 xub_StrLen nNameLen;
290 xub_StrLen nKeyLen;
291 sal_uInt64 i;
292 const BYTE* pLine;
293 ImplKeyData* pPrevKey = NULL;
294 ImplKeyData* pKey;
295 ImplGroupData* pPrevGroup = NULL;
296 ImplGroupData* pGroup = NULL;
297 i = 0;
298 while ( i < nLen )
300 // Ctrl+Z
301 if ( pBuf[i] == 0x1A )
302 break;
304 // Spaces und Tabs entfernen
305 while ( (pBuf[i] == ' ') || (pBuf[i] == '\t') )
306 i++;
308 // Zeilenanfang merken
309 nStart = i;
310 pLine = pBuf+i;
312 // Zeilenende suchen
313 while ( (i < nLen) && pBuf[i] && (pBuf[i] != '\r') && (pBuf[i] != '\n') &&
314 (pBuf[i] != 0x1A) )
315 i++;
317 nLineLen = i-nStart;
319 // Wenn Zeilenende (CR/LF), dann noch einen weiterschalten
320 if ( (i+1 < nLen) &&
321 (pBuf[i] != pBuf[i+1]) &&
322 ((pBuf[i+1] == '\r') || (pBuf[i+1] == '\n')) )
323 i++;
324 i++;
326 // Zeile auswerten
327 if ( *pLine == '[' )
329 pGroup = new ImplGroupData;
330 pGroup->mpNext = NULL;
331 pGroup->mpFirstKey = NULL;
332 pGroup->mnEmptyLines = 0;
333 if ( pPrevGroup )
334 pPrevGroup->mpNext = pGroup;
335 else
336 pData->mpFirstGroup = pGroup;
337 pPrevGroup = pGroup;
338 pPrevKey = NULL;
339 pKey = NULL;
341 // Gruppennamen rausfiltern
342 pLine++;
343 nLineLen--;
344 // Spaces und Tabs entfernen
345 while ( (*pLine == ' ') || (*pLine == '\t') )
347 nLineLen--;
348 pLine++;
350 nNameLen = 0;
351 while ( (nNameLen < nLineLen) && (pLine[nNameLen] != ']') )
352 nNameLen++;
353 if ( nNameLen )
355 while ( (pLine[nNameLen-1] == ' ') || (pLine[nNameLen-1] == '\t') )
356 nNameLen--;
358 pGroup->maGroupName = ByteString( (const sal_Char*)pLine, nNameLen );
360 else
362 if ( nLineLen )
364 // Wenn noch keine Gruppe existiert, dann alle Keys in die
365 // Default-Gruppe
366 if ( !pGroup )
368 pGroup = new ImplGroupData;
369 pGroup->mpNext = NULL;
370 pGroup->mpFirstKey = NULL;
371 pGroup->mnEmptyLines = 0;
372 if ( pPrevGroup )
373 pPrevGroup->mpNext = pGroup;
374 else
375 pData->mpFirstGroup = pGroup;
376 pPrevGroup = pGroup;
377 pPrevKey = NULL;
380 // Falls Leerzeile vorhanden, dann anhaengen
381 if ( pPrevKey )
383 while ( pGroup->mnEmptyLines )
385 pKey = new ImplKeyData;
386 pKey->mbIsComment = TRUE;
387 pPrevKey->mpNext = pKey;
388 pPrevKey = pKey;
389 pGroup->mnEmptyLines--;
393 // Neuen Key erzeugen
394 pKey = new ImplKeyData;
395 pKey->mpNext = NULL;
396 if ( pPrevKey )
397 pPrevKey->mpNext = pKey;
398 else
399 pGroup->mpFirstKey = pKey;
400 pPrevKey = pKey;
401 if ( pLine[0] == ';' )
403 pKey->maValue = makeByteString(pLine, nLineLen);
404 pKey->mbIsComment = TRUE;
406 else
408 pKey->mbIsComment = FALSE;
409 nNameLen = 0;
410 while ( (nNameLen < nLineLen) && (pLine[nNameLen] != '=') )
411 nNameLen++;
412 nKeyLen = nNameLen;
413 // Spaces und Tabs entfernen
414 if ( nNameLen )
416 while ( (pLine[nNameLen-1] == ' ') || (pLine[nNameLen-1] == '\t') )
417 nNameLen--;
419 pKey->maKey = ByteString( (const sal_Char*)pLine, nNameLen );
420 nKeyLen++;
421 if ( nKeyLen < nLineLen )
423 pLine += nKeyLen;
424 nLineLen -= nKeyLen;
425 // Spaces und Tabs entfernen
426 while ( (*pLine == ' ') || (*pLine == '\t') )
428 nLineLen--;
429 pLine++;
431 if ( nLineLen )
433 while ( (pLine[nLineLen-1] == ' ') || (pLine[nLineLen-1] == '\t') )
434 nLineLen--;
435 pKey->maValue = makeByteString(pLine, nLineLen);
440 else
442 // Leerzeilen werden nur gezaehlt und beim Erzeugen des
443 // naechsten Keys angehaengt, da wir Leerzeilen am Ende
444 // einer Gruppe auch nach hinzufuegen von neuen Keys nur
445 // am Ende der Gruppe wieder speichern wollen
446 if ( pGroup )
447 pGroup->mnEmptyLines++;
453 // -----------------------------------------------------------------------
455 static BYTE* ImplGetConfigBuffer( const ImplConfigData* pData, ULONG& rLen )
457 BYTE* pWriteBuf;
458 BYTE* pBuf;
459 BYTE aLineEndBuf[2] = {0, 0};
460 ImplKeyData* pKey;
461 ImplGroupData* pGroup;
462 unsigned int nBufLen;
463 USHORT nValueLen;
464 USHORT nKeyLen;
465 USHORT nLineEndLen;
467 if ( pData->meLineEnd == LINEEND_CR )
469 aLineEndBuf[0] = _CR;
470 nLineEndLen = 1;
472 else if ( pData->meLineEnd == LINEEND_LF )
474 aLineEndBuf[0] = _LF;
475 nLineEndLen = 1;
477 else
479 aLineEndBuf[0] = _CR;
480 aLineEndBuf[1] = _LF;
481 nLineEndLen = 2;
484 // Buffergroesse ermitteln
485 nBufLen = 0;
486 pGroup = pData->mpFirstGroup;
487 while ( pGroup )
489 // Leere Gruppen werden nicht geschrieben
490 if ( pGroup->mpFirstKey )
492 nBufLen += pGroup->maGroupName.Len() + nLineEndLen + 2;
493 pKey = pGroup->mpFirstKey;
494 while ( pKey )
496 nValueLen = pKey->maValue.Len();
497 if ( pKey->mbIsComment )
498 nBufLen += nValueLen + nLineEndLen;
499 else
500 nBufLen += pKey->maKey.Len() + nValueLen + nLineEndLen + 1;
502 pKey = pKey->mpNext;
505 // Leerzeile nach jeder Gruppe auch wieder speichern
506 if ( !pGroup->mnEmptyLines )
507 pGroup->mnEmptyLines = 1;
508 nBufLen += nLineEndLen * pGroup->mnEmptyLines;
511 pGroup = pGroup->mpNext;
514 // Laenge dem Aufrufer mitteilen
515 rLen = nBufLen;
516 if ( !nBufLen )
518 pWriteBuf = new BYTE[nLineEndLen];
519 if ( pWriteBuf )
521 pWriteBuf[0] = aLineEndBuf[0];
522 if ( nLineEndLen == 2 )
523 pWriteBuf[1] = aLineEndBuf[1];
524 return pWriteBuf;
526 else
527 return 0;
530 // Schreibbuffer anlegen (wird vom Aufrufer zerstoert)
531 pWriteBuf = new BYTE[nBufLen];
532 if ( !pWriteBuf )
533 return 0;
535 // Buffer fuellen
536 pBuf = pWriteBuf;
537 pGroup = pData->mpFirstGroup;
538 while ( pGroup )
540 // Leere Gruppen werden nicht geschrieben
541 if ( pGroup->mpFirstKey )
543 *pBuf = '['; pBuf++;
544 memcpy( pBuf, pGroup->maGroupName.GetBuffer(), pGroup->maGroupName.Len() );
545 pBuf += pGroup->maGroupName.Len();
546 *pBuf = ']'; pBuf++;
547 *pBuf = aLineEndBuf[0]; pBuf++;
548 if ( nLineEndLen == 2 )
550 *pBuf = aLineEndBuf[1]; pBuf++;
552 pKey = pGroup->mpFirstKey;
553 while ( pKey )
555 nValueLen = pKey->maValue.Len();
556 if ( pKey->mbIsComment )
558 if ( nValueLen )
560 memcpy( pBuf, pKey->maValue.GetBuffer(), nValueLen );
561 pBuf += nValueLen;
563 *pBuf = aLineEndBuf[0]; pBuf++;
564 if ( nLineEndLen == 2 )
566 *pBuf = aLineEndBuf[1]; pBuf++;
569 else
571 nKeyLen = pKey->maKey.Len();
572 memcpy( pBuf, pKey->maKey.GetBuffer(), nKeyLen );
573 pBuf += nKeyLen;
574 *pBuf = '='; pBuf++;
575 memcpy( pBuf, pKey->maValue.GetBuffer(), nValueLen );
576 pBuf += nValueLen;
577 *pBuf = aLineEndBuf[0]; pBuf++;
578 if ( nLineEndLen == 2 )
580 *pBuf = aLineEndBuf[1]; pBuf++;
584 pKey = pKey->mpNext;
587 // Leerzeile nach jeder Gruppe auch wieder speichern
588 USHORT nEmptyLines = pGroup->mnEmptyLines;
589 while ( nEmptyLines )
591 *pBuf = aLineEndBuf[0]; pBuf++;
592 if ( nLineEndLen == 2 )
594 *pBuf = aLineEndBuf[1]; pBuf++;
596 nEmptyLines--;
600 pGroup = pGroup->mpNext;
603 return pWriteBuf;
606 // -----------------------------------------------------------------------
608 static void ImplReadConfig( ImplConfigData* pData )
610 ULONG nTimeStamp = 0;
611 sal_uInt64 nRead = 0;
612 BOOL bRead = FALSE;
613 BOOL bIsUTF8BOM =FALSE;
614 BYTE* pBuf = ImplSysReadConfig( pData->maFileName, nRead, bRead, bIsUTF8BOM, nTimeStamp );
616 // Aus dem Buffer die Config-Verwaltungsliste aufbauen
617 if ( pBuf )
619 ImplMakeConfigList( pData, pBuf, nRead );
620 delete[] pBuf;
622 pData->mnTimeStamp = nTimeStamp;
623 pData->mbModified = FALSE;
624 if ( bRead )
625 pData->mbRead = TRUE;
626 if ( bIsUTF8BOM )
627 pData->mbIsUTF8BOM = TRUE;
630 // -----------------------------------------------------------------------
632 static void ImplWriteConfig( ImplConfigData* pData )
634 #ifdef DBG_UTIL
635 if ( DbgIsAssert() )
637 if ( pData->mnTimeStamp != ImplSysGetConfigTimeStamp( pData->maFileName ) )
639 DBG_ERROR1( "Config overwrites modified configfile:\n %s", ByteString( pData->maFileName, RTL_TEXTENCODING_UTF8 ).GetBuffer() );
642 #endif
644 // Aus der Config-Liste einen Buffer zusammenbauen
645 ULONG nBufLen;
646 BYTE* pBuf = ImplGetConfigBuffer( pData, nBufLen );
647 if ( pBuf )
649 if ( ImplSysWriteConfig( pData->maFileName, pBuf, nBufLen, pData->mbIsUTF8BOM, pData->mnTimeStamp ) )
650 pData->mbModified = FALSE;
651 delete[] pBuf;
653 else
654 pData->mbModified = FALSE;
657 // -----------------------------------------------------------------------
659 static void ImplDeleteConfigData( ImplConfigData* pData )
661 ImplKeyData* pTempKey;
662 ImplKeyData* pKey;
663 ImplGroupData* pTempGroup;
664 ImplGroupData* pGroup = pData->mpFirstGroup;
665 while ( pGroup )
667 pTempGroup = pGroup->mpNext;
669 // Alle Keys loeschen
670 pKey = pGroup->mpFirstKey;
671 while ( pKey )
673 pTempKey = pKey->mpNext;
674 delete pKey;
675 pKey = pTempKey;
678 // Gruppe loeschen und weiterschalten
679 delete pGroup;
680 pGroup = pTempGroup;
683 pData->mpFirstGroup = NULL;
686 // =======================================================================
688 static ImplConfigData* ImplGetConfigData( const XubString& rFileName )
690 ImplConfigData* pData;
692 pData = new ImplConfigData;
693 pData->maFileName = rFileName;
694 pData->mpFirstGroup = NULL;
695 pData->mnDataUpdateId = 0;
696 pData->meLineEnd = LINEEND_CRLF;
697 pData->mnRefCount = 0;
698 pData->mbRead = FALSE;
699 pData->mbIsUTF8BOM = FALSE;
700 ImplReadConfig( pData );
702 return pData;
705 // -----------------------------------------------------------------------
707 static void ImplFreeConfigData( ImplConfigData* pDelData )
709 ImplDeleteConfigData( pDelData );
710 delete pDelData;
713 // =======================================================================
715 BOOL Config::ImplUpdateConfig() const
717 // Wenn sich TimeStamp unterscheidet, dann Datei neu einlesen
718 if ( mpData->mnTimeStamp != ImplSysGetConfigTimeStamp( maFileName ) )
720 ImplDeleteConfigData( mpData );
721 ImplReadConfig( mpData );
722 mpData->mnDataUpdateId++;
723 return TRUE;
725 else
726 return FALSE;
729 // -----------------------------------------------------------------------
731 ImplGroupData* Config::ImplGetGroup() const
733 if ( !mpActGroup || (mnDataUpdateId != mpData->mnDataUpdateId) )
735 ImplGroupData* pPrevGroup = NULL;
736 ImplGroupData* pGroup = mpData->mpFirstGroup;
737 while ( pGroup )
739 if ( pGroup->maGroupName.EqualsIgnoreCaseAscii( maGroupName ) )
740 break;
742 pPrevGroup = pGroup;
743 pGroup = pGroup->mpNext;
746 // Falls Gruppe noch nicht existiert, dann dazufuegen
747 if ( !pGroup )
749 pGroup = new ImplGroupData;
750 pGroup->mpNext = NULL;
751 pGroup->mpFirstKey = NULL;
752 pGroup->mnEmptyLines = 1;
753 if ( pPrevGroup )
754 pPrevGroup->mpNext = pGroup;
755 else
756 mpData->mpFirstGroup = pGroup;
759 // Gruppenname immer uebernehmen, da er auch in dieser Form
760 // geschrieben werden soll. Ausserdem die Cache-Members der
761 // Config-Klasse updaten
762 pGroup->maGroupName = maGroupName;
763 ((Config*)this)->mnDataUpdateId = mpData->mnDataUpdateId;
764 ((Config*)this)->mpActGroup = pGroup;
767 return mpActGroup;
770 // =======================================================================
772 Config::Config()
774 // Daten initialisieren und einlesen
775 maFileName = ImplMakeConfigName( NULL, NULL );
776 mpData = ImplGetConfigData( maFileName );
777 mpActGroup = NULL;
778 mnDataUpdateId = 0;
779 mnLockCount = 1;
780 mbPersistence = TRUE;
782 #ifdef DBG_UTIL
783 DBG_TRACE( "Config::Config()" );
784 #endif
787 // -----------------------------------------------------------------------
789 Config::Config( const XubString& rFileName )
791 // Daten initialisieren und einlesen
792 maFileName = toUncPath( rFileName );
793 mpData = ImplGetConfigData( maFileName );
794 mpActGroup = NULL;
795 mnDataUpdateId = 0;
796 mnLockCount = 1;
797 mbPersistence = TRUE;
799 #ifdef DBG_UTIL
800 ByteString aTraceStr( "Config::Config( " );
801 aTraceStr += ByteString( maFileName, RTL_TEXTENCODING_UTF8 );
802 aTraceStr += " )";
803 DBG_TRACE( aTraceStr.GetBuffer() );
804 #endif
807 // -----------------------------------------------------------------------
809 Config::~Config()
811 #ifdef DBG_UTIL
812 DBG_TRACE( "Config::~Config()" );
813 #endif
815 Flush();
816 ImplFreeConfigData( mpData );
819 // -----------------------------------------------------------------------
821 String Config::GetDefDirectory()
823 ::rtl::OUString aDefConfig;
824 oslSecurity aSec = osl_getCurrentSecurity();
825 osl_getConfigDir( aSec, &aDefConfig.pData );
826 osl_freeSecurityHandle( aSec );
828 return aDefConfig;
831 // -----------------------------------------------------------------------
833 XubString Config::GetConfigName( const XubString& rPath,
834 const XubString& rBaseName )
836 return ImplMakeConfigName( &rBaseName, &rPath );
839 // -----------------------------------------------------------------------
841 void Config::SetGroup( const ByteString& rGroup )
843 // Wenn neue Gruppe gesetzt wird, muss beim naechsten mal die
844 // Gruppe neu ermittelt werden
845 if ( maGroupName != rGroup )
847 maGroupName = rGroup;
848 mnDataUpdateId = mpData->mnDataUpdateId-1;
852 // -----------------------------------------------------------------------
854 void Config::DeleteGroup( const ByteString& rGroup )
856 // Config-Daten evt. updaten
857 if ( !mnLockCount || !mpData->mbRead )
859 ImplUpdateConfig();
860 mpData->mbRead = TRUE;
863 ImplGroupData* pPrevGroup = NULL;
864 ImplGroupData* pGroup = mpData->mpFirstGroup;
865 while ( pGroup )
867 if ( pGroup->maGroupName.EqualsIgnoreCaseAscii( rGroup ) )
868 break;
870 pPrevGroup = pGroup;
871 pGroup = pGroup->mpNext;
874 if ( pGroup )
876 // Alle Keys loeschen
877 ImplKeyData* pTempKey;
878 ImplKeyData* pKey = pGroup->mpFirstKey;
879 while ( pKey )
881 pTempKey = pKey->mpNext;
882 delete pKey;
883 pKey = pTempKey;
886 // Gruppe weiterschalten und loeschen
887 if ( pPrevGroup )
888 pPrevGroup->mpNext = pGroup->mpNext;
889 else
890 mpData->mpFirstGroup = pGroup->mpNext;
891 delete pGroup;
893 // Config-Datei neu schreiben
894 if ( !mnLockCount && mbPersistence )
895 ImplWriteConfig( mpData );
896 else
898 mpData->mbModified = TRUE;
901 // Gruppen auf ungluetig setzen
902 mnDataUpdateId = mpData->mnDataUpdateId;
903 mpData->mnDataUpdateId++;
907 // -----------------------------------------------------------------------
909 ByteString Config::GetGroupName( USHORT nGroup ) const
911 // Config-Daten evt. updaten
912 if ( !mnLockCount )
913 ImplUpdateConfig();
915 ImplGroupData* pGroup = mpData->mpFirstGroup;
916 USHORT nGroupCount = 0;
917 ByteString aGroupName;
918 while ( pGroup )
920 if ( nGroup == nGroupCount )
922 aGroupName = pGroup->maGroupName;
923 break;
926 nGroupCount++;
927 pGroup = pGroup->mpNext;
930 return aGroupName;
933 // -----------------------------------------------------------------------
935 USHORT Config::GetGroupCount() const
937 // Config-Daten evt. updaten
938 if ( !mnLockCount )
939 ImplUpdateConfig();
941 ImplGroupData* pGroup = mpData->mpFirstGroup;
942 USHORT nGroupCount = 0;
943 while ( pGroup )
945 nGroupCount++;
946 pGroup = pGroup->mpNext;
949 return nGroupCount;
952 // -----------------------------------------------------------------------
954 BOOL Config::HasGroup( const ByteString& rGroup ) const
956 // Config-Daten evt. updaten
957 if ( !mnLockCount )
958 ImplUpdateConfig();
960 ImplGroupData* pGroup = mpData->mpFirstGroup;
961 BOOL bRet = FALSE;
963 while( pGroup )
965 if( pGroup->maGroupName.EqualsIgnoreCaseAscii( rGroup ) )
967 bRet = TRUE;
968 break;
971 pGroup = pGroup->mpNext;
974 return bRet;
977 // -----------------------------------------------------------------------
979 ByteString Config::ReadKey( const ByteString& rKey ) const
981 return ReadKey( rKey, getEmptyByteString() );
984 // -----------------------------------------------------------------------
986 UniString Config::ReadKey( const ByteString& rKey, rtl_TextEncoding eEncoding ) const
988 if ( mpData->mbIsUTF8BOM )
989 eEncoding = RTL_TEXTENCODING_UTF8;
990 return UniString( ReadKey( rKey ), eEncoding );
993 // -----------------------------------------------------------------------
995 ByteString Config::ReadKey( const ByteString& rKey, const ByteString& rDefault ) const
997 #ifdef DBG_UTIL
998 ByteString aTraceStr( "Config::ReadKey( " );
999 aTraceStr += rKey;
1000 aTraceStr += " ) from ";
1001 aTraceStr += GetGroup();
1002 aTraceStr += " in ";
1003 aTraceStr += ByteString( maFileName, RTL_TEXTENCODING_UTF8 );
1004 DBG_TRACE( aTraceStr.GetBuffer() );
1005 #endif
1007 // Config-Daten evt. updaten
1008 if ( !mnLockCount )
1009 ImplUpdateConfig();
1011 // Key suchen und Value zurueckgeben
1012 ImplGroupData* pGroup = ImplGetGroup();
1013 if ( pGroup )
1015 ImplKeyData* pKey = pGroup->mpFirstKey;
1016 while ( pKey )
1018 if ( !pKey->mbIsComment && pKey->maKey.EqualsIgnoreCaseAscii( rKey ) )
1019 return pKey->maValue;
1021 pKey = pKey->mpNext;
1025 return rDefault;
1028 // -----------------------------------------------------------------------
1030 void Config::WriteKey( const ByteString& rKey, const ByteString& rStr )
1032 #ifdef DBG_UTIL
1033 ByteString aTraceStr( "Config::WriteKey( " );
1034 aTraceStr += rKey;
1035 aTraceStr += ", ";
1036 aTraceStr += rStr;
1037 aTraceStr += " ) to ";
1038 aTraceStr += GetGroup();
1039 aTraceStr += " in ";
1040 aTraceStr += ByteString( maFileName, RTL_TEXTENCODING_UTF8 );
1041 DBG_TRACE( aTraceStr.GetBuffer() );
1042 DBG_ASSERTWARNING( rStr != ReadKey( rKey ), "Config::WriteKey() with the same Value" );
1043 #endif
1045 // Config-Daten evt. updaten
1046 if ( !mnLockCount || !mpData->mbRead )
1048 ImplUpdateConfig();
1049 mpData->mbRead = TRUE;
1052 // Key suchen und Value setzen
1053 ImplGroupData* pGroup = ImplGetGroup();
1054 if ( pGroup )
1056 ImplKeyData* pPrevKey = NULL;
1057 ImplKeyData* pKey = pGroup->mpFirstKey;
1058 while ( pKey )
1060 if ( !pKey->mbIsComment && pKey->maKey.EqualsIgnoreCaseAscii( rKey ) )
1061 break;
1063 pPrevKey = pKey;
1064 pKey = pKey->mpNext;
1067 BOOL bNewValue;
1068 if ( !pKey )
1070 pKey = new ImplKeyData;
1071 pKey->mpNext = NULL;
1072 pKey->maKey = rKey;
1073 pKey->mbIsComment = FALSE;
1074 if ( pPrevKey )
1075 pPrevKey->mpNext = pKey;
1076 else
1077 pGroup->mpFirstKey = pKey;
1078 bNewValue = TRUE;
1080 else
1081 bNewValue = pKey->maValue != rStr;
1083 if ( bNewValue )
1085 pKey->maValue = rStr;
1087 if ( !mnLockCount && mbPersistence )
1088 ImplWriteConfig( mpData );
1089 else
1091 mpData->mbModified = TRUE;
1097 // -----------------------------------------------------------------------
1099 void Config::WriteKey( const ByteString& rKey, const UniString& rValue, rtl_TextEncoding eEncoding )
1101 if ( mpData->mbIsUTF8BOM )
1102 eEncoding = RTL_TEXTENCODING_UTF8;
1103 WriteKey( rKey, ByteString( rValue, eEncoding ) );
1106 // -----------------------------------------------------------------------
1108 void Config::DeleteKey( const ByteString& rKey )
1110 // Config-Daten evt. updaten
1111 if ( !mnLockCount || !mpData->mbRead )
1113 ImplUpdateConfig();
1114 mpData->mbRead = TRUE;
1117 // Key suchen und Value setzen
1118 ImplGroupData* pGroup = ImplGetGroup();
1119 if ( pGroup )
1121 ImplKeyData* pPrevKey = NULL;
1122 ImplKeyData* pKey = pGroup->mpFirstKey;
1123 while ( pKey )
1125 if ( !pKey->mbIsComment && pKey->maKey.EqualsIgnoreCaseAscii( rKey ) )
1126 break;
1128 pPrevKey = pKey;
1129 pKey = pKey->mpNext;
1132 if ( pKey )
1134 // Gruppe weiterschalten und loeschen
1135 if ( pPrevKey )
1136 pPrevKey->mpNext = pKey->mpNext;
1137 else
1138 pGroup->mpFirstKey = pKey->mpNext;
1139 delete pKey;
1141 // Config-Datei neu schreiben
1142 if ( !mnLockCount && mbPersistence )
1143 ImplWriteConfig( mpData );
1144 else
1146 mpData->mbModified = TRUE;
1152 // -----------------------------------------------------------------------
1154 USHORT Config::GetKeyCount() const
1156 #ifdef DBG_UTIL
1157 ByteString aTraceStr( "Config::GetKeyCount()" );
1158 aTraceStr += " from ";
1159 aTraceStr += GetGroup();
1160 aTraceStr += " in ";
1161 aTraceStr += ByteString( maFileName, RTL_TEXTENCODING_UTF8 );
1162 DBG_TRACE( aTraceStr.GetBuffer() );
1163 #endif
1165 // Config-Daten evt. updaten
1166 if ( !mnLockCount )
1167 ImplUpdateConfig();
1169 // Key suchen und Value zurueckgeben
1170 USHORT nCount = 0;
1171 ImplGroupData* pGroup = ImplGetGroup();
1172 if ( pGroup )
1174 ImplKeyData* pKey = pGroup->mpFirstKey;
1175 while ( pKey )
1177 if ( !pKey->mbIsComment )
1178 nCount++;
1180 pKey = pKey->mpNext;
1184 return nCount;
1187 // -----------------------------------------------------------------------
1189 ByteString Config::GetKeyName( USHORT nKey ) const
1191 #ifdef DBG_UTIL
1192 ByteString aTraceStr( "Config::GetKeyName( " );
1193 aTraceStr += ByteString::CreateFromInt32(nKey);
1194 aTraceStr += " ) from ";
1195 aTraceStr += GetGroup();
1196 aTraceStr += " in ";
1197 aTraceStr += ByteString( maFileName, RTL_TEXTENCODING_UTF8 );
1198 DBG_TRACE( aTraceStr.GetBuffer() );
1199 #endif
1201 // Key suchen und Name zurueckgeben
1202 ImplGroupData* pGroup = ImplGetGroup();
1203 if ( pGroup )
1205 ImplKeyData* pKey = pGroup->mpFirstKey;
1206 while ( pKey )
1208 if ( !pKey->mbIsComment )
1210 if ( !nKey )
1211 return pKey->maKey;
1212 nKey--;
1215 pKey = pKey->mpNext;
1219 return getEmptyByteString();
1222 // -----------------------------------------------------------------------
1224 ByteString Config::ReadKey( USHORT nKey ) const
1226 #ifdef DBG_UTIL
1227 ByteString aTraceStr( "Config::ReadKey( " );
1228 aTraceStr += ByteString::CreateFromInt32( nKey );
1229 aTraceStr += " ) from ";
1230 aTraceStr += GetGroup();
1231 aTraceStr += " in ";
1232 aTraceStr += ByteString( maFileName, RTL_TEXTENCODING_UTF8 );
1233 DBG_TRACE( aTraceStr.GetBuffer() );
1234 #endif
1236 // Key suchen und Value zurueckgeben
1237 ImplGroupData* pGroup = ImplGetGroup();
1238 if ( pGroup )
1240 ImplKeyData* pKey = pGroup->mpFirstKey;
1241 while ( pKey )
1243 if ( !pKey->mbIsComment )
1245 if ( !nKey )
1246 return pKey->maValue;
1247 nKey--;
1250 pKey = pKey->mpNext;
1254 return getEmptyByteString();
1257 // -----------------------------------------------------------------------
1259 void Config::EnterLock()
1261 // Config-Daten evt. updaten
1262 if ( !mnLockCount )
1263 ImplUpdateConfig();
1265 mnLockCount++;
1268 // -----------------------------------------------------------------------
1270 void Config::LeaveLock()
1272 DBG_ASSERT( mnLockCount, "Config::LeaveLook() without Config::EnterLook()" );
1273 mnLockCount--;
1275 if ( (mnLockCount == 0) && mpData->mbModified && mbPersistence )
1276 ImplWriteConfig( mpData );
1279 // -----------------------------------------------------------------------
1281 BOOL Config::Update()
1283 return ImplUpdateConfig();
1286 // -----------------------------------------------------------------------
1288 void Config::Flush()
1290 if ( mpData->mbModified && mbPersistence )
1291 ImplWriteConfig( mpData );
1294 // -----------------------------------------------------------------------
1296 void Config::SetLineEnd( LineEnd eLineEnd )
1298 mpData->meLineEnd = eLineEnd;
1301 // -----------------------------------------------------------------------
1303 LineEnd Config::GetLineEnd() const
1305 return mpData->meLineEnd;