LCOV - code coverage report
Current view: top level - package/source/zippackage - ZipPackageFolder.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 158 210 75.2 %
Date: 2015-06-13 12:38:46 Functions: 19 26 73.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 <string.h>
      21             : 
      22             : #include <ZipPackageFolder.hxx>
      23             : #include <ZipFile.hxx>
      24             : #include <ZipOutputStream.hxx>
      25             : #include <ZipPackageStream.hxx>
      26             : #include <PackageConstants.hxx>
      27             : #include <ZipPackageFolderEnumeration.hxx>
      28             : #include <com/sun/star/packages/zip/ZipConstants.hpp>
      29             : #include <com/sun/star/embed/StorageFormats.hpp>
      30             : #include <cppuhelper/supportsservice.hxx>
      31             : #include <cppuhelper/typeprovider.hxx>
      32             : #include <osl/diagnose.h>
      33             : #include <osl/time.h>
      34             : #include <rtl/digest.h>
      35             : #include <ContentInfo.hxx>
      36             : #include <com/sun/star/beans/PropertyValue.hpp>
      37             : #include <EncryptedDataHeader.hxx>
      38             : #include <rtl/instance.hxx>
      39             : #include <boost/scoped_ptr.hpp>
      40             : 
      41             : using namespace com::sun::star;
      42             : using namespace com::sun::star::packages::zip::ZipConstants;
      43             : using namespace com::sun::star::packages::zip;
      44             : using namespace com::sun::star::packages;
      45             : using namespace com::sun::star::container;
      46             : using namespace com::sun::star::beans;
      47             : using namespace com::sun::star::lang;
      48             : using namespace com::sun::star::io;
      49             : using namespace cppu;
      50             : 
      51             : #if OSL_DEBUG_LEVEL > 0
      52             : #define THROW_WHERE SAL_WHERE
      53             : #else
      54             : #define THROW_WHERE ""
      55             : #endif
      56             : 
      57             : namespace { struct lcl_CachedImplId : public rtl::Static< cppu::OImplementationId, lcl_CachedImplId > {}; }
      58             : 
      59      145093 : ZipPackageFolder::ZipPackageFolder( const css::uno::Reference < css::uno::XComponentContext >& xContext,
      60             :                                     sal_Int32 nFormat,
      61      145093 :                                     bool bAllowRemoveOnInsert )
      62             : {
      63      145093 :     m_xContext = xContext;
      64      145093 :     m_nFormat = nFormat;
      65      145093 :     mbAllowRemoveOnInsert = bAllowRemoveOnInsert;
      66      145093 :     SetFolder ( true );
      67      145093 :     aEntry.nVersion     = -1;
      68      145093 :     aEntry.nFlag        = 0;
      69      145093 :     aEntry.nMethod      = STORED;
      70      145093 :     aEntry.nTime        = -1;
      71      145093 :     aEntry.nCrc         = 0;
      72      145093 :     aEntry.nCompressedSize = 0;
      73      145093 :     aEntry.nSize        = 0;
      74      145093 :     aEntry.nOffset      = -1;
      75      145093 : }
      76             : 
      77      289790 : ZipPackageFolder::~ZipPackageFolder()
      78             : {
      79      289790 : }
      80             : 
      81       12592 : bool ZipPackageFolder::LookForUnexpectedODF12Streams( const OUString& aPath )
      82             : {
      83       12592 :     bool bHasUnexpected = false;
      84             : 
      85       63404 :     for ( ContentHash::const_iterator aCI = maContents.begin(), aEnd = maContents.end();
      86       31702 :           !bHasUnexpected && aCI != aEnd;
      87             :           ++aCI)
      88             :     {
      89       19110 :         const OUString &rShortName = (*aCI).first;
      90       19110 :         const ContentInfo &rInfo = *(*aCI).second;
      91             : 
      92       19110 :         if ( rInfo.bFolder )
      93             :         {
      94       11538 :             if ( aPath == "META-INF/" )
      95             :             {
      96             :                 // META-INF is not allowed to contain subfolders
      97           0 :                 bHasUnexpected = true;
      98             :             }
      99             :             else
     100             :             {
     101       11538 :                 OUString sOwnPath = aPath + rShortName + "/";
     102       11538 :                 bHasUnexpected = rInfo.pFolder->LookForUnexpectedODF12Streams( sOwnPath );
     103             :             }
     104             :         }
     105             :         else
     106             :         {
     107        7572 :             if ( aPath == "META-INF/" )
     108             :             {
     109           0 :                 if ( rShortName != "manifest.xml"
     110           0 :                   && rShortName.indexOf( "signatures" ) == -1 )
     111             :                 {
     112             :                     // a stream from META-INF with unexpected name
     113           0 :                     bHasUnexpected = true;
     114             :                 }
     115             : 
     116             :                 // streams from META-INF with expected names are allowed not to be registered in manifest.xml
     117             :             }
     118        7572 :             else if ( !rInfo.pStream->IsFromManifest() )
     119             :             {
     120             :                 // the stream is not in META-INF and is not registered in manifest.xml,
     121             :                 // check whether it is an internal part of the package format
     122           6 :                 if ( !aPath.isEmpty() || rShortName != "mimetype" )
     123             :                 {
     124             :                     // if it is not "mimetype" from the root it is not a part of the package
     125           6 :                     bHasUnexpected = true;
     126             :                 }
     127             :             }
     128             :         }
     129             :     }
     130             : 
     131       12592 :     return bHasUnexpected;
     132             : }
     133             : 
     134       52377 : void ZipPackageFolder::setChildStreamsTypeByExtension( const beans::StringPair& aPair )
     135             : {
     136       52377 :     OUString aExt;
     137       52377 :     if ( aPair.First.toChar() == (sal_Unicode)'.' )
     138           0 :         aExt = aPair.First;
     139             :     else
     140       52377 :         aExt = "." + aPair.First;
     141             : 
     142      259384 :     for ( ContentHash::const_iterator aCI = maContents.begin(), aEnd = maContents.end();
     143             :           aCI != aEnd;
     144             :           ++aCI)
     145             :     {
     146      207007 :         const OUString &rShortName = (*aCI).first;
     147      207007 :         const ContentInfo &rInfo = *(*aCI).second;
     148             : 
     149      207007 :         if ( rInfo.bFolder )
     150       45294 :             rInfo.pFolder->setChildStreamsTypeByExtension( aPair );
     151             :         else
     152             :         {
     153      161713 :             sal_Int32 nPathLength = rShortName.getLength();
     154      161713 :             sal_Int32 nExtLength = aExt.getLength();
     155      161713 :             if ( nPathLength >= nExtLength && rShortName.match( aExt, nPathLength - nExtLength ) )
     156       59846 :                 rInfo.pStream->SetMediaType( aPair.Second );
     157             :         }
     158       52377 :     }
     159       52377 : }
     160             : 
     161       21185 : void ZipPackageFolder::copyZipEntry( ZipEntry &rDest, const ZipEntry &rSource)
     162             : {
     163       21185 :       rDest.nVersion            = rSource.nVersion;
     164       21185 :     rDest.nFlag             = rSource.nFlag;
     165       21185 :     rDest.nMethod           = rSource.nMethod;
     166       21185 :     rDest.nTime             = rSource.nTime;
     167       21185 :     rDest.nCrc              = rSource.nCrc;
     168       21185 :     rDest.nCompressedSize   = rSource.nCompressedSize;
     169       21185 :     rDest.nSize             = rSource.nSize;
     170       21185 :     rDest.nOffset           = rSource.nOffset;
     171       21185 :     rDest.sPath             = rSource.sPath;
     172       21185 :     rDest.nPathLen          = rSource.nPathLen;
     173       21185 :     rDest.nExtraLen         = rSource.nExtraLen;
     174       21185 : }
     175             : 
     176       69330 : ::com::sun::star::uno::Sequence < sal_Int8 > ZipPackageFolder::static_getImplementationId()
     177             : {
     178       69330 :     return lcl_CachedImplId::get().getImplementationId();
     179             : }
     180             : 
     181             :     // XNameContainer
     182       17250 : void SAL_CALL ZipPackageFolder::insertByName( const OUString& aName, const uno::Any& aElement )
     183             :         throw(IllegalArgumentException, ElementExistException, WrappedTargetException, uno::RuntimeException, std::exception)
     184             : {
     185       17250 :     if (hasByName(aName))
     186           0 :         throw ElementExistException(THROW_WHERE );
     187             :     else
     188             :     {
     189       17250 :         uno::Reference < XUnoTunnel > xRef;
     190       17250 :         aElement >>= xRef;
     191       17250 :         if ( (  aElement >>= xRef ) )
     192             :         {
     193             :             sal_Int64 nTest;
     194             :             ZipPackageEntry *pEntry;
     195       17250 :             if ( ( nTest = xRef->getSomething ( ZipPackageFolder::static_getImplementationId() ) ) != 0 )
     196             :             {
     197        4804 :                 ZipPackageFolder *pFolder = reinterpret_cast < ZipPackageFolder * > ( nTest );
     198        4804 :                 pEntry = static_cast < ZipPackageEntry * > ( pFolder );
     199             :             }
     200       12446 :             else if ( ( nTest = xRef->getSomething ( ZipPackageStream::static_getImplementationId() ) ) != 0 )
     201             :             {
     202       12446 :                 ZipPackageStream *pStream = reinterpret_cast < ZipPackageStream * > ( nTest );
     203       12446 :                 pEntry = static_cast < ZipPackageEntry * > ( pStream );
     204             :             }
     205             :             else
     206           0 :                 throw IllegalArgumentException(THROW_WHERE, uno::Reference< uno::XInterface >(), 0 );
     207             : 
     208       17250 :             if (pEntry->getName() != aName )
     209       17242 :                 pEntry->setName (aName);
     210       17250 :             doInsertByName ( pEntry, true );
     211             :         }
     212             :         else
     213           0 :             throw IllegalArgumentException(THROW_WHERE, uno::Reference< uno::XInterface >(), 0 );
     214             :     }
     215       17250 : }
     216        7832 : void SAL_CALL ZipPackageFolder::removeByName( const OUString& Name )
     217             :         throw(NoSuchElementException, WrappedTargetException, uno::RuntimeException, std::exception)
     218             : {
     219        7832 :     ContentHash::iterator aIter = maContents.find ( Name );
     220        7832 :     if ( aIter == maContents.end() )
     221           0 :         throw NoSuchElementException(THROW_WHERE );
     222        7832 :     maContents.erase( aIter );
     223        7832 : }
     224             :     // XEnumerationAccess
     225       63304 : uno::Reference< XEnumeration > SAL_CALL ZipPackageFolder::createEnumeration(  )
     226             :         throw(uno::RuntimeException, std::exception)
     227             : {
     228       63304 :     return uno::Reference < XEnumeration> (new ZipPackageFolderEnumeration(maContents));
     229             : }
     230             :     // XElementAccess
     231           0 : uno::Type SAL_CALL ZipPackageFolder::getElementType(  )
     232             :         throw(uno::RuntimeException, std::exception)
     233             : {
     234           0 :     return cppu::UnoType<XUnoTunnel>::get();
     235             : }
     236           0 : sal_Bool SAL_CALL ZipPackageFolder::hasElements(  )
     237             :         throw(uno::RuntimeException, std::exception)
     238             : {
     239           0 :     return maContents.size() > 0;
     240             : }
     241             :     // XNameAccess
     242      186861 : ContentInfo& ZipPackageFolder::doGetByName( const OUString& aName )
     243             :     throw(NoSuchElementException, WrappedTargetException, uno::RuntimeException)
     244             : {
     245      186861 :     ContentHash::iterator aIter = maContents.find ( aName );
     246      186861 :     if ( aIter == maContents.end())
     247           0 :         throw NoSuchElementException(THROW_WHERE );
     248      186861 :     return *(*aIter).second;
     249             : }
     250      142935 : uno::Any SAL_CALL ZipPackageFolder::getByName( const OUString& aName )
     251             :     throw(NoSuchElementException, WrappedTargetException, uno::RuntimeException, std::exception)
     252             : {
     253      142935 :     return uno::makeAny ( doGetByName ( aName ).xTunnel );
     254             : }
     255           0 : uno::Sequence< OUString > SAL_CALL ZipPackageFolder::getElementNames(  )
     256             :         throw(uno::RuntimeException, std::exception)
     257             : {
     258           0 :     sal_uInt32 i=0, nSize = maContents.size();
     259           0 :     uno::Sequence < OUString > aSequence ( nSize );
     260           0 :     for ( ContentHash::const_iterator aIterator = maContents.begin(), aEnd = maContents.end();
     261             :           aIterator != aEnd;
     262             :           ++i, ++aIterator)
     263           0 :         aSequence[i] = (*aIterator).first;
     264           0 :     return aSequence;
     265             : }
     266      605435 : sal_Bool SAL_CALL ZipPackageFolder::hasByName( const OUString& aName )
     267             :     throw(uno::RuntimeException, std::exception)
     268             : {
     269      605435 :     return maContents.find ( aName ) != maContents.end ();
     270             : }
     271             :     // XNameReplace
     272           0 : void SAL_CALL ZipPackageFolder::replaceByName( const OUString& aName, const uno::Any& aElement )
     273             :         throw(IllegalArgumentException, NoSuchElementException, WrappedTargetException, uno::RuntimeException, std::exception)
     274             : {
     275           0 :     if ( hasByName( aName ) )
     276           0 :         removeByName( aName );
     277             :     else
     278           0 :         throw NoSuchElementException(THROW_WHERE );
     279           0 :     insertByName(aName, aElement);
     280           0 : }
     281             : 
     282        4859 : bool ZipPackageFolder::saveChild(
     283             :         const OUString &rPath,
     284             :         std::vector < uno::Sequence < PropertyValue > > &rManList,
     285             :         ZipOutputStream & rZipOut,
     286             :         const uno::Sequence < sal_Int8 >& rEncryptionKey,
     287             :         const rtlRandomPool &rRandomPool)
     288             : {
     289        4859 :     bool bSuccess = true;
     290             : 
     291        4859 :     const OUString sMediaTypeProperty ("MediaType");
     292        9718 :     const OUString sVersionProperty ("Version");
     293        9718 :     const OUString sFullPathProperty ("FullPath");
     294             : 
     295        9718 :     uno::Sequence < PropertyValue > aPropSet (PKG_SIZE_NOENCR_MNFST);
     296        9718 :     OUString sTempName = rPath + "/";
     297             : 
     298        4859 :     if ( !GetMediaType().isEmpty() )
     299             :     {
     300         124 :         aPropSet[PKG_MNFST_MEDIATYPE].Name = sMediaTypeProperty;
     301         124 :         aPropSet[PKG_MNFST_MEDIATYPE].Value <<= GetMediaType();
     302         124 :         aPropSet[PKG_MNFST_VERSION].Name = sVersionProperty;
     303         124 :         aPropSet[PKG_MNFST_VERSION].Value <<= GetVersion();
     304         124 :         aPropSet[PKG_MNFST_FULLPATH].Name = sFullPathProperty;
     305         124 :         aPropSet[PKG_MNFST_FULLPATH].Value <<= sTempName;
     306             :     }
     307             :     else
     308        4735 :         aPropSet.realloc( 0 );
     309             : 
     310        4859 :     saveContents( sTempName, rManList, rZipOut, rEncryptionKey, rRandomPool);
     311             : 
     312             :     // folder can have a mediatype only in package format
     313        4859 :     if ( aPropSet.getLength() && ( m_nFormat == embed::StorageFormats::PACKAGE ) )
     314         124 :         rManList.push_back( aPropSet );
     315             : 
     316        9718 :     return bSuccess;
     317             : }
     318             : 
     319        5691 : void ZipPackageFolder::saveContents(
     320             :         const OUString &rPath,
     321             :         std::vector < uno::Sequence < PropertyValue > > &rManList,
     322             :         ZipOutputStream & rZipOut,
     323             :         const uno::Sequence < sal_Int8 >& rEncryptionKey,
     324             :         const rtlRandomPool &rRandomPool ) const
     325             :     throw( uno::RuntimeException )
     326             : {
     327        5691 :     bool bWritingFailed = false;
     328             : 
     329        5691 :     if ( maContents.begin() == maContents.end() && !rPath.isEmpty() && m_nFormat != embed::StorageFormats::OFOPXML )
     330             :     {
     331             :         // it is an empty subfolder, use workaround to store it
     332         851 :         ZipEntry* pTempEntry = new ZipEntry();
     333         851 :         ZipPackageFolder::copyZipEntry ( *pTempEntry, aEntry );
     334         851 :         pTempEntry->nPathLen = (sal_Int16)( OUStringToOString( rPath, RTL_TEXTENCODING_UTF8 ).getLength() );
     335         851 :         pTempEntry->nExtraLen = -1;
     336         851 :         pTempEntry->sPath = rPath;
     337             : 
     338             :         try
     339             :         {
     340         851 :             ZipOutputStream::setEntry(pTempEntry);
     341         851 :             rZipOut.writeLOC(pTempEntry);
     342         851 :             rZipOut.rawCloseEntry();
     343             :         }
     344           0 :         catch ( ZipException& )
     345             :         {
     346           0 :             bWritingFailed = true;
     347             :         }
     348           0 :         catch ( IOException& )
     349             :         {
     350           0 :             bWritingFailed = true;
     351             :         }
     352             :     }
     353             : 
     354        5691 :     bool bMimeTypeStreamStored = false;
     355        5691 :     OUString aMimeTypeStreamName("mimetype");
     356        5691 :     if ( m_nFormat == embed::StorageFormats::ZIP && rPath.isEmpty() )
     357             :     {
     358             :         // let the "mimetype" stream in root folder be stored as the first stream if it is zip format
     359           0 :         ContentHash::const_iterator aIter = maContents.find ( aMimeTypeStreamName );
     360           0 :         if ( aIter != maContents.end() && !(*aIter).second->bFolder )
     361             :         {
     362           0 :             bMimeTypeStreamStored = true;
     363           0 :             bWritingFailed = !aIter->second->pStream->saveChild(
     364           0 :                 rPath + aIter->first, rManList, rZipOut, rEncryptionKey, rRandomPool );
     365             :         }
     366             :     }
     367             : 
     368       20717 :     for ( ContentHash::const_iterator aCI = maContents.begin(), aEnd = maContents.end();
     369             :           aCI != aEnd;
     370             :           ++aCI)
     371             :     {
     372       15026 :         const OUString &rShortName = (*aCI).first;
     373       15026 :         const ContentInfo &rInfo = *(*aCI).second;
     374             : 
     375       15026 :         if ( !bMimeTypeStreamStored || !rShortName.equals( aMimeTypeStreamName ) )
     376             :         {
     377       15026 :             if (rInfo.bFolder)
     378             :             {
     379             :                 bWritingFailed = !rInfo.pFolder->saveChild(
     380        4859 :                     rPath + rShortName, rManList, rZipOut, rEncryptionKey, rRandomPool );
     381             :             }
     382             :             else
     383             :             {
     384             :                 bWritingFailed = !rInfo.pStream->saveChild(
     385       10167 :                     rPath + rShortName, rManList, rZipOut, rEncryptionKey, rRandomPool );
     386             :             }
     387             :         }
     388             :     }
     389             : 
     390        5691 :     if( bWritingFailed )
     391           0 :         throw uno::RuntimeException(THROW_WHERE );
     392        5691 : }
     393             : 
     394       24644 : sal_Int64 SAL_CALL ZipPackageFolder::getSomething( const uno::Sequence< sal_Int8 >& aIdentifier )
     395             :     throw(uno::RuntimeException, std::exception)
     396             : {
     397       24644 :     sal_Int64 nMe = 0;
     398       98576 :     if ( aIdentifier.getLength() == 16 &&
     399       98576 :          0 == memcmp(static_getImplementationId().getConstArray(),  aIdentifier.getConstArray(), 16 ) )
     400       24644 :         nMe = reinterpret_cast < sal_Int64 > ( this );
     401       24644 :     return nMe;
     402             : }
     403        5498 : void SAL_CALL ZipPackageFolder::setPropertyValue( const OUString& aPropertyName, const uno::Any& aValue )
     404             :         throw(UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, uno::RuntimeException, std::exception)
     405             : {
     406        5498 :     if ( aPropertyName == "MediaType" )
     407             :     {
     408             :         // TODO/LATER: activate when zip ucp is ready
     409             :         // if ( m_nFormat != embed::StorageFormats::PACKAGE )
     410             :         //  throw UnknownPropertyException(THROW_WHERE );
     411             : 
     412        2749 :         aValue >>= msMediaType;
     413             :     }
     414        2749 :     else if ( aPropertyName == "Version" )
     415        2749 :         aValue >>= m_sVersion;
     416           0 :     else if ( aPropertyName == "Size" )
     417           0 :         aValue >>= aEntry.nSize;
     418             :     else
     419           0 :         throw UnknownPropertyException(THROW_WHERE );
     420        5498 : }
     421       75821 : uno::Any SAL_CALL ZipPackageFolder::getPropertyValue( const OUString& PropertyName )
     422             :         throw(UnknownPropertyException, WrappedTargetException, uno::RuntimeException, std::exception)
     423             : {
     424       75821 :     if ( PropertyName == "MediaType" )
     425             :     {
     426             :         // TODO/LATER: activate when zip ucp is ready
     427             :         // if ( m_nFormat != embed::StorageFormats::PACKAGE )
     428             :         //  throw UnknownPropertyException(THROW_WHERE );
     429             : 
     430       37880 :         return uno::makeAny ( msMediaType );
     431             :     }
     432       37941 :     else if ( PropertyName == "Version" )
     433       37941 :         return uno::makeAny( m_sVersion );
     434           0 :     else if ( PropertyName == "Size" )
     435           0 :         return uno::makeAny ( aEntry.nSize );
     436             :     else
     437           0 :         throw UnknownPropertyException(THROW_WHERE );
     438             : }
     439             : 
     440      306949 : void ZipPackageFolder::doInsertByName ( ZipPackageEntry *pEntry, bool bSetParent )
     441             :         throw(IllegalArgumentException, ElementExistException, WrappedTargetException, uno::RuntimeException)
     442             : {
     443             :     try
     444             :     {
     445      306949 :         if ( pEntry->IsFolder() )
     446       82958 :             maContents[pEntry->getName()] = new ContentInfo ( static_cast < ZipPackageFolder *> ( pEntry ) );
     447             :         else
     448      223991 :             maContents[pEntry->getName()] = new ContentInfo ( static_cast < ZipPackageStream *> ( pEntry ) );
     449             :     }
     450           0 :     catch(const uno::Exception& rEx)
     451             :     {
     452             :         (void)rEx;
     453           0 :         throw;
     454             :     }
     455      306949 :     if ( bSetParent )
     456       17250 :         pEntry->setParent ( *this );
     457      306949 : }
     458           0 : OUString ZipPackageFolder::getImplementationName()
     459             :     throw (uno::RuntimeException, std::exception)
     460             : {
     461           0 :     return OUString("ZipPackageFolder");
     462             : }
     463             : 
     464           0 : uno::Sequence< OUString > ZipPackageFolder::getSupportedServiceNames()
     465             :     throw (uno::RuntimeException, std::exception)
     466             : {
     467           0 :     uno::Sequence< OUString > aNames(1);
     468           0 :     aNames[0] = "com.sun.star.packages.PackageFolder";
     469           0 :     return aNames;
     470             : }
     471             : 
     472           0 : sal_Bool SAL_CALL ZipPackageFolder::supportsService( OUString const & rServiceName )
     473             :     throw (uno::RuntimeException, std::exception)
     474             : {
     475           0 :     return cppu::supportsService(this, rServiceName);
     476             : }
     477             : 
     478             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11