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

Generated by: LCOV version 1.11