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