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

Generated by: LCOV version 1.10