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 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 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 79 ZCodec::~ZCodec() 80 { 81 delete (z_stream*) mpsC_Stream; 82 } 83 84 // ------------------------------------------------------------------------ 85 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 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 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 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 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 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 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 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 358 void ZCodec::SetBreak( sal_uIntPtr nInToRead ) 359 { 360 mnInToRead = nInToRead; 361 } 362 363 // ------------------------------------------------------------------------ 364 365 sal_uIntPtr ZCodec::GetBreak( void ) 366 { 367 return ( mnInToRead + PZSTREAM->avail_in ); 368 } 369 370 // ------------------------------------------------------------------------ 371 372 void ZCodec::SetCRC( sal_uIntPtr nCRC ) 373 { 374 mnCRC = nCRC; 375 } 376 377 // ------------------------------------------------------------------------ 378 379 sal_uIntPtr ZCodec::GetCRC() 380 { 381 return mnCRC; 382 } 383 384 // ------------------------------------------------------------------------ 385 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 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 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 479 void GZCodec::BeginCompression( sal_uIntPtr nCompressMethod ) 480 { 481 ZCodec::BeginCompression( nCompressMethod | ZCODEC_GZ_LIB ); 482 }; 483 484 485