1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <tools/stream.hxx>
24 #include <tools/zcodec.hxx>
26 #include <osl/endian.h>
28 #define PZSTREAM static_cast<z_stream*>(mpsC_Stream)
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 */
38 static const int gz_magic
[2] = { 0x1f, 0x8b }; /* gzip magic header */
40 ZCodec::ZCodec( sal_uIntPtr nInBufSize
, sal_uIntPtr nOutBufSize
)
45 , mnInBufSize(nInBufSize
)
49 , mnOutBufSize(nOutBufSize
)
55 mpsC_Stream
= new z_stream
;
60 delete static_cast<z_stream
*>(mpsC_Stream
);
63 void ZCodec::BeginCompression( int nCompressLevel
, bool updateCrc
, bool gzLib
)
65 assert(meState
== STATE_INIT
);
69 mnInToRead
= 0xffffffff;
70 mpInBuf
= mpOutBuf
= NULL
;
71 PZSTREAM
->total_out
= PZSTREAM
->total_in
= 0;
72 mnCompressLevel
= nCompressLevel
;
73 mbUpdateCrc
= updateCrc
;
75 PZSTREAM
->zalloc
= ( alloc_func
)0;
76 PZSTREAM
->zfree
= ( free_func
)0;
77 PZSTREAM
->opaque
= ( voidpf
)0;
78 PZSTREAM
->avail_out
= PZSTREAM
->avail_in
= 0;
81 long ZCodec::EndCompression()
85 if (meState
!= STATE_INIT
)
87 if (meState
== STATE_COMPRESS
)
93 while ( deflate( PZSTREAM
, Z_FINISH
) != Z_STREAM_END
);
97 retvalue
= PZSTREAM
->total_in
;
98 deflateEnd( PZSTREAM
);
102 retvalue
= PZSTREAM
->total_out
;
103 inflateEnd( PZSTREAM
);
107 meState
= STATE_INIT
;
109 return ( mbStatus
) ? retvalue
: -1;
112 long ZCodec::Compress( SvStream
& rIStm
, SvStream
& rOStm
)
114 long nOldTotal_In
= PZSTREAM
->total_in
;
116 assert(meState
== STATE_INIT
);
119 mpInBuf
= new sal_uInt8
[ mnInBufSize
];
120 while (( PZSTREAM
->avail_in
= rIStm
.Read( PZSTREAM
->next_in
= mpInBuf
, mnInBufSize
)) != 0 )
122 if ( PZSTREAM
->avail_out
== 0 )
124 if ( deflate( PZSTREAM
, Z_NO_FLUSH
) < 0 )
130 return ( mbStatus
) ? (long)(PZSTREAM
->total_in
- nOldTotal_In
) : -1;
133 long ZCodec::Decompress( SvStream
& rIStm
, SvStream
& rOStm
)
136 sal_uIntPtr nInToRead
;
137 long nOldTotal_Out
= PZSTREAM
->total_out
;
139 assert(meState
== STATE_INIT
);
141 InitDecompress(rIStm
);
142 PZSTREAM
->next_out
= mpOutBuf
= new sal_uInt8
[ PZSTREAM
->avail_out
= mnOutBufSize
];
145 if ( PZSTREAM
->avail_out
== 0 ) ImplWriteBack();
146 if ( PZSTREAM
->avail_in
== 0 && mnInToRead
)
148 nInToRead
= ( mnInBufSize
> mnInToRead
) ? mnInToRead
: mnInBufSize
;
149 PZSTREAM
->avail_in
= rIStm
.Read( PZSTREAM
->next_in
= mpInBuf
, nInToRead
);
150 mnInToRead
-= nInToRead
;
153 UpdateCRC( mpInBuf
, nInToRead
);
156 err
= mbStatus
? inflate(PZSTREAM
, Z_NO_FLUSH
) : Z_ERRNO
;
164 while ( ( err
!= Z_STREAM_END
) && ( PZSTREAM
->avail_in
|| mnInToRead
) );
167 return ( mbStatus
) ? (long)(PZSTREAM
->total_out
- nOldTotal_Out
) : -1;
170 long ZCodec::Write( SvStream
& rOStm
, const sal_uInt8
* pData
, sal_uIntPtr nSize
)
172 if (meState
== STATE_INIT
)
177 assert(&rOStm
== mpOStm
);
179 PZSTREAM
->avail_in
= nSize
;
180 PZSTREAM
->next_in
= const_cast<unsigned char*>(pData
);
182 while ( PZSTREAM
->avail_in
|| ( PZSTREAM
->avail_out
== 0 ) )
184 if ( PZSTREAM
->avail_out
== 0 )
187 if ( deflate( PZSTREAM
, Z_NO_FLUSH
) < 0 )
193 return ( mbStatus
) ? (long)nSize
: -1;
196 long ZCodec::Read( SvStream
& rIStm
, sal_uInt8
* pData
, sal_uIntPtr nSize
)
199 sal_uIntPtr nInToRead
;
202 return 0; // PZSTREAM->total_out;
204 if (meState
== STATE_INIT
)
206 InitDecompress(rIStm
);
208 PZSTREAM
->avail_out
= nSize
;
209 PZSTREAM
->next_out
= pData
;
212 if ( PZSTREAM
->avail_in
== 0 && mnInToRead
)
214 nInToRead
= (mnInBufSize
> mnInToRead
) ? mnInToRead
: mnInBufSize
;
215 PZSTREAM
->avail_in
= rIStm
.Read (
216 PZSTREAM
->next_in
= mpInBuf
, nInToRead
);
217 mnInToRead
-= nInToRead
;
220 UpdateCRC( mpInBuf
, nInToRead
);
223 err
= mbStatus
? inflate(PZSTREAM
, Z_NO_FLUSH
) : Z_ERRNO
;
226 // Accept Z_BUF_ERROR as EAGAIN or EWOULDBLOCK.
227 mbStatus
= (err
== Z_BUF_ERROR
);
231 while ( (err
!= Z_STREAM_END
) &&
232 (PZSTREAM
->avail_out
!= 0) &&
233 (PZSTREAM
->avail_in
|| mnInToRead
) );
234 if ( err
== Z_STREAM_END
)
237 return (mbStatus
? (long)(nSize
- PZSTREAM
->avail_out
) : -1);
240 long ZCodec::ReadAsynchron( SvStream
& rIStm
, sal_uInt8
* pData
, sal_uIntPtr nSize
)
243 sal_uIntPtr nInToRead
;
246 return 0; // PZSTREAM->total_out;
248 if (meState
== STATE_INIT
)
250 InitDecompress(rIStm
);
252 PZSTREAM
->avail_out
= nSize
;
253 PZSTREAM
->next_out
= pData
;
256 if ( PZSTREAM
->avail_in
== 0 && mnInToRead
)
258 nInToRead
= (mnInBufSize
> mnInToRead
) ? mnInToRead
: mnInBufSize
;
260 sal_uInt64
const nRemaining
= rIStm
.remainingSize();
261 if (nRemaining
< nInToRead
)
263 rIStm
.SetError( ERRCODE_IO_PENDING
);
264 err
= int(!Z_STREAM_END
); // TODO What is appropriate code for this?
268 PZSTREAM
->avail_in
= rIStm
.Read (
269 PZSTREAM
->next_in
= mpInBuf
, nInToRead
);
270 mnInToRead
-= nInToRead
;
273 UpdateCRC( mpInBuf
, nInToRead
);
276 err
= mbStatus
? inflate(PZSTREAM
, Z_NO_FLUSH
) : Z_ERRNO
;
279 // Accept Z_BUF_ERROR as EAGAIN or EWOULDBLOCK.
280 mbStatus
= (err
== Z_BUF_ERROR
);
284 while ( (err
== Z_OK
) &&
285 (PZSTREAM
->avail_out
!= 0) &&
286 (PZSTREAM
->avail_in
|| mnInToRead
) );
287 if ( err
== Z_STREAM_END
)
290 return (mbStatus
? (long)(nSize
- PZSTREAM
->avail_out
) : -1);
293 void ZCodec::ImplWriteBack()
295 sal_uIntPtr nAvail
= mnOutBufSize
- PZSTREAM
->avail_out
;
299 if (meState
== STATE_COMPRESS
&& mbUpdateCrc
)
300 UpdateCRC( mpOutBuf
, nAvail
);
301 mpOStm
->Write( PZSTREAM
->next_out
= mpOutBuf
, nAvail
);
302 PZSTREAM
->avail_out
= mnOutBufSize
;
306 void ZCodec::SetBreak( sal_uIntPtr nInToRead
)
308 mnInToRead
= nInToRead
;
311 sal_uIntPtr
ZCodec::GetBreak()
313 return ( mnInToRead
+ PZSTREAM
->avail_in
);
316 void ZCodec::SetCRC( sal_uIntPtr nCRC
)
322 void ZCodec::InitCompress()
324 assert(meState
== STATE_INIT
);
325 meState
= STATE_COMPRESS
;
326 mbStatus
= deflateInit2_(
327 PZSTREAM
, mnCompressLevel
, Z_DEFLATED
, MAX_WBITS
, MAX_MEM_LEVEL
,
328 Z_DEFAULT_STRATEGY
, ZLIB_VERSION
, sizeof (z_stream
)) >= 0;
329 mpOutBuf
= new sal_uInt8
[mnOutBufSize
];
330 PZSTREAM
->next_out
= mpOutBuf
;
331 PZSTREAM
->avail_out
= mnOutBufSize
;
334 void ZCodec::InitDecompress(SvStream
& inStream
)
336 assert(meState
== STATE_INIT
);
337 meState
= STATE_DECOMPRESS
;
338 if ( mbStatus
&& mbGzLib
)
340 sal_uInt8 n1
, n2
, j
, nMethod
, nFlags
;
341 for ( int i
= 0; i
< 2; i
++ ) // gz - magic number
343 inStream
.ReadUChar( j
);
344 if ( j
!= gz_magic
[ i
] )
347 inStream
.ReadUChar( nMethod
);
348 inStream
.ReadUChar( nFlags
);
349 if ( nMethod
!= Z_DEFLATED
)
351 if ( ( nFlags
& GZ_RESERVED
) != 0 )
353 /* Discard time, xflags and OS code: */
354 inStream
.SeekRel( 6 );
355 /* skip the extra field */
356 if ( nFlags
& GZ_EXTRA_FIELD
)
358 inStream
.ReadUChar( n1
).ReadUChar( n2
);
359 inStream
.SeekRel( n1
+ ( n2
<< 8 ) );
361 /* skip the original file name */
362 if ( nFlags
& GZ_ORIG_NAME
)
366 inStream
.ReadUChar( j
);
368 while ( j
&& !inStream
.IsEof() );
370 /* skip the .gz file comment */
371 if ( nFlags
& GZ_COMMENT
)
375 inStream
.ReadUChar( j
);
377 while ( j
&& !inStream
.IsEof() );
379 /* skip the header crc */
380 if ( nFlags
& GZ_HEAD_CRC
)
381 inStream
.SeekRel( 2 );
383 mbStatus
= inflateInit2( PZSTREAM
, -MAX_WBITS
) == Z_OK
;
387 mbStatus
= ( inflateInit( PZSTREAM
) >= 0 );
389 mpInBuf
= new sal_uInt8
[ mnInBufSize
];
392 void ZCodec::UpdateCRC ( sal_uInt8
* pSource
, long nDatSize
)
394 mnCRC
= rtl_crc32( mnCRC
, pSource
, nDatSize
);
397 bool ZCodec::AttemptDecompression(SvStream
& rIStm
, SvStream
& rOStm
, bool updateCrc
, bool gzLib
)
399 assert(meState
== STATE_INIT
);
400 sal_uLong nStreamPos
= rIStm
.Tell();
401 BeginCompression(ZCODEC_DEFAULT_COMPRESSION
, updateCrc
, gzLib
);
402 InitDecompress(rIStm
);
404 if ( !mbStatus
|| rIStm
.GetError() )
406 rIStm
.Seek(nStreamPos
);
409 rIStm
.Seek(nStreamPos
);
410 BeginCompression(ZCODEC_DEFAULT_COMPRESSION
, updateCrc
, gzLib
);
411 Decompress(rIStm
, rOStm
);
413 if( !mbStatus
|| rIStm
.GetError() || rOStm
.GetError() )
415 rIStm
.Seek(nStreamPos
);
418 rIStm
.Seek(nStreamPos
);
423 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */