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 mbInit = 0; 131 } 132 return ( mbStatus ) ? retvalue : -1; 133 } 134 135 136 // ------------------------------------------------------------------------ 137 138 long ZCodec::Compress( SvStream& rIStm, SvStream& rOStm ) 139 { 140 long nOldTotal_In = PZSTREAM->total_in; 141 142 if ( mbInit == 0 ) 143 { 144 mpIStm = &rIStm; 145 mpOStm = &rOStm; 146 ImplInitBuf( sal_False ); 147 mpInBuf = new sal_uInt8[ mnInBufSize ]; 148 } 149 while (( PZSTREAM->avail_in = mpIStm->Read( PZSTREAM->next_in = mpInBuf, mnInBufSize )) != 0 ) 150 { 151 if ( PZSTREAM->avail_out == 0 ) 152 ImplWriteBack(); 153 if ( deflate( PZSTREAM, Z_NO_FLUSH ) < 0 ) 154 { 155 mbStatus = sal_False; 156 break; 157 } 158 }; 159 return ( mbStatus ) ? (long)(PZSTREAM->total_in - nOldTotal_In) : -1; 160 } 161 162 // ------------------------------------------------------------------------ 163 164 long ZCodec::Decompress( SvStream& rIStm, SvStream& rOStm ) 165 { 166 int err; 167 sal_uIntPtr nInToRead; 168 long nOldTotal_Out = PZSTREAM->total_out; 169 170 if ( mbFinish ) 171 return PZSTREAM->total_out - nOldTotal_Out; 172 173 if ( mbInit == 0 ) 174 { 175 mpIStm = &rIStm; 176 mpOStm = &rOStm; 177 ImplInitBuf( sal_True ); 178 PZSTREAM->next_out = mpOutBuf = new sal_uInt8[ PZSTREAM->avail_out = mnOutBufSize ]; 179 } 180 do 181 { 182 if ( PZSTREAM->avail_out == 0 ) ImplWriteBack(); 183 if ( PZSTREAM->avail_in == 0 && mnInToRead ) 184 { 185 nInToRead = ( mnInBufSize > mnInToRead ) ? mnInToRead : mnInBufSize; 186 PZSTREAM->avail_in = mpIStm->Read( PZSTREAM->next_in = mpInBuf, nInToRead ); 187 mnInToRead -= nInToRead; 188 189 if ( mnCompressMethod & ZCODEC_UPDATE_CRC ) 190 mnCRC = UpdateCRC( mnCRC, mpInBuf, nInToRead ); 191 192 } 193 err = inflate( PZSTREAM, Z_NO_FLUSH ); 194 if ( err < 0 ) 195 { 196 mbStatus = sal_False; 197 break; 198 } 199 200 } 201 while ( ( err != Z_STREAM_END) && ( PZSTREAM->avail_in || mnInToRead ) ); 202 ImplWriteBack(); 203 204 if ( err == Z_STREAM_END ) 205 mbFinish = sal_True; 206 return ( mbStatus ) ? (long)(PZSTREAM->total_out - nOldTotal_Out) : -1; 207 } 208 209 // ------------------------------------------------------------------------ 210 211 long ZCodec::Write( SvStream& rOStm, const sal_uInt8* pData, sal_uIntPtr nSize ) 212 { 213 if ( mbInit == 0 ) 214 { 215 mpOStm = &rOStm; 216 ImplInitBuf( sal_False ); 217 } 218 219 PZSTREAM->avail_in = nSize; 220 PZSTREAM->next_in = (unsigned char*)pData; 221 222 while ( PZSTREAM->avail_in || ( PZSTREAM->avail_out == 0 ) ) 223 { 224 if ( PZSTREAM->avail_out == 0 ) 225 ImplWriteBack(); 226 227 if ( deflate( PZSTREAM, Z_NO_FLUSH ) < 0 ) 228 { 229 mbStatus = sal_False; 230 break; 231 } 232 } 233 return ( mbStatus ) ? (long)nSize : -1; 234 } 235 236 // ------------------------------------------------------------------------ 237 238 long ZCodec::Read( SvStream& rIStm, sal_uInt8* pData, sal_uIntPtr nSize ) 239 { 240 int err; 241 sal_uIntPtr nInToRead; 242 243 if ( mbFinish ) 244 return 0; // PZSTREAM->total_out; 245 246 mpIStm = &rIStm; 247 if ( mbInit == 0 ) 248 { 249 ImplInitBuf( sal_True ); 250 } 251 PZSTREAM->avail_out = nSize; 252 PZSTREAM->next_out = pData; 253 do 254 { 255 if ( PZSTREAM->avail_in == 0 && mnInToRead ) 256 { 257 nInToRead = (mnInBufSize > mnInToRead) ? mnInToRead : mnInBufSize; 258 PZSTREAM->avail_in = mpIStm->Read ( 259 PZSTREAM->next_in = mpInBuf, nInToRead); 260 mnInToRead -= nInToRead; 261 262 if ( mnCompressMethod & ZCODEC_UPDATE_CRC ) 263 mnCRC = UpdateCRC( mnCRC, mpInBuf, nInToRead ); 264 265 } 266 err = inflate( PZSTREAM, Z_NO_FLUSH ); 267 if ( err < 0 ) 268 { 269 // Accept Z_BUF_ERROR as EAGAIN or EWOULDBLOCK. 270 mbStatus = (err == Z_BUF_ERROR); 271 break; 272 } 273 } 274 while ( (err != Z_STREAM_END) && 275 (PZSTREAM->avail_out != 0) && 276 (PZSTREAM->avail_in || mnInToRead) ); 277 if ( err == Z_STREAM_END ) 278 mbFinish = sal_True; 279 280 return (mbStatus ? (long)(nSize - PZSTREAM->avail_out) : -1); 281 } 282 283 // ------------------------------------------------------------------------ 284 285 long ZCodec::ReadAsynchron( SvStream& rIStm, sal_uInt8* pData, sal_uIntPtr nSize ) 286 { 287 int err = 0; 288 sal_uIntPtr nInToRead; 289 290 if ( mbFinish ) 291 return 0; // PZSTREAM->total_out; 292 293 if ( mbInit == 0 ) 294 { 295 mpIStm = &rIStm; 296 ImplInitBuf( sal_True ); 297 } 298 PZSTREAM->avail_out = nSize; 299 PZSTREAM->next_out = pData; 300 do 301 { 302 if ( PZSTREAM->avail_in == 0 && mnInToRead ) 303 { 304 nInToRead = (mnInBufSize > mnInToRead) ? mnInToRead : mnInBufSize; 305 306 sal_uIntPtr nStreamPos = rIStm.Tell(); 307 rIStm.Seek( STREAM_SEEK_TO_END ); 308 sal_uIntPtr nMaxPos = rIStm.Tell(); 309 rIStm.Seek( nStreamPos ); 310 if ( ( nMaxPos - nStreamPos ) < nInToRead ) 311 { 312 rIStm.SetError( ERRCODE_IO_PENDING ); 313 err= ! Z_STREAM_END; // TODO What is appropriate code for this? 314 break; 315 } 316 317 PZSTREAM->avail_in = mpIStm->Read ( 318 PZSTREAM->next_in = mpInBuf, nInToRead); 319 mnInToRead -= nInToRead; 320 321 if ( mnCompressMethod & ZCODEC_UPDATE_CRC ) 322 mnCRC = UpdateCRC( mnCRC, mpInBuf, nInToRead ); 323 324 } 325 err = inflate( PZSTREAM, Z_NO_FLUSH ); 326 if ( err < 0 ) 327 { 328 // Accept Z_BUF_ERROR as EAGAIN or EWOULDBLOCK. 329 mbStatus = (err == Z_BUF_ERROR); 330 break; 331 } 332 } 333 while ( (err != Z_STREAM_END) && 334 (PZSTREAM->avail_out != 0) && 335 (PZSTREAM->avail_in || mnInToRead) ); 336 if ( err == Z_STREAM_END ) 337 mbFinish = sal_True; 338 339 return (mbStatus ? (long)(nSize - PZSTREAM->avail_out) : -1); 340 } 341 342 // ------------------------------------------------------------------------ 343 344 void ZCodec::ImplWriteBack() 345 { 346 sal_uIntPtr nAvail = mnOutBufSize - PZSTREAM->avail_out; 347 348 if ( nAvail ) 349 { 350 if ( mbInit & 2 && ( mnCompressMethod & ZCODEC_UPDATE_CRC ) ) 351 mnCRC = UpdateCRC( mnCRC, mpOutBuf, nAvail ); 352 mpOStm->Write( PZSTREAM->next_out = mpOutBuf, nAvail ); 353 PZSTREAM->avail_out = mnOutBufSize; 354 } 355 } 356 357 // ------------------------------------------------------------------------ 358 359 void ZCodec::SetBreak( sal_uIntPtr nInToRead ) 360 { 361 mnInToRead = nInToRead; 362 } 363 364 // ------------------------------------------------------------------------ 365 366 sal_uIntPtr ZCodec::GetBreak( void ) 367 { 368 return ( mnInToRead + PZSTREAM->avail_in ); 369 } 370 371 // ------------------------------------------------------------------------ 372 373 void ZCodec::SetCRC( sal_uIntPtr nCRC ) 374 { 375 mnCRC = nCRC; 376 } 377 378 // ------------------------------------------------------------------------ 379 380 sal_uIntPtr ZCodec::GetCRC() 381 { 382 return mnCRC; 383 } 384 385 // ------------------------------------------------------------------------ 386 387 void ZCodec::ImplInitBuf ( sal_Bool nIOFlag ) 388 { 389 if ( mbInit == 0 ) 390 { 391 if ( nIOFlag ) 392 { 393 mbInit = 1; 394 if ( mbStatus && ( mnCompressMethod & ZCODEC_GZ_LIB ) ) 395 { 396 sal_uInt8 n1, n2, j, nMethod, nFlags; 397 for ( int i = 0; i < 2; i++ ) // gz - magic number 398 { 399 *mpIStm >> j; 400 if ( j != gz_magic[ i ] ) 401 mbStatus = sal_False; 402 } 403 *mpIStm >> nMethod; 404 *mpIStm >> nFlags; 405 if ( nMethod != Z_DEFLATED ) 406 mbStatus = sal_False; 407 if ( ( nFlags & GZ_RESERVED ) != 0 ) 408 mbStatus = sal_False; 409 /* Discard time, xflags and OS code: */ 410 mpIStm->SeekRel( 6 ); 411 /* skip the extra field */ 412 if ( nFlags & GZ_EXTRA_FIELD ) 413 { 414 *mpIStm >> n1 >> n2; 415 mpIStm->SeekRel( n1 + ( n2 << 8 ) ); 416 } 417 /* skip the original file name */ 418 if ( nFlags & GZ_ORIG_NAME) 419 { 420 do 421 { 422 *mpIStm >> j; 423 } 424 while ( j && !mpIStm->IsEof() ); 425 } 426 /* skip the .gz file comment */ 427 if ( nFlags & GZ_COMMENT ) 428 { 429 do 430 { 431 *mpIStm >> j; 432 } 433 while ( j && !mpIStm->IsEof() ); 434 } 435 /* skip the header crc */ 436 if ( nFlags & GZ_HEAD_CRC ) 437 mpIStm->SeekRel( 2 ); 438 if ( mbStatus ) 439 mbStatus = ( inflateInit2( PZSTREAM, -MAX_WBITS) != Z_OK ) ? sal_False : sal_True; 440 } 441 else 442 { 443 mbStatus = ( inflateInit( PZSTREAM ) >= 0 ); 444 } 445 mpInBuf = new sal_uInt8[ mnInBufSize ]; 446 } 447 else 448 { 449 mbInit = 3; 450 451 mbStatus = ( deflateInit2_( PZSTREAM, mnCompressMethod & 0xff, Z_DEFLATED, 452 MAX_WBITS, mnMemUsage, ( mnCompressMethod >> 8 ) & 0xff, 453 ZLIB_VERSION, sizeof( z_stream ) ) >= 0 ); 454 455 PZSTREAM->next_out = mpOutBuf = new sal_uInt8[ PZSTREAM->avail_out = mnOutBufSize ]; 456 } 457 } 458 } 459 460 // ------------------------------------------------------------------------ 461 462 sal_uIntPtr ZCodec::UpdateCRC ( sal_uIntPtr nLatestCRC, sal_uIntPtr nNumber ) 463 { 464 465 #ifdef OSL_LITENDIAN 466 nNumber = SWAPLONG( nNumber ); 467 #endif 468 return rtl_crc32( nLatestCRC, &nNumber, 4 ); 469 } 470 471 // ------------------------------------------------------------------------ 472 473 sal_uIntPtr ZCodec::UpdateCRC ( sal_uIntPtr nLatestCRC, sal_uInt8* pSource, long nDatSize) 474 { 475 return rtl_crc32( nLatestCRC, pSource, nDatSize ); 476 } 477 478 // ------------------------------------------------------------------------ 479 480 void GZCodec::BeginCompression( sal_uIntPtr nCompressMethod ) 481 { 482 ZCodec::BeginCompression( nCompressMethod | ZCODEC_GZ_LIB ); 483 }; 484