summaryrefslogtreecommitdiff
path: root/tools/source/generic/config.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'tools/source/generic/config.cxx')
-rw-r--r--tools/source/generic/config.cxx1304
1 files changed, 1304 insertions, 0 deletions
diff --git a/tools/source/generic/config.cxx b/tools/source/generic/config.cxx
new file mode 100644
index 000000000000..1a94c2b11198
--- /dev/null
+++ b/tools/source/generic/config.cxx
@@ -0,0 +1,1304 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_tools.hxx"
+
+#define _CONFIG_CXX
+
+#include <cstddef>
+#include <cstdlib>
+#include <limits>
+#include <new>
+#include <string.h>
+
+#ifdef WNT
+#include "stdlib.h"
+#endif
+#include <osl/file.hxx>
+#include <tools/stream.hxx>
+#include <tools/debug.hxx>
+#include <tools/config.hxx>
+#include <osl/security.h>
+
+#define MAXBUFLEN 1024 // Fuer Buffer bei VOS-Funktionen
+
+// -----------------
+// - ImplConfigData -
+// -----------------
+
+struct ImplKeyData
+{
+ ImplKeyData* mpNext;
+ ByteString maKey;
+ ByteString maValue;
+ BOOL mbIsComment;
+};
+
+struct ImplGroupData
+{
+ ImplGroupData* mpNext;
+ ImplKeyData* mpFirstKey;
+ ByteString maGroupName;
+ USHORT mnEmptyLines;
+};
+
+struct ImplConfigData
+{
+ ImplGroupData* mpFirstGroup;
+ XubString maFileName;
+ ULONG mnDataUpdateId;
+ ULONG mnTimeStamp;
+ LineEnd meLineEnd;
+ USHORT mnRefCount;
+ BOOL mbModified;
+ BOOL mbRead;
+ BOOL mbIsUTF8BOM;
+};
+
+// =======================================================================
+
+static ByteString& getEmptyByteString()
+{
+ static ByteString aEmpty;
+ return aEmpty;
+}
+
+// =======================================================================
+
+static String toUncPath( const String& rPath )
+{
+ ::rtl::OUString aFileURL;
+
+ // check if rFileName is already a URL; if not make it so
+ if( rPath.CompareToAscii( "file://", 7 ) == COMPARE_EQUAL )
+ aFileURL = rPath;
+ else if( ::osl::FileBase::getFileURLFromSystemPath( rPath, aFileURL ) != ::osl::FileBase::E_None )
+ aFileURL = rPath;
+
+ return aFileURL;
+}
+
+static ULONG ImplSysGetConfigTimeStamp( const XubString& rFileName )
+{
+ ULONG nTimeStamp = 0;
+ ::osl::DirectoryItem aItem;
+ ::osl::FileStatus aStatus( osl_FileStatus_Mask_ModifyTime );
+
+ int nError = 0;
+ if( ( nError = ::osl::DirectoryItem::get( rFileName, aItem ) ) == ::osl::FileBase::E_None &&
+ aItem.getFileStatus( aStatus ) == ::osl::FileBase::E_None )
+ {
+ nTimeStamp = aStatus.getModifyTime().Seconds;
+ }
+
+ return nTimeStamp;
+}
+
+// -----------------------------------------------------------------------
+
+static BYTE* ImplSysReadConfig( const XubString& rFileName,
+ sal_uInt64& rRead, BOOL& rbRead, BOOL& rbIsUTF8BOM, ULONG& rTimeStamp )
+{
+ BYTE* pBuf = NULL;
+ ::osl::File aFile( rFileName );
+
+ if( aFile.open( osl_File_OpenFlag_Read ) == ::osl::FileBase::E_None )
+ {
+ sal_uInt64 nPos = 0, nRead = 0;
+ if( aFile.getSize( nPos ) == ::osl::FileBase::E_None )
+ {
+ if (nPos > std::numeric_limits< std::size_t >::max()) {
+ aFile.close();
+ return 0;
+ }
+ pBuf = new BYTE[static_cast< std::size_t >(nPos)];
+ if( aFile.read( pBuf, nPos, nRead ) == ::osl::FileBase::E_None && nRead == nPos )
+ {
+ //skip the byte-order-mark 0xEF 0xBB 0xBF, if it was UTF8 files
+ unsigned char BOM[3] = {0xEF, 0xBB, 0xBF};
+ if (nRead > 2 && memcmp(pBuf, BOM, 3) == 0)
+ {
+ nRead -= 3;
+ rtl_moveMemory(pBuf, pBuf + 3, sal::static_int_cast<sal_Size>(nRead * sizeof(BYTE)) );
+ rbIsUTF8BOM = TRUE;
+ }
+
+ rTimeStamp = ImplSysGetConfigTimeStamp( rFileName );
+ rbRead = TRUE;
+ rRead = nRead;
+ }
+ else
+ {
+ delete[] pBuf;
+ pBuf = NULL;
+ }
+ }
+ aFile.close();
+ }
+
+ return pBuf;
+}
+
+// -----------------------------------------------------------------------
+
+static BOOL ImplSysWriteConfig( const XubString& rFileName,
+ const BYTE* pBuf, ULONG nBufLen, BOOL rbIsUTF8BOM, ULONG& rTimeStamp )
+{
+ BOOL bSuccess = FALSE;
+ BOOL bUTF8BOMSuccess = FALSE;
+
+ ::osl::File aFile( rFileName );
+ ::osl::FileBase::RC eError = aFile.open( osl_File_OpenFlag_Write | osl_File_OpenFlag_Create );
+ if( eError != ::osl::FileBase::E_None )
+ eError = aFile.open( osl_File_OpenFlag_Write );
+ if( eError == ::osl::FileBase::E_None )
+ {
+ // truncate
+ aFile.setSize( 0 );
+ sal_uInt64 nWritten;
+
+ //write the the byte-order-mark 0xEF 0xBB 0xBF first , if it was UTF8 files
+ if ( rbIsUTF8BOM )
+ {
+ unsigned char BOM[3] = {0xEF, 0xBB, 0xBF};
+ sal_uInt64 nUTF8BOMWritten;
+ if( aFile.write( BOM, 3, nUTF8BOMWritten ) == ::osl::FileBase::E_None && 3 == nUTF8BOMWritten )
+ {
+ bUTF8BOMSuccess = TRUE;
+ }
+ }
+
+ if( aFile.write( pBuf, nBufLen, nWritten ) == ::osl::FileBase::E_None && nWritten == nBufLen )
+ {
+ bSuccess = TRUE;
+ }
+ if ( rbIsUTF8BOM ? bSuccess && bUTF8BOMSuccess : bSuccess )
+ {
+ rTimeStamp = ImplSysGetConfigTimeStamp( rFileName );
+ }
+ }
+
+ return rbIsUTF8BOM ? bSuccess && bUTF8BOMSuccess : bSuccess;
+}
+
+// -----------------------------------------------------------------------
+
+static String ImplMakeConfigName( const XubString* pFileName,
+ const XubString* pPathName )
+{
+ ::rtl::OUString aFileName;
+ ::rtl::OUString aPathName;
+ if ( pFileName )
+ {
+#ifdef UNX
+ aFileName = ::rtl::OUString::createFromAscii( "." );
+ aFileName += *pFileName;
+ aFileName += ::rtl::OUString::createFromAscii( "rc" );
+#else
+ aFileName = *pFileName;
+ aFileName += ::rtl::OUString::createFromAscii( ".ini" );
+#endif
+ }
+ else
+ {
+#ifdef UNX
+ aFileName = ::rtl::OUString::createFromAscii( ".sversionrc" );
+#else
+ aFileName = ::rtl::OUString::createFromAscii( "sversion.ini" );
+#endif
+ }
+
+ // #88208# in case pPathName is set but empty and pFileName is set
+ // and not empty just return the filename; on the default case
+ // prepend default path as usual
+ if ( pPathName && pPathName->Len() )
+ aPathName = toUncPath( *pPathName );
+ else if( pPathName && pFileName && pFileName->Len() )
+ return aFileName;
+ else
+ {
+ oslSecurity aSec = osl_getCurrentSecurity();
+ osl_getConfigDir( aSec, &aPathName.pData );
+ osl_freeSecurityHandle( aSec );
+ }
+
+ ::rtl::OUString aName( aPathName );
+ aName += ::rtl::OUString::createFromAscii( "/" );
+ aName += aFileName;
+
+ return aName;
+}
+
+// -----------------------------------------------------------------------
+
+namespace {
+
+ByteString makeByteString(BYTE const * p, sal_uInt64 n) {
+ if (n > STRING_MAXLEN) {
+ #ifdef WNT
+ abort();
+ #else
+ ::std::abort(); //TODO: handle this gracefully
+ #endif
+ }
+ return ByteString(
+ reinterpret_cast< char const * >(p),
+ sal::static_int_cast< xub_StrLen >(n));
+}
+
+}
+
+static void ImplMakeConfigList( ImplConfigData* pData,
+ const BYTE* pBuf, sal_uInt64 nLen )
+{
+ // kein Buffer, keine Daten
+ if ( !nLen )
+ return;
+
+ // Buffer parsen und Liste zusammenbauen
+ sal_uInt64 nStart;
+ sal_uInt64 nLineLen;
+ xub_StrLen nNameLen;
+ xub_StrLen nKeyLen;
+ sal_uInt64 i;
+ const BYTE* pLine;
+ ImplKeyData* pPrevKey = NULL;
+ ImplKeyData* pKey;
+ ImplGroupData* pPrevGroup = NULL;
+ ImplGroupData* pGroup = NULL;
+ i = 0;
+ while ( i < nLen )
+ {
+ // Ctrl+Z
+ if ( pBuf[i] == 0x1A )
+ break;
+
+ // Spaces und Tabs entfernen
+ while ( (pBuf[i] == ' ') || (pBuf[i] == '\t') )
+ i++;
+
+ // Zeilenanfang merken
+ nStart = i;
+ pLine = pBuf+i;
+
+ // Zeilenende suchen
+ while ( (i < nLen) && pBuf[i] && (pBuf[i] != '\r') && (pBuf[i] != '\n') &&
+ (pBuf[i] != 0x1A) )
+ i++;
+
+ nLineLen = i-nStart;
+
+ // Wenn Zeilenende (CR/LF), dann noch einen weiterschalten
+ if ( (i+1 < nLen) &&
+ (pBuf[i] != pBuf[i+1]) &&
+ ((pBuf[i+1] == '\r') || (pBuf[i+1] == '\n')) )
+ i++;
+ i++;
+
+ // Zeile auswerten
+ if ( *pLine == '[' )
+ {
+ pGroup = new ImplGroupData;
+ pGroup->mpNext = NULL;
+ pGroup->mpFirstKey = NULL;
+ pGroup->mnEmptyLines = 0;
+ if ( pPrevGroup )
+ pPrevGroup->mpNext = pGroup;
+ else
+ pData->mpFirstGroup = pGroup;
+ pPrevGroup = pGroup;
+ pPrevKey = NULL;
+ pKey = NULL;
+
+ // Gruppennamen rausfiltern
+ pLine++;
+ nLineLen--;
+ // Spaces und Tabs entfernen
+ while ( (*pLine == ' ') || (*pLine == '\t') )
+ {
+ nLineLen--;
+ pLine++;
+ }
+ nNameLen = 0;
+ while ( (nNameLen < nLineLen) && (pLine[nNameLen] != ']') )
+ nNameLen++;
+ if ( nNameLen )
+ {
+ while ( (pLine[nNameLen-1] == ' ') || (pLine[nNameLen-1] == '\t') )
+ nNameLen--;
+ }
+ pGroup->maGroupName = ByteString( (const sal_Char*)pLine, nNameLen );
+ }
+ else
+ {
+ if ( nLineLen )
+ {
+ // Wenn noch keine Gruppe existiert, dann alle Keys in die
+ // Default-Gruppe
+ if ( !pGroup )
+ {
+ pGroup = new ImplGroupData;
+ pGroup->mpNext = NULL;
+ pGroup->mpFirstKey = NULL;
+ pGroup->mnEmptyLines = 0;
+ if ( pPrevGroup )
+ pPrevGroup->mpNext = pGroup;
+ else
+ pData->mpFirstGroup = pGroup;
+ pPrevGroup = pGroup;
+ pPrevKey = NULL;
+ }
+
+ // Falls Leerzeile vorhanden, dann anhaengen
+ if ( pPrevKey )
+ {
+ while ( pGroup->mnEmptyLines )
+ {
+ pKey = new ImplKeyData;
+ pKey->mbIsComment = TRUE;
+ pPrevKey->mpNext = pKey;
+ pPrevKey = pKey;
+ pGroup->mnEmptyLines--;
+ }
+ }
+
+ // Neuen Key erzeugen
+ pKey = new ImplKeyData;
+ pKey->mpNext = NULL;
+ if ( pPrevKey )
+ pPrevKey->mpNext = pKey;
+ else
+ pGroup->mpFirstKey = pKey;
+ pPrevKey = pKey;
+ if ( pLine[0] == ';' )
+ {
+ pKey->maValue = makeByteString(pLine, nLineLen);
+ pKey->mbIsComment = TRUE;
+ }
+ else
+ {
+ pKey->mbIsComment = FALSE;
+ nNameLen = 0;
+ while ( (nNameLen < nLineLen) && (pLine[nNameLen] != '=') )
+ nNameLen++;
+ nKeyLen = nNameLen;
+ // Spaces und Tabs entfernen
+ if ( nNameLen )
+ {
+ while ( (pLine[nNameLen-1] == ' ') || (pLine[nNameLen-1] == '\t') )
+ nNameLen--;
+ }
+ pKey->maKey = ByteString( (const sal_Char*)pLine, nNameLen );
+ nKeyLen++;
+ if ( nKeyLen < nLineLen )
+ {
+ pLine += nKeyLen;
+ nLineLen -= nKeyLen;
+ // Spaces und Tabs entfernen
+ while ( (*pLine == ' ') || (*pLine == '\t') )
+ {
+ nLineLen--;
+ pLine++;
+ }
+ if ( nLineLen )
+ {
+ while ( (pLine[nLineLen-1] == ' ') || (pLine[nLineLen-1] == '\t') )
+ nLineLen--;
+ pKey->maValue = makeByteString(pLine, nLineLen);
+ }
+ }
+ }
+ }
+ else
+ {
+ // Leerzeilen werden nur gezaehlt und beim Erzeugen des
+ // naechsten Keys angehaengt, da wir Leerzeilen am Ende
+ // einer Gruppe auch nach hinzufuegen von neuen Keys nur
+ // am Ende der Gruppe wieder speichern wollen
+ if ( pGroup )
+ pGroup->mnEmptyLines++;
+ }
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+static BYTE* ImplGetConfigBuffer( const ImplConfigData* pData, ULONG& rLen )
+{
+ BYTE* pWriteBuf;
+ BYTE* pBuf;
+ BYTE aLineEndBuf[2] = {0, 0};
+ ImplKeyData* pKey;
+ ImplGroupData* pGroup;
+ unsigned int nBufLen;
+ USHORT nValueLen;
+ USHORT nKeyLen;
+ USHORT nLineEndLen;
+
+ if ( pData->meLineEnd == LINEEND_CR )
+ {
+ aLineEndBuf[0] = _CR;
+ nLineEndLen = 1;
+ }
+ else if ( pData->meLineEnd == LINEEND_LF )
+ {
+ aLineEndBuf[0] = _LF;
+ nLineEndLen = 1;
+ }
+ else
+ {
+ aLineEndBuf[0] = _CR;
+ aLineEndBuf[1] = _LF;
+ nLineEndLen = 2;
+ }
+
+ // Buffergroesse ermitteln
+ nBufLen = 0;
+ pGroup = pData->mpFirstGroup;
+ while ( pGroup )
+ {
+ // Leere Gruppen werden nicht geschrieben
+ if ( pGroup->mpFirstKey )
+ {
+ nBufLen += pGroup->maGroupName.Len() + nLineEndLen + 2;
+ pKey = pGroup->mpFirstKey;
+ while ( pKey )
+ {
+ nValueLen = pKey->maValue.Len();
+ if ( pKey->mbIsComment )
+ nBufLen += nValueLen + nLineEndLen;
+ else
+ nBufLen += pKey->maKey.Len() + nValueLen + nLineEndLen + 1;
+
+ pKey = pKey->mpNext;
+ }
+
+ // Leerzeile nach jeder Gruppe auch wieder speichern
+ if ( !pGroup->mnEmptyLines )
+ pGroup->mnEmptyLines = 1;
+ nBufLen += nLineEndLen * pGroup->mnEmptyLines;
+ }
+
+ pGroup = pGroup->mpNext;
+ }
+
+ // Laenge dem Aufrufer mitteilen
+ rLen = nBufLen;
+ if ( !nBufLen )
+ {
+ pWriteBuf = new BYTE[nLineEndLen];
+ if ( pWriteBuf )
+ {
+ pWriteBuf[0] = aLineEndBuf[0];
+ if ( nLineEndLen == 2 )
+ pWriteBuf[1] = aLineEndBuf[1];
+ return pWriteBuf;
+ }
+ else
+ return 0;
+ }
+
+ // Schreibbuffer anlegen (wird vom Aufrufer zerstoert)
+ pWriteBuf = new BYTE[nBufLen];
+ if ( !pWriteBuf )
+ return 0;
+
+ // Buffer fuellen
+ pBuf = pWriteBuf;
+ pGroup = pData->mpFirstGroup;
+ while ( pGroup )
+ {
+ // Leere Gruppen werden nicht geschrieben
+ if ( pGroup->mpFirstKey )
+ {
+ *pBuf = '['; pBuf++;
+ memcpy( pBuf, pGroup->maGroupName.GetBuffer(), pGroup->maGroupName.Len() );
+ pBuf += pGroup->maGroupName.Len();
+ *pBuf = ']'; pBuf++;
+ *pBuf = aLineEndBuf[0]; pBuf++;
+ if ( nLineEndLen == 2 )
+ {
+ *pBuf = aLineEndBuf[1]; pBuf++;
+ }
+ pKey = pGroup->mpFirstKey;
+ while ( pKey )
+ {
+ nValueLen = pKey->maValue.Len();
+ if ( pKey->mbIsComment )
+ {
+ if ( nValueLen )
+ {
+ memcpy( pBuf, pKey->maValue.GetBuffer(), nValueLen );
+ pBuf += nValueLen;
+ }
+ *pBuf = aLineEndBuf[0]; pBuf++;
+ if ( nLineEndLen == 2 )
+ {
+ *pBuf = aLineEndBuf[1]; pBuf++;
+ }
+ }
+ else
+ {
+ nKeyLen = pKey->maKey.Len();
+ memcpy( pBuf, pKey->maKey.GetBuffer(), nKeyLen );
+ pBuf += nKeyLen;
+ *pBuf = '='; pBuf++;
+ memcpy( pBuf, pKey->maValue.GetBuffer(), nValueLen );
+ pBuf += nValueLen;
+ *pBuf = aLineEndBuf[0]; pBuf++;
+ if ( nLineEndLen == 2 )
+ {
+ *pBuf = aLineEndBuf[1]; pBuf++;
+ }
+ }
+
+ pKey = pKey->mpNext;
+ }
+
+ // Leerzeile nach jeder Gruppe auch wieder speichern
+ USHORT nEmptyLines = pGroup->mnEmptyLines;
+ while ( nEmptyLines )
+ {
+ *pBuf = aLineEndBuf[0]; pBuf++;
+ if ( nLineEndLen == 2 )
+ {
+ *pBuf = aLineEndBuf[1]; pBuf++;
+ }
+ nEmptyLines--;
+ }
+ }
+
+ pGroup = pGroup->mpNext;
+ }
+
+ return pWriteBuf;
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplReadConfig( ImplConfigData* pData )
+{
+ ULONG nTimeStamp = 0;
+ sal_uInt64 nRead = 0;
+ BOOL bRead = FALSE;
+ BOOL bIsUTF8BOM =FALSE;
+ BYTE* pBuf = ImplSysReadConfig( pData->maFileName, nRead, bRead, bIsUTF8BOM, nTimeStamp );
+
+ // Aus dem Buffer die Config-Verwaltungsliste aufbauen
+ if ( pBuf )
+ {
+ ImplMakeConfigList( pData, pBuf, nRead );
+ delete[] pBuf;
+ }
+ pData->mnTimeStamp = nTimeStamp;
+ pData->mbModified = FALSE;
+ if ( bRead )
+ pData->mbRead = TRUE;
+ if ( bIsUTF8BOM )
+ pData->mbIsUTF8BOM = TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplWriteConfig( ImplConfigData* pData )
+{
+#ifdef DBG_UTIL
+ if ( DbgIsAssert() )
+ {
+ if ( pData->mnTimeStamp != ImplSysGetConfigTimeStamp( pData->maFileName ) )
+ {
+ DBG_ERROR1( "Config overwrites modified configfile:\n %s", ByteString( pData->maFileName, RTL_TEXTENCODING_UTF8 ).GetBuffer() );
+ }
+ }
+#endif
+
+ // Aus der Config-Liste einen Buffer zusammenbauen
+ ULONG nBufLen;
+ BYTE* pBuf = ImplGetConfigBuffer( pData, nBufLen );
+ if ( pBuf )
+ {
+ if ( ImplSysWriteConfig( pData->maFileName, pBuf, nBufLen, pData->mbIsUTF8BOM, pData->mnTimeStamp ) )
+ pData->mbModified = FALSE;
+ delete[] pBuf;
+ }
+ else
+ pData->mbModified = FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplDeleteConfigData( ImplConfigData* pData )
+{
+ ImplKeyData* pTempKey;
+ ImplKeyData* pKey;
+ ImplGroupData* pTempGroup;
+ ImplGroupData* pGroup = pData->mpFirstGroup;
+ while ( pGroup )
+ {
+ pTempGroup = pGroup->mpNext;
+
+ // Alle Keys loeschen
+ pKey = pGroup->mpFirstKey;
+ while ( pKey )
+ {
+ pTempKey = pKey->mpNext;
+ delete pKey;
+ pKey = pTempKey;
+ }
+
+ // Gruppe loeschen und weiterschalten
+ delete pGroup;
+ pGroup = pTempGroup;
+ }
+
+ pData->mpFirstGroup = NULL;
+}
+
+// =======================================================================
+
+static ImplConfigData* ImplGetConfigData( const XubString& rFileName )
+{
+ ImplConfigData* pData;
+
+ pData = new ImplConfigData;
+ pData->maFileName = rFileName;
+ pData->mpFirstGroup = NULL;
+ pData->mnDataUpdateId = 0;
+ pData->meLineEnd = LINEEND_CRLF;
+ pData->mnRefCount = 0;
+ pData->mbRead = FALSE;
+ pData->mbIsUTF8BOM = FALSE;
+ ImplReadConfig( pData );
+
+ return pData;
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplFreeConfigData( ImplConfigData* pDelData )
+{
+ ImplDeleteConfigData( pDelData );
+ delete pDelData;
+}
+
+// =======================================================================
+
+BOOL Config::ImplUpdateConfig() const
+{
+ // Wenn sich TimeStamp unterscheidet, dann Datei neu einlesen
+ if ( mpData->mnTimeStamp != ImplSysGetConfigTimeStamp( maFileName ) )
+ {
+ ImplDeleteConfigData( mpData );
+ ImplReadConfig( mpData );
+ mpData->mnDataUpdateId++;
+ return TRUE;
+ }
+ else
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+ImplGroupData* Config::ImplGetGroup() const
+{
+ if ( !mpActGroup || (mnDataUpdateId != mpData->mnDataUpdateId) )
+ {
+ ImplGroupData* pPrevGroup = NULL;
+ ImplGroupData* pGroup = mpData->mpFirstGroup;
+ while ( pGroup )
+ {
+ if ( pGroup->maGroupName.EqualsIgnoreCaseAscii( maGroupName ) )
+ break;
+
+ pPrevGroup = pGroup;
+ pGroup = pGroup->mpNext;
+ }
+
+ // Falls Gruppe noch nicht existiert, dann dazufuegen
+ if ( !pGroup )
+ {
+ pGroup = new ImplGroupData;
+ pGroup->mpNext = NULL;
+ pGroup->mpFirstKey = NULL;
+ pGroup->mnEmptyLines = 1;
+ if ( pPrevGroup )
+ pPrevGroup->mpNext = pGroup;
+ else
+ mpData->mpFirstGroup = pGroup;
+ }
+
+ // Gruppenname immer uebernehmen, da er auch in dieser Form
+ // geschrieben werden soll. Ausserdem die Cache-Members der
+ // Config-Klasse updaten
+ pGroup->maGroupName = maGroupName;
+ ((Config*)this)->mnDataUpdateId = mpData->mnDataUpdateId;
+ ((Config*)this)->mpActGroup = pGroup;
+ }
+
+ return mpActGroup;
+}
+
+// =======================================================================
+
+Config::Config()
+{
+ // Daten initialisieren und einlesen
+ maFileName = ImplMakeConfigName( NULL, NULL );
+ mpData = ImplGetConfigData( maFileName );
+ mpActGroup = NULL;
+ mnDataUpdateId = 0;
+ mnLockCount = 1;
+ mbPersistence = TRUE;
+
+#ifdef DBG_UTIL
+ DBG_TRACE( "Config::Config()" );
+#endif
+}
+
+// -----------------------------------------------------------------------
+
+Config::Config( const XubString& rFileName )
+{
+ // Daten initialisieren und einlesen
+ maFileName = toUncPath( rFileName );
+ mpData = ImplGetConfigData( maFileName );
+ mpActGroup = NULL;
+ mnDataUpdateId = 0;
+ mnLockCount = 1;
+ mbPersistence = TRUE;
+
+#ifdef DBG_UTIL
+ ByteString aTraceStr( "Config::Config( " );
+ aTraceStr += ByteString( maFileName, RTL_TEXTENCODING_UTF8 );
+ aTraceStr += " )";
+ DBG_TRACE( aTraceStr.GetBuffer() );
+#endif
+}
+
+// -----------------------------------------------------------------------
+
+Config::~Config()
+{
+#ifdef DBG_UTIL
+ DBG_TRACE( "Config::~Config()" );
+#endif
+
+ Flush();
+ ImplFreeConfigData( mpData );
+}
+
+// -----------------------------------------------------------------------
+
+String Config::GetDefDirectory()
+{
+ ::rtl::OUString aDefConfig;
+ oslSecurity aSec = osl_getCurrentSecurity();
+ osl_getConfigDir( aSec, &aDefConfig.pData );
+ osl_freeSecurityHandle( aSec );
+
+ return aDefConfig;
+}
+
+// -----------------------------------------------------------------------
+
+XubString Config::GetConfigName( const XubString& rPath,
+ const XubString& rBaseName )
+{
+ return ImplMakeConfigName( &rBaseName, &rPath );
+}
+
+// -----------------------------------------------------------------------
+
+void Config::SetGroup( const ByteString& rGroup )
+{
+ // Wenn neue Gruppe gesetzt wird, muss beim naechsten mal die
+ // Gruppe neu ermittelt werden
+ if ( maGroupName != rGroup )
+ {
+ maGroupName = rGroup;
+ mnDataUpdateId = mpData->mnDataUpdateId-1;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Config::DeleteGroup( const ByteString& rGroup )
+{
+ // Config-Daten evt. updaten
+ if ( !mnLockCount || !mpData->mbRead )
+ {
+ ImplUpdateConfig();
+ mpData->mbRead = TRUE;
+ }
+
+ ImplGroupData* pPrevGroup = NULL;
+ ImplGroupData* pGroup = mpData->mpFirstGroup;
+ while ( pGroup )
+ {
+ if ( pGroup->maGroupName.EqualsIgnoreCaseAscii( rGroup ) )
+ break;
+
+ pPrevGroup = pGroup;
+ pGroup = pGroup->mpNext;
+ }
+
+ if ( pGroup )
+ {
+ // Alle Keys loeschen
+ ImplKeyData* pTempKey;
+ ImplKeyData* pKey = pGroup->mpFirstKey;
+ while ( pKey )
+ {
+ pTempKey = pKey->mpNext;
+ delete pKey;
+ pKey = pTempKey;
+ }
+
+ // Gruppe weiterschalten und loeschen
+ if ( pPrevGroup )
+ pPrevGroup->mpNext = pGroup->mpNext;
+ else
+ mpData->mpFirstGroup = pGroup->mpNext;
+ delete pGroup;
+
+ // Config-Datei neu schreiben
+ if ( !mnLockCount && mbPersistence )
+ ImplWriteConfig( mpData );
+ else
+ {
+ mpData->mbModified = TRUE;
+ }
+
+ // Gruppen auf ungluetig setzen
+ mnDataUpdateId = mpData->mnDataUpdateId;
+ mpData->mnDataUpdateId++;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+ByteString Config::GetGroupName( USHORT nGroup ) const
+{
+ // Config-Daten evt. updaten
+ if ( !mnLockCount )
+ ImplUpdateConfig();
+
+ ImplGroupData* pGroup = mpData->mpFirstGroup;
+ USHORT nGroupCount = 0;
+ ByteString aGroupName;
+ while ( pGroup )
+ {
+ if ( nGroup == nGroupCount )
+ {
+ aGroupName = pGroup->maGroupName;
+ break;
+ }
+
+ nGroupCount++;
+ pGroup = pGroup->mpNext;
+ }
+
+ return aGroupName;
+}
+
+// -----------------------------------------------------------------------
+
+USHORT Config::GetGroupCount() const
+{
+ // Config-Daten evt. updaten
+ if ( !mnLockCount )
+ ImplUpdateConfig();
+
+ ImplGroupData* pGroup = mpData->mpFirstGroup;
+ USHORT nGroupCount = 0;
+ while ( pGroup )
+ {
+ nGroupCount++;
+ pGroup = pGroup->mpNext;
+ }
+
+ return nGroupCount;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Config::HasGroup( const ByteString& rGroup ) const
+{
+ // Config-Daten evt. updaten
+ if ( !mnLockCount )
+ ImplUpdateConfig();
+
+ ImplGroupData* pGroup = mpData->mpFirstGroup;
+ BOOL bRet = FALSE;
+
+ while( pGroup )
+ {
+ if( pGroup->maGroupName.EqualsIgnoreCaseAscii( rGroup ) )
+ {
+ bRet = TRUE;
+ break;
+ }
+
+ pGroup = pGroup->mpNext;
+ }
+
+ return bRet;
+}
+
+// -----------------------------------------------------------------------
+
+ByteString Config::ReadKey( const ByteString& rKey ) const
+{
+ return ReadKey( rKey, getEmptyByteString() );
+}
+
+// -----------------------------------------------------------------------
+
+UniString Config::ReadKey( const ByteString& rKey, rtl_TextEncoding eEncoding ) const
+{
+ if ( mpData->mbIsUTF8BOM )
+ eEncoding = RTL_TEXTENCODING_UTF8;
+ return UniString( ReadKey( rKey ), eEncoding );
+}
+
+// -----------------------------------------------------------------------
+
+ByteString Config::ReadKey( const ByteString& rKey, const ByteString& rDefault ) const
+{
+#ifdef DBG_UTIL
+ ByteString aTraceStr( "Config::ReadKey( " );
+ aTraceStr += rKey;
+ aTraceStr += " ) from ";
+ aTraceStr += GetGroup();
+ aTraceStr += " in ";
+ aTraceStr += ByteString( maFileName, RTL_TEXTENCODING_UTF8 );
+ DBG_TRACE( aTraceStr.GetBuffer() );
+#endif
+
+ // Config-Daten evt. updaten
+ if ( !mnLockCount )
+ ImplUpdateConfig();
+
+ // Key suchen und Value zurueckgeben
+ ImplGroupData* pGroup = ImplGetGroup();
+ if ( pGroup )
+ {
+ ImplKeyData* pKey = pGroup->mpFirstKey;
+ while ( pKey )
+ {
+ if ( !pKey->mbIsComment && pKey->maKey.EqualsIgnoreCaseAscii( rKey ) )
+ return pKey->maValue;
+
+ pKey = pKey->mpNext;
+ }
+ }
+
+ return rDefault;
+}
+
+// -----------------------------------------------------------------------
+
+void Config::WriteKey( const ByteString& rKey, const ByteString& rStr )
+{
+#ifdef DBG_UTIL
+ ByteString aTraceStr( "Config::WriteKey( " );
+ aTraceStr += rKey;
+ aTraceStr += ", ";
+ aTraceStr += rStr;
+ aTraceStr += " ) to ";
+ aTraceStr += GetGroup();
+ aTraceStr += " in ";
+ aTraceStr += ByteString( maFileName, RTL_TEXTENCODING_UTF8 );
+ DBG_TRACE( aTraceStr.GetBuffer() );
+ DBG_ASSERTWARNING( rStr != ReadKey( rKey ), "Config::WriteKey() with the same Value" );
+#endif
+
+ // Config-Daten evt. updaten
+ if ( !mnLockCount || !mpData->mbRead )
+ {
+ ImplUpdateConfig();
+ mpData->mbRead = TRUE;
+ }
+
+ // Key suchen und Value setzen
+ ImplGroupData* pGroup = ImplGetGroup();
+ if ( pGroup )
+ {
+ ImplKeyData* pPrevKey = NULL;
+ ImplKeyData* pKey = pGroup->mpFirstKey;
+ while ( pKey )
+ {
+ if ( !pKey->mbIsComment && pKey->maKey.EqualsIgnoreCaseAscii( rKey ) )
+ break;
+
+ pPrevKey = pKey;
+ pKey = pKey->mpNext;
+ }
+
+ BOOL bNewValue;
+ if ( !pKey )
+ {
+ pKey = new ImplKeyData;
+ pKey->mpNext = NULL;
+ pKey->maKey = rKey;
+ pKey->mbIsComment = FALSE;
+ if ( pPrevKey )
+ pPrevKey->mpNext = pKey;
+ else
+ pGroup->mpFirstKey = pKey;
+ bNewValue = TRUE;
+ }
+ else
+ bNewValue = pKey->maValue != rStr;
+
+ if ( bNewValue )
+ {
+ pKey->maValue = rStr;
+
+ if ( !mnLockCount && mbPersistence )
+ ImplWriteConfig( mpData );
+ else
+ {
+ mpData->mbModified = TRUE;
+ }
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Config::WriteKey( const ByteString& rKey, const UniString& rValue, rtl_TextEncoding eEncoding )
+{
+ if ( mpData->mbIsUTF8BOM )
+ eEncoding = RTL_TEXTENCODING_UTF8;
+ WriteKey( rKey, ByteString( rValue, eEncoding ) );
+}
+
+// -----------------------------------------------------------------------
+
+void Config::DeleteKey( const ByteString& rKey )
+{
+ // Config-Daten evt. updaten
+ if ( !mnLockCount || !mpData->mbRead )
+ {
+ ImplUpdateConfig();
+ mpData->mbRead = TRUE;
+ }
+
+ // Key suchen und Value setzen
+ ImplGroupData* pGroup = ImplGetGroup();
+ if ( pGroup )
+ {
+ ImplKeyData* pPrevKey = NULL;
+ ImplKeyData* pKey = pGroup->mpFirstKey;
+ while ( pKey )
+ {
+ if ( !pKey->mbIsComment && pKey->maKey.EqualsIgnoreCaseAscii( rKey ) )
+ break;
+
+ pPrevKey = pKey;
+ pKey = pKey->mpNext;
+ }
+
+ if ( pKey )
+ {
+ // Gruppe weiterschalten und loeschen
+ if ( pPrevKey )
+ pPrevKey->mpNext = pKey->mpNext;
+ else
+ pGroup->mpFirstKey = pKey->mpNext;
+ delete pKey;
+
+ // Config-Datei neu schreiben
+ if ( !mnLockCount && mbPersistence )
+ ImplWriteConfig( mpData );
+ else
+ {
+ mpData->mbModified = TRUE;
+ }
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+USHORT Config::GetKeyCount() const
+{
+#ifdef DBG_UTIL
+ ByteString aTraceStr( "Config::GetKeyCount()" );
+ aTraceStr += " from ";
+ aTraceStr += GetGroup();
+ aTraceStr += " in ";
+ aTraceStr += ByteString( maFileName, RTL_TEXTENCODING_UTF8 );
+ DBG_TRACE( aTraceStr.GetBuffer() );
+#endif
+
+ // Config-Daten evt. updaten
+ if ( !mnLockCount )
+ ImplUpdateConfig();
+
+ // Key suchen und Value zurueckgeben
+ USHORT nCount = 0;
+ ImplGroupData* pGroup = ImplGetGroup();
+ if ( pGroup )
+ {
+ ImplKeyData* pKey = pGroup->mpFirstKey;
+ while ( pKey )
+ {
+ if ( !pKey->mbIsComment )
+ nCount++;
+
+ pKey = pKey->mpNext;
+ }
+ }
+
+ return nCount;
+}
+
+// -----------------------------------------------------------------------
+
+ByteString Config::GetKeyName( USHORT nKey ) const
+{
+#ifdef DBG_UTIL
+ ByteString aTraceStr( "Config::GetKeyName( " );
+ aTraceStr += ByteString::CreateFromInt32(nKey);
+ aTraceStr += " ) from ";
+ aTraceStr += GetGroup();
+ aTraceStr += " in ";
+ aTraceStr += ByteString( maFileName, RTL_TEXTENCODING_UTF8 );
+ DBG_TRACE( aTraceStr.GetBuffer() );
+#endif
+
+ // Key suchen und Name zurueckgeben
+ ImplGroupData* pGroup = ImplGetGroup();
+ if ( pGroup )
+ {
+ ImplKeyData* pKey = pGroup->mpFirstKey;
+ while ( pKey )
+ {
+ if ( !pKey->mbIsComment )
+ {
+ if ( !nKey )
+ return pKey->maKey;
+ nKey--;
+ }
+
+ pKey = pKey->mpNext;
+ }
+ }
+
+ return getEmptyByteString();
+}
+
+// -----------------------------------------------------------------------
+
+ByteString Config::ReadKey( USHORT nKey ) const
+{
+#ifdef DBG_UTIL
+ ByteString aTraceStr( "Config::ReadKey( " );
+ aTraceStr += ByteString::CreateFromInt32( nKey );
+ aTraceStr += " ) from ";
+ aTraceStr += GetGroup();
+ aTraceStr += " in ";
+ aTraceStr += ByteString( maFileName, RTL_TEXTENCODING_UTF8 );
+ DBG_TRACE( aTraceStr.GetBuffer() );
+#endif
+
+ // Key suchen und Value zurueckgeben
+ ImplGroupData* pGroup = ImplGetGroup();
+ if ( pGroup )
+ {
+ ImplKeyData* pKey = pGroup->mpFirstKey;
+ while ( pKey )
+ {
+ if ( !pKey->mbIsComment )
+ {
+ if ( !nKey )
+ return pKey->maValue;
+ nKey--;
+ }
+
+ pKey = pKey->mpNext;
+ }
+ }
+
+ return getEmptyByteString();
+}
+
+// -----------------------------------------------------------------------
+
+void Config::EnterLock()
+{
+ // Config-Daten evt. updaten
+ if ( !mnLockCount )
+ ImplUpdateConfig();
+
+ mnLockCount++;
+}
+
+// -----------------------------------------------------------------------
+
+void Config::LeaveLock()
+{
+ DBG_ASSERT( mnLockCount, "Config::LeaveLook() without Config::EnterLook()" );
+ mnLockCount--;
+
+ if ( (mnLockCount == 0) && mpData->mbModified && mbPersistence )
+ ImplWriteConfig( mpData );
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Config::Update()
+{
+ return ImplUpdateConfig();
+}
+
+// -----------------------------------------------------------------------
+
+void Config::Flush()
+{
+ if ( mpData->mbModified && mbPersistence )
+ ImplWriteConfig( mpData );
+}
+
+// -----------------------------------------------------------------------
+
+void Config::SetLineEnd( LineEnd eLineEnd )
+{
+ mpData->meLineEnd = eLineEnd;
+}
+
+// -----------------------------------------------------------------------
+
+LineEnd Config::GetLineEnd() const
+{
+ return mpData->meLineEnd;
+}
+