LCOV - code coverage report
Current view: top level - tools/source/zcodec - zcodec.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 170 213 79.8 %
Date: 2015-06-13 12:38:46 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             : #include <tools/stream.hxx>
      21             : 
      22             : #include <zlib.h>
      23             : 
      24             : #include <tools/zcodec.hxx>
      25             : #include <rtl/crc.h>
      26             : #include <osl/endian.h>
      27             : 
      28             : #define PZSTREAM static_cast<z_stream*>(mpsC_Stream)
      29             : 
      30             : /* gzip flag byte */
      31             : //      GZ_ASCII_FLAG   0x01 /* bit 0 set: file probably ascii text */
      32             : #define GZ_HEAD_CRC     0x02 /* bit 1 set: header CRC present */
      33             : #define GZ_EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
      34             : #define GZ_ORIG_NAME    0x08 /* bit 3 set: original file name present */
      35             : #define GZ_COMMENT      0x10 /* bit 4 set: file comment present */
      36             : #define GZ_RESERVED     0xE0 /* bits 5..7: reserved */
      37             : 
      38             : static const int gz_magic[2] = { 0x1f, 0x8b }; /* gzip magic header */
      39             : 
      40       12972 : ZCodec::ZCodec( sal_uIntPtr nInBufSize, sal_uIntPtr nOutBufSize )
      41             :     : meState(STATE_INIT)
      42             :     , mbStatus(false)
      43             :     , mbFinish(false)
      44             :     , mpInBuf(NULL)
      45             :     , mnInBufSize(nInBufSize)
      46             :     , mnInToRead(0)
      47             :     , mpOStm(NULL)
      48             :     , mpOutBuf(NULL)
      49             :     , mnOutBufSize(nOutBufSize)
      50             :     , mnCRC(0)
      51             :     , mnCompressLevel(0)
      52             :     , mbUpdateCrc(false)
      53       12972 :     , mbGzLib(false)
      54             : {
      55       12972 :     mpsC_Stream = new z_stream;
      56       12972 : }
      57             : 
      58       12972 : ZCodec::~ZCodec()
      59             : {
      60       12972 :     delete static_cast<z_stream*>(mpsC_Stream);
      61       12972 : }
      62             : 
      63       12967 : void ZCodec::BeginCompression( int nCompressLevel, bool updateCrc, bool gzLib )
      64             : {
      65             :     assert(meState == STATE_INIT);
      66       12967 :     mbStatus = true;
      67       12967 :     mbFinish = false;
      68       12967 :     mpOStm = NULL;
      69       12967 :     mnInToRead = 0xffffffff;
      70       12967 :     mpInBuf = mpOutBuf = NULL;
      71       12967 :     PZSTREAM->total_out = PZSTREAM->total_in = 0;
      72       12967 :     mnCompressLevel = nCompressLevel;
      73       12967 :     mbUpdateCrc = updateCrc;
      74       12967 :     mbGzLib = gzLib;
      75       12967 :     PZSTREAM->zalloc = nullptr;
      76       12967 :     PZSTREAM->zfree = nullptr;
      77       12967 :     PZSTREAM->opaque = nullptr;
      78       12967 :     PZSTREAM->avail_out = PZSTREAM->avail_in = 0;
      79       12967 : }
      80             : 
      81       12967 : long ZCodec::EndCompression()
      82             : {
      83       12967 :     long retvalue = 0;
      84             : 
      85       12967 :     if (meState != STATE_INIT)
      86             :     {
      87       12967 :         if (meState == STATE_COMPRESS)
      88             :         {
      89        1168 :             do
      90             :             {
      91        1168 :                 ImplWriteBack();
      92             :             }
      93        1168 :             while ( deflate( PZSTREAM, Z_FINISH ) != Z_STREAM_END );
      94             : 
      95        1168 :             ImplWriteBack();
      96             : 
      97        1168 :             retvalue = PZSTREAM->total_in;
      98        1168 :             deflateEnd( PZSTREAM );
      99             :         }
     100             :         else
     101             :         {
     102       11799 :             retvalue = PZSTREAM->total_out;
     103       11799 :             inflateEnd( PZSTREAM );
     104             :         }
     105       12967 :         delete[] mpOutBuf;
     106       12967 :         delete[] mpInBuf;
     107       12967 :         meState = STATE_INIT;
     108             :     }
     109       12967 :     return ( mbStatus ) ? retvalue : -1;
     110             : }
     111             : 
     112           0 : long ZCodec::Compress( SvStream& rIStm, SvStream& rOStm )
     113             : {
     114           0 :     long nOldTotal_In = PZSTREAM->total_in;
     115             : 
     116             :     assert(meState == STATE_INIT);
     117           0 :     mpOStm = &rOStm;
     118           0 :     InitCompress();
     119           0 :     mpInBuf = new sal_uInt8[ mnInBufSize ];
     120           0 :     while (( PZSTREAM->avail_in = rIStm.Read( PZSTREAM->next_in = mpInBuf, mnInBufSize )) != 0 )
     121             :     {
     122           0 :         if ( PZSTREAM->avail_out == 0 )
     123           0 :             ImplWriteBack();
     124           0 :         if ( deflate( PZSTREAM, Z_NO_FLUSH ) < 0 )
     125             :         {
     126           0 :             mbStatus = false;
     127           0 :             break;
     128             :         }
     129             :     };
     130           0 :     return ( mbStatus ) ? (long)(PZSTREAM->total_in - nOldTotal_In) : -1;
     131             : }
     132             : 
     133          63 : long ZCodec::Decompress( SvStream& rIStm, SvStream& rOStm )
     134             : {
     135             :     int err;
     136             :     sal_uIntPtr nInToRead;
     137          63 :     long    nOldTotal_Out = PZSTREAM->total_out;
     138             : 
     139             :     assert(meState == STATE_INIT);
     140          63 :     mpOStm = &rOStm;
     141          63 :     InitDecompress(rIStm);
     142          63 :     PZSTREAM->next_out = mpOutBuf = new sal_uInt8[ PZSTREAM->avail_out = mnOutBufSize ];
     143          66 :     do
     144             :     {
     145          70 :         if ( PZSTREAM->avail_out == 0 ) ImplWriteBack();
     146          70 :         if ( PZSTREAM->avail_in == 0 && mnInToRead )
     147             :         {
     148          63 :             nInToRead = ( mnInBufSize > mnInToRead ) ? mnInToRead : mnInBufSize;
     149          63 :             PZSTREAM->avail_in = rIStm.Read( PZSTREAM->next_in = mpInBuf, nInToRead );
     150          63 :             mnInToRead -= nInToRead;
     151             : 
     152          63 :             if ( mbUpdateCrc )
     153           0 :                 UpdateCRC( mpInBuf, nInToRead );
     154             : 
     155             :         }
     156          70 :         err = inflate( PZSTREAM, Z_NO_FLUSH );
     157          70 :         if ( err < 0 )
     158             :         {
     159           4 :             mbStatus = false;
     160           4 :             break;
     161             :         }
     162             : 
     163             :     }
     164           7 :     while ( ( err != Z_STREAM_END)  && ( PZSTREAM->avail_in || mnInToRead ) );
     165          63 :     ImplWriteBack();
     166             : 
     167          63 :     return ( mbStatus ) ? (long)(PZSTREAM->total_out - nOldTotal_Out) : -1;
     168             : }
     169             : 
     170       25887 : long ZCodec::Write( SvStream& rOStm, const sal_uInt8* pData, sal_uIntPtr nSize )
     171             : {
     172       25887 :     if (meState == STATE_INIT)
     173             :     {
     174        1168 :         mpOStm = &rOStm;
     175        1168 :         InitCompress();
     176             :     }
     177             :     assert(&rOStm == mpOStm);
     178             : 
     179       25887 :     PZSTREAM->avail_in = nSize;
     180       25887 :     PZSTREAM->next_in = const_cast<unsigned char*>(pData);
     181             : 
     182       77673 :     while ( PZSTREAM->avail_in || ( PZSTREAM->avail_out == 0 ) )
     183             :     {
     184       25899 :         if ( PZSTREAM->avail_out == 0 )
     185          12 :             ImplWriteBack();
     186             : 
     187       25899 :         if ( deflate( PZSTREAM, Z_NO_FLUSH ) < 0 )
     188             :         {
     189           0 :             mbStatus = false;
     190           0 :             break;
     191             :         }
     192             :     }
     193       25887 :     return ( mbStatus ) ? (long)nSize : -1;
     194             : }
     195             : 
     196           4 : long ZCodec::Read( SvStream& rIStm, sal_uInt8* pData, sal_uIntPtr nSize )
     197             : {
     198             :     int err;
     199             :     sal_uIntPtr nInToRead;
     200             : 
     201           4 :     if ( mbFinish )
     202           0 :         return 0;           // PZSTREAM->total_out;
     203             : 
     204           4 :     if (meState == STATE_INIT)
     205             :     {
     206           4 :         InitDecompress(rIStm);
     207             :     }
     208           4 :     PZSTREAM->avail_out = nSize;
     209           4 :     PZSTREAM->next_out = pData;
     210           4 :     do
     211             :     {
     212           4 :         if ( PZSTREAM->avail_in == 0 && mnInToRead )
     213             :         {
     214           4 :             nInToRead = (mnInBufSize > mnInToRead) ? mnInToRead : mnInBufSize;
     215             :             PZSTREAM->avail_in = rIStm.Read (
     216           4 :                 PZSTREAM->next_in = mpInBuf, nInToRead);
     217           4 :             mnInToRead -= nInToRead;
     218             : 
     219           4 :             if ( mbUpdateCrc )
     220           0 :                 UpdateCRC( mpInBuf, nInToRead );
     221             : 
     222             :         }
     223           4 :         err = inflate( PZSTREAM, Z_NO_FLUSH );
     224           4 :         if ( err < 0 )
     225             :         {
     226             :             // Accept Z_BUF_ERROR as EAGAIN or EWOULDBLOCK.
     227           0 :             mbStatus = (err == Z_BUF_ERROR);
     228           0 :             break;
     229             :         }
     230             :     }
     231           0 :     while ( (err != Z_STREAM_END) &&
     232           0 :             (PZSTREAM->avail_out != 0) &&
     233           0 :             (PZSTREAM->avail_in || mnInToRead) );
     234           4 :     if ( err == Z_STREAM_END )
     235           4 :         mbFinish = true;
     236             : 
     237           4 :     return (mbStatus ? (long)(nSize - PZSTREAM->avail_out) : -1);
     238             : }
     239             : 
     240      371815 : long ZCodec::ReadAsynchron( SvStream& rIStm, sal_uInt8* pData, sal_uIntPtr nSize )
     241             : {
     242      371815 :     int err = 0;
     243             :     sal_uIntPtr nInToRead;
     244             : 
     245      371815 :     if ( mbFinish )
     246           0 :         return 0;           // PZSTREAM->total_out;
     247             : 
     248      371815 :     if (meState == STATE_INIT)
     249             :     {
     250       11728 :         InitDecompress(rIStm);
     251             :     }
     252      371815 :     PZSTREAM->avail_out = nSize;
     253      371815 :     PZSTREAM->next_out = pData;
     254      371953 :     do
     255             :     {
     256      371954 :         if ( PZSTREAM->avail_in == 0 && mnInToRead )
     257             :         {
     258       11982 :             nInToRead = (mnInBufSize > mnInToRead) ? mnInToRead : mnInBufSize;
     259             : 
     260       11982 :             sal_uInt64 const nRemaining = rIStm.remainingSize();
     261       11982 :             if (nRemaining < nInToRead)
     262             :             {
     263           0 :                 rIStm.SetError( ERRCODE_IO_PENDING );
     264           0 :                 err= int(!Z_STREAM_END); // TODO What is appropriate code for this?
     265           0 :                 break;
     266             :             }
     267             : 
     268             :             PZSTREAM->avail_in = rIStm.Read (
     269       11982 :                 PZSTREAM->next_in = mpInBuf, nInToRead);
     270       11982 :             mnInToRead -= nInToRead;
     271             : 
     272       11982 :             if ( mbUpdateCrc )
     273       11982 :                 UpdateCRC( mpInBuf, nInToRead );
     274             : 
     275             :         }
     276      371954 :         err = inflate( PZSTREAM, Z_NO_FLUSH );
     277      371954 :         if ( err < 0 )
     278             :         {
     279             :             // Accept Z_BUF_ERROR as EAGAIN or EWOULDBLOCK.
     280           1 :             mbStatus = (err == Z_BUF_ERROR);
     281           1 :             break;
     282             :         }
     283             :     }
     284      360227 :     while ( (err == Z_OK) &&
     285      360480 :             (PZSTREAM->avail_out != 0) &&
     286         253 :             (PZSTREAM->avail_in || mnInToRead) );
     287      371815 :     if ( err == Z_STREAM_END )
     288       11725 :         mbFinish = true;
     289             : 
     290      371815 :     return (mbStatus ? (long)(nSize - PZSTREAM->avail_out) : -1);
     291             : }
     292             : 
     293        2418 : void ZCodec::ImplWriteBack()
     294             : {
     295        2418 :     sal_uIntPtr nAvail = mnOutBufSize - PZSTREAM->avail_out;
     296             : 
     297        2418 :     if ( nAvail )
     298             :     {
     299        2418 :         if (meState == STATE_COMPRESS && mbUpdateCrc)
     300         364 :             UpdateCRC( mpOutBuf, nAvail );
     301        2418 :         mpOStm->Write( PZSTREAM->next_out = mpOutBuf, nAvail );
     302        2418 :         PZSTREAM->avail_out = mnOutBufSize;
     303             :     }
     304        2418 : }
     305             : 
     306       11842 : void ZCodec::SetBreak( sal_uIntPtr nInToRead )
     307             : {
     308       11842 :     mnInToRead = nInToRead;
     309       11842 : }
     310             : 
     311      371815 : sal_uIntPtr ZCodec::GetBreak()
     312             : {
     313      371815 :     return ( mnInToRead + PZSTREAM->avail_in );
     314             : }
     315             : 
     316         176 : void ZCodec::SetCRC( sal_uIntPtr nCRC )
     317             : {
     318         176 :     mnCRC = nCRC;
     319         176 : }
     320             : 
     321             : 
     322        1168 : void ZCodec::InitCompress()
     323             : {
     324             :     assert(meState == STATE_INIT);
     325        1168 :     meState = STATE_COMPRESS;
     326             :     mbStatus = deflateInit2_(
     327             :         PZSTREAM, mnCompressLevel, Z_DEFLATED, MAX_WBITS, MAX_MEM_LEVEL,
     328        1168 :         Z_DEFAULT_STRATEGY, ZLIB_VERSION, sizeof (z_stream)) >= 0;
     329        1168 :     mpOutBuf = new sal_uInt8[mnOutBufSize];
     330        1168 :     PZSTREAM->next_out = mpOutBuf;
     331        1168 :     PZSTREAM->avail_out = mnOutBufSize;
     332        1168 : }
     333             : 
     334       11799 : void ZCodec::InitDecompress(SvStream & inStream)
     335             : {
     336             :     assert(meState == STATE_INIT);
     337       11799 :     meState = STATE_DECOMPRESS;
     338       11799 :     if ( mbStatus &&  mbGzLib )
     339             :     {
     340             :         sal_uInt8 n1, n2, j, nMethod, nFlags;
     341          12 :         for ( int i = 0; i < 2; i++ )   // gz - magic number
     342             :         {
     343           8 :             inStream.ReadUChar( j );
     344           8 :             if ( j != gz_magic[ i ] )
     345           8 :                 mbStatus = false;
     346             :         }
     347           4 :         inStream.ReadUChar( nMethod );
     348           4 :         inStream.ReadUChar( nFlags );
     349           4 :         if ( nMethod != Z_DEFLATED )
     350           4 :             mbStatus = false;
     351           4 :         if ( ( nFlags & GZ_RESERVED ) != 0 )
     352           4 :             mbStatus = false;
     353             :         /* Discard time, xflags and OS code: */
     354           4 :         inStream.SeekRel( 6 );
     355             :         /* skip the extra field */
     356           4 :         if ( nFlags & GZ_EXTRA_FIELD )
     357             :         {
     358           1 :             inStream.ReadUChar( n1 ).ReadUChar( n2 );
     359           1 :             inStream.SeekRel( n1 + ( n2 << 8 ) );
     360             :         }
     361             :         /* skip the original file name */
     362           4 :         if ( nFlags & GZ_ORIG_NAME)
     363             :         {
     364           0 :             do
     365             :             {
     366           0 :                 inStream.ReadUChar( j );
     367             :             }
     368           0 :             while ( j && !inStream.IsEof() );
     369             :         }
     370             :         /* skip the .gz file comment */
     371           4 :         if ( nFlags & GZ_COMMENT )
     372             :         {
     373           0 :             do
     374             :             {
     375           0 :                 inStream.ReadUChar( j );
     376             :             }
     377           0 :             while ( j && !inStream.IsEof() );
     378             :         }
     379             :         /* skip the header crc */
     380           4 :         if ( nFlags & GZ_HEAD_CRC )
     381           1 :             inStream.SeekRel( 2 );
     382           4 :         if ( mbStatus )
     383           0 :             mbStatus = inflateInit2( PZSTREAM, -MAX_WBITS) == Z_OK;
     384             :     }
     385             :     else
     386             :     {
     387       11795 :         mbStatus = ( inflateInit( PZSTREAM ) >= 0 );
     388             :     }
     389       11799 :     mpInBuf = new sal_uInt8[ mnInBufSize ];
     390       11799 : }
     391             : 
     392       12346 : void ZCodec::UpdateCRC ( sal_uInt8* pSource, long nDatSize)
     393             : {
     394       12346 :     mnCRC = rtl_crc32( mnCRC, pSource, nDatSize );
     395       12346 : }
     396             : 
     397           4 : bool ZCodec::AttemptDecompression(SvStream& rIStm, SvStream& rOStm, bool updateCrc, bool gzLib)
     398             : {
     399             :     assert(meState == STATE_INIT);
     400           4 :     sal_uLong nStreamPos = rIStm.Tell();
     401           4 :     BeginCompression(ZCODEC_DEFAULT_COMPRESSION, updateCrc, gzLib);
     402           4 :     InitDecompress(rIStm);
     403           4 :     EndCompression();
     404           4 :     if ( !mbStatus || rIStm.GetError() )
     405             :     {
     406           4 :         rIStm.Seek(nStreamPos);
     407           4 :         return false;
     408             :     }
     409           0 :     rIStm.Seek(nStreamPos);
     410           0 :     BeginCompression(ZCODEC_DEFAULT_COMPRESSION, updateCrc, gzLib);
     411           0 :     Decompress(rIStm, rOStm);
     412           0 :     EndCompression();
     413           0 :     if( !mbStatus || rIStm.GetError() || rOStm.GetError() )
     414             :     {
     415           0 :         rIStm.Seek(nStreamPos);
     416           0 :         return false;
     417             :     }
     418           0 :     rIStm.Seek(nStreamPos);
     419           0 :     rOStm.Seek(0);
     420           0 :     return true;
     421             : }
     422             : 
     423             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11