📄 scompression.cpp
字号:
// Do the decompression
explode(ReadInputData, WriteOutputData, work_buf, &Info);
// Fix: If PKLIB is unable to decompress the data, they are uncompressed
if(Info.nOutPos == 0)
{
Info.nOutPos = min(*pdwOutLength, dwInLength);
memcpy(pbOutBuffer, pbInBuffer, Info.nOutPos);
}
*pdwOutLength = Info.nOutPos;
FREEMEM(work_buf);
return 0;
}
/*****************************************************************************/
/* */
/* The "10" (de)compression is the Bzip2 (de)compression */
/* */
/*****************************************************************************/
int Compress_bzip2(char * pbOutBuffer, int * pdwOutLength, char * pbInBuffer, int dwInLength, int * pCmpType, int nCmpLevel)
{
bz_stream strm;
int blockSize100k;
int workFactor = 30;
// Keep compiler happy
nCmpLevel = nCmpLevel;
// Initialize the BZLIB compression
strm.bzalloc = NULL;
strm.bzfree = NULL;
// Adjust the block size
blockSize100k = *pCmpType;
if(blockSize100k < 1 || blockSize100k > 9)
blockSize100k = 9;
// Blizzard uses 9 as blockSize100k, (0 as workFactor)
if(BZ2_bzCompressInit(&strm, blockSize100k, 0, workFactor) == 0)
{
strm.next_in = pbInBuffer;
strm.avail_in = dwInLength;
strm.next_out = pbOutBuffer;
strm.avail_out = *pdwOutLength;
// Perform the compression
while(BZ2_bzCompress(&strm, (strm.avail_in != 0) ? BZ_RUN : BZ_FINISH) != BZ_STREAM_END);
// Put the stream into idle state
BZ2_bzCompressEnd(&strm);
*pdwOutLength = strm.total_out_lo32;
}
else
{
*pdwOutLength = 0;
}
return 0;
}
int Decompress_bzip2(char * pbOutBuffer, int * pdwOutLength, char * pbInBuffer, int dwInLength)
{
bz_stream strm;
// Initialize the BZLIB decompression
strm.bzalloc = NULL;
strm.bzfree = NULL;
if(BZ2_bzDecompressInit(&strm, 0, 0) == 0)
{
strm.next_in = pbInBuffer;
strm.avail_in = dwInLength;
strm.next_out = pbOutBuffer;
strm.avail_out = *pdwOutLength;
// Perform the decompression
while(BZ2_bzDecompress(&strm) != BZ_STREAM_END);
// Put the stream into idle state
BZ2_bzDecompressEnd(&strm);
*pdwOutLength = strm.total_out_lo32;
}
else
{
// Set zero output length
*pdwOutLength = 0;
}
return 0;
}
/*****************************************************************************/
/* */
/* SCompCompress */
/* */
/*****************************************************************************/
// This table contains compress functions which can be applied to
// uncompressed blocks. Each bit set means the corresponding
// compression method/function must be applied.
//
// WAVes compression Data compression
// ------------------ -------------------
// 1st block - 0x08 0x08 (D, HF, W2, SC, D2)
// Rest blocks - 0x81 0x02 (W3)
static TCompressTable cmp_table[] =
{
{MPQ_COMPRESSION_WAVE_MONO, Compress_wave_mono}, // IMA ADPCM mono compression
{MPQ_COMPRESSION_WAVE_STEREO, Compress_wave_stereo}, // IMA ADPCM stereo compression
{MPQ_COMPRESSION_HUFFMANN, Compress_huff}, // Huffmann compression
{MPQ_COMPRESSION_ZLIB, Compress_zlib}, // Compression with the "zlib" library
{MPQ_COMPRESSION_PKWARE, Compress_pklib}, // Compression with Pkware DCL
{MPQ_COMPRESSION_BZIP2, Compress_bzip2} // Compression Bzip2 library
};
int WINAPI SCompCompress(char * pbCompressed, int * pdwOutLength, char * pbUncompressed, int dwInLength,
int uCompressions, int nCmpType, int nCmpLevel)
{
char * pbTempBuff = NULL; // Temporary storage for decompressed data
char * pbOutput = pbCompressed; // Current output buffer
char * pbInput; // Current input buffer
int uCompressions2;
int dwCompressCount = 0;
int dwDoneCount = 0;
int dwOutSize = 0;
int dwInSize = dwInLength;
int dwEntries = (sizeof(cmp_table) / sizeof(TCompressTable));
int nResult = 1;
int i;
// Check for valid parameters
if(!pdwOutLength || *pdwOutLength < dwInLength || !pbCompressed || !pbUncompressed)
{
SetLastError(ERROR_INVALID_PARAMETER);
return 0;
}
// Count the compressions
for(i = 0, uCompressions2 = uCompressions; i < dwEntries; i++)
{
if(uCompressions & cmp_table[i].dwMask)
dwCompressCount++;
uCompressions2 &= ~cmp_table[i].dwMask;
}
// If a compression remains, do nothing
if(uCompressions2 != 0)
{
SetLastError(ERROR_INVALID_PARAMETER);
return 0;
}
// If more that one compression, allocate intermediate buffer
if(dwCompressCount >= 2)
pbTempBuff = ALLOCMEM(char, *pdwOutLength + 1);
// Perform the compressions
pbInput = pbUncompressed;
dwInSize = dwInLength;
for(i = 0, uCompressions2 = uCompressions; i < dwEntries; i++)
{
if(uCompressions2 & cmp_table[i].dwMask)
{
// Set the right output buffer
dwCompressCount--;
pbOutput = (dwCompressCount & 1) ? pbTempBuff : pbCompressed;
// Perform the partial compression
dwOutSize = *pdwOutLength - 1;
cmp_table[i].Compress(pbOutput + 1, &dwOutSize, pbInput, dwInSize, &nCmpType, nCmpLevel);
if(dwOutSize == 0)
{
SetLastError(ERROR_GEN_FAILURE);
*pdwOutLength = 0;
nResult = 0;
break;
}
// If the compression failed, copy the block instead
if(dwOutSize >= dwInSize - 1)
{
if(dwDoneCount > 0)
pbOutput++;
memcpy(pbOutput, pbInput, dwInSize);
pbInput = pbOutput;
uCompressions &= ~cmp_table[i].dwMask;
dwOutSize = dwInSize;
}
else
{
pbInput = pbOutput + 1;
dwInSize = dwOutSize;
dwDoneCount++;
}
}
}
// Copy the compressed data to the correct output buffer
if(nResult != 0)
{
if(uCompressions && (dwInSize + 1) < *pdwOutLength)
{
if(pbOutput != pbCompressed && pbOutput != pbCompressed + 1)
memcpy(pbCompressed, pbOutput, dwInSize);
*pbCompressed = (char)uCompressions;
*pdwOutLength = dwInSize + 1;
}
else
{
memmove(pbCompressed, pbUncompressed, dwInSize);
*pdwOutLength = dwInSize;
}
}
// Cleanup and return
if(pbTempBuff != NULL)
FREEMEM(pbTempBuff);
return nResult;
}
/*****************************************************************************/
/* */
/* SCompDecompress */
/* */
/*****************************************************************************/
// This table contains decompress functions which can be applied to
// uncompressed blocks. The compression mask is stored in the first byte
// of compressed block
static TDecompressTable dcmp_table[] =
{
{MPQ_COMPRESSION_BZIP2, Decompress_bzip2}, // Decompression with Bzip2 library
{MPQ_COMPRESSION_PKWARE, Decompress_pklib}, // Decompression with Pkware Data Compression Library
{MPQ_COMPRESSION_ZLIB, Decompress_zlib}, // Decompression with the "zlib" library
{MPQ_COMPRESSION_HUFFMANN, Decompress_huff}, // Huffmann decompression
{MPQ_COMPRESSION_WAVE_STEREO, Decompress_wave_stereo}, // IMA ADPCM stereo decompression
{MPQ_COMPRESSION_WAVE_MONO, Decompress_wave_mono} // IMA ADPCM mono decompression
};
int WINAPI SCompDecompress(char * pbOutBuffer, int * pdwOutLength, char * pbInBuffer, int dwInLength)
{
char * pbTempBuff = NULL; // Temporary storage for decompressed data
char * pbWorkBuff = NULL; // Where to store decompressed data
int dwOutLength = *pdwOutLength; // For storage number of output bytes
unsigned fDecompressions1; // Decompressions applied to the block
unsigned fDecompressions2; // Just another copy of decompressions applied to the block
int dwCount = 0; // Counter for every use
int dwEntries = (sizeof(dcmp_table) / sizeof(TDecompressTable));
int nResult = 1;
int i;
// If the input length is the same as output, do nothing.
if(dwInLength == dwOutLength)
{
if(pbInBuffer == pbOutBuffer)
return 1;
memcpy(pbOutBuffer, pbInBuffer, dwInLength);
*pdwOutLength = dwInLength;
return 1;
}
// Get applied compression types and decrement data length
fDecompressions1 = fDecompressions2 = (unsigned char)*pbInBuffer++;
dwInLength--;
// Search decompression table type and get all types of compression
for(i = 0; i < dwEntries; i++)
{
// We have to apply this decompression ?
if(fDecompressions1 & dcmp_table[i].dwMask)
dwCount++;
// Clear this flag from temporary variable.
fDecompressions2 &= ~dcmp_table[i].dwMask;
}
// Check if there is some method unhandled
// (E.g. compressed by future versions)
if(fDecompressions2 != 0)
{
SetLastError(ERROR_INVALID_PARAMETER);
return 0;
}
// If there is more than only one compression, we have to allocate extra buffer
if(dwCount >= 2)
pbTempBuff = ALLOCMEM(char, dwOutLength);
// Apply all decompressions
for(i = 0, dwCount = 0; i < dwEntries; i++)
{
// If not used this kind of compression, skip the loop
if(fDecompressions1 & dcmp_table[i].dwMask)
{
// If odd case, use target buffer for output, otherwise use allocated tempbuffer
pbWorkBuff = (dwCount++ & 1) ? pbTempBuff : pbOutBuffer;
dwOutLength = *pdwOutLength;
// Decompress buffer using corresponding function
dcmp_table[i].Decompress(pbWorkBuff, &dwOutLength, pbInBuffer, dwInLength);
if(dwOutLength == 0)
{
SetLastError(ERROR_GEN_FAILURE);
nResult = 0;
break;
}
// Move output length to src length for next compression
dwInLength = dwOutLength;
pbInBuffer = pbWorkBuff;
}
}
// If output buffer is not the same like target buffer, we have to copy data
if(nResult != 0)
{
if(pbWorkBuff != pbOutBuffer)
memcpy(pbOutBuffer, pbInBuffer, dwOutLength);
}
// Delete temporary buffer, if necessary
if(pbTempBuff != NULL)
FREEMEM(pbTempBuff);
*pdwOutLength = dwOutLength;
return nResult;
}
/*****************************************************************************/
/* */
/* SCompSetDataCompression */
/* */
/*****************************************************************************/
int WINAPI SCompSetDataCompression(int nDataCompression)
{
int nValidMask = (MPQ_COMPRESSION_ZLIB | MPQ_COMPRESSION_PKWARE | MPQ_COMPRESSION_BZIP2);
if((nDataCompression & nValidMask) != nDataCompression)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
SetDataCompression(nDataCompression);
return TRUE;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -