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 mbInit = 0;
131 }
132 return ( mbStatus ) ? retvalue : -1;
133 }
134
135
136 // ------------------------------------------------------------------------
137
Compress(SvStream & rIStm,SvStream & rOStm)138 long ZCodec::Compress( SvStream& rIStm, SvStream& rOStm )
139 {
140 long nOldTotal_In = PZSTREAM->total_in;
141
142 if ( mbInit == 0 )
143 {
144 mpIStm = &rIStm;
145 mpOStm = &rOStm;
146 ImplInitBuf( sal_False );
147 mpInBuf = new sal_uInt8[ mnInBufSize ];
148 }
149 while (( PZSTREAM->avail_in = mpIStm->Read( PZSTREAM->next_in = mpInBuf, mnInBufSize )) != 0 )
150 {
151 if ( PZSTREAM->avail_out == 0 )
152 ImplWriteBack();
153 if ( deflate( PZSTREAM, Z_NO_FLUSH ) < 0 )
154 {
155 mbStatus = sal_False;
156 break;
157 }
158 };
159 return ( mbStatus ) ? (long)(PZSTREAM->total_in - nOldTotal_In) : -1;
160 }
161
162 // ------------------------------------------------------------------------
163
Decompress(SvStream & rIStm,SvStream & rOStm)164 long ZCodec::Decompress( SvStream& rIStm, SvStream& rOStm )
165 {
166 int err;
167 sal_uIntPtr nInToRead;
168 long nOldTotal_Out = PZSTREAM->total_out;
169
170 if ( mbFinish )
171 return PZSTREAM->total_out - nOldTotal_Out;
172
173 if ( mbInit == 0 )
174 {
175 mpIStm = &rIStm;
176 mpOStm = &rOStm;
177 ImplInitBuf( sal_True );
178 PZSTREAM->next_out = mpOutBuf = new sal_uInt8[ PZSTREAM->avail_out = mnOutBufSize ];
179 }
180 do
181 {
182 if ( PZSTREAM->avail_out == 0 ) ImplWriteBack();
183 if ( PZSTREAM->avail_in == 0 && mnInToRead )
184 {
185 nInToRead = ( mnInBufSize > mnInToRead ) ? mnInToRead : mnInBufSize;
186 PZSTREAM->avail_in = mpIStm->Read( PZSTREAM->next_in = mpInBuf, nInToRead );
187 mnInToRead -= nInToRead;
188
189 if ( mnCompressMethod & ZCODEC_UPDATE_CRC )
190 mnCRC = UpdateCRC( mnCRC, mpInBuf, nInToRead );
191
192 }
193 err = inflate( PZSTREAM, Z_NO_FLUSH );
194 if ( err < 0 )
195 {
196 mbStatus = sal_False;
197 break;
198 }
199
200 }
201 while ( ( err != Z_STREAM_END) && ( PZSTREAM->avail_in || mnInToRead ) );
202 ImplWriteBack();
203
204 if ( err == Z_STREAM_END )
205 mbFinish = sal_True;
206 return ( mbStatus ) ? (long)(PZSTREAM->total_out - nOldTotal_Out) : -1;
207 }
208
209 // ------------------------------------------------------------------------
210
Write(SvStream & rOStm,const sal_uInt8 * pData,sal_uIntPtr nSize)211 long ZCodec::Write( SvStream& rOStm, const sal_uInt8* pData, sal_uIntPtr nSize )
212 {
213 if ( mbInit == 0 )
214 {
215 mpOStm = &rOStm;
216 ImplInitBuf( sal_False );
217 }
218
219 PZSTREAM->avail_in = nSize;
220 PZSTREAM->next_in = (unsigned char*)pData;
221
222 while ( PZSTREAM->avail_in || ( PZSTREAM->avail_out == 0 ) )
223 {
224 if ( PZSTREAM->avail_out == 0 )
225 ImplWriteBack();
226
227 if ( deflate( PZSTREAM, Z_NO_FLUSH ) < 0 )
228 {
229 mbStatus = sal_False;
230 break;
231 }
232 }
233 return ( mbStatus ) ? (long)nSize : -1;
234 }
235
236 // ------------------------------------------------------------------------
237
Read(SvStream & rIStm,sal_uInt8 * pData,sal_uIntPtr nSize)238 long ZCodec::Read( SvStream& rIStm, sal_uInt8* pData, sal_uIntPtr nSize )
239 {
240 int err;
241 sal_uIntPtr nInToRead;
242
243 if ( mbFinish )
244 return 0; // PZSTREAM->total_out;
245
246 mpIStm = &rIStm;
247 if ( mbInit == 0 )
248 {
249 ImplInitBuf( sal_True );
250 }
251 PZSTREAM->avail_out = nSize;
252 PZSTREAM->next_out = pData;
253 do
254 {
255 if ( PZSTREAM->avail_in == 0 && mnInToRead )
256 {
257 nInToRead = (mnInBufSize > mnInToRead) ? mnInToRead : mnInBufSize;
258 PZSTREAM->avail_in = mpIStm->Read (
259 PZSTREAM->next_in = mpInBuf, nInToRead);
260 mnInToRead -= nInToRead;
261
262 if ( mnCompressMethod & ZCODEC_UPDATE_CRC )
263 mnCRC = UpdateCRC( mnCRC, mpInBuf, nInToRead );
264
265 }
266 err = inflate( PZSTREAM, Z_NO_FLUSH );
267 if ( err < 0 )
268 {
269 // Accept Z_BUF_ERROR as EAGAIN or EWOULDBLOCK.
270 mbStatus = (err == Z_BUF_ERROR);
271 break;
272 }
273 }
274 while ( (err != Z_STREAM_END) &&
275 (PZSTREAM->avail_out != 0) &&
276 (PZSTREAM->avail_in || mnInToRead) );
277 if ( err == Z_STREAM_END )
278 mbFinish = sal_True;
279
280 return (mbStatus ? (long)(nSize - PZSTREAM->avail_out) : -1);
281 }
282
283 // ------------------------------------------------------------------------
284
ReadAsynchron(SvStream & rIStm,sal_uInt8 * pData,sal_uIntPtr nSize)285 long ZCodec::ReadAsynchron( SvStream& rIStm, sal_uInt8* pData, sal_uIntPtr nSize )
286 {
287 int err = 0;
288 sal_uIntPtr nInToRead;
289
290 if ( mbFinish )
291 return 0; // PZSTREAM->total_out;
292
293 if ( mbInit == 0 )
294 {
295 mpIStm = &rIStm;
296 ImplInitBuf( sal_True );
297 }
298 PZSTREAM->avail_out = nSize;
299 PZSTREAM->next_out = pData;
300 do
301 {
302 if ( PZSTREAM->avail_in == 0 && mnInToRead )
303 {
304 nInToRead = (mnInBufSize > mnInToRead) ? mnInToRead : mnInBufSize;
305
306 sal_uIntPtr nStreamPos = rIStm.Tell();
307 rIStm.Seek( STREAM_SEEK_TO_END );
308 sal_uIntPtr nMaxPos = rIStm.Tell();
309 rIStm.Seek( nStreamPos );
310 if ( ( nMaxPos - nStreamPos ) < nInToRead )
311 {
312 rIStm.SetError( ERRCODE_IO_PENDING );
313 err= ! Z_STREAM_END; // TODO What is appropriate code for this?
314 break;
315 }
316
317 PZSTREAM->avail_in = mpIStm->Read (
318 PZSTREAM->next_in = mpInBuf, nInToRead);
319 mnInToRead -= nInToRead;
320
321 if ( mnCompressMethod & ZCODEC_UPDATE_CRC )
322 mnCRC = UpdateCRC( mnCRC, mpInBuf, nInToRead );
323
324 }
325 err = inflate( PZSTREAM, Z_NO_FLUSH );
326 if ( err < 0 )
327 {
328 // Accept Z_BUF_ERROR as EAGAIN or EWOULDBLOCK.
329 mbStatus = (err == Z_BUF_ERROR);
330 break;
331 }
332 }
333 while ( (err != Z_STREAM_END) &&
334 (PZSTREAM->avail_out != 0) &&
335 (PZSTREAM->avail_in || mnInToRead) );
336 if ( err == Z_STREAM_END )
337 mbFinish = sal_True;
338
339 return (mbStatus ? (long)(nSize - PZSTREAM->avail_out) : -1);
340 }
341
342 // ------------------------------------------------------------------------
343
ImplWriteBack()344 void ZCodec::ImplWriteBack()
345 {
346 sal_uIntPtr nAvail = mnOutBufSize - PZSTREAM->avail_out;
347
348 if ( nAvail )
349 {
350 if ( mbInit & 2 && ( mnCompressMethod & ZCODEC_UPDATE_CRC ) )
351 mnCRC = UpdateCRC( mnCRC, mpOutBuf, nAvail );
352 mpOStm->Write( PZSTREAM->next_out = mpOutBuf, nAvail );
353 PZSTREAM->avail_out = mnOutBufSize;
354 }
355 }
356
357 // ------------------------------------------------------------------------
358
SetBreak(sal_uIntPtr nInToRead)359 void ZCodec::SetBreak( sal_uIntPtr nInToRead )
360 {
361 mnInToRead = nInToRead;
362 }
363
364 // ------------------------------------------------------------------------
365
GetBreak(void)366 sal_uIntPtr ZCodec::GetBreak( void )
367 {
368 return ( mnInToRead + PZSTREAM->avail_in );
369 }
370
371 // ------------------------------------------------------------------------
372
SetCRC(sal_uIntPtr nCRC)373 void ZCodec::SetCRC( sal_uIntPtr nCRC )
374 {
375 mnCRC = nCRC;
376 }
377
378 // ------------------------------------------------------------------------
379
GetCRC()380 sal_uIntPtr ZCodec::GetCRC()
381 {
382 return mnCRC;
383 }
384
385 // ------------------------------------------------------------------------
386
ImplInitBuf(sal_Bool nIOFlag)387 void ZCodec::ImplInitBuf ( sal_Bool nIOFlag )
388 {
389 if ( mbInit == 0 )
390 {
391 if ( nIOFlag )
392 {
393 mbInit = 1;
394 if ( mbStatus && ( mnCompressMethod & ZCODEC_GZ_LIB ) )
395 {
396 sal_uInt8 n1, n2, j, nMethod, nFlags;
397 for ( int i = 0; i < 2; i++ ) // gz - magic number
398 {
399 *mpIStm >> j;
400 if ( j != gz_magic[ i ] )
401 mbStatus = sal_False;
402 }
403 *mpIStm >> nMethod;
404 *mpIStm >> nFlags;
405 if ( nMethod != Z_DEFLATED )
406 mbStatus = sal_False;
407 if ( ( nFlags & GZ_RESERVED ) != 0 )
408 mbStatus = sal_False;
409 /* Discard time, xflags and OS code: */
410 mpIStm->SeekRel( 6 );
411 /* skip the extra field */
412 if ( nFlags & GZ_EXTRA_FIELD )
413 {
414 *mpIStm >> n1 >> n2;
415 mpIStm->SeekRel( n1 + ( n2 << 8 ) );
416 }
417 /* skip the original file name */
418 if ( nFlags & GZ_ORIG_NAME)
419 {
420 do
421 {
422 *mpIStm >> j;
423 }
424 while ( j && !mpIStm->IsEof() );
425 }
426 /* skip the .gz file comment */
427 if ( nFlags & GZ_COMMENT )
428 {
429 do
430 {
431 *mpIStm >> j;
432 }
433 while ( j && !mpIStm->IsEof() );
434 }
435 /* skip the header crc */
436 if ( nFlags & GZ_HEAD_CRC )
437 mpIStm->SeekRel( 2 );
438 if ( mbStatus )
439 mbStatus = ( inflateInit2( PZSTREAM, -MAX_WBITS) != Z_OK ) ? sal_False : sal_True;
440 }
441 else
442 {
443 mbStatus = ( inflateInit( PZSTREAM ) >= 0 );
444 }
445 mpInBuf = new sal_uInt8[ mnInBufSize ];
446 }
447 else
448 {
449 mbInit = 3;
450
451 mbStatus = ( deflateInit2_( PZSTREAM, mnCompressMethod & 0xff, Z_DEFLATED,
452 MAX_WBITS, mnMemUsage, ( mnCompressMethod >> 8 ) & 0xff,
453 ZLIB_VERSION, sizeof( z_stream ) ) >= 0 );
454
455 PZSTREAM->next_out = mpOutBuf = new sal_uInt8[ PZSTREAM->avail_out = mnOutBufSize ];
456 }
457 }
458 }
459
460 // ------------------------------------------------------------------------
461
UpdateCRC(sal_uIntPtr nLatestCRC,sal_uIntPtr nNumber)462 sal_uIntPtr ZCodec::UpdateCRC ( sal_uIntPtr nLatestCRC, sal_uIntPtr nNumber )
463 {
464
465 #ifdef OSL_LITENDIAN
466 nNumber = SWAPLONG( nNumber );
467 #endif
468 return rtl_crc32( nLatestCRC, &nNumber, 4 );
469 }
470
471 // ------------------------------------------------------------------------
472
UpdateCRC(sal_uIntPtr nLatestCRC,sal_uInt8 * pSource,long nDatSize)473 sal_uIntPtr ZCodec::UpdateCRC ( sal_uIntPtr nLatestCRC, sal_uInt8* pSource, long nDatSize)
474 {
475 return rtl_crc32( nLatestCRC, pSource, nDatSize );
476 }
477
478 // ------------------------------------------------------------------------
479
BeginCompression(sal_uIntPtr nCompressMethod)480 void GZCodec::BeginCompression( sal_uIntPtr nCompressMethod )
481 {
482 ZCodec::BeginCompression( nCompressMethod | ZCODEC_GZ_LIB );
483 };
484