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

Generated by: LCOV version 1.10