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