xref: /aoo41x/main/tools/source/zcodec/zcodec.cxx (revision cdf0e10c)
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