LCOV - code coverage report
Current view: top level - libreoffice/tools/source/generic - config.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 0 500 0.0 %
Date: 2012-12-27 Functions: 0 36 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : #define _CONFIG_CXX
      20             : 
      21             : #include <cstddef>
      22             : #include <cstdlib>
      23             : #include <limits>
      24             : #include <new>
      25             : #include <string.h>
      26             : 
      27             : #ifdef WNT
      28             : #include "stdlib.h"
      29             : #endif
      30             : 
      31             : #include <osl/file.hxx>
      32             : #include <tools/stream.hxx>
      33             : #include <tools/debug.hxx>
      34             : #include <tools/config.hxx>
      35             : #include <osl/security.h>
      36             : #include <rtl/strbuf.hxx>
      37             : 
      38           0 : struct ImplKeyData
      39             : {
      40             :     ImplKeyData*    mpNext;
      41             :     rtl::OString maKey;
      42             :     rtl::OString maValue;
      43             :     sal_Bool            mbIsComment;
      44             : };
      45             : 
      46           0 : struct ImplGroupData
      47             : {
      48             :     ImplGroupData*  mpNext;
      49             :     ImplKeyData*    mpFirstKey;
      50             :     rtl::OString maGroupName;
      51             :     sal_uInt16          mnEmptyLines;
      52             : };
      53             : 
      54           0 : struct ImplConfigData
      55             : {
      56             :     ImplGroupData*  mpFirstGroup;
      57             :     rtl::OUString   maFileName;
      58             :     sal_uIntPtr         mnDataUpdateId;
      59             :     sal_uIntPtr         mnTimeStamp;
      60             :     LineEnd         meLineEnd;
      61             :     sal_uInt16          mnRefCount;
      62             :     sal_Bool            mbModified;
      63             :     sal_Bool            mbRead;
      64             :     sal_Bool            mbIsUTF8BOM;
      65             : };
      66             : 
      67           0 : static String toUncPath( const String& rPath )
      68             : {
      69           0 :     ::rtl::OUString aFileURL;
      70             : 
      71             :     // check if rFileName is already a URL; if not make it so
      72           0 :     if( rPath.CompareToAscii( "file://", 7 ) == COMPARE_EQUAL )
      73           0 :         aFileURL = rPath;
      74           0 :     else if( ::osl::FileBase::getFileURLFromSystemPath( rPath, aFileURL ) != ::osl::FileBase::E_None )
      75           0 :         aFileURL = rPath;
      76             : 
      77           0 :     return aFileURL;
      78             : }
      79             : 
      80           0 : static sal_uIntPtr ImplSysGetConfigTimeStamp( const rtl::OUString& rFileName )
      81             : {
      82           0 :     sal_uIntPtr nTimeStamp = 0;
      83           0 :     ::osl::DirectoryItem aItem;
      84           0 :     ::osl::FileStatus aStatus( osl_FileStatus_Mask_ModifyTime );
      85             : 
      86           0 :     if( ::osl::DirectoryItem::get( rFileName, aItem ) == ::osl::FileBase::E_None &&
      87           0 :         aItem.getFileStatus( aStatus ) == ::osl::FileBase::E_None )
      88             :     {
      89           0 :         nTimeStamp = aStatus.getModifyTime().Seconds;
      90             :     }
      91             : 
      92           0 :     return nTimeStamp;
      93             : }
      94             : 
      95           0 : static sal_uInt8* ImplSysReadConfig( const rtl::OUString& rFileName,
      96             :                                 sal_uInt64& rRead, sal_Bool& rbRead, sal_Bool& rbIsUTF8BOM, sal_uIntPtr& rTimeStamp )
      97             : {
      98           0 :     sal_uInt8*          pBuf = NULL;
      99           0 :     ::osl::File aFile( rFileName );
     100             : 
     101           0 :     if( aFile.open( osl_File_OpenFlag_Read ) == ::osl::FileBase::E_None )
     102             :     {
     103           0 :         sal_uInt64 nPos = 0;
     104           0 :         if( aFile.getSize( nPos ) == ::osl::FileBase::E_None )
     105             :         {
     106           0 :             if (nPos > std::numeric_limits< std::size_t >::max()) {
     107           0 :                 aFile.close();
     108           0 :                 return 0;
     109             :             }
     110           0 :             pBuf = new sal_uInt8[static_cast< std::size_t >(nPos)];
     111           0 :             sal_uInt64 nRead = 0;
     112           0 :             if( aFile.read( pBuf, nPos, nRead ) == ::osl::FileBase::E_None && nRead == nPos )
     113             :             {
     114             :                 //skip the byte-order-mark 0xEF 0xBB 0xBF, if it was UTF8 files
     115           0 :                 unsigned char BOM[3] = {0xEF, 0xBB, 0xBF};
     116           0 :                 if (nRead > 2 && memcmp(pBuf, BOM, 3) == 0)
     117             :                 {
     118           0 :                     nRead -= 3;
     119           0 :                     memmove(pBuf, pBuf + 3, sal::static_int_cast<sal_Size>(nRead * sizeof(sal_uInt8)) );
     120           0 :                     rbIsUTF8BOM = sal_True;
     121             :                 }
     122             : 
     123           0 :                 rTimeStamp = ImplSysGetConfigTimeStamp( rFileName );
     124           0 :                 rbRead = sal_True;
     125           0 :                 rRead = nRead;
     126             :             }
     127             :             else
     128             :             {
     129           0 :                 delete[] pBuf;
     130           0 :                 pBuf = NULL;
     131             :             }
     132             :         }
     133           0 :         aFile.close();
     134             :     }
     135             : 
     136           0 :     return pBuf;
     137             : }
     138             : 
     139           0 : static sal_Bool ImplSysWriteConfig( const rtl::OUString& rFileName,
     140             :                                 const sal_uInt8* pBuf, sal_uIntPtr nBufLen, sal_Bool rbIsUTF8BOM, sal_uIntPtr& rTimeStamp )
     141             : {
     142           0 :     sal_Bool bSuccess = sal_False;
     143           0 :     sal_Bool bUTF8BOMSuccess = sal_False;
     144             : 
     145           0 :     ::osl::File aFile( rFileName );
     146           0 :     ::osl::FileBase::RC eError = aFile.open( osl_File_OpenFlag_Write | osl_File_OpenFlag_Create );
     147           0 :     if( eError != ::osl::FileBase::E_None )
     148           0 :         eError = aFile.open( osl_File_OpenFlag_Write );
     149           0 :     if( eError == ::osl::FileBase::E_None )
     150             :     {
     151             :         // truncate
     152           0 :         aFile.setSize( 0 );
     153             :         sal_uInt64 nWritten;
     154             : 
     155             :         //write the the byte-order-mark 0xEF 0xBB 0xBF first , if it was UTF8 files
     156           0 :         if ( rbIsUTF8BOM )
     157             :         {
     158           0 :             unsigned char BOM[3] = {0xEF, 0xBB, 0xBF};
     159             :             sal_uInt64 nUTF8BOMWritten;
     160           0 :             if( aFile.write( BOM, 3, nUTF8BOMWritten ) == ::osl::FileBase::E_None && 3 == nUTF8BOMWritten )
     161             :             {
     162           0 :                 bUTF8BOMSuccess = sal_True;
     163             :             }
     164             :         }
     165             : 
     166           0 :         if( aFile.write( pBuf, nBufLen, nWritten ) == ::osl::FileBase::E_None && nWritten == nBufLen )
     167             :         {
     168           0 :             bSuccess = sal_True;
     169             :         }
     170           0 :         if ( rbIsUTF8BOM ? bSuccess && bUTF8BOMSuccess : bSuccess )
     171             :         {
     172           0 :             rTimeStamp = ImplSysGetConfigTimeStamp( rFileName );
     173             :         }
     174             :     }
     175             : 
     176           0 :     return rbIsUTF8BOM ? bSuccess && bUTF8BOMSuccess : bSuccess;
     177             : }
     178             : 
     179             : namespace {
     180           0 : rtl::OString makeOString(const sal_uInt8* p, sal_uInt64 n)
     181             : {
     182           0 :     if (n > SAL_MAX_INT32)
     183             :     {
     184             :         #ifdef WNT
     185             :         abort();
     186             :         #else
     187           0 :         ::std::abort(); //TODO: handle this gracefully
     188             :         #endif
     189             :     }
     190             :     return rtl::OString(
     191             :         reinterpret_cast< char const * >(p),
     192           0 :         sal::static_int_cast< sal_Int32 >(n));
     193             : }
     194             : }
     195             : 
     196           0 : static void ImplMakeConfigList( ImplConfigData* pData,
     197             :                                 const sal_uInt8* pBuf, sal_uInt64 nLen )
     198             : {
     199           0 :     if ( !nLen )
     200           0 :         return;
     201             : 
     202             :     // Parse buffer and build config list
     203             :     sal_uInt64 nStart;
     204             :     sal_uInt64 nLineLen;
     205             :     sal_uInt64 nNameLen;
     206             :     sal_uInt64 nKeyLen;
     207             :     sal_uInt64 i;
     208             :     const sal_uInt8*    pLine;
     209           0 :     ImplKeyData*    pPrevKey = NULL;
     210             :     ImplKeyData*    pKey;
     211           0 :     ImplGroupData*  pPrevGroup = NULL;
     212           0 :     ImplGroupData*  pGroup = NULL;
     213           0 :     i = 0;
     214           0 :     while ( i < nLen )
     215             :     {
     216             :         // Ctrl+Z
     217           0 :         if ( pBuf[i] == 0x1A )
     218           0 :             break;
     219             : 
     220             :         // Remove spaces and tabs
     221           0 :         while ( (pBuf[i] == ' ') || (pBuf[i] == '\t') )
     222           0 :             i++;
     223             : 
     224             :         // remember line-starts
     225           0 :         nStart = i;
     226           0 :         pLine = pBuf+i;
     227             : 
     228             :         // search line-endings
     229           0 :         while (  (i < nLen) && pBuf[i] && (pBuf[i] != '\r') && (pBuf[i] != '\n') &&
     230           0 :                 (pBuf[i] != 0x1A) )
     231           0 :             i++;
     232             : 
     233           0 :         nLineLen = i-nStart;
     234             : 
     235             :         // if Line-ending is found, continue once
     236           0 :         if ( (i+1 < nLen) &&
     237           0 :              (pBuf[i] != pBuf[i+1]) &&
     238           0 :              ((pBuf[i+1] == '\r') || (pBuf[i+1] == '\n')) )
     239           0 :             i++;
     240           0 :         i++;
     241             : 
     242             :         // evaluate line
     243           0 :         if ( *pLine == '[' )
     244             :         {
     245           0 :             pGroup               = new ImplGroupData;
     246           0 :             pGroup->mpNext       = NULL;
     247           0 :             pGroup->mpFirstKey   = NULL;
     248           0 :             pGroup->mnEmptyLines = 0;
     249           0 :             if ( pPrevGroup )
     250           0 :                 pPrevGroup->mpNext = pGroup;
     251             :             else
     252           0 :                 pData->mpFirstGroup = pGroup;
     253           0 :             pPrevGroup  = pGroup;
     254           0 :             pPrevKey    = NULL;
     255           0 :             pKey        = NULL;
     256             : 
     257             :             // filter group names
     258           0 :             pLine++;
     259           0 :             nLineLen--;
     260             :             // remove spaces and tabs
     261           0 :             while ( (*pLine == ' ') || (*pLine == '\t') )
     262             :             {
     263           0 :                 nLineLen--;
     264           0 :                 pLine++;
     265             :             }
     266           0 :             nNameLen = 0;
     267           0 :             while ( (nNameLen < nLineLen) && (pLine[nNameLen] != ']') )
     268           0 :                 nNameLen++;
     269           0 :             if ( nNameLen )
     270             :             {
     271           0 :                 while ( (pLine[nNameLen-1] == ' ') || (pLine[nNameLen-1] == '\t') )
     272           0 :                     nNameLen--;
     273             :             }
     274           0 :             pGroup->maGroupName = makeOString(pLine, nNameLen);
     275             :         }
     276             :         else
     277             :         {
     278           0 :             if ( nLineLen )
     279             :             {
     280             :                 // If no group exists yet, add to default
     281           0 :                 if ( !pGroup )
     282             :                 {
     283           0 :                     pGroup              = new ImplGroupData;
     284           0 :                     pGroup->mpNext      = NULL;
     285           0 :                     pGroup->mpFirstKey  = NULL;
     286           0 :                     pGroup->mnEmptyLines = 0;
     287           0 :                     if ( pPrevGroup )
     288           0 :                         pPrevGroup->mpNext = pGroup;
     289             :                     else
     290           0 :                         pData->mpFirstGroup = pGroup;
     291           0 :                     pPrevGroup  = pGroup;
     292           0 :                     pPrevKey    = NULL;
     293             :                 }
     294             : 
     295             :                 // if empty line, append it
     296           0 :                 if ( pPrevKey )
     297             :                 {
     298           0 :                     while ( pGroup->mnEmptyLines )
     299             :                     {
     300           0 :                         pKey                = new ImplKeyData;
     301           0 :                         pKey->mbIsComment   = sal_True;
     302           0 :                         pPrevKey->mpNext    = pKey;
     303           0 :                         pPrevKey            = pKey;
     304           0 :                         pGroup->mnEmptyLines--;
     305             :                     }
     306             :                 }
     307             : 
     308             :                 // Generate new key
     309           0 :                 pKey        = new ImplKeyData;
     310           0 :                 pKey->mpNext = NULL;
     311           0 :                 if ( pPrevKey )
     312           0 :                     pPrevKey->mpNext = pKey;
     313             :                 else
     314           0 :                     pGroup->mpFirstKey = pKey;
     315           0 :                 pPrevKey = pKey;
     316           0 :                 if ( pLine[0] == ';' )
     317             :                 {
     318           0 :                     pKey->maValue = makeOString(pLine, nLineLen);
     319           0 :                     pKey->mbIsComment = sal_True;
     320             :                 }
     321             :                 else
     322             :                 {
     323           0 :                     pKey->mbIsComment = sal_False;
     324           0 :                     nNameLen = 0;
     325           0 :                     while ( (nNameLen < nLineLen) && (pLine[nNameLen] != '=') )
     326           0 :                         nNameLen++;
     327           0 :                     nKeyLen = nNameLen;
     328             :                     // Remove spaces and tabs
     329           0 :                     if ( nNameLen )
     330             :                     {
     331           0 :                         while ( (pLine[nNameLen-1] == ' ') || (pLine[nNameLen-1] == '\t') )
     332           0 :                             nNameLen--;
     333             :                     }
     334           0 :                     pKey->maKey = makeOString(pLine, nNameLen);
     335           0 :                     nKeyLen++;
     336           0 :                     if ( nKeyLen < nLineLen )
     337             :                     {
     338           0 :                         pLine += nKeyLen;
     339           0 :                         nLineLen -= nKeyLen;
     340             :                         // Remove spaces and tabs
     341           0 :                         while ( (*pLine == ' ') || (*pLine == '\t') )
     342             :                         {
     343           0 :                             nLineLen--;
     344           0 :                             pLine++;
     345             :                         }
     346           0 :                         if ( nLineLen )
     347             :                         {
     348           0 :                             while ( (pLine[nLineLen-1] == ' ') || (pLine[nLineLen-1] == '\t') )
     349           0 :                                 nLineLen--;
     350           0 :                             pKey->maValue = makeOString(pLine, nLineLen);
     351             :                         }
     352             :                     }
     353             :                 }
     354             :             }
     355             :             else
     356             :             {
     357             :                 // Spaces are counted and appended only after key generation,
     358             :                 // as we want to store spaces even after adding new keys
     359           0 :                 if ( pGroup )
     360           0 :                     pGroup->mnEmptyLines++;
     361             :             }
     362             :         }
     363             :     }
     364             : }
     365             : 
     366           0 : static sal_uInt8* ImplGetConfigBuffer( const ImplConfigData* pData, sal_uIntPtr& rLen )
     367             : {
     368             :     sal_uInt8*      pWriteBuf;
     369             :     sal_uInt8*      pBuf;
     370           0 :     sal_uInt8       aLineEndBuf[2] = {0, 0};
     371             :     ImplKeyData*    pKey;
     372             :     ImplGroupData*  pGroup;
     373             :     unsigned int    nBufLen;
     374             :     sal_uInt32      nValueLen;
     375             :     sal_uInt32      nKeyLen;
     376             :     sal_uInt32      nLineEndLen;
     377             : 
     378           0 :     if ( pData->meLineEnd == LINEEND_CR )
     379             :     {
     380           0 :         aLineEndBuf[0] = _CR;
     381           0 :         nLineEndLen = 1;
     382             :     }
     383           0 :     else if ( pData->meLineEnd == LINEEND_LF )
     384             :     {
     385           0 :         aLineEndBuf[0] = _LF;
     386           0 :         nLineEndLen = 1;
     387             :     }
     388             :     else
     389             :     {
     390           0 :         aLineEndBuf[0] = _CR;
     391           0 :         aLineEndBuf[1] = _LF;
     392           0 :         nLineEndLen = 2;
     393             :     }
     394             : 
     395           0 :     nBufLen = 0;
     396           0 :     pGroup = pData->mpFirstGroup;
     397           0 :     while ( pGroup )
     398             :     {
     399             :         // Don't write empty groups
     400           0 :         if ( pGroup->mpFirstKey )
     401             :         {
     402           0 :             nBufLen += pGroup->maGroupName.getLength() + nLineEndLen + 2;
     403           0 :             pKey = pGroup->mpFirstKey;
     404           0 :             while ( pKey )
     405             :             {
     406           0 :                 nValueLen = pKey->maValue.getLength();
     407           0 :                 if ( pKey->mbIsComment )
     408           0 :                     nBufLen += nValueLen + nLineEndLen;
     409             :                 else
     410           0 :                     nBufLen += pKey->maKey.getLength() + nValueLen + nLineEndLen + 1;
     411             : 
     412           0 :                 pKey = pKey->mpNext;
     413             :             }
     414             : 
     415             :             // Write empty lines after each group
     416           0 :             if ( !pGroup->mnEmptyLines )
     417           0 :                 pGroup->mnEmptyLines = 1;
     418           0 :             nBufLen += nLineEndLen * pGroup->mnEmptyLines;
     419             :         }
     420             : 
     421           0 :         pGroup = pGroup->mpNext;
     422             :     }
     423             : 
     424             :     // Output buffer length
     425           0 :     rLen = nBufLen;
     426           0 :     if ( !nBufLen )
     427             :     {
     428           0 :         pWriteBuf = new sal_uInt8[nLineEndLen];
     429           0 :         if ( pWriteBuf )
     430             :         {
     431           0 :             pWriteBuf[0] = aLineEndBuf[0];
     432           0 :             if ( nLineEndLen == 2 )
     433           0 :                 pWriteBuf[1] = aLineEndBuf[1];
     434           0 :             return pWriteBuf;
     435             :         }
     436             :         else
     437           0 :             return 0;
     438             :     }
     439             : 
     440             :     // Allocate new write buffer (caller frees it)
     441           0 :     pWriteBuf = new sal_uInt8[nBufLen];
     442           0 :     if ( !pWriteBuf )
     443           0 :         return 0;
     444             : 
     445             :     // fill buffer
     446           0 :     pBuf = pWriteBuf;
     447           0 :     pGroup = pData->mpFirstGroup;
     448           0 :     while ( pGroup )
     449             :     {
     450             :         // Don't write empty groups
     451           0 :         if ( pGroup->mpFirstKey )
     452             :         {
     453           0 :             *pBuf = '[';    pBuf++;
     454           0 :             memcpy( pBuf, pGroup->maGroupName.getStr(), pGroup->maGroupName.getLength() );
     455           0 :             pBuf += pGroup->maGroupName.getLength();
     456           0 :             *pBuf = ']';    pBuf++;
     457           0 :             *pBuf = aLineEndBuf[0]; pBuf++;
     458           0 :             if ( nLineEndLen == 2 )
     459             :             {
     460           0 :                 *pBuf = aLineEndBuf[1]; pBuf++;
     461             :             }
     462           0 :             pKey = pGroup->mpFirstKey;
     463           0 :             while ( pKey )
     464             :             {
     465           0 :                 nValueLen = pKey->maValue.getLength();
     466           0 :                 if ( pKey->mbIsComment )
     467             :                 {
     468           0 :                     if ( nValueLen )
     469             :                     {
     470           0 :                         memcpy( pBuf, pKey->maValue.getStr(), nValueLen );
     471           0 :                         pBuf += nValueLen;
     472             :                     }
     473           0 :                     *pBuf = aLineEndBuf[0]; pBuf++;
     474           0 :                     if ( nLineEndLen == 2 )
     475             :                     {
     476           0 :                         *pBuf = aLineEndBuf[1]; pBuf++;
     477             :                     }
     478             :                 }
     479             :                 else
     480             :                 {
     481           0 :                     nKeyLen = pKey->maKey.getLength();
     482           0 :                     memcpy( pBuf, pKey->maKey.getStr(), nKeyLen );
     483           0 :                     pBuf += nKeyLen;
     484           0 :                     *pBuf = '=';    pBuf++;
     485           0 :                     memcpy( pBuf, pKey->maValue.getStr(), nValueLen );
     486           0 :                     pBuf += nValueLen;
     487           0 :                     *pBuf = aLineEndBuf[0]; pBuf++;
     488           0 :                     if ( nLineEndLen == 2 )
     489             :                     {
     490           0 :                         *pBuf = aLineEndBuf[1]; pBuf++;
     491             :                     }
     492             :                 }
     493             : 
     494           0 :                 pKey = pKey->mpNext;
     495             :             }
     496             : 
     497             :             // Store empty line after each group
     498           0 :             sal_uInt16 nEmptyLines = pGroup->mnEmptyLines;
     499           0 :             while ( nEmptyLines )
     500             :             {
     501           0 :                 *pBuf = aLineEndBuf[0]; pBuf++;
     502           0 :                 if ( nLineEndLen == 2 )
     503             :                 {
     504           0 :                     *pBuf = aLineEndBuf[1]; pBuf++;
     505             :                 }
     506           0 :                 nEmptyLines--;
     507             :             }
     508             :         }
     509             : 
     510           0 :         pGroup = pGroup->mpNext;
     511             :     }
     512             : 
     513           0 :     return pWriteBuf;
     514             : }
     515             : 
     516           0 : static void ImplReadConfig( ImplConfigData* pData )
     517             : {
     518           0 :     sal_uIntPtr nTimeStamp = 0;
     519           0 :     sal_uInt64  nRead = 0;
     520           0 :     sal_Bool    bRead = sal_False;
     521           0 :     sal_Bool    bIsUTF8BOM =sal_False;
     522           0 :     sal_uInt8*  pBuf = ImplSysReadConfig( pData->maFileName, nRead, bRead, bIsUTF8BOM, nTimeStamp );
     523             : 
     524             :     // Read config list from buffer
     525           0 :     if ( pBuf )
     526             :     {
     527           0 :         ImplMakeConfigList( pData, pBuf, nRead );
     528           0 :         delete[] pBuf;
     529             :     }
     530           0 :     pData->mnTimeStamp = nTimeStamp;
     531           0 :     pData->mbModified  = sal_False;
     532           0 :     if ( bRead )
     533           0 :         pData->mbRead = sal_True;
     534           0 :     if ( bIsUTF8BOM )
     535           0 :         pData->mbIsUTF8BOM = sal_True;
     536           0 : }
     537             : 
     538           0 : static void ImplWriteConfig( ImplConfigData* pData )
     539             : {
     540             : #ifdef DBG_UTIL
     541             :     if ( DbgIsAssert() )
     542             :     {
     543             :         if ( pData->mnTimeStamp != ImplSysGetConfigTimeStamp( pData->maFileName ) )
     544             :         {
     545             :             OSL_TRACE( "Config overwrites modified configfile:\n %s", rtl::OUStringToOString(pData->maFileName, RTL_TEXTENCODING_UTF8).getStr() );
     546             :         }
     547             :     }
     548             : #endif
     549             : 
     550             :     // Read config list from buffer
     551             :     sal_uIntPtr nBufLen;
     552           0 :     sal_uInt8*  pBuf = ImplGetConfigBuffer( pData, nBufLen );
     553           0 :     if ( pBuf )
     554             :     {
     555           0 :         if ( ImplSysWriteConfig( pData->maFileName, pBuf, nBufLen, pData->mbIsUTF8BOM, pData->mnTimeStamp ) )
     556           0 :             pData->mbModified = sal_False;
     557           0 :         delete[] pBuf;
     558             :     }
     559             :     else
     560           0 :         pData->mbModified = sal_False;
     561           0 : }
     562             : 
     563           0 : static void ImplDeleteConfigData( ImplConfigData* pData )
     564             : {
     565             :     ImplKeyData*    pTempKey;
     566             :     ImplKeyData*    pKey;
     567             :     ImplGroupData*  pTempGroup;
     568           0 :     ImplGroupData*  pGroup = pData->mpFirstGroup;
     569           0 :     while ( pGroup )
     570             :     {
     571           0 :         pTempGroup = pGroup->mpNext;
     572             : 
     573             :         // remove all keys
     574           0 :         pKey = pGroup->mpFirstKey;
     575           0 :         while ( pKey )
     576             :         {
     577           0 :             pTempKey = pKey->mpNext;
     578           0 :             delete pKey;
     579           0 :             pKey = pTempKey;
     580             :         }
     581             : 
     582             :         // remove group and continue
     583           0 :         delete pGroup;
     584           0 :         pGroup = pTempGroup;
     585             :     }
     586             : 
     587           0 :     pData->mpFirstGroup = NULL;
     588           0 : }
     589             : 
     590           0 : static ImplConfigData* ImplGetConfigData( const rtl::OUString& rFileName )
     591             : {
     592             :     ImplConfigData* pData;
     593             : 
     594           0 :     pData                   = new ImplConfigData;
     595           0 :     pData->maFileName       = rFileName;
     596           0 :     pData->mpFirstGroup     = NULL;
     597           0 :     pData->mnDataUpdateId   = 0;
     598           0 :     pData->meLineEnd        = LINEEND_CRLF;
     599           0 :     pData->mnRefCount       = 0;
     600           0 :     pData->mbRead           = sal_False;
     601           0 :     pData->mbIsUTF8BOM      = sal_False;
     602           0 :     ImplReadConfig( pData );
     603             : 
     604           0 :     return pData;
     605             : }
     606             : 
     607           0 : static void ImplFreeConfigData( ImplConfigData* pDelData )
     608             : {
     609           0 :     ImplDeleteConfigData( pDelData );
     610           0 :     delete pDelData;
     611           0 : }
     612             : 
     613           0 : sal_Bool Config::ImplUpdateConfig() const
     614             : {
     615             :     // Re-read file if timestamp differs
     616           0 :     if ( mpData->mnTimeStamp != ImplSysGetConfigTimeStamp( maFileName ) )
     617             :     {
     618           0 :         ImplDeleteConfigData( mpData );
     619           0 :         ImplReadConfig( mpData );
     620           0 :         mpData->mnDataUpdateId++;
     621           0 :         return sal_True;
     622             :     }
     623             :     else
     624           0 :         return sal_False;
     625             : }
     626             : 
     627           0 : ImplGroupData* Config::ImplGetGroup() const
     628             : {
     629           0 :     if ( !mpActGroup || (mnDataUpdateId != mpData->mnDataUpdateId) )
     630             :     {
     631           0 :         ImplGroupData* pPrevGroup = NULL;
     632           0 :         ImplGroupData* pGroup = mpData->mpFirstGroup;
     633           0 :         while ( pGroup )
     634             :         {
     635           0 :             if ( pGroup->maGroupName.equalsIgnoreAsciiCase(maGroupName) )
     636           0 :                 break;
     637             : 
     638           0 :             pPrevGroup = pGroup;
     639           0 :             pGroup = pGroup->mpNext;
     640             :         }
     641             : 
     642             :         // Add group if not exists
     643           0 :         if ( !pGroup )
     644             :         {
     645           0 :             pGroup               = new ImplGroupData;
     646           0 :             pGroup->mpNext       = NULL;
     647           0 :             pGroup->mpFirstKey   = NULL;
     648           0 :             pGroup->mnEmptyLines = 1;
     649           0 :             if ( pPrevGroup )
     650           0 :                 pPrevGroup->mpNext = pGroup;
     651             :             else
     652           0 :                 mpData->mpFirstGroup = pGroup;
     653             :         }
     654             : 
     655             :         // Always inherit group names and upate cache members
     656           0 :         pGroup->maGroupName             = maGroupName;
     657           0 :         ((Config*)this)->mnDataUpdateId = mpData->mnDataUpdateId;
     658           0 :         ((Config*)this)->mpActGroup     = pGroup;
     659             :     }
     660             : 
     661           0 :     return mpActGroup;
     662             : }
     663             : 
     664           0 : Config::Config( const rtl::OUString& rFileName )
     665             : {
     666             :     // Initialize config data
     667           0 :     maFileName      = toUncPath( rFileName );
     668           0 :     mpData          = ImplGetConfigData( maFileName );
     669           0 :     mpActGroup      = NULL;
     670           0 :     mnDataUpdateId  = 0;
     671           0 :     mnLockCount     = 1;
     672           0 :     mbPersistence   = sal_True;
     673             : 
     674             : #ifdef DBG_UTIL
     675             :     rtl::OStringBuffer aTraceStr(
     676             :         RTL_CONSTASCII_STRINGPARAM("Config::Config( "));
     677             :     aTraceStr.append(rtl::OUStringToOString(maFileName, RTL_TEXTENCODING_UTF8));
     678             :     aTraceStr.append(RTL_CONSTASCII_STRINGPARAM(" )"));
     679             :     OSL_TRACE("%s", aTraceStr.getStr());
     680             : #endif
     681           0 : }
     682             : 
     683           0 : Config::~Config()
     684             : {
     685             : #ifdef DBG_UTIL
     686             :     OSL_TRACE( "Config::~Config()" );
     687             : #endif
     688             : 
     689           0 :     Flush();
     690           0 :     ImplFreeConfigData( mpData );
     691           0 : }
     692             : 
     693           0 : void Config::SetGroup(const rtl::OString& rGroup)
     694             : {
     695             :     // If group is to be reset, it needs to be updated on next call
     696           0 :     if ( maGroupName != rGroup )
     697             :     {
     698           0 :         maGroupName     = rGroup;
     699           0 :         mnDataUpdateId  = mpData->mnDataUpdateId-1;
     700             :     }
     701           0 : }
     702             : 
     703           0 : void Config::DeleteGroup(const rtl::OString& rGroup)
     704             : {
     705             :     // Update config data if necessary
     706           0 :     if ( !mnLockCount || !mpData->mbRead )
     707             :     {
     708           0 :         ImplUpdateConfig();
     709           0 :         mpData->mbRead = sal_True;
     710             :     }
     711             : 
     712           0 :     ImplGroupData* pPrevGroup = NULL;
     713           0 :     ImplGroupData* pGroup = mpData->mpFirstGroup;
     714           0 :     while ( pGroup )
     715             :     {
     716           0 :         if ( pGroup->maGroupName.equalsIgnoreAsciiCase(rGroup) )
     717           0 :             break;
     718             : 
     719           0 :         pPrevGroup = pGroup;
     720           0 :         pGroup = pGroup->mpNext;
     721             :     }
     722             : 
     723           0 :     if ( pGroup )
     724             :     {
     725             :         // Remove all keys
     726             :         ImplKeyData* pTempKey;
     727           0 :         ImplKeyData* pKey = pGroup->mpFirstKey;
     728           0 :         while ( pKey )
     729             :         {
     730           0 :             pTempKey = pKey->mpNext;
     731           0 :             delete pKey;
     732           0 :             pKey = pTempKey;
     733             :         }
     734             : 
     735             :         // Rewire pointers and remove group
     736           0 :         if ( pPrevGroup )
     737           0 :             pPrevGroup->mpNext = pGroup->mpNext;
     738             :         else
     739           0 :             mpData->mpFirstGroup = pGroup->mpNext;
     740           0 :         delete pGroup;
     741             : 
     742             :         // Rewrite config data
     743           0 :         if ( !mnLockCount && mbPersistence )
     744           0 :             ImplWriteConfig( mpData );
     745             :         else
     746             :         {
     747           0 :             mpData->mbModified = sal_True;
     748             :         }
     749             : 
     750           0 :         mnDataUpdateId = mpData->mnDataUpdateId;
     751           0 :         mpData->mnDataUpdateId++;
     752             :     }
     753           0 : }
     754             : 
     755           0 : rtl::OString Config::GetGroupName(sal_uInt16 nGroup) const
     756             : {
     757             :     // Update config data if necessary
     758           0 :     if ( !mnLockCount )
     759           0 :         ImplUpdateConfig();
     760             : 
     761           0 :     ImplGroupData*  pGroup = mpData->mpFirstGroup;
     762           0 :     sal_uInt16          nGroupCount = 0;
     763           0 :     rtl::OString aGroupName;
     764           0 :     while ( pGroup )
     765             :     {
     766           0 :         if ( nGroup == nGroupCount )
     767             :         {
     768           0 :             aGroupName = pGroup->maGroupName;
     769           0 :             break;
     770             :         }
     771             : 
     772           0 :         nGroupCount++;
     773           0 :         pGroup = pGroup->mpNext;
     774             :     }
     775             : 
     776           0 :     return aGroupName;
     777             : }
     778             : 
     779           0 : sal_uInt16 Config::GetGroupCount() const
     780             : {
     781             :     // Update config data if necessary
     782           0 :     if ( !mnLockCount )
     783           0 :         ImplUpdateConfig();
     784             : 
     785           0 :     ImplGroupData*  pGroup = mpData->mpFirstGroup;
     786           0 :     sal_uInt16          nGroupCount = 0;
     787           0 :     while ( pGroup )
     788             :     {
     789           0 :         nGroupCount++;
     790           0 :         pGroup = pGroup->mpNext;
     791             :     }
     792             : 
     793           0 :     return nGroupCount;
     794             : }
     795             : 
     796           0 : sal_Bool Config::HasGroup(const rtl::OString& rGroup) const
     797             : {
     798             :     // Update config data if necessary
     799           0 :     if ( !mnLockCount )
     800           0 :         ImplUpdateConfig();
     801             : 
     802           0 :     ImplGroupData*  pGroup = mpData->mpFirstGroup;
     803           0 :     sal_Bool            bRet = sal_False;
     804             : 
     805           0 :     while( pGroup )
     806             :     {
     807           0 :         if( pGroup->maGroupName.equalsIgnoreAsciiCase(rGroup) )
     808             :         {
     809           0 :             bRet = sal_True;
     810           0 :             break;
     811             :         }
     812             : 
     813           0 :         pGroup = pGroup->mpNext;
     814             :     }
     815             : 
     816           0 :     return bRet;
     817             : }
     818             : 
     819           0 : rtl::OString Config::ReadKey(const rtl::OString& rKey) const
     820             : {
     821           0 :     return ReadKey(rKey, rtl::OString());
     822             : }
     823             : 
     824           0 : rtl::OUString Config::ReadKey(const rtl::OString& rKey, rtl_TextEncoding eEncoding) const
     825             : {
     826           0 :     if ( mpData->mbIsUTF8BOM )
     827           0 :         eEncoding = RTL_TEXTENCODING_UTF8;
     828           0 :     return rtl::OStringToOUString(ReadKey(rKey), eEncoding);
     829             : }
     830             : 
     831           0 : rtl::OString Config::ReadKey(const rtl::OString& rKey, const rtl::OString& rDefault) const
     832             : {
     833             : #ifdef DBG_UTIL
     834             :     rtl::OStringBuffer aTraceStr(
     835             :         RTL_CONSTASCII_STRINGPARAM("Config::ReadKey( "));
     836             :     aTraceStr.append(rKey);
     837             :     aTraceStr.append(RTL_CONSTASCII_STRINGPARAM(" ) from "));
     838             :     aTraceStr.append(GetGroup());
     839             :     aTraceStr.append(RTL_CONSTASCII_STRINGPARAM(" in "));
     840             :     aTraceStr.append(rtl::OUStringToOString(maFileName, RTL_TEXTENCODING_UTF8));
     841             :     OSL_TRACE("%s", aTraceStr.getStr());
     842             : #endif
     843             : 
     844             :     // Update config data if necessary
     845           0 :     if ( !mnLockCount )
     846           0 :         ImplUpdateConfig();
     847             : 
     848             :     // Search key, return value if found
     849           0 :     ImplGroupData* pGroup = ImplGetGroup();
     850           0 :     if ( pGroup )
     851             :     {
     852           0 :         ImplKeyData* pKey = pGroup->mpFirstKey;
     853           0 :         while ( pKey )
     854             :         {
     855           0 :             if ( !pKey->mbIsComment && pKey->maKey.equalsIgnoreAsciiCase(rKey) )
     856           0 :                 return pKey->maValue;
     857             : 
     858           0 :             pKey = pKey->mpNext;
     859             :         }
     860             :     }
     861             : 
     862           0 :     return rDefault;
     863             : }
     864             : 
     865           0 : void Config::WriteKey(const rtl::OString& rKey, const rtl::OString& rStr)
     866             : {
     867             : #ifdef DBG_UTIL
     868             :     rtl::OStringBuffer aTraceStr(RTL_CONSTASCII_STRINGPARAM("Config::WriteKey( "));
     869             :     aTraceStr.append(rKey);
     870             :     aTraceStr.append(RTL_CONSTASCII_STRINGPARAM(", "));
     871             :     aTraceStr.append(rStr);
     872             :     aTraceStr.append(RTL_CONSTASCII_STRINGPARAM(" ) to "));
     873             :     aTraceStr.append(GetGroup());
     874             :     aTraceStr.append(RTL_CONSTASCII_STRINGPARAM(" in "));
     875             :     aTraceStr.append(rtl::OUStringToOString(maFileName, RTL_TEXTENCODING_UTF8));
     876             :     OSL_TRACE("%s", aTraceStr.getStr());
     877             : #endif
     878             : 
     879             :     // Update config data if necessary
     880           0 :     if ( !mnLockCount || !mpData->mbRead )
     881             :     {
     882           0 :         ImplUpdateConfig();
     883           0 :         mpData->mbRead = sal_True;
     884             :     }
     885             : 
     886             :     // Search key and update value if found
     887           0 :     ImplGroupData* pGroup = ImplGetGroup();
     888           0 :     if ( pGroup )
     889             :     {
     890           0 :         ImplKeyData* pPrevKey = NULL;
     891           0 :         ImplKeyData* pKey = pGroup->mpFirstKey;
     892           0 :         while ( pKey )
     893             :         {
     894           0 :             if ( !pKey->mbIsComment && pKey->maKey.equalsIgnoreAsciiCase(rKey) )
     895           0 :                 break;
     896             : 
     897           0 :             pPrevKey = pKey;
     898           0 :             pKey = pKey->mpNext;
     899             :         }
     900             : 
     901             :         sal_Bool bNewValue;
     902           0 :         if ( !pKey )
     903             :         {
     904           0 :             pKey              = new ImplKeyData;
     905           0 :             pKey->mpNext      = NULL;
     906           0 :             pKey->maKey       = rKey;
     907           0 :             pKey->mbIsComment = sal_False;
     908           0 :             if ( pPrevKey )
     909           0 :                 pPrevKey->mpNext = pKey;
     910             :             else
     911           0 :                 pGroup->mpFirstKey = pKey;
     912           0 :             bNewValue = sal_True;
     913             :         }
     914             :         else
     915           0 :             bNewValue = pKey->maValue != rStr;
     916             : 
     917           0 :         if ( bNewValue )
     918             :         {
     919           0 :             pKey->maValue = rStr;
     920             : 
     921           0 :             if ( !mnLockCount && mbPersistence )
     922           0 :                 ImplWriteConfig( mpData );
     923             :             else
     924             :             {
     925           0 :                 mpData->mbModified = sal_True;
     926             :             }
     927             :         }
     928             :     }
     929           0 : }
     930             : 
     931           0 : void Config::DeleteKey(const rtl::OString& rKey)
     932             : {
     933             :     // Update config data if necessary
     934           0 :     if ( !mnLockCount || !mpData->mbRead )
     935             :     {
     936           0 :         ImplUpdateConfig();
     937           0 :         mpData->mbRead = sal_True;
     938             :     }
     939             : 
     940             :     // Search key and update value
     941           0 :     ImplGroupData* pGroup = ImplGetGroup();
     942           0 :     if ( pGroup )
     943             :     {
     944           0 :         ImplKeyData* pPrevKey = NULL;
     945           0 :         ImplKeyData* pKey = pGroup->mpFirstKey;
     946           0 :         while ( pKey )
     947             :         {
     948           0 :             if ( !pKey->mbIsComment && pKey->maKey.equalsIgnoreAsciiCase(rKey) )
     949           0 :                 break;
     950             : 
     951           0 :             pPrevKey = pKey;
     952           0 :             pKey = pKey->mpNext;
     953             :         }
     954             : 
     955           0 :         if ( pKey )
     956             :         {
     957             :             // Rewire group pointers and delete
     958           0 :             if ( pPrevKey )
     959           0 :                 pPrevKey->mpNext = pKey->mpNext;
     960             :             else
     961           0 :                 pGroup->mpFirstKey = pKey->mpNext;
     962           0 :             delete pKey;
     963             : 
     964             :             // Rewrite config file
     965           0 :             if ( !mnLockCount && mbPersistence )
     966           0 :                 ImplWriteConfig( mpData );
     967             :             else
     968             :             {
     969           0 :                 mpData->mbModified = sal_True;
     970             :             }
     971             :         }
     972             :     }
     973           0 : }
     974             : 
     975           0 : sal_uInt16 Config::GetKeyCount() const
     976             : {
     977             : #ifdef DBG_UTIL
     978             :     rtl::OStringBuffer aTraceStr(
     979             :         RTL_CONSTASCII_STRINGPARAM("Config::GetKeyCount()"));
     980             :     aTraceStr.append(RTL_CONSTASCII_STRINGPARAM(" from "));
     981             :     aTraceStr.append(GetGroup());
     982             :     aTraceStr.append(RTL_CONSTASCII_STRINGPARAM(" in "));
     983             :     aTraceStr.append(rtl::OUStringToOString(maFileName, RTL_TEXTENCODING_UTF8));
     984             :     OSL_TRACE("%s", aTraceStr.getStr());
     985             : #endif
     986             : 
     987             :     // Update config data if necessary
     988           0 :     if ( !mnLockCount )
     989           0 :         ImplUpdateConfig();
     990             : 
     991             :     // Search key and update value
     992           0 :     sal_uInt16 nCount = 0;
     993           0 :     ImplGroupData* pGroup = ImplGetGroup();
     994           0 :     if ( pGroup )
     995             :     {
     996           0 :         ImplKeyData* pKey = pGroup->mpFirstKey;
     997           0 :         while ( pKey )
     998             :         {
     999           0 :             if ( !pKey->mbIsComment )
    1000           0 :                 nCount++;
    1001             : 
    1002           0 :             pKey = pKey->mpNext;
    1003             :         }
    1004             :     }
    1005             : 
    1006           0 :     return nCount;
    1007             : }
    1008             : 
    1009           0 : rtl::OString Config::GetKeyName(sal_uInt16 nKey) const
    1010             : {
    1011             : #ifdef DBG_UTIL
    1012             :     rtl::OStringBuffer aTraceStr(
    1013             :         RTL_CONSTASCII_STRINGPARAM("Config::GetKeyName( "));
    1014             :     aTraceStr.append(static_cast<sal_Int32>(nKey));
    1015             :     aTraceStr.append(RTL_CONSTASCII_STRINGPARAM(" ) from "));
    1016             :     aTraceStr.append(GetGroup());
    1017             :     aTraceStr.append(RTL_CONSTASCII_STRINGPARAM(" in "));
    1018             :     aTraceStr.append(rtl::OUStringToOString(
    1019             :         maFileName, RTL_TEXTENCODING_UTF8));
    1020             :     OSL_TRACE("%s", aTraceStr.getStr());
    1021             : #endif
    1022             : 
    1023             :     // search key and return name if found
    1024           0 :     ImplGroupData* pGroup = ImplGetGroup();
    1025           0 :     if ( pGroup )
    1026             :     {
    1027           0 :         ImplKeyData* pKey = pGroup->mpFirstKey;
    1028           0 :         while ( pKey )
    1029             :         {
    1030           0 :             if ( !pKey->mbIsComment )
    1031             :             {
    1032           0 :                 if ( !nKey )
    1033           0 :                     return pKey->maKey;
    1034           0 :                 nKey--;
    1035             :             }
    1036             : 
    1037           0 :             pKey = pKey->mpNext;
    1038             :         }
    1039             :     }
    1040             : 
    1041           0 :     return rtl::OString();
    1042             : }
    1043             : 
    1044           0 : rtl::OString Config::ReadKey(sal_uInt16 nKey) const
    1045             : {
    1046             : #ifdef DBG_UTIL
    1047             :     rtl::OStringBuffer aTraceStr(
    1048             :         RTL_CONSTASCII_STRINGPARAM("Config::ReadKey( "));
    1049             :     aTraceStr.append(static_cast<sal_Int32>(nKey));
    1050             :     aTraceStr.append(RTL_CONSTASCII_STRINGPARAM(" ) from "));
    1051             :     aTraceStr.append(GetGroup());
    1052             :     aTraceStr.append(RTL_CONSTASCII_STRINGPARAM(" in "));
    1053             :     aTraceStr.append(rtl::OUStringToOString(maFileName,
    1054             :         RTL_TEXTENCODING_UTF8));
    1055             :     OSL_TRACE("%s", aTraceStr.getStr());
    1056             : #endif
    1057             : 
    1058             :     // Search key and return value if found
    1059           0 :     ImplGroupData* pGroup = ImplGetGroup();
    1060           0 :     if ( pGroup )
    1061             :     {
    1062           0 :         ImplKeyData* pKey = pGroup->mpFirstKey;
    1063           0 :         while ( pKey )
    1064             :         {
    1065           0 :             if ( !pKey->mbIsComment )
    1066             :             {
    1067           0 :                 if ( !nKey )
    1068           0 :                     return pKey->maValue;
    1069           0 :                 nKey--;
    1070             :             }
    1071             : 
    1072           0 :             pKey = pKey->mpNext;
    1073             :         }
    1074             :     }
    1075             : 
    1076           0 :     return rtl::OString();
    1077             : }
    1078             : 
    1079           0 : void Config::Flush()
    1080             : {
    1081           0 :     if ( mpData->mbModified && mbPersistence )
    1082           0 :         ImplWriteConfig( mpData );
    1083           0 : }
    1084             : 
    1085             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10