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