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 84 : ZCodec::ZCodec( sal_uIntPtr nInBufSize, sal_uIntPtr nOutBufSize, sal_uIntPtr nMemUsage )
47 84 : : mnCRC(0)
48 : {
49 84 : mnMemUsage = nMemUsage;
50 84 : mnInBufSize = nInBufSize;
51 84 : mnOutBufSize = nOutBufSize;
52 84 : mpsC_Stream = new z_stream;
53 84 : }
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 142 : ZCodec::~ZCodec()
65 : {
66 84 : delete (z_stream*) mpsC_Stream;
67 142 : }
68 :
69 79 : void ZCodec::BeginCompression( sal_uIntPtr nCompressMethod )
70 : {
71 79 : mbInit = 0;
72 79 : mbStatus = sal_True;
73 79 : mbFinish = sal_False;
74 79 : mpIStm = mpOStm = NULL;
75 79 : mnInToRead = 0xffffffff;
76 79 : mpInBuf = mpOutBuf = NULL;
77 79 : PZSTREAM->total_out = PZSTREAM->total_in = 0;
78 79 : mnCompressMethod = nCompressMethod;
79 79 : PZSTREAM->zalloc = ( alloc_func )0;
80 79 : PZSTREAM->zfree = ( free_func )0;
81 79 : PZSTREAM->opaque = ( voidpf )0;
82 79 : PZSTREAM->avail_out = PZSTREAM->avail_in = 0;
83 79 : }
84 :
85 79 : long ZCodec::EndCompression()
86 : {
87 79 : long retvalue = 0;
88 :
89 79 : if ( mbInit != 0 )
90 : {
91 79 : if ( mbInit & 2 ) // 1->decompress, 3->compress
92 : {
93 32 : do
94 : {
95 32 : ImplWriteBack();
96 : }
97 32 : while ( deflate( PZSTREAM, Z_FINISH ) != Z_STREAM_END );
98 :
99 32 : ImplWriteBack();
100 :
101 32 : retvalue = PZSTREAM->total_in;
102 32 : deflateEnd( PZSTREAM );
103 : }
104 : else
105 : {
106 47 : retvalue = PZSTREAM->total_out;
107 47 : inflateEnd( PZSTREAM );
108 : }
109 79 : delete[] mpOutBuf;
110 79 : delete[] mpInBuf;
111 : }
112 79 : 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 26 : long ZCodec::Decompress( SvStream& rIStm, SvStream& rOStm )
140 : {
141 : int err;
142 : sal_uIntPtr nInToRead;
143 26 : long nOldTotal_Out = PZSTREAM->total_out;
144 :
145 26 : if ( mbFinish )
146 0 : return PZSTREAM->total_out - nOldTotal_Out;
147 :
148 26 : if ( mbInit == 0 )
149 : {
150 26 : mpIStm = &rIStm;
151 26 : mpOStm = &rOStm;
152 26 : ImplInitBuf( sal_True );
153 26 : PZSTREAM->next_out = mpOutBuf = new sal_uInt8[ PZSTREAM->avail_out = mnOutBufSize ];
154 : }
155 29 : do
156 : {
157 32 : if ( PZSTREAM->avail_out == 0 ) ImplWriteBack();
158 32 : if ( PZSTREAM->avail_in == 0 && mnInToRead )
159 : {
160 26 : nInToRead = ( mnInBufSize > mnInToRead ) ? mnInToRead : mnInBufSize;
161 26 : PZSTREAM->avail_in = mpIStm->Read( PZSTREAM->next_in = mpInBuf, nInToRead );
162 26 : mnInToRead -= nInToRead;
163 :
164 26 : if ( mnCompressMethod & ZCODEC_UPDATE_CRC )
165 0 : mnCRC = UpdateCRC( mnCRC, mpInBuf, nInToRead );
166 :
167 : }
168 32 : err = inflate( PZSTREAM, Z_NO_FLUSH );
169 32 : if ( err < 0 )
170 : {
171 3 : mbStatus = sal_False;
172 3 : break;
173 : }
174 :
175 : }
176 : while ( ( err != Z_STREAM_END) && ( PZSTREAM->avail_in || mnInToRead ) );
177 26 : ImplWriteBack();
178 :
179 26 : if ( err == Z_STREAM_END )
180 23 : mbFinish = sal_True;
181 26 : return ( mbStatus ) ? (long)(PZSTREAM->total_out - nOldTotal_Out) : -1;
182 : }
183 :
184 1653 : long ZCodec::Write( SvStream& rOStm, const sal_uInt8* pData, sal_uIntPtr nSize )
185 : {
186 1653 : if ( mbInit == 0 )
187 : {
188 32 : mpOStm = &rOStm;
189 32 : ImplInitBuf( sal_False );
190 : }
191 :
192 1653 : PZSTREAM->avail_in = nSize;
193 1653 : PZSTREAM->next_in = (unsigned char*)pData;
194 :
195 4959 : while ( PZSTREAM->avail_in || ( PZSTREAM->avail_out == 0 ) )
196 : {
197 1653 : if ( PZSTREAM->avail_out == 0 )
198 0 : ImplWriteBack();
199 :
200 1653 : if ( deflate( PZSTREAM, Z_NO_FLUSH ) < 0 )
201 : {
202 0 : mbStatus = sal_False;
203 0 : break;
204 : }
205 : }
206 1653 : 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 2109 : long ZCodec::ReadAsynchron( SvStream& rIStm, sal_uInt8* pData, sal_uIntPtr nSize )
255 : {
256 2109 : int err = 0;
257 : sal_uIntPtr nInToRead;
258 :
259 2109 : if ( mbFinish )
260 0 : return 0; // PZSTREAM->total_out;
261 :
262 2109 : if ( mbInit == 0 )
263 : {
264 21 : mpIStm = &rIStm;
265 21 : ImplInitBuf( sal_True );
266 : }
267 2109 : PZSTREAM->avail_out = nSize;
268 2109 : PZSTREAM->next_out = pData;
269 2108 : do
270 : {
271 2109 : if ( PZSTREAM->avail_in == 0 && mnInToRead )
272 : {
273 23 : nInToRead = (mnInBufSize > mnInToRead) ? mnInToRead : mnInBufSize;
274 :
275 23 : sal_uIntPtr nStreamPos = rIStm.Tell();
276 23 : rIStm.Seek( STREAM_SEEK_TO_END );
277 23 : sal_uIntPtr nMaxPos = rIStm.Tell();
278 23 : rIStm.Seek( nStreamPos );
279 23 : 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 23 : PZSTREAM->next_in = mpInBuf, nInToRead);
288 23 : mnInToRead -= nInToRead;
289 :
290 23 : if ( mnCompressMethod & ZCODEC_UPDATE_CRC )
291 23 : mnCRC = UpdateCRC( mnCRC, mpInBuf, nInToRead );
292 :
293 : }
294 2109 : err = inflate( PZSTREAM, Z_NO_FLUSH );
295 2109 : if ( err < 0 )
296 : {
297 : // Accept Z_BUF_ERROR as EAGAIN or EWOULDBLOCK.
298 1 : mbStatus = (err == Z_BUF_ERROR);
299 1 : break;
300 : }
301 : }
302 : while ( (err != Z_STREAM_END) &&
303 : (PZSTREAM->avail_out != 0) &&
304 : (PZSTREAM->avail_in || mnInToRead) );
305 2109 : if ( err == Z_STREAM_END )
306 20 : mbFinish = sal_True;
307 :
308 2109 : return (mbStatus ? (long)(nSize - PZSTREAM->avail_out) : -1);
309 : }
310 :
311 96 : void ZCodec::ImplWriteBack()
312 : {
313 96 : sal_uIntPtr nAvail = mnOutBufSize - PZSTREAM->avail_out;
314 :
315 96 : if ( nAvail )
316 : {
317 96 : if ( mbInit & 2 && ( mnCompressMethod & ZCODEC_UPDATE_CRC ) )
318 64 : mnCRC = UpdateCRC( mnCRC, mpOutBuf, nAvail );
319 96 : mpOStm->Write( PZSTREAM->next_out = mpOutBuf, nAvail );
320 96 : PZSTREAM->avail_out = mnOutBufSize;
321 : }
322 96 : }
323 :
324 23 : void ZCodec::SetBreak( sal_uIntPtr nInToRead )
325 : {
326 23 : mnInToRead = nInToRead;
327 23 : }
328 :
329 2109 : sal_uIntPtr ZCodec::GetBreak( void )
330 : {
331 2109 : return ( mnInToRead + PZSTREAM->avail_in );
332 : }
333 :
334 32 : void ZCodec::SetCRC( sal_uIntPtr nCRC )
335 : {
336 32 : mnCRC = nCRC;
337 32 : }
338 :
339 32 : sal_uIntPtr ZCodec::GetCRC()
340 : {
341 32 : return mnCRC;
342 : }
343 :
344 79 : void ZCodec::ImplInitBuf ( sal_Bool nIOFlag )
345 : {
346 79 : if ( mbInit == 0 )
347 : {
348 79 : if ( nIOFlag )
349 : {
350 47 : mbInit = 1;
351 47 : 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 47 : mbStatus = ( inflateInit( PZSTREAM ) >= 0 );
401 : }
402 47 : mpInBuf = new sal_uInt8[ mnInBufSize ];
403 : }
404 : else
405 : {
406 32 : mbInit = 3;
407 :
408 : mbStatus = ( deflateInit2_( PZSTREAM, mnCompressMethod & 0xff, Z_DEFLATED,
409 : MAX_WBITS, mnMemUsage, ( mnCompressMethod >> 8 ) & 0xff,
410 32 : ZLIB_VERSION, sizeof( z_stream ) ) >= 0 );
411 :
412 32 : PZSTREAM->next_out = mpOutBuf = new sal_uInt8[ PZSTREAM->avail_out = mnOutBufSize ];
413 : }
414 : }
415 79 : }
416 :
417 87 : sal_uIntPtr ZCodec::UpdateCRC ( sal_uIntPtr nLatestCRC, sal_uInt8* pSource, long nDatSize)
418 : {
419 87 : 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: */
|