DOOM-3-BFG

DOOM 3 BFG Edition
Log | Files | Refs

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 }