| /************************************************************** |
| * |
| * 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; |
| } |
| |