xref: /AOO41X/main/tools/source/zcodec/zcodec.cxx (revision 3a2bd4d8359b8c4ed4da5f7c49d8578b6061adee)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_tools.hxx"
26 #include <tools/stream.hxx>
27 #ifndef _ZLIB_H
28 #ifdef SYSTEM_ZLIB
29 #include "zlib.h"
30 #else
31 #include "zlib/zlib.h"
32 #endif
33 #endif
34 #include <tools/zcodec.hxx>
35 #include <rtl/crc.h>
36 #include <osl/endian.h>
37 
38 // -----------
39 // - Defines -
40 // -----------
41 
42 #define PZSTREAM ((z_stream*) mpsC_Stream)
43 
44 /* gzip flag byte */
45 #define GZ_ASCII_FLAG   0x01 /* bit 0 set: file probably ascii text */
46 #define GZ_HEAD_CRC     0x02 /* bit 1 set: header CRC present */
47 #define GZ_EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
48 #define GZ_ORIG_NAME    0x08 /* bit 3 set: original file name present */
49 #define GZ_COMMENT      0x10 /* bit 4 set: file comment present */
50 #define GZ_RESERVED     0xE0 /* bits 5..7: reserved */
51 
52 static int gz_magic[2] = { 0x1f, 0x8b }; /* gzip magic header */
53 
54 
55 // ----------
56 // - ZCodec -
57 // ----------
58 
ZCodec(sal_uIntPtr nInBufSize,sal_uIntPtr nOutBufSize,sal_uIntPtr nMemUsage)59 ZCodec::ZCodec( sal_uIntPtr nInBufSize, sal_uIntPtr nOutBufSize, sal_uIntPtr nMemUsage )
60     : mnCRC(0)
61 {
62     mnMemUsage = nMemUsage;
63     mnInBufSize = nInBufSize;
64     mnOutBufSize = nOutBufSize;
65     mpsC_Stream = new z_stream;
66 }
67 
ZCodec(void)68 ZCodec::ZCodec( void )
69     : mnCRC(0)
70 {
71     mnMemUsage = MAX_MEM_USAGE;
72     mnInBufSize = DEFAULT_IN_BUFSIZE;
73     mnOutBufSize = DEFAULT_OUT_BUFSIZE;
74     mpsC_Stream = new z_stream;
75 }
76 
77 // ------------------------------------------------------------------------
78 
~ZCodec()79 ZCodec::~ZCodec()
80 {
81     delete (z_stream*) mpsC_Stream;
82 }
83 
84 // ------------------------------------------------------------------------
85 
BeginCompression(sal_uIntPtr nCompressMethod)86 void ZCodec::BeginCompression( sal_uIntPtr nCompressMethod )
87 {
88     mbInit = 0;
89     mbStatus = sal_True;
90     mbFinish = sal_False;
91     mpIStm = mpOStm = NULL;
92     mnInToRead = 0xffffffff;
93     mpInBuf = mpOutBuf = NULL;
94     PZSTREAM->total_out = PZSTREAM->total_in = 0;
95     mnCompressMethod = nCompressMethod;
96     PZSTREAM->zalloc = ( alloc_func )0;
97     PZSTREAM->zfree = ( free_func )0;
98     PZSTREAM->opaque = ( voidpf )0;
99     PZSTREAM->avail_out = PZSTREAM->avail_in = 0;
100 }
101 
102 // ------------------------------------------------------------------------
103 
EndCompression()104 long ZCodec::EndCompression()
105 {
106     long retvalue = 0;
107 
108     if ( mbInit != 0 )
109     {
110         if ( mbInit & 2 )   // 1->decompress, 3->compress
111         {
112             do
113             {
114                 ImplWriteBack();
115             }
116             while ( deflate( PZSTREAM, Z_FINISH ) != Z_STREAM_END );
117 
118             ImplWriteBack();
119 
120             retvalue = PZSTREAM->total_in;
121             deflateEnd( PZSTREAM );
122         }
123         else
124         {
125             retvalue = PZSTREAM->total_out;
126             inflateEnd( PZSTREAM );
127         }
128         delete[] mpOutBuf;
129         delete[] mpInBuf;
130     }
131     return ( mbStatus ) ? retvalue : -1;
132 }
133 
134 
135 // ------------------------------------------------------------------------
136 
Compress(SvStream & rIStm,SvStream & rOStm)137 long ZCodec::Compress( SvStream& rIStm, SvStream& rOStm )
138 {
139     long nOldTotal_In = PZSTREAM->total_in;
140 
141     if ( mbInit == 0 )
142     {
143         mpIStm = &rIStm;
144         mpOStm = &rOStm;
145         ImplInitBuf( sal_False );
146         mpInBuf = new sal_uInt8[ mnInBufSize ];
147     }
148     while (( PZSTREAM->avail_in = mpIStm->Read( PZSTREAM->next_in = mpInBuf, mnInBufSize )) != 0 )
149     {
150         if ( PZSTREAM->avail_out == 0 )
151             ImplWriteBack();
152         if ( deflate( PZSTREAM, Z_NO_FLUSH ) < 0 )
153         {
154             mbStatus = sal_False;
155             break;
156         }
157     };
158     return ( mbStatus ) ? (long)(PZSTREAM->total_in - nOldTotal_In) : -1;
159 }
160 
161 // ------------------------------------------------------------------------
162 
Decompress(SvStream & rIStm,SvStream & rOStm)163 long ZCodec::Decompress( SvStream& rIStm, SvStream& rOStm )
164 {
165     int err;
166     sal_uIntPtr nInToRead;
167     long    nOldTotal_Out = PZSTREAM->total_out;
168 
169     if ( mbFinish )
170         return PZSTREAM->total_out - nOldTotal_Out;
171 
172     if ( mbInit == 0 )
173     {
174         mpIStm = &rIStm;
175         mpOStm = &rOStm;
176         ImplInitBuf( sal_True );
177         PZSTREAM->next_out = mpOutBuf = new sal_uInt8[ PZSTREAM->avail_out = mnOutBufSize ];
178     }
179     do
180     {
181         if ( PZSTREAM->avail_out == 0 ) ImplWriteBack();
182         if ( PZSTREAM->avail_in == 0 && mnInToRead )
183         {
184             nInToRead = ( mnInBufSize > mnInToRead ) ? mnInToRead : mnInBufSize;
185             PZSTREAM->avail_in = mpIStm->Read( PZSTREAM->next_in = mpInBuf, nInToRead );
186             mnInToRead -= nInToRead;
187 
188             if ( mnCompressMethod & ZCODEC_UPDATE_CRC )
189                 mnCRC = UpdateCRC( mnCRC, mpInBuf, nInToRead );
190 
191         }
192         err = inflate( PZSTREAM, Z_NO_FLUSH );
193         if ( err < 0 )
194         {
195             mbStatus = sal_False;
196             break;
197         }
198 
199     }
200     while ( ( err != Z_STREAM_END) && ( PZSTREAM->avail_in || mnInToRead ) );
201     ImplWriteBack();
202 
203     if ( err == Z_STREAM_END )
204         mbFinish = sal_True;
205     return ( mbStatus ) ? (long)(PZSTREAM->total_out - nOldTotal_Out) : -1;
206 }
207 
208 // ------------------------------------------------------------------------
209 
Write(SvStream & rOStm,const sal_uInt8 * pData,sal_uIntPtr nSize)210 long ZCodec::Write( SvStream& rOStm, const sal_uInt8* pData, sal_uIntPtr nSize )
211 {
212     if ( mbInit == 0 )
213     {
214         mpOStm = &rOStm;
215         ImplInitBuf( sal_False );
216     }
217 
218     PZSTREAM->avail_in = nSize;
219     PZSTREAM->next_in = (unsigned char*)pData;
220 
221     while ( PZSTREAM->avail_in || ( PZSTREAM->avail_out == 0 ) )
222     {
223         if ( PZSTREAM->avail_out == 0 )
224             ImplWriteBack();
225 
226         if ( deflate( PZSTREAM, Z_NO_FLUSH ) < 0 )
227         {
228             mbStatus = sal_False;
229             break;
230         }
231     }
232     return ( mbStatus ) ? (long)nSize : -1;
233 }
234 
235 // ------------------------------------------------------------------------
236 
Read(SvStream & rIStm,sal_uInt8 * pData,sal_uIntPtr nSize)237 long ZCodec::Read( SvStream& rIStm, sal_uInt8* pData, sal_uIntPtr nSize )
238 {
239     int err;
240     sal_uIntPtr nInToRead;
241 
242     if ( mbFinish )
243         return 0;           // PZSTREAM->total_out;
244 
245     mpIStm = &rIStm;
246     if ( mbInit == 0 )
247     {
248         ImplInitBuf( sal_True );
249     }
250     PZSTREAM->avail_out = nSize;
251     PZSTREAM->next_out = pData;
252     do
253     {
254         if ( PZSTREAM->avail_in == 0 && mnInToRead )
255         {
256             nInToRead = (mnInBufSize > mnInToRead) ? mnInToRead : mnInBufSize;
257             PZSTREAM->avail_in = mpIStm->Read (
258                 PZSTREAM->next_in = mpInBuf, nInToRead);
259             mnInToRead -= nInToRead;
260 
261             if ( mnCompressMethod & ZCODEC_UPDATE_CRC )
262                 mnCRC = UpdateCRC( mnCRC, mpInBuf, nInToRead );
263 
264         }
265         err = inflate( PZSTREAM, Z_NO_FLUSH );
266         if ( err < 0 )
267         {
268             // Accept Z_BUF_ERROR as EAGAIN or EWOULDBLOCK.
269             mbStatus = (err == Z_BUF_ERROR);
270             break;
271         }
272     }
273     while ( (err != Z_STREAM_END) &&
274             (PZSTREAM->avail_out != 0) &&
275             (PZSTREAM->avail_in || mnInToRead) );
276     if ( err == Z_STREAM_END )
277         mbFinish = sal_True;
278 
279     return (mbStatus ? (long)(nSize - PZSTREAM->avail_out) : -1);
280 }
281 
282 // ------------------------------------------------------------------------
283 
ReadAsynchron(SvStream & rIStm,sal_uInt8 * pData,sal_uIntPtr nSize)284 long ZCodec::ReadAsynchron( SvStream& rIStm, sal_uInt8* pData, sal_uIntPtr nSize )
285 {
286     int err = 0;
287     sal_uIntPtr nInToRead;
288 
289     if ( mbFinish )
290         return 0;           // PZSTREAM->total_out;
291 
292     if ( mbInit == 0 )
293     {
294         mpIStm = &rIStm;
295         ImplInitBuf( sal_True );
296     }
297     PZSTREAM->avail_out = nSize;
298     PZSTREAM->next_out = pData;
299     do
300     {
301         if ( PZSTREAM->avail_in == 0 && mnInToRead )
302         {
303             nInToRead = (mnInBufSize > mnInToRead) ? mnInToRead : mnInBufSize;
304 
305             sal_uIntPtr nStreamPos = rIStm.Tell();
306             rIStm.Seek( STREAM_SEEK_TO_END );
307             sal_uIntPtr nMaxPos = rIStm.Tell();
308             rIStm.Seek( nStreamPos );
309             if ( ( nMaxPos - nStreamPos ) < nInToRead )
310             {
311                 rIStm.SetError( ERRCODE_IO_PENDING );
312                 err= ! Z_STREAM_END; // TODO What is appropriate code for this?
313                 break;
314             }
315 
316             PZSTREAM->avail_in = mpIStm->Read (
317                 PZSTREAM->next_in = mpInBuf, nInToRead);
318             mnInToRead -= nInToRead;
319 
320             if ( mnCompressMethod & ZCODEC_UPDATE_CRC )
321                 mnCRC = UpdateCRC( mnCRC, mpInBuf, nInToRead );
322 
323         }
324         err = inflate( PZSTREAM, Z_NO_FLUSH );
325         if ( err < 0 )
326         {
327             // Accept Z_BUF_ERROR as EAGAIN or EWOULDBLOCK.
328             mbStatus = (err == Z_BUF_ERROR);
329             break;
330         }
331     }
332     while ( (err != Z_STREAM_END) &&
333             (PZSTREAM->avail_out != 0) &&
334             (PZSTREAM->avail_in || mnInToRead) );
335     if ( err == Z_STREAM_END )
336         mbFinish = sal_True;
337 
338     return (mbStatus ? (long)(nSize - PZSTREAM->avail_out) : -1);
339 }
340 
341 // ------------------------------------------------------------------------
342 
ImplWriteBack()343 void ZCodec::ImplWriteBack()
344 {
345     sal_uIntPtr nAvail = mnOutBufSize - PZSTREAM->avail_out;
346 
347     if ( nAvail )
348     {
349         if ( mbInit & 2 && ( mnCompressMethod & ZCODEC_UPDATE_CRC ) )
350             mnCRC = UpdateCRC( mnCRC, mpOutBuf, nAvail );
351         mpOStm->Write( PZSTREAM->next_out = mpOutBuf, nAvail );
352         PZSTREAM->avail_out = mnOutBufSize;
353     }
354 }
355 
356 // ------------------------------------------------------------------------
357 
SetBreak(sal_uIntPtr nInToRead)358 void ZCodec::SetBreak( sal_uIntPtr nInToRead )
359 {
360     mnInToRead = nInToRead;
361 }
362 
363 // ------------------------------------------------------------------------
364 
GetBreak(void)365 sal_uIntPtr ZCodec::GetBreak( void )
366 {
367     return ( mnInToRead + PZSTREAM->avail_in );
368 }
369 
370 // ------------------------------------------------------------------------
371 
SetCRC(sal_uIntPtr nCRC)372 void ZCodec::SetCRC( sal_uIntPtr nCRC )
373 {
374     mnCRC = nCRC;
375 }
376 
377 // ------------------------------------------------------------------------
378 
GetCRC()379 sal_uIntPtr ZCodec::GetCRC()
380 {
381     return mnCRC;
382 }
383 
384 // ------------------------------------------------------------------------
385 
ImplInitBuf(sal_Bool nIOFlag)386 void ZCodec::ImplInitBuf ( sal_Bool nIOFlag )
387 {
388     if ( mbInit == 0 )
389     {
390         if ( nIOFlag )
391         {
392             mbInit = 1;
393             if ( mbStatus && ( mnCompressMethod & ZCODEC_GZ_LIB ) )
394             {
395                 sal_uInt8 n1, n2, j, nMethod, nFlags;
396                 for ( int i = 0; i < 2; i++ )   // gz - magic number
397                 {
398                     *mpIStm >> j;
399                     if ( j != gz_magic[ i ] )
400                         mbStatus = sal_False;
401                 }
402                 *mpIStm >> nMethod;
403                 *mpIStm >> nFlags;
404                 if ( nMethod != Z_DEFLATED )
405                     mbStatus = sal_False;
406                 if ( ( nFlags & GZ_RESERVED ) != 0 )
407                     mbStatus = sal_False;
408                 /* Discard time, xflags and OS code: */
409                 mpIStm->SeekRel( 6 );
410                 /* skip the extra field */
411                 if ( nFlags & GZ_EXTRA_FIELD )
412                 {
413                     *mpIStm >> n1 >> n2;
414                     mpIStm->SeekRel( n1 + ( n2 << 8 ) );
415                 }
416                 /* skip the original file name */
417                 if ( nFlags & GZ_ORIG_NAME)
418                 {
419                     do
420                     {
421                         *mpIStm >> j;
422                     }
423                     while ( j && !mpIStm->IsEof() );
424                 }
425                 /* skip the .gz file comment */
426                 if ( nFlags & GZ_COMMENT )
427                 {
428                     do
429                     {
430                         *mpIStm >> j;
431                     }
432                     while ( j && !mpIStm->IsEof() );
433                 }
434                 /* skip the header crc */
435                 if ( nFlags & GZ_HEAD_CRC )
436                     mpIStm->SeekRel( 2 );
437                 if ( mbStatus )
438                     mbStatus = ( inflateInit2( PZSTREAM, -MAX_WBITS) != Z_OK ) ? sal_False : sal_True;
439             }
440             else
441             {
442                 mbStatus = ( inflateInit( PZSTREAM ) >= 0 );
443             }
444             mpInBuf = new sal_uInt8[ mnInBufSize ];
445         }
446         else
447         {
448             mbInit = 3;
449 
450             mbStatus = ( deflateInit2_( PZSTREAM, mnCompressMethod & 0xff, Z_DEFLATED,
451                 MAX_WBITS, mnMemUsage, ( mnCompressMethod >> 8 ) & 0xff,
452                     ZLIB_VERSION, sizeof( z_stream ) ) >= 0 );
453 
454             PZSTREAM->next_out = mpOutBuf = new sal_uInt8[ PZSTREAM->avail_out = mnOutBufSize ];
455         }
456     }
457 }
458 
459 // ------------------------------------------------------------------------
460 
UpdateCRC(sal_uIntPtr nLatestCRC,sal_uIntPtr nNumber)461 sal_uIntPtr ZCodec::UpdateCRC ( sal_uIntPtr nLatestCRC, sal_uIntPtr nNumber )
462 {
463 
464 #ifdef OSL_LITENDIAN
465     nNumber = SWAPLONG( nNumber );
466 #endif
467     return rtl_crc32( nLatestCRC, &nNumber, 4 );
468 }
469 
470 // ------------------------------------------------------------------------
471 
UpdateCRC(sal_uIntPtr nLatestCRC,sal_uInt8 * pSource,long nDatSize)472 sal_uIntPtr ZCodec::UpdateCRC ( sal_uIntPtr nLatestCRC, sal_uInt8* pSource, long nDatSize)
473 {
474     return rtl_crc32( nLatestCRC, pSource, nDatSize );
475 }
476 
477 // ------------------------------------------------------------------------
478 
BeginCompression(sal_uIntPtr nCompressMethod)479 void GZCodec::BeginCompression( sal_uIntPtr nCompressMethod )
480 {
481     ZCodec::BeginCompression( nCompressMethod | ZCODEC_GZ_LIB );
482 };
483