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

Generated by: LCOV version 1.10