LCOV - code coverage report
Current view: top level - libreoffice/package/source/zipapi - ZipOutputStream.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 207 229 90.4 %
Date: 2012-12-27 Functions: 16 17 94.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             : 
      21             : #include <com/sun/star/packages/zip/ZipConstants.hpp>
      22             : #include <com/sun/star/io/XOutputStream.hpp>
      23             : #include <comphelper/storagehelper.hxx>
      24             : 
      25             : #include <osl/time.h>
      26             : 
      27             : #include <EncryptionData.hxx>
      28             : #include <PackageConstants.hxx>
      29             : #include <ZipEntry.hxx>
      30             : #include <ZipFile.hxx>
      31             : #include <ZipPackageStream.hxx>
      32             : #include <ZipOutputStream.hxx>
      33             : 
      34             : using namespace com::sun::star;
      35             : using namespace com::sun::star::io;
      36             : using namespace com::sun::star::uno;
      37             : using namespace com::sun::star::packages;
      38             : using namespace com::sun::star::packages::zip;
      39             : using namespace com::sun::star::packages::zip::ZipConstants;
      40             : 
      41             : /** This class is used to write Zip files
      42             :  */
      43          33 : ZipOutputStream::ZipOutputStream( const uno::Reference< uno::XComponentContext >& rxContext,
      44             :                                   const uno::Reference < XOutputStream > &xOStream )
      45             : : m_xContext( rxContext )
      46             : , xStream(xOStream)
      47             : , m_aDeflateBuffer(n_ConstBufferSize)
      48             : , aDeflater(DEFAULT_COMPRESSION, sal_True)
      49             : , aChucker(xOStream)
      50             : , pCurrentEntry(NULL)
      51             : , nMethod(DEFLATED)
      52             : , bFinished(sal_False)
      53             : , bEncryptCurrentEntry(sal_False)
      54          33 : , m_pCurrentStream(NULL)
      55             : {
      56          33 : }
      57             : 
      58          66 : ZipOutputStream::~ZipOutputStream( void )
      59             : {
      60         333 :     for (sal_Int32 i = 0, nEnd = aZipList.size(); i < nEnd; i++)
      61         300 :         delete aZipList[i];
      62          33 : }
      63             : 
      64          33 : void SAL_CALL ZipOutputStream::setMethod( sal_Int32 nNewMethod )
      65             :     throw(RuntimeException)
      66             : {
      67          33 :     nMethod = static_cast < sal_Int16 > (nNewMethod);
      68          33 : }
      69          33 : void SAL_CALL ZipOutputStream::setLevel( sal_Int32 nNewLevel )
      70             :     throw(RuntimeException)
      71             : {
      72          33 :     aDeflater.setLevel( nNewLevel);
      73          33 : }
      74             : 
      75         300 : void SAL_CALL ZipOutputStream::putNextEntry( ZipEntry& rEntry,
      76             :                         ZipPackageStream* pStream,
      77             :                         sal_Bool bEncrypt)
      78             :     throw(IOException, RuntimeException)
      79             : {
      80         300 :     if (pCurrentEntry != NULL)
      81           0 :         closeEntry();
      82         300 :     if (rEntry.nTime == -1)
      83         259 :         rEntry.nTime = getCurrentDosTime();
      84         300 :     if (rEntry.nMethod == -1)
      85           0 :         rEntry.nMethod = nMethod;
      86         300 :     rEntry.nVersion = 20;
      87         300 :     rEntry.nFlag = 1 << 11;
      88         300 :     if (rEntry.nSize == -1 || rEntry.nCompressedSize == -1 ||
      89             :         rEntry.nCrc == -1)
      90             :     {
      91         263 :         rEntry.nSize = rEntry.nCompressedSize = 0;
      92         263 :         rEntry.nFlag |= 8;
      93             :     }
      94             : 
      95         300 :     if (bEncrypt)
      96             :     {
      97           4 :         bEncryptCurrentEntry = sal_True;
      98             : 
      99           4 :         m_xCipherContext = ZipFile::StaticGetCipher( m_xContext, pStream->GetEncryptionData(), true );
     100           4 :         m_xDigestContext = ZipFile::StaticGetDigestContextForChecksum( m_xContext, pStream->GetEncryptionData() );
     101           4 :         mnDigested = 0;
     102           4 :         rEntry.nFlag |= 1 << 4;
     103           4 :         m_pCurrentStream = pStream;
     104             :     }
     105         300 :     sal_Int32 nLOCLength = writeLOC(rEntry);
     106         300 :     rEntry.nOffset = aChucker.GetPosition() - nLOCLength;
     107         300 :     aZipList.push_back( &rEntry );
     108         300 :     pCurrentEntry = &rEntry;
     109         300 : }
     110             : 
     111         276 : void SAL_CALL ZipOutputStream::closeEntry(  )
     112             :     throw(IOException, RuntimeException)
     113             : {
     114         276 :     ZipEntry *pEntry = pCurrentEntry;
     115         276 :     if (pEntry)
     116             :     {
     117         276 :         switch (pEntry->nMethod)
     118             :         {
     119             :             case DEFLATED:
     120         263 :                 aDeflater.finish();
     121         789 :                 while (!aDeflater.finished())
     122         263 :                     doDeflate();
     123         263 :                 if ((pEntry->nFlag & 8) == 0)
     124             :                 {
     125           0 :                     if (pEntry->nSize != aDeflater.getTotalIn())
     126             :                     {
     127             :                         OSL_FAIL("Invalid entry size");
     128             :                     }
     129           0 :                     if (pEntry->nCompressedSize != aDeflater.getTotalOut())
     130             :                     {
     131             :                         // Different compression strategies make the merit of this
     132             :                         // test somewhat dubious
     133           0 :                         pEntry->nCompressedSize = aDeflater.getTotalOut();
     134             :                     }
     135           0 :                     if (pEntry->nCrc != aCRC.getValue())
     136             :                     {
     137             :                         OSL_FAIL("Invalid entry CRC-32");
     138             :                     }
     139             :                 }
     140             :                 else
     141             :                 {
     142         263 :                     if ( !bEncryptCurrentEntry )
     143             :                     {
     144         259 :                         pEntry->nSize = aDeflater.getTotalIn();
     145         259 :                         pEntry->nCompressedSize = aDeflater.getTotalOut();
     146             :                     }
     147         263 :                     pEntry->nCrc = aCRC.getValue();
     148         263 :                     writeEXT(*pEntry);
     149             :                 }
     150         263 :                 aDeflater.reset();
     151         263 :                 aCRC.reset();
     152         263 :                 break;
     153             :             case STORED:
     154          13 :                 if (!((pEntry->nFlag & 8) == 0))
     155             :                     OSL_FAIL( "Serious error, one of compressed size, size or CRC was -1 in a STORED stream");
     156          13 :                 break;
     157             :             default:
     158             :                 OSL_FAIL("Invalid compression method");
     159           0 :                 break;
     160             :         }
     161             : 
     162         276 :         if (bEncryptCurrentEntry)
     163             :         {
     164           4 :             bEncryptCurrentEntry = sal_False;
     165             : 
     166           4 :             m_xCipherContext.clear();
     167             : 
     168           4 :             uno::Sequence< sal_Int8 > aDigestSeq;
     169           4 :             if ( m_xDigestContext.is() )
     170             :             {
     171           4 :                 aDigestSeq = m_xDigestContext->finalizeDigestAndDispose();
     172           4 :                 m_xDigestContext.clear();
     173             :             }
     174             : 
     175           4 :             if ( m_pCurrentStream )
     176           4 :                 m_pCurrentStream->setDigest( aDigestSeq );
     177             :         }
     178         276 :         pCurrentEntry = NULL;
     179         276 :         m_pCurrentStream = NULL;
     180             :     }
     181         276 : }
     182             : 
     183         280 : void SAL_CALL ZipOutputStream::write( const Sequence< sal_Int8 >& rBuffer, sal_Int32 nNewOffset, sal_Int32 nNewLength )
     184             :     throw(IOException, RuntimeException)
     185             : {
     186         280 :     switch (pCurrentEntry->nMethod)
     187             :     {
     188             :         case DEFLATED:
     189         267 :             if (!aDeflater.finished())
     190             :             {
     191         267 :                 aDeflater.setInputSegment(rBuffer, nNewOffset, nNewLength);
     192         798 :                  while (!aDeflater.needsInput())
     193         264 :                     doDeflate();
     194         267 :                 if (!bEncryptCurrentEntry)
     195         263 :                     aCRC.updateSegment(rBuffer, nNewOffset, nNewLength);
     196             :             }
     197         267 :             break;
     198             :         case STORED:
     199             :             {
     200          13 :                 Sequence < sal_Int8 > aTmpBuffer ( rBuffer.getConstArray(), nNewLength );
     201          13 :                 aChucker.WriteBytes( aTmpBuffer );
     202             :             }
     203          13 :             break;
     204             :     }
     205         280 : }
     206             : 
     207           0 : void SAL_CALL ZipOutputStream::rawWrite( Sequence< sal_Int8 >& rBuffer, sal_Int32 /*nNewOffset*/, sal_Int32 nNewLength )
     208             :     throw(IOException, RuntimeException)
     209             : {
     210           0 :     Sequence < sal_Int8 > aTmpBuffer ( rBuffer.getConstArray(), nNewLength );
     211           0 :     aChucker.WriteBytes( aTmpBuffer );
     212           0 : }
     213             : 
     214          24 : void SAL_CALL ZipOutputStream::rawCloseEntry(  )
     215             :     throw(IOException, RuntimeException)
     216             : {
     217          24 :     if ( pCurrentEntry->nMethod == DEFLATED && ( pCurrentEntry->nFlag & 8 ) )
     218           0 :         writeEXT(*pCurrentEntry);
     219          24 :     pCurrentEntry = NULL;
     220          24 : }
     221             : 
     222          33 : void SAL_CALL ZipOutputStream::finish(  )
     223             :     throw(IOException, RuntimeException)
     224             : {
     225          33 :     if (bFinished)
     226          33 :         return;
     227             : 
     228          33 :     if (pCurrentEntry != NULL)
     229           0 :         closeEntry();
     230             : 
     231          33 :     if (aZipList.size() < 1)
     232             :         OSL_FAIL("Zip file must have at least one entry!\n");
     233             : 
     234          33 :     sal_Int32 nOffset= static_cast < sal_Int32 > (aChucker.GetPosition());
     235         333 :     for (sal_Int32 i =0, nEnd = aZipList.size(); i < nEnd; i++)
     236         300 :         writeCEN( *aZipList[i] );
     237          33 :     writeEND( nOffset, static_cast < sal_Int32 > (aChucker.GetPosition()) - nOffset);
     238          33 :     bFinished = sal_True;
     239          33 :     xStream->flush();
     240             : }
     241             : 
     242         527 : void ZipOutputStream::doDeflate()
     243             : {
     244         527 :     sal_Int32 nLength = aDeflater.doDeflateSegment(m_aDeflateBuffer, 0, m_aDeflateBuffer.getLength());
     245             : 
     246         527 :     if ( nLength > 0 )
     247             :     {
     248         264 :         uno::Sequence< sal_Int8 > aTmpBuffer( m_aDeflateBuffer.getConstArray(), nLength );
     249         264 :         if ( bEncryptCurrentEntry && m_xDigestContext.is() && m_xCipherContext.is() )
     250             :         {
     251             :             // Need to update our digest before encryption...
     252           4 :             sal_Int32 nDiff = n_ConstDigestLength - mnDigested;
     253           4 :             if ( nDiff )
     254             :             {
     255           4 :                 sal_Int32 nEat = ::std::min( nLength, nDiff );
     256           4 :                 uno::Sequence< sal_Int8 > aTmpSeq( aTmpBuffer.getConstArray(), nEat );
     257           4 :                 m_xDigestContext->updateDigest( aTmpSeq );
     258           4 :                 mnDigested = mnDigested + static_cast< sal_Int16 >( nEat );
     259             :             }
     260             : 
     261             :             // FIXME64: uno::Sequence not 64bit safe.
     262           4 :             uno::Sequence< sal_Int8 > aEncryptionBuffer = m_xCipherContext->convertWithCipherContext( aTmpBuffer );
     263             : 
     264           4 :             aChucker.WriteBytes( aEncryptionBuffer );
     265             : 
     266             :             // the sizes as well as checksum for encrypted streams is calculated here
     267           4 :             pCurrentEntry->nCompressedSize += aEncryptionBuffer.getLength();
     268           4 :             pCurrentEntry->nSize = pCurrentEntry->nCompressedSize;
     269           4 :             aCRC.update( aEncryptionBuffer );
     270             :         }
     271             :         else
     272             :         {
     273         260 :             aChucker.WriteBytes ( aTmpBuffer );
     274         264 :         }
     275             :     }
     276             : 
     277         527 :     if ( aDeflater.finished() && bEncryptCurrentEntry && m_xDigestContext.is() && m_xCipherContext.is() )
     278             :     {
     279             :         // FIXME64: sequence not 64bit safe.
     280           4 :         uno::Sequence< sal_Int8 > aEncryptionBuffer = m_xCipherContext->finalizeCipherContextAndDispose();
     281           4 :         if ( aEncryptionBuffer.getLength() )
     282             :         {
     283           4 :             aChucker.WriteBytes( aEncryptionBuffer );
     284             : 
     285             :             // the sizes as well as checksum for encrypted streams is calculated hier
     286           4 :             pCurrentEntry->nCompressedSize += aEncryptionBuffer.getLength();
     287           4 :             pCurrentEntry->nSize = pCurrentEntry->nCompressedSize;
     288           4 :             aCRC.update( aEncryptionBuffer );
     289           4 :         }
     290             :     }
     291         527 : }
     292             : 
     293          33 : void ZipOutputStream::writeEND(sal_uInt32 nOffset, sal_uInt32 nLength)
     294             :     throw(IOException, RuntimeException)
     295             : {
     296          33 :     aChucker << ENDSIG;
     297          33 :     aChucker << static_cast < sal_Int16 > ( 0 );
     298          33 :     aChucker << static_cast < sal_Int16 > ( 0 );
     299          33 :     aChucker << static_cast < sal_Int16 > ( aZipList.size() );
     300          33 :     aChucker << static_cast < sal_Int16 > ( aZipList.size() );
     301          33 :     aChucker << nLength;
     302          33 :     aChucker << nOffset;
     303          33 :     aChucker << static_cast < sal_Int16 > ( 0 );
     304          33 : }
     305             : 
     306        1500 : static sal_uInt32 getTruncated( sal_Int64 nNum, bool *pIsTruncated )
     307             : {
     308        1500 :     if( nNum >= 0xffffffff )
     309             :     {
     310           0 :         *pIsTruncated = true;
     311           0 :         return 0xffffffff;
     312             :     }
     313             :     else
     314        1500 :         return static_cast< sal_uInt32 >( nNum );
     315             : }
     316             : 
     317         300 : void ZipOutputStream::writeCEN( const ZipEntry &rEntry )
     318             :     throw(IOException, RuntimeException)
     319             : {
     320         300 :     if ( !::comphelper::OStorageHelper::IsValidZipEntryFileName( rEntry.sPath, sal_True ) )
     321           0 :         throw IOException("Unexpected character is used in file name.", uno::Reference< XInterface >() );
     322             : 
     323         300 :     ::rtl::OString sUTF8Name = ::rtl::OUStringToOString( rEntry.sPath, RTL_TEXTENCODING_UTF8 );
     324         300 :     sal_Int16 nNameLength       = static_cast < sal_Int16 > ( sUTF8Name.getLength() );
     325             : 
     326         300 :     aChucker << CENSIG;
     327         300 :     aChucker << rEntry.nVersion;
     328         300 :     aChucker << rEntry.nVersion;
     329         300 :     if (rEntry.nFlag & (1 << 4) )
     330             :     {
     331             :         // If it's an encrypted entry, we pretend its stored plain text
     332           4 :         ZipEntry *pEntry = const_cast < ZipEntry * > ( &rEntry );
     333           4 :         pEntry->nFlag &= ~(1 <<4 );
     334           4 :         aChucker << rEntry.nFlag;
     335           4 :         aChucker << static_cast < sal_Int16 > ( STORED );
     336             :     }
     337             :     else
     338             :     {
     339         296 :         aChucker << rEntry.nFlag;
     340         296 :         aChucker << rEntry.nMethod;
     341             :     }
     342         300 :     bool bWrite64Header = false;
     343             : 
     344         300 :     aChucker << static_cast < sal_uInt32> ( rEntry.nTime );
     345         300 :     aChucker << static_cast < sal_uInt32> ( rEntry.nCrc );
     346         300 :     aChucker << getTruncated( rEntry.nCompressedSize, &bWrite64Header );
     347         300 :     aChucker << getTruncated( rEntry.nSize, &bWrite64Header );
     348         300 :     aChucker << nNameLength;
     349         300 :     aChucker << static_cast < sal_Int16> (0);
     350         300 :     aChucker << static_cast < sal_Int16> (0);
     351         300 :     aChucker << static_cast < sal_Int16> (0);
     352         300 :     aChucker << static_cast < sal_Int16> (0);
     353         300 :     aChucker << static_cast < sal_Int32> (0);
     354         300 :     aChucker << getTruncated( rEntry.nOffset, &bWrite64Header );
     355             : 
     356         300 :     if( bWrite64Header )
     357             :     {
     358             :         // FIXME64: need to append a ZIP64 header instead of throwing
     359             :         // We're about to silently loose people's data - which they are
     360             :         // unlikely to appreciate so fail instead:
     361             :         throw IOException( "File contains streams that are too large.",
     362           0 :                            uno::Reference< XInterface >() );
     363             :     }
     364             : 
     365         300 :     Sequence < sal_Int8 > aSequence( (sal_Int8*)sUTF8Name.getStr(), sUTF8Name.getLength() );
     366         300 :     aChucker.WriteBytes( aSequence );
     367         300 : }
     368         263 : void ZipOutputStream::writeEXT( const ZipEntry &rEntry )
     369             :     throw(IOException, RuntimeException)
     370             : {
     371         263 :     bool bWrite64Header = false;
     372             : 
     373         263 :     aChucker << EXTSIG;
     374         263 :     aChucker << static_cast < sal_uInt32> ( rEntry.nCrc );
     375         263 :     aChucker << getTruncated( rEntry.nCompressedSize, &bWrite64Header );
     376         263 :     aChucker << getTruncated( rEntry.nSize, &bWrite64Header );
     377             : 
     378         263 :     if( bWrite64Header )
     379             :     {
     380             :         // FIXME64: need to append a ZIP64 header instead of throwing
     381             :         // We're about to silently loose people's data - which they are
     382             :         // unlikely to appreciate so fail instead:
     383             :         throw IOException( "File contains streams that are too large.",
     384           0 :                            uno::Reference< XInterface >() );
     385             :     }
     386         263 : }
     387             : 
     388         300 : sal_Int32 ZipOutputStream::writeLOC( const ZipEntry &rEntry )
     389             :     throw(IOException, RuntimeException)
     390             : {
     391         300 :     if ( !::comphelper::OStorageHelper::IsValidZipEntryFileName( rEntry.sPath, sal_True ) )
     392           0 :         throw IOException("Unexpected character is used in file name.", uno::Reference< XInterface >() );
     393             : 
     394         300 :     ::rtl::OString sUTF8Name = ::rtl::OUStringToOString( rEntry.sPath, RTL_TEXTENCODING_UTF8 );
     395         300 :     sal_Int16 nNameLength       = static_cast < sal_Int16 > ( sUTF8Name.getLength() );
     396             : 
     397         300 :     aChucker << LOCSIG;
     398         300 :     aChucker << rEntry.nVersion;
     399             : 
     400         300 :     if (rEntry.nFlag & (1 << 4) )
     401             :     {
     402             :         // If it's an encrypted entry, we pretend its stored plain text
     403           4 :         sal_Int16 nTmpFlag = rEntry.nFlag;
     404           4 :         nTmpFlag &= ~(1 <<4 );
     405           4 :         aChucker << nTmpFlag;
     406           4 :         aChucker << static_cast < sal_Int16 > ( STORED );
     407             :     }
     408             :     else
     409             :     {
     410         296 :         aChucker << rEntry.nFlag;
     411         296 :         aChucker << rEntry.nMethod;
     412             :     }
     413             : 
     414         300 :     bool bWrite64Header = false;
     415             : 
     416         300 :     aChucker << static_cast < sal_uInt32 > (rEntry.nTime);
     417         300 :     if ((rEntry.nFlag & 8) == 8 )
     418             :     {
     419         263 :         aChucker << static_cast < sal_Int32 > (0);
     420         263 :         aChucker << static_cast < sal_Int32 > (0);
     421         263 :         aChucker << static_cast < sal_Int32 > (0);
     422             :     }
     423             :     else
     424             :     {
     425          37 :         aChucker << static_cast < sal_uInt32 > (rEntry.nCrc);
     426          37 :         aChucker << getTruncated( rEntry.nCompressedSize, &bWrite64Header );
     427          37 :         aChucker << getTruncated( rEntry.nSize, &bWrite64Header );
     428             :     }
     429         300 :     aChucker << nNameLength;
     430         300 :     aChucker << static_cast < sal_Int16 > (0);
     431             : 
     432         300 :     if( bWrite64Header )
     433             :     {
     434             :         // FIXME64: need to append a ZIP64 header instead of throwing
     435             :         // We're about to silently loose people's data - which they are
     436             :         // unlikely to appreciate so fail instead:
     437             :         throw IOException( "File contains streams that are too large.",
     438           0 :                            uno::Reference< XInterface >() );
     439             :     }
     440             : 
     441         300 :     Sequence < sal_Int8 > aSequence( (sal_Int8*)sUTF8Name.getStr(), sUTF8Name.getLength() );
     442         300 :     aChucker.WriteBytes( aSequence );
     443             : 
     444         300 :     return LOCHDR + nNameLength;
     445             : }
     446         300 : sal_uInt32 ZipOutputStream::getCurrentDosTime( )
     447             : {
     448             :     oslDateTime aDateTime;
     449             :     TimeValue aTimeValue;
     450         300 :     osl_getSystemTime ( &aTimeValue );
     451         300 :     osl_getDateTimeFromTimeValue( &aTimeValue, &aDateTime);
     452             : 
     453         300 :     sal_uInt32 nYear = static_cast <sal_uInt32> (aDateTime.Year);
     454             : 
     455         300 :     if (nYear>1980)
     456         300 :         nYear-=1980;
     457           0 :     else if (nYear>80)
     458           0 :         nYear-=80;
     459             :     sal_uInt32 nResult = static_cast < sal_uInt32>( ( ( ( aDateTime.Day) +
     460             :                                           ( 32 * (aDateTime.Month)) +
     461             :                                           ( 512 * nYear ) ) << 16) |
     462             :                                         ( ( aDateTime.Seconds/2) +
     463             :                                             ( 32 * aDateTime.Minutes) +
     464         300 :                                           ( 2048 * static_cast <sal_uInt32 > (aDateTime.Hours) ) ) );
     465         300 :     return nResult;
     466             : }
     467             : /*
     468             : 
     469             :    This is actually never used, so I removed it, but thought that the
     470             :    implementation details may be useful in the future...mtg 20010307
     471             : 
     472             :    I stopped using the time library and used the OSL version instead, but
     473             :    it might still be useful to have this code here..
     474             : 
     475             : void ZipOutputStream::dosDateToTMDate ( tm &rTime, sal_uInt32 nDosDate)
     476             : {
     477             :     sal_uInt32 nDate = static_cast < sal_uInt32 > (nDosDate >> 16);
     478             :     rTime.tm_mday = static_cast < sal_uInt32 > ( nDate & 0x1F);
     479             :     rTime.tm_mon  = static_cast < sal_uInt32 > ( ( ( (nDate) & 0x1E0)/0x20)-1);
     480             :     rTime.tm_year = static_cast < sal_uInt32 > ( ( (nDate & 0x0FE00)/0x0200)+1980);
     481             : 
     482             :     rTime.tm_hour = static_cast < sal_uInt32 > ( (nDosDate & 0xF800)/0x800);
     483             :     rTime.tm_min  = static_cast < sal_uInt32 > ( (nDosDate & 0x7E0)/0x20);
     484             :     rTime.tm_sec  = static_cast < sal_uInt32 > ( 2 * (nDosDate & 0x1F) );
     485             : }
     486             : */
     487             : 
     488             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10