LightweightCompression.cpp (11886B)
1 /* 2 =========================================================================== 3 4 Doom 3 BFG Edition GPL Source Code 5 Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. 6 7 This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code"). 8 9 Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify 10 it under the terms of the GNU General Public License as published by 11 the Free Software Foundation, either version 3 of the License, or 12 (at your option) any later version. 13 14 Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>. 21 22 In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below. 23 24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. 25 26 =========================================================================== 27 */ 28 #pragma hdrstop 29 #include "../idLib/precompiled.h" 30 #include "LightweightCompression.h" 31 32 /* 33 ======================== 34 HashIndex 35 ======================== 36 */ 37 static int HashIndex( int w, int k ) { 38 return ( w ^ k ) & idLZWCompressor::HASH_MASK; 39 } 40 41 /* 42 ======================== 43 idLZWCompressor::Start 44 ======================== 45 */ 46 void idLZWCompressor::Start( uint8 * data_, int maxSize_, bool append ) { 47 // Clear hash 48 ClearHash(); 49 50 if ( append ) { 51 assert( lzwData->nextCode > LZW_FIRST_CODE ); 52 53 int originalNextCode = lzwData->nextCode; 54 55 lzwData->nextCode = LZW_FIRST_CODE; 56 57 // If we are appending, then fill up the hash 58 for ( int i = LZW_FIRST_CODE; i < originalNextCode; i++ ) { 59 AddToDict( lzwData->dictionaryW[i], lzwData->dictionaryK[i] ); 60 } 61 62 assert( originalNextCode == lzwData->nextCode ); 63 } else { 64 for ( int i = 0; i < LZW_FIRST_CODE; i++ ) { 65 lzwData->dictionaryK[i] = (uint8)i; 66 lzwData->dictionaryW[i] = 0xFFFF; 67 } 68 69 lzwData->nextCode = LZW_FIRST_CODE; 70 lzwData->codeBits = LZW_START_BITS; 71 lzwData->codeWord = -1; 72 lzwData->tempValue = 0; 73 lzwData->tempBits = 0; 74 lzwData->bytesWritten = 0; 75 } 76 77 oldCode = -1; // Used by DecompressBlock 78 data = data_; 79 80 blockSize = 0; 81 blockIndex = 0; 82 83 bytesRead = 0; 84 85 maxSize = maxSize_; 86 overflowed = false; 87 88 savedBytesWritten = 0; 89 savedCodeWord = 0; 90 saveCodeBits = 0; 91 savedTempValue = 0; 92 savedTempBits = 0; 93 } 94 95 /* 96 ======================== 97 idLZWCompressor::ReadBits 98 ======================== 99 */ 100 int idLZWCompressor::ReadBits( int bits ) { 101 int bitsToRead = bits - lzwData->tempBits; 102 103 while ( bitsToRead > 0 ) { 104 if ( bytesRead >= maxSize ) { 105 return -1; 106 } 107 lzwData->tempValue |= (uint64)data[bytesRead++] << lzwData->tempBits; 108 lzwData->tempBits += 8; 109 bitsToRead -= 8; 110 } 111 112 int value = (int)lzwData->tempValue & ( ( 1 << bits ) - 1 ); 113 lzwData->tempValue >>= bits; 114 lzwData->tempBits -= bits; 115 116 return value; 117 } 118 119 /* 120 ======================== 121 idLZWCompressor::WriteBits 122 ======================== 123 */ 124 void idLZWCompressor::WriteBits( uint32 value, int bits ) { 125 126 // Queue up bits into temp value 127 lzwData->tempValue |= (uint64)value << lzwData->tempBits; 128 lzwData->tempBits += bits; 129 130 // Flush 8 bits (1 byte) at a time ( leftovers will get caught in idLZWCompressor::End() ) 131 while ( lzwData->tempBits >= 8 ) { 132 if ( lzwData->bytesWritten >= maxSize ) { 133 overflowed = true; 134 return; 135 } 136 137 data[lzwData->bytesWritten++] = (uint8)( lzwData->tempValue & 255 ); 138 lzwData->tempValue >>= 8; 139 lzwData->tempBits -= 8; 140 } 141 } 142 143 /* 144 ======================== 145 idLZWCompressor::WriteChain 146 147 The chain is stored backwards, so we have to write it to a buffer then output the buffer in 148 reverse. 149 ======================== 150 */ 151 int idLZWCompressor::WriteChain( int code ) { 152 byte chain[lzwCompressionData_t::LZW_DICT_SIZE]; 153 int firstChar = 0; 154 int i = 0; 155 do { 156 assert( i < lzwCompressionData_t::LZW_DICT_SIZE && code < lzwCompressionData_t::LZW_DICT_SIZE && code >= 0 ); 157 chain[i++] = (byte)lzwData->dictionaryK[code]; 158 code = lzwData->dictionaryW[code]; 159 } while ( code != 0xFFFF ); 160 firstChar = chain[--i]; 161 for ( ; i >= 0; i-- ) { 162 block[blockSize++] = chain[i]; 163 } 164 return firstChar; 165 } 166 167 /* 168 ======================== 169 idLZWCompressor::DecompressBlock 170 ======================== 171 */ 172 void idLZWCompressor::DecompressBlock() { 173 assert( blockIndex == blockSize ); // Make sure we've read all we can 174 175 blockIndex = 0; 176 blockSize = 0; 177 178 int firstChar = -1; 179 while ( blockSize < LZW_BLOCK_SIZE - lzwCompressionData_t::LZW_DICT_SIZE ) { 180 assert( lzwData->codeBits <= lzwCompressionData_t::LZW_DICT_BITS ); 181 182 int code = ReadBits( lzwData->codeBits ); 183 if ( code == -1 ) { 184 break; 185 } 186 187 if ( oldCode == -1 ) { 188 assert( code < 256 ); 189 block[blockSize++] = (uint8)code; 190 oldCode = code; 191 firstChar = code; 192 continue; 193 } 194 195 if ( code >= lzwData->nextCode ) { 196 assert( code == lzwData->nextCode ); 197 firstChar = WriteChain( oldCode ); 198 block[blockSize++] = (uint8)firstChar; 199 } else { 200 firstChar = WriteChain( code ); 201 } 202 AddToDict( oldCode, firstChar ); 203 if ( BumpBits() ) { 204 oldCode = -1; 205 } else { 206 oldCode = code; 207 } 208 } 209 } 210 211 /* 212 ======================== 213 idLZWCompressor::ReadByte 214 ======================== 215 */ 216 int idLZWCompressor::ReadByte( bool ignoreOverflow ) { 217 if ( blockIndex == blockSize ) { 218 DecompressBlock(); 219 } 220 221 if ( blockIndex == blockSize ) { //-V581 DecompressBlock() updates these values, the if() isn't redundant 222 if ( !ignoreOverflow ) { 223 overflowed = true; 224 assert( !"idLZWCompressor::ReadByte overflowed!" ); 225 } 226 return -1; 227 } 228 229 return block[blockIndex++]; 230 } 231 232 233 /* 234 ======================== 235 idLZWCompressor::WriteByte 236 ======================== 237 */ 238 void idLZWCompressor::WriteByte( uint8 value ) { 239 int code = Lookup( lzwData->codeWord, value ); 240 if ( code >= 0 ) { 241 lzwData->codeWord = code; 242 } else { 243 WriteBits( lzwData->codeWord, lzwData->codeBits ); 244 if ( !BumpBits() ) { 245 AddToDict( lzwData->codeWord, value ); 246 } 247 lzwData->codeWord = value; 248 } 249 250 if ( lzwData->bytesWritten >= maxSize - ( lzwData->codeBits + lzwData->tempBits + 7 ) / 8 ) { 251 overflowed = true; // At any point, if we can't perform an End call, then trigger an overflow 252 return; 253 } 254 } 255 256 /* 257 ======================== 258 idLZWCompressor::Lookup 259 ======================== 260 */ 261 int idLZWCompressor::Lookup( int w, int k ) { 262 if ( w == -1 ) { 263 return k; 264 } else { 265 int i = HashIndex( w, k ); 266 267 for ( int j = hash[i]; j != 0xFFFF; j = nextHash[j] ) { 268 assert( j < lzwCompressionData_t::LZW_DICT_SIZE ); 269 if ( lzwData->dictionaryK[j] == k && lzwData->dictionaryW[j] == w ) { 270 return j; 271 } 272 } 273 } 274 return -1; 275 } 276 277 /* 278 ======================== 279 idLZWCompressor::AddToDict 280 ======================== 281 */ 282 int idLZWCompressor::AddToDict( int w, int k ) { 283 assert( w < 0xFFFF - 1 ); 284 assert( k < 256 ); 285 assert( lzwData->nextCode < lzwCompressionData_t::LZW_DICT_SIZE ); 286 287 lzwData->dictionaryK[lzwData->nextCode] = (uint8)k; 288 lzwData->dictionaryW[lzwData->nextCode] = (uint16)w; 289 int i = HashIndex( w, k ); 290 nextHash[lzwData->nextCode] = hash[i]; 291 hash[i] = (uint16)lzwData->nextCode; 292 return lzwData->nextCode++; 293 } 294 295 /* 296 ======================== 297 idLZWCompressor::BumpBits 298 299 Possibly increments codeBits. 300 return: bool - true, if the dictionary was cleared. 301 ======================== 302 */ 303 bool idLZWCompressor::BumpBits() { 304 if ( lzwData->nextCode == ( 1 << lzwData->codeBits ) ) { 305 lzwData->codeBits ++; 306 if ( lzwData->codeBits > lzwCompressionData_t::LZW_DICT_BITS ) { 307 lzwData->nextCode = LZW_FIRST_CODE; 308 lzwData->codeBits = LZW_START_BITS; 309 ClearHash(); 310 return true; 311 } 312 } 313 return false; 314 } 315 316 /* 317 ======================== 318 idLZWCompressor::End 319 ======================== 320 */ 321 int idLZWCompressor::End() { 322 assert( lzwData->tempBits < 8 ); 323 assert( lzwData->bytesWritten < maxSize - ( lzwData->codeBits + lzwData->tempBits + 7 ) / 8 ); 324 325 assert( ( Length() > 0 ) == ( lzwData->codeWord != -1 ) ); 326 327 if ( lzwData->codeWord != -1 ) { 328 WriteBits( lzwData->codeWord, lzwData->codeBits ); 329 } 330 331 if ( lzwData->tempBits > 0 ) { 332 if ( lzwData->bytesWritten >= maxSize ) { 333 overflowed = true; 334 return -1; 335 } 336 data[lzwData->bytesWritten++] = (uint8)lzwData->tempValue & ( ( 1 << lzwData->tempBits ) - 1 ); 337 } 338 339 return Length() > 0 ? Length() : -1; // Total bytes written (or failure) 340 } 341 342 /* 343 ======================== 344 idLZWCompressor::Save 345 ======================== 346 */ 347 void idLZWCompressor::Save() { 348 assert( !overflowed ); 349 // Check and make sure we are at a good spot (can call End) 350 assert( lzwData->bytesWritten < maxSize - ( lzwData->codeBits + lzwData->tempBits + 7 ) / 8 ); 351 352 savedBytesWritten = lzwData->bytesWritten; 353 savedCodeWord = lzwData->codeWord; 354 saveCodeBits = lzwData->codeBits; 355 savedTempValue = lzwData->tempValue; 356 savedTempBits = lzwData->tempBits; 357 } 358 359 /* 360 ======================== 361 idLZWCompressor::Restore 362 ======================== 363 */ 364 void idLZWCompressor::Restore() { 365 lzwData->bytesWritten = savedBytesWritten; 366 lzwData->codeWord = savedCodeWord; 367 lzwData->codeBits = saveCodeBits; 368 lzwData->tempValue = savedTempValue; 369 lzwData->tempBits = savedTempBits; 370 } 371 372 /* 373 ======================== 374 idLZWCompressor::ClearHash 375 ======================== 376 */ 377 void idLZWCompressor::ClearHash() { 378 memset( hash, 0xFF, sizeof( hash ) ); 379 } 380 381 /* 382 ======================== 383 idZeroRunLengthCompressor 384 Simple zero based run length encoder/decoder 385 ======================== 386 */ 387 388 void idZeroRunLengthCompressor::Start( uint8 * dest_, idLZWCompressor * comp_, int maxSize_ ) { 389 zeroCount = 0; 390 dest = dest_; 391 comp = comp_; 392 compressed = 0; 393 maxSize = maxSize_; 394 } 395 396 bool idZeroRunLengthCompressor::WriteRun() { 397 if ( zeroCount > 0 ) { 398 assert( zeroCount <= 255 ); 399 if ( compressed + 2 > maxSize ) { 400 maxSize = -1; 401 return false; 402 } 403 if ( comp != NULL ) { 404 comp->WriteByte( 0 ); 405 comp->WriteByte( (uint8)zeroCount ); 406 } else { 407 *dest++ = 0; 408 *dest++ = (uint8)zeroCount; 409 } 410 compressed += 2; 411 zeroCount = 0; 412 } 413 return true; 414 } 415 416 bool idZeroRunLengthCompressor::WriteByte( uint8 value ) { 417 if ( value != 0 || zeroCount >= 255 ) { 418 if ( !WriteRun() ) { 419 maxSize = -1; 420 return false; 421 } 422 } 423 424 if ( value != 0 ) { 425 if ( compressed + 1 > maxSize ) { 426 maxSize = -1; 427 return false; 428 } 429 if ( comp != NULL ) { 430 comp->WriteByte( value ); 431 } else { 432 *dest++ = value; 433 } 434 compressed++; 435 } else { 436 zeroCount++; 437 } 438 439 return true; 440 } 441 442 byte idZeroRunLengthCompressor::ReadByte() { 443 // See if we need to possibly read more data 444 if ( zeroCount == 0 ) { 445 int value = ReadInternal(); 446 if ( value == -1 ) { 447 assert( 0 ); 448 } 449 if ( value != 0 ) { 450 return (byte)value; // Return non zero values immediately 451 } 452 // Read the number of zeroes 453 zeroCount = ReadInternal(); 454 } 455 456 assert( zeroCount > 0 ); 457 458 zeroCount--; 459 return 0; 460 } 461 462 void idZeroRunLengthCompressor::ReadBytes( byte * dest, int count ) { 463 for ( int i = 0; i < count; i++ ) { 464 *dest++ = ReadByte(); 465 } 466 } 467 468 void idZeroRunLengthCompressor::WriteBytes( uint8 * src, int count ) { 469 for ( int i = 0; i < count; i++ ) { 470 WriteByte( *src++ ); 471 } 472 } 473 474 int idZeroRunLengthCompressor::End() { 475 WriteRun(); 476 if ( maxSize == -1 ) { 477 return -1; 478 } 479 return compressed; 480 } 481 482 int idZeroRunLengthCompressor::ReadInternal() { 483 compressed++; 484 if ( comp != NULL ) { 485 return comp->ReadByte(); 486 } 487 return *dest++; 488 }