chore(build): update StormLib

This commit is contained in:
VDm 2024-02-07 00:05:24 +04:00
parent 1e5f4fb542
commit 6c4f278065
23 changed files with 753 additions and 287 deletions

View File

@ -40,6 +40,7 @@ set(TOMCRYPT_FILES
src/libtomcrypt/src/hashes/hash_memory.c src/libtomcrypt/src/hashes/hash_memory.c
src/libtomcrypt/src/hashes/md5.c src/libtomcrypt/src/hashes/md5.c
src/libtomcrypt/src/hashes/sha1.c src/libtomcrypt/src/hashes/sha1.c
src/libtomcrypt/src/hashes/sha256.c
src/libtomcrypt/src/math/ltm_desc.c src/libtomcrypt/src/math/ltm_desc.c
src/libtomcrypt/src/math/multi.c src/libtomcrypt/src/math/multi.c
src/libtomcrypt/src/math/rand_prime.c src/libtomcrypt/src/math/rand_prime.c

View File

@ -16,10 +16,8 @@
// Neutral resources // Neutral resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU) #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU)
#ifdef _WIN32
LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
#pragma code_page(1250) #pragma code_page(1250)
#endif //_WIN32
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
// //
@ -27,8 +25,8 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 9,22,0,3 FILEVERSION 9,25,0,3
PRODUCTVERSION 9,22,0,3 PRODUCTVERSION 9,25,0,3
FILEFLAGSMASK 0x17L FILEFLAGSMASK 0x17L
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
@ -45,12 +43,12 @@ BEGIN
BEGIN BEGIN
VALUE "Comments", "http://www.zezula.net/mpq.html" VALUE "Comments", "http://www.zezula.net/mpq.html"
VALUE "FileDescription", "StormLib library for reading Blizzard MPQ archives" VALUE "FileDescription", "StormLib library for reading Blizzard MPQ archives"
VALUE "FileVersion", "9, 22, 0, 3\0" VALUE "FileVersion", "9.25.0.3"
VALUE "InternalName", "StormLib" VALUE "InternalName", "StormLib"
VALUE "LegalCopyright", "Copyright (c) 2014 - 2020 Ladislav Zezula" VALUE "LegalCopyright", "Copyright (c) 2014 - 2023 Ladislav Zezula"
VALUE "OriginalFilename", "StormLib.dll" VALUE "OriginalFilename", "StormLib.dll"
VALUE "ProductName", "StormLib" VALUE "ProductName", "StormLib"
VALUE "ProductVersion", "9, 22, 0, 3\0" VALUE "ProductVersion", "9.25.0.3"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"
@ -64,13 +62,11 @@ END
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
// Czech resources // Czech (Czech Republic) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CSY) #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CSY)
#ifdef _WIN32
LANGUAGE LANG_CZECH, SUBLANG_DEFAULT LANGUAGE LANG_CZECH, SUBLANG_DEFAULT
#pragma code_page(1250) #pragma code_page(1250)
#endif //_WIN32
#ifdef APSTUDIO_INVOKED #ifdef APSTUDIO_INVOKED
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
@ -97,7 +93,7 @@ END
#endif // APSTUDIO_INVOKED #endif // APSTUDIO_INVOKED
#endif // Czech resources #endif // Czech (Czech Republic) resources
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////

View File

@ -8,6 +8,7 @@
#include "libtomcrypt/src/hashes/hash_memory.c" #include "libtomcrypt/src/hashes/hash_memory.c"
#include "libtomcrypt/src/hashes/md5.c" #include "libtomcrypt/src/hashes/md5.c"
#include "libtomcrypt/src/hashes/sha1.c" #include "libtomcrypt/src/hashes/sha1.c"
#include "libtomcrypt/src/hashes/sha256.c"
#include "libtomcrypt/src/math/multi.c" #include "libtomcrypt/src/math/multi.c"
#include "libtomcrypt/src/math/rand_prime.c" #include "libtomcrypt/src/math/rand_prime.c"
#include "libtomcrypt/src/misc/base64_decode.c" #include "libtomcrypt/src/misc/base64_decode.c"

View File

@ -15,7 +15,7 @@
#include "StormLib.h" #include "StormLib.h"
#include "StormCommon.h" #include "StormCommon.h"
char StormLibCopyright[] = "StormLib v " STORMLIB_VERSION_STRING " Copyright Ladislav Zezula 1998-2014"; char StormLibCopyright[] = "StormLib v " STORMLIB_VERSION_STRING " Copyright Ladislav Zezula 1998-2023";
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Local variables // Local variables
@ -244,8 +244,8 @@ void InitializeMpqCryptography()
} }
// Also register both MD5 and SHA1 hash algorithms // Also register both MD5 and SHA1 hash algorithms
register_hash(&md5_desc);
register_hash(&sha1_desc); register_hash(&sha1_desc);
register_hash(&md5_desc);
// Use LibTomMath as support math library for LibTomCrypt // Use LibTomMath as support math library for LibTomCrypt
ltc_mp = ltm_desc; ltc_mp = ltm_desc;
@ -403,7 +403,7 @@ DWORD GetDefaultSpecialFileFlags(DWORD dwFileSize, USHORT wFormatVersion)
{ {
// Fixed for format 1.0 // Fixed for format 1.0
if(wFormatVersion == MPQ_FORMAT_VERSION_1) if(wFormatVersion == MPQ_FORMAT_VERSION_1)
return MPQ_FILE_COMPRESS | MPQ_FILE_ENCRYPTED | MPQ_FILE_FIX_KEY; return MPQ_FILE_COMPRESS | MPQ_FILE_ENCRYPTED | MPQ_FILE_KEY_V2;
// Size-dependent for formats 2.0-4.0 // Size-dependent for formats 2.0-4.0
return (dwFileSize > 0x4000) ? (MPQ_FILE_COMPRESS | MPQ_FILE_SECTOR_CRC) : (MPQ_FILE_COMPRESS | MPQ_FILE_SINGLE_UNIT); return (dwFileSize > 0x4000) ? (MPQ_FILE_COMPRESS | MPQ_FILE_SECTOR_CRC) : (MPQ_FILE_COMPRESS | MPQ_FILE_SINGLE_UNIT);
@ -696,7 +696,7 @@ DWORD DecryptFileKey(
dwFileKey = HashString(szFileName, MPQ_HASH_FILE_KEY); dwFileKey = HashString(szFileName, MPQ_HASH_FILE_KEY);
// Fix the key, if needed // Fix the key, if needed
if(dwFlags & MPQ_FILE_FIX_KEY) if(dwFlags & MPQ_FILE_KEY_V2)
dwFileKey = (dwFileKey + dwMpqPos) ^ dwFileSize; dwFileKey = (dwFileKey + dwMpqPos) ^ dwFileSize;
// Return the key // Return the key
@ -999,18 +999,20 @@ void * LoadMpqTable(
LPBYTE pbCompressed = NULL; LPBYTE pbCompressed = NULL;
LPBYTE pbMpqTable; LPBYTE pbMpqTable;
LPBYTE pbToRead; LPBYTE pbToRead;
DWORD dwBytesToRead = dwCompressedSize; DWORD dwBytesToRead = dwTableSize;
DWORD dwErrCode = ERROR_SUCCESS; DWORD dwErrCode = ERROR_SUCCESS;
// Allocate the MPQ table // Allocate the MPQ table
pbMpqTable = pbToRead = STORM_ALLOC(BYTE, dwTableSize); pbMpqTable = pbToRead = STORM_ALLOC(BYTE, dwTableSize);
if(pbMpqTable != NULL) if(pbMpqTable != NULL)
{ {
// Check if the MPQ table is encrypted // Check if the MPQ table is compressed
if(dwCompressedSize < dwTableSize) if(dwCompressedSize < dwTableSize)
{ {
// Allocate temporary buffer for holding compressed data // Allocate temporary buffer for holding compressed data
pbCompressed = pbToRead = STORM_ALLOC(BYTE, dwCompressedSize); pbCompressed = pbToRead = STORM_ALLOC(BYTE, dwCompressedSize);
dwBytesToRead = dwCompressedSize;
if(pbCompressed == NULL) if(pbCompressed == NULL)
{ {
STORM_FREE(pbMpqTable); STORM_FREE(pbMpqTable);
@ -1152,6 +1154,7 @@ DWORD AllocateSectorBuffer(TMPQFile * hf)
DWORD AllocatePatchInfo(TMPQFile * hf, bool bLoadFromFile) DWORD AllocatePatchInfo(TMPQFile * hf, bool bLoadFromFile)
{ {
TMPQArchive * ha = hf->ha; TMPQArchive * ha = hf->ha;
TPatchInfo * pPatchInfo;
DWORD dwLength = sizeof(TPatchInfo); DWORD dwLength = sizeof(TPatchInfo);
// The following conditions must be true // The following conditions must be true
@ -1162,35 +1165,39 @@ __AllocateAndLoadPatchInfo:
// Allocate space for patch header. Start with default size, // Allocate space for patch header. Start with default size,
// and if its size if bigger, then we reload them // and if its size if bigger, then we reload them
hf->pPatchInfo = STORM_ALLOC(TPatchInfo, 1); pPatchInfo = (TPatchInfo *)(STORM_ALLOC(BYTE, dwLength));
if(hf->pPatchInfo == NULL) if(pPatchInfo == NULL)
return ERROR_NOT_ENOUGH_MEMORY; return ERROR_NOT_ENOUGH_MEMORY;
// Do we have to load the patch header from the file ? // Do we have to load the patch header from the file ?
if(bLoadFromFile) if(bLoadFromFile)
{ {
// Load the patch header // Load the patch header
if(!FileStream_Read(ha->pStream, &hf->RawFilePos, hf->pPatchInfo, dwLength)) if(!FileStream_Read(ha->pStream, &hf->RawFilePos, pPatchInfo, dwLength))
{ {
// Free the patch info STORM_FREE(pPatchInfo);
STORM_FREE(hf->pPatchInfo);
hf->pPatchInfo = NULL;
return GetLastError(); return GetLastError();
} }
// Perform necessary swapping // Perform necessary swapping
hf->pPatchInfo->dwLength = BSWAP_INT32_UNSIGNED(hf->pPatchInfo->dwLength); pPatchInfo->dwLength = BSWAP_INT32_UNSIGNED(pPatchInfo->dwLength);
hf->pPatchInfo->dwFlags = BSWAP_INT32_UNSIGNED(hf->pPatchInfo->dwFlags); pPatchInfo->dwFlags = BSWAP_INT32_UNSIGNED(pPatchInfo->dwFlags);
hf->pPatchInfo->dwDataSize = BSWAP_INT32_UNSIGNED(hf->pPatchInfo->dwDataSize); pPatchInfo->dwDataSize = BSWAP_INT32_UNSIGNED(pPatchInfo->dwDataSize);
// Do nothing if the patch info is not valid
if(!(pPatchInfo->dwFlags & MPQ_PATCH_INFO_VALID))
{
STORM_FREE(pPatchInfo);
return ERROR_FILE_CORRUPT;
}
// Verify the size of the patch header // Verify the size of the patch header
// If it's not default size, we have to reload them // If it's not default size, we have to reload them
if(hf->pPatchInfo->dwLength > dwLength) if(pPatchInfo->dwLength > dwLength)
{ {
// Free the patch info // Free the patch info
dwLength = hf->pPatchInfo->dwLength; dwLength = pPatchInfo->dwLength;
STORM_FREE(hf->pPatchInfo); STORM_FREE(pPatchInfo);
hf->pPatchInfo = NULL;
// If the length is out of all possible ranges, fail the operation // If the length is out of all possible ranges, fail the operation
if(dwLength > 0x400) if(dwLength > 0x400)
@ -1199,16 +1206,17 @@ __AllocateAndLoadPatchInfo:
} }
// Patch file data size according to the patch header // Patch file data size according to the patch header
hf->dwDataSize = hf->pPatchInfo->dwDataSize; hf->dwDataSize = pPatchInfo->dwDataSize;
} }
else else
{ {
memset(hf->pPatchInfo, 0, dwLength); memset(pPatchInfo, 0, dwLength);
pPatchInfo->dwLength = dwLength;
pPatchInfo->dwFlags = MPQ_PATCH_INFO_VALID;
} }
// Save the final length to the patch header // Save the final length to the patch header
hf->pPatchInfo->dwLength = dwLength; hf->pPatchInfo = pPatchInfo;
hf->pPatchInfo->dwFlags = 0x80000000;
return ERROR_SUCCESS; return ERROR_SUCCESS;
} }

View File

@ -312,34 +312,38 @@ static ULONGLONG DetermineArchiveSize_V1(
return (EndOfMpq - MpqOffset); return (EndOfMpq - MpqOffset);
} }
static ULONGLONG DetermineArchiveSize_V2( static ULONGLONG DetermineBlockTableSize_V2(TMPQHeader * pHeader, ULONGLONG MpqHeaderPos, ULONGLONG FileSize)
TMPQHeader * pHeader,
ULONGLONG MpqOffset,
ULONGLONG FileSize)
{ {
ULONGLONG EndOfMpq = FileSize; ULONGLONG BlockTablePos = MAKE_OFFSET64(pHeader->wBlockTablePosHi, pHeader->dwBlockTablePos);
DWORD dwArchiveSize32; ULONGLONG ArchiveSize = FileSize - MpqHeaderPos;
// This could only be called for MPQs version 2.0 // If there is a hi-block table and it is beyond the block table,
assert(pHeader->wFormatVersion == MPQ_FORMAT_VERSION_2); // we can determine the block table size from it
if(pHeader->HiBlockTablePos64 != 0)
// Check if we can rely on the archive size in the header
if((FileSize >> 0x20) == 0)
{ {
if(pHeader->dwBlockTablePos < pHeader->dwArchiveSize) if(pHeader->HiBlockTablePos64 > BlockTablePos)
{ {
if((pHeader->dwArchiveSize - pHeader->dwBlockTablePos) <= (pHeader->dwBlockTableSize * sizeof(TMPQBlock))) return (pHeader->HiBlockTablePos64 - BlockTablePos);
return pHeader->dwArchiveSize;
// If the archive size in the header is less than real file size
dwArchiveSize32 = (DWORD)(FileSize - MpqOffset);
if(pHeader->dwArchiveSize <= dwArchiveSize32)
return pHeader->dwArchiveSize;
} }
} }
// Return the calculated archive size // If we have valid archive size, we can determine the block table size from the archive size
return (EndOfMpq - MpqOffset); else
{
if((BlockTablePos >> 0x20) == 0 && (ArchiveSize >> 0x20) == 0)
{
DWORD dwBlockTablePos32 = (DWORD)(BlockTablePos);
DWORD dwArchiveSize32 = (DWORD)(ArchiveSize);
if(pHeader->dwArchiveSize == dwArchiveSize32)
{
return (dwArchiveSize32 - dwBlockTablePos32);
}
}
}
// Default is the block table size from MPQ header
return (ULONGLONG)(pHeader->dwBlockTableSize) * sizeof(TMPQBlock);
} }
static ULONGLONG DetermineArchiveSize_V4( static ULONGLONG DetermineArchiveSize_V4(
@ -381,20 +385,39 @@ static ULONGLONG DetermineArchiveSize_V4(
return ArchiveSize; return ArchiveSize;
} }
ULONGLONG GetFileOffsetMask(TMPQArchive * ha)
{
ULONGLONG FileOffsetMask = (ULONGLONG)(-1);
// Sanity checks
assert(ha != NULL);
assert(ha->pHeader != NULL);
// MPQs of format 1 are 32-bit only
if(ha->pHeader->wFormatVersion == MPQ_FORMAT_VERSION_1)
FileOffsetMask = (ULONGLONG)(DWORD)(-1);
return FileOffsetMask;
}
ULONGLONG FileOffsetFromMpqOffset(TMPQArchive * ha, ULONGLONG MpqOffset) ULONGLONG FileOffsetFromMpqOffset(TMPQArchive * ha, ULONGLONG MpqOffset)
{ {
if(ha->pHeader->wFormatVersion == MPQ_FORMAT_VERSION_1) return (ha->MpqPos + MpqOffset) & ha->FileOffsetMask;
{
// For MPQ archive v1, any file offset is only 32-bit
return (ULONGLONG)((DWORD)ha->MpqPos + (DWORD)MpqOffset);
}
else
{
// For MPQ archive v2+, file offsets are full 64-bit
return ha->MpqPos + MpqOffset;
}
} }
//ULONGLONG FileOffsetFromMpqOffset(TMPQArchive * ha, ULONGLONG MpqOffset)
//{
// if(ha->pHeader->wFormatVersion == MPQ_FORMAT_VERSION_1)
// {
// // For MPQ archive v1, any file offset is only 32-bit
// return (ULONGLONG)((DWORD)ha->MpqPos + (DWORD)MpqOffset);
// }
// else
// {
// // For MPQ archive v2+, file offsets are full 64-bit
// return ha->MpqPos + MpqOffset;
// }
//}
ULONGLONG CalculateRawSectorOffset( ULONGLONG CalculateRawSectorOffset(
TMPQFile * hf, TMPQFile * hf,
DWORD dwSectorOffset) DWORD dwSectorOffset)
@ -414,9 +437,7 @@ ULONGLONG CalculateRawSectorOffset(
// For MPQs version 1.0, the offset is purely 32-bit // For MPQs version 1.0, the offset is purely 32-bit
// //
RawFilePos = hf->RawFilePos + dwSectorOffset; RawFilePos = (hf->RawFilePos + dwSectorOffset) & hf->ha->FileOffsetMask;
if(hf->ha->pHeader->wFormatVersion == MPQ_FORMAT_VERSION_1)
RawFilePos = (DWORD)hf->ha->MpqPos + (DWORD)hf->pFileEntry->ByteOffset + dwSectorOffset;
// We also have to add patch header size, if patch header is present // We also have to add patch header size, if patch header is present
if(hf->pPatchInfo != NULL) if(hf->pPatchInfo != NULL)
@ -541,34 +562,14 @@ DWORD ConvertMpqHeaderToFormat4(
// We require the block table to follow hash table // We require the block table to follow hash table
if(BlockTablePos64 >= HashTablePos64) if(BlockTablePos64 >= HashTablePos64)
{ {
// HashTableSize64 may be less than TblSize * sizeof(TMPQHash). // Determine whether the hash table is compressed. This can be detected
// That means that the hash table is compressed. // by subtracting hash table position from the block table position.
pHeader->HashTableSize64 = BlockTablePos64 - HashTablePos64; pHeader->HashTableSize64 = BlockTablePos64 - HashTablePos64;
// Calculate the compressed block table size // Also, block table may be compressed. We check whether the HiBlockTable is there.
if(pHeader->HiBlockTablePos64 != 0) // If not, we try to use the archive size. Note that ArchiveSize may have
{ // an arbitrary value, because it is not tested by Blizzard games anymore
// BlockTableSize64 may be less than TblSize * sizeof(TMPQBlock). pHeader->BlockTableSize64 = DetermineBlockTableSize_V2(pHeader, ByteOffset, FileSize);
// That means that the block table is compressed.
pHeader->BlockTableSize64 = pHeader->HiBlockTablePos64 - BlockTablePos64;
assert(pHeader->BlockTableSize64 <= (pHeader->dwBlockTableSize * sizeof(TMPQBlock)));
// Determine real archive size
pHeader->ArchiveSize64 = DetermineArchiveSize_V2(pHeader, ByteOffset, FileSize);
// Calculate the size of the hi-block table
pHeader->HiBlockTableSize64 = pHeader->ArchiveSize64 - pHeader->HiBlockTablePos64;
assert(pHeader->HiBlockTableSize64 == (pHeader->dwBlockTableSize * sizeof(USHORT)));
}
else
{
// Determine real archive size
pHeader->ArchiveSize64 = DetermineArchiveSize_V2(pHeader, ByteOffset, FileSize);
// Calculate size of the block table
pHeader->BlockTableSize64 = pHeader->ArchiveSize64 - BlockTablePos64;
assert(pHeader->BlockTableSize64 <= (pHeader->dwBlockTableSize * sizeof(TMPQBlock)));
}
} }
else else
{ {

View File

@ -895,6 +895,16 @@ int WINAPI SCompCompress(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuff
/* */ /* */
/*****************************************************************************/ /*****************************************************************************/
// Decompression table specific for Starcraft I BETA
// WAVE files are compressed by different ADPCM compression
static TDecompressTable dcmp_table_sc_beta[] =
{
{MPQ_COMPRESSION_PKWARE, Decompress_PKLIB}, // Decompression with Pkware Data Compression Library
{MPQ_COMPRESSION_HUFFMANN, Decompress_huff}, // Huffmann decompression
{0x10, Decompress_ADPCM1_sc1b}, // IMA ADPCM mono decompression
{0x20, Decompress_ADPCM2_sc1b}, // IMA ADPCM stereo decompression
};
// This table contains decompress functions which can be applied to // This table contains decompress functions which can be applied to
// uncompressed data. The compression mask is stored in the first byte // uncompressed data. The compression mask is stored in the first byte
// of compressed data // of compressed data
@ -909,25 +919,22 @@ static TDecompressTable dcmp_table[] =
{MPQ_COMPRESSION_SPARSE, Decompress_SPARSE} // Sparse decompression {MPQ_COMPRESSION_SPARSE, Decompress_SPARSE} // Sparse decompression
}; };
// Decompression table specific for Starcraft I BETA static int SCompDecompressInternal(
// WAVE files are compressed by different ADPCM compression TDecompressTable * table,
static TDecompressTable dcmp_table_sc1b[] = size_t table_length,
{ void * pvOutBuffer,
{MPQ_COMPRESSION_PKWARE, Decompress_PKLIB}, // Decompression with Pkware Data Compression Library int * pcbOutBuffer,
{MPQ_COMPRESSION_HUFFMANN, Decompress_huff}, // Huffmann decompression void * pvInBuffer,
{0x10, Decompress_ADPCM1_sc1b}, // IMA ADPCM mono decompression int cbInBuffer,
{0x20, Decompress_ADPCM2_sc1b}, // IMA ADPCM stereo decompression unsigned uValidMask = 0xFF)
};
static int SCompDecompressInternal(TDecompressTable * table, size_t table_length, void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer)
{ {
unsigned char * pbWorkBuffer = NULL; unsigned char * pbWorkBuffer = NULL;
unsigned char * pbOutBuffer = (unsigned char *)pvOutBuffer; unsigned char * pbOutBuffer = (unsigned char *)pvOutBuffer;
unsigned char * pbInBuffer = (unsigned char *)pvInBuffer; unsigned char * pbInBuffer = (unsigned char *)pvInBuffer;
unsigned char * pbOutput = (unsigned char *)pvOutBuffer; unsigned char * pbOutput = (unsigned char *)pvOutBuffer;
unsigned char * pbInput; unsigned char * pbInput;
unsigned uCompressionMask; // Decompressions applied to the data unsigned uCompressionMask1; // Decompressions applied to the data
unsigned uCompressionCopy; // Decompressions applied to the data unsigned uCompressionMask2; // Decompressions applied to the data
int cbOutBuffer = *pcbOutBuffer; // Current size of the output buffer int cbOutBuffer = *pcbOutBuffer; // Current size of the output buffer
int cbInLength; // Current size of the input buffer int cbInLength; // Current size of the input buffer
int nCompressCount = 0; // Number of compressions to be applied int nCompressCount = 0; // Number of compressions to be applied
@ -948,7 +955,8 @@ static int SCompDecompressInternal(TDecompressTable * table, size_t table_length
} }
// Get applied compression types and decrement data length // Get applied compression types and decrement data length
uCompressionMask = uCompressionCopy = (unsigned char)(*pbInBuffer++); uCompressionMask1 = ((unsigned char)(*pbInBuffer++) & (uValidMask));
uCompressionMask2 = uCompressionMask1;
cbInBuffer--; cbInBuffer--;
// Get current compressed data and length of it // Get current compressed data and length of it
@ -956,21 +964,21 @@ static int SCompDecompressInternal(TDecompressTable * table, size_t table_length
cbInLength = cbInBuffer; cbInLength = cbInBuffer;
// This compression function doesn't support LZMA // This compression function doesn't support LZMA
assert(uCompressionMask != MPQ_COMPRESSION_LZMA); assert(uCompressionMask1 != MPQ_COMPRESSION_LZMA);
// Parse the compression mask // Parse the compression mask
for(size_t i = 0; i < table_length; i++) for(size_t i = 0; i < table_length; i++)
{ {
// If the mask agrees, insert the compression function to the array // If the mask agrees, insert the compression function to the array
if(uCompressionMask & table[i].uMask) if(uCompressionMask1 & table[i].uMask)
{ {
uCompressionCopy &= ~table[i].uMask; uCompressionMask2 &= ~table[i].uMask;
nCompressCount++; nCompressCount++;
} }
} }
// If at least one of the compressions remaing unknown, return an error // If at least one of the compressions remaing unknown, return an error
if(nCompressCount == 0 || uCompressionCopy != 0) if(nCompressCount == 0 || uCompressionMask2 != 0)
{ {
SetLastError(ERROR_NOT_SUPPORTED); SetLastError(ERROR_NOT_SUPPORTED);
return 0; return 0;
@ -994,7 +1002,7 @@ static int SCompDecompressInternal(TDecompressTable * table, size_t table_length
for(size_t i = 0; i < table_length; i++) for(size_t i = 0; i < table_length; i++)
{ {
// Perform the (next) decompression // Perform the (next) decompression
if(uCompressionMask & table[i].uMask) if(uCompressionMask1 & table[i].uMask)
{ {
// Get the correct output buffer // Get the correct output buffer
pbOutput = (nCompressIndex & 1) ? pbWorkBuffer : pbOutBuffer; pbOutput = (nCompressIndex & 1) ? pbWorkBuffer : pbOutBuffer;
@ -1030,11 +1038,6 @@ int WINAPI SCompDecompress(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBu
return SCompDecompressInternal(dcmp_table, _countof(dcmp_table), pvOutBuffer, pcbOutBuffer, pvInBuffer, cbInBuffer); return SCompDecompressInternal(dcmp_table, _countof(dcmp_table), pvOutBuffer, pcbOutBuffer, pvInBuffer, cbInBuffer);
} }
int WINAPI SCompDecompress_SC1B(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer)
{
return SCompDecompressInternal(dcmp_table_sc1b, _countof(dcmp_table_sc1b), pvOutBuffer, pcbOutBuffer, pvInBuffer, cbInBuffer);
}
int WINAPI SCompDecompress2(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer) int WINAPI SCompDecompress2(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer)
{ {
DECOMPRESS pfnDecompress1 = NULL; DECOMPRESS pfnDecompress1 = NULL;
@ -1149,6 +1152,24 @@ int WINAPI SCompDecompress2(void * pvOutBuffer, int * pcbOutBuffer, void * pvInB
return nResult; return nResult;
} }
int WINAPI SCompDecompressX(TMPQArchive * ha, void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer)
{
// MPQs version 2 use their own fixed list of compression flags.
if(ha->pHeader->wFormatVersion >= MPQ_FORMAT_VERSION_2)
{
return SCompDecompress2(pvOutBuffer, pcbOutBuffer, pvInBuffer, cbInBuffer);
}
// Starcraft BETA has specific decompression table.
if(ha->dwFlags & MPQ_FLAG_STARCRAFT_BETA)
{
return SCompDecompressInternal(dcmp_table_sc_beta, _countof(dcmp_table_sc_beta), pvOutBuffer, pcbOutBuffer, pvInBuffer, cbInBuffer);
}
// Default: Use the common MPQ v1 decompression routine
return SCompDecompressInternal(dcmp_table, _countof(dcmp_table), pvOutBuffer, pcbOutBuffer, pvInBuffer, cbInBuffer);
}
/*****************************************************************************/ /*****************************************************************************/
/* */ /* */
/* File decompression for MPK archives */ /* File decompression for MPK archives */

View File

@ -246,6 +246,14 @@ static DWORD WriteDataToMpqFile(
BSWAP_ARRAY32_UNSIGNED(pbToWrite, dwBytesInSector); BSWAP_ARRAY32_UNSIGNED(pbToWrite, dwBytesInSector);
} }
// Do not allow Warcraft III maps to go over 2GB.
// https://github.com/ladislav-zezula/StormLib/issues/306
if((ha->dwFlags & MPQ_FLAG_WAR3_MAP) && (ByteOffset + dwBytesInSector) > 0x7FFFFFFF)
{
dwErrCode = ERROR_DISK_FULL;
break;
}
// Write the file sector // Write the file sector
if(!FileStream_Write(ha->pStream, &ByteOffset, pbToWrite, dwBytesInSector)) if(!FileStream_Write(ha->pStream, &ByteOffset, pbToWrite, dwBytesInSector))
{ {
@ -425,7 +433,7 @@ DWORD SFileAddFile_Init(
// Fix Key is not allowed if the file is not encrypted // Fix Key is not allowed if the file is not encrypted
if(!(dwFlags & MPQ_FILE_ENCRYPTED)) if(!(dwFlags & MPQ_FILE_ENCRYPTED))
dwFlags &= ~MPQ_FILE_FIX_KEY; dwFlags &= ~MPQ_FILE_KEY_V2;
// If the MPQ is of version 3.0 or higher, we ignore file locale. // If the MPQ is of version 3.0 or higher, we ignore file locale.
// This is because HET and BET tables have no known support for it // This is because HET and BET tables have no known support for it
@ -1295,7 +1303,7 @@ bool WINAPI SFileSetFileLocale(HANDLE hFile, LCID lcNewLocale)
} }
// We have to check if the file+locale is not already there // We have to check if the file+locale is not already there
pFileEntry = GetFileEntryLocale(ha, hf->pFileEntry->szFileName, lcNewLocale, NULL); pFileEntry = GetFileEntryExact(ha, hf->pFileEntry->szFileName, lcNewLocale, NULL);
if(pFileEntry != NULL) if(pFileEntry != NULL)
{ {
SetLastError(ERROR_ALREADY_EXISTS); SetLastError(ERROR_ALREADY_EXISTS);

View File

@ -391,7 +391,10 @@ DWORD SAttrLoadAttributes(TMPQArchive * ha)
pbAttrFile[cbAttrFile] = 0; pbAttrFile[cbAttrFile] = 0;
// Load the entire file to memory // Load the entire file to memory
SFileReadFile(hFile, pbAttrFile, cbAttrFile, &dwBytesRead, NULL); if(!SFileReadFile(hFile, pbAttrFile, cbAttrFile, &dwBytesRead, NULL))
ha->dwFlags |= (GetLastError() == ERROR_FILE_CORRUPT) ? MPQ_FLAG_MALFORMED : 0;
// Parse the (attributes)
if(dwBytesRead == cbAttrFile) if(dwBytesRead == cbAttrFile)
dwErrCode = LoadAttributesFile(ha, pbAttrFile, cbAttrFile); dwErrCode = LoadAttributesFile(ha, pbAttrFile, cbAttrFile);

View File

@ -163,7 +163,7 @@ static DWORD CopyMpqFileSectors(
if(dwErrCode == ERROR_SUCCESS && (pFileEntry->dwFlags & MPQ_FILE_ENCRYPTED)) if(dwErrCode == ERROR_SUCCESS && (pFileEntry->dwFlags & MPQ_FILE_ENCRYPTED))
{ {
dwFileKey2 = dwFileKey1 = hf->dwFileKey; dwFileKey2 = dwFileKey1 = hf->dwFileKey;
if(pFileEntry->dwFlags & MPQ_FILE_FIX_KEY) if(pFileEntry->dwFlags & MPQ_FILE_KEY_V2)
{ {
dwFileKey2 = (dwFileKey1 ^ pFileEntry->dwFileSize) - (DWORD)pFileEntry->ByteOffset; dwFileKey2 = (dwFileKey1 ^ pFileEntry->dwFileSize) - (DWORD)pFileEntry->ByteOffset;
dwFileKey2 = (dwFileKey2 + (DWORD)MpqFilePos) ^ pFileEntry->dwFileSize; dwFileKey2 = (dwFileKey2 + (DWORD)MpqFilePos) ^ pFileEntry->dwFileSize;

View File

@ -238,6 +238,9 @@ bool WINAPI SFileCreateArchive2(const TCHAR * szMpqName, PSFILE_CREATE_MPQ pCrea
pHeader->dwBlockTablePos = pHeader->dwHashTablePos + dwHashTableSize * sizeof(TMPQHash); pHeader->dwBlockTablePos = pHeader->dwHashTablePos + dwHashTableSize * sizeof(TMPQHash);
pHeader->dwBlockTableSize = dwBlockTableSize; pHeader->dwBlockTableSize = dwBlockTableSize;
// Set the mask for MPQ byte offset
ha->FileOffsetMask = GetFileOffsetMask(ha);
// For MPQs version 4 and higher, we set the size of raw data block // For MPQs version 4 and higher, we set the size of raw data block
// for calculating MD5 // for calculating MD5
if(pCreateInfo->dwMpqVersion >= MPQ_FORMAT_VERSION_4) if(pCreateInfo->dwMpqVersion >= MPQ_FORMAT_VERSION_4)

View File

@ -68,6 +68,10 @@ static bool GetInfo_BufferCheck(void * pvFileInfo, DWORD cbFileInfo, DWORD cbDat
static bool GetInfo(void * pvFileInfo, DWORD cbFileInfo, const void * pvData, DWORD cbData, LPDWORD pcbLengthNeeded) static bool GetInfo(void * pvFileInfo, DWORD cbFileInfo, const void * pvData, DWORD cbData, LPDWORD pcbLengthNeeded)
{ {
// Verify the input parameter
if(pvData == NULL)
return GetInfo_ReturnError(ERROR_INVALID_PARAMETER);
// Verify buffer pointer and buffer size // Verify buffer pointer and buffer size
if(!GetInfo_BufferCheck(pvFileInfo, cbFileInfo, cbData, pcbLengthNeeded)) if(!GetInfo_BufferCheck(pvFileInfo, cbFileInfo, cbData, pcbLengthNeeded))
return false; return false;
@ -81,6 +85,10 @@ static bool GetInfo_Allocated(void * pvFileInfo, DWORD cbFileInfo, void * pvData
{ {
bool bResult; bool bResult;
// Verify the input parameter
if(pvData == NULL)
return GetInfo_ReturnError(ERROR_INVALID_PARAMETER);
// Verify buffer pointer and buffer size // Verify buffer pointer and buffer size
if((bResult = GetInfo_BufferCheck(pvFileInfo, cbFileInfo, cbData, pcbLengthNeeded)) != false) if((bResult = GetInfo_BufferCheck(pvFileInfo, cbFileInfo, cbData, pcbLengthNeeded)) != false)
memcpy(pvFileInfo, pvData, cbData); memcpy(pvFileInfo, pvData, cbData);
@ -401,15 +409,21 @@ bool WINAPI SFileGetFileInfo(
return GetInfo(pvFileInfo, cbFileInfo, &hf->dwHashIndex, sizeof(DWORD), pcbLengthNeeded); return GetInfo(pvFileInfo, cbFileInfo, &hf->dwHashIndex, sizeof(DWORD), pcbLengthNeeded);
case SFileInfoNameHash1: case SFileInfoNameHash1:
if(hf->pHashEntry == NULL)
return GetInfo_ReturnError(ERROR_INVALID_PARAMETER);
return GetInfo(pvFileInfo, cbFileInfo, &hf->pHashEntry->dwName1, sizeof(DWORD), pcbLengthNeeded); return GetInfo(pvFileInfo, cbFileInfo, &hf->pHashEntry->dwName1, sizeof(DWORD), pcbLengthNeeded);
case SFileInfoNameHash2: case SFileInfoNameHash2:
if(hf->pHashEntry == NULL)
return GetInfo_ReturnError(ERROR_INVALID_PARAMETER);
return GetInfo(pvFileInfo, cbFileInfo, &hf->pHashEntry->dwName2, sizeof(DWORD), pcbLengthNeeded); return GetInfo(pvFileInfo, cbFileInfo, &hf->pHashEntry->dwName2, sizeof(DWORD), pcbLengthNeeded);
case SFileInfoNameHash3: case SFileInfoNameHash3:
return GetInfo(pvFileInfo, cbFileInfo, &pFileEntry->FileNameHash, sizeof(ULONGLONG), pcbLengthNeeded); return GetInfo(pvFileInfo, cbFileInfo, &pFileEntry->FileNameHash, sizeof(ULONGLONG), pcbLengthNeeded);
case SFileInfoLocale: case SFileInfoLocale:
if(hf->pHashEntry == NULL)
return GetInfo_ReturnError(ERROR_INVALID_PARAMETER);
dwInt32Value = SFILE_MAKE_LCID(hf->pHashEntry->Locale, hf->pHashEntry->Platform); dwInt32Value = SFILE_MAKE_LCID(hf->pHashEntry->Locale, hf->pHashEntry->Platform);
return GetInfo(pvFileInfo, cbFileInfo, &dwInt32Value, sizeof(DWORD), pcbLengthNeeded); return GetInfo(pvFileInfo, cbFileInfo, &dwInt32Value, sizeof(DWORD), pcbLengthNeeded);
@ -437,7 +451,7 @@ bool WINAPI SFileGetFileInfo(
case SFileInfoEncryptionKeyRaw: case SFileInfoEncryptionKeyRaw:
dwInt32Value = hf->dwFileKey; dwInt32Value = hf->dwFileKey;
if(pFileEntry->dwFlags & MPQ_FILE_FIX_KEY) if(pFileEntry->dwFlags & MPQ_FILE_KEY_V2)
dwInt32Value = (dwInt32Value ^ pFileEntry->dwFileSize) - (DWORD)hf->MpqFilePos; dwInt32Value = (dwInt32Value ^ pFileEntry->dwFileSize) - (DWORD)hf->MpqFilePos;
return GetInfo(pvFileInfo, cbFileInfo, &dwInt32Value, sizeof(DWORD), pcbLengthNeeded); return GetInfo(pvFileInfo, cbFileInfo, &dwInt32Value, sizeof(DWORD), pcbLengthNeeded);
@ -564,11 +578,11 @@ static DWORD CreatePseudoFileName(HANDLE hFile, TFileEntry * pFileEntry, char *
bool WINAPI SFileGetFileName(HANDLE hFile, char * szFileName) bool WINAPI SFileGetFileName(HANDLE hFile, char * szFileName)
{ {
TMPQFile * hf = (TMPQFile *)hFile; // MPQ File handle TMPQFile * hf;
DWORD dwErrCode = ERROR_INVALID_HANDLE; DWORD dwErrCode = ERROR_INVALID_HANDLE;
// Check valid parameters // Check valid parameters
if(IsValidFileHandle(hFile)) if((hf = IsValidFileHandle(hFile)) != NULL)
{ {
TFileEntry * pFileEntry = hf->pFileEntry; TFileEntry * pFileEntry = hf->pFileEntry;

View File

@ -558,6 +558,27 @@ static DWORD SFileAddArbitraryListFile(
return (pCache != NULL) ? ERROR_SUCCESS : ERROR_FILE_CORRUPT; return (pCache != NULL) ? ERROR_SUCCESS : ERROR_FILE_CORRUPT;
} }
static DWORD SFileAddArbitraryListFile(
TMPQArchive * ha,
const char ** listFileEntries,
DWORD dwEntryCount)
{
if(listFileEntries != NULL && dwEntryCount > 0)
{
// Get the next line
for(DWORD dwListFileNum = 0; dwListFileNum < dwEntryCount; dwListFileNum++)
{
const char * listFileEntry = listFileEntries[dwListFileNum];
if(listFileEntry != NULL)
{
SListFileCreateNodeForAllLocales(ha, listFileEntry);
}
}
}
return (listFileEntries != NULL && dwEntryCount > 0) ? ERROR_SUCCESS : ERROR_INVALID_PARAMETER;
}
static DWORD SFileAddInternalListFile( static DWORD SFileAddInternalListFile(
TMPQArchive * ha, TMPQArchive * ha,
HANDLE hMpq) HANDLE hMpq)
@ -662,6 +683,32 @@ DWORD WINAPI SFileAddListFile(HANDLE hMpq, const TCHAR * szListFile)
return dwErrCode; return dwErrCode;
} }
DWORD WINAPI SFileAddListFileEntries(HANDLE hMpq, const char ** listFileEntries, DWORD dwEntryCount)
{
TMPQArchive * ha = (TMPQArchive *)hMpq;
DWORD dwErrCode = ERROR_SUCCESS;
// Add the listfile for each MPQ in the patch chain
while(ha != NULL)
{
if(listFileEntries != NULL && dwEntryCount > 0)
dwErrCode = SFileAddArbitraryListFile(ha, listFileEntries, dwEntryCount);
else
dwErrCode = SFileAddInternalListFile(ha, hMpq);
// Also, add three special files to the listfile:
// (listfile) itself, (attributes) and (signature)
SListFileCreateNodeForAllLocales(ha, LISTFILE_NAME);
SListFileCreateNodeForAllLocales(ha, SIGNATURE_NAME);
SListFileCreateNodeForAllLocales(ha, ATTRIBUTES_NAME);
// Move to the next archive in the chain
ha = ha->haPatch;
}
return dwErrCode;
}
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Enumerating files in listfile // Enumerating files in listfile

View File

@ -387,7 +387,7 @@ bool WINAPI SFileOpenArchive(
} }
// Check for MPK archives (Longwu Online - MPQ fork) // Check for MPK archives (Longwu Online - MPQ fork)
if(MapType == MapTypeNotRecognized && dwHeaderID == ID_MPK) if(MapType == MapTypeNotRecognized && (dwFlags & MPQ_OPEN_FORCE_MPQ_V1) == 0 && dwHeaderID == ID_MPK)
{ {
// Now convert the MPK header to MPQ Header version 4 // Now convert the MPK header to MPQ Header version 4
dwErrCode = ConvertMpkHeaderToFormat4(ha, FileSize, dwFlags); dwErrCode = ConvertMpkHeaderToFormat4(ha, FileSize, dwFlags);
@ -463,17 +463,25 @@ bool WINAPI SFileOpenArchive(
if(IsStarcraftBetaArchive(ha->pHeader)) if(IsStarcraftBetaArchive(ha->pHeader))
ha->dwFlags |= MPQ_FLAG_STARCRAFT_BETA; ha->dwFlags |= MPQ_FLAG_STARCRAFT_BETA;
// Remember whether whis is a map for Warcraft III // Set the mask for the file offset. In MPQs version 1,
if(MapType == MapTypeWarcraft3) // all offsets are 32-bit and overflow is allowed.
// For MPQs v2+, file offset if 64-bit.
ha->FileOffsetMask = GetFileOffsetMask(ha);
// Maps from StarCraft and Warcraft III need special treatment
switch(MapType)
{ {
case MapTypeStarcraft:
ha->dwValidFileFlags = MPQ_FILE_VALID_FLAGS_SCX;
ha->dwFlags |= MPQ_FLAG_STARCRAFT;
break;
case MapTypeWarcraft3:
ha->dwValidFileFlags = MPQ_FILE_VALID_FLAGS_W3X; ha->dwValidFileFlags = MPQ_FILE_VALID_FLAGS_W3X;
ha->dwFlags |= MPQ_FLAG_WAR3_MAP; ha->dwFlags |= MPQ_FLAG_WAR3_MAP;
break;
} }
// If this is starcraft map, set the flag mask
if(MapType == MapTypeStarcraft)
ha->dwValidFileFlags = MPQ_FILE_VALID_FLAGS_SCX;
// Set the size of file sector // Set the size of file sector
ha->dwSectorSize = (0x200 << ha->pHeader->wSectorSize); ha->dwSectorSize = (0x200 << ha->pHeader->wSectorSize);

View File

@ -16,11 +16,13 @@
/* Local functions */ /* Local functions */
/*****************************************************************************/ /*****************************************************************************/
// Finds hash index of the entry that was open by pseudo-name
static DWORD FindHashIndex(TMPQArchive * ha, DWORD dwFileIndex) static DWORD FindHashIndex(TMPQArchive * ha, DWORD dwFileIndex)
{ {
TMPQHash * pHashTableEnd; TMPQHash * pHashTableEnd;
TMPQHash * pHash; TMPQHash * pHash;
DWORD dwFirstIndex = HASH_ENTRY_FREE; DWORD dwHashIndex = HASH_ENTRY_FREE;
DWORD dwCount = 0;
// Should only be called if the archive has hash table // Should only be called if the archive has hash table
assert(ha->pHashTable != NULL); assert(ha->pHashTable != NULL);
@ -32,15 +34,18 @@ static DWORD FindHashIndex(TMPQArchive * ha, DWORD dwFileIndex)
{ {
if(MPQ_BLOCK_INDEX(pHash) == dwFileIndex) if(MPQ_BLOCK_INDEX(pHash) == dwFileIndex)
{ {
// Duplicate hash entry found // Example: MPQ_2023_v1_Lusin2Rpg1.28.w3x, file index 24483
if(dwFirstIndex != HASH_ENTRY_FREE) // ReplaceableTextures\CommandButtons\BTNHaboss79.blp
// Hash Table Index #1 = 18
// Hash Table Index #2 = 8446
if(dwCount++ > 0)
return HASH_ENTRY_FREE; return HASH_ENTRY_FREE;
dwFirstIndex = (DWORD)(pHash - ha->pHashTable); dwHashIndex = (DWORD)(pHash - ha->pHashTable);
} }
} }
// Return the hash table entry index // Return the found hash index, if there are no duplicities
return dwFirstIndex; return dwHashIndex;
} }
static const char * GetPatchFileName(TMPQArchive * ha, const char * szFileName, char * szBuffer) static const char * GetPatchFileName(TMPQArchive * ha, const char * szFileName, char * szBuffer)
@ -311,7 +316,7 @@ bool WINAPI SFileOpenFileEx(HANDLE hMpq, const char * szFileName, DWORD dwSearch
} }
// Still not found? // Still not found?
if (pFileEntry == NULL) if(pFileEntry == NULL || (pFileEntry->dwFlags & MPQ_FILE_EXISTS) == 0)
{ {
dwErrCode = ERROR_FILE_NOT_FOUND; dwErrCode = ERROR_FILE_NOT_FOUND;
} }

View File

@ -13,6 +13,11 @@
#include "StormLib.h" #include "StormLib.h"
#include "StormCommon.h" #include "StormCommon.h"
//-----------------------------------------------------------------------------
// External references (not public functions)
int WINAPI SCompDecompressX(TMPQArchive * ha, void * pvOutBuffer, int * pcbOutBuffer, void * pbInBuffer, int cbInBuffer);
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Local functions // Local functions
@ -171,18 +176,10 @@ static DWORD ReadMpqSectors(TMPQFile * hf, LPBYTE pbBuffer, DWORD dwByteOffset,
// Remember the last used compression // Remember the last used compression
hf->dwCompression0 = pbInSector[0]; hf->dwCompression0 = pbInSector[0];
// Decompress the data // Decompress the data. We need to perform MPQ-specific decompression,
if(ha->pHeader->wFormatVersion >= MPQ_FORMAT_VERSION_2) // as multiple Blizzard games may have their own decompression tables
{ // and even decompression methods.
nResult = SCompDecompress2(pbOutSector, &cbOutSector, pbInSector, cbInSector); nResult = SCompDecompressX(ha, pbOutSector, &cbOutSector, pbInSector, cbInSector);
}
else
{
if(ha->dwFlags & MPQ_FLAG_STARCRAFT_BETA)
nResult = SCompDecompress_SC1B(pbOutSector, &cbOutSector, pbInSector, cbInSector);
else
nResult = SCompDecompress(pbOutSector, &cbOutSector, pbInSector, cbInSector);
}
} }
// Is the file compressed by PKWARE Data Compression Library ? // Is the file compressed by PKWARE Data Compression Library ?

View File

@ -82,7 +82,7 @@
#endif #endif
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// MTYPE definition - specifies what kind of MPQ is the map type // MTYPE definition - specifies what kind of MPQ is the file
typedef enum _MTYPE typedef enum _MTYPE
{ {
@ -251,6 +251,7 @@ TMPQFile * IsValidFileHandle(HANDLE hFile);
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Support for MPQ file tables // Support for MPQ file tables
ULONGLONG GetFileOffsetMask(TMPQArchive * ha);
ULONGLONG FileOffsetFromMpqOffset(TMPQArchive * ha, ULONGLONG MpqOffset); ULONGLONG FileOffsetFromMpqOffset(TMPQArchive * ha, ULONGLONG MpqOffset);
ULONGLONG CalculateRawSectorOffset(TMPQFile * hf, DWORD dwSectorOffset); ULONGLONG CalculateRawSectorOffset(TMPQFile * hf, DWORD dwSectorOffset);

View File

@ -143,8 +143,8 @@ extern "C" {
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Defines // Defines
#define STORMLIB_VERSION 0x0918 // Current version of StormLib (9.24) #define STORMLIB_VERSION 0x0919 // Current version of StormLib
#define STORMLIB_VERSION_STRING "9.24" // String version of StormLib version #define STORMLIB_VERSION_STRING "9.25" // Current version of StormLib as string
#define ID_MPQ 0x1A51504D // MPQ archive header ID ('MPQ\x1A') #define ID_MPQ 0x1A51504D // MPQ archive header ID ('MPQ\x1A')
#define ID_MPQ_USERDATA 0x1B51504D // MPQ userdata entry ('MPQ\x1B') #define ID_MPQ_USERDATA 0x1B51504D // MPQ userdata entry ('MPQ\x1B')
@ -194,15 +194,16 @@ extern "C" {
#define MPQ_FLAG_CHECK_SECTOR_CRC 0x00000020 // Checking sector CRC when reading files #define MPQ_FLAG_CHECK_SECTOR_CRC 0x00000020 // Checking sector CRC when reading files
#define MPQ_FLAG_SAVING_TABLES 0x00000040 // If set, we are saving MPQ internal files and MPQ tables #define MPQ_FLAG_SAVING_TABLES 0x00000040 // If set, we are saving MPQ internal files and MPQ tables
#define MPQ_FLAG_PATCH 0x00000080 // If set, this MPQ is a patch archive #define MPQ_FLAG_PATCH 0x00000080 // If set, this MPQ is a patch archive
#define MPQ_FLAG_WAR3_MAP 0x00000100 // If set, this MPQ is a Warcraft III map #define MPQ_FLAG_STARCRAFT_BETA 0x00000100 // If set, this MPQ is from Starcraft I BETA
#define MPQ_FLAG_STARCRAFT_BETA 0x00000200 // If set, this MPQ is StarDat.mpq from Starcraft I BETA #define MPQ_FLAG_STARCRAFT 0x00000200 // If set, this MPQ is from Starcraft I
#define MPQ_FLAG_LISTFILE_NONE 0x00000400 // Set when no (listfile) was found in InvalidateInternalFiles #define MPQ_FLAG_WAR3_MAP 0x00000400 // If set, this MPQ is a Warcraft III map
#define MPQ_FLAG_LISTFILE_NEW 0x00000800 // Set when (listfile) invalidated by InvalidateInternalFiles #define MPQ_FLAG_LISTFILE_NONE 0x00000800 // Set when no (listfile) was found in InvalidateInternalFiles
#define MPQ_FLAG_LISTFILE_FORCE 0x00001000 // Save updated listfile on exit #define MPQ_FLAG_LISTFILE_NEW 0x00001000 // Set when (listfile) invalidated by InvalidateInternalFiles
#define MPQ_FLAG_ATTRIBUTES_NONE 0x00002000 // Set when no (attributes) was found in InvalidateInternalFiles #define MPQ_FLAG_LISTFILE_FORCE 0x00002000 // Save updated listfile on exit
#define MPQ_FLAG_ATTRIBUTES_NEW 0x00004000 // Set when (attributes) invalidated by InvalidateInternalFiles #define MPQ_FLAG_ATTRIBUTES_NONE 0x00004000 // Set when no (attributes) was found in InvalidateInternalFiles
#define MPQ_FLAG_SIGNATURE_NONE 0x00008000 // Set when no (signature) was found in InvalidateInternalFiles #define MPQ_FLAG_ATTRIBUTES_NEW 0x00008000 // Set when (attributes) invalidated by InvalidateInternalFiles
#define MPQ_FLAG_SIGNATURE_NEW 0x00010000 // Set when (signature) invalidated by InvalidateInternalFiles #define MPQ_FLAG_SIGNATURE_NONE 0x00010000 // Set when no (signature) was found in InvalidateInternalFiles
#define MPQ_FLAG_SIGNATURE_NEW 0x00020000 // Set when (signature) invalidated by InvalidateInternalFiles
// Values for TMPQArchive::dwSubType // Values for TMPQArchive::dwSubType
#define MPQ_SUBTYPE_MPQ 0x00000000 // The file is a MPQ file (Blizzard games) #define MPQ_SUBTYPE_MPQ 0x00000000 // The file is a MPQ file (Blizzard games)
@ -214,11 +215,11 @@ extern "C" {
#define SFILE_INVALID_POS 0xFFFFFFFF #define SFILE_INVALID_POS 0xFFFFFFFF
#define SFILE_INVALID_ATTRIBUTES 0xFFFFFFFF #define SFILE_INVALID_ATTRIBUTES 0xFFFFFFFF
// Flags for SFileAddFile // Flags for TMPQBlock::dwFlags
#define MPQ_FILE_IMPLODE 0x00000100 // Implode method (By PKWARE Data Compression Library) #define MPQ_FILE_IMPLODE 0x00000100 // Implode method (By PKWARE Data Compression Library)
#define MPQ_FILE_COMPRESS 0x00000200 // Compress methods (By multiple methods) #define MPQ_FILE_COMPRESS 0x00000200 // Compress methods (By multiple methods)
#define MPQ_FILE_ENCRYPTED 0x00010000 // Indicates whether file is encrypted #define MPQ_FILE_ENCRYPTED 0x00010000 // Indicates an encrypted file
#define MPQ_FILE_FIX_KEY 0x00020000 // File decryption key has to be fixed #define MPQ_FILE_KEY_V2 0x00020000 // Indicates an encrypted file with key v2
#define MPQ_FILE_PATCH_FILE 0x00100000 // The file is a patch file. Raw file data begin with TPatchInfo structure #define MPQ_FILE_PATCH_FILE 0x00100000 // The file is a patch file. Raw file data begin with TPatchInfo structure
#define MPQ_FILE_SINGLE_UNIT 0x01000000 // File is stored as a single unit, rather than split into sectors (Thx, Quantam) #define MPQ_FILE_SINGLE_UNIT 0x01000000 // File is stored as a single unit, rather than split into sectors (Thx, Quantam)
#define MPQ_FILE_DELETE_MARKER 0x02000000 // File is a deletion marker. Used in MPQ patches, indicating that the file no longer exists. #define MPQ_FILE_DELETE_MARKER 0x02000000 // File is a deletion marker. Used in MPQ patches, indicating that the file no longer exists.
@ -232,10 +233,12 @@ extern "C" {
#define MPQ_FILE_DEFAULT_INTERNAL 0xFFFFFFFF // Use default flags for internal files #define MPQ_FILE_DEFAULT_INTERNAL 0xFFFFFFFF // Use default flags for internal files
#define MPQ_FILE_FIX_KEY 0x00020000 // Obsolete, do not use
#define MPQ_FILE_VALID_FLAGS (MPQ_FILE_IMPLODE | \ #define MPQ_FILE_VALID_FLAGS (MPQ_FILE_IMPLODE | \
MPQ_FILE_COMPRESS | \ MPQ_FILE_COMPRESS | \
MPQ_FILE_ENCRYPTED | \ MPQ_FILE_ENCRYPTED | \
MPQ_FILE_FIX_KEY | \ MPQ_FILE_KEY_V2 | \
MPQ_FILE_PATCH_FILE | \ MPQ_FILE_PATCH_FILE | \
MPQ_FILE_SINGLE_UNIT | \ MPQ_FILE_SINGLE_UNIT | \
MPQ_FILE_DELETE_MARKER | \ MPQ_FILE_DELETE_MARKER | \
@ -246,7 +249,7 @@ extern "C" {
#define MPQ_FILE_VALID_FLAGS_W3X (MPQ_FILE_IMPLODE | \ #define MPQ_FILE_VALID_FLAGS_W3X (MPQ_FILE_IMPLODE | \
MPQ_FILE_COMPRESS | \ MPQ_FILE_COMPRESS | \
MPQ_FILE_ENCRYPTED | \ MPQ_FILE_ENCRYPTED | \
MPQ_FILE_FIX_KEY | \ MPQ_FILE_KEY_V2 | \
MPQ_FILE_DELETE_MARKER | \ MPQ_FILE_DELETE_MARKER | \
MPQ_FILE_SECTOR_CRC | \ MPQ_FILE_SECTOR_CRC | \
MPQ_FILE_SIGNATURE | \ MPQ_FILE_SIGNATURE | \
@ -255,9 +258,12 @@ extern "C" {
#define MPQ_FILE_VALID_FLAGS_SCX (MPQ_FILE_IMPLODE | \ #define MPQ_FILE_VALID_FLAGS_SCX (MPQ_FILE_IMPLODE | \
MPQ_FILE_COMPRESS | \ MPQ_FILE_COMPRESS | \
MPQ_FILE_ENCRYPTED | \ MPQ_FILE_ENCRYPTED | \
MPQ_FILE_FIX_KEY | \ MPQ_FILE_KEY_V2 | \
MPQ_FILE_EXISTS) MPQ_FILE_EXISTS)
// Flags for TPatchInfo::dwFlags
#define MPQ_PATCH_INFO_VALID 0x80000000 // Set if the patch info is valid
// We need to mask out the upper 4 bits of the block table index. // We need to mask out the upper 4 bits of the block table index.
// This is because it gets shifted out when calculating block table offset // This is because it gets shifted out when calculating block table offset
// BlockTableOffset = pHash->dwBlockIndex << 0x04 // BlockTableOffset = pHash->dwBlockIndex << 0x04
@ -471,6 +477,8 @@ typedef enum _SFileInfoClass
SFileInfoEncryptionKey, // File encryption key SFileInfoEncryptionKey, // File encryption key
SFileInfoEncryptionKeyRaw, // Unfixed value of the file key SFileInfoEncryptionKeyRaw, // Unfixed value of the file key
SFileInfoCRC32, // CRC32 of the file SFileInfoCRC32, // CRC32 of the file
SFileInfoInvalid = 0xFFF, // Invalid file info class
} SFileInfoClass; } SFileInfoClass;
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -675,7 +683,7 @@ typedef struct _TMPQBlock
typedef struct _TPatchInfo typedef struct _TPatchInfo
{ {
DWORD dwLength; // Length of patch info header, in bytes DWORD dwLength; // Length of patch info header, in bytes
DWORD dwFlags; // Flags. 0x80000000 = MD5 (?) DWORD dwFlags; // Flags. 0x80000000 = valid (?)
DWORD dwDataSize; // Uncompressed size of the patch file DWORD dwDataSize; // Uncompressed size of the patch file
BYTE md5[0x10]; // MD5 of the entire patch file after decompression BYTE md5[0x10]; // MD5 of the entire patch file after decompression
@ -822,6 +830,7 @@ typedef struct _TMPQArchive
ULONGLONG UserDataPos; // Position of user data (relative to the begin of the file) ULONGLONG UserDataPos; // Position of user data (relative to the begin of the file)
ULONGLONG MpqPos; // MPQ header offset (relative to the begin of the file) ULONGLONG MpqPos; // MPQ header offset (relative to the begin of the file)
ULONGLONG FileSize; // Size of the file at the moment of file open ULONGLONG FileSize; // Size of the file at the moment of file open
ULONGLONG FileOffsetMask; // 0xFFFFFFFF for MPQ v 1, otherwise 0xFFFFFFFFFFFFFFFFull
struct _TMPQArchive * haPatch; // Pointer to patch archive, if any struct _TMPQArchive * haPatch; // Pointer to patch archive, if any
struct _TMPQArchive * haBase; // Pointer to base ("previous version") archive, if any struct _TMPQArchive * haBase; // Pointer to base ("previous version") archive, if any
@ -1025,6 +1034,7 @@ bool WINAPI SFileCloseArchive(HANDLE hMpq);
// so you can use this API to combining more listfiles. // so you can use this API to combining more listfiles.
// Note that this function is internally called by SFileFindFirstFile // Note that this function is internally called by SFileFindFirstFile
DWORD WINAPI SFileAddListFile(HANDLE hMpq, const TCHAR * szListFile); DWORD WINAPI SFileAddListFile(HANDLE hMpq, const TCHAR * szListFile);
DWORD WINAPI SFileAddListFileEntries(HANDLE hMpq, const char ** listFileEntries, DWORD dwEntryCount);
// Archive compacting // Archive compacting
bool WINAPI SFileSetCompactCallback(HANDLE hMpq, SFILE_COMPACT_CALLBACK CompactCB, void * pvUserData); bool WINAPI SFileSetCompactCallback(HANDLE hMpq, SFILE_COMPACT_CALLBACK CompactCB, void * pvUserData);
@ -1120,7 +1130,6 @@ int WINAPI SCompExplode (void * pvOutBuffer, int * pcbOutBuffer, void * pv
int WINAPI SCompCompress (void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer, unsigned uCompressionMask, int nCmpType, int nCmpLevel); int WINAPI SCompCompress (void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer, unsigned uCompressionMask, int nCmpType, int nCmpLevel);
int WINAPI SCompDecompress (void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer); int WINAPI SCompDecompress (void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer);
int WINAPI SCompDecompress2(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer); int WINAPI SCompDecompress2(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer);
int WINAPI SCompDecompress_SC1B(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer);
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Non-Windows support for SetLastError/GetLastError // Non-Windows support for SetLastError/GetLastError

View File

@ -269,24 +269,6 @@ TInputStream::TInputStream(void * pvInBuffer, size_t cbInBuffer)
BitCount = 0; BitCount = 0;
} }
// Gets 7 bits from the stream. DOES NOT remove the bits from input stream
unsigned int TInputStream::Peek7Bits()
{
unsigned int dwReloadByte = 0;
// If there is not enough bits to get the value,
// we have to add 8 more bits from the input buffer
if(BitCount < 7)
{
dwReloadByte = *pbInBuffer++;
BitBuffer |= dwReloadByte << BitCount;
BitCount += 8;
}
// Return the first available 7 bits. DO NOT remove them from the input stream
return (BitBuffer & 0x7F);
}
// Gets one bit from input stream // Gets one bit from input stream
unsigned int TInputStream::Get1Bit() unsigned int TInputStream::Get1Bit()
{ {
@ -330,6 +312,30 @@ unsigned int TInputStream::Get8Bits()
return dwOneByte; return dwOneByte;
} }
// Gets 7 bits from the stream. DOES NOT remove the bits from input stream
bool TInputStream::Peek7Bits(unsigned int & Value)
{
unsigned int Value8Bits = 0;
// If there is not enough bits to get the value,
// we have to add 8 more bits from the input buffer
if(BitCount < 7)
{
// Load additional 8 bits. Be careful if we have no more data
if(pbInBuffer >= pbInBufferEnd)
return false;
Value8Bits = *pbInBuffer++;
// Add these 8 bits to the bit buffer
BitBuffer |= Value8Bits << BitCount;
BitCount += 8;
}
// Return 7 bits of data. DO NOT remove them from the input stream
Value = (BitBuffer & 0x7F);
return true;
}
void TInputStream::SkipBits(unsigned int dwBitsToSkip) void TInputStream::SkipBits(unsigned int dwBitsToSkip)
{ {
unsigned int dwReloadByte = 0; unsigned int dwReloadByte = 0;
@ -696,16 +702,13 @@ unsigned int THuffmannTree::DecodeOneByte(TInputStream * is)
THTreeItem * pItem; THTreeItem * pItem;
unsigned int ItemLinkIndex; unsigned int ItemLinkIndex;
unsigned int BitCount = 0; unsigned int BitCount = 0;
bool bHasItemLinkIndex;
// Check for the end of the input stream // Try to retrieve quick link index
if(is->pbInBuffer >= is->pbInBufferEnd && is->BitCount < 7) bHasItemLinkIndex = is->Peek7Bits(ItemLinkIndex);
return 0x1FF;
// Get the eventual quick-link index
ItemLinkIndex = is->Peek7Bits();
// Is the quick-link item valid? // Is the quick-link item valid?
if(QuickLinks[ItemLinkIndex].ValidValue > MinValidValue) if(bHasItemLinkIndex && QuickLinks[ItemLinkIndex].ValidValue > MinValidValue)
{ {
// If that item needs less than 7 bits, we can get decompressed value directly // If that item needs less than 7 bits, we can get decompressed value directly
if(QuickLinks[ItemLinkIndex].ValidBits <= 7) if(QuickLinks[ItemLinkIndex].ValidBits <= 7)
@ -745,7 +748,7 @@ unsigned int THuffmannTree::DecodeOneByte(TInputStream * is)
// If we didn't get the item from the quick-link array, // If we didn't get the item from the quick-link array,
// set the entry in it // set the entry in it
if(QuickLinks[ItemLinkIndex].ValidValue < MinValidValue) if(bHasItemLinkIndex && QuickLinks[ItemLinkIndex].ValidValue < MinValidValue)
{ {
// If the current compressed byte was more than 7 bits, // If the current compressed byte was more than 7 bits,
// set a quick-link item with pointer to tree item // set a quick-link item with pointer to tree item
@ -876,10 +879,10 @@ unsigned int THuffmannTree::Decompress(void * pvOutBuffer, unsigned int cbOutLen
IncWeightsAndRebalance(ItemsByByte[DecompressedValue]); IncWeightsAndRebalance(ItemsByByte[DecompressedValue]);
} }
// A byte successfully decoded - store it in the output stream // Store the byte to the output stream
*pbOutBuffer++ = (unsigned char)DecompressedValue;
if(pbOutBuffer >= pbOutBufferEnd) if(pbOutBuffer >= pbOutBufferEnd)
break; break;
*pbOutBuffer++ = (unsigned char)DecompressedValue;
if(bIsCmp0) if(bIsCmp0)
{ {

View File

@ -29,8 +29,8 @@ class TInputStream
TInputStream(void * pvInBuffer, size_t cbInBuffer); TInputStream(void * pvInBuffer, size_t cbInBuffer);
unsigned int Get1Bit(); unsigned int Get1Bit();
unsigned int Peek7Bits();
unsigned int Get8Bits(); unsigned int Get8Bits();
bool Peek7Bits(unsigned int & Value);
void SkipBits(unsigned int BitCount); void SkipBits(unsigned int BitCount);
unsigned char * pbInBufferEnd; // End position in the the input buffer unsigned char * pbInBufferEnd; // End position in the the input buffer

View File

@ -0,0 +1,340 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis
*
* LibTomCrypt is a library that provides various cryptographic
* algorithms in a highly modular and flexible manner.
*
* The library is free for all purposes without any express
* guarantee it works.
*
* Tom St Denis, tomstdenis@gmail.com, http://libtom.org
*/
#include "../headers/tomcrypt.h"
/**
@file sha256.c
LTC_SHA256 by Tom St Denis
*/
#ifdef LTC_SHA256
const struct ltc_hash_descriptor sha256_desc =
{
"sha256",
0,
32,
64,
/* OID */
{ 2, 16, 840, 1, 101, 3, 4, 2, 1, },
9,
&sha256_init,
&sha256_process,
&sha256_done,
&sha256_test,
NULL
};
#ifdef LTC_SMALL_CODE
/* the K array */
static const ulong32 K[64] = {
0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL,
0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, 0xd807aa98UL, 0x12835b01UL,
0x243185beUL, 0x550c7dc3UL, 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL,
0xc19bf174UL, 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL,
0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, 0x983e5152UL,
0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, 0xc6e00bf3UL, 0xd5a79147UL,
0x06ca6351UL, 0x14292967UL, 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL,
0x53380d13UL, 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL,
0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, 0xd192e819UL,
0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, 0x19a4c116UL, 0x1e376c08UL,
0x2748774cUL, 0x34b0bcb5UL, 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL,
0x682e6ff3UL, 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL,
0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL
};
#endif
/* Various logical functions */
#define Ch(x,y,z) (z ^ (x & (y ^ z)))
#define Maj(x,y,z) (((x | y) & z) | (x & y))
#define S(x, n) RORc((x),(n))
#define R(x, n) (((x)&0xFFFFFFFFUL)>>(n))
#define Sigma0(x) (S(x, 2) ^ S(x, 13) ^ S(x, 22))
#define Sigma1(x) (S(x, 6) ^ S(x, 11) ^ S(x, 25))
#define Gamma0(x) (S(x, 7) ^ S(x, 18) ^ R(x, 3))
#define Gamma1(x) (S(x, 17) ^ S(x, 19) ^ R(x, 10))
/* compress 512-bits */
#ifdef LTC_CLEAN_STACK
static int _sha256_compress(hash_state * md, unsigned char *buf)
#else
static int sha256_compress(hash_state * md, unsigned char *buf)
#endif
{
ulong32 S[8], W[64], t0, t1;
#ifdef LTC_SMALL_CODE
ulong32 t;
#endif
int i;
/* copy state into S */
for (i = 0; i < 8; i++) {
S[i] = md->sha256.state[i];
}
/* copy the state into 512-bits into W[0..15] */
for (i = 0; i < 16; i++) {
LOAD32H(W[i], buf + (4*i));
}
/* fill W[16..63] */
for (i = 16; i < 64; i++) {
W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16];
}
/* Compress */
#ifdef LTC_SMALL_CODE
#define RND(a,b,c,d,e,f,g,h,i) \
t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; \
t1 = Sigma0(a) + Maj(a, b, c); \
d += t0; \
h = t0 + t1;
for (i = 0; i < 64; ++i) {
RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],i);
t = S[7]; S[7] = S[6]; S[6] = S[5]; S[5] = S[4];
S[4] = S[3]; S[3] = S[2]; S[2] = S[1]; S[1] = S[0]; S[0] = t;
}
#else
#define RND(a,b,c,d,e,f,g,h,i,ki) \
t0 = h + Sigma1(e) + Ch(e, f, g) + ki + W[i]; \
t1 = Sigma0(a) + Maj(a, b, c); \
d += t0; \
h = t0 + t1;
RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],0,0x428a2f98);
RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],1,0x71374491);
RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],2,0xb5c0fbcf);
RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],3,0xe9b5dba5);
RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],4,0x3956c25b);
RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],5,0x59f111f1);
RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],6,0x923f82a4);
RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],7,0xab1c5ed5);
RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],8,0xd807aa98);
RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],9,0x12835b01);
RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],10,0x243185be);
RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],11,0x550c7dc3);
RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],12,0x72be5d74);
RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],13,0x80deb1fe);
RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],14,0x9bdc06a7);
RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],15,0xc19bf174);
RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],16,0xe49b69c1);
RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],17,0xefbe4786);
RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],18,0x0fc19dc6);
RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],19,0x240ca1cc);
RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],20,0x2de92c6f);
RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],21,0x4a7484aa);
RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],22,0x5cb0a9dc);
RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],23,0x76f988da);
RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],24,0x983e5152);
RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],25,0xa831c66d);
RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],26,0xb00327c8);
RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],27,0xbf597fc7);
RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],28,0xc6e00bf3);
RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],29,0xd5a79147);
RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],30,0x06ca6351);
RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],31,0x14292967);
RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],32,0x27b70a85);
RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],33,0x2e1b2138);
RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],34,0x4d2c6dfc);
RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],35,0x53380d13);
RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],36,0x650a7354);
RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],37,0x766a0abb);
RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],38,0x81c2c92e);
RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],39,0x92722c85);
RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],40,0xa2bfe8a1);
RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],41,0xa81a664b);
RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],42,0xc24b8b70);
RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],43,0xc76c51a3);
RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],44,0xd192e819);
RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],45,0xd6990624);
RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],46,0xf40e3585);
RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],47,0x106aa070);
RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],48,0x19a4c116);
RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],49,0x1e376c08);
RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],50,0x2748774c);
RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],51,0x34b0bcb5);
RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],52,0x391c0cb3);
RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],53,0x4ed8aa4a);
RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],54,0x5b9cca4f);
RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],55,0x682e6ff3);
RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],56,0x748f82ee);
RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],57,0x78a5636f);
RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],58,0x84c87814);
RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],59,0x8cc70208);
RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],60,0x90befffa);
RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],61,0xa4506ceb);
RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],62,0xbef9a3f7);
RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],63,0xc67178f2);
#undef RND
#endif
/* feedback */
for (i = 0; i < 8; i++) {
md->sha256.state[i] = md->sha256.state[i] + S[i];
}
return CRYPT_OK;
}
#ifdef LTC_CLEAN_STACK
static int sha256_compress(hash_state * md, unsigned char *buf)
{
int err;
err = _sha256_compress(md, buf);
burn_stack(sizeof(ulong32) * 74);
return err;
}
#endif
/**
Initialize the hash state
@param md The hash state you wish to initialize
@return CRYPT_OK if successful
*/
int sha256_init(hash_state * md)
{
LTC_ARGCHK(md != NULL);
md->sha256.curlen = 0;
md->sha256.length = 0;
md->sha256.state[0] = 0x6A09E667UL;
md->sha256.state[1] = 0xBB67AE85UL;
md->sha256.state[2] = 0x3C6EF372UL;
md->sha256.state[3] = 0xA54FF53AUL;
md->sha256.state[4] = 0x510E527FUL;
md->sha256.state[5] = 0x9B05688CUL;
md->sha256.state[6] = 0x1F83D9ABUL;
md->sha256.state[7] = 0x5BE0CD19UL;
return CRYPT_OK;
}
/**
Process a block of memory though the hash
@param md The hash state
@param in The data to hash
@param inlen The length of the data (octets)
@return CRYPT_OK if successful
*/
HASH_PROCESS(sha256_process, sha256_compress, sha256, 64)
/**
Terminate the hash to get the digest
@param md The hash state
@param out [out] The destination of the hash (32 bytes)
@return CRYPT_OK if successful
*/
int sha256_done(hash_state * md, unsigned char *out)
{
int i;
LTC_ARGCHK(md != NULL);
LTC_ARGCHK(out != NULL);
if (md->sha256.curlen >= sizeof(md->sha256.buf)) {
return CRYPT_INVALID_ARG;
}
/* increase the length of the message */
md->sha256.length += md->sha256.curlen * 8;
/* append the '1' bit */
md->sha256.buf[md->sha256.curlen++] = (unsigned char)0x80;
/* if the length is currently above 56 bytes we append zeros
* then compress. Then we can fall back to padding zeros and length
* encoding like normal.
*/
if (md->sha256.curlen > 56) {
while (md->sha256.curlen < 64) {
md->sha256.buf[md->sha256.curlen++] = (unsigned char)0;
}
sha256_compress(md, md->sha256.buf);
md->sha256.curlen = 0;
}
/* pad upto 56 bytes of zeroes */
while (md->sha256.curlen < 56) {
md->sha256.buf[md->sha256.curlen++] = (unsigned char)0;
}
/* store length */
STORE64H(md->sha256.length, md->sha256.buf+56);
sha256_compress(md, md->sha256.buf);
/* copy output */
for (i = 0; i < 8; i++) {
STORE32H(md->sha256.state[i], out+(4*i));
}
#ifdef LTC_CLEAN_STACK
zeromem(md, sizeof(hash_state));
#endif
return CRYPT_OK;
}
/**
Self-test the hash
@return CRYPT_OK if successful, CRYPT_NOP if self-tests have been disabled
*/
int sha256_test(void)
{
#ifndef LTC_TEST
return CRYPT_NOP;
#else
static const struct {
char *msg;
unsigned char hash[32];
} tests[] = {
{ "abc",
{ 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea,
0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23,
0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c,
0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad }
},
{ "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
{ 0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8,
0xe5, 0xc0, 0x26, 0x93, 0x0c, 0x3e, 0x60, 0x39,
0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff, 0x21, 0x67,
0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1 }
},
};
int i;
unsigned char tmp[32];
hash_state md;
for (i = 0; i < (int)(sizeof(tests) / sizeof(tests[0])); i++) {
sha256_init(&md);
sha256_process(&md, (unsigned char*)tests[i].msg, (unsigned long)strlen(tests[i].msg));
sha256_done(&md, tmp);
if (XMEMCMP(tmp, tests[i].hash, 32) != 0) {
return CRYPT_FAIL_TESTVECTOR;
}
}
return CRYPT_OK;
#endif
}
#ifdef LTC_SHA224
#include "sha224.c"
#endif
#endif
/* $Source: /cvs/libtom/libtomcrypt/src/hashes/sha2/sha256.c,v $ */
/* $Revision: 1.11 $ */
/* $Date: 2007/05/12 14:25:28 $ */

View File

@ -11,13 +11,13 @@
#define LTC_NO_ROLC #define LTC_NO_ROLC
#define LTC_SOURCE #define LTC_SOURCE
#define LTC_SHA256
#define LTC_SHA1 #define LTC_SHA1
#define LTC_MD5 #define LTC_MD5
#define LTC_DER #define LTC_DER
#define LTC_RC4
#define USE_LTM
#define LTM_DESC #define LTM_DESC
#define USE_LTM
/* macros for various libc functions you can change for embedded targets */ /* macros for various libc functions you can change for embedded targets */
#ifndef XMALLOC #ifndef XMALLOC