blob: a060dc468b612c26607948932f200dd0c8d6a716 [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the 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;
sal_Bool mbIsComment;
};
struct ImplGroupData
{
ImplGroupData* mpNext;
ImplKeyData* mpFirstKey;
ByteString maGroupName;
sal_uInt16 mnEmptyLines;
};
struct ImplConfigData
{
ImplGroupData* mpFirstGroup;
XubString maFileName;
sal_uIntPtr mnDataUpdateId;
sal_uIntPtr mnTimeStamp;
LineEnd meLineEnd;
sal_uInt16 mnRefCount;
sal_Bool mbModified;
sal_Bool mbRead;
sal_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 sal_uIntPtr ImplSysGetConfigTimeStamp( const XubString& rFileName )
{
sal_uIntPtr 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 sal_uInt8* ImplSysReadConfig( const XubString& rFileName,
sal_uInt64& rRead, sal_Bool& rbRead, sal_Bool& rbIsUTF8BOM, sal_uIntPtr& rTimeStamp )
{
sal_uInt8* 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 sal_uInt8[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(sal_uInt8)) );
rbIsUTF8BOM = sal_True;
}
rTimeStamp = ImplSysGetConfigTimeStamp( rFileName );
rbRead = sal_True;
rRead = nRead;
}
else
{
delete[] pBuf;
pBuf = NULL;
}
}
aFile.close();
}
return pBuf;
}
// -----------------------------------------------------------------------
static sal_Bool ImplSysWriteConfig( const XubString& rFileName,
const sal_uInt8* pBuf, sal_uIntPtr nBufLen, sal_Bool rbIsUTF8BOM, sal_uIntPtr& rTimeStamp )
{
sal_Bool bSuccess = sal_False;
sal_Bool bUTF8BOMSuccess = sal_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 = sal_True;
}
}
if( aFile.write( pBuf, nBufLen, nWritten ) == ::osl::FileBase::E_None && nWritten == nBufLen )
{
bSuccess = sal_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(sal_uInt8 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 sal_uInt8* 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 sal_uInt8* 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 = sal_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 = sal_True;
}
else
{
pKey->mbIsComment = sal_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 sal_uInt8* ImplGetConfigBuffer( const ImplConfigData* pData, sal_uIntPtr& rLen )
{
sal_uInt8* pWriteBuf;
sal_uInt8* pBuf;
sal_uInt8 aLineEndBuf[2] = {0, 0};
ImplKeyData* pKey;
ImplGroupData* pGroup;
unsigned int nBufLen;
sal_uInt16 nValueLen;
sal_uInt16 nKeyLen;
sal_uInt16 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 sal_uInt8[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 sal_uInt8[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
sal_uInt16 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 )
{
sal_uIntPtr nTimeStamp = 0;
sal_uInt64 nRead = 0;
sal_Bool bRead = sal_False;
sal_Bool bIsUTF8BOM =sal_False;
sal_uInt8* 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 = sal_False;
if ( bRead )
pData->mbRead = sal_True;
if ( bIsUTF8BOM )
pData->mbIsUTF8BOM = sal_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
sal_uIntPtr nBufLen;
sal_uInt8* pBuf = ImplGetConfigBuffer( pData, nBufLen );
if ( pBuf )
{
if ( ImplSysWriteConfig( pData->maFileName, pBuf, nBufLen, pData->mbIsUTF8BOM, pData->mnTimeStamp ) )
pData->mbModified = sal_False;
delete[] pBuf;
}
else
pData->mbModified = sal_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 = sal_False;
pData->mbIsUTF8BOM = sal_False;
ImplReadConfig( pData );
return pData;
}
// -----------------------------------------------------------------------
static void ImplFreeConfigData( ImplConfigData* pDelData )
{
ImplDeleteConfigData( pDelData );
delete pDelData;
}
// =======================================================================
sal_Bool Config::ImplUpdateConfig() const
{
// Wenn sich TimeStamp unterscheidet, dann Datei neu einlesen
if ( mpData->mnTimeStamp != ImplSysGetConfigTimeStamp( maFileName ) )
{
ImplDeleteConfigData( mpData );
ImplReadConfig( mpData );
mpData->mnDataUpdateId++;
return sal_True;
}
else
return sal_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 = sal_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 = sal_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 = sal_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 = sal_True;
}
// Gruppen auf ungluetig setzen
mnDataUpdateId = mpData->mnDataUpdateId;
mpData->mnDataUpdateId++;
}
}
// -----------------------------------------------------------------------
ByteString Config::GetGroupName( sal_uInt16 nGroup ) const
{
// Config-Daten evt. updaten
if ( !mnLockCount )
ImplUpdateConfig();
ImplGroupData* pGroup = mpData->mpFirstGroup;
sal_uInt16 nGroupCount = 0;
ByteString aGroupName;
while ( pGroup )
{
if ( nGroup == nGroupCount )
{
aGroupName = pGroup->maGroupName;
break;
}
nGroupCount++;
pGroup = pGroup->mpNext;
}
return aGroupName;
}
// -----------------------------------------------------------------------
sal_uInt16 Config::GetGroupCount() const
{
// Config-Daten evt. updaten
if ( !mnLockCount )
ImplUpdateConfig();
ImplGroupData* pGroup = mpData->mpFirstGroup;
sal_uInt16 nGroupCount = 0;
while ( pGroup )
{
nGroupCount++;
pGroup = pGroup->mpNext;
}
return nGroupCount;
}
// -----------------------------------------------------------------------
sal_Bool Config::HasGroup( const ByteString& rGroup ) const
{
// Config-Daten evt. updaten
if ( !mnLockCount )
ImplUpdateConfig();
ImplGroupData* pGroup = mpData->mpFirstGroup;
sal_Bool bRet = sal_False;
while( pGroup )
{
if( pGroup->maGroupName.EqualsIgnoreCaseAscii( rGroup ) )
{
bRet = sal_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 = sal_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;
}
sal_Bool bNewValue;
if ( !pKey )
{
pKey = new ImplKeyData;
pKey->mpNext = NULL;
pKey->maKey = rKey;
pKey->mbIsComment = sal_False;
if ( pPrevKey )
pPrevKey->mpNext = pKey;
else
pGroup->mpFirstKey = pKey;
bNewValue = sal_True;
}
else
bNewValue = pKey->maValue != rStr;
if ( bNewValue )
{
pKey->maValue = rStr;
if ( !mnLockCount && mbPersistence )
ImplWriteConfig( mpData );
else
{
mpData->mbModified = sal_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 = sal_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 = sal_True;
}
}
}
}
// -----------------------------------------------------------------------
sal_uInt16 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
sal_uInt16 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( sal_uInt16 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( sal_uInt16 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 );
}
// -----------------------------------------------------------------------
sal_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;
}