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