1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_tools.hxx" 30 #include <tools/stream.hxx> 31 #ifndef _ZLIB_H 32 #ifdef SYSTEM_ZLIB 33 #include "zlib.h" 34 #else 35 #include "zlib/zlib.h" 36 #endif 37 #endif 38 #include <tools/zcodec.hxx> 39 #include <rtl/crc.h> 40 #include <osl/endian.h> 41 42 // ----------- 43 // - Defines - 44 // ----------- 45 46 #define PZSTREAM ((z_stream*) mpsC_Stream) 47 48 /* gzip flag byte */ 49 #define GZ_ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ 50 #define GZ_HEAD_CRC 0x02 /* bit 1 set: header CRC present */ 51 #define GZ_EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ 52 #define GZ_ORIG_NAME 0x08 /* bit 3 set: original file name present */ 53 #define GZ_COMMENT 0x10 /* bit 4 set: file comment present */ 54 #define GZ_RESERVED 0xE0 /* bits 5..7: reserved */ 55 56 static int gz_magic[2] = { 0x1f, 0x8b }; /* gzip magic header */ 57 58 59 // ---------- 60 // - ZCodec - 61 // ---------- 62 63 ZCodec::ZCodec( sal_uIntPtr nInBufSize, sal_uIntPtr nOutBufSize, sal_uIntPtr nMemUsage ) 64 : mnCRC(0) 65 { 66 mnMemUsage = nMemUsage; 67 mnInBufSize = nInBufSize; 68 mnOutBufSize = nOutBufSize; 69 mpsC_Stream = new z_stream; 70 } 71 72 ZCodec::ZCodec( void ) 73 : mnCRC(0) 74 { 75 mnMemUsage = MAX_MEM_USAGE; 76 mnInBufSize = DEFAULT_IN_BUFSIZE; 77 mnOutBufSize = DEFAULT_OUT_BUFSIZE; 78 mpsC_Stream = new z_stream; 79 } 80 81 // ------------------------------------------------------------------------ 82 83 ZCodec::~ZCodec() 84 { 85 delete (z_stream*) mpsC_Stream; 86 } 87 88 // ------------------------------------------------------------------------ 89 90 void ZCodec::BeginCompression( sal_uIntPtr nCompressMethod ) 91 { 92 mbInit = 0; 93 mbStatus = sal_True; 94 mbFinish = sal_False; 95 mpIStm = mpOStm = NULL; 96 mnInToRead = 0xffffffff; 97 mpInBuf = mpOutBuf = NULL; 98 PZSTREAM->total_out = PZSTREAM->total_in = 0; 99 mnCompressMethod = nCompressMethod; 100 PZSTREAM->zalloc = ( alloc_func )0; 101 PZSTREAM->zfree = ( free_func )0; 102 PZSTREAM->opaque = ( voidpf )0; 103 PZSTREAM->avail_out = PZSTREAM->avail_in = 0; 104 } 105 106 // ------------------------------------------------------------------------ 107 108 long ZCodec::EndCompression() 109 { 110 long retvalue = 0; 111 112 if ( mbInit != 0 ) 113 { 114 if ( mbInit & 2 ) // 1->decompress, 3->compress 115 { 116 do 117 { 118 ImplWriteBack(); 119 } 120 while ( deflate( PZSTREAM, Z_FINISH ) != Z_STREAM_END ); 121 122 ImplWriteBack(); 123 124 retvalue = PZSTREAM->total_in; 125 deflateEnd( PZSTREAM ); 126 } 127 else 128 { 129 retvalue = PZSTREAM->total_out; 130 inflateEnd( PZSTREAM ); 131 } 132 delete[] mpOutBuf; 133 delete[] mpInBuf; 134 } 135 return ( mbStatus ) ? retvalue : -1; 136 } 137 138 139 // ------------------------------------------------------------------------ 140 141 long ZCodec::Compress( SvStream& rIStm, SvStream& rOStm ) 142 { 143 long nOldTotal_In = PZSTREAM->total_in; 144 145 if ( mbInit == 0 ) 146 { 147 mpIStm = &rIStm; 148 mpOStm = &rOStm; 149 ImplInitBuf( sal_False ); 150 mpInBuf = new sal_uInt8[ mnInBufSize ]; 151 } 152 while (( PZSTREAM->avail_in = mpIStm->Read( PZSTREAM->next_in = mpInBuf, mnInBufSize )) != 0 ) 153 { 154 if ( PZSTREAM->avail_out == 0 ) 155 ImplWriteBack(); 156 if ( deflate( PZSTREAM, Z_NO_FLUSH ) < 0 ) 157 { 158 mbStatus = sal_False; 159 break; 160 } 161 }; 162 return ( mbStatus ) ? (long)(PZSTREAM->total_in - nOldTotal_In) : -1; 163 } 164 165 // ------------------------------------------------------------------------ 166 167 long ZCodec::Decompress( SvStream& rIStm, SvStream& rOStm ) 168 { 169 int err; 170 sal_uIntPtr nInToRead; 171 long nOldTotal_Out = PZSTREAM->total_out; 172 173 if ( mbFinish ) 174 return PZSTREAM->total_out - nOldTotal_Out; 175 176 if ( mbInit == 0 ) 177 { 178 mpIStm = &rIStm; 179 mpOStm = &rOStm; 180 ImplInitBuf( sal_True ); 181 PZSTREAM->next_out = mpOutBuf = new sal_uInt8[ PZSTREAM->avail_out = mnOutBufSize ]; 182 } 183 do 184 { 185 if ( PZSTREAM->avail_out == 0 ) ImplWriteBack(); 186 if ( PZSTREAM->avail_in == 0 && mnInToRead ) 187 { 188 nInToRead = ( mnInBufSize > mnInToRead ) ? mnInToRead : mnInBufSize; 189 PZSTREAM->avail_in = mpIStm->Read( PZSTREAM->next_in = mpInBuf, nInToRead ); 190 mnInToRead -= nInToRead; 191 192 if ( mnCompressMethod & ZCODEC_UPDATE_CRC ) 193 mnCRC = UpdateCRC( mnCRC, mpInBuf, nInToRead ); 194 195 } 196 err = inflate( PZSTREAM, Z_NO_FLUSH ); 197 if ( err < 0 ) 198 { 199 mbStatus = sal_False; 200 break; 201 } 202 203 } 204 while ( ( err != Z_STREAM_END) && ( PZSTREAM->avail_in || mnInToRead ) ); 205 ImplWriteBack(); 206 207 if ( err == Z_STREAM_END ) 208 mbFinish = sal_True; 209 return ( mbStatus ) ? (long)(PZSTREAM->total_out - nOldTotal_Out) : -1; 210 } 211 212 // ------------------------------------------------------------------------ 213 214 long ZCodec::Write( SvStream& rOStm, const sal_uInt8* pData, sal_uIntPtr nSize ) 215 { 216 if ( mbInit == 0 ) 217 { 218 mpOStm = &rOStm; 219 ImplInitBuf( sal_False ); 220 } 221 222 PZSTREAM->avail_in = nSize; 223 PZSTREAM->next_in = (unsigned char*)pData; 224 225 while ( PZSTREAM->avail_in || ( PZSTREAM->avail_out == 0 ) ) 226 { 227 if ( PZSTREAM->avail_out == 0 ) 228 ImplWriteBack(); 229 230 if ( deflate( PZSTREAM, Z_NO_FLUSH ) < 0 ) 231 { 232 mbStatus = sal_False; 233 break; 234 } 235 } 236 return ( mbStatus ) ? (long)nSize : -1; 237 } 238 239 // ------------------------------------------------------------------------ 240 241 long ZCodec::Read( SvStream& rIStm, sal_uInt8* pData, sal_uIntPtr nSize ) 242 { 243 int err; 244 sal_uIntPtr nInToRead; 245 246 if ( mbFinish ) 247 return 0; // PZSTREAM->total_out; 248 249 mpIStm = &rIStm; 250 if ( mbInit == 0 ) 251 { 252 ImplInitBuf( sal_True ); 253 } 254 PZSTREAM->avail_out = nSize; 255 PZSTREAM->next_out = pData; 256 do 257 { 258 if ( PZSTREAM->avail_in == 0 && mnInToRead ) 259 { 260 nInToRead = (mnInBufSize > mnInToRead) ? mnInToRead : mnInBufSize; 261 PZSTREAM->avail_in = mpIStm->Read ( 262 PZSTREAM->next_in = mpInBuf, nInToRead); 263 mnInToRead -= nInToRead; 264 265 if ( mnCompressMethod & ZCODEC_UPDATE_CRC ) 266 mnCRC = UpdateCRC( mnCRC, mpInBuf, nInToRead ); 267 268 } 269 err = inflate( PZSTREAM, Z_NO_FLUSH ); 270 if ( err < 0 ) 271 { 272 // Accept Z_BUF_ERROR as EAGAIN or EWOULDBLOCK. 273 mbStatus = (err == Z_BUF_ERROR); 274 break; 275 } 276 } 277 while ( (err != Z_STREAM_END) && 278 (PZSTREAM->avail_out != 0) && 279 (PZSTREAM->avail_in || mnInToRead) ); 280 if ( err == Z_STREAM_END ) 281 mbFinish = sal_True; 282 283 return (mbStatus ? (long)(nSize - PZSTREAM->avail_out) : -1); 284 } 285 286 // ------------------------------------------------------------------------ 287 288 long ZCodec::ReadAsynchron( SvStream& rIStm, sal_uInt8* pData, sal_uIntPtr nSize ) 289 { 290 int err = 0; 291 sal_uIntPtr nInToRead; 292 293 if ( mbFinish ) 294 return 0; // PZSTREAM->total_out; 295 296 if ( mbInit == 0 ) 297 { 298 mpIStm = &rIStm; 299 ImplInitBuf( sal_True ); 300 } 301 PZSTREAM->avail_out = nSize; 302 PZSTREAM->next_out = pData; 303 do 304 { 305 if ( PZSTREAM->avail_in == 0 && mnInToRead ) 306 { 307 nInToRead = (mnInBufSize > mnInToRead) ? mnInToRead : mnInBufSize; 308 309 sal_uIntPtr nStreamPos = rIStm.Tell(); 310 rIStm.Seek( STREAM_SEEK_TO_END ); 311 sal_uIntPtr nMaxPos = rIStm.Tell(); 312 rIStm.Seek( nStreamPos ); 313 if ( ( nMaxPos - nStreamPos ) < nInToRead ) 314 { 315 rIStm.SetError( ERRCODE_IO_PENDING ); 316 err= ! Z_STREAM_END; // TODO What is appropriate code for this? 317 break; 318 } 319 320 PZSTREAM->avail_in = mpIStm->Read ( 321 PZSTREAM->next_in = mpInBuf, nInToRead); 322 mnInToRead -= nInToRead; 323 324 if ( mnCompressMethod & ZCODEC_UPDATE_CRC ) 325 mnCRC = UpdateCRC( mnCRC, mpInBuf, nInToRead ); 326 327 } 328 err = inflate( PZSTREAM, Z_NO_FLUSH ); 329 if ( err < 0 ) 330 { 331 // Accept Z_BUF_ERROR as EAGAIN or EWOULDBLOCK. 332 mbStatus = (err == Z_BUF_ERROR); 333 break; 334 } 335 } 336 while ( (err != Z_STREAM_END) && 337 (PZSTREAM->avail_out != 0) && 338 (PZSTREAM->avail_in || mnInToRead) ); 339 if ( err == Z_STREAM_END ) 340 mbFinish = sal_True; 341 342 return (mbStatus ? (long)(nSize - PZSTREAM->avail_out) : -1); 343 } 344 345 // ------------------------------------------------------------------------ 346 347 void ZCodec::ImplWriteBack() 348 { 349 sal_uIntPtr nAvail = mnOutBufSize - PZSTREAM->avail_out; 350 351 if ( nAvail ) 352 { 353 if ( mbInit & 2 && ( mnCompressMethod & ZCODEC_UPDATE_CRC ) ) 354 mnCRC = UpdateCRC( mnCRC, mpOutBuf, nAvail ); 355 mpOStm->Write( PZSTREAM->next_out = mpOutBuf, nAvail ); 356 PZSTREAM->avail_out = mnOutBufSize; 357 } 358 } 359 360 // ------------------------------------------------------------------------ 361 362 void ZCodec::SetBreak( sal_uIntPtr nInToRead ) 363 { 364 mnInToRead = nInToRead; 365 } 366 367 // ------------------------------------------------------------------------ 368 369 sal_uIntPtr ZCodec::GetBreak( void ) 370 { 371 return ( mnInToRead + PZSTREAM->avail_in ); 372 } 373 374 // ------------------------------------------------------------------------ 375 376 void ZCodec::SetCRC( sal_uIntPtr nCRC ) 377 { 378 mnCRC = nCRC; 379 } 380 381 // ------------------------------------------------------------------------ 382 383 sal_uIntPtr ZCodec::GetCRC() 384 { 385 return mnCRC; 386 } 387 388 // ------------------------------------------------------------------------ 389 390 void ZCodec::ImplInitBuf ( sal_Bool nIOFlag ) 391 { 392 if ( mbInit == 0 ) 393 { 394 if ( nIOFlag ) 395 { 396 mbInit = 1; 397 if ( mbStatus && ( mnCompressMethod & ZCODEC_GZ_LIB ) ) 398 { 399 sal_uInt8 n1, n2, j, nMethod, nFlags; 400 for ( int i = 0; i < 2; i++ ) // gz - magic number 401 { 402 *mpIStm >> j; 403 if ( j != gz_magic[ i ] ) 404 mbStatus = sal_False; 405 } 406 *mpIStm >> nMethod; 407 *mpIStm >> nFlags; 408 if ( nMethod != Z_DEFLATED ) 409 mbStatus = sal_False; 410 if ( ( nFlags & GZ_RESERVED ) != 0 ) 411 mbStatus = sal_False; 412 /* Discard time, xflags and OS code: */ 413 mpIStm->SeekRel( 6 ); 414 /* skip the extra field */ 415 if ( nFlags & GZ_EXTRA_FIELD ) 416 { 417 *mpIStm >> n1 >> n2; 418 mpIStm->SeekRel( n1 + ( n2 << 8 ) ); 419 } 420 /* skip the original file name */ 421 if ( nFlags & GZ_ORIG_NAME) 422 { 423 do 424 { 425 *mpIStm >> j; 426 } 427 while ( j && !mpIStm->IsEof() ); 428 } 429 /* skip the .gz file comment */ 430 if ( nFlags & GZ_COMMENT ) 431 { 432 do 433 { 434 *mpIStm >> j; 435 } 436 while ( j && !mpIStm->IsEof() ); 437 } 438 /* skip the header crc */ 439 if ( nFlags & GZ_HEAD_CRC ) 440 mpIStm->SeekRel( 2 ); 441 if ( mbStatus ) 442 mbStatus = ( inflateInit2( PZSTREAM, -MAX_WBITS) != Z_OK ) ? sal_False : sal_True; 443 } 444 else 445 { 446 mbStatus = ( inflateInit( PZSTREAM ) >= 0 ); 447 } 448 mpInBuf = new sal_uInt8[ mnInBufSize ]; 449 } 450 else 451 { 452 mbInit = 3; 453 454 mbStatus = ( deflateInit2_( PZSTREAM, mnCompressMethod & 0xff, Z_DEFLATED, 455 MAX_WBITS, mnMemUsage, ( mnCompressMethod >> 8 ) & 0xff, 456 ZLIB_VERSION, sizeof( z_stream ) ) >= 0 ); 457 458 PZSTREAM->next_out = mpOutBuf = new sal_uInt8[ PZSTREAM->avail_out = mnOutBufSize ]; 459 } 460 } 461 } 462 463 // ------------------------------------------------------------------------ 464 465 sal_uIntPtr ZCodec::UpdateCRC ( sal_uIntPtr nLatestCRC, sal_uIntPtr nNumber ) 466 { 467 468 #ifdef OSL_LITENDIAN 469 nNumber = SWAPLONG( nNumber ); 470 #endif 471 return rtl_crc32( nLatestCRC, &nNumber, 4 ); 472 } 473 474 // ------------------------------------------------------------------------ 475 476 sal_uIntPtr ZCodec::UpdateCRC ( sal_uIntPtr nLatestCRC, sal_uInt8* pSource, long nDatSize) 477 { 478 return rtl_crc32( nLatestCRC, pSource, nDatSize ); 479 } 480 481 // ------------------------------------------------------------------------ 482 483 void GZCodec::BeginCompression( sal_uIntPtr nCompressMethod ) 484 { 485 ZCodec::BeginCompression( nCompressMethod | ZCODEC_GZ_LIB ); 486 }; 487 488 489