blob: 390e23a29da9bca3cee784fc21893ab2a2ad2bf3 [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_tools.hxx"
#include <tools/stream.hxx>
#ifndef _ZLIB_H
#ifdef SYSTEM_ZLIB
#include "zlib.h"
#else
#include "zlib/zlib.h"
#endif
#endif
#include <tools/zcodec.hxx>
#include <rtl/crc.h>
#include <osl/endian.h>
// -----------
// - Defines -
// -----------
#define PZSTREAM ((z_stream*) mpsC_Stream)
/* gzip flag byte */
#define GZ_ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
#define GZ_HEAD_CRC 0x02 /* bit 1 set: header CRC present */
#define GZ_EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
#define GZ_ORIG_NAME 0x08 /* bit 3 set: original file name present */
#define GZ_COMMENT 0x10 /* bit 4 set: file comment present */
#define GZ_RESERVED 0xE0 /* bits 5..7: reserved */
static int gz_magic[2] = { 0x1f, 0x8b }; /* gzip magic header */
// ----------
// - ZCodec -
// ----------
ZCodec::ZCodec( sal_uIntPtr nInBufSize, sal_uIntPtr nOutBufSize, sal_uIntPtr nMemUsage )
: mnCRC(0)
{
mnMemUsage = nMemUsage;
mnInBufSize = nInBufSize;
mnOutBufSize = nOutBufSize;
mpsC_Stream = new z_stream;
}
ZCodec::ZCodec( void )
: mnCRC(0)
{
mnMemUsage = MAX_MEM_USAGE;
mnInBufSize = DEFAULT_IN_BUFSIZE;
mnOutBufSize = DEFAULT_OUT_BUFSIZE;
mpsC_Stream = new z_stream;
}
// ------------------------------------------------------------------------
ZCodec::~ZCodec()
{
delete (z_stream*) mpsC_Stream;
}
// ------------------------------------------------------------------------
void ZCodec::BeginCompression( sal_uIntPtr nCompressMethod )
{
mbInit = 0;
mbStatus = sal_True;
mbFinish = sal_False;
mpIStm = mpOStm = NULL;
mnInToRead = 0xffffffff;
mpInBuf = mpOutBuf = NULL;
PZSTREAM->total_out = PZSTREAM->total_in = 0;
mnCompressMethod = nCompressMethod;
PZSTREAM->zalloc = ( alloc_func )0;
PZSTREAM->zfree = ( free_func )0;
PZSTREAM->opaque = ( voidpf )0;
PZSTREAM->avail_out = PZSTREAM->avail_in = 0;
}
// ------------------------------------------------------------------------
long ZCodec::EndCompression()
{
long retvalue = 0;
if ( mbInit != 0 )
{
if ( mbInit & 2 ) // 1->decompress, 3->compress
{
do
{
ImplWriteBack();
}
while ( deflate( PZSTREAM, Z_FINISH ) != Z_STREAM_END );
ImplWriteBack();
retvalue = PZSTREAM->total_in;
deflateEnd( PZSTREAM );
}
else
{
retvalue = PZSTREAM->total_out;
inflateEnd( PZSTREAM );
}
delete[] mpOutBuf;
delete[] mpInBuf;
}
return ( mbStatus ) ? retvalue : -1;
}
// ------------------------------------------------------------------------
long ZCodec::Compress( SvStream& rIStm, SvStream& rOStm )
{
long nOldTotal_In = PZSTREAM->total_in;
if ( mbInit == 0 )
{
mpIStm = &rIStm;
mpOStm = &rOStm;
ImplInitBuf( sal_False );
mpInBuf = new sal_uInt8[ mnInBufSize ];
}
while (( PZSTREAM->avail_in = mpIStm->Read( PZSTREAM->next_in = mpInBuf, mnInBufSize )) != 0 )
{
if ( PZSTREAM->avail_out == 0 )
ImplWriteBack();
if ( deflate( PZSTREAM, Z_NO_FLUSH ) < 0 )
{
mbStatus = sal_False;
break;
}
};
return ( mbStatus ) ? (long)(PZSTREAM->total_in - nOldTotal_In) : -1;
}
// ------------------------------------------------------------------------
long ZCodec::Decompress( SvStream& rIStm, SvStream& rOStm )
{
int err;
sal_uIntPtr nInToRead;
long nOldTotal_Out = PZSTREAM->total_out;
if ( mbFinish )
return PZSTREAM->total_out - nOldTotal_Out;
if ( mbInit == 0 )
{
mpIStm = &rIStm;
mpOStm = &rOStm;
ImplInitBuf( sal_True );
PZSTREAM->next_out = mpOutBuf = new sal_uInt8[ PZSTREAM->avail_out = mnOutBufSize ];
}
do
{
if ( PZSTREAM->avail_out == 0 ) ImplWriteBack();
if ( PZSTREAM->avail_in == 0 && mnInToRead )
{
nInToRead = ( mnInBufSize > mnInToRead ) ? mnInToRead : mnInBufSize;
PZSTREAM->avail_in = mpIStm->Read( PZSTREAM->next_in = mpInBuf, nInToRead );
mnInToRead -= nInToRead;
if ( mnCompressMethod & ZCODEC_UPDATE_CRC )
mnCRC = UpdateCRC( mnCRC, mpInBuf, nInToRead );
}
err = inflate( PZSTREAM, Z_NO_FLUSH );
if ( err < 0 )
{
mbStatus = sal_False;
break;
}
}
while ( ( err != Z_STREAM_END) && ( PZSTREAM->avail_in || mnInToRead ) );
ImplWriteBack();
if ( err == Z_STREAM_END )
mbFinish = sal_True;
return ( mbStatus ) ? (long)(PZSTREAM->total_out - nOldTotal_Out) : -1;
}
// ------------------------------------------------------------------------
long ZCodec::Write( SvStream& rOStm, const sal_uInt8* pData, sal_uIntPtr nSize )
{
if ( mbInit == 0 )
{
mpOStm = &rOStm;
ImplInitBuf( sal_False );
}
PZSTREAM->avail_in = nSize;
PZSTREAM->next_in = (unsigned char*)pData;
while ( PZSTREAM->avail_in || ( PZSTREAM->avail_out == 0 ) )
{
if ( PZSTREAM->avail_out == 0 )
ImplWriteBack();
if ( deflate( PZSTREAM, Z_NO_FLUSH ) < 0 )
{
mbStatus = sal_False;
break;
}
}
return ( mbStatus ) ? (long)nSize : -1;
}
// ------------------------------------------------------------------------
long ZCodec::Read( SvStream& rIStm, sal_uInt8* pData, sal_uIntPtr nSize )
{
int err;
sal_uIntPtr nInToRead;
if ( mbFinish )
return 0; // PZSTREAM->total_out;
mpIStm = &rIStm;
if ( mbInit == 0 )
{
ImplInitBuf( sal_True );
}
PZSTREAM->avail_out = nSize;
PZSTREAM->next_out = pData;
do
{
if ( PZSTREAM->avail_in == 0 && mnInToRead )
{
nInToRead = (mnInBufSize > mnInToRead) ? mnInToRead : mnInBufSize;
PZSTREAM->avail_in = mpIStm->Read (
PZSTREAM->next_in = mpInBuf, nInToRead);
mnInToRead -= nInToRead;
if ( mnCompressMethod & ZCODEC_UPDATE_CRC )
mnCRC = UpdateCRC( mnCRC, mpInBuf, nInToRead );
}
err = inflate( PZSTREAM, Z_NO_FLUSH );
if ( err < 0 )
{
// Accept Z_BUF_ERROR as EAGAIN or EWOULDBLOCK.
mbStatus = (err == Z_BUF_ERROR);
break;
}
}
while ( (err != Z_STREAM_END) &&
(PZSTREAM->avail_out != 0) &&
(PZSTREAM->avail_in || mnInToRead) );
if ( err == Z_STREAM_END )
mbFinish = sal_True;
return (mbStatus ? (long)(nSize - PZSTREAM->avail_out) : -1);
}
// ------------------------------------------------------------------------
long ZCodec::ReadAsynchron( SvStream& rIStm, sal_uInt8* pData, sal_uIntPtr nSize )
{
int err = 0;
sal_uIntPtr nInToRead;
if ( mbFinish )
return 0; // PZSTREAM->total_out;
if ( mbInit == 0 )
{
mpIStm = &rIStm;
ImplInitBuf( sal_True );
}
PZSTREAM->avail_out = nSize;
PZSTREAM->next_out = pData;
do
{
if ( PZSTREAM->avail_in == 0 && mnInToRead )
{
nInToRead = (mnInBufSize > mnInToRead) ? mnInToRead : mnInBufSize;
sal_uIntPtr nStreamPos = rIStm.Tell();
rIStm.Seek( STREAM_SEEK_TO_END );
sal_uIntPtr nMaxPos = rIStm.Tell();
rIStm.Seek( nStreamPos );
if ( ( nMaxPos - nStreamPos ) < nInToRead )
{
rIStm.SetError( ERRCODE_IO_PENDING );
err= ! Z_STREAM_END; // TODO What is appropriate code for this?
break;
}
PZSTREAM->avail_in = mpIStm->Read (
PZSTREAM->next_in = mpInBuf, nInToRead);
mnInToRead -= nInToRead;
if ( mnCompressMethod & ZCODEC_UPDATE_CRC )
mnCRC = UpdateCRC( mnCRC, mpInBuf, nInToRead );
}
err = inflate( PZSTREAM, Z_NO_FLUSH );
if ( err < 0 )
{
// Accept Z_BUF_ERROR as EAGAIN or EWOULDBLOCK.
mbStatus = (err == Z_BUF_ERROR);
break;
}
}
while ( (err != Z_STREAM_END) &&
(PZSTREAM->avail_out != 0) &&
(PZSTREAM->avail_in || mnInToRead) );
if ( err == Z_STREAM_END )
mbFinish = sal_True;
return (mbStatus ? (long)(nSize - PZSTREAM->avail_out) : -1);
}
// ------------------------------------------------------------------------
void ZCodec::ImplWriteBack()
{
sal_uIntPtr nAvail = mnOutBufSize - PZSTREAM->avail_out;
if ( nAvail )
{
if ( mbInit & 2 && ( mnCompressMethod & ZCODEC_UPDATE_CRC ) )
mnCRC = UpdateCRC( mnCRC, mpOutBuf, nAvail );
mpOStm->Write( PZSTREAM->next_out = mpOutBuf, nAvail );
PZSTREAM->avail_out = mnOutBufSize;
}
}
// ------------------------------------------------------------------------
void ZCodec::SetBreak( sal_uIntPtr nInToRead )
{
mnInToRead = nInToRead;
}
// ------------------------------------------------------------------------
sal_uIntPtr ZCodec::GetBreak( void )
{
return ( mnInToRead + PZSTREAM->avail_in );
}
// ------------------------------------------------------------------------
void ZCodec::SetCRC( sal_uIntPtr nCRC )
{
mnCRC = nCRC;
}
// ------------------------------------------------------------------------
sal_uIntPtr ZCodec::GetCRC()
{
return mnCRC;
}
// ------------------------------------------------------------------------
void ZCodec::ImplInitBuf ( sal_Bool nIOFlag )
{
if ( mbInit == 0 )
{
if ( nIOFlag )
{
mbInit = 1;
if ( mbStatus && ( mnCompressMethod & ZCODEC_GZ_LIB ) )
{
sal_uInt8 n1, n2, j, nMethod, nFlags;
for ( int i = 0; i < 2; i++ ) // gz - magic number
{
*mpIStm >> j;
if ( j != gz_magic[ i ] )
mbStatus = sal_False;
}
*mpIStm >> nMethod;
*mpIStm >> nFlags;
if ( nMethod != Z_DEFLATED )
mbStatus = sal_False;
if ( ( nFlags & GZ_RESERVED ) != 0 )
mbStatus = sal_False;
/* Discard time, xflags and OS code: */
mpIStm->SeekRel( 6 );
/* skip the extra field */
if ( nFlags & GZ_EXTRA_FIELD )
{
*mpIStm >> n1 >> n2;
mpIStm->SeekRel( n1 + ( n2 << 8 ) );
}
/* skip the original file name */
if ( nFlags & GZ_ORIG_NAME)
{
do
{
*mpIStm >> j;
}
while ( j && !mpIStm->IsEof() );
}
/* skip the .gz file comment */
if ( nFlags & GZ_COMMENT )
{
do
{
*mpIStm >> j;
}
while ( j && !mpIStm->IsEof() );
}
/* skip the header crc */
if ( nFlags & GZ_HEAD_CRC )
mpIStm->SeekRel( 2 );
if ( mbStatus )
mbStatus = ( inflateInit2( PZSTREAM, -MAX_WBITS) != Z_OK ) ? sal_False : sal_True;
}
else
{
mbStatus = ( inflateInit( PZSTREAM ) >= 0 );
}
mpInBuf = new sal_uInt8[ mnInBufSize ];
}
else
{
mbInit = 3;
mbStatus = ( deflateInit2_( PZSTREAM, mnCompressMethod & 0xff, Z_DEFLATED,
MAX_WBITS, mnMemUsage, ( mnCompressMethod >> 8 ) & 0xff,
ZLIB_VERSION, sizeof( z_stream ) ) >= 0 );
PZSTREAM->next_out = mpOutBuf = new sal_uInt8[ PZSTREAM->avail_out = mnOutBufSize ];
}
}
}
// ------------------------------------------------------------------------
sal_uIntPtr ZCodec::UpdateCRC ( sal_uIntPtr nLatestCRC, sal_uIntPtr nNumber )
{
#ifdef OSL_LITENDIAN
nNumber = SWAPLONG( nNumber );
#endif
return rtl_crc32( nLatestCRC, &nNumber, 4 );
}
// ------------------------------------------------------------------------
sal_uIntPtr ZCodec::UpdateCRC ( sal_uIntPtr nLatestCRC, sal_uInt8* pSource, long nDatSize)
{
return rtl_crc32( nLatestCRC, pSource, nDatSize );
}
// ------------------------------------------------------------------------
void GZCodec::BeginCompression( sal_uIntPtr nCompressMethod )
{
ZCodec::BeginCompression( nCompressMethod | ZCODEC_GZ_LIB );
};