aboutsummaryrefslogtreecommitdiff
path: root/dep/CascLib/src
diff options
context:
space:
mode:
Diffstat (limited to 'dep/CascLib/src')
-rw-r--r--dep/CascLib/src/CascBuildCfg.cpp922
-rw-r--r--dep/CascLib/src/CascCommon.cpp67
-rw-r--r--dep/CascLib/src/CascCommon.h374
-rw-r--r--dep/CascLib/src/CascDecompress.cpp83
-rw-r--r--dep/CascLib/src/CascDumpData.cpp524
-rw-r--r--dep/CascLib/src/CascFindFile.cpp364
-rw-r--r--dep/CascLib/src/CascLib.h171
-rw-r--r--dep/CascLib/src/CascMndxRoot.cpp3476
-rw-r--r--dep/CascLib/src/CascMndxRoot.h365
-rw-r--r--dep/CascLib/src/CascMndxRoot_x86.asm4369
-rw-r--r--dep/CascLib/src/CascOpenFile.cpp440
-rw-r--r--dep/CascLib/src/CascOpenStorage.cpp1226
-rw-r--r--dep/CascLib/src/CascPort.h260
-rw-r--r--dep/CascLib/src/CascReadFile.cpp475
-rw-r--r--dep/CascLib/src/common/Common.cpp672
-rw-r--r--dep/CascLib/src/common/Common.h98
-rw-r--r--dep/CascLib/src/common/Directory.cpp102
-rw-r--r--dep/CascLib/src/common/FileStream.cpp2721
-rw-r--r--dep/CascLib/src/common/FileStream.h238
-rw-r--r--dep/CascLib/src/common/ListFile.cpp266
-rw-r--r--dep/CascLib/src/common/ListFile.h18
-rw-r--r--dep/CascLib/src/common/Map.cpp178
-rw-r--r--dep/CascLib/src/common/Map.h39
-rw-r--r--dep/CascLib/src/jenkins/lookup.h24
-rw-r--r--dep/CascLib/src/jenkins/lookup3.c1003
-rw-r--r--dep/CascLib/src/libtomcrypt/src/hashes/hash_memory.c69
-rw-r--r--dep/CascLib/src/libtomcrypt/src/hashes/md5.c368
-rw-r--r--dep/CascLib/src/libtomcrypt/src/headers/tomcrypt.h87
-rw-r--r--dep/CascLib/src/libtomcrypt/src/headers/tomcrypt_argchk.h38
-rw-r--r--dep/CascLib/src/libtomcrypt/src/headers/tomcrypt_cfg.h136
-rw-r--r--dep/CascLib/src/libtomcrypt/src/headers/tomcrypt_cipher.h891
-rw-r--r--dep/CascLib/src/libtomcrypt/src/headers/tomcrypt_custom.h424
-rw-r--r--dep/CascLib/src/libtomcrypt/src/headers/tomcrypt_hash.h378
-rw-r--r--dep/CascLib/src/libtomcrypt/src/headers/tomcrypt_mac.h384
-rw-r--r--dep/CascLib/src/libtomcrypt/src/headers/tomcrypt_macros.h424
-rw-r--r--dep/CascLib/src/libtomcrypt/src/headers/tomcrypt_math.h500
-rw-r--r--dep/CascLib/src/libtomcrypt/src/headers/tomcrypt_misc.h23
-rw-r--r--dep/CascLib/src/libtomcrypt/src/headers/tomcrypt_pk.h558
-rw-r--r--dep/CascLib/src/libtomcrypt/src/headers/tomcrypt_pkcs.h89
-rw-r--r--dep/CascLib/src/libtomcrypt/src/headers/tomcrypt_prng.h199
-rw-r--r--dep/CascLib/src/libtomcrypt/src/misc/crypt_argchk.c30
-rw-r--r--dep/CascLib/src/libtomcrypt/src/misc/crypt_hash_descriptor.c27
-rw-r--r--dep/CascLib/src/libtomcrypt/src/misc/crypt_hash_is_valid.c36
-rw-r--r--dep/CascLib/src/libtomcrypt/src/misc/crypt_libc.c43
44 files changed, 23179 insertions, 0 deletions
diff --git a/dep/CascLib/src/CascBuildCfg.cpp b/dep/CascLib/src/CascBuildCfg.cpp
new file mode 100644
index 00000000000..effb74552c5
--- /dev/null
+++ b/dep/CascLib/src/CascBuildCfg.cpp
@@ -0,0 +1,922 @@
+/*****************************************************************************/
+/* CascBuildCfg.cpp Copyright (c) Ladislav Zezula 2014 */
+/*---------------------------------------------------------------------------*/
+/* Build configuration for CascLib */
+/*---------------------------------------------------------------------------*/
+/* Date Ver Who Comment */
+/* -------- ---- --- ------- */
+/* 29.04.14 1.00 Lad The first version of CascBuildCfg.cpp */
+/*****************************************************************************/
+
+#define __CASCLIB_SELF__
+#include "CascLib.h"
+#include "CascCommon.h"
+
+//-----------------------------------------------------------------------------
+// Local functions
+
+static bool inline IsValueSeparator(LPBYTE pbVarValue)
+{
+ return ((0 <= pbVarValue[0] && pbVarValue[0] <= 0x20) || (pbVarValue[0] == '|'));
+}
+
+static bool IsCharDigit(BYTE OneByte)
+{
+ return ('0' <= OneByte && OneByte <= '9');
+}
+
+static void FreeCascBlob(PQUERY_KEY pBlob)
+{
+ if(pBlob != NULL)
+ {
+ if(pBlob->pbData != NULL)
+ CASC_FREE(pBlob->pbData);
+
+ pBlob->pbData = NULL;
+ pBlob->cbData = 0;
+ }
+}
+
+static bool IsInfoVariable(const char * szLineBegin, const char * szLineEnd, const char * szVarName, const char * szVarType)
+{
+ size_t nLength;
+
+ // Check the variable name
+ nLength = strlen(szVarName);
+ if((size_t)(szLineEnd - szLineBegin) > nLength)
+ {
+ // Check the variable name
+ if(!_strnicmp(szLineBegin, szVarName, nLength))
+ {
+ // Skip variable name and the exclamation mark
+ szLineBegin += nLength;
+ if(szLineBegin < szLineEnd && szLineBegin[0] == '!')
+ {
+ // Skip the exclamation mark
+ szLineBegin++;
+
+ // Check the variable type
+ nLength = strlen(szVarType);
+ if((size_t)(szLineEnd - szLineBegin) > nLength)
+ {
+ // Check the variable name
+ if(!_strnicmp(szLineBegin, szVarType, nLength))
+ {
+ // Skip variable type and the doublecolon
+ szLineBegin += nLength;
+ return (szLineBegin < szLineEnd && szLineBegin[0] == ':');
+ }
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+static const char * SkipInfoVariable(const char * szLineBegin, const char * szLineEnd)
+{
+ while(szLineBegin < szLineEnd)
+ {
+ if(szLineBegin[0] == '|')
+ return szLineBegin + 1;
+
+ szLineBegin++;
+ }
+
+ return NULL;
+}
+
+static TCHAR * CheckForIndexDirectory(TCascStorage * hs, const TCHAR * szSubDir)
+{
+ TCHAR * szIndexPath;
+
+ // Cpmbine the index path
+ szIndexPath = CombinePath(hs->szDataPath, szSubDir);
+ if(DirectoryExists(szIndexPath))
+ {
+ hs->szIndexPath = szIndexPath;
+ return hs->szIndexPath;
+ }
+
+ delete [] szIndexPath;
+ return NULL;
+}
+
+TCHAR * AppendBlobText(TCHAR * szBuffer, LPBYTE pbData, DWORD cbData, TCHAR chSeparator)
+{
+ // Put the separator, if any
+ if(chSeparator != 0)
+ *szBuffer++ = chSeparator;
+
+ // Copy the blob data as text
+ for(DWORD i = 0; i < cbData; i++)
+ {
+ *szBuffer++ = IntToHexChar[pbData[0] >> 0x04];
+ *szBuffer++ = IntToHexChar[pbData[0] & 0x0F];
+ pbData++;
+ }
+
+ // Terminate the string
+ *szBuffer = 0;
+
+ // Return new buffer position
+ return szBuffer;
+}
+
+static int StringBlobToBinaryBlob(
+ PQUERY_KEY pBlob,
+ LPBYTE pbBlobBegin,
+ LPBYTE pbBlobEnd)
+{
+ // Sanity checks
+ assert(pBlob != NULL && pBlob->pbData != NULL);
+
+ // Reset the blob length
+ pBlob->cbData = 0;
+
+ // Convert the blob
+ while(pbBlobBegin < pbBlobEnd)
+ {
+ BYTE DigitOne;
+ BYTE DigitTwo;
+
+ DigitOne = (BYTE)(AsciiToUpperTable[pbBlobBegin[0]] - '0');
+ if(DigitOne > 9)
+ DigitOne -= 'A' - '9' - 1;
+
+ DigitTwo = (BYTE)(AsciiToUpperTable[pbBlobBegin[1]] - '0');
+ if(DigitTwo > 9)
+ DigitTwo -= 'A' - '9' - 1;
+
+ if(DigitOne > 0x0F || DigitTwo > 0x0F || pBlob->cbData >= MAX_CASC_KEY_LENGTH)
+ return ERROR_BAD_FORMAT;
+
+ pBlob->pbData[pBlob->cbData++] = (DigitOne << 0x04) | DigitTwo;
+ pbBlobBegin += 2;
+ }
+
+ return ERROR_SUCCESS;
+}
+
+
+static LPBYTE FindNextSeparator(PQUERY_KEY pFileBlob, LPBYTE pbFilePtr)
+{
+ LPBYTE pbFileBegin = pFileBlob->pbData;
+ LPBYTE pbFileEnd = pFileBlob->pbData + pFileBlob->cbData;
+
+ if(pbFileBegin <= pbFilePtr && pbFilePtr < pbFileEnd)
+ {
+ while(pbFilePtr < pbFileEnd && pbFilePtr[0] != '|')
+ pbFilePtr++;
+
+ return pbFilePtr;
+ }
+
+ return NULL;
+}
+
+static bool GetNextFileLine(PQUERY_KEY pFileBlob, LPBYTE * ppbLineBegin, LPBYTE * ppbLineEnd)
+{
+ LPBYTE pbLineBegin = *ppbLineBegin;
+ LPBYTE pbLineEnd = *ppbLineEnd;
+ LPBYTE pbFileEnd = pFileBlob->pbData + pFileBlob->cbData;
+
+ // If there was a previous line, skip all end-of-line chars
+ if(pbLineEnd != NULL)
+ {
+ // Go to the next line
+ while(pbLineEnd < pbFileEnd && (pbLineEnd[0] == 0x0A || pbLineEnd[0] == 0x0D))
+ pbLineEnd++;
+ pbLineBegin = pbLineEnd;
+
+ // If there is no more data, return false
+ if(pbLineEnd >= pbFileEnd)
+ return false;
+ }
+
+ // Skip all spaces before the line begins
+ while(pbLineBegin < pbFileEnd && (pbLineBegin[0] == 0x09 || pbLineBegin[0] == 0x20))
+ pbLineBegin++;
+ pbLineEnd = pbLineBegin;
+
+ // Go to the end of the line
+ while(pbLineEnd < pbFileEnd && pbLineEnd[0] != 0x0A && pbLineEnd[0] != 0x0D)
+ pbLineEnd++;
+
+ // Give the results to the caller
+ *ppbLineBegin = pbLineBegin;
+ *ppbLineEnd = pbLineEnd;
+ return true;
+}
+
+static LPBYTE CheckLineVariable(LPBYTE pbLineBegin, LPBYTE pbLineEnd, const char * szVarName)
+{
+ size_t nLineLength = (size_t)(pbLineEnd - pbLineBegin);
+ size_t nNameLength = strlen(szVarName);
+
+ // If the line longer than the variable name?
+ if(nLineLength > nNameLength)
+ {
+ if(!_strnicmp((const char *)pbLineBegin, szVarName, nNameLength))
+ {
+ // Skip the variable name
+ pbLineBegin += nNameLength;
+
+ // Skip the separator(s)
+ while(pbLineBegin < pbLineEnd && IsValueSeparator(pbLineBegin))
+ pbLineBegin++;
+
+ // Check if there is "="
+ if(pbLineBegin >= pbLineEnd || pbLineBegin[0] != '=')
+ return NULL;
+ pbLineBegin++;
+
+ // Skip the separator(s)
+ while(pbLineBegin < pbLineEnd && IsValueSeparator(pbLineBegin))
+ pbLineBegin++;
+
+ // Check if there is "="
+ if(pbLineBegin >= pbLineEnd)
+ return NULL;
+
+ // Return the begin of the variable
+ return pbLineBegin;
+ }
+ }
+
+ return NULL;
+}
+
+static int LoadInfoVariable(PQUERY_KEY pVarBlob, const char * szLineBegin, const char * szLineEnd, bool bHexaValue)
+{
+ const char * szLinePtr = szLineBegin;
+
+ // Sanity checks
+ assert(pVarBlob->pbData == NULL);
+ assert(pVarBlob->cbData == 0);
+
+ // Check length of the variable
+ while(szLinePtr < szLineEnd && szLinePtr[0] != '|')
+ szLinePtr++;
+
+ // Allocate space for the blob
+ if(bHexaValue)
+ {
+ // Initialize the blob
+ pVarBlob->pbData = CASC_ALLOC(BYTE, (szLinePtr - szLineBegin) / 2);
+ return StringBlobToBinaryBlob(pVarBlob, (LPBYTE)szLineBegin, (LPBYTE)szLinePtr);
+ }
+
+ // Initialize the blob
+ pVarBlob->pbData = CASC_ALLOC(BYTE, (szLinePtr - szLineBegin) + 1);
+ pVarBlob->cbData = (size_t)(szLinePtr - szLineBegin);
+
+ // Check for success
+ if(pVarBlob->pbData == NULL)
+ return ERROR_NOT_ENOUGH_MEMORY;
+
+ // Copy the string
+ memcpy(pVarBlob->pbData, szLineBegin, pVarBlob->cbData);
+ pVarBlob->pbData[pVarBlob->cbData] = 0;
+ return ERROR_SUCCESS;
+}
+
+
+static void AppendConfigFilePath(TCHAR * szFileName, PQUERY_KEY pFileKey)
+{
+ // Get to the end of the file name
+ szFileName = szFileName + _tcslen(szFileName);
+
+ // Append the "config" directory
+ _tcscat(szFileName, _T("/config"));
+ szFileName += 7;
+
+ // Append the first level directory
+ szFileName = AppendBlobText(szFileName, pFileKey->pbData, 1, _T('/'));
+ szFileName = AppendBlobText(szFileName, pFileKey->pbData + 1, 1, _T('/'));
+ szFileName = AppendBlobText(szFileName, pFileKey->pbData, pFileKey->cbData, _T('/'));
+}
+
+static DWORD GetBlobCount(LPBYTE pbLineBegin, LPBYTE pbLineEnd)
+{
+ DWORD dwBlobCount = 0;
+
+ // Until we find an end of the line
+ while(pbLineBegin < pbLineEnd)
+ {
+ // Skip the blob
+ while(pbLineBegin < pbLineEnd && IsValueSeparator(pbLineBegin) == false)
+ pbLineBegin++;
+
+ // Increment the number of blobs
+ dwBlobCount++;
+
+ // Skip the separator
+ while(pbLineBegin < pbLineEnd && IsValueSeparator(pbLineBegin))
+ pbLineBegin++;
+ }
+
+ return dwBlobCount;
+}
+
+static int LoadBlobArray(
+ PQUERY_KEY pBlob,
+ DWORD dwMaxBlobs,
+ LPBYTE pbLineBegin,
+ LPBYTE pbLineEnd,
+ LPBYTE pbBuffer,
+ DWORD dwBufferSize)
+{
+ LPBYTE pbBlobBegin = pbLineBegin;
+ LPBYTE pbBlobEnd = pbLineBegin;
+ int nError = ERROR_SUCCESS;
+
+ // Sanity check
+ assert(pbBuffer != NULL);
+
+ // Until we find an end of the line
+ while(pbBlobBegin < pbLineEnd)
+ {
+ // Convert the blob from string to binary
+ if(dwBufferSize < MAX_CASC_KEY_LENGTH)
+ return ERROR_NOT_ENOUGH_MEMORY;
+
+ // Find the end of the text blob
+ while(pbBlobEnd < pbLineEnd && IsValueSeparator(pbBlobEnd) == false)
+ pbBlobEnd++;
+
+ // Convert the blob from ANSI to binary
+ pBlob->pbData = pbBuffer;
+ nError = StringBlobToBinaryBlob(pBlob, pbBlobBegin, pbBlobEnd);
+ if(nError != ERROR_SUCCESS || dwMaxBlobs == 1)
+ break;
+
+ // Move the blob, buffer, and limits
+ dwBufferSize -= MAX_CASC_KEY_LENGTH;
+ pbBuffer += MAX_CASC_KEY_LENGTH;
+ dwMaxBlobs--;
+ pBlob++;
+
+ // Skip the separator
+ while(pbBlobEnd < pbLineEnd && IsValueSeparator(pbBlobEnd))
+ pbBlobEnd++;
+ pbBlobBegin = pbBlobEnd;
+ }
+
+ return nError;
+}
+
+static int LoadSingleBlob(PQUERY_KEY pBlob, LPBYTE pbBlobBegin, LPBYTE pbBlobEnd)
+{
+ LPBYTE pbBuffer;
+ size_t nLength = (pbBlobEnd - pbBlobBegin) / 2;
+
+ // Check maximum size
+ if(nLength > MAX_CASC_KEY_LENGTH)
+ return ERROR_INVALID_PARAMETER;
+
+ // Allocate the blob buffer
+ pbBuffer = CASC_ALLOC(BYTE, MAX_CASC_KEY_LENGTH);
+ if(pbBuffer == NULL)
+ return ERROR_NOT_ENOUGH_MEMORY;
+
+ return LoadBlobArray(pBlob, 1, pbBlobBegin, pbBlobEnd, pbBuffer, MAX_CASC_KEY_LENGTH);
+}
+
+static PQUERY_KEY LoadMultipleBlobs(LPBYTE pbLineBegin, LPBYTE pbLineEnd, DWORD * pdwBlobCount)
+{
+ PQUERY_KEY pBlobArray = NULL;
+ LPBYTE pbBuffer = NULL;
+ DWORD dwBlobCount = GetBlobCount(pbLineBegin, pbLineEnd);
+ int nError;
+
+ // Only if there is at least 1 blob
+ if(dwBlobCount != 0)
+ {
+ // Allocate the array of blobs
+ pBlobArray = CASC_ALLOC(QUERY_KEY, dwBlobCount);
+ if(pBlobArray != NULL)
+ {
+ // Zero the blob array
+ memset(pBlobArray, 0, dwBlobCount * sizeof(QUERY_KEY));
+
+ // Allocate buffer for the blobs
+ pbBuffer = CASC_ALLOC(BYTE, dwBlobCount * MAX_CASC_KEY_LENGTH);
+ if(pbBuffer != NULL)
+ {
+ // Zero the buffer
+ memset(pbBuffer, 0, dwBlobCount * MAX_CASC_KEY_LENGTH);
+
+ // Load the entire blob array
+ nError = LoadBlobArray(pBlobArray, dwBlobCount, pbLineBegin, pbLineEnd, pbBuffer, dwBlobCount * MAX_CASC_KEY_LENGTH);
+ if(nError == ERROR_SUCCESS)
+ {
+ *pdwBlobCount = dwBlobCount;
+ return pBlobArray;
+ }
+
+ // Free the buffer
+ CASC_FREE(pbBuffer);
+ }
+
+ // Free the array of blobs
+ CASC_FREE(pBlobArray);
+ pBlobArray = NULL;
+ }
+
+ // Reset the blob count
+ dwBlobCount = 0;
+ }
+
+ *pdwBlobCount = dwBlobCount;
+ return pBlobArray;
+}
+
+static int LoadTextFile(const TCHAR * szFileName, PQUERY_KEY pFileBlob)
+{
+ TFileStream * pStream;
+ ULONGLONG FileSize = 0;
+ int nError = ERROR_SUCCESS;
+
+ // Open the agent file
+ pStream = FileStream_OpenFile(szFileName, STREAM_FLAG_READ_ONLY | STREAM_PROVIDER_FLAT | BASE_PROVIDER_FILE);
+ if(pStream != NULL)
+ {
+ // Retrieve its size
+ FileStream_GetSize(pStream, &FileSize);
+
+ // Load the file to memory
+ if(0 < FileSize && FileSize < 0x100000)
+ {
+ // Initialize the blob
+ pFileBlob->cbData = (DWORD)FileSize;
+ pFileBlob->pbData = CASC_ALLOC(BYTE, pFileBlob->cbData + 1);
+
+ // Load the file data into the blob
+ if(pFileBlob->pbData != NULL)
+ {
+ FileStream_Read(pStream, NULL, pFileBlob->pbData, (DWORD)FileSize);
+ pFileBlob->pbData[pFileBlob->cbData] = 0;
+ }
+ else
+ nError = ERROR_NOT_ENOUGH_MEMORY;
+ }
+ else
+ nError = ERROR_INVALID_PARAMETER;
+
+ FileStream_Close(pStream);
+ }
+ else
+ nError = GetLastError();
+
+ return nError;
+}
+
+static int GetGameType(TCascStorage * hs, LPBYTE pbVarBegin, LPBYTE pbLineEnd)
+{
+ // Alpha build of Heroes of the Storm
+ if((pbLineEnd - pbVarBegin) == 4 && !_strnicmp((const char *)pbVarBegin, "Hero", 4))
+ {
+ hs->dwGameInfo = CASC_GAME_HOTS;
+ return ERROR_SUCCESS;
+ }
+
+ // Alpha build of World of Warcraft - Warlords of Draenor
+ if((pbLineEnd - pbVarBegin) == 3 && !_strnicmp((const char *)pbVarBegin, "WoW", 3))
+ {
+ hs->dwGameInfo = CASC_GAME_WOW6;
+ return ERROR_SUCCESS;
+ }
+
+ // An unknown game
+ assert(false);
+ return ERROR_BAD_FORMAT;
+}
+
+// "B29049"
+// "WOW-18125patch6.0.1"
+static int GetBuildNumber(TCascStorage * hs, LPBYTE pbVarBegin, LPBYTE pbLineEnd)
+{
+ DWORD dwBuildNumber = 0;
+
+ // Skip all non-digit characters
+ while(pbVarBegin < pbLineEnd && IsCharDigit(pbVarBegin[0]) == false)
+ pbVarBegin++;
+
+ // Convert the build number
+ while(pbVarBegin < pbLineEnd && IsCharDigit(pbVarBegin[0]))
+ dwBuildNumber = (dwBuildNumber * 10) + (*pbVarBegin++ - '0');
+
+ assert(dwBuildNumber != 0);
+ hs->dwBuildNumber = dwBuildNumber;
+ return (dwBuildNumber != 0) ? ERROR_SUCCESS : ERROR_BAD_FORMAT;
+}
+
+static int FetchAndVerifyConfigFile(TCascStorage * hs, PQUERY_KEY pFileKey, PQUERY_KEY pFileBlob)
+{
+ TCHAR * szFileName;
+ int nError;
+
+ // Construct the local file name
+ szFileName = NewStr(hs->szDataPath, 8 + 3 + 3 + 32);
+ if(szFileName == NULL)
+ return ERROR_NOT_ENOUGH_MEMORY;
+
+ // Add the part where the config file path is
+ AppendConfigFilePath(szFileName, pFileKey);
+
+ // Load the config file
+ nError = LoadTextFile(szFileName, pFileBlob);
+ if(nError == ERROR_SUCCESS)
+ {
+ // Verify the blob's MD5
+ if(!VerifyDataBlockHash(pFileBlob->pbData, pFileBlob->cbData, pFileKey->pbData))
+ {
+ FreeCascBlob(pFileBlob);
+ nError = ERROR_BAD_FORMAT;
+ }
+ }
+
+ CASC_FREE(szFileName);
+ return nError;
+}
+
+static int ParseInfoFile(TCascStorage * hs, PQUERY_KEY pFileBlob)
+{
+ QUERY_KEY CdnHost = {NULL, 0};
+ QUERY_KEY CdnPath = {NULL, 0};
+ const char * szLineBegin1 = NULL;
+ const char * szLineBegin2 = NULL;
+ const char * szLineEnd1 = NULL;
+ const char * szLineEnd2 = NULL;
+ const char * szFileEnd = (const char *)(pFileBlob->pbData + pFileBlob->cbData);
+ const char * szFilePtr = (const char *)pFileBlob->pbData;
+ int nError = ERROR_BAD_FORMAT;
+
+ // Find the first line
+ szLineBegin1 = szFilePtr;
+ while(szFilePtr < szFileEnd)
+ {
+ // Check for the end of the line
+ if(szFilePtr[0] == 0x0D || szFilePtr[0] == 0x0A)
+ {
+ szLineEnd1 = szFilePtr;
+ break;
+ }
+
+ szFilePtr++;
+ }
+
+ // Skip the newline character(s)
+ while(szFilePtr < szFileEnd && (szFilePtr[0] == 0x0D || szFilePtr[0] == 0x0A))
+ szFilePtr++;
+
+ // Find the second line
+ szLineBegin2 = szFilePtr;
+ while(szFilePtr < szFileEnd)
+ {
+ // Check for the end of the line
+ if(szFilePtr[0] == 0x0D || szFilePtr[0] == 0x0A)
+ {
+ szLineEnd2 = szFilePtr;
+ break;
+ }
+
+ szFilePtr++;
+ }
+
+ // Find the build key, CDN config key and the URL path
+ while(szLineBegin1 < szLineEnd1)
+ {
+ // Check for variables we need
+ if(IsInfoVariable(szLineBegin1, szLineEnd1, "Build Key", "HEX"))
+ LoadInfoVariable(&hs->CdnBuildKey, szLineBegin2, szLineEnd2, true);
+ if(IsInfoVariable(szLineBegin1, szLineEnd1, "CDN Key", "HEX"))
+ LoadInfoVariable(&hs->CdnConfigKey, szLineBegin2, szLineEnd2, true);
+ if(IsInfoVariable(szLineBegin1, szLineEnd1, "CDN Hosts", "STRING"))
+ LoadInfoVariable(&CdnHost, szLineBegin2, szLineEnd2, false);
+ if(IsInfoVariable(szLineBegin1, szLineEnd1, "CDN Path", "STRING"))
+ LoadInfoVariable(&CdnPath, szLineBegin2, szLineEnd2, false);
+
+ // Move both line pointers
+ szLineBegin1 = SkipInfoVariable(szLineBegin1, szLineEnd1);
+ if(szLineBegin1 == NULL)
+ break;
+
+ szLineBegin2 = SkipInfoVariable(szLineBegin2, szLineEnd2);
+ if(szLineBegin2 == NULL)
+ break;
+ }
+
+ // All four must be present
+ if(hs->CdnBuildKey.pbData != NULL &&
+ hs->CdnConfigKey.pbData != NULL &&
+ CdnHost.pbData != NULL &&
+ CdnPath.pbData != NULL)
+ {
+ // Merge the CDN host and CDN path
+ hs->szUrlPath = CASC_ALLOC(TCHAR, CdnHost.cbData + CdnPath.cbData + 1);
+ if(hs->szUrlPath != NULL)
+ {
+ CopyString(hs->szUrlPath, (char *)CdnHost.pbData, CdnHost.cbData);
+ CopyString(hs->szUrlPath + CdnHost.cbData, (char *)CdnPath.pbData, CdnPath.cbData);
+ nError = ERROR_SUCCESS;
+ }
+ }
+
+ FreeCascBlob(&CdnHost);
+ FreeCascBlob(&CdnPath);
+ return nError;
+}
+
+static int ParseAgentFile(TCascStorage * hs, PQUERY_KEY pFileBlob)
+{
+ LPBYTE pbBlobBegin = pFileBlob->pbData;
+ LPBYTE pbBlobEnd;
+ int nError = ERROR_SUCCESS;
+
+ // Extract the CDN build hash
+ pbBlobEnd = FindNextSeparator(pFileBlob, pbBlobBegin);
+ if(pbBlobEnd != NULL)
+ {
+ // Convert the string to a blob
+ nError = LoadSingleBlob(&hs->CdnBuildKey, pbBlobBegin, pbBlobEnd);
+
+ // Move to the next part
+ if(pbBlobEnd[0] == _T('|'))
+ pbBlobEnd++;
+ pbBlobBegin = pbBlobEnd;
+ }
+
+ // Extract the CDN config hash
+ pbBlobEnd = FindNextSeparator(pFileBlob, pbBlobBegin);
+ if(pbBlobEnd != NULL)
+ {
+ // Convert the string to a blob
+ nError = LoadSingleBlob(&hs->CdnConfigKey, pbBlobBegin, pbBlobEnd);
+
+ // Move to the next part
+ if(pbBlobEnd[0] == _T('|'))
+ pbBlobEnd++;
+ pbBlobBegin = pbBlobEnd;
+ }
+
+ // Skip the intermediate part
+ pbBlobEnd = FindNextSeparator(pFileBlob, pbBlobBegin);
+ if(pbBlobEnd != NULL)
+ {
+ // Move to the next part
+ if(pbBlobEnd[0] == _T('|'))
+ pbBlobEnd++;
+ pbBlobBegin = pbBlobEnd;
+ }
+
+ // Extract the URL config hash
+ pbBlobEnd = FindNextSeparator(pFileBlob, pbBlobBegin);
+ if(pbBlobEnd != NULL)
+ {
+ // Convert the string to a blob
+ hs->szUrlPath = NewStrFromAnsi(pbBlobBegin, pbBlobEnd);
+ }
+
+ // Verify all variables
+ if(hs->CdnBuildKey.pbData == NULL || hs->CdnConfigKey.pbData == NULL || hs->szUrlPath == NULL)
+ nError = ERROR_BAD_FORMAT;
+ return nError;
+}
+
+static int LoadCdnConfigFile(TCascStorage * hs, PQUERY_KEY pFileBlob)
+{
+ LPBYTE pbLineBegin = pFileBlob->pbData;
+ LPBYTE pbVarBegin;
+ LPBYTE pbLineEnd = NULL;
+ int nError;
+
+ while(pbLineBegin != NULL)
+ {
+ // Get the next line
+ if(!GetNextFileLine(pFileBlob, &pbLineBegin, &pbLineEnd))
+ break;
+
+ // Archive group
+ pbVarBegin = CheckLineVariable(pbLineBegin, pbLineEnd, "archive-group");
+ if(pbVarBegin != NULL)
+ {
+ nError = LoadSingleBlob(&hs->ArchiveGroup, pbVarBegin, pbLineEnd);
+ if(nError != ERROR_SUCCESS)
+ return nError;
+ continue;
+ }
+
+ // Archives
+ pbVarBegin = CheckLineVariable(pbLineBegin, pbLineEnd, "archives");
+ if(pbVarBegin != NULL)
+ {
+ hs->pArchiveArray = LoadMultipleBlobs(pbVarBegin, pbLineEnd, &hs->ArchiveCount);
+ if(hs->pArchiveArray == NULL || hs->ArchiveCount == 0)
+ return ERROR_BAD_FORMAT;
+ continue;
+ }
+
+ // Patch archive group
+ pbVarBegin = CheckLineVariable(pbLineBegin, pbLineEnd, "patch-archive-group");
+ if(pbVarBegin != NULL)
+ {
+ LoadSingleBlob(&hs->PatchArchiveGroup, pbVarBegin, pbLineEnd);
+ continue;
+ }
+
+ // Patch archives
+ pbVarBegin = CheckLineVariable(pbLineBegin, pbLineEnd, "patch-archives");
+ if(pbVarBegin != NULL)
+ {
+ hs->pPatchArchiveArray = LoadMultipleBlobs(pbVarBegin, pbLineEnd, &hs->PatchArchiveCount);
+ continue;
+ }
+ }
+
+ // Check if all required fields are present
+ if(hs->ArchiveGroup.pbData == NULL || hs->ArchiveGroup.cbData == 0 || hs->pArchiveArray == NULL || hs->ArchiveCount == 0)
+ return ERROR_BAD_FORMAT;
+
+ return ERROR_SUCCESS;
+}
+
+static int LoadCdnBuildFile(TCascStorage * hs, PQUERY_KEY pFileBlob)
+{
+ LPBYTE pbLineBegin = pFileBlob->pbData;
+ LPBYTE pbVarBegin;
+ LPBYTE pbLineEnd = NULL;
+
+ while(pbLineBegin != NULL)
+ {
+ // Get the next line
+ if(!GetNextFileLine(pFileBlob, &pbLineBegin, &pbLineEnd))
+ break;
+
+ // Game name
+ pbVarBegin = CheckLineVariable(pbLineBegin, pbLineEnd, "build-product");
+ if(pbVarBegin != NULL)
+ {
+ GetGameType(hs, pbVarBegin, pbLineEnd);
+ continue;
+ }
+
+ // Game build number
+ pbVarBegin = CheckLineVariable(pbLineBegin, pbLineEnd, "build-name");
+ if(pbVarBegin != NULL)
+ {
+ GetBuildNumber(hs, pbVarBegin, pbLineEnd);
+ continue;
+ }
+
+ // Root
+ pbVarBegin = CheckLineVariable(pbLineBegin, pbLineEnd, "root");
+ if(pbVarBegin != NULL)
+ {
+ LoadSingleBlob(&hs->RootKey, pbVarBegin, pbLineEnd);
+ continue;
+ }
+
+ // Patch
+ pbVarBegin = CheckLineVariable(pbLineBegin, pbLineEnd, "patch");
+ if(pbVarBegin != NULL)
+ {
+ LoadSingleBlob(&hs->PatchKey, pbVarBegin, pbLineEnd);
+ continue;
+ }
+
+ // Download
+ pbVarBegin = CheckLineVariable(pbLineBegin, pbLineEnd, "download");
+ if(pbVarBegin != NULL)
+ {
+ LoadSingleBlob(&hs->DownloadKey, pbVarBegin, pbLineEnd);
+ continue;
+ }
+
+ // Install
+ pbVarBegin = CheckLineVariable(pbLineBegin, pbLineEnd, "install");
+ if(pbVarBegin != NULL)
+ {
+ LoadSingleBlob(&hs->InstallKey, pbVarBegin, pbLineEnd);
+ continue;
+ }
+
+ // Encoding keys
+ pbVarBegin = CheckLineVariable(pbLineBegin, pbLineEnd, "encoding");
+ if(pbVarBegin != NULL)
+ {
+ hs->pEncodingKeys = LoadMultipleBlobs(pbVarBegin, pbLineEnd, &hs->EncodingKeys);
+ if(hs->pEncodingKeys == NULL || hs->EncodingKeys != 2)
+ return ERROR_BAD_FORMAT;
+
+ hs->EncodingKey = hs->pEncodingKeys[0];
+ hs->EncodingEKey = hs->pEncodingKeys[1];
+ continue;
+ }
+ }
+
+ // Check the encoding keys
+ if(hs->pEncodingKeys == NULL || hs->EncodingKeys == 0)
+ return ERROR_BAD_FORMAT;
+ return ERROR_SUCCESS;
+}
+
+//-----------------------------------------------------------------------------
+// Public functions
+
+int LoadBuildConfiguration(TCascStorage * hs)
+{
+ QUERY_KEY InfoFile = {NULL, 0};
+ QUERY_KEY FileData = {NULL, 0};
+ TCHAR * szAgentFile;
+ TCHAR * szInfoFile;
+ bool bBuildConfigComplete = false;
+ int nError = ERROR_SUCCESS;
+
+ // Since HOTS build 30027, the game uses build.info file for storage info
+ if(bBuildConfigComplete == false)
+ {
+ szInfoFile = CombinePath(hs->szRootPath, _T(".build.info"));
+ if(szInfoFile != NULL)
+ {
+ nError = LoadTextFile(szInfoFile, &InfoFile);
+ if(nError == ERROR_SUCCESS)
+ {
+ // Parse the info file
+ nError = ParseInfoFile(hs, &InfoFile);
+ if(nError == ERROR_SUCCESS)
+ bBuildConfigComplete = true;
+
+ // Free the loaded blob
+ FreeCascBlob(&InfoFile);
+ }
+
+ CASC_FREE(szInfoFile);
+ }
+ }
+
+ // If the info file has not been loaded, try the legacy .build.db
+ if(bBuildConfigComplete == false)
+ {
+ szAgentFile = CombinePath(hs->szRootPath, _T(".build.db"));
+ if(szAgentFile != NULL)
+ {
+ nError = LoadTextFile(szAgentFile, &FileData);
+ if(nError == ERROR_SUCCESS)
+ {
+ nError = ParseAgentFile(hs, &FileData);
+ if(nError == ERROR_SUCCESS)
+ bBuildConfigComplete = true;
+
+ FreeCascBlob(&FileData);
+ }
+ CASC_FREE(szAgentFile);
+ }
+ }
+
+ // If the .build.info and .build.db file hasn't been loaded,
+ if(nError == ERROR_SUCCESS && bBuildConfigComplete == false)
+ {
+ nError = ERROR_FILE_CORRUPT;
+ }
+
+ // Load the configuration file
+ if(nError == ERROR_SUCCESS)
+ {
+ nError = FetchAndVerifyConfigFile(hs, &hs->CdnConfigKey, &FileData);
+ if(nError == ERROR_SUCCESS)
+ {
+ nError = LoadCdnConfigFile(hs, &FileData);
+ FreeCascBlob(&FileData);
+ }
+ }
+
+ // Load the build file
+ if(nError == ERROR_SUCCESS)
+ {
+ nError = FetchAndVerifyConfigFile(hs, &hs->CdnBuildKey, &FileData);
+ if(nError == ERROR_SUCCESS)
+ {
+ nError = LoadCdnBuildFile(hs, &FileData);
+ FreeCascBlob(&FileData);
+ }
+ }
+
+ // Fill the index directory
+ if(nError == ERROR_SUCCESS)
+ {
+ // First, check for more common "data" subdirectory
+ if((hs->szIndexPath = CheckForIndexDirectory(hs, _T("data"))) != NULL)
+ return ERROR_SUCCESS;
+
+ // Second, try the "darch" subdirectory (older builds of HOTS - Alpha)
+ if((hs->szIndexPath = CheckForIndexDirectory(hs, _T("darch"))) != NULL)
+ return ERROR_SUCCESS;
+
+ nError = ERROR_FILE_NOT_FOUND;
+ }
+
+ return nError;
+}
diff --git a/dep/CascLib/src/CascCommon.cpp b/dep/CascLib/src/CascCommon.cpp
new file mode 100644
index 00000000000..8ad7d716b82
--- /dev/null
+++ b/dep/CascLib/src/CascCommon.cpp
@@ -0,0 +1,67 @@
+/*****************************************************************************/
+/* CascCommon.cpp Copyright (c) Ladislav Zezula 2014 */
+/*---------------------------------------------------------------------------*/
+/* Common functions for CascLib */
+/*---------------------------------------------------------------------------*/
+/* Date Ver Who Comment */
+/* -------- ---- --- ------- */
+/* 29.04.14 1.00 Lad The first version of CascCommon.cpp */
+/*****************************************************************************/
+
+#define __CASCLIB_SELF__
+#include "CascLib.h"
+#include "CascCommon.h"
+
+//-----------------------------------------------------------------------------
+// Conversion of big-endian to integer
+
+// Read the 24-bit big-endian offset into ULONGLONG
+DWORD ConvertBytesToInteger_3(LPBYTE ValueAsBytes)
+{
+ DWORD Value = 0;
+
+ Value = (Value << 0x08) | ValueAsBytes[0];
+ Value = (Value << 0x08) | ValueAsBytes[1];
+ Value = (Value << 0x08) | ValueAsBytes[2];
+
+ return Value;
+}
+
+// Read the 32-bit big-endian offset into ULONGLONG
+DWORD ConvertBytesToInteger_4(LPBYTE ValueAsBytes)
+{
+ DWORD Value = 0;
+
+ Value = (Value << 0x08) | ValueAsBytes[0];
+ Value = (Value << 0x08) | ValueAsBytes[1];
+ Value = (Value << 0x08) | ValueAsBytes[2];
+ Value = (Value << 0x08) | ValueAsBytes[3];
+
+ return Value;
+}
+
+DWORD ConvertBytesToInteger_4_LE(LPBYTE ValueAsBytes)
+{
+ DWORD Value = 0;
+
+ Value = (Value << 0x08) | ValueAsBytes[3];
+ Value = (Value << 0x08) | ValueAsBytes[2];
+ Value = (Value << 0x08) | ValueAsBytes[1];
+ Value = (Value << 0x08) | ValueAsBytes[0];
+
+ return Value;
+}
+
+// Read the 40-bit big-endian offset into ULONGLONG
+ULONGLONG ConvertBytesToInteger_5(LPBYTE ValueAsBytes)
+{
+ ULONGLONG Value = 0;
+
+ Value = (Value << 0x08) | ValueAsBytes[0];
+ Value = (Value << 0x08) | ValueAsBytes[1];
+ Value = (Value << 0x08) | ValueAsBytes[2];
+ Value = (Value << 0x08) | ValueAsBytes[3];
+ Value = (Value << 0x08) | ValueAsBytes[4];
+
+ return Value;
+}
diff --git a/dep/CascLib/src/CascCommon.h b/dep/CascLib/src/CascCommon.h
new file mode 100644
index 00000000000..b2f6a156e39
--- /dev/null
+++ b/dep/CascLib/src/CascCommon.h
@@ -0,0 +1,374 @@
+/*****************************************************************************/
+/* CascCommon.h Copyright (c) Ladislav Zezula 2014 */
+/*---------------------------------------------------------------------------*/
+/* Common functions for CascLib */
+/*---------------------------------------------------------------------------*/
+/* Date Ver Who Comment */
+/* -------- ---- --- ------- */
+/* 29.04.14 1.00 Lad The first version of CascCommon.h */
+/*****************************************************************************/
+
+#ifndef __CASCCOMMON_H__
+#define __CASCCOMMON_H__
+
+//-----------------------------------------------------------------------------
+// Compression support
+
+// Include functions from zlib
+#ifndef __SYS_ZLIB
+ #include "zlib/zlib.h"
+#else
+ #include <zlib.h>
+#endif
+
+#include "CascPort.h"
+#include "common/Common.h"
+#include "common/FileStream.h"
+#include "common/ListFile.h"
+#include "common/Map.h"
+
+// Headers from LibTomCrypt
+#include "libtomcrypt/src/headers/tomcrypt.h"
+
+// For HashStringJenkins
+#include "jenkins/lookup.h"
+
+//-----------------------------------------------------------------------------
+// CascLib private defines
+
+#define CASC_GAME_HOTS 0x00010000 // Heroes of the Storm
+#define CASC_GAME_WOW6 0x00020000 // World of Warcraft - Warlords of Draenor
+#define CASC_GAME_MASK 0xFFFF0000 // Mask for getting game ID
+
+#define CASC_INDEX_COUNT 0x10
+#define CASC_FILE_KEY_SIZE 0x09 // Size of the file key
+#define CASC_MAX_DATA_FILES 0x100
+#define CASC_MAX_MAR_FILES 3 // Maximum of 3 MAR files are supported
+#define CASC_MNDX_SIGNATURE 0x58444E4D // 'MNDX'
+
+#define CASC_SEARCH_HAVE_NAME 0x0001 // Indicated that previous search found a name
+
+// Prevent problems with CRT "min" and "max" functions,
+// as they are not defined on all platforms
+#define CASCLIB_MIN(a, b) ((a < b) ? a : b)
+#define CASCLIB_MAX(a, b) ((a > b) ? a : b)
+#define CASCLIB_UNUSED(p) ((void)(p))
+
+#define CASC_PACKAGE_BUFFER 0x1000
+
+//-----------------------------------------------------------------------------
+// Structures
+
+struct TFileStream;
+struct _MAR_FILE;
+
+typedef struct _CASC_INDEX_ENTRY
+{
+ BYTE IndexKey[CASC_FILE_KEY_SIZE]; // The first 9 bytes of the encoding key
+ BYTE FileOffset[5]; //
+ BYTE FileSize[4];
+} CASC_INDEX_ENTRY, *PCASC_INDEX_ENTRY;
+
+typedef struct _CASC_MAPPING_TABLE
+{
+ TCHAR * szFileName; // Name of the key mapping file
+ LPBYTE pbFileData; // Pointer to the file data
+ DWORD cbFileData; // Length of the file data
+ BYTE ExtraBytes; // (?) Extra bytes in the key record
+ BYTE SpanSizeBytes; // Size of field with file size
+ BYTE SpanOffsBytes; // Size of field with file offset
+ BYTE KeyBytes; // Size of the file key
+ BYTE SegmentBits; // Number of bits for the file offset (rest is archive index)
+ ULONGLONG MaxFileOffset;
+
+ PCASC_INDEX_ENTRY pIndexEntries; // Sorted array of index entries
+ DWORD nIndexEntries; // Number of index entries
+
+} CASC_MAPPING_TABLE, *PCASC_MAPPING_TABLE;
+
+typedef struct _CASC_FILE_FRAME
+{
+ DWORD FrameArchiveOffset; // Archive file pointer corresponding to the begin of the frame
+ DWORD FrameFileOffset; // File pointer corresponding to the begin of the frame
+ DWORD CompressedSize; // Compressed size of the file
+ DWORD FrameSize; // Size of the frame
+ BYTE md5[MD5_HASH_SIZE]; // MD5 hash of the file sector
+} CASC_FILE_FRAME, *PCASC_FILE_FRAME;
+
+typedef struct _CASC_ENCODING_HEADER
+{
+ BYTE Magic[2]; // "EN"
+ BYTE field_2;
+ BYTE field_3;
+ BYTE field_4;
+ BYTE field_5[2];
+ BYTE field_7[2];
+ BYTE NumSegments[4]; // Number of entries (big endian)
+ BYTE field_D[4];
+ BYTE field_11;
+ BYTE SegmentsPos[4]; // Offset of encoding segments
+
+} CASC_ENCODING_HEADER, *PCASC_ENCODING_HEADER;
+
+typedef struct _CASC_ENCODING_ENTRY
+{
+ USHORT KeyCount; // Number of subitems
+ BYTE FileSizeBytes[4]; // File size as bytes (big-endian)
+ BYTE EncodingKey[MD5_HASH_SIZE]; // File encoding key
+
+ // Followed by the index keys
+ // (number of items = KeyCount)
+ // Followed by the index keys (number of items = KeyCount)
+} CASC_ENCODING_ENTRY, *PCASC_ENCODING_ENTRY;
+
+typedef struct _CASC_ROOT_LOCALE_BLOCK
+{
+ DWORD NumberOfFiles; // Number of entries
+ DWORD Flags;
+ DWORD FileLocales; // File locales (CASC_LOCALE_XXX)
+
+ // Followed by a block of 32-bit integers (count: NumberOfFiles)
+ // Followed by the MD5 and file name hash (count: NumberOfFiles)
+
+} CASC_ROOT_LOCALE_BLOCK, *PCASC_ROOT_LOCALE_BLOCK;
+
+typedef struct _CASC_ROOT_ENTRY
+{
+ BYTE EncodingKey[MD5_HASH_SIZE]; // File encoding key (MD5)
+ ULONGLONG FileNameHash; // Jenkins hash of the file name
+ DWORD Locales; // File locales (see CASC_LOCALE_XXX)
+ DWORD Flags; // File flags
+
+} CASC_ROOT_ENTRY, *PCASC_ROOT_ENTRY;
+
+typedef struct _CASC_ROOT_KEY_INFO
+{
+ BYTE EncodingKey[MD5_HASH_SIZE]; // Encoding key for the file, obtained from root info
+ ULONGLONG FileSize; // Size of the file, in bytes
+ BYTE Flags; // File flags
+} CASC_ROOT_KEY_INFO, *PCASC_ROOT_KEY_INFO;
+
+typedef struct _CASC_MNDX_ENTRY
+{
+ DWORD Flags; // High 8 bits: Flags, low 24 bits: package index
+ BYTE EncodingKey[MD5_HASH_SIZE]; // Encoding key for the file
+ DWORD FileSize; // Size of the file, in bytes
+
+} CASC_MNDX_ENTRY, *PCASC_MNDX_ENTRY;
+
+typedef struct _CASC_MNDX_INFO
+{
+ bool bRootFileLoaded; // true if the root info file was properly loaded
+ BYTE RootFileName[MD5_HASH_SIZE]; // Name (aka MD5) of the root file
+ DWORD HeaderVersion; // Must be <= 2
+ DWORD FormatVersion;
+ DWORD field_1C;
+ DWORD field_20;
+ DWORD MarInfoOffset; // Offset of the first MAR entry info
+ DWORD MarInfoCount; // Number of the MAR info entries
+ DWORD MarInfoSize; // Size of the MAR info entry
+ DWORD MndxEntriesOffset;
+ DWORD MndxEntriesTotal; // Total number of MNDX root entries
+ DWORD MndxEntriesValid; // Number of valid MNDX root entries
+ DWORD MndxEntrySize; // Size of one MNDX root entry
+ struct _MAR_FILE * pMarFile1; // File name list for the packages
+ struct _MAR_FILE * pMarFile2; // File name list for names stripped of package names
+ struct _MAR_FILE * pMarFile3; // File name list for complete names
+ PCASC_MNDX_ENTRY pMndxEntries;
+ PCASC_MNDX_ENTRY * ppValidEntries;
+
+} CASC_MNDX_INFO, *PCASC_MNDX_INFO;
+
+typedef struct _CASC_PACKAGE
+{
+ char * szFileName; // Pointer to file name
+ size_t nLength; // Length of the file name
+
+} CASC_PACKAGE, *PCASC_PACKAGE;
+
+typedef struct _CASC_PACKAGES
+{
+ char * szNameBuffer; // Pointer to the buffer for file names
+ size_t NameEntries; // Number of name entries in Names
+ size_t NameBufferUsed; // Number of bytes used in the name buffer
+ size_t NameBufferMax; // Total size of the name buffer
+
+ CASC_PACKAGE Packages[1]; // List of packages
+
+} CASC_PACKAGES, *PCASC_PACKAGES;
+
+typedef struct _TCascStorage
+{
+ const char * szClassName; // "TCascStorage"
+ const TCHAR * szIndexFormat; // Format of the index file name
+ TCHAR * szRootPath; // This is the game directory
+ TCHAR * szDataPath; // This is the directory where data files are
+ TCHAR * szIndexPath; // This is the directory where index files are
+ TCHAR * szUrlPath; // URL to the Blizzard servers
+ DWORD dwRefCount; // Number of references
+ DWORD dwGameInfo; // Game type
+ DWORD dwBuildNumber; // Game build number
+
+ QUERY_KEY CdnConfigKey;
+ QUERY_KEY CdnBuildKey;
+
+ PQUERY_KEY pArchiveArray; // Array of the archives
+ QUERY_KEY ArchiveGroup; // Name of the group archive file
+ DWORD ArchiveCount; // Number of archives in the array
+
+ PQUERY_KEY pPatchArchiveArray; // Array of the patch archives
+ QUERY_KEY PatchArchiveGroup; // Name of the patch group archive file
+ DWORD PatchArchiveCount; // Number of patch archives in the array
+
+ QUERY_KEY RootKey;
+ QUERY_KEY PatchKey;
+ QUERY_KEY DownloadKey;
+ QUERY_KEY InstallKey;
+
+ PQUERY_KEY pEncodingKeys;
+ QUERY_KEY EncodingKey;
+ QUERY_KEY EncodingEKey;
+ DWORD EncodingKeys;
+
+ TFileStream * DataFileArray[CASC_MAX_DATA_FILES]; // Data file handles
+
+ CASC_MAPPING_TABLE KeyMapping[CASC_INDEX_COUNT]; // Key mapping
+ PCASC_MAP pIndexEntryMap; // Map of index entries
+
+ PCASC_ENCODING_HEADER pEncodingHeader; // The encoding file
+ PCASC_ENCODING_ENTRY * ppEncodingEntries; // Map of encoding entries
+ size_t nEncodingEntries;
+
+ PCASC_ROOT_ENTRY * ppRootEntries; // Sorted array of root entries
+ PCASC_ROOT_ENTRY pRootEntries; // Linear array of root entries
+ size_t nRootEntries; // Number of root entries
+
+ PCASC_MNDX_INFO pMndxInfo; // Used for storages which have MNDX/MAR file
+ PCASC_PACKAGES pPackages; // Linear list of present packages
+
+} TCascStorage;
+
+typedef struct _TCascFile
+{
+ TCascStorage * hs; // Pointer to storage structure
+ TFileStream * pStream; // An open data stream
+ const char * szClassName; // "TCascFile"
+
+ DWORD FilePointer; // Current file pointer
+
+ DWORD ArchiveIndex; // Index of the archive (data.###)
+ DWORD HeaderOffset; // Offset of the BLTE header, relative to the begin of the archive
+ DWORD FramesOffset; // Offset of the frame data, relative to the begin of the archive
+ DWORD CompressedSize; // Compressed size of the file (in bytes)
+ DWORD FileSize; // Size of file, in bytes
+
+ PCASC_FILE_FRAME pFrames; // Array of file frames
+ DWORD FrameCount; // Number of the file frames
+
+ LPBYTE pbFileCache; // Pointer to file cache
+ DWORD cbFileCache; // Size of the file cache
+ DWORD CacheStart; // Starting offset in the cache
+ DWORD CacheEnd; // Ending offset in the cache
+
+} TCascFile;
+
+class TMndxFindResult;
+
+typedef struct _TCascSearch
+{
+ TCascStorage * hs; // Pointer to the storage handle
+ const char * szClassName;
+ TCHAR * szListFile;
+ void * pCache; // Listfile cache
+ TMndxFindResult * pStruct1C; // Search structure for MNDX info
+ char * szMask;
+ char szFileName[MAX_PATH]; // Buffer for the file name
+ char szNormName[MAX_PATH]; // Buffer for normalized file name
+ ULONGLONG FileNameHash; // Name hash being searched right now
+ size_t RootIndex; // Root index of the previously found item
+ DWORD dwState; // Pointer to the state (0 = listfile, 1 = nameless, 2 = done)
+ BYTE BitArray[1]; // Bit array of already-reported files
+
+} TCascSearch;
+
+//-----------------------------------------------------------------------------
+// Memory management
+//
+// We use our own macros for allocating/freeing memory. If you want
+// to redefine them, please keep the following rules:
+//
+// - The memory allocation must return NULL if not enough memory
+// (i.e not to throw exception)
+// - The allocating function does not need to fill the allocated buffer with zeros
+// - The reallocating function must support NULL as the previous block
+// - Memory freeing function doesn't have to test the pointer to NULL
+//
+
+#if defined(_MSC_VER) && defined(_DEBUG)
+/*
+void * DbgRealloc(void * ptr, size_t nSize);
+
+#define CASC_REALLOC(type, ptr, count) (type *)DbgRealloc(ptr, ((count) * sizeof(type)))
+#define CASC_ALLOC(type, count) (type *)HeapAlloc(GetProcessHeap(), 0, ((count) * sizeof(type)))
+#define CASC_FREE(ptr) HeapFree(GetProcessHeap(), 0, ptr)
+*/
+
+#define CASC_REALLOC(type, ptr, count) (type *)realloc(ptr, (count) * sizeof(type))
+#define CASC_ALLOC(type, count) (type *)malloc((count) * sizeof(type))
+#define CASC_FREE(ptr) free(ptr)
+
+#else
+
+#define CASC_REALLOC(type, ptr, count) (type *)realloc(ptr, (count) * sizeof(type))
+#define CASC_ALLOC(type, count) (type *)malloc((count) * sizeof(type))
+#define CASC_FREE(ptr) free(ptr)
+
+#endif
+
+//-----------------------------------------------------------------------------
+// Big endian number manipulation
+
+DWORD ConvertBytesToInteger_3(LPBYTE ValueAsBytes);
+DWORD ConvertBytesToInteger_4(LPBYTE ValueAsBytes);
+DWORD ConvertBytesToInteger_4_LE(LPBYTE ValueAsBytes);
+ULONGLONG ConvertBytesToInteger_5(LPBYTE ValueAsBytes);
+
+//-----------------------------------------------------------------------------
+// Build configuration reading
+
+int LoadBuildConfiguration(TCascStorage * hs);
+
+//-----------------------------------------------------------------------------
+// Internal file functions
+
+TCascStorage * IsValidStorageHandle(HANDLE hStorage);
+TCascFile * IsValidFileHandle(HANDLE hFile);
+
+PCASC_ROOT_ENTRY FindFirstRootEntry(TCascStorage * hs, const char * szFileName, size_t * PtrIndex);
+PCASC_ENCODING_ENTRY FindEncodingEntry(TCascStorage * hs, PQUERY_KEY pEncodingKey, size_t * PtrIndex);
+PCASC_INDEX_ENTRY FindIndexEntry(TCascStorage * hs, PQUERY_KEY pIndexKey);
+
+int CascDecompress(void * pvOutBuffer, PDWORD pcbOutBuffer, void * pvInBuffer, DWORD cbInBuffer);
+
+//-----------------------------------------------------------------------------
+// Dump data
+
+#ifdef _DEBUG
+void CascDumpSparseArray(const char * szFileName, void * pvSparseArray);
+void CascDumpNameFragTable(const char * szFileName, void * pvMarFile);
+void CascDumpFileNames(const char * szFileName, void * pvMarFile);
+void CascDumpMndxRoot(const char * szFileName, PCASC_MNDX_INFO pMndxInfo);
+void CascDumpIndexEntries(const char * szFileName, TCascStorage * hs);
+void CascDumpStorage(const char * szFileName, TCascStorage * hs, const TCHAR * szListFile);
+void CascDumpFile(const char * szFileName, HANDLE hFile);
+#else // _DEBUG
+#define CascDumpSparseArray(n,a) /* */
+#define CascDumpNameFragTable(n, m) /* */
+#define CascDumpFileNames(n, m) /* */
+#define CascDumpMndxRoot(n,i) /* */
+#define CascDumpIndexEntries(n,h) /* */
+#define CascDumpStorage(n,h) /* */
+#define CascDumpFile(n,h) /* */
+#endif // _DEBUG
+
+#endif // __CASCCOMMON_H__
diff --git a/dep/CascLib/src/CascDecompress.cpp b/dep/CascLib/src/CascDecompress.cpp
new file mode 100644
index 00000000000..2858bcec5ab
--- /dev/null
+++ b/dep/CascLib/src/CascDecompress.cpp
@@ -0,0 +1,83 @@
+/*****************************************************************************/
+/* CascDecompress.cpp Copyright (c) Ladislav Zezula 2014 */
+/*---------------------------------------------------------------------------*/
+/* Decompression functions */
+/*---------------------------------------------------------------------------*/
+/* Date Ver Who Comment */
+/* -------- ---- --- ------- */
+/* 02.05.14 1.00 Lad The first version of CascDecompress.cpp */
+/*****************************************************************************/
+
+#define __CASCLIB_SELF__
+#include "CascLib.h"
+#include "CascCommon.h"
+
+//-----------------------------------------------------------------------------
+// Local functions
+
+static int Decompress_ZLIB(LPBYTE pbOutBuffer, PDWORD pcbOutBuffer, LPBYTE pbInBuffer, DWORD cbInBuffer)
+{
+ z_stream z; // Stream information for zlib
+ int nResult;
+
+ // Fill the stream structure for zlib
+ z.next_in = pbInBuffer;
+ z.avail_in = cbInBuffer;
+ z.total_in = cbInBuffer;
+ z.next_out = pbOutBuffer;
+ z.avail_out = *pcbOutBuffer;
+ z.total_out = 0;
+ z.zalloc = NULL;
+ z.zfree = NULL;
+
+ // Initialize the decompression structure
+ if((nResult = inflateInit(&z)) == Z_OK)
+ {
+ // Call zlib to decompress the data
+ nResult = inflate(&z, Z_NO_FLUSH);
+ inflateEnd(&z);
+
+ // Give the size of the uncompressed data
+ *pcbOutBuffer = z.total_out;
+ }
+
+ // Return an error code
+ return (nResult == Z_OK || nResult == Z_STREAM_END) ? ERROR_SUCCESS : ERROR_FILE_CORRUPT;
+}
+
+//-----------------------------------------------------------------------------
+// Public functions
+
+int CascDecompress(void * pvOutBuffer, PDWORD pcbOutBuffer, void * pvInBuffer, DWORD cbInBuffer)
+{
+ LPBYTE pbOutBuffer = (LPBYTE)pvOutBuffer;
+ LPBYTE pbInBuffer = (LPBYTE)pvInBuffer;
+ DWORD cbOutBuffer = *pcbOutBuffer; // Current size of the output buffer
+ BYTE uCompression; // Decompressions applied to the data
+
+ // Verify buffer sizes
+ if(cbInBuffer <= 1)
+ return 0;
+
+ // Get applied compression types and decrement data length
+ uCompression = *pbInBuffer++;
+ cbInBuffer--;
+
+ // Perform the decompressions
+ switch(uCompression)
+ {
+ case 'N': // Uncompressed
+
+ assert(cbOutBuffer == cbInBuffer);
+ memcpy(pbOutBuffer, pbInBuffer, cbInBuffer);
+ *pcbOutBuffer = cbOutBuffer;
+ return ERROR_SUCCESS;
+
+ case 'Z': // ZLIB
+
+ return Decompress_ZLIB(pbOutBuffer, pcbOutBuffer, pbInBuffer, cbInBuffer);
+ }
+
+ assert(false);
+ return ERROR_NOT_SUPPORTED;
+}
diff --git a/dep/CascLib/src/CascDumpData.cpp b/dep/CascLib/src/CascDumpData.cpp
new file mode 100644
index 00000000000..d3871709fce
--- /dev/null
+++ b/dep/CascLib/src/CascDumpData.cpp
@@ -0,0 +1,524 @@
+/*****************************************************************************/
+/* CascDumpData.cpp Copyright (c) Ladislav Zezula 2014 */
+/*---------------------------------------------------------------------------*/
+/* System-dependent directory functions for CascLib */
+/*---------------------------------------------------------------------------*/
+/* Date Ver Who Comment */
+/* -------- ---- --- ------- */
+/* 07.05.14 1.00 Lad The first version of CascDumpData.cpp */
+/*****************************************************************************/
+
+#define __CASCLIB_SELF__
+#include "CascLib.h"
+#include "CascCommon.h"
+#include "CascMndxRoot.h"
+
+#ifdef _DEBUG // The entire file is only valid for debug purposes
+
+//-----------------------------------------------------------------------------
+// Local functions
+
+static char * StringFromIndexKey(LPBYTE md5, char * szBuffer)
+{
+ return StringFromBinary(md5, 9, szBuffer);
+}
+
+static char * StringFromMD5(LPBYTE md5, char * szBuffer)
+{
+ return StringFromBinary(md5, MD5_HASH_SIZE, szBuffer);
+}
+
+static int CompareIndexEntries_FilePos(const void *, const void * pvIndexEntry1, const void * pvIndexEntry2)
+{
+ PCASC_INDEX_ENTRY pIndexEntry1 = (PCASC_INDEX_ENTRY)pvIndexEntry1;
+ PCASC_INDEX_ENTRY pIndexEntry2 = (PCASC_INDEX_ENTRY)pvIndexEntry2;
+ ULONGLONG FileOffset1 = ConvertBytesToInteger_5(pIndexEntry1->FileOffset);
+ ULONGLONG FileOffset2 = ConvertBytesToInteger_5(pIndexEntry2->FileOffset);
+ DWORD ArchIndex1 = (DWORD)(FileOffset1 >> 0x1E);
+ DWORD ArchIndex2 = (DWORD)(FileOffset2 >> 0x1E);
+
+ // First, compare the archive index
+ if(ArchIndex1 < ArchIndex2)
+ return -1;
+ if(ArchIndex1 > ArchIndex2)
+ return +1;
+
+ // Second, compare the archive offset
+ FileOffset1 &= 0x3FFFFFFF;
+ FileOffset2 &= 0x3FFFFFFF;
+ if(FileOffset1 < FileOffset2)
+ return -1;
+ if(FileOffset1 > FileOffset2)
+ return +1;
+
+ return 0;
+}
+
+
+static char ** CreateFileNameArray(TCascStorage * hs, const TCHAR * szListFile)
+{
+ PCASC_ROOT_ENTRY pRootEntry;
+ char ** FileNameArray = NULL;
+ void * pvListFile;
+ size_t nRootIndex;
+ char szFileName1[MAX_PATH+1];
+ char szFileName2[MAX_PATH+1];
+
+ // Open the listfile stream and initialize the listfile cache
+ pvListFile = ListFile_OpenExternal(szListFile);
+ if(pvListFile != NULL)
+ {
+ // Allocate the array of file names
+ FileNameArray = CASC_ALLOC(char*, hs->nRootEntries);
+ if(FileNameArray != NULL)
+ {
+ // Zero the name array
+ memset(FileNameArray, 0, hs->nRootEntries * sizeof(char *));
+
+ // Perform search
+ while(ListFile_GetNext(pvListFile, "*", szFileName1, MAX_PATH))
+ {
+ // Create normalized name
+ strcpy(szFileName2, szFileName1);
+ NormalizeFileName_UpperBkSlash(szFileName2);
+
+ // Try to find the root entry
+ pRootEntry = FindFirstRootEntry(hs, szFileName2, &nRootIndex);
+ if(pRootEntry != NULL)
+ {
+ assert(nRootIndex < hs->nRootEntries);
+ if(FileNameArray[nRootIndex] == NULL)
+ FileNameArray[nRootIndex] = NewStr(szFileName1, 0);
+ }
+ }
+ }
+
+ // Close the listfile cache
+ ListFile_Free(pvListFile);
+ }
+
+ return FileNameArray;
+}
+
+static void FreeFileNameArray(TCascStorage * hs, char ** FileNameArray)
+{
+ if(FileNameArray != NULL)
+ {
+ // Free all sub-entries
+ for(size_t i = 0; i < hs->nRootEntries; i++)
+ {
+ if(FileNameArray[i] != NULL)
+ CASC_FREE(FileNameArray[i]);
+ }
+
+ // Free the array itself
+ CASC_FREE(FileNameArray);
+ }
+}
+
+static void DumpIndexKey(
+ FILE * fp,
+ TCascStorage * hs,
+ LPBYTE pbEncodingKey,
+ PCASC_INDEX_ENTRY * ppIndexEntries)
+{
+ PCASC_INDEX_ENTRY pIndexEntry;
+ QUERY_KEY QueryKey;
+ size_t EntryIndex = 0;
+ char szMd5[MD5_STRING_SIZE];
+
+ QueryKey.pbData = pbEncodingKey;
+ QueryKey.cbData = MD5_HASH_SIZE;
+ pIndexEntry = FindIndexEntry(hs, &QueryKey);
+ if(pIndexEntry != NULL)
+ {
+ ULONGLONG FileOffset = ConvertBytesToInteger_5(pIndexEntry->FileOffset);
+ DWORD ArchIndex = (DWORD)(FileOffset >> 0x1E);
+ DWORD FileSize = *(PDWORD)pIndexEntry->FileSize;
+
+ // Mark the index entry as dumped
+ ppIndexEntries[EntryIndex] = NULL;
+
+ // Mask the file offset
+ FileOffset &= 0x3FFFFFFF;
+ fprintf(fp, " Index: %s, ArchIdx: %02x FileOffset %08x FileSize: %lx\n",
+ StringFromIndexKey(pIndexEntry->IndexKey, szMd5),
+ ArchIndex,
+ (DWORD)FileOffset,
+ FileSize);
+ }
+ else
+ {
+ fprintf(fp, " NO INDEX ENTRY\n");
+ }
+}
+
+static void DumpEncodingEntry(
+ FILE * fp,
+ TCascStorage * hs,
+ PCASC_ENCODING_ENTRY pEncodingEntry,
+ PCASC_INDEX_ENTRY * ppIndexEntries)
+{
+ LPBYTE pbEncodingKey;
+ char szMd5[MD5_STRING_SIZE];
+
+ fprintf(fp, " Encoding Key: %s Key Count: %u Size: %lx\n",
+ StringFromMD5(pEncodingEntry->EncodingKey, szMd5),
+ pEncodingEntry->KeyCount,
+ ConvertBytesToInteger_4(pEncodingEntry->FileSizeBytes));
+
+ // If there is a file key
+ if(pEncodingEntry->KeyCount != 0)
+ {
+ // Get the first encoding key
+ pbEncodingKey = pEncodingEntry->EncodingKey + MD5_HASH_SIZE;
+
+ // Dump all encoding keys
+ for(DWORD j = 0; j < pEncodingEntry->KeyCount; j++)
+ {
+ fprintf(fp, " Index Key: %s\n", StringFromMD5(pbEncodingKey, szMd5));
+ DumpIndexKey(fp, hs, pbEncodingKey, ppIndexEntries);
+ pbEncodingKey += MD5_HASH_SIZE;
+ }
+ }
+ else
+ {
+ fprintf(fp, " ZERO FILE KEYS\n");
+ return;
+ }
+}
+
+static void DumpEncodingEntry(
+ FILE * fp,
+ TCascStorage * hs,
+ PCASC_ROOT_ENTRY pRootEntry,
+ PCASC_ENCODING_ENTRY * ppEncodingKeys,
+ PCASC_INDEX_ENTRY * ppIndexEntries)
+{
+ PCASC_ENCODING_ENTRY pEncodingKey;
+ QUERY_KEY QueryKey;
+ size_t EntryIndex = 0;
+
+ // Find the encoding key
+ QueryKey.pbData = pRootEntry->EncodingKey;
+ QueryKey.cbData = MD5_HASH_SIZE;
+ pEncodingKey = FindEncodingEntry(hs, &QueryKey, &EntryIndex);
+ if(pEncodingKey == NULL)
+ {
+ fprintf(fp, " NO ENCODING KEY\n");
+ return;
+ }
+
+ // Get the file key, clear the encoding key
+ ppEncodingKeys[EntryIndex] = NULL;
+ DumpEncodingEntry(fp, hs, pEncodingKey, ppIndexEntries);
+}
+
+static void DumpRootEntries(FILE * fp, TCascStorage * hs, char ** FileNameArray)
+{
+ PCASC_ENCODING_ENTRY * ppEncodingEntries; // Array of encoding entries
+ PCASC_INDEX_ENTRY * ppIndexEntries; // Complete list of key entries for all files
+ const char * szFileName = NULL;
+ ULONGLONG PrevNameHash = (ULONGLONG)-1;
+ char szMd5[MD5_STRING_SIZE];
+
+ // Create copy of the encoding keys and file keys
+ ppEncodingEntries = CASC_ALLOC(PCASC_ENCODING_ENTRY, hs->nEncodingEntries);
+ ppIndexEntries = CASC_ALLOC(PCASC_INDEX_ENTRY, hs->pIndexEntryMap->ItemCount);
+ if(ppEncodingEntries && ppIndexEntries)
+ {
+ // Copy all pointers
+ memcpy(ppEncodingEntries, hs->ppEncodingEntries, hs->nEncodingEntries * sizeof(PCASC_ENCODING_ENTRY));
+ Map_EnumObjects(hs->pIndexEntryMap, (void **)ppIndexEntries);
+
+ // Parse all entries
+ for(size_t i = 0; i < hs->nRootEntries; i++)
+ {
+ PCASC_ROOT_ENTRY pRootEntry = hs->ppRootEntries[i];
+ const char * szDuplicate = "";
+
+ // Check duplicates
+ if(pRootEntry->FileNameHash != PrevNameHash)
+ szFileName = FileNameArray[i];
+ else
+ szDuplicate = "(DUPLICATE) ";
+
+ // Dump the root entry
+ fprintf(fp, "NameHash: %016llx Locales: %08lx MD5: %s %sFileName: %s\n",
+ pRootEntry->FileNameHash,
+ pRootEntry->Locales,
+ StringFromMD5(pRootEntry->EncodingKey, szMd5),
+ szDuplicate,
+ szFileName);
+
+ DumpEncodingEntry(fp, hs, pRootEntry, ppEncodingEntries, ppIndexEntries);
+ PrevNameHash = pRootEntry->FileNameHash;
+ fprintf(fp, "\n");
+ }
+
+ // Dump all orphaned encoding keys
+ for(size_t i = 0; i < hs->nEncodingEntries; i++)
+ {
+ if(ppEncodingEntries[i] != NULL)
+ {
+ fprintf(fp, "[NO ROOT KEY]\n");
+
+ DumpEncodingEntry(fp, hs, ppEncodingEntries[i], ppIndexEntries);
+ ppEncodingEntries[i] = NULL;
+
+ fprintf(fp, "\n");
+ }
+ }
+
+
+ CASC_FREE(ppIndexEntries);
+ CASC_FREE(ppEncodingEntries);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Public functions
+
+void CascDumpSparseArray(const char * szFileName, void * pvSparseArray)
+{
+ TSparseArray * pSparseArray = (TSparseArray *)pvSparseArray;
+ FILE * fp;
+
+ // Create the dump file
+ fp = fopen(szFileName, "wt");
+ if(fp != NULL)
+ {
+ // Write header
+ fprintf(fp, "## Value\n-- -----\n");
+
+ // Write the values
+ for(DWORD i = 0; i < pSparseArray->TotalItemCount; i++)
+ {
+ DWORD Value = 0;
+
+ if(pSparseArray->IsItemPresent(i))
+ {
+ Value = pSparseArray->GetItemValue(i);
+ fprintf(fp, "%02X %02X\n", i, Value);
+ }
+ else
+ {
+ fprintf(fp, "%02X --\n", i);
+ }
+ }
+
+ fclose(fp);
+ }
+}
+
+void CascDumpNameFragTable(const char * szFileName, void * pMarFile)
+{
+ TFileNameDatabase * pDB = ((PMAR_FILE)pMarFile)->pDatabasePtr->pDB;
+ FILE * fp;
+
+ // Create the dump file
+ fp = fopen(szFileName, "wt");
+ if(fp != NULL)
+ {
+ PNAME_FRAG pNameTable = pDB->NameFragTable.NameFragArray;
+ const char * szNames = pDB->IndexStruct_174.NameFragments.CharArray;
+ const char * szLastEntry;
+ char szMatchType[0x100];
+
+ // Dump the table header
+ fprintf(fp, "Indx ThisHash NextHash FragOffs\n");
+ fprintf(fp, "---- -------- -------- --------\n");
+
+ // Dump all name entries
+ for(DWORD i = 0; i < pDB->NameFragTable.ItemCount; i++)
+ {
+ // Reset both match types
+ szMatchType[0] = 0;
+ szLastEntry = "";
+
+ // Only if the table entry is not empty
+ if(pNameTable->ItemIndex != 0xFFFFFFFF)
+ {
+ // Prepare the entry
+ if(IS_SINGLE_CHAR_MATCH(pDB->NameFragTable, i))
+ sprintf(szMatchType, "SINGLE_CHAR (\'%c\')", (pNameTable->FragOffs & 0xFF));
+ else
+ sprintf(szMatchType, "NAME_FRAGMT (\"%s\")", szNames + pNameTable->FragOffs);
+ }
+
+ // Dump the entry
+ fprintf(fp, "0x%02X %08x %08x %08x %s%s\n", i, pNameTable->ItemIndex,
+ pNameTable->NextIndex,
+ pNameTable->FragOffs,
+ szMatchType,
+ szLastEntry);
+ pNameTable++;
+ }
+ fclose(fp);
+ }
+}
+
+void CascDumpFileNames(const char * szFileName, void * pvMarFile)
+{
+ TMndxFindResult Struct1C;
+ PMAR_FILE pMarFile = (PMAR_FILE)pvMarFile;
+ FILE * fp;
+ char szNameBuff[0x200];
+ bool bFindResult;
+
+ // Create the dump file
+ fp = fopen(szFileName, "wt");
+ if(fp != NULL)
+ {
+ // Set an empty path as search mask (?)
+ Struct1C.SetSearchPath("", 0);
+
+ // Keep searching
+ for(;;)
+ {
+ // Search the next file name
+ pMarFile->pDatabasePtr->sub_1956CE0(&Struct1C, &bFindResult);
+
+ // Stop the search in case of failure
+ if(!bFindResult)
+ break;
+
+ // Printf the found file name
+ memcpy(szNameBuff, Struct1C.szFoundPath, Struct1C.cchFoundPath);
+ szNameBuff[Struct1C.cchFoundPath] = 0;
+ fprintf(fp, "%s\n", szNameBuff);
+ }
+
+ fclose(fp);
+ }
+
+ // Free the search structures
+ Struct1C.FreeStruct40();
+}
+
+void CascDumpMndxRoot(const char * szFileName, PCASC_MNDX_INFO pMndxInfo)
+{
+ PCASC_MNDX_ENTRY pMndxEntry;
+ FILE * fp;
+ char szMd5[MD5_STRING_SIZE];
+
+ // Create the dump file
+ fp = fopen(szFileName, "wt");
+ if(fp != NULL)
+ {
+ fprintf(fp, "Indx Fl+Asset EncodingKey FileSize\n==== ======== ================================ ========\n");
+ for(DWORD i = 0; i < pMndxInfo->MndxEntriesValid; i++)
+ {
+ pMndxEntry = pMndxInfo->ppValidEntries[i];
+
+ fprintf(fp, "%04X %08X %s %08X\n", i,
+ pMndxEntry->Flags,
+ StringFromMD5(pMndxEntry->EncodingKey, szMd5),
+ pMndxEntry->FileSize);
+ }
+ fclose(fp);
+ }
+}
+
+void CascDumpIndexEntries(const char * szFileName, TCascStorage * hs)
+{
+ PCASC_INDEX_ENTRY * ppIndexEntries;
+ FILE * fp;
+ size_t nIndexEntries = hs->pIndexEntryMap->ItemCount;
+ char szIndexKey[0x40];
+
+ // Create the dump file
+ fp = fopen(szFileName, "wt");
+ if(fp != NULL)
+ {
+ // Create linear aray
+ ppIndexEntries = CASC_ALLOC(PCASC_INDEX_ENTRY, nIndexEntries);
+ if(ppIndexEntries != NULL)
+ {
+ // Obtain the linear array of index entries
+ Map_EnumObjects(hs->pIndexEntryMap, (void **)ppIndexEntries);
+
+ // Sort the array by archive number and archive offset
+ qsort_pointer_array((void **)ppIndexEntries, nIndexEntries, CompareIndexEntries_FilePos, NULL);
+
+ // Parse the array
+ fprintf(fp, "ArNo ArOffset FileSize IndexKey\n==== ======== ======== ================================\n");
+ for(size_t i = 0; i < nIndexEntries; i++)
+ {
+ PCASC_INDEX_ENTRY pIndexEntry = ppIndexEntries[i];
+ ULONGLONG ArchOffset = ConvertBytesToInteger_5(pIndexEntry->FileOffset);
+ DWORD ArchIndex = (DWORD)(ArchOffset >> 0x1E);
+ DWORD FileSize;
+
+ FileSize = ConvertBytesToInteger_4_LE(pIndexEntry->FileSize);
+ ArchOffset &= 0x3FFFFFFF;
+
+ fprintf(fp, " %02X %08X %08X %s\n", ArchIndex, ArchOffset, FileSize, StringFromBinary(pIndexEntry->IndexKey, CASC_FILE_KEY_SIZE, szIndexKey));
+ }
+
+ CASC_FREE(ppIndexEntries);
+ }
+
+ fclose(fp);
+ }
+}
+
+void CascDumpStorage(const char * szFileName, TCascStorage * hs, const TCHAR * szListFile)
+{
+ char ** FileNameArray = NULL;
+ FILE * fp;
+
+ // Validate the storage handle
+ if(hs != NULL)
+ {
+ // Create the dump file
+ fp = fopen(szFileName, "wt");
+ if(fp != NULL)
+ {
+ // If we also have listfile, open it
+ if(szListFile != NULL)
+ FileNameArray = CreateFileNameArray(hs, szListFile);
+
+ // Dump all root keys
+ fprintf(fp, "Root Entries\n=========\n\n");
+ DumpRootEntries(fp, hs, FileNameArray);
+
+ FreeFileNameArray(hs, FileNameArray);
+ fclose(fp);
+ }
+ }
+}
+
+
+void CascDumpFile(const char * szFileName, HANDLE hFile)
+{
+ FILE * fp;
+ DWORD dwBytesRead = 1;
+ DWORD dwFilePos = CascSetFilePointer(hFile, 0, NULL, FILE_BEGIN);
+ BYTE Buffer[0x1000];
+
+ // Create the dump file
+ fp = fopen(szFileName, "wb");
+ if(fp != NULL)
+ {
+ // Read data as long as we can, write as long as we can
+ while(dwBytesRead != 0)
+ {
+ // Read from the source file
+ if(!CascReadFile(hFile, Buffer, sizeof(Buffer), &dwBytesRead))
+ break;
+
+ // Write to the destination file
+ if(fwrite(Buffer, 1, dwBytesRead, fp) != dwBytesRead)
+ break;
+ }
+
+ // Close the local file
+ fclose(fp);
+
+ // Restore the file pointer
+ CascSetFilePointer(hFile, dwFilePos, NULL, FILE_BEGIN);
+ }
+}
+
+#endif // _DEBUG
diff --git a/dep/CascLib/src/CascFindFile.cpp b/dep/CascLib/src/CascFindFile.cpp
new file mode 100644
index 00000000000..f1b14560bed
--- /dev/null
+++ b/dep/CascLib/src/CascFindFile.cpp
@@ -0,0 +1,364 @@
+/*****************************************************************************/
+/* CascFindFile.cpp Copyright (c) Ladislav Zezula 2014 */
+/*---------------------------------------------------------------------------*/
+/* System-dependent directory functions for CascLib */
+/*---------------------------------------------------------------------------*/
+/* Date Ver Who Comment */
+/* -------- ---- --- ------- */
+/* 10.05.14 1.00 Lad The first version of CascFindFile.cpp */
+/*****************************************************************************/
+
+#define __CASCLIB_SELF__
+#include "CascLib.h"
+#include "CascCommon.h"
+#include "CascMndxRoot.h"
+
+//-----------------------------------------------------------------------------
+// Local functions
+
+static TCascSearch * IsValidSearchHandle(HANDLE hFind)
+{
+ TCascSearch * pSearch = (TCascSearch *)hFind;
+
+ return (pSearch != NULL && pSearch->szClassName != NULL && !strcmp(pSearch->szClassName, "TCascSearch") && pSearch->szMask != NULL) ? pSearch : NULL;
+}
+
+static void FreeSearchHandle(TCascSearch * pSearch)
+{
+ // Only if the storage handle is valid
+ assert(pSearch != NULL);
+
+ // Close (dereference) the archive handle
+ if(pSearch->hs != NULL)
+ CascCloseStorage((HANDLE)pSearch->hs);
+ pSearch->hs = NULL;
+
+ // Free the file cache and frame array
+ if(pSearch->szMask != NULL)
+ CASC_FREE(pSearch->szMask);
+ if(pSearch->szListFile != NULL)
+ CASC_FREE(pSearch->szListFile);
+ if(pSearch->pStruct1C != NULL)
+ delete pSearch->pStruct1C;
+ if(pSearch->pCache != NULL)
+ ListFile_Free(pSearch->pCache);
+
+ // Free the structure itself
+ pSearch->szClassName = NULL;
+ CASC_FREE(pSearch);
+}
+/*
+DWORD dwRootEntries = 0;
+DWORD dwEncoEntries = 0;
+DWORD dwIndexEntries = 0;
+*/
+static bool VerifyRootEntry(TCascSearch * pSearch, PCASC_ROOT_ENTRY pRootEntry, PCASC_FIND_DATA pFindData, size_t nRootIndex)
+{
+ PCASC_ENCODING_ENTRY pEncodingEntry;
+ PCASC_INDEX_ENTRY pIndexEntry;
+ TCascStorage * hs = pSearch->hs;
+ QUERY_KEY QueryKey;
+ DWORD dwByteIndex = (DWORD)(nRootIndex / 0x08);
+ DWORD dwBitIndex = (DWORD)(nRootIndex & 0x07);
+
+ // First of all, check if that entry has been reported before
+ // If the bit is set, then the file has already been reported
+ // by a previous search iteration
+ if(pSearch->BitArray[dwByteIndex] & (1 << dwBitIndex))
+ return false;
+ pSearch->BitArray[dwByteIndex] |= (1 << dwBitIndex);
+
+ // Increment the number of root entries
+// dwRootEntries++;
+
+ // Now try to find that encoding key in the array of encoding keys
+ QueryKey.pbData = pRootEntry->EncodingKey;
+ QueryKey.cbData = MD5_HASH_SIZE;
+ pEncodingEntry = FindEncodingEntry(hs, &QueryKey, NULL);
+ if(pEncodingEntry == NULL)
+ return false;
+
+// dwEncoEntries++;
+
+ // Now try to find the index entry. Note that we take the first key
+ QueryKey.pbData = pEncodingEntry->EncodingKey + MD5_HASH_SIZE;
+ QueryKey.cbData = MD5_HASH_SIZE;
+ pIndexEntry = FindIndexEntry(hs, &QueryKey);
+ if(pIndexEntry == NULL)
+ return false;
+
+// dwIndexEntries++;
+
+ // Fill the name hash and the MD5
+ memcpy(pFindData->EncodingKey, pRootEntry->EncodingKey, MD5_HASH_SIZE);
+ pFindData->FileNameHash = pRootEntry->FileNameHash;
+ pFindData->dwPackageIndex = 0;
+ pFindData->dwLocaleFlags = pRootEntry->Locales;
+ pFindData->dwFileSize = ConvertBytesToInteger_4(pEncodingEntry->FileSizeBytes);
+ return true;
+}
+
+static TCascSearch * AllocateSearchHandle(TCascStorage * hs, const TCHAR * szListFile, const char * szMask)
+{
+ TCascSearch * pSearch;
+ size_t cbToAllocate;
+
+ // When using the MNDX info, do not allocate the extra bit array
+ cbToAllocate = sizeof(TCascSearch) + ((hs->pMndxInfo == NULL) ? (hs->nRootEntries / 8) : 0);
+ pSearch = (TCascSearch *)CASC_ALLOC(BYTE, cbToAllocate);
+ if(pSearch != NULL)
+ {
+ // Initialize the structure
+ memset(pSearch, 0, cbToAllocate);
+ pSearch->szClassName = "TCascSearch";
+
+ // Save the search handle
+ pSearch->hs = hs;
+ hs->dwRefCount++;
+
+ // If the mask was not given, use default
+ if(szMask == NULL)
+ szMask = "*";
+
+ // Save the other variables
+ if(szListFile != NULL)
+ {
+ pSearch->szListFile = NewStr(szListFile, 0);
+ if(pSearch->szListFile == NULL)
+ {
+ FreeSearchHandle(pSearch);
+ return NULL;
+ }
+ }
+
+ // Allocate the search mask
+ pSearch->szMask = NewStr(szMask, 0);
+ if(pSearch->szMask == NULL)
+ {
+ FreeSearchHandle(pSearch);
+ return NULL;
+ }
+ }
+
+ return pSearch;
+}
+
+static bool DoStorageSearch_ListFile(TCascSearch * pSearch, PCASC_FIND_DATA pFindData)
+{
+ PCASC_ROOT_ENTRY pRootEntry;
+ TCascStorage * hs = pSearch->hs;
+ size_t RootIndex;
+
+ for(;;)
+ {
+ // Shall we get a new file name from the listfile?
+ if(pSearch->FileNameHash == 0)
+ {
+ // Try to get next file from the listfile
+ if(!ListFile_GetNext(pSearch->pCache, pSearch->szMask, pSearch->szFileName, MAX_PATH))
+ break;
+
+// if(!_stricmp(pSearch->szFileName, "Interface\\Glues\\MODELS\\UI_MainMenu_Warlords\\Caustic_MedFreq.blp"))
+// DebugBreak();
+
+ // Normalize the file name
+ strcpy(pSearch->szNormName, pSearch->szFileName);
+ NormalizeFileName_UpperBkSlash(pSearch->szNormName);
+
+ // Find the first root entry belonging to this file name
+ pRootEntry = FindFirstRootEntry(pSearch->hs, pSearch->szNormName, &RootIndex);
+ if(pRootEntry == NULL)
+ continue;
+
+ // We have the name now, search all locales
+ pSearch->FileNameHash = pRootEntry->FileNameHash;
+ pSearch->RootIndex = RootIndex;
+ }
+
+ // Is the root index in range?
+ while(pSearch->RootIndex < hs->nRootEntries)
+ {
+ // Get the next root entry. If name mismatches, stop searching
+ pRootEntry = hs->ppRootEntries[pSearch->RootIndex];
+ if(pRootEntry->FileNameHash != pSearch->FileNameHash)
+ break;
+
+ // Verify whether the file exists in the storage
+ if(VerifyRootEntry(pSearch, pRootEntry, pFindData, pSearch->RootIndex++))
+ {
+ strcpy(pFindData->szFileName, pSearch->szFileName);
+ pFindData->szPlainName = (char *)GetPlainFileName(pFindData->szFileName);
+ return true;
+ }
+ }
+
+ // Reset the name hash and root index and retry search
+ pSearch->FileNameHash = 0;
+ }
+
+ // Listfile search ended
+ return false;
+}
+
+static bool DoStorageSearch_Hash(TCascSearch * pSearch, PCASC_FIND_DATA pFindData)
+{
+ PCASC_ROOT_ENTRY pRootEntry;
+ TCascStorage * hs = pSearch->hs;
+
+ // Check if there is more files with the same name hash
+ while(pSearch->RootIndex < hs->nRootEntries)
+ {
+ // Get the pointer to the root entry
+ pRootEntry = hs->ppRootEntries[pSearch->RootIndex];
+
+ // Verify if that root entry exists in the CASC storage
+ // Note that the file name will be there from the previous search
+ if(VerifyRootEntry(pSearch, pRootEntry, pFindData, pSearch->RootIndex))
+ {
+ pFindData->szFileName[0] = 0;
+ pFindData->szPlainName = NULL;
+ return true;
+ }
+
+ // Move to the next entry
+ pSearch->RootIndex++;
+ }
+
+ // Nameless search ended
+ return false;
+}
+
+static bool DoStorageSearch(TCascSearch * pSearch, PCASC_FIND_DATA pFindData)
+{
+ // Are we searching using the MNDX ?
+ if(pSearch->hs->pMndxInfo != NULL)
+ return DoStorageSearch_MNDX(pSearch, pFindData);
+
+ // State 0: No search done yet
+ if(pSearch->dwState == 0)
+ {
+ // Does the search specify listfile?
+ if(pSearch->szListFile != NULL)
+ pSearch->pCache = ListFile_OpenExternal(pSearch->szListFile);
+
+ // Move the search phase to the listfile searching
+ pSearch->FileNameHash = 0;
+ pSearch->RootIndex = 0;
+ pSearch->dwState++;
+
+ // If either file stream or listfile cache are invalid,
+ // move to the next phase
+ if(pSearch->pCache == NULL)
+ pSearch->dwState++;
+ }
+
+ // State 1: Searching the list file
+ if(pSearch->dwState == 1)
+ {
+ if(DoStorageSearch_ListFile(pSearch, pFindData))
+ return true;
+
+ // Move to the nameless search state
+ pSearch->RootIndex = 0;
+ pSearch->dwState++;
+ }
+
+ // State 2: Searching the remaining entries
+ if(pSearch->dwState == 2)
+ {
+ if(DoStorageSearch_Hash(pSearch, pFindData))
+ return true;
+
+ // Move to the final search state
+ pSearch->dwState++;
+ }
+
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Public functions
+
+HANDLE WINAPI CascFindFirstFile(
+ HANDLE hStorage,
+ const char * szMask,
+ PCASC_FIND_DATA pFindData,
+ const TCHAR * szListFile)
+{
+ TCascStorage * hs;
+ TCascSearch * pSearch = NULL;
+ int nError = ERROR_SUCCESS;
+
+ // Check parameters
+ if((hs = IsValidStorageHandle(hStorage)) == NULL)
+ nError = ERROR_INVALID_HANDLE;
+ if(szMask == NULL || pFindData == NULL)
+ nError = ERROR_INVALID_PARAMETER;
+
+ // Allocate the structure for archive search
+ if(nError == ERROR_SUCCESS)
+ {
+ // Clear the entire search structure
+ memset(pFindData, 0, sizeof(CASC_FIND_DATA));
+
+ // We must have listfile for non-MNDX storages
+ if(hs->pMndxInfo == NULL && szListFile == NULL)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return NULL;
+ }
+
+ // Allocate the search handle
+ pSearch = AllocateSearchHandle(hs, szListFile, szMask);
+ if(pSearch == NULL)
+ nError = ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ // Perform search
+ if(nError == ERROR_SUCCESS)
+ {
+ if(!DoStorageSearch(pSearch, pFindData))
+ nError = ERROR_NO_MORE_FILES;
+ }
+
+ if(nError != ERROR_SUCCESS)
+ {
+ if(pSearch != NULL)
+ FreeSearchHandle(pSearch);
+ pSearch = NULL;
+ }
+
+ return (HANDLE)pSearch;
+}
+
+bool WINAPI CascFindNextFile(
+ HANDLE hFind,
+ PCASC_FIND_DATA pFindData)
+{
+ TCascSearch * pSearch;
+
+ pSearch = IsValidSearchHandle(hFind);
+ if(pSearch == NULL || pFindData == NULL)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return false;
+ }
+
+ // Perform search
+ return DoStorageSearch(pSearch, pFindData);
+}
+
+bool WINAPI CascFindClose(HANDLE hFind)
+{
+ TCascSearch * pSearch;
+
+ pSearch = IsValidSearchHandle(hFind);
+ if(pSearch == NULL)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return false;
+ }
+
+ FreeSearchHandle(pSearch);
+ return true;
+}
diff --git a/dep/CascLib/src/CascLib.h b/dep/CascLib/src/CascLib.h
new file mode 100644
index 00000000000..a3960a558c2
--- /dev/null
+++ b/dep/CascLib/src/CascLib.h
@@ -0,0 +1,171 @@
+/*****************************************************************************/
+/* CascLib.h Copyright (c) Ladislav Zezula 2014 */
+/*---------------------------------------------------------------------------*/
+/* CascLib library v 1.00 */
+/* */
+/* Author : Ladislav Zezula */
+/* E-mail : ladik@zezula.net */
+/* WWW : http://www.zezula.net */
+/*---------------------------------------------------------------------------*/
+/* Date Ver Who Comment */
+/* -------- ---- --- ------- */
+/* 29.04.14 1.00 Lad Created */
+/*****************************************************************************/
+
+#ifndef __CASCLIB_H__
+#define __CASCLIB_H__
+
+#ifdef _MSC_VER
+#pragma warning(disable:4668) // 'XXX' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif'
+#pragma warning(disable:4820) // 'XXX' : '2' bytes padding added after data member 'XXX::yyy'
+#endif
+
+#include "CascPort.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//-----------------------------------------------------------------------------
+// Defines
+
+#define CASCLIB_VERSION 0x0100 // Current version of CascLib (1.0)
+#define CASCLIB_VERSION_STRING "1.00" // String version of CascLib version
+
+#define ERROR_UNKNOWN_FILE_KEY 10001 // Returned by encrypted stream when can't find file key
+#define ERROR_FILE_INCOMPLETE 10006 // The required file part is missing
+
+// Values for CascOpenStorage
+#define CASC_STOR_XXXXX 0x00000001 // Not used
+
+// Values for CascOpenFile
+#define CASC_FILE_XXXXX 0x00000001 // Not used
+
+// Flags for file stream
+#define BASE_PROVIDER_FILE 0x00000000 // Base data source is a file
+#define BASE_PROVIDER_MAP 0x00000001 // Base data source is memory-mapped file
+#define BASE_PROVIDER_HTTP 0x00000002 // Base data source is a file on web server
+#define BASE_PROVIDER_MASK 0x0000000F // Mask for base provider value
+
+#define STREAM_PROVIDER_FLAT 0x00000000 // Stream is linear with no offset mapping
+#define STREAM_PROVIDER_PARTIAL 0x00000010 // Stream is partial file (.part)
+#define STREAM_PROVIDER_ENCRYPTED 0x00000020 // Stream is an encrypted archive
+#define STREAM_PROVIDER_BLOCK4 0x00000030 // 0x4000 per block, text MD5 after each block, max 0x2000 blocks per file
+#define STREAM_PROVIDER_MASK 0x000000F0 // Mask for stream provider value
+
+#define STREAM_FLAG_READ_ONLY 0x00000100 // Stream is read only
+#define STREAM_FLAG_WRITE_SHARE 0x00000200 // Allow write sharing when open for write
+#define STREAM_FLAG_USE_BITMAP 0x00000400 // If the file has a file bitmap, load it and use it
+#define STREAM_OPTIONS_MASK 0x0000FF00 // Mask for stream options
+
+#define STREAM_PROVIDERS_MASK 0x000000FF // Mask to get stream providers
+#define STREAM_FLAGS_MASK 0x0000FFFF // Mask for all stream flags (providers+options)
+
+#define CASC_LOCALE_ALL 0xFFFFFFFF
+#define CASC_LOCALE_NONE 0x00000000
+#define CASC_LOCALE_UNKNOWN1 0x00000001
+#define CASC_LOCALE_ENUS 0x00000002
+#define CASC_LOCALE_KOKR 0x00000004
+#define CASC_LOCALE_UNKNOWN8 0x00000008
+#define CASC_LOCALE_FRFR 0x00000010
+#define CASC_LOCALE_DEDE 0x00000020
+#define CASC_LOCALE_ZHCN 0x00000040
+#define CASC_LOCALE_ESES 0x00000080
+#define CASC_LOCALE_ZHTW 0x00000100
+#define CASC_LOCALE_ENGB 0x00000200
+#define CASC_LOCALE_ENCN 0x00000400
+#define CASC_LOCALE_ENTW 0x00000800
+#define CASC_LOCALE_ESMX 0x00001000
+#define CASC_LOCALE_RURU 0x00002000
+#define CASC_LOCALE_PTBR 0x00004000
+#define CASC_LOCALE_ITIT 0x00008000
+#define CASC_LOCALE_PTPT 0x00010000
+
+#define MAX_CASC_KEY_LENGTH 0x10 // Maximum length of the key (equal to MD5 hash)
+
+#ifndef MD5_HASH_SIZE
+#define MD5_HASH_SIZE 0x10
+#define MD5_STRING_SIZE 0x21
+#endif
+
+#ifndef SHA1_DIGEST_SIZE
+#define SHA1_DIGEST_SIZE 0x14 // 160 bits
+#endif
+
+#ifndef LANG_NEUTRAL
+#define LANG_NEUTRAL 0x00 // Neutral locale
+#endif
+
+// Return value for CascGetFileSize and CascSetFilePointer
+#define CASC_INVALID_SIZE 0xFFFFFFFF
+#define CASC_INVALID_POS 0xFFFFFFFF
+
+// Flags for CascGetStorageInfo
+#define CASC_FEATURE_LISTFILE 0x00000001 // The storage supports listfile
+
+//-----------------------------------------------------------------------------
+// Structures
+
+typedef enum _CASC_STORAGE_INFO_CLASS
+{
+ CascStorageFileCount,
+ CascStorageFeatures,
+ CascStorageInfoClassMax
+
+} CASC_STORAGE_INFO_CLASS, *PCASC_STORAGE_INFO_CLASS;
+
+
+typedef struct _QUERY_KEY
+{
+ LPBYTE pbData;
+ DWORD cbData;
+} QUERY_KEY, *PQUERY_KEY;
+
+// Structure for SFileFindFirstFile and SFileFindNextFile
+typedef struct _CASC_FIND_DATA
+{
+ char szFileName[MAX_PATH]; // Full name of the found file
+ char * szPlainName; // Plain name of the found file
+ ULONGLONG FileNameHash; // File name hash
+ BYTE EncodingKey[MD5_HASH_SIZE]; // Encoding key
+ DWORD dwPackageIndex; // File package index (HOTS only)
+ DWORD dwLocaleFlags; // Locale flags (WoW only)
+ DWORD dwFileSize; // Size of the file
+
+} CASC_FIND_DATA, *PCASC_FIND_DATA;
+
+//-----------------------------------------------------------------------------
+// Callback functions
+
+typedef struct TFileStream TFileStream;
+typedef void (WINAPI * STREAM_DOWNLOAD_CALLBACK)(void * pvUserData, ULONGLONG ByteOffset, DWORD dwTotalBytes);
+
+//-----------------------------------------------------------------------------
+// We have our own qsort implementation, optimized for sorting array of pointers
+
+void qsort_pointer_array(void ** base, size_t num, int (*compare)(const void *, const void *, const void *), const void * context);
+
+//-----------------------------------------------------------------------------
+// Functions for storage manipulation
+
+bool WINAPI CascOpenStorage(const TCHAR * szDataPath, DWORD dwFlags, HANDLE * phStorage);
+bool WINAPI CascGetStorageInfo(HANDLE hStorage, CASC_STORAGE_INFO_CLASS InfoClass, void * pvStorageInfo, size_t cbStorageInfo, size_t * pcbLengthNeeded);
+bool WINAPI CascCloseStorage(HANDLE hStorage);
+
+bool WINAPI CascOpenFileByIndexKey(HANDLE hStorage, PQUERY_KEY pIndexKey, DWORD dwFlags, HANDLE * phFile);
+bool WINAPI CascOpenFileByEncodingKey(HANDLE hStorage, PQUERY_KEY pEncodingKey, DWORD dwFlags, HANDLE * phFile);
+bool WINAPI CascOpenFile(HANDLE hStorage, const char * szFileName, DWORD dwLocale, DWORD dwFlags, HANDLE * phFile);
+DWORD WINAPI CascGetFileSize(HANDLE hFile, PDWORD pdwFileSizeHigh);
+DWORD WINAPI CascSetFilePointer(HANDLE hFile, LONG lFilePos, LONG * plFilePosHigh, DWORD dwMoveMethod);
+bool WINAPI CascReadFile(HANDLE hFile, void * lpBuffer, DWORD dwToRead, PDWORD pdwRead);
+bool WINAPI CascCloseFile(HANDLE hFile);
+
+HANDLE WINAPI CascFindFirstFile(HANDLE hStorage, const char * szMask, PCASC_FIND_DATA pFindData, const TCHAR * szListFile);
+bool WINAPI CascFindNextFile(HANDLE hFind, PCASC_FIND_DATA pFindData);
+bool WINAPI CascFindClose(HANDLE hFind);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // __CASCLIB_H__
diff --git a/dep/CascLib/src/CascMndxRoot.cpp b/dep/CascLib/src/CascMndxRoot.cpp
new file mode 100644
index 00000000000..a788b652573
--- /dev/null
+++ b/dep/CascLib/src/CascMndxRoot.cpp
@@ -0,0 +1,3476 @@
+/*****************************************************************************/
+/* CascMndxRoot.cpp Copyright (c) Ladislav Zezula 2014 */
+/*---------------------------------------------------------------------------*/
+/* Common functions for CascLib */
+/* Note: "HOTS" refers to Play.exe, v2.5.0.29049 (Heroes of the Storm Alpha) */
+/*---------------------------------------------------------------------------*/
+/* Date Ver Who Comment */
+/* -------- ---- --- ------- */
+/* 18.05.14 1.00 Lad The first version of CascMndxRoot.cpp */
+/*****************************************************************************/
+
+#define __CASCLIB_SELF__
+#include "CascLib.h"
+#include "CascCommon.h"
+#include "CascMndxRoot.h"
+
+//-----------------------------------------------------------------------------
+// Local defines
+
+#define CASC_MAR_SIGNATURE 0x0052414d // 'MAR\0'
+
+//-----------------------------------------------------------------------------
+// Local structures
+
+typedef struct _FILE_MNDX_HEADER
+{
+ DWORD Signature; // 'MNDX'
+ DWORD HeaderVersion; // Must be <= 2
+ DWORD FormatVersion;
+
+} FILE_MNDX_HEADER, *PFILE_MNDX_HEADER;
+
+typedef struct _FILE_MAR_INFO
+{
+ DWORD MarIndex;
+ DWORD MarDataSize;
+ DWORD MarDataSizeHi;
+ DWORD MarDataOffset;
+ DWORD MarDataOffsetHi;
+} FILE_MAR_INFO, *PFILE_MAR_INFO;
+
+//-----------------------------------------------------------------------------
+// Testing functions prototypes
+
+#if defined(_DEBUG) && defined(_X86_) && defined(CASCLIB_TEST)
+extern "C" bool _cdecl sub_1958B00_x86(TFileNameDatabase * pDB, TMndxFindResult * pStruct1C);
+void TestMndxRootFile(PCASC_MNDX_INFO pMndxInfo);
+#endif
+
+//-----------------------------------------------------------------------------
+// Local variables
+
+unsigned char table_1BA1818[0x800] =
+{
+ 0x07, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00,
+ 0x04, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00,
+ 0x05, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00,
+ 0x04, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00,
+ 0x06, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00,
+ 0x04, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00,
+ 0x05, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00,
+ 0x04, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00,
+ 0x07, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00,
+ 0x04, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00,
+ 0x05, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00,
+ 0x04, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00,
+ 0x06, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00,
+ 0x04, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00,
+ 0x05, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00,
+ 0x04, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00,
+ 0x07, 0x07, 0x07, 0x01, 0x07, 0x02, 0x02, 0x01, 0x07, 0x03, 0x03, 0x01, 0x03, 0x02, 0x02, 0x01,
+ 0x07, 0x04, 0x04, 0x01, 0x04, 0x02, 0x02, 0x01, 0x04, 0x03, 0x03, 0x01, 0x03, 0x02, 0x02, 0x01,
+ 0x07, 0x05, 0x05, 0x01, 0x05, 0x02, 0x02, 0x01, 0x05, 0x03, 0x03, 0x01, 0x03, 0x02, 0x02, 0x01,
+ 0x05, 0x04, 0x04, 0x01, 0x04, 0x02, 0x02, 0x01, 0x04, 0x03, 0x03, 0x01, 0x03, 0x02, 0x02, 0x01,
+ 0x07, 0x06, 0x06, 0x01, 0x06, 0x02, 0x02, 0x01, 0x06, 0x03, 0x03, 0x01, 0x03, 0x02, 0x02, 0x01,
+ 0x06, 0x04, 0x04, 0x01, 0x04, 0x02, 0x02, 0x01, 0x04, 0x03, 0x03, 0x01, 0x03, 0x02, 0x02, 0x01,
+ 0x06, 0x05, 0x05, 0x01, 0x05, 0x02, 0x02, 0x01, 0x05, 0x03, 0x03, 0x01, 0x03, 0x02, 0x02, 0x01,
+ 0x05, 0x04, 0x04, 0x01, 0x04, 0x02, 0x02, 0x01, 0x04, 0x03, 0x03, 0x01, 0x03, 0x02, 0x02, 0x01,
+ 0x07, 0x07, 0x07, 0x01, 0x07, 0x02, 0x02, 0x01, 0x07, 0x03, 0x03, 0x01, 0x03, 0x02, 0x02, 0x01,
+ 0x07, 0x04, 0x04, 0x01, 0x04, 0x02, 0x02, 0x01, 0x04, 0x03, 0x03, 0x01, 0x03, 0x02, 0x02, 0x01,
+ 0x07, 0x05, 0x05, 0x01, 0x05, 0x02, 0x02, 0x01, 0x05, 0x03, 0x03, 0x01, 0x03, 0x02, 0x02, 0x01,
+ 0x05, 0x04, 0x04, 0x01, 0x04, 0x02, 0x02, 0x01, 0x04, 0x03, 0x03, 0x01, 0x03, 0x02, 0x02, 0x01,
+ 0x07, 0x06, 0x06, 0x01, 0x06, 0x02, 0x02, 0x01, 0x06, 0x03, 0x03, 0x01, 0x03, 0x02, 0x02, 0x01,
+ 0x06, 0x04, 0x04, 0x01, 0x04, 0x02, 0x02, 0x01, 0x04, 0x03, 0x03, 0x01, 0x03, 0x02, 0x02, 0x01,
+ 0x06, 0x05, 0x05, 0x01, 0x05, 0x02, 0x02, 0x01, 0x05, 0x03, 0x03, 0x01, 0x03, 0x02, 0x02, 0x01,
+ 0x05, 0x04, 0x04, 0x01, 0x04, 0x02, 0x02, 0x01, 0x04, 0x03, 0x03, 0x01, 0x03, 0x02, 0x02, 0x01,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x02, 0x07, 0x07, 0x07, 0x03, 0x07, 0x03, 0x03, 0x02,
+ 0x07, 0x07, 0x07, 0x04, 0x07, 0x04, 0x04, 0x02, 0x07, 0x04, 0x04, 0x03, 0x04, 0x03, 0x03, 0x02,
+ 0x07, 0x07, 0x07, 0x05, 0x07, 0x05, 0x05, 0x02, 0x07, 0x05, 0x05, 0x03, 0x05, 0x03, 0x03, 0x02,
+ 0x07, 0x05, 0x05, 0x04, 0x05, 0x04, 0x04, 0x02, 0x05, 0x04, 0x04, 0x03, 0x04, 0x03, 0x03, 0x02,
+ 0x07, 0x07, 0x07, 0x06, 0x07, 0x06, 0x06, 0x02, 0x07, 0x06, 0x06, 0x03, 0x06, 0x03, 0x03, 0x02,
+ 0x07, 0x06, 0x06, 0x04, 0x06, 0x04, 0x04, 0x02, 0x06, 0x04, 0x04, 0x03, 0x04, 0x03, 0x03, 0x02,
+ 0x07, 0x06, 0x06, 0x05, 0x06, 0x05, 0x05, 0x02, 0x06, 0x05, 0x05, 0x03, 0x05, 0x03, 0x03, 0x02,
+ 0x06, 0x05, 0x05, 0x04, 0x05, 0x04, 0x04, 0x02, 0x05, 0x04, 0x04, 0x03, 0x04, 0x03, 0x03, 0x02,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x02, 0x07, 0x07, 0x07, 0x03, 0x07, 0x03, 0x03, 0x02,
+ 0x07, 0x07, 0x07, 0x04, 0x07, 0x04, 0x04, 0x02, 0x07, 0x04, 0x04, 0x03, 0x04, 0x03, 0x03, 0x02,
+ 0x07, 0x07, 0x07, 0x05, 0x07, 0x05, 0x05, 0x02, 0x07, 0x05, 0x05, 0x03, 0x05, 0x03, 0x03, 0x02,
+ 0x07, 0x05, 0x05, 0x04, 0x05, 0x04, 0x04, 0x02, 0x05, 0x04, 0x04, 0x03, 0x04, 0x03, 0x03, 0x02,
+ 0x07, 0x07, 0x07, 0x06, 0x07, 0x06, 0x06, 0x02, 0x07, 0x06, 0x06, 0x03, 0x06, 0x03, 0x03, 0x02,
+ 0x07, 0x06, 0x06, 0x04, 0x06, 0x04, 0x04, 0x02, 0x06, 0x04, 0x04, 0x03, 0x04, 0x03, 0x03, 0x02,
+ 0x07, 0x06, 0x06, 0x05, 0x06, 0x05, 0x05, 0x02, 0x06, 0x05, 0x05, 0x03, 0x05, 0x03, 0x03, 0x02,
+ 0x06, 0x05, 0x05, 0x04, 0x05, 0x04, 0x04, 0x02, 0x05, 0x04, 0x04, 0x03, 0x04, 0x03, 0x03, 0x02,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x03,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x04, 0x07, 0x07, 0x07, 0x04, 0x07, 0x04, 0x04, 0x03,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x07, 0x07, 0x07, 0x05, 0x07, 0x05, 0x05, 0x03,
+ 0x07, 0x07, 0x07, 0x05, 0x07, 0x05, 0x05, 0x04, 0x07, 0x05, 0x05, 0x04, 0x05, 0x04, 0x04, 0x03,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06, 0x07, 0x07, 0x07, 0x06, 0x07, 0x06, 0x06, 0x03,
+ 0x07, 0x07, 0x07, 0x06, 0x07, 0x06, 0x06, 0x04, 0x07, 0x06, 0x06, 0x04, 0x06, 0x04, 0x04, 0x03,
+ 0x07, 0x07, 0x07, 0x06, 0x07, 0x06, 0x06, 0x05, 0x07, 0x06, 0x06, 0x05, 0x06, 0x05, 0x05, 0x03,
+ 0x07, 0x06, 0x06, 0x05, 0x06, 0x05, 0x05, 0x04, 0x06, 0x05, 0x05, 0x04, 0x05, 0x04, 0x04, 0x03,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x03,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x04, 0x07, 0x07, 0x07, 0x04, 0x07, 0x04, 0x04, 0x03,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x07, 0x07, 0x07, 0x05, 0x07, 0x05, 0x05, 0x03,
+ 0x07, 0x07, 0x07, 0x05, 0x07, 0x05, 0x05, 0x04, 0x07, 0x05, 0x05, 0x04, 0x05, 0x04, 0x04, 0x03,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06, 0x07, 0x07, 0x07, 0x06, 0x07, 0x06, 0x06, 0x03,
+ 0x07, 0x07, 0x07, 0x06, 0x07, 0x06, 0x06, 0x04, 0x07, 0x06, 0x06, 0x04, 0x06, 0x04, 0x04, 0x03,
+ 0x07, 0x07, 0x07, 0x06, 0x07, 0x06, 0x06, 0x05, 0x07, 0x06, 0x06, 0x05, 0x06, 0x05, 0x05, 0x03,
+ 0x07, 0x06, 0x06, 0x05, 0x06, 0x05, 0x05, 0x04, 0x06, 0x05, 0x05, 0x04, 0x05, 0x04, 0x04, 0x03,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x04,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x05,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x07, 0x07, 0x07, 0x05, 0x07, 0x05, 0x05, 0x04,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06, 0x07, 0x07, 0x07, 0x06, 0x07, 0x06, 0x06, 0x04,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06, 0x07, 0x07, 0x07, 0x06, 0x07, 0x06, 0x06, 0x05,
+ 0x07, 0x07, 0x07, 0x06, 0x07, 0x06, 0x06, 0x05, 0x07, 0x06, 0x06, 0x05, 0x06, 0x05, 0x05, 0x04,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x04,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x05,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x07, 0x07, 0x07, 0x05, 0x07, 0x05, 0x05, 0x04,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06, 0x07, 0x07, 0x07, 0x06, 0x07, 0x06, 0x06, 0x04,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06, 0x07, 0x07, 0x07, 0x06, 0x07, 0x06, 0x06, 0x05,
+ 0x07, 0x07, 0x07, 0x06, 0x07, 0x06, 0x06, 0x05, 0x07, 0x06, 0x06, 0x05, 0x06, 0x05, 0x05, 0x04,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x05,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06, 0x07, 0x07, 0x07, 0x06, 0x07, 0x06, 0x06, 0x05,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x05,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06, 0x07, 0x07, 0x07, 0x06, 0x07, 0x06, 0x06, 0x05,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07
+};
+
+//-----------------------------------------------------------------------------
+// Local functions - Number of set bits in an integer
+
+// HOTS: inlined
+DWORD GetNumberOfSetBits(DWORD Value32)
+{
+ Value32 = ((Value32 >> 1) & 0x55555555) + (Value32 & 0x55555555);
+ Value32 = ((Value32 >> 2) & 0x33333333) + (Value32 & 0x33333333);
+ Value32 = ((Value32 >> 4) & 0x0F0F0F0F) + (Value32 & 0x0F0F0F0F);
+
+ return (Value32 * 0x01010101);
+}
+
+#define GetNumbrOfSetBits32(x) (GetNumberOfSetBits(x) >> 0x18)
+
+//-----------------------------------------------------------------------------
+// Local functions - common
+
+static bool RootFileRead(LPBYTE pbFilePointer, LPBYTE pbFileEnd, void * pvBuffer, size_t dwBytesToRead)
+{
+ if((size_t)(pbFileEnd - pbFilePointer) < dwBytesToRead)
+ return false;
+
+ memcpy(pvBuffer, pbFilePointer, dwBytesToRead);
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Local functions - TMndxFindResult
+
+// HOTS: 01956EE0
+TMndxFindResult::TMndxFindResult()
+{
+ szSearchMask = NULL;
+ cchSearchMask = 0;
+ field_8 = 0;
+ szFoundPath = NULL;
+ cchFoundPath = 0;
+ FileNameIndex = 0;
+ pStruct40 = NULL;
+}
+
+// HOTS: 01956F00
+TMndxFindResult::~TMndxFindResult()
+{
+ FreeStruct40();
+}
+
+// HOTS: 01956F30
+int TMndxFindResult::CreateStruct40()
+{
+ if(pStruct40 != NULL)
+ return ERROR_INVALID_PARAMETER;
+
+ pStruct40 = new TStruct40();
+ return (pStruct40 != NULL) ? ERROR_SUCCESS : ERROR_NOT_ENOUGH_MEMORY;
+}
+
+void TMndxFindResult::FreeStruct40()
+{
+ if(pStruct40 != NULL)
+ delete pStruct40;
+ pStruct40 = NULL;
+}
+
+// HOTS: 01956E70
+int TMndxFindResult::SetSearchPath(
+ const char * szNewSearchMask,
+ size_t cchNewSearchMask)
+{
+ if(szSearchMask == NULL && cchSearchMask != 0)
+ return ERROR_INVALID_PARAMETER;
+
+ if(pStruct40 != NULL)
+ pStruct40->SearchPhase = CASC_SEARCH_INITIALIZING;
+
+ szSearchMask = szNewSearchMask;
+ cchSearchMask = cchNewSearchMask;
+ return ERROR_SUCCESS;
+}
+
+//-----------------------------------------------------------------------------
+// TByteStream functions
+
+// HOTS: 01959990
+TByteStream::TByteStream()
+{
+ pbByteData = NULL;
+ pvMappedFile = NULL;
+ cbByteData = 0;
+ field_C = 0;
+ hFile = 0;
+ hMap = 0;
+}
+
+// HOTS: 19599F0
+void TByteStream::ExchangeWith(TByteStream & Target)
+{
+ TByteStream WorkBuff;
+
+ WorkBuff = *this;
+ *this = Target;
+ Target = WorkBuff;
+}
+
+// HOTS: 19599F0
+int TByteStream::GetBytes(DWORD cbByteCount, PARRAY_POINTER PtrArray)
+{
+ if(cbByteData < cbByteCount)
+ return ERROR_BAD_FORMAT;
+
+ // Give the buffer to the caller
+ PtrArray->Bytes = pbByteData;
+
+ // Move pointers
+ pbByteData += cbByteCount;
+ cbByteData -= cbByteCount;
+ return ERROR_SUCCESS;
+}
+
+// HOTS: 1957190
+int TByteStream::GetArray_DWORDs(PARRAY_POINTER PtrArray, DWORD ItemCount)
+{
+ if(PtrArray == NULL && ItemCount != 0)
+ return ERROR_INVALID_PARAMETER;
+ if(ItemCount > CASC_MAX_ENTRIES(DWORD))
+ return ERROR_NOT_ENOUGH_MEMORY;
+
+ return GetBytes(ItemCount * 4, PtrArray);
+}
+
+// HOTS: 19571E0
+int TByteStream::GetArray_Triplets(PARRAY_POINTER PtrArray, DWORD ItemCount)
+{
+ if(PtrArray == NULL && ItemCount != 0)
+ return ERROR_INVALID_PARAMETER;
+ if(ItemCount > CASC_MAX_ENTRIES(TRIPLET))
+ return ERROR_NOT_ENOUGH_MEMORY;
+
+ return GetBytes(ItemCount * sizeof(TRIPLET), PtrArray);
+}
+
+// HOTS: 1957230
+int TByteStream::GetArray_BYTES(PARRAY_POINTER PtrArray, DWORD ItemCount)
+{
+ if(PtrArray == NULL && ItemCount != 0)
+ return ERROR_INVALID_PARAMETER;
+ if(ItemCount > CASC_MAX_ENTRIES(BYTE))
+ return ERROR_NOT_ENOUGH_MEMORY;
+
+ return GetBytes(ItemCount, PtrArray);
+}
+
+// HOTS: 1957280
+int TByteStream::GetArray_NameTable(PARRAY_POINTER PtrArray, DWORD ItemCount)
+{
+ if(PtrArray == NULL && ItemCount != 0)
+ return ERROR_INVALID_PARAMETER;
+ if(ItemCount > CASC_MAX_ENTRIES(NAME_FRAG))
+ return ERROR_NOT_ENOUGH_MEMORY;
+
+ return GetBytes(ItemCount * sizeof(NAME_FRAG), PtrArray);
+}
+
+// HOTS: 1959A60
+int TByteStream::SkipBytes(DWORD cbByteCount)
+{
+ ARRAY_POINTER Dummy;
+
+ return GetBytes(cbByteCount, &Dummy);
+}
+
+// HOTS: 1959AF0
+int TByteStream::SetByteBuffer(LPBYTE pbNewByteData, DWORD cbNewByteData)
+{
+ if(pbNewByteData != NULL || cbNewByteData == 0)
+ {
+ pbByteData = pbNewByteData;
+ cbByteData = cbNewByteData;
+ return ERROR_SUCCESS;
+ }
+
+ return ERROR_INVALID_PARAMETER;
+}
+
+
+// HOTS: 1957160
+int TByteStream::GetValue_DWORD(DWORD & Value)
+{
+ ARRAY_POINTER Pointer;
+ int nError;
+
+ nError = GetBytes(sizeof(DWORD), &Pointer);
+ if(nError != ERROR_SUCCESS)
+ return nError;
+
+ Value = Pointer.Uint32s[0];
+ return ERROR_SUCCESS;
+}
+
+int TByteStream::GetValue_ItemCount(DWORD & NumberOfBytes, DWORD & ItemCount, DWORD ItemSize)
+{
+ ARRAY_POINTER Pointer;
+ ULONGLONG ByteCount;
+ int nError;
+
+ // Verify if there is at least - 8 bytes
+ nError = GetBytes(sizeof(ULONGLONG), &Pointer);
+ if(nError != ERROR_SUCCESS)
+ return nError;
+
+ // Extract the number of bytes
+ ByteCount = Pointer.Int64Ptr[0];
+ if(ByteCount > 0xFFFFFFFF || (ByteCount % ItemSize) != 0)
+ return ERROR_BAD_FORMAT;
+
+ // Give the result to the caller
+ NumberOfBytes = (DWORD)ByteCount;
+ ItemCount = (DWORD)(ByteCount / ItemSize);
+ return ERROR_SUCCESS;
+}
+
+//-----------------------------------------------------------------------------
+// TGenericArray functions
+
+TGenericArray::TGenericArray()
+{
+ DataBuffer.Bytes = NULL;
+ FirstValid.Bytes = NULL;
+ ArrayPointer.Bytes = NULL;
+ ItemCount = 0;
+ MaxItemCount = 0;
+ bIsValidArray = false;
+}
+
+TGenericArray::~TGenericArray()
+{
+ if(DataBuffer.Bytes != NULL)
+ CASC_FREE(DataBuffer.Bytes);
+}
+
+// HOTS: inlined
+void TGenericArray::ExchangeWith(TGenericArray & Target)
+{
+ TGenericArray WorkBuff;
+
+ WorkBuff = *this;
+ *this = Target;
+ Target = WorkBuff;
+}
+
+// HOTS: Inlined
+void TGenericArray::CopyFrom(TGenericArray & Source)
+{
+ if(DataBuffer.Bytes != NULL)
+ CASC_FREE(DataBuffer.Bytes);
+ *this = Source;
+}
+
+// HOTS: 1957090 (SetDwordsValid)
+// HOTS: 19570B0 (SetTripletsValid)
+// HOTS: 19570D0 (? SetBitsValid ?)
+// HOTS: 19570F0 (SetNameFragmentsValid)
+int TGenericArray::SetArrayValid()
+{
+ if(bIsValidArray != 0)
+ return 1;
+
+ bIsValidArray = true;
+ return ERROR_SUCCESS;
+}
+
+
+// HOTS: 19575A0
+void TGenericArray::SetMaxItems_CHARS(DWORD NewMaxItemCount)
+{
+ ARRAY_POINTER OldDataBuffer = DataBuffer;
+ ARRAY_POINTER NewDataBuffer;
+
+ // Allocate new data buffer
+ NewDataBuffer.Chars = CASC_ALLOC(char, NewMaxItemCount);
+ if(NewDataBuffer.Chars != NULL)
+ {
+ // Copy the old items to the buffer
+ for(DWORD i = 0; i < ItemCount; i++)
+ {
+ NewDataBuffer.Chars[i] = FirstValid.Chars[i];
+ }
+ }
+
+ DataBuffer = NewDataBuffer;
+ FirstValid = NewDataBuffer;
+ ArrayPointer = NewDataBuffer;
+ MaxItemCount = NewMaxItemCount;
+ CASC_FREE(OldDataBuffer.Chars);
+}
+
+// HOTS: 1957600
+void TGenericArray::SetMaxItems_PATH_STOP(DWORD NewMaxItemCount)
+{
+ ARRAY_POINTER OldDataBuffer = DataBuffer;
+ ARRAY_POINTER NewDataBuffer;
+
+ // Allocate new data buffer
+ NewDataBuffer.PathStopPtr = CASC_ALLOC(PATH_STOP, NewMaxItemCount);
+ if(NewDataBuffer.PathStopPtr != NULL)
+ {
+ // Copy the old items to the buffer
+ for(DWORD i = 0; i < ItemCount; i++)
+ {
+ NewDataBuffer.PathStopPtr[i] = FirstValid.PathStopPtr[i];
+ }
+ }
+
+ DataBuffer = NewDataBuffer;
+ FirstValid = NewDataBuffer;
+ ArrayPointer = NewDataBuffer;
+ MaxItemCount = NewMaxItemCount;
+ CASC_FREE(OldDataBuffer.PathStopPtr);
+}
+
+// HOTS: inline
+void TGenericArray::InsertOneItem_CHAR(char NewItem)
+{
+ DWORD NewMaxItemCount;
+ DWORD NewItemCount;
+
+ NewItemCount = ItemCount + 1;
+ if(NewItemCount > MaxItemCount)
+ {
+ NewMaxItemCount = NewItemCount;
+
+ if(MaxItemCount > (NewItemCount / 2))
+ {
+ if(MaxItemCount <= (CASC_MAX_ENTRIES(BYTE) / 2))
+ NewMaxItemCount = MaxItemCount + MaxItemCount;
+ else
+ NewMaxItemCount = CASC_MAX_ENTRIES(BYTE);
+ }
+
+ SetMaxItems_CHARS(NewMaxItemCount);
+ }
+
+ // Put the character to the slot that has been reserved
+ FirstValid.Chars[ItemCount++] = NewItem;
+}
+
+// HOTS: 1958330, inline
+void TGenericArray::InsertOneItem_PATH_STOP(PATH_STOP & NewItem)
+{
+ DWORD NewMaxItemCount;
+ DWORD NewItemCount;
+
+ NewItemCount = ItemCount + 1;
+ if(NewItemCount > MaxItemCount)
+ {
+ NewMaxItemCount = NewItemCount;
+
+ if(MaxItemCount > (NewItemCount / 2))
+ {
+ if(MaxItemCount <= (CASC_MAX_ENTRIES(PATH_STOP) / 2))
+ NewMaxItemCount = MaxItemCount + MaxItemCount;
+ else
+ NewMaxItemCount = CASC_MAX_ENTRIES(PATH_STOP);
+ }
+
+ SetMaxItems_PATH_STOP(NewMaxItemCount);
+ }
+
+ // Put the structure to the slot that has been reserved
+ FirstValid.PathStopPtr[ItemCount++] = NewItem;
+}
+
+// HOTS: 19583A0
+void TGenericArray::sub_19583A0(DWORD NewItemCount)
+{
+ DWORD OldMaxItemCount = MaxItemCount;
+
+ if(NewItemCount > MaxItemCount)
+ {
+ DWORD NewMaxItemCount = NewItemCount;
+
+ if(MaxItemCount > (NewItemCount / 2))
+ {
+ if(MaxItemCount <= (CASC_MAX_ENTRIES(PATH_STOP) / 2))
+ NewMaxItemCount = MaxItemCount + MaxItemCount;
+ else
+ NewMaxItemCount = CASC_MAX_ENTRIES(PATH_STOP);
+ }
+
+ SetMaxItems_PATH_STOP(NewMaxItemCount);
+ }
+
+ // Initialize the newly inserted items
+ for(DWORD i = OldMaxItemCount; i < NewItemCount; i++)
+ {
+ FirstValid.PathStopPtr[i].ItemIndex = 0;
+ FirstValid.PathStopPtr[i].field_4 = 0;
+ FirstValid.PathStopPtr[i].field_8 = 0;
+ FirstValid.PathStopPtr[i].field_C = 0xFFFFFFFF;
+ FirstValid.PathStopPtr[i].field_10 = 0xFFFFFFFF;
+ }
+
+ ItemCount = NewItemCount;
+}
+
+// HOTS: 1957440
+int TGenericArray::LoadDwordsArray(TByteStream & InStream)
+{
+ DWORD NumberOfBytes;
+ int nError;
+
+ // Get and verify the number of items
+ nError = InStream.GetValue_ItemCount(NumberOfBytes, ItemCount, sizeof(DWORD));
+ if(nError != ERROR_SUCCESS)
+ return nError;
+
+ nError = InStream.GetArray_DWORDs(&ArrayPointer, ItemCount);
+ if(nError != ERROR_SUCCESS)
+ return nError;
+
+ nError = InStream.SkipBytes((0 - (DWORD)NumberOfBytes) & 0x07);
+ if(nError != ERROR_SUCCESS)
+ return nError;
+
+ return SetArrayValid();
+}
+
+// HOTS: 19574E0
+int TGenericArray::LoadTripletsArray(TByteStream & InStream)
+{
+ DWORD NumberOfBytes;
+ int nError;
+
+ // Get and verify the number of items
+ nError = InStream.GetValue_ItemCount(NumberOfBytes, ItemCount, sizeof(TRIPLET));
+ if(nError != ERROR_SUCCESS)
+ return nError;
+
+ nError = InStream.GetArray_Triplets(&ArrayPointer, ItemCount);
+ if(nError != ERROR_SUCCESS)
+ return nError;
+
+ nError = InStream.SkipBytes((0 - (DWORD)NumberOfBytes) & 0x07);
+ if(nError != ERROR_SUCCESS)
+ return nError;
+
+ return SetArrayValid();
+}
+
+// HOTS: 1957690
+int TGenericArray::LoadByteArray(TByteStream & InStream)
+{
+ DWORD NumberOfBytes;
+ int nError;
+
+ // Get and verify the number of items
+ nError = InStream.GetValue_ItemCount(NumberOfBytes, ItemCount, sizeof(BYTE));
+ if(nError != ERROR_SUCCESS)
+ return nError;
+
+ nError = InStream.GetArray_BYTES(&ArrayPointer, ItemCount);
+ if(nError != ERROR_SUCCESS)
+ return nError;
+
+ nError = InStream.SkipBytes((0 - (DWORD)NumberOfBytes) & 0x07);
+ if(nError != ERROR_SUCCESS)
+ return nError;
+
+ return SetArrayValid();
+}
+
+// HOTS: 1957700
+int TGenericArray::LoadFragmentInfos(TByteStream & InStream)
+{
+ DWORD NumberOfBytes;
+ int nError;
+
+ // Get and verify the number of items
+ nError = InStream.GetValue_ItemCount(NumberOfBytes, ItemCount, sizeof(NAME_FRAG));
+ if(nError != ERROR_SUCCESS)
+ return nError;
+
+ nError = InStream.GetArray_NameTable(&ArrayPointer, ItemCount);
+ if(nError != ERROR_SUCCESS)
+ return nError;
+
+ nError = InStream.SkipBytes((0 - (DWORD)NumberOfBytes) & 0x07);
+ if(nError != ERROR_SUCCESS)
+ return nError;
+
+ return SetArrayValid();
+}
+
+// HOTS: 195A220
+int TGenericArray::LoadStrings(TByteStream & InStream)
+{
+ DWORD NumberOfBytes;
+ int nError;
+
+ // Get and verify the number of items
+ nError = InStream.GetValue_ItemCount(NumberOfBytes, ItemCount, sizeof(char));
+ if(nError != ERROR_SUCCESS)
+ return nError;
+
+ nError = InStream.GetArray_BYTES(&ArrayPointer, ItemCount);
+ if(nError != ERROR_SUCCESS)
+ return nError;
+
+ nError = InStream.SkipBytes((0 - (DWORD)NumberOfBytes) & 0x07);
+ if(nError != ERROR_SUCCESS)
+ return nError;
+
+ return SetArrayValid();
+}
+
+// HOTS: 19581C0
+int TGenericArray::LoadDwordsArray_Copy(TByteStream & InStream)
+{
+ TGenericArray TempArray;
+ int nError;
+
+ nError = TempArray.LoadDwordsArray(InStream);
+ if(nError != ERROR_SUCCESS)
+ return nError;
+
+ CopyFrom(TempArray);
+ return ERROR_SUCCESS;
+}
+
+// HOTS: 1958250
+int TGenericArray::LoadTripletsArray_Copy(TByteStream & InStream)
+{
+ TGenericArray TempArray;
+ int nError;
+
+ nError = TempArray.LoadTripletsArray(InStream);
+ if(nError != ERROR_SUCCESS)
+ return nError;
+
+ CopyFrom(TempArray);
+ return ERROR_SUCCESS;
+}
+
+// HOTS: 1958420
+int TGenericArray::LoadBytes_Copy(TByteStream & InStream)
+{
+ TGenericArray TempArray;
+ int nError;
+
+ nError = TempArray.LoadByteArray(InStream);
+ if(nError != ERROR_SUCCESS)
+ return nError;
+
+ CopyFrom(TempArray);
+ return 0;
+}
+
+// HOTS: 19584F0
+int TGenericArray::LoadFragmentInfos_Copy(TByteStream & InStream)
+{
+ TGenericArray TempArray;
+ int nError;
+
+ nError = TempArray.LoadFragmentInfos(InStream);
+ if(nError != ERROR_SUCCESS)
+ return nError;
+
+ CopyFrom(TempArray);
+ return ERROR_SUCCESS;
+}
+
+// HOTS: 195A360
+int TGenericArray::LoadStringsWithCopy(TByteStream & InStream)
+{
+ TGenericArray TempArray;
+ int nError;
+
+ nError = TempArray.LoadStrings(InStream);
+ if(nError != ERROR_SUCCESS)
+ return nError;
+
+ CopyFrom(TempArray);
+ return ERROR_SUCCESS;
+}
+
+//-----------------------------------------------------------------------------
+// TBitEntryArray functions
+
+TBitEntryArray::TBitEntryArray()
+{
+ BitsPerEntry = 0;
+ EntryBitMask = 0;
+ TotalEntries = 0;
+}
+
+TBitEntryArray::~TBitEntryArray()
+{}
+
+// HOTS: 01957D20
+void TBitEntryArray::ExchangeWith(TBitEntryArray & Target)
+{
+ TBitEntryArray WorkBuff;
+
+ WorkBuff = *this;
+ *this = Target;
+ Target = WorkBuff;
+}
+
+// HOTS: 1958580
+int TBitEntryArray::LoadFromStream(TByteStream & InStream)
+{
+ ARRAY_POINTER Pointer;
+ ULONGLONG Value = 0;
+ int nError;
+
+ nError = LoadDwordsArray_Copy(InStream);
+ if(nError != ERROR_SUCCESS)
+ return nError;
+
+ nError = InStream.GetBytes(sizeof(DWORD), &Pointer);
+ if(nError != ERROR_SUCCESS)
+ return nError;
+
+ BitsPerEntry = Pointer.Uint32s[0];
+ if(BitsPerEntry > 0x20)
+ return ERROR_BAD_FORMAT;
+
+ nError = InStream.GetBytes(sizeof(DWORD), &Pointer);
+ if(nError != ERROR_SUCCESS)
+ return nError;
+ EntryBitMask = Pointer.Uint32s[0];
+
+ nError = InStream.GetBytes(sizeof(ULONGLONG), &Pointer);
+ if(nError == ERROR_SUCCESS)
+ Value = Pointer.Int64Ptr[0];
+ if(Value > 0xFFFFFFFF)
+ return ERROR_BAD_FORMAT;
+ TotalEntries = (DWORD)Value;
+
+ assert((BitsPerEntry * TotalEntries) / 32 <= ItemCount);
+ return ERROR_SUCCESS;
+}
+
+// HOTS: 1959300
+int TBitEntryArray::LoadFromStream_Exchange(TByteStream & InStream)
+{
+ TBitEntryArray TempArray;
+ int nError;
+
+ nError = TempArray.LoadFromStream(InStream);
+ if(nError != ERROR_SUCCESS)
+ return nError;
+
+ ExchangeWith(TempArray);
+ return ERROR_SUCCESS;
+}
+
+//-----------------------------------------------------------------------------
+// TStruct40 functions
+
+TStruct40::TStruct40()
+{
+ ItemIndex = 0;
+ CharIndex = 0;
+ ItemCount = 0;
+ SearchPhase = CASC_SEARCH_INITIALIZING;
+}
+
+// HOTS: 19586B0
+void TStruct40::InitSearchBuffers()
+{
+ DWORD NewMaxItemCount;
+
+ array_00.ItemCount = 0;
+
+ // HOTS: 19586BD
+ if(array_00.MaxItemCount < 0x40)
+ {
+ // HOTS: 19586C2
+ NewMaxItemCount = 0x40;
+
+ if(array_00.MaxItemCount > 0x20)
+ {
+ if(array_00.MaxItemCount <= 0x7FFFFFFF)
+ NewMaxItemCount = array_00.MaxItemCount + array_00.MaxItemCount;
+ else
+ NewMaxItemCount = CASC_MAX_ENTRIES(BYTE);
+ }
+
+ array_00.SetMaxItems_CHARS(NewMaxItemCount);
+ }
+
+ // HOTS: 19586E1
+ // Set the new item count
+ PathStops.sub_19583A0(0);
+
+ if(PathStops.MaxItemCount < 4)
+ {
+ // HOTS: 19586F2
+ NewMaxItemCount = 4;
+
+ // HOTS: 19586EA
+ if(PathStops.MaxItemCount > 2)
+ {
+ if(PathStops.MaxItemCount <= 0x6666666)
+ NewMaxItemCount = PathStops.MaxItemCount + PathStops.MaxItemCount;
+ else
+ NewMaxItemCount = CASC_MAX_ENTRIES(PATH_STOP);
+ }
+
+ // HOTS: 195870B
+ PathStops.SetMaxItems_PATH_STOP(NewMaxItemCount);
+ }
+
+ ItemIndex = 0;
+ CharIndex = 0;
+ ItemCount = 0;
+ SearchPhase = CASC_SEARCH_SEARCHING;
+}
+
+//-----------------------------------------------------------------------------
+// TSparseArray functions
+
+TSparseArray::TSparseArray()
+{
+ TotalItemCount = 0;
+ ValidItemCount = 0;
+}
+
+// HOTS: 1957DA0
+void TSparseArray::ExchangeWith(TSparseArray & Target)
+{
+ TSparseArray WorkBuff;
+
+ WorkBuff = *this;
+ *this = Target;
+ Target = WorkBuff;
+}
+
+// HOTS: 1958630
+int TSparseArray::LoadFromStream(TByteStream & InStream)
+{
+ ARRAY_POINTER Pointer;
+ int nError;
+
+ nError = ItemBits.LoadDwordsArray_Copy(InStream);
+ if(nError != ERROR_SUCCESS)
+ return nError;
+
+ nError = InStream.GetBytes(sizeof(DWORD), &Pointer);
+ if(nError != ERROR_SUCCESS)
+ return nError;
+ TotalItemCount = Pointer.Uint32s[0];
+
+ nError = InStream.GetBytes(sizeof(DWORD), &Pointer);
+ if(nError != ERROR_SUCCESS)
+ return nError;
+ ValidItemCount = Pointer.Uint32s[0];
+
+ if(ValidItemCount > TotalItemCount)
+ return ERROR_FILE_CORRUPT;
+
+ nError = BaseValues.LoadTripletsArray_Copy(InStream);
+ if(nError != ERROR_SUCCESS)
+ return nError;
+
+ nError = ArrayDwords_38.LoadDwordsArray_Copy(InStream);
+ if(nError != ERROR_SUCCESS)
+ return nError;
+
+ nError = ArrayDwords_50.LoadDwordsArray_Copy(InStream);
+ if(nError != ERROR_SUCCESS)
+ return nError;
+
+ return ERROR_SUCCESS;
+}
+
+// HOTS: 1959380
+int TSparseArray::LoadFromStream_Exchange(TByteStream & InStream)
+{
+ TSparseArray NewStruct68;
+ int nError;
+
+ nError = NewStruct68.LoadFromStream(InStream);
+ if(nError != ERROR_SUCCESS)
+ return nError;
+
+ ExchangeWith(NewStruct68);
+ return ERROR_SUCCESS;
+}
+
+// HOTS: 1959B60
+DWORD TSparseArray::GetItemValue(DWORD ItemIndex)
+{
+ PTRIPLET pTriplet;
+ DWORD DwordIndex;
+ DWORD BaseValue;
+ DWORD BitMask;
+
+ //
+ // Divide the low-8-bits index to four parts:
+ //
+ // |-----------------------|---|------------|
+ // | A (23 bits) | B | C |
+ // |-----------------------|---|------------|
+ //
+ // A (23-bits): Index to the table (60 bits per entry)
+ //
+ // Layout of the table entry:
+ // |--------------------------------|-------|--------|--------|---------|---------|---------|---------|-----|
+ // | Base Value | val[0]| val[1] | val[2] | val[3] | val[4] | val[5] | val[6] | - |
+ // | 32 bits | 7 bits| 8 bits | 8 bits | 9 bits | 9 bits | 9 bits | 9 bits |5bits|
+ // |--------------------------------|-------|--------|--------|---------|---------|---------|---------|-----|
+ //
+ // B (3 bits) : Index of the variable-bit value in the array (val[#], see above)
+ //
+ // C (32 bits): Number of bits to be checked (up to 0x3F bits).
+ // Number of set bits is then added to the values obtained from A and B
+
+ // Upper 23 bits contain index to the table
+ pTriplet = BaseValues.TripletArray + (ItemIndex >> 0x09);
+ BaseValue = pTriplet->BaseValue;
+
+ // Next 3 bits contain the index to the VBR
+ switch(((ItemIndex >> 0x06) & 0x07) - 1)
+ {
+ case 0: // Add the 1st value (7 bits)
+ BaseValue += (pTriplet->Value2 & 0x7F);
+ break;
+
+ case 1: // Add the 2nd value (8 bits)
+ BaseValue += (pTriplet->Value2 >> 0x07) & 0xFF;
+ break;
+
+ case 2: // Add the 3rd value (8 bits)
+ BaseValue += (pTriplet->Value2 >> 0x0F) & 0xFF;
+ break;
+
+ case 3: // Add the 4th value (9 bits)
+ BaseValue += (pTriplet->Value2 >> 0x17);
+ break;
+
+ case 4: // Add the 5th value (9 bits)
+ BaseValue += (pTriplet->Value3 & 0x1FF);
+ break;
+
+ case 5: // Add the 6th value (9 bits)
+ BaseValue += (pTriplet->Value3 >> 0x09) & 0x1FF;
+ break;
+
+ case 6: // Add the 7th value (9 bits)
+ BaseValue += (pTriplet->Value3 >> 0x12) & 0x1FF;
+ break;
+ }
+
+ //
+ // Take the upper 27 bits as an index to DWORD array, take lower 5 bits
+ // as number of bits to mask. Then calculate number of set bits in the value
+ // masked value.
+ //
+
+ // Get the index into the array of DWORDs
+ DwordIndex = (ItemIndex >> 0x05);
+
+ // Add number of set bits in the masked value up to 0x3F bits
+ if(ItemIndex & 0x20)
+ BaseValue += GetNumbrOfSetBits32(ItemBits.Uint32Array[DwordIndex - 1]);
+
+ BitMask = (1 << (ItemIndex & 0x1F)) - 1;
+ return BaseValue + GetNumbrOfSetBits32(ItemBits.Uint32Array[DwordIndex] & BitMask);
+}
+
+//-----------------------------------------------------------------------------
+// TNameIndexStruct functions
+
+// HOTS: 0195A290
+TNameIndexStruct::TNameIndexStruct()
+{}
+
+// HOTS: inlined
+TNameIndexStruct::~TNameIndexStruct()
+{}
+
+// HOTS: 195A180
+bool TNameIndexStruct::CheckNameFragment(TMndxFindResult * pStruct1C, DWORD dwFragOffs)
+{
+ TStruct40 * pStruct40 = pStruct1C->pStruct40;
+ const char * szPathFragment;
+ const char * szSearchMask;
+
+ if(!Struct68.TotalItemCount)
+ {
+ // Get the offset of the fragment to compare. For convenience with pStruct40->CharIndex,
+ // subtract the CharIndex from the fragment offset
+ szPathFragment = (NameFragments.CharArray + dwFragOffs - pStruct40->CharIndex);
+ szSearchMask = pStruct1C->szSearchMask;
+
+ // Keep searching as long as the name matches with the fragment
+ while(szPathFragment[pStruct40->CharIndex] == szSearchMask[pStruct40->CharIndex])
+ {
+ // Move to the next character
+ pStruct40->CharIndex++;
+
+ // Is it the end of the fragment or end of the path?
+ if(szPathFragment[pStruct40->CharIndex] == 0)
+ return true;
+ if(pStruct40->CharIndex >= pStruct1C->cchSearchMask)
+ return false;
+ }
+
+ return false;
+ }
+ else
+ {
+ // Get the offset of the fragment to compare.
+ szPathFragment = (const char *)(NameFragments.CharArray);
+ szSearchMask = pStruct1C->szSearchMask;
+
+ // Keep searching as long as the name matches with the fragment
+ while(szPathFragment[dwFragOffs] == szSearchMask[pStruct40->CharIndex])
+ {
+ // Move to the next character
+ pStruct40->CharIndex++;
+
+ // Is it the end of the fragment or end of the path?
+ if(Struct68.IsItemPresent(dwFragOffs++))
+ return true;
+ if(dwFragOffs >= pStruct1C->cchSearchMask)
+ return false;
+ }
+
+ return false;
+ }
+}
+
+// HOTS: 195A570
+bool TNameIndexStruct::CheckAndCopyNameFragment(TMndxFindResult * pStruct1C, DWORD dwFragOffs)
+{
+ TStruct40 * pStruct40 = pStruct1C->pStruct40;
+ const char * szPathFragment;
+ const char * szSearchMask;
+
+ if(!Struct68.TotalItemCount)
+ {
+ // Get the offset of the fragment to compare. For convenience with pStruct40->CharIndex,
+ // subtract the CharIndex from the fragment offset
+ szPathFragment = (const char *)(NameFragments.CharArray + dwFragOffs - pStruct40->CharIndex);
+ szSearchMask = pStruct1C->szSearchMask;
+
+ // Keep copying as long as we don't reach the end of the search mask
+ while(pStruct40->CharIndex < pStruct1C->cchSearchMask)
+ {
+ // HOTS: 195A5A0
+ if(szPathFragment[pStruct40->CharIndex] != szSearchMask[pStruct40->CharIndex])
+ return false;
+
+ // HOTS: 195A5B7
+ pStruct40->array_00.InsertOneItem_CHAR(szPathFragment[pStruct40->CharIndex]);
+ pStruct40->CharIndex++;
+
+ if(szPathFragment[pStruct40->CharIndex] == 0)
+ return true;
+ }
+
+ // Fixup the address of the fragment
+ szPathFragment += pStruct40->CharIndex;
+
+ // HOTS: 195A660
+ // Now we need to copy the rest of the fragment
+ while(szPathFragment[0] != 0)
+ {
+ pStruct40->array_00.InsertOneItem_CHAR(szPathFragment[0]);
+ szPathFragment++;
+ }
+ }
+ else
+ {
+ // Get the offset of the fragment to compare
+ // HOTS: 195A6B7
+ szPathFragment = NameFragments.CharArray;
+ szSearchMask = pStruct1C->szSearchMask;
+
+ // Keep copying as long as we don't reach the end of the search mask
+ while(dwFragOffs < pStruct1C->cchSearchMask)
+ {
+ if(szPathFragment[dwFragOffs] != szSearchMask[pStruct40->CharIndex])
+ return false;
+
+ pStruct40->array_00.InsertOneItem_CHAR(szPathFragment[dwFragOffs]);
+ pStruct40->CharIndex++;
+
+ // Keep going as long as the given bit is not set
+ if(Struct68.IsItemPresent(dwFragOffs++))
+ return true;
+ }
+
+ // Fixup the address of the fragment
+ szPathFragment += dwFragOffs;
+
+ // Now we need to copy the rest of the fragment
+ while(Struct68.IsItemPresent(dwFragOffs++) == 0)
+ {
+ // HOTS: 195A7A6
+ pStruct40->array_00.InsertOneItem_CHAR(szPathFragment[0]);
+ szPathFragment++;
+ }
+ }
+
+ return true;
+}
+
+// HOTS: 195A3F0
+void TNameIndexStruct::CopyNameFragment(TMndxFindResult * pStruct1C, DWORD dwFragOffs)
+{
+ TStruct40 * pStruct40 = pStruct1C->pStruct40;
+ const char * szPathFragment;
+
+ // HOTS: 195A3FA
+ if(!Struct68.TotalItemCount)
+ {
+ // HOTS: 195A40C
+ szPathFragment = NameFragments.CharArray + dwFragOffs;
+ while(szPathFragment[0] != 0)
+ {
+ // Insert the character to the path being built
+ pStruct40->array_00.InsertOneItem_CHAR(*szPathFragment++);
+ }
+ }
+ else
+ {
+ // HOTS: 195A4B3
+ for(;;)
+ {
+ // Insert the character to the path being built
+ pStruct40->array_00.InsertOneItem_CHAR(NameFragments.CharArray[dwFragOffs]);
+
+ // Keep going as long as the given bit is not set
+ if(Struct68.IsItemPresent(dwFragOffs++))
+ break;
+ }
+ }
+}
+
+// HOTS: 0195A300
+void TNameIndexStruct::ExchangeWith(TNameIndexStruct & Target)
+{
+ TNameIndexStruct WorkBuff;
+
+ WorkBuff = *this;
+ *this = Target;
+ Target = WorkBuff;
+}
+
+// HOTS: 0195A820
+int TNameIndexStruct::LoadFromStream(TByteStream & InStream)
+{
+ int nError;
+
+ nError = NameFragments.LoadStringsWithCopy(InStream);
+ if(nError != ERROR_SUCCESS)
+ return nError;
+
+ return Struct68.LoadFromStream_Exchange(InStream);
+}
+
+// HOTS: 195A850
+int TNameIndexStruct::LoadFromStream_Exchange(TByteStream & InStream)
+{
+ TNameIndexStruct TempIndexStruct;
+ int nError;
+
+ nError = TempIndexStruct.LoadFromStream(InStream);
+ if(nError != ERROR_SUCCESS)
+ return nError;
+
+ ExchangeWith(TempIndexStruct);
+ return ERROR_SUCCESS;
+}
+
+//-----------------------------------------------------------------------------
+// TStruct10 functions
+
+TStruct10::TStruct10()
+{
+ field_0 = 0x03;
+ field_4 = 0x200;
+ field_8 = 0x1000;
+ field_C = 0x20000;
+}
+
+// HOTS: inline
+void TStruct10::CopyFrom(TStruct10 & Target)
+{
+ field_0 = Target.field_0;
+ field_4 = Target.field_4;
+ field_8 = Target.field_8;
+ field_C = Target.field_C;
+}
+
+// HOTS: 1956FD0
+int TStruct10::sub_1956FD0(DWORD dwBitMask)
+{
+ switch(dwBitMask & 0xF80)
+ {
+ case 0x00:
+ field_4 = 0x200;
+ return ERROR_SUCCESS;
+
+ case 0x80:
+ field_4 = 0x80;
+ return ERROR_SUCCESS;
+
+ case 0x100:
+ field_4 = 0x100;
+ return ERROR_SUCCESS;
+
+ case 0x200:
+ field_4 = 0x200;
+ return ERROR_SUCCESS;
+
+ case 0x400:
+ field_4 = 0x400;
+ return ERROR_SUCCESS;
+
+ case 0x800:
+ field_4 = 0x800;
+ return ERROR_SUCCESS;
+ }
+
+ return ERROR_INVALID_PARAMETER;
+}
+
+// HOTS: 1957050
+int TStruct10::sub_1957050(DWORD dwBitMask)
+{
+ switch(dwBitMask & 0xF0000)
+ {
+ case 0x00:
+ field_C = 0x20000;
+ return ERROR_SUCCESS;
+
+ case 0x10000:
+ field_C = 0x10000;
+ return ERROR_SUCCESS;
+
+ case 0x20000:
+ field_C = 0x20000;
+ return ERROR_SUCCESS;
+ }
+
+ return ERROR_INVALID_PARAMETER;
+}
+
+// HOTS: 19572E0
+int TStruct10::sub_19572E0(DWORD dwBitMask)
+{
+ DWORD dwSubMask;
+ int nError;
+
+ if(dwBitMask & 0xFFF00000)
+ return ERROR_INVALID_PARAMETER;
+
+ dwSubMask = dwBitMask & 0x7F;
+ if(dwSubMask)
+ field_0 = dwSubMask;
+
+ nError = sub_1956FD0(dwBitMask);
+ if(nError != ERROR_SUCCESS)
+ return nError;
+
+ dwSubMask = dwBitMask & 0xF000;
+ if(dwSubMask == 0 || dwSubMask == 0x1000)
+ {
+ field_8 = 0x1000;
+ return sub_1957050(dwBitMask);
+ }
+
+ if(dwSubMask == 0x2000)
+ {
+ field_8 = 0x2000;
+ return sub_1957050(dwBitMask);
+ }
+
+ return ERROR_INVALID_PARAMETER;
+}
+
+// HOTS: 1957800
+int TStruct10::sub_1957800(DWORD dwBitMask)
+{
+ TStruct10 TempStruct;
+ int nError;
+
+ nError = TempStruct.sub_19572E0(dwBitMask);
+ if(nError != ERROR_SUCCESS)
+ return nError;
+
+ CopyFrom(TempStruct);
+ return ERROR_SUCCESS;
+}
+
+//-----------------------------------------------------------------------------
+// TFileNameDatabase functions
+
+// HOTS: 01958730
+TFileNameDatabase::TFileNameDatabase()
+{
+ NameFragIndexMask = 0;
+ field_214 = 0;
+}
+
+// HOTS: inlined
+void TFileNameDatabase::ExchangeWith(TFileNameDatabase & Target)
+{
+ TFileNameDatabasePtr TempPtr;
+ DWORD dwTemp;
+
+ Struct68_00.ExchangeWith(Target.Struct68_00);
+ FileNameIndexes.ExchangeWith(Target.FileNameIndexes);
+ Struct68_D0.ExchangeWith(Target.Struct68_D0);
+
+ FrgmDist_LoBits.ExchangeWith(Target.FrgmDist_LoBits);
+ FrgmDist_HiBits.ExchangeWith(Target.FrgmDist_HiBits);
+
+ IndexStruct_174.ExchangeWith(Target.IndexStruct_174);
+
+ TempPtr = NextDB;
+ NextDB = Target.NextDB;
+ Target.NextDB = TempPtr;
+
+ NameFragTable.ExchangeWith(Target.NameFragTable);
+
+ dwTemp = NameFragIndexMask;
+ NameFragIndexMask = Target.NameFragIndexMask;
+ Target.NameFragIndexMask = dwTemp;
+
+ dwTemp = field_214;
+ field_214 = Target.field_214;
+ Target.field_214 = dwTemp;
+
+ Struct10.CopyFrom(Target.Struct10);
+}
+
+// HOTS: 1959CB0
+DWORD TFileNameDatabase::sub_1959CB0(DWORD dwItemIndex)
+{
+ PTRIPLET pTriplet;
+ DWORD dwKeyShifted = (dwItemIndex >> 9);
+ DWORD eax, ebx, ecx, edx, esi, edi;
+
+ // If lower 9 is zero
+ edx = dwItemIndex;
+ if((edx & 0x1FF) == 0)
+ return Struct68_00.ArrayDwords_38.Uint32Array[dwKeyShifted];
+
+ eax = Struct68_00.ArrayDwords_38.Uint32Array[dwKeyShifted] >> 9;
+ esi = (Struct68_00.ArrayDwords_38.Uint32Array[dwKeyShifted + 1] + 0x1FF) >> 9;
+ dwItemIndex = esi;
+
+ if((eax + 0x0A) >= esi)
+ {
+ // HOTS: 1959CF7
+ pTriplet = Struct68_00.BaseValues.TripletArray + eax + 1;
+ edi = (eax << 0x09);
+ ebx = edi - pTriplet->BaseValue + 0x200;
+ while(edx >= ebx)
+ {
+ // HOTS: 1959D14
+ edi += 0x200;
+ pTriplet++;
+
+ ebx = edi - pTriplet->BaseValue + 0x200;
+ eax++;
+ }
+ }
+ else
+ {
+ // HOTS: 1959D2E
+ while((eax + 1) < esi)
+ {
+ // HOTS: 1959D38
+ // ecx = Struct68_00.BaseValues.TripletArray;
+ esi = (esi + eax) >> 1;
+ ebx = (esi << 0x09) - Struct68_00.BaseValues.TripletArray[esi].BaseValue;
+ if(edx < ebx)
+ {
+ // HOTS: 01959D4B
+ dwItemIndex = esi;
+ }
+ else
+ {
+ // HOTS: 1959D50
+ eax = esi;
+ esi = dwItemIndex;
+ }
+ }
+ }
+
+ // HOTS: 1959D5F
+ pTriplet = Struct68_00.BaseValues.TripletArray + eax;
+ edx += pTriplet->BaseValue - (eax << 0x09);
+ edi = (eax << 4);
+
+ eax = pTriplet->Value2;
+ ecx = (eax >> 0x17);
+ ebx = 0x100 - ecx;
+ if(edx < ebx)
+ {
+ // HOTS: 1959D8C
+ ecx = ((eax >> 0x07) & 0xFF);
+ esi = 0x80 - ecx;
+ if(edx < esi)
+ {
+ // HOTS: 01959DA2
+ eax = eax & 0x7F;
+ ecx = 0x40 - eax;
+ if(edx >= ecx)
+ {
+ // HOTS: 01959DB7
+ edi += 2;
+ edx = edx + eax - 0x40;
+ }
+ }
+ else
+ {
+ // HOTS: 1959DC0
+ eax = (eax >> 0x0F) & 0xFF;
+ esi = 0xC0 - eax;
+ if(edx < esi)
+ {
+ // HOTS: 1959DD3
+ edi += 4;
+ edx = edx + ecx - 0x80;
+ }
+ else
+ {
+ // HOTS: 1959DD3
+ edi += 6;
+ edx = edx + eax - 0xC0;
+ }
+ }
+ }
+ else
+ {
+ // HOTS: 1959DE8
+ esi = pTriplet->Value3;
+ eax = ((esi >> 0x09) & 0x1FF);
+ ebx = 0x180 - eax;
+ if(edx < ebx)
+ {
+ // HOTS: 01959E00
+ esi = esi & 0x1FF;
+ eax = (0x140 - esi);
+ if(edx < eax)
+ {
+ // HOTS: 1959E11
+ edi = edi + 8;
+ edx = edx + ecx - 0x100;
+ }
+ else
+ {
+ // HOTS: 1959E1D
+ edi = edi + 0x0A;
+ edx = edx + esi - 0x140;
+ }
+ }
+ else
+ {
+ // HOTS: 1959E29
+ esi = (esi >> 0x12) & 0x1FF;
+ ecx = (0x1C0 - esi);
+ if(edx < ecx)
+ {
+ // HOTS: 1959E3D
+ edi = edi + 0x0C;
+ edx = edx + eax - 0x180;
+ }
+ else
+ {
+ // HOTS: 1959E49
+ edi = edi + 0x0E;
+ edx = edx + esi - 0x1C0;
+ }
+ }
+ }
+
+ // HOTS: 1959E53:
+ // Calculate the number of bits set in the value of "ecx"
+ ecx = ~Struct68_00.ItemBits.Uint32Array[edi];
+ eax = GetNumberOfSetBits(ecx);
+ esi = eax >> 0x18;
+
+ if(edx >= esi)
+ {
+ // HOTS: 1959ea4
+ ecx = ~Struct68_00.ItemBits.Uint32Array[++edi];
+ edx = edx - esi;
+ eax = GetNumberOfSetBits(ecx);
+ }
+
+ // HOTS: 1959eea
+ // ESI gets the number of set bits in the lower 16 bits of ECX
+ esi = (eax >> 0x08) & 0xFF;
+ edi = edi << 0x05;
+ if(edx < esi)
+ {
+ // HOTS: 1959EFC
+ eax = eax & 0xFF;
+ if(edx >= eax)
+ {
+ // HOTS: 1959F05
+ ecx >>= 0x08;
+ edi += 0x08;
+ edx -= eax;
+ }
+ }
+ else
+ {
+ // HOTS: 1959F0D
+ eax = (eax >> 0x10) & 0xFF;
+ if(edx < eax)
+ {
+ // HOTS: 1959F19
+ ecx >>= 0x10;
+ edi += 0x10;
+ edx -= esi;
+ }
+ else
+ {
+ // HOTS: 1959F23
+ ecx >>= 0x18;
+ edi += 0x18;
+ edx -= eax;
+ }
+ }
+
+ // HOTS: 1959f2b
+ edx = edx << 0x08;
+ ecx = ecx & 0xFF;
+
+ // BUGBUG: Possible buffer overflow here. Happens when dwItemIndex >= 0x9C.
+ // The same happens in Heroes of the Storm (build 29049), so I am not sure
+ // if this is a bug or a case that never happens
+ assert((ecx + edx) < sizeof(table_1BA1818));
+ return table_1BA1818[ecx + edx] + edi;
+}
+
+DWORD TFileNameDatabase::sub_1959F50(DWORD arg_0)
+{
+ PTRIPLET pTriplet;
+ PDWORD ItemArray;
+ DWORD eax, ebx, ecx, edx, esi, edi;
+
+ edx = arg_0;
+ eax = arg_0 >> 0x09;
+ if((arg_0 & 0x1FF) == 0)
+ return Struct68_00.ArrayDwords_50.Uint32Array[eax];
+
+ ItemArray = Struct68_00.ArrayDwords_50.Uint32Array + eax;
+ eax = (ItemArray[0] >> 0x09);
+ edi = (ItemArray[1] + 0x1FF) >> 0x09;
+
+ if((eax + 0x0A) > edi)
+ {
+ // HOTS: 01959F94
+ pTriplet = Struct68_00.BaseValues.TripletArray + eax + 1;
+ while(edx >= pTriplet->BaseValue)
+ {
+ // HOTS: 1959FA3
+ pTriplet++;
+ eax++;
+ }
+ }
+ else
+ {
+ // Binary search
+ // HOTS: 1959FAD
+ if((eax + 1) < edi)
+ {
+ // HOTS: 1959FB4
+ esi = (edi + eax) >> 1;
+ if(edx < Struct68_00.BaseValues.TripletArray[esi].BaseValue)
+ {
+ // HOTS: 1959FC4
+ edi = esi;
+ }
+ else
+ {
+ // HOTS: 1959FC8
+ eax = esi;
+ }
+ }
+ }
+
+ // HOTS: 1959FD4
+ pTriplet = Struct68_00.BaseValues.TripletArray + eax;
+ edx = edx - pTriplet->BaseValue;
+ edi = eax << 0x04;
+ eax = pTriplet->Value2;
+ ebx = (eax >> 0x17);
+ if(edx < ebx)
+ {
+ // HOTS: 1959FF1
+ esi = (eax >> 0x07) & 0xFF;
+ if(edx < esi)
+ {
+ // HOTS: 0195A000
+ eax = eax & 0x7F;
+ if(edx >= eax)
+ {
+ // HOTS: 195A007
+ edi = edi + 2;
+ edx = edx - eax;
+ }
+ }
+ else
+ {
+ // HOTS: 195A00E
+ eax = (eax >> 0x0F) & 0xFF;
+ if(edx < eax)
+ {
+ // HOTS: 195A01A
+ edi += 4;
+ edx = edx - esi;
+ }
+ else
+ {
+ // HOTS: 195A01F
+ edi += 6;
+ edx = edx - eax;
+ }
+ }
+ }
+ else
+ {
+ // HOTS: 195A026
+ esi = pTriplet->Value3;
+ eax = (pTriplet->Value3 >> 0x09) & 0x1FF;
+ if(edx < eax)
+ {
+ // HOTS: 195A037
+ esi = esi & 0x1FF;
+ if(edx < esi)
+ {
+ // HOTS: 195A041
+ edi = edi + 8;
+ edx = edx - ebx;
+ }
+ else
+ {
+ // HOTS: 195A048
+ edi = edi + 0x0A;
+ edx = edx - esi;
+ }
+ }
+ else
+ {
+ // HOTS: 195A04D
+ esi = (esi >> 0x12) & 0x1FF;
+ if(edx < esi)
+ {
+ // HOTS: 195A05A
+ edi = edi + 0x0C;
+ edx = edx - eax;
+ }
+ else
+ {
+ // HOTS: 195A061
+ edi = edi + 0x0E;
+ edx = edx - esi;
+ }
+ }
+ }
+
+ // HOTS: 195A066
+ esi = Struct68_00.ItemBits.Uint32Array[edi];
+ eax = GetNumberOfSetBits(esi);
+ ecx = eax >> 0x18;
+
+ if(edx >= ecx)
+ {
+ // HOTS: 195A0B2
+ esi = Struct68_00.ItemBits.Uint32Array[++edi];
+ edx = edx - ecx;
+ eax = GetNumberOfSetBits(esi);
+ }
+
+ // HOTS: 195A0F6
+ ecx = (eax >> 0x08) & 0xFF;
+
+ edi = (edi << 0x05);
+ if(edx < ecx)
+ {
+ // HOTS: 195A111
+ eax = eax & 0xFF;
+ if(edx >= eax)
+ {
+ // HOTS: 195A111
+ edi = edi + 0x08;
+ esi = esi >> 0x08;
+ edx = edx - eax;
+ }
+ }
+ else
+ {
+ // HOTS: 195A119
+ eax = (eax >> 0x10) & 0xFF;
+ if(edx < eax)
+ {
+ // HOTS: 195A125
+ esi = esi >> 0x10;
+ edi = edi + 0x10;
+ edx = edx - ecx;
+ }
+ else
+ {
+ // HOTS: 195A12F
+ esi = esi >> 0x18;
+ edi = edi + 0x18;
+ edx = edx - eax;
+ }
+ }
+
+ esi = esi & 0xFF;
+ edx = edx << 0x08;
+
+ // BUGBUG: Potential buffer overflow
+ // Happens in Heroes of the Storm when arg_0 == 0x5B
+ assert((esi + edx) < sizeof(table_1BA1818));
+ return table_1BA1818[esi + edx] + edi;
+}
+
+// HOTS: 1957970
+bool TFileNameDatabase::CheckNextPathFragment(TMndxFindResult * pStruct1C)
+{
+ TStruct40 * pStruct40 = pStruct1C->pStruct40;
+ LPBYTE pbPathName = (LPBYTE)pStruct1C->szSearchMask;
+ DWORD CollisionIndex;
+ DWORD NameFragIndex;
+ DWORD SaveCharIndex;
+ DWORD HiBitsIndex;
+ DWORD FragOffs;
+
+ // Calculate index of the next name fragment in the name fragment table
+ NameFragIndex = ((pStruct40->ItemIndex << 0x05) ^ pStruct40->ItemIndex ^ pbPathName[pStruct40->CharIndex]) & NameFragIndexMask;
+
+ // Does the hash value match?
+ if(NameFragTable.NameFragArray[NameFragIndex].ItemIndex == pStruct40->ItemIndex)
+ {
+ // Check if there is single character match
+ if(IS_SINGLE_CHAR_MATCH(NameFragTable, NameFragIndex))
+ {
+ pStruct40->ItemIndex = NameFragTable.NameFragArray[NameFragIndex].NextIndex;
+ pStruct40->CharIndex++;
+ return true;
+ }
+
+ // Check if there is a name fragment match
+ if(NextDB.pDB != NULL)
+ {
+ if(!NextDB.pDB->sub_1957B80(pStruct1C, NameFragTable.NameFragArray[NameFragIndex].FragOffs))
+ return false;
+ }
+ else
+ {
+ if(!IndexStruct_174.CheckNameFragment(pStruct1C, NameFragTable.NameFragArray[NameFragIndex].FragOffs))
+ return false;
+ }
+
+ pStruct40->ItemIndex = NameFragTable.NameFragArray[NameFragIndex].NextIndex;
+ return true;
+ }
+
+ //
+ // Conflict: Multiple hashes give the same table index
+ //
+
+ // HOTS: 1957A0E
+ CollisionIndex = sub_1959CB0(pStruct40->ItemIndex) + 1;
+ if(!Struct68_00.IsItemPresent(CollisionIndex))
+ return false;
+
+ pStruct40->ItemIndex = (CollisionIndex - pStruct40->ItemIndex - 1);
+ HiBitsIndex = 0xFFFFFFFF;
+
+// CascDumpSparseArray("E:\\casc-array-68.txt", &FileNameIndexes);
+// CascDumpSparseArray("E:\\casc-array-D0.txt", &Struct68_D0);
+
+ // HOTS: 1957A41:
+ do
+ {
+ // HOTS: 1957A41
+ // Check if the low 8 bits if the fragment offset contain a single character
+ // or an offset to a name fragment
+ if(Struct68_D0.IsItemPresent(pStruct40->ItemIndex))
+ {
+ if(HiBitsIndex == 0xFFFFFFFF)
+ {
+ // HOTS: 1957A6C
+ HiBitsIndex = Struct68_D0.GetItemValue(pStruct40->ItemIndex);
+ }
+ else
+ {
+ // HOTS: 1957A7F
+ HiBitsIndex++;
+ }
+
+ // HOTS: 1957A83
+ SaveCharIndex = pStruct40->CharIndex;
+
+ // Get the name fragment offset as combined value from lower 8 bits and upper bits
+ FragOffs = GetNameFragmentOffsetEx(pStruct40->ItemIndex, HiBitsIndex);
+
+ // Compare the string with the fragment name database
+ if(NextDB.pDB != NULL)
+ {
+ // HOTS: 1957AEC
+ if(NextDB.pDB->sub_1957B80(pStruct1C, FragOffs))
+ return true;
+ }
+ else
+ {
+ // HOTS: 1957AF7
+ if(IndexStruct_174.CheckNameFragment(pStruct1C, FragOffs))
+ return true;
+ }
+
+ // HOTS: 1957B0E
+ // If there was partial match with the fragment, end the search
+ if(pStruct40->CharIndex != SaveCharIndex)
+ return false;
+ }
+ else
+ {
+ // HOTS: 1957B1C
+ if(FrgmDist_LoBits.ByteArray[pStruct40->ItemIndex] == pStruct1C->szSearchMask[pStruct40->CharIndex])
+ {
+ pStruct40->CharIndex++;
+ return true;
+ }
+ }
+
+ // HOTS: 1957B32
+ pStruct40->ItemIndex++;
+ CollisionIndex++;
+ }
+ while(Struct68_00.IsItemPresent(CollisionIndex));
+ return false;
+}
+
+// HOTS: 1957B80
+bool TFileNameDatabase::sub_1957B80(TMndxFindResult * pStruct1C, DWORD arg_4)
+{
+ TStruct40 * pStruct40 = pStruct1C->pStruct40;
+ PNAME_FRAG pNameEntry;
+ DWORD FragOffs;
+ DWORD eax, edi;
+
+ edi = arg_4;
+
+ // HOTS: 1957B95
+ for(;;)
+ {
+ pNameEntry = NameFragTable.NameFragArray + (edi & NameFragIndexMask);
+ if(edi == pNameEntry->NextIndex)
+ {
+ // HOTS: 01957BB4
+ if((pNameEntry->FragOffs & 0xFFFFFF00) != 0xFFFFFF00)
+ {
+ // HOTS: 1957BC7
+ if(NextDB.pDB != NULL)
+ {
+ // HOTS: 1957BD3
+ if(!NextDB.pDB->sub_1957B80(pStruct1C, pNameEntry->FragOffs))
+ return false;
+ }
+ else
+ {
+ // HOTS: 1957BE0
+ if(!IndexStruct_174.CheckNameFragment(pStruct1C, pNameEntry->FragOffs))
+ return false;
+ }
+ }
+ else
+ {
+ // HOTS: 1957BEE
+ if(pStruct1C->szSearchMask[pStruct40->CharIndex] != (char)pNameEntry->FragOffs)
+ return false;
+ pStruct40->CharIndex++;
+ }
+
+ // HOTS: 1957C05
+ edi = pNameEntry->ItemIndex;
+ if(edi == 0)
+ return true;
+
+ if(pStruct40->CharIndex >= pStruct1C->cchSearchMask)
+ return false;
+ }
+ else
+ {
+ // HOTS: 1957C30
+ if(Struct68_D0.IsItemPresent(edi))
+ {
+ // HOTS: 1957C4C
+ if(NextDB.pDB != NULL)
+ {
+ // HOTS: 1957C58
+ FragOffs = GetNameFragmentOffset(edi);
+ if(!NextDB.pDB->sub_1957B80(pStruct1C, FragOffs))
+ return false;
+ }
+ else
+ {
+ // HOTS: 1957350
+ FragOffs = GetNameFragmentOffset(edi);
+ if(!IndexStruct_174.CheckNameFragment(pStruct1C, FragOffs))
+ return false;
+ }
+ }
+ else
+ {
+ // HOTS: 1957C8E
+ if(FrgmDist_LoBits.ByteArray[edi] != pStruct1C->szSearchMask[pStruct40->CharIndex])
+ return false;
+
+ pStruct40->CharIndex++;
+ }
+
+ // HOTS: 1957CB2
+ if(edi <= field_214)
+ return true;
+
+ if(pStruct40->CharIndex >= pStruct1C->cchSearchMask)
+ return false;
+
+ eax = sub_1959F50(edi);
+ edi = (eax - edi - 1);
+ }
+ }
+}
+
+// HOTS: 1958D70
+void TFileNameDatabase::sub_1958D70(TMndxFindResult * pStruct1C, DWORD arg_4)
+{
+ TStruct40 * pStruct40 = pStruct1C->pStruct40;
+ PNAME_FRAG pNameEntry;
+
+ // HOTS: 1958D84
+ for(;;)
+ {
+ pNameEntry = NameFragTable.NameFragArray + (arg_4 & NameFragIndexMask);
+ if(arg_4 == pNameEntry->NextIndex)
+ {
+ // HOTS: 1958DA6
+ if((pNameEntry->FragOffs & 0xFFFFFF00) != 0xFFFFFF00)
+ {
+ // HOTS: 1958DBA
+ if(NextDB.pDB != NULL)
+ {
+ NextDB.pDB->sub_1958D70(pStruct1C, pNameEntry->FragOffs);
+ }
+ else
+ {
+ IndexStruct_174.CopyNameFragment(pStruct1C, pNameEntry->FragOffs);
+ }
+ }
+ else
+ {
+ // HOTS: 1958DE7
+ // Insert the low 8 bits to the path being built
+ pStruct40->array_00.InsertOneItem_CHAR((char)(pNameEntry->FragOffs & 0xFF));
+ }
+
+ // HOTS: 1958E71
+ arg_4 = pNameEntry->ItemIndex;
+ if(arg_4 == 0)
+ return;
+ }
+ else
+ {
+ // HOTS: 1958E8E
+ if(Struct68_D0.IsItemPresent(arg_4))
+ {
+ DWORD FragOffs;
+
+ // HOTS: 1958EAF
+ FragOffs = GetNameFragmentOffset(arg_4);
+ if(NextDB.pDB != NULL)
+ {
+ NextDB.pDB->sub_1958D70(pStruct1C, FragOffs);
+ }
+ else
+ {
+ IndexStruct_174.CopyNameFragment(pStruct1C, FragOffs);
+ }
+ }
+ else
+ {
+ // HOTS: 1958F50
+ // Insert one character to the path being built
+ pStruct40->array_00.InsertOneItem_CHAR(FrgmDist_LoBits.CharArray[arg_4]);
+ }
+
+ // HOTS: 1958FDE
+ if(arg_4 <= field_214)
+ return;
+
+ arg_4 = 0xFFFFFFFF - arg_4 + sub_1959F50(arg_4);
+ }
+ }
+}
+
+// HOTS: 1959010
+bool TFileNameDatabase::sub_1959010(TMndxFindResult * pStruct1C, DWORD arg_4)
+{
+ TStruct40 * pStruct40 = pStruct1C->pStruct40;
+ PNAME_FRAG pNameEntry;
+
+ // HOTS: 1959024
+ for(;;)
+ {
+ pNameEntry = NameFragTable.NameFragArray + (arg_4 & NameFragIndexMask);
+ if(arg_4 == pNameEntry->NextIndex)
+ {
+ // HOTS: 1959047
+ if((pNameEntry->FragOffs & 0xFFFFFF00) != 0xFFFFFF00)
+ {
+ // HOTS: 195905A
+ if(NextDB.pDB != NULL)
+ {
+ if(!NextDB.pDB->sub_1959010(pStruct1C, pNameEntry->FragOffs))
+ return false;
+ }
+ else
+ {
+ if(!IndexStruct_174.CheckAndCopyNameFragment(pStruct1C, pNameEntry->FragOffs))
+ return false;
+ }
+ }
+ else
+ {
+ // HOTS: 1959092
+ if((char)(pNameEntry->FragOffs & 0xFF) != pStruct1C->szSearchMask[pStruct40->CharIndex])
+ return false;
+
+ // Insert the low 8 bits to the path being built
+ pStruct40->array_00.InsertOneItem_CHAR((char)(pNameEntry->FragOffs & 0xFF));
+ pStruct40->CharIndex++;
+ }
+
+ // HOTS: 195912E
+ arg_4 = pNameEntry->ItemIndex;
+ if(arg_4 == 0)
+ return true;
+ }
+ else
+ {
+ // HOTS: 1959147
+ if(Struct68_D0.IsItemPresent(arg_4))
+ {
+ DWORD FragOffs;
+
+ // HOTS: 195917C
+ FragOffs = GetNameFragmentOffset(arg_4);
+ if(NextDB.pDB != NULL)
+ {
+ if(!NextDB.pDB->sub_1959010(pStruct1C, FragOffs))
+ return false;
+ }
+ else
+ {
+ if(!IndexStruct_174.CheckAndCopyNameFragment(pStruct1C, FragOffs))
+ return false;
+ }
+ }
+ else
+ {
+ // HOTS: 195920E
+ if(FrgmDist_LoBits.CharArray[arg_4] != pStruct1C->szSearchMask[pStruct40->CharIndex])
+ return false;
+
+ // Insert one character to the path being built
+ pStruct40->array_00.InsertOneItem_CHAR(FrgmDist_LoBits.CharArray[arg_4]);
+ pStruct40->CharIndex++;
+ }
+
+ // HOTS: 19592B6
+ if(arg_4 <= field_214)
+ return true;
+
+ arg_4 = 0xFFFFFFFF - arg_4 + sub_1959F50(arg_4);
+ }
+
+ // HOTS: 19592D5
+ if(pStruct40->CharIndex >= pStruct1C->cchSearchMask)
+ break;
+ }
+
+ sub_1958D70(pStruct1C, arg_4);
+ return true;
+}
+
+// HOTS: 1959460
+bool TFileNameDatabase::sub_1959460(TMndxFindResult * pStruct1C)
+{
+ TStruct40 * pStruct40 = pStruct1C->pStruct40;
+ PPATH_STOP pPathStop;
+ PATH_STOP PathStop;
+ DWORD NewMaxItemCount;
+ DWORD FragOffs;
+ DWORD edi;
+
+ if(pStruct40->SearchPhase == CASC_SEARCH_FINISHED)
+ return false;
+
+ if(pStruct40->SearchPhase != CASC_SEARCH_SEARCHING)
+ {
+ // HOTS: 1959489
+ pStruct40->InitSearchBuffers();
+
+ // If the caller passed a part of the search path, we need to find that one
+ while(pStruct40->CharIndex < pStruct1C->cchSearchMask)
+ {
+ if(!sub_1958B00(pStruct1C))
+ {
+ pStruct40->SearchPhase = CASC_SEARCH_FINISHED;
+ return false;
+ }
+ }
+
+ // HOTS: 19594b0
+ PathStop.ItemIndex = pStruct40->ItemIndex;
+ PathStop.field_4 = 0;
+ PathStop.field_8 = pStruct40->array_00.ItemCount;
+ PathStop.field_C = 0xFFFFFFFF;
+ PathStop.field_10 = 0xFFFFFFFF;
+ pStruct40->PathStops.InsertOneItem_PATH_STOP(PathStop);
+ pStruct40->ItemCount = 1;
+
+ if(FileNameIndexes.IsItemPresent(pStruct40->ItemIndex))
+ {
+ pStruct1C->szFoundPath = pStruct40->array_00.FirstValid.Chars;
+ pStruct1C->cchFoundPath = pStruct40->array_00.ItemCount;
+ pStruct1C->FileNameIndex = FileNameIndexes.GetItemValue(pStruct40->ItemIndex);
+ return true;
+ }
+ }
+
+ // HOTS: 1959522
+ for(;;)
+ {
+ // HOTS: 1959530
+ if(pStruct40->ItemCount == pStruct40->PathStops.ItemCount)
+ {
+ PPATH_STOP pLastStop;
+ DWORD CollisionIndex;
+
+ pLastStop = pStruct40->PathStops.FirstValid.PathStopPtr + pStruct40->PathStops.ItemCount - 1;
+ CollisionIndex = sub_1959CB0(pLastStop->ItemIndex) + 1;
+
+ // Insert a new structure
+ PathStop.ItemIndex = CollisionIndex - pLastStop->ItemIndex - 1;;
+ PathStop.field_4 = CollisionIndex;
+ PathStop.field_8 = 0;
+ PathStop.field_C = 0xFFFFFFFF;
+ PathStop.field_10 = 0xFFFFFFFF;
+ pStruct40->PathStops.InsertOneItem_PATH_STOP(PathStop);
+ }
+
+ // HOTS: 19595BD
+ pPathStop = pStruct40->PathStops.FirstValid.PathStopPtr + pStruct40->ItemCount;
+
+ // HOTS: 19595CC
+ if(Struct68_00.IsItemPresent(pPathStop->field_4++))
+ {
+ // HOTS: 19595F2
+ pStruct40->ItemCount++;
+
+ if(Struct68_D0.IsItemPresent(pPathStop->ItemIndex))
+ {
+ // HOTS: 1959617
+ if(pPathStop->field_C == 0xFFFFFFFF)
+ pPathStop->field_C = Struct68_D0.GetItemValue(pPathStop->ItemIndex);
+ else
+ pPathStop->field_C++;
+
+ // HOTS: 1959630
+ FragOffs = GetNameFragmentOffsetEx(pPathStop->ItemIndex, pPathStop->field_C);
+ if(NextDB.pDB != NULL)
+ {
+ // HOTS: 1959649
+ NextDB.pDB->sub_1958D70(pStruct1C, FragOffs);
+ }
+ else
+ {
+ // HOTS: 1959654
+ IndexStruct_174.CopyNameFragment(pStruct1C, FragOffs);
+ }
+ }
+ else
+ {
+ // HOTS: 1959665
+ // Insert one character to the path being built
+ pStruct40->array_00.InsertOneItem_CHAR(FrgmDist_LoBits.CharArray[pPathStop->ItemIndex]);
+ }
+
+ // HOTS: 19596AE
+ pPathStop->field_8 = pStruct40->array_00.ItemCount;
+
+ // HOTS: 19596b6
+ if(FileNameIndexes.IsItemPresent(pPathStop->ItemIndex))
+ {
+ // HOTS: 19596D1
+ if(pPathStop->field_10 == 0xFFFFFFFF)
+ {
+ // HOTS: 19596D9
+ pPathStop->field_10 = FileNameIndexes.GetItemValue(pPathStop->ItemIndex);
+ }
+ else
+ {
+ pPathStop->field_10++;
+ }
+
+ // HOTS: 1959755
+ pStruct1C->szFoundPath = pStruct40->array_00.FirstValid.Chars;
+ pStruct1C->cchFoundPath = pStruct40->array_00.ItemCount;
+ pStruct1C->FileNameIndex = pPathStop->field_10;
+ return true;
+ }
+ }
+ else
+ {
+ // HOTS: 19596E9
+ if(pStruct40->ItemCount == 1)
+ {
+ pStruct40->SearchPhase = CASC_SEARCH_FINISHED;
+ return false;
+ }
+
+ // HOTS: 19596F5
+ pPathStop = pStruct40->PathStops.FirstValid.PathStopPtr + pStruct40->ItemCount - 1;
+ pPathStop->ItemIndex++;
+
+ pPathStop = pStruct40->PathStops.FirstValid.PathStopPtr + pStruct40->ItemCount - 2;
+ edi = pPathStop->field_8;
+
+ if(edi > pStruct40->array_00.MaxItemCount)
+ {
+ // HOTS: 1959717
+ NewMaxItemCount = edi;
+
+ if(pStruct40->array_00.MaxItemCount > (edi / 2))
+ {
+ if(pStruct40->array_00.MaxItemCount > 0x7FFFFFFF)
+ {
+ NewMaxItemCount = 0xFFFFFFFF;
+ }
+ else
+ {
+ NewMaxItemCount = pStruct40->array_00.MaxItemCount + pStruct40->array_00.MaxItemCount;
+ }
+ }
+
+ pStruct40->array_00.SetMaxItems_CHARS(NewMaxItemCount);
+ }
+
+ // HOTS: 1959749
+ pStruct40->array_00.ItemCount = edi;
+ pStruct40->ItemCount--;
+ }
+ }
+}
+
+// HOTS: 1958B00
+bool TFileNameDatabase::sub_1958B00(TMndxFindResult * pStruct1C)
+{
+ TStruct40 * pStruct40 = pStruct1C->pStruct40;
+ LPBYTE pbPathName = (LPBYTE)pStruct1C->szSearchMask;
+ DWORD CollisionIndex;
+ DWORD FragmentOffset;
+ DWORD SaveCharIndex;
+ DWORD ItemIndex;
+ DWORD FragOffs;
+ DWORD var_4;
+
+ ItemIndex = pbPathName[pStruct40->CharIndex] ^ (pStruct40->ItemIndex << 0x05) ^ pStruct40->ItemIndex;
+ ItemIndex = ItemIndex & NameFragIndexMask;
+ if(pStruct40->ItemIndex == NameFragTable.NameFragArray[ItemIndex].ItemIndex)
+ {
+ // HOTS: 1958B45
+ FragmentOffset = NameFragTable.NameFragArray[ItemIndex].FragOffs;
+ if((FragmentOffset & 0xFFFFFF00) == 0xFFFFFF00)
+ {
+ // HOTS: 1958B88
+ pStruct40->array_00.InsertOneItem_CHAR((char)FragmentOffset);
+ pStruct40->ItemIndex = NameFragTable.NameFragArray[ItemIndex].NextIndex;
+ pStruct40->CharIndex++;
+ return true;
+ }
+
+ // HOTS: 1958B59
+ if(NextDB.pDB != NULL)
+ {
+ if(!NextDB.pDB->sub_1959010(pStruct1C, FragmentOffset))
+ return false;
+ }
+ else
+ {
+ if(!IndexStruct_174.CheckAndCopyNameFragment(pStruct1C, FragmentOffset))
+ return false;
+ }
+
+ // HOTS: 1958BCA
+ pStruct40->ItemIndex = NameFragTable.NameFragArray[ItemIndex].NextIndex;
+ return true;
+ }
+
+ // HOTS: 1958BE5
+ CollisionIndex = sub_1959CB0(pStruct40->ItemIndex) + 1;
+ if(!Struct68_00.IsItemPresent(CollisionIndex))
+ return false;
+
+ pStruct40->ItemIndex = (CollisionIndex - pStruct40->ItemIndex - 1);
+ var_4 = 0xFFFFFFFF;
+
+ // HOTS: 1958C20
+ for(;;)
+ {
+ if(Struct68_D0.IsItemPresent(pStruct40->ItemIndex))
+ {
+ // HOTS: 1958C0E
+ if(var_4 == 0xFFFFFFFF)
+ {
+ // HOTS: 1958C4B
+ var_4 = Struct68_D0.GetItemValue(pStruct40->ItemIndex);
+ }
+ else
+ {
+ var_4++;
+ }
+
+ // HOTS: 1958C62
+ SaveCharIndex = pStruct40->CharIndex;
+
+ FragOffs = GetNameFragmentOffsetEx(pStruct40->ItemIndex, var_4);
+ if(NextDB.pDB != NULL)
+ {
+ // HOTS: 1958CCB
+ if(NextDB.pDB->sub_1959010(pStruct1C, FragOffs))
+ return true;
+ }
+ else
+ {
+ // HOTS: 1958CD6
+ if(IndexStruct_174.CheckAndCopyNameFragment(pStruct1C, FragOffs))
+ return true;
+ }
+
+ // HOTS: 1958CED
+ if(SaveCharIndex != pStruct40->CharIndex)
+ return false;
+ }
+ else
+ {
+ // HOTS: 1958CFB
+ if(FrgmDist_LoBits.ByteArray[pStruct40->ItemIndex] == pStruct1C->szSearchMask[pStruct40->CharIndex])
+ {
+ // HOTS: 1958D11
+ pStruct40->array_00.InsertOneItem_CHAR(FrgmDist_LoBits.ByteArray[pStruct40->ItemIndex]);
+ pStruct40->CharIndex++;
+ return true;
+ }
+ }
+
+ // HOTS: 1958D11
+ pStruct40->ItemIndex++;
+ CollisionIndex++;
+
+ if(!Struct68_00.IsItemPresent(CollisionIndex))
+ break;
+ }
+
+ return false;
+}
+
+// HOTS: 1957EF0
+bool TFileNameDatabase::FindFileInDatabase(TMndxFindResult * pStruct1C)
+{
+ TStruct40 * pStruct40 = pStruct1C->pStruct40;
+
+ pStruct40->ItemIndex = 0;
+ pStruct40->CharIndex = 0;
+ pStruct40->SearchPhase = CASC_SEARCH_INITIALIZING;
+
+ if(pStruct1C->cchSearchMask > 0)
+ {
+ while(pStruct40->CharIndex < pStruct1C->cchSearchMask)
+ {
+ // HOTS: 01957F12
+ if(!CheckNextPathFragment(pStruct1C))
+ return false;
+ }
+ }
+
+ // HOTS: 1957F26
+ if(!FileNameIndexes.IsItemPresent(pStruct40->ItemIndex))
+ return false;
+
+ pStruct1C->szFoundPath = pStruct1C->szSearchMask;
+ pStruct1C->cchFoundPath = pStruct1C->cchSearchMask;
+ pStruct1C->FileNameIndex = FileNameIndexes.GetItemValue(pStruct40->ItemIndex);
+ return true;
+}
+
+// HOTS: 1959790
+int TFileNameDatabase::LoadFromStream(TByteStream & InStream)
+{
+ DWORD dwBitMask;
+ int nError;
+
+ nError = Struct68_00.LoadFromStream_Exchange(InStream);
+ if(nError != ERROR_SUCCESS)
+ return nError;
+
+ nError = FileNameIndexes.LoadFromStream_Exchange(InStream);
+ if(nError != ERROR_SUCCESS)
+ return nError;
+
+ nError = Struct68_D0.LoadFromStream_Exchange(InStream);
+ if(nError != ERROR_SUCCESS)
+ return nError;
+
+ // HOTS: 019597CD
+ nError = FrgmDist_LoBits.LoadBytes_Copy(InStream);
+ if(nError != ERROR_SUCCESS)
+ return nError;
+
+ nError = FrgmDist_HiBits.LoadFromStream_Exchange(InStream);
+ if(nError != ERROR_SUCCESS)
+ return nError;
+
+ // HOTS: 019597F5
+ nError = IndexStruct_174.LoadFromStream_Exchange(InStream);
+ if(nError != ERROR_SUCCESS)
+ return nError;
+
+ // HOTS: 0195980A
+ if(Struct68_D0.ValidItemCount != 0 && IndexStruct_174.NameFragments.ItemCount == 0)
+ {
+ TFileNameDatabase * pNextDB = new TFileNameDatabase;
+
+ nError = NextDB.SetDatabase(pNextDB);
+ if(nError != ERROR_SUCCESS)
+ return nError;
+
+ if(NextDB.pDB == NULL)
+ return ERROR_NOT_ENOUGH_MEMORY;
+
+ nError = NextDB.pDB->LoadFromStream(InStream);
+ if(nError != ERROR_SUCCESS)
+ return nError;
+ }
+
+ // HOTS: 0195986B
+ nError = NameFragTable.LoadFragmentInfos_Copy(InStream);
+ if(nError != ERROR_SUCCESS)
+ return nError;
+
+ NameFragIndexMask = NameFragTable.ItemCount - 1;
+
+ nError = InStream.GetValue_DWORD(field_214);
+ if(nError != ERROR_SUCCESS)
+ return nError;
+
+ nError = InStream.GetValue_DWORD(dwBitMask);
+ if(nError != ERROR_SUCCESS)
+ return nError;
+
+ return Struct10.sub_1957800(dwBitMask);
+}
+
+// HOTS: 19598D0
+int TFileNameDatabase::LoadFromStream_Exchange(TByteStream & InStream)
+{
+ TFileNameDatabase TempDatabase;
+ ARRAY_POINTER Pointer;
+ DWORD dwSignature;
+ int nError;
+
+ // Get pointer to MAR signature
+ nError = InStream.GetBytes(sizeof(DWORD), &Pointer);
+ if(nError != ERROR_SUCCESS)
+ return nError;
+
+ // Verify the signature
+ dwSignature = Pointer.Uint32s[0];
+ if(dwSignature != CASC_MAR_SIGNATURE)
+ return ERROR_BAD_FORMAT;
+
+ nError = TempDatabase.LoadFromStream(InStream);
+ if(nError != ERROR_SUCCESS)
+ return nError;
+
+ MarStream.ExchangeWith(InStream);
+ ExchangeWith(TempDatabase);
+ return ERROR_SUCCESS;
+}
+
+//-----------------------------------------------------------------------------
+// TFileNameDatabasePtr functions
+
+// HOTS: 01956D70
+TFileNameDatabasePtr::TFileNameDatabasePtr()
+{
+ pDB = NULL;
+}
+
+TFileNameDatabasePtr::~TFileNameDatabasePtr()
+{
+ delete pDB;
+}
+
+// HOTS: 1956C60
+int TFileNameDatabasePtr::FindFileInDatabase(TMndxFindResult * pStruct1C)
+{
+ int nError = ERROR_SUCCESS;
+
+ if(pDB == NULL)
+ return ERROR_INVALID_PARAMETER;
+
+ nError = pStruct1C->CreateStruct40();
+ if(nError != ERROR_SUCCESS)
+ return nError;
+
+ if(!pDB->FindFileInDatabase(pStruct1C))
+ nError = ERROR_FILE_NOT_FOUND;
+
+ pStruct1C->FreeStruct40();
+ return nError;
+}
+
+// HOTS: 1956CE0
+int TFileNameDatabasePtr::sub_1956CE0(TMndxFindResult * pStruct1C, bool * pbFindResult)
+{
+ int nError = ERROR_SUCCESS;
+
+ if(pDB == NULL)
+ return ERROR_INVALID_PARAMETER;
+
+ // Create the pStruct40, if not initialized yet
+ if(pStruct1C->pStruct40 == NULL)
+ {
+ nError = pStruct1C->CreateStruct40();
+ if(nError != ERROR_SUCCESS)
+ return nError;
+ }
+
+ *pbFindResult = pDB->sub_1959460(pStruct1C);
+ return nError;
+}
+
+// HOTS: 1956D20
+int TFileNameDatabasePtr::GetFileNameCount(PDWORD PtrFileNameCount)
+{
+ if(pDB == NULL)
+ return ERROR_INVALID_PARAMETER;
+
+ PtrFileNameCount[0] = pDB->FileNameIndexes.ValidItemCount;
+ return ERROR_SUCCESS;
+}
+
+// HOTS: 1956DA0
+int TFileNameDatabasePtr::CreateDatabase(LPBYTE pbMarData, DWORD cbMarData)
+{
+ TFileNameDatabase * pDatabase;
+ TByteStream ByteStream;
+ int nError;
+
+ if(pbMarData == NULL && cbMarData != 0)
+ return ERROR_INVALID_PARAMETER;
+
+ pDatabase = new TFileNameDatabase;
+ if(pDatabase == NULL)
+ return ERROR_NOT_ENOUGH_MEMORY;
+
+ nError = ByteStream.SetByteBuffer(pbMarData, cbMarData);
+ if(nError != ERROR_SUCCESS)
+ return nError;
+
+ // HOTS: 1956E11
+ nError = pDatabase->LoadFromStream_Exchange(ByteStream);
+ if(nError != ERROR_SUCCESS)
+ return nError;
+
+ pDB = pDatabase;
+ return ERROR_SUCCESS;
+}
+
+// HOTS: 19584B0
+int TFileNameDatabasePtr::SetDatabase(TFileNameDatabase * pNewDB)
+{
+ if(pNewDB != NULL && pDB == pNewDB)
+ return ERROR_INVALID_PARAMETER;
+
+ if(pDB != NULL)
+ delete pDB;
+ pDB = pNewDB;
+ return ERROR_SUCCESS;
+}
+
+//-----------------------------------------------------------------------------
+// Local functions - MAR file
+
+// HOTS: 00E94180
+static void MAR_FILE_CreateDatabase(PMAR_FILE pMarFile)
+{
+ pMarFile->pDatabasePtr = new TFileNameDatabasePtr;
+ if(pMarFile->pDatabasePtr != NULL)
+ pMarFile->pDatabasePtr->CreateDatabase(pMarFile->pbMarData, pMarFile->cbMarData);
+}
+
+static int MAR_FILE_SearchFile(PMAR_FILE pMarFile, TMndxFindResult * pStruct1C)
+{
+ return pMarFile->pDatabasePtr->FindFileInDatabase(pStruct1C);
+}
+
+static void MAR_FILE_Destructor(PMAR_FILE pMarFile)
+{
+ if(pMarFile != NULL)
+ {
+ if(pMarFile->pDatabasePtr != NULL)
+ delete pMarFile->pDatabasePtr;
+ if(pMarFile->pbMarData != NULL)
+ CASC_FREE(pMarFile->pbMarData);
+
+ CASC_FREE(pMarFile);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Package functions
+
+// TODO: When working, increment these values to lower number of (re)allocations
+#define CASC_PACKAGES_INIT 0x10
+#define CASC_PACKAGES_DELTA 0x10
+
+static PCASC_PACKAGES AllocatePackages(size_t nNameEntries, size_t nNameBufferMax)
+{
+ PCASC_PACKAGES pPackages;
+ size_t cbToAllocate;
+
+ // Allocate space
+ cbToAllocate = sizeof(CASC_PACKAGES) + (nNameEntries * sizeof(CASC_PACKAGE)) + nNameBufferMax;
+ pPackages = (PCASC_PACKAGES)CASC_ALLOC(BYTE, cbToAllocate);
+ if(pPackages != NULL)
+ {
+ // Fill the structure
+ memset(pPackages, 0, cbToAllocate);
+
+ // Init the list entries
+ pPackages->szNameBuffer = (char *)(&pPackages->Packages[nNameEntries]);
+ pPackages->NameEntries = nNameEntries;
+ pPackages->NameBufferUsed = 0;
+ pPackages->NameBufferMax = nNameBufferMax;
+ }
+
+ return pPackages;
+}
+
+static PCASC_PACKAGES InsertToPackageList(
+ PCASC_PACKAGES pPackages,
+ const char * szFileName,
+ size_t cchFileName,
+ size_t nPackageIndex)
+{
+ size_t nNewNameEntries = pPackages->NameEntries;
+ size_t nNewNameBufferMax = pPackages->NameBufferMax;
+ size_t cbToAllocate;
+ char * szNameBuffer;
+
+ // Need to reallocate?
+ while(nPackageIndex >= nNewNameEntries)
+ nNewNameEntries = nNewNameEntries + CASC_PACKAGES_DELTA;
+ if((pPackages->NameBufferUsed + cchFileName + 1) > nNewNameBufferMax)
+ nNewNameBufferMax = nNewNameBufferMax + 0x1000;
+
+ // If any of the two variables overflowed, we need to reallocate the name list
+ if(nNewNameEntries > pPackages->NameEntries || nNewNameBufferMax > pPackages->NameBufferMax)
+ {
+ PCASC_PACKAGES pOldPackages = pPackages;
+
+ // Allocate new name list
+ cbToAllocate = sizeof(CASC_PACKAGES) + (nNewNameEntries * sizeof(CASC_PACKAGE)) + nNewNameBufferMax;
+ pPackages = (PCASC_PACKAGES)CASC_ALLOC(BYTE, cbToAllocate);
+ if(pPackages == NULL)
+ return NULL;
+
+ // Copy the old entries
+ memset(pPackages, 0, cbToAllocate);
+ pPackages->szNameBuffer = szNameBuffer = (char *)(&pPackages->Packages[nNewNameEntries]);
+ memcpy(pPackages->szNameBuffer, pOldPackages->szNameBuffer, pOldPackages->NameBufferUsed);
+
+ // Copy the old entries
+ for(size_t i = 0; i < pOldPackages->NameEntries; i++)
+ {
+ if(pOldPackages->Packages[i].szFileName != NULL)
+ {
+ pPackages->Packages[i].szFileName = pPackages->szNameBuffer + (pOldPackages->Packages[i].szFileName - pOldPackages->szNameBuffer);
+ pPackages->Packages[i].nLength = pOldPackages->Packages[i].nLength;
+ }
+ }
+
+ // Fill the limits
+ pPackages->NameEntries = nNewNameEntries;
+ pPackages->NameBufferUsed = pOldPackages->NameBufferUsed;
+ pPackages->NameBufferMax = nNewNameBufferMax;
+
+ // Switch the name lists
+ CASC_FREE(pOldPackages);
+ }
+
+ // The slot is expected to be empty at the moment
+ assert(pPackages->Packages[nPackageIndex].szFileName == NULL);
+ assert(pPackages->Packages[nPackageIndex].nLength == 0);
+
+ // Set the file name entry
+ szNameBuffer = pPackages->szNameBuffer + pPackages->NameBufferUsed;
+ pPackages->Packages[nPackageIndex].szFileName = szNameBuffer;
+ pPackages->Packages[nPackageIndex].nLength = cchFileName;
+ memcpy(szNameBuffer, szFileName, cchFileName);
+ pPackages->NameBufferUsed += (cchFileName + 1);
+ return pPackages;
+}
+
+static int LoadPackageNames(TCascStorage * hs)
+{
+ TMndxFindResult Struct1C;
+ PCASC_PACKAGES pPackages = NULL;
+ PMAR_FILE pMarFile;
+
+ // Sanity checks
+ assert(hs->pMndxInfo != NULL);
+
+ // Prepare the file name search in the top level directory
+ pMarFile = hs->pMndxInfo->pMarFile1;
+ Struct1C.SetSearchPath("", 0);
+
+ // Allocate initial name list structure
+ pPackages = AllocatePackages(CASC_PACKAGES_INIT, 0x1000);
+ if(pPackages == NULL)
+ return ERROR_NOT_ENOUGH_MEMORY;
+
+ // Keep searching as long as we find something
+ for(;;)
+ {
+ bool bFindResult = false;
+
+ // Search the next file name
+ pMarFile->pDatabasePtr->sub_1956CE0(&Struct1C, &bFindResult);
+ if(bFindResult == false)
+ break;
+
+ // Insert the found name to the top level directory list
+ pPackages = InsertToPackageList(pPackages, Struct1C.szFoundPath, Struct1C.cchFoundPath, Struct1C.FileNameIndex);
+ if(pPackages == NULL)
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ // Set the name list to the CASC storage structure
+ hs->pPackages = pPackages;
+ return ERROR_SUCCESS;
+}
+
+PCASC_PACKAGE FindMndxPackage(TCascStorage * hs, const char * szFileName)
+{
+ PCASC_PACKAGE pMatching = NULL;
+ PCASC_PACKAGE pPackage;
+ size_t nMaxLength = 0;
+ size_t nLength = strlen(szFileName);
+
+ // Packages must be loaded
+ assert(hs->pPackages != NULL);
+ pPackage = hs->pPackages->Packages;
+
+ // Find the longest matching name
+ for(size_t i = 0; i < hs->pPackages->NameEntries; i++, pPackage++)
+ {
+ if(pPackage->szFileName != NULL && pPackage->nLength < nLength && pPackage->nLength > nMaxLength)
+ {
+ // Compare the package name
+ if(!strncmp(szFileName, pPackage->szFileName, pPackage->nLength))
+ {
+ pMatching = pPackage;
+ nMaxLength = pPackage->nLength;
+ }
+ }
+ }
+
+ // Give the package pointer or NULL if not found
+ return pMatching;
+}
+
+static bool FillFindData(TCascSearch * pSearch, PCASC_FIND_DATA pFindData, TMndxFindResult * pStruct1C)
+{
+ CASC_ROOT_KEY_INFO RootKeyInfo;
+ TCascStorage * hs = pSearch->hs;
+ PCASC_PACKAGE pPackage;
+ char * szStrippedName;
+ int nError;
+
+ // Sanity check
+ assert(pStruct1C->cchFoundPath < MAX_PATH);
+
+ // Fill the file name
+ memcpy(pFindData->szFileName, pStruct1C->szFoundPath, pStruct1C->cchFoundPath);
+ pFindData->szFileName[pStruct1C->cchFoundPath] = 0;
+ pFindData->dwFileSize = CASC_INVALID_SIZE;
+
+ // Fill the file size
+ pPackage = FindMndxPackage(hs, pFindData->szFileName);
+ if(pPackage != NULL)
+ {
+ // Cut the package name off the full path
+ szStrippedName = pFindData->szFileName + pPackage->nLength;
+ while(szStrippedName[0] == '/')
+ szStrippedName++;
+
+ nError = SearchMndxInfo(hs->pMndxInfo, szStrippedName, (DWORD)(pPackage - hs->pPackages->Packages), &RootKeyInfo);
+ if(nError == ERROR_SUCCESS)
+ {
+ pFindData->dwFileSize = (DWORD)RootKeyInfo.FileSize;
+ }
+ }
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Public functions - MNDX info
+
+int LoadMndxRootFile(TCascStorage * hs, LPBYTE pbRootFile, DWORD cbRootFile)
+{
+ PFILE_MNDX_HEADER pMndxHeader = (PFILE_MNDX_HEADER)pbRootFile;
+ PCASC_MNDX_INFO pMndxInfo;
+ FILE_MAR_INFO MarInfo;
+ PMAR_FILE pMarFile;
+ LPBYTE pbRootFileEnd = pbRootFile + cbRootFile;
+ DWORD cbToAllocate;
+ DWORD dwFilePointer = 0;
+ DWORD i;
+ int nError = ERROR_SUCCESS;
+
+ // Check signature and the other variables
+ if(pMndxHeader->Signature != CASC_MNDX_SIGNATURE || pMndxHeader->FormatVersion > 2 || pMndxHeader->FormatVersion < 1)
+ return ERROR_BAD_FORMAT;
+
+ // Allocate space for the CASC_MNDX_INFO structure
+ pMndxInfo = CASC_ALLOC(CASC_MNDX_INFO, 1);
+ if(pMndxInfo == NULL)
+ return ERROR_NOT_ENOUGH_MEMORY;
+
+ // Copy the header into the MNDX info
+ memset(pMndxInfo, 0, sizeof(CASC_MNDX_INFO));
+ pMndxInfo->HeaderVersion = pMndxHeader->HeaderVersion;
+ pMndxInfo->FormatVersion = pMndxHeader->FormatVersion;
+ dwFilePointer += sizeof(FILE_MNDX_HEADER);
+
+ // Header version 2 has 2 extra fields that we need to load
+ if(pMndxInfo->HeaderVersion == 2)
+ {
+ if(!RootFileRead(pbRootFile + dwFilePointer, pbRootFileEnd, &pMndxInfo->field_1C, sizeof(DWORD) + sizeof(DWORD)))
+ return ERROR_FILE_CORRUPT;
+ dwFilePointer += sizeof(DWORD) + sizeof(DWORD);
+ }
+
+ // Load the rest of the file header
+ if(!RootFileRead(pbRootFile + dwFilePointer, pbRootFileEnd, &pMndxInfo->MarInfoOffset, 0x1C))
+ return ERROR_FILE_CORRUPT;
+
+ // Verify the structure
+ if(pMndxInfo->MarInfoCount > CASC_MAX_MAR_FILES || pMndxInfo->MarInfoSize != sizeof(FILE_MAR_INFO))
+ return ERROR_FILE_CORRUPT;
+
+ // Load all MAR infos
+ for(i = 0; i < pMndxInfo->MarInfoCount; i++)
+ {
+ // Load the n-th MAR info
+ dwFilePointer = pMndxInfo->MarInfoOffset + (pMndxInfo->MarInfoSize * i);
+ if(!RootFileRead(pbRootFile + dwFilePointer, pbRootFileEnd, &MarInfo, sizeof(FILE_MAR_INFO)))
+ return ERROR_FILE_CORRUPT;
+
+ // Allocate MAR_FILE structure
+ pMarFile = CASC_ALLOC(MAR_FILE, 1);
+ if(pMarFile == NULL)
+ {
+ nError = ERROR_NOT_ENOUGH_MEMORY;
+ break;
+ }
+
+ // Allocate space for the MAR data
+ pMarFile->pDatabasePtr = NULL;
+ pMarFile->pbMarData = CASC_ALLOC(BYTE, MarInfo.MarDataSize);
+ pMarFile->cbMarData = MarInfo.MarDataSize;
+ if(pMarFile->pbMarData == NULL)
+ {
+ nError = ERROR_NOT_ENOUGH_MEMORY;
+ break;
+ }
+
+ // Read the MAR data
+ if(!RootFileRead(pbRootFile + MarInfo.MarDataOffset, pbRootFileEnd, pMarFile->pbMarData, pMarFile->cbMarData))
+ {
+ nError = ERROR_FILE_CORRUPT;
+ break;
+ }
+
+ // HOTS: 00E94FF1
+ MAR_FILE_CreateDatabase(pMarFile);
+ if(i == 0)
+ pMndxInfo->pMarFile1 = pMarFile;
+ if(i == 1)
+ pMndxInfo->pMarFile2 = pMarFile;
+ if(i == 2)
+ pMndxInfo->pMarFile3 = pMarFile;
+ }
+
+ // All three MAR files must be loaded
+ // HOTS: 00E9503B
+ if(nError == ERROR_SUCCESS)
+ {
+ if(pMndxInfo->pMarFile1 == NULL || pMndxInfo->pMarFile2 == NULL || pMndxInfo->pMarFile3 == NULL)
+ nError = ERROR_BAD_FORMAT;
+ if(pMndxInfo->MndxEntrySize != sizeof(CASC_MNDX_ENTRY))
+ nError = ERROR_BAD_FORMAT;
+ }
+
+ // Load the complete array of MNDX entries
+ if(nError == ERROR_SUCCESS)
+ {
+ TFileNameDatabasePtr * pDbPtr = pMndxInfo->pMarFile2->pDatabasePtr;
+ DWORD FileNameCount;
+
+ nError = pDbPtr->GetFileNameCount(&FileNameCount);
+ if(nError == ERROR_SUCCESS && FileNameCount == pMndxInfo->MndxEntriesValid)
+ {
+ cbToAllocate = pMndxInfo->MndxEntriesTotal * pMndxInfo->MndxEntrySize;
+ pMndxInfo->pMndxEntries = (PCASC_MNDX_ENTRY)CASC_ALLOC(BYTE, cbToAllocate);
+ if(pMndxInfo->pMndxEntries != NULL)
+ {
+ if(!RootFileRead(pbRootFile + pMndxInfo->MndxEntriesOffset, pbRootFileEnd, pMndxInfo->pMndxEntries, cbToAllocate))
+ nError = ERROR_FILE_CORRUPT;
+ }
+ else
+ nError = ERROR_NOT_ENOUGH_MEMORY;
+ }
+ else
+ nError = ERROR_FILE_CORRUPT;
+ }
+
+ // Pick the valid MNDX entries and put them to a separate array
+ if(nError == ERROR_SUCCESS)
+ {
+ assert(pMndxInfo->MndxEntriesValid <= pMndxInfo->MndxEntriesTotal);
+ pMndxInfo->ppValidEntries = CASC_ALLOC(PCASC_MNDX_ENTRY, pMndxInfo->MndxEntriesValid + 1);
+ if(pMndxInfo->ppValidEntries != NULL)
+ {
+ PCASC_MNDX_ENTRY pMndxEntry = pMndxInfo->pMndxEntries;
+ DWORD ValidEntryCount = 1; // edx
+ DWORD nIndex1 = 0;
+
+ // The first entry is always valid
+ pMndxInfo->ppValidEntries[nIndex1++] = pMndxInfo->pMndxEntries;
+
+ // Put the remaining entries
+ for(i = 0; i < pMndxInfo->MndxEntriesTotal; i++, pMndxEntry++)
+ {
+ if(ValidEntryCount > pMndxInfo->MndxEntriesValid)
+ break;
+
+ if(pMndxEntry->Flags & 0x80000000)
+ {
+ pMndxInfo->ppValidEntries[nIndex1++] = pMndxEntry + 1;
+ ValidEntryCount++;
+ }
+ }
+
+ // Verify the final number of valid entries
+ if((ValidEntryCount - 1) != pMndxInfo->MndxEntriesValid)
+ nError = ERROR_BAD_FORMAT;
+
+ // Mark the MNDX info as fully loaded
+ pMndxInfo->bRootFileLoaded = true;
+ }
+ else
+ nError = ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ // Save the MNDX info to the archive storage
+ if(nError == ERROR_SUCCESS)
+ {
+ // Store the MNDX database into the archive
+ hs->pMndxInfo = pMndxInfo;
+ pMndxInfo = NULL;
+
+#if defined(_DEBUG) && defined(_X86_) && defined(CASCLIB_TEST)
+// CascDumpNameFragTable("E:\\casc-name-fragment-table.txt", hs->pMndxInfo->pMarFile1);
+// CascDumpFileNames("E:\\casc-listfile.txt", hs->pMndxInfo->pMarFile1);
+ TestMndxRootFile(hs->pMndxInfo);
+#endif
+ // Load the top level entries
+ nError = LoadPackageNames(hs);
+ }
+
+ // If anything failed, free the memory remaining allocated
+ if(nError != ERROR_SUCCESS)
+ {
+ if(pMndxInfo != NULL)
+ FreeMndxInfo(pMndxInfo);
+ pMndxInfo = NULL;
+ }
+
+ return nError;
+}
+
+int SearchMndxInfo(PCASC_MNDX_INFO pMndxInfo, const char * szFileName, DWORD dwPackage, PCASC_ROOT_KEY_INFO pFoundInfo)
+{
+ PCASC_MNDX_ENTRY pMndxEntry;
+ TMndxFindResult Struct1C;
+
+ // Search the database for the file name
+ if(pMndxInfo->bRootFileLoaded)
+ {
+ Struct1C.SetSearchPath(szFileName, strlen(szFileName));
+
+ // Search the file name in the second MAR info (the one with stripped package names)
+ if(MAR_FILE_SearchFile(pMndxInfo->pMarFile2, &Struct1C) != ERROR_SUCCESS)
+ return ERROR_FILE_NOT_FOUND;
+
+ // The found MNDX index must fall into range of valid MNDX entries
+ if(Struct1C.FileNameIndex < pMndxInfo->MndxEntriesValid)
+ {
+ // HOTS: E945F4
+ pMndxEntry = pMndxInfo->ppValidEntries[Struct1C.FileNameIndex];
+ while((pMndxEntry->Flags & 0x00FFFFFF) != dwPackage)
+ {
+ // The highest bit serves as a terminator if set
+ if(pMndxEntry->Flags & 0x80000000)
+ return ERROR_FILE_NOT_FOUND;
+
+ pMndxEntry++;
+ }
+
+ // Fill the root info
+ memcpy(pFoundInfo->EncodingKey, pMndxEntry->EncodingKey, MD5_HASH_SIZE);
+ pFoundInfo->FileSize = pMndxEntry->FileSize;
+ pFoundInfo->Flags = (BYTE)((pMndxEntry->Flags >> 0x18) & 0x3F);
+ return ERROR_SUCCESS;
+ }
+ }
+
+ return ERROR_FILE_NOT_FOUND;
+}
+
+bool DoStorageSearch_MNDX(TCascSearch * pSearch, PCASC_FIND_DATA pFindData)
+{
+ TMndxFindResult * pStruct1C = NULL;
+ PCASC_MNDX_INFO pMndxInfo = pSearch->hs->pMndxInfo;
+ PMAR_FILE pMarFile = pMndxInfo->pMarFile3;
+ bool bFindResult = false;
+
+ // Sanity checks
+ assert(pMndxInfo != NULL);
+
+ // If the first time, allocate the structure for the search result
+ if(pSearch->pStruct1C == NULL)
+ {
+ // Create the new search structure
+ pSearch->pStruct1C = pStruct1C = new TMndxFindResult;
+ if(pSearch->pStruct1C == NULL)
+ return false;
+
+ // Setup the search mask
+ pStruct1C->SetSearchPath("", 0);
+ }
+
+ // Make shortcut for the search structure
+ assert(pSearch->pStruct1C != NULL);
+ pStruct1C = (TMndxFindResult *)pSearch->pStruct1C;
+
+ // Search the next file name (our code)
+ pMarFile->pDatabasePtr->sub_1956CE0(pStruct1C, &bFindResult);
+ if(bFindResult)
+ return FillFindData(pSearch, pFindData, pStruct1C);
+
+ return false;
+}
+
+void FreeMndxInfo(PCASC_MNDX_INFO pMndxInfo)
+{
+ if(pMndxInfo != NULL)
+ {
+ if(pMndxInfo->pMarFile1 != NULL)
+ MAR_FILE_Destructor(pMndxInfo->pMarFile1);
+ if(pMndxInfo->pMarFile2 != NULL)
+ MAR_FILE_Destructor(pMndxInfo->pMarFile2);
+ if(pMndxInfo->pMarFile3 != NULL)
+ MAR_FILE_Destructor(pMndxInfo->pMarFile3);
+ if(pMndxInfo->ppValidEntries != NULL)
+ CASC_FREE(pMndxInfo->ppValidEntries);
+ if(pMndxInfo->pMndxEntries != NULL)
+ CASC_FREE(pMndxInfo->pMndxEntries);
+ CASC_FREE(pMndxInfo);
+ }
+}
+
+//----------------------------------------------------------------------------
+// Unit tests
+
+#if defined(_DEBUG) && defined(_X86_) && defined(CASCLIB_TEST)
+
+extern "C" {
+ DWORD _cdecl sub_19573D0_x86(TFileNameDatabase * pDB, DWORD arg_0, DWORD arg_4);
+ DWORD _cdecl sub_1957EF0_x86(TFileNameDatabase * pDB, TMndxFindResult * pStruct1C);
+ bool _cdecl sub_1959460_x86(TFileNameDatabase * pDB, TMndxFindResult * pStruct1C);
+ DWORD _cdecl GetItemValue_x86(TSparseArray * pStruct, DWORD dwKey);
+ DWORD _cdecl sub_1959CB0_x86(TFileNameDatabase * pDB, DWORD dwKey);
+ DWORD _cdecl sub_1959F50_x86(TFileNameDatabase * pDB, DWORD arg_0);
+}
+
+extern "C" void * allocate_zeroed_memory_x86(size_t bytes)
+{
+ return calloc(bytes, 1);
+}
+
+extern "C" void free_memory_x86(void * ptr)
+{
+ if(ptr != NULL)
+ {
+ free(ptr);
+ }
+}
+
+static int sub_1956CE0_x86(TFileNameDatabasePtr * pDatabasePtr, TMndxFindResult * pStruct1C, bool * pbFindResult)
+{
+ int nError = ERROR_SUCCESS;
+
+ if(pDatabasePtr->pDB == NULL)
+ return ERROR_INVALID_PARAMETER;
+
+ // Create the pStruct40, if not initialized yet
+ if(pStruct1C->pStruct40 == NULL)
+ {
+ nError = pStruct1C->CreateStruct40();
+ if(nError != ERROR_SUCCESS)
+ return nError;
+ }
+
+ *pbFindResult = sub_1959460_x86(pDatabasePtr->pDB, pStruct1C);
+ return nError;
+}
+/*
+static void TestFileSearch_SubStrings(PMAR_FILE pMarFile, char * szFileName, size_t nLength)
+{
+ TMndxFindResult Struct1C_1;
+ TMndxFindResult Struct1C_2;
+
+// if(strcmp(szFileName, "mods/heroes.stormmod/base.stormassets/assets/textures/storm_temp_war3_btnstatup.dds"))
+// return;
+
+ // Perform search on anything, that is longer than 4 chars
+ while(nLength >= 4)
+ {
+ // Set a substring as search name
+ Struct1C_1.SetSearchPath(szFileName, nLength);
+ Struct1C_2.SetSearchPath(szFileName, nLength);
+ szFileName[nLength] = 0;
+
+ // Keep searching
+ for(;;)
+ {
+ bool bFindResult1 = false;
+ bool bFindResult2 = false;
+
+ // Search the next file name (orig HOTS code)
+ sub_1956CE0_x86(pMarFile->pDatabasePtr, &Struct1C_1, &bFindResult1);
+
+ // Search the next file name (our code)
+ pMarFile->pDatabasePtr->sub_1956CE0(&Struct1C_2, &bFindResult2);
+
+ // Check the result
+ assert(bFindResult1 == bFindResult2);
+ assert(Struct1C_1.cchFoundPath == Struct1C_1.cchFoundPath);
+ assert(Struct1C_1.FileNameIndex == Struct1C_2.FileNameIndex);
+ assert(strncmp(Struct1C_1.szFoundPath, Struct1C_2.szFoundPath, Struct1C_1.cchFoundPath) == 0);
+ assert(Struct1C_1.cchFoundPath < MAX_PATH);
+
+ // Stop the search in case of failure
+ if(bFindResult1 == false || bFindResult2 == false)
+ break;
+ }
+
+ // Free the search structures
+ Struct1C_1.FreeStruct40();
+ Struct1C_2.FreeStruct40();
+ nLength--;
+ }
+}
+*/
+
+static void TestFindPackage(PMAR_FILE pMarFile, const char * szPackageName)
+{
+ TMndxFindResult Struct1C;
+
+ // Search the database for the file name
+ Struct1C.SetSearchPath(szPackageName, strlen(szPackageName));
+
+ // Search the file name in the second MAR info (the one with stripped package names)
+ MAR_FILE_SearchFile(pMarFile, &Struct1C);
+}
+
+static void TestFileSearch(PMAR_FILE pMarFile, const char * szFileName)
+{
+ TMndxFindResult Struct1C_1;
+ TMndxFindResult Struct1C_2;
+ size_t nLength = strlen(szFileName);
+ char szNameBuff[MAX_PATH + 1];
+
+ // Set an empty path as search mask (?)
+ Struct1C_1.SetSearchPath(szFileName, nLength);
+ Struct1C_2.SetSearchPath(szFileName, nLength);
+
+ // Keep searching
+ for(;;)
+ {
+ bool bFindResult1 = false;
+ bool bFindResult2 = false;
+
+ // Search the next file name (orig HOTS code)
+ sub_1956CE0_x86(pMarFile->pDatabasePtr, &Struct1C_1, &bFindResult1);
+
+ // Search the next file name (our code)
+ pMarFile->pDatabasePtr->sub_1956CE0(&Struct1C_2, &bFindResult2);
+
+ assert(bFindResult1 == bFindResult2);
+ assert(Struct1C_1.cchFoundPath == Struct1C_1.cchFoundPath);
+ assert(Struct1C_1.FileNameIndex == Struct1C_2.FileNameIndex);
+ assert(strncmp(Struct1C_1.szFoundPath, Struct1C_2.szFoundPath, Struct1C_1.cchFoundPath) == 0);
+ assert(Struct1C_1.cchFoundPath < MAX_PATH);
+
+ // Stop the search in case of failure
+ if(bFindResult1 == false || bFindResult2 == false)
+ break;
+
+ // Printf the found file name
+ memcpy(szNameBuff, Struct1C_2.szFoundPath, Struct1C_2.cchFoundPath);
+ szNameBuff[Struct1C_2.cchFoundPath] = 0;
+// printf("%s \r", szNameBuff);
+
+ // Perform sub-searches on this string and its substrings that are longer than 4 chars
+// TestFileSearch_SubStrings(pMarFile, szNameBuff, Struct1C_2.cchFoundPath);
+ }
+
+ // Free the search structures
+ Struct1C_1.FreeStruct40();
+ Struct1C_2.FreeStruct40();
+}
+
+static void TestMarFile(PMAR_FILE pMarFile, const char * szFileName, size_t nLength)
+{
+ TFileNameDatabase * pDB = pMarFile->pDatabasePtr->pDB;
+ DWORD dwFileNameIndex1 = 0xFFFFFFFF;
+ DWORD dwFileNameIndex2 = 0xFFFFFFFF;
+
+ // Perform the search using original HOTS code
+ {
+ TMndxFindResult Struct1C;
+
+ Struct1C.CreateStruct40();
+ Struct1C.SetSearchPath(szFileName, nLength);
+
+ // Call the original HOTS function
+ sub_1957EF0_x86(pDB, &Struct1C);
+ dwFileNameIndex1 = Struct1C.FileNameIndex;
+ }
+
+ // Perform the search using our code
+ {
+ TMndxFindResult Struct1C;
+
+ Struct1C.CreateStruct40();
+ Struct1C.SetSearchPath(szFileName, nLength);
+
+ // Call our function
+ pDB->FindFileInDatabase(&Struct1C);
+ dwFileNameIndex2 = Struct1C.FileNameIndex;
+ }
+
+ // Compare both
+ assert(dwFileNameIndex1 == dwFileNameIndex2);
+}
+
+static void TestMndxFunctions(PMAR_FILE pMarFile)
+{
+ TFileNameDatabase * pDB = pMarFile->pDatabasePtr->pDB;
+
+ // Exercise function sub_19573D0
+ for(DWORD arg_0 = 0; arg_0 < 0x100; arg_0++)
+ {
+ for(DWORD arg_4 = 0; arg_4 < 0x100; arg_4++)
+ {
+ DWORD dwResult1 = sub_19573D0_x86(pDB, arg_0, arg_4);
+ DWORD dwResult2 = pDB->GetNameFragmentOffsetEx(arg_0, arg_4);
+
+ assert(dwResult1 == dwResult2);
+ }
+ }
+
+ // Exercise function GetItemValue
+ for(DWORD i = 0; i < 0x10000; i++)
+ {
+ DWORD dwResult1 = GetItemValue_x86(&pDB->Struct68_D0, i);
+ DWORD dwResult2 = pDB->Struct68_D0.GetItemValue(i);
+
+ assert(dwResult1 == dwResult2);
+ }
+
+ // Exercise function sub_1959CB0
+ for(DWORD i = 0; i < 0x9C; i++)
+ {
+ DWORD dwResult1 = sub_1959CB0_x86(pDB, i);
+ DWORD dwResult2 = pDB->sub_1959CB0(i);
+
+ assert(dwResult1 == dwResult2);
+ }
+
+ // Exercise function sub_1959F50
+ for(DWORD i = 0; i < 0x40; i++)
+ {
+ DWORD dwResult1 = sub_1959F50_x86(pDB, i);
+ DWORD dwResult2 = pDB->sub_1959F50(i);
+
+ assert(dwResult1 == dwResult2);
+ }
+}
+
+void TestMndxRootFile(PCASC_MNDX_INFO pMndxInfo)
+{
+ size_t nLength;
+ char szFileName[MAX_PATH+1];
+ void * pvListFile;
+
+ // Exercise low level functions and compare their results
+ // with original code from Heroes of the Storm
+ TestMndxFunctions(pMndxInfo->pMarFile1);
+ TestMndxFunctions(pMndxInfo->pMarFile2);
+ TestMndxFunctions(pMndxInfo->pMarFile3);
+
+ // Find a "mods" in the package array
+ TestFindPackage(pMndxInfo->pMarFile3, "mods/heroes.stormmod/base.stormassets/assets/textures/glow_green2.dds");
+ TestMarFile(pMndxInfo->pMarFile3, "mods/heroes.stormmod/base.stormassets/assets/textures/glow_green2.dds", 69);
+
+ // Search the package MAR file aith a path shorter than a fragment
+ TestFileSearch(pMndxInfo->pMarFile1, "mods/heroes.s");
+
+ // Test the file search
+ TestFileSearch(pMndxInfo->pMarFile1, "");
+ TestFileSearch(pMndxInfo->pMarFile2, "");
+ TestFileSearch(pMndxInfo->pMarFile3, "");
+
+ // False file search
+ TestFileSearch(pMndxInfo->pMarFile2, "assets/textures/storm_temp_hrhu");
+
+ // Open the listfile stream and initialize the listfile cache
+ pvListFile = ListFile_OpenExternal(_T("e:\\Ladik\\Appdir\\CascLib\\listfile\\listfile-hots-29049.txt"));
+ if(pvListFile != NULL)
+ {
+ // Check every file in the database
+ while((nLength = ListFile_GetNext(pvListFile, "*", szFileName, MAX_PATH)) != 0)
+ {
+ // Normalize the file name: ToLower + BackSlashToSlash
+ NormalizeFileName_LowerSlash(szFileName);
+
+ // Check the file with all three MAR files
+ TestMarFile(pMndxInfo->pMarFile1, szFileName, nLength);
+ TestMarFile(pMndxInfo->pMarFile2, szFileName, nLength);
+ TestMarFile(pMndxInfo->pMarFile3, szFileName, nLength);
+ }
+
+ ListFile_Free(pvListFile);
+ }
+}
+#endif // defined(_DEBUG) && defined(_X86_) && defined(CASCLIB_TEST)
diff --git a/dep/CascLib/src/CascMndxRoot.h b/dep/CascLib/src/CascMndxRoot.h
new file mode 100644
index 00000000000..23017642ff9
--- /dev/null
+++ b/dep/CascLib/src/CascMndxRoot.h
@@ -0,0 +1,365 @@
+/*****************************************************************************/
+/* CascMndxRoot.h Copyright (c) Ladislav Zezula 2014 */
+/*---------------------------------------------------------------------------*/
+/* Interface file for MNDX structures */
+/*---------------------------------------------------------------------------*/
+/* Date Ver Who Comment */
+/* -------- ---- --- ------- */
+/* 15.05.14 1.00 Lad Created */
+/*****************************************************************************/
+
+#ifndef __CASC_MNDX_ROOT__
+#define __CASC_MNDX_ROOT__
+
+class TFileNameDatabase;
+
+#define CASC_MAX_ENTRIES(type) (0xFFFFFFFF / sizeof(type))
+
+#define CASC_SEARCH_INITIALIZING 0
+#define CASC_SEARCH_SEARCHING 2
+#define CASC_SEARCH_FINISHED 4
+
+typedef struct _TRIPLET
+{
+ DWORD BaseValue;
+ DWORD Value2;
+ DWORD Value3;
+} TRIPLET, *PTRIPLET;
+
+typedef struct _NAME_FRAG
+{
+ DWORD ItemIndex; // Back index to various tables
+ DWORD NextIndex; // The following item index
+ DWORD FragOffs; // Higher 24 bits are 0xFFFFFF00 --> A single matching character
+ // Otherwise --> Offset to the name fragment table
+} NAME_FRAG, *PNAME_FRAG;
+
+typedef struct _PATH_STOP
+{
+ DWORD ItemIndex;
+ DWORD field_4;
+ DWORD field_8;
+ DWORD field_C;
+ DWORD field_10;
+} PATH_STOP, *PPATH_STOP;
+
+typedef union _ARRAY_POINTER
+{
+ LPBYTE Bytes; // Pointer to an octet
+ char * Chars; // Pointer to a character
+ PDWORD Uint32s; // Pointer to a DWORD
+ PTRIPLET Triplets; // Pointer to TRIPLET
+ PNAME_FRAG NameFrags; // Pointer to name fragment entry
+ PPATH_STOP PathStopPtr; // Pointer to path checkpoint
+ PULONGLONG Int64Ptr; // Pointer to 64-bit integer
+
+} ARRAY_POINTER, *PARRAY_POINTER;
+
+// Simple access to various tables within TGenericArray
+#define ByteArray ArrayPointer.Bytes
+#define CharArray ArrayPointer.Chars
+#define Uint32Array ArrayPointer.Uint32s
+#define TripletArray ArrayPointer.Triplets
+#define NameFragArray ArrayPointer.NameFrags
+
+class TByteStream
+{
+ public:
+
+ TByteStream();
+
+ void ExchangeWith(TByteStream & Target);
+ int GetBytes(DWORD cbByteCount, PARRAY_POINTER PtrArray);
+ int SkipBytes(DWORD cbByteCount);
+ int SetByteBuffer(LPBYTE pbNewMarData, DWORD cbNewMarData);
+ int GetValue_DWORD(DWORD & Value);
+ int GetValue_ItemCount(DWORD & NumberOfBytes, DWORD & ItemCount, DWORD ItemSize);
+ int GetArray_DWORDs(PARRAY_POINTER PtrArray, DWORD ItemCount);
+ int GetArray_Triplets(PARRAY_POINTER PtrArray, DWORD ItemCount);
+ int GetArray_NameTable(PARRAY_POINTER PtrArray, DWORD ItemCount);
+ int GetArray_BYTES(PARRAY_POINTER PtrArray, DWORD ItemCount);
+
+ LPBYTE pbByteData;
+ void * pvMappedFile;
+ DWORD cbByteData;
+ DWORD field_C;
+ HANDLE hFile;
+ HANDLE hMap;
+};
+
+class TGenericArray
+{
+ public:
+
+ TGenericArray();
+ ~TGenericArray();
+
+ int SetArrayValid();
+
+ void ExchangeWith(TGenericArray & Target);
+ void CopyFrom(TGenericArray & Source);
+
+ void SetMaxItems_CHARS(DWORD NewMaxItemCount);
+ void SetMaxItems_PATH_STOP(DWORD NewMaxItemCount);
+
+ void InsertOneItem_CHAR(char OneChar);
+ void InsertOneItem_PATH_STOP(PATH_STOP & NewItem);
+
+ void sub_19583A0(DWORD NewItemCount);
+
+ int LoadDwordsArray(TByteStream & InStream);
+ int LoadTripletsArray(TByteStream & InStream);
+ int LoadByteArray(TByteStream & InStream);
+ int LoadFragmentInfos(TByteStream & InStream);
+ int LoadStrings(TByteStream & InStream);
+
+ int LoadDwordsArray_Copy(TByteStream & InStream);
+ int LoadTripletsArray_Copy(TByteStream & InStream);
+ int LoadBytes_Copy(TByteStream & InStream);
+ int LoadFragmentInfos_Copy(TByteStream & InStream);
+ int LoadStringsWithCopy(TByteStream & InStream);
+
+ ARRAY_POINTER DataBuffer;
+ ARRAY_POINTER FirstValid;
+
+ ARRAY_POINTER ArrayPointer;
+ DWORD ItemCount; // Number of items in the array
+ DWORD MaxItemCount; // Capacity of the array
+ bool bIsValidArray;
+};
+
+class TBitEntryArray : public TGenericArray
+{
+ public:
+
+ TBitEntryArray();
+ ~TBitEntryArray();
+
+ DWORD GetBitEntry(DWORD EntryIndex)
+ {
+ DWORD dwItemIndex = (EntryIndex * BitsPerEntry) >> 0x05;
+ DWORD dwStartBit = (EntryIndex * BitsPerEntry) & 0x1F;
+ DWORD dwEndBit = dwStartBit + BitsPerEntry;
+ DWORD dwResult;
+
+ // If the end bit index is greater than 32,
+ // we also need to load from the next 32-bit item
+ if(dwEndBit > 0x20)
+ {
+ dwResult = (Uint32Array[dwItemIndex + 1] << (0x20 - dwStartBit)) | (Uint32Array[dwItemIndex] >> dwStartBit);
+ }
+ else
+ {
+ dwResult = Uint32Array[dwItemIndex] >> dwStartBit;
+ }
+
+ // Now we also need to mask the result by the bit mask
+ return dwResult & EntryBitMask;
+ }
+
+ void ExchangeWith(TBitEntryArray & Target);
+ int LoadFromStream(TByteStream & InStream);
+ int LoadFromStream_Exchange(TByteStream & InStream);
+
+ DWORD BitsPerEntry;
+ DWORD EntryBitMask;
+ DWORD TotalEntries;
+};
+
+class TStruct40
+{
+ public:
+
+ TStruct40();
+
+ void InitSearchBuffers();
+
+ TGenericArray array_00;
+ TGenericArray PathStops; // Array of path checkpoints
+ DWORD ItemIndex; // Current name fragment: Index to various tables
+ DWORD CharIndex;
+ DWORD ItemCount;
+ DWORD SearchPhase; // 0 = initializing, 2 = searching, 4 = finished
+};
+
+class TMndxFindResult
+{
+ public:
+
+ TMndxFindResult();
+ ~TMndxFindResult();
+
+ int CreateStruct40();
+ void FreeStruct40();
+
+ int SetSearchPath(const char * szNewSearchPath, size_t cchNewSearchPath);
+
+ const char * szSearchMask; // Search mask without wioldcards
+ size_t cchSearchMask; // Length of the search mask
+ DWORD field_8;
+ const char * szFoundPath; // Found path name
+ size_t cchFoundPath; // Length of the found path name
+ DWORD FileNameIndex; // Index of the file name
+ TStruct40 * pStruct40;
+};
+
+class TSparseArray
+{
+ public:
+
+ TSparseArray();
+
+ void ExchangeWith(TSparseArray & TargetObject);
+ int LoadFromStream(TByteStream & InStream);
+ int LoadFromStream_Exchange(TByteStream & InStream);
+
+ // Returns true if the item at n-th position is present
+ DWORD IsItemPresent(DWORD ItemIndex)
+ {
+ return (ItemBits.Uint32Array[ItemIndex >> 0x05] & (1 << (ItemIndex & 0x1F)));
+ }
+
+ DWORD GetItemValue(DWORD ItemIndex);
+
+ TGenericArray ItemBits; // Bit array for each item (1 = item is present)
+ DWORD TotalItemCount; // Total number of items in the array
+ DWORD ValidItemCount; // Number of present items in the array
+ TGenericArray BaseValues; // Array of base values for item indexes >= 0x200
+ TGenericArray ArrayDwords_38;
+ TGenericArray ArrayDwords_50;
+};
+
+class TNameIndexStruct
+{
+ public:
+
+ TNameIndexStruct();
+ ~TNameIndexStruct();
+
+ bool CheckNameFragment(TMndxFindResult * pStruct1C, DWORD dwFragOffs);
+ bool CheckAndCopyNameFragment(TMndxFindResult * pStruct1C, DWORD dwFragOffs);
+ void CopyNameFragment(TMndxFindResult * pStruct1C, DWORD dwFragOffs);
+
+ void ExchangeWith(TNameIndexStruct & Target);
+ int LoadFromStream(TByteStream & InStream);
+ int LoadFromStream_Exchange(TByteStream & InStream);
+
+ TGenericArray NameFragments;
+ TSparseArray Struct68;
+};
+
+class TStruct10
+{
+ public:
+
+ TStruct10();
+
+ void CopyFrom(TStruct10 & Target);
+ int sub_1956FD0(DWORD dwBitMask);
+ int sub_1957050(DWORD dwBitMask);
+ int sub_19572E0(DWORD dwBitMask);
+ int sub_1957800(DWORD dwBitMask);
+
+ DWORD field_0;
+ DWORD field_4;
+ DWORD field_8;
+ DWORD field_C;
+};
+
+class TFileNameDatabasePtr
+{
+ public:
+
+ TFileNameDatabasePtr();
+ ~TFileNameDatabasePtr();
+
+ int FindFileInDatabase(TMndxFindResult * pStruct1C);
+ int sub_1956CE0(TMndxFindResult * pStruct1C, bool * pbFindResult);
+
+ int GetFileNameCount(PDWORD PtrFileNameCount);
+ int CreateDatabase(LPBYTE pbMarData, DWORD cbMarData);
+ int SetDatabase(TFileNameDatabase * pNewDB);
+
+ TFileNameDatabase * pDB;
+};
+
+class TFileNameDatabase
+{
+ public:
+
+ TFileNameDatabase();
+
+ void ExchangeWith(TFileNameDatabase & Target);
+ int LoadFromStream(TByteStream & InStream);
+ int LoadFromStream_Exchange(TByteStream & InStream);
+
+ DWORD sub_1959CB0(DWORD dwHashValue);
+ DWORD sub_1959F50(DWORD arg_0);
+
+ // Retrieves the name fragment distance
+ // HOTS: 19573D0/inlined
+ DWORD GetNameFragmentOffsetEx(DWORD LoBitsIndex, DWORD HiBitsIndex)
+ {
+ return (FrgmDist_HiBits.GetBitEntry(HiBitsIndex) << 0x08) | FrgmDist_LoBits.ByteArray[LoBitsIndex];
+ }
+
+ // HOTS: 1957350, inlined
+ DWORD GetNameFragmentOffset(DWORD LoBitsIndex)
+ {
+ return GetNameFragmentOffsetEx(LoBitsIndex, Struct68_D0.GetItemValue(LoBitsIndex));
+ }
+
+ bool sub_1957B80(TMndxFindResult * pStruct1C, DWORD dwKey);
+ bool CheckNextPathFragment(TMndxFindResult * pStruct1C);
+ bool FindFileInDatabase(TMndxFindResult * pStruct1C);
+
+ void sub_1958D70(TMndxFindResult * pStruct1C, DWORD arg_4);
+ bool sub_1959010(TMndxFindResult * pStruct1C, DWORD arg_4);
+ bool sub_1958B00(TMndxFindResult * pStruct1C);
+ bool sub_1959460(TMndxFindResult * pStruct1C);
+
+ TSparseArray Struct68_00;
+ TSparseArray FileNameIndexes; // Array of file name indexes
+ TSparseArray Struct68_D0;
+
+ // This pair of arrays serves for fast conversion from name hash to fragment offset
+ TGenericArray FrgmDist_LoBits; // Array of lower 8 bits of name fragment offset
+ TBitEntryArray FrgmDist_HiBits; // Array of upper x bits of name fragment offset
+
+ TNameIndexStruct IndexStruct_174;
+ TFileNameDatabasePtr NextDB;
+
+ TGenericArray NameFragTable;
+
+ DWORD NameFragIndexMask;
+ DWORD field_214;
+ TStruct10 Struct10;
+ TByteStream MarStream;
+};
+
+typedef struct _MAR_FILE
+{
+ TFileNameDatabasePtr * pDatabasePtr;
+ LPBYTE pbMarData;
+ DWORD cbMarData;
+} MAR_FILE, *PMAR_FILE;
+
+//-----------------------------------------------------------------------------
+// Macros
+
+// Returns nonzero if the name fragment match is a single-char match
+inline bool IS_SINGLE_CHAR_MATCH(TGenericArray & Table, DWORD ItemIndex)
+{
+ return ((Table.NameFragArray[ItemIndex].FragOffs & 0xFFFFFF00) == 0xFFFFFF00);
+}
+
+//-----------------------------------------------------------------------------
+// CASC functions related to MNDX
+
+int LoadMndxRootFile(TCascStorage * hs, LPBYTE pbRootFile, DWORD cbRootFile);
+PCASC_PACKAGE FindMndxPackage(TCascStorage * hs, const char * szFileName);
+int SearchMndxInfo(PCASC_MNDX_INFO pMndxInfo, const char * szFileName, DWORD dwPackage, PCASC_ROOT_KEY_INFO pFoundInfo);
+bool DoStorageSearch_MNDX(TCascSearch * pSearch, PCASC_FIND_DATA pFindData);
+void FreeMndxInfo(PCASC_MNDX_INFO pMndxInfo);
+
+#endif // __CASC_MNDX_ROOT__
diff --git a/dep/CascLib/src/CascMndxRoot_x86.asm b/dep/CascLib/src/CascMndxRoot_x86.asm
new file mode 100644
index 00000000000..c0e787d0872
--- /dev/null
+++ b/dep/CascLib/src/CascMndxRoot_x86.asm
@@ -0,0 +1,4369 @@
+.686P
+.MODEL FLAT
+ASSUME FS: NOTHING
+
+; ---------------------------------------------------------------------------
+
+TMndxFindResult struc ; (sizeof=0x1C) ; XREF: GAME_OBJECT_03F7E848::sub_E94500_r
+szSearchMask dd ? ; XREF: TMndxFindResult__SetPath+2D_w
+ ; TMndxFindResult__Constructor+4_w ...
+cchSearchMask dd ? ; XREF: TMndxFindResult__SetPath:loc_1956E9A_w
+ ; TMndxFindResult__Constructor+6_w ...
+field_8 dd ? ; XREF: TMndxFindResult__Constructor+9_w
+szFoundPath dd ? ; XREF: TMndxFindResult__Constructor+C_w
+ ; TFileNameDatabase__FindFileInDatabase+55_w
+cchFoundPath dd ? ; XREF: TMndxFindResult__Constructor+F_w
+ ; TFileNameDatabase__FindFileInDatabase+5B_w
+FileNameIndex dd ? ; XREF: TMndxFindResult__Constructor+12_w
+ ; TFileNameDatabase__FindFileInDatabase+6B_w
+pStruct40 dd ? ; XREF: MAR_FILE__FindFileInDatabase+19_r
+ ; TMndxFindResult__SetPath:loc_1956E8C_r ...
+TMndxFindResult ends
+
+; ---------------------------------------------------------------------------
+
+TRIPLET struc ; (sizeof=0xC)
+BitIndex dd ? ; XREF: TFileNameDatabase__CheckNextPathFragment+39_r
+NextKey dd ? ; XREF: TFileNameDatabase__CheckNextPathFragment+8C_r
+ ; TSparseArray__GetItemValue:loc_1959B8F_r ...
+Distance dd ? ; XREF: TFileNameDatabase__CheckNextPathFragment+3E_r
+ ; TSparseArray__GetItemValue:loc_1959BBE_r ...
+TRIPLET ends
+
+; ---------------------------------------------------------------------------
+
+NAME_ENTRY struc ; (sizeof=0xC)
+ExpectedHashModifier dd ?
+NextHashModifier dd ? ; XREF: TArchiveDatabase__sub_1958B00+D3r
+ ; sub_1958D70+2Cr
+FragmentOffset dd ? ; XREF: TArchiveDatabase__sub_1958B00+45r
+ ; sub_1958D70+36r
+NAME_ENTRY ends
+
+; ---------------------------------------------------------------------------
+
+TStruct14 struc ; (sizeof=0x14) ; XREF: TFileNameDatabase::sub_1959460r
+HashValue dd ? ; XREF: TGenericArray__InsertItem_STRUCT14+44r
+ ; TGenericArray__InsertItem_STRUCT14+46w ...
+field_4 dd ? ; XREF: TGenericArray__InsertItem_STRUCT14+48r
+ ; TGenericArray__InsertItem_STRUCT14+4Bw ...
+field_8 dd ? ; XREF: TGenericArray__InsertItem_STRUCT14+4Er
+ ; TGenericArray__InsertItem_STRUCT14+51w ...
+field_C dd ? ; XREF: TGenericArray__InsertItem_STRUCT14+54r
+ ; TGenericArray__InsertItem_STRUCT14+57w ...
+field_10 dd ? ; XREF: TGenericArray__InsertItem_STRUCT14+5Ar
+ ; TGenericArray__InsertItem_STRUCT14+5Dw ...
+TStruct14 ends
+
+; ---------------------------------------------------------------------------
+
+TGenericArray struc ; (sizeof=0x15) ; XREF: TGenericArray::LoadDwordsArrayWithCopyr
+ ; TFileNameDatabase::LoadBytesr ...
+DataBuffer dd ? ; XREF: TMndxFindResult__CreateStruct40+24w
+ ; TMndxFindResult__CreateStruct40+35w ...
+field_4 dd ? ; XREF: TMndxFindResult__CreateStruct40+26w
+ ; TMndxFindResult__CreateStruct40+38w ...
+ItemArray dd ? ; XREF: TMndxFindResult__CreateStruct40+29w
+ ; TMndxFindResult__CreateStruct40+3Bw ...
+ItemCount dd ? ; XREF: TMndxFindResult__CreateStruct40+2Cw
+ ; TMndxFindResult__CreateStruct40+3Ew ...
+MaxItemCount dd ? ; XREF: TFileNameDatabasePtr__CreateDatabase+27o
+ ; TMndxFindResult__CreateStruct40+2Fw ...
+bIsValidArray db ? ; XREF: LoadAndVerifyIndexFileHeader+31w
+ ; TMndxFindResult__CreateStruct40+32w ...
+TGenericArray ends
+
+; ---------------------------------------------------------------------------
+
+TBitEntryArray struc ; (sizeof=0x24) ; XREF: TGenericArrayEx::LoadFromStream_Exchanger
+ ; TFileNameDatabaser
+DataBuffer dd ? ; XREF: TArchiveDatabase__Destructor+64r
+ ; TArchiveDatabase__Constructor+1A3w
+field_4 dd ? ; XREF: TArchiveDatabase__Constructor+1A9w
+ItemArray dd ? ; XREF: sub_1957350+31r
+ ; sub_19573D0+1Fr ...
+ItemCount dd ? ; XREF: TArchiveDatabase__Constructor+1B5w
+MaxItemCount dd ? ; XREF: TArchiveDatabase__Constructor+1BBw
+bIsValidArray db ? ; XREF: TArchiveDatabase__Constructor+1C1w
+ db ? ; undefined
+ db ? ; undefined
+ db ? ; undefined
+BitsPerEntry dd ? ; XREF: sub_1957350+1Fr
+ ; sub_19573D0+6r ...
+EntryBitMask dd ? ; XREF: sub_1957350:loc_19573B1r
+ ; sub_19573D0:loc_1957419r ...
+TotalEntries dd ? ; XREF: TGenericArrayEx__LoadFromStream:loc_195861Bw
+ ; TArchiveDatabase__Constructor+1D3w
+TBitEntryArray ends
+ ; TFileNameDatabase__Constructor+1D3_w
+; ---------------------------------------------------------------------------
+
+TStruct40 struc ; (sizeof=0x40)
+array_00 TGenericArray <> ; XREF: TMndxFindResult__CreateStruct40+24w
+ ; TMndxFindResult__CreateStruct40+26w ...
+ db ? ; undefined
+ db ? ; undefined
+ db ? ; undefined
+array_18 TGenericArray <> ; XREF: TMndxFindResult__CreateStruct40+35w
+ ; TMndxFindResult__CreateStruct40+38w ...
+ db ? ; undefined
+ db ? ; undefined
+ db ? ; undefined
+HashValue dd ? ; XREF: TMndxFindResult__CreateStruct40+47w
+ ; TFileNameDatabase__CheckNextPathFragment+1Ar ...
+CharIndex dd ? ; XREF: TMndxFindResult__CreateStruct40+4Aw
+ ; TFileNameDatabase__CheckNextPathFragment+11r ...
+ItemCount dd ? ; XREF: TMndxFindResult__CreateStruct40+4Dw
+ ; TStruct40__InitSearchBuffers+6Bw ...
+SearchPhase dd ? ; XREF: TMndxFindResult__CreateStruct40+50w
+ ; TFileNameDatabase__FindFileInDatabase+17w ...
+TStruct40 ends
+
+; ---------------------------------------------------------------------------
+
+TSparseArray struc ; (sizeof=0x65) ; XREF: TSparseArray::LoadFromStream_Exchange_r
+ ; TNameIndexStruct_r ...
+ItemIsPresent TGenericArray <> ; XREF: LoadAndVerifyIndexFileHeader+31_w
+ ; TFileNameDatabase__Destructor+4C_r ...
+ db ? ; undefined
+ db ? ; undefined
+ db ? ; undefined
+TotalItemCount dd ? ; XREF: TSparseArray__ExchangeWith+4D_r
+ ; TSparseArray__ExchangeWith+56_w ...
+ValidItemCount dd ? ; XREF: TFileNameDatabasePtr__GetFileNameCount:loc_1956D32_r
+ ; TSparseArray__ExchangeWith+59_r ...
+ArrayTriplets_20 TGenericArray <> ; XREF: TFileNameDatabase__Destructor+40_r
+ ; TFileNameDatabase__Destructor+94_r ...
+ db ? ; undefined
+ db ? ; undefined
+ db ? ; undefined
+ArrayDwords_38 TGenericArray <> ; XREF: TFileNameDatabasePtr__CreateDatabase+27_o
+ ; TFileNameDatabase__Destructor+34_r ...
+ db ? ; undefined
+ db ? ; undefined
+ db ? ; undefined
+ArrayDwords_50 TGenericArray <> ; XREF: TFileNameDatabase__Destructor+28_r
+ ; TFileNameDatabase__Destructor+7C_r ...
+TSparseArray ends
+
+; ---------------------------------------------------------------------------
+
+TNameIndexStruct struc ; (sizeof=0x7D) ; XREF: TNameIndexStruct::LoadFromStream_Exchange_r
+ ; TFileNameDatabaser
+NameFragments TGenericArray <> ; XREF: TFileNameDatabase__Destructor+58_r
+ ; TFileNameDatabase__LoadFromStream+82_r ...
+ db ? ; undefined
+ db ? ; undefined
+ db ? ; undefined
+Struct68 TSparseArray <> ; XREF: LoadAndVerifyIndexFileHeader+31_w
+ ; TFileNameDatabase__Destructor+28_r ...
+TNameIndexStruct ends
+
+; ---------------------------------------------------------------------------
+
+TByteStream struc ; (sizeof=0x18) ; XREF: TFileNameDatabasePtr::CreateDatabase_r
+ ; TFileNameDatabase_r
+pbData dd ? ; XREF: TByteStream__Constructor+4_w
+ ; TByteStream__IsMarDataValid+2_r ...
+pvMappedFile dd ? ; XREF: TByteStream__Constructor+6_w
+ ; TByteStream__Destructor+3_r
+cbData dd ? ; XREF: TByteStream__Constructor+9_w
+ ; TByteStream__GetBytes:loc_1959A05_r ...
+field_C dd ? ; XREF: TByteStream__Constructor+C_w
+hFile dd ? ; XREF: TByteStream__Constructor+F_w
+ ; TByteStream__Destructor:loc_19599D2_r
+hMap dd ? ; XREF: TByteStream__Constructor+12_w
+ ; TByteStream__Destructor:loc_19599C2_r
+TByteStream ends
+
+; ---------------------------------------------------------------------------
+
+TStruct10 struc ; (sizeof=0x10) ; XREF: TStruct10::sub_1957800_r
+ ; TFileNameDatabase_r
+field_0 dd ? ; XREF: sub_19572E0+24_w
+ ; TFileNameDatabase__Constructor+21A_w
+field_4 dd ? ; XREF: sub_1956FD0+28_w
+ ; sub_1956FD0:loc_1957001_w ...
+field_8 dd ? ; XREF: sub_19572E0+4A_w
+ ; sub_19572E0+5B_w ...
+field_C dd ? ; XREF: sub_1957050:loc_1957074_w
+ ; sub_1957050:loc_1957081_w ...
+TStruct10 ends
+
+; ---------------------------------------------------------------------------
+
+TFileNameDatabasePtr struc ; (sizeof=0x4) ; XREF: TFileNameDatabase_r
+ ; MAR_FILE_r
+pDatabase dd ? ; XREF: MAR_FILE__Constructor+1D_w
+ ; MAR_FILE__CreateDatabase+22_w ...
+TFileNameDatabasePtr ends
+
+; ---------------------------------------------------------------------------
+
+TFileNameDatabase struc ; (sizeof=0x240) ; XREF: TFileNameDatabase::LoadFromStream_Exchange_r
+Struct68_00 TSparseArray <> ; XREF: TFileNameDatabasePtr__CreateDatabase+27_o
+ ; TFileNameDatabase__Destructor+D9_r ...
+ db ? ; undefined
+ db ? ; undefined
+ db ? ; undefined
+FileNameIndexes TSparseArray <> ; XREF: TFileNameDatabasePtr__GetFileNameCount:loc_1956D32_r
+ ; TFileNameDatabase__Destructor+AC_r ...
+ db ? ; undefined
+ db ? ; undefined
+ db ? ; undefined
+Struct68_D0 TSparseArray <> ; XREF: TFileNameDatabase__Destructor+7C_r
+ ; TFileNameDatabase__Destructor+88_r ...
+ db ? ; undefined
+ db ? ; undefined
+ db ? ; undefined
+FrgmDist_LoBits TGenericArray <> ; XREF: TFileNameDatabase__Destructor+70_r
+ ; TFileNameDatabase__CheckNextPathFragment:loc_1957AC9_r ...
+ db ? ; undefined
+ db ? ; undefined
+ db ? ; undefined
+FrgmDist_HiBits TBitEntryArray <> ; XREF: TFileNameDatabase__Destructor+64_r
+ ; TFileNameDatabase__CheckNextPathFragment+119_r ...
+IndexStruct_174 TNameIndexStruct <> ; XREF: TFileNameDatabase__Destructor+28_r
+ ; TFileNameDatabase__Destructor+34_r ...
+ db ? ; undefined
+ db ? ; undefined
+ db ? ; undefined
+NextDB TFileNameDatabasePtr <> ; XREF: TFileNameDatabase__Destructor+1D_o
+ ; TFileNameDatabase__CheckNextPathFragment+52_r ...
+NameFragTable TGenericArray <> ; XREF: TFileNameDatabase__Destructor+E_r
+ ; TFileNameDatabase__CheckNextPathFragment+2F_r ...
+ db ? ; undefined
+ db ? ; undefined
+ db ? ; undefined
+NameFragIndexMask dd ? ; XREF: TFileNameDatabase__CheckNextPathFragment+26_r
+ ; sub_1957B80:loc_1957B95_r ...
+field_214 dd ? ; XREF: TFileNameDatabase__Constructor+20E_w
+ ; TFileNameDatabase__LoadFromStream+110_w
+Struct10 TStruct10 <> ; XREF: TFileNameDatabase__Constructor+21A_w
+ ; TFileNameDatabase__Constructor+224_w ...
+MarStream TByteStream <> ; XREF: TFileNameDatabase__Destructor+3_o
+ ; TFileNameDatabase__Constructor+214_o
+TFileNameDatabase ends
+
+; ---------------------------------------------------------------------------
+
+MAR_FILE struc ; (sizeof=0xC)
+pDatabasePtr TFileNameDatabasePtr <> ; XREF: MAR_FILE__Constructor+1D_w
+ ; MAR_FILE__CreateDatabase+22_w ...
+pbMarFileData dd ? ; XREF: MAR_FILE__Constructor+1A_w
+ ; MAR_FILE__CreateDatabase+1B_r ...
+cbMarFileData dd ? ; XREF: MAR_FILE__Constructor+12_w
+ ; MAR_FILE__CreateDatabase+18_r ...
+MAR_FILE ends
+
+.DATA
+table_1BA1818 db 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0
+ db 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0
+ db 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0
+ db 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0
+ db 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0
+ db 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0
+ db 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0
+ db 1, 0, 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
+ db 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0
+ db 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0
+ db 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 6, 0, 1, 0, 2, 0
+ db 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0
+ db 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0
+ db 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0
+ db 2, 0, 1, 0, 3 dup(7), 1, 7, 2 dup(2), 1, 7, 2 dup(3)
+ db 1, 3, 2 dup(2), 1, 7, 2 dup(4), 1, 4, 2 dup(2), 1, 4
+ db 2 dup(3), 1, 3, 2 dup(2), 1, 7, 2 dup(5), 1, 5, 2 dup(2)
+ db 1, 5, 2 dup(3), 1, 3, 2 dup(2), 1, 5, 2 dup(4), 1, 4
+ db 2 dup(2), 1, 4, 2 dup(3), 1, 3, 2 dup(2), 1, 7, 2 dup(6)
+ db 1, 6, 2 dup(2), 1, 6, 2 dup(3), 1, 3, 2 dup(2), 1, 6
+ db 2 dup(4), 1, 4, 2 dup(2), 1, 4, 2 dup(3), 1, 3, 2 dup(2)
+ db 1, 6, 2 dup(5), 1, 5, 2 dup(2), 1, 5, 2 dup(3), 1, 3
+ db 2 dup(2), 1, 5, 2 dup(4), 1, 4, 2 dup(2), 1, 4, 2 dup(3)
+ db 1, 3, 2 dup(2), 1, 3 dup(7), 1, 7, 2 dup(2), 1, 7, 2 dup(3)
+ db 1, 3, 2 dup(2), 1, 7, 2 dup(4), 1, 4, 2 dup(2), 1, 4
+ db 2 dup(3), 1, 3, 2 dup(2), 1, 7, 2 dup(5), 1, 5, 2 dup(2)
+ db 1, 5, 2 dup(3), 1, 3, 2 dup(2), 1, 5, 2 dup(4), 1, 4
+ db 2 dup(2), 1, 4, 2 dup(3), 1, 3, 2 dup(2), 1, 7, 2 dup(6)
+ db 1, 6, 2 dup(2), 1, 6, 2 dup(3), 1, 3, 2 dup(2), 1, 6
+ db 2 dup(4), 1, 4, 2 dup(2), 1, 4, 2 dup(3), 1, 3, 2 dup(2)
+ db 1, 6, 2 dup(5), 1, 5, 2 dup(2), 1, 5, 2 dup(3), 1, 3
+ db 2 dup(2), 1, 5, 2 dup(4), 1, 4, 2 dup(2), 1, 4, 2 dup(3)
+ db 1, 3, 2 dup(2), 1, 7 dup(7), 2, 3 dup(7), 3, 7, 2 dup(3)
+ db 2, 3 dup(7), 4, 7, 2 dup(4), 2, 7, 2 dup(4), 3, 4, 2 dup(3)
+ db 2, 3 dup(7), 5, 7, 2 dup(5), 2, 7, 2 dup(5), 3, 5, 2 dup(3)
+ db 2, 7, 2 dup(5), 4, 5, 2 dup(4), 2, 5, 2 dup(4), 3, 4
+ db 2 dup(3), 2, 3 dup(7), 6, 7, 2 dup(6), 2, 7, 2 dup(6)
+ db 3, 6, 2 dup(3), 2, 7, 2 dup(6), 4, 6, 2 dup(4), 2, 6
+ db 2 dup(4), 3, 4, 2 dup(3), 2, 7, 2 dup(6), 5, 6, 2 dup(5)
+ db 2, 6, 2 dup(5), 3, 5, 2 dup(3), 2, 6, 2 dup(5), 4, 5
+ db 2 dup(4), 2, 5, 2 dup(4), 3, 4, 2 dup(3), 2, 7 dup(7)
+ db 2, 3 dup(7), 3, 7, 2 dup(3), 2, 3 dup(7), 4, 7, 2 dup(4)
+ db 2, 7, 2 dup(4), 3, 4, 2 dup(3), 2, 3 dup(7), 5, 7, 2 dup(5)
+ db 2, 7, 2 dup(5), 3, 5, 2 dup(3), 2, 7, 2 dup(5), 4, 5
+ db 2 dup(4), 2, 5, 2 dup(4), 3, 4, 2 dup(3), 2, 3 dup(7)
+ db 6, 7, 2 dup(6), 2, 7, 2 dup(6), 3, 6, 2 dup(3), 2, 7
+ db 2 dup(6), 4, 6, 2 dup(4), 2, 6, 2 dup(4), 3, 4, 2 dup(3)
+ db 2, 7, 2 dup(6), 5, 6, 2 dup(5), 2, 6, 2 dup(5), 3, 5
+ db 2 dup(3), 2, 6, 2 dup(5), 4, 5, 2 dup(4), 2, 5, 2 dup(4)
+ db 3, 4, 2 dup(3), 2, 0Fh dup(7), 3, 7 dup(7), 4, 3 dup(7)
+ db 4, 7, 2 dup(4), 3, 7 dup(7), 5, 3 dup(7), 5, 7, 2 dup(5)
+ db 3, 3 dup(7), 5, 7, 2 dup(5), 4, 7, 2 dup(5), 4, 5, 2 dup(4)
+ db 3, 7 dup(7), 6, 3 dup(7), 6, 7, 2 dup(6), 3, 3 dup(7)
+ db 6, 7, 2 dup(6), 4, 7, 2 dup(6), 4, 6, 2 dup(4), 3, 3 dup(7)
+ db 6, 7, 2 dup(6), 5, 7, 2 dup(6), 5, 6, 2 dup(5), 3, 7
+ db 2 dup(6), 5, 6, 2 dup(5), 4, 6, 2 dup(5), 4, 5, 2 dup(4)
+ db 3, 0Fh dup(7), 3, 7 dup(7), 4, 3 dup(7), 4, 7, 2 dup(4)
+ db 3, 7 dup(7), 5, 3 dup(7), 5, 7, 2 dup(5), 3, 3 dup(7)
+ db 5, 7, 2 dup(5), 4, 7, 2 dup(5), 4, 5, 2 dup(4), 3, 7 dup(7)
+ db 6, 3 dup(7), 6, 7, 2 dup(6), 3, 3 dup(7), 6, 7, 2 dup(6)
+ db 4, 7, 2 dup(6), 4, 6, 2 dup(4), 3, 3 dup(7), 6, 7, 2 dup(6)
+ db 5, 7, 2 dup(6), 5, 6, 2 dup(5), 3, 7, 2 dup(6), 5, 6
+ db 2 dup(5), 4, 6, 2 dup(5), 4, 5, 2 dup(4), 3, 1Fh dup(7)
+ db 4, 0Fh dup(7), 5, 7 dup(7), 5, 3 dup(7), 5, 7, 2 dup(5)
+ db 4, 0Fh dup(7), 6, 7 dup(7), 6, 3 dup(7), 6, 7, 2 dup(6)
+ db 4, 7 dup(7), 6, 3 dup(7), 6, 7, 2 dup(6), 5, 3 dup(7)
+ db 6, 7, 2 dup(6), 5, 7, 2 dup(6), 5, 6, 2 dup(5), 4, 1Fh dup(7)
+ db 4, 0Fh dup(7), 5, 7 dup(7), 5, 3 dup(7), 5, 7, 2 dup(5)
+ db 4, 0Fh dup(7), 6, 7 dup(7), 6, 3 dup(7), 6, 7, 2 dup(6)
+ db 4, 7 dup(7), 6, 3 dup(7), 6, 7, 2 dup(6), 5, 3 dup(7)
+ db 6, 7, 2 dup(6), 5, 7, 2 dup(6), 5, 6, 2 dup(5), 4, 3Fh dup(7)
+ db 5, 1Fh dup(7), 6, 0Fh dup(7), 6, 7 dup(7), 6, 3 dup(7)
+ db 6, 7, 2 dup(6), 5, 3Fh dup(7), 5, 1Fh dup(7), 6, 0Fh dup(7)
+ db 6, 7 dup(7), 6, 3 dup(7), 6, 7, 2 dup(6), 5, 7Fh dup(7)
+ db 6, 7Fh dup(7), 6, 100h dup(7)
+
+unk_53ABE00 db 0
+
+.CODE
+
+;
+; void * operator_new_safe(size_t ByteCount, void * unk_53ABE00);
+;
+
+EXTERN _allocate_zeroed_memory_x86:PROC
+EXTERN _free_memory_x86:PROC
+
+j_operator_new_safe PROC
+ push ebp
+ mov ebp, esp
+ push [ebp+08]
+ call _allocate_zeroed_memory_x86
+ add esp, 4
+ mov esp, ebp
+ pop ebp
+ ret
+j_operator_new_safe ENDP
+
+operator_delete PROC
+ push ebp
+ mov ebp, esp
+ push [ebp+08]
+ call _free_memory_x86
+ add esp, 4
+ mov esp, ebp
+ pop ebp
+ ret
+operator_delete ENDP
+
+
+TSparseArray__GetItemValue proc near ; CODE XREF: sub_1957350+1A_p
+ ; TFileNameDatabase__CheckNextPathFragment+103_p ...
+
+arg_0 = dword ptr 8
+
+ push ebp
+ mov ebp, esp
+ mov edx, [ecx+28h]
+ push ebx
+ push esi
+ push edi
+ mov edi, [ebp+arg_0]
+ mov eax, edi
+ shr eax, 9
+ lea eax, [eax+eax*2]
+ mov esi, [edx+eax*4]
+ lea eax, [edx+eax*4]
+ mov edx, edi
+ shr edx, 6
+ and edx, 7
+ dec edx
+ cmp edx, 6 ; switch 7 cases
+ ja short loc_1959BE0 ; jumptable 01959B88 default case
+ jmp ds:off_1959C90[edx*4] ; switch jump
+
+loc_1959B8F: ; DATA XREF: .text:off_1959C90o
+ mov eax, [eax+4] ; jumptable 01959B88 case 0
+ and eax, 7Fh
+ jmp short loc_1959BDE
+; ---------------------------------------------------------------------------
+
+loc_1959B97: ; CODE XREF: TSparseArray__GetItemValue+28_j
+ ; DATA XREF: .text:off_1959C90o
+ mov edx, [eax+4] ; jumptable 01959B88 case 1
+ shr edx, 7
+ and edx, 0FFh
+ add esi, edx
+ jmp short loc_1959BE0 ; jumptable 01959B88 default case
+; ---------------------------------------------------------------------------
+
+loc_1959BA7: ; CODE XREF: TSparseArray__GetItemValue+28_j
+ ; DATA XREF: .text:off_1959C90o
+ mov eax, [eax+4] ; jumptable 01959B88 case 2
+ shr eax, 0Fh
+ and eax, 0FFh
+ jmp short loc_1959BDE
+; ---------------------------------------------------------------------------
+
+loc_1959BB4: ; CODE XREF: TSparseArray__GetItemValue+28_j
+ ; DATA XREF: .text:off_1959C90o
+ mov edx, [eax+4] ; jumptable 01959B88 case 3
+ shr edx, 17h
+ add esi, edx
+ jmp short loc_1959BE0 ; jumptable 01959B88 default case
+; ---------------------------------------------------------------------------
+
+loc_1959BBE: ; CODE XREF: TSparseArray__GetItemValue+28_j
+ ; DATA XREF: .text:off_1959C90o
+ mov eax, [eax+8] ; jumptable 01959B88 case 4
+ jmp short loc_1959BD9
+; ---------------------------------------------------------------------------
+
+loc_1959BC3: ; CODE XREF: TSparseArray__GetItemValue+28_j
+ ; DATA XREF: .text:off_1959C90o
+ mov edx, [eax+8] ; jumptable 01959B88 case 5
+ shr edx, 9
+ and edx, 1FFh
+ add esi, edx
+ jmp short loc_1959BE0 ; jumptable 01959B88 default case
+; ---------------------------------------------------------------------------
+
+loc_1959BD3: ; CODE XREF: TSparseArray__GetItemValue+28_j
+ ; DATA XREF: .text:off_1959C90o
+ mov eax, [eax+8] ; jumptable 01959B88 case 6
+ shr eax, 12h
+
+loc_1959BD9: ; CODE XREF: TSparseArray__GetItemValue+61_j
+ and eax, 1FFh
+
+loc_1959BDE: ; CODE XREF: TSparseArray__GetItemValue+35_j
+ ; TSparseArray__GetItemValue+52_j
+ add esi, eax
+
+loc_1959BE0: ; CODE XREF: TSparseArray__GetItemValue+26_j
+ ; TSparseArray__GetItemValue+45_j ...
+ mov ebx, edi ; jumptable 01959B88 default case
+ shr ebx, 5
+ test bl, 1
+ jz short loc_1959C31
+ mov edx, [ecx+8]
+ mov edx, [edx+ebx*4-4]
+ mov eax, edx
+ shr eax, 1
+ and eax, 55555555h
+ and edx, 55555555h
+ add eax, edx
+ mov edx, eax
+ and eax, 33333333h
+ shr edx, 2
+ and edx, 33333333h
+ add edx, eax
+ mov eax, edx
+ shr eax, 4
+ and eax, 0F0F0F0Fh
+ and edx, 0F0F0F0Fh
+ add eax, edx
+ imul eax, 1010101h
+ shr eax, 18h
+ add esi, eax
+
+loc_1959C31: ; CODE XREF: TSparseArray__GetItemValue+88_j
+ mov edx, [ecx+8]
+ mov ecx, edi
+ and ecx, 1Fh
+ mov eax, 1
+ shl eax, cl
+ mov ecx, [edx+ebx*4]
+ pop edi
+ dec eax
+ and ecx, eax
+ mov eax, ecx
+ shr eax, 1
+ and eax, 55555555h
+ and ecx, 55555555h
+ add eax, ecx
+ mov ecx, eax
+ and eax, 33333333h
+ shr ecx, 2
+ and ecx, 33333333h
+ add ecx, eax
+ mov eax, ecx
+ shr eax, 4
+ and eax, 0F0F0F0Fh
+ and ecx, 0F0F0F0Fh
+ add eax, ecx
+ imul eax, 1010101h
+ shr eax, 18h
+ add eax, esi
+ pop esi
+ pop ebx
+ pop ebp
+ retn 4
+
+off_1959C90 dd offset loc_1959B8F ; DATA XREF: TSparseArray__GetItemValue+28_r
+ dd offset loc_1959B97 ; jump table for switch statement
+ dd offset loc_1959BA7
+ dd offset loc_1959BB4
+ dd offset loc_1959BBE
+ dd offset loc_1959BC3
+ dd offset loc_1959BD3
+
+TSparseArray__GetItemValue endp
+
+;------------------------------------------------------------------------------
+; TArchiveDatabase__sub_1959CB0
+
+TArchiveDatabase__sub_1959CB0 proc near
+ ; CODE XREF: TFileNameDatabase__CheckNextPathFragment+A1_p
+ ; sub_1958B00+E8_p ...
+
+pThis = dword ptr -4
+dwKey = dword ptr 8
+
+ push ebp
+ mov ebp, esp
+ push ecx
+ mov edx, [ebp+dwKey]
+ mov eax, edx
+ shr eax, 9
+ mov [ebp+pThis], ecx
+ test edx, 1FFh ; if(dwKey & 0x01FF)
+ jnz short loc_1959CD3
+ mov ecx, [ecx+40h]
+ mov eax, [ecx+eax*4] ; EAX = pDatabase->NextKeyTable[dwKey >> 0x09]
+ mov esp, ebp
+ pop ebp
+ retn 4
+; ---------------------------------------------------------------------------
+
+loc_1959CD3: ; CODE XREF: TFileNameDatabase__FindNextMatch+15_j
+ push ebx
+ push esi
+ mov esi, [ecx+40h]
+ lea esi, [esi+eax*4]
+ mov eax, [esi]
+ mov esi, [esi+4]
+ shr eax, 9
+ add esi, 1FFh
+ push edi
+ shr esi, 9
+ lea edi, [eax+0Ah]
+ mov [ebp+dwKey], esi
+ cmp edi, esi
+ jb short loc_1959D2E
+ mov edi, [ecx+28h]
+ lea esi, [eax+eax*2+3]
+ lea esi, [edi+esi*4]
+ mov edi, eax
+ shl edi, 9
+ mov ebx, edi
+ sub ebx, [esi]
+ add ebx, 200h
+ cmp edx, ebx
+ jb short loc_1959D5F
+
+loc_1959D14: ; CODE XREF: TFileNameDatabase__FindNextMatch+7Aj
+ add edi, 200h
+ add esi, 0Ch
+ mov ebx, edi
+ sub ebx, [esi]
+ inc eax
+ add ebx, 200h
+ cmp edx, ebx
+ jnb short loc_1959D14
+ jmp short loc_1959D5F
+; ---------------------------------------------------------------------------
+
+loc_1959D2E: ; CODE XREF: TFileNameDatabase__FindNextMatch+45_j
+ lea edi, [eax+1]
+ cmp edi, esi
+ jnb short loc_1959D5F
+ mov ecx, [ecx+28h]
+
+loc_1959D38: ; CODE XREF: TFileNameDatabase__FindNextMatch+AAj
+ add esi, eax
+ shr esi, 1
+ mov ebx, esi
+ shl ebx, 9
+ lea edi, [esi+esi*2]
+ sub ebx, [ecx+edi*4]
+ cmp edx, ebx
+ jnb short loc_1959D50
+ mov [ebp+dwKey], esi
+ jmp short loc_1959D55
+; ---------------------------------------------------------------------------
+
+loc_1959D50: ; CODE XREF: TFileNameDatabase__FindNextMatch+99_j
+ mov eax, esi
+ mov esi, [ebp+dwKey]
+
+loc_1959D55: ; CODE XREF: TFileNameDatabase__FindNextMatch+9E_j
+ lea edi, [eax+1]
+ cmp edi, esi
+ jb short loc_1959D38
+ mov ecx, [ebp+pThis]
+
+loc_1959D5F: ; CODE XREF: TFileNameDatabase__FindNextMatch+62_j
+ ; TFileNameDatabase__FindNextMatch+7C_j ...
+ mov ecx, [ecx+28h]
+ lea esi, [eax+eax*2]
+ mov edi, [ecx+esi*4] ; EDI = Struct68_00.ArrayTriplets_20.ItemArray[eax]
+ lea esi, [ecx+esi*4] ; ESI = Struct68_00.ArrayTriplets_20.ItemArray + eax
+ mov ecx, eax
+ shl ecx, 9
+ sub edi, ecx
+ shl eax, 4
+ add edx, edi
+ mov edi, eax
+ mov eax, [esi+4]
+ mov ecx, eax
+ shr ecx, 17h
+ mov ebx, 100h
+ sub ebx, ecx
+ cmp edx, ebx
+ jnb short loc_1959DE8
+ mov ecx, eax
+ shr ecx, 7
+ and ecx, 0FFh
+ mov esi, 80h
+ sub esi, ecx
+ cmp edx, esi
+ jnb short loc_1959DC0
+ and eax, 7Fh
+ mov ecx, 40h
+ sub ecx, eax
+ cmp edx, ecx
+ jb loc_1959E53
+ add edi, 2
+ lea edx, [edx+eax-40h]
+ jmp loc_1959E53
+; ---------------------------------------------------------------------------
+
+loc_1959DC0: ; CODE XREF: TFileNameDatabase__FindNextMatch+F0_j
+ shr eax, 0Fh
+ and eax, 0FFh
+ mov esi, 0C0h
+ sub esi, eax
+ cmp edx, esi
+ jnb short loc_1959DDC
+ add edi, 4
+ lea edx, [edx+ecx-80h]
+ jmp short loc_1959E53
+; ---------------------------------------------------------------------------
+
+loc_1959DDC: ; CODE XREF: TFileNameDatabase__FindNextMatch+121_j
+ add edi, 6
+ lea edx, [edx+eax-0C0h]
+ jmp short loc_1959E53
+; ---------------------------------------------------------------------------
+
+loc_1959DE8: ; CODE XREF: TFileNameDatabase__FindNextMatch+DA_j
+ mov esi, [esi+8]
+ mov eax, esi
+ shr eax, 9
+ and eax, 1FFh
+ mov ebx, 180h
+ sub ebx, eax
+ cmp edx, ebx
+ jnb short loc_1959E29
+ and esi, 1FFh
+ mov eax, 140h
+ sub eax, esi
+ cmp edx, eax
+ jnb short loc_1959E1D
+ add edi, 8
+ lea edx, [edx+ecx-100h]
+ jmp short loc_1959E53
+; ---------------------------------------------------------------------------
+
+loc_1959E1D: ; CODE XREF: TFileNameDatabase__FindNextMatch+15F_j
+ add edi, 0Ah
+ lea edx, [edx+esi-140h]
+ jmp short loc_1959E53
+; ---------------------------------------------------------------------------
+
+loc_1959E29: ; CODE XREF: TFileNameDatabase__FindNextMatch+14E_j
+ shr esi, 12h
+ and esi, 1FFh
+ mov ecx, 1C0h
+ sub ecx, esi
+ cmp edx, ecx
+ jnb short loc_1959E49
+ add edi, 0Ch
+ lea edx, [edx+eax-180h]
+ jmp short loc_1959E53
+; ---------------------------------------------------------------------------
+
+loc_1959E49: ; CODE XREF: TFileNameDatabase__FindNextMatch+18B_j
+ add edi, 0Eh
+ lea edx, [edx+esi-1C0h]
+
+loc_1959E53: ; CODE XREF: TFileNameDatabase__FindNextMatch+FE_j
+ ; TFileNameDatabase__FindNextMatch+10B_j ...
+ mov eax, [ebp+pThis]
+ mov ebx, [eax+8]
+ mov ecx, [ebx+edi*4]
+ not ecx
+ mov eax, ecx
+ shr eax, 1
+ and eax, 55555555h
+ mov esi, ecx
+ and esi, 55555555h
+ add eax, esi
+ mov esi, eax
+ shr esi, 2
+ and eax, 33333333h
+ and esi, 33333333h
+ add esi, eax
+ mov eax, esi
+ shr eax, 4
+ and esi, 0F0F0F0Fh
+ and eax, 0F0F0F0Fh
+ add eax, esi
+ imul eax, 1010101h
+ mov esi, eax
+ shr esi, 18h
+ cmp edx, esi
+ jb short loc_1959EEA
+ mov ecx, [ebx+edi*4+4]
+ inc edi
+ sub edx, esi
+ not ecx
+ mov eax, ecx
+ shr eax, 1
+ and eax, 55555555h
+ mov esi, ecx
+ and esi, 55555555h
+ add eax, esi
+ mov esi, eax
+ shr esi, 2
+ and eax, 33333333h
+ and esi, 33333333h
+ add esi, eax
+ mov eax, esi
+ shr eax, 4
+ and eax, 0F0F0F0Fh
+ and esi, 0F0F0F0Fh
+ add eax, esi
+ imul eax, 1010101h
+
+loc_1959EEA: ; CODE XREF: TFileNameDatabase__FindNextMatch+1F2_j
+ mov esi, eax
+ shr esi, 8
+ and esi, 0FFh
+ shl edi, 5
+ cmp edx, esi
+ jnb short loc_1959F0D
+ and eax, 0FFh
+ cmp edx, eax
+ jb short loc_1959F2B
+ add edi, 8
+ shr ecx, 8
+ jmp short loc_1959F29
+; ---------------------------------------------------------------------------
+
+loc_1959F0D: ; CODE XREF: TFileNameDatabase__FindNextMatch+24A_j
+ shr eax, 10h
+ and eax, 0FFh
+ cmp edx, eax
+ jnb short loc_1959F23
+ add edi, 10h
+ shr ecx, 10h
+ sub edx, esi
+ jmp short loc_1959F2B
+; ---------------------------------------------------------------------------
+
+loc_1959F23: ; CODE XREF: TFileNameDatabase__FindNextMatch+267_j
+ add edi, 18h
+ shr ecx, 18h
+
+loc_1959F29: ; CODE XREF: TFileNameDatabase__FindNextMatch+25B_j
+ sub edx, eax
+
+loc_1959F2B: ; CODE XREF: TFileNameDatabase__FindNextMatch+253_j
+ ; TFileNameDatabase__FindNextMatch+271_j
+ and ecx, 0FFh
+ shl edx, 8
+ movzx eax, byte ptr ds:table_1BA1818[ecx+edx]
+ add eax, edi
+ pop edi
+ pop esi
+ pop ebx
+ mov esp, ebp
+ pop ebp
+ retn 4
+TArchiveDatabase__sub_1959CB0 endp
+
+; =============== S U B R O U T I N E =======================================
+
+; Attributes: bp-based frame
+
+TNameIndexStruct__CheckNameFragment proc near ; CODE XREF: TFileNameDatabase__CheckNextPathFragment+6B_p
+ ; TFileNameDatabase__CheckNextPathFragment+191_p ...
+
+pThis = dword ptr -4
+pUnknownStruct1C= dword ptr 8
+dwDistance = dword ptr 0Ch
+
+ push ebp
+ mov ebp, esp
+ push ecx
+ push ebx
+ push esi
+ push edi
+ mov edi, ecx
+ cmp [edi+TNameIndexStruct.Struct68.TotalItemCount], 0
+ mov ecx, [ebp+pUnknownStruct1C]
+ mov edx, [ecx+TMndxFindResult.pStruct40]
+ mov [ebp+pThis], edi
+ jnz short loc_195A1C8
+ mov edi, [edi+TNameIndexStruct.NameFragments.ItemArray] ; Pointer to name table
+ sub edi, [edx+TStruct40.CharIndex]
+ add edi, [ebp+dwDistance] ; EDI = szPathFragment
+
+loc_195A1A1: ; CODE XREF: TNameIndexStruct__CheckNameFragment+3Bj
+ mov eax, [edx+TStruct40.CharIndex]
+ mov esi, [ecx+TMndxFindResult.szSearchMask]
+ mov bl, [eax+edi]
+ cmp bl, [eax+esi]
+ jnz short loc_195A1BD
+ inc eax
+ mov [edx+TStruct40.CharIndex], eax
+ cmp byte ptr [eax+edi], 0
+ jz short loc_195A215
+ cmp eax, [ecx+TMndxFindResult.cchSearchMask]
+ jb short loc_195A1A1
+
+loc_195A1BD: ; CODE XREF: TNameIndexStruct__CheckNameFragment+2C_j
+ ; TNameIndexStruct__CheckNameFragment+5Ej ...
+ pop edi
+ pop esi
+ xor al, al
+ pop ebx
+ mov esp, ebp
+ pop ebp
+ retn 8
+; ---------------------------------------------------------------------------
+
+loc_195A1C8: ; CODE XREF: TNameIndexStruct__CheckNameFragment+16_j
+ mov eax, [ebp+dwDistance]
+ jmp short loc_195A1D0
+; ---------------------------------------------------------------------------
+ align 10h
+
+loc_195A1D0: ; CODE XREF: TNameIndexStruct__CheckNameFragment+4B_j
+ ; TNameIndexStruct__CheckNameFragment+93j
+ mov ebx, [edi+TNameIndexStruct.NameFragments.ItemArray]
+ mov esi, [edx+TStruct40.CharIndex]
+ mov ecx, [ecx+TMndxFindResult.szSearchMask]
+ mov bl, [eax+ebx] ; pNameList[dwNameOffset] == szPathName[nCharIndex]
+ cmp bl, [esi+ecx]
+ jnz short loc_195A1BD
+ lea ecx, [esi+1]
+ mov [edx+TStruct40.CharIndex], ecx
+ mov edi, [edi+TNameIndexStruct.Struct68.ItemIsPresent.ItemArray]
+ mov [ebp+dwDistance], ecx
+ mov ecx, eax
+ and ecx, 1Fh ; ecx = (dwNameOffset & 0x1F)
+ mov esi, eax
+ mov ebx, 1
+ shl ebx, cl ; ebx = 1 << (dwNameOffset & 0x1F);
+ shr esi, 5 ; esi = (dwNameOffset >> 0x05)
+ mov ecx, [edi+esi*4]
+ inc eax
+ and ecx, ebx
+ jnz short loc_195A215
+ mov esi, [ebp+dwDistance]
+ mov ecx, [ebp+pUnknownStruct1C]
+ cmp esi, [ecx+4]
+ jnb short loc_195A1BD
+ mov edi, [ebp+pThis]
+ jmp short loc_195A1D0
+; ---------------------------------------------------------------------------
+
+loc_195A215: ; CODE XREF: TNameIndexStruct__CheckNameFragment+36_j
+ ; TNameIndexStruct__CheckNameFragment+83_j
+ pop edi
+ pop esi
+ mov al, 1
+ pop ebx
+ mov esp, ebp
+ pop ebp
+ retn 8
+TNameIndexStruct__CheckNameFragment endp
+
+; =============== S U B R O U T I N E =======================================
+
+; Attributes: bp-based frame
+
+sub_1957350 proc near ; CODE XREF: sub_1957B80+D8p
+ ; sub_1957B80:loc_1957C73p ...
+
+arg_0 = dword ptr 8
+
+ push ebp
+ mov ebp, esp
+ mov eax, [ebp+arg_0]
+ push ebx
+ push esi
+ mov esi, ecx
+ mov ebx, [esi+140h]
+ push edi
+ push eax
+ lea ecx, [esi+0D0h]
+ add ebx, eax
+ call TSparseArray__GetItemValue
+ mov edi, [esi+168h]
+ mov ecx, edi
+ imul ecx, eax
+ mov eax, ecx
+ and ecx, 1Fh
+ mov edx, ecx
+ mov ecx, [esi+158h]
+ add edi, edx
+ shr eax, 5
+ cmp edi, 20h
+ ja short loc_195739A
+ mov eax, [ecx+eax*4]
+ mov ecx, edx
+ shr eax, cl
+ jmp short loc_19573B1
+; ---------------------------------------------------------------------------
+
+loc_195739A: ; CODE XREF: sub_1957350+3F_j
+ lea edi, [ecx+eax*4]
+ mov eax, [edi+4]
+ mov edi, [edi]
+ mov ecx, 20h
+ sub ecx, edx
+ shl eax, cl
+ mov ecx, edx
+ shr edi, cl
+ or eax, edi
+
+loc_19573B1: ; CODE XREF: sub_1957350+48_j
+ and eax, [esi+16Ch]
+ movzx edx, byte ptr [ebx]
+ pop edi
+ shl eax, 8
+ pop esi
+ or eax, edx
+ pop ebx
+ pop ebp
+ retn 4
+sub_1957350 endp
+
+; ---------------------------------------------------------------------------
+
+
+; =============== S U B R O U T I N E =======================================
+
+; Attributes: bp-based frame
+
+sub_1959F50 proc near ; CODE XREF: sub_1957B80+14C_p
+ ; sub_1958980+62_p ...
+
+var_4 = dword ptr -4
+arg_0 = dword ptr 8
+
+ push ebp
+ mov ebp, esp
+ push ecx
+ mov edx, [ebp+arg_0]
+ mov eax, edx
+ shr eax, 9
+ mov [ebp+var_4], ecx
+ test edx, 1FFh
+ jnz short loc_1959F73
+ mov ecx, [ecx+58h]
+ mov eax, [ecx+eax*4]
+ mov esp, ebp
+ pop ebp
+ retn 4
+; ---------------------------------------------------------------------------
+
+loc_1959F73: ; CODE XREF: sub_1959F50+15_j
+ push ebx
+ push esi
+ mov esi, [ecx+58h]
+ lea esi, [esi+eax*4]
+ mov eax, [esi]
+ push edi
+ mov edi, [esi+4]
+ shr eax, 9
+ add edi, 1FFh
+ shr edi, 9
+ lea esi, [eax+0Ah]
+ cmp esi, edi
+ jb short loc_1959FAD
+ mov edi, [ecx+28h]
+ lea esi, [eax+eax*2+3]
+ cmp edx, [edi+esi*4]
+ lea esi, [edi+esi*4]
+ jb short loc_1959FD4
+
+loc_1959FA3: ; CODE XREF: sub_1959F50+59j
+ add esi, 0Ch
+ inc eax
+ cmp edx, [esi]
+ jnb short loc_1959FA3
+ jmp short loc_1959FD4
+; ---------------------------------------------------------------------------
+
+loc_1959FAD: ; CODE XREF: sub_1959F50+42_j
+ lea esi, [eax+1]
+ cmp esi, edi
+ jnb short loc_1959FD4
+ mov ecx, [ecx+28h]
+
+loc_1959FB7: ; CODE XREF: sub_1959F50+7Fj
+ lea esi, [edi+eax]
+ shr esi, 1
+ lea ebx, [esi+esi*2]
+ cmp edx, [ecx+ebx*4]
+ jnb short loc_1959FC8
+ mov edi, esi
+ jmp short loc_1959FCA
+; ---------------------------------------------------------------------------
+
+loc_1959FC8: ; CODE XREF: sub_1959F50+72_j
+ mov eax, esi
+
+loc_1959FCA: ; CODE XREF: sub_1959F50+76_j
+ lea esi, [eax+1]
+ cmp esi, edi
+ jb short loc_1959FB7
+ mov ecx, [ebp+var_4]
+
+loc_1959FD4: ; CODE XREF: sub_1959F50+51_j
+ ; sub_1959F50+5B_j ...
+ mov edi, [ecx+28h]
+ lea esi, [eax+eax*2]
+ sub edx, [edi+esi*4]
+ shl eax, 4
+ lea esi, [edi+esi*4]
+ mov edi, eax
+ mov eax, [esi+4]
+ mov ebx, eax
+ shr ebx, 17h
+ cmp edx, ebx
+ jnb short loc_195A026
+ mov esi, eax
+ shr esi, 7
+ and esi, 0FFh
+ cmp edx, esi
+ jnb short loc_195A00E
+ and eax, 7Fh
+ cmp edx, eax
+ jb short loc_195A066
+ add edi, 2
+ sub edx, eax
+ jmp short loc_195A066
+; ---------------------------------------------------------------------------
+
+loc_195A00E: ; CODE XREF: sub_1959F50+AE_j
+ shr eax, 0Fh
+ and eax, 0FFh
+ cmp edx, eax
+ jnb short loc_195A01F
+ add edi, 4
+ jmp short loc_195A064
+; ---------------------------------------------------------------------------
+
+loc_195A01F: ; CODE XREF: sub_1959F50+C8_j
+ add edi, 6
+ sub edx, eax
+ jmp short loc_195A066
+; ---------------------------------------------------------------------------
+
+loc_195A026: ; CODE XREF: sub_1959F50+9F_j
+ mov esi, [esi+8]
+ mov eax, esi
+ shr eax, 9
+ and eax, 1FFh
+ cmp edx, eax
+ jnb short loc_195A04D
+ and esi, 1FFh
+ cmp edx, esi
+ jnb short loc_195A048
+ add edi, 8
+ sub edx, ebx
+ jmp short loc_195A066
+; ---------------------------------------------------------------------------
+
+loc_195A048: ; CODE XREF: sub_1959F50+EF_j
+ add edi, 0Ah
+ jmp short loc_195A064
+; ---------------------------------------------------------------------------
+
+loc_195A04D: ; CODE XREF: sub_1959F50+E5_j
+ shr esi, 12h
+ and esi, 1FFh
+ cmp edx, esi
+ jnb short loc_195A061
+ add edi, 0Ch
+ sub edx, eax
+ jmp short loc_195A066
+; ---------------------------------------------------------------------------
+
+loc_195A061: ; CODE XREF: sub_1959F50+108_j
+ add edi, 0Eh
+
+loc_195A064: ; CODE XREF: sub_1959F50+CD_j
+ ; sub_1959F50+FB_j
+ sub edx, esi
+
+loc_195A066: ; CODE XREF: sub_1959F50+B5_j
+ ; sub_1959F50+BC_j ...
+ mov ebx, [ecx+8]
+ mov esi, [ebx+edi*4]
+ mov eax, esi
+ shr eax, 1
+ and eax, 55555555h
+ mov ecx, esi
+ and ecx, 55555555h
+ add eax, ecx
+ mov ecx, eax
+ shr ecx, 2
+ and eax, 33333333h
+ and ecx, 33333333h
+ add ecx, eax
+ mov eax, ecx
+ shr eax, 4
+ and ecx, 0F0F0F0Fh
+ and eax, 0F0F0F0Fh
+ add eax, ecx
+ imul eax, 1010101h
+ mov ecx, eax
+ shr ecx, 18h
+ cmp edx, ecx
+ jb short loc_195A0F6
+ mov esi, [ebx+edi*4+4]
+ sub edx, ecx
+ inc edi
+ mov eax, esi
+ shr eax, 1
+ and eax, 55555555h
+ mov ecx, esi
+ and ecx, 55555555h
+ add eax, ecx
+ mov ecx, eax
+ shr ecx, 2
+ and eax, 33333333h
+ and ecx, 33333333h
+ add ecx, eax
+ mov eax, ecx
+ shr eax, 4
+ and eax, 0F0F0F0Fh
+ and ecx, 0F0F0F0Fh
+ add eax, ecx
+ imul eax, 1010101h
+
+loc_195A0F6: ; CODE XREF: sub_1959F50+160_j
+ mov ecx, eax
+ shr ecx, 8
+ and ecx, 0FFh
+ shl edi, 5
+ cmp edx, ecx
+ jnb short loc_195A119
+ and eax, 0FFh
+ cmp edx, eax
+ jb short loc_195A137
+ add edi, 8
+ shr esi, 8
+ jmp short loc_195A135
+; ---------------------------------------------------------------------------
+
+loc_195A119: ; CODE XREF: sub_1959F50+1B6_j
+ shr eax, 10h
+ and eax, 0FFh
+ cmp edx, eax
+ jnb short loc_195A12F
+ add edi, 10h
+ shr esi, 10h
+ sub edx, ecx
+ jmp short loc_195A137
+; ---------------------------------------------------------------------------
+
+loc_195A12F: ; CODE XREF: sub_1959F50+1D3_j
+ add edi, 18h
+ shr esi, 18h
+
+loc_195A135: ; CODE XREF: sub_1959F50+1C7_j
+ sub edx, eax
+
+loc_195A137: ; CODE XREF: sub_1959F50+1BF_j
+ ; sub_1959F50+1DD_j
+ and esi, 0FFh
+ shl edx, 8
+ movzx eax, ds:table_1BA1818[esi+edx]
+ add eax, edi
+ pop edi
+ pop esi
+ pop ebx
+ mov esp, ebp
+ pop ebp
+ retn 4
+sub_1959F50 endp
+
+; ---------------------------------------------------------------------------
+
+; =============== S U B R O U T I N E =======================================
+
+; Attributes: bp-based frame
+
+sub_1957B80 proc near ; CODE XREF: TFileNameDatabase__CheckNextPathFragment+5E_p
+ ; TFileNameDatabase__CheckNextPathFragment+180_p ...
+
+pStruct40 = dword ptr -4
+arg_0 = dword ptr 8
+arg_4 = dword ptr 0Ch
+
+ push ebp
+ mov ebp, esp
+ push ecx
+ push ebx
+ mov ebx, [ebp+arg_0]
+ mov eax, [ebx+18h]
+ push esi
+ push edi
+ mov edi, [ebp+arg_4]
+ mov esi, ecx
+ mov [ebp+pStruct40], eax
+
+loc_1957B95: ; CODE XREF: sub_1957B80+9Fj
+ ; sub_1957B80+156j
+ mov eax, [esi+TFileNameDatabase.NameFragIndexMask]
+ and eax, edi
+ lea ecx, [eax+eax*2]
+ mov eax, [esi+TFileNameDatabase.NameFragTable.ItemArray]
+ add ecx, ecx
+ add ecx, ecx
+ add eax, ecx
+ mov [ebp+arg_4], ecx
+ cmp edi, [eax+4]
+ jnz short loc_1957C30
+ mov edx, [eax+8]
+ mov edi, edx
+ and edi, 0FFFFFF00h
+ cmp edi, 0FFFFFF00h
+ jz short loc_1957BEE
+ mov ecx, [esi+TFileNameDatabase.NextDB.pDatabase]
+ push edx
+ push ebx
+ test ecx, ecx
+ jz short loc_1957BDA
+ call sub_1957B80
+ jmp short loc_1957BE5
+; ---------------------------------------------------------------------------
+
+loc_1957BDA: ; CODE XREF: sub_1957B80+51_j
+ lea ecx, [esi+TFileNameDatabase.IndexStruct_174]
+ call TNameIndexStruct__CheckNameFragment
+
+loc_1957BE5: ; CODE XREF: sub_1957B80+58_j
+ test al, al
+ jz short loc_1957C25
+ mov ecx, [ebp+arg_4]
+ jmp short loc_1957C05
+; ---------------------------------------------------------------------------
+
+loc_1957BEE: ; CODE XREF: sub_1957B80+45_j
+ mov edx, [ebp+pStruct40]
+ mov edi, [edx+34h]
+ mov edx, [ebx]
+ mov al, [eax+8]
+ cmp al, [edi+edx]
+ jnz short loc_1957C25
+ mov edx, [ebp+pStruct40]
+ inc edi
+ mov [edx+34h], edi
+
+loc_1957C05: ; CODE XREF: sub_1957B80+6C_j
+ mov eax, [esi+200h]
+ mov edi, [ecx+eax]
+ test edi, edi
+ jz loc_1957CDB
+ mov ecx, [ebp+pStruct40]
+ mov edx, [ecx+34h]
+ cmp edx, [ebx+4]
+ jb loc_1957B95
+
+loc_1957C25: ; CODE XREF: sub_1957B80+67_j
+ ; sub_1957B80+7C_j ...
+ pop edi
+ pop esi
+ xor al, al
+ pop ebx
+ mov esp, ebp
+ pop ebp
+ retn 8
+; ---------------------------------------------------------------------------
+
+loc_1957C30: ; CODE XREF: sub_1957B80+32_j
+ mov edx, [esi+0D8h]
+ mov ecx, edi
+ and ecx, 1Fh
+ mov ebx, 1
+ shl ebx, cl
+ mov eax, edi
+ shr eax, 5
+ test [edx+eax*4], ebx
+ jz short loc_1957C8E
+ cmp dword ptr [esi+1F4h], 0
+ push edi
+ mov ecx, esi
+ jz short loc_1957C73
+ call sub_1957350
+ mov ecx, [esi+1F4h]
+ mov ebx, [ebp+arg_0]
+ push eax
+ push ebx
+ test ecx, ecx
+ jz short loc_1957C7D
+ call sub_1957B80
+ jmp short loc_1957C88
+; ---------------------------------------------------------------------------
+
+loc_1957C73: ; CODE XREF: sub_1957B80+D6_j
+ call sub_1957350
+ mov ebx, [ebp+arg_0]
+ push eax
+ push ebx
+
+loc_1957C7D: ; CODE XREF: sub_1957B80+EA_j
+ lea ecx, [esi+174h]
+ call TNameIndexStruct__CheckNameFragment
+
+loc_1957C88: ; CODE XREF: sub_1957B80+F1_j
+ test al, al
+ jz short loc_1957C25
+ jmp short loc_1957CB2
+; ---------------------------------------------------------------------------
+
+loc_1957C8E: ; CODE XREF: sub_1957B80+CA_j
+ mov eax, [ebp+pStruct40]
+ mov ecx, [esi+140h]
+ mov ebx, [ebp+arg_0]
+ mov eax, [eax+34h]
+ mov edx, [ebx]
+ mov cl, [edi+ecx]
+ cmp cl, [eax+edx]
+ jnz loc_1957C25
+ mov edx, [ebp+pStruct40]
+ inc eax
+ mov [edx+34h], eax
+
+loc_1957CB2: ; CODE XREF: sub_1957B80+10C_j
+ cmp edi, [esi+214h]
+ jbe short loc_1957CDB
+ mov eax, [ebp+pStruct40]
+ mov ecx, [eax+34h]
+ cmp ecx, [ebx+4]
+ jnb loc_1957C25
+ push edi
+ mov ecx, esi
+ call sub_1959F50
+ sub eax, edi
+ lea edi, [eax-1]
+ jmp loc_1957B95
+; ---------------------------------------------------------------------------
+
+loc_1957CDB: ; CODE XREF: sub_1957B80+90_j
+ ; sub_1957B80+138_j
+ pop edi
+ pop esi
+ mov al, 1
+ pop ebx
+ mov esp, ebp
+ pop ebp
+ retn 8
+sub_1957B80 endp
+
+
+; =============== S U B R O U T I N E =======================================
+
+; Attributes: bp-based frame
+
+sub_19573D0 proc near ; CODE XREF: TFileNameDatabase__sub_1959460+1D9p
+
+arg_0 = dword ptr 8
+arg_4 = dword ptr 0Ch
+
+ push ebp
+ mov ebp, esp
+ push esi
+ mov esi, ecx
+ mov edx, [esi+TFileNameDatabase.FrgmDist_HiBits.BitsPerEntry]
+ mov eax, edx
+ imul eax, [ebp+arg_4]
+ mov ecx, eax
+ and eax, 1Fh
+ add edx, eax
+ shr ecx, 5
+ cmp edx, 20h
+ mov edx, [esi+TFileNameDatabase.FrgmDist_HiBits.ItemArray]
+ ja short loc_1957400
+ mov edx, [edx+ecx*4]
+ mov ecx, eax
+ shr edx, cl
+ jmp short loc_1957419
+; ---------------------------------------------------------------------------
+
+loc_1957400: ; CODE XREF: sub_19573D0+25j
+ push edi
+ lea edi, [edx+ecx*4]
+ mov edx, [edi+4]
+ mov edi, [edi]
+ mov ecx, 20h
+ sub ecx, eax
+ shl edx, cl
+ mov ecx, eax
+ shr edi, cl
+ or edx, edi
+ pop edi
+
+loc_1957419: ; CODE XREF: sub_19573D0+2Ej
+ and edx, [esi+TFileNameDatabase.FrgmDist_HiBits.EntryBitMask]
+ mov eax, [esi+TFileNameDatabase.FrgmDist_LoBits.ItemArray]
+ mov ecx, [ebp+arg_0]
+ movzx eax, byte ptr [eax+ecx]
+ shl edx, 8
+ or eax, edx
+ pop esi
+ pop ebp
+ retn 8
+sub_19573D0 endp
+
+; ---------------------------------------------------------------------------
+
+; =============== S U B R O U T I N E =======================================
+
+; Attributes: bp-based frame
+
+TFileNameDatabase__CheckNextPathFragment proc near ; CODE XREF: TFileNameDatabase__FindFileInDatabase+25p
+
+var_C = dword ptr -0Ch
+CollisionIndex = dword ptr -8
+var_4 = dword ptr -4
+pStruct1C = dword ptr 8
+
+ push ebp
+ mov ebp, esp
+ mov edx, [ebp+pStruct1C]
+ sub esp, 0Ch
+ push ebx
+ mov ebx, [edx+TMndxFindResult.szSearchMask]
+ push esi
+ push edi
+ mov edi, [edx+TMndxFindResult.pStruct40]
+ mov eax, [edi+TStruct40.CharIndex]
+ movzx eax, byte ptr [eax+ebx] ; EAX = szPathName[nCharIndex]
+ mov esi, ecx
+ mov ecx, [edi+TStruct40.HashValue]
+ mov ebx, ecx
+ shl ebx, 5
+ xor eax, ebx
+ xor eax, ecx
+ and eax, [esi+TFileNameDatabase.NameFragIndexMask] ; (000000ff) - Mask value
+ lea ebx, [eax+eax*2]
+ mov eax, [esi+TFileNameDatabase.NameFragTable.ItemArray] ; (7f3ae128) - Array of 256 triplets
+ add ebx, ebx
+ add ebx, ebx ; EBX = Offset of the triplet we want to know
+ cmp ecx, [eax+ebx+TRIPLET.BitIndex]
+ jnz short loc_1957A0E
+ mov eax, [eax+ebx+TRIPLET.Distance]
+ mov ecx, eax
+ and ecx, 0FFFFFF00h
+ cmp ecx, 0FFFFFF00h
+ jz short loc_19579EF
+ mov ecx, [esi+TFileNameDatabase.NextDB.pDatabase]
+ push eax
+ push edx
+ test ecx, ecx
+ jz short loc_19579D5
+ call sub_1957B80
+ jmp short loc_19579E0
+; ---------------------------------------------------------------------------
+
+loc_19579D5: ; CODE XREF: TFileNameDatabase__CheckNextPathFragment+5C_j
+ lea ecx, [esi+TFileNameDatabase.IndexStruct_174]
+ call TNameIndexStruct__CheckNameFragment
+
+loc_19579E0: ; CODE XREF: TFileNameDatabase__CheckNextPathFragment+63_j
+ test al, al
+ jnz short loc_19579F6
+
+loc_19579E4: ; CODE XREF: TFileNameDatabase__CheckNextPathFragment+C1j
+ ; TFileNameDatabase__CheckNextPathFragment+1A4j
+ pop edi
+ pop esi
+ xor al, al
+ pop ebx
+ mov esp, ebp
+ pop ebp
+ retn 4
+; ---------------------------------------------------------------------------
+
+loc_19579EF: ; CODE XREF: TFileNameDatabase__CheckNextPathFragment+50_j
+ mov eax, [edi+TStruct40.CharIndex] ; nCharIndex = nCharIndex + 1
+ inc eax
+ mov [edi+TStruct40.CharIndex], eax
+
+loc_19579F6: ; CODE XREF: TFileNameDatabase__CheckNextPathFragment+72_j
+ mov edx, [esi+TFileNameDatabase.NameFragTable.ItemArray] ; EDX = pTripletArray
+ mov eax, [edx+ebx+TRIPLET.NextKey]
+ mov [edi+TStruct40.HashValue], eax
+
+loc_1957A03: ; CODE XREF: TFileNameDatabase__CheckNextPathFragment+198j
+ pop edi
+ pop esi
+ mov al, 1
+ pop ebx
+ mov esp, ebp
+ pop ebp
+ retn 4
+; ---------------------------------------------------------------------------
+
+loc_1957A0E: ; CODE XREF: TFileNameDatabase__CheckNextPathFragment+3C_j
+ push ecx ; dwKey
+ mov ecx, esi ; pDatabase
+ call TArchiveDatabase__sub_1959CB0
+ mov ebx, [esi+TFileNameDatabase.Struct68_00.ItemIsPresent.ItemArray]
+ inc eax
+ mov ecx, eax
+ and ecx, 1Fh
+ mov edx, 1
+ shl edx, cl
+ mov ecx, eax
+ shr ecx, 5
+ mov [ebp+CollisionIndex], eax
+ test [ebx+ecx*4], edx
+ jz short loc_19579E4
+ sub eax, [edi+TStruct40.HashValue]
+ mov [ebp+var_4], 0FFFFFFFFh
+ dec eax
+ mov [edi+TStruct40.HashValue], eax
+
+loc_1957A41: ; CODE XREF: TFileNameDatabase__CheckNextPathFragment+1E1j
+ mov eax, [edi+TStruct40.HashValue]
+ mov ebx, [esi+TFileNameDatabase.Struct68_D0.ItemIsPresent.ItemArray]
+ mov ecx, eax
+ and ecx, 1Fh
+ mov edx, 1
+ shl edx, cl
+ mov ecx, eax
+ shr ecx, 5
+ test [ebx+ecx*4], edx
+ jz loc_1957B1C
+ mov ecx, [ebp+var_4]
+ cmp ecx, 0FFFFFFFFh
+ jnz short loc_1957A7F
+ push eax
+ lea ecx, [esi+TFileNameDatabase.Struct68_D0]
+ call TSparseArray__GetItemValue
+ mov ecx, eax
+ mov [ebp+var_4], eax
+ jmp short loc_1957A83
+; ---------------------------------------------------------------------------
+
+loc_1957A7F: ; CODE XREF: TFileNameDatabase__CheckNextPathFragment+FA_j
+ inc ecx
+ mov [ebp+var_4], ecx
+
+loc_1957A83: ; CODE XREF: TFileNameDatabase__CheckNextPathFragment+10D_j
+ mov edx, [edi+TStruct40.CharIndex]
+ mov [ebp+var_C], edx
+ mov edx, [esi+TFileNameDatabase.FrgmDist_HiBits.BitsPerEntry]
+ mov eax, edx
+ imul eax, ecx
+ mov ecx, eax
+ and eax, 1Fh
+ add edx, eax
+ shr ecx, 5
+ cmp edx, 20h
+ mov edx, [esi+TFileNameDatabase.FrgmDist_HiBits.ItemArray]
+ ja short loc_1957AB2
+ mov edx, [edx+ecx*4]
+ mov ecx, eax
+ shr edx, cl
+ jmp short loc_1957AC9
+; ---------------------------------------------------------------------------
+
+loc_1957AB2: ; CODE XREF: TFileNameDatabase__CheckNextPathFragment+137_j
+ lea ebx, [edx+ecx*4]
+ mov edx, [ebx+4]
+ mov ebx, [ebx]
+ mov ecx, 20h
+ sub ecx, eax
+ shl edx, cl
+ mov ecx, eax
+ shr ebx, cl
+ or edx, ebx
+
+loc_1957AC9: ; CODE XREF: TFileNameDatabase__CheckNextPathFragment+140_j
+ mov ecx, [esi+TFileNameDatabase.FrgmDist_LoBits.ItemArray]
+ and edx, [esi+TFileNameDatabase.FrgmDist_HiBits.EntryBitMask]
+ mov eax, [edi+TStruct40.HashValue]
+ movzx eax, byte ptr [ecx+eax]
+ mov ecx, [esi+TFileNameDatabase.NextDB.pDatabase]
+ shl edx, 8
+ or eax, edx
+ push eax
+ test ecx, ecx
+ jz short loc_1957AF7
+ mov edx, [ebp+pStruct1C]
+ push edx
+ call sub_1957B80
+ jmp short loc_1957B06
+; ---------------------------------------------------------------------------
+
+loc_1957AF7: ; CODE XREF: TFileNameDatabase__CheckNextPathFragment+17A_j
+ mov eax, [ebp+pStruct1C]
+ push eax
+ lea ecx, [esi+TFileNameDatabase.IndexStruct_174]
+ call TNameIndexStruct__CheckNameFragment
+
+loc_1957B06: ; CODE XREF: TFileNameDatabase__CheckNextPathFragment+185_j
+ test al, al
+ jnz loc_1957A03
+ mov ecx, [ebp+var_C]
+ cmp [edi+TStruct40.CharIndex], ecx
+ jnz loc_19579E4
+ jmp short loc_1957B32
+; ---------------------------------------------------------------------------
+
+loc_1957B1C: ; CODE XREF: TFileNameDatabase__CheckNextPathFragment+EE_j
+ mov edx, [esi+TFileNameDatabase.FrgmDist_LoBits.ItemArray]
+ mov ebx, [ebp+pStruct1C]
+ mov ecx, [edi+TStruct40.CharIndex]
+ mov ebx, [ebx+TMndxFindResult.szSearchMask]
+ mov dl, [eax+edx]
+ cmp dl, [ecx+ebx]
+ jz short loc_1957B62
+
+loc_1957B32: ; CODE XREF: TFileNameDatabase__CheckNextPathFragment+1AA_j
+ mov eax, [ebp+CollisionIndex]
+ inc [edi+TStruct40.HashValue]
+ inc eax
+ mov ecx, eax
+ and ecx, 1Fh
+ mov edx, 1
+ shl edx, cl
+ mov ecx, [esi+TFileNameDatabase.Struct68_00.ItemIsPresent.ItemArray]
+ mov [ebp+CollisionIndex], eax
+ shr eax, 5
+ test [ecx+eax*4], edx
+ jnz loc_1957A41
+ pop edi
+ pop esi
+ xor al, al
+ pop ebx
+ mov esp, ebp
+ pop ebp
+ retn 4
+; ---------------------------------------------------------------------------
+
+loc_1957B62: ; CODE XREF: TFileNameDatabase__CheckNextPathFragment+1C0_j
+ mov eax, 1
+ add [edi+TStruct40.CharIndex], eax
+ pop edi
+ pop esi
+ pop ebx
+ mov esp, ebp
+ pop ebp
+ retn 4
+TFileNameDatabase__CheckNextPathFragment endp
+
+
+TFileNameDatabase__FindFileInDatabase proc near
+ ; CODE XREF: MAR_FILE__FindFileInDatabase+2D_p
+
+pThis = dword ptr -4
+pStruct1C = dword ptr 8
+
+ push ebp ; ecx = Pointer to ARCHIVE_DATABASE
+ mov ebp, esp
+ push ecx
+ push ebx
+ push esi
+ mov esi, [ebp+pStruct1C]
+ xor eax, eax
+ push edi
+ mov edi, [esi+TMndxFindResult.pStruct40]
+ mov ebx, ecx
+ mov [edi+TStruct40.HashValue], eax
+ mov [edi+TStruct40.CharIndex], eax
+ mov [edi+TStruct40.SearchPhase], eax
+ mov [ebp+pThis], ebx
+ cmp [esi+TMndxFindResult.cchSearchMask], eax
+ jbe short loc_1957F26
+
+label_process_all_characters: ; CODE XREF: TFileNameDatabase__FindFileInDatabase+34j
+ push esi
+ mov ecx, ebx
+ call TFileNameDatabase__CheckNextPathFragment
+ test al, al
+ jz short label_return_false
+ mov eax, [edi+TStruct40.CharIndex]
+ cmp eax, [esi+TMndxFindResult.cchSearchMask]
+ jb short label_process_all_characters
+
+loc_1957F26: ; CODE XREF: TFileNameDatabase__FindFileInDatabase+20_j
+ mov ecx, [edi+TStruct40.HashValue]
+ mov eax, [ebx+TFileNameDatabase.FileNameIndexes.ItemIsPresent.ItemArray]
+ mov edx, ecx
+ and ecx, 1Fh
+ mov ebx, 1
+ shl ebx, cl
+ shr edx, 5
+ test [eax+edx*4], ebx
+ jz short label_return_false
+ mov ecx, [esi+TMndxFindResult.szSearchMask]
+ mov eax, [esi+TMndxFindResult.cchSearchMask]
+ mov [esi+TMndxFindResult.szFoundPath], ecx
+ mov ecx, [ebp+pThis]
+ mov [esi+TMndxFindResult.cchFoundPath], eax
+ mov edi, [edi+TStruct40.HashValue]
+ push edi
+ add ecx, TFileNameDatabase.FileNameIndexes
+ call TSparseArray__GetItemValue
+ pop edi
+ mov [esi+TMndxFindResult.FileNameIndex], eax
+ pop esi
+ mov al, 1
+ pop ebx
+ mov esp, ebp
+ pop ebp
+ retn 4
+; ---------------------------------------------------------------------------
+
+label_return_false: ; CODE XREF: TFileNameDatabase__FindFileInDatabase+2C_j
+ ; TFileNameDatabase__FindFileInDatabase+4E_j
+ pop edi
+ pop esi
+ xor al, al
+ pop ebx
+ mov esp, ebp
+ pop ebp
+ retn 4
+TFileNameDatabase__FindFileInDatabase endp
+
+
+; =============== S U B R O U T I N E =======================================
+
+; Attributes: bp-based frame
+
+TGenericArray__SetMaxItems_BYTE proc near ; CODE XREF: sub_19582E0+2Cp
+ ; TStruct40__InitSearchBuffers+2Cp ...
+
+ByteCount = dword ptr 8
+
+ push ebp
+ mov ebp, esp
+ push ebx
+ mov ebx, [ebp+ByteCount]
+ push esi
+ push edi
+ push offset unk_53ABE00
+ push ebx
+ mov esi, ecx
+ call j_operator_new_safe
+ xor ecx, ecx
+ add esp, 8
+ mov edi, eax
+ cmp [esi+TGenericArray.ItemCount], ecx
+ jbe short loc_19575D7
+
+loc_19575C2: ; CODE XREF: TGenericArray__SetMaxItems_BYTE+35j
+ lea edx, [ecx+edi]
+ test edx, edx
+ jz short loc_19575D1
+ mov eax, [esi+TGenericArray.field_4]
+ mov al, [ecx+eax]
+ mov [edx], al
+
+loc_19575D1: ; CODE XREF: TGenericArray__SetMaxItems_BYTE+27j
+ inc ecx
+ cmp ecx, [esi+TGenericArray.ItemCount]
+ jb short loc_19575C2
+
+loc_19575D7: ; CODE XREF: TGenericArray__SetMaxItems_BYTE+20j
+ mov eax, [esi+TGenericArray.DataBuffer]
+ push eax
+ mov [esi+TGenericArray.DataBuffer], edi
+ mov [esi+TGenericArray.field_4], edi
+ mov [esi+TGenericArray.ItemArray], edi
+ mov [esi+TGenericArray.MaxItemCount], ebx
+ call operator_delete
+ add esp, 4
+ pop edi
+ pop esi
+ pop ebx
+ pop ebp
+ retn 4
+TGenericArray__SetMaxItems_BYTE endp
+
+; =============== S U B R O U T I N E =======================================
+
+; Attributes: bp-based frame
+
+TGenericArray__SetMaxItems_STRUCT14 proc near
+ ; CODE XREF: TGenericArray__InsertItem_STRUCT14+2Cp
+ ; TGenericArray__sub_19583A0+2Dp ...
+
+var_4 = dword ptr -4
+ItemCount = dword ptr 8
+
+ push ebp
+ mov ebp, esp
+ push ecx
+ push esi
+ push edi
+ mov edi, [ebp+ItemCount]
+ lea eax, [edi+edi*4] ; EAX = (ItemCount * 5)
+ add eax, eax ; EAX = (ItemCount * 10)
+ add eax, eax ; EAX = (ItemCount * 20)
+ push offset unk_53ABE00
+ push eax
+ mov esi, ecx
+ call j_operator_new_safe
+ mov ecx, eax
+ xor eax, eax
+ add esp, 8
+ mov [ebp+var_4], ecx
+ cmp [esi+0Ch], eax
+ jbe short loc_195766A
+ xor edi, edi
+ mov edx, ecx
+ push ebx
+
+loc_1957631: ; CODE XREF: TGenericArray__SetMaxItems_STRUCT14+64j
+ test edx, edx
+ jz short loc_195765A
+ mov ecx, [esi+4]
+ mov ebx, [ecx+edi]
+ add ecx, edi
+ mov [edx], ebx
+ mov ebx, [ecx+4]
+ mov [edx+4], ebx
+ mov ebx, [ecx+8]
+ mov [edx+8], ebx
+ mov ebx, [ecx+0Ch]
+ mov [edx+0Ch], ebx
+ mov ecx, [ecx+10h]
+ mov [edx+10h], ecx
+ mov ecx, [ebp+var_4]
+
+loc_195765A: ; CODE XREF: TGenericArray__SetMaxItems_STRUCT14+33j
+ inc eax
+ add edi, 14h
+ add edx, 14h
+ cmp eax, [esi+0Ch]
+ jb short loc_1957631
+ mov edi, [ebp+ItemCount]
+ pop ebx
+
+loc_195766A: ; CODE XREF: TGenericArray__SetMaxItems_STRUCT14+2Aj
+ mov eax, [esi+TGenericArray.DataBuffer]
+ push eax
+ mov [esi+TGenericArray.DataBuffer], ecx
+ mov [esi+TGenericArray.field_4], ecx
+ mov [esi+TGenericArray.ItemArray], ecx
+ mov [esi+TGenericArray.MaxItemCount], edi
+ call operator_delete
+ add esp, 4
+ pop edi
+ pop esi
+ mov esp, ebp
+ pop ebp
+ retn 4
+TGenericArray__SetMaxItems_STRUCT14 endp
+
+; =============== S U B R O U T I N E =======================================
+
+; Attributes: bp-based frame
+
+TGenericArray__sub_19583A0 proc near ; CODE XREF: TStruct40__InitSearchBuffers+35p
+
+NewItemCount = dword ptr 8
+
+ push ebp
+ mov ebp, esp
+ push esi
+ mov esi, ecx
+ mov eax, [esi+TGenericArray.MaxItemCount]
+ push edi
+ mov edi, [ebp+NewItemCount]
+ cmp edi, eax
+ jbe short loc_19583D2
+ mov edx, edi
+ shr edx, 1
+ mov ecx, edi
+ cmp eax, edx
+ jbe short loc_19583CA
+ mov ecx, 0CCCCCCCh
+ cmp eax, 6666666h
+ ja short loc_19583CA
+ lea ecx, [eax+eax]
+
+loc_19583CA: ; CODE XREF: TGenericArray__sub_19583A0+19j
+ ; TGenericArray__sub_19583A0+25j
+ push ecx
+ mov ecx, esi
+ call TGenericArray__SetMaxItems_STRUCT14
+
+loc_19583D2: ; CODE XREF: TGenericArray__sub_19583A0+Fj
+ mov eax, [esi+TGenericArray.ItemCount]
+ cmp eax, edi
+ jnb short loc_1958410
+ lea ecx, [eax+eax*4]
+ add ecx, ecx
+ mov edx, edi
+ push ebx
+ add ecx, ecx
+ sub edx, eax
+ or ebx, 0FFFFFFFFh
+
+loc_19583E8: ; CODE XREF: TGenericArray__sub_19583A0+6Dj
+ mov eax, [esi+TGenericArray.field_4]
+ add eax, ecx
+ jz short loc_1958409
+ mov dword ptr [eax], 0
+ mov dword ptr [eax+4], 0
+ mov dword ptr [eax+8], 0
+ mov [eax+0Ch], ebx
+ mov [eax+10h], ebx
+
+loc_1958409: ; CODE XREF: TGenericArray__sub_19583A0+4Dj
+ add ecx, 14h
+ dec edx
+ jnz short loc_19583E8
+ pop ebx
+
+loc_1958410: ; CODE XREF: TGenericArray__sub_19583A0+37j
+ mov [esi+TGenericArray.ItemCount], edi
+ pop edi
+ pop esi
+ pop ebp
+ retn 4
+TGenericArray__sub_19583A0 endp
+
+; =============== S U B R O U T I N E =======================================
+
+
+TStruct40__InitSearchBuffers proc near ; CODE XREF: TFileNameDatabase__sub_1959460+2Bp
+ push ebx
+ push esi
+ mov esi, ecx
+ mov eax, [esi+TStruct40.array_00.MaxItemCount]
+ xor ebx, ebx
+ push edi
+ mov [esi+TStruct40.array_00.ItemCount], ebx
+ cmp eax, 40h
+ jnb short loc_19586E1
+ lea ecx, [ebx+40h] ; ECX = 0x40
+ cmp eax, 20h
+ jbe short loc_19586D9
+ cmp eax, 7FFFFFFFh
+ jbe short loc_19586D6
+ or ecx, 0FFFFFFFFh
+ jmp short loc_19586D9
+; ---------------------------------------------------------------------------
+
+loc_19586D6: ; CODE XREF: TStruct40__InitSearchBuffers+1Fj
+ lea ecx, [eax+eax]
+
+loc_19586D9: ; CODE XREF: TStruct40__InitSearchBuffers+18j
+ ; TStruct40__InitSearchBuffers+24j
+ push ecx
+ mov ecx, esi
+ call TGenericArray__SetMaxItems_BYTE
+
+loc_19586E1: ; CODE XREF: TStruct40__InitSearchBuffers+10j
+ push ebx
+ lea ecx, [esi+TStruct40.array_18]
+ call TGenericArray__sub_19583A0
+ mov eax, [esi+TStruct40.array_18.MaxItemCount]
+ cmp eax, 4
+ jnb short loc_1958714
+ mov ecx, 4
+ cmp eax, 2
+ jbe short loc_195870B
+ mov ecx, 0CCCCCCCh
+ cmp eax, 6666666h
+ ja short loc_195870B
+ lea ecx, [eax+eax]
+
+loc_195870B: ; CODE XREF: TStruct40__InitSearchBuffers+4Aj
+ ; TStruct40__InitSearchBuffers+56j
+ push ecx
+ lea ecx, [esi+TStruct40.array_18]
+ call TGenericArray__SetMaxItems_STRUCT14
+
+loc_1958714: ; CODE XREF: TStruct40__InitSearchBuffers+40j
+ pop edi
+ mov [esi+TStruct40.HashValue], ebx
+ mov [esi+TStruct40.CharIndex], ebx
+ mov [esi+TStruct40.ItemCount], ebx
+ mov [esi+TStruct40.SearchPhase], 2
+ pop esi
+ pop ebx
+ retn
+TStruct40__InitSearchBuffers endp
+
+; =============== S U B R O U T I N E =======================================
+
+; Attributes: bp-based frame
+
+TGenericArray__InsertItem_STRUCT14 proc near
+ ; CODE XREF: TFileNameDatabase__sub_1959460+73p
+
+pStruct14 = dword ptr 8
+
+ push ebp
+ mov ebp, esp
+ push esi
+ mov esi, ecx
+ mov eax, [esi+TGenericArray.ItemCount]
+ mov ecx, [esi+TGenericArray.MaxItemCount]
+ inc eax
+ cmp eax, ecx
+ jbe short loc_1958361
+ mov edx, eax
+ shr eax, 1
+ cmp ecx, eax
+ jbe short loc_1958359
+ mov edx, 0CCCCCCCh
+ cmp ecx, 6666666h
+ ja short loc_1958359
+ lea edx, [ecx+ecx]
+
+loc_1958359: ; CODE XREF: TGenericArray__InsertItem_STRUCT14+17j
+ ; TGenericArray__InsertItem_STRUCT14+24j
+ push edx
+ mov ecx, esi
+ call TGenericArray__SetMaxItems_STRUCT14
+
+loc_1958361: ; CODE XREF: TGenericArray__InsertItem_STRUCT14+Fj
+ mov eax, [esi+TGenericArray.ItemCount]
+ mov ecx, [esi+TGenericArray.field_4]
+ lea eax, [eax+eax*4]
+ lea eax, [ecx+eax*4]
+ test eax, eax
+ jz short loc_1958390
+ mov ecx, [ebp+pStruct14]
+ mov edx, [ecx+TStruct14.HashValue]
+ mov [eax+TStruct14.HashValue], edx
+ mov edx, [ecx+TStruct14.field_4]
+ mov [eax+TStruct14.field_4], edx
+ mov edx, [ecx+TStruct14.field_8]
+ mov [eax+TStruct14.field_8], edx
+ mov edx, [ecx+TStruct14.field_C]
+ mov [eax+TStruct14.field_C], edx
+ mov ecx, [ecx+TStruct14.field_10]
+ mov [eax+TStruct14.field_10], ecx
+
+loc_1958390: ; CODE XREF: TGenericArray__InsertItem_STRUCT14+3Fj
+ inc [esi+TGenericArray.ItemCount]
+ pop esi
+ pop ebp
+ retn 4
+TGenericArray__InsertItem_STRUCT14 endp
+
+; =============== S U B R O U T I N E =======================================
+
+; Attributes: bp-based frame
+
+CopyNameFragment proc near ; CODE XREF: sub_1958980+DAp
+ ; sub_1958D70+6Dp ...
+
+pThis = dword ptr -4
+pStruct1C = dword ptr 8
+dwDistance = dword ptr 0Ch
+
+ push ebp
+ mov ebp, esp
+ push ecx
+ mov eax, [ebp+pStruct1C]
+ push ebx
+ mov ebx, ecx
+ cmp [ebx+TNameIndexStruct.Struct68.TotalItemCount], 0
+ push esi
+ mov esi, [eax+TMndxFindResult.pStruct40]
+ push edi
+ mov [ebp+pThis], ebx
+ jnz loc_195A4B3
+ mov ebx, [ebx+TNameIndexStruct.NameFragments.ItemArray]
+ add ebx, [ebp+dwDistance]
+ cmp byte ptr [ebx], 0
+ mov [ebp+dwDistance], ebx
+ jz loc_195A55E
+ mov edi, edi
+
+loc_195A420: ; CODE XREF: CopyNameFragment+B4j
+ mov eax, [esi+TStruct40.array_00.ItemCount]
+ mov ecx, [esi+TStruct40.array_00.MaxItemCount]
+ inc eax
+ cmp eax, ecx
+ jbe short loc_195A48E
+ mov ebx, eax
+ shr eax, 1
+ cmp ecx, eax
+ jbe short loc_195A443
+ cmp ecx, 7FFFFFFFh
+ jbe short loc_195A440
+ or ebx, 0FFFFFFFFh
+ jmp short loc_195A443
+; ---------------------------------------------------------------------------
+
+loc_195A440: ; CODE XREF: CopyNameFragment+49j
+ lea ebx, [ecx+ecx]
+
+loc_195A443: ; CODE XREF: CopyNameFragment+41j
+ ; CopyNameFragment+4Ej
+ push offset unk_53ABE00
+ push ebx
+ call j_operator_new_safe
+ xor ecx, ecx
+ add esp, 8
+ mov edi, eax
+ cmp [esi+TStruct40.array_00.ItemCount], ecx
+ jbe short loc_195A475
+ lea ebx, [ebx+0]
+
+loc_195A460: ; CODE XREF: CopyNameFragment+83j
+ lea edx, [ecx+edi]
+ test edx, edx
+ jz short loc_195A46F
+ mov eax, [esi+TStruct40.array_00.field_4]
+ mov al, [ecx+eax]
+ mov [edx], al
+
+loc_195A46F: ; CODE XREF: CopyNameFragment+75j
+ inc ecx
+ cmp ecx, [esi+TStruct40.array_00.ItemCount]
+ jb short loc_195A460
+
+loc_195A475: ; CODE XREF: CopyNameFragment+68j
+ mov eax, [esi+TStruct40.array_00.DataBuffer]
+ push eax
+ mov [esi+TStruct40.array_00.DataBuffer], edi
+ mov [esi+TStruct40.array_00.field_4], edi
+ mov [esi+TStruct40.array_00.ItemArray], edi
+ mov [esi+TStruct40.array_00.MaxItemCount], ebx
+ call operator_delete
+ mov ebx, [ebp+dwDistance]
+ add esp, 4
+
+loc_195A48E: ; CODE XREF: CopyNameFragment+39j
+ mov eax, [esi+TStruct40.array_00.ItemCount]
+ add eax, [esi+TStruct40.array_00.field_4]
+ jz short loc_195A49A
+ mov cl, [ebx]
+ mov [eax], cl
+
+loc_195A49A: ; CODE XREF: CopyNameFragment+A4j
+ inc [esi+TStruct40.array_00.ItemCount]
+ inc ebx
+ cmp byte ptr [ebx], 0
+ mov [ebp+dwDistance], ebx
+ jnz loc_195A420
+ pop edi
+ pop esi
+ pop ebx
+ mov esp, ebp
+ pop ebp
+ retn 8
+; ---------------------------------------------------------------------------
+
+loc_195A4B3: ; CODE XREF: CopyNameFragment+16j
+ ; CopyNameFragment+168j
+ mov eax, [esi+TStruct40.array_00.ItemCount]
+ mov edx, [ebx+TNameIndexStruct.NameFragments.ItemArray]
+ mov edi, [ebp+dwDistance]
+ mov ecx, [esi+TStruct40.array_00.MaxItemCount]
+ add edx, edi
+ inc eax
+ mov [ebp+pStruct1C], edx
+ cmp eax, ecx
+ jbe short loc_195A52C
+ mov ebx, eax
+ shr eax, 1
+ cmp ecx, eax
+ jbe short loc_195A4E1
+ cmp ecx, 7FFFFFFFh
+ jbe short loc_195A4DE
+ or ebx, 0FFFFFFFFh
+ jmp short loc_195A4E1
+; ---------------------------------------------------------------------------
+
+loc_195A4DE: ; CODE XREF: CopyNameFragment+E7j
+ lea ebx, [ecx+ecx]
+
+loc_195A4E1: ; CODE XREF: CopyNameFragment+DFj
+ ; CopyNameFragment+ECj
+ push offset unk_53ABE00
+ push ebx
+ call j_operator_new_safe
+ xor ecx, ecx
+ add esp, 8
+ mov edi, eax
+ cmp [esi+TStruct40.array_00.ItemCount], ecx
+ jbe short loc_195A50D
+
+loc_195A4F8: ; CODE XREF: CopyNameFragment+11Bj
+ lea edx, [ecx+edi]
+ test edx, edx
+ jz short loc_195A507
+ mov eax, [esi+TStruct40.array_00.field_4]
+ mov al, [ecx+eax]
+ mov [edx], al
+
+loc_195A507: ; CODE XREF: CopyNameFragment+10Dj
+ inc ecx
+ cmp ecx, [esi+TStruct40.array_00.ItemCount]
+ jb short loc_195A4F8
+
+loc_195A50D: ; CODE XREF: CopyNameFragment+106j
+ mov eax, [esi+TStruct40.array_00.DataBuffer]
+ push eax
+ mov [esi+TStruct40.array_00.DataBuffer], edi
+ mov [esi+TStruct40.array_00.field_4], edi
+ mov [esi+TStruct40.array_00.ItemArray], edi
+ mov [esi+TStruct40.array_00.MaxItemCount], ebx
+ call operator_delete
+ mov edx, [ebp+pStruct1C]
+ mov edi, [ebp+dwDistance]
+ mov ebx, [ebp+pThis]
+ add esp, 4
+
+loc_195A52C: ; CODE XREF: CopyNameFragment+D7j
+ mov eax, [esi+TStruct40.array_00.ItemCount]
+ add eax, [esi+TStruct40.array_00.field_4]
+ jz short loc_195A538
+ mov cl, [edx]
+ mov [eax], cl
+
+loc_195A538: ; CODE XREF: CopyNameFragment+142j
+ inc [esi+TStruct40.array_00.ItemCount]
+ mov ecx, edi
+ and ecx, 1Fh
+ mov edx, 1
+ shl edx, cl
+ mov ecx, [ebx+TNameIndexStruct.Struct68.ItemIsPresent.ItemArray]
+ mov eax, edi
+ shr eax, 5
+ and edx, [ecx+eax*4]
+ inc edi
+ mov [ebp+dwDistance], edi
+ test edx, edx
+ jz loc_195A4B3
+
+loc_195A55E: ; CODE XREF: CopyNameFragment+28j
+ pop edi
+ pop esi
+ pop ebx
+ mov esp, ebp
+ pop ebp
+ retn 8
+CopyNameFragment endp
+
+; =============== S U B R O U T I N E =======================================
+
+; Attributes: bp-based frame
+
+sub_1958D70 proc near ; CODE XREF: sub_1958980+C9p
+ ; sub_1958D70+59p ...
+
+var_C = dword ptr -0Ch
+var_8 = dword ptr -8
+var_1 = byte ptr -1
+pStruct1C = dword ptr 8
+arg_4 = dword ptr 0Ch
+
+ push ebp
+ mov ebp, esp
+ mov eax, [ebp+pStruct1C]
+ sub esp, 0Ch
+ push ebx
+ push esi
+ mov esi, [eax+TMndxFindResult.pStruct40]
+ push edi
+ mov edi, ecx
+ mov ecx, [ebp+arg_4]
+
+loc_1958D84: ; CODE XREF: sub_1958D70+10Fj
+ ; sub_1958D70+28Fj
+ mov eax, [edi+TFileNameDatabase.NameFragIndexMask]
+ and eax, ecx
+ lea ebx, [eax+eax*2]
+ mov eax, [edi+TFileNameDatabase.NameFragTable.ItemArray]
+ add ebx, ebx
+ add ebx, ebx
+ mov [ebp+var_C], ebx
+ cmp ecx, [eax+ebx+4]
+ jnz loc_1958E8E
+ mov edx, [eax+ebx+8]
+ mov ecx, edx
+ and ecx, 0FFFFFF00h
+ cmp ecx, 0FFFFFF00h
+ jz short loc_1958DE7
+ mov ecx, [edi+TFileNameDatabase.NextDB.pDatabase]
+ push edx
+ test ecx, ecx
+ jz short loc_1958DD3
+ mov edx, [ebp+pStruct1C]
+ push edx
+ call sub_1958D70
+ jmp loc_1958E71
+; ---------------------------------------------------------------------------
+
+loc_1958DD3: ; CODE XREF: sub_1958D70+53j
+ mov eax, [ebp+pStruct1C]
+ push eax
+ lea ecx, [edi+TFileNameDatabase.IndexStruct_174]
+ call CopyNameFragment
+ jmp loc_1958E71
+; ---------------------------------------------------------------------------
+
+loc_1958DE7: ; CODE XREF: sub_1958D70+48j
+ mov eax, [esi+TStruct40.array_00.ItemCount]
+ mov ecx, [esi+TStruct40.array_00.MaxItemCount]
+ inc eax
+ mov byte ptr [ebp+arg_4+3], dl
+ cmp eax, ecx
+ jbe short loc_1958E61
+ mov [ebp+var_8], eax
+ shr eax, 1
+ cmp ecx, eax
+ jbe short loc_1958E15
+ cmp ecx, 7FFFFFFFh
+ jbe short loc_1958E0F
+ mov [ebp+var_8], 0FFFFFFFFh
+ jmp short loc_1958E15
+; ---------------------------------------------------------------------------
+
+loc_1958E0F: ; CODE XREF: sub_1958D70+94j
+ lea edx, [ecx+ecx]
+ mov [ebp+var_8], edx
+
+loc_1958E15: ; CODE XREF: sub_1958D70+8Cj
+ ; sub_1958D70+9Dj
+ mov eax, [ebp+var_8]
+ push offset unk_53ABE00
+ push eax
+ call j_operator_new_safe
+ xor ecx, ecx
+ add esp, 8
+ cmp [esi+TStruct40.array_00.ItemCount], ecx
+ jbe short loc_1958E48
+ lea ecx, [ecx+0]
+
+loc_1958E30: ; CODE XREF: sub_1958D70+D6j
+ lea edx, [ecx+eax]
+ test edx, edx
+ jz short loc_1958E42
+ mov ebx, [esi+4]
+ mov bl, [ecx+ebx]
+ mov [edx], bl
+ mov ebx, [ebp+var_C]
+
+loc_1958E42: ; CODE XREF: sub_1958D70+C5j
+ inc ecx
+ cmp ecx, [esi+TStruct40.array_00.ItemCount]
+ jb short loc_1958E30
+
+loc_1958E48: ; CODE XREF: sub_1958D70+BBj
+ mov ecx, [esi]
+ mov edx, [ebp+var_8]
+ push ecx
+ mov [esi+TStruct40.array_00.DataBuffer], eax
+ mov [esi+TStruct40.array_00.field_4], eax
+ mov [esi+TStruct40.array_00.ItemArray], eax
+ mov [esi+TStruct40.array_00.MaxItemCount], edx
+ call operator_delete
+ add esp, 4
+
+loc_1958E61: ; CODE XREF: sub_1958D70+83j
+ mov eax, [esi+TStruct40.array_00.field_4]
+ add eax, [esi+TStruct40.array_00.ItemCount]
+ jz short loc_1958E6E
+ mov cl, byte ptr [ebp+arg_4+3]
+ mov [eax], cl
+
+loc_1958E6E: ; CODE XREF: sub_1958D70+F7j
+ inc [esi+TStruct40.array_00.ItemCount]
+
+loc_1958E71: ; CODE XREF: sub_1958D70+5Ej
+ ; sub_1958D70+72j
+ mov edx, [edi+TFileNameDatabase.NameFragTable.ItemArray]
+ mov ecx, [ebx+edx]
+ mov [ebp+arg_4], ecx
+ test ecx, ecx
+ jnz loc_1958D84
+
+loc_1958E85: ; CODE XREF: sub_1958D70+277j
+ pop edi
+ pop esi
+ pop ebx
+ mov esp, ebp
+ pop ebp
+ retn 8
+; ---------------------------------------------------------------------------
+
+loc_1958E8E: ; CODE XREF: sub_1958D70+30j
+ mov edx, [edi+TFileNameDatabase.Struct68_D0.ItemIsPresent.ItemArray]
+ mov eax, ecx
+ and ecx, 1Fh
+ mov ebx, 1
+ shl ebx, cl
+ shr eax, 5
+ test [edx+eax*4], ebx
+ mov eax, [ebp+arg_4]
+ jz loc_1958F50
+ mov ebx, [edi+TFileNameDatabase.FrgmDist_LoBits.ItemArray]
+ push eax
+ lea ecx, [edi+TFileNameDatabase.Struct68_D0]
+ add ebx, eax
+ call TSparseArray__GetItemValue
+ mov ecx, [edi+TFileNameDatabase.FrgmDist_HiBits.BitsPerEntry]
+ imul ecx, eax
+ mov eax, ecx
+ and ecx, 1Fh
+ mov edx, ecx
+ mov ecx, [edi+TFileNameDatabase.FrgmDist_HiBits.BitsPerEntry]
+ add ecx, edx
+ shr eax, 5
+ cmp ecx, 20h
+ mov ecx, [edi+TFileNameDatabase.FrgmDist_HiBits.ItemArray]
+ ja short loc_1958EF2
+ mov eax, [ecx+eax*4]
+ mov ecx, edx
+ shr eax, cl
+ jmp short loc_1958F15
+; ---------------------------------------------------------------------------
+
+loc_1958EF2: ; CODE XREF: sub_1958D70+177j
+ lea eax, [ecx+eax*4]
+ mov [ebp+var_C], eax
+ mov eax, [eax+4]
+ mov ecx, 20h
+ sub ecx, edx
+ shl eax, cl
+ mov ecx, [ebp+var_C]
+ mov ecx, [ecx]
+ mov [ebp+var_C], ecx
+ mov ecx, edx
+ mov edx, [ebp+var_C]
+ shr edx, cl
+ or eax, edx
+
+loc_1958F15: ; CODE XREF: sub_1958D70+180j
+ and eax, [edi+TFileNameDatabase.FrgmDist_HiBits.EntryBitMask]
+ movzx edx, byte ptr [ebx]
+ mov ecx, [edi+TFileNameDatabase.NextDB.pDatabase]
+ shl eax, 8
+ or eax, edx
+ push eax
+ test ecx, ecx
+ jz short loc_1958F3C
+ mov eax, [ebp+pStruct1C]
+ push eax
+ call sub_1958D70
+ jmp loc_1958FDE
+; ---------------------------------------------------------------------------
+
+loc_1958F3C: ; CODE XREF: sub_1958D70+1BCj
+ mov ecx, [ebp+pStruct1C]
+ push ecx
+ lea ecx, [edi+TFileNameDatabase.IndexStruct_174]
+ call CopyNameFragment
+ jmp loc_1958FDE
+; ---------------------------------------------------------------------------
+
+loc_1958F50: ; CODE XREF: sub_1958D70+139j
+ mov edx, [edi+TFileNameDatabase.FrgmDist_LoBits.ItemArray]
+ mov cl, [eax+edx]
+ mov eax, [esi+TStruct40.array_00.ItemCount]
+ mov [ebp+var_1], cl
+ mov ecx, [esi+TStruct40.array_00.MaxItemCount]
+ inc eax
+ cmp eax, ecx
+ jbe short loc_1958FCE
+ mov ebx, eax
+ shr eax, 1
+ mov [ebp+var_8], ebx
+ cmp ecx, eax
+ jbe short loc_1958F85
+ cmp ecx, 7FFFFFFFh
+ jbe short loc_1958F7F
+ or ebx, 0FFFFFFFFh
+ jmp short loc_1958F82
+; ---------------------------------------------------------------------------
+
+loc_1958F7F: ; CODE XREF: sub_1958D70+208j
+ lea ebx, [ecx+ecx]
+
+loc_1958F82: ; CODE XREF: sub_1958D70+20Dj
+ mov [ebp+var_8], ebx
+
+loc_1958F85: ; CODE XREF: sub_1958D70+200j
+ push offset unk_53ABE00
+ push ebx
+ call j_operator_new_safe
+ xor ecx, ecx
+ add esp, 8
+ cmp [esi+TStruct40.array_00.ItemCount], ecx
+ jbe short loc_1958FB8
+ lea ebx, [ebx+0]
+
+loc_1958FA0: ; CODE XREF: sub_1958D70+243j
+ lea edx, [ecx+eax]
+ test edx, edx
+ jz short loc_1958FAF
+ mov ebx, [esi+TStruct40.array_00.field_4]
+ mov bl, [ecx+ebx]
+ mov [edx], bl
+
+loc_1958FAF: ; CODE XREF: sub_1958D70+235j
+ inc ecx
+ cmp ecx, [esi+TStruct40.array_00.ItemCount]
+ jb short loc_1958FA0
+ mov ebx, [ebp+var_8]
+
+loc_1958FB8: ; CODE XREF: sub_1958D70+228j
+ mov ecx, [esi+TStruct40.array_00.DataBuffer]
+ push ecx
+ mov [esi+TStruct40.array_00.DataBuffer], eax
+ mov [esi+TStruct40.array_00.field_4], eax
+ mov [esi+TStruct40.array_00.ItemArray], eax
+ mov [esi+TStruct40.array_00.MaxItemCount], ebx
+ call operator_delete
+ add esp, 4
+
+loc_1958FCE: ; CODE XREF: sub_1958D70+1F5j
+ mov eax, [esi+TStruct40.array_00.field_4]
+ add eax, [esi+TStruct40.array_00.ItemCount]
+ jz short loc_1958FDB
+ mov dl, [ebp+var_1]
+ mov [eax], dl
+
+loc_1958FDB: ; CODE XREF: sub_1958D70+264j
+ inc [esi+TStruct40.array_00.ItemCount]
+
+loc_1958FDE: ; CODE XREF: sub_1958D70+1C7j
+ ; sub_1958D70+1DBj
+ mov ebx, [ebp+arg_4]
+ cmp ebx, [edi+TFileNameDatabase.field_214]
+ jbe loc_1958E85
+ push ebx
+ mov ecx, edi
+ call sub_1959F50
+ or ecx, 0FFFFFFFFh
+ sub ecx, ebx
+ add ecx, eax
+ mov [ebp+arg_4], ecx
+ jmp loc_1958D84
+sub_1958D70 endp
+
+; =============== S U B R O U T I N E =======================================
+
+; Attributes: bp-based frame
+
+TFileNameDatabase__sub_1959CB0 proc near ; CODE XREF: TFileNameDatabase__CheckNextPathFragment+A1p
+ ; TFileNameDatabase__sub_1958B00+E8p ...
+
+pThis = dword ptr -4
+dwKey = dword ptr 8
+
+ push ebp
+ mov ebp, esp
+ push ecx
+ mov edx, [ebp+dwKey]
+ mov eax, edx
+ shr eax, 9
+ mov [ebp+pThis], ecx
+ test edx, 1FFh ; if(dwKey & 0x01FF)
+ jnz short loc_1959CD3
+ mov ecx, [ecx+TFileNameDatabase.Struct68_00.ArrayDwords_38.ItemArray]
+ mov eax, [ecx+eax*4] ; EAX = pDatabase->NextKeyTable[dwKey >> 0x09]
+ mov esp, ebp
+ pop ebp
+ retn 4
+; ---------------------------------------------------------------------------
+
+loc_1959CD3: ; CODE XREF: TFileNameDatabase__sub_1959CB0+15j
+ push ebx
+ push esi
+ mov esi, [ecx+TFileNameDatabase.Struct68_00.ArrayDwords_38.ItemArray]
+ lea esi, [esi+eax*4]
+ mov eax, [esi]
+ mov esi, [esi+4]
+ shr eax, 9
+ add esi, 1FFh
+ push edi
+ shr esi, 9
+ lea edi, [eax+0Ah]
+ mov [ebp+dwKey], esi
+ cmp edi, esi
+ jb short loc_1959D2E
+ mov edi, [ecx+TFileNameDatabase.Struct68_00.ArrayTriplets_20.ItemArray]
+ lea esi, [eax+eax*2+3]
+ lea esi, [edi+esi*4]
+ mov edi, eax
+ shl edi, 9
+ mov ebx, edi
+ sub ebx, [esi]
+ add ebx, 200h
+ cmp edx, ebx
+ jb short loc_1959D5F
+
+loc_1959D14: ; CODE XREF: TFileNameDatabase__sub_1959CB0+7Aj
+ add edi, 200h
+ add esi, 0Ch
+ mov ebx, edi
+ sub ebx, [esi]
+ inc eax
+ add ebx, 200h
+ cmp edx, ebx
+ jnb short loc_1959D14
+ jmp short loc_1959D5F
+; ---------------------------------------------------------------------------
+
+loc_1959D2E: ; CODE XREF: TFileNameDatabase__sub_1959CB0+45j
+ lea edi, [eax+1]
+ cmp edi, esi
+ jnb short loc_1959D5F
+ mov ecx, [ecx+TFileNameDatabase.Struct68_00.ArrayTriplets_20.ItemArray]
+
+loc_1959D38: ; CODE XREF: TFileNameDatabase__sub_1959CB0+AAj
+ add esi, eax
+ shr esi, 1
+ mov ebx, esi
+ shl ebx, 9
+ lea edi, [esi+esi*2]
+ sub ebx, [ecx+edi*4]
+ cmp edx, ebx
+ jnb short loc_1959D50
+ mov [ebp+dwKey], esi
+ jmp short loc_1959D55
+; ---------------------------------------------------------------------------
+
+loc_1959D50: ; CODE XREF: TFileNameDatabase__sub_1959CB0+99j
+ mov eax, esi
+ mov esi, [ebp+dwKey]
+
+loc_1959D55: ; CODE XREF: TFileNameDatabase__sub_1959CB0+9Ej
+ lea edi, [eax+1]
+ cmp edi, esi
+ jb short loc_1959D38
+ mov ecx, [ebp+pThis]
+
+loc_1959D5F: ; CODE XREF: TFileNameDatabase__sub_1959CB0+62j
+ ; TFileNameDatabase__sub_1959CB0+7Cj ...
+ mov ecx, [ecx+TFileNameDatabase.Struct68_00.ArrayTriplets_20.ItemArray]
+ lea esi, [eax+eax*2]
+ mov edi, [ecx+esi*4] ; EDI = Struct68_00.ArrayTriplets_20.ItemArray[eax]
+ lea esi, [ecx+esi*4] ; ESI = Struct68_00.ArrayTriplets_20.ItemArray + eax
+ mov ecx, eax
+ shl ecx, 9
+ sub edi, ecx
+ shl eax, 4
+ add edx, edi
+ mov edi, eax
+ mov eax, [esi+TRIPLET.NextKey]
+ mov ecx, eax
+ shr ecx, 17h
+ mov ebx, 100h
+ sub ebx, ecx
+ cmp edx, ebx
+ jnb short loc_1959DE8
+ mov ecx, eax
+ shr ecx, 7
+ and ecx, 0FFh
+ mov esi, 80h
+ sub esi, ecx
+ cmp edx, esi
+ jnb short loc_1959DC0
+ and eax, 7Fh
+ mov ecx, 40h
+ sub ecx, eax
+ cmp edx, ecx
+ jb loc_1959E53
+ add edi, 2
+ lea edx, [edx+eax-40h]
+ jmp loc_1959E53
+; ---------------------------------------------------------------------------
+
+loc_1959DC0: ; CODE XREF: TFileNameDatabase__sub_1959CB0+F0j
+ shr eax, 0Fh
+ and eax, 0FFh
+ mov esi, 0C0h
+ sub esi, eax
+ cmp edx, esi
+ jnb short loc_1959DDC
+ add edi, 4
+ lea edx, [edx+ecx-80h]
+ jmp short loc_1959E53
+; ---------------------------------------------------------------------------
+
+loc_1959DDC: ; CODE XREF: TFileNameDatabase__sub_1959CB0+121j
+ add edi, 6
+ lea edx, [edx+eax-0C0h]
+ jmp short loc_1959E53
+; ---------------------------------------------------------------------------
+
+loc_1959DE8: ; CODE XREF: TFileNameDatabase__sub_1959CB0+DAj
+ mov esi, [esi+TRIPLET.Distance]
+ mov eax, esi
+ shr eax, 9
+ and eax, 1FFh
+ mov ebx, 180h
+ sub ebx, eax
+ cmp edx, ebx
+ jnb short loc_1959E29
+ and esi, 1FFh
+ mov eax, 140h
+ sub eax, esi
+ cmp edx, eax
+ jnb short loc_1959E1D
+ add edi, 8
+ lea edx, [edx+ecx-100h]
+ jmp short loc_1959E53
+; ---------------------------------------------------------------------------
+
+loc_1959E1D: ; CODE XREF: TFileNameDatabase__sub_1959CB0+15Fj
+ add edi, 0Ah
+ lea edx, [edx+esi-140h]
+ jmp short loc_1959E53
+; ---------------------------------------------------------------------------
+
+loc_1959E29: ; CODE XREF: TFileNameDatabase__sub_1959CB0+14Ej
+ shr esi, 12h
+ and esi, 1FFh
+ mov ecx, 1C0h
+ sub ecx, esi
+ cmp edx, ecx
+ jnb short loc_1959E49
+ add edi, 0Ch
+ lea edx, [edx+eax-180h]
+ jmp short loc_1959E53
+; ---------------------------------------------------------------------------
+
+loc_1959E49: ; CODE XREF: TFileNameDatabase__sub_1959CB0+18Bj
+ add edi, 0Eh
+ lea edx, [edx+esi-1C0h]
+
+loc_1959E53: ; CODE XREF: TFileNameDatabase__sub_1959CB0+FEj
+ ; TFileNameDatabase__sub_1959CB0+10Bj ...
+ mov eax, [ebp+pThis]
+ mov ebx, [eax+TFileNameDatabase.Struct68_00.ItemIsPresent.ItemArray]
+ mov ecx, [ebx+edi*4]
+ not ecx
+ mov eax, ecx
+ shr eax, 1
+ and eax, 55555555h
+ mov esi, ecx
+ and esi, 55555555h
+ add eax, esi
+ mov esi, eax
+ shr esi, 2
+ and eax, 33333333h
+ and esi, 33333333h
+ add esi, eax
+ mov eax, esi
+ shr eax, 4
+ and esi, 0F0F0F0Fh
+ and eax, 0F0F0F0Fh
+ add eax, esi
+ imul eax, 1010101h
+ mov esi, eax
+ shr esi, 18h
+ cmp edx, esi
+ jb short loc_1959EEA
+ mov ecx, [ebx+edi*4+4]
+ inc edi
+ sub edx, esi
+ not ecx
+ mov eax, ecx
+ shr eax, 1
+ and eax, 55555555h
+ mov esi, ecx
+ and esi, 55555555h
+ add eax, esi
+ mov esi, eax
+ shr esi, 2
+ and eax, 33333333h
+ and esi, 33333333h
+ add esi, eax
+ mov eax, esi
+ shr eax, 4
+ and eax, 0F0F0F0Fh
+ and esi, 0F0F0F0Fh
+ add eax, esi
+ imul eax, 1010101h
+
+loc_1959EEA: ; CODE XREF: TFileNameDatabase__sub_1959CB0+1F2j
+ mov esi, eax
+ shr esi, 8
+ and esi, 0FFh
+ shl edi, 5
+ cmp edx, esi
+ jnb short loc_1959F0D
+ and eax, 0FFh
+ cmp edx, eax
+ jb short loc_1959F2B
+ add edi, 8
+ shr ecx, 8
+ jmp short loc_1959F29
+; ---------------------------------------------------------------------------
+
+loc_1959F0D: ; CODE XREF: TFileNameDatabase__sub_1959CB0+24Aj
+ shr eax, 10h
+ and eax, 0FFh
+ cmp edx, eax
+ jnb short loc_1959F23
+ add edi, 10h
+ shr ecx, 10h
+ sub edx, esi
+ jmp short loc_1959F2B
+; ---------------------------------------------------------------------------
+
+loc_1959F23: ; CODE XREF: TFileNameDatabase__sub_1959CB0+267j
+ add edi, 18h
+ shr ecx, 18h
+
+loc_1959F29: ; CODE XREF: TFileNameDatabase__sub_1959CB0+25Bj
+ sub edx, eax
+
+loc_1959F2B: ; CODE XREF: TFileNameDatabase__sub_1959CB0+253j
+ ; TFileNameDatabase__sub_1959CB0+271j
+ and ecx, 0FFh
+ shl edx, 8
+ movzx eax, ds:table_1BA1818[ecx+edx]
+ add eax, edi
+ pop edi
+ pop esi
+ pop ebx
+ mov esp, ebp
+ pop ebp
+ retn 4
+TFileNameDatabase__sub_1959CB0 endp
+
+; =============== S U B R O U T I N E =======================================
+
+; Attributes: bp-based frame
+
+TNameIndexStruct__CheckAndCopyNameFragment proc near ; CODE XREF: TArchiveDatabase__sub_1958B00+74p
+ ; TArchiveDatabase__sub_1958B00+1E0p ...
+
+var_C = dword ptr -0Ch
+pThis = dword ptr -8
+var_4 = dword ptr -4
+pStruct1C = dword ptr 8
+dwDistance = dword ptr 0Ch
+
+ push ebp
+ mov ebp, esp
+ sub esp, 0Ch
+ mov eax, [ebp+pStruct1C]
+ push ebx
+ mov edx, ecx
+ cmp [edx+TNameIndexStruct.Struct68.TotalItemCount], 0
+ push esi
+ mov esi, [eax+TMndxFindResult.pStruct40]
+ push edi
+ mov [ebp+pThis], edx
+ jnz loc_195A6B7
+ mov edi, [edx+TNameIndexStruct.NameFragments.ItemArray]
+ sub edi, [esi+TStruct40.CharIndex]
+ add edi, [ebp+dwDistance]
+ mov [ebp+pThis], edi
+ lea ebx, [ebx+0]
+
+loc_195A5A0: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+E6j
+ mov edx, [esi+TStruct40.CharIndex]
+ mov ecx, [ebp+pStruct1C]
+ mov eax, [ecx+TMndxFindResult.szSearchMask]
+ mov cl, [edx+edi]
+ mov [ebp+dwDistance], edx
+ cmp cl, [edx+eax]
+ jnz loc_195A67D
+ mov eax, [esi+TStruct40.array_00.ItemCount]
+ mov ecx, [esi+TStruct40.array_00.MaxItemCount]
+ mov ebx, 1
+ add eax, ebx
+ cmp eax, ecx
+ jbe short loc_195A62D
+ mov ebx, eax
+ shr eax, 1
+ cmp ecx, eax
+ jbe short loc_195A5E0
+ cmp ecx, 7FFFFFFFh
+ jbe short loc_195A5DD
+ or ebx, 0FFFFFFFFh
+ jmp short loc_195A5E0
+; ---------------------------------------------------------------------------
+
+loc_195A5DD: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+66j
+ lea ebx, [ecx+ecx]
+
+loc_195A5E0: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+5Ej
+ ; TNameIndexStruct__CheckAndCopyNameFragment+6Bj
+ push offset unk_53ABE00
+ push ebx
+ call j_operator_new_safe
+ xor ecx, ecx
+ add esp, 8
+ mov edi, eax
+ cmp [esi+TStruct40.array_00.ItemCount], ecx
+ jbe short loc_195A60C
+
+loc_195A5F7: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+9Aj
+ lea edx, [ecx+edi]
+ test edx, edx
+ jz short loc_195A606
+ mov eax, [esi+TStruct40.array_00.field_4]
+ mov al, [ecx+eax]
+ mov [edx], al
+
+loc_195A606: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+8Cj
+ inc ecx
+ cmp ecx, [esi+TStruct40.array_00.ItemCount]
+ jb short loc_195A5F7
+
+loc_195A60C: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+85j
+ mov eax, [esi+TStruct40.array_00.DataBuffer]
+ push eax
+ mov [esi+TStruct40.array_00.DataBuffer], edi
+ mov [esi+TStruct40.array_00.field_4], edi
+ mov [esi+TStruct40.array_00.ItemArray], edi
+ mov [esi+TStruct40.array_00.MaxItemCount], ebx
+ call operator_delete
+ mov edx, [ebp+dwDistance]
+ mov edi, [ebp+pThis]
+ add esp, 4
+ mov ebx, 1
+
+loc_195A62D: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+56j
+ mov eax, [esi+TStruct40.array_00.field_4]
+ add eax, [esi+TStruct40.array_00.ItemCount]
+ jz short loc_195A63A
+ mov cl, [edx+edi]
+ mov [eax], cl
+
+loc_195A63A: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+C3j
+ add [esi+TStruct40.CharIndex], ebx
+ add [esi+TStruct40.array_00.ItemCount], ebx
+ mov ecx, [esi+TStruct40.CharIndex]
+ cmp byte ptr [ecx+edi], 0
+ mov eax, [esi+TStruct40.array_00.ItemCount]
+ jz loc_195A806
+ mov edx, [ebp+pStruct1C]
+ cmp ecx, [edx+TMndxFindResult.cchSearchMask]
+ jb loc_195A5A0
+ add edi, ecx
+ mov edi, edi
+
+loc_195A660: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+13Aj
+ mov ecx, [esi+TStruct40.array_00.MaxItemCount]
+ inc eax
+ cmp eax, ecx
+ jbe short loc_195A693
+ mov edx, eax
+ shr eax, 1
+ cmp ecx, eax
+ jbe short loc_195A68B
+ cmp ecx, 7FFFFFFFh
+ jbe short loc_195A688
+ or edx, 0FFFFFFFFh
+ jmp short loc_195A68B
+; ---------------------------------------------------------------------------
+
+loc_195A67D: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+41j
+ ; TNameIndexStruct__CheckAndCopyNameFragment+16Bj
+ pop edi
+ pop esi
+ xor al, al
+ pop ebx
+ mov esp, ebp
+ pop ebp
+ retn 8
+; ---------------------------------------------------------------------------
+
+loc_195A688: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+106j
+ lea edx, [ecx+ecx]
+
+loc_195A68B: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+FEj
+ ; TNameIndexStruct__CheckAndCopyNameFragment+10Bj
+ push edx
+ mov ecx, esi
+ call TGenericArray__SetMaxItems_BYTE
+
+loc_195A693: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+F6j
+ mov eax, [esi+TStruct40.array_00.field_4]
+ add eax, [esi+TStruct40.array_00.ItemCount]
+ jz short loc_195A69F
+ mov cl, [edi]
+ mov [eax], cl
+
+loc_195A69F: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+129j
+ add [esi+TStruct40.array_00.ItemCount], ebx
+ mov eax, [esi+TStruct40.array_00.ItemCount]
+ add edi, ebx
+ cmp byte ptr [edi], 0
+ jnz short loc_195A660
+ pop edi
+ pop esi
+ mov al, 1
+ pop ebx
+ mov esp, ebp
+ pop ebp
+ retn 8
+; ---------------------------------------------------------------------------
+
+loc_195A6B7: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+18j
+ mov ebx, [ebp+dwDistance]
+ lea ebx, [ebx+0]
+
+loc_195A6C0: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+231j
+ mov edi, [edx+TNameIndexStruct.NameFragments.ItemArray]
+ mov eax, [ebp+pStruct1C]
+ mov ecx, [esi+TStruct40.CharIndex]
+ mov eax, [eax]
+ add edi, ebx
+ mov [ebp+var_4], edx
+ mov dl, [edi]
+ cmp dl, [ecx+eax]
+ mov edx, [ebp+var_4]
+ mov [ebp+var_C], edi
+ jnz short loc_195A67D
+ mov eax, [esi+TStruct40.array_00.ItemCount]
+ mov ecx, [esi+TStruct40.array_00.MaxItemCount]
+ inc eax
+ cmp eax, ecx
+ jbe short loc_195A752
+ mov [ebp+var_4], eax
+ shr eax, 1
+ cmp ecx, eax
+ jbe short loc_195A707
+ cmp ecx, 7FFFFFFFh
+ jbe short loc_195A702
+ mov [ebp+var_4], 0FFFFFFFFh
+ jmp short loc_195A707
+; ---------------------------------------------------------------------------
+
+loc_195A702: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+187j
+ add ecx, ecx
+ mov [ebp+var_4], ecx
+
+loc_195A707: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+17Fj
+ ; TNameIndexStruct__CheckAndCopyNameFragment+190j
+ mov edx, [ebp+var_4]
+ push offset unk_53ABE00
+ push edx
+ call j_operator_new_safe
+ xor ecx, ecx
+ add esp, 8
+ mov edi, eax
+ cmp [esi+TStruct40.array_00.ItemCount], ecx
+ jbe short loc_195A736
+
+loc_195A721: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+1C4j
+ lea edx, [ecx+edi]
+ test edx, edx
+ jz short loc_195A730
+ mov eax, [esi+TStruct40.array_00.field_4]
+ mov al, [ecx+eax]
+ mov [edx], al
+
+loc_195A730: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+1B6j
+ inc ecx
+ cmp ecx, [esi+TStruct40.array_00.ItemCount]
+ jb short loc_195A721
+
+loc_195A736: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+1AFj
+ mov eax, [esi+TStruct40.array_00.DataBuffer]
+ mov ecx, [ebp+var_4]
+ push eax
+ mov [esi+TStruct40.array_00.DataBuffer], edi
+ mov [esi+TStruct40.array_00.field_4], edi
+ mov [esi+TStruct40.array_00.ItemArray], edi
+ mov [esi+TStruct40.array_00.MaxItemCount], ecx
+ call operator_delete
+ mov edx, [ebp+pThis]
+ add esp, 4
+
+loc_195A752: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+176j
+ mov edi, [esi+TStruct40.array_00.field_4]
+ add edi, [esi+TStruct40.array_00.ItemCount]
+ jz short loc_195A761
+ mov eax, [ebp+var_C]
+ mov cl, [eax]
+ mov [edi], cl
+
+loc_195A761: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+1E8j
+ mov ecx, 1
+ add [esi+TStruct40.array_00.ItemCount], ecx
+ add [esi+TStruct40.CharIndex], ecx
+ mov edx, [edx+20h]
+ mov eax, [esi+TStruct40.array_00.ItemCount]
+ mov ecx, ebx
+ mov edi, ebx
+ and ecx, 1Fh
+ mov ebx, 1
+ shl ebx, cl
+ shr edi, 5
+ mov ecx, [edx+edi*4]
+ and ecx, ebx
+ mov ebx, [ebp+dwDistance]
+ inc ebx
+ mov [ebp+dwDistance], ebx
+ test ecx, ecx
+ jnz short loc_195A806
+ mov ecx, [esi+TStruct40.CharIndex]
+ mov edx, [ebp+pStruct1C]
+ cmp ecx, [edx+4]
+ jnb short loc_195A7A6
+ mov edx, [ebp+pThis]
+ jmp loc_195A6C0
+; ---------------------------------------------------------------------------
+
+loc_195A7A6: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+22Cj
+ ; TNameIndexStruct__CheckAndCopyNameFragment+294j
+ mov ecx, [ebp+pThis]
+ mov edi, [ecx+8]
+ mov ecx, [esi+TStruct40.array_00.MaxItemCount]
+ inc eax
+ cmp eax, ecx
+ jbe short loc_195A7D4
+ mov edx, eax
+ shr eax, 1
+ cmp ecx, eax
+ jbe short loc_195A7CC
+ cmp ecx, 7FFFFFFFh
+ jbe short loc_195A7C9
+ or edx, 0FFFFFFFFh
+ jmp short loc_195A7CC
+; ---------------------------------------------------------------------------
+
+loc_195A7C9: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+252j
+ lea edx, [ecx+ecx]
+
+loc_195A7CC: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+24Aj
+ ; TNameIndexStruct__CheckAndCopyNameFragment+257j
+ push edx
+ mov ecx, esi
+ call TGenericArray__SetMaxItems_BYTE
+
+loc_195A7D4: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+242j
+ mov eax, [esi+TStruct40.array_00.field_4]
+ add eax, [esi+TStruct40.array_00.ItemCount]
+ jz short loc_195A7E1
+ mov dl, [edi+ebx]
+ mov [eax], dl
+
+loc_195A7E1: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+26Aj
+ inc [esi+TStruct40.array_00.ItemCount]
+ mov edi, [ebp+pThis]
+ mov edi, [edi+20h]
+ mov eax, [esi+TStruct40.array_00.ItemCount]
+ mov ecx, ebx
+ and ecx, 1Fh
+ mov edx, 1
+ shl edx, cl
+ mov ecx, ebx
+ shr ecx, 5
+ inc ebx
+ and edx, [edi+ecx*4]
+ test edx, edx
+ jz short loc_195A7A6
+
+loc_195A806: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+DAj
+ ; TNameIndexStruct__CheckAndCopyNameFragment+221j
+ pop edi
+ pop esi
+ mov al, 1
+ pop ebx
+ mov esp, ebp
+ pop ebp
+ retn 8
+TNameIndexStruct__CheckAndCopyNameFragment endp
+
+; =============== S U B R O U T I N E =======================================
+
+; Attributes: bp-based frame
+
+sub_1959010 proc near ; CODE XREF: TArchiveDatabase__sub_1958B00+67p
+ ; TArchiveDatabase__sub_1958B00+1CFp ...
+
+pFragmentInfo = dword ptr -0Ch
+var_8 = dword ptr -8
+var_1 = byte ptr -1
+pStruct1C = dword ptr 8
+arg_4 = dword ptr 0Ch
+
+ push ebp
+ mov ebp, esp
+ mov eax, [ebp+pStruct1C]
+ sub esp, 0Ch
+ push ebx
+ push esi
+ mov esi, [eax+TMndxFindResult.pStruct40]
+ push edi
+ mov edi, ecx
+ mov ecx, [ebp+arg_4]
+
+loc_1959024: ; CODE XREF: sub_1959010+2CEj
+ mov eax, [edi+TFileNameDatabase.NameFragIndexMask]
+ and eax, ecx
+ lea ebx, [eax+eax*2]
+ mov eax, [edi+TFileNameDatabase.NameFragTable.ItemArray]
+ add ebx, ebx
+ add ebx, ebx
+ add eax, ebx
+ mov [ebp+pFragmentInfo], ebx
+ cmp ecx, [eax+NAME_ENTRY.NextHashModifier]
+ jnz loc_1959147
+ mov edx, [eax+NAME_ENTRY.FragmentOffset]
+ mov ecx, edx
+ and ecx, 0FFFFFF00h
+ cmp ecx, 0FFFFFF00h
+ jz short loc_1959092
+ mov ecx, [edi+TFileNameDatabase.NextDB.pDatabase]
+ push edx
+ test ecx, ecx
+ jz short loc_1959070
+ mov edx, [ebp+pStruct1C]
+ push edx
+ call sub_1959010
+ jmp short loc_195907F
+; ---------------------------------------------------------------------------
+
+loc_1959070: ; CODE XREF: sub_1959010+53j
+ mov eax, [ebp+pStruct1C]
+ push eax
+ lea ecx, [edi+TFileNameDatabase.IndexStruct_174]
+ call TNameIndexStruct__CheckAndCopyNameFragment
+
+loc_195907F: ; CODE XREF: sub_1959010+5Ej
+ test al, al
+ jnz loc_195912E
+
+loc_1959087: ; CODE XREF: sub_1959010+90j
+ ; sub_1959010+1F3j ...
+ pop edi
+ pop esi
+ xor al, al
+ pop ebx
+ mov esp, ebp
+ pop ebp
+ retn 8
+; ---------------------------------------------------------------------------
+
+loc_1959092: ; CODE XREF: sub_1959010+48j
+ mov ecx, [ebp+pStruct1C]
+ mov eax, [ecx+TMndxFindResult.szSearchMask]
+ mov ecx, [esi+TStruct40.CharIndex]
+ mov byte ptr [ebp+arg_4+3], dl
+ cmp dl, [eax+ecx]
+ jnz short loc_1959087
+ mov eax, [esi+TStruct40.array_00.ItemCount]
+ mov ecx, [esi+TStruct40.array_00.MaxItemCount]
+ inc eax
+ cmp eax, ecx
+ jbe short loc_1959119
+ mov [ebp+var_8], eax
+ shr eax, 1
+ cmp ecx, eax
+ jbe short loc_19590CD
+ cmp ecx, 7FFFFFFFh
+ jbe short loc_19590C7
+ mov [ebp+var_8], 0FFFFFFFFh
+ jmp short loc_19590CD
+; ---------------------------------------------------------------------------
+
+loc_19590C7: ; CODE XREF: sub_1959010+ACj
+ lea edx, [ecx+ecx]
+ mov [ebp+var_8], edx
+
+loc_19590CD: ; CODE XREF: sub_1959010+A4j
+ ; sub_1959010+B5j
+ mov eax, [ebp+var_8]
+ push offset unk_53ABE00
+ push eax
+ call j_operator_new_safe
+ xor ecx, ecx
+ add esp, 8
+ cmp [esi+TStruct40.array_00.ItemCount], ecx
+ jbe short loc_19590FD
+
+loc_19590E5: ; CODE XREF: sub_1959010+EBj
+ lea edx, [ecx+eax]
+ test edx, edx
+ jz short loc_19590F7
+ mov ebx, [esi+TStruct40.array_00.field_4]
+ mov bl, [ecx+ebx]
+ mov [edx], bl
+ mov ebx, [ebp+pFragmentInfo]
+
+loc_19590F7: ; CODE XREF: sub_1959010+DAj
+ inc ecx
+ cmp ecx, [esi+TStruct40.array_00.ItemCount]
+ jb short loc_19590E5
+
+loc_19590FD: ; CODE XREF: sub_1959010+D3j
+ mov ecx, [esi+TStruct40.array_00.DataBuffer]
+ mov edx, [ebp+var_8]
+ push ecx
+ mov [esi+TStruct40.array_00.DataBuffer], eax
+ mov [esi+TStruct40.array_00.field_4], eax
+ mov [esi+TStruct40.array_00.ItemArray], eax
+ mov [esi+TStruct40.array_00.MaxItemCount], edx
+ call operator_delete
+ mov dl, byte ptr [ebp+arg_4+3]
+ add esp, 4
+
+loc_1959119: ; CODE XREF: sub_1959010+9Bj
+ mov eax, [esi+TStruct40.array_00.field_4]
+ add eax, [esi+TStruct40.array_00.ItemCount]
+ jz short loc_1959123
+ mov [eax], dl
+
+loc_1959123: ; CODE XREF: sub_1959010+10Fj
+ mov eax, 1
+ add [esi+TStruct40.array_00.ItemCount], eax
+ add [esi+TStruct40.CharIndex], eax
+
+loc_195912E: ; CODE XREF: sub_1959010+71j
+ mov eax, [edi+TFileNameDatabase.NameFragTable.ItemArray]
+ mov ecx, [ebx+eax]
+ mov [ebp+arg_4], ecx
+ test ecx, ecx
+ jz loc_19592ED
+ jmp loc_19592D5
+; ---------------------------------------------------------------------------
+
+loc_1959147: ; CODE XREF: sub_1959010+31j
+ mov eax, [edi+TFileNameDatabase.Struct68_D0.ItemIsPresent.ItemArray]
+ mov edx, ecx
+ and ecx, 1Fh
+ mov ebx, 1
+ shl ebx, cl
+ shr edx, 5
+ test [eax+edx*4], ebx
+ mov eax, [ebp+arg_4]
+ jz loc_195920E
+ mov ebx, [edi+TFileNameDatabase.FrgmDist_LoBits.ItemArray]
+ push eax
+ lea ecx, [edi+TFileNameDatabase.Struct68_D0]
+ add ebx, eax
+ call TSparseArray__GetItemValue
+ mov ecx, [edi+TFileNameDatabase.FrgmDist_HiBits.BitsPerEntry]
+ imul ecx, eax
+ mov eax, ecx
+ and ecx, 1Fh
+ mov edx, ecx
+ mov ecx, [edi+TFileNameDatabase.FrgmDist_HiBits.BitsPerEntry]
+ add ecx, edx
+ shr eax, 5
+ cmp ecx, 20h
+ mov ecx, [edi+TFileNameDatabase.FrgmDist_HiBits.ItemArray]
+ ja short loc_19591AB
+ mov eax, [ecx+eax*4]
+ mov ecx, edx
+ shr eax, cl
+ jmp short loc_19591CE
+; ---------------------------------------------------------------------------
+
+loc_19591AB: ; CODE XREF: sub_1959010+190j
+ lea eax, [ecx+eax*4]
+ mov [ebp+pFragmentInfo], eax
+ mov eax, [eax+4]
+ mov ecx, 20h
+ sub ecx, edx
+ shl eax, cl
+ mov ecx, [ebp+pFragmentInfo]
+ mov ecx, [ecx]
+ mov [ebp+pFragmentInfo], ecx
+ mov ecx, edx
+ mov edx, [ebp+pFragmentInfo]
+ shr edx, cl
+ or eax, edx
+
+loc_19591CE: ; CODE XREF: sub_1959010+199j
+ and eax, [edi+TFileNameDatabase.FrgmDist_HiBits.EntryBitMask]
+ movzx edx, byte ptr [ebx]
+ mov ecx, [edi+TFileNameDatabase.NextDB.pDatabase]
+ shl eax, 8
+ or eax, edx
+ push eax
+ test ecx, ecx
+ jz short loc_19591F2
+ mov eax, [ebp+pStruct1C]
+ push eax
+ call sub_1959010
+ jmp short loc_1959201
+; ---------------------------------------------------------------------------
+
+loc_19591F2: ; CODE XREF: sub_1959010+1D5j
+ mov ecx, [ebp+pStruct1C]
+ push ecx
+ lea ecx, [edi+TFileNameDatabase.IndexStruct_174]
+ call TNameIndexStruct__CheckAndCopyNameFragment
+
+loc_1959201: ; CODE XREF: sub_1959010+1E0j
+ test al, al
+ jz loc_1959087
+ jmp loc_19592B6
+; ---------------------------------------------------------------------------
+
+loc_195920E: ; CODE XREF: sub_1959010+152j
+ mov edx, [edi+TFileNameDatabase.FrgmDist_LoBits.ItemArray]
+ mov dl, [eax+edx]
+ mov ecx, [ebp+pStruct1C]
+ mov eax, [ecx+TMndxFindResult.szSearchMask]
+ mov ecx, [esi+TStruct40.CharIndex]
+ mov [ebp+var_1], dl
+ cmp dl, [eax+ecx]
+ jnz loc_1959087
+ mov eax, [esi+TStruct40.array_00.ItemCount]
+ mov ecx, [esi+TStruct40.array_00.MaxItemCount]
+ inc eax
+ cmp eax, ecx
+ jbe short loc_19592A1
+ mov ebx, eax
+ shr eax, 1
+ mov [ebp+var_8], ebx
+ cmp ecx, eax
+ jbe short loc_1959254
+ cmp ecx, 7FFFFFFFh
+ jbe short loc_195924E
+ or ebx, 0FFFFFFFFh
+ jmp short loc_1959251
+; ---------------------------------------------------------------------------
+
+loc_195924E: ; CODE XREF: sub_1959010+237j
+ lea ebx, [ecx+ecx]
+
+loc_1959251: ; CODE XREF: sub_1959010+23Cj
+ mov [ebp+var_8], ebx
+
+loc_1959254: ; CODE XREF: sub_1959010+22Fj
+ push offset unk_53ABE00
+ push ebx
+ call j_operator_new_safe
+ xor ecx, ecx
+ add esp, 8
+ cmp [esi+TStruct40.array_00.ItemCount], ecx
+ jbe short loc_1959288
+ lea esp, [esp+0]
+
+loc_1959270: ; CODE XREF: sub_1959010+273j
+ lea edx, [ecx+eax]
+ test edx, edx
+ jz short loc_195927F
+ mov ebx, [esi+TStruct40.array_00.field_4]
+ mov bl, [ecx+ebx]
+ mov [edx], bl
+
+loc_195927F: ; CODE XREF: sub_1959010+265j
+ inc ecx
+ cmp ecx, [esi+TStruct40.array_00.ItemCount]
+ jb short loc_1959270
+ mov ebx, [ebp+var_8]
+
+loc_1959288: ; CODE XREF: sub_1959010+257j
+ mov ecx, [esi+TStruct40.array_00.DataBuffer]
+ push ecx
+ mov [esi+TStruct40.array_00.DataBuffer], eax
+ mov [esi+TStruct40.array_00.field_4], eax
+ mov [esi+TStruct40.array_00.ItemArray], eax
+ mov [esi+TStruct40.array_00.MaxItemCount], ebx
+ call operator_delete
+ mov dl, [ebp+var_1]
+ add esp, 4
+
+loc_19592A1: ; CODE XREF: sub_1959010+224j
+ mov eax, [esi+TStruct40.array_00.field_4]
+ add eax, [esi+TStruct40.array_00.ItemCount]
+ jz short loc_19592AB
+ mov [eax], dl
+
+loc_19592AB: ; CODE XREF: sub_1959010+297j
+ mov eax, 1
+ add [esi+TStruct40.array_00.ItemCount], eax
+ add [esi+TStruct40.CharIndex], eax
+
+loc_19592B6: ; CODE XREF: sub_1959010+1F9j
+ mov ebx, [ebp+arg_4]
+ cmp ebx, [edi+TFileNameDatabase.field_214]
+ jbe short loc_19592ED
+ push ebx
+ mov ecx, edi
+ call sub_1959F50
+ or edx, 0FFFFFFFFh
+ sub edx, ebx
+ add eax, edx
+ mov ecx, eax
+ mov [ebp+arg_4], eax
+
+loc_19592D5: ; CODE XREF: sub_1959010+132j
+ mov edx, [esi+TStruct40.CharIndex]
+ mov eax, [ebp+pStruct1C]
+ cmp edx, [eax+TMndxFindResult.cchSearchMask]
+ jb loc_1959024
+ push ecx
+ push eax
+ mov ecx, edi
+ call sub_1958D70
+
+loc_19592ED: ; CODE XREF: sub_1959010+12Cj
+ ; sub_1959010+2AFj
+ pop edi
+ pop esi
+ mov al, 1
+ pop ebx
+ mov esp, ebp
+ pop ebp
+ retn 8
+sub_1959010 endp
+
+; =============== S U B R O U T I N E =======================================
+
+; Attributes: bp-based frame
+
+sub_19582E0 proc near ; CODE XREF: TFileNameDatabase__sub_1958B00+253p
+
+arg_0 = dword ptr 8
+
+ push ebp
+ mov ebp, esp
+ push esi
+ mov esi, ecx
+ mov eax, [esi+0Ch]
+ mov ecx, [esi+10h]
+ inc eax
+ cmp eax, ecx
+ jbe short loc_1958311
+ mov edx, eax
+ shr eax, 1
+ cmp ecx, eax
+ jbe short loc_1958309
+ cmp ecx, 7FFFFFFFh
+ jbe short loc_1958306
+ or edx, 0FFFFFFFFh
+ jmp short loc_1958309
+; ---------------------------------------------------------------------------
+
+loc_1958306: ; CODE XREF: sub_19582E0+1Fj
+ lea edx, [ecx+ecx]
+
+loc_1958309: ; CODE XREF: sub_19582E0+17j
+ ; sub_19582E0+24j
+ push edx
+ mov ecx, esi
+ call TGenericArray__SetMaxItems_BYTE
+
+loc_1958311: ; CODE XREF: sub_19582E0+Fj
+ mov eax, [esi+4]
+ add eax, [esi+0Ch]
+ jz short loc_1958320
+ mov ecx, [ebp+arg_0]
+ mov dl, [ecx]
+ mov [eax], dl
+
+loc_1958320: ; CODE XREF: sub_19582E0+37j
+ inc dword ptr [esi+0Ch]
+ pop esi
+ pop ebp
+ retn 4
+sub_19582E0 endp
+
+; =============== S U B R O U T I N E =======================================
+
+; Attributes: bp-based frame
+
+TFileNameDatabase__sub_1958B00 proc near ; CODE XREF: TFileNameDatabase__sub_1959460+3Bp
+
+var_C = dword ptr -0Ch
+ItemArrayOffset = dword ptr -8
+var_4 = dword ptr -4
+arg_0 = dword ptr 8
+
+ push ebp
+ mov ebp, esp
+ sub esp, 0Ch
+ mov edx, [ebp+pStruct1C]
+ push ebx
+ mov ebx, [edx+TMndxFindResult.szSearchMask]
+ push esi
+ push edi
+ mov edi, [edx+TMndxFindResult.pStruct40]
+ mov eax, [edi+TStruct40.CharIndex]
+ movzx eax, byte ptr [eax+ebx]
+ mov esi, ecx
+ mov ecx, [edi+TStruct40.HashValue]
+ mov ebx, ecx
+ shl ebx, 5
+ xor eax, ebx
+ mov ebx, [esi+TFileNameDatabase.NameFragTable.ItemArray]
+ xor eax, ecx
+ and eax, [esi+TFileNameDatabase.NameFragIndexMask]
+ lea eax, [eax+eax*2]
+ add eax, eax
+ add eax, eax
+ mov [ebp+ItemArrayOffset], eax
+ cmp ecx, [eax+ebx]
+ jnz loc_1958BE5
+ mov ecx, [eax+ebx+NAME_ENTRY.FragmentOffset]
+ mov ebx, ecx
+ and ebx, 0FFFFFF00h
+ cmp ebx, 0FFFFFF00h
+ jz short loc_1958B88
+ mov eax, [esi+TFileNameDatabase.NextDB.pDatabase]
+ push ecx
+ push edx
+ test eax, eax
+ jz short loc_1958B6E
+ mov ecx, eax
+ call sub_1959010
+ jmp short loc_1958B79
+; ---------------------------------------------------------------------------
+
+loc_1958B6E: ; CODE XREF: TArchiveDatabase__sub_1958B00+63j
+ lea ecx, [esi+TFileNameDatabase.IndexStruct_174]
+ call TNameIndexStruct__CheckAndCopyNameFragment
+
+loc_1958B79: ; CODE XREF: TArchiveDatabase__sub_1958B00+6Cj
+ test al, al
+ jnz short loc_1958BCA
+
+loc_1958B7D: ; CODE XREF: TArchiveDatabase__sub_1958B00+108j
+ ; TArchiveDatabase__sub_1958B00+1F3j
+ pop edi
+ pop esi
+ xor al, al
+ pop ebx
+ mov esp, ebp
+ pop ebp
+ retn 4
+; ---------------------------------------------------------------------------
+
+loc_1958B88: ; CODE XREF: TArchiveDatabase__sub_1958B00+57j
+ mov eax, [edi+TStruct40.array_00.ItemCount]
+ mov bl, cl
+ mov ecx, [edi+TStruct40.array_00.MaxItemCount]
+ inc eax
+ cmp eax, ecx
+ jbe short loc_1958BB5
+ mov edx, eax
+ shr eax, 1
+ cmp ecx, eax
+ jbe short loc_1958BAD
+ cmp ecx, 7FFFFFFFh
+ jbe short loc_1958BAA
+ or edx, 0FFFFFFFFh
+ jmp short loc_1958BAD
+; ---------------------------------------------------------------------------
+
+loc_1958BAA: ; CODE XREF: TArchiveDatabase__sub_1958B00+A3j
+ lea edx, [ecx+ecx]
+
+loc_1958BAD: ; CODE XREF: TArchiveDatabase__sub_1958B00+9Bj
+ ; TArchiveDatabase__sub_1958B00+A8j
+ push edx
+ mov ecx, edi
+ call TGenericArray__SetMaxItems_BYTE
+
+loc_1958BB5: ; CODE XREF: TArchiveDatabase__sub_1958B00+93j
+ mov eax, [edi+TStruct40.array_00.field_4]
+ add eax, [edi+TStruct40.array_00.ItemCount]
+ jz short loc_1958BBF
+ mov [eax], bl
+
+loc_1958BBF: ; CODE XREF: TArchiveDatabase__sub_1958B00+BBj
+ mov eax, 1
+ add [edi+TStruct40.array_00.ItemCount], eax
+ add [edi+TStruct40.CharIndex], eax
+
+loc_1958BCA: ; CODE XREF: TArchiveDatabase__sub_1958B00+7Bj
+ mov ecx, [esi+TFileNameDatabase.NameFragTable.ItemArray]
+ mov edx, [ebp+ItemArrayOffset]
+ mov eax, [ecx+edx+NAME_ENTRY.NextHashModifier]
+ mov [edi+TStruct40.HashValue], eax
+
+loc_1958BDA: ; CODE XREF: TArchiveDatabase__sub_1958B00+1E7j
+ pop edi
+ pop esi
+ mov al, 1
+ pop ebx
+ mov esp, ebp
+ pop ebp
+ retn 4
+; ---------------------------------------------------------------------------
+
+loc_1958BE5: ; CODE XREF: TArchiveDatabase__sub_1958B00+3Fj
+ push ecx
+ mov ecx, esi
+ call TArchiveDatabase__sub_1959CB0
+ mov ebx, [esi+TFileNameDatabase.Struct68_00.ItemIsPresent.ItemArray]
+ inc eax
+ mov ecx, eax
+ and ecx, 1Fh
+ mov edx, 1
+ shl edx, cl
+ mov ecx, eax
+ shr ecx, 5
+ mov [ebp+ItemArrayOffset], eax
+ test [ebx+ecx*4], edx
+ jz loc_1958B7D
+ sub eax, [edi+TStruct40.HashValue]
+ mov [ebp+var_4], 0FFFFFFFFh
+ dec eax
+ mov [edi+TStruct40.HashValue], eax
+ lea esp, [esp+0]
+
+loc_1958C20: ; CODE XREF: TArchiveDatabase__sub_1958B00+230j
+ mov eax, [edi+TStruct40.HashValue]
+ mov ebx, [esi+TFileNameDatabase.Struct68_D0.ItemIsPresent.ItemArray]
+ mov ecx, eax
+ and ecx, 1Fh
+ mov edx, 1
+ shl edx, cl
+ mov ecx, eax
+ shr ecx, 5
+ test [ebx+ecx*4], edx
+ jz loc_1958CFB
+ mov ecx, [ebp+var_4]
+ cmp ecx, 0FFFFFFFFh
+ jnz short loc_1958C5E
+ push eax
+ lea ecx, [esi+TFileNameDatabase.Struct68_D0]
+ call TSparseArray__GetItemValue
+ mov ecx, eax
+ mov [ebp+var_4], eax
+ jmp short loc_1958C62
+; ---------------------------------------------------------------------------
+
+loc_1958C5E: ; CODE XREF: TArchiveDatabase__sub_1958B00+149j
+ inc ecx
+ mov [ebp+var_4], ecx
+
+loc_1958C62: ; CODE XREF: TArchiveDatabase__sub_1958B00+15Cj
+ mov edx, [edi+TStruct40.CharIndex]
+ mov [ebp+var_C], edx
+ mov edx, [esi+TFileNameDatabase.FrgmDist_HiBits.BitsPerEntry]
+ mov eax, edx
+ imul eax, ecx
+ mov ecx, eax
+ and eax, 1Fh
+ add edx, eax
+ shr ecx, 5
+ cmp edx, 20h
+ mov edx, [esi+TFileNameDatabase.FrgmDist_HiBits.ItemArray]
+ ja short loc_1958C91
+ mov edx, [edx+ecx*4]
+ mov ecx, eax
+ shr edx, cl
+ jmp short loc_1958CA8
+; ---------------------------------------------------------------------------
+
+loc_1958C91: ; CODE XREF: TArchiveDatabase__sub_1958B00+186j
+ lea ebx, [edx+ecx*4]
+ mov edx, [ebx+4]
+ mov ebx, [ebx]
+ mov ecx, 20h
+ sub ecx, eax
+ shl edx, cl
+ mov ecx, eax
+ shr ebx, cl
+ or edx, ebx
+
+loc_1958CA8: ; CODE XREF: TArchiveDatabase__sub_1958B00+18Fj
+ mov ecx, [esi+TFileNameDatabase.FrgmDist_LoBits.ItemArray]
+ and edx, [esi+TFileNameDatabase.FrgmDist_HiBits.EntryBitMask]
+ mov eax, [edi+TStruct40.HashValue]
+ movzx eax, byte ptr [ecx+eax]
+ mov ecx, [esi+TFileNameDatabase.NextDB.pDatabase]
+ shl edx, 8
+ or eax, edx
+ push eax
+ test ecx, ecx
+ jz short loc_1958CD6
+ mov edx, [ebp+pStruct1C]
+ push edx
+ call sub_1959010
+ jmp short loc_1958CE5
+; ---------------------------------------------------------------------------
+
+loc_1958CD6: ; CODE XREF: TArchiveDatabase__sub_1958B00+1C9j
+ mov eax, [ebp+pStruct1C]
+ push eax
+ lea ecx, [esi+TFileNameDatabase.IndexStruct_174]
+ call TNameIndexStruct__CheckAndCopyNameFragment
+
+loc_1958CE5: ; CODE XREF: TArchiveDatabase__sub_1958B00+1D4j
+ test al, al
+ jnz loc_1958BDA
+ mov ecx, [ebp+var_C]
+ cmp [edi+TStruct40.CharIndex], ecx
+ jnz loc_1958B7D
+ jmp short loc_1958D11
+; ---------------------------------------------------------------------------
+
+loc_1958CFB: ; CODE XREF: TArchiveDatabase__sub_1958B00+13Dj
+ mov edx, [esi+TFileNameDatabase.FrgmDist_LoBits.ItemArray]
+ mov ebx, [ebp+pStruct1C]
+ mov ecx, [edi+TStruct40.CharIndex]
+ mov ebx, [ebx+TMndxFindResult.szSearchMask]
+ mov dl, [eax+edx]
+ cmp dl, [ecx+ebx]
+ jz short loc_1958D41
+
+loc_1958D11: ; CODE XREF: TArchiveDatabase__sub_1958B00+1F9j
+ mov eax, [ebp+ItemArrayOffset]
+ inc [edi+TStruct40.HashValue]
+ inc eax
+ mov ecx, eax
+ and ecx, 1Fh
+ mov edx, 1
+ shl edx, cl
+ mov ecx, [esi+TFileNameDatabase.Struct68_00.ItemIsPresent.ItemArray]
+ mov [ebp+ItemArrayOffset], eax
+ shr eax, 5
+ test [ecx+eax*4], edx
+ jnz loc_1958C20
+ pop edi
+ pop esi
+ xor al, al
+ pop ebx
+ mov esp, ebp
+ pop ebp
+ retn 4
+; ---------------------------------------------------------------------------
+
+loc_1958D41: ; CODE XREF: TArchiveDatabase__sub_1958B00+20Fj
+ mov edx, [esi+TFileNameDatabase.FrgmDist_LoBits.ItemArray]
+ mov cl, [edx+eax]
+ lea edx, [ebp+pStruct1C+3]
+ mov byte ptr [ebp+pStruct1C+3], cl
+ push edx
+ mov ecx, edi
+ call sub_19582E0
+ mov eax, 1
+ add [edi+TStruct40.CharIndex], eax
+ pop edi
+ pop esi
+ pop ebx
+ mov esp, ebp
+ pop ebp
+ retn 4
+TFileNameDatabase__sub_1958B00 endp
+
+; =============== S U B R O U T I N E =======================================
+
+; Attributes: bp-based frame
+
+TFileNameDatabase__sub_1959460 proc near ; CODE XREF: TFileNameDatabasePtr__sub_1956CE0+2Dp
+
+Struct14 = dword ptr -20h
+var_1C = dword ptr -1Ch
+var_18 = dword ptr -18h
+var_14 = dword ptr -14h
+var_10 = dword ptr -10h
+pStruct14 = dword ptr -0Ch
+pThis = dword ptr -8
+OneChar = byte ptr -1
+pStruct1C = dword ptr 8
+
+ push ebp
+ mov ebp, esp
+ sub esp, 20h
+ push ebx
+ push esi
+ push edi
+ mov edi, [ebp+pStruct1C]
+ mov esi, [edi+TMndxFindResult.pStruct40]
+ mov eax, [esi+TStruct40.SearchPhase]
+ mov ebx, ecx
+ mov [ebp+pThis], ebx
+ cmp eax, 4
+ jz return_false
+ cmp eax, 2
+ jz loc_1959530
+ mov ecx, esi
+ call TStruct40__InitSearchBuffers
+ mov eax, [esi+TStruct40.CharIndex]
+ cmp eax, [edi+TMndxFindResult.cchSearchMask]
+ jnb short loc_19594B0
+
+loc_1959498: ; CODE XREF: TFileNameDatabase__sub_1959460+4Ej
+ push edi
+ mov ecx, ebx
+ call TFileNameDatabase__sub_1958B00
+ test al, al
+ jz loc_1959778
+ mov ecx, [esi+TStruct40.CharIndex]
+ cmp ecx, [edi+TMndxFindResult.cchSearchMask]
+ jb short loc_1959498
+
+loc_19594B0: ; CODE XREF: TFileNameDatabase__sub_1959460+36j
+ mov edx, [esi+TStruct40.HashValue]
+ or eax, 0FFFFFFFFh
+ mov [ebp+Struct14], edx
+ mov [ebp+var_14], eax
+ mov [ebp+var_10], eax
+ mov eax, [esi+TStruct40.array_00.ItemCount]
+ lea edx, [ebp+Struct14]
+ lea ecx, [esi+TStruct40.array_18]
+ push edx
+ mov [ebp+var_1C], 0
+ mov [ebp+var_18], eax
+ call TGenericArray__InsertItem_STRUCT14
+ mov ecx, [esi+TStruct40.HashValue]
+ mov eax, ecx
+ and ecx, 1Fh
+ mov edi, 1
+ shl edi, cl
+ mov [esi+TStruct40.ItemCount], 1
+ mov edx, [ebx+TFileNameDatabase.FileNameIndexes.ItemIsPresent.ItemArray]
+ shr eax, 5
+ test [edx+eax*4], edi
+ jz short loc_1959530
+ mov ecx, [esi+TStruct40.array_00.field_4]
+ mov eax, [esi+TStruct40.array_00.ItemCount]
+ mov edi, [ebp+pStruct1C]
+ mov [edi+TMndxFindResult.szFoundPath], ecx
+ mov [edi+TMndxFindResult.cchFoundPath], eax
+ mov esi, [esi+TStruct40.HashValue]
+ push esi
+ lea ecx, [ebx+TFileNameDatabase.FileNameIndexes]
+ call TSparseArray__GetItemValue
+ mov [edi+TMndxFindResult.FileNameIndex], eax
+ pop edi
+ pop esi
+ mov al, 1
+ pop ebx
+ mov esp, ebp
+ pop ebp
+ retn 4
+; ---------------------------------------------------------------------------
+
+loc_1959522: ; CODE XREF: TFileNameDatabase__sub_1959460+26Bj
+ ; TFileNameDatabase__sub_1959460+2D9j ...
+ mov ebx, [ebp+pThis]
+ jmp short loc_1959530
+; ---------------------------------------------------------------------------
+ align 10h
+
+loc_1959530: ; CODE XREF: TFileNameDatabase__sub_1959460+23j
+ ; TFileNameDatabase__sub_1959460+97j ...
+ mov edx, [esi+TStruct40.ItemCount]
+ cmp edx, [esi+TStruct40.array_18.ItemCount]
+ jnz loc_19595BD
+ mov eax, [esi+TStruct40.array_18.ItemCount]
+ mov ecx, [esi+TStruct40.array_18.field_4]
+ lea eax, [eax+eax*4]
+ lea eax, [ecx+eax*4-14h]
+ mov [ebp+pStruct14], eax
+ mov eax, [eax+TStruct14.HashValue]
+ push eax
+ mov ecx, ebx
+ call TFileNameDatabase__sub_1959CB0
+ mov edx, [ebp+pStruct14]
+ mov ecx, [esi+TStruct40.array_18.ItemCount]
+ inc eax
+ mov ebx, eax
+ sub ebx, [edx+TStruct14.HashValue]
+ mov edx, [esi+TStruct40.array_18.MaxItemCount]
+ inc ecx
+ dec ebx
+ mov [ebp+var_1C], eax
+ cmp ecx, edx
+ jbe short loc_1959591
+ mov eax, ecx
+ shr ecx, 1
+ cmp edx, ecx
+ jbe short loc_1959585
+ mov eax, 0CCCCCCCh
+ cmp edx, 6666666h
+ ja short loc_1959585
+ lea eax, [edx+edx]
+
+loc_1959585: ; CODE XREF: TFileNameDatabase__sub_1959460+113j
+ ; TFileNameDatabase__sub_1959460+120j
+ push eax
+ lea ecx, [esi+TStruct40.array_18]
+ call TGenericArray__SetMaxItems_STRUCT14
+ mov eax, [ebp+var_1C]
+
+loc_1959591: ; CODE XREF: TFileNameDatabase__sub_1959460+10Bj
+ mov ecx, [esi+TStruct40.array_18.ItemCount]
+ mov edx, [esi+TStruct40.array_18.field_4]
+ lea ecx, [ecx+ecx*4]
+ lea ecx, [edx+ecx*4]
+ test ecx, ecx
+ jz short loc_19595B7
+ mov [ecx+TStruct14.HashValue], ebx
+ mov [ecx+TStruct14.field_4], eax
+ xor eax, eax
+ mov [ecx+TStruct14.field_8], eax
+ or eax, 0FFFFFFFFh
+ mov [ecx+TStruct14.field_C], eax
+ or eax, 0FFFFFFFFh
+ mov [ecx+TStruct14.field_10], eax
+
+loc_19595B7: ; CODE XREF: TFileNameDatabase__sub_1959460+13Fj
+ inc [esi+TStruct40.array_18.ItemCount]
+ mov ebx, [ebp+pThis]
+
+loc_19595BD: ; CODE XREF: TFileNameDatabase__sub_1959460+D6j
+ mov eax, [esi+TStruct40.ItemCount]
+ mov ecx, [esi+TStruct40.array_18.field_4]
+ mov ebx, [ebx+TFileNameDatabase.Struct68_00.ItemIsPresent.ItemArray]
+ lea eax, [eax+eax*4]
+ lea edi, [ecx+eax*4]
+ mov eax, [edi+TStruct14.field_4]
+ mov ecx, eax
+ and ecx, 1Fh
+ mov edx, 1
+ shl edx, cl
+ mov ecx, eax
+ shr ecx, 5
+ test [ebx+ecx*4], edx
+ setnz cl
+ inc eax
+ mov [edi+TStruct14.field_4], eax
+ test cl, cl
+ jz loc_19596E9
+ inc [esi+TStruct40.ItemCount]
+ mov ecx, [edi+TStruct14.HashValue]
+ mov eax, [ebp+pThis]
+ mov eax, [eax+TFileNameDatabase.Struct68_D0.ItemIsPresent.ItemArray]
+ mov edx, ecx
+ and ecx, 1Fh
+ mov ebx, 1
+ shl ebx, cl
+ shr edx, 5
+ test [eax+edx*4], ebx
+ mov ebx, [ebp+pThis]
+ jz short loc_1959665
+ mov eax, [edi+TStruct14.field_C]
+ cmp eax, 0FFFFFFFFh
+ jnz short loc_195962F
+ mov eax, [edi+TStruct14.HashValue]
+ push eax
+ lea ecx, [ebx+TFileNameDatabase.Struct68_D0]
+ call TSparseArray__GetItemValue
+ jmp short loc_1959630
+; ---------------------------------------------------------------------------
+
+loc_195962F: ; CODE XREF: TFileNameDatabase__sub_1959460+1BDj
+ inc eax
+
+loc_1959630: ; CODE XREF: TFileNameDatabase__sub_1959460+1CDj
+ mov ecx, [edi+TStruct14.HashValue]
+ push eax
+ push ecx
+ mov ecx, ebx
+ mov [edi+TStruct14.field_C], eax
+ call sub_19573D0
+ mov ecx, [ebx+TFileNameDatabase.NextDB.pDatabase]
+ push eax
+ test ecx, ecx
+ jz short loc_1959654
+ mov edx, [ebp+pStruct1C]
+ push edx
+ call sub_1958D70
+ jmp short loc_19596AE
+; ---------------------------------------------------------------------------
+
+loc_1959654: ; CODE XREF: TFileNameDatabase__sub_1959460+1E7j
+ mov eax, [ebp+pStruct1C]
+ push eax
+ lea ecx, [ebx+TFileNameDatabase.IndexStruct_174]
+ call CopyNameFragment
+ jmp short loc_19596AE
+; ---------------------------------------------------------------------------
+
+loc_1959665: ; CODE XREF: TFileNameDatabase__sub_1959460+1B5j
+ mov ecx, [ebx+TFileNameDatabase.FrgmDist_LoBits.ItemArray]
+ mov eax, [edi+TStruct14.HashValue]
+ mov dl, [eax+ecx]
+ mov eax, [esi+TStruct40.array_00.ItemCount]
+ mov ecx, [esi+TStruct40.array_00.MaxItemCount]
+ inc eax
+ mov [ebp+OneChar], dl
+ cmp eax, ecx
+ jbe short loc_195969E
+ mov edx, eax
+ shr eax, 1
+ cmp ecx, eax
+ jbe short loc_1959696
+ cmp ecx, 7FFFFFFFh
+ jbe short loc_1959693
+ or edx, 0FFFFFFFFh
+ jmp short loc_1959696
+; ---------------------------------------------------------------------------
+
+loc_1959693: ; CODE XREF: TFileNameDatabase__sub_1959460+22Cj
+ lea edx, [ecx+ecx]
+
+loc_1959696: ; CODE XREF: TFileNameDatabase__sub_1959460+224j
+ ; TFileNameDatabase__sub_1959460+231j
+ push edx
+ mov ecx, esi
+ call TGenericArray__SetMaxItems_BYTE
+
+loc_195969E: ; CODE XREF: TFileNameDatabase__sub_1959460+21Cj
+ mov eax, [esi+TStruct40.array_00.field_4]
+ add eax, [esi+TStruct40.array_00.ItemCount]
+ jz short loc_19596AB
+ mov cl, [ebp+OneChar]
+ mov [eax], cl
+
+loc_19596AB: ; CODE XREF: TFileNameDatabase__sub_1959460+244j
+ inc [esi+TStruct40.array_00.ItemCount]
+
+loc_19596AE: ; CODE XREF: TFileNameDatabase__sub_1959460+1F2j
+ ; TFileNameDatabase__sub_1959460+203j
+ mov edx, [esi+TStruct40.array_00.ItemCount]
+ mov ecx, [edi+TStruct14.HashValue]
+ mov [edi+TStruct14.field_8], edx
+ mov edx, [ebx+TFileNameDatabase.FileNameIndexes.ItemIsPresent.ItemArray]
+ mov eax, ecx
+ and ecx, 1Fh
+ mov ebx, 1
+ shl ebx, cl
+ shr eax, 5
+ test [edx+eax*4], ebx
+ jz loc_1959522
+ mov eax, [edi+TStruct14.field_10]
+ cmp eax, 0FFFFFFFFh
+ jnz short loc_1959754
+ mov eax, [edi+TStruct14.HashValue]
+ mov ecx, [ebp+pThis]
+ push eax
+ add ecx, TFileNameDatabase.FileNameIndexes
+ call TSparseArray__GetItemValue
+ jmp short loc_1959755
+; ---------------------------------------------------------------------------
+
+loc_19596E9: ; CODE XREF: TFileNameDatabase__sub_1959460+18Cj
+ mov eax, [esi+TStruct40.ItemCount]
+ cmp eax, 1
+ jz loc_1959778
+ mov ecx, [esi+TStruct40.array_18.field_4]
+ lea eax, [eax+eax*4]
+ inc dword ptr [ecx+eax*4-14h]
+ lea eax, [ecx+eax*4-14h]
+ mov eax, [esi+TStruct40.ItemCount]
+ lea edx, [eax+eax*4]
+ mov eax, [esi+TStruct40.array_18.field_4]
+ mov edi, [eax+edx*4-20h]
+ mov eax, [esi+TStruct40.array_00.MaxItemCount]
+ cmp edi, eax
+ jbe short loc_1959749
+ mov edx, edi
+ shr edx, 1
+ mov ecx, edi
+ cmp eax, edx
+ jbe short loc_1959741
+ cmp eax, 7FFFFFFFh
+ jbe short loc_195973E
+ or ecx, 0FFFFFFFFh
+ push ecx
+ mov ecx, esi
+ call TGenericArray__SetMaxItems_BYTE
+ dec [esi+TStruct40.ItemCount]
+ mov [esi+TStruct40.array_00.ItemCount], edi
+ jmp loc_1959522
+; ---------------------------------------------------------------------------
+
+loc_195973E: ; CODE XREF: TFileNameDatabase__sub_1959460+2C6j
+ lea ecx, [eax+eax]
+
+loc_1959741: ; CODE XREF: TFileNameDatabase__sub_1959460+2BFj
+ push ecx
+ mov ecx, esi
+ call TGenericArray__SetMaxItems_BYTE
+
+loc_1959749: ; CODE XREF: TFileNameDatabase__sub_1959460+2B5j
+ dec [esi+TStruct40.ItemCount]
+ mov [esi+TStruct40.array_00.ItemCount], edi
+ jmp loc_1959522
+; ---------------------------------------------------------------------------
+
+loc_1959754: ; CODE XREF: TFileNameDatabase__sub_1959460+277j
+ inc eax
+
+loc_1959755: ; CODE XREF: TFileNameDatabase__sub_1959460+287j
+ mov [edi+TStruct14.field_10], eax
+ mov ecx, [esi+TStruct40.array_00.ItemCount]
+ mov edx, [esi+TStruct40.array_00.field_4]
+ mov eax, [ebp+pStruct1C]
+ mov [eax+TMndxFindResult.szFoundPath], edx
+ mov [eax+TMndxFindResult.cchFoundPath], ecx
+ mov ecx, [edi+TStruct14.field_10]
+ pop edi
+ pop esi
+ mov [eax+TMndxFindResult.FileNameIndex], ecx
+ mov al, 1
+ pop ebx
+ mov esp, ebp
+ pop ebp
+ retn 4
+; ---------------------------------------------------------------------------
+
+loc_1959778: ; CODE XREF: TFileNameDatabase__sub_1959460+42j
+ ; TFileNameDatabase__sub_1959460+28Fj
+ mov [esi+TStruct40.SearchPhase], 4
+
+return_false: ; CODE XREF: TFileNameDatabase__sub_1959460+1Aj
+ pop edi
+ pop esi
+ xor al, al
+ pop ebx
+ mov esp, ebp
+ pop ebp
+ retn 4
+TFileNameDatabase__sub_1959460 endp
+
+; ---------------------------------------------------------------------------
+
+;------------------------------------------------------------------------------
+; Public functions callable from C++
+
+;
+; DWORD _cdecl sub_19573D0_x86(TFileNameDatabase * pDB, DWORD arg_0, DWORD arg_4);
+;
+
+_sub_19573D0_x86 PROC
+
+ push ebp
+ mov ebp, esp
+ mov ecx, [ebp+8] ; pDB
+ push [ebp+10h] ; arg_4
+ push [ebp+0Ch] ; arg_0
+ call sub_19573D0
+ mov esp, ebp
+ pop ebp
+ ret
+
+_sub_19573D0_x86 ENDP
+
+;
+; DWORD _cdecl sub_1957EF0_x86(TFileNameDatabase * pDB, TMndxFindResult * pStruct1C);
+;
+
+_sub_1957EF0_x86 PROC
+
+ push ebp
+ mov ebp, esp
+ mov ecx, [ebp+8] ; pDB
+ push [ebp+0Ch] ; pStruct1C
+ call TFileNameDatabase__FindFileInDatabase
+ mov esp, ebp
+ pop ebp
+ ret
+
+_sub_1957EF0_x86 ENDP
+
+;
+; bool _cdecl _sub_1959460_x86(TFileNameDatabase * pDB, TMndxFindResult * pStruct1C);
+;
+
+_sub_1959460_x86 PROC
+
+ push ebp
+ mov ebp, esp
+ mov ecx, [ebp+8] ; pDB
+ push [ebp+0Ch] ; pStruct1C
+ call TFileNameDatabase__sub_1959460
+ mov esp, ebp
+ pop ebp
+ ret
+
+_sub_1959460_x86 ENDP
+
+;
+; bool _cdecl sub_1958B00_x86(TFileNameDatabase * pDB, TMndxFindResult * pStruct1C);
+;
+
+_sub_1958B00_x86 PROC
+
+ push ebp
+ mov ebp, esp
+ mov ecx, [ebp+8] ; pDB
+ push [ebp+0Ch] ; pStruct1C
+ call TFileNameDatabase__sub_1959460
+ mov esp, ebp
+ pop ebp
+ ret
+
+_sub_1958B00_x86 ENDP
+
+;
+; DWORD _cdecl GetItemValue_x86(TSparseArray * pStruct, DWORD dwKey);
+;
+
+_GetItemValue_x86 PROC
+
+ push ebp
+ mov ebp, esp
+ mov ecx, [ebp+8] ; pStruct68
+ push [ebp+0Ch] ; dwKey
+ call TSparseArray__GetItemValue
+ mov esp, ebp
+ pop ebp
+ ret
+
+_GetItemValue_x86 ENDP
+
+;
+; DWORD _cdecl sub_1959CB0_x86(TFileNameDatabase * pDB, DWORD dwKey);
+;
+
+_sub_1959CB0_x86 PROC
+
+ push ebp
+ mov ebp, esp
+ mov ecx, [ebp+8] ; pDB
+ push [ebp+0Ch] ; dwKey
+ call TArchiveDatabase__sub_1959CB0
+ mov esp, ebp
+ pop ebp
+ ret
+
+_sub_1959CB0_x86 ENDP
+
+;
+; DWORD _cdecl sub_1959F50_x86(TFileNameDatabase * pDB, DWORD arg_0);
+;
+
+_sub_1959F50_x86 PROC
+
+ push ebp
+ mov ebp, esp
+ mov ecx, [ebp+8] ; pDB
+ push [ebp+0Ch] ; dwKey
+ call sub_1959F50
+ mov esp, ebp
+ pop ebp
+ ret
+
+_sub_1959F50_x86 ENDP
+
+END
diff --git a/dep/CascLib/src/CascOpenFile.cpp b/dep/CascLib/src/CascOpenFile.cpp
new file mode 100644
index 00000000000..e7cdb9aa107
--- /dev/null
+++ b/dep/CascLib/src/CascOpenFile.cpp
@@ -0,0 +1,440 @@
+/*****************************************************************************/
+/* CascOpenFile.cpp Copyright (c) Ladislav Zezula 2014 */
+/*---------------------------------------------------------------------------*/
+/* System-dependent directory functions for CascLib */
+/*---------------------------------------------------------------------------*/
+/* Date Ver Who Comment */
+/* -------- ---- --- ------- */
+/* 01.05.14 1.00 Lad The first version of CascOpenFile.cpp */
+/*****************************************************************************/
+
+#define __CASCLIB_SELF__
+#include "CascLib.h"
+#include "CascCommon.h"
+#include "CascMndxRoot.h"
+
+//-----------------------------------------------------------------------------
+// Local structures
+
+//-----------------------------------------------------------------------------
+// Local functions
+
+TCascFile * IsValidFileHandle(HANDLE hFile)
+{
+ TCascFile * hf = (TCascFile *)hFile;
+
+ return (hf != NULL && hf->hs != NULL && hf->szClassName != NULL && !strcmp(hf->szClassName, "TCascFile")) ? hf : NULL;
+}
+
+PCASC_INDEX_ENTRY FindIndexEntry(TCascStorage * hs, PQUERY_KEY pIndexKey)
+{
+ PCASC_INDEX_ENTRY pIndexEntry = NULL;
+
+ if(hs->pIndexEntryMap != NULL)
+ pIndexEntry = (PCASC_INDEX_ENTRY)Map_FindObject(hs->pIndexEntryMap, pIndexKey->pbData);
+
+ return pIndexEntry;
+}
+
+PCASC_ENCODING_ENTRY FindEncodingEntry(TCascStorage * hs, PQUERY_KEY pEncodingKey, size_t * PtrIndex)
+{
+ PCASC_ENCODING_ENTRY pEncodingEntry;
+ size_t StartEntry = 0;
+ size_t MidlEntry;
+ size_t EndEntry = hs->nEncodingEntries;
+ int nResult;
+
+ // Perform binary search
+ while(StartEntry < EndEntry)
+ {
+ // Calculate the middle of the interval
+ MidlEntry = StartEntry + ((EndEntry - StartEntry) / 2);
+ pEncodingEntry = hs->ppEncodingEntries[MidlEntry];
+
+ // Did we find it?
+ nResult = memcmp(pEncodingKey->pbData, pEncodingEntry->EncodingKey, MD5_HASH_SIZE);
+ if(nResult == 0)
+ {
+ if(PtrIndex != NULL)
+ PtrIndex[0] = MidlEntry;
+ return pEncodingEntry;
+ }
+
+ // Move the interval to the left or right
+ (nResult < 0) ? EndEntry = MidlEntry : StartEntry = MidlEntry + 1;
+ }
+
+ // Not found, sorry
+ return NULL;
+}
+
+// Also used in CascSearchFile
+PCASC_ROOT_ENTRY FindFirstRootEntry(TCascStorage * hs, const char * szFileName, size_t * PtrIndex)
+{
+ PCASC_ROOT_ENTRY pFoundEntry = NULL;
+ PCASC_ROOT_ENTRY pRootEntry;
+ ULONGLONG FileNameHash;
+ uint32_t dwHashHigh = 0;
+ uint32_t dwHashLow = 0;
+ size_t StartEntry = 0;
+ size_t MidlEntry = 0;
+ size_t EndEntry = hs->nRootEntries;
+
+ // Calculate the HASH value of the normalized file name
+ hashlittle2(szFileName, strlen(szFileName), &dwHashHigh, &dwHashLow);
+ FileNameHash = ((ULONGLONG)dwHashHigh << 0x20) | dwHashLow;
+
+ // Perform binary search
+ while(StartEntry < EndEntry)
+ {
+ // Calculate the middle of the interval
+ MidlEntry = StartEntry + ((EndEntry - StartEntry) / 2);
+ pRootEntry = hs->ppRootEntries[MidlEntry];
+
+ // Did we find it?
+ if(pRootEntry->FileNameHash == FileNameHash)
+ {
+ pFoundEntry = pRootEntry;
+ break;
+ }
+
+ // Move the interval to the left or right
+ (FileNameHash < pRootEntry->FileNameHash) ? EndEntry = MidlEntry : StartEntry = MidlEntry + 1;
+ }
+
+ // Move the pointer back to the first entry with that hash
+ if(pFoundEntry != NULL)
+ {
+ while(MidlEntry > 0 && hs->ppRootEntries[MidlEntry - 1]->FileNameHash == FileNameHash)
+ {
+ pFoundEntry = hs->ppRootEntries[MidlEntry - 1];
+ MidlEntry--;
+ }
+ }
+
+ // Return what we found
+ if(PtrIndex != NULL)
+ *PtrIndex = MidlEntry;
+ return pFoundEntry;
+}
+
+// Check the root directory for that hash
+PCASC_ROOT_ENTRY FindRootEntryLocale(TCascStorage * hs, char * szFileName, DWORD Locale)
+{
+ PCASC_ROOT_ENTRY pThatEntry = NULL;
+ PCASC_ROOT_ENTRY pENUSEntry = NULL;
+ PCASC_ROOT_ENTRY pENGBEntry = NULL;
+ PCASC_ROOT_ENTRY pAnyEntry = NULL;
+ PCASC_ROOT_ENTRY pEndEntry = NULL;
+ PCASC_ROOT_ENTRY pRootEntry = NULL;
+ ULONGLONG FileNameHash;
+ size_t EntryIndex = 0;
+ size_t EndEntry = hs->nRootEntries;
+
+ // Find a root entry with the given name hash
+ pRootEntry = FindFirstRootEntry(hs, szFileName, &EntryIndex);
+ if(pRootEntry != NULL)
+ {
+ // Rememeber the file name hash
+ pEndEntry = hs->pRootEntries + hs->nRootEntries;
+ FileNameHash = pRootEntry->FileNameHash;
+
+ // Find all suitable root entries
+ while(EntryIndex < EndEntry)
+ {
+ // Get the root entry
+ pRootEntry = hs->ppRootEntries[EntryIndex++];
+ if(pRootEntry->FileNameHash != FileNameHash)
+ break;
+
+ // If a locale has been given, check it
+ if(pThatEntry == NULL && Locale != 0 && (Locale & pRootEntry->Locales))
+ pThatEntry = pRootEntry;
+ if(pENUSEntry == NULL && (pRootEntry->Locales & CASC_LOCALE_ENUS))
+ pENUSEntry = pRootEntry;
+ if(pENGBEntry == NULL && (pRootEntry->Locales & CASC_LOCALE_ENGB))
+ pENGBEntry = pRootEntry;
+ if(pAnyEntry == NULL)
+ pAnyEntry = pRootEntry;
+
+ // Move to the next one
+ pRootEntry++;
+ }
+
+ // Return the key by priority
+ if(pThatEntry != NULL)
+ return pThatEntry;
+ if(pENGBEntry != NULL)
+ return pENGBEntry;
+ if(pENUSEntry != NULL)
+ return pENUSEntry;
+ }
+
+ // Return whatever we got
+ return pAnyEntry;
+}
+
+static TCascFile * CreateFileHandle(TCascStorage * hs, PCASC_INDEX_ENTRY pIndexEntry)
+{
+ ULONGLONG FileOffsMask = ((ULONGLONG)1 << hs->KeyMapping[0].SegmentBits) - 1;
+ ULONGLONG FileOffset = ConvertBytesToInteger_5(pIndexEntry->FileOffset);
+ TCascFile * hf;
+
+ // Allocate the CASC file structure
+ hf = (TCascFile *)CASC_ALLOC(TCascFile, 1);
+ if(hf != NULL)
+ {
+ // Initialize the structure
+ memset(hf, 0, sizeof(TCascFile));
+ hf->ArchiveIndex = (DWORD)(FileOffset >> hs->KeyMapping[0].SegmentBits);
+ hf->HeaderOffset = (DWORD)(FileOffset & FileOffsMask);
+ hf->szClassName = "TCascFile";
+
+ // Copy the compressed file size
+ hf->CompressedSize = ConvertBytesToInteger_4_LE(pIndexEntry->FileSize) - 0x1E;
+
+ // For now, we set the file size to be equal to compressed size
+ // This is used when loading the "encoding" file, which does not
+ // have entry in the encoding itself
+ hf->FileSize = hf->CompressedSize;
+
+ // Increment the number of references to the archive
+ hs->dwRefCount++;
+ hf->hs = hs;
+ }
+
+ return hf;
+}
+
+static bool OpenFileByIndexKey(TCascStorage * hs, PQUERY_KEY pIndexKey, DWORD dwFlags, HANDLE * phFile)
+{
+ PCASC_INDEX_ENTRY pIndexEntry;
+ TCascFile * hf = NULL;
+ int nError = ERROR_SUCCESS;
+
+ CASCLIB_UNUSED(dwFlags);
+
+ // Find the key entry in the array of file keys
+ pIndexEntry = FindIndexEntry(hs, pIndexKey);
+ if(pIndexEntry == NULL)
+ nError = ERROR_FILE_NOT_FOUND;
+
+ // Create the file handle structure
+ if(nError == ERROR_SUCCESS)
+ {
+ hf = CreateFileHandle(hs, pIndexEntry);
+ *phFile = (HANDLE)hf;
+ if(hf == NULL)
+ nError = ERROR_FILE_NOT_FOUND;
+ }
+
+ if(nError != ERROR_SUCCESS)
+ SetLastError(nError);
+ return (nError == ERROR_SUCCESS);
+}
+
+static bool OpenFileByEncodingKey(TCascStorage * hs, PQUERY_KEY pEncodingKey, DWORD dwFlags, HANDLE * phFile)
+{
+ PCASC_ENCODING_ENTRY pEncodingEntry;
+ QUERY_KEY IndexKey;
+ TCascFile * hf = NULL;
+ int nError = ERROR_SUCCESS;
+
+ // Find the encoding entry
+ pEncodingEntry = FindEncodingEntry(hs, pEncodingKey, NULL);
+ if(pEncodingEntry == NULL)
+ nError = ERROR_FILE_NOT_FOUND;
+
+ // Prepare the file index and open the file by index
+ // Note: We don't know what to do if there is more than just one index key
+ // We always take the first file present. Is that correct?
+// IndexKey.pbData = pEncodingEntry->EncodingKey + (MD5_HASH_SIZE * pEncodingEntry->KeyCount);
+// assert(pEncodingEntry->KeyCount == 1);
+ IndexKey.pbData = pEncodingEntry->EncodingKey + MD5_HASH_SIZE;
+ IndexKey.cbData = MD5_HASH_SIZE;
+ if(OpenFileByIndexKey(hs, &IndexKey, dwFlags, phFile))
+ {
+ // Fix the file size from the encoding key
+ hf = IsValidFileHandle(*phFile);
+ if(hf != NULL)
+ {
+ hf->FileSize = ConvertBytesToInteger_4(pEncodingEntry->FileSizeBytes);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Public functions
+
+bool WINAPI CascOpenFileByIndexKey(HANDLE hStorage, PQUERY_KEY pIndexKey, DWORD dwFlags, HANDLE * phFile)
+{
+ TCascStorage * hs;
+
+ // Validate the storage handle
+ hs = IsValidStorageHandle(hStorage);
+ if(hs == NULL)
+ {
+ SetLastError(ERROR_INVALID_HANDLE);
+ return false;
+ }
+
+ // Validate the other parameters
+ if(pIndexKey == NULL || pIndexKey->pbData == NULL || pIndexKey->cbData == 0 || phFile == NULL)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return false;
+ }
+
+ // Use the internal function to open the file
+ return OpenFileByIndexKey(hs, pIndexKey, dwFlags, phFile);
+}
+
+bool WINAPI CascOpenFileByEncodingKey(HANDLE hStorage, PQUERY_KEY pEncodingKey, DWORD dwFlags, HANDLE * phFile)
+{
+ TCascStorage * hs;
+
+ // Validate the storage handle
+ hs = IsValidStorageHandle(hStorage);
+ if(hs == NULL)
+ {
+ SetLastError(ERROR_INVALID_HANDLE);
+ return false;
+ }
+
+ // Validate the other parameters
+ if(pEncodingKey == NULL || pEncodingKey->pbData == NULL || pEncodingKey->cbData == 0 || phFile == NULL)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return false;
+ }
+
+ // Use the internal function fo open the file
+ return OpenFileByEncodingKey(hs, pEncodingKey, dwFlags, phFile);
+}
+
+bool WINAPI CascOpenFile(HANDLE hStorage, const char * szFileName, DWORD dwLocale, DWORD dwFlags, HANDLE * phFile)
+{
+ CASC_ROOT_KEY_INFO EncodingKeyInfo;
+ PCASC_ROOT_ENTRY pRootEntry;
+ PCASC_PACKAGE pPackage;
+ TCascStorage * hs;
+ QUERY_KEY EncodingKey;
+ char * szStrippedName;
+ char * szFileName2;
+ int nError = ERROR_SUCCESS;
+
+ // Validate the storage handle
+ hs = IsValidStorageHandle(hStorage);
+ if(hs == NULL)
+ {
+ SetLastError(ERROR_INVALID_HANDLE);
+ return false;
+ }
+
+ // Validate the other parameters
+ if(szFileName == NULL || szFileName[0] == 0 || phFile == NULL)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return false;
+ }
+
+ // Create the copy of the file name
+ szFileName2 = NewStr(szFileName, 0);
+ if(szFileName2 != NULL)
+ {
+ // If the storage has a MNDX root directory, use it to search the entry
+ if(hs->pMndxInfo != NULL)
+ {
+ // Convert the file name to lowercase + slashes
+ NormalizeFileName_LowerSlash(szFileName2);
+
+ // Find the package number
+ pPackage = FindMndxPackage(hs, szFileName2);
+ if(pPackage != NULL)
+ {
+ // Cut the package name off the full path
+ szStrippedName = szFileName2 + pPackage->nLength;
+ while(szStrippedName[0] == '/')
+ szStrippedName++;
+
+ nError = SearchMndxInfo(hs->pMndxInfo, szStrippedName, (DWORD)(pPackage - hs->pPackages->Packages), &EncodingKeyInfo);
+ if(nError == ERROR_SUCCESS)
+ {
+ // Prepare the encoding key
+ EncodingKey.pbData = EncodingKeyInfo.EncodingKey;
+ EncodingKey.cbData = MD5_HASH_SIZE;
+ }
+ }
+ else
+ {
+ nError = ERROR_FILE_NOT_FOUND;
+ }
+ }
+ else
+ {
+ // Convert the file name to lowercase + slashes
+ NormalizeFileName_UpperBkSlash(szFileName2);
+
+ // Check the root directory for that hash
+ pRootEntry = FindRootEntryLocale(hs, szFileName2, dwLocale);
+ nError = (pRootEntry != NULL) ? ERROR_SUCCESS : ERROR_FILE_NOT_FOUND;
+ if(pRootEntry != NULL)
+ {
+ // Prepare the root key
+ EncodingKey.pbData = pRootEntry->EncodingKey;
+ EncodingKey.cbData = MD5_HASH_SIZE;
+ }
+ }
+
+ // Use the root key to find the file in the encoding table entry
+ if(nError == ERROR_SUCCESS)
+ {
+ if(!OpenFileByEncodingKey(hs, &EncodingKey, dwFlags, phFile))
+ {
+ assert(GetLastError() != ERROR_SUCCESS);
+ nError = GetLastError();
+ }
+ }
+
+ // Delete the file name copy
+ delete [] szFileName2;
+ }
+ else
+ nError = ERROR_NOT_ENOUGH_MEMORY;
+
+ if(nError != ERROR_SUCCESS)
+ SetLastError(nError);
+ return (nError == ERROR_SUCCESS);
+}
+
+bool WINAPI CascCloseFile(HANDLE hFile)
+{
+ TCascFile * hf;
+
+ hf = IsValidFileHandle(hFile);
+ if(hf != NULL)
+ {
+ // Close (dereference) the archive handle
+ if(hf->hs != NULL)
+ CascCloseStorage((HANDLE)hf->hs);
+ hf->hs = NULL;
+
+ // Free the file cache and frame array
+ if(hf->pbFileCache != NULL)
+ CASC_FREE(hf->pbFileCache);
+ if(hf->pFrames != NULL)
+ CASC_FREE(hf->pFrames);
+
+ // Free the structure itself
+ hf->szClassName = NULL;
+ CASC_FREE(hf);
+ return true;
+ }
+
+ SetLastError(ERROR_INVALID_HANDLE);
+ return false;
+}
+
diff --git a/dep/CascLib/src/CascOpenStorage.cpp b/dep/CascLib/src/CascOpenStorage.cpp
new file mode 100644
index 00000000000..f9e6ba6f4d4
--- /dev/null
+++ b/dep/CascLib/src/CascOpenStorage.cpp
@@ -0,0 +1,1226 @@
+/*****************************************************************************/
+/* CascOpenStorage.cpp Copyright (c) Ladislav Zezula 2014 */
+/*---------------------------------------------------------------------------*/
+/* Storage functions for CASC */
+/*---------------------------------------------------------------------------*/
+/* Date Ver Who Comment */
+/* -------- ---- --- ------- */
+/* 29.04.14 1.00 Lad The first version of CascOpenStorage.cpp */
+/*****************************************************************************/
+
+#define __CASCLIB_SELF__
+#include "CascLib.h"
+#include "CascCommon.h"
+#include "CascMndxRoot.h"
+
+//-----------------------------------------------------------------------------
+// Local structures
+
+#define CASC_ENCODING_SEGMENT_SIZE 0x1000
+
+typedef struct _BLOCK_SIZE_AND_HASH
+{
+ DWORD cbBlockSize;
+ DWORD dwBlockHash;
+
+} BLOCK_SIZE_AND_HASH, *PBLOCK_SIZE_AND_HASH;
+
+typedef struct _FILE_INDEX_HEADER_V1
+{
+ USHORT field_0;
+ BYTE KeyIndex; // Key index (0 for data.i0x, 1 for data.i1x, 2 for data.i2x etc.)
+ BYTE align_3;
+ DWORD field_4;
+ ULONGLONG field_8;
+ ULONGLONG MaxFileOffset;
+ BYTE SpanSizeBytes;
+ BYTE SpanOffsBytes;
+ BYTE KeyBytes;
+ BYTE SegmentBits; // Number of bits for file offset
+ DWORD KeyCount1;
+ DWORD KeyCount2;
+ DWORD KeysHash1;
+ DWORD KeysHash2;
+ DWORD dwHeaderHash;
+} FILE_INDEX_HEADER_V1, *PFILE_INDEX_HEADER_V1;
+
+typedef struct _FILE_INDEX_HEADER_V2
+{
+ USHORT IndexVersion; // Must be 0x07
+ BYTE KeyIndex; // Must be equal to the file key index
+ BYTE ExtraBytes; // (?) Extra bytes in the key record
+ BYTE SpanSizeBytes; // Size of field with file size
+ BYTE SpanOffsBytes; // Size of field with file offset
+ BYTE KeyBytes; // Size of the file key (bytes)
+ BYTE SegmentBits; // Number of bits for the file offset (rest is archive index)
+ ULONGLONG MaxFileOffset;
+
+} FILE_INDEX_HEADER_V2, *PFILE_INDEX_HEADER_V2;
+
+typedef struct _FILE_ENCODING_HEADER
+{
+ BYTE Magic[2]; // "EN"
+ BYTE field_2;
+ BYTE field_3;
+ BYTE field_4;
+ BYTE field_5[2];
+ BYTE field_7[2];
+ BYTE NumSegments[4]; // Number of entries (big endian)
+ BYTE field_D[4];
+ BYTE field_11;
+ BYTE SegmentsPos[4]; // Offset of encoding segments
+
+} FILE_ENCODING_HEADER, *PFILE_ENCODING_HEADER;
+
+typedef struct _FILE_ENCODING_SEGMENT
+{
+ BYTE FirstEncodingKey[MD5_HASH_SIZE]; // The first encoding key in the segment
+ BYTE SegmentHash[MD5_HASH_SIZE]; // MD5 hash of the entire segment
+
+} FILE_ENCODING_SEGMENT, *PFILE_ENCODING_SEGMENT;
+
+typedef struct _FILE_LOCALE_BLOCK
+{
+ DWORD NumberOfFiles; // Number of entries
+ DWORD Flags;
+ DWORD Locales; // File locale mask (CASC_LOCALE_XXX)
+
+ // Followed by a block of 32-bit integers (count: NumberOfFiles)
+ // Followed by the MD5 and file name hash (count: NumberOfFiles)
+
+} FILE_LOCALE_BLOCK, *PFILE_LOCALE_BLOCK;
+
+typedef struct _FILE_ROOT_ENTRY
+{
+ BYTE EncodingKey[MD5_HASH_SIZE]; // MD5 of the file
+ ULONGLONG FileNameHash; // Jenkins hash of the file name
+
+} FILE_ROOT_ENTRY, *PFILE_ROOT_ENTRY;
+
+typedef struct _ROOT_BLOCK_INFO
+{
+ PFILE_LOCALE_BLOCK pLocaleBlockHdr; // Pointer to the locale block
+ PDWORD pInt32Array; // Pointer to the array of 32-bit integers
+ PFILE_ROOT_ENTRY pRootEntries;
+
+} ROOT_BLOCK_INFO, *PROOT_BLOCK_INFO;
+
+//-----------------------------------------------------------------------------
+// Local variables
+
+static const TCHAR * szAllowedHexChars = _T("0123456789aAbBcCdDeEfF");
+static const TCHAR * szIndexFormat_V1 = _T("data.i%x%x");
+static const TCHAR * szIndexFormat_V2 = _T("%02x%08x.idx");
+
+//-----------------------------------------------------------------------------
+// Local functions
+
+inline void CopyFileKey(LPBYTE Trg, LPBYTE Src)
+{
+ Trg[0x00] = Src[0x00];
+ Trg[0x01] = Src[0x01];
+ Trg[0x02] = Src[0x02];
+ Trg[0x03] = Src[0x03];
+ Trg[0x04] = Src[0x04];
+ Trg[0x05] = Src[0x05];
+ Trg[0x06] = Src[0x06];
+ Trg[0x07] = Src[0x07];
+ Trg[0x08] = Src[0x08];
+ Trg[0x09] = Src[0x09];
+ Trg[0x0A] = Src[0x0A];
+ Trg[0x0B] = Src[0x0B];
+ Trg[0x0C] = Src[0x0C];
+ Trg[0x0D] = Src[0x0D];
+ Trg[0x0E] = Src[0x0E];
+ Trg[0x0F] = Src[0x0F];
+}
+
+TCascStorage * IsValidStorageHandle(HANDLE hStorage)
+{
+ TCascStorage * hs = (TCascStorage *)hStorage;
+
+ return (hs != NULL && hs->szClassName != NULL && !strcmp(hs->szClassName, "TCascStorage")) ? hs : NULL;
+}
+
+// "data.iXY"
+static bool IsIndexFileName_V1(const TCHAR * szFileName)
+{
+ // Check if the name looks like a valid index file
+ return (_tcslen(szFileName) == 8 &&
+ _tcsnicmp(szFileName, _T("data.i"), 6) == 0 &&
+ _tcsspn(szFileName + 6, szAllowedHexChars) == 2);
+}
+
+static bool IsIndexFileName_V2(const TCHAR * szFileName)
+{
+ // Check if the name looks like a valid index file
+ return (_tcslen(szFileName) == 14 &&
+ _tcsspn(szFileName, _T("0123456789aAbBcCdDeEfF")) == 0x0A &&
+ _tcsicmp(szFileName + 0x0A, _T(".idx")) == 0);
+}
+
+static void QUERY_KEY_Free(PQUERY_KEY pBlob)
+{
+ if(pBlob != NULL)
+ {
+ if(pBlob->pbData != NULL)
+ CASC_FREE(pBlob->pbData);
+
+ pBlob->pbData = NULL;
+ pBlob->cbData = 0;
+ }
+}
+
+static void QUERY_KEY_FreeArray(PQUERY_KEY pBlobArray)
+{
+ // Free the buffer in the first blob
+ // (will also free all buffers in the array)
+ QUERY_KEY_Free(pBlobArray);
+
+ // Free the array itself
+ CASC_FREE(pBlobArray);
+}
+
+static int CompareRootEntries(const void *, const void * pvKeyEntry1, const void * pvKeyEntry2)
+{
+ PCASC_ROOT_ENTRY pRootEntry1 = (PCASC_ROOT_ENTRY)pvKeyEntry1;
+ PCASC_ROOT_ENTRY pRootEntry2 = (PCASC_ROOT_ENTRY)pvKeyEntry2;
+
+ // Compare name hash first
+ if(pRootEntry1->FileNameHash < pRootEntry2->FileNameHash)
+ return -1;
+ if(pRootEntry1->FileNameHash > pRootEntry2->FileNameHash)
+ return +1;
+ return 0;
+}
+
+static bool IsCascIndexHeader_V1(LPBYTE pbFileData, DWORD cbFileData)
+{
+ PFILE_INDEX_HEADER_V1 pIndexHeader = (PFILE_INDEX_HEADER_V1)pbFileData;
+ DWORD dwHeaderHash;
+ bool bResult = false;
+
+ // Check the size
+ if(cbFileData >= sizeof(FILE_INDEX_HEADER_V1))
+ {
+ // Save the header hash
+ dwHeaderHash = pIndexHeader->dwHeaderHash;
+ pIndexHeader->dwHeaderHash = 0;
+
+ // Calculate the hash
+ if(hashlittle(pIndexHeader, sizeof(FILE_INDEX_HEADER_V1), 0) == dwHeaderHash)
+ bResult = true;
+
+ // Put the hash back
+ pIndexHeader->dwHeaderHash = dwHeaderHash;
+ }
+
+ return bResult;
+}
+
+static bool IsCascIndexHeader_V2(LPBYTE pbFileData, DWORD cbFileData)
+{
+ PBLOCK_SIZE_AND_HASH pSizeAndHash = (PBLOCK_SIZE_AND_HASH)pbFileData;
+ unsigned int HashHigh = 0;
+ unsigned int HashLow = 0;
+
+ // Check for the header
+ if(cbFileData < sizeof(BLOCK_SIZE_AND_HASH) || pSizeAndHash->cbBlockSize < 0x10)
+ return false;
+ if(cbFileData < pSizeAndHash->cbBlockSize + sizeof(BLOCK_SIZE_AND_HASH))
+ return false;
+
+ // The index header for CASC v 2.0 begins with length and checksum
+ hashlittle2(pSizeAndHash + 1, pSizeAndHash->cbBlockSize, &HashHigh, &HashLow);
+ return (HashHigh == pSizeAndHash->dwBlockHash);
+}
+
+static LPBYTE VerifyLocaleBlock(PROOT_BLOCK_INFO pBlockInfo, LPBYTE pbFilePointer, LPBYTE pbFileEnd)
+{
+ // Validate the locale header
+ pBlockInfo->pLocaleBlockHdr = (PFILE_LOCALE_BLOCK)pbFilePointer;
+ pbFilePointer += sizeof(FILE_LOCALE_BLOCK);
+ if(pbFilePointer >= pbFileEnd)
+ return NULL;
+
+ // Validate the array of 32-bit integers
+ pBlockInfo->pInt32Array = (PDWORD)pbFilePointer;
+ pbFilePointer = (LPBYTE)(pBlockInfo->pInt32Array + pBlockInfo->pLocaleBlockHdr->NumberOfFiles);
+ if(pbFilePointer >= pbFileEnd)
+ return NULL;
+
+ // Validate the array of root entries
+ pBlockInfo->pRootEntries = (PFILE_ROOT_ENTRY)pbFilePointer;
+ pbFilePointer = (LPBYTE)(pBlockInfo->pRootEntries + pBlockInfo->pLocaleBlockHdr->NumberOfFiles);
+ if(pbFilePointer > pbFileEnd)
+ return NULL;
+
+ // Return the position of the next block
+ return pbFilePointer;
+}
+
+static int InitializeCascDirectories(TCascStorage * hs, const TCHAR * szDataPath)
+{
+ TCHAR * szLastPathPart;
+
+ // Save the game data directory
+ hs->szDataPath = NewStr(szDataPath, 0);
+
+ // Save the root game directory
+ hs->szRootPath = NewStr(szDataPath, 0);
+
+ // Find the last part
+ szLastPathPart = hs->szRootPath;
+ for(size_t i = 0; hs->szRootPath[i] != 0; i++)
+ {
+ if(hs->szRootPath[i] == '\\' || hs->szRootPath[i] == '/')
+ szLastPathPart = hs->szRootPath + i;
+ }
+
+ // Cut the last part
+ if(szLastPathPart != NULL)
+ szLastPathPart[0] = 0;
+ return (hs->szRootPath && hs->szDataPath) ? ERROR_SUCCESS : ERROR_NOT_ENOUGH_MEMORY;
+}
+
+static bool IndexDirectory_OnFileFound(
+ const TCHAR * szFileName,
+ PDWORD IndexArray,
+ PDWORD OldIndexArray,
+ void * pvContext)
+{
+ TCascStorage * hs = (TCascStorage *)pvContext;
+ DWORD IndexValue = 0;
+ DWORD IndexVersion = 0;
+
+ // Auto-detect the format of the index file name
+ if(hs->szIndexFormat == NULL)
+ {
+ if(IsIndexFileName_V1(szFileName))
+ hs->szIndexFormat = szIndexFormat_V1;
+ else if(IsIndexFileName_V2(szFileName))
+ hs->szIndexFormat = szIndexFormat_V2;
+ else
+ return false;
+ }
+
+ if(hs->szIndexFormat == szIndexFormat_V1)
+ {
+ // Check the index file name format
+ if(!IsIndexFileName_V1(szFileName))
+ return false;
+
+ // Get the main index from the first two digits
+ if(ConvertDigitToInt32(szFileName + 6, &IndexValue) != ERROR_SUCCESS)
+ return false;
+ if(ConvertDigitToInt32(szFileName + 7, &IndexVersion) != ERROR_SUCCESS)
+ return false;
+ }
+
+ else if(hs->szIndexFormat == szIndexFormat_V2)
+ {
+ // Check the index file name format
+ if(!IsIndexFileName_V2(szFileName))
+ return false;
+
+ // Get the main index from the first two digits
+ if(ConvertStringToInt32(szFileName, 2, &IndexValue) != ERROR_SUCCESS)
+ return false;
+ if(ConvertStringToInt32(szFileName + 2, 8, &IndexVersion) != ERROR_SUCCESS)
+ return false;
+ }
+ else
+ {
+ // Should never happen
+ assert(false);
+ return false;
+ }
+
+ // The index value must not be greater than 0x0F
+ if(IndexValue >= CASC_INDEX_COUNT)
+ return false;
+
+ // If the new subindex is greater than the previous one,
+ // use this one instead
+ if(IndexVersion > IndexArray[IndexValue])
+ {
+ OldIndexArray[IndexValue] = IndexArray[IndexValue];
+ IndexArray[IndexValue] = IndexVersion;
+ }
+ else if(IndexVersion > OldIndexArray[IndexValue])
+ {
+ OldIndexArray[IndexValue] = IndexVersion;
+ }
+
+ // Note: WoW6 only keeps last two index files
+ // Any additional index files are deleted at this point
+ return true;
+}
+
+static TCHAR * CreateIndexFileName(TCascStorage * hs, DWORD IndexValue, DWORD IndexVersion)
+{
+ TCHAR szPlainName[0x40];
+
+ // Sanity checks
+ assert(hs->szIndexFormat != NULL);
+ assert(hs->szIndexPath != NULL);
+ assert(IndexValue <= 0x0F);
+
+ // Create the full path
+ _stprintf(szPlainName, hs->szIndexFormat, IndexValue, IndexVersion);
+ return CombinePath(hs->szIndexPath, szPlainName);
+}
+
+static int VerifyAndParseKeyMapping_V1(PCASC_MAPPING_TABLE pKeyMapping, DWORD KeyIndex)
+{
+ PFILE_INDEX_HEADER_V1 pIndexHeader = (PFILE_INDEX_HEADER_V1)pKeyMapping->pbFileData;
+ DWORD dwDataHash1;
+ DWORD dwDataHash2;
+
+ // Verify the format
+ if(pIndexHeader->field_0 != 0x0005)
+ return ERROR_NOT_SUPPORTED;
+ if(pIndexHeader->KeyIndex != KeyIndex)
+ return ERROR_NOT_SUPPORTED;
+ if(pIndexHeader->field_8 == 0)
+ return ERROR_NOT_SUPPORTED;
+
+ // Verofy the bit counts
+ if(pIndexHeader->SpanSizeBytes != 0x04 ||
+ pIndexHeader->SpanOffsBytes != 0x05 ||
+ pIndexHeader->KeyBytes != 0x09)
+ return ERROR_NOT_SUPPORTED;
+
+ pKeyMapping->ExtraBytes = 0;
+ pKeyMapping->SpanSizeBytes = pIndexHeader->SpanSizeBytes;
+ pKeyMapping->SpanOffsBytes = pIndexHeader->SpanOffsBytes;
+ pKeyMapping->KeyBytes = pIndexHeader->KeyBytes;
+ pKeyMapping->SegmentBits = pIndexHeader->SegmentBits;
+ pKeyMapping->MaxFileOffset = pIndexHeader->MaxFileOffset;
+
+ // Get the pointer to the key entry array
+ pKeyMapping->nIndexEntries = pIndexHeader->KeyCount1 + pIndexHeader->KeyCount2;
+ if(pKeyMapping->nIndexEntries != 0)
+ pKeyMapping->pIndexEntries = (PCASC_INDEX_ENTRY)(pKeyMapping->pbFileData + sizeof(FILE_INDEX_HEADER_V1));
+
+ // Verify hashes
+ dwDataHash1 = hashlittle(pKeyMapping->pIndexEntries, pIndexHeader->KeyCount1 * sizeof(CASC_INDEX_ENTRY), 0);
+ dwDataHash2 = hashlittle(pKeyMapping->pIndexEntries + pIndexHeader->KeyCount1, pIndexHeader->KeyCount2 * sizeof(CASC_INDEX_ENTRY), 0);
+ if(dwDataHash1 != pIndexHeader->KeysHash1 || dwDataHash2 != pIndexHeader->KeysHash2)
+ return ERROR_FILE_CORRUPT;
+
+ return ERROR_SUCCESS;
+}
+
+static int VerifyAndParseKeyMapping_V2(PCASC_MAPPING_TABLE pKeyMapping, DWORD KeyIndex)
+{
+ PFILE_INDEX_HEADER_V2 pIndexHeader = (PFILE_INDEX_HEADER_V2)pKeyMapping->pbFileData;
+ PBLOCK_SIZE_AND_HASH pSizeAndHash;
+ LPBYTE pbLastPartEnd;
+ LPBYTE pbLastPart;
+ DWORD FilePosition;
+ DWORD LastPartLength;
+ unsigned int HashHigh = 0;
+ unsigned int HashLow = 0;
+
+ // The index header v2 begins after the SizeAndHash
+ pSizeAndHash = (PBLOCK_SIZE_AND_HASH)pKeyMapping->pbFileData;
+ pIndexHeader = (PFILE_INDEX_HEADER_V2)(pSizeAndHash + 1);
+ if(pIndexHeader->IndexVersion != 0x07 || pIndexHeader->KeyIndex != KeyIndex)
+ return ERROR_BAD_FORMAT;
+
+ if(pIndexHeader->ExtraBytes != 0x00 ||
+ pIndexHeader->SpanSizeBytes != 0x04 ||
+ pIndexHeader->SpanOffsBytes != 0x05 ||
+ pIndexHeader->KeyBytes != CASC_FILE_KEY_SIZE)
+ return ERROR_BAD_FORMAT;
+
+ // Remember the sizes
+ pKeyMapping->ExtraBytes = pIndexHeader->ExtraBytes;
+ pKeyMapping->SpanSizeBytes = pIndexHeader->SpanSizeBytes;
+ pKeyMapping->SpanOffsBytes = pIndexHeader->SpanOffsBytes;
+ pKeyMapping->KeyBytes = pIndexHeader->KeyBytes;
+ pKeyMapping->SegmentBits = pIndexHeader->SegmentBits;
+ pKeyMapping->MaxFileOffset = pIndexHeader->MaxFileOffset;
+
+ // Get the data position
+ FilePosition = (sizeof(BLOCK_SIZE_AND_HASH) + pSizeAndHash->cbBlockSize + 0x0F) & 0xFFFFFFF0;
+ if((FilePosition + 0x08) > pKeyMapping->cbFileData)
+ return ERROR_BAD_FORMAT;
+
+ // Get the pointer to "size+hash" block
+ pSizeAndHash = (PBLOCK_SIZE_AND_HASH)(pKeyMapping->pbFileData + FilePosition);
+ FilePosition += 0x08;
+
+ if((FilePosition + pSizeAndHash->cbBlockSize) > pKeyMapping->cbFileData)
+ return ERROR_BAD_FORMAT;
+ if(pSizeAndHash->cbBlockSize < sizeof(CASC_INDEX_ENTRY))
+ return ERROR_BAD_FORMAT;
+
+ // Remember the array of file keys
+ pKeyMapping->pIndexEntries = (PCASC_INDEX_ENTRY)(pKeyMapping->pbFileData + FilePosition);
+ pKeyMapping->nIndexEntries = pSizeAndHash->cbBlockSize / sizeof(CASC_INDEX_ENTRY);
+ FilePosition += pSizeAndHash->cbBlockSize;
+
+ // Verify the integrity of the key array
+ for(DWORD i = 0; i < pKeyMapping->nIndexEntries; i++)
+ hashlittle2(pKeyMapping->pIndexEntries + i, sizeof(CASC_INDEX_ENTRY), &HashHigh, &HashLow);
+ if(HashHigh != pSizeAndHash->dwBlockHash)
+ return ERROR_BAD_FORMAT;
+
+ // Align the data position up to next 0x1000
+ FilePosition = ALIGN_TO_SIZE(FilePosition, 0x1000);
+ if(FilePosition > pKeyMapping->cbFileData)
+ return ERROR_BAD_FORMAT;
+
+ LastPartLength = pKeyMapping->cbFileData - FilePosition;
+ if(LastPartLength < 0x7800)
+ return ERROR_BAD_FORMAT;
+
+ pbLastPart = pKeyMapping->pbFileData + FilePosition;
+ pbLastPartEnd = pbLastPart + ((LastPartLength >> 0x09) << 0x09);
+
+ while(pbLastPart < pbLastPartEnd)
+ {
+ for(int i = 0; i < 0x1F8; i += 0x18)
+ {
+ PDWORD PtrLastPart = (PDWORD)pbLastPart;
+ if(PtrLastPart[0] == 0)
+ return ERROR_SUCCESS;
+
+ HashLow = hashlittle(PtrLastPart + 1, 0x13, 0) | 0x80000000;
+ if(HashLow != PtrLastPart[0])
+ return ERROR_BAD_FORMAT;
+ }
+
+ pbLastPart += 0x200;
+ }
+
+ return ERROR_SUCCESS;
+}
+
+static int VerifyAndParseKeyMapping(PCASC_MAPPING_TABLE pKeyMapping, DWORD KeyIndex)
+{
+ // Sanity checks
+ assert(pKeyMapping->pbFileData != NULL);
+ assert(pKeyMapping->cbFileData != 0);
+
+ // Check for CASC version 2
+ if(IsCascIndexHeader_V2(pKeyMapping->pbFileData, pKeyMapping->cbFileData))
+ return VerifyAndParseKeyMapping_V2(pKeyMapping, KeyIndex);
+
+ // Check for CASC version 1
+ if(IsCascIndexHeader_V1(pKeyMapping->pbFileData, pKeyMapping->cbFileData))
+ return VerifyAndParseKeyMapping_V1(pKeyMapping, KeyIndex);
+
+ // Unknown CASC version
+ assert(false);
+ return ERROR_BAD_FORMAT;
+}
+
+static int LoadKeyMapping(PCASC_MAPPING_TABLE pKeyMapping, DWORD KeyIndex)
+{
+ TFileStream * pStream;
+ ULONGLONG FileSize = 0;
+ int nError = ERROR_SUCCESS;
+
+ // Sanity checks
+ assert(pKeyMapping->szFileName != NULL && pKeyMapping->szFileName[0] != 0);
+
+ // Open the stream for read-only access and read the file
+ pStream = FileStream_OpenFile(pKeyMapping->szFileName, STREAM_FLAG_READ_ONLY | STREAM_PROVIDER_FLAT | BASE_PROVIDER_FILE);
+ if(pStream != NULL)
+ {
+ // Retrieve the file size
+ FileStream_GetSize(pStream, &FileSize);
+ if((0 < FileSize && FileSize <= 0x90000) || 1)
+ {
+ // WoW6 actually reads THE ENTIRE file to memory
+ // Verified on Mac build (x64)
+ pKeyMapping->pbFileData = CASC_ALLOC(BYTE, (DWORD)FileSize);
+ pKeyMapping->cbFileData = (DWORD)FileSize;
+
+ // Load the data to memory and parse it
+ if(pKeyMapping->pbFileData != NULL)
+ {
+ if(FileStream_Read(pStream, NULL, pKeyMapping->pbFileData, pKeyMapping->cbFileData))
+ {
+ nError = VerifyAndParseKeyMapping(pKeyMapping, KeyIndex);
+ }
+ }
+ else
+ nError = ERROR_NOT_ENOUGH_MEMORY;
+ }
+ else
+ {
+ assert(false);
+ nError = ERROR_BAD_FORMAT;
+ }
+
+ // Close the file stream
+ FileStream_Close(pStream);
+ }
+ else
+ nError = GetLastError();
+
+ return ERROR_SUCCESS;
+}
+
+static int CreateArrayOfIndexEntries(TCascStorage * hs)
+{
+ PCASC_MAP pMap;
+ DWORD TotalCount = 0;
+ int nError = ERROR_NOT_ENOUGH_MEMORY;
+
+ // Count the total number of files in the storage
+ for(size_t i = 0; i < CASC_INDEX_COUNT; i++)
+ TotalCount += hs->KeyMapping[i].nIndexEntries;
+
+ // Create the map of all index entries
+ pMap = Map_Create(TotalCount, CASC_FILE_KEY_SIZE, FIELD_OFFSET(CASC_INDEX_ENTRY, IndexKey));
+ if(pMap != NULL)
+ {
+ // Put all index entries in the map
+ for(size_t i = 0; i < CASC_INDEX_COUNT; i++)
+ {
+ PCASC_INDEX_ENTRY pIndexEntry = hs->KeyMapping[i].pIndexEntries;
+ DWORD nIndexEntries = hs->KeyMapping[i].nIndexEntries;
+
+ for(DWORD j = 0; j < nIndexEntries; j++)
+ {
+ // Insert the index entry to the map
+ // Note that duplicate entries will not be inserted to the map
+ //
+ // Duplicate entries in WoW-WOD build 18179:
+ // 9e dc a7 8f e2 09 ad d8 b7 (encoding file)
+ // f3 5e bb fb d1 2b 3f ef 8b
+ // c8 69 9f 18 a2 5e df 7e 52
+ Map_InsertObject(pMap, pIndexEntry->IndexKey);
+
+ // Move to the next entry
+ pIndexEntry++;
+ }
+ }
+
+ // Store the map to the storage handle
+ hs->pIndexEntryMap = pMap;
+ nError = ERROR_SUCCESS;
+ }
+
+ return nError;
+}
+
+static int CreateMapOfEncodingKeys(TCascStorage * hs, PFILE_ENCODING_SEGMENT pEncodingSegment, DWORD dwNumberOfSegments)
+{
+ PCASC_ENCODING_ENTRY pEncodingEntry;
+ size_t nMaxEntries;
+ size_t nEntries = 0;
+ int nError = ERROR_SUCCESS;
+
+ // Sanity check
+ assert(hs->ppEncodingEntries == NULL);
+ assert(hs->pIndexEntryMap != NULL);
+
+ // Calculate the largest eventual number of encodign entries
+ nMaxEntries = (dwNumberOfSegments * CASC_ENCODING_SEGMENT_SIZE) / (sizeof(CASC_ENCODING_ENTRY) + MD5_HASH_SIZE);
+
+ // Allocate the array of pointers to encoding entries
+ hs->ppEncodingEntries = CASC_ALLOC(PCASC_ENCODING_ENTRY, nMaxEntries);
+ if(hs->ppEncodingEntries != NULL)
+ {
+ LPBYTE pbStartOfSegment = (LPBYTE)(pEncodingSegment + dwNumberOfSegments);
+
+ // Parse all segments
+ for(DWORD i = 0; i < dwNumberOfSegments; i++)
+ {
+ LPBYTE pbEncodingEntry = pbStartOfSegment;
+ LPBYTE pbEndOfSegment = pbStartOfSegment + CASC_ENCODING_SEGMENT_SIZE - sizeof(CASC_ENCODING_ENTRY) - MD5_HASH_SIZE;
+
+ // Parse all encoding entries
+ while(pbEncodingEntry <= pbEndOfSegment)
+ {
+ // Get pointer to the encoding entry
+ pEncodingEntry = (PCASC_ENCODING_ENTRY)pbEncodingEntry;
+ if(pEncodingEntry->KeyCount == 0)
+ break;
+
+ // Insert the pointer the array
+ hs->ppEncodingEntries[nEntries++] = pEncodingEntry;
+
+ // Move to the next encoding entry
+ pbEncodingEntry += sizeof(CASC_ENCODING_ENTRY) + (pEncodingEntry->KeyCount * MD5_HASH_SIZE);
+ }
+
+ // Move to the next segment
+ pbStartOfSegment += CASC_ENCODING_SEGMENT_SIZE;
+ }
+
+ // Remember the total number of encoding entries
+ hs->nEncodingEntries = nEntries;
+ }
+ else
+ nError = ERROR_NOT_ENOUGH_MEMORY;
+
+ return nError;
+}
+
+static DWORD GetSizeOfEncodingFile(HANDLE hFile)
+{
+ CASC_ENCODING_HEADER EncodingHeader;
+ DWORD cbEncodingFile = 0;
+ DWORD dwSegmentPos;
+ DWORD dwNumSegments;
+ DWORD dwBytesRead;
+
+ // Read the endoding header
+ CascReadFile(hFile, &EncodingHeader, sizeof(CASC_ENCODING_HEADER), &dwBytesRead);
+ if(dwBytesRead == sizeof(CASC_ENCODING_HEADER))
+ {
+ dwNumSegments = ConvertBytesToInteger_4(EncodingHeader.NumSegments);
+ dwSegmentPos = ConvertBytesToInteger_4(EncodingHeader.SegmentsPos);
+
+ cbEncodingFile = sizeof(CASC_ENCODING_HEADER) +
+ dwSegmentPos +
+ dwNumSegments * (sizeof(FILE_ENCODING_SEGMENT) + CASC_ENCODING_SEGMENT_SIZE);
+ }
+
+ // Reset the position back
+ CascSetFilePointer(hFile, 0, NULL, FILE_BEGIN);
+ return cbEncodingFile;
+}
+
+static LPBYTE LoadCascFile(HANDLE hFile, DWORD cbMaxSize, PDWORD pcbFileData)
+{
+ LPBYTE pbFileData = NULL;
+ DWORD cbFileData;
+ DWORD dwBytesRead = 0;
+ int nError = ERROR_SUCCESS;
+
+ // Retrieve the size of the file
+ cbFileData = CascGetFileSize(hFile, NULL);
+ if(cbFileData != 0 && cbFileData != CASC_INVALID_SIZE)
+ {
+ // Trim the size to the maximum
+ cbFileData = CASCLIB_MIN(cbMaxSize, cbFileData);
+
+ // Allocate the buffer that will hold the entire file
+ pbFileData = CASC_ALLOC(BYTE, cbFileData);
+ if(pbFileData != NULL)
+ {
+ // Read the entire file to memory
+ CascReadFile(hFile, pbFileData, cbFileData, &dwBytesRead);
+ if(dwBytesRead != cbFileData)
+ nError = ERROR_FILE_CORRUPT;
+ }
+ else
+ nError = ERROR_NOT_ENOUGH_MEMORY;
+ }
+ else
+ nError = ERROR_FILE_CORRUPT;
+
+ // If something failed, clean-up the buffers
+ if(nError != ERROR_SUCCESS)
+ {
+ // Clear the file data
+ if(pbFileData != NULL)
+ CASC_FREE(pbFileData);
+ pbFileData = NULL;
+ cbFileData = 0;
+
+ // Set the last error value
+ SetLastError(nError);
+ }
+
+ // Return what we got
+ if(pcbFileData != NULL)
+ *pcbFileData = cbFileData;
+ return pbFileData;
+}
+
+static int LoadIndexFiles(TCascStorage * hs)
+{
+ DWORD IndexArray[CASC_INDEX_COUNT];
+ DWORD OldIndexArray[CASC_INDEX_COUNT];
+ int nError;
+ int i;
+
+ // Scan all index files
+ memset(IndexArray, 0, sizeof(IndexArray));
+ memset(OldIndexArray, 0, sizeof(OldIndexArray));
+ nError = ScanIndexDirectory(hs->szIndexPath, IndexDirectory_OnFileFound, IndexArray, OldIndexArray, hs);
+ if(nError == ERROR_SUCCESS)
+ {
+ // Load each index file
+ for(i = 0; i < CASC_INDEX_COUNT; i++)
+ {
+ hs->KeyMapping[i].szFileName = CreateIndexFileName(hs, i, IndexArray[i]);
+ if(hs->KeyMapping[i].szFileName != NULL)
+ {
+ nError = LoadKeyMapping(&hs->KeyMapping[i], i);
+ if(nError != ERROR_SUCCESS)
+ break;
+ }
+ }
+ }
+
+ // Now we need to build the map of the index entries
+ if(nError == ERROR_SUCCESS)
+ {
+ nError = CreateArrayOfIndexEntries(hs);
+ }
+
+ return nError;
+}
+
+static int LoadEncodingFile(TCascStorage * hs)
+{
+ PFILE_ENCODING_SEGMENT pEncodingSegment;
+ PCASC_ENCODING_ENTRY pEncodingEntry;
+ LPBYTE pbStartOfSegment;
+ LPBYTE pbEncodingFile = NULL;
+ HANDLE hFile = NULL;
+ DWORD cbEncodingFile = 0;
+ DWORD dwNumberOfSegments = 0;
+ DWORD dwSegmentsPos = 0;
+ int nError = ERROR_SUCCESS;
+
+ // Open the encoding file
+ if(!CascOpenFileByIndexKey((HANDLE)hs, &hs->EncodingEKey, 0, &hFile))
+ nError = GetLastError();
+
+ // Load the encoding file to memory
+ if(nError == ERROR_SUCCESS)
+ {
+ // Retrieve the CASC header. We do not usually need to load
+ // the entire file, but we need to know how big part of it we need
+ cbEncodingFile = GetSizeOfEncodingFile(hFile);
+
+ // Load the entire file to memory
+ pbEncodingFile = LoadCascFile(hFile, cbEncodingFile, &cbEncodingFile);
+ if(pbEncodingFile == NULL || cbEncodingFile <= sizeof(CASC_ENCODING_HEADER))
+ nError = ERROR_FILE_CORRUPT;
+
+ CascCloseFile(hFile);
+ }
+
+ // Verify all encoding segments
+ if(nError == ERROR_SUCCESS)
+ {
+ // Save the encoding header
+ hs->pEncodingHeader = (PCASC_ENCODING_HEADER)pbEncodingFile;
+
+ // Convert size and offset
+ dwNumberOfSegments = ConvertBytesToInteger_4(hs->pEncodingHeader->NumSegments);
+ dwSegmentsPos = ConvertBytesToInteger_4(hs->pEncodingHeader->SegmentsPos);
+
+ // Allocate the array of encoding segments
+ pEncodingSegment = (PFILE_ENCODING_SEGMENT)(pbEncodingFile + sizeof(CASC_ENCODING_HEADER) + dwSegmentsPos);
+ pbStartOfSegment = (LPBYTE)(pEncodingSegment + dwNumberOfSegments);
+
+ // Go through all encoding segments and verify them
+ for(DWORD i = 0; i < dwNumberOfSegments; i++)
+ {
+ // Check if there is enough space in the buffer
+ if((pbStartOfSegment + CASC_ENCODING_SEGMENT_SIZE) > (pbEncodingFile + cbEncodingFile))
+ {
+ nError = ERROR_FILE_CORRUPT;
+ break;
+ }
+
+ // Check the hash of the entire segment
+ // Note that verifying takes considerable time of the storage loading
+// if(!VerifyDataBlockHash(pbStartOfSegment, CASC_ENCODING_SEGMENT_SIZE, pEncodingSegment->SegmentHash))
+// {
+// nError = ERROR_FILE_CORRUPT;
+// break;
+// }
+
+ // Check if the encoding key matches
+ pEncodingEntry = (PCASC_ENCODING_ENTRY)pbStartOfSegment;
+ if(memcmp(pEncodingEntry->EncodingKey, pEncodingSegment->FirstEncodingKey, MD5_HASH_SIZE))
+ {
+ nError = ERROR_FILE_CORRUPT;
+ break;
+ }
+
+ // Move to the next segment
+ pbStartOfSegment += CASC_ENCODING_SEGMENT_SIZE;
+ pEncodingSegment++;
+ }
+ }
+
+ // Create the map of the encoding keys
+ // Note that the array of encoding keys is already sorted - no need to sort it
+ if(nError == ERROR_SUCCESS)
+ {
+ pEncodingSegment = (PFILE_ENCODING_SEGMENT)(pbEncodingFile + sizeof(CASC_ENCODING_HEADER) + dwSegmentsPos);
+ nError = CreateMapOfEncodingKeys(hs, pEncodingSegment, dwNumberOfSegments);
+ }
+ return nError;
+}
+
+static int LoadRootFile(TCascStorage * hs, LPBYTE pbRootFile, DWORD cbRootFile)
+{
+ PFILE_ROOT_ENTRY pSrcEntry;
+ PCASC_ROOT_ENTRY pTrgEntry;
+ ROOT_BLOCK_INFO BlockInfo;
+ LPBYTE pbRootFileEnd = pbRootFile + cbRootFile;
+ LPBYTE pbFilePointer;
+ size_t nRootEntries = 0;
+ size_t nRootIndex = 0;
+ int nError = ERROR_NOT_ENOUGH_MEMORY;
+
+ // Calculate the root entries
+ for(pbFilePointer = pbRootFile; pbFilePointer <= pbRootFileEnd; )
+ {
+ // Validate the root block
+ pbFilePointer = VerifyLocaleBlock(&BlockInfo, pbFilePointer, pbRootFileEnd);
+ if(pbFilePointer == NULL)
+ break;
+
+ // Add the number of entries
+ nRootEntries = nRootEntries + BlockInfo.pLocaleBlockHdr->NumberOfFiles;
+ }
+
+ // Create a linear array of the root entries and sort it
+ hs->pRootEntries = pTrgEntry = CASC_ALLOC(CASC_ROOT_ENTRY, nRootEntries);
+ hs->ppRootEntries = CASC_ALLOC(PCASC_ROOT_ENTRY, nRootEntries);
+ if(hs->ppRootEntries && hs->pRootEntries)
+ {
+ // Convert each entry from FILE_ROOT_ENTRY to CASC_ROOT_ENTRY
+ for(pbFilePointer = pbRootFile; pbFilePointer <= pbRootFileEnd; )
+ {
+ // Validate the root block
+ pbFilePointer = VerifyLocaleBlock(&BlockInfo, pbFilePointer, pbRootFileEnd);
+ if(pbFilePointer == NULL)
+ break;
+
+ // Get the pointer to the first root entry
+ pSrcEntry = (PFILE_ROOT_ENTRY)BlockInfo.pRootEntries;
+
+ // Convert all entries
+ for(DWORD i = 0; i < BlockInfo.pLocaleBlockHdr->NumberOfFiles; i++)
+ {
+ // Copy the root entry
+ CopyFileKey(pTrgEntry->EncodingKey, pSrcEntry->EncodingKey);
+ pTrgEntry->FileNameHash = pSrcEntry->FileNameHash;
+ pTrgEntry->Locales = BlockInfo.pLocaleBlockHdr->Locales;
+ pTrgEntry->Flags = BlockInfo.pLocaleBlockHdr->Flags;
+
+// if(pTrgEntry->FileNameHash == 0x5ddb88608673f698ULL)
+// DebugBreak();
+
+ // Insert the CASC root entry to the linear array of pointers
+ hs->ppRootEntries[nRootIndex++] = pTrgEntry;
+
+ // Move to the next root entry
+ pSrcEntry++;
+ pTrgEntry++;
+ }
+ }
+
+ // Save the number of entries
+ assert(nRootIndex == nRootEntries);
+ hs->nRootEntries = nRootIndex;
+
+ // Now sort the array
+ qsort_pointer_array((void **)hs->ppRootEntries, hs->nRootEntries, CompareRootEntries, NULL);
+ nError = ERROR_SUCCESS;
+ }
+
+ return nError;
+
+/*
+ FILE * fp = fopen("E:\\root_entries.txt", "wt");
+ if(fp != NULL)
+ {
+ for(size_t i = 0; i < nRootEntries; i++)
+ {
+ fprintf(fp, "%08X: %016I64lX\n", i, hs->ppRootEntries[i]->FileNameHash);
+ }
+ fclose(fp);
+ }
+*/
+}
+
+static int LoadRootFile(TCascStorage * hs)
+{
+ PDWORD FileSignature;
+ HANDLE hFile = NULL;
+ LPBYTE pbRootFile = NULL;
+ DWORD cbRootFile = 0;
+ int nError = ERROR_SUCCESS;
+
+ // Sanity checks
+ assert(hs->ppEncodingEntries != NULL);
+ assert(hs->pRootEntries == NULL);
+ assert(hs->nRootEntries == 0);
+
+ // The root file is either MNDX file (Heroes of the Storm)
+ // or a file containing an array of root entries (World of Warcraft 6.0+)
+ // Note: The "root" key file's MD5 hash is equal to its name
+ // in the configuration
+ if(!CascOpenFileByEncodingKey((HANDLE)hs, &hs->RootKey, 0, &hFile))
+ nError = GetLastError();
+
+ // Load ther entire root file to memory
+ if(nError == ERROR_SUCCESS)
+ {
+ // Load the entire root file to memory
+ pbRootFile = LoadCascFile(hFile, 0xFFFFFFFF, &cbRootFile);
+ if(pbRootFile == NULL || cbRootFile == 0)
+ nError = ERROR_FILE_CORRUPT;
+
+ // Close the root file
+ CascCloseFile(hFile);
+ }
+
+ // Check if the file is a MNDX file
+ if(nError == ERROR_SUCCESS)
+ {
+ FileSignature = (PDWORD)pbRootFile;
+ if(FileSignature[0] == CASC_MNDX_SIGNATURE)
+ {
+ nError = LoadMndxRootFile(hs, pbRootFile, cbRootFile);
+ }
+ else
+ {
+ nError = LoadRootFile(hs, pbRootFile, cbRootFile);
+ }
+ }
+
+ // Free the root file
+ CASC_FREE(pbRootFile);
+ return nError;
+}
+
+static TCascStorage * FreeCascStorage(TCascStorage * hs)
+{
+ size_t i;
+
+ if(hs != NULL)
+ {
+ // Free the MNDX info
+ if(hs->pPackages != NULL)
+ CASC_FREE(hs->pPackages);
+ if(hs->pMndxInfo != NULL)
+ FreeMndxInfo(hs->pMndxInfo);
+
+ // Free the pointers to file entries
+ if(hs->ppRootEntries != NULL)
+ CASC_FREE(hs->ppRootEntries);
+ if(hs->pRootEntries != NULL)
+ CASC_FREE(hs->pRootEntries);
+ if(hs->ppEncodingEntries != NULL)
+ CASC_FREE(hs->ppEncodingEntries);
+ if(hs->pEncodingHeader != NULL)
+ CASC_FREE(hs->pEncodingHeader);
+ if(hs->pIndexEntryMap != NULL)
+ Map_Free(hs->pIndexEntryMap);
+
+ // Close all data files
+ for(i = 0; i < CASC_MAX_DATA_FILES; i++)
+ {
+ if(hs->DataFileArray[i] != NULL)
+ {
+ FileStream_Close(hs->DataFileArray[i]);
+ hs->DataFileArray[i] = NULL;
+ }
+ }
+
+ // Close all key mappings
+ for(i = 0; i < CASC_INDEX_COUNT; i++)
+ {
+ if(hs->KeyMapping[i].szFileName != NULL)
+ CASC_FREE(hs->KeyMapping[i].szFileName);
+ if(hs->KeyMapping[i].pbFileData != NULL)
+ CASC_FREE(hs->KeyMapping[i].pbFileData);
+ hs->KeyMapping[i].pIndexEntries = NULL;
+ }
+
+ // Free the file paths
+ if(hs->szRootPath != NULL)
+ CASC_FREE(hs->szRootPath);
+ if(hs->szDataPath != NULL)
+ CASC_FREE(hs->szDataPath);
+ if(hs->szIndexPath != NULL)
+ CASC_FREE(hs->szIndexPath);
+ if(hs->szUrlPath != NULL)
+ CASC_FREE(hs->szUrlPath);
+
+ // Fre the blob arrays
+ QUERY_KEY_FreeArray(hs->pArchiveArray);
+ QUERY_KEY_FreeArray(hs->pPatchArchiveArray);
+ QUERY_KEY_FreeArray(hs->pEncodingKeys);
+
+ // Free the blobs
+ QUERY_KEY_Free(&hs->CdnConfigKey);
+ QUERY_KEY_Free(&hs->CdnBuildKey);
+ QUERY_KEY_Free(&hs->ArchiveGroup);
+ QUERY_KEY_Free(&hs->PatchArchiveGroup);
+ QUERY_KEY_Free(&hs->RootKey);
+ QUERY_KEY_Free(&hs->PatchKey);
+ QUERY_KEY_Free(&hs->DownloadKey);
+ QUERY_KEY_Free(&hs->InstallKey);
+
+ // Free the storage structure
+ hs->szClassName = NULL;
+ CASC_FREE(hs);
+ }
+
+ return NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Public functions
+
+bool WINAPI CascOpenStorage(const TCHAR * szDataPath, DWORD dwFlags, HANDLE * phStorage)
+{
+ TCascStorage * hs;
+ int nError = ERROR_SUCCESS;
+
+ CASCLIB_UNUSED(dwFlags);
+
+ // Allocate the storage structure
+ hs = (TCascStorage *)CASC_ALLOC(TCascStorage, 1);
+ if(hs == NULL)
+ nError = ERROR_NOT_ENOUGH_MEMORY;
+
+ // Load the storage configuration
+ if(nError == ERROR_SUCCESS)
+ {
+ // Prepare the base storage parameters
+ memset(hs, 0, sizeof(TCascStorage));
+ hs->szClassName = "TCascStorage";
+ hs->dwRefCount = 1;
+ nError = InitializeCascDirectories(hs, szDataPath);
+ }
+
+ // Now we need to load the root file so we know the config files
+ if(nError == ERROR_SUCCESS)
+ {
+ nError = LoadBuildConfiguration(hs);
+ }
+
+ // Load the index files
+ if(nError == ERROR_SUCCESS)
+ {
+ nError = LoadIndexFiles(hs);
+ }
+
+ // Load the index files
+ if(nError == ERROR_SUCCESS)
+ {
+ nError = LoadEncodingFile(hs);
+ }
+
+ // Load the index files
+ if(nError == ERROR_SUCCESS)
+ {
+ nError = LoadRootFile(hs);
+ }
+
+#ifdef _DEBUG
+// if(nError == ERROR_SUCCESS)
+// {
+// CascDumpStorage("E:\\casc_dump.txt", hs, _T("e:\\Ladik\\Appdir\\CascLib\\listfile\\listfile-wow6.txt"));
+// CascDumpIndexEntries("E:\\casc_index.txt", hs);
+// }
+#endif
+
+ // If something failed, free the storage and return
+ if(nError != ERROR_SUCCESS)
+ {
+ hs = FreeCascStorage(hs);
+ SetLastError(nError);
+ }
+
+ *phStorage = (HANDLE)hs;
+ return (nError == ERROR_SUCCESS);
+}
+
+bool WINAPI CascGetStorageInfo(
+ HANDLE hStorage,
+ CASC_STORAGE_INFO_CLASS InfoClass,
+ void * pvStorageInfo,
+ size_t cbStorageInfo,
+ size_t * pcbLengthNeeded)
+{
+ TCascStorage * hs;
+ DWORD dwCascFeatures = 0;
+
+ // Verify the storage handle
+ hs = IsValidStorageHandle(hStorage);
+ if(hs == NULL)
+ {
+ SetLastError(ERROR_INVALID_HANDLE);
+ return false;
+ }
+
+ // Differentiate between info classes
+ switch(InfoClass)
+ {
+ case CascStorageFileCount:
+
+ // Check the buffer size
+ if(cbStorageInfo < sizeof(DWORD))
+ {
+ *pcbLengthNeeded = sizeof(DWORD);
+ SetLastError(ERROR_INSUFFICIENT_BUFFER);
+ return false;
+ }
+
+ // Give the number of files
+ *(PDWORD)pvStorageInfo = (DWORD)hs->pIndexEntryMap->ItemCount;
+ return true;
+
+ case CascStorageFeatures:
+
+ // Check the buffer size
+ if(cbStorageInfo < sizeof(DWORD))
+ {
+ *pcbLengthNeeded = sizeof(DWORD);
+ SetLastError(ERROR_INSUFFICIENT_BUFFER);
+ return false;
+ }
+
+ // Construct the features
+ if(hs->pMndxInfo != NULL)
+ dwCascFeatures |= CASC_FEATURE_LISTFILE;
+
+ // Give the number of files
+ *(PDWORD)pvStorageInfo = dwCascFeatures;
+ return true;
+
+ default:
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return false;
+ }
+}
+
+
+
+bool WINAPI CascCloseStorage(HANDLE hStorage)
+{
+ TCascStorage * hs;
+
+ // Verify the storage handle
+ hs = IsValidStorageHandle(hStorage);
+ if(hs == NULL)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return false;
+ }
+
+ // Only free the storage if the reference count reaches 0
+ if(hs->dwRefCount == 1)
+ {
+ FreeCascStorage(hs);
+ return true;
+ }
+
+ // Just decrement number of references
+ hs->dwRefCount--;
+ return true;
+}
+
diff --git a/dep/CascLib/src/CascPort.h b/dep/CascLib/src/CascPort.h
new file mode 100644
index 00000000000..6d0595ce522
--- /dev/null
+++ b/dep/CascLib/src/CascPort.h
@@ -0,0 +1,260 @@
+/*****************************************************************************/
+/* CascPort.h Copyright (c) Ladislav Zezula 2014 */
+/*---------------------------------------------------------------------------*/
+/* Portability module for the CascLib library. Contains a wrapper symbols */
+/* to make the compilation under Linux work */
+/*---------------------------------------------------------------------------*/
+/* Date Ver Who Comment */
+/* -------- ---- --- ------- */
+/* 29.04.14 1.00 Lad Created */
+/*****************************************************************************/
+
+#ifndef __CASCPORT_H__
+#define __CASCPORT_H__
+
+#ifndef __cplusplus
+ #define bool char
+ #define true 1
+ #define false 0
+#endif
+
+//-----------------------------------------------------------------------------
+// Defines for Windows
+
+#if !defined(PLATFORM_DEFINED) && (defined(WIN32) || defined(WIN64))
+
+ // In MSVC 8.0, there are some functions declared as deprecated.
+ #if _MSC_VER >= 1400
+ #define _CRT_SECURE_NO_DEPRECATE
+ #define _CRT_NON_CONFORMING_SWPRINTFS
+ #endif
+
+ #include <tchar.h>
+ #include <assert.h>
+ #include <ctype.h>
+ #include <stdio.h>
+ #include <windows.h>
+ #include <wininet.h>
+ #include <sys/types.h>
+ #define PLATFORM_LITTLE_ENDIAN
+
+ #ifdef WIN64
+ #define PLATFORM_64BIT
+ #else
+ #define PLATFORM_32BIT
+ #endif
+
+ #define PATH_SEPARATOR '\\'
+ #define CREATE_DIRECTORY(name) CreateDirectory(name, NULL);
+
+ #define PLATFORM_WINDOWS
+ #define PLATFORM_DEFINED // The platform is known now
+
+#endif
+
+//-----------------------------------------------------------------------------
+// Defines for Mac
+
+#if !defined(PLATFORM_DEFINED) && defined(__APPLE__) // Mac BSD API
+
+ // Macintosh
+ #include <sys/types.h>
+ #include <sys/stat.h>
+ #include <sys/mman.h>
+ #include <unistd.h>
+ #include <fcntl.h>
+ #include <stdlib.h>
+ #include <dirent.h>
+ #include <errno.h>
+
+ // Support for PowerPC on Max OS X
+ #if (__ppc__ == 1) || (__POWERPC__ == 1) || (_ARCH_PPC == 1)
+ #include <stdint.h>
+ #include <CoreFoundation/CFByteOrder.h>
+ #endif
+
+ #define PKEXPORT
+ #define __SYS_ZLIB
+ #define __SYS_BZLIB
+
+ #ifndef __BIG_ENDIAN__
+ #define PLATFORM_LITTLE_ENDIAN
+ #endif
+
+ #define PATH_SEPARATOR '/'
+ #define CREATE_DIRECTORY(name) mkdir(name, 0755)
+
+ #define PLATFORM_MAC
+ #define PLATFORM_DEFINED // The platform is known now
+
+ #define FIELD_OFFSET(t,f) offsetof(t,f)
+#endif
+
+//-----------------------------------------------------------------------------
+// Assumption: we are not on Windows nor Macintosh, so this must be linux *grin*
+
+#if !defined(PLATFORM_DEFINED)
+
+ #include <sys/types.h>
+ #include <sys/stat.h>
+ #include <sys/mman.h>
+ #include <fcntl.h>
+ #include <dirent.h>
+ #include <unistd.h>
+ #include <stddef.h>
+ #include <stdint.h>
+ #include <stdlib.h>
+ #include <stdio.h>
+ #include <stdarg.h>
+ #include <string.h>
+ #include <ctype.h>
+ #include <assert.h>
+ #include <errno.h>
+
+ #define PATH_SEPARATOR '/'
+ #define CREATE_DIRECTORY(name) mkdir(name, 0755)
+
+ #define PLATFORM_LITTLE_ENDIAN
+ #define PLATFORM_LINUX
+ #define PLATFORM_DEFINED
+
+ #define FIELD_OFFSET(t,f) offsetof(t,f)
+#endif
+
+//-----------------------------------------------------------------------------
+// Definition of Windows-specific types for non-Windows platforms
+
+#ifndef PLATFORM_WINDOWS
+ #if __LP64__
+ #define PLATFORM_64BIT
+ #else
+ #define PLATFORM_32BIT
+ #endif
+
+ // Typedefs for ANSI C
+ typedef unsigned char BYTE;
+ typedef unsigned short USHORT;
+ typedef int LONG;
+ typedef unsigned int DWORD;
+ typedef unsigned long DWORD_PTR;
+ typedef long LONG_PTR;
+ typedef long INT_PTR;
+ typedef long long LONGLONG;
+ typedef unsigned long long ULONGLONG;
+ typedef unsigned long long *PULONGLONG;
+ typedef void * HANDLE;
+ typedef void * LPOVERLAPPED; // Unsupported on Linux and Mac
+ typedef char TCHAR;
+ typedef unsigned int LCID;
+ typedef LONG * PLONG;
+ typedef DWORD * PDWORD;
+ typedef BYTE * LPBYTE;
+
+ #ifdef PLATFORM_32BIT
+ #define _LZMA_UINT32_IS_ULONG
+ #endif
+
+ // Some Windows-specific defines
+ #ifndef MAX_PATH
+ #define MAX_PATH 1024
+ #endif
+
+ #define WINAPI
+
+ #define FILE_BEGIN SEEK_SET
+ #define FILE_CURRENT SEEK_CUR
+ #define FILE_END SEEK_END
+
+ #define INVALID_HANDLE_VALUE ((HANDLE)-1)
+
+ #define _T(x) x
+ #define _tcslen strlen
+ #define _tcscpy strcpy
+ #define _tcscat strcat
+ #define _tcschr strchr
+ #define _tcsrchr strrchr
+ #define _tcsstr strstr
+ #define _tcsspn strspn
+ #define _tprintf printf
+ #define _stprintf sprintf
+ #define _tremove remove
+ #define _tmkdir mkdir
+
+ #define _stricmp strcasecmp
+ #define _strnicmp strncasecmp
+ #define _tcsicmp strcasecmp
+ #define _tcsnicmp strncasecmp
+
+#endif // !PLATFORM_WINDOWS
+
+// 64-bit calls are supplied by "normal" calls on Mac
+#if defined(PLATFORM_MAC)
+ #define stat64 stat
+ #define fstat64 fstat
+ #define lseek64 lseek
+ #define ftruncate64 ftruncate
+ #define off64_t off_t
+ #define O_LARGEFILE 0
+#endif
+
+// Platform-specific error codes for UNIX-based platforms
+#if defined(PLATFORM_MAC) || defined(PLATFORM_LINUX)
+ #define ERROR_SUCCESS 0
+ #define ERROR_FILE_NOT_FOUND ENOENT
+ #define ERROR_ACCESS_DENIED EPERM
+ #define ERROR_INVALID_HANDLE EBADF
+ #define ERROR_NOT_ENOUGH_MEMORY ENOMEM
+ #define ERROR_NOT_SUPPORTED ENOTSUP
+ #define ERROR_INVALID_PARAMETER EINVAL
+ #define ERROR_DISK_FULL ENOSPC
+ #define ERROR_ALREADY_EXISTS EEXIST
+ #define ERROR_INSUFFICIENT_BUFFER ENOBUFS
+ #define ERROR_BAD_FORMAT 1000 // No such error code under Linux
+ #define ERROR_NO_MORE_FILES 1001 // No such error code under Linux
+ #define ERROR_HANDLE_EOF 1002 // No such error code under Linux
+ #define ERROR_CAN_NOT_COMPLETE 1003 // No such error code under Linux
+ #define ERROR_FILE_CORRUPT 1004 // No such error code under Linux
+#endif
+
+//-----------------------------------------------------------------------------
+// Swapping functions
+
+#ifdef PLATFORM_LITTLE_ENDIAN
+ #define BSWAP_INT16_UNSIGNED(a) (a)
+ #define BSWAP_INT16_SIGNED(a) (a)
+ #define BSWAP_INT32_UNSIGNED(a) (a)
+ #define BSWAP_INT32_SIGNED(a) (a)
+ #define BSWAP_INT64_SIGNED(a) (a)
+ #define BSWAP_INT64_UNSIGNED(a) (a)
+ #define BSWAP_ARRAY16_UNSIGNED(a,b) {}
+ #define BSWAP_ARRAY32_UNSIGNED(a,b) {}
+ #define BSWAP_ARRAY64_UNSIGNED(a,b) {}
+#else
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+ int16_t SwapInt16(uint16_t);
+ uint16_t SwapUInt16(uint16_t);
+ int32_t SwapInt32(uint32_t);
+ uint32_t SwapUInt32(uint32_t);
+ int64_t SwapInt64(uint64_t);
+ uint64_t SwapUInt64(uint64_t);
+ void ConvertUInt16Buffer(void * ptr, size_t length);
+ void ConvertUInt32Buffer(void * ptr, size_t length);
+ void ConvertUInt64Buffer(void * ptr, size_t length);
+#ifdef __cplusplus
+ }
+#endif
+ #define BSWAP_INT16_SIGNED(a) SwapInt16((a))
+ #define BSWAP_INT16_UNSIGNED(a) SwapUInt16((a))
+ #define BSWAP_INT32_SIGNED(a) SwapInt32((a))
+ #define BSWAP_INT32_UNSIGNED(a) SwapUInt32((a))
+ #define BSWAP_INT64_SIGNED(a) SwapInt64((a))
+ #define BSWAP_INT64_UNSIGNED(a) SwapUInt64((a))
+ #define BSWAP_ARRAY16_UNSIGNED(a,b) ConvertUInt16Buffer((a),(b))
+ #define BSWAP_ARRAY32_UNSIGNED(a,b) ConvertUInt32Buffer((a),(b))
+ #define BSWAP_ARRAY64_UNSIGNED(a,b) ConvertUInt64Buffer((a),(b))
+#endif
+
+#endif // __CASCPORT_H__
diff --git a/dep/CascLib/src/CascReadFile.cpp b/dep/CascLib/src/CascReadFile.cpp
new file mode 100644
index 00000000000..64dd66ef88a
--- /dev/null
+++ b/dep/CascLib/src/CascReadFile.cpp
@@ -0,0 +1,475 @@
+/*****************************************************************************/
+/* CascOpenFile.cpp Copyright (c) Ladislav Zezula 2014 */
+/*---------------------------------------------------------------------------*/
+/* System-dependent directory functions for CascLib */
+/*---------------------------------------------------------------------------*/
+/* Date Ver Who Comment */
+/* -------- ---- --- ------- */
+/* 01.05.14 1.00 Lad The first version of CascOpenFile.cpp */
+/*****************************************************************************/
+
+#define __CASCLIB_SELF__
+#include "CascLib.h"
+#include "CascCommon.h"
+
+//-----------------------------------------------------------------------------
+// Local structures
+
+#define BLTE_HEADER_SIGNATURE 0x45544C42
+
+// Data file begin:
+// BYTE HeaderHash[MD5_HASH_SIZE]; // MD5 of the frame array
+// DWORD dwFileSize; // Size of the file
+// BYTE SomeSize[4]; // Some size (big endian)
+// BYTE Padding[6]; // Padding (?)
+
+typedef struct _BLTE_HEADER
+{
+ DWORD dwSignature; // Must be "BLTE"
+ BYTE HeaderSizeAsBytes[4]; // Header size in bytes (big endian)
+ BYTE MustBe0F; // Must be 0x0F
+ BYTE FrameCount[3]; // Number of frames (big endian)
+
+} BLTE_HEADER, *PBLTE_HEADER;
+
+typedef struct _BLTE_FRAME
+{
+ BYTE CompressedSize[4]; // Compressed file size as big endian
+ BYTE FrameSize[4]; // File size as big endian
+ BYTE md5[MD5_HASH_SIZE]; // Hash of the frame
+
+} BLTE_FRAME, *PBLTE_FRAME;
+
+//-----------------------------------------------------------------------------
+// Local functions
+
+TCascFile * IsValidFileHandle(HANDLE hFile); // In CascOpenFile.cpp
+
+static int EnsureDataStreamIsOpen(TCascFile * hf)
+{
+ TCascStorage * hs = hf->hs;
+ TFileStream * pStream = NULL;
+ TCHAR * szDataFile;
+ TCHAR szPlainName[0x40];
+
+ // If the file is not open yet, do it
+ if(hs->DataFileArray[hf->ArchiveIndex] == NULL)
+ {
+ // Prepare the name of the data file
+ _stprintf(szPlainName, _T("data.%03u"), hf->ArchiveIndex);
+ szDataFile = CombinePath(hs->szIndexPath, szPlainName);
+
+ // Open the data file
+ if(szDataFile != NULL)
+ {
+ // Open the stream
+ pStream = FileStream_OpenFile(szDataFile, STREAM_FLAG_READ_ONLY | STREAM_PROVIDER_FLAT | BASE_PROVIDER_FILE);
+ hs->DataFileArray[hf->ArchiveIndex] = pStream;
+
+ // TODO: There is 0x1E bytes at the beginning of the file stream
+ // Ignore them for now, but we will want to know what they mean
+ // Offs0000: MD5 of something
+ // Offs0010: 2 bytes
+ CASC_FREE(szDataFile);
+ }
+ }
+
+ // Return error or success
+ hf->pStream = hs->DataFileArray[hf->ArchiveIndex];
+ return (hf->pStream != NULL) ? ERROR_SUCCESS : ERROR_FILE_NOT_FOUND;
+}
+
+static int LoadFileFrames(TCascFile * hf, DWORD FrameCount)
+{
+ PBLTE_FRAME pFileFrames;
+ PBLTE_FRAME pFileFrame;
+ ULONGLONG ArchiveFileOffset;
+ DWORD FrameOffset = 0;
+ DWORD FileSize = 0;
+ int nError = ERROR_SUCCESS;
+
+ assert(hf != NULL);
+ assert(hf->pStream != NULL);
+ assert(hf->pFrames != NULL);
+
+ // Allocate frame array
+ pFileFrames = pFileFrame = CASC_ALLOC(BLTE_FRAME, FrameCount);
+ if(pFileFrames != NULL)
+ {
+ // Load the frame array
+ ArchiveFileOffset = hf->FramesOffset;
+ if(FileStream_Read(hf->pStream, &ArchiveFileOffset, pFileFrames, FrameCount * sizeof(BLTE_FRAME)))
+ {
+ // Move the raw archive offset
+ ArchiveFileOffset += (hf->FrameCount * sizeof(BLTE_FRAME));
+
+ // Copy the frames to the file structure
+ for(DWORD i = 0; i < FrameCount; i++, pFileFrame++)
+ {
+ hf->pFrames[i].FrameArchiveOffset = (DWORD)ArchiveFileOffset;
+ hf->pFrames[i].FrameFileOffset = FrameOffset;
+ hf->pFrames[i].CompressedSize = ConvertBytesToInteger_4(pFileFrame->CompressedSize);
+ hf->pFrames[i].FrameSize = ConvertBytesToInteger_4(pFileFrame->FrameSize);
+ memcpy(hf->pFrames[i].md5, pFileFrame->md5, MD5_HASH_SIZE);
+
+ ArchiveFileOffset += hf->pFrames[i].CompressedSize;
+ FrameOffset += hf->pFrames[i].FrameSize;
+ FileSize += hf->pFrames[i].FrameSize;
+ }
+
+ // Fill-in the frame count
+ hf->FrameCount = FrameCount;
+ }
+ else
+ nError = GetLastError();
+
+ // Verify the file size
+// assert(FileSize == hf->FileSize);
+// hf->FileSize = FileSize;
+
+ // Free the array
+ CASC_FREE(pFileFrames);
+ }
+ else
+ nError = ERROR_NOT_ENOUGH_MEMORY;
+
+ return nError;
+}
+
+static int EnsureFrameHeadersLoaded(TCascFile * hf)
+{
+ PBLTE_HEADER pBlteHeader;
+ ULONGLONG FileOffset = hf->HeaderOffset;
+ DWORD dwHeaderOffsetFixup = 0;
+ DWORD dwFrameHeaderSize;
+ DWORD dwFrameCount;
+ BYTE HeaderBuffer[sizeof(BLTE_HEADER) + 0x20];
+ int nError = ERROR_SUCCESS;
+
+ // Sanity check
+ assert(hf->pStream != NULL);
+
+ // If the frame headers are not loaded yet, do it
+ if(hf->pFrames == NULL)
+ {
+ // Note that older builds of Heroes of the Storm have entries pointing
+ // to the begin of the BLTE header, which is MD5 + some junk.
+ // Newer versions of HOTS have encoding entries pointing directly to
+ // the BLTE header
+ FileStream_Read(hf->pStream, &FileOffset, HeaderBuffer, sizeof(HeaderBuffer));
+ pBlteHeader = (PBLTE_HEADER)HeaderBuffer;
+
+ // If we don't have the BLTE header right there,
+ // just get the block that is 0x1E bytes later
+ if(pBlteHeader->dwSignature != BLTE_HEADER_SIGNATURE)
+ {
+ memcpy(&HeaderBuffer[0x00], &HeaderBuffer[0x1E], sizeof(BLTE_HEADER));
+ dwHeaderOffsetFixup = 0x1E;
+ }
+
+ // Check for the BLTE header signature
+ if(pBlteHeader->dwSignature != BLTE_HEADER_SIGNATURE)
+ return ERROR_BAD_FORMAT;
+ hf->HeaderOffset += dwHeaderOffsetFixup;
+
+ // Check for a single unit file
+ dwFrameHeaderSize = ConvertBytesToInteger_4(pBlteHeader->HeaderSizeAsBytes);
+ dwFrameCount = (dwFrameHeaderSize != 0) ? ConvertBytesToInteger_3(pBlteHeader->FrameCount) : 1;
+
+ // Allocate the frame array
+ hf->pFrames = CASC_ALLOC(CASC_FILE_FRAME, dwFrameCount);
+ if(hf->pFrames != NULL)
+ {
+ // Save the number of frames
+ hf->FrameCount = dwFrameCount;
+
+ // Either load the frames from the file or supply them on our own
+ if(dwFrameHeaderSize != 0)
+ {
+ if(pBlteHeader->MustBe0F != 0x0F)
+ return ERROR_FILE_CORRUPT;
+
+ hf->FramesOffset = hf->HeaderOffset + sizeof(BLTE_HEADER);
+ nError = LoadFileFrames(hf, dwFrameCount);
+ }
+ else
+ {
+ // Offset of the first frame is right after the file frames
+ hf->FramesOffset = hf->HeaderOffset + sizeof(pBlteHeader->dwSignature) + sizeof(pBlteHeader->HeaderSizeAsBytes);
+
+ hf->pFrames[0].FrameArchiveOffset = hf->FramesOffset;
+ hf->pFrames[0].FrameFileOffset = 0;
+ hf->pFrames[0].CompressedSize = hf->CompressedSize;
+ hf->pFrames[0].FrameSize = hf->FileSize;
+ memset(hf->pFrames[0].md5, 0, MD5_HASH_SIZE);
+ }
+ }
+
+ // Return result
+ return (hf->pFrames != NULL) ? ERROR_SUCCESS : ERROR_FILE_CORRUPT;
+ }
+
+ return ERROR_SUCCESS;
+}
+
+static PCASC_FILE_FRAME FindFileFrame(TCascFile * hf, DWORD FilePointer)
+{
+ PCASC_FILE_FRAME pFrame = hf->pFrames;
+ DWORD FrameBegin;
+ DWORD FrameEnd;
+
+ // Sanity checks
+ assert(hf->pFrames != NULL);
+ assert(hf->FrameCount != 0);
+
+ // Find the frame where to read from
+ for(DWORD i = 0; i < hf->FrameCount; i++, pFrame++)
+ {
+ // Does the read request fit into the current frame?
+ FrameBegin = pFrame->FrameFileOffset;
+ FrameEnd = FrameBegin + pFrame->FrameSize;
+ if(FrameBegin <= FilePointer && FilePointer < FrameEnd)
+ return pFrame;
+ }
+
+ // Not found, sorry
+ return NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Public functions
+
+DWORD WINAPI CascGetFileSize(HANDLE hFile, PDWORD pdwFileSizeHigh)
+{
+ TCascFile * hf;
+
+ CASCLIB_UNUSED(pdwFileSizeHigh);
+
+ // Validate the file handle
+ if((hf = IsValidFileHandle(hFile)) == NULL)
+ {
+ SetLastError(ERROR_INVALID_HANDLE);
+ return CASC_INVALID_SIZE;
+ }
+
+ // Give the file size to the caller
+ if(pdwFileSizeHigh != NULL)
+ *pdwFileSizeHigh = 0;
+ return hf->FileSize;
+}
+
+DWORD WINAPI CascSetFilePointer(HANDLE hFile, LONG lFilePos, LONG * plFilePosHigh, DWORD dwMoveMethod)
+{
+ TCascFile * hf;
+ ULONGLONG FilePosition;
+ ULONGLONG MoveOffset;
+ DWORD dwFilePosHi;
+
+ // If the hFile is not a valid file handle, return an error.
+ hf = IsValidFileHandle(hFile);
+ if(hf == NULL)
+ {
+ SetLastError(ERROR_INVALID_HANDLE);
+ return CASC_INVALID_POS;
+ }
+
+ // Get the relative point where to move from
+ switch(dwMoveMethod)
+ {
+ case FILE_BEGIN:
+ FilePosition = 0;
+ break;
+
+ case FILE_CURRENT:
+ FilePosition = hf->FilePointer;
+ break;
+
+ case FILE_END:
+ FilePosition = hf->FileSize;
+ break;
+
+ default:
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return CASC_INVALID_POS;
+ }
+
+ // Now get the move offset. Note that both values form
+ // a signed 64-bit value (a file pointer can be moved backwards)
+ if(plFilePosHigh != NULL)
+ dwFilePosHi = *plFilePosHigh;
+ else
+ dwFilePosHi = (lFilePos & 0x80000000) ? 0xFFFFFFFF : 0;
+ MoveOffset = MAKE_OFFSET64(dwFilePosHi, lFilePos);
+
+ // Now calculate the new file pointer
+ // Do not allow the file pointer to overflow
+ FilePosition = ((FilePosition + MoveOffset) >= FilePosition) ? (FilePosition + MoveOffset) : 0;
+
+ // CASC files can't be bigger than 4 GB.
+ // We don't allow to go past 4 GB
+ if(FilePosition >> 32)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return CASC_INVALID_POS;
+ }
+
+ // Change the file position
+ hf->FilePointer = (DWORD)FilePosition;
+
+ // Return the new file position
+ if(plFilePosHigh != NULL)
+ *plFilePosHigh = 0;
+ return hf->FilePointer;
+}
+
+bool WINAPI CascReadFile(HANDLE hFile, void * pvBuffer, DWORD dwBytesToRead, PDWORD pdwBytesRead)
+{
+ PCASC_FILE_FRAME pFrame = NULL;
+ ULONGLONG FileOffset;
+ TCascFile * hf;
+ LPBYTE pbBuffer = (LPBYTE)pvBuffer;
+ DWORD dwStartPointer = 0;
+ DWORD dwFilePointer = 0;
+ DWORD dwEndPointer = 0;
+ DWORD cbOutBuffer;
+ int nError = ERROR_SUCCESS;
+
+ // The buffer must be valid
+ if(pvBuffer == NULL)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return false;
+ }
+
+ // Validate the file handle
+ if((hf = IsValidFileHandle(hFile)) == NULL)
+ {
+ SetLastError(ERROR_INVALID_HANDLE);
+ return false;
+ }
+
+ // If the file position is at or beyond end of file, do nothing
+ if(hf->FilePointer >= hf->FileSize)
+ {
+ *pdwBytesRead = 0;
+ return ERROR_SUCCESS;
+ }
+
+ // Make sure we have that data file open
+ if(nError == ERROR_SUCCESS)
+ {
+ nError = EnsureDataStreamIsOpen(hf);
+ }
+
+ // If the file frames are not loaded yet, do it now
+ if(nError == ERROR_SUCCESS)
+ {
+ nError = EnsureFrameHeadersLoaded(hf);
+ }
+
+ // Find the file frame where to read from
+ if(nError == ERROR_SUCCESS)
+ {
+ // Get the frame
+ pFrame = FindFileFrame(hf, hf->FilePointer);
+ if(pFrame == NULL)
+ nError = ERROR_FILE_CORRUPT;
+ }
+
+ // Perform the read
+ if(nError == ERROR_SUCCESS)
+ {
+ // If not enough bytes in the file remaining, cut them
+ dwStartPointer = dwFilePointer = hf->FilePointer;
+ dwEndPointer = dwStartPointer + dwBytesToRead;
+ if(dwEndPointer > hf->FileSize)
+ dwEndPointer = hf->FileSize;
+
+ // Perform block read from each file frame
+ while(dwFilePointer < dwEndPointer)
+ {
+ LPBYTE pbRawData = NULL;
+ DWORD dwFrameStart = pFrame->FrameFileOffset;
+ DWORD dwFrameEnd = pFrame->FrameFileOffset + pFrame->FrameSize;
+
+ // Shall we populate the cache with a new data?
+ if(dwFrameStart != hf->CacheStart || hf->CacheEnd != dwFrameEnd)
+ {
+ // Shall we reallocate the cache buffer?
+ if(pFrame->FrameSize > hf->cbFileCache)
+ {
+ if(hf->pbFileCache != NULL)
+ CASC_FREE(hf->pbFileCache);
+
+ hf->pbFileCache = CASC_ALLOC(BYTE, pFrame->FrameSize);
+ hf->cbFileCache = pFrame->FrameSize;
+ }
+
+ // We also need to allocate buffer for the raw data
+ pbRawData = CASC_ALLOC(BYTE, pFrame->CompressedSize);
+ if(pbRawData == NULL)
+ {
+ nError = ERROR_NOT_ENOUGH_MEMORY;
+ break;
+ }
+
+ // Load the raw file data to memory
+ FileOffset = pFrame->FrameArchiveOffset;
+ if(!FileStream_Read(hf->pStream, &FileOffset, pbRawData, pFrame->CompressedSize))
+ {
+ CASC_FREE(pbRawData);
+ nError = GetLastError();
+ break;
+ }
+
+ // Verify the block MD5
+ if(IsValidMD5(pFrame->md5) && !VerifyDataBlockHash(pbRawData, pFrame->CompressedSize, pFrame->md5))
+ {
+ CASC_FREE(pbRawData);
+ nError = ERROR_FILE_CORRUPT;
+ break;
+ }
+
+ // Decompress the file frame
+ cbOutBuffer = pFrame->FrameSize;
+ nError = CascDecompress(hf->pbFileCache, &cbOutBuffer, pbRawData, pFrame->CompressedSize);
+ if(nError != ERROR_SUCCESS || cbOutBuffer != pFrame->FrameSize)
+ {
+ CASC_FREE(pbRawData);
+ nError = ERROR_FILE_CORRUPT;
+ break;
+ }
+
+ // Set the start and end of the cache
+ hf->CacheStart = dwFrameStart;
+ hf->CacheEnd = dwFrameEnd;
+
+ // Free the decompress buffer, if needed
+ CASC_FREE(pbRawData);
+ }
+
+ // Copy the decompressed data
+ if(dwFrameEnd > dwEndPointer)
+ dwFrameEnd = dwEndPointer;
+ memcpy(pbBuffer, hf->pbFileCache + (dwFilePointer - dwFrameStart), (dwFrameEnd - dwFilePointer));
+ pbBuffer += (dwFrameEnd - dwFilePointer);
+
+ // Move pointers
+ dwFilePointer = dwFrameEnd;
+ pFrame++;
+ }
+ }
+
+ // Update the file position
+ if(nError == ERROR_SUCCESS)
+ {
+ if(pdwBytesRead != NULL)
+ *pdwBytesRead = (dwFilePointer - dwStartPointer);
+ hf->FilePointer = dwFilePointer;
+ }
+
+ if(nError != ERROR_SUCCESS)
+ SetLastError(nError);
+ return (nError == ERROR_SUCCESS);
+}
+
diff --git a/dep/CascLib/src/common/Common.cpp b/dep/CascLib/src/common/Common.cpp
new file mode 100644
index 00000000000..d81c1b6fd89
--- /dev/null
+++ b/dep/CascLib/src/common/Common.cpp
@@ -0,0 +1,672 @@
+/*****************************************************************************/
+/* CascCommon.cpp Copyright (c) Ladislav Zezula 2014 */
+/*---------------------------------------------------------------------------*/
+/* Common functions for CascLib */
+/*---------------------------------------------------------------------------*/
+/* Date Ver Who Comment */
+/* -------- ---- --- ------- */
+/* 29.04.14 1.00 Lad The first version of CascCommon.cpp */
+/*****************************************************************************/
+
+#define __CASCLIB_SELF__
+#include "../CascLib.h"
+#include "../CascCommon.h"
+
+//-----------------------------------------------------------------------------
+// Conversion to uppercase/lowercase
+
+// Converts ASCII characters to lowercase
+// Converts slash (0x2F) to backslash (0x5C)
+unsigned char AsciiToLowerTable[256] =
+{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x5C,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
+ 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
+ 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
+ 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
+ 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
+ 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
+ 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
+ 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
+};
+
+// Converts ASCII characters to uppercase
+// Converts slash (0x2F) to backslash (0x5C)
+unsigned char AsciiToUpperTable[256] =
+{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x5C,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
+ 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
+ 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
+ 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
+ 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
+ 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
+ 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
+ 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
+};
+
+unsigned char IntToHexChar[] = "0123456789abcdef";
+
+//-----------------------------------------------------------------------------
+// Support for memory reallocation
+
+#if defined(_MSC_VER) && defined(_DEBUG)
+void * DbgRealloc(void * ptr, size_t nSize)
+{
+ // HeapReAlloc does not support NULL as previous block
+ if(ptr == NULL)
+ return HeapAlloc(GetProcessHeap, 0, nSize);
+
+ return HeapReAlloc(GetProcessHeap(), 0, ptr, nSize);
+}
+#endif
+
+//-----------------------------------------------------------------------------
+// GetLastError/SetLastError support for non-Windows platform
+
+#ifndef PLATFORM_WINDOWS
+static int nLastError = ERROR_SUCCESS;
+
+int GetLastError()
+{
+ return nLastError;
+}
+
+void SetLastError(int nError)
+{
+ nLastError = nError;
+}
+#endif
+
+//-----------------------------------------------------------------------------
+// String manipulation
+
+void CopyString(char * szTarget, const char * szSource, size_t cchLength)
+{
+ memcpy(szTarget, szSource, cchLength);
+ szTarget[cchLength] = 0;
+}
+
+void CopyString(wchar_t * szTarget, const char * szSource, size_t cchLength)
+{
+ mbstowcs(szTarget, szSource, cchLength);
+ szTarget[cchLength] = 0;
+}
+
+void CopyString(char * szTarget, const wchar_t * szSource, size_t cchLength)
+{
+ wcstombs(szTarget, szSource, cchLength);
+ szTarget[cchLength] = 0;
+}
+
+char * NewStr(const char * szString, size_t nCharsToReserve)
+{
+ char * szNewString = NULL;
+ size_t nLength;
+
+ if(szString != NULL)
+ {
+ nLength = strlen(szString);
+ szNewString = CASC_ALLOC(char, nLength + nCharsToReserve + 1);
+ if(szNewString != NULL)
+ {
+ memcpy(szNewString, szString, nLength);
+ szNewString[nLength] = 0;
+ }
+ }
+
+ return szNewString;
+}
+
+wchar_t * NewStr(const wchar_t * szString, size_t nCharsToReserve)
+{
+ wchar_t * szNewString = NULL;
+ size_t nLength;
+
+ if(szString != NULL)
+ {
+ nLength = wcslen(szString);
+ szNewString = CASC_ALLOC(wchar_t, nLength + nCharsToReserve + 1);
+ if(szNewString != NULL)
+ {
+ memcpy(szNewString, szString, nLength * sizeof(wchar_t));
+ szNewString[nLength] = 0;
+ }
+ }
+
+ return szNewString;
+}
+
+TCHAR * NewStrFromAnsi(LPBYTE pbStringBegin, LPBYTE pbStringEnd)
+{
+ TCHAR * szNewString = NULL;
+ TCHAR * szStringPtr = NULL;
+ size_t nLength = (size_t)(pbStringEnd - pbStringBegin);
+
+ if(pbStringEnd > pbStringBegin)
+ {
+ szNewString = szStringPtr = CASC_ALLOC(TCHAR, nLength + 1);
+ if(szNewString != NULL)
+ {
+ CopyString(szStringPtr, (const char *)pbStringBegin, nLength);
+ szStringPtr[nLength] = 0;
+ }
+ }
+
+ return szNewString;
+}
+
+TCHAR * CombinePath(const TCHAR * szDirectory, const TCHAR * szSubDir)
+{
+ TCHAR * szFullPath = NULL;
+ TCHAR * szPathPtr;
+ size_t nLength1 = 0;
+ size_t nLength2 = 0;
+
+ // Calculate lengths of each part
+ if(szDirectory != NULL)
+ {
+ // Get the length of the directory
+ nLength1 = _tcslen(szDirectory);
+
+ // Cut all ending backslashes
+ while(nLength1 > 0 && szDirectory[nLength1 - 1] == _T(PATH_SEPARATOR))
+ nLength1--;
+ }
+
+ if(szSubDir != NULL)
+ {
+ // Cut all leading backslashes
+ while(szSubDir[0] == _T(PATH_SEPARATOR))
+ szSubDir++;
+
+ // Get the length of the subdir
+ nLength2 = _tcslen(szSubDir);
+
+ // Cut all ending backslashes
+ while(nLength2 > 0 && szSubDir[nLength2 - 1] == _T(PATH_SEPARATOR))
+ nLength2--;
+ }
+
+ // Allocate space for the full path
+ szFullPath = szPathPtr = CASC_ALLOC(TCHAR, nLength1 + nLength2 + 2);
+ if(szFullPath != NULL)
+ {
+ // Copy the directory
+ if(szDirectory != NULL && nLength1 != 0)
+ {
+ memcpy(szPathPtr, szDirectory, (nLength1 * sizeof(TCHAR)));
+ szPathPtr += nLength1;
+ }
+
+ // Copy the sub-directory
+ if(szSubDir != NULL && nLength2 != 0)
+ {
+ // Append backslash to the previous one
+ if(szPathPtr > szFullPath)
+ *szPathPtr++ = _T(PATH_SEPARATOR);
+
+ // Copy the string
+ memcpy(szPathPtr, szSubDir, (nLength2 * sizeof(TCHAR)));
+ szPathPtr += nLength2;
+ }
+
+ // Terminate the string
+ szPathPtr[0] = 0;
+ }
+
+ return szFullPath;
+}
+
+void NormalizeFileName_UpperBkSlash(char * szFileName)
+{
+ // Normalize the file name: ToLower + BackSlashToSlash
+ for(size_t i = 0; szFileName[i] != 0; i++)
+ szFileName[i] = AsciiToUpperTable[szFileName[i]];
+}
+
+void NormalizeFileName_LowerSlash(char * szFileName)
+{
+ // Normalize the file name: ToLower + BackSlashToSlash
+ for(size_t i = 0; szFileName[i] != 0; i++)
+ {
+ szFileName[i] = AsciiToLowerTable[szFileName[i]];
+ szFileName[i] = (szFileName[i] != '\\') ? szFileName[i] : '/';
+ }
+}
+
+int ConvertDigitToInt32(const TCHAR * szString, PDWORD PtrValue)
+{
+ BYTE Digit;
+
+ Digit = (BYTE)(AsciiToUpperTable[szString[0]] - _T('0'));
+ if(Digit > 9)
+ Digit -= 'A' - '9' - 1;
+
+ PtrValue[0] = Digit;
+ return (Digit > 0x0F) ? ERROR_BAD_FORMAT : ERROR_SUCCESS;
+}
+
+int ConvertStringToInt32(const TCHAR * szString, size_t nMaxDigits, PDWORD PtrValue)
+{
+ // The number of digits must be even
+ assert((nMaxDigits & 0x01) == 0);
+ assert(nMaxDigits <= 8);
+
+ // Prepare the variables
+ PtrValue[0] = 0;
+ nMaxDigits >>= 1;
+
+ // Convert the string up to the number of digits
+ for(size_t i = 0; i < nMaxDigits; i++)
+ {
+ BYTE DigitOne;
+ BYTE DigitTwo;
+
+ DigitOne = (BYTE)(AsciiToUpperTable[szString[0]] - _T('0'));
+ if(DigitOne > 9)
+ DigitOne -= 'A' - '9' - 1;
+
+ DigitTwo = (BYTE)(AsciiToUpperTable[szString[1]] - _T('0'));
+ if(DigitTwo > 9)
+ DigitTwo -= 'A' - '9' - 1;
+
+ if(DigitOne > 0x0F || DigitTwo > 0x0F)
+ return ERROR_BAD_FORMAT;
+
+ PtrValue[0] = (PtrValue[0] << 0x08) | (DigitOne << 0x04) | DigitTwo;
+ szString += 2;
+ }
+
+ return ERROR_SUCCESS;
+}
+
+char * StringFromBinary(LPBYTE pbBinary, size_t cbBinary, char * szBuffer)
+{
+ char * szSaveBuffer = szBuffer;
+
+ // Convert the string to the array of MD5
+ // Copy the blob data as text
+ for(size_t i = 0; i < cbBinary; i++)
+ {
+ *szBuffer++ = IntToHexChar[pbBinary[0] >> 0x04];
+ *szBuffer++ = IntToHexChar[pbBinary[0] & 0x0F];
+ pbBinary++;
+ }
+
+ // Terminate the string
+ *szBuffer = 0;
+ return szSaveBuffer;
+}
+
+//-----------------------------------------------------------------------------
+// File name utilities
+
+const wchar_t * GetPlainFileName(const wchar_t * szFileName)
+{
+ const wchar_t * szPlainName = szFileName;
+
+ while(*szFileName != 0)
+ {
+ if(*szFileName == '\\' || *szFileName == '/')
+ szPlainName = szFileName + 1;
+ szFileName++;
+ }
+
+ return szPlainName;
+}
+
+const char * GetPlainFileName(const char * szFileName)
+{
+ const char * szPlainName = szFileName;
+
+ while(*szFileName != 0)
+ {
+ if(*szFileName == '\\' || *szFileName == '/')
+ szPlainName = szFileName + 1;
+ szFileName++;
+ }
+
+ return szPlainName;
+}
+
+bool CheckWildCard(const char * szString, const char * szWildCard)
+{
+ const char * szSubString;
+ int nSubStringLength;
+ int nMatchCount = 0;
+
+ // When the mask is empty, it never matches
+ if(szWildCard == NULL || *szWildCard == 0)
+ return false;
+
+ // If the wildcard contains just "*", then it always matches
+ if(szWildCard[0] == '*' && szWildCard[1] == 0)
+ return true;
+
+ // Do normal test
+ for(;;)
+ {
+ // If there is '?' in the wildcard, we skip one char
+ while(*szWildCard == '?')
+ {
+ szWildCard++;
+ szString++;
+ }
+
+ // If there is '*', means zero or more chars. We have to
+ // find the sequence after '*'
+ if(*szWildCard == '*')
+ {
+ // More stars is equal to one star
+ while(*szWildCard == '*' || *szWildCard == '?')
+ szWildCard++;
+
+ // If we found end of the wildcard, it's a match
+ if(*szWildCard == 0)
+ return true;
+
+ // Determine the length of the substring in szWildCard
+ szSubString = szWildCard;
+ while(*szSubString != 0 && *szSubString != '?' && *szSubString != '*')
+ szSubString++;
+ nSubStringLength = (int)(szSubString - szWildCard);
+ nMatchCount = 0;
+
+ // Now we have to find a substring in szString,
+ // that matches the substring in szWildCard
+ while(*szString != 0)
+ {
+ // Calculate match count
+ while(nMatchCount < nSubStringLength)
+ {
+ if(AsciiToUpperTable[(BYTE)szString[nMatchCount]] != AsciiToUpperTable[(BYTE)szWildCard[nMatchCount]])
+ break;
+ if(szString[nMatchCount] == 0)
+ break;
+ nMatchCount++;
+ }
+
+ // If the match count has reached substring length, we found a match
+ if(nMatchCount == nSubStringLength)
+ {
+ szWildCard += nMatchCount;
+ szString += nMatchCount;
+ break;
+ }
+
+ // No match, move to the next char in szString
+ nMatchCount = 0;
+ szString++;
+ }
+ }
+ else
+ {
+ // If we came to the end of the string, compare it to the wildcard
+ if(AsciiToUpperTable[(BYTE)*szString] != AsciiToUpperTable[(BYTE)*szWildCard])
+ return false;
+
+ // If we arrived to the end of the string, it's a match
+ if(*szString == 0)
+ return true;
+
+ // Otherwise, continue in comparing
+ szWildCard++;
+ szString++;
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Hashing functions
+
+bool IsValidMD5(LPBYTE pbMd5)
+{
+ BYTE BitSummary = 0;
+
+ // The MD5 is considered invalid of it is zeroed
+ BitSummary |= pbMd5[0x00] | pbMd5[0x01] | pbMd5[0x02] | pbMd5[0x03] | pbMd5[0x04] | pbMd5[0x05] | pbMd5[0x06] | pbMd5[0x07];
+ BitSummary |= pbMd5[0x08] | pbMd5[0x09] | pbMd5[0x0A] | pbMd5[0x0B] | pbMd5[0x0C] | pbMd5[0x0D] | pbMd5[0x0E] | pbMd5[0x0F];
+ return (BitSummary != 0);
+}
+
+bool VerifyDataBlockHash(void * pvDataBlock, DWORD cbDataBlock, LPBYTE expected_md5)
+{
+ hash_state md5_state;
+ BYTE md5_digest[MD5_HASH_SIZE];
+
+ // Don't verify the block if the MD5 is not valid.
+ if(!IsValidMD5(expected_md5))
+ return true;
+
+ // Calculate the MD5 of the data block
+ md5_init(&md5_state);
+ md5_process(&md5_state, (unsigned char *)pvDataBlock, cbDataBlock);
+ md5_done(&md5_state, md5_digest);
+
+ // Does the MD5's match?
+ return (memcmp(md5_digest, expected_md5, MD5_HASH_SIZE) == 0);
+}
+
+void CalculateDataBlockHash(void * pvDataBlock, DWORD cbDataBlock, LPBYTE md5_hash)
+{
+ hash_state md5_state;
+
+ md5_init(&md5_state);
+ md5_process(&md5_state, (unsigned char *)pvDataBlock, cbDataBlock);
+ md5_done(&md5_state, md5_hash);
+}
+
+//-----------------------------------------------------------------------------
+// We have our own qsort implementation, optimized for using array of pointers
+
+#define STKSIZ (8*sizeof(void*) - 2)
+
+#define SWAP_ENTRIES(index1, index2) \
+{ \
+ temp = base[index1]; \
+ base[index1] = base[index2]; \
+ base[index2] = temp; \
+}
+
+void qsort_pointer_array(void ** base, size_t num, int (*compare)(const void *, const void *, const void *), const void * context)
+{
+ size_t lo, hi; /* ends of sub-array currently sorting */
+ size_t mid; /* points to middle of subarray */
+ size_t loguy, higuy; /* traveling pointers for partition step */
+ size_t size; /* size of the sub-array */
+ size_t lostk[STKSIZ], histk[STKSIZ];
+ void * temp;
+ int stkptr; /* stack for saving sub-array to be processed */
+
+ /* validation section */
+ assert(base != NULL);
+ assert(compare != NULL);
+
+ if (num < 2)
+ return; /* nothing to do */
+
+ stkptr = 0; /* initialize stack */
+
+ lo = 0;
+ hi = (num-1); /* initialize limits */
+
+ /* this entry point is for pseudo-recursion calling: setting
+ lo and hi and jumping to here is like recursion, but stkptr is
+ preserved, locals aren't, so we preserve stuff on the stack */
+recurse:
+
+ size = (hi - lo) + 1; /* number of el's to sort */
+
+ /* First we pick a partitioning element. The efficiency of the
+ algorithm demands that we find one that is approximately the median
+ of the values, but also that we select one fast. We choose the
+ median of the first, middle, and last elements, to avoid bad
+ performance in the face of already sorted data, or data that is made
+ up of multiple sorted runs appended together. Testing shows that a
+ median-of-three algorithm provides better performance than simply
+ picking the middle element for the latter case. */
+
+ mid = lo + (size / 2); /* find middle element */
+
+ /* Sort the first, middle, last elements into order */
+ if (compare(context, base[lo], base[mid]) > 0) {
+ SWAP_ENTRIES(lo, mid);
+ }
+ if (compare(context, base[lo], base[hi]) > 0) {
+ SWAP_ENTRIES(lo, hi);
+ }
+ if (compare(context, base[mid], base[hi]) > 0) {
+ SWAP_ENTRIES(mid, hi);
+ }
+
+ /* We now wish to partition the array into three pieces, one consisting
+ of elements <= partition element, one of elements equal to the
+ partition element, and one of elements > than it. This is done
+ below; comments indicate conditions established at every step. */
+
+ loguy = lo;
+ higuy = hi;
+
+ /* Note that higuy decreases and loguy increases on every iteration,
+ so loop must terminate. */
+ for (;;) {
+ /* lo <= loguy < hi, lo < higuy <= hi,
+ A[i] <= A[mid] for lo <= i <= loguy,
+ A[i] > A[mid] for higuy <= i < hi,
+ A[hi] >= A[mid] */
+
+ /* The doubled loop is to avoid calling comp(mid,mid), since some
+ existing comparison funcs don't work when passed the same
+ value for both pointers. */
+
+ if (mid > loguy) {
+ do {
+ loguy ++;
+ } while (loguy < mid && compare(context, base[loguy], base[mid]) <= 0);
+ }
+ if (mid <= loguy) {
+ do {
+ loguy ++;
+ } while (loguy <= hi && compare(context, base[loguy], base[mid]) <= 0);
+ }
+
+ /* lo < loguy <= hi+1, A[i] <= A[mid] for lo <= i < loguy,
+ either loguy > hi or A[loguy] > A[mid] */
+
+ do {
+ higuy --;
+ } while (higuy > mid && compare(context, base[higuy], base[mid]) > 0);
+
+ /* lo <= higuy < hi, A[i] > A[mid] for higuy < i < hi,
+ either higuy == lo or A[higuy] <= A[mid] */
+
+ if (higuy < loguy)
+ break;
+
+ /* if loguy > hi or higuy == lo, then we would have exited, so
+ A[loguy] > A[mid], A[higuy] <= A[mid],
+ loguy <= hi, higuy > lo */
+
+ SWAP_ENTRIES(loguy, higuy);
+
+ /* If the partition element was moved, follow it. Only need
+ to check for mid == higuy, since before the swap,
+ A[loguy] > A[mid] implies loguy != mid. */
+
+ if (mid == higuy)
+ mid = loguy;
+
+ /* A[loguy] <= A[mid], A[higuy] > A[mid]; so condition at top
+ of loop is re-established */
+ }
+
+ /* A[i] <= A[mid] for lo <= i < loguy,
+ A[i] > A[mid] for higuy < i < hi,
+ A[hi] >= A[mid]
+ higuy < loguy
+ implying:
+ higuy == loguy-1
+ or higuy == hi - 1, loguy == hi + 1, A[hi] == A[mid] */
+
+ /* Find adjacent elements equal to the partition element. The
+ doubled loop is to avoid calling comp(mid,mid), since some
+ existing comparison funcs don't work when passed the same value
+ for both pointers. */
+
+ higuy ++;
+ if (mid < higuy) {
+ do {
+ higuy --;
+ } while (higuy > mid && compare(context, base[higuy], base[mid]) == 0);
+ }
+ if (mid >= higuy) {
+ do {
+ higuy --;
+ } while (higuy > lo && compare(context, base[higuy], base[mid]) == 0);
+ }
+
+ /* OK, now we have the following:
+ higuy < loguy
+ lo <= higuy <= hi
+ A[i] <= A[mid] for lo <= i <= higuy
+ A[i] == A[mid] for higuy < i < loguy
+ A[i] > A[mid] for loguy <= i < hi
+ A[hi] >= A[mid] */
+
+ /* We've finished the partition, now we want to sort the subarrays
+ [lo, higuy] and [loguy, hi].
+ We do the smaller one first to minimize stack usage.
+ We only sort arrays of length 2 or more.*/
+
+ if ( higuy - lo >= hi - loguy ) {
+ if (lo < higuy) {
+ lostk[stkptr] = lo;
+ histk[stkptr] = higuy;
+ ++stkptr;
+ } /* save big recursion for later */
+
+ if (loguy < hi) {
+ lo = loguy;
+ goto recurse; /* do small recursion */
+ }
+ }
+ else {
+ if (loguy < hi) {
+ lostk[stkptr] = loguy;
+ histk[stkptr] = hi;
+ ++stkptr; /* save big recursion for later */
+ }
+
+ if (lo < higuy) {
+ hi = higuy;
+ goto recurse; /* do small recursion */
+ }
+ }
+
+ /* We have sorted the array, except for any pending sorts on the stack.
+ Check if there are any, and do them. */
+
+ --stkptr;
+ if (stkptr >= 0) {
+ lo = lostk[stkptr];
+ hi = histk[stkptr];
+ goto recurse; /* pop subarray from stack */
+ }
+ else
+ return; /* all subarrays done */
+}
diff --git a/dep/CascLib/src/common/Common.h b/dep/CascLib/src/common/Common.h
new file mode 100644
index 00000000000..eb192fd50ca
--- /dev/null
+++ b/dep/CascLib/src/common/Common.h
@@ -0,0 +1,98 @@
+/*****************************************************************************/
+/* CascCommon.h Copyright (c) Ladislav Zezula 2014 */
+/*---------------------------------------------------------------------------*/
+/* Common functions for CascLib */
+/*---------------------------------------------------------------------------*/
+/* Date Ver Who Comment */
+/* -------- ---- --- ------- */
+/* 29.04.14 1.00 Lad The first version of CascCommon.h */
+/*****************************************************************************/
+
+#ifndef __COMMON_H__
+#define __COMMON_H__
+
+//-----------------------------------------------------------------------------
+// Common macros
+
+// Macro for building 64-bit file offset from two 32-bit
+#define MAKE_OFFSET64(hi, lo) (((ULONGLONG)hi << 32) | (ULONGLONG)lo)
+
+#ifndef ALIGN_TO_SIZE
+#define ALIGN_TO_SIZE(x, a) (((x) + (a)-1) & ~((a)-1))
+#endif
+
+//-----------------------------------------------------------------------------
+// Conversion tables
+
+extern unsigned char AsciiToLowerTable[256];
+extern unsigned char AsciiToUpperTable[256];
+extern unsigned char IntToHexChar[];
+
+//-----------------------------------------------------------------------------
+// Memory management helper
+
+#if defined(_MSC_VER) && defined(_DEBUG)
+void * DbgRealloc(void * ptr, size_t nSize);
+#endif
+
+//-----------------------------------------------------------------------------
+// GetLastError/SetLastError support for non-Windows platform
+
+#ifndef PLATFORM_WINDOWS
+int GetLastError();
+void SetLastError(int nError);
+#endif // PLATFORM_WINDOWS
+
+//-----------------------------------------------------------------------------
+// String manipulation
+
+void CopyString(char * szTarget, const char * szSource, size_t cchLength);
+void CopyString(wchar_t * szTarget, const char * szSource, size_t cchLength);
+void CopyString(char * szTarget, const wchar_t * szSource, size_t cchLength);
+
+char * NewStr(const char * szString, size_t nCharsToReserve);
+wchar_t * NewStr(const wchar_t * szString, size_t nCharsToReserve);
+
+TCHAR * NewStrFromAnsi(LPBYTE pbStringBegin, LPBYTE pbStringEnd);
+
+TCHAR * CombinePath(const TCHAR * szPath, const TCHAR * szSubDir);
+
+void NormalizeFileName_UpperBkSlash(char * szFileName);
+void NormalizeFileName_LowerSlash(char * szFileName);
+
+int ConvertDigitToInt32(const TCHAR * szString, PDWORD PtrValue);
+int ConvertStringToInt32(const TCHAR * szString, size_t nMaxDigits, PDWORD PtrValue);
+char * StringFromBinary(LPBYTE pbBinary, size_t cbBinary, char * szBuffer);
+
+//-----------------------------------------------------------------------------
+// File name utilities
+
+bool CheckWildCard(const char * szString, const char * szWildCard);
+const wchar_t * GetPlainFileName(const wchar_t * szFileName);
+const char * GetPlainFileName(const char * szFileName);
+
+//-----------------------------------------------------------------------------
+// Hashing functions
+
+ULONGLONG HashStringJenkins(const char * szFileName);
+
+bool IsValidMD5(LPBYTE pbMd5);
+void CalculateDataBlockHash(void * pvDataBlock, DWORD cbDataBlock, LPBYTE md5_hash);
+bool VerifyDataBlockHash(void * pvDataBlock, DWORD cbDataBlock, LPBYTE expected_md5);
+
+//-----------------------------------------------------------------------------
+// Scanning a directory
+
+typedef bool (*INDEX_FILE_FOUND)(const TCHAR * szFileName, PDWORD IndexArray, PDWORD OldIndexArray, void * pvContext);
+
+bool DirectoryExists(const TCHAR * szDirectory);
+
+int ScanIndexDirectory(
+ const TCHAR * szIndexPath,
+ INDEX_FILE_FOUND pfnOnFileFound,
+ PDWORD IndexArray,
+ PDWORD OldIndexArray,
+ void * pvContext
+ );
+
+#endif // __COMMON_H__
diff --git a/dep/CascLib/src/common/Directory.cpp b/dep/CascLib/src/common/Directory.cpp
new file mode 100644
index 00000000000..cd02db19be3
--- /dev/null
+++ b/dep/CascLib/src/common/Directory.cpp
@@ -0,0 +1,102 @@
+/*****************************************************************************/
+/* Directory.cpp Copyright (c) Ladislav Zezula 2014 */
+/*---------------------------------------------------------------------------*/
+/* System-dependent directory functions for CascLib */
+/*---------------------------------------------------------------------------*/
+/* Date Ver Who Comment */
+/* -------- ---- --- ------- */
+/* 29.04.14 1.00 Lad The first version of Directory.cpp */
+/*****************************************************************************/
+
+#define __CASCLIB_SELF__
+#include "../CascLib.h"
+#include "../CascCommon.h"
+
+//-----------------------------------------------------------------------------
+// Public functions
+
+bool DirectoryExists(const TCHAR * szDirectory)
+{
+#ifdef PLATFORM_WINDOWS
+
+ DWORD dwAttributes = GetFileAttributes(szDirectory);
+ if((dwAttributes != INVALID_FILE_ATTRIBUTES) && (dwAttributes & FILE_ATTRIBUTE_DIRECTORY))
+ return true;
+
+#else // PLATFORM_WINDOWS
+
+ DIR * dir = opendir(szDirectory);
+
+ if(dir != NULL)
+ {
+ closedir(dir);
+ return true;
+ }
+
+#endif
+
+ return false;
+}
+
+int ScanIndexDirectory(
+ const TCHAR * szIndexPath,
+ INDEX_FILE_FOUND pfnOnFileFound,
+ PDWORD MainIndexes,
+ PDWORD OldIndexArray,
+ void * pvContext)
+{
+#ifdef PLATFORM_WINDOWS
+
+ WIN32_FIND_DATA wf;
+ TCHAR * szSearchMask;
+ HANDLE hFind;
+
+ // Prepare the search mask
+ szSearchMask = CombinePath(szIndexPath, _T("*"));
+ if(szSearchMask == NULL)
+ return ERROR_NOT_ENOUGH_MEMORY;
+
+ // Prepare directory search
+ hFind = FindFirstFile(szSearchMask, &wf);
+ if(hFind != INVALID_HANDLE_VALUE)
+ {
+ // Skip the first file as it's always just "." or ".."
+ while(FindNextFile(hFind, &wf))
+ {
+ // If the found object is a file, pass it to the handler
+ if(!(wf.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
+ {
+ // Let the callback scan the file name
+ pfnOnFileFound(wf.cFileName, MainIndexes, OldIndexArray, pvContext);
+ }
+ }
+
+ // Close the search handle
+ FindClose(hFind);
+ }
+
+ CASC_FREE(szSearchMask);
+
+#else // PLATFORM_WINDOWS
+
+ struct dirent * dir_entry;
+ DIR * dir;
+
+ dir = opendir(szIndexPath);
+ if(dir != NULL)
+ {
+ while((dir_entry = readdir(dir)) != NULL)
+ {
+ if(dir_entry->d_type != DT_DIR)
+ {
+ pfnOnFileFound(dir_entry->d_name, MainIndexes, OldIndexArray, pvContext);
+ }
+ }
+
+ closedir(dir);
+ }
+
+#endif
+
+ return ERROR_SUCCESS;
+}
diff --git a/dep/CascLib/src/common/FileStream.cpp b/dep/CascLib/src/common/FileStream.cpp
new file mode 100644
index 00000000000..09ac47bd095
--- /dev/null
+++ b/dep/CascLib/src/common/FileStream.cpp
@@ -0,0 +1,2721 @@
+/*****************************************************************************/
+/* FileStream.cpp Copyright (c) Ladislav Zezula 2010 */
+/*---------------------------------------------------------------------------*/
+/* File stream support for CascLib */
+/* */
+/* Windows support: Written by Ladislav Zezula */
+/* Mac support: Written by Sam Wilkins */
+/* Linux support: Written by Sam Wilkins and Ivan Komissarov */
+/* Big-endian: Written & debugged by Sam Wilkins */
+/*---------------------------------------------------------------------------*/
+/* Date Ver Who Comment */
+/* -------- ---- --- ------- */
+/* 28.04.14 1.00 Lad Copied from StormLib */
+/*****************************************************************************/
+
+#define __CASCLIB_SELF__
+#include "../CascLib.h"
+#include "../CascCommon.h"
+#include "FileStream.h"
+
+#ifdef _MSC_VER
+#pragma comment(lib, "wininet.lib") // Internet functions for HTTP stream
+#pragma warning(disable: 4800) // 'BOOL' : forcing value to bool 'true' or 'false' (performance warning)
+#endif
+
+//-----------------------------------------------------------------------------
+// Local functions - platform-specific functions
+
+static DWORD StringToInt(const char * szString)
+{
+ DWORD dwValue = 0;
+
+ while('0' <= szString[0] && szString[0] <= '9')
+ {
+ dwValue = (dwValue * 10) + (szString[0] - '9');
+ szString++;
+ }
+
+ return dwValue;
+}
+
+//-----------------------------------------------------------------------------
+// Dummy init function
+
+static void BaseNone_Init(TFileStream *)
+{
+ // Nothing here
+}
+
+//-----------------------------------------------------------------------------
+// Local functions - base file support
+
+static bool BaseFile_Create(TFileStream * pStream)
+{
+#ifdef PLATFORM_WINDOWS
+ {
+ DWORD dwWriteShare = (pStream->dwFlags & STREAM_FLAG_WRITE_SHARE) ? FILE_SHARE_WRITE : 0;
+
+ pStream->Base.File.hFile = CreateFile(pStream->szFileName,
+ GENERIC_READ | GENERIC_WRITE,
+ dwWriteShare | FILE_SHARE_READ,
+ NULL,
+ CREATE_ALWAYS,
+ 0,
+ NULL);
+ if(pStream->Base.File.hFile == INVALID_HANDLE_VALUE)
+ return false;
+ }
+#endif
+
+#if defined(PLATFORM_MAC) || defined(PLATFORM_LINUX)
+ {
+ intptr_t handle;
+
+ handle = open(pStream->szFileName, O_RDWR | O_CREAT | O_TRUNC | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+ if(handle == -1)
+ {
+ SetLastError(errno);
+ return false;
+ }
+
+ pStream->Base.File.hFile = (HANDLE)handle;
+ }
+#endif
+
+ // Reset the file size and position
+ pStream->Base.File.FileSize = 0;
+ pStream->Base.File.FilePos = 0;
+ return true;
+}
+
+static bool BaseFile_Open(TFileStream * pStream, const TCHAR * szFileName, DWORD dwStreamFlags)
+{
+#ifdef PLATFORM_WINDOWS
+ {
+ ULARGE_INTEGER FileSize;
+ DWORD dwWriteAccess = (dwStreamFlags & STREAM_FLAG_READ_ONLY) ? 0 : FILE_WRITE_DATA | FILE_APPEND_DATA | FILE_WRITE_ATTRIBUTES;
+ DWORD dwWriteShare = (dwStreamFlags & STREAM_FLAG_WRITE_SHARE) ? FILE_SHARE_WRITE : 0;
+
+ // Open the file
+ pStream->Base.File.hFile = CreateFile(szFileName,
+ FILE_READ_DATA | FILE_READ_ATTRIBUTES | dwWriteAccess,
+ FILE_SHARE_READ | dwWriteShare,
+ NULL,
+ OPEN_EXISTING,
+ 0,
+ NULL);
+ if(pStream->Base.File.hFile == INVALID_HANDLE_VALUE)
+ return false;
+
+ // Query the file size
+ FileSize.LowPart = GetFileSize(pStream->Base.File.hFile, &FileSize.HighPart);
+ pStream->Base.File.FileSize = FileSize.QuadPart;
+
+ // Query last write time
+ GetFileTime(pStream->Base.File.hFile, NULL, NULL, (LPFILETIME)&pStream->Base.File.FileTime);
+ }
+#endif
+
+#if defined(PLATFORM_MAC) || defined(PLATFORM_LINUX)
+ {
+ struct stat64 fileinfo;
+ int oflag = (dwStreamFlags & STREAM_FLAG_READ_ONLY) ? O_RDONLY : O_RDWR;
+ intptr_t handle;
+
+ // Open the file
+ handle = open(szFileName, oflag | O_LARGEFILE);
+ if(handle == -1)
+ {
+ SetLastError(errno);
+ return false;
+ }
+
+ // Get the file size
+ if(fstat64(handle, &fileinfo) == -1)
+ {
+ SetLastError(errno);
+ return false;
+ }
+
+ // time_t is number of seconds since 1.1.1970, UTC.
+ // 1 second = 10000000 (decimal) in FILETIME
+ // Set the start to 1.1.1970 00:00:00
+ pStream->Base.File.FileTime = 0x019DB1DED53E8000ULL + (10000000 * fileinfo.st_mtime);
+ pStream->Base.File.FileSize = (ULONGLONG)fileinfo.st_size;
+ pStream->Base.File.hFile = (HANDLE)handle;
+ }
+#endif
+
+ // Reset the file position
+ pStream->Base.File.FilePos = 0;
+ return true;
+}
+
+static bool BaseFile_Read(
+ TFileStream * pStream, // Pointer to an open stream
+ ULONGLONG * pByteOffset, // Pointer to file byte offset. If NULL, it reads from the current position
+ void * pvBuffer, // Pointer to data to be read
+ DWORD dwBytesToRead) // Number of bytes to read from the file
+{
+ ULONGLONG ByteOffset = (pByteOffset != NULL) ? *pByteOffset : pStream->Base.File.FilePos;
+ DWORD dwBytesRead = 0; // Must be set by platform-specific code
+
+#ifdef PLATFORM_WINDOWS
+ {
+ // Note: CascLib no longer supports Windows 9x.
+ // Thus, we can use the OVERLAPPED structure to specify
+ // file offset to read from file. This allows us to skip
+ // one system call to SetFilePointer
+
+ // Update the byte offset
+ pStream->Base.File.FilePos = ByteOffset;
+
+ // Read the data
+ if(dwBytesToRead != 0)
+ {
+ OVERLAPPED Overlapped;
+
+ Overlapped.OffsetHigh = (DWORD)(ByteOffset >> 32);
+ Overlapped.Offset = (DWORD)ByteOffset;
+ Overlapped.hEvent = NULL;
+ if(!ReadFile(pStream->Base.File.hFile, pvBuffer, dwBytesToRead, &dwBytesRead, &Overlapped))
+ return false;
+ }
+ }
+#endif
+
+#if defined(PLATFORM_MAC) || defined(PLATFORM_LINUX)
+ {
+ ssize_t bytes_read;
+
+ // If the byte offset is different from the current file position,
+ // we have to update the file position
+ if(ByteOffset != pStream->Base.File.FilePos)
+ {
+ lseek64((intptr_t)pStream->Base.File.hFile, (off64_t)(ByteOffset), SEEK_SET);
+ pStream->Base.File.FilePos = ByteOffset;
+ }
+
+ // Perform the read operation
+ if(dwBytesToRead != 0)
+ {
+ bytes_read = read((intptr_t)pStream->Base.File.hFile, pvBuffer, (size_t)dwBytesToRead);
+ if(bytes_read == -1)
+ {
+ SetLastError(errno);
+ return false;
+ }
+
+ dwBytesRead = (DWORD)(size_t)bytes_read;
+ }
+ }
+#endif
+
+ // Increment the current file position by number of bytes read
+ // If the number of bytes read doesn't match to required amount, return false
+ pStream->Base.File.FilePos = ByteOffset + dwBytesRead;
+ if(dwBytesRead != dwBytesToRead)
+ SetLastError(ERROR_HANDLE_EOF);
+ return (dwBytesRead == dwBytesToRead);
+}
+
+/**
+ * \a pStream Pointer to an open stream
+ * \a pByteOffset Pointer to file byte offset. If NULL, writes to current position
+ * \a pvBuffer Pointer to data to be written
+ * \a dwBytesToWrite Number of bytes to write to the file
+ */
+
+static bool BaseFile_Write(TFileStream * pStream, ULONGLONG * pByteOffset, const void * pvBuffer, DWORD dwBytesToWrite)
+{
+ ULONGLONG ByteOffset = (pByteOffset != NULL) ? *pByteOffset : pStream->Base.File.FilePos;
+ DWORD dwBytesWritten = 0; // Must be set by platform-specific code
+
+#ifdef PLATFORM_WINDOWS
+ {
+ // Note: CascLib no longer supports Windows 9x.
+ // Thus, we can use the OVERLAPPED structure to specify
+ // file offset to read from file. This allows us to skip
+ // one system call to SetFilePointer
+
+ // Update the byte offset
+ pStream->Base.File.FilePos = ByteOffset;
+
+ // Read the data
+ if(dwBytesToWrite != 0)
+ {
+ OVERLAPPED Overlapped;
+
+ Overlapped.OffsetHigh = (DWORD)(ByteOffset >> 32);
+ Overlapped.Offset = (DWORD)ByteOffset;
+ Overlapped.hEvent = NULL;
+ if(!WriteFile(pStream->Base.File.hFile, pvBuffer, dwBytesToWrite, &dwBytesWritten, &Overlapped))
+ return false;
+ }
+ }
+#endif
+
+#if defined(PLATFORM_MAC) || defined(PLATFORM_LINUX)
+ {
+ ssize_t bytes_written;
+
+ // If the byte offset is different from the current file position,
+ // we have to update the file position
+ if(ByteOffset != pStream->Base.File.FilePos)
+ {
+ lseek64((intptr_t)pStream->Base.File.hFile, (off64_t)(ByteOffset), SEEK_SET);
+ pStream->Base.File.FilePos = ByteOffset;
+ }
+
+ // Perform the read operation
+ bytes_written = write((intptr_t)pStream->Base.File.hFile, pvBuffer, (size_t)dwBytesToWrite);
+ if(bytes_written == -1)
+ {
+ SetLastError(errno);
+ return false;
+ }
+
+ dwBytesWritten = (DWORD)(size_t)bytes_written;
+ }
+#endif
+
+ // Increment the current file position by number of bytes read
+ pStream->Base.File.FilePos = ByteOffset + dwBytesWritten;
+
+ // Also modify the file size, if needed
+ if(pStream->Base.File.FilePos > pStream->Base.File.FileSize)
+ pStream->Base.File.FileSize = pStream->Base.File.FilePos;
+
+ if(dwBytesWritten != dwBytesToWrite)
+ SetLastError(ERROR_DISK_FULL);
+ return (dwBytesWritten == dwBytesToWrite);
+}
+
+/**
+ * \a pStream Pointer to an open stream
+ * \a NewFileSize New size of the file
+ */
+static bool BaseFile_Resize(TFileStream * pStream, ULONGLONG NewFileSize)
+{
+#ifdef PLATFORM_WINDOWS
+ {
+ LONG FileSizeHi = (LONG)(NewFileSize >> 32);
+ LONG FileSizeLo;
+ DWORD dwNewPos;
+ bool bResult;
+
+ // Set the position at the new file size
+ dwNewPos = SetFilePointer(pStream->Base.File.hFile, (LONG)NewFileSize, &FileSizeHi, FILE_BEGIN);
+ if(dwNewPos == INVALID_SET_FILE_POINTER && GetLastError() != ERROR_SUCCESS)
+ return false;
+
+ // Set the current file pointer as the end of the file
+ bResult = (bool)SetEndOfFile(pStream->Base.File.hFile);
+ if(bResult)
+ pStream->Base.File.FileSize = NewFileSize;
+
+ // Restore the file position
+ FileSizeHi = (LONG)(pStream->Base.File.FilePos >> 32);
+ FileSizeLo = (LONG)(pStream->Base.File.FilePos);
+ SetFilePointer(pStream->Base.File.hFile, FileSizeLo, &FileSizeHi, FILE_BEGIN);
+ return bResult;
+ }
+#endif
+
+#if defined(PLATFORM_MAC) || defined(PLATFORM_LINUX)
+ {
+ if(ftruncate64((intptr_t)pStream->Base.File.hFile, (off64_t)NewFileSize) == -1)
+ {
+ SetLastError(errno);
+ return false;
+ }
+
+ pStream->Base.File.FileSize = NewFileSize;
+ return true;
+ }
+#endif
+}
+
+// Gives the current file size
+static bool BaseFile_GetSize(TFileStream * pStream, ULONGLONG * pFileSize)
+{
+ // Note: Used by all thre base providers.
+ // Requires the TBaseData union to have the same layout for all three base providers
+ *pFileSize = pStream->Base.File.FileSize;
+ return true;
+}
+
+// Gives the current file position
+static bool BaseFile_GetPos(TFileStream * pStream, ULONGLONG * pByteOffset)
+{
+ // Note: Used by all thre base providers.
+ // Requires the TBaseData union to have the same layout for all three base providers
+ *pByteOffset = pStream->Base.File.FilePos;
+ return true;
+}
+
+// Renames the file pointed by pStream so that it contains data from pNewStream
+static bool BaseFile_Replace(TFileStream * pStream, TFileStream * pNewStream)
+{
+#ifdef PLATFORM_WINDOWS
+ // Delete the original stream file. Don't check the result value,
+ // because if the file doesn't exist, it would fail
+ DeleteFile(pStream->szFileName);
+
+ // Rename the new file to the old stream's file
+ return (bool)MoveFile(pNewStream->szFileName, pStream->szFileName);
+#endif
+
+#if defined(PLATFORM_MAC) || defined(PLATFORM_LINUX)
+ // "rename" on Linux also works if the target file exists
+ if(rename(pNewStream->szFileName, pStream->szFileName) == -1)
+ {
+ SetLastError(errno);
+ return false;
+ }
+
+ return true;
+#endif
+}
+
+static void BaseFile_Close(TFileStream * pStream)
+{
+ if(pStream->Base.File.hFile != INVALID_HANDLE_VALUE)
+ {
+#ifdef PLATFORM_WINDOWS
+ CloseHandle(pStream->Base.File.hFile);
+#endif
+
+#if defined(PLATFORM_MAC) || defined(PLATFORM_LINUX)
+ close((intptr_t)pStream->Base.File.hFile);
+#endif
+ }
+
+ // Also invalidate the handle
+ pStream->Base.File.hFile = INVALID_HANDLE_VALUE;
+}
+
+// Initializes base functions for the disk file
+static void BaseFile_Init(TFileStream * pStream)
+{
+ pStream->BaseCreate = BaseFile_Create;
+ pStream->BaseOpen = BaseFile_Open;
+ pStream->BaseRead = BaseFile_Read;
+ pStream->BaseWrite = BaseFile_Write;
+ pStream->BaseResize = BaseFile_Resize;
+ pStream->BaseGetSize = BaseFile_GetSize;
+ pStream->BaseGetPos = BaseFile_GetPos;
+ pStream->BaseClose = BaseFile_Close;
+}
+
+//-----------------------------------------------------------------------------
+// Local functions - base memory-mapped file support
+
+static bool BaseMap_Open(TFileStream * pStream, const TCHAR * szFileName, DWORD dwStreamFlags)
+{
+#ifdef PLATFORM_WINDOWS
+
+ ULARGE_INTEGER FileSize;
+ HANDLE hFile;
+ HANDLE hMap;
+ bool bResult = false;
+
+ // Keep compiler happy
+ dwStreamFlags = dwStreamFlags;
+
+ // Open the file for read access
+ hFile = CreateFile(szFileName, FILE_READ_DATA, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
+ if(hFile != INVALID_HANDLE_VALUE)
+ {
+ // Retrieve file size. Don't allow mapping file of a zero size.
+ FileSize.LowPart = GetFileSize(hFile, &FileSize.HighPart);
+ if(FileSize.QuadPart != 0)
+ {
+ // Now create mapping object
+ hMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
+ if(hMap != NULL)
+ {
+ // Map the entire view into memory
+ // Note that this operation will fail if the file can't fit
+ // into usermode address space
+ pStream->Base.Map.pbFile = (LPBYTE)MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0);
+ if(pStream->Base.Map.pbFile != NULL)
+ {
+ // Retrieve file time
+ GetFileTime(hFile, NULL, NULL, (LPFILETIME)&pStream->Base.Map.FileTime);
+
+ // Retrieve file size and position
+ pStream->Base.Map.FileSize = FileSize.QuadPart;
+ pStream->Base.Map.FilePos = 0;
+ bResult = true;
+ }
+
+ // Close the map handle
+ CloseHandle(hMap);
+ }
+ }
+
+ // Close the file handle
+ CloseHandle(hFile);
+ }
+
+ // If the file is not there and is not available for random access,
+ // report error
+ if(bResult == false)
+ return false;
+#endif
+
+#if defined(PLATFORM_MAC) || defined(PLATFORM_LINUX)
+ struct stat64 fileinfo;
+ intptr_t handle;
+ bool bResult = false;
+
+ // Open the file
+ handle = open(szFileName, O_RDONLY);
+ if(handle != -1)
+ {
+ // Get the file size
+ if(fstat64(handle, &fileinfo) != -1)
+ {
+ pStream->Base.Map.pbFile = (LPBYTE)mmap(NULL, (size_t)fileinfo.st_size, PROT_READ, MAP_PRIVATE, handle, 0);
+ if(pStream->Base.Map.pbFile != NULL)
+ {
+ // time_t is number of seconds since 1.1.1970, UTC.
+ // 1 second = 10000000 (decimal) in FILETIME
+ // Set the start to 1.1.1970 00:00:00
+ pStream->Base.Map.FileTime = 0x019DB1DED53E8000ULL + (10000000 * fileinfo.st_mtime);
+ pStream->Base.Map.FileSize = (ULONGLONG)fileinfo.st_size;
+ pStream->Base.Map.FilePos = 0;
+ bResult = true;
+ }
+ }
+ close(handle);
+ }
+
+ // Did the mapping fail?
+ if(bResult == false)
+ {
+ SetLastError(errno);
+ return false;
+ }
+#endif
+
+ return true;
+}
+
+static bool BaseMap_Read(
+ TFileStream * pStream, // Pointer to an open stream
+ ULONGLONG * pByteOffset, // Pointer to file byte offset. If NULL, it reads from the current position
+ void * pvBuffer, // Pointer to data to be read
+ DWORD dwBytesToRead) // Number of bytes to read from the file
+{
+ ULONGLONG ByteOffset = (pByteOffset != NULL) ? *pByteOffset : pStream->Base.Map.FilePos;
+
+ // Do we have to read anything at all?
+ if(dwBytesToRead != 0)
+ {
+ // Don't allow reading past file size
+ if((ByteOffset + dwBytesToRead) > pStream->Base.Map.FileSize)
+ return false;
+
+ // Copy the required data
+ memcpy(pvBuffer, pStream->Base.Map.pbFile + (size_t)ByteOffset, dwBytesToRead);
+ }
+
+ // Move the current file position
+ pStream->Base.Map.FilePos += dwBytesToRead;
+ return true;
+}
+
+static void BaseMap_Close(TFileStream * pStream)
+{
+#ifdef PLATFORM_WINDOWS
+ if(pStream->Base.Map.pbFile != NULL)
+ UnmapViewOfFile(pStream->Base.Map.pbFile);
+#endif
+
+#if defined(PLATFORM_MAC) || defined(PLATFORM_LINUX)
+ if(pStream->Base.Map.pbFile != NULL)
+ munmap(pStream->Base.Map.pbFile, (size_t )pStream->Base.Map.FileSize);
+#endif
+
+ pStream->Base.Map.pbFile = NULL;
+}
+
+// Initializes base functions for the mapped file
+static void BaseMap_Init(TFileStream * pStream)
+{
+ // Supply the file stream functions
+ pStream->BaseOpen = BaseMap_Open;
+ pStream->BaseRead = BaseMap_Read;
+ pStream->BaseGetSize = BaseFile_GetSize; // Reuse BaseFile function
+ pStream->BaseGetPos = BaseFile_GetPos; // Reuse BaseFile function
+ pStream->BaseClose = BaseMap_Close;
+
+ // Mapped files are read-only
+ pStream->dwFlags |= STREAM_FLAG_READ_ONLY;
+}
+
+//-----------------------------------------------------------------------------
+// Local functions - base HTTP file support
+
+static const TCHAR * BaseHttp_ExtractServerName(const TCHAR * szFileName, TCHAR * szServerName)
+{
+ // Check for HTTP
+ if(!_tcsnicmp(szFileName, _T("http://"), 7))
+ szFileName += 7;
+
+ // Cut off the server name
+ if(szServerName != NULL)
+ {
+ while(szFileName[0] != 0 && szFileName[0] != _T('/'))
+ *szServerName++ = *szFileName++;
+ *szServerName = 0;
+ }
+ else
+ {
+ while(szFileName[0] != 0 && szFileName[0] != _T('/'))
+ szFileName++;
+ }
+
+ // Return the remainder
+ return szFileName;
+}
+
+static bool BaseHttp_Open(TFileStream * pStream, const TCHAR * szFileName, DWORD dwStreamFlags)
+{
+#ifdef PLATFORM_WINDOWS
+
+ HINTERNET hRequest;
+ DWORD dwTemp = 0;
+ bool bFileAvailable = false;
+ int nError = ERROR_SUCCESS;
+
+ // Keep compiler happy
+ dwStreamFlags = dwStreamFlags;
+
+ // Don't connect to the internet
+ if(!InternetGetConnectedState(&dwTemp, 0))
+ nError = GetLastError();
+
+ // Initiate the connection to the internet
+ if(nError == ERROR_SUCCESS)
+ {
+ pStream->Base.Http.hInternet = InternetOpen(_T("CascLib HTTP archive reader"),
+ INTERNET_OPEN_TYPE_PRECONFIG,
+ NULL,
+ NULL,
+ 0);
+ if(pStream->Base.Http.hInternet == NULL)
+ nError = GetLastError();
+ }
+
+ // Connect to the server
+ if(nError == ERROR_SUCCESS)
+ {
+ TCHAR szServerName[MAX_PATH];
+ DWORD dwFlags = INTERNET_FLAG_KEEP_CONNECTION | INTERNET_FLAG_NO_UI | INTERNET_FLAG_NO_CACHE_WRITE;
+
+ // Initiate connection with the server
+ szFileName = BaseHttp_ExtractServerName(szFileName, szServerName);
+ pStream->Base.Http.hConnect = InternetConnect(pStream->Base.Http.hInternet,
+ szServerName,
+ INTERNET_DEFAULT_HTTP_PORT,
+ NULL,
+ NULL,
+ INTERNET_SERVICE_HTTP,
+ dwFlags,
+ 0);
+ if(pStream->Base.Http.hConnect == NULL)
+ nError = GetLastError();
+ }
+
+ // Now try to query the file size
+ if(nError == ERROR_SUCCESS)
+ {
+ // Open HTTP request to the file
+ hRequest = HttpOpenRequest(pStream->Base.Http.hConnect, _T("GET"), szFileName, NULL, NULL, NULL, INTERNET_FLAG_NO_CACHE_WRITE, 0);
+ if(hRequest != NULL)
+ {
+ if(HttpSendRequest(hRequest, NULL, 0, NULL, 0))
+ {
+ ULONGLONG FileTime = 0;
+ DWORD dwFileSize = 0;
+ DWORD dwDataSize;
+ DWORD dwIndex = 0;
+
+ // Check if the archive has Last Modified field
+ dwDataSize = sizeof(ULONGLONG);
+ if(HttpQueryInfo(hRequest, HTTP_QUERY_LAST_MODIFIED | HTTP_QUERY_FLAG_SYSTEMTIME, &FileTime, &dwDataSize, &dwIndex))
+ pStream->Base.Http.FileTime = FileTime;
+
+ // Verify if the server supports random access
+ dwDataSize = sizeof(DWORD);
+ if(HttpQueryInfo(hRequest, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER, &dwFileSize, &dwDataSize, &dwIndex))
+ {
+ if(dwFileSize != 0)
+ {
+ pStream->Base.Http.FileSize = dwFileSize;
+ pStream->Base.Http.FilePos = 0;
+ bFileAvailable = true;
+ }
+ }
+ }
+ InternetCloseHandle(hRequest);
+ }
+ }
+
+ // If the file is not there and is not available for random access,
+ // report error
+ if(bFileAvailable == false)
+ {
+ pStream->BaseClose(pStream);
+ return false;
+ }
+
+ return true;
+
+#else
+
+ // Not supported
+ SetLastError(ERROR_NOT_SUPPORTED);
+ pStream = pStream;
+ return false;
+
+#endif
+}
+
+static bool BaseHttp_Read(
+ TFileStream * pStream, // Pointer to an open stream
+ ULONGLONG * pByteOffset, // Pointer to file byte offset. If NULL, it reads from the current position
+ void * pvBuffer, // Pointer to data to be read
+ DWORD dwBytesToRead) // Number of bytes to read from the file
+{
+#ifdef PLATFORM_WINDOWS
+ ULONGLONG ByteOffset = (pByteOffset != NULL) ? *pByteOffset : pStream->Base.Http.FilePos;
+ DWORD dwTotalBytesRead = 0;
+
+ // Do we have to read anything at all?
+ if(dwBytesToRead != 0)
+ {
+ HINTERNET hRequest;
+ LPCTSTR szFileName;
+ LPBYTE pbBuffer = (LPBYTE)pvBuffer;
+ TCHAR szRangeRequest[0x80];
+ DWORD dwStartOffset = (DWORD)ByteOffset;
+ DWORD dwEndOffset = dwStartOffset + dwBytesToRead;
+
+ // Open HTTP request to the file
+ szFileName = BaseHttp_ExtractServerName(pStream->szFileName, NULL);
+ hRequest = HttpOpenRequest(pStream->Base.Http.hConnect, _T("GET"), szFileName, NULL, NULL, NULL, INTERNET_FLAG_NO_CACHE_WRITE, 0);
+ if(hRequest != NULL)
+ {
+ // Add range request to the HTTP headers
+ // http://www.clevercomponents.com/articles/article015/resuming.asp
+ _stprintf(szRangeRequest, _T("Range: bytes=%u-%u"), (unsigned int)dwStartOffset, (unsigned int)dwEndOffset);
+ HttpAddRequestHeaders(hRequest, szRangeRequest, 0xFFFFFFFF, HTTP_ADDREQ_FLAG_ADD_IF_NEW);
+
+ // Send the request to the server
+ if(HttpSendRequest(hRequest, NULL, 0, NULL, 0))
+ {
+ while(dwTotalBytesRead < dwBytesToRead)
+ {
+ DWORD dwBlockBytesToRead = dwBytesToRead - dwTotalBytesRead;
+ DWORD dwBlockBytesRead = 0;
+
+ // Read the block from the file
+ if(dwBlockBytesToRead > 0x200)
+ dwBlockBytesToRead = 0x200;
+ InternetReadFile(hRequest, pbBuffer, dwBlockBytesToRead, &dwBlockBytesRead);
+
+ // Check for end
+ if(dwBlockBytesRead == 0)
+ break;
+
+ // Move buffers
+ dwTotalBytesRead += dwBlockBytesRead;
+ pbBuffer += dwBlockBytesRead;
+ }
+ }
+ InternetCloseHandle(hRequest);
+ }
+ }
+
+ // Increment the current file position by number of bytes read
+ pStream->Base.Http.FilePos = ByteOffset + dwTotalBytesRead;
+
+ // If the number of bytes read doesn't match the required amount, return false
+ if(dwTotalBytesRead != dwBytesToRead)
+ SetLastError(ERROR_HANDLE_EOF);
+ return (dwTotalBytesRead == dwBytesToRead);
+
+#else
+
+ // Not supported
+ pStream = pStream;
+ pByteOffset = pByteOffset;
+ pvBuffer = pvBuffer;
+ dwBytesToRead = dwBytesToRead;
+ SetLastError(ERROR_NOT_SUPPORTED);
+ return false;
+
+#endif
+}
+
+static void BaseHttp_Close(TFileStream * pStream)
+{
+#ifdef PLATFORM_WINDOWS
+ if(pStream->Base.Http.hConnect != NULL)
+ InternetCloseHandle(pStream->Base.Http.hConnect);
+ pStream->Base.Http.hConnect = NULL;
+
+ if(pStream->Base.Http.hInternet != NULL)
+ InternetCloseHandle(pStream->Base.Http.hInternet);
+ pStream->Base.Http.hInternet = NULL;
+#else
+ pStream = pStream;
+#endif
+}
+
+// Initializes base functions for the mapped file
+static void BaseHttp_Init(TFileStream * pStream)
+{
+ // Supply the stream functions
+ pStream->BaseOpen = BaseHttp_Open;
+ pStream->BaseRead = BaseHttp_Read;
+ pStream->BaseGetSize = BaseFile_GetSize; // Reuse BaseFile function
+ pStream->BaseGetPos = BaseFile_GetPos; // Reuse BaseFile function
+ pStream->BaseClose = BaseHttp_Close;
+
+ // HTTP files are read-only
+ pStream->dwFlags |= STREAM_FLAG_READ_ONLY;
+}
+
+//-----------------------------------------------------------------------------
+// Local functions - base block-based support
+
+// Generic function that loads blocks from the file
+// The function groups the block with the same availability,
+// so the called BlockRead can finish the request in a single system call
+static bool BlockStream_Read(
+ TBlockStream * pStream, // Pointer to an open stream
+ ULONGLONG * pByteOffset, // Pointer to file byte offset. If NULL, it reads from the current position
+ void * pvBuffer, // Pointer to data to be read
+ DWORD dwBytesToRead) // Number of bytes to read from the file
+{
+ ULONGLONG BlockOffset0;
+ ULONGLONG BlockOffset;
+ ULONGLONG ByteOffset;
+ ULONGLONG EndOffset;
+ LPBYTE TransferBuffer;
+ LPBYTE BlockBuffer;
+ DWORD BlockBufferOffset; // Offset of the desired data in the block buffer
+ DWORD BytesNeeded; // Number of bytes that really need to be read
+ DWORD BlockSize = pStream->BlockSize;
+ DWORD BlockCount;
+ bool bPrevBlockAvailable;
+ bool bCallbackCalled = false;
+ bool bBlockAvailable;
+ bool bResult = true;
+
+ // The base block read function must be present
+ assert(pStream->BlockRead != NULL);
+
+ // NOP reading of zero bytes
+ if(dwBytesToRead == 0)
+ return true;
+
+ // Get the current position in the stream
+ ByteOffset = (pByteOffset != NULL) ? pByteOffset[0] : pStream->StreamPos;
+ EndOffset = ByteOffset + dwBytesToRead;
+ if(EndOffset > pStream->StreamSize)
+ {
+ SetLastError(ERROR_HANDLE_EOF);
+ return false;
+ }
+
+ // Calculate the block parameters
+ BlockOffset0 = BlockOffset = ByteOffset & ~((ULONGLONG)BlockSize - 1);
+ BlockCount = (DWORD)(((EndOffset - BlockOffset) + (BlockSize - 1)) / BlockSize);
+ BytesNeeded = (DWORD)(EndOffset - BlockOffset);
+
+ // Remember where we have our data
+ assert((BlockSize & (BlockSize - 1)) == 0);
+ BlockBufferOffset = (DWORD)(ByteOffset & (BlockSize - 1));
+
+ // Allocate buffer for reading blocks
+ TransferBuffer = BlockBuffer = CASC_ALLOC(BYTE, (BlockCount * BlockSize));
+ if(TransferBuffer == NULL)
+ {
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ return false;
+ }
+
+ // If all blocks are available, just read all blocks at once
+ if(pStream->IsComplete == 0)
+ {
+ // Now parse the blocks and send the block read request
+ // to all blocks with the same availability
+ assert(pStream->BlockCheck != NULL);
+ bPrevBlockAvailable = pStream->BlockCheck(pStream, BlockOffset);
+
+ // Loop as long as we have something to read
+ while(BlockOffset < EndOffset)
+ {
+ // Determine availability of the next block
+ bBlockAvailable = pStream->BlockCheck(pStream, BlockOffset);
+
+ // If the availability has changed, read all blocks up to this one
+ if(bBlockAvailable != bPrevBlockAvailable)
+ {
+ // Call the file stream callback, if the block is not available
+ if(pStream->pMaster && pStream->pfnCallback && bPrevBlockAvailable == false)
+ {
+ pStream->pfnCallback(pStream->UserData, BlockOffset0, (DWORD)(BlockOffset - BlockOffset0));
+ bCallbackCalled = true;
+ }
+
+ // Load the continuous blocks with the same availability
+ assert(BlockOffset > BlockOffset0);
+ bResult = pStream->BlockRead(pStream, BlockOffset0, BlockOffset, BlockBuffer, BytesNeeded, bPrevBlockAvailable);
+ if(!bResult)
+ break;
+
+ // Move the block offset
+ BlockBuffer += (DWORD)(BlockOffset - BlockOffset0);
+ BytesNeeded -= (DWORD)(BlockOffset - BlockOffset0);
+ bPrevBlockAvailable = bBlockAvailable;
+ BlockOffset0 = BlockOffset;
+ }
+
+ // Move to the block offset in the stream
+ BlockOffset += BlockSize;
+ }
+
+ // If there is a block(s) remaining to be read, do it
+ if(BlockOffset > BlockOffset0)
+ {
+ // Call the file stream callback, if the block is not available
+ if(pStream->pMaster && pStream->pfnCallback && bPrevBlockAvailable == false)
+ {
+ pStream->pfnCallback(pStream->UserData, BlockOffset0, (DWORD)(BlockOffset - BlockOffset0));
+ bCallbackCalled = true;
+ }
+
+ // Read the complete blocks from the file
+ if(BlockOffset > pStream->StreamSize)
+ BlockOffset = pStream->StreamSize;
+ bResult = pStream->BlockRead(pStream, BlockOffset0, BlockOffset, BlockBuffer, BytesNeeded, bPrevBlockAvailable);
+ }
+ }
+ else
+ {
+ // Read the complete blocks from the file
+ if(EndOffset > pStream->StreamSize)
+ EndOffset = pStream->StreamSize;
+ bResult = pStream->BlockRead(pStream, BlockOffset, EndOffset, BlockBuffer, BytesNeeded, true);
+ }
+
+ // Now copy the data to the user buffer
+ if(bResult)
+ {
+ memcpy(pvBuffer, TransferBuffer + BlockBufferOffset, dwBytesToRead);
+ pStream->StreamPos = ByteOffset + dwBytesToRead;
+ }
+ else
+ {
+ // If the block read failed, set the last error
+ SetLastError(ERROR_FILE_INCOMPLETE);
+ }
+
+ // Call the callback to indicate we are done
+ if(bCallbackCalled)
+ pStream->pfnCallback(pStream->UserData, 0, 0);
+
+ // Free the block buffer and return
+ CASC_FREE(TransferBuffer);
+ return bResult;
+}
+
+static bool BlockStream_GetSize(TFileStream * pStream, ULONGLONG * pFileSize)
+{
+ *pFileSize = pStream->StreamSize;
+ return true;
+}
+
+static bool BlockStream_GetPos(TFileStream * pStream, ULONGLONG * pByteOffset)
+{
+ *pByteOffset = pStream->StreamPos;
+ return true;
+}
+
+static void BlockStream_Close(TBlockStream * pStream)
+{
+ // Free the data map, if any
+ if(pStream->FileBitmap != NULL)
+ CASC_FREE(pStream->FileBitmap);
+ pStream->FileBitmap = NULL;
+
+ // Call the base class for closing the stream
+ pStream->BaseClose(pStream);
+}
+
+//-----------------------------------------------------------------------------
+// File stream allocation function
+
+static STREAM_INIT StreamBaseInit[4] =
+{
+ BaseFile_Init,
+ BaseMap_Init,
+ BaseHttp_Init,
+ BaseNone_Init
+};
+
+// This function allocates an empty structure for the file stream
+// The stream structure is created as flat block, variable length
+// The file name is placed after the end of the stream structure data
+static TFileStream * AllocateFileStream(
+ const TCHAR * szFileName,
+ size_t StreamSize,
+ DWORD dwStreamFlags)
+{
+ TFileStream * pMaster = NULL;
+ TFileStream * pStream;
+ const TCHAR * szNextFile = szFileName;
+ size_t FileNameSize;
+
+ // Sanity check
+ assert(StreamSize != 0);
+
+ // The caller can specify chain of files in the following form:
+ // C:\archive.MPQ*http://www.server.com/MPQs/archive-server.MPQ
+ // In that case, we use the part after "*" as master file name
+ while(szNextFile[0] != 0 && szNextFile[0] != _T('*'))
+ szNextFile++;
+ FileNameSize = (size_t)((szNextFile - szFileName) * sizeof(TCHAR));
+
+ // If we have a next file, we need to open it as master stream
+ // Note that we don't care if the master stream exists or not,
+ // If it doesn't, later attempts to read missing file block will fail
+ if(szNextFile[0] == _T('*'))
+ {
+ // Don't allow another master file in the string
+ if(_tcschr(szNextFile + 1, _T('*')) != NULL)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return NULL;
+ }
+
+ // Open the master file
+ pMaster = FileStream_OpenFile(szNextFile + 1, STREAM_FLAG_READ_ONLY);
+ }
+
+ // Allocate the stream structure for the given stream type
+ pStream = (TFileStream *)CASC_ALLOC(BYTE, StreamSize + FileNameSize + sizeof(TCHAR));
+ if(pStream != NULL)
+ {
+ // Zero the entire structure
+ memset(pStream, 0, StreamSize);
+ pStream->pMaster = pMaster;
+ pStream->dwFlags = dwStreamFlags;
+
+ // Initialize the file name
+ pStream->szFileName = (TCHAR *)((BYTE *)pStream + StreamSize);
+ memcpy(pStream->szFileName, szFileName, FileNameSize);
+ pStream->szFileName[FileNameSize / sizeof(TCHAR)] = 0;
+
+ // Initialize the stream functions
+ StreamBaseInit[dwStreamFlags & 0x03](pStream);
+ }
+
+ return pStream;
+}
+
+//-----------------------------------------------------------------------------
+// Local functions - flat stream support
+
+static DWORD FlatStream_CheckFile(TBlockStream * pStream)
+{
+ LPBYTE FileBitmap = (LPBYTE)pStream->FileBitmap;
+ DWORD WholeByteCount = (pStream->BlockCount / 8);
+ DWORD ExtraBitsCount = (pStream->BlockCount & 7);
+ BYTE ExpectedValue;
+
+ // Verify the whole bytes - their value must be 0xFF
+ for(DWORD i = 0; i < WholeByteCount; i++)
+ {
+ if(FileBitmap[i] != 0xFF)
+ return 0;
+ }
+
+ // If there are extra bits, calculate the mask
+ if(ExtraBitsCount != 0)
+ {
+ ExpectedValue = (BYTE)((1 << ExtraBitsCount) - 1);
+ if(FileBitmap[WholeByteCount] != ExpectedValue)
+ return 0;
+ }
+
+ // Yes, the file is complete
+ return 1;
+}
+
+static bool FlatStream_LoadBitmap(TBlockStream * pStream)
+{
+ FILE_BITMAP_FOOTER Footer;
+ ULONGLONG ByteOffset;
+ LPBYTE FileBitmap;
+ DWORD BlockCount;
+ DWORD BitmapSize;
+
+ // Do not load the bitmap if we should not have to
+ if(!(pStream->dwFlags & STREAM_FLAG_USE_BITMAP))
+ return false;
+
+ // Only if the size is greater than size of bitmap footer
+ if(pStream->Base.File.FileSize > sizeof(FILE_BITMAP_FOOTER))
+ {
+ // Load the bitmap footer
+ ByteOffset = pStream->Base.File.FileSize - sizeof(FILE_BITMAP_FOOTER);
+ if(pStream->BaseRead(pStream, &ByteOffset, &Footer, sizeof(FILE_BITMAP_FOOTER)))
+ {
+ // Make sure that the array is properly BSWAP-ed
+ BSWAP_ARRAY32_UNSIGNED((PDWORD)(&Footer), sizeof(FILE_BITMAP_FOOTER));
+
+ // Verify if there is actually a footer
+ if(Footer.Signature == ID_FILE_BITMAP_FOOTER && Footer.Version == 0x03)
+ {
+ // Get the offset of the bitmap, number of blocks and size of the bitmap
+ ByteOffset = MAKE_OFFSET64(Footer.MapOffsetHi, Footer.MapOffsetLo);
+ BlockCount = (DWORD)(((ByteOffset - 1) / Footer.BlockSize) + 1);
+ BitmapSize = ((BlockCount + 7) / 8);
+
+ // Check if the sizes match
+ if(ByteOffset + BitmapSize + sizeof(FILE_BITMAP_FOOTER) == pStream->Base.File.FileSize)
+ {
+ // Allocate space for the bitmap
+ FileBitmap = CASC_ALLOC(BYTE, BitmapSize);
+ if(FileBitmap != NULL)
+ {
+ // Load the bitmap bits
+ if(!pStream->BaseRead(pStream, &ByteOffset, FileBitmap, BitmapSize))
+ {
+ CASC_FREE(FileBitmap);
+ return false;
+ }
+
+ // Update the stream size
+ pStream->BuildNumber = Footer.BuildNumber;
+ pStream->StreamSize = ByteOffset;
+
+ // Fill the bitmap information
+ pStream->FileBitmap = FileBitmap;
+ pStream->BitmapSize = BitmapSize;
+ pStream->BlockSize = Footer.BlockSize;
+ pStream->BlockCount = BlockCount;
+ pStream->IsComplete = FlatStream_CheckFile(pStream);
+ return true;
+ }
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+static void FlatStream_UpdateBitmap(
+ TBlockStream * pStream, // Pointer to an open stream
+ ULONGLONG StartOffset,
+ ULONGLONG EndOffset)
+{
+ LPBYTE FileBitmap = (LPBYTE)pStream->FileBitmap;
+ DWORD BlockIndex;
+ DWORD BlockSize = pStream->BlockSize;
+ DWORD ByteIndex;
+ BYTE BitMask;
+
+ // Sanity checks
+ assert((StartOffset & (BlockSize - 1)) == 0);
+ assert(FileBitmap != NULL);
+
+ // Calculate the index of the block
+ BlockIndex = (DWORD)(StartOffset / BlockSize);
+ ByteIndex = (BlockIndex / 0x08);
+ BitMask = (BYTE)(1 << (BlockIndex & 0x07));
+
+ // Set all bits for the specified range
+ while(StartOffset < EndOffset)
+ {
+ // Set the bit
+ FileBitmap[ByteIndex] |= BitMask;
+
+ // Move all
+ StartOffset += BlockSize;
+ ByteIndex += (BitMask >> 0x07);
+ BitMask = (BitMask >> 0x07) | (BitMask << 0x01);
+ }
+
+ // Increment the bitmap update count
+ pStream->IsModified = 1;
+}
+
+static bool FlatStream_BlockCheck(
+ TBlockStream * pStream, // Pointer to an open stream
+ ULONGLONG BlockOffset)
+{
+ LPBYTE FileBitmap = (LPBYTE)pStream->FileBitmap;
+ DWORD BlockIndex;
+ BYTE BitMask;
+
+ // Sanity checks
+ assert((BlockOffset & (pStream->BlockSize - 1)) == 0);
+ assert(FileBitmap != NULL);
+
+ // Calculate the index of the block
+ BlockIndex = (DWORD)(BlockOffset / pStream->BlockSize);
+ BitMask = (BYTE)(1 << (BlockIndex & 0x07));
+
+ // Check if the bit is present
+ return (FileBitmap[BlockIndex / 0x08] & BitMask) ? true : false;
+}
+
+static bool FlatStream_BlockRead(
+ TBlockStream * pStream, // Pointer to an open stream
+ ULONGLONG StartOffset,
+ ULONGLONG EndOffset,
+ LPBYTE BlockBuffer,
+ DWORD BytesNeeded,
+ bool bAvailable)
+{
+ DWORD BytesToRead = (DWORD)(EndOffset - StartOffset);
+
+ // The starting offset must be aligned to size of the block
+ assert(pStream->FileBitmap != NULL);
+ assert((StartOffset & (pStream->BlockSize - 1)) == 0);
+ assert(StartOffset < EndOffset);
+
+ // If the blocks are not available, we need to load them from the master
+ // and then save to the mirror
+ if(bAvailable == false)
+ {
+ // If we have no master, we cannot satisfy read request
+ if(pStream->pMaster == NULL)
+ return false;
+
+ // Load the blocks from the master stream
+ // Note that we always have to read complete blocks
+ // so they get properly stored to the mirror stream
+ if(!FileStream_Read(pStream->pMaster, &StartOffset, BlockBuffer, BytesToRead))
+ return false;
+
+ // Store the loaded blocks to the mirror file.
+ // Note that this operation is not required to succeed
+ if(pStream->BaseWrite(pStream, &StartOffset, BlockBuffer, BytesToRead))
+ FlatStream_UpdateBitmap(pStream, StartOffset, EndOffset);
+
+ return true;
+ }
+ else
+ {
+ if(BytesToRead > BytesNeeded)
+ BytesToRead = BytesNeeded;
+ return pStream->BaseRead(pStream, &StartOffset, BlockBuffer, BytesToRead);
+ }
+}
+
+static void FlatStream_Close(TBlockStream * pStream)
+{
+ FILE_BITMAP_FOOTER Footer;
+
+ if(pStream->FileBitmap && pStream->IsModified)
+ {
+ // Write the file bitmap
+ pStream->BaseWrite(pStream, &pStream->StreamSize, pStream->FileBitmap, pStream->BitmapSize);
+
+ // Prepare and write the file footer
+ Footer.Signature = ID_FILE_BITMAP_FOOTER;
+ Footer.Version = 3;
+ Footer.BuildNumber = pStream->BuildNumber;
+ Footer.MapOffsetLo = (DWORD)(pStream->StreamSize & 0xFFFFFFFF);
+ Footer.MapOffsetHi = (DWORD)(pStream->StreamSize >> 0x20);
+ Footer.BlockSize = pStream->BlockSize;
+ BSWAP_ARRAY32_UNSIGNED(&Footer, sizeof(FILE_BITMAP_FOOTER));
+ pStream->BaseWrite(pStream, NULL, &Footer, sizeof(FILE_BITMAP_FOOTER));
+ }
+
+ // Close the base class
+ BlockStream_Close(pStream);
+}
+
+static bool FlatStream_CreateMirror(TBlockStream * pStream)
+{
+ ULONGLONG MasterSize = 0;
+ ULONGLONG MirrorSize = 0;
+ LPBYTE FileBitmap = NULL;
+ DWORD dwBitmapSize;
+ DWORD dwBlockCount;
+ bool bNeedCreateMirrorStream = true;
+ bool bNeedResizeMirrorStream = true;
+
+ // Do we have master function and base creation function?
+ if(pStream->pMaster == NULL || pStream->BaseCreate == NULL)
+ return false;
+
+ // Retrieve the master file size, block count and bitmap size
+ FileStream_GetSize(pStream->pMaster, &MasterSize);
+ dwBlockCount = (DWORD)((MasterSize + DEFAULT_BLOCK_SIZE - 1) / DEFAULT_BLOCK_SIZE);
+ dwBitmapSize = (DWORD)((dwBlockCount + 7) / 8);
+
+ // Setup stream size and position
+ pStream->BuildNumber = DEFAULT_BUILD_NUMBER; // BUGBUG: Really???
+ pStream->StreamSize = MasterSize;
+ pStream->StreamPos = 0;
+
+ // Open the base stream for write access
+ if(pStream->BaseOpen(pStream, pStream->szFileName, 0))
+ {
+ // If the file open succeeded, check if the file size matches required size
+ pStream->BaseGetSize(pStream, &MirrorSize);
+ if(MirrorSize == MasterSize + dwBitmapSize + sizeof(FILE_BITMAP_FOOTER))
+ {
+ // Attempt to load an existing file bitmap
+ if(FlatStream_LoadBitmap(pStream))
+ return true;
+
+ // We need to create new file bitmap
+ bNeedResizeMirrorStream = false;
+ }
+
+ // We need to create mirror stream
+ bNeedCreateMirrorStream = false;
+ }
+
+ // Create a new stream, if needed
+ if(bNeedCreateMirrorStream)
+ {
+ if(!pStream->BaseCreate(pStream))
+ return false;
+ }
+
+ // If we need to, then resize the mirror stream
+ if(bNeedResizeMirrorStream)
+ {
+ if(!pStream->BaseResize(pStream, MasterSize + dwBitmapSize + sizeof(FILE_BITMAP_FOOTER)))
+ return false;
+ }
+
+ // Allocate the bitmap array
+ FileBitmap = CASC_ALLOC(BYTE, dwBitmapSize);
+ if(FileBitmap == NULL)
+ return false;
+
+ // Initialize the bitmap
+ memset(FileBitmap, 0, dwBitmapSize);
+ pStream->FileBitmap = FileBitmap;
+ pStream->BitmapSize = dwBitmapSize;
+ pStream->BlockSize = DEFAULT_BLOCK_SIZE;
+ pStream->BlockCount = dwBlockCount;
+ pStream->IsComplete = 0;
+ pStream->IsModified = 1;
+
+ // Note: Don't write the stream bitmap right away.
+ // Doing so would cause sparse file resize on NTFS,
+ // which would take long time on larger files.
+ return true;
+}
+
+static TFileStream * FlatStream_Open(const TCHAR * szFileName, DWORD dwStreamFlags)
+{
+ TBlockStream * pStream;
+ ULONGLONG ByteOffset = 0;
+
+ // Create new empty stream
+ pStream = (TBlockStream *)AllocateFileStream(szFileName, sizeof(TBlockStream), dwStreamFlags);
+ if(pStream == NULL)
+ return NULL;
+
+ // Do we have a master stream?
+ if(pStream->pMaster != NULL)
+ {
+ if(!FlatStream_CreateMirror(pStream))
+ {
+ FileStream_Close(pStream);
+ SetLastError(ERROR_FILE_NOT_FOUND);
+ return NULL;
+ }
+ }
+ else
+ {
+ // Attempt to open the base stream
+ if(!pStream->BaseOpen(pStream, pStream->szFileName, dwStreamFlags))
+ {
+ FileStream_Close(pStream);
+ return NULL;
+ }
+
+ // Load the bitmap, if required to
+ if(dwStreamFlags & STREAM_FLAG_USE_BITMAP)
+ FlatStream_LoadBitmap(pStream);
+ }
+
+ // If we have a stream bitmap, set the reading functions
+ // which check presence of each file block
+ if(pStream->FileBitmap != NULL)
+ {
+ // Set the stream position to zero. Stream size is already set
+ assert(pStream->StreamSize != 0);
+ pStream->StreamPos = 0;
+ pStream->dwFlags |= STREAM_FLAG_READ_ONLY;
+
+ // Supply the stream functions
+ pStream->StreamRead = (STREAM_READ)BlockStream_Read;
+ pStream->StreamGetSize = BlockStream_GetSize;
+ pStream->StreamGetPos = BlockStream_GetPos;
+ pStream->StreamClose = (STREAM_CLOSE)FlatStream_Close;
+
+ // Supply the block functions
+ pStream->BlockCheck = (BLOCK_CHECK)FlatStream_BlockCheck;
+ pStream->BlockRead = (BLOCK_READ)FlatStream_BlockRead;
+ }
+ else
+ {
+ // Reset the base position to zero
+ pStream->BaseRead(pStream, &ByteOffset, NULL, 0);
+
+ // Setup stream size and position
+ pStream->StreamSize = pStream->Base.File.FileSize;
+ pStream->StreamPos = 0;
+
+ // Set the base functions
+ pStream->StreamRead = pStream->BaseRead;
+ pStream->StreamWrite = pStream->BaseWrite;
+ pStream->StreamResize = pStream->BaseResize;
+ pStream->StreamGetSize = pStream->BaseGetSize;
+ pStream->StreamGetPos = pStream->BaseGetPos;
+ pStream->StreamClose = pStream->BaseClose;
+ }
+
+ return pStream;
+}
+
+//-----------------------------------------------------------------------------
+// Local functions - partial stream support
+
+static bool IsPartHeader(PPART_FILE_HEADER pPartHdr)
+{
+ // Version number must be 2
+ if(pPartHdr->PartialVersion == 2)
+ {
+ // GameBuildNumber must be an ASCII number
+ if(isdigit(pPartHdr->GameBuildNumber[0]) && isdigit(pPartHdr->GameBuildNumber[1]) && isdigit(pPartHdr->GameBuildNumber[2]))
+ {
+ // Block size must be power of 2
+ if((pPartHdr->BlockSize & (pPartHdr->BlockSize - 1)) == 0)
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static DWORD PartStream_CheckFile(TBlockStream * pStream)
+{
+ PPART_FILE_MAP_ENTRY FileBitmap = (PPART_FILE_MAP_ENTRY)pStream->FileBitmap;
+ DWORD dwBlockCount;
+
+ // Get the number of blocks
+ dwBlockCount = (DWORD)((pStream->StreamSize + pStream->BlockSize - 1) / pStream->BlockSize);
+
+ // Check all blocks
+ for(DWORD i = 0; i < dwBlockCount; i++, FileBitmap++)
+ {
+ // Few sanity checks
+ assert(FileBitmap->LargeValueHi == 0);
+ assert(FileBitmap->LargeValueLo == 0);
+ assert(FileBitmap->Flags == 0 || FileBitmap->Flags == 3);
+
+ // Check if this block is present
+ if(FileBitmap->Flags != 3)
+ return 0;
+ }
+
+ // Yes, the file is complete
+ return 1;
+}
+
+static bool PartStream_LoadBitmap(TBlockStream * pStream)
+{
+ PPART_FILE_MAP_ENTRY FileBitmap;
+ PART_FILE_HEADER PartHdr;
+ ULONGLONG ByteOffset = 0;
+ ULONGLONG StreamSize = 0;
+ DWORD BlockCount;
+ DWORD BitmapSize;
+
+ // Only if the size is greater than size of the bitmap header
+ if(pStream->Base.File.FileSize > sizeof(PART_FILE_HEADER))
+ {
+ // Attempt to read PART file header
+ if(pStream->BaseRead(pStream, &ByteOffset, &PartHdr, sizeof(PART_FILE_HEADER)))
+ {
+ // We need to swap PART file header on big-endian platforms
+ BSWAP_ARRAY32_UNSIGNED(&PartHdr, sizeof(PART_FILE_HEADER));
+
+ // Verify the PART file header
+ if(IsPartHeader(&PartHdr))
+ {
+ // Get the number of blocks and size of one block
+ StreamSize = MAKE_OFFSET64(PartHdr.FileSizeHi, PartHdr.FileSizeLo);
+ ByteOffset = sizeof(PART_FILE_HEADER);
+ BlockCount = (DWORD)((StreamSize + PartHdr.BlockSize - 1) / PartHdr.BlockSize);
+ BitmapSize = BlockCount * sizeof(PART_FILE_MAP_ENTRY);
+
+ // Check if sizes match
+ if((ByteOffset + BitmapSize) < pStream->Base.File.FileSize)
+ {
+ // Allocate space for the array of PART_FILE_MAP_ENTRY
+ FileBitmap = CASC_ALLOC(PART_FILE_MAP_ENTRY, BlockCount);
+ if(FileBitmap != NULL)
+ {
+ // Load the block map
+ if(!pStream->BaseRead(pStream, &ByteOffset, FileBitmap, BitmapSize))
+ {
+ CASC_FREE(FileBitmap);
+ return false;
+ }
+
+ // Make sure that the byte order is correct
+ BSWAP_ARRAY32_UNSIGNED(FileBitmap, BitmapSize);
+
+ // Update the stream size
+ pStream->BuildNumber = StringToInt(PartHdr.GameBuildNumber);
+ pStream->StreamSize = StreamSize;
+
+ // Fill the bitmap information
+ pStream->FileBitmap = FileBitmap;
+ pStream->BitmapSize = BitmapSize;
+ pStream->BlockSize = PartHdr.BlockSize;
+ pStream->BlockCount = BlockCount;
+ pStream->IsComplete = PartStream_CheckFile(pStream);
+ return true;
+ }
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+static void PartStream_UpdateBitmap(
+ TBlockStream * pStream, // Pointer to an open stream
+ ULONGLONG StartOffset,
+ ULONGLONG EndOffset,
+ ULONGLONG RealOffset)
+{
+ PPART_FILE_MAP_ENTRY FileBitmap;
+ DWORD BlockSize = pStream->BlockSize;
+
+ // Sanity checks
+ assert((StartOffset & (BlockSize - 1)) == 0);
+ assert(pStream->FileBitmap != NULL);
+
+ // Calculate the first entry in the block map
+ FileBitmap = (PPART_FILE_MAP_ENTRY)pStream->FileBitmap + (StartOffset / BlockSize);
+
+ // Set all bits for the specified range
+ while(StartOffset < EndOffset)
+ {
+ // Set the bit
+ FileBitmap->BlockOffsHi = (DWORD)(RealOffset >> 0x20);
+ FileBitmap->BlockOffsLo = (DWORD)(RealOffset & 0xFFFFFFFF);
+ FileBitmap->Flags = 3;
+
+ // Move all
+ StartOffset += BlockSize;
+ RealOffset += BlockSize;
+ FileBitmap++;
+ }
+
+ // Increment the bitmap update count
+ pStream->IsModified = 1;
+}
+
+static bool PartStream_BlockCheck(
+ TBlockStream * pStream, // Pointer to an open stream
+ ULONGLONG BlockOffset)
+{
+ PPART_FILE_MAP_ENTRY FileBitmap;
+
+ // Sanity checks
+ assert((BlockOffset & (pStream->BlockSize - 1)) == 0);
+ assert(pStream->FileBitmap != NULL);
+
+ // Calculate the block map entry
+ FileBitmap = (PPART_FILE_MAP_ENTRY)pStream->FileBitmap + (BlockOffset / pStream->BlockSize);
+
+ // Check if the flags are present
+ return (FileBitmap->Flags & 0x03) ? true : false;
+}
+
+static bool PartStream_BlockRead(
+ TBlockStream * pStream,
+ ULONGLONG StartOffset,
+ ULONGLONG EndOffset,
+ LPBYTE BlockBuffer,
+ DWORD BytesNeeded,
+ bool bAvailable)
+{
+ PPART_FILE_MAP_ENTRY FileBitmap;
+ ULONGLONG ByteOffset;
+ DWORD BytesToRead;
+ DWORD BlockIndex = (DWORD)(StartOffset / pStream->BlockSize);
+
+ // The starting offset must be aligned to size of the block
+ assert(pStream->FileBitmap != NULL);
+ assert((StartOffset & (pStream->BlockSize - 1)) == 0);
+ assert(StartOffset < EndOffset);
+
+ // If the blocks are not available, we need to load them from the master
+ // and then save to the mirror
+ if(bAvailable == false)
+ {
+ // If we have no master, we cannot satisfy read request
+ if(pStream->pMaster == NULL)
+ return false;
+
+ // Load the blocks from the master stream
+ // Note that we always have to read complete blocks
+ // so they get properly stored to the mirror stream
+ BytesToRead = (DWORD)(EndOffset - StartOffset);
+ if(!FileStream_Read(pStream->pMaster, &StartOffset, BlockBuffer, BytesToRead))
+ return false;
+
+ // The loaded blocks are going to be stored to the end of the file
+ // Note that this operation is not required to succeed
+ if(pStream->BaseGetSize(pStream, &ByteOffset))
+ {
+ // Store the loaded blocks to the mirror file.
+ if(pStream->BaseWrite(pStream, &ByteOffset, BlockBuffer, BytesToRead))
+ {
+ PartStream_UpdateBitmap(pStream, StartOffset, EndOffset, ByteOffset);
+ }
+ }
+ }
+ else
+ {
+ // Get the file map entry
+ FileBitmap = (PPART_FILE_MAP_ENTRY)pStream->FileBitmap + BlockIndex;
+
+ // Read all blocks
+ while(StartOffset < EndOffset)
+ {
+ // Get the number of bytes to be read
+ BytesToRead = (DWORD)(EndOffset - StartOffset);
+ if(BytesToRead > pStream->BlockSize)
+ BytesToRead = pStream->BlockSize;
+ if(BytesToRead > BytesNeeded)
+ BytesToRead = BytesNeeded;
+
+ // Read the block
+ ByteOffset = MAKE_OFFSET64(FileBitmap->BlockOffsHi, FileBitmap->BlockOffsLo);
+ if(!pStream->BaseRead(pStream, &ByteOffset, BlockBuffer, BytesToRead))
+ return false;
+
+ // Move the pointers
+ StartOffset += pStream->BlockSize;
+ BlockBuffer += pStream->BlockSize;
+ BytesNeeded -= pStream->BlockSize;
+ FileBitmap++;
+ }
+ }
+
+ return true;
+}
+
+static void PartStream_Close(TBlockStream * pStream)
+{
+ PART_FILE_HEADER PartHeader;
+ ULONGLONG ByteOffset = 0;
+
+ if(pStream->FileBitmap && pStream->IsModified)
+ {
+ // Prepare the part file header
+ memset(&PartHeader, 0, sizeof(PART_FILE_HEADER));
+ PartHeader.PartialVersion = 2;
+ PartHeader.FileSizeHi = (DWORD)(pStream->StreamSize >> 0x20);
+ PartHeader.FileSizeLo = (DWORD)(pStream->StreamSize & 0xFFFFFFFF);
+ PartHeader.BlockSize = pStream->BlockSize;
+
+ // Make sure that the header is properly BSWAPed
+ BSWAP_ARRAY32_UNSIGNED(&PartHeader, sizeof(PART_FILE_HEADER));
+ sprintf(PartHeader.GameBuildNumber, "%u", (unsigned int)pStream->BuildNumber);
+
+ // Write the part header
+ pStream->BaseWrite(pStream, &ByteOffset, &PartHeader, sizeof(PART_FILE_HEADER));
+
+ // Write the block bitmap
+ BSWAP_ARRAY32_UNSIGNED(pStream->FileBitmap, pStream->BitmapSize);
+ pStream->BaseWrite(pStream, NULL, pStream->FileBitmap, pStream->BitmapSize);
+ }
+
+ // Close the base class
+ BlockStream_Close(pStream);
+}
+
+static bool PartStream_CreateMirror(TBlockStream * pStream)
+{
+ ULONGLONG RemainingSize;
+ ULONGLONG MasterSize = 0;
+ ULONGLONG MirrorSize = 0;
+ LPBYTE FileBitmap = NULL;
+ DWORD dwBitmapSize;
+ DWORD dwBlockCount;
+ bool bNeedCreateMirrorStream = true;
+ bool bNeedResizeMirrorStream = true;
+
+ // Do we have master function and base creation function?
+ if(pStream->pMaster == NULL || pStream->BaseCreate == NULL)
+ return false;
+
+ // Retrieve the master file size, block count and bitmap size
+ FileStream_GetSize(pStream->pMaster, &MasterSize);
+ dwBlockCount = (DWORD)((MasterSize + DEFAULT_BLOCK_SIZE - 1) / DEFAULT_BLOCK_SIZE);
+ dwBitmapSize = (DWORD)(dwBlockCount * sizeof(PART_FILE_MAP_ENTRY));
+
+ // Setup stream size and position
+ pStream->BuildNumber = DEFAULT_BUILD_NUMBER; // BUGBUG: Really???
+ pStream->StreamSize = MasterSize;
+ pStream->StreamPos = 0;
+
+ // Open the base stream for write access
+ if(pStream->BaseOpen(pStream, pStream->szFileName, 0))
+ {
+ // If the file open succeeded, check if the file size matches required size
+ pStream->BaseGetSize(pStream, &MirrorSize);
+ if(MirrorSize >= sizeof(PART_FILE_HEADER) + dwBitmapSize)
+ {
+ // Check if the remaining size is aligned to block
+ RemainingSize = MirrorSize - sizeof(PART_FILE_HEADER) - dwBitmapSize;
+ if((RemainingSize & (DEFAULT_BLOCK_SIZE - 1)) == 0 || RemainingSize == MasterSize)
+ {
+ // Attempt to load an existing file bitmap
+ if(PartStream_LoadBitmap(pStream))
+ return true;
+ }
+ }
+
+ // We need to create mirror stream
+ bNeedCreateMirrorStream = false;
+ }
+
+ // Create a new stream, if needed
+ if(bNeedCreateMirrorStream)
+ {
+ if(!pStream->BaseCreate(pStream))
+ return false;
+ }
+
+ // If we need to, then resize the mirror stream
+ if(bNeedResizeMirrorStream)
+ {
+ if(!pStream->BaseResize(pStream, sizeof(PART_FILE_HEADER) + dwBitmapSize))
+ return false;
+ }
+
+ // Allocate the bitmap array
+ FileBitmap = CASC_ALLOC(BYTE, dwBitmapSize);
+ if(FileBitmap == NULL)
+ return false;
+
+ // Initialize the bitmap
+ memset(FileBitmap, 0, dwBitmapSize);
+ pStream->FileBitmap = FileBitmap;
+ pStream->BitmapSize = dwBitmapSize;
+ pStream->BlockSize = DEFAULT_BLOCK_SIZE;
+ pStream->BlockCount = dwBlockCount;
+ pStream->IsComplete = 0;
+ pStream->IsModified = 1;
+
+ // Note: Don't write the stream bitmap right away.
+ // Doing so would cause sparse file resize on NTFS,
+ // which would take long time on larger files.
+ return true;
+}
+
+
+static TFileStream * PartStream_Open(const TCHAR * szFileName, DWORD dwStreamFlags)
+{
+ TBlockStream * pStream;
+
+ // Create new empty stream
+ pStream = (TBlockStream *)AllocateFileStream(szFileName, sizeof(TBlockStream), dwStreamFlags);
+ if(pStream == NULL)
+ return NULL;
+
+ // Do we have a master stream?
+ if(pStream->pMaster != NULL)
+ {
+ if(!PartStream_CreateMirror(pStream))
+ {
+ FileStream_Close(pStream);
+ SetLastError(ERROR_FILE_NOT_FOUND);
+ return NULL;
+ }
+ }
+ else
+ {
+ // Attempt to open the base stream
+ if(!pStream->BaseOpen(pStream, pStream->szFileName, dwStreamFlags))
+ {
+ FileStream_Close(pStream);
+ return NULL;
+ }
+
+ // Load the part stream block map
+ if(!PartStream_LoadBitmap(pStream))
+ {
+ FileStream_Close(pStream);
+ SetLastError(ERROR_BAD_FORMAT);
+ return NULL;
+ }
+ }
+
+ // Set the stream position to zero. Stream size is already set
+ assert(pStream->StreamSize != 0);
+ pStream->StreamPos = 0;
+ pStream->dwFlags |= STREAM_FLAG_READ_ONLY;
+
+ // Set new function pointers
+ pStream->StreamRead = (STREAM_READ)BlockStream_Read;
+ pStream->StreamGetPos = BlockStream_GetPos;
+ pStream->StreamGetSize = BlockStream_GetSize;
+ pStream->StreamClose = (STREAM_CLOSE)PartStream_Close;
+
+ // Supply the block functions
+ pStream->BlockCheck = (BLOCK_CHECK)PartStream_BlockCheck;
+ pStream->BlockRead = (BLOCK_READ)PartStream_BlockRead;
+ return pStream;
+}
+
+//-----------------------------------------------------------------------------
+// Local functions - encrypted stream support
+
+static const char * szKeyTemplate = "expand 32-byte k000000000000000000000000000000000000000000000000";
+
+static const char * AuthCodeArray[] =
+{
+ // Starcraft II (Heart of the Swarm)
+ // Authentication code URL: http://dist.blizzard.com/mediakey/hots-authenticationcode-bgdl.txt
+ // -0C- -1C--08- -18--04- -14--00- -10-
+ "S48B6CDTN5XEQAKQDJNDLJBJ73FDFM3U", // SC2 Heart of the Swarm-all : "expand 32-byte kQAKQ0000FM3UN5XE000073FD6CDT0000LJBJS48B0000DJND"
+
+ // Diablo III: Agent.exe (1.0.0.954)
+ // Address of decryption routine: 00502b00
+ // Pointer to decryptor object: ECX
+ // Pointer to key: ECX+0x5C
+ // Authentication code URL: http://dist.blizzard.com/mediakey/d3-authenticationcode-enGB.txt
+ // -0C- -1C--08- -18--04- -14--00- -10-
+ "UCMXF6EJY352EFH4XFRXCFH2XC9MQRZK", // Diablo III Installer (deDE): "expand 32-byte kEFH40000QRZKY3520000XC9MF6EJ0000CFH2UCMX0000XFRX"
+ "MMKVHY48RP7WXP4GHYBQ7SL9J9UNPHBP", // Diablo III Installer (enGB): "expand 32-byte kXP4G0000PHBPRP7W0000J9UNHY4800007SL9MMKV0000HYBQ"
+ "8MXLWHQ7VGGLTZ9MQZQSFDCLJYET3CPP", // Diablo III Installer (enSG): "expand 32-byte kTZ9M00003CPPVGGL0000JYETWHQ70000FDCL8MXL0000QZQS"
+ "EJ2R5TM6XFE2GUNG5QDGHKQ9UAKPWZSZ", // Diablo III Installer (enUS): "expand 32-byte kGUNG0000WZSZXFE20000UAKP5TM60000HKQ9EJ2R00005QDG"
+ "PBGFBE42Z6LNK65UGJQ3WZVMCLP4HQQT", // Diablo III Installer (esES): "expand 32-byte kK65U0000HQQTZ6LN0000CLP4BE420000WZVMPBGF0000GJQ3"
+ "X7SEJJS9TSGCW5P28EBSC47AJPEY8VU2", // Diablo III Installer (esMX): "expand 32-byte kW5P200008VU2TSGC0000JPEYJJS90000C47AX7SE00008EBS"
+ "5KVBQA8VYE6XRY3DLGC5ZDE4XS4P7YA2", // Diablo III Installer (frFR): "expand 32-byte kRY3D00007YA2YE6X0000XS4PQA8V0000ZDE45KVB0000LGC5"
+ "478JD2K56EVNVVY4XX8TDWYT5B8KB254", // Diablo III Installer (itIT): "expand 32-byte kVVY40000B2546EVN00005B8KD2K50000DWYT478J0000XX8T"
+ "8TS4VNFQRZTN6YWHE9CHVDH9NVWD474A", // Diablo III Installer (koKR): "expand 32-byte k6YWH0000474ARZTN0000NVWDVNFQ0000VDH98TS40000E9CH"
+ "LJ52Z32DF4LZ4ZJJXVKK3AZQA6GABLJB", // Diablo III Installer (plPL): "expand 32-byte k4ZJJ0000BLJBF4LZ0000A6GAZ32D00003AZQLJ520000XVKK"
+ "K6BDHY2ECUE2545YKNLBJPVYWHE7XYAG", // Diablo III Installer (ptBR): "expand 32-byte k545Y0000XYAGCUE20000WHE7HY2E0000JPVYK6BD0000KNLB"
+ "NDVW8GWLAYCRPGRNY8RT7ZZUQU63VLPR", // Diablo III Installer (ruRU): "expand 32-byte kXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
+ "6VWCQTN8V3ZZMRUCZXV8A8CGUX2TAA8H", // Diablo III Installer (zhTW): "expand 32-byte kMRUC0000AA8HV3ZZ0000UX2TQTN80000A8CG6VWC0000ZXV8"
+// "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", // Diablo III Installer (zhCN): "expand 32-byte kXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
+
+ // Starcraft II (Wings of Liberty): Installer.exe (4.1.1.4219)
+ // Address of decryption routine: 0053A3D0
+ // Pointer to decryptor object: ECX
+ // Pointer to key: ECX+0x5C
+ // Authentication code URL: http://dist.blizzard.com/mediakey/sc2-authenticationcode-enUS.txt
+ // -0C- -1C--08- -18--04- -14--00- -10-
+ "Y45MD3CAK4KXSSXHYD9VY64Z8EKJ4XFX", // SC2 Wings of Liberty (deDE): "expand 32-byte kSSXH00004XFXK4KX00008EKJD3CA0000Y64ZY45M0000YD9V"
+ "G8MN8UDG6NA2ANGY6A3DNY82HRGF29ZH", // SC2 Wings of Liberty (enGB): "expand 32-byte kANGY000029ZH6NA20000HRGF8UDG0000NY82G8MN00006A3D"
+ "W9RRHLB2FDU9WW5B3ECEBLRSFWZSF7HW", // SC2 Wings of Liberty (enSG): "expand 32-byte kWW5B0000F7HWFDU90000FWZSHLB20000BLRSW9RR00003ECE"
+ "3DH5RE5NVM5GTFD85LXGWT6FK859ETR5", // SC2 Wings of Liberty (enUS): "expand 32-byte kTFD80000ETR5VM5G0000K859RE5N0000WT6F3DH500005LXG"
+ "8WLKUAXE94PFQU4Y249PAZ24N4R4XKTQ", // SC2 Wings of Liberty (esES): "expand 32-byte kQU4Y0000XKTQ94PF0000N4R4UAXE0000AZ248WLK0000249P"
+ "A34DXX3VHGGXSQBRFE5UFFDXMF9G4G54", // SC2 Wings of Liberty (esMX): "expand 32-byte kSQBR00004G54HGGX0000MF9GXX3V0000FFDXA34D0000FE5U"
+ "ZG7J9K938HJEFWPQUA768MA2PFER6EAJ", // SC2 Wings of Liberty (frFR): "expand 32-byte kFWPQ00006EAJ8HJE0000PFER9K9300008MA2ZG7J0000UA76"
+ "NE7CUNNNTVAPXV7E3G2BSVBWGVMW8BL2", // SC2 Wings of Liberty (itIT): "expand 32-byte kXV7E00008BL2TVAP0000GVMWUNNN0000SVBWNE7C00003G2B"
+ "3V9E2FTMBM9QQWK7U6MAMWAZWQDB838F", // SC2 Wings of Liberty (koKR): "expand 32-byte kQWK70000838FBM9Q0000WQDB2FTM0000MWAZ3V9E0000U6MA"
+ "2NSFB8MELULJ83U6YHA3UP6K4MQD48L6", // SC2 Wings of Liberty (plPL): "expand 32-byte k83U6000048L6LULJ00004MQDB8ME0000UP6K2NSF0000YHA3"
+ "QA2TZ9EWZ4CUU8BMB5WXCTY65F9CSW4E", // SC2 Wings of Liberty (ptBR): "expand 32-byte kU8BM0000SW4EZ4CU00005F9CZ9EW0000CTY6QA2T0000B5WX"
+ "VHB378W64BAT9SH7D68VV9NLQDK9YEGT", // SC2 Wings of Liberty (ruRU): "expand 32-byte k9SH70000YEGT4BAT0000QDK978W60000V9NLVHB30000D68V"
+ "U3NFQJV4M6GC7KBN9XQJ3BRDN3PLD9NE", // SC2 Wings of Liberty (zhTW): "expand 32-byte k7KBN0000D9NEM6GC0000N3PLQJV400003BRDU3NF00009XQJ"
+
+ NULL
+};
+
+static DWORD Rol32(DWORD dwValue, DWORD dwRolCount)
+{
+ DWORD dwShiftRight = 32 - dwRolCount;
+
+ return (dwValue << dwRolCount) | (dwValue >> dwShiftRight);
+}
+
+static void CreateKeyFromAuthCode(
+ LPBYTE pbKeyBuffer,
+ const char * szAuthCode)
+{
+ PDWORD KeyPosition = (PDWORD)(pbKeyBuffer + 0x10);
+ PDWORD AuthCode32 = (PDWORD)szAuthCode;
+
+ memcpy(pbKeyBuffer, szKeyTemplate, ENCRYPTED_CHUNK_SIZE);
+ KeyPosition[0x00] = AuthCode32[0x03];
+ KeyPosition[0x02] = AuthCode32[0x07];
+ KeyPosition[0x03] = AuthCode32[0x02];
+ KeyPosition[0x05] = AuthCode32[0x06];
+ KeyPosition[0x06] = AuthCode32[0x01];
+ KeyPosition[0x08] = AuthCode32[0x05];
+ KeyPosition[0x09] = AuthCode32[0x00];
+ KeyPosition[0x0B] = AuthCode32[0x04];
+ BSWAP_ARRAY32_UNSIGNED(pbKeyBuffer, ENCRYPTED_CHUNK_SIZE);
+}
+
+static void DecryptFileChunk(
+ DWORD * ChunkData,
+ LPBYTE pbKey,
+ ULONGLONG ByteOffset,
+ DWORD dwLength)
+{
+ ULONGLONG ChunkOffset;
+ DWORD KeyShuffled[0x10];
+ DWORD KeyMirror[0x10];
+ DWORD RoundCount = 0x14;
+
+ // Prepare the key
+ ChunkOffset = ByteOffset / ENCRYPTED_CHUNK_SIZE;
+ memcpy(KeyMirror, pbKey, ENCRYPTED_CHUNK_SIZE);
+ BSWAP_ARRAY32_UNSIGNED(KeyMirror, ENCRYPTED_CHUNK_SIZE);
+ KeyMirror[0x05] = (DWORD)(ChunkOffset >> 32);
+ KeyMirror[0x08] = (DWORD)(ChunkOffset);
+
+ while(dwLength >= ENCRYPTED_CHUNK_SIZE)
+ {
+ // Shuffle the key - part 1
+ KeyShuffled[0x0E] = KeyMirror[0x00];
+ KeyShuffled[0x0C] = KeyMirror[0x01];
+ KeyShuffled[0x05] = KeyMirror[0x02];
+ KeyShuffled[0x0F] = KeyMirror[0x03];
+ KeyShuffled[0x0A] = KeyMirror[0x04];
+ KeyShuffled[0x07] = KeyMirror[0x05];
+ KeyShuffled[0x0B] = KeyMirror[0x06];
+ KeyShuffled[0x09] = KeyMirror[0x07];
+ KeyShuffled[0x03] = KeyMirror[0x08];
+ KeyShuffled[0x06] = KeyMirror[0x09];
+ KeyShuffled[0x08] = KeyMirror[0x0A];
+ KeyShuffled[0x0D] = KeyMirror[0x0B];
+ KeyShuffled[0x02] = KeyMirror[0x0C];
+ KeyShuffled[0x04] = KeyMirror[0x0D];
+ KeyShuffled[0x01] = KeyMirror[0x0E];
+ KeyShuffled[0x00] = KeyMirror[0x0F];
+
+ // Shuffle the key - part 2
+ for(DWORD i = 0; i < RoundCount; i += 2)
+ {
+ KeyShuffled[0x0A] = KeyShuffled[0x0A] ^ Rol32((KeyShuffled[0x0E] + KeyShuffled[0x02]), 0x07);
+ KeyShuffled[0x03] = KeyShuffled[0x03] ^ Rol32((KeyShuffled[0x0A] + KeyShuffled[0x0E]), 0x09);
+ KeyShuffled[0x02] = KeyShuffled[0x02] ^ Rol32((KeyShuffled[0x03] + KeyShuffled[0x0A]), 0x0D);
+ KeyShuffled[0x0E] = KeyShuffled[0x0E] ^ Rol32((KeyShuffled[0x02] + KeyShuffled[0x03]), 0x12);
+
+ KeyShuffled[0x07] = KeyShuffled[0x07] ^ Rol32((KeyShuffled[0x0C] + KeyShuffled[0x04]), 0x07);
+ KeyShuffled[0x06] = KeyShuffled[0x06] ^ Rol32((KeyShuffled[0x07] + KeyShuffled[0x0C]), 0x09);
+ KeyShuffled[0x04] = KeyShuffled[0x04] ^ Rol32((KeyShuffled[0x06] + KeyShuffled[0x07]), 0x0D);
+ KeyShuffled[0x0C] = KeyShuffled[0x0C] ^ Rol32((KeyShuffled[0x04] + KeyShuffled[0x06]), 0x12);
+
+ KeyShuffled[0x0B] = KeyShuffled[0x0B] ^ Rol32((KeyShuffled[0x05] + KeyShuffled[0x01]), 0x07);
+ KeyShuffled[0x08] = KeyShuffled[0x08] ^ Rol32((KeyShuffled[0x0B] + KeyShuffled[0x05]), 0x09);
+ KeyShuffled[0x01] = KeyShuffled[0x01] ^ Rol32((KeyShuffled[0x08] + KeyShuffled[0x0B]), 0x0D);
+ KeyShuffled[0x05] = KeyShuffled[0x05] ^ Rol32((KeyShuffled[0x01] + KeyShuffled[0x08]), 0x12);
+
+ KeyShuffled[0x09] = KeyShuffled[0x09] ^ Rol32((KeyShuffled[0x0F] + KeyShuffled[0x00]), 0x07);
+ KeyShuffled[0x0D] = KeyShuffled[0x0D] ^ Rol32((KeyShuffled[0x09] + KeyShuffled[0x0F]), 0x09);
+ KeyShuffled[0x00] = KeyShuffled[0x00] ^ Rol32((KeyShuffled[0x0D] + KeyShuffled[0x09]), 0x0D);
+ KeyShuffled[0x0F] = KeyShuffled[0x0F] ^ Rol32((KeyShuffled[0x00] + KeyShuffled[0x0D]), 0x12);
+
+ KeyShuffled[0x04] = KeyShuffled[0x04] ^ Rol32((KeyShuffled[0x0E] + KeyShuffled[0x09]), 0x07);
+ KeyShuffled[0x08] = KeyShuffled[0x08] ^ Rol32((KeyShuffled[0x04] + KeyShuffled[0x0E]), 0x09);
+ KeyShuffled[0x09] = KeyShuffled[0x09] ^ Rol32((KeyShuffled[0x08] + KeyShuffled[0x04]), 0x0D);
+ KeyShuffled[0x0E] = KeyShuffled[0x0E] ^ Rol32((KeyShuffled[0x09] + KeyShuffled[0x08]), 0x12);
+
+ KeyShuffled[0x01] = KeyShuffled[0x01] ^ Rol32((KeyShuffled[0x0C] + KeyShuffled[0x0A]), 0x07);
+ KeyShuffled[0x0D] = KeyShuffled[0x0D] ^ Rol32((KeyShuffled[0x01] + KeyShuffled[0x0C]), 0x09);
+ KeyShuffled[0x0A] = KeyShuffled[0x0A] ^ Rol32((KeyShuffled[0x0D] + KeyShuffled[0x01]), 0x0D);
+ KeyShuffled[0x0C] = KeyShuffled[0x0C] ^ Rol32((KeyShuffled[0x0A] + KeyShuffled[0x0D]), 0x12);
+
+ KeyShuffled[0x00] = KeyShuffled[0x00] ^ Rol32((KeyShuffled[0x05] + KeyShuffled[0x07]), 0x07);
+ KeyShuffled[0x03] = KeyShuffled[0x03] ^ Rol32((KeyShuffled[0x00] + KeyShuffled[0x05]), 0x09);
+ KeyShuffled[0x07] = KeyShuffled[0x07] ^ Rol32((KeyShuffled[0x03] + KeyShuffled[0x00]), 0x0D);
+ KeyShuffled[0x05] = KeyShuffled[0x05] ^ Rol32((KeyShuffled[0x07] + KeyShuffled[0x03]), 0x12);
+
+ KeyShuffled[0x02] = KeyShuffled[0x02] ^ Rol32((KeyShuffled[0x0F] + KeyShuffled[0x0B]), 0x07);
+ KeyShuffled[0x06] = KeyShuffled[0x06] ^ Rol32((KeyShuffled[0x02] + KeyShuffled[0x0F]), 0x09);
+ KeyShuffled[0x0B] = KeyShuffled[0x0B] ^ Rol32((KeyShuffled[0x06] + KeyShuffled[0x02]), 0x0D);
+ KeyShuffled[0x0F] = KeyShuffled[0x0F] ^ Rol32((KeyShuffled[0x0B] + KeyShuffled[0x06]), 0x12);
+ }
+
+ // Decrypt one data chunk
+ BSWAP_ARRAY32_UNSIGNED(ChunkData, ENCRYPTED_CHUNK_SIZE);
+ ChunkData[0x00] = ChunkData[0x00] ^ (KeyShuffled[0x0E] + KeyMirror[0x00]);
+ ChunkData[0x01] = ChunkData[0x01] ^ (KeyShuffled[0x04] + KeyMirror[0x0D]);
+ ChunkData[0x02] = ChunkData[0x02] ^ (KeyShuffled[0x08] + KeyMirror[0x0A]);
+ ChunkData[0x03] = ChunkData[0x03] ^ (KeyShuffled[0x09] + KeyMirror[0x07]);
+ ChunkData[0x04] = ChunkData[0x04] ^ (KeyShuffled[0x0A] + KeyMirror[0x04]);
+ ChunkData[0x05] = ChunkData[0x05] ^ (KeyShuffled[0x0C] + KeyMirror[0x01]);
+ ChunkData[0x06] = ChunkData[0x06] ^ (KeyShuffled[0x01] + KeyMirror[0x0E]);
+ ChunkData[0x07] = ChunkData[0x07] ^ (KeyShuffled[0x0D] + KeyMirror[0x0B]);
+ ChunkData[0x08] = ChunkData[0x08] ^ (KeyShuffled[0x03] + KeyMirror[0x08]);
+ ChunkData[0x09] = ChunkData[0x09] ^ (KeyShuffled[0x07] + KeyMirror[0x05]);
+ ChunkData[0x0A] = ChunkData[0x0A] ^ (KeyShuffled[0x05] + KeyMirror[0x02]);
+ ChunkData[0x0B] = ChunkData[0x0B] ^ (KeyShuffled[0x00] + KeyMirror[0x0F]);
+ ChunkData[0x0C] = ChunkData[0x0C] ^ (KeyShuffled[0x02] + KeyMirror[0x0C]);
+ ChunkData[0x0D] = ChunkData[0x0D] ^ (KeyShuffled[0x06] + KeyMirror[0x09]);
+ ChunkData[0x0E] = ChunkData[0x0E] ^ (KeyShuffled[0x0B] + KeyMirror[0x06]);
+ ChunkData[0x0F] = ChunkData[0x0F] ^ (KeyShuffled[0x0F] + KeyMirror[0x03]);
+ BSWAP_ARRAY32_UNSIGNED(ChunkData, ENCRYPTED_CHUNK_SIZE);
+
+ // Update byte offset in the key
+ KeyMirror[0x08]++;
+ if(KeyMirror[0x08] == 0)
+ KeyMirror[0x05]++;
+
+ // Move pointers and decrease number of bytes to decrypt
+ ChunkData += (ENCRYPTED_CHUNK_SIZE / sizeof(DWORD));
+ dwLength -= ENCRYPTED_CHUNK_SIZE;
+ }
+}
+
+static bool EncrStream_DetectFileKey(TEncryptedStream * pStream)
+{
+ ULONGLONG ByteOffset = 0;
+ BYTE EncryptedHeader[ENCRYPTED_CHUNK_SIZE];
+ BYTE FileHeader[ENCRYPTED_CHUNK_SIZE];
+
+ // Read the first file chunk
+ if(pStream->BaseRead(pStream, &ByteOffset, EncryptedHeader, sizeof(EncryptedHeader)))
+ {
+ // We just try all known keys one by one
+ for(int i = 0; AuthCodeArray[i] != NULL; i++)
+ {
+ // Prepare they decryption key from game serial number
+ CreateKeyFromAuthCode(pStream->Key, AuthCodeArray[i]);
+
+ // Try to decrypt with the given key
+ memcpy(FileHeader, EncryptedHeader, ENCRYPTED_CHUNK_SIZE);
+ DecryptFileChunk((PDWORD)FileHeader, pStream->Key, ByteOffset, ENCRYPTED_CHUNK_SIZE);
+
+ // We check the decrypted data
+ // All known encrypted archives have header at the begin of the file,
+ // so we check for archive signature there.
+ if(FileHeader[0] == 'M' && FileHeader[1] == 'P' && FileHeader[2] == 'Q')
+ {
+ // Update the stream size
+ pStream->StreamSize = pStream->Base.File.FileSize;
+
+ // Fill the block information
+ pStream->BlockSize = ENCRYPTED_CHUNK_SIZE;
+ pStream->BlockCount = (DWORD)(pStream->Base.File.FileSize + ENCRYPTED_CHUNK_SIZE - 1) / ENCRYPTED_CHUNK_SIZE;
+ pStream->IsComplete = 1;
+ return true;
+ }
+ }
+ }
+
+ // Key not found, sorry
+ return false;
+}
+
+static bool EncrStream_BlockRead(
+ TEncryptedStream * pStream,
+ ULONGLONG StartOffset,
+ ULONGLONG EndOffset,
+ LPBYTE BlockBuffer,
+ DWORD BytesNeeded,
+ bool bAvailable)
+{
+ DWORD dwBytesToRead;
+
+ assert((StartOffset & (pStream->BlockSize - 1)) == 0);
+ assert(StartOffset < EndOffset);
+ assert(bAvailable != false);
+ BytesNeeded = BytesNeeded;
+ bAvailable = bAvailable;
+
+ // Read the file from the stream as-is
+ // Limit the reading to number of blocks really needed
+ dwBytesToRead = (DWORD)(EndOffset - StartOffset);
+ if(!pStream->BaseRead(pStream, &StartOffset, BlockBuffer, dwBytesToRead))
+ return false;
+
+ // Decrypt the data
+ dwBytesToRead = (dwBytesToRead + ENCRYPTED_CHUNK_SIZE - 1) & ~(ENCRYPTED_CHUNK_SIZE - 1);
+ DecryptFileChunk((PDWORD)BlockBuffer, pStream->Key, StartOffset, dwBytesToRead);
+ return true;
+}
+
+static TFileStream * EncrStream_Open(const TCHAR * szFileName, DWORD dwStreamFlags)
+{
+ TEncryptedStream * pStream;
+
+ // Create new empty stream
+ pStream = (TEncryptedStream *)AllocateFileStream(szFileName, sizeof(TEncryptedStream), dwStreamFlags);
+ if(pStream == NULL)
+ return NULL;
+
+ // Attempt to open the base stream
+ assert(pStream->BaseOpen != NULL);
+ if(!pStream->BaseOpen(pStream, pStream->szFileName, dwStreamFlags))
+ return NULL;
+
+ // Determine the encryption key for the archive
+ if(EncrStream_DetectFileKey(pStream))
+ {
+ // Set the stream position and size
+ assert(pStream->StreamSize != 0);
+ pStream->StreamPos = 0;
+ pStream->dwFlags |= STREAM_FLAG_READ_ONLY;
+
+ // Set new function pointers
+ pStream->StreamRead = (STREAM_READ)BlockStream_Read;
+ pStream->StreamGetPos = BlockStream_GetPos;
+ pStream->StreamGetSize = BlockStream_GetSize;
+ pStream->StreamClose = pStream->BaseClose;
+
+ // Supply the block functions
+ pStream->BlockRead = (BLOCK_READ)EncrStream_BlockRead;
+ return pStream;
+ }
+
+ // Cleanup the stream and return
+ FileStream_Close(pStream);
+ SetLastError(ERROR_UNKNOWN_FILE_KEY);
+ return NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Local functions - Block4 stream support
+
+#define BLOCK4_BLOCK_SIZE 0x4000 // Size of one block
+#define BLOCK4_HASH_SIZE 0x20 // Size of MD5 hash that is after each block
+#define BLOCK4_MAX_BLOCKS 0x00002000 // Maximum amount of blocks per file
+#define BLOCK4_MAX_FSIZE 0x08040000 // Max size of one file
+
+static bool Block4Stream_BlockRead(
+ TBlockStream * pStream, // Pointer to an open stream
+ ULONGLONG StartOffset,
+ ULONGLONG EndOffset,
+ LPBYTE BlockBuffer,
+ DWORD BytesNeeded,
+ bool bAvailable)
+{
+ TBaseProviderData * BaseArray = (TBaseProviderData *)pStream->FileBitmap;
+ ULONGLONG ByteOffset;
+ DWORD BytesToRead;
+ DWORD StreamIndex;
+ DWORD BlockIndex;
+ bool bResult;
+
+ // The starting offset must be aligned to size of the block
+ assert(pStream->FileBitmap != NULL);
+ assert((StartOffset & (pStream->BlockSize - 1)) == 0);
+ assert(StartOffset < EndOffset);
+ assert(bAvailable == true);
+
+ // Keep compiler happy
+ bAvailable = bAvailable;
+ EndOffset = EndOffset;
+
+ while(BytesNeeded != 0)
+ {
+ // Calculate the block index and the file index
+ StreamIndex = (DWORD)((StartOffset / pStream->BlockSize) / BLOCK4_MAX_BLOCKS);
+ BlockIndex = (DWORD)((StartOffset / pStream->BlockSize) % BLOCK4_MAX_BLOCKS);
+ if(StreamIndex > pStream->BitmapSize)
+ return false;
+
+ // Calculate the block offset
+ ByteOffset = ((ULONGLONG)BlockIndex * (BLOCK4_BLOCK_SIZE + BLOCK4_HASH_SIZE));
+ BytesToRead = CASCLIB_MIN(BytesNeeded, BLOCK4_BLOCK_SIZE);
+
+ // Read from the base stream
+ pStream->Base = BaseArray[StreamIndex];
+ bResult = pStream->BaseRead(pStream, &ByteOffset, BlockBuffer, BytesToRead);
+ BaseArray[StreamIndex] = pStream->Base;
+
+ // Did the result succeed?
+ if(bResult == false)
+ return false;
+
+ // Move pointers
+ StartOffset += BytesToRead;
+ BlockBuffer += BytesToRead;
+ BytesNeeded -= BytesToRead;
+ }
+
+ return true;
+}
+
+
+static void Block4Stream_Close(TBlockStream * pStream)
+{
+ TBaseProviderData * BaseArray = (TBaseProviderData *)pStream->FileBitmap;
+
+ // If we have a non-zero count of base streams,
+ // we have to close them all
+ if(BaseArray != NULL)
+ {
+ // Close all base streams
+ for(DWORD i = 0; i < pStream->BitmapSize; i++)
+ {
+ memcpy(&pStream->Base, BaseArray + i, sizeof(TBaseProviderData));
+ pStream->BaseClose(pStream);
+ }
+ }
+
+ // Free the data map, if any
+ if(pStream->FileBitmap != NULL)
+ CASC_FREE(pStream->FileBitmap);
+ pStream->FileBitmap = NULL;
+
+ // Do not call the BaseClose function,
+ // we closed all handles already
+ return;
+}
+
+static TFileStream * Block4Stream_Open(const TCHAR * szFileName, DWORD dwStreamFlags)
+{
+ TBaseProviderData * NewBaseArray = NULL;
+ ULONGLONG RemainderBlock;
+ ULONGLONG BlockCount;
+ ULONGLONG FileSize;
+ TBlockStream * pStream;
+ TCHAR * szNameBuff;
+ size_t nNameLength;
+ DWORD dwBaseFiles = 0;
+ DWORD dwBaseFlags;
+
+ // Create new empty stream
+ pStream = (TBlockStream *)AllocateFileStream(szFileName, sizeof(TBlockStream), dwStreamFlags);
+ if(pStream == NULL)
+ return NULL;
+
+ // Sanity check
+ assert(pStream->BaseOpen != NULL);
+
+ // Get the length of the file name without numeric suffix
+ nNameLength = _tcslen(pStream->szFileName);
+ if(pStream->szFileName[nNameLength - 2] == '.' && pStream->szFileName[nNameLength - 1] == '0')
+ nNameLength -= 2;
+ pStream->szFileName[nNameLength] = 0;
+
+ // Supply the stream functions
+ pStream->StreamRead = (STREAM_READ)BlockStream_Read;
+ pStream->StreamGetSize = BlockStream_GetSize;
+ pStream->StreamGetPos = BlockStream_GetPos;
+ pStream->StreamClose = (STREAM_CLOSE)Block4Stream_Close;
+ pStream->BlockRead = (BLOCK_READ)Block4Stream_BlockRead;
+
+ // Allocate work space for numeric names
+ szNameBuff = CASC_ALLOC(TCHAR, nNameLength + 4);
+ if(szNameBuff != NULL)
+ {
+ // Set the base flags
+ dwBaseFlags = (dwStreamFlags & STREAM_PROVIDERS_MASK) | STREAM_FLAG_READ_ONLY;
+
+ // Go all suffixes from 0 to 30
+ for(int nSuffix = 0; nSuffix < 30; nSuffix++)
+ {
+ // Open the n-th file
+ _stprintf(szNameBuff, _T("%s.%u"), pStream->szFileName, nSuffix);
+ if(!pStream->BaseOpen(pStream, szNameBuff, dwBaseFlags))
+ break;
+
+ // If the open succeeded, we re-allocate the base provider array
+ NewBaseArray = CASC_ALLOC(TBaseProviderData, dwBaseFiles + 1);
+ if(NewBaseArray == NULL)
+ {
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ return NULL;
+ }
+
+ // Copy the old base data array to the new base data array
+ if(pStream->FileBitmap != NULL)
+ {
+ memcpy(NewBaseArray, pStream->FileBitmap, sizeof(TBaseProviderData) * dwBaseFiles);
+ CASC_FREE(pStream->FileBitmap);
+ }
+
+ // Also copy the opened base array
+ memcpy(NewBaseArray + dwBaseFiles, &pStream->Base, sizeof(TBaseProviderData));
+ pStream->FileBitmap = NewBaseArray;
+ dwBaseFiles++;
+
+ // Get the size of the base stream
+ pStream->BaseGetSize(pStream, &FileSize);
+ assert(FileSize <= BLOCK4_MAX_FSIZE);
+ RemainderBlock = FileSize % (BLOCK4_BLOCK_SIZE + BLOCK4_HASH_SIZE);
+ BlockCount = FileSize / (BLOCK4_BLOCK_SIZE + BLOCK4_HASH_SIZE);
+
+ // Increment the stream size and number of blocks
+ pStream->StreamSize += (BlockCount * BLOCK4_BLOCK_SIZE);
+ pStream->BlockCount += (DWORD)BlockCount;
+
+ // Is this the last file?
+ if(FileSize < BLOCK4_MAX_FSIZE)
+ {
+ if(RemainderBlock)
+ {
+ pStream->StreamSize += (RemainderBlock - BLOCK4_HASH_SIZE);
+ pStream->BlockCount++;
+ }
+ break;
+ }
+ }
+
+ // Fill the remainining block stream variables
+ pStream->BitmapSize = dwBaseFiles;
+ pStream->BlockSize = BLOCK4_BLOCK_SIZE;
+ pStream->IsComplete = 1;
+ pStream->IsModified = 0;
+
+ // Fill the remaining stream variables
+ pStream->StreamPos = 0;
+ pStream->dwFlags |= STREAM_FLAG_READ_ONLY;
+
+ CASC_FREE(szNameBuff);
+ }
+
+ // If we opened something, return success
+ if(dwBaseFiles == 0)
+ {
+ FileStream_Close(pStream);
+ SetLastError(ERROR_FILE_NOT_FOUND);
+ pStream = NULL;
+ }
+
+ return pStream;
+}
+
+//-----------------------------------------------------------------------------
+// Public functions
+
+/**
+ * This function creates a new file for read-write access
+ *
+ * - If the current platform supports file sharing,
+ * the file must be created for read sharing (i.e. another application
+ * can open the file for read, but not for write)
+ * - If the file does not exist, the function must create new one
+ * - If the file exists, the function must rewrite it and set to zero size
+ * - The parameters of the function must be validate by the caller
+ * - The function must initialize all stream function pointers in TFileStream
+ * - If the function fails from any reason, it must close all handles
+ * and free all memory that has been allocated in the process of stream creation,
+ * including the TFileStream structure itself
+ *
+ * \a szFileName Name of the file to create
+ */
+
+TFileStream * FileStream_CreateFile(
+ const TCHAR * szFileName,
+ DWORD dwStreamFlags)
+{
+ TFileStream * pStream;
+
+ // We only support creation of flat, local file
+ if((dwStreamFlags & (STREAM_PROVIDERS_MASK)) != (STREAM_PROVIDER_FLAT | BASE_PROVIDER_FILE))
+ {
+ SetLastError(ERROR_NOT_SUPPORTED);
+ return NULL;
+ }
+
+ // Allocate file stream structure for flat stream
+ pStream = AllocateFileStream(szFileName, sizeof(TBlockStream), dwStreamFlags);
+ if(pStream != NULL)
+ {
+ // Attempt to create the disk file
+ if(BaseFile_Create(pStream))
+ {
+ // Fill the stream provider functions
+ pStream->StreamRead = pStream->BaseRead;
+ pStream->StreamWrite = pStream->BaseWrite;
+ pStream->StreamResize = pStream->BaseResize;
+ pStream->StreamGetSize = pStream->BaseGetSize;
+ pStream->StreamGetPos = pStream->BaseGetPos;
+ pStream->StreamClose = pStream->BaseClose;
+ return pStream;
+ }
+
+ // File create failed, delete the stream
+ CASC_FREE(pStream);
+ pStream = NULL;
+ }
+
+ // Return the stream
+ return pStream;
+}
+
+/**
+ * This function opens an existing file for read or read-write access
+ * - If the current platform supports file sharing,
+ * the file must be open for read sharing (i.e. another application
+ * can open the file for read, but not for write)
+ * - If the file does not exist, the function must return NULL
+ * - If the file exists but cannot be open, then function must return NULL
+ * - The parameters of the function must be validate by the caller
+ * - The function must initialize all stream function pointers in TFileStream
+ * - If the function fails from any reason, it must close all handles
+ * and free all memory that has been allocated in the process of stream creation,
+ * including the TFileStream structure itself
+ *
+ * \a szFileName Name of the file to open
+ * \a dwStreamFlags specifies the provider and base storage type
+ */
+
+TFileStream * FileStream_OpenFile(
+ const TCHAR * szFileName,
+ DWORD dwStreamFlags)
+{
+ DWORD dwProvider = dwStreamFlags & STREAM_PROVIDERS_MASK;
+ size_t nPrefixLength = FileStream_Prefix(szFileName, &dwProvider);
+
+ // Re-assemble the stream flags
+ dwStreamFlags = (dwStreamFlags & STREAM_OPTIONS_MASK) | dwProvider;
+ szFileName += nPrefixLength;
+
+ // Perform provider-specific open
+ switch(dwStreamFlags & STREAM_PROVIDER_MASK)
+ {
+ case STREAM_PROVIDER_FLAT:
+ return FlatStream_Open(szFileName, dwStreamFlags);
+
+ case STREAM_PROVIDER_PARTIAL:
+ return PartStream_Open(szFileName, dwStreamFlags);
+
+ case STREAM_PROVIDER_ENCRYPTED:
+ return EncrStream_Open(szFileName, dwStreamFlags);
+
+ case STREAM_PROVIDER_BLOCK4:
+ return Block4Stream_Open(szFileName, dwStreamFlags);
+
+ default:
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return NULL;
+ }
+}
+
+/**
+ * Returns the file name of the stream
+ *
+ * \a pStream Pointer to an open stream
+ */
+const TCHAR * FileStream_GetFileName(TFileStream * pStream)
+{
+ assert(pStream != NULL);
+ return pStream->szFileName;
+}
+
+/**
+ * Returns the length of the provider prefix. Returns zero if no prefix
+ *
+ * \a szFileName Pointer to a stream name (file, mapped file, URL)
+ * \a pdwStreamProvider Pointer to a DWORD variable that receives stream provider (STREAM_PROVIDER_XXX)
+ */
+
+size_t FileStream_Prefix(const TCHAR * szFileName, DWORD * pdwProvider)
+{
+ size_t nPrefixLength1 = 0;
+ size_t nPrefixLength2 = 0;
+ DWORD dwProvider = 0;
+
+ if(szFileName != NULL)
+ {
+ //
+ // Determine the stream provider
+ //
+
+ if(!_tcsnicmp(szFileName, _T("flat-"), 5))
+ {
+ dwProvider |= STREAM_PROVIDER_FLAT;
+ nPrefixLength1 = 5;
+ }
+
+ else if(!_tcsnicmp(szFileName, _T("part-"), 5))
+ {
+ dwProvider |= STREAM_PROVIDER_PARTIAL;
+ nPrefixLength1 = 5;
+ }
+
+ else if(!_tcsnicmp(szFileName, _T("mpqe-"), 5))
+ {
+ dwProvider |= STREAM_PROVIDER_ENCRYPTED;
+ nPrefixLength1 = 5;
+ }
+
+ else if(!_tcsnicmp(szFileName, _T("blk4-"), 5))
+ {
+ dwProvider |= STREAM_PROVIDER_BLOCK4;
+ nPrefixLength1 = 5;
+ }
+
+ //
+ // Determine the base provider
+ //
+
+ if(!_tcsnicmp(szFileName+nPrefixLength1, _T("file:"), 5))
+ {
+ dwProvider |= BASE_PROVIDER_FILE;
+ nPrefixLength2 = 5;
+ }
+
+ else if(!_tcsnicmp(szFileName+nPrefixLength1, _T("map:"), 4))
+ {
+ dwProvider |= BASE_PROVIDER_MAP;
+ nPrefixLength2 = 4;
+ }
+
+ else if(!_tcsnicmp(szFileName+nPrefixLength1, _T("http:"), 5))
+ {
+ dwProvider |= BASE_PROVIDER_HTTP;
+ nPrefixLength2 = 5;
+ }
+
+ // Only accept stream provider if we recognized the base provider
+ if(nPrefixLength2 != 0)
+ {
+ // It is also allowed to put "//" after the base provider, e.g. "file://", "http://"
+ if(szFileName[nPrefixLength1+nPrefixLength2] == '/' && szFileName[nPrefixLength1+nPrefixLength2+1] == '/')
+ nPrefixLength2 += 2;
+
+ if(pdwProvider != NULL)
+ *pdwProvider = dwProvider;
+ return nPrefixLength1 + nPrefixLength2;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * Sets a download callback. Whenever the stream needs to download one or more blocks
+ * from the server, the callback is called
+ *
+ * \a pStream Pointer to an open stream
+ * \a pfnCallback Pointer to callback function
+ * \a pvUserData Arbitrary user pointer passed to the download callback
+ */
+
+bool FileStream_SetCallback(TFileStream * pStream, STREAM_DOWNLOAD_CALLBACK pfnCallback, void * pvUserData)
+{
+ TBlockStream * pBlockStream = (TBlockStream *)pStream;
+
+ if(pStream->BlockRead == NULL)
+ {
+ SetLastError(ERROR_NOT_SUPPORTED);
+ return false;
+ }
+
+ pBlockStream->pfnCallback = pfnCallback;
+ pBlockStream->UserData = pvUserData;
+ return true;
+}
+
+/**
+ * Reads data from the stream
+ *
+ * - Returns true if the read operation succeeded and all bytes have been read
+ * - Returns false if either read failed or not all bytes have been read
+ * - If the pByteOffset is NULL, the function must read the data from the current file position
+ * - The function can be called with dwBytesToRead = 0. In that case, pvBuffer is ignored
+ * and the function just adjusts file pointer.
+ *
+ * \a pStream Pointer to an open stream
+ * \a pByteOffset Pointer to file byte offset. If NULL, it reads from the current position
+ * \a pvBuffer Pointer to data to be read
+ * \a dwBytesToRead Number of bytes to read from the file
+ *
+ * \returns
+ * - If the function reads the required amount of bytes, it returns true.
+ * - If the function reads less than required bytes, it returns false and GetLastError() returns ERROR_HANDLE_EOF
+ * - If the function fails, it reads false and GetLastError() returns an error code different from ERROR_HANDLE_EOF
+ */
+bool FileStream_Read(TFileStream * pStream, ULONGLONG * pByteOffset, void * pvBuffer, DWORD dwBytesToRead)
+{
+ assert(pStream->StreamRead != NULL);
+ return pStream->StreamRead(pStream, pByteOffset, pvBuffer, dwBytesToRead);
+}
+
+/**
+ * This function writes data to the stream
+ *
+ * - Returns true if the write operation succeeded and all bytes have been written
+ * - Returns false if either write failed or not all bytes have been written
+ * - If the pByteOffset is NULL, the function must write the data to the current file position
+ *
+ * \a pStream Pointer to an open stream
+ * \a pByteOffset Pointer to file byte offset. If NULL, it reads from the current position
+ * \a pvBuffer Pointer to data to be written
+ * \a dwBytesToWrite Number of bytes to write to the file
+ */
+bool FileStream_Write(TFileStream * pStream, ULONGLONG * pByteOffset, const void * pvBuffer, DWORD dwBytesToWrite)
+{
+ if(pStream->dwFlags & STREAM_FLAG_READ_ONLY)
+ {
+ SetLastError(ERROR_ACCESS_DENIED);
+ return false;
+ }
+
+ assert(pStream->StreamWrite != NULL);
+ return pStream->StreamWrite(pStream, pByteOffset, pvBuffer, dwBytesToWrite);
+}
+
+/**
+ * Returns the size of a file
+ *
+ * \a pStream Pointer to an open stream
+ * \a FileSize Pointer where to store the file size
+ */
+bool FileStream_GetSize(TFileStream * pStream, ULONGLONG * pFileSize)
+{
+ assert(pStream->StreamGetSize != NULL);
+ return pStream->StreamGetSize(pStream, pFileSize);
+}
+
+/**
+ * Sets the size of a file
+ *
+ * \a pStream Pointer to an open stream
+ * \a NewFileSize File size to set
+ */
+bool FileStream_SetSize(TFileStream * pStream, ULONGLONG NewFileSize)
+{
+ if(pStream->dwFlags & STREAM_FLAG_READ_ONLY)
+ {
+ SetLastError(ERROR_ACCESS_DENIED);
+ return false;
+ }
+
+ assert(pStream->StreamResize != NULL);
+ return pStream->StreamResize(pStream, NewFileSize);
+}
+
+/**
+ * This function returns the current file position
+ * \a pStream
+ * \a pByteOffset
+ */
+bool FileStream_GetPos(TFileStream * pStream, ULONGLONG * pByteOffset)
+{
+ assert(pStream->StreamGetPos != NULL);
+ return pStream->StreamGetPos(pStream, pByteOffset);
+}
+
+/**
+ * Returns the last write time of a file
+ *
+ * \a pStream Pointer to an open stream
+ * \a pFileType Pointer where to store the file last write time
+ */
+bool FileStream_GetTime(TFileStream * pStream, ULONGLONG * pFileTime)
+{
+ // Just use the saved filetime value
+ *pFileTime = pStream->Base.File.FileTime;
+ return true;
+}
+
+/**
+ * Returns the stream flags
+ *
+ * \a pStream Pointer to an open stream
+ * \a pdwStreamFlags Pointer where to store the stream flags
+ */
+bool FileStream_GetFlags(TFileStream * pStream, PDWORD pdwStreamFlags)
+{
+ *pdwStreamFlags = pStream->dwFlags;
+ return true;
+}
+
+/**
+ * Switches a stream with another. Used for final phase of archive compacting.
+ * Performs these steps:
+ *
+ * 1) Closes the handle to the existing file
+ * 2) Renames the temporary file to the original file, overwrites existing one
+ * 3) Opens the file stores the handle and stream position to the new stream structure
+ *
+ * \a pStream Pointer to an open stream
+ * \a pNewStream Temporary ("working") stream (created during archive compacting)
+ */
+bool FileStream_Replace(TFileStream * pStream, TFileStream * pNewStream)
+{
+ // Only supported on flat files
+ if((pStream->dwFlags & STREAM_PROVIDERS_MASK) != (STREAM_PROVIDER_FLAT | BASE_PROVIDER_FILE))
+ {
+ SetLastError(ERROR_NOT_SUPPORTED);
+ return false;
+ }
+
+ // Not supported on read-only streams
+ if(pStream->dwFlags & STREAM_FLAG_READ_ONLY)
+ {
+ SetLastError(ERROR_ACCESS_DENIED);
+ return false;
+ }
+
+ // Close both stream's base providers
+ pNewStream->BaseClose(pNewStream);
+ pStream->BaseClose(pStream);
+
+ // Now we have to delete the (now closed) old file and rename the new file
+ if(!BaseFile_Replace(pStream, pNewStream))
+ return false;
+
+ // Now open the base file again
+ if(!BaseFile_Open(pStream, pStream->szFileName, pStream->dwFlags))
+ return false;
+
+ // Cleanup the new stream
+ FileStream_Close(pNewStream);
+ return true;
+}
+
+/**
+ * This function closes an archive file and frees any data buffers
+ * that have been allocated for stream management. The function must also
+ * support partially allocated structure, i.e. one or more buffers
+ * can be NULL, if there was an allocation failure during the process
+ *
+ * \a pStream Pointer to an open stream
+ */
+void FileStream_Close(TFileStream * pStream)
+{
+ // Check if the stream structure is allocated at all
+ if(pStream != NULL)
+ {
+ // Free the master stream, if any
+ if(pStream->pMaster != NULL)
+ FileStream_Close(pStream->pMaster);
+ pStream->pMaster = NULL;
+
+ // Close the stream provider.
+ if(pStream->StreamClose != NULL)
+ pStream->StreamClose(pStream);
+
+ // Also close base stream, if any
+ else if(pStream->BaseClose != NULL)
+ pStream->BaseClose(pStream);
+
+ // Free the stream itself
+ CASC_FREE(pStream);
+ }
+}
diff --git a/dep/CascLib/src/common/FileStream.h b/dep/CascLib/src/common/FileStream.h
new file mode 100644
index 00000000000..1e51acfc845
--- /dev/null
+++ b/dep/CascLib/src/common/FileStream.h
@@ -0,0 +1,238 @@
+/*****************************************************************************/
+/* FileStream.h Copyright (c) Ladislav Zezula 2012 */
+/*---------------------------------------------------------------------------*/
+/* Description: Definitions for FileStream object */
+/*---------------------------------------------------------------------------*/
+/* Date Ver Who Comment */
+/* -------- ---- --- ------- */
+/* 14.04.12 1.00 Lad The first version of FileStream.h */
+/*****************************************************************************/
+
+#ifndef __FILESTREAM_H__
+#define __FILESTREAM_H__
+
+//-----------------------------------------------------------------------------
+// Function prototypes
+
+typedef void (*STREAM_INIT)(
+ struct TFileStream * pStream // Pointer to an unopened stream
+);
+
+typedef bool (*STREAM_CREATE)(
+ struct TFileStream * pStream // Pointer to an unopened stream
+ );
+
+typedef bool (*STREAM_OPEN)(
+ struct TFileStream * pStream, // Pointer to an unopened stream
+ const TCHAR * szFileName, // Pointer to file name to be open
+ DWORD dwStreamFlags // Stream flags
+ );
+
+typedef bool (*STREAM_READ)(
+ struct TFileStream * pStream, // Pointer to an open stream
+ ULONGLONG * pByteOffset, // Pointer to file byte offset. If NULL, it reads from the current position
+ void * pvBuffer, // Pointer to data to be read
+ DWORD dwBytesToRead // Number of bytes to read from the file
+ );
+
+typedef bool (*STREAM_WRITE)(
+ struct TFileStream * pStream, // Pointer to an open stream
+ ULONGLONG * pByteOffset, // Pointer to file byte offset. If NULL, it writes to the current position
+ const void * pvBuffer, // Pointer to data to be written
+ DWORD dwBytesToWrite // Number of bytes to read from the file
+ );
+
+typedef bool (*STREAM_RESIZE)(
+ struct TFileStream * pStream, // Pointer to an open stream
+ ULONGLONG FileSize // New size for the file, in bytes
+ );
+
+typedef bool (*STREAM_GETSIZE)(
+ struct TFileStream * pStream, // Pointer to an open stream
+ ULONGLONG * pFileSize // Receives the file size, in bytes
+ );
+
+typedef bool (*STREAM_GETPOS)(
+ struct TFileStream * pStream, // Pointer to an open stream
+ ULONGLONG * pByteOffset // Pointer to store current file position
+ );
+
+typedef void (*STREAM_CLOSE)(
+ struct TFileStream * pStream // Pointer to an open stream
+ );
+
+typedef bool (*BLOCK_READ)(
+ struct TFileStream * pStream, // Pointer to a block-oriented stream
+ ULONGLONG StartOffset, // Byte offset of start of the block array
+ ULONGLONG EndOffset, // End offset (either end of the block or end of the file)
+ LPBYTE BlockBuffer, // Pointer to block-aligned buffer
+ DWORD BytesNeeded, // Number of bytes that are really needed
+ bool bAvailable // true if the block is available
+ );
+
+typedef bool (*BLOCK_CHECK)(
+ struct TFileStream * pStream, // Pointer to a block-oriented stream
+ ULONGLONG BlockOffset // Offset of the file to check
+ );
+
+typedef void (*BLOCK_SAVEMAP)(
+ struct TFileStream * pStream // Pointer to a block-oriented stream
+ );
+
+//-----------------------------------------------------------------------------
+// Local structures - partial file structure and bitmap footer
+
+#define ID_FILE_BITMAP_FOOTER 0x33767470 // Signature of the file bitmap footer ('ptv3')
+#define DEFAULT_BLOCK_SIZE 0x00004000 // Default size of the stream block
+#define DEFAULT_BUILD_NUMBER 10958 // Build number for newly created partial MPQs
+
+typedef struct _PART_FILE_HEADER
+{
+ DWORD PartialVersion; // Always set to 2
+ char GameBuildNumber[0x20]; // Minimum build number of the game that can use this MPQ
+ DWORD Flags; // Flags (details unknown)
+ DWORD FileSizeLo; // Low 32 bits of the contained file size
+ DWORD FileSizeHi; // High 32 bits of the contained file size
+ DWORD BlockSize; // Size of one file block, in bytes
+
+} PART_FILE_HEADER, *PPART_FILE_HEADER;
+
+// Structure describing the block-to-file map entry
+typedef struct _PART_FILE_MAP_ENTRY
+{
+ DWORD Flags; // 3 = the block is present in the file
+ DWORD BlockOffsLo; // Low 32 bits of the block position in the file
+ DWORD BlockOffsHi; // High 32 bits of the block position in the file
+ DWORD LargeValueLo; // 64-bit value, meaning is unknown
+ DWORD LargeValueHi;
+
+} PART_FILE_MAP_ENTRY, *PPART_FILE_MAP_ENTRY;
+
+typedef struct _FILE_BITMAP_FOOTER
+{
+ DWORD Signature; // 'ptv3' (ID_FILE_BITMAP_FOOTER)
+ DWORD Version; // Unknown, seems to always have value of 3 (version?)
+ DWORD BuildNumber; // Game build number for that MPQ
+ DWORD MapOffsetLo; // Low 32-bits of the offset of the bit map
+ DWORD MapOffsetHi; // High 32-bits of the offset of the bit map
+ DWORD BlockSize; // Size of one block (usually 0x4000 bytes)
+
+} FILE_BITMAP_FOOTER, *PFILE_BITMAP_FOOTER;
+
+//-----------------------------------------------------------------------------
+// Structure for file stream
+
+union TBaseProviderData
+{
+ struct
+ {
+ ULONGLONG FileSize; // Size of the file
+ ULONGLONG FilePos; // Current file position
+ ULONGLONG FileTime; // Last write time
+ HANDLE hFile; // File handle
+ } File;
+
+ struct
+ {
+ ULONGLONG FileSize; // Size of the file
+ ULONGLONG FilePos; // Current file position
+ ULONGLONG FileTime; // Last write time
+ LPBYTE pbFile; // Pointer to mapped view
+ } Map;
+
+ struct
+ {
+ ULONGLONG FileSize; // Size of the file
+ ULONGLONG FilePos; // Current file position
+ ULONGLONG FileTime; // Last write time
+ HANDLE hInternet; // Internet handle
+ HANDLE hConnect; // Connection to the internet server
+ } Http;
+};
+
+struct TFileStream
+{
+ // Stream provider functions
+ STREAM_READ StreamRead; // Pointer to stream read function for this archive. Do not use directly.
+ STREAM_WRITE StreamWrite; // Pointer to stream write function for this archive. Do not use directly.
+ STREAM_RESIZE StreamResize; // Pointer to function changing file size
+ STREAM_GETSIZE StreamGetSize; // Pointer to function returning file size
+ STREAM_GETPOS StreamGetPos; // Pointer to function that returns current file position
+ STREAM_CLOSE StreamClose; // Pointer to function closing the stream
+
+ // Block-oriented functions
+ BLOCK_READ BlockRead; // Pointer to function reading one or more blocks
+ BLOCK_CHECK BlockCheck; // Pointer to function checking whether the block is present
+
+ // Base provider functions
+ STREAM_CREATE BaseCreate; // Pointer to base create function
+ STREAM_OPEN BaseOpen; // Pointer to base open function
+ STREAM_READ BaseRead; // Read from the stream
+ STREAM_WRITE BaseWrite; // Write to the stream
+ STREAM_RESIZE BaseResize; // Pointer to function changing file size
+ STREAM_GETSIZE BaseGetSize; // Pointer to function returning file size
+ STREAM_GETPOS BaseGetPos; // Pointer to function that returns current file position
+ STREAM_CLOSE BaseClose; // Pointer to function closing the stream
+
+ // Base provider data (file size, file position)
+ TBaseProviderData Base;
+
+ // Stream provider data
+ TFileStream * pMaster; // Master stream (e.g. MPQ on a web server)
+ TCHAR * szFileName; // File name (self-relative pointer)
+
+ ULONGLONG StreamSize; // Stream size (can be less than file size)
+ ULONGLONG StreamPos; // Stream position
+ DWORD BuildNumber; // Game build number
+ DWORD dwFlags; // Stream flags
+
+ // Followed by stream provider data, with variable length
+};
+
+//-----------------------------------------------------------------------------
+// Structures for block-oriented stream
+
+struct TBlockStream : public TFileStream
+{
+ STREAM_DOWNLOAD_CALLBACK pfnCallback; // Callback for downloading
+ void * FileBitmap; // Array of bits for file blocks
+ void * UserData; // User data to be passed to the download callback
+ DWORD BitmapSize; // Size of the file bitmap (in bytes)
+ DWORD BlockSize; // Size of one block, in bytes
+ DWORD BlockCount; // Number of data blocks in the file
+ DWORD IsComplete; // If nonzero, no blocks are missing
+ DWORD IsModified; // nonzero if the bitmap has been modified
+};
+
+//-----------------------------------------------------------------------------
+// Structure for encrypted stream
+
+#define ENCRYPTED_CHUNK_SIZE 0x40 // Size of one chunk to be decrypted
+
+struct TEncryptedStream : public TBlockStream
+{
+ BYTE Key[ENCRYPTED_CHUNK_SIZE]; // File key
+};
+
+//-----------------------------------------------------------------------------
+// Public functions for file stream
+
+TFileStream * FileStream_CreateFile(const TCHAR * szFileName, DWORD dwStreamFlags);
+TFileStream * FileStream_OpenFile(const TCHAR * szFileName, DWORD dwStreamFlags);
+const TCHAR * FileStream_GetFileName(TFileStream * pStream);
+size_t FileStream_Prefix(const TCHAR * szFileName, DWORD * pdwProvider);
+
+bool FileStream_SetCallback(TFileStream * pStream, STREAM_DOWNLOAD_CALLBACK pfnCallback, void * pvUserData);
+
+bool FileStream_Read(TFileStream * pStream, ULONGLONG * pByteOffset, void * pvBuffer, DWORD dwBytesToRead);
+bool FileStream_Write(TFileStream * pStream, ULONGLONG * pByteOffset, const void * pvBuffer, DWORD dwBytesToWrite);
+bool FileStream_SetSize(TFileStream * pStream, ULONGLONG NewFileSize);
+bool FileStream_GetSize(TFileStream * pStream, ULONGLONG * pFileSize);
+bool FileStream_GetPos(TFileStream * pStream, ULONGLONG * pByteOffset);
+bool FileStream_GetTime(TFileStream * pStream, ULONGLONG * pFT);
+bool FileStream_GetFlags(TFileStream * pStream, PDWORD pdwStreamFlags);
+bool FileStream_Replace(TFileStream * pStream, TFileStream * pNewStream);
+void FileStream_Close(TFileStream * pStream);
+
+
+#endif // __FILESTREAM_H__
diff --git a/dep/CascLib/src/common/ListFile.cpp b/dep/CascLib/src/common/ListFile.cpp
new file mode 100644
index 00000000000..4b742b1d07c
--- /dev/null
+++ b/dep/CascLib/src/common/ListFile.cpp
@@ -0,0 +1,266 @@
+/*****************************************************************************/
+/* ListFile.cpp Copyright (c) Ladislav Zezula 2004 */
+/*---------------------------------------------------------------------------*/
+/* Description: */
+/*---------------------------------------------------------------------------*/
+/* Date Ver Who Comment */
+/* -------- ---- --- ------- */
+/* 12.06.04 1.00 Lad The first version of ListFile.cpp */
+/*****************************************************************************/
+
+#define __CASCLIB_SELF__
+#include "../CascLib.h"
+#include "../CascCommon.h"
+
+//-----------------------------------------------------------------------------
+// Listfile entry structure
+
+#define CACHE_BUFFER_SIZE 0x1000 // Size of the cache buffer
+
+typedef bool (*RELOAD_CACHE)(void * pvCacheContext, LPBYTE pbBuffer, DWORD dwBytesToRead);
+typedef void (*CLOSE_STREAM)(void * pvCacheContext);
+
+struct TListFileCache
+{
+ RELOAD_CACHE pfnReloadCache; // Function for reloading the cache
+ CLOSE_STREAM pfnCloseStream; // Function for closing the stream
+ void * pvCacheContext; // Reload context passed to reload function
+ char * szMask; // Self-relative pointer to file mask
+ DWORD dwFileSize; // Total size of the cached file
+ DWORD dwFilePos; // Position of the cache in the file
+ BYTE * pBegin; // The begin of the listfile cache
+ BYTE * pPos;
+ BYTE * pEnd; // The last character in the file cache
+
+ BYTE Buffer[CACHE_BUFFER_SIZE];
+// char MaskBuff[1] // Followed by the name mask (if any)
+};
+
+//-----------------------------------------------------------------------------
+// Local functions
+
+static bool ReloadCache_ExternalFile(void * pvCacheContext, LPBYTE pbBuffer, DWORD dwBytesToRead)
+{
+ TFileStream * pStream = (TFileStream *)pvCacheContext;
+
+ return FileStream_Read(pStream, NULL, pbBuffer, dwBytesToRead);
+}
+
+static void CloseStream_ExternalFile(void * pvCacheContext)
+{
+ TFileStream * pStream = (TFileStream *)pvCacheContext;
+
+ return FileStream_Close(pStream);
+}
+
+
+// Reloads the cache. Returns number of characters
+// that has been loaded into the cache.
+static DWORD ReloadListFileCache(TListFileCache * pCache)
+{
+ DWORD dwBytesToRead = 0;
+
+ // Only do something if the cache is empty
+ if(pCache->pPos >= pCache->pEnd)
+ {
+ // Move the file position forward
+ pCache->dwFilePos += CACHE_BUFFER_SIZE;
+ if(pCache->dwFilePos >= pCache->dwFileSize)
+ return 0;
+
+ // Get the number of bytes remaining
+ dwBytesToRead = pCache->dwFileSize - pCache->dwFilePos;
+ if(dwBytesToRead > CACHE_BUFFER_SIZE)
+ dwBytesToRead = CACHE_BUFFER_SIZE;
+
+ // Load the next data chunk to the cache
+ // If we didn't read anything, it might mean that the block
+ // of the file is not available
+ // We stop reading the file at this point, because the rest
+ // of the listfile is unreliable
+ if(!pCache->pfnReloadCache(pCache->pvCacheContext, pCache->Buffer, dwBytesToRead))
+ return 0;
+
+ // Set the buffer pointers
+ pCache->pBegin =
+ pCache->pPos = &pCache->Buffer[0];
+ pCache->pEnd = pCache->pBegin + dwBytesToRead;
+ }
+
+ return dwBytesToRead;
+}
+
+static size_t ReadListFileLine(TListFileCache * pCache, char * szLine, size_t nMaxChars)
+{
+ char * szLineBegin = szLine;
+ char * szLineEnd = szLine + nMaxChars - 1;
+ char * szExtraString = NULL;
+
+ // Skip newlines, spaces, tabs and another non-printable stuff
+ for(;;)
+ {
+ // If we need to reload the cache, do it
+ if(pCache->pPos == pCache->pEnd)
+ {
+ if(ReloadListFileCache(pCache) == 0)
+ break;
+ }
+
+ // If we found a non-whitespace character, stop
+ if(pCache->pPos[0] > 0x20)
+ break;
+
+ // Skip the character
+ pCache->pPos++;
+ }
+
+ // Copy the remaining characters
+ while(szLine < szLineEnd)
+ {
+ // If we need to reload the cache, do it now and resume copying
+ if(pCache->pPos == pCache->pEnd)
+ {
+ if(ReloadListFileCache(pCache) == 0)
+ break;
+ }
+
+ // If we have found a newline, stop loading
+ if(*pCache->pPos == 0x0D || *pCache->pPos == 0x0A)
+ break;
+
+ // Blizzard listfiles can also contain information about patch:
+ // Pass1\Files\MacOS\unconditional\user\Background Downloader.app\Contents\Info.plist~Patch(Data#frFR#base-frFR,1326)
+ if(*pCache->pPos == '~')
+ szExtraString = szLine;
+
+ // Copy the character
+ *szLine++ = *pCache->pPos++;
+ }
+
+ // Terminate line with zero
+ *szLine = 0;
+
+ // If there was extra string after the file name, clear it
+ if(szExtraString != NULL)
+ {
+ if(szExtraString[0] == '~' && szExtraString[1] == 'P')
+ {
+ szLine = szExtraString;
+ *szExtraString = 0;
+ }
+ }
+
+ // Return the length of the line
+ return (szLine - szLineBegin);
+}
+
+static TListFileCache * CreateListFileCache(RELOAD_CACHE pfnReloadCache, CLOSE_STREAM pfnCloseStream, void * pvCacheContext, DWORD dwFileSize)
+{
+ TListFileCache * pCache = NULL;
+ DWORD dwBytesToRead;
+
+ // Allocate cache for one file block
+ pCache = (TListFileCache *)CASC_ALLOC(BYTE, sizeof(TListFileCache));
+ if(pCache != NULL)
+ {
+ // Clear the entire structure
+ memset(pCache, 0, sizeof(TListFileCache));
+ pCache->pfnReloadCache = pfnReloadCache;
+ pCache->pfnCloseStream = pfnCloseStream;
+ pCache->pvCacheContext = pvCacheContext;
+ pCache->dwFileSize = dwFileSize;
+
+ // Load the file cache from the file
+ dwBytesToRead = CASCLIB_MIN(CACHE_BUFFER_SIZE, dwFileSize);
+ if(pfnReloadCache(pvCacheContext, pCache->Buffer, dwBytesToRead))
+ {
+ // Allocate pointers
+ pCache->pBegin = pCache->pPos = &pCache->Buffer[0];
+ pCache->pEnd = pCache->pBegin + dwBytesToRead;
+ }
+ else
+ {
+ ListFile_Free(pCache);
+ pCache = NULL;
+ }
+ }
+
+ // Return the cache
+ return pCache;
+}
+
+//-----------------------------------------------------------------------------
+// Listfile functions
+
+void * ListFile_OpenExternal(const TCHAR * szListFile)
+{
+ TListFileCache * pCache;
+ TFileStream * pStream;
+ ULONGLONG FileSize = 0;
+
+ // Open the external listfile
+ pStream = FileStream_OpenFile(szListFile, STREAM_FLAG_READ_ONLY);
+ if(pStream != NULL)
+ {
+ // Retrieve the size of the external listfile
+ FileStream_GetSize(pStream, &FileSize);
+ if(0 < FileSize && FileSize <= 0xFFFFFFFF)
+ {
+ // Create the cache for the listfile
+ pCache = CreateListFileCache(ReloadCache_ExternalFile, CloseStream_ExternalFile, pStream, (DWORD)FileSize);
+ if(pCache != NULL)
+ return pCache;
+ }
+
+ // Close the file stream
+ FileStream_Close(pStream);
+ }
+
+ return NULL;
+}
+
+size_t ListFile_GetNext(void * pvListFile, const char * szMask, char * szBuffer, size_t nMaxChars)
+{
+ TListFileCache * pCache = (TListFileCache *)pvListFile;
+ size_t nLength = 0;
+ int nError = ERROR_INVALID_PARAMETER;
+
+ // Check for parameters
+ if(pCache != NULL)
+ {
+ for(;;)
+ {
+ // Read the (next) line
+ nLength = ReadListFileLine(pCache, szBuffer, nMaxChars);
+ if(nLength == 0)
+ {
+ nError = ERROR_NO_MORE_FILES;
+ break;
+ }
+
+ // If some mask entered, check it
+ if(CheckWildCard(szBuffer, szMask))
+ {
+ nError = ERROR_SUCCESS;
+ break;
+ }
+ }
+ }
+
+ if(nError != ERROR_SUCCESS)
+ SetLastError(nError);
+ return nLength;
+}
+
+void ListFile_Free(void * pvListFile)
+{
+ TListFileCache * pCache = (TListFileCache *)pvListFile;
+
+ // Valid parameter check
+ if(pCache != NULL)
+ {
+ if(pCache->pfnCloseStream != NULL)
+ pCache->pfnCloseStream(pCache->pvCacheContext);
+ CASC_FREE(pCache);
+ }
+}
diff --git a/dep/CascLib/src/common/ListFile.h b/dep/CascLib/src/common/ListFile.h
new file mode 100644
index 00000000000..1c603af3766
--- /dev/null
+++ b/dep/CascLib/src/common/ListFile.h
@@ -0,0 +1,18 @@
+/*****************************************************************************/
+/* ListFile.h Copyright (c) Ladislav Zezula 2014 */
+/*---------------------------------------------------------------------------*/
+/* Common functions for CascLib */
+/*---------------------------------------------------------------------------*/
+/* Date Ver Who Comment */
+/* -------- ---- --- ------- */
+/* 10.05.14 1.00 Lad The first version of ListFile.h */
+/*****************************************************************************/
+
+#ifndef __LISTFILE_H__
+#define __LISTFILE_H__
+
+void * ListFile_OpenExternal(const TCHAR * szListFile);
+size_t ListFile_GetNext(void * pvListFile, const char * szMask, char * szBuffer, size_t nMaxChars);
+void ListFile_Free(void * pvListFile);
+
+#endif // __LISTFILE_H__
diff --git a/dep/CascLib/src/common/Map.cpp b/dep/CascLib/src/common/Map.cpp
new file mode 100644
index 00000000000..70697a158ab
--- /dev/null
+++ b/dep/CascLib/src/common/Map.cpp
@@ -0,0 +1,178 @@
+/*****************************************************************************/
+/* Map.cpp Copyright (c) Ladislav Zezula 2014 */
+/*---------------------------------------------------------------------------*/
+/* Implementation of map for CascLib */
+/*---------------------------------------------------------------------------*/
+/* Date Ver Who Comment */
+/* -------- ---- --- ------- */
+/* 10.06.14 1.00 Lad The first version of Map.cpp */
+/*****************************************************************************/
+
+#define __CASCLIB_SELF__
+#include "../CascLib.h"
+#include "../CascCommon.h"
+
+//-----------------------------------------------------------------------------
+// Local functions
+
+static DWORD CalcHashIndex(PCASC_MAP pMap, void * pvIdentifier)
+{
+ DWORD dwHash = 0x7EEE7EEE;
+
+ // Is it a string table?
+ if(pMap->KeyLength == KEY_LENGTH_STRING)
+ {
+ char * szString = (char *)pvIdentifier;
+
+ for(size_t i = 0; szString[i] != 0; i++)
+ dwHash = (dwHash >> 24) ^ (dwHash << 5) ^ dwHash ^ szString[i];
+ }
+ else
+ {
+ LPBYTE pbHash = (LPBYTE)pvIdentifier;
+
+ // Construct the hash from the first 4 digits
+ for(size_t i = 0; i < pMap->KeyLength; i++)
+ dwHash = (dwHash >> 24) ^ (dwHash << 5) ^ dwHash ^ pbHash[i];
+ }
+
+ // Return the hash limited by the table size
+ return (dwHash % pMap->TableSize);
+}
+
+static bool CompareIdentifier(PCASC_MAP pMap, void * pvTableEntry, void * pvIdentifier)
+{
+ // Is it a string table?
+ if(pMap->KeyLength == KEY_LENGTH_STRING)
+ {
+ char * szTableEntry = (char *)pvTableEntry;
+ char * szIdentifier = (char *)pvIdentifier;
+
+ return (strcmp(szTableEntry, szIdentifier) == 0);
+ }
+ else
+ {
+ return (memcmp(pvTableEntry, pvIdentifier, pMap->KeyLength) == 0);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Public functions
+
+PCASC_MAP Map_Create(DWORD dwMaxItems, DWORD dwKeyLength, DWORD dwMemberOffset)
+{
+ PCASC_MAP pMap;
+ size_t cbToAllocate;
+ size_t dwTableSize;
+
+ // Calculate the size of the table
+ dwTableSize = (dwMaxItems * 3 / 2) | 0x01;
+
+ // Allocate new map for the objects
+ cbToAllocate = sizeof(CASC_MAP) + (dwTableSize * sizeof(void *));
+ pMap = (PCASC_MAP)CASC_ALLOC(LPBYTE, cbToAllocate);
+ if(pMap != NULL)
+ {
+ memset(pMap, 0, cbToAllocate);
+ pMap->KeyLength = dwKeyLength;
+ pMap->TableSize = dwTableSize;
+ pMap->MemberOffset = dwMemberOffset;
+ }
+
+ // Return the allocated map
+ return pMap;
+}
+
+size_t Map_EnumObjects(PCASC_MAP pMap, void **ppvArray)
+{
+ size_t nIndex = 0;
+
+ // Verify pointer to the map
+ if(pMap != NULL && ppvArray != NULL)
+ {
+ // Enumerate all items in main table
+ for(size_t i = 0; i < pMap->TableSize; i++)
+ {
+ // Is that cell valid?
+ if(pMap->HashTable[i] != NULL)
+ {
+ ppvArray[nIndex++] = pMap->HashTable[i];
+ }
+ }
+ }
+
+ return pMap->ItemCount;
+}
+
+void * Map_FindObject(PCASC_MAP pMap, void * pvIdentifier)
+{
+ void * pvTableEntry;
+ DWORD dwHashIndex;
+
+ // Verify pointer to the map
+ if(pMap != NULL)
+ {
+ // Construct the main index
+ dwHashIndex = CalcHashIndex(pMap, pvIdentifier);
+ while(pMap->HashTable[dwHashIndex] != NULL)
+ {
+ // Get the pointer at that position
+ pvTableEntry = pMap->HashTable[dwHashIndex];
+
+ // Compare the hash
+ if(CompareIdentifier(pMap, pvTableEntry, pvIdentifier))
+ return ((LPBYTE)pvTableEntry - pMap->MemberOffset);
+
+ // Move to the next entry
+ dwHashIndex = (dwHashIndex + 1) % pMap->TableSize;
+ }
+ }
+
+ // Not found, sorry
+ return NULL;
+}
+
+bool Map_InsertObject(PCASC_MAP pMap, void * pvIdentifier)
+{
+ void * pvTableEntry;
+ DWORD dwHashIndex;
+
+ // Verify pointer to the map
+ if(pMap != NULL)
+ {
+ // Limit check
+ if((pMap->ItemCount + 1) >= pMap->TableSize)
+ return false;
+
+ // Construct the hash index
+ dwHashIndex = CalcHashIndex(pMap, pvIdentifier);
+ while(pMap->HashTable[dwHashIndex] != NULL)
+ {
+ // Get the pointer at that position
+ pvTableEntry = pMap->HashTable[dwHashIndex];
+
+ // Check if hash being inserted conflicts with an existing hash
+ if(CompareIdentifier(pMap, pvTableEntry, pvIdentifier))
+ return false;
+
+ // Move to the next entry
+ dwHashIndex = (dwHashIndex + 1) % pMap->TableSize;
+ }
+
+ // Insert at that position
+ pMap->HashTable[dwHashIndex] = pvIdentifier;
+ pMap->ItemCount++;
+ return true;
+ }
+
+ // Failed
+ return false;
+}
+
+void Map_Free(PCASC_MAP pMap)
+{
+ if(pMap != NULL)
+ {
+ CASC_FREE(pMap);
+ }
+}
diff --git a/dep/CascLib/src/common/Map.h b/dep/CascLib/src/common/Map.h
new file mode 100644
index 00000000000..b4b9c918df3
--- /dev/null
+++ b/dep/CascLib/src/common/Map.h
@@ -0,0 +1,39 @@
+/*****************************************************************************/
+/* Map.h Copyright (c) Ladislav Zezula 2014 */
+/*---------------------------------------------------------------------------*/
+/* Interface of hash-to-ptr map for CascLib */
+/*---------------------------------------------------------------------------*/
+/* Date Ver Who Comment */
+/* -------- ---- --- ------- */
+/* 10.06.14 1.00 Lad The first version of Map.h */
+/*****************************************************************************/
+
+#ifndef __HASHTOPTR_H__
+#define __HASHTOPTR_H__
+
+//-----------------------------------------------------------------------------
+// Structures
+
+#define KEY_LENGTH_STRING 0xFFFFFFFF // Pass this to Map_Create as dwKeyLength when you want map of string->object
+
+typedef struct _CASC_MAP
+{
+ size_t TableSize;
+ size_t ItemCount; // Number of items in the map
+ size_t MemberOffset; // How far is the hash from the begin of the structure (in bytes)
+ size_t KeyLength; // Length of the hash key
+ void * HashTable[1]; // Pointer table
+
+} CASC_MAP, *PCASC_MAP;
+
+//-----------------------------------------------------------------------------
+// Functions
+
+PCASC_MAP Map_Create(DWORD dwMaxItems, DWORD dwKeyLength, DWORD dwMemberOffset);
+size_t Map_EnumObjects(PCASC_MAP pMap, void **ppvArray);
+void * Map_FindObject(PCASC_MAP pMap, void * pvIdentifier);
+bool Map_InsertObject(PCASC_MAP pMap, void * pvIdentifier);
+void Map_Sort(PCASC_MAP pMap);
+void Map_Free(PCASC_MAP pMap);
+
+#endif // __HASHTOPTR_H__
diff --git a/dep/CascLib/src/jenkins/lookup.h b/dep/CascLib/src/jenkins/lookup.h
new file mode 100644
index 00000000000..54ccc979ca6
--- /dev/null
+++ b/dep/CascLib/src/jenkins/lookup.h
@@ -0,0 +1,24 @@
+#ifndef __LOOKUP3_H__
+#define __LOOKUP3_H__
+
+#ifdef WIN32
+typedef unsigned char uint8_t;
+typedef unsigned short uint16_t;
+typedef unsigned int uint32_t;
+#else
+#include <stdint.h> /* defines uint32_t etc */
+#endif
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+uint32_t hashlittle(const void *key, size_t length, uint32_t initval);
+void hashlittle2(const void *key, size_t length, uint32_t *pc, uint32_t *pb);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __LOOKUP3_H__
diff --git a/dep/CascLib/src/jenkins/lookup3.c b/dep/CascLib/src/jenkins/lookup3.c
new file mode 100644
index 00000000000..6af56b481ad
--- /dev/null
+++ b/dep/CascLib/src/jenkins/lookup3.c
@@ -0,0 +1,1003 @@
+/*
+-------------------------------------------------------------------------------
+lookup3.c, by Bob Jenkins, May 2006, Public Domain.
+
+These are functions for producing 32-bit hashes for hash table lookup.
+hashword(), hashlittle(), hashlittle2(), hashbig(), mix(), and final()
+are externally useful functions. Routines to test the hash are included
+if SELF_TEST is defined. You can use this free for any purpose. It's in
+the public domain. It has no warranty.
+
+You probably want to use hashlittle(). hashlittle() and hashbig()
+hash byte arrays. hashlittle() is is faster than hashbig() on
+little-endian machines. Intel and AMD are little-endian machines.
+On second thought, you probably want hashlittle2(), which is identical to
+hashlittle() except it returns two 32-bit hashes for the price of one.
+You could implement hashbig2() if you wanted but I haven't bothered here.
+
+If you want to find a hash of, say, exactly 7 integers, do
+ a = i1; b = i2; c = i3;
+ mix(a,b,c);
+ a += i4; b += i5; c += i6;
+ mix(a,b,c);
+ a += i7;
+ final(a,b,c);
+then use c as the hash value. If you have a variable length array of
+4-byte integers to hash, use hashword(). If you have a byte array (like
+a character string), use hashlittle(). If you have several byte arrays, or
+a mix of things, see the comments above hashlittle().
+
+Why is this so big? I read 12 bytes at a time into 3 4-byte integers,
+then mix those integers. This is fast (you can do a lot more thorough
+mixing with 12*3 instructions on 3 integers than you can with 3 instructions
+on 1 byte), but shoehorning those bytes into integers efficiently is messy.
+-------------------------------------------------------------------------------
+*/
+//#define SELF_TEST 1
+
+#include <stdio.h> /* defines printf for tests */
+#include <time.h> /* defines time_t for timings in the test */
+
+#ifdef linux
+#include <sys/param.h> /* attempt to define endianness */
+#include <endian.h> /* attempt to define endianness */
+#endif
+
+#include "lookup.h"
+
+/*
+ * My best guess at if you are big-endian or little-endian. This may
+ * need adjustment.
+ */
+#if (defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && \
+ __BYTE_ORDER == __LITTLE_ENDIAN) || \
+ (defined(i386) || defined(__i386__) || defined(__i486__) || \
+ defined(__i586__) || defined(__i686__) || defined(vax) || defined(MIPSEL))
+# define HASH_LITTLE_ENDIAN 1
+# define HASH_BIG_ENDIAN 0
+#elif (defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && \
+ __BYTE_ORDER == __BIG_ENDIAN) || \
+ (defined(sparc) || defined(POWERPC) || defined(mc68000) || defined(sel))
+# define HASH_LITTLE_ENDIAN 0
+# define HASH_BIG_ENDIAN 1
+#else
+# define HASH_LITTLE_ENDIAN 0
+# define HASH_BIG_ENDIAN 0
+#endif
+
+#define hashsize(n) ((uint32_t)1<<(n))
+#define hashmask(n) (hashsize(n)-1)
+#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
+
+/*
+-------------------------------------------------------------------------------
+mix -- mix 3 32-bit values reversibly.
+
+This is reversible, so any information in (a,b,c) before mix() is
+still in (a,b,c) after mix().
+
+If four pairs of (a,b,c) inputs are run through mix(), or through
+mix() in reverse, there are at least 32 bits of the output that
+are sometimes the same for one pair and different for another pair.
+This was tested for:
+* pairs that differed by one bit, by two bits, in any combination
+ of top bits of (a,b,c), or in any combination of bottom bits of
+ (a,b,c).
+* "differ" is defined as +, -, ^, or ~^. For + and -, I transformed
+ the output delta to a Gray code (a^(a>>1)) so a string of 1's (as
+ is commonly produced by subtraction) look like a single 1-bit
+ difference.
+* the base values were pseudorandom, all zero but one bit set, or
+ all zero plus a counter that starts at zero.
+
+Some k values for my "a-=c; a^=rot(c,k); c+=b;" arrangement that
+satisfy this are
+ 4 6 8 16 19 4
+ 9 15 3 18 27 15
+ 14 9 3 7 17 3
+Well, "9 15 3 18 27 15" didn't quite get 32 bits diffing
+for "differ" defined as + with a one-bit base and a two-bit delta. I
+used http://burtleburtle.net/bob/hash/avalanche.html to choose
+the operations, constants, and arrangements of the variables.
+
+This does not achieve avalanche. There are input bits of (a,b,c)
+that fail to affect some output bits of (a,b,c), especially of a. The
+most thoroughly mixed value is c, but it doesn't really even achieve
+avalanche in c.
+
+This allows some parallelism. Read-after-writes are good at doubling
+the number of bits affected, so the goal of mixing pulls in the opposite
+direction as the goal of parallelism. I did what I could. Rotates
+seem to cost as much as shifts on every machine I could lay my hands
+on, and rotates are much kinder to the top and bottom bits, so I used
+rotates.
+-------------------------------------------------------------------------------
+*/
+#define mix(a,b,c) \
+{ \
+ a -= c; a ^= rot(c, 4); c += b; \
+ b -= a; b ^= rot(a, 6); a += c; \
+ c -= b; c ^= rot(b, 8); b += a; \
+ a -= c; a ^= rot(c,16); c += b; \
+ b -= a; b ^= rot(a,19); a += c; \
+ c -= b; c ^= rot(b, 4); b += a; \
+}
+
+/*
+-------------------------------------------------------------------------------
+final -- final mixing of 3 32-bit values (a,b,c) into c
+
+Pairs of (a,b,c) values differing in only a few bits will usually
+produce values of c that look totally different. This was tested for
+* pairs that differed by one bit, by two bits, in any combination
+ of top bits of (a,b,c), or in any combination of bottom bits of
+ (a,b,c).
+* "differ" is defined as +, -, ^, or ~^. For + and -, I transformed
+ the output delta to a Gray code (a^(a>>1)) so a string of 1's (as
+ is commonly produced by subtraction) look like a single 1-bit
+ difference.
+* the base values were pseudorandom, all zero but one bit set, or
+ all zero plus a counter that starts at zero.
+
+These constants passed:
+ 14 11 25 16 4 14 24
+ 12 14 25 16 4 14 24
+and these came close:
+ 4 8 15 26 3 22 24
+ 10 8 15 26 3 22 24
+ 11 8 15 26 3 22 24
+-------------------------------------------------------------------------------
+*/
+#define final(a,b,c) \
+{ \
+ c ^= b; c -= rot(b,14); \
+ a ^= c; a -= rot(c,11); \
+ b ^= a; b -= rot(a,25); \
+ c ^= b; c -= rot(b,16); \
+ a ^= c; a -= rot(c,4); \
+ b ^= a; b -= rot(a,14); \
+ c ^= b; c -= rot(b,24); \
+}
+
+/*
+--------------------------------------------------------------------
+ This works on all machines. To be useful, it requires
+ -- that the key be an array of uint32_t's, and
+ -- that the length be the number of uint32_t's in the key
+
+ The function hashword() is identical to hashlittle() on little-endian
+ machines, and identical to hashbig() on big-endian machines,
+ except that the length has to be measured in uint32_ts rather than in
+ bytes. hashlittle() is more complicated than hashword() only because
+ hashlittle() has to dance around fitting the key bytes into registers.
+--------------------------------------------------------------------
+*/
+uint32_t hashword(
+const uint32_t *k, /* the key, an array of uint32_t values */
+size_t length, /* the length of the key, in uint32_ts */
+uint32_t initval) /* the previous hash, or an arbitrary value */
+{
+ uint32_t a,b,c;
+
+ /* Set up the internal state */
+ a = b = c = 0xdeadbeef + (((uint32_t)length)<<2) + initval;
+
+ /*------------------------------------------------- handle most of the key */
+ while (length > 3)
+ {
+ a += k[0];
+ b += k[1];
+ c += k[2];
+ mix(a,b,c);
+ length -= 3;
+ k += 3;
+ }
+
+ /*------------------------------------------- handle the last 3 uint32_t's */
+ switch(length) /* all the case statements fall through */
+ {
+ case 3 : c+=k[2];
+ case 2 : b+=k[1];
+ case 1 : a+=k[0];
+ final(a,b,c);
+ case 0: /* case 0: nothing left to add */
+ break;
+ }
+ /*------------------------------------------------------ report the result */
+ return c;
+}
+
+
+/*
+--------------------------------------------------------------------
+hashword2() -- same as hashword(), but take two seeds and return two
+32-bit values. pc and pb must both be nonnull, and *pc and *pb must
+both be initialized with seeds. If you pass in (*pb)==0, the output
+(*pc) will be the same as the return value from hashword().
+--------------------------------------------------------------------
+*/
+void hashword2 (
+const uint32_t *k, /* the key, an array of uint32_t values */
+size_t length, /* the length of the key, in uint32_ts */
+uint32_t *pc, /* IN: seed OUT: primary hash value */
+uint32_t *pb) /* IN: more seed OUT: secondary hash value */
+{
+ uint32_t a,b,c;
+
+ /* Set up the internal state */
+ a = b = c = 0xdeadbeef + ((uint32_t)(length<<2)) + *pc;
+ c += *pb;
+
+ /*------------------------------------------------- handle most of the key */
+ while (length > 3)
+ {
+ a += k[0];
+ b += k[1];
+ c += k[2];
+ mix(a,b,c);
+ length -= 3;
+ k += 3;
+ }
+
+ /*------------------------------------------- handle the last 3 uint32_t's */
+ switch(length) /* all the case statements fall through */
+ {
+ case 3 : c+=k[2];
+ case 2 : b+=k[1];
+ case 1 : a+=k[0];
+ final(a,b,c);
+ case 0: /* case 0: nothing left to add */
+ break;
+ }
+ /*------------------------------------------------------ report the result */
+ *pc=c; *pb=b;
+}
+
+
+/*
+-------------------------------------------------------------------------------
+hashlittle() -- hash a variable-length key into a 32-bit value
+ k : the key (the unaligned variable-length array of bytes)
+ length : the length of the key, counting by bytes
+ initval : can be any 4-byte value
+Returns a 32-bit value. Every bit of the key affects every bit of
+the return value. Two keys differing by one or two bits will have
+totally different hash values.
+
+The best hash table sizes are powers of 2. There is no need to do
+mod a prime (mod is sooo slow!). If you need less than 32 bits,
+use a bitmask. For example, if you need only 10 bits, do
+ h = (h & hashmask(10));
+In which case, the hash table should have hashsize(10) elements.
+
+If you are hashing n strings (uint8_t **)k, do it like this:
+ for (i=0, h=0; i<n; ++i) h = hashlittle( k[i], len[i], h);
+
+By Bob Jenkins, 2006. bob_jenkins@burtleburtle.net. You may use this
+code any way you wish, private, educational, or commercial. It's free.
+
+Use for hash table lookup, or anything where one collision in 2^^32 is
+acceptable. Do NOT use for cryptographic purposes.
+-------------------------------------------------------------------------------
+*/
+
+uint32_t hashlittle( const void *key, size_t length, uint32_t initval)
+{
+ uint32_t a,b,c; /* internal state */
+ union { const void *ptr; size_t i; } u; /* needed for Mac Powerbook G4 */
+
+ /* Set up the internal state */
+ a = b = c = 0xdeadbeef + ((uint32_t)length) + initval;
+
+ u.ptr = key;
+ if (HASH_LITTLE_ENDIAN && ((u.i & 0x3) == 0)) {
+ const uint32_t *k = (const uint32_t *)key; /* read 32-bit chunks */
+ const uint8_t *k8;
+
+ /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */
+ while (length > 12)
+ {
+ a += k[0];
+ b += k[1];
+ c += k[2];
+ mix(a,b,c);
+ length -= 12;
+ k += 3;
+ }
+
+ /*----------------------------- handle the last (probably partial) block */
+ /*
+ * "k[2]&0xffffff" actually reads beyond the end of the string, but
+ * then masks off the part it's not allowed to read. Because the
+ * string is aligned, the masked-off tail is in the same word as the
+ * rest of the string. Every machine with memory protection I've seen
+ * does it on word boundaries, so is OK with this. But VALGRIND will
+ * still catch it and complain. The masking trick does make the hash
+ * noticably faster for short strings (like English words).
+ */
+#ifndef VALGRIND
+
+ switch(length)
+ {
+ case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
+ case 11: c+=k[2]&0xffffff; b+=k[1]; a+=k[0]; break;
+ case 10: c+=k[2]&0xffff; b+=k[1]; a+=k[0]; break;
+ case 9 : c+=k[2]&0xff; b+=k[1]; a+=k[0]; break;
+ case 8 : b+=k[1]; a+=k[0]; break;
+ case 7 : b+=k[1]&0xffffff; a+=k[0]; break;
+ case 6 : b+=k[1]&0xffff; a+=k[0]; break;
+ case 5 : b+=k[1]&0xff; a+=k[0]; break;
+ case 4 : a+=k[0]; break;
+ case 3 : a+=k[0]&0xffffff; break;
+ case 2 : a+=k[0]&0xffff; break;
+ case 1 : a+=k[0]&0xff; break;
+ case 0 : return c; /* zero length strings require no mixing */
+ }
+
+#else /* make valgrind happy */
+
+ k8 = (const uint8_t *)k;
+ switch(length)
+ {
+ case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
+ case 11: c+=((uint32_t)k8[10])<<16; /* fall through */
+ case 10: c+=((uint32_t)k8[9])<<8; /* fall through */
+ case 9 : c+=k8[8]; /* fall through */
+ case 8 : b+=k[1]; a+=k[0]; break;
+ case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */
+ case 6 : b+=((uint32_t)k8[5])<<8; /* fall through */
+ case 5 : b+=k8[4]; /* fall through */
+ case 4 : a+=k[0]; break;
+ case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */
+ case 2 : a+=((uint32_t)k8[1])<<8; /* fall through */
+ case 1 : a+=k8[0]; break;
+ case 0 : return c;
+ }
+
+#endif /* !valgrind */
+
+ } else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) {
+ const uint16_t *k = (const uint16_t *)key; /* read 16-bit chunks */
+ const uint8_t *k8;
+
+ /*--------------- all but last block: aligned reads and different mixing */
+ while (length > 12)
+ {
+ a += k[0] + (((uint32_t)k[1])<<16);
+ b += k[2] + (((uint32_t)k[3])<<16);
+ c += k[4] + (((uint32_t)k[5])<<16);
+ mix(a,b,c);
+ length -= 12;
+ k += 6;
+ }
+
+ /*----------------------------- handle the last (probably partial) block */
+ k8 = (const uint8_t *)k;
+ switch(length)
+ {
+ case 12: c+=k[4]+(((uint32_t)k[5])<<16);
+ b+=k[2]+(((uint32_t)k[3])<<16);
+ a+=k[0]+(((uint32_t)k[1])<<16);
+ break;
+ case 11: c+=((uint32_t)k8[10])<<16; /* fall through */
+ case 10: c+=k[4];
+ b+=k[2]+(((uint32_t)k[3])<<16);
+ a+=k[0]+(((uint32_t)k[1])<<16);
+ break;
+ case 9 : c+=k8[8]; /* fall through */
+ case 8 : b+=k[2]+(((uint32_t)k[3])<<16);
+ a+=k[0]+(((uint32_t)k[1])<<16);
+ break;
+ case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */
+ case 6 : b+=k[2];
+ a+=k[0]+(((uint32_t)k[1])<<16);
+ break;
+ case 5 : b+=k8[4]; /* fall through */
+ case 4 : a+=k[0]+(((uint32_t)k[1])<<16);
+ break;
+ case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */
+ case 2 : a+=k[0];
+ break;
+ case 1 : a+=k8[0];
+ break;
+ case 0 : return c; /* zero length requires no mixing */
+ }
+
+ } else { /* need to read the key one byte at a time */
+ const uint8_t *k = (const uint8_t *)key;
+
+ /*--------------- all but the last block: affect some 32 bits of (a,b,c) */
+ while (length > 12)
+ {
+ a += k[0];
+ a += ((uint32_t)k[1])<<8;
+ a += ((uint32_t)k[2])<<16;
+ a += ((uint32_t)k[3])<<24;
+ b += k[4];
+ b += ((uint32_t)k[5])<<8;
+ b += ((uint32_t)k[6])<<16;
+ b += ((uint32_t)k[7])<<24;
+ c += k[8];
+ c += ((uint32_t)k[9])<<8;
+ c += ((uint32_t)k[10])<<16;
+ c += ((uint32_t)k[11])<<24;
+ mix(a,b,c);
+ length -= 12;
+ k += 12;
+ }
+
+ /*-------------------------------- last block: affect all 32 bits of (c) */
+ switch(length) /* all the case statements fall through */
+ {
+ case 12: c+=((uint32_t)k[11])<<24;
+ case 11: c+=((uint32_t)k[10])<<16;
+ case 10: c+=((uint32_t)k[9])<<8;
+ case 9 : c+=k[8];
+ case 8 : b+=((uint32_t)k[7])<<24;
+ case 7 : b+=((uint32_t)k[6])<<16;
+ case 6 : b+=((uint32_t)k[5])<<8;
+ case 5 : b+=k[4];
+ case 4 : a+=((uint32_t)k[3])<<24;
+ case 3 : a+=((uint32_t)k[2])<<16;
+ case 2 : a+=((uint32_t)k[1])<<8;
+ case 1 : a+=k[0];
+ break;
+ case 0 : return c;
+ }
+ }
+
+ final(a,b,c);
+ return c;
+}
+
+
+/*
+ * hashlittle2: return 2 32-bit hash values
+ *
+ * This is identical to hashlittle(), except it returns two 32-bit hash
+ * values instead of just one. This is good enough for hash table
+ * lookup with 2^^64 buckets, or if you want a second hash if you're not
+ * happy with the first, or if you want a probably-unique 64-bit ID for
+ * the key. *pc is better mixed than *pb, so use *pc first. If you want
+ * a 64-bit value do something like "*pc + (((uint64_t)*pb)<<32)".
+ */
+void hashlittle2(
+ const void *key, /* the key to hash */
+ size_t length, /* length of the key */
+ uint32_t *pc, /* IN: primary initval, OUT: primary hash */
+ uint32_t *pb) /* IN: secondary initval, OUT: secondary hash */
+{
+ uint32_t a,b,c; /* internal state */
+ union { const void *ptr; size_t i; } u; /* needed for Mac Powerbook G4 */
+
+ /* Set up the internal state */
+ a = b = c = 0xdeadbeef + ((uint32_t)length) + *pc;
+ c += *pb;
+
+ u.ptr = key;
+ if (HASH_LITTLE_ENDIAN && ((u.i & 0x3) == 0)) {
+ const uint32_t *k = (const uint32_t *)key; /* read 32-bit chunks */
+ const uint8_t *k8;
+
+ /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */
+ while (length > 12)
+ {
+ a += k[0];
+ b += k[1];
+ c += k[2];
+ mix(a,b,c);
+ length -= 12;
+ k += 3;
+ }
+
+ /*----------------------------- handle the last (probably partial) block */
+ /*
+ * "k[2]&0xffffff" actually reads beyond the end of the string, but
+ * then masks off the part it's not allowed to read. Because the
+ * string is aligned, the masked-off tail is in the same word as the
+ * rest of the string. Every machine with memory protection I've seen
+ * does it on word boundaries, so is OK with this. But VALGRIND will
+ * still catch it and complain. The masking trick does make the hash
+ * noticably faster for short strings (like English words).
+ */
+#ifndef VALGRIND
+
+ switch(length)
+ {
+ case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
+ case 11: c+=k[2]&0xffffff; b+=k[1]; a+=k[0]; break;
+ case 10: c+=k[2]&0xffff; b+=k[1]; a+=k[0]; break;
+ case 9 : c+=k[2]&0xff; b+=k[1]; a+=k[0]; break;
+ case 8 : b+=k[1]; a+=k[0]; break;
+ case 7 : b+=k[1]&0xffffff; a+=k[0]; break;
+ case 6 : b+=k[1]&0xffff; a+=k[0]; break;
+ case 5 : b+=k[1]&0xff; a+=k[0]; break;
+ case 4 : a+=k[0]; break;
+ case 3 : a+=k[0]&0xffffff; break;
+ case 2 : a+=k[0]&0xffff; break;
+ case 1 : a+=k[0]&0xff; break;
+ case 0 : *pc=c; *pb=b; return; /* zero length strings require no mixing */
+ }
+
+#else /* make valgrind happy */
+
+ k8 = (const uint8_t *)k;
+ switch(length)
+ {
+ case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
+ case 11: c+=((uint32_t)k8[10])<<16; /* fall through */
+ case 10: c+=((uint32_t)k8[9])<<8; /* fall through */
+ case 9 : c+=k8[8]; /* fall through */
+ case 8 : b+=k[1]; a+=k[0]; break;
+ case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */
+ case 6 : b+=((uint32_t)k8[5])<<8; /* fall through */
+ case 5 : b+=k8[4]; /* fall through */
+ case 4 : a+=k[0]; break;
+ case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */
+ case 2 : a+=((uint32_t)k8[1])<<8; /* fall through */
+ case 1 : a+=k8[0]; break;
+ case 0 : *pc=c; *pb=b; return; /* zero length strings require no mixing */
+ }
+
+#endif /* !valgrind */
+
+ } else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) {
+ const uint16_t *k = (const uint16_t *)key; /* read 16-bit chunks */
+ const uint8_t *k8;
+
+ /*--------------- all but last block: aligned reads and different mixing */
+ while (length > 12)
+ {
+ a += k[0] + (((uint32_t)k[1])<<16);
+ b += k[2] + (((uint32_t)k[3])<<16);
+ c += k[4] + (((uint32_t)k[5])<<16);
+ mix(a,b,c);
+ length -= 12;
+ k += 6;
+ }
+
+ /*----------------------------- handle the last (probably partial) block */
+ k8 = (const uint8_t *)k;
+ switch(length)
+ {
+ case 12: c+=k[4]+(((uint32_t)k[5])<<16);
+ b+=k[2]+(((uint32_t)k[3])<<16);
+ a+=k[0]+(((uint32_t)k[1])<<16);
+ break;
+ case 11: c+=((uint32_t)k8[10])<<16; /* fall through */
+ case 10: c+=k[4];
+ b+=k[2]+(((uint32_t)k[3])<<16);
+ a+=k[0]+(((uint32_t)k[1])<<16);
+ break;
+ case 9 : c+=k8[8]; /* fall through */
+ case 8 : b+=k[2]+(((uint32_t)k[3])<<16);
+ a+=k[0]+(((uint32_t)k[1])<<16);
+ break;
+ case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */
+ case 6 : b+=k[2];
+ a+=k[0]+(((uint32_t)k[1])<<16);
+ break;
+ case 5 : b+=k8[4]; /* fall through */
+ case 4 : a+=k[0]+(((uint32_t)k[1])<<16);
+ break;
+ case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */
+ case 2 : a+=k[0];
+ break;
+ case 1 : a+=k8[0];
+ break;
+ case 0 : *pc=c; *pb=b; return; /* zero length strings require no mixing */
+ }
+
+ } else { /* need to read the key one byte at a time */
+ const uint8_t *k = (const uint8_t *)key;
+
+ /*--------------- all but the last block: affect some 32 bits of (a,b,c) */
+ while (length > 12)
+ {
+ a += k[0];
+ a += ((uint32_t)k[1])<<8;
+ a += ((uint32_t)k[2])<<16;
+ a += ((uint32_t)k[3])<<24;
+ b += k[4];
+ b += ((uint32_t)k[5])<<8;
+ b += ((uint32_t)k[6])<<16;
+ b += ((uint32_t)k[7])<<24;
+ c += k[8];
+ c += ((uint32_t)k[9])<<8;
+ c += ((uint32_t)k[10])<<16;
+ c += ((uint32_t)k[11])<<24;
+ mix(a,b,c);
+ length -= 12;
+ k += 12;
+ }
+
+ /*-------------------------------- last block: affect all 32 bits of (c) */
+ switch(length) /* all the case statements fall through */
+ {
+ case 12: c+=((uint32_t)k[11])<<24;
+ case 11: c+=((uint32_t)k[10])<<16;
+ case 10: c+=((uint32_t)k[9])<<8;
+ case 9 : c+=k[8];
+ case 8 : b+=((uint32_t)k[7])<<24;
+ case 7 : b+=((uint32_t)k[6])<<16;
+ case 6 : b+=((uint32_t)k[5])<<8;
+ case 5 : b+=k[4];
+ case 4 : a+=((uint32_t)k[3])<<24;
+ case 3 : a+=((uint32_t)k[2])<<16;
+ case 2 : a+=((uint32_t)k[1])<<8;
+ case 1 : a+=k[0];
+ break;
+ case 0 : *pc=c; *pb=b; return; /* zero length strings require no mixing */
+ }
+ }
+
+ final(a,b,c);
+ *pc=c; *pb=b;
+}
+
+
+
+/*
+ * hashbig():
+ * This is the same as hashword() on big-endian machines. It is different
+ * from hashlittle() on all machines. hashbig() takes advantage of
+ * big-endian byte ordering.
+ */
+uint32_t hashbig( const void *key, size_t length, uint32_t initval)
+{
+ uint32_t a,b,c;
+ union { const void *ptr; size_t i; } u; /* to cast key to (size_t) happily */
+
+ /* Set up the internal state */
+ a = b = c = 0xdeadbeef + ((uint32_t)length) + initval;
+
+ u.ptr = key;
+ if (HASH_BIG_ENDIAN && ((u.i & 0x3) == 0)) {
+ const uint32_t *k = (const uint32_t *)key; /* read 32-bit chunks */
+ const uint8_t *k8;
+
+ /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */
+ while (length > 12)
+ {
+ a += k[0];
+ b += k[1];
+ c += k[2];
+ mix(a,b,c);
+ length -= 12;
+ k += 3;
+ }
+
+ /*----------------------------- handle the last (probably partial) block */
+ /*
+ * "k[2]<<8" actually reads beyond the end of the string, but
+ * then shifts out the part it's not allowed to read. Because the
+ * string is aligned, the illegal read is in the same word as the
+ * rest of the string. Every machine with memory protection I've seen
+ * does it on word boundaries, so is OK with this. But VALGRIND will
+ * still catch it and complain. The masking trick does make the hash
+ * noticably faster for short strings (like English words).
+ */
+#ifndef VALGRIND
+
+ switch(length)
+ {
+ case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
+ case 11: c+=k[2]&0xffffff00; b+=k[1]; a+=k[0]; break;
+ case 10: c+=k[2]&0xffff0000; b+=k[1]; a+=k[0]; break;
+ case 9 : c+=k[2]&0xff000000; b+=k[1]; a+=k[0]; break;
+ case 8 : b+=k[1]; a+=k[0]; break;
+ case 7 : b+=k[1]&0xffffff00; a+=k[0]; break;
+ case 6 : b+=k[1]&0xffff0000; a+=k[0]; break;
+ case 5 : b+=k[1]&0xff000000; a+=k[0]; break;
+ case 4 : a+=k[0]; break;
+ case 3 : a+=k[0]&0xffffff00; break;
+ case 2 : a+=k[0]&0xffff0000; break;
+ case 1 : a+=k[0]&0xff000000; break;
+ case 0 : return c; /* zero length strings require no mixing */
+ }
+
+#else /* make valgrind happy */
+
+ k8 = (const uint8_t *)k;
+ switch(length) /* all the case statements fall through */
+ {
+ case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
+ case 11: c+=((uint32_t)k8[10])<<8; /* fall through */
+ case 10: c+=((uint32_t)k8[9])<<16; /* fall through */
+ case 9 : c+=((uint32_t)k8[8])<<24; /* fall through */
+ case 8 : b+=k[1]; a+=k[0]; break;
+ case 7 : b+=((uint32_t)k8[6])<<8; /* fall through */
+ case 6 : b+=((uint32_t)k8[5])<<16; /* fall through */
+ case 5 : b+=((uint32_t)k8[4])<<24; /* fall through */
+ case 4 : a+=k[0]; break;
+ case 3 : a+=((uint32_t)k8[2])<<8; /* fall through */
+ case 2 : a+=((uint32_t)k8[1])<<16; /* fall through */
+ case 1 : a+=((uint32_t)k8[0])<<24; break;
+ case 0 : return c;
+ }
+
+#endif /* !VALGRIND */
+
+ } else { /* need to read the key one byte at a time */
+ const uint8_t *k = (const uint8_t *)key;
+
+ /*--------------- all but the last block: affect some 32 bits of (a,b,c) */
+ while (length > 12)
+ {
+ a += ((uint32_t)k[0])<<24;
+ a += ((uint32_t)k[1])<<16;
+ a += ((uint32_t)k[2])<<8;
+ a += ((uint32_t)k[3]);
+ b += ((uint32_t)k[4])<<24;
+ b += ((uint32_t)k[5])<<16;
+ b += ((uint32_t)k[6])<<8;
+ b += ((uint32_t)k[7]);
+ c += ((uint32_t)k[8])<<24;
+ c += ((uint32_t)k[9])<<16;
+ c += ((uint32_t)k[10])<<8;
+ c += ((uint32_t)k[11]);
+ mix(a,b,c);
+ length -= 12;
+ k += 12;
+ }
+
+ /*-------------------------------- last block: affect all 32 bits of (c) */
+ switch(length) /* all the case statements fall through */
+ {
+ case 12: c+=k[11];
+ case 11: c+=((uint32_t)k[10])<<8;
+ case 10: c+=((uint32_t)k[9])<<16;
+ case 9 : c+=((uint32_t)k[8])<<24;
+ case 8 : b+=k[7];
+ case 7 : b+=((uint32_t)k[6])<<8;
+ case 6 : b+=((uint32_t)k[5])<<16;
+ case 5 : b+=((uint32_t)k[4])<<24;
+ case 4 : a+=k[3];
+ case 3 : a+=((uint32_t)k[2])<<8;
+ case 2 : a+=((uint32_t)k[1])<<16;
+ case 1 : a+=((uint32_t)k[0])<<24;
+ break;
+ case 0 : return c;
+ }
+ }
+
+ final(a,b,c);
+ return c;
+}
+
+
+#ifdef SELF_TEST
+
+/* used for timings */
+void driver1()
+{
+ uint8_t buf[256];
+ uint32_t i;
+ uint32_t h=0;
+ time_t a,z;
+
+ time(&a);
+ for (i=0; i<256; ++i) buf[i] = 'x';
+ for (i=0; i<1; ++i)
+ {
+ h = hashlittle(&buf[0],1,h);
+ }
+ time(&z);
+ if (z-a > 0) printf("time %d %.8x\n", z-a, h);
+}
+
+/* check that every input bit changes every output bit half the time */
+#define HASHSTATE 1
+#define HASHLEN 1
+#define MAXPAIR 60
+#define MAXLEN 70
+void driver2()
+{
+ uint8_t qa[MAXLEN+1], qb[MAXLEN+2], *a = &qa[0], *b = &qb[1];
+ uint32_t c[HASHSTATE], d[HASHSTATE], i=0, j=0, k, l, m=0, z;
+ uint32_t e[HASHSTATE],f[HASHSTATE],g[HASHSTATE],h[HASHSTATE];
+ uint32_t x[HASHSTATE],y[HASHSTATE];
+ uint32_t hlen;
+
+ printf("No more than %d trials should ever be needed \n",MAXPAIR/2);
+ for (hlen=0; hlen < MAXLEN; ++hlen)
+ {
+ z=0;
+ for (i=0; i<hlen; ++i) /*----------------------- for each input byte, */
+ {
+ for (j=0; j<8; ++j) /*------------------------ for each input bit, */
+ {
+ for (m=1; m<8; ++m) /*------------ for serveral possible initvals, */
+ {
+ for (l=0; l<HASHSTATE; ++l)
+ e[l]=f[l]=g[l]=h[l]=x[l]=y[l]=~((uint32_t)0);
+
+ /*---- check that every output bit is affected by that input bit */
+ for (k=0; k<MAXPAIR; k+=2)
+ {
+ uint32_t finished=1;
+ /* keys have one bit different */
+ for (l=0; l<hlen+1; ++l) {a[l] = b[l] = (uint8_t)0;}
+ /* have a and b be two keys differing in only one bit */
+ a[i] ^= (k<<j);
+ a[i] ^= (k>>(8-j));
+ c[0] = hashlittle(a, hlen, m);
+ b[i] ^= ((k+1)<<j);
+ b[i] ^= ((k+1)>>(8-j));
+ d[0] = hashlittle(b, hlen, m);
+ /* check every bit is 1, 0, set, and not set at least once */
+ for (l=0; l<HASHSTATE; ++l)
+ {
+ e[l] &= (c[l]^d[l]);
+ f[l] &= ~(c[l]^d[l]);
+ g[l] &= c[l];
+ h[l] &= ~c[l];
+ x[l] &= d[l];
+ y[l] &= ~d[l];
+ if (e[l]|f[l]|g[l]|h[l]|x[l]|y[l]) finished=0;
+ }
+ if (finished) break;
+ }
+ if (k>z) z=k;
+ if (k==MAXPAIR)
+ {
+ printf("Some bit didn't change: ");
+ printf("%.8x %.8x %.8x %.8x %.8x %.8x ",
+ e[0],f[0],g[0],h[0],x[0],y[0]);
+ printf("i %d j %d m %d len %d\n", i, j, m, hlen);
+ }
+ if (z==MAXPAIR) goto done;
+ }
+ }
+ }
+ done:
+ if (z < MAXPAIR)
+ {
+ printf("Mix success %2d bytes %2d initvals ",i,m);
+ printf("required %d trials\n", z/2);
+ }
+ }
+ printf("\n");
+}
+
+/* Check for reading beyond the end of the buffer and alignment problems */
+void driver3()
+{
+ uint8_t buf[MAXLEN+20], *b;
+ uint32_t len;
+ uint8_t q[] = "This is the time for all good men to come to the aid of their country...";
+ uint32_t h;
+ uint8_t qq[] = "xThis is the time for all good men to come to the aid of their country...";
+ uint32_t i;
+ uint8_t qqq[] = "xxThis is the time for all good men to come to the aid of their country...";
+ uint32_t j;
+ uint8_t qqqq[] = "xxxThis is the time for all good men to come to the aid of their country...";
+ uint32_t ref,x,y;
+ uint8_t *p;
+
+ printf("Endianness. These lines should all be the same (for values filled in):\n");
+ printf("%.8x %.8x %.8x\n",
+ hashword((const uint32_t *)q, (sizeof(q)-1)/4, 13),
+ hashword((const uint32_t *)q, (sizeof(q)-5)/4, 13),
+ hashword((const uint32_t *)q, (sizeof(q)-9)/4, 13));
+ p = q;
+ printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n",
+ hashlittle(p, sizeof(q)-1, 13), hashlittle(p, sizeof(q)-2, 13),
+ hashlittle(p, sizeof(q)-3, 13), hashlittle(p, sizeof(q)-4, 13),
+ hashlittle(p, sizeof(q)-5, 13), hashlittle(p, sizeof(q)-6, 13),
+ hashlittle(p, sizeof(q)-7, 13), hashlittle(p, sizeof(q)-8, 13),
+ hashlittle(p, sizeof(q)-9, 13), hashlittle(p, sizeof(q)-10, 13),
+ hashlittle(p, sizeof(q)-11, 13), hashlittle(p, sizeof(q)-12, 13));
+ p = &qq[1];
+ printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n",
+ hashlittle(p, sizeof(q)-1, 13), hashlittle(p, sizeof(q)-2, 13),
+ hashlittle(p, sizeof(q)-3, 13), hashlittle(p, sizeof(q)-4, 13),
+ hashlittle(p, sizeof(q)-5, 13), hashlittle(p, sizeof(q)-6, 13),
+ hashlittle(p, sizeof(q)-7, 13), hashlittle(p, sizeof(q)-8, 13),
+ hashlittle(p, sizeof(q)-9, 13), hashlittle(p, sizeof(q)-10, 13),
+ hashlittle(p, sizeof(q)-11, 13), hashlittle(p, sizeof(q)-12, 13));
+ p = &qqq[2];
+ printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n",
+ hashlittle(p, sizeof(q)-1, 13), hashlittle(p, sizeof(q)-2, 13),
+ hashlittle(p, sizeof(q)-3, 13), hashlittle(p, sizeof(q)-4, 13),
+ hashlittle(p, sizeof(q)-5, 13), hashlittle(p, sizeof(q)-6, 13),
+ hashlittle(p, sizeof(q)-7, 13), hashlittle(p, sizeof(q)-8, 13),
+ hashlittle(p, sizeof(q)-9, 13), hashlittle(p, sizeof(q)-10, 13),
+ hashlittle(p, sizeof(q)-11, 13), hashlittle(p, sizeof(q)-12, 13));
+ p = &qqqq[3];
+ printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n",
+ hashlittle(p, sizeof(q)-1, 13), hashlittle(p, sizeof(q)-2, 13),
+ hashlittle(p, sizeof(q)-3, 13), hashlittle(p, sizeof(q)-4, 13),
+ hashlittle(p, sizeof(q)-5, 13), hashlittle(p, sizeof(q)-6, 13),
+ hashlittle(p, sizeof(q)-7, 13), hashlittle(p, sizeof(q)-8, 13),
+ hashlittle(p, sizeof(q)-9, 13), hashlittle(p, sizeof(q)-10, 13),
+ hashlittle(p, sizeof(q)-11, 13), hashlittle(p, sizeof(q)-12, 13));
+ printf("\n");
+
+ /* check that hashlittle2 and hashlittle produce the same results */
+ i=47; j=0;
+ hashlittle2(q, sizeof(q), &i, &j);
+ if (hashlittle(q, sizeof(q), 47) != i)
+ printf("hashlittle2 and hashlittle mismatch\n");
+
+ /* check that hashword2 and hashword produce the same results */
+ len = 0xdeadbeef;
+ i=47, j=0;
+ hashword2(&len, 1, &i, &j);
+ if (hashword(&len, 1, 47) != i)
+ printf("hashword2 and hashword mismatch %x %x\n",
+ i, hashword(&len, 1, 47));
+
+ /* check hashlittle doesn't read before or after the ends of the string */
+ for (h=0, b=buf+1; h<8; ++h, ++b)
+ {
+ for (i=0; i<MAXLEN; ++i)
+ {
+ len = i;
+ for (j=0; j<i; ++j) *(b+j)=0;
+
+ /* these should all be equal */
+ ref = hashlittle(b, len, (uint32_t)1);
+ *(b+i)=(uint8_t)~0;
+ *(b-1)=(uint8_t)~0;
+ x = hashlittle(b, len, (uint32_t)1);
+ y = hashlittle(b, len, (uint32_t)1);
+ if ((ref != x) || (ref != y))
+ {
+ printf("alignment error: %.8x %.8x %.8x %d %d\n",ref,x,y,
+ h, i);
+ }
+ }
+ }
+}
+
+/* check for problems with nulls */
+ void driver4()
+{
+ uint8_t buf[1];
+ uint32_t h,i,state[HASHSTATE];
+
+
+ buf[0] = ~0;
+ for (i=0; i<HASHSTATE; ++i) state[i] = 1;
+ printf("These should all be different\n");
+ for (i=0, h=0; i<8; ++i)
+ {
+ h = hashlittle(buf, 0, h);
+ printf("%2ld 0-byte strings, hash is %.8x\n", i, h);
+ }
+}
+
+void driver5()
+{
+ uint32_t b,c;
+ b=0, c=0, hashlittle2("", 0, &c, &b);
+ printf("hash is %.8lx %.8lx\n", c, b); /* deadbeef deadbeef */
+ b=0xdeadbeef, c=0, hashlittle2("", 0, &c, &b);
+ printf("hash is %.8lx %.8lx\n", c, b); /* bd5b7dde deadbeef */
+ b=0xdeadbeef, c=0xdeadbeef, hashlittle2("", 0, &c, &b);
+ printf("hash is %.8lx %.8lx\n", c, b); /* 9c093ccd bd5b7dde */
+ b=0, c=0, hashlittle2("Four score and seven years ago", 30, &c, &b);
+ printf("hash is %.8lx %.8lx\n", c, b); /* 17770551 ce7226e6 */
+ b=1, c=0, hashlittle2("Four score and seven years ago", 30, &c, &b);
+ printf("hash is %.8lx %.8lx\n", c, b); /* e3607cae bd371de4 */
+ b=0, c=1, hashlittle2("Four score and seven years ago", 30, &c, &b);
+ printf("hash is %.8lx %.8lx\n", c, b); /* cd628161 6cbea4b3 */
+ c = hashlittle("Four score and seven years ago", 30, 0);
+ printf("hash is %.8lx\n", c); /* 17770551 */
+ c = hashlittle("Four score and seven years ago", 30, 1);
+ printf("hash is %.8lx\n", c); /* cd628161 */
+}
+
+
+int main()
+{
+ driver1(); /* test that the key is hashed: used for timings */
+ driver2(); /* test that whole key is hashed thoroughly */
+ driver3(); /* test that nothing but the key is hashed */
+ driver4(); /* test hashing multiple buffers (all buffers are null) */
+ driver5(); /* test the hash against known vectors */
+ return 1;
+}
+
+#endif /* SELF_TEST */
diff --git a/dep/CascLib/src/libtomcrypt/src/hashes/hash_memory.c b/dep/CascLib/src/libtomcrypt/src/hashes/hash_memory.c
new file mode 100644
index 00000000000..1daf0bffa1b
--- /dev/null
+++ b/dep/CascLib/src/libtomcrypt/src/hashes/hash_memory.c
@@ -0,0 +1,69 @@
+/* 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 hash_memory.c
+ Hash memory helper, Tom St Denis
+*/
+
+/**
+ Hash a block of memory and store the digest.
+ @param hash The index of the hash you wish to use
+ @param in The data you wish to hash
+ @param inlen The length of the data to hash (octets)
+ @param out [out] Where to store the digest
+ @param outlen [in/out] Max size and resulting size of the digest
+ @return CRYPT_OK if successful
+*/
+int hash_memory(int hash, const unsigned char *in, unsigned long inlen, unsigned char *out, unsigned long *outlen)
+{
+ hash_state *md;
+ int err;
+
+ LTC_ARGCHK(in != NULL);
+ LTC_ARGCHK(out != NULL);
+ LTC_ARGCHK(outlen != NULL);
+
+ if ((err = hash_is_valid(hash)) != CRYPT_OK) {
+ return err;
+ }
+
+ if (*outlen < hash_descriptor[hash].hashsize) {
+ *outlen = hash_descriptor[hash].hashsize;
+ return CRYPT_BUFFER_OVERFLOW;
+ }
+
+ md = XMALLOC(sizeof(hash_state));
+ if (md == NULL) {
+ return CRYPT_MEM;
+ }
+
+ if ((err = hash_descriptor[hash].init(md)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ if ((err = hash_descriptor[hash].process(md, in, inlen)) != CRYPT_OK) {
+ goto LBL_ERR;
+ }
+ err = hash_descriptor[hash].done(md, out);
+ *outlen = hash_descriptor[hash].hashsize;
+LBL_ERR:
+#ifdef LTC_CLEAN_STACK
+ zeromem(md, sizeof(hash_state));
+#endif
+ XFREE(md);
+
+ return err;
+}
+
+/* $Source: /cvs/libtom/libtomcrypt/src/hashes/helper/hash_memory.c,v $ */
+/* $Revision: 1.6 $ */
+/* $Date: 2006/12/28 01:27:23 $ */
diff --git a/dep/CascLib/src/libtomcrypt/src/hashes/md5.c b/dep/CascLib/src/libtomcrypt/src/hashes/md5.c
new file mode 100644
index 00000000000..4cbd000c0d4
--- /dev/null
+++ b/dep/CascLib/src/libtomcrypt/src/hashes/md5.c
@@ -0,0 +1,368 @@
+/* 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 md5.c
+ LTC_MD5 hash function by Tom St Denis
+*/
+
+#ifdef LTC_MD5
+
+const struct ltc_hash_descriptor md5_desc =
+{
+ "md5",
+ 3,
+ 16,
+ 64,
+
+ /* OID */
+ { 1, 2, 840, 113549, 2, 5, },
+ 6,
+
+ &md5_init,
+ &md5_process,
+ &md5_done,
+ &md5_test,
+ NULL
+};
+
+#define F(x,y,z) (z ^ (x & (y ^ z)))
+#define G(x,y,z) (y ^ (z & (y ^ x)))
+#define H(x,y,z) (x^y^z)
+#define I(x,y,z) (y^(x|(~z)))
+
+#ifdef LTC_SMALL_CODE
+
+#define FF(a,b,c,d,M,s,t) \
+ a = (a + F(b,c,d) + M + t); a = ROL(a, s) + b;
+
+#define GG(a,b,c,d,M,s,t) \
+ a = (a + G(b,c,d) + M + t); a = ROL(a, s) + b;
+
+#define HH(a,b,c,d,M,s,t) \
+ a = (a + H(b,c,d) + M + t); a = ROL(a, s) + b;
+
+#define II(a,b,c,d,M,s,t) \
+ a = (a + I(b,c,d) + M + t); a = ROL(a, s) + b;
+
+static const unsigned char Worder[64] = {
+ 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
+ 1,6,11,0,5,10,15,4,9,14,3,8,13,2,7,12,
+ 5,8,11,14,1,4,7,10,13,0,3,6,9,12,15,2,
+ 0,7,14,5,12,3,10,1,8,15,6,13,4,11,2,9
+};
+
+static const unsigned char Rorder[64] = {
+ 7,12,17,22,7,12,17,22,7,12,17,22,7,12,17,22,
+ 5,9,14,20,5,9,14,20,5,9,14,20,5,9,14,20,
+ 4,11,16,23,4,11,16,23,4,11,16,23,4,11,16,23,
+ 6,10,15,21,6,10,15,21,6,10,15,21,6,10,15,21
+};
+
+static const ulong32 Korder[64] = {
+0xd76aa478UL, 0xe8c7b756UL, 0x242070dbUL, 0xc1bdceeeUL, 0xf57c0fafUL, 0x4787c62aUL, 0xa8304613UL, 0xfd469501UL,
+0x698098d8UL, 0x8b44f7afUL, 0xffff5bb1UL, 0x895cd7beUL, 0x6b901122UL, 0xfd987193UL, 0xa679438eUL, 0x49b40821UL,
+0xf61e2562UL, 0xc040b340UL, 0x265e5a51UL, 0xe9b6c7aaUL, 0xd62f105dUL, 0x02441453UL, 0xd8a1e681UL, 0xe7d3fbc8UL,
+0x21e1cde6UL, 0xc33707d6UL, 0xf4d50d87UL, 0x455a14edUL, 0xa9e3e905UL, 0xfcefa3f8UL, 0x676f02d9UL, 0x8d2a4c8aUL,
+0xfffa3942UL, 0x8771f681UL, 0x6d9d6122UL, 0xfde5380cUL, 0xa4beea44UL, 0x4bdecfa9UL, 0xf6bb4b60UL, 0xbebfbc70UL,
+0x289b7ec6UL, 0xeaa127faUL, 0xd4ef3085UL, 0x04881d05UL, 0xd9d4d039UL, 0xe6db99e5UL, 0x1fa27cf8UL, 0xc4ac5665UL,
+0xf4292244UL, 0x432aff97UL, 0xab9423a7UL, 0xfc93a039UL, 0x655b59c3UL, 0x8f0ccc92UL, 0xffeff47dUL, 0x85845dd1UL,
+0x6fa87e4fUL, 0xfe2ce6e0UL, 0xa3014314UL, 0x4e0811a1UL, 0xf7537e82UL, 0xbd3af235UL, 0x2ad7d2bbUL, 0xeb86d391UL
+};
+
+#else
+
+#define FF(a,b,c,d,M,s,t) \
+ a = (a + F(b,c,d) + M + t); a = ROLc(a, s) + b;
+
+#define GG(a,b,c,d,M,s,t) \
+ a = (a + G(b,c,d) + M + t); a = ROLc(a, s) + b;
+
+#define HH(a,b,c,d,M,s,t) \
+ a = (a + H(b,c,d) + M + t); a = ROLc(a, s) + b;
+
+#define II(a,b,c,d,M,s,t) \
+ a = (a + I(b,c,d) + M + t); a = ROLc(a, s) + b;
+
+
+#endif
+
+#ifdef LTC_CLEAN_STACK
+static int _md5_compress(hash_state *md, unsigned char *buf)
+#else
+static int md5_compress(hash_state *md, unsigned char *buf)
+#endif
+{
+ ulong32 i, W[16], a, b, c, d;
+#ifdef LTC_SMALL_CODE
+ ulong32 t;
+#endif
+
+ /* copy the state into 512-bits into W[0..15] */
+ for (i = 0; i < 16; i++) {
+ LOAD32L(W[i], buf + (4*i));
+ }
+
+ /* copy state */
+ a = md->md5.state[0];
+ b = md->md5.state[1];
+ c = md->md5.state[2];
+ d = md->md5.state[3];
+
+#ifdef LTC_SMALL_CODE
+ for (i = 0; i < 16; ++i) {
+ FF(a,b,c,d,W[Worder[i]],Rorder[i],Korder[i]);
+ t = d; d = c; c = b; b = a; a = t;
+ }
+
+ for (; i < 32; ++i) {
+ GG(a,b,c,d,W[Worder[i]],Rorder[i],Korder[i]);
+ t = d; d = c; c = b; b = a; a = t;
+ }
+
+ for (; i < 48; ++i) {
+ HH(a,b,c,d,W[Worder[i]],Rorder[i],Korder[i]);
+ t = d; d = c; c = b; b = a; a = t;
+ }
+
+ for (; i < 64; ++i) {
+ II(a,b,c,d,W[Worder[i]],Rorder[i],Korder[i]);
+ t = d; d = c; c = b; b = a; a = t;
+ }
+
+#else
+ FF(a,b,c,d,W[0],7,0xd76aa478UL)
+ FF(d,a,b,c,W[1],12,0xe8c7b756UL)
+ FF(c,d,a,b,W[2],17,0x242070dbUL)
+ FF(b,c,d,a,W[3],22,0xc1bdceeeUL)
+ FF(a,b,c,d,W[4],7,0xf57c0fafUL)
+ FF(d,a,b,c,W[5],12,0x4787c62aUL)
+ FF(c,d,a,b,W[6],17,0xa8304613UL)
+ FF(b,c,d,a,W[7],22,0xfd469501UL)
+ FF(a,b,c,d,W[8],7,0x698098d8UL)
+ FF(d,a,b,c,W[9],12,0x8b44f7afUL)
+ FF(c,d,a,b,W[10],17,0xffff5bb1UL)
+ FF(b,c,d,a,W[11],22,0x895cd7beUL)
+ FF(a,b,c,d,W[12],7,0x6b901122UL)
+ FF(d,a,b,c,W[13],12,0xfd987193UL)
+ FF(c,d,a,b,W[14],17,0xa679438eUL)
+ FF(b,c,d,a,W[15],22,0x49b40821UL)
+ GG(a,b,c,d,W[1],5,0xf61e2562UL)
+ GG(d,a,b,c,W[6],9,0xc040b340UL)
+ GG(c,d,a,b,W[11],14,0x265e5a51UL)
+ GG(b,c,d,a,W[0],20,0xe9b6c7aaUL)
+ GG(a,b,c,d,W[5],5,0xd62f105dUL)
+ GG(d,a,b,c,W[10],9,0x02441453UL)
+ GG(c,d,a,b,W[15],14,0xd8a1e681UL)
+ GG(b,c,d,a,W[4],20,0xe7d3fbc8UL)
+ GG(a,b,c,d,W[9],5,0x21e1cde6UL)
+ GG(d,a,b,c,W[14],9,0xc33707d6UL)
+ GG(c,d,a,b,W[3],14,0xf4d50d87UL)
+ GG(b,c,d,a,W[8],20,0x455a14edUL)
+ GG(a,b,c,d,W[13],5,0xa9e3e905UL)
+ GG(d,a,b,c,W[2],9,0xfcefa3f8UL)
+ GG(c,d,a,b,W[7],14,0x676f02d9UL)
+ GG(b,c,d,a,W[12],20,0x8d2a4c8aUL)
+ HH(a,b,c,d,W[5],4,0xfffa3942UL)
+ HH(d,a,b,c,W[8],11,0x8771f681UL)
+ HH(c,d,a,b,W[11],16,0x6d9d6122UL)
+ HH(b,c,d,a,W[14],23,0xfde5380cUL)
+ HH(a,b,c,d,W[1],4,0xa4beea44UL)
+ HH(d,a,b,c,W[4],11,0x4bdecfa9UL)
+ HH(c,d,a,b,W[7],16,0xf6bb4b60UL)
+ HH(b,c,d,a,W[10],23,0xbebfbc70UL)
+ HH(a,b,c,d,W[13],4,0x289b7ec6UL)
+ HH(d,a,b,c,W[0],11,0xeaa127faUL)
+ HH(c,d,a,b,W[3],16,0xd4ef3085UL)
+ HH(b,c,d,a,W[6],23,0x04881d05UL)
+ HH(a,b,c,d,W[9],4,0xd9d4d039UL)
+ HH(d,a,b,c,W[12],11,0xe6db99e5UL)
+ HH(c,d,a,b,W[15],16,0x1fa27cf8UL)
+ HH(b,c,d,a,W[2],23,0xc4ac5665UL)
+ II(a,b,c,d,W[0],6,0xf4292244UL)
+ II(d,a,b,c,W[7],10,0x432aff97UL)
+ II(c,d,a,b,W[14],15,0xab9423a7UL)
+ II(b,c,d,a,W[5],21,0xfc93a039UL)
+ II(a,b,c,d,W[12],6,0x655b59c3UL)
+ II(d,a,b,c,W[3],10,0x8f0ccc92UL)
+ II(c,d,a,b,W[10],15,0xffeff47dUL)
+ II(b,c,d,a,W[1],21,0x85845dd1UL)
+ II(a,b,c,d,W[8],6,0x6fa87e4fUL)
+ II(d,a,b,c,W[15],10,0xfe2ce6e0UL)
+ II(c,d,a,b,W[6],15,0xa3014314UL)
+ II(b,c,d,a,W[13],21,0x4e0811a1UL)
+ II(a,b,c,d,W[4],6,0xf7537e82UL)
+ II(d,a,b,c,W[11],10,0xbd3af235UL)
+ II(c,d,a,b,W[2],15,0x2ad7d2bbUL)
+ II(b,c,d,a,W[9],21,0xeb86d391UL)
+#endif
+
+ md->md5.state[0] = md->md5.state[0] + a;
+ md->md5.state[1] = md->md5.state[1] + b;
+ md->md5.state[2] = md->md5.state[2] + c;
+ md->md5.state[3] = md->md5.state[3] + d;
+
+ return CRYPT_OK;
+}
+
+#ifdef LTC_CLEAN_STACK
+static int md5_compress(hash_state *md, unsigned char *buf)
+{
+ int err;
+ err = _md5_compress(md, buf);
+ burn_stack(sizeof(ulong32) * 21);
+ return err;
+}
+#endif
+
+/**
+ Initialize the hash state
+ @param md The hash state you wish to initialize
+ @return CRYPT_OK if successful
+*/
+int md5_init(hash_state * md)
+{
+ LTC_ARGCHK(md != NULL);
+ md->md5.state[0] = 0x67452301UL;
+ md->md5.state[1] = 0xefcdab89UL;
+ md->md5.state[2] = 0x98badcfeUL;
+ md->md5.state[3] = 0x10325476UL;
+ md->md5.curlen = 0;
+ md->md5.length = 0;
+ 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(md5_process, md5_compress, md5, 64)
+
+/**
+ Terminate the hash to get the digest
+ @param md The hash state
+ @param out [out] The destination of the hash (16 bytes)
+ @return CRYPT_OK if successful
+*/
+int md5_done(hash_state * md, unsigned char *out)
+{
+ int i;
+
+ LTC_ARGCHK(md != NULL);
+ LTC_ARGCHK(out != NULL);
+
+ if (md->md5.curlen >= sizeof(md->md5.buf)) {
+ return CRYPT_INVALID_ARG;
+ }
+
+
+ /* increase the length of the message */
+ md->md5.length += md->md5.curlen * 8;
+
+ /* append the '1' bit */
+ md->md5.buf[md->md5.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->md5.curlen > 56) {
+ while (md->md5.curlen < 64) {
+ md->md5.buf[md->md5.curlen++] = (unsigned char)0;
+ }
+ md5_compress(md, md->md5.buf);
+ md->md5.curlen = 0;
+ }
+
+ /* pad upto 56 bytes of zeroes */
+ while (md->md5.curlen < 56) {
+ md->md5.buf[md->md5.curlen++] = (unsigned char)0;
+ }
+
+ /* store length */
+ STORE64L(md->md5.length, md->md5.buf+56);
+ md5_compress(md, md->md5.buf);
+
+ /* copy output */
+ for (i = 0; i < 4; i++) {
+ STORE32L(md->md5.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 md5_test(void)
+{
+ #ifndef LTC_TEST
+ return CRYPT_NOP;
+ #else
+ static const struct {
+ char *msg;
+ unsigned char hash[16];
+ } tests[] = {
+ { "",
+ { 0xd4, 0x1d, 0x8c, 0xd9, 0x8f, 0x00, 0xb2, 0x04,
+ 0xe9, 0x80, 0x09, 0x98, 0xec, 0xf8, 0x42, 0x7e } },
+ { "a",
+ {0x0c, 0xc1, 0x75, 0xb9, 0xc0, 0xf1, 0xb6, 0xa8,
+ 0x31, 0xc3, 0x99, 0xe2, 0x69, 0x77, 0x26, 0x61 } },
+ { "abc",
+ { 0x90, 0x01, 0x50, 0x98, 0x3c, 0xd2, 0x4f, 0xb0,
+ 0xd6, 0x96, 0x3f, 0x7d, 0x28, 0xe1, 0x7f, 0x72 } },
+ { "message digest",
+ { 0xf9, 0x6b, 0x69, 0x7d, 0x7c, 0xb7, 0x93, 0x8d,
+ 0x52, 0x5a, 0x2f, 0x31, 0xaa, 0xf1, 0x61, 0xd0 } },
+ { "abcdefghijklmnopqrstuvwxyz",
+ { 0xc3, 0xfc, 0xd3, 0xd7, 0x61, 0x92, 0xe4, 0x00,
+ 0x7d, 0xfb, 0x49, 0x6c, 0xca, 0x67, 0xe1, 0x3b } },
+ { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
+ { 0xd1, 0x74, 0xab, 0x98, 0xd2, 0x77, 0xd9, 0xf5,
+ 0xa5, 0x61, 0x1c, 0x2c, 0x9f, 0x41, 0x9d, 0x9f } },
+ { "12345678901234567890123456789012345678901234567890123456789012345678901234567890",
+ { 0x57, 0xed, 0xf4, 0xa2, 0x2b, 0xe3, 0xc9, 0x55,
+ 0xac, 0x49, 0xda, 0x2e, 0x21, 0x07, 0xb6, 0x7a } },
+ { NULL, { 0 } }
+ };
+
+ int i;
+ unsigned char tmp[16];
+ hash_state md;
+
+ for (i = 0; tests[i].msg != NULL; i++) {
+ md5_init(&md);
+ md5_process(&md, (unsigned char *)tests[i].msg, (unsigned long)strlen(tests[i].msg));
+ md5_done(&md, tmp);
+ if (XMEMCMP(tmp, tests[i].hash, 16) != 0) {
+ return CRYPT_FAIL_TESTVECTOR;
+ }
+ }
+ return CRYPT_OK;
+ #endif
+}
+
+#endif
+
+
+
+/* $Source: /cvs/libtom/libtomcrypt/src/hashes/md5.c,v $ */
+/* $Revision: 1.10 $ */
+/* $Date: 2007/05/12 14:25:28 $ */
diff --git a/dep/CascLib/src/libtomcrypt/src/headers/tomcrypt.h b/dep/CascLib/src/libtomcrypt/src/headers/tomcrypt.h
new file mode 100644
index 00000000000..74cdff47549
--- /dev/null
+++ b/dep/CascLib/src/libtomcrypt/src/headers/tomcrypt.h
@@ -0,0 +1,87 @@
+#ifndef TOMCRYPT_H_
+#define TOMCRYPT_H_
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+#include <ctype.h>
+#include <limits.h>
+
+/* use configuration data */
+#include "tomcrypt_custom.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* version */
+#define CRYPT 0x0117
+#define SCRYPT "1.17"
+
+/* max size of either a cipher/hash block or symmetric key [largest of the two] */
+#define MAXBLOCKSIZE 128
+
+/* descriptor table size */
+#define TAB_SIZE 32
+
+/* error codes [will be expanded in future releases] */
+enum {
+ CRYPT_OK=0, /* Result OK */
+ CRYPT_ERROR, /* Generic Error */
+ CRYPT_NOP, /* Not a failure but no operation was performed */
+
+ CRYPT_INVALID_KEYSIZE, /* Invalid key size given */
+ CRYPT_INVALID_ROUNDS, /* Invalid number of rounds */
+ CRYPT_FAIL_TESTVECTOR, /* Algorithm failed test vectors */
+
+ CRYPT_BUFFER_OVERFLOW, /* Not enough space for output */
+ CRYPT_INVALID_PACKET, /* Invalid input packet given */
+
+ CRYPT_INVALID_PRNGSIZE, /* Invalid number of bits for a PRNG */
+ CRYPT_ERROR_READPRNG, /* Could not read enough from PRNG */
+
+ CRYPT_INVALID_CIPHER, /* Invalid cipher specified */
+ CRYPT_INVALID_HASH, /* Invalid hash specified */
+ CRYPT_INVALID_PRNG, /* Invalid PRNG specified */
+
+ CRYPT_MEM, /* Out of memory */
+
+ CRYPT_PK_TYPE_MISMATCH, /* Not equivalent types of PK keys */
+ CRYPT_PK_NOT_PRIVATE, /* Requires a private PK key */
+
+ CRYPT_INVALID_ARG, /* Generic invalid argument */
+ CRYPT_FILE_NOTFOUND, /* File Not Found */
+
+ CRYPT_PK_INVALID_TYPE, /* Invalid type of PK key */
+ CRYPT_PK_INVALID_SYSTEM,/* Invalid PK system specified */
+ CRYPT_PK_DUP, /* Duplicate key already in key ring */
+ CRYPT_PK_NOT_FOUND, /* Key not found in keyring */
+ CRYPT_PK_INVALID_SIZE, /* Invalid size input for PK parameters */
+
+ CRYPT_INVALID_PRIME_SIZE,/* Invalid size of prime requested */
+ CRYPT_PK_INVALID_PADDING /* Invalid padding on input */
+};
+
+#include "tomcrypt_cfg.h"
+#include "tomcrypt_macros.h"
+#include "tomcrypt_cipher.h"
+#include "tomcrypt_hash.h"
+#include "tomcrypt_mac.h"
+#include "tomcrypt_prng.h"
+#include "tomcrypt_pk.h"
+#include "tomcrypt_math.h"
+#include "tomcrypt_misc.h"
+#include "tomcrypt_argchk.h"
+#include "tomcrypt_pkcs.h"
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* TOMCRYPT_H_ */
+
+
+/* $Source: /cvs/libtom/libtomcrypt/src/headers/tomcrypt.h,v $ */
+/* $Revision: 1.21 $ */
+/* $Date: 2006/12/16 19:34:05 $ */
diff --git a/dep/CascLib/src/libtomcrypt/src/headers/tomcrypt_argchk.h b/dep/CascLib/src/libtomcrypt/src/headers/tomcrypt_argchk.h
new file mode 100644
index 00000000000..cfc93ad7ea6
--- /dev/null
+++ b/dep/CascLib/src/libtomcrypt/src/headers/tomcrypt_argchk.h
@@ -0,0 +1,38 @@
+/* Defines the LTC_ARGCHK macro used within the library */
+/* ARGTYPE is defined in mycrypt_cfg.h */
+#if ARGTYPE == 0
+
+#include <signal.h>
+
+/* this is the default LibTomCrypt macro */
+void crypt_argchk(char *v, char *s, int d);
+#define LTC_ARGCHK(x) if (!(x)) { crypt_argchk(#x, __FILE__, __LINE__); }
+#define LTC_ARGCHKVD(x) LTC_ARGCHK(x)
+
+#elif ARGTYPE == 1
+
+/* fatal type of error */
+#define LTC_ARGCHK(x) assert((x))
+#define LTC_ARGCHKVD(x) LTC_ARGCHK(x)
+
+#elif ARGTYPE == 2
+
+#define LTC_ARGCHK(x) if (!(x)) { fprintf(stderr, "\nwarning: ARGCHK failed at %s:%d\n", __FILE__, __LINE__); }
+#define LTC_ARGCHKVD(x) LTC_ARGCHK(x)
+
+#elif ARGTYPE == 3
+
+#define LTC_ARGCHK(x)
+#define LTC_ARGCHKVD(x) LTC_ARGCHK(x)
+
+#elif ARGTYPE == 4
+
+#define LTC_ARGCHK(x) if (!(x)) return CRYPT_INVALID_ARG;
+#define LTC_ARGCHKVD(x) if (!(x)) return;
+
+#endif
+
+
+/* $Source: /cvs/libtom/libtomcrypt/src/headers/tomcrypt_argchk.h,v $ */
+/* $Revision: 1.5 $ */
+/* $Date: 2006/08/27 20:50:21 $ */
diff --git a/dep/CascLib/src/libtomcrypt/src/headers/tomcrypt_cfg.h b/dep/CascLib/src/libtomcrypt/src/headers/tomcrypt_cfg.h
new file mode 100644
index 00000000000..7feae6e8bdc
--- /dev/null
+++ b/dep/CascLib/src/libtomcrypt/src/headers/tomcrypt_cfg.h
@@ -0,0 +1,136 @@
+/* This is the build config file.
+ *
+ * With this you can setup what to inlcude/exclude automatically during any build. Just comment
+ * out the line that #define's the word for the thing you want to remove. phew!
+ */
+
+#ifndef TOMCRYPT_CFG_H
+#define TOMCRYPT_CFG_H
+
+#if defined(_WIN32) || defined(_MSC_VER)
+#define LTC_CALL __cdecl
+#else
+#ifndef LTC_CALL
+ #define LTC_CALL
+#endif
+#endif
+
+#ifndef LTC_EXPORT
+#define LTC_EXPORT
+#endif
+
+/* certain platforms use macros for these, making the prototypes broken */
+#ifndef LTC_NO_PROTOTYPES
+
+/* you can change how memory allocation works ... */
+LTC_EXPORT void * LTC_CALL XMALLOC(size_t n);
+LTC_EXPORT void * LTC_CALL XREALLOC(void *p, size_t n);
+LTC_EXPORT void * LTC_CALL XCALLOC(size_t n, size_t s);
+LTC_EXPORT void LTC_CALL XFREE(void *p);
+
+LTC_EXPORT void LTC_CALL XQSORT(void *base, size_t nmemb, size_t size, int(*compar)(const void *, const void *));
+
+
+/* change the clock function too */
+LTC_EXPORT clock_t LTC_CALL XCLOCK(void);
+
+/* various other functions */
+LTC_EXPORT void * LTC_CALL XMEMCPY(void *dest, const void *src, size_t n);
+LTC_EXPORT int LTC_CALL XMEMCMP(const void *s1, const void *s2, size_t n);
+LTC_EXPORT void * LTC_CALL XMEMSET(void *s, int c, size_t n);
+
+LTC_EXPORT int LTC_CALL XSTRCMP(const char *s1, const char *s2);
+
+#endif
+
+/* type of argument checking, 0=default, 1=fatal and 2=error+continue, 3=nothing */
+#ifndef ARGTYPE
+ #define ARGTYPE 0
+#endif
+
+/* Controls endianess and size of registers. Leave uncommented to get platform neutral [slower] code
+ *
+ * Note: in order to use the optimized macros your platform must support unaligned 32 and 64 bit read/writes.
+ * The x86 platforms allow this but some others [ARM for instance] do not. On those platforms you **MUST**
+ * use the portable [slower] macros.
+ */
+
+/* detect x86-32 machines somewhat */
+#if !defined(__STRICT_ANSI__) && (defined(INTEL_CC) || (defined(_MSC_VER) && defined(WIN32)) || (defined(__GNUC__) && (defined(__DJGPP__) || defined(__CYGWIN__) || defined(__MINGW32__) || defined(__i386__))))
+ #define ENDIAN_LITTLE
+ #define ENDIAN_32BITWORD
+ #define LTC_FAST
+ #define LTC_FAST_TYPE unsigned long
+#endif
+
+/* detects MIPS R5900 processors (PS2) */
+#if (defined(__R5900) || defined(R5900) || defined(__R5900__)) && (defined(_mips) || defined(__mips__) || defined(mips))
+ #define ENDIAN_LITTLE
+ #define ENDIAN_64BITWORD
+#endif
+
+/* detect amd64 */
+#if !defined(__STRICT_ANSI__) && defined(__x86_64__)
+ #define ENDIAN_LITTLE
+ #define ENDIAN_64BITWORD
+ #define LTC_FAST
+ #define LTC_FAST_TYPE unsigned long
+#endif
+
+/* detect PPC32 */
+#if !defined(__STRICT_ANSI__) && defined(LTC_PPC32)
+ #define ENDIAN_BIG
+ #define ENDIAN_32BITWORD
+ #define LTC_FAST
+ #define LTC_FAST_TYPE unsigned long
+#endif
+
+/* detect sparc and sparc64 */
+#if defined(__sparc__)
+ #define ENDIAN_BIG
+ #if defined(__arch64__)
+ #define ENDIAN_64BITWORD
+ #else
+ #define ENDIAN_32BITWORD
+ #endif
+#endif
+
+
+#ifdef LTC_NO_FAST
+ #ifdef LTC_FAST
+ #undef LTC_FAST
+ #endif
+#endif
+
+/* No asm is a quick way to disable anything "not portable" */
+#ifdef LTC_NO_ASM
+ #undef ENDIAN_LITTLE
+ #undef ENDIAN_BIG
+ #undef ENDIAN_32BITWORD
+ #undef ENDIAN_64BITWORD
+ #undef LTC_FAST
+ #undef LTC_FAST_TYPE
+ #define LTC_NO_ROLC
+ #define LTC_NO_BSWAP
+#endif
+
+/* #define ENDIAN_LITTLE */
+/* #define ENDIAN_BIG */
+
+/* #define ENDIAN_32BITWORD */
+/* #define ENDIAN_64BITWORD */
+
+#if (defined(ENDIAN_BIG) || defined(ENDIAN_LITTLE)) && !(defined(ENDIAN_32BITWORD) || defined(ENDIAN_64BITWORD))
+ #error You must specify a word size as well as endianess in tomcrypt_cfg.h
+#endif
+
+#if !(defined(ENDIAN_BIG) || defined(ENDIAN_LITTLE))
+ #define ENDIAN_NEUTRAL
+#endif
+
+#endif
+
+
+/* $Source: /cvs/libtom/libtomcrypt/src/headers/tomcrypt_cfg.h,v $ */
+/* $Revision: 1.19 $ */
+/* $Date: 2006/12/04 02:19:48 $ */
diff --git a/dep/CascLib/src/libtomcrypt/src/headers/tomcrypt_cipher.h b/dep/CascLib/src/libtomcrypt/src/headers/tomcrypt_cipher.h
new file mode 100644
index 00000000000..bd740bf4a0c
--- /dev/null
+++ b/dep/CascLib/src/libtomcrypt/src/headers/tomcrypt_cipher.h
@@ -0,0 +1,891 @@
+/* ---- SYMMETRIC KEY STUFF -----
+ *
+ * We put each of the ciphers scheduled keys in their own structs then we put all of
+ * the key formats in one union. This makes the function prototypes easier to use.
+ */
+#ifdef LTC_BLOWFISH
+struct blowfish_key {
+ ulong32 S[4][256];
+ ulong32 K[18];
+};
+#endif
+
+#ifdef LTC_RC5
+struct rc5_key {
+ int rounds;
+ ulong32 K[50];
+};
+#endif
+
+#ifdef LTC_RC6
+struct rc6_key {
+ ulong32 K[44];
+};
+#endif
+
+#ifdef LTC_SAFERP
+struct saferp_key {
+ unsigned char K[33][16];
+ long rounds;
+};
+#endif
+
+#ifdef LTC_RIJNDAEL
+struct rijndael_key {
+ ulong32 eK[60], dK[60];
+ int Nr;
+};
+#endif
+
+#ifdef LTC_KSEED
+struct kseed_key {
+ ulong32 K[32], dK[32];
+};
+#endif
+
+#ifdef LTC_KASUMI
+struct kasumi_key {
+ ulong32 KLi1[8], KLi2[8],
+ KOi1[8], KOi2[8], KOi3[8],
+ KIi1[8], KIi2[8], KIi3[8];
+};
+#endif
+
+#ifdef LTC_XTEA
+struct xtea_key {
+ unsigned long A[32], B[32];
+};
+#endif
+
+#ifdef LTC_TWOFISH
+#ifndef LTC_TWOFISH_SMALL
+ struct twofish_key {
+ ulong32 S[4][256], K[40];
+ };
+#else
+ struct twofish_key {
+ ulong32 K[40];
+ unsigned char S[32], start;
+ };
+#endif
+#endif
+
+#ifdef LTC_SAFER
+#define LTC_SAFER_K64_DEFAULT_NOF_ROUNDS 6
+#define LTC_SAFER_K128_DEFAULT_NOF_ROUNDS 10
+#define LTC_SAFER_SK64_DEFAULT_NOF_ROUNDS 8
+#define LTC_SAFER_SK128_DEFAULT_NOF_ROUNDS 10
+#define LTC_SAFER_MAX_NOF_ROUNDS 13
+#define LTC_SAFER_BLOCK_LEN 8
+#define LTC_SAFER_KEY_LEN (1 + LTC_SAFER_BLOCK_LEN * (1 + 2 * LTC_SAFER_MAX_NOF_ROUNDS))
+typedef unsigned char safer_block_t[LTC_SAFER_BLOCK_LEN];
+typedef unsigned char safer_key_t[LTC_SAFER_KEY_LEN];
+struct safer_key { safer_key_t key; };
+#endif
+
+#ifdef LTC_RC2
+struct rc2_key { unsigned xkey[64]; };
+#endif
+
+#ifdef LTC_DES
+struct des_key {
+ ulong32 ek[32], dk[32];
+};
+
+struct des3_key {
+ ulong32 ek[3][32], dk[3][32];
+};
+#endif
+
+#ifdef LTC_CAST5
+struct cast5_key {
+ ulong32 K[32], keylen;
+};
+#endif
+
+#ifdef LTC_NOEKEON
+struct noekeon_key {
+ ulong32 K[4], dK[4];
+};
+#endif
+
+#ifdef LTC_SKIPJACK
+struct skipjack_key {
+ unsigned char key[10];
+};
+#endif
+
+#ifdef LTC_KHAZAD
+struct khazad_key {
+ ulong64 roundKeyEnc[8 + 1];
+ ulong64 roundKeyDec[8 + 1];
+};
+#endif
+
+#ifdef LTC_ANUBIS
+struct anubis_key {
+ int keyBits;
+ int R;
+ ulong32 roundKeyEnc[18 + 1][4];
+ ulong32 roundKeyDec[18 + 1][4];
+};
+#endif
+
+#ifdef LTC_MULTI2
+struct multi2_key {
+ int N;
+ ulong32 uk[8];
+};
+#endif
+
+typedef union Symmetric_key {
+#ifdef LTC_DES
+ struct des_key des;
+ struct des3_key des3;
+#endif
+#ifdef LTC_RC2
+ struct rc2_key rc2;
+#endif
+#ifdef LTC_SAFER
+ struct safer_key safer;
+#endif
+#ifdef LTC_TWOFISH
+ struct twofish_key twofish;
+#endif
+#ifdef LTC_BLOWFISH
+ struct blowfish_key blowfish;
+#endif
+#ifdef LTC_RC5
+ struct rc5_key rc5;
+#endif
+#ifdef LTC_RC6
+ struct rc6_key rc6;
+#endif
+#ifdef LTC_SAFERP
+ struct saferp_key saferp;
+#endif
+#ifdef LTC_RIJNDAEL
+ struct rijndael_key rijndael;
+#endif
+#ifdef LTC_XTEA
+ struct xtea_key xtea;
+#endif
+#ifdef LTC_CAST5
+ struct cast5_key cast5;
+#endif
+#ifdef LTC_NOEKEON
+ struct noekeon_key noekeon;
+#endif
+#ifdef LTC_SKIPJACK
+ struct skipjack_key skipjack;
+#endif
+#ifdef LTC_KHAZAD
+ struct khazad_key khazad;
+#endif
+#ifdef LTC_ANUBIS
+ struct anubis_key anubis;
+#endif
+#ifdef LTC_KSEED
+ struct kseed_key kseed;
+#endif
+#ifdef LTC_KASUMI
+ struct kasumi_key kasumi;
+#endif
+#ifdef LTC_MULTI2
+ struct multi2_key multi2;
+#endif
+ void *data;
+} symmetric_key;
+
+#ifdef LTC_ECB_MODE
+/** A block cipher ECB structure */
+typedef struct {
+ /** The index of the cipher chosen */
+ int cipher,
+ /** The block size of the given cipher */
+ blocklen;
+ /** The scheduled key */
+ symmetric_key key;
+} symmetric_ECB;
+#endif
+
+#ifdef LTC_CFB_MODE
+/** A block cipher CFB structure */
+typedef struct {
+ /** The index of the cipher chosen */
+ int cipher,
+ /** The block size of the given cipher */
+ blocklen,
+ /** The padding offset */
+ padlen;
+ /** The current IV */
+ unsigned char IV[MAXBLOCKSIZE],
+ /** The pad used to encrypt/decrypt */
+ pad[MAXBLOCKSIZE];
+ /** The scheduled key */
+ symmetric_key key;
+} symmetric_CFB;
+#endif
+
+#ifdef LTC_OFB_MODE
+/** A block cipher OFB structure */
+typedef struct {
+ /** The index of the cipher chosen */
+ int cipher,
+ /** The block size of the given cipher */
+ blocklen,
+ /** The padding offset */
+ padlen;
+ /** The current IV */
+ unsigned char IV[MAXBLOCKSIZE];
+ /** The scheduled key */
+ symmetric_key key;
+} symmetric_OFB;
+#endif
+
+#ifdef LTC_CBC_MODE
+/** A block cipher CBC structure */
+typedef struct {
+ /** The index of the cipher chosen */
+ int cipher,
+ /** The block size of the given cipher */
+ blocklen;
+ /** The current IV */
+ unsigned char IV[MAXBLOCKSIZE];
+ /** The scheduled key */
+ symmetric_key key;
+} symmetric_CBC;
+#endif
+
+
+#ifdef LTC_CTR_MODE
+/** A block cipher CTR structure */
+typedef struct {
+ /** The index of the cipher chosen */
+ int cipher,
+ /** The block size of the given cipher */
+ blocklen,
+ /** The padding offset */
+ padlen,
+ /** The mode (endianess) of the CTR, 0==little, 1==big */
+ mode,
+ /** counter width */
+ ctrlen;
+
+ /** The counter */
+ unsigned char ctr[MAXBLOCKSIZE],
+ /** The pad used to encrypt/decrypt */
+ pad[MAXBLOCKSIZE];
+ /** The scheduled key */
+ symmetric_key key;
+} symmetric_CTR;
+#endif
+
+
+#ifdef LTC_LRW_MODE
+/** A LRW structure */
+typedef struct {
+ /** The index of the cipher chosen (must be a 128-bit block cipher) */
+ int cipher;
+
+ /** The current IV */
+ unsigned char IV[16],
+
+ /** the tweak key */
+ tweak[16],
+
+ /** The current pad, it's the product of the first 15 bytes against the tweak key */
+ pad[16];
+
+ /** The scheduled symmetric key */
+ symmetric_key key;
+
+#ifdef LRW_TABLES
+ /** The pre-computed multiplication table */
+ unsigned char PC[16][256][16];
+#endif
+} symmetric_LRW;
+#endif
+
+#ifdef LTC_F8_MODE
+/** A block cipher F8 structure */
+typedef struct {
+ /** The index of the cipher chosen */
+ int cipher,
+ /** The block size of the given cipher */
+ blocklen,
+ /** The padding offset */
+ padlen;
+ /** The current IV */
+ unsigned char IV[MAXBLOCKSIZE],
+ MIV[MAXBLOCKSIZE];
+ /** Current block count */
+ ulong32 blockcnt;
+ /** The scheduled key */
+ symmetric_key key;
+} symmetric_F8;
+#endif
+
+
+/** cipher descriptor table, last entry has "name == NULL" to mark the end of table */
+extern struct ltc_cipher_descriptor {
+ /** name of cipher */
+ char *name;
+ /** internal ID */
+ unsigned char ID;
+ /** min keysize (octets) */
+ int min_key_length,
+ /** max keysize (octets) */
+ max_key_length,
+ /** block size (octets) */
+ block_length,
+ /** default number of rounds */
+ default_rounds;
+ /** Setup the cipher
+ @param key The input symmetric key
+ @param keylen The length of the input key (octets)
+ @param num_rounds The requested number of rounds (0==default)
+ @param skey [out] The destination of the scheduled key
+ @return CRYPT_OK if successful
+ */
+ int (*setup)(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+ /** Encrypt a block
+ @param pt The plaintext
+ @param ct [out] The ciphertext
+ @param skey The scheduled key
+ @return CRYPT_OK if successful
+ */
+ int (*ecb_encrypt)(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
+ /** Decrypt a block
+ @param ct The ciphertext
+ @param pt [out] The plaintext
+ @param skey The scheduled key
+ @return CRYPT_OK if successful
+ */
+ int (*ecb_decrypt)(const unsigned char *ct, unsigned char *pt, symmetric_key *skey);
+ /** Test the block cipher
+ @return CRYPT_OK if successful, CRYPT_NOP if self-testing has been disabled
+ */
+ int (*test)(void);
+
+ /** Terminate the context
+ @param skey The scheduled key
+ */
+ void (*done)(symmetric_key *skey);
+
+ /** Determine a key size
+ @param keysize [in/out] The size of the key desired and the suggested size
+ @return CRYPT_OK if successful
+ */
+ int (*keysize)(int *keysize);
+
+/** Accelerators **/
+ /** Accelerated ECB encryption
+ @param pt Plaintext
+ @param ct Ciphertext
+ @param blocks The number of complete blocks to process
+ @param skey The scheduled key context
+ @return CRYPT_OK if successful
+ */
+ int (*accel_ecb_encrypt)(const unsigned char *pt, unsigned char *ct, unsigned long blocks, symmetric_key *skey);
+
+ /** Accelerated ECB decryption
+ @param pt Plaintext
+ @param ct Ciphertext
+ @param blocks The number of complete blocks to process
+ @param skey The scheduled key context
+ @return CRYPT_OK if successful
+ */
+ int (*accel_ecb_decrypt)(const unsigned char *ct, unsigned char *pt, unsigned long blocks, symmetric_key *skey);
+
+ /** Accelerated CBC encryption
+ @param pt Plaintext
+ @param ct Ciphertext
+ @param blocks The number of complete blocks to process
+ @param IV The initial value (input/output)
+ @param skey The scheduled key context
+ @return CRYPT_OK if successful
+ */
+ int (*accel_cbc_encrypt)(const unsigned char *pt, unsigned char *ct, unsigned long blocks, unsigned char *IV, symmetric_key *skey);
+
+ /** Accelerated CBC decryption
+ @param pt Plaintext
+ @param ct Ciphertext
+ @param blocks The number of complete blocks to process
+ @param IV The initial value (input/output)
+ @param skey The scheduled key context
+ @return CRYPT_OK if successful
+ */
+ int (*accel_cbc_decrypt)(const unsigned char *ct, unsigned char *pt, unsigned long blocks, unsigned char *IV, symmetric_key *skey);
+
+ /** Accelerated CTR encryption
+ @param pt Plaintext
+ @param ct Ciphertext
+ @param blocks The number of complete blocks to process
+ @param IV The initial value (input/output)
+ @param mode little or big endian counter (mode=0 or mode=1)
+ @param skey The scheduled key context
+ @return CRYPT_OK if successful
+ */
+ int (*accel_ctr_encrypt)(const unsigned char *pt, unsigned char *ct, unsigned long blocks, unsigned char *IV, int mode, symmetric_key *skey);
+
+ /** Accelerated LRW
+ @param pt Plaintext
+ @param ct Ciphertext
+ @param blocks The number of complete blocks to process
+ @param IV The initial value (input/output)
+ @param tweak The LRW tweak
+ @param skey The scheduled key context
+ @return CRYPT_OK if successful
+ */
+ int (*accel_lrw_encrypt)(const unsigned char *pt, unsigned char *ct, unsigned long blocks, unsigned char *IV, const unsigned char *tweak, symmetric_key *skey);
+
+ /** Accelerated LRW
+ @param ct Ciphertext
+ @param pt Plaintext
+ @param blocks The number of complete blocks to process
+ @param IV The initial value (input/output)
+ @param tweak The LRW tweak
+ @param skey The scheduled key context
+ @return CRYPT_OK if successful
+ */
+ int (*accel_lrw_decrypt)(const unsigned char *ct, unsigned char *pt, unsigned long blocks, unsigned char *IV, const unsigned char *tweak, symmetric_key *skey);
+
+ /** Accelerated CCM packet (one-shot)
+ @param key The secret key to use
+ @param keylen The length of the secret key (octets)
+ @param uskey A previously scheduled key [optional can be NULL]
+ @param nonce The session nonce [use once]
+ @param noncelen The length of the nonce
+ @param header The header for the session
+ @param headerlen The length of the header (octets)
+ @param pt [out] The plaintext
+ @param ptlen The length of the plaintext (octets)
+ @param ct [out] The ciphertext
+ @param tag [out] The destination tag
+ @param taglen [in/out] The max size and resulting size of the authentication tag
+ @param direction Encrypt or Decrypt direction (0 or 1)
+ @return CRYPT_OK if successful
+ */
+ int (*accel_ccm_memory)(
+ const unsigned char *key, unsigned long keylen,
+ symmetric_key *uskey,
+ const unsigned char *nonce, unsigned long noncelen,
+ const unsigned char *header, unsigned long headerlen,
+ unsigned char *pt, unsigned long ptlen,
+ unsigned char *ct,
+ unsigned char *tag, unsigned long *taglen,
+ int direction);
+
+ /** Accelerated GCM packet (one shot)
+ @param key The secret key
+ @param keylen The length of the secret key
+ @param IV The initial vector
+ @param IVlen The length of the initial vector
+ @param adata The additional authentication data (header)
+ @param adatalen The length of the adata
+ @param pt The plaintext
+ @param ptlen The length of the plaintext (ciphertext length is the same)
+ @param ct The ciphertext
+ @param tag [out] The MAC tag
+ @param taglen [in/out] The MAC tag length
+ @param direction Encrypt or Decrypt mode (GCM_ENCRYPT or GCM_DECRYPT)
+ @return CRYPT_OK on success
+ */
+ int (*accel_gcm_memory)(
+ const unsigned char *key, unsigned long keylen,
+ const unsigned char *IV, unsigned long IVlen,
+ const unsigned char *adata, unsigned long adatalen,
+ unsigned char *pt, unsigned long ptlen,
+ unsigned char *ct,
+ unsigned char *tag, unsigned long *taglen,
+ int direction);
+
+ /** Accelerated one shot LTC_OMAC
+ @param key The secret key
+ @param keylen The key length (octets)
+ @param in The message
+ @param inlen Length of message (octets)
+ @param out [out] Destination for tag
+ @param outlen [in/out] Initial and final size of out
+ @return CRYPT_OK on success
+ */
+ int (*omac_memory)(
+ const unsigned char *key, unsigned long keylen,
+ const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen);
+
+ /** Accelerated one shot XCBC
+ @param key The secret key
+ @param keylen The key length (octets)
+ @param in The message
+ @param inlen Length of message (octets)
+ @param out [out] Destination for tag
+ @param outlen [in/out] Initial and final size of out
+ @return CRYPT_OK on success
+ */
+ int (*xcbc_memory)(
+ const unsigned char *key, unsigned long keylen,
+ const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen);
+
+ /** Accelerated one shot F9
+ @param key The secret key
+ @param keylen The key length (octets)
+ @param in The message
+ @param inlen Length of message (octets)
+ @param out [out] Destination for tag
+ @param outlen [in/out] Initial and final size of out
+ @return CRYPT_OK on success
+ @remark Requires manual padding
+ */
+ int (*f9_memory)(
+ const unsigned char *key, unsigned long keylen,
+ const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen);
+} cipher_descriptor[];
+
+#ifdef LTC_BLOWFISH
+int blowfish_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+int blowfish_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
+int blowfish_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey);
+int blowfish_test(void);
+void blowfish_done(symmetric_key *skey);
+int blowfish_keysize(int *keysize);
+extern const struct ltc_cipher_descriptor blowfish_desc;
+#endif
+
+#ifdef LTC_RC5
+int rc5_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+int rc5_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
+int rc5_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey);
+int rc5_test(void);
+void rc5_done(symmetric_key *skey);
+int rc5_keysize(int *keysize);
+extern const struct ltc_cipher_descriptor rc5_desc;
+#endif
+
+#ifdef LTC_RC6
+int rc6_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+int rc6_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
+int rc6_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey);
+int rc6_test(void);
+void rc6_done(symmetric_key *skey);
+int rc6_keysize(int *keysize);
+extern const struct ltc_cipher_descriptor rc6_desc;
+#endif
+
+#ifdef LTC_RC2
+int rc2_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+int rc2_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
+int rc2_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey);
+int rc2_test(void);
+void rc2_done(symmetric_key *skey);
+int rc2_keysize(int *keysize);
+extern const struct ltc_cipher_descriptor rc2_desc;
+#endif
+
+#ifdef LTC_SAFERP
+int saferp_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+int saferp_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
+int saferp_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey);
+int saferp_test(void);
+void saferp_done(symmetric_key *skey);
+int saferp_keysize(int *keysize);
+extern const struct ltc_cipher_descriptor saferp_desc;
+#endif
+
+#ifdef LTC_SAFER
+int safer_k64_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+int safer_sk64_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+int safer_k128_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+int safer_sk128_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+int safer_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key);
+int safer_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key);
+int safer_k64_test(void);
+int safer_sk64_test(void);
+int safer_sk128_test(void);
+void safer_done(symmetric_key *skey);
+int safer_64_keysize(int *keysize);
+int safer_128_keysize(int *keysize);
+extern const struct ltc_cipher_descriptor safer_k64_desc, safer_k128_desc, safer_sk64_desc, safer_sk128_desc;
+#endif
+
+#ifdef LTC_RIJNDAEL
+
+/* make aes an alias */
+#define aes_setup rijndael_setup
+#define aes_ecb_encrypt rijndael_ecb_encrypt
+#define aes_ecb_decrypt rijndael_ecb_decrypt
+#define aes_test rijndael_test
+#define aes_done rijndael_done
+#define aes_keysize rijndael_keysize
+
+#define aes_enc_setup rijndael_enc_setup
+#define aes_enc_ecb_encrypt rijndael_enc_ecb_encrypt
+#define aes_enc_keysize rijndael_enc_keysize
+
+int rijndael_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+int rijndael_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
+int rijndael_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey);
+int rijndael_test(void);
+void rijndael_done(symmetric_key *skey);
+int rijndael_keysize(int *keysize);
+int rijndael_enc_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+int rijndael_enc_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
+void rijndael_enc_done(symmetric_key *skey);
+int rijndael_enc_keysize(int *keysize);
+extern const struct ltc_cipher_descriptor rijndael_desc, aes_desc;
+extern const struct ltc_cipher_descriptor rijndael_enc_desc, aes_enc_desc;
+#endif
+
+#ifdef LTC_XTEA
+int xtea_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+int xtea_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
+int xtea_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey);
+int xtea_test(void);
+void xtea_done(symmetric_key *skey);
+int xtea_keysize(int *keysize);
+extern const struct ltc_cipher_descriptor xtea_desc;
+#endif
+
+#ifdef LTC_TWOFISH
+int twofish_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+int twofish_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
+int twofish_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey);
+int twofish_test(void);
+void twofish_done(symmetric_key *skey);
+int twofish_keysize(int *keysize);
+extern const struct ltc_cipher_descriptor twofish_desc;
+#endif
+
+#ifdef LTC_DES
+int des_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+int des_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
+int des_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey);
+int des_test(void);
+void des_done(symmetric_key *skey);
+int des_keysize(int *keysize);
+int des3_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+int des3_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
+int des3_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey);
+int des3_test(void);
+void des3_done(symmetric_key *skey);
+int des3_keysize(int *keysize);
+extern const struct ltc_cipher_descriptor des_desc, des3_desc;
+#endif
+
+#ifdef LTC_CAST5
+int cast5_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+int cast5_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
+int cast5_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey);
+int cast5_test(void);
+void cast5_done(symmetric_key *skey);
+int cast5_keysize(int *keysize);
+extern const struct ltc_cipher_descriptor cast5_desc;
+#endif
+
+#ifdef LTC_NOEKEON
+int noekeon_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+int noekeon_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
+int noekeon_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey);
+int noekeon_test(void);
+void noekeon_done(symmetric_key *skey);
+int noekeon_keysize(int *keysize);
+extern const struct ltc_cipher_descriptor noekeon_desc;
+#endif
+
+#ifdef LTC_SKIPJACK
+int skipjack_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+int skipjack_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
+int skipjack_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey);
+int skipjack_test(void);
+void skipjack_done(symmetric_key *skey);
+int skipjack_keysize(int *keysize);
+extern const struct ltc_cipher_descriptor skipjack_desc;
+#endif
+
+#ifdef LTC_KHAZAD
+int khazad_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+int khazad_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
+int khazad_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey);
+int khazad_test(void);
+void khazad_done(symmetric_key *skey);
+int khazad_keysize(int *keysize);
+extern const struct ltc_cipher_descriptor khazad_desc;
+#endif
+
+#ifdef LTC_ANUBIS
+int anubis_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+int anubis_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
+int anubis_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey);
+int anubis_test(void);
+void anubis_done(symmetric_key *skey);
+int anubis_keysize(int *keysize);
+extern const struct ltc_cipher_descriptor anubis_desc;
+#endif
+
+#ifdef LTC_KSEED
+int kseed_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+int kseed_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
+int kseed_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey);
+int kseed_test(void);
+void kseed_done(symmetric_key *skey);
+int kseed_keysize(int *keysize);
+extern const struct ltc_cipher_descriptor kseed_desc;
+#endif
+
+#ifdef LTC_KASUMI
+int kasumi_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+int kasumi_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
+int kasumi_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey);
+int kasumi_test(void);
+void kasumi_done(symmetric_key *skey);
+int kasumi_keysize(int *keysize);
+extern const struct ltc_cipher_descriptor kasumi_desc;
+#endif
+
+
+#ifdef LTC_MULTI2
+int multi2_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+int multi2_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
+int multi2_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey);
+int multi2_test(void);
+void multi2_done(symmetric_key *skey);
+int multi2_keysize(int *keysize);
+extern const struct ltc_cipher_descriptor multi2_desc;
+#endif
+
+#ifdef LTC_ECB_MODE
+int ecb_start(int cipher, const unsigned char *key,
+ int keylen, int num_rounds, symmetric_ECB *ecb);
+int ecb_encrypt(const unsigned char *pt, unsigned char *ct, unsigned long len, symmetric_ECB *ecb);
+int ecb_decrypt(const unsigned char *ct, unsigned char *pt, unsigned long len, symmetric_ECB *ecb);
+int ecb_done(symmetric_ECB *ecb);
+#endif
+
+#ifdef LTC_CFB_MODE
+int cfb_start(int cipher, const unsigned char *IV, const unsigned char *key,
+ int keylen, int num_rounds, symmetric_CFB *cfb);
+int cfb_encrypt(const unsigned char *pt, unsigned char *ct, unsigned long len, symmetric_CFB *cfb);
+int cfb_decrypt(const unsigned char *ct, unsigned char *pt, unsigned long len, symmetric_CFB *cfb);
+int cfb_getiv(unsigned char *IV, unsigned long *len, symmetric_CFB *cfb);
+int cfb_setiv(const unsigned char *IV, unsigned long len, symmetric_CFB *cfb);
+int cfb_done(symmetric_CFB *cfb);
+#endif
+
+#ifdef LTC_OFB_MODE
+int ofb_start(int cipher, const unsigned char *IV, const unsigned char *key,
+ int keylen, int num_rounds, symmetric_OFB *ofb);
+int ofb_encrypt(const unsigned char *pt, unsigned char *ct, unsigned long len, symmetric_OFB *ofb);
+int ofb_decrypt(const unsigned char *ct, unsigned char *pt, unsigned long len, symmetric_OFB *ofb);
+int ofb_getiv(unsigned char *IV, unsigned long *len, symmetric_OFB *ofb);
+int ofb_setiv(const unsigned char *IV, unsigned long len, symmetric_OFB *ofb);
+int ofb_done(symmetric_OFB *ofb);
+#endif
+
+#ifdef LTC_CBC_MODE
+int cbc_start(int cipher, const unsigned char *IV, const unsigned char *key,
+ int keylen, int num_rounds, symmetric_CBC *cbc);
+int cbc_encrypt(const unsigned char *pt, unsigned char *ct, unsigned long len, symmetric_CBC *cbc);
+int cbc_decrypt(const unsigned char *ct, unsigned char *pt, unsigned long len, symmetric_CBC *cbc);
+int cbc_getiv(unsigned char *IV, unsigned long *len, symmetric_CBC *cbc);
+int cbc_setiv(const unsigned char *IV, unsigned long len, symmetric_CBC *cbc);
+int cbc_done(symmetric_CBC *cbc);
+#endif
+
+#ifdef LTC_CTR_MODE
+
+#define CTR_COUNTER_LITTLE_ENDIAN 0x0000
+#define CTR_COUNTER_BIG_ENDIAN 0x1000
+#define LTC_CTR_RFC3686 0x2000
+
+int ctr_start( int cipher,
+ const unsigned char *IV,
+ const unsigned char *key, int keylen,
+ int num_rounds, int ctr_mode,
+ symmetric_CTR *ctr);
+int ctr_encrypt(const unsigned char *pt, unsigned char *ct, unsigned long len, symmetric_CTR *ctr);
+int ctr_decrypt(const unsigned char *ct, unsigned char *pt, unsigned long len, symmetric_CTR *ctr);
+int ctr_getiv(unsigned char *IV, unsigned long *len, symmetric_CTR *ctr);
+int ctr_setiv(const unsigned char *IV, unsigned long len, symmetric_CTR *ctr);
+int ctr_done(symmetric_CTR *ctr);
+int ctr_test(void);
+#endif
+
+#ifdef LTC_LRW_MODE
+
+#define LRW_ENCRYPT 0
+#define LRW_DECRYPT 1
+
+int lrw_start( int cipher,
+ const unsigned char *IV,
+ const unsigned char *key, int keylen,
+ const unsigned char *tweak,
+ int num_rounds,
+ symmetric_LRW *lrw);
+int lrw_encrypt(const unsigned char *pt, unsigned char *ct, unsigned long len, symmetric_LRW *lrw);
+int lrw_decrypt(const unsigned char *ct, unsigned char *pt, unsigned long len, symmetric_LRW *lrw);
+int lrw_getiv(unsigned char *IV, unsigned long *len, symmetric_LRW *lrw);
+int lrw_setiv(const unsigned char *IV, unsigned long len, symmetric_LRW *lrw);
+int lrw_done(symmetric_LRW *lrw);
+int lrw_test(void);
+
+/* don't call */
+int lrw_process(const unsigned char *pt, unsigned char *ct, unsigned long len, int mode, symmetric_LRW *lrw);
+#endif
+
+#ifdef LTC_F8_MODE
+int f8_start( int cipher, const unsigned char *IV,
+ const unsigned char *key, int keylen,
+ const unsigned char *salt_key, int skeylen,
+ int num_rounds, symmetric_F8 *f8);
+int f8_encrypt(const unsigned char *pt, unsigned char *ct, unsigned long len, symmetric_F8 *f8);
+int f8_decrypt(const unsigned char *ct, unsigned char *pt, unsigned long len, symmetric_F8 *f8);
+int f8_getiv(unsigned char *IV, unsigned long *len, symmetric_F8 *f8);
+int f8_setiv(const unsigned char *IV, unsigned long len, symmetric_F8 *f8);
+int f8_done(symmetric_F8 *f8);
+int f8_test_mode(void);
+#endif
+
+#ifdef LTC_XTS_MODE
+typedef struct {
+ symmetric_key key1, key2;
+ int cipher;
+} symmetric_xts;
+
+int xts_start( int cipher,
+ const unsigned char *key1,
+ const unsigned char *key2,
+ unsigned long keylen,
+ int num_rounds,
+ symmetric_xts *xts);
+
+int xts_encrypt(
+ const unsigned char *pt, unsigned long ptlen,
+ unsigned char *ct,
+ const unsigned char *tweak,
+ symmetric_xts *xts);
+int xts_decrypt(
+ const unsigned char *ct, unsigned long ptlen,
+ unsigned char *pt,
+ const unsigned char *tweak,
+ symmetric_xts *xts);
+
+void xts_done(symmetric_xts *xts);
+int xts_test(void);
+void xts_mult_x(unsigned char *I);
+#endif
+
+int find_cipher(const char *name);
+int find_cipher_any(const char *name, int blocklen, int keylen);
+int find_cipher_id(unsigned char ID);
+int register_cipher(const struct ltc_cipher_descriptor *cipher);
+int unregister_cipher(const struct ltc_cipher_descriptor *cipher);
+int cipher_is_valid(int idx);
+
+LTC_MUTEX_PROTO(ltc_cipher_mutex)
+
+/* $Source: /cvs/libtom/libtomcrypt/src/headers/tomcrypt_cipher.h,v $ */
+/* $Revision: 1.54 $ */
+/* $Date: 2007/05/12 14:37:41 $ */
diff --git a/dep/CascLib/src/libtomcrypt/src/headers/tomcrypt_custom.h b/dep/CascLib/src/libtomcrypt/src/headers/tomcrypt_custom.h
new file mode 100644
index 00000000000..88ec8f984ab
--- /dev/null
+++ b/dep/CascLib/src/libtomcrypt/src/headers/tomcrypt_custom.h
@@ -0,0 +1,424 @@
+#ifndef TOMCRYPT_CUSTOM_H_
+#define TOMCRYPT_CUSTOM_H_
+
+#define LTC_NO_CIPHERS
+#define LTC_NO_HASHES
+#define LTC_NO_MACS
+#define LTC_NO_PRNGS
+#define LTC_NO_CURVES
+#define LTC_NO_MODES
+#define LTC_NO_PKCS
+#define LTC_NO_ROLC
+
+#define LTC_SOURCE
+#define LTC_SHA1
+#define LTC_MD5
+#define LTC_DER
+#define LTC_RC4
+
+#define USE_LTM
+#define LTM_DESC
+
+/* macros for various libc functions you can change for embedded targets */
+#ifndef XMALLOC
+ #ifdef malloc
+ #define LTC_NO_PROTOTYPES
+ #endif
+#define XMALLOC LibTomMalloc
+#endif
+#ifndef XREALLOC
+ #ifdef realloc
+ #define LTC_NO_PROTOTYPES
+ #endif
+#define XREALLOC LibTomRealloc
+#endif
+#ifndef XCALLOC
+ #ifdef calloc
+ #define LTC_NO_PROTOTYPES
+ #endif
+#define XCALLOC LibTomCalloc
+#endif
+#ifndef XFREE
+ #ifdef free
+ #define LTC_NO_PROTOTYPES
+ #endif
+#define XFREE LibTomFree
+#endif
+
+#ifndef XMEMSET
+ #ifdef memset
+ #define LTC_NO_PROTOTYPES
+ #endif
+#define XMEMSET memset
+#endif
+#ifndef XMEMCPY
+ #ifdef memcpy
+ #define LTC_NO_PROTOTYPES
+ #endif
+#define XMEMCPY memcpy
+#endif
+#ifndef XMEMCMP
+ #ifdef memcmp
+ #define LTC_NO_PROTOTYPES
+ #endif
+#define XMEMCMP memcmp
+#endif
+#ifndef XSTRCMP
+ #ifdef strcmp
+ #define LTC_NO_PROTOTYPES
+ #endif
+#define XSTRCMP strcmp
+#endif
+
+#ifndef XCLOCK
+#define XCLOCK LibTomClock
+#endif
+#ifndef XCLOCKS_PER_SEC
+#define XCLOCKS_PER_SEC CLOCKS_PER_SEC
+#endif
+
+#ifndef XQSORT
+ #ifdef qsort
+ #define LTC_NO_PROTOTYPES
+ #endif
+#define XQSORT LibTomQsort
+#endif
+
+/* Easy button? */
+#ifdef LTC_EASY
+ #define LTC_NO_CIPHERS
+ #define LTC_RIJNDAEL
+ #define LTC_BLOWFISH
+ #define LTC_DES
+ #define LTC_CAST5
+
+ #define LTC_NO_MODES
+ #define LTC_ECB_MODE
+ #define LTC_CBC_MODE
+ #define LTC_CTR_MODE
+
+ #define LTC_NO_HASHES
+ #define LTC_SHA1
+ #define LTC_SHA512
+ #define LTC_SHA384
+ #define LTC_SHA256
+ #define LTC_SHA224
+
+ #define LTC_NO_MACS
+ #define LTC_HMAC
+ #define LTC_OMAC
+ #define LTC_CCM_MODE
+
+ #define LTC_NO_PRNGS
+ #define LTC_SPRNG
+ #define LTC_YARROW
+ #define LTC_DEVRANDOM
+ #define TRY_URANDOM_FIRST
+
+ #define LTC_NO_PK
+ #define LTC_MRSA
+ #define LTC_MECC
+#endif
+
+/* Use small code where possible */
+/* #define LTC_SMALL_CODE */
+
+/* Enable self-test test vector checking */
+#ifndef LTC_NO_TEST
+ #define LTC_TEST
+#endif
+
+/* clean the stack of functions which put private information on stack */
+/* #define LTC_CLEAN_STACK */
+
+/* disable all file related functions */
+/* #define LTC_NO_FILE */
+
+/* disable all forms of ASM */
+/* #define LTC_NO_ASM */
+
+/* disable FAST mode */
+/* #define LTC_NO_FAST */
+
+/* disable BSWAP on x86 */
+/* #define LTC_NO_BSWAP */
+
+/* ---> Symmetric Block Ciphers <--- */
+#ifndef LTC_NO_CIPHERS
+
+#define LTC_BLOWFISH
+#define LTC_RC2
+#define LTC_RC5
+#define LTC_RC6
+#define LTC_SAFERP
+#define LTC_RIJNDAEL
+#define LTC_XTEA
+/* _TABLES tells it to use tables during setup, _SMALL means to use the smaller scheduled key format
+ * (saves 4KB of ram), _ALL_TABLES enables all tables during setup */
+#define LTC_TWOFISH
+#ifndef LTC_NO_TABLES
+ #define LTC_TWOFISH_TABLES
+ /* #define LTC_TWOFISH_ALL_TABLES */
+#else
+ #define LTC_TWOFISH_SMALL
+#endif
+/* #define LTC_TWOFISH_SMALL */
+/* LTC_DES includes EDE triple-LTC_DES */
+#define LTC_DES
+#define LTC_CAST5
+#define LTC_NOEKEON
+#define LTC_SKIPJACK
+#define LTC_SAFER
+#define LTC_KHAZAD
+#define LTC_ANUBIS
+#define LTC_ANUBIS_TWEAK
+#define LTC_KSEED
+#define LTC_KASUMI
+
+#endif /* LTC_NO_CIPHERS */
+
+
+/* ---> Block Cipher Modes of Operation <--- */
+#ifndef LTC_NO_MODES
+
+#define LTC_CFB_MODE
+#define LTC_OFB_MODE
+#define LTC_ECB_MODE
+#define LTC_CBC_MODE
+#define LTC_CTR_MODE
+
+/* F8 chaining mode */
+#define LTC_F8_MODE
+
+/* LRW mode */
+#define LTC_LRW_MODE
+#ifndef LTC_NO_TABLES
+ /* like GCM mode this will enable 16 8x128 tables [64KB] that make
+ * seeking very fast.
+ */
+ #define LRW_TABLES
+#endif
+
+/* XTS mode */
+#define LTC_XTS_MODE
+
+#endif /* LTC_NO_MODES */
+
+/* ---> One-Way Hash Functions <--- */
+#ifndef LTC_NO_HASHES
+
+#define LTC_CHC_HASH
+#define LTC_WHIRLPOOL
+#define LTC_SHA512
+#define LTC_SHA384
+#define LTC_SHA256
+#define LTC_SHA224
+#define LTC_TIGER
+#define LTC_SHA1
+#define LTC_MD5
+#define LTC_MD4
+#define LTC_MD2
+#define LTC_RIPEMD128
+#define LTC_RIPEMD160
+#define LTC_RIPEMD256
+#define LTC_RIPEMD320
+
+#endif /* LTC_NO_HASHES */
+
+/* ---> MAC functions <--- */
+#ifndef LTC_NO_MACS
+
+#define LTC_HMAC
+#define LTC_OMAC
+#define LTC_PMAC
+#define LTC_XCBC
+#define LTC_F9_MODE
+#define LTC_PELICAN
+
+#if defined(LTC_PELICAN) && !defined(LTC_RIJNDAEL)
+ #error Pelican-MAC requires LTC_RIJNDAEL
+#endif
+
+/* ---> Encrypt + Authenticate Modes <--- */
+
+#define LTC_EAX_MODE
+#if defined(LTC_EAX_MODE) && !(defined(LTC_CTR_MODE) && defined(LTC_OMAC))
+ #error LTC_EAX_MODE requires CTR and LTC_OMAC mode
+#endif
+
+#define LTC_OCB_MODE
+#define LTC_CCM_MODE
+#define LTC_GCM_MODE
+
+/* Use 64KiB tables */
+#ifndef LTC_NO_TABLES
+ #define LTC_GCM_TABLES
+#endif
+
+/* USE SSE2? requires GCC works on x86_32 and x86_64*/
+#ifdef LTC_GCM_TABLES
+/* #define LTC_GCM_TABLES_SSE2 */
+#endif
+
+#endif /* LTC_NO_MACS */
+
+/* Various tidbits of modern neatoness */
+#define LTC_BASE64
+
+/* --> Pseudo Random Number Generators <--- */
+#ifndef LTC_NO_PRNGS
+
+/* Yarrow */
+#define LTC_YARROW
+/* which descriptor of AES to use? */
+/* 0 = rijndael_enc 1 = aes_enc, 2 = rijndael [full], 3 = aes [full] */
+#define LTC_YARROW_AES 0
+
+#if defined(LTC_YARROW) && !defined(LTC_CTR_MODE)
+ #error LTC_YARROW requires LTC_CTR_MODE chaining mode to be defined!
+#endif
+
+/* a PRNG that simply reads from an available system source */
+#define LTC_SPRNG
+
+/* The LTC_RC4 stream cipher */
+#define LTC_RC4
+
+/* Fortuna PRNG */
+#define LTC_FORTUNA
+/* reseed every N calls to the read function */
+#define LTC_FORTUNA_WD 10
+/* number of pools (4..32) can save a bit of ram by lowering the count */
+#define LTC_FORTUNA_POOLS 32
+
+/* Greg's LTC_SOBER128 PRNG ;-0 */
+#define LTC_SOBER128
+
+/* the *nix style /dev/random device */
+#define LTC_DEVRANDOM
+/* try /dev/urandom before trying /dev/random */
+#define TRY_URANDOM_FIRST
+
+#endif /* LTC_NO_PRNGS */
+
+/* ---> math provider? <--- */
+#ifndef LTC_NO_MATH
+
+/* LibTomMath */
+#define LTM_LTC_DESC
+
+/* TomsFastMath */
+//#define TFM_LTC_DESC
+
+#endif /* LTC_NO_MATH */
+
+/* ---> Public Key Crypto <--- */
+#ifndef LTC_NO_PK
+
+/* Include RSA support */
+#define LTC_MRSA
+
+/* Include Katja (a Rabin variant like RSA) */
+/* #define MKAT */
+
+/* Digital Signature Algorithm */
+#define LTC_MDSA
+
+/* ECC */
+#define LTC_MECC
+
+/* use Shamir's trick for point mul (speeds up signature verification) */
+#define LTC_ECC_SHAMIR
+
+#if defined(TFM_LTC_DESC) && defined(LTC_MECC)
+ #define LTC_MECC_ACCEL
+#endif
+
+/* do we want fixed point ECC */
+/* #define LTC_MECC_FP */
+
+/* Timing Resistant? */
+/* #define LTC_ECC_TIMING_RESISTANT */
+
+#endif /* LTC_NO_PK */
+
+/* LTC_PKCS #1 (RSA) and #5 (Password Handling) stuff */
+#ifndef LTC_NO_PKCS
+
+#define LTC_PKCS_1
+#define LTC_PKCS_5
+
+/* Include ASN.1 DER (required by DSA/RSA) */
+#define LTC_DER
+
+#endif /* LTC_NO_PKCS */
+
+/* cleanup */
+
+#ifdef LTC_MECC
+/* Supported ECC Key Sizes */
+#ifndef LTC_NO_CURVES
+ #define ECC112
+ #define ECC128
+ #define ECC160
+ #define ECC192
+ #define ECC224
+ #define ECC256
+ #define ECC384
+ #define ECC521
+#endif
+#endif
+
+#if defined(LTC_MECC) || defined(LTC_MRSA) || defined(LTC_MDSA) || defined(MKATJA)
+ /* Include the MPI functionality? (required by the PK algorithms) */
+ #define MPI
+#endif
+
+#ifdef LTC_MRSA
+ #define LTC_PKCS_1
+#endif
+
+#if defined(LTC_DER) && !defined(MPI)
+ #error ASN.1 DER requires MPI functionality
+#endif
+
+#if (defined(LTC_MDSA) || defined(LTC_MRSA) || defined(LTC_MECC) || defined(MKATJA)) && !defined(LTC_DER)
+ #error PK requires ASN.1 DER functionality, make sure LTC_DER is enabled
+#endif
+
+/* THREAD management */
+#ifdef LTC_PTHREAD
+
+#include <pthread.h>
+
+#define LTC_MUTEX_GLOBAL(x) pthread_mutex_t x = PTHREAD_MUTEX_INITIALIZER;
+#define LTC_MUTEX_PROTO(x) extern pthread_mutex_t x;
+#define LTC_MUTEX_TYPE(x) pthread_mutex_t x;
+#define LTC_MUTEX_INIT(x) pthread_mutex_init(x, NULL);
+#define LTC_MUTEX_LOCK(x) pthread_mutex_lock(x);
+#define LTC_MUTEX_UNLOCK(x) pthread_mutex_unlock(x);
+
+#else
+
+/* default no functions */
+#define LTC_MUTEX_GLOBAL(x)
+#define LTC_MUTEX_PROTO(x)
+#define LTC_MUTEX_TYPE(x)
+#define LTC_MUTEX_INIT(x)
+#define LTC_MUTEX_LOCK(x)
+#define LTC_MUTEX_UNLOCK(x)
+
+#endif
+
+/* Debuggers */
+
+/* define this if you use Valgrind, note: it CHANGES the way SOBER-128 and LTC_RC4 work (see the code) */
+/* #define LTC_VALGRIND */
+
+#endif
+
+
+
+/* $Source: /cvs/libtom/libtomcrypt/src/headers/tomcrypt_custom.h,v $ */
+/* $Revision: 1.73 $ */
+/* $Date: 2007/05/12 14:37:41 $ */
diff --git a/dep/CascLib/src/libtomcrypt/src/headers/tomcrypt_hash.h b/dep/CascLib/src/libtomcrypt/src/headers/tomcrypt_hash.h
new file mode 100644
index 00000000000..18553ebf9da
--- /dev/null
+++ b/dep/CascLib/src/libtomcrypt/src/headers/tomcrypt_hash.h
@@ -0,0 +1,378 @@
+/* ---- HASH FUNCTIONS ---- */
+#ifdef LTC_SHA512
+struct sha512_state {
+ ulong64 length, state[8];
+ unsigned long curlen;
+ unsigned char buf[128];
+};
+#endif
+
+#ifdef LTC_SHA256
+struct sha256_state {
+ ulong64 length;
+ ulong32 state[8], curlen;
+ unsigned char buf[64];
+};
+#endif
+
+#ifdef LTC_SHA1
+struct sha1_state {
+ ulong64 length;
+ ulong32 state[5], curlen;
+ unsigned char buf[64];
+};
+#endif
+
+#ifdef LTC_MD5
+struct md5_state {
+ ulong64 length;
+ ulong32 state[4], curlen;
+ unsigned char buf[64];
+};
+#endif
+
+#ifdef LTC_MD4
+struct md4_state {
+ ulong64 length;
+ ulong32 state[4], curlen;
+ unsigned char buf[64];
+};
+#endif
+
+#ifdef LTC_TIGER
+struct tiger_state {
+ ulong64 state[3], length;
+ unsigned long curlen;
+ unsigned char buf[64];
+};
+#endif
+
+#ifdef LTC_MD2
+struct md2_state {
+ unsigned char chksum[16], X[48], buf[16];
+ unsigned long curlen;
+};
+#endif
+
+#ifdef LTC_RIPEMD128
+struct rmd128_state {
+ ulong64 length;
+ unsigned char buf[64];
+ ulong32 curlen, state[4];
+};
+#endif
+
+#ifdef LTC_RIPEMD160
+struct rmd160_state {
+ ulong64 length;
+ unsigned char buf[64];
+ ulong32 curlen, state[5];
+};
+#endif
+
+#ifdef LTC_RIPEMD256
+struct rmd256_state {
+ ulong64 length;
+ unsigned char buf[64];
+ ulong32 curlen, state[8];
+};
+#endif
+
+#ifdef LTC_RIPEMD320
+struct rmd320_state {
+ ulong64 length;
+ unsigned char buf[64];
+ ulong32 curlen, state[10];
+};
+#endif
+
+#ifdef LTC_WHIRLPOOL
+struct whirlpool_state {
+ ulong64 length, state[8];
+ unsigned char buf[64];
+ ulong32 curlen;
+};
+#endif
+
+#ifdef LTC_CHC_HASH
+struct chc_state {
+ ulong64 length;
+ unsigned char state[MAXBLOCKSIZE], buf[MAXBLOCKSIZE];
+ ulong32 curlen;
+};
+#endif
+
+typedef union Hash_state {
+#ifdef LTC_CHC_HASH
+ struct chc_state chc;
+#endif
+#ifdef LTC_WHIRLPOOL
+ struct whirlpool_state whirlpool;
+#endif
+#ifdef LTC_SHA512
+ struct sha512_state sha512;
+#endif
+#ifdef LTC_SHA256
+ struct sha256_state sha256;
+#endif
+#ifdef LTC_SHA1
+ struct sha1_state sha1;
+#endif
+#ifdef LTC_MD5
+ struct md5_state md5;
+#endif
+#ifdef LTC_MD4
+ struct md4_state md4;
+#endif
+#ifdef LTC_MD2
+ struct md2_state md2;
+#endif
+#ifdef LTC_TIGER
+ struct tiger_state tiger;
+#endif
+#ifdef LTC_RIPEMD128
+ struct rmd128_state rmd128;
+#endif
+#ifdef LTC_RIPEMD160
+ struct rmd160_state rmd160;
+#endif
+#ifdef LTC_RIPEMD256
+ struct rmd256_state rmd256;
+#endif
+#ifdef LTC_RIPEMD320
+ struct rmd320_state rmd320;
+#endif
+ void *data;
+} hash_state;
+
+/** hash descriptor */
+extern struct ltc_hash_descriptor {
+ /** name of hash */
+ char *name;
+ /** internal ID */
+ unsigned char ID;
+ /** Size of digest in octets */
+ unsigned long hashsize;
+ /** Input block size in octets */
+ unsigned long blocksize;
+ /** ASN.1 OID */
+ unsigned long OID[16];
+ /** Length of DER encoding */
+ unsigned long OIDlen;
+
+ /** Init a hash state
+ @param hash The hash to initialize
+ @return CRYPT_OK if successful
+ */
+ int (*init)(hash_state *hash);
+ /** Process a block of data
+ @param hash The hash state
+ @param in The data to hash
+ @param inlen The length of the data (octets)
+ @return CRYPT_OK if successful
+ */
+ int (*process)(hash_state *hash, const unsigned char *in, unsigned long inlen);
+ /** Produce the digest and store it
+ @param hash The hash state
+ @param out [out] The destination of the digest
+ @return CRYPT_OK if successful
+ */
+ int (*done)(hash_state *hash, unsigned char *out);
+ /** Self-test
+ @return CRYPT_OK if successful, CRYPT_NOP if self-tests have been disabled
+ */
+ int (*test)(void);
+
+ /* accelerated hmac callback: if you need to-do multiple packets just use the generic hmac_memory and provide a hash callback */
+ int (*hmac_block)(const unsigned char *key, unsigned long keylen,
+ const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen);
+
+} hash_descriptor[];
+
+#ifdef LTC_CHC_HASH
+int chc_register(int cipher);
+int chc_init(hash_state * md);
+int chc_process(hash_state * md, const unsigned char *in, unsigned long inlen);
+int chc_done(hash_state * md, unsigned char *hash);
+int chc_test(void);
+extern const struct ltc_hash_descriptor chc_desc;
+#endif
+
+#ifdef LTC_WHIRLPOOL
+int whirlpool_init(hash_state * md);
+int whirlpool_process(hash_state * md, const unsigned char *in, unsigned long inlen);
+int whirlpool_done(hash_state * md, unsigned char *hash);
+int whirlpool_test(void);
+extern const struct ltc_hash_descriptor whirlpool_desc;
+#endif
+
+#ifdef LTC_SHA512
+int sha512_init(hash_state * md);
+int sha512_process(hash_state * md, const unsigned char *in, unsigned long inlen);
+int sha512_done(hash_state * md, unsigned char *hash);
+int sha512_test(void);
+extern const struct ltc_hash_descriptor sha512_desc;
+#endif
+
+#ifdef LTC_SHA384
+#ifndef LTC_SHA512
+ #error LTC_SHA512 is required for LTC_SHA384
+#endif
+int sha384_init(hash_state * md);
+#define sha384_process sha512_process
+int sha384_done(hash_state * md, unsigned char *hash);
+int sha384_test(void);
+extern const struct ltc_hash_descriptor sha384_desc;
+#endif
+
+#ifdef LTC_SHA256
+int sha256_init(hash_state * md);
+int sha256_process(hash_state * md, const unsigned char *in, unsigned long inlen);
+int sha256_done(hash_state * md, unsigned char *hash);
+int sha256_test(void);
+extern const struct ltc_hash_descriptor sha256_desc;
+
+#ifdef LTC_SHA224
+#ifndef LTC_SHA256
+ #error LTC_SHA256 is required for LTC_SHA224
+#endif
+int sha224_init(hash_state * md);
+#define sha224_process sha256_process
+int sha224_done(hash_state * md, unsigned char *hash);
+int sha224_test(void);
+extern const struct ltc_hash_descriptor sha224_desc;
+#endif
+#endif
+
+#ifdef LTC_SHA1
+int sha1_init(hash_state * md);
+int sha1_process(hash_state * md, const unsigned char *in, unsigned long inlen);
+int sha1_done(hash_state * md, unsigned char *hash);
+int sha1_test(void);
+extern const struct ltc_hash_descriptor sha1_desc;
+#endif
+
+#ifdef LTC_MD5
+int md5_init(hash_state * md);
+int md5_process(hash_state * md, const unsigned char *in, unsigned long inlen);
+int md5_done(hash_state * md, unsigned char *hash);
+int md5_test(void);
+extern const struct ltc_hash_descriptor md5_desc;
+#endif
+
+#ifdef LTC_MD4
+int md4_init(hash_state * md);
+int md4_process(hash_state * md, const unsigned char *in, unsigned long inlen);
+int md4_done(hash_state * md, unsigned char *hash);
+int md4_test(void);
+extern const struct ltc_hash_descriptor md4_desc;
+#endif
+
+#ifdef LTC_MD2
+int md2_init(hash_state * md);
+int md2_process(hash_state * md, const unsigned char *in, unsigned long inlen);
+int md2_done(hash_state * md, unsigned char *hash);
+int md2_test(void);
+extern const struct ltc_hash_descriptor md2_desc;
+#endif
+
+#ifdef LTC_TIGER
+int tiger_init(hash_state * md);
+int tiger_process(hash_state * md, const unsigned char *in, unsigned long inlen);
+int tiger_done(hash_state * md, unsigned char *hash);
+int tiger_test(void);
+extern const struct ltc_hash_descriptor tiger_desc;
+#endif
+
+#ifdef LTC_RIPEMD128
+int rmd128_init(hash_state * md);
+int rmd128_process(hash_state * md, const unsigned char *in, unsigned long inlen);
+int rmd128_done(hash_state * md, unsigned char *hash);
+int rmd128_test(void);
+extern const struct ltc_hash_descriptor rmd128_desc;
+#endif
+
+#ifdef LTC_RIPEMD160
+int rmd160_init(hash_state * md);
+int rmd160_process(hash_state * md, const unsigned char *in, unsigned long inlen);
+int rmd160_done(hash_state * md, unsigned char *hash);
+int rmd160_test(void);
+extern const struct ltc_hash_descriptor rmd160_desc;
+#endif
+
+#ifdef LTC_RIPEMD256
+int rmd256_init(hash_state * md);
+int rmd256_process(hash_state * md, const unsigned char *in, unsigned long inlen);
+int rmd256_done(hash_state * md, unsigned char *hash);
+int rmd256_test(void);
+extern const struct ltc_hash_descriptor rmd256_desc;
+#endif
+
+#ifdef LTC_RIPEMD320
+int rmd320_init(hash_state * md);
+int rmd320_process(hash_state * md, const unsigned char *in, unsigned long inlen);
+int rmd320_done(hash_state * md, unsigned char *hash);
+int rmd320_test(void);
+extern const struct ltc_hash_descriptor rmd320_desc;
+#endif
+
+
+int find_hash(const char *name);
+int find_hash_id(unsigned char ID);
+int find_hash_oid(const unsigned long *ID, unsigned long IDlen);
+int find_hash_any(const char *name, int digestlen);
+int register_hash(const struct ltc_hash_descriptor *hash);
+int unregister_hash(const struct ltc_hash_descriptor *hash);
+int hash_is_valid(int idx);
+
+LTC_MUTEX_PROTO(ltc_hash_mutex)
+
+int hash_memory(int hash,
+ const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen);
+int hash_memory_multi(int hash, unsigned char *out, unsigned long *outlen,
+ const unsigned char *in, unsigned long inlen, ...);
+int hash_filehandle(int hash, FILE *in, unsigned char *out, unsigned long *outlen);
+int hash_file(int hash, const char *fname, unsigned char *out, unsigned long *outlen);
+
+/* a simple macro for making hash "process" functions */
+#define HASH_PROCESS(func_name, compress_name, state_var, block_size) \
+int func_name (hash_state * md, const unsigned char *in, unsigned long inlen) \
+{ \
+ unsigned long n; \
+ int err; \
+ LTC_ARGCHK(md != NULL); \
+ LTC_ARGCHK(in != NULL); \
+ if (md-> state_var .curlen > sizeof(md-> state_var .buf)) { \
+ return CRYPT_INVALID_ARG; \
+ } \
+ while (inlen > 0) { \
+ if (md-> state_var .curlen == 0 && inlen >= block_size) { \
+ if ((err = compress_name (md, (unsigned char *)in)) != CRYPT_OK) { \
+ return err; \
+ } \
+ md-> state_var .length += block_size * 8; \
+ in += block_size; \
+ inlen -= block_size; \
+ } else { \
+ n = MIN(inlen, (block_size - md-> state_var .curlen)); \
+ memcpy(md-> state_var .buf + md-> state_var.curlen, in, (size_t)n); \
+ md-> state_var .curlen += n; \
+ in += n; \
+ inlen -= n; \
+ if (md-> state_var .curlen == block_size) { \
+ if ((err = compress_name (md, md-> state_var .buf)) != CRYPT_OK) { \
+ return err; \
+ } \
+ md-> state_var .length += 8*block_size; \
+ md-> state_var .curlen = 0; \
+ } \
+ } \
+ } \
+ return CRYPT_OK; \
+}
+
+/* $Source: /cvs/libtom/libtomcrypt/src/headers/tomcrypt_hash.h,v $ */
+/* $Revision: 1.22 $ */
+/* $Date: 2007/05/12 14:32:35 $ */
diff --git a/dep/CascLib/src/libtomcrypt/src/headers/tomcrypt_mac.h b/dep/CascLib/src/libtomcrypt/src/headers/tomcrypt_mac.h
new file mode 100644
index 00000000000..7ad9516bd29
--- /dev/null
+++ b/dep/CascLib/src/libtomcrypt/src/headers/tomcrypt_mac.h
@@ -0,0 +1,384 @@
+#ifdef LTC_HMAC
+typedef struct Hmac_state {
+ hash_state md;
+ int hash;
+ hash_state hashstate;
+ unsigned char *key;
+} hmac_state;
+
+int hmac_init(hmac_state *hmac, int hash, const unsigned char *key, unsigned long keylen);
+int hmac_process(hmac_state *hmac, const unsigned char *in, unsigned long inlen);
+int hmac_done(hmac_state *hmac, unsigned char *out, unsigned long *outlen);
+int hmac_test(void);
+int hmac_memory(int hash,
+ const unsigned char *key, unsigned long keylen,
+ const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen);
+int hmac_memory_multi(int hash,
+ const unsigned char *key, unsigned long keylen,
+ unsigned char *out, unsigned long *outlen,
+ const unsigned char *in, unsigned long inlen, ...);
+int hmac_file(int hash, const char *fname, const unsigned char *key,
+ unsigned long keylen,
+ unsigned char *dst, unsigned long *dstlen);
+#endif
+
+#ifdef LTC_OMAC
+
+typedef struct {
+ int cipher_idx,
+ buflen,
+ blklen;
+ unsigned char block[MAXBLOCKSIZE],
+ prev[MAXBLOCKSIZE],
+ Lu[2][MAXBLOCKSIZE];
+ symmetric_key key;
+} omac_state;
+
+int omac_init(omac_state *omac, int cipher, const unsigned char *key, unsigned long keylen);
+int omac_process(omac_state *omac, const unsigned char *in, unsigned long inlen);
+int omac_done(omac_state *omac, unsigned char *out, unsigned long *outlen);
+int omac_memory(int cipher,
+ const unsigned char *key, unsigned long keylen,
+ const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen);
+int omac_memory_multi(int cipher,
+ const unsigned char *key, unsigned long keylen,
+ unsigned char *out, unsigned long *outlen,
+ const unsigned char *in, unsigned long inlen, ...);
+int omac_file(int cipher,
+ const unsigned char *key, unsigned long keylen,
+ const char *filename,
+ unsigned char *out, unsigned long *outlen);
+int omac_test(void);
+#endif /* LTC_OMAC */
+
+#ifdef LTC_PMAC
+
+typedef struct {
+ unsigned char Ls[32][MAXBLOCKSIZE], /* L shifted by i bits to the left */
+ Li[MAXBLOCKSIZE], /* value of Li [current value, we calc from previous recall] */
+ Lr[MAXBLOCKSIZE], /* L * x^-1 */
+ block[MAXBLOCKSIZE], /* currently accumulated block */
+ checksum[MAXBLOCKSIZE]; /* current checksum */
+
+ symmetric_key key; /* scheduled key for cipher */
+ unsigned long block_index; /* index # for current block */
+ int cipher_idx, /* cipher idx */
+ block_len, /* length of block */
+ buflen; /* number of bytes in the buffer */
+} pmac_state;
+
+int pmac_init(pmac_state *pmac, int cipher, const unsigned char *key, unsigned long keylen);
+int pmac_process(pmac_state *pmac, const unsigned char *in, unsigned long inlen);
+int pmac_done(pmac_state *pmac, unsigned char *out, unsigned long *outlen);
+
+int pmac_memory(int cipher,
+ const unsigned char *key, unsigned long keylen,
+ const unsigned char *msg, unsigned long msglen,
+ unsigned char *out, unsigned long *outlen);
+
+int pmac_memory_multi(int cipher,
+ const unsigned char *key, unsigned long keylen,
+ unsigned char *out, unsigned long *outlen,
+ const unsigned char *in, unsigned long inlen, ...);
+
+int pmac_file(int cipher,
+ const unsigned char *key, unsigned long keylen,
+ const char *filename,
+ unsigned char *out, unsigned long *outlen);
+
+int pmac_test(void);
+
+/* internal functions */
+int pmac_ntz(unsigned long x);
+void pmac_shift_xor(pmac_state *pmac);
+
+#endif /* PMAC */
+
+#ifdef LTC_EAX_MODE
+
+#if !(defined(LTC_OMAC) && defined(LTC_CTR_MODE))
+ #error LTC_EAX_MODE requires LTC_OMAC and CTR
+#endif
+
+typedef struct {
+ unsigned char N[MAXBLOCKSIZE];
+ symmetric_CTR ctr;
+ omac_state headeromac, ctomac;
+} eax_state;
+
+int eax_init(eax_state *eax, int cipher, const unsigned char *key, unsigned long keylen,
+ const unsigned char *nonce, unsigned long noncelen,
+ const unsigned char *header, unsigned long headerlen);
+
+int eax_encrypt(eax_state *eax, const unsigned char *pt, unsigned char *ct, unsigned long length);
+int eax_decrypt(eax_state *eax, const unsigned char *ct, unsigned char *pt, unsigned long length);
+int eax_addheader(eax_state *eax, const unsigned char *header, unsigned long length);
+int eax_done(eax_state *eax, unsigned char *tag, unsigned long *taglen);
+
+int eax_encrypt_authenticate_memory(int cipher,
+ const unsigned char *key, unsigned long keylen,
+ const unsigned char *nonce, unsigned long noncelen,
+ const unsigned char *header, unsigned long headerlen,
+ const unsigned char *pt, unsigned long ptlen,
+ unsigned char *ct,
+ unsigned char *tag, unsigned long *taglen);
+
+int eax_decrypt_verify_memory(int cipher,
+ const unsigned char *key, unsigned long keylen,
+ const unsigned char *nonce, unsigned long noncelen,
+ const unsigned char *header, unsigned long headerlen,
+ const unsigned char *ct, unsigned long ctlen,
+ unsigned char *pt,
+ unsigned char *tag, unsigned long taglen,
+ int *stat);
+
+ int eax_test(void);
+#endif /* EAX MODE */
+
+#ifdef LTC_OCB_MODE
+typedef struct {
+ unsigned char L[MAXBLOCKSIZE], /* L value */
+ Ls[32][MAXBLOCKSIZE], /* L shifted by i bits to the left */
+ Li[MAXBLOCKSIZE], /* value of Li [current value, we calc from previous recall] */
+ Lr[MAXBLOCKSIZE], /* L * x^-1 */
+ R[MAXBLOCKSIZE], /* R value */
+ checksum[MAXBLOCKSIZE]; /* current checksum */
+
+ symmetric_key key; /* scheduled key for cipher */
+ unsigned long block_index; /* index # for current block */
+ int cipher, /* cipher idx */
+ block_len; /* length of block */
+} ocb_state;
+
+int ocb_init(ocb_state *ocb, int cipher,
+ const unsigned char *key, unsigned long keylen, const unsigned char *nonce);
+
+int ocb_encrypt(ocb_state *ocb, const unsigned char *pt, unsigned char *ct);
+int ocb_decrypt(ocb_state *ocb, const unsigned char *ct, unsigned char *pt);
+
+int ocb_done_encrypt(ocb_state *ocb,
+ const unsigned char *pt, unsigned long ptlen,
+ unsigned char *ct,
+ unsigned char *tag, unsigned long *taglen);
+
+int ocb_done_decrypt(ocb_state *ocb,
+ const unsigned char *ct, unsigned long ctlen,
+ unsigned char *pt,
+ const unsigned char *tag, unsigned long taglen, int *stat);
+
+int ocb_encrypt_authenticate_memory(int cipher,
+ const unsigned char *key, unsigned long keylen,
+ const unsigned char *nonce,
+ const unsigned char *pt, unsigned long ptlen,
+ unsigned char *ct,
+ unsigned char *tag, unsigned long *taglen);
+
+int ocb_decrypt_verify_memory(int cipher,
+ const unsigned char *key, unsigned long keylen,
+ const unsigned char *nonce,
+ const unsigned char *ct, unsigned long ctlen,
+ unsigned char *pt,
+ const unsigned char *tag, unsigned long taglen,
+ int *stat);
+
+int ocb_test(void);
+
+/* internal functions */
+void ocb_shift_xor(ocb_state *ocb, unsigned char *Z);
+int ocb_ntz(unsigned long x);
+int s_ocb_done(ocb_state *ocb, const unsigned char *pt, unsigned long ptlen,
+ unsigned char *ct, unsigned char *tag, unsigned long *taglen, int mode);
+
+#endif /* LTC_OCB_MODE */
+
+#ifdef LTC_CCM_MODE
+
+#define CCM_ENCRYPT 0
+#define CCM_DECRYPT 1
+
+int ccm_memory(int cipher,
+ const unsigned char *key, unsigned long keylen,
+ symmetric_key *uskey,
+ const unsigned char *nonce, unsigned long noncelen,
+ const unsigned char *header, unsigned long headerlen,
+ unsigned char *pt, unsigned long ptlen,
+ unsigned char *ct,
+ unsigned char *tag, unsigned long *taglen,
+ int direction);
+
+int ccm_test(void);
+
+#endif /* LTC_CCM_MODE */
+
+#if defined(LRW_MODE) || defined(LTC_GCM_MODE)
+void gcm_gf_mult(const unsigned char *a, const unsigned char *b, unsigned char *c);
+#endif
+
+
+/* table shared between GCM and LRW */
+#if defined(LTC_GCM_TABLES) || defined(LRW_TABLES) || ((defined(LTC_GCM_MODE) || defined(LTC_GCM_MODE)) && defined(LTC_FAST))
+extern const unsigned char gcm_shift_table[];
+#endif
+
+#ifdef LTC_GCM_MODE
+
+#define GCM_ENCRYPT 0
+#define GCM_DECRYPT 1
+
+#define LTC_GCM_MODE_IV 0
+#define LTC_GCM_MODE_AAD 1
+#define LTC_GCM_MODE_TEXT 2
+
+typedef struct {
+ symmetric_key K;
+ unsigned char H[16], /* multiplier */
+ X[16], /* accumulator */
+ Y[16], /* counter */
+ Y_0[16], /* initial counter */
+ buf[16]; /* buffer for stuff */
+
+ int cipher, /* which cipher */
+ ivmode, /* Which mode is the IV in? */
+ mode, /* mode the GCM code is in */
+ buflen; /* length of data in buf */
+
+ ulong64 totlen, /* 64-bit counter used for IV and AAD */
+ pttotlen; /* 64-bit counter for the PT */
+
+#ifdef LTC_GCM_TABLES
+ unsigned char PC[16][256][16] /* 16 tables of 8x128 */
+#ifdef LTC_GCM_TABLES_SSE2
+__attribute__ ((aligned (16)))
+#endif
+;
+#endif
+} gcm_state;
+
+void gcm_mult_h(gcm_state *gcm, unsigned char *I);
+
+int gcm_init(gcm_state *gcm, int cipher,
+ const unsigned char *key, int keylen);
+
+int gcm_reset(gcm_state *gcm);
+
+int gcm_add_iv(gcm_state *gcm,
+ const unsigned char *IV, unsigned long IVlen);
+
+int gcm_add_aad(gcm_state *gcm,
+ const unsigned char *adata, unsigned long adatalen);
+
+int gcm_process(gcm_state *gcm,
+ unsigned char *pt, unsigned long ptlen,
+ unsigned char *ct,
+ int direction);
+
+int gcm_done(gcm_state *gcm,
+ unsigned char *tag, unsigned long *taglen);
+
+int gcm_memory( int cipher,
+ const unsigned char *key, unsigned long keylen,
+ const unsigned char *IV, unsigned long IVlen,
+ const unsigned char *adata, unsigned long adatalen,
+ unsigned char *pt, unsigned long ptlen,
+ unsigned char *ct,
+ unsigned char *tag, unsigned long *taglen,
+ int direction);
+int gcm_test(void);
+
+#endif /* LTC_GCM_MODE */
+
+#ifdef LTC_PELICAN
+
+typedef struct pelican_state
+{
+ symmetric_key K;
+ unsigned char state[16];
+ int buflen;
+} pelican_state;
+
+int pelican_init(pelican_state *pelmac, const unsigned char *key, unsigned long keylen);
+int pelican_process(pelican_state *pelmac, const unsigned char *in, unsigned long inlen);
+int pelican_done(pelican_state *pelmac, unsigned char *out);
+int pelican_test(void);
+
+int pelican_memory(const unsigned char *key, unsigned long keylen,
+ const unsigned char *in, unsigned long inlen,
+ unsigned char *out);
+
+#endif
+
+#ifdef LTC_XCBC
+
+/* add this to "keylen" to xcbc_init to use a pure three-key XCBC MAC */
+#define LTC_XCBC_PURE 0x8000UL
+
+typedef struct {
+ unsigned char K[3][MAXBLOCKSIZE],
+ IV[MAXBLOCKSIZE];
+
+ symmetric_key key;
+
+ int cipher,
+ buflen,
+ blocksize;
+} xcbc_state;
+
+int xcbc_init(xcbc_state *xcbc, int cipher, const unsigned char *key, unsigned long keylen);
+int xcbc_process(xcbc_state *xcbc, const unsigned char *in, unsigned long inlen);
+int xcbc_done(xcbc_state *xcbc, unsigned char *out, unsigned long *outlen);
+int xcbc_memory(int cipher,
+ const unsigned char *key, unsigned long keylen,
+ const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen);
+int xcbc_memory_multi(int cipher,
+ const unsigned char *key, unsigned long keylen,
+ unsigned char *out, unsigned long *outlen,
+ const unsigned char *in, unsigned long inlen, ...);
+int xcbc_file(int cipher,
+ const unsigned char *key, unsigned long keylen,
+ const char *filename,
+ unsigned char *out, unsigned long *outlen);
+int xcbc_test(void);
+
+#endif
+
+#ifdef LTC_F9_MODE
+
+typedef struct {
+ unsigned char akey[MAXBLOCKSIZE],
+ ACC[MAXBLOCKSIZE],
+ IV[MAXBLOCKSIZE];
+
+ symmetric_key key;
+
+ int cipher,
+ buflen,
+ keylen,
+ blocksize;
+} f9_state;
+
+int f9_init(f9_state *f9, int cipher, const unsigned char *key, unsigned long keylen);
+int f9_process(f9_state *f9, const unsigned char *in, unsigned long inlen);
+int f9_done(f9_state *f9, unsigned char *out, unsigned long *outlen);
+int f9_memory(int cipher,
+ const unsigned char *key, unsigned long keylen,
+ const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen);
+int f9_memory_multi(int cipher,
+ const unsigned char *key, unsigned long keylen,
+ unsigned char *out, unsigned long *outlen,
+ const unsigned char *in, unsigned long inlen, ...);
+int f9_file(int cipher,
+ const unsigned char *key, unsigned long keylen,
+ const char *filename,
+ unsigned char *out, unsigned long *outlen);
+int f9_test(void);
+
+#endif
+
+
+/* $Source: /cvs/libtom/libtomcrypt/src/headers/tomcrypt_mac.h,v $ */
+/* $Revision: 1.23 $ */
+/* $Date: 2007/05/12 14:37:41 $ */
diff --git a/dep/CascLib/src/libtomcrypt/src/headers/tomcrypt_macros.h b/dep/CascLib/src/libtomcrypt/src/headers/tomcrypt_macros.h
new file mode 100644
index 00000000000..53bda9bb4ba
--- /dev/null
+++ b/dep/CascLib/src/libtomcrypt/src/headers/tomcrypt_macros.h
@@ -0,0 +1,424 @@
+/* fix for MSVC ...evil! */
+#ifdef _MSC_VER
+ #define CONST64(n) n ## ui64
+ typedef unsigned __int64 ulong64;
+#else
+ #define CONST64(n) n ## ULL
+ typedef unsigned long long ulong64;
+#endif
+
+/* this is the "32-bit at least" data type
+ * Re-define it to suit your platform but it must be at least 32-bits
+ */
+#if defined(__x86_64__) || (defined(__sparc__) && defined(__arch64__))
+ typedef unsigned ulong32;
+#else
+ typedef unsigned long ulong32;
+#endif
+
+/* ---- HELPER MACROS ---- */
+#ifdef ENDIAN_NEUTRAL
+
+#define STORE32L(x, y) \
+ { (y)[3] = (unsigned char)(((x)>>24)&255); (y)[2] = (unsigned char)(((x)>>16)&255); \
+ (y)[1] = (unsigned char)(((x)>>8)&255); (y)[0] = (unsigned char)((x)&255); }
+
+#define LOAD32L(x, y) \
+ { x = ((unsigned long)((y)[3] & 255)<<24) | \
+ ((unsigned long)((y)[2] & 255)<<16) | \
+ ((unsigned long)((y)[1] & 255)<<8) | \
+ ((unsigned long)((y)[0] & 255)); }
+
+#define STORE64L(x, y) \
+ { (y)[7] = (unsigned char)(((x)>>56)&255); (y)[6] = (unsigned char)(((x)>>48)&255); \
+ (y)[5] = (unsigned char)(((x)>>40)&255); (y)[4] = (unsigned char)(((x)>>32)&255); \
+ (y)[3] = (unsigned char)(((x)>>24)&255); (y)[2] = (unsigned char)(((x)>>16)&255); \
+ (y)[1] = (unsigned char)(((x)>>8)&255); (y)[0] = (unsigned char)((x)&255); }
+
+#define LOAD64L(x, y) \
+ { x = (((ulong64)((y)[7] & 255))<<56)|(((ulong64)((y)[6] & 255))<<48)| \
+ (((ulong64)((y)[5] & 255))<<40)|(((ulong64)((y)[4] & 255))<<32)| \
+ (((ulong64)((y)[3] & 255))<<24)|(((ulong64)((y)[2] & 255))<<16)| \
+ (((ulong64)((y)[1] & 255))<<8)|(((ulong64)((y)[0] & 255))); }
+
+#define STORE32H(x, y) \
+ { (y)[0] = (unsigned char)(((x)>>24)&255); (y)[1] = (unsigned char)(((x)>>16)&255); \
+ (y)[2] = (unsigned char)(((x)>>8)&255); (y)[3] = (unsigned char)((x)&255); }
+
+#define LOAD32H(x, y) \
+ { x = ((unsigned long)((y)[0] & 255)<<24) | \
+ ((unsigned long)((y)[1] & 255)<<16) | \
+ ((unsigned long)((y)[2] & 255)<<8) | \
+ ((unsigned long)((y)[3] & 255)); }
+
+#define STORE64H(x, y) \
+ { (y)[0] = (unsigned char)(((x)>>56)&255); (y)[1] = (unsigned char)(((x)>>48)&255); \
+ (y)[2] = (unsigned char)(((x)>>40)&255); (y)[3] = (unsigned char)(((x)>>32)&255); \
+ (y)[4] = (unsigned char)(((x)>>24)&255); (y)[5] = (unsigned char)(((x)>>16)&255); \
+ (y)[6] = (unsigned char)(((x)>>8)&255); (y)[7] = (unsigned char)((x)&255); }
+
+#define LOAD64H(x, y) \
+ { x = (((ulong64)((y)[0] & 255))<<56)|(((ulong64)((y)[1] & 255))<<48) | \
+ (((ulong64)((y)[2] & 255))<<40)|(((ulong64)((y)[3] & 255))<<32) | \
+ (((ulong64)((y)[4] & 255))<<24)|(((ulong64)((y)[5] & 255))<<16) | \
+ (((ulong64)((y)[6] & 255))<<8)|(((ulong64)((y)[7] & 255))); }
+
+#endif /* ENDIAN_NEUTRAL */
+
+#ifdef ENDIAN_LITTLE
+
+#if !defined(LTC_NO_BSWAP) && (defined(INTEL_CC) || (defined(__GNUC__) && (defined(__DJGPP__) || defined(__CYGWIN__) || defined(__MINGW32__) || defined(__i386__) || defined(__x86_64__))))
+
+#define STORE32H(x, y) \
+asm __volatile__ ( \
+ "bswapl %0 \n\t" \
+ "movl %0,(%1)\n\t" \
+ "bswapl %0 \n\t" \
+ ::"r"(x), "r"(y));
+
+#define LOAD32H(x, y) \
+asm __volatile__ ( \
+ "movl (%1),%0\n\t" \
+ "bswapl %0\n\t" \
+ :"=r"(x): "r"(y));
+
+#else
+
+#define STORE32H(x, y) \
+ { (y)[0] = (unsigned char)(((x)>>24)&255); (y)[1] = (unsigned char)(((x)>>16)&255); \
+ (y)[2] = (unsigned char)(((x)>>8)&255); (y)[3] = (unsigned char)((x)&255); }
+
+#define LOAD32H(x, y) \
+ { x = ((unsigned long)((y)[0] & 255)<<24) | \
+ ((unsigned long)((y)[1] & 255)<<16) | \
+ ((unsigned long)((y)[2] & 255)<<8) | \
+ ((unsigned long)((y)[3] & 255)); }
+
+#endif
+
+
+/* x86_64 processor */
+#if !defined(LTC_NO_BSWAP) && (defined(__GNUC__) && defined(__x86_64__))
+
+#define STORE64H(x, y) \
+asm __volatile__ ( \
+ "bswapq %0 \n\t" \
+ "movq %0,(%1)\n\t" \
+ "bswapq %0 \n\t" \
+ ::"r"(x), "r"(y));
+
+#define LOAD64H(x, y) \
+asm __volatile__ ( \
+ "movq (%1),%0\n\t" \
+ "bswapq %0\n\t" \
+ :"=r"(x): "r"(y));
+
+#else
+
+#define STORE64H(x, y) \
+ { (y)[0] = (unsigned char)(((x)>>56)&255); (y)[1] = (unsigned char)(((x)>>48)&255); \
+ (y)[2] = (unsigned char)(((x)>>40)&255); (y)[3] = (unsigned char)(((x)>>32)&255); \
+ (y)[4] = (unsigned char)(((x)>>24)&255); (y)[5] = (unsigned char)(((x)>>16)&255); \
+ (y)[6] = (unsigned char)(((x)>>8)&255); (y)[7] = (unsigned char)((x)&255); }
+
+#define LOAD64H(x, y) \
+ { x = (((ulong64)((y)[0] & 255))<<56)|(((ulong64)((y)[1] & 255))<<48) | \
+ (((ulong64)((y)[2] & 255))<<40)|(((ulong64)((y)[3] & 255))<<32) | \
+ (((ulong64)((y)[4] & 255))<<24)|(((ulong64)((y)[5] & 255))<<16) | \
+ (((ulong64)((y)[6] & 255))<<8)|(((ulong64)((y)[7] & 255))); }
+
+#endif
+
+#ifdef ENDIAN_32BITWORD
+
+#define STORE32L(x, y) \
+ { ulong32 __t = (x); XMEMCPY(y, &__t, 4); }
+
+#define LOAD32L(x, y) \
+ XMEMCPY(&(x), y, 4);
+
+#define STORE64L(x, y) \
+ { (y)[7] = (unsigned char)(((x)>>56)&255); (y)[6] = (unsigned char)(((x)>>48)&255); \
+ (y)[5] = (unsigned char)(((x)>>40)&255); (y)[4] = (unsigned char)(((x)>>32)&255); \
+ (y)[3] = (unsigned char)(((x)>>24)&255); (y)[2] = (unsigned char)(((x)>>16)&255); \
+ (y)[1] = (unsigned char)(((x)>>8)&255); (y)[0] = (unsigned char)((x)&255); }
+
+#define LOAD64L(x, y) \
+ { x = (((ulong64)((y)[7] & 255))<<56)|(((ulong64)((y)[6] & 255))<<48)| \
+ (((ulong64)((y)[5] & 255))<<40)|(((ulong64)((y)[4] & 255))<<32)| \
+ (((ulong64)((y)[3] & 255))<<24)|(((ulong64)((y)[2] & 255))<<16)| \
+ (((ulong64)((y)[1] & 255))<<8)|(((ulong64)((y)[0] & 255))); }
+
+#else /* 64-bit words then */
+
+#define STORE32L(x, y) \
+ { ulong32 __t = (x); XMEMCPY(y, &__t, 4); }
+
+#define LOAD32L(x, y) \
+ { XMEMCPY(&(x), y, 4); x &= 0xFFFFFFFF; }
+
+#define STORE64L(x, y) \
+ { ulong64 __t = (x); XMEMCPY(y, &__t, 8); }
+
+#define LOAD64L(x, y) \
+ { XMEMCPY(&(x), y, 8); }
+
+#endif /* ENDIAN_64BITWORD */
+
+#endif /* ENDIAN_LITTLE */
+
+#ifdef ENDIAN_BIG
+#define STORE32L(x, y) \
+ { (y)[3] = (unsigned char)(((x)>>24)&255); (y)[2] = (unsigned char)(((x)>>16)&255); \
+ (y)[1] = (unsigned char)(((x)>>8)&255); (y)[0] = (unsigned char)((x)&255); }
+
+#define LOAD32L(x, y) \
+ { x = ((unsigned long)((y)[3] & 255)<<24) | \
+ ((unsigned long)((y)[2] & 255)<<16) | \
+ ((unsigned long)((y)[1] & 255)<<8) | \
+ ((unsigned long)((y)[0] & 255)); }
+
+#define STORE64L(x, y) \
+ { (y)[7] = (unsigned char)(((x)>>56)&255); (y)[6] = (unsigned char)(((x)>>48)&255); \
+ (y)[5] = (unsigned char)(((x)>>40)&255); (y)[4] = (unsigned char)(((x)>>32)&255); \
+ (y)[3] = (unsigned char)(((x)>>24)&255); (y)[2] = (unsigned char)(((x)>>16)&255); \
+ (y)[1] = (unsigned char)(((x)>>8)&255); (y)[0] = (unsigned char)((x)&255); }
+
+#define LOAD64L(x, y) \
+ { x = (((ulong64)((y)[7] & 255))<<56)|(((ulong64)((y)[6] & 255))<<48) | \
+ (((ulong64)((y)[5] & 255))<<40)|(((ulong64)((y)[4] & 255))<<32) | \
+ (((ulong64)((y)[3] & 255))<<24)|(((ulong64)((y)[2] & 255))<<16) | \
+ (((ulong64)((y)[1] & 255))<<8)|(((ulong64)((y)[0] & 255))); }
+
+#ifdef ENDIAN_32BITWORD
+
+#define STORE32H(x, y) \
+ { ulong32 __t = (x); XMEMCPY(y, &__t, 4); }
+
+#define LOAD32H(x, y) \
+ XMEMCPY(&(x), y, 4);
+
+#define STORE64H(x, y) \
+ { (y)[0] = (unsigned char)(((x)>>56)&255); (y)[1] = (unsigned char)(((x)>>48)&255); \
+ (y)[2] = (unsigned char)(((x)>>40)&255); (y)[3] = (unsigned char)(((x)>>32)&255); \
+ (y)[4] = (unsigned char)(((x)>>24)&255); (y)[5] = (unsigned char)(((x)>>16)&255); \
+ (y)[6] = (unsigned char)(((x)>>8)&255); (y)[7] = (unsigned char)((x)&255); }
+
+#define LOAD64H(x, y) \
+ { x = (((ulong64)((y)[0] & 255))<<56)|(((ulong64)((y)[1] & 255))<<48)| \
+ (((ulong64)((y)[2] & 255))<<40)|(((ulong64)((y)[3] & 255))<<32)| \
+ (((ulong64)((y)[4] & 255))<<24)|(((ulong64)((y)[5] & 255))<<16)| \
+ (((ulong64)((y)[6] & 255))<<8)| (((ulong64)((y)[7] & 255))); }
+
+#else /* 64-bit words then */
+
+#define STORE32H(x, y) \
+ { ulong32 __t = (x); XMEMCPY(y, &__t, 4); }
+
+#define LOAD32H(x, y) \
+ { XMEMCPY(&(x), y, 4); x &= 0xFFFFFFFF; }
+
+#define STORE64H(x, y) \
+ { ulong64 __t = (x); XMEMCPY(y, &__t, 8); }
+
+#define LOAD64H(x, y) \
+ { XMEMCPY(&(x), y, 8); }
+
+#endif /* ENDIAN_64BITWORD */
+#endif /* ENDIAN_BIG */
+
+#define BSWAP(x) ( ((x>>24)&0x000000FFUL) | ((x<<24)&0xFF000000UL) | \
+ ((x>>8)&0x0000FF00UL) | ((x<<8)&0x00FF0000UL) )
+
+
+/* 32-bit Rotates */
+#if defined(_MSC_VER)
+
+/* instrinsic rotate */
+#include <stdlib.h>
+#pragma intrinsic(_lrotr,_lrotl)
+#define ROR(x,n) _lrotr(x,n)
+#define ROL(x,n) _lrotl(x,n)
+#define RORc(x,n) _lrotr(x,n)
+#define ROLc(x,n) _lrotl(x,n)
+
+#elif !defined(__STRICT_ANSI__) && defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) && !defined(INTEL_CC) && !defined(LTC_NO_ASM)
+
+static inline unsigned ROL(unsigned word, int i)
+{
+ asm ("roll %%cl,%0"
+ :"=r" (word)
+ :"0" (word),"c" (i));
+ return word;
+}
+
+static inline unsigned ROR(unsigned word, int i)
+{
+ asm ("rorl %%cl,%0"
+ :"=r" (word)
+ :"0" (word),"c" (i));
+ return word;
+}
+
+#ifndef LTC_NO_ROLC
+
+static inline unsigned ROLc(unsigned word, const int i)
+{
+ asm ("roll %2,%0"
+ :"=r" (word)
+ :"0" (word),"I" (i));
+ return word;
+}
+
+static inline unsigned RORc(unsigned word, const int i)
+{
+ asm ("rorl %2,%0"
+ :"=r" (word)
+ :"0" (word),"I" (i));
+ return word;
+}
+
+#else
+
+#define ROLc ROL
+#define RORc ROR
+
+#endif
+
+#elif !defined(__STRICT_ANSI__) && defined(LTC_PPC32)
+
+static inline unsigned ROL(unsigned word, int i)
+{
+ asm ("rotlw %0,%0,%2"
+ :"=r" (word)
+ :"0" (word),"r" (i));
+ return word;
+}
+
+static inline unsigned ROR(unsigned word, int i)
+{
+ asm ("rotlw %0,%0,%2"
+ :"=r" (word)
+ :"0" (word),"r" (32-i));
+ return word;
+}
+
+#ifndef LTC_NO_ROLC
+
+static inline unsigned ROLc(unsigned word, const int i)
+{
+ asm ("rotlwi %0,%0,%2"
+ :"=r" (word)
+ :"0" (word),"I" (i));
+ return word;
+}
+
+static inline unsigned RORc(unsigned word, const int i)
+{
+ asm ("rotrwi %0,%0,%2"
+ :"=r" (word)
+ :"0" (word),"I" (i));
+ return word;
+}
+
+#else
+
+#define ROLc ROL
+#define RORc ROR
+
+#endif
+
+
+#else
+
+/* rotates the hard way */
+#define ROL(x, y) ( (((unsigned long)(x)<<(unsigned long)((y)&31)) | (((unsigned long)(x)&0xFFFFFFFFUL)>>(unsigned long)(32-((y)&31)))) & 0xFFFFFFFFUL)
+#define ROR(x, y) ( ((((unsigned long)(x)&0xFFFFFFFFUL)>>(unsigned long)((y)&31)) | ((unsigned long)(x)<<(unsigned long)(32-((y)&31)))) & 0xFFFFFFFFUL)
+#define ROLc(x, y) ( (((unsigned long)(x)<<(unsigned long)((y)&31)) | (((unsigned long)(x)&0xFFFFFFFFUL)>>(unsigned long)(32-((y)&31)))) & 0xFFFFFFFFUL)
+#define RORc(x, y) ( ((((unsigned long)(x)&0xFFFFFFFFUL)>>(unsigned long)((y)&31)) | ((unsigned long)(x)<<(unsigned long)(32-((y)&31)))) & 0xFFFFFFFFUL)
+
+#endif
+
+
+/* 64-bit Rotates */
+#if !defined(__STRICT_ANSI__) && defined(__GNUC__) && defined(__x86_64__) && !defined(LTC_NO_ASM)
+
+static inline unsigned long ROL64(unsigned long word, int i)
+{
+ asm("rolq %%cl,%0"
+ :"=r" (word)
+ :"0" (word),"c" (i));
+ return word;
+}
+
+static inline unsigned long ROR64(unsigned long word, int i)
+{
+ asm("rorq %%cl,%0"
+ :"=r" (word)
+ :"0" (word),"c" (i));
+ return word;
+}
+
+#ifndef LTC_NO_ROLC
+
+static inline unsigned long ROL64c(unsigned long word, const int i)
+{
+ asm("rolq %2,%0"
+ :"=r" (word)
+ :"0" (word),"J" (i));
+ return word;
+}
+
+static inline unsigned long ROR64c(unsigned long word, const int i)
+{
+ asm("rorq %2,%0"
+ :"=r" (word)
+ :"0" (word),"J" (i));
+ return word;
+}
+
+#else /* LTC_NO_ROLC */
+
+#define ROL64c ROL64
+#define ROR64c ROR64
+
+#endif
+
+#else /* Not x86_64 */
+
+#define ROL64(x, y) \
+ ( (((x)<<((ulong64)(y)&63)) | \
+ (((x)&CONST64(0xFFFFFFFFFFFFFFFF))>>((ulong64)64-((y)&63)))) & CONST64(0xFFFFFFFFFFFFFFFF))
+
+#define ROR64(x, y) \
+ ( ((((x)&CONST64(0xFFFFFFFFFFFFFFFF))>>((ulong64)(y)&CONST64(63))) | \
+ ((x)<<((ulong64)(64-((y)&CONST64(63)))))) & CONST64(0xFFFFFFFFFFFFFFFF))
+
+#define ROL64c(x, y) \
+ ( (((x)<<((ulong64)(y)&63)) | \
+ (((x)&CONST64(0xFFFFFFFFFFFFFFFF))>>((ulong64)64-((y)&63)))) & CONST64(0xFFFFFFFFFFFFFFFF))
+
+#define ROR64c(x, y) \
+ ( ((((x)&CONST64(0xFFFFFFFFFFFFFFFF))>>((ulong64)(y)&CONST64(63))) | \
+ ((x)<<((ulong64)(64-((y)&CONST64(63)))))) & CONST64(0xFFFFFFFFFFFFFFFF))
+
+#endif
+
+#ifndef MAX
+ #define MAX(x, y) ( ((x)>(y))?(x):(y) )
+#endif
+
+#ifndef MIN
+ #define MIN(x, y) ( ((x)<(y))?(x):(y) )
+#endif
+
+/* extract a byte portably */
+#ifdef _MSC_VER
+ #define byte(x, n) ((unsigned char)((x) >> (8 * (n))))
+#else
+ #define byte(x, n) (((x) >> (8 * (n))) & 255)
+#endif
+
+/* $Source: /cvs/libtom/libtomcrypt/src/headers/tomcrypt_macros.h,v $ */
+/* $Revision: 1.15 $ */
+/* $Date: 2006/11/29 23:43:57 $ */
diff --git a/dep/CascLib/src/libtomcrypt/src/headers/tomcrypt_math.h b/dep/CascLib/src/libtomcrypt/src/headers/tomcrypt_math.h
new file mode 100644
index 00000000000..a05d7fff942
--- /dev/null
+++ b/dep/CascLib/src/libtomcrypt/src/headers/tomcrypt_math.h
@@ -0,0 +1,500 @@
+/** math functions **/
+
+#define LTC_MP_LT -1
+#define LTC_MP_EQ 0
+#define LTC_MP_GT 1
+
+#define LTC_MP_NO 0
+#define LTC_MP_YES 1
+
+#ifndef LTC_MECC
+ typedef void ecc_point;
+#endif
+
+#ifndef LTC_MRSA
+ typedef void rsa_key;
+#endif
+
+/** math descriptor */
+typedef struct {
+ /** Name of the math provider */
+ char *name;
+
+ /** Bits per digit, amount of bits must fit in an unsigned long */
+ int bits_per_digit;
+
+/* ---- init/deinit functions ---- */
+
+ /** initialize a bignum
+ @param a The number to initialize
+ @return CRYPT_OK on success
+ */
+ int (*init)(void **a);
+
+ /** init copy
+ @param dst The number to initialize and write to
+ @param src The number to copy from
+ @return CRYPT_OK on success
+ */
+ int (*init_copy)(void **dst, void *src);
+
+ /** deinit
+ @param a The number to free
+ @return CRYPT_OK on success
+ */
+ void (*deinit)(void *a);
+
+/* ---- data movement ---- */
+
+ /** negate
+ @param src The number to negate
+ @param dst The destination
+ @return CRYPT_OK on success
+ */
+ int (*neg)(void *src, void *dst);
+
+ /** copy
+ @param src The number to copy from
+ @param dst The number to write to
+ @return CRYPT_OK on success
+ */
+ int (*copy)(void *src, void *dst);
+
+/* ---- trivial low level functions ---- */
+
+ /** set small constant
+ @param a Number to write to
+ @param n Source upto bits_per_digit (actually meant for very small constants)
+ @return CRYPT_OK on succcess
+ */
+ int (*set_int)(void *a, unsigned long n);
+
+ /** get small constant
+ @param a Number to read, only fetches upto bits_per_digit from the number
+ @return The lower bits_per_digit of the integer (unsigned)
+ */
+ unsigned long (*get_int)(void *a);
+
+ /** get digit n
+ @param a The number to read from
+ @param n The number of the digit to fetch
+ @return The bits_per_digit sized n'th digit of a
+ */
+ unsigned long (*get_digit)(void *a, int n);
+
+ /** Get the number of digits that represent the number
+ @param a The number to count
+ @return The number of digits used to represent the number
+ */
+ int (*get_digit_count)(void *a);
+
+ /** compare two integers
+ @param a The left side integer
+ @param b The right side integer
+ @return LTC_MP_LT if a < b, LTC_MP_GT if a > b and LTC_MP_EQ otherwise. (signed comparison)
+ */
+ int (*compare)(void *a, void *b);
+
+ /** compare against int
+ @param a The left side integer
+ @param b The right side integer (upto bits_per_digit)
+ @return LTC_MP_LT if a < b, LTC_MP_GT if a > b and LTC_MP_EQ otherwise. (signed comparison)
+ */
+ int (*compare_d)(void *a, unsigned long n);
+
+ /** Count the number of bits used to represent the integer
+ @param a The integer to count
+ @return The number of bits required to represent the integer
+ */
+ int (*count_bits)(void * a);
+
+ /** Count the number of LSB bits which are zero
+ @param a The integer to count
+ @return The number of contiguous zero LSB bits
+ */
+ int (*count_lsb_bits)(void *a);
+
+ /** Compute a power of two
+ @param a The integer to store the power in
+ @param n The power of two you want to store (a = 2^n)
+ @return CRYPT_OK on success
+ */
+ int (*twoexpt)(void *a , int n);
+
+/* ---- radix conversions ---- */
+
+ /** read ascii string
+ @param a The integer to store into
+ @param str The string to read
+ @param radix The radix the integer has been represented in (2-64)
+ @return CRYPT_OK on success
+ */
+ int (*read_radix)(void *a, const char *str, int radix);
+
+ /** write number to string
+ @param a The integer to store
+ @param str The destination for the string
+ @param radix The radix the integer is to be represented in (2-64)
+ @return CRYPT_OK on success
+ */
+ int (*write_radix)(void *a, char *str, int radix);
+
+ /** get size as unsigned char string
+ @param a The integer to get the size (when stored in array of octets)
+ @return The length of the integer
+ */
+ unsigned long (*unsigned_size)(void *a);
+
+ /** store an integer as an array of octets
+ @param src The integer to store
+ @param dst The buffer to store the integer in
+ @return CRYPT_OK on success
+ */
+ int (*unsigned_write)(void *src, unsigned char *dst);
+
+ /** read an array of octets and store as integer
+ @param dst The integer to load
+ @param src The array of octets
+ @param len The number of octets
+ @return CRYPT_OK on success
+ */
+ int (*unsigned_read)(void *dst, unsigned char *src, unsigned long len);
+
+/* ---- basic math ---- */
+
+ /** add two integers
+ @param a The first source integer
+ @param b The second source integer
+ @param c The destination of "a + b"
+ @return CRYPT_OK on success
+ */
+ int (*add)(void *a, void *b, void *c);
+
+
+ /** add two integers
+ @param a The first source integer
+ @param b The second source integer (single digit of upto bits_per_digit in length)
+ @param c The destination of "a + b"
+ @return CRYPT_OK on success
+ */
+ int (*addi)(void *a, unsigned long b, void *c);
+
+ /** subtract two integers
+ @param a The first source integer
+ @param b The second source integer
+ @param c The destination of "a - b"
+ @return CRYPT_OK on success
+ */
+ int (*sub)(void *a, void *b, void *c);
+
+ /** subtract two integers
+ @param a The first source integer
+ @param b The second source integer (single digit of upto bits_per_digit in length)
+ @param c The destination of "a - b"
+ @return CRYPT_OK on success
+ */
+ int (*subi)(void *a, unsigned long b, void *c);
+
+ /** multiply two integers
+ @param a The first source integer
+ @param b The second source integer (single digit of upto bits_per_digit in length)
+ @param c The destination of "a * b"
+ @return CRYPT_OK on success
+ */
+ int (*mul)(void *a, void *b, void *c);
+
+ /** multiply two integers
+ @param a The first source integer
+ @param b The second source integer (single digit of upto bits_per_digit in length)
+ @param c The destination of "a * b"
+ @return CRYPT_OK on success
+ */
+ int (*muli)(void *a, unsigned long b, void *c);
+
+ /** Square an integer
+ @param a The integer to square
+ @param b The destination
+ @return CRYPT_OK on success
+ */
+ int (*sqr)(void *a, void *b);
+
+ /** Divide an integer
+ @param a The dividend
+ @param b The divisor
+ @param c The quotient (can be NULL to signify don't care)
+ @param d The remainder (can be NULL to signify don't care)
+ @return CRYPT_OK on success
+ */
+ int (*mpdiv)(void *a, void *b, void *c, void *d);
+
+ /** divide by two
+ @param a The integer to divide (shift right)
+ @param b The destination
+ @return CRYPT_OK on success
+ */
+ int (*div_2)(void *a, void *b);
+
+ /** Get remainder (small value)
+ @param a The integer to reduce
+ @param b The modulus (upto bits_per_digit in length)
+ @param c The destination for the residue
+ @return CRYPT_OK on success
+ */
+ int (*modi)(void *a, unsigned long b, unsigned long *c);
+
+ /** gcd
+ @param a The first integer
+ @param b The second integer
+ @param c The destination for (a, b)
+ @return CRYPT_OK on success
+ */
+ int (*gcd)(void *a, void *b, void *c);
+
+ /** lcm
+ @param a The first integer
+ @param b The second integer
+ @param c The destination for [a, b]
+ @return CRYPT_OK on success
+ */
+ int (*lcm)(void *a, void *b, void *c);
+
+ /** Modular multiplication
+ @param a The first source
+ @param b The second source
+ @param c The modulus
+ @param d The destination (a*b mod c)
+ @return CRYPT_OK on success
+ */
+ int (*mulmod)(void *a, void *b, void *c, void *d);
+
+ /** Modular squaring
+ @param a The first source
+ @param b The modulus
+ @param c The destination (a*a mod b)
+ @return CRYPT_OK on success
+ */
+ int (*sqrmod)(void *a, void *b, void *c);
+
+ /** Modular inversion
+ @param a The value to invert
+ @param b The modulus
+ @param c The destination (1/a mod b)
+ @return CRYPT_OK on success
+ */
+ int (*invmod)(void *, void *, void *);
+
+/* ---- reduction ---- */
+
+ /** setup montgomery
+ @param a The modulus
+ @param b The destination for the reduction digit
+ @return CRYPT_OK on success
+ */
+ int (*montgomery_setup)(void *a, void **b);
+
+ /** get normalization value
+ @param a The destination for the normalization value
+ @param b The modulus
+ @return CRYPT_OK on success
+ */
+ int (*montgomery_normalization)(void *a, void *b);
+
+ /** reduce a number
+ @param a The number [and dest] to reduce
+ @param b The modulus
+ @param c The value "b" from montgomery_setup()
+ @return CRYPT_OK on success
+ */
+ int (*montgomery_reduce)(void *a, void *b, void *c);
+
+ /** clean up (frees memory)
+ @param a The value "b" from montgomery_setup()
+ @return CRYPT_OK on success
+ */
+ void (*montgomery_deinit)(void *a);
+
+/* ---- exponentiation ---- */
+
+ /** Modular exponentiation
+ @param a The base integer
+ @param b The power (can be negative) integer
+ @param c The modulus integer
+ @param d The destination
+ @return CRYPT_OK on success
+ */
+ int (*exptmod)(void *a, void *b, void *c, void *d);
+
+ /** Primality testing
+ @param a The integer to test
+ @param b The destination of the result (FP_YES if prime)
+ @return CRYPT_OK on success
+ */
+ int (*isprime)(void *a, int *b);
+
+/* ---- (optional) ecc point math ---- */
+
+ /** ECC GF(p) point multiplication (from the NIST curves)
+ @param k The integer to multiply the point by
+ @param G The point to multiply
+ @param R The destination for kG
+ @param modulus The modulus for the field
+ @param map Boolean indicated whether to map back to affine or not (can be ignored if you work in affine only)
+ @return CRYPT_OK on success
+ */
+ int (*ecc_ptmul)(void *k, ecc_point *G, ecc_point *R, void *modulus, int map);
+
+ /** ECC GF(p) point addition
+ @param P The first point
+ @param Q The second point
+ @param R The destination of P + Q
+ @param modulus The modulus
+ @param mp The "b" value from montgomery_setup()
+ @return CRYPT_OK on success
+ */
+ int (*ecc_ptadd)(ecc_point *P, ecc_point *Q, ecc_point *R, void *modulus, void *mp);
+
+ /** ECC GF(p) point double
+ @param P The first point
+ @param R The destination of 2P
+ @param modulus The modulus
+ @param mp The "b" value from montgomery_setup()
+ @return CRYPT_OK on success
+ */
+ int (*ecc_ptdbl)(ecc_point *P, ecc_point *R, void *modulus, void *mp);
+
+ /** ECC mapping from projective to affine, currently uses (x,y,z) => (x/z^2, y/z^3, 1)
+ @param P The point to map
+ @param modulus The modulus
+ @param mp The "b" value from montgomery_setup()
+ @return CRYPT_OK on success
+ @remark The mapping can be different but keep in mind a ecc_point only has three
+ integers (x,y,z) so if you use a different mapping you have to make it fit.
+ */
+ int (*ecc_map)(ecc_point *P, void *modulus, void *mp);
+
+ /** Computes kA*A + kB*B = C using Shamir's Trick
+ @param A First point to multiply
+ @param kA What to multiple A by
+ @param B Second point to multiply
+ @param kB What to multiple B by
+ @param C [out] Destination point (can overlap with A or B
+ @param modulus Modulus for curve
+ @return CRYPT_OK on success
+ */
+ int (*ecc_mul2add)(ecc_point *A, void *kA,
+ ecc_point *B, void *kB,
+ ecc_point *C,
+ void *modulus);
+
+/* ---- (optional) rsa optimized math (for internal CRT) ---- */
+
+ /** RSA Key Generation
+ @param prng An active PRNG state
+ @param wprng The index of the PRNG desired
+ @param size The size of the modulus (key size) desired (octets)
+ @param e The "e" value (public key). e==65537 is a good choice
+ @param key [out] Destination of a newly created private key pair
+ @return CRYPT_OK if successful, upon error all allocated ram is freed
+ */
+ int (*rsa_keygen)(prng_state *prng, int wprng, int size, long e, rsa_key *key);
+
+
+ /** RSA exponentiation
+ @param in The octet array representing the base
+ @param inlen The length of the input
+ @param out The destination (to be stored in an octet array format)
+ @param outlen The length of the output buffer and the resulting size (zero padded to the size of the modulus)
+ @param which PK_PUBLIC for public RSA and PK_PRIVATE for private RSA
+ @param key The RSA key to use
+ @return CRYPT_OK on success
+ */
+ int (*rsa_me)(const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen, int which,
+ rsa_key *key);
+} ltc_math_descriptor;
+
+extern ltc_math_descriptor ltc_mp;
+
+int ltc_init_multi(void **a, ...);
+void ltc_deinit_multi(void *a, ...);
+
+#ifdef LTM_DESC
+extern const ltc_math_descriptor ltm_desc;
+#endif
+
+#ifdef TFM_DESC
+extern const ltc_math_descriptor tfm_desc;
+#endif
+
+#ifdef GMP_DESC
+extern const ltc_math_descriptor gmp_desc;
+#endif
+
+#if !defined(DESC_DEF_ONLY) && defined(LTC_SOURCE)
+
+#define MP_DIGIT_BIT ltc_mp.bits_per_digit
+
+/* some handy macros */
+#define mp_init(a) ltc_mp.init(a)
+#define mp_init_multi ltc_init_multi
+#define mp_clear(a) ltc_mp.deinit(a)
+#define mp_clear_multi ltc_deinit_multi
+#define mp_init_copy(a, b) ltc_mp.init_copy(a, b)
+
+#define mp_neg(a, b) ltc_mp.neg(a, b)
+#define mp_copy(a, b) ltc_mp.copy(a, b)
+
+#define mp_set(a, b) ltc_mp.set_int(a, b)
+#define mp_set_int(a, b) ltc_mp.set_int(a, b)
+#define mp_get_int(a) ltc_mp.get_int(a)
+#define mp_get_digit(a, n) ltc_mp.get_digit(a, n)
+#define mp_get_digit_count(a) ltc_mp.get_digit_count(a)
+#define mp_cmp(a, b) ltc_mp.compare(a, b)
+#define mp_cmp_d(a, b) ltc_mp.compare_d(a, b)
+#define mp_count_bits(a) ltc_mp.count_bits(a)
+#define mp_cnt_lsb(a) ltc_mp.count_lsb_bits(a)
+#define mp_2expt(a, b) ltc_mp.twoexpt(a, b)
+
+#define mp_read_radix(a, b, c) ltc_mp.read_radix(a, b, c)
+#define mp_toradix(a, b, c) ltc_mp.write_radix(a, b, c)
+#define mp_unsigned_bin_size(a) ltc_mp.unsigned_size(a)
+#define mp_to_unsigned_bin(a, b) ltc_mp.unsigned_write(a, b)
+#define mp_read_unsigned_bin(a, b, c) ltc_mp.unsigned_read(a, b, c)
+
+#define mp_add(a, b, c) ltc_mp.add(a, b, c)
+#define mp_add_d(a, b, c) ltc_mp.addi(a, b, c)
+#define mp_sub(a, b, c) ltc_mp.sub(a, b, c)
+#define mp_sub_d(a, b, c) ltc_mp.subi(a, b, c)
+#define mp_mul(a, b, c) ltc_mp.mul(a, b, c)
+#define mp_mul_d(a, b, c) ltc_mp.muli(a, b, c)
+#define mp_sqr(a, b) ltc_mp.sqr(a, b)
+#define mp_div(a, b, c, d) ltc_mp.mpdiv(a, b, c, d)
+#define mp_div_2(a, b) ltc_mp.div_2(a, b)
+#define mp_mod(a, b, c) ltc_mp.mpdiv(a, b, NULL, c)
+#define mp_mod_d(a, b, c) ltc_mp.modi(a, b, c)
+#define mp_gcd(a, b, c) ltc_mp.gcd(a, b, c)
+#define mp_lcm(a, b, c) ltc_mp.lcm(a, b, c)
+
+#define mp_mulmod(a, b, c, d) ltc_mp.mulmod(a, b, c, d)
+#define mp_sqrmod(a, b, c) ltc_mp.sqrmod(a, b, c)
+#define mp_invmod(a, b, c) ltc_mp.invmod(a, b, c)
+
+#define mp_montgomery_setup(a, b) ltc_mp.montgomery_setup(a, b)
+#define mp_montgomery_normalization(a, b) ltc_mp.montgomery_normalization(a, b)
+#define mp_montgomery_reduce(a, b, c) ltc_mp.montgomery_reduce(a, b, c)
+#define mp_montgomery_free(a) ltc_mp.montgomery_deinit(a)
+
+#define mp_exptmod(a,b,c,d) ltc_mp.exptmod(a,b,c,d)
+#define mp_prime_is_prime(a, b, c) ltc_mp.isprime(a, c)
+
+#define mp_iszero(a) (mp_cmp_d(a, 0) == LTC_MP_EQ ? LTC_MP_YES : LTC_MP_NO)
+#define mp_isodd(a) (mp_get_digit_count(a) > 0 ? (mp_get_digit(a, 0) & 1 ? LTC_MP_YES : LTC_MP_NO) : LTC_MP_NO)
+#define mp_exch(a, b) do { void *ABC__tmp = a; a = b; b = ABC__tmp; } while(0);
+
+#define mp_tohex(a, b) mp_toradix(a, b, 16)
+
+#endif
+
+/* $Source: /cvs/libtom/libtomcrypt/src/headers/tomcrypt_math.h,v $ */
+/* $Revision: 1.44 $ */
+/* $Date: 2007/05/12 14:32:35 $ */
diff --git a/dep/CascLib/src/libtomcrypt/src/headers/tomcrypt_misc.h b/dep/CascLib/src/libtomcrypt/src/headers/tomcrypt_misc.h
new file mode 100644
index 00000000000..f5384cacc51
--- /dev/null
+++ b/dep/CascLib/src/libtomcrypt/src/headers/tomcrypt_misc.h
@@ -0,0 +1,23 @@
+/* ---- LTC_BASE64 Routines ---- */
+#ifdef LTC_BASE64
+int base64_encode(const unsigned char *in, unsigned long len,
+ unsigned char *out, unsigned long *outlen);
+
+int base64_decode(const unsigned char *in, unsigned long len,
+ unsigned char *out, unsigned long *outlen);
+#endif
+
+/* ---- MEM routines ---- */
+void zeromem(void *dst, size_t len);
+void burn_stack(unsigned long len);
+
+const char *error_to_string(int err);
+
+extern const char *crypt_build_settings;
+
+/* ---- HMM ---- */
+int crypt_fsa(void *mp, ...);
+
+/* $Source: /cvs/libtom/libtomcrypt/src/headers/tomcrypt_misc.h,v $ */
+/* $Revision: 1.5 $ */
+/* $Date: 2007/05/12 14:32:35 $ */
diff --git a/dep/CascLib/src/libtomcrypt/src/headers/tomcrypt_pk.h b/dep/CascLib/src/libtomcrypt/src/headers/tomcrypt_pk.h
new file mode 100644
index 00000000000..b5f277a8848
--- /dev/null
+++ b/dep/CascLib/src/libtomcrypt/src/headers/tomcrypt_pk.h
@@ -0,0 +1,558 @@
+/* ---- NUMBER THEORY ---- */
+
+enum {
+ PK_PUBLIC=0,
+ PK_PRIVATE=1
+};
+
+int rand_prime(void *N, long len, prng_state *prng, int wprng);
+
+/* ---- RSA ---- */
+#ifdef LTC_MRSA
+
+/* Min and Max RSA key sizes (in bits) */
+#define MIN_RSA_SIZE 1024
+#define MAX_RSA_SIZE 4096
+
+/** RSA LTC_PKCS style key */
+typedef struct Rsa_key {
+ /** Type of key, PK_PRIVATE or PK_PUBLIC */
+ int type;
+ /** The public exponent */
+ void *e;
+ /** The private exponent */
+ void *d;
+ /** The modulus */
+ void *N;
+ /** The p factor of N */
+ void *p;
+ /** The q factor of N */
+ void *q;
+ /** The 1/q mod p CRT param */
+ void *qP;
+ /** The d mod (p - 1) CRT param */
+ void *dP;
+ /** The d mod (q - 1) CRT param */
+ void *dQ;
+} rsa_key;
+
+int rsa_make_key(prng_state *prng, int wprng, int size, long e, rsa_key *key);
+
+int rsa_exptmod(const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen, int which,
+ rsa_key *key);
+
+void rsa_free(rsa_key *key);
+
+/* These use LTC_PKCS #1 v2.0 padding */
+#define rsa_encrypt_key(_in, _inlen, _out, _outlen, _lparam, _lparamlen, _prng, _prng_idx, _hash_idx, _key) \
+ rsa_encrypt_key_ex(_in, _inlen, _out, _outlen, _lparam, _lparamlen, _prng, _prng_idx, _hash_idx, LTC_LTC_PKCS_1_OAEP, _key)
+
+#define rsa_decrypt_key(_in, _inlen, _out, _outlen, _lparam, _lparamlen, _hash_idx, _stat, _key) \
+ rsa_decrypt_key_ex(_in, _inlen, _out, _outlen, _lparam, _lparamlen, _hash_idx, LTC_LTC_PKCS_1_OAEP, _stat, _key)
+
+#define rsa_sign_hash(_in, _inlen, _out, _outlen, _prng, _prng_idx, _hash_idx, _saltlen, _key) \
+ rsa_sign_hash_ex(_in, _inlen, _out, _outlen, LTC_LTC_PKCS_1_PSS, _prng, _prng_idx, _hash_idx, _saltlen, _key)
+
+#define rsa_verify_hash(_sig, _siglen, _hash, _hashlen, _hash_idx, _saltlen, _stat, _key) \
+ rsa_verify_hash_ex(_sig, _siglen, _hash, _hashlen, LTC_LTC_PKCS_1_PSS, _hash_idx, _saltlen, _stat, _key)
+
+/* These can be switched between LTC_PKCS #1 v2.x and LTC_PKCS #1 v1.5 paddings */
+int rsa_encrypt_key_ex(const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen,
+ const unsigned char *lparam, unsigned long lparamlen,
+ prng_state *prng, int prng_idx, int hash_idx, int padding, rsa_key *key);
+
+int rsa_decrypt_key_ex(const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen,
+ const unsigned char *lparam, unsigned long lparamlen,
+ int hash_idx, int padding,
+ int *stat, rsa_key *key);
+
+int rsa_sign_hash_ex(const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen,
+ int padding,
+ prng_state *prng, int prng_idx,
+ int hash_idx, unsigned long saltlen,
+ rsa_key *key);
+
+int rsa_verify_hash_ex(const unsigned char *sig, unsigned long siglen,
+ const unsigned char *hash, unsigned long hashlen,
+ int padding,
+ int hash_idx, unsigned long saltlen,
+ int *stat, rsa_key *key);
+
+/* LTC_PKCS #1 import/export */
+int rsa_export(unsigned char *out, unsigned long *outlen, int type, rsa_key *key);
+int rsa_import(const unsigned char *in, unsigned long inlen, rsa_key *key);
+
+/* Ladik: Added for verifying Blizzard strong signature verification */
+int rsa_verify_simple(const unsigned char *sig, unsigned long siglen,
+ const unsigned char *hash, unsigned long hashlen,
+ int *stat,
+ rsa_key *key);
+
+#endif
+
+/* ---- Katja ---- */
+#ifdef MKAT
+
+/* Min and Max KAT key sizes (in bits) */
+#define MIN_KAT_SIZE 1024
+#define MAX_KAT_SIZE 4096
+
+/** Katja LTC_PKCS style key */
+typedef struct KAT_key {
+ /** Type of key, PK_PRIVATE or PK_PUBLIC */
+ int type;
+ /** The private exponent */
+ void *d;
+ /** The modulus */
+ void *N;
+ /** The p factor of N */
+ void *p;
+ /** The q factor of N */
+ void *q;
+ /** The 1/q mod p CRT param */
+ void *qP;
+ /** The d mod (p - 1) CRT param */
+ void *dP;
+ /** The d mod (q - 1) CRT param */
+ void *dQ;
+ /** The pq param */
+ void *pq;
+} katja_key;
+
+int katja_make_key(prng_state *prng, int wprng, int size, katja_key *key);
+
+int katja_exptmod(const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen, int which,
+ katja_key *key);
+
+void katja_free(katja_key *key);
+
+/* These use LTC_PKCS #1 v2.0 padding */
+int katja_encrypt_key(const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen,
+ const unsigned char *lparam, unsigned long lparamlen,
+ prng_state *prng, int prng_idx, int hash_idx, katja_key *key);
+
+int katja_decrypt_key(const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen,
+ const unsigned char *lparam, unsigned long lparamlen,
+ int hash_idx, int *stat,
+ katja_key *key);
+
+/* LTC_PKCS #1 import/export */
+int katja_export(unsigned char *out, unsigned long *outlen, int type, katja_key *key);
+int katja_import(const unsigned char *in, unsigned long inlen, katja_key *key);
+
+#endif
+
+/* ---- ECC Routines ---- */
+#ifdef LTC_MECC
+
+/* size of our temp buffers for exported keys */
+#define ECC_BUF_SIZE 256
+
+/* max private key size */
+#define ECC_MAXSIZE 66
+
+/** Structure defines a NIST GF(p) curve */
+typedef struct {
+ /** The size of the curve in octets */
+ int size;
+
+ /** name of curve */
+ char *name;
+
+ /** The prime that defines the field the curve is in (encoded in hex) */
+ char *prime;
+
+ /** The fields B param (hex) */
+ char *B;
+
+ /** The order of the curve (hex) */
+ char *order;
+
+ /** The x co-ordinate of the base point on the curve (hex) */
+ char *Gx;
+
+ /** The y co-ordinate of the base point on the curve (hex) */
+ char *Gy;
+} ltc_ecc_set_type;
+
+/** A point on a ECC curve, stored in Jacbobian format such that (x,y,z) => (x/z^2, y/z^3, 1) when interpretted as affine */
+typedef struct {
+ /** The x co-ordinate */
+ void *x;
+
+ /** The y co-ordinate */
+ void *y;
+
+ /** The z co-ordinate */
+ void *z;
+} ecc_point;
+
+/** An ECC key */
+typedef struct {
+ /** Type of key, PK_PRIVATE or PK_PUBLIC */
+ int type;
+
+ /** Index into the ltc_ecc_sets[] for the parameters of this curve; if -1, then this key is using user supplied curve in dp */
+ int idx;
+
+ /** pointer to domain parameters; either points to NIST curves (identified by idx >= 0) or user supplied curve */
+ const ltc_ecc_set_type *dp;
+
+ /** The public key */
+ ecc_point pubkey;
+
+ /** The private key */
+ void *k;
+} ecc_key;
+
+/** the ECC params provided */
+extern const ltc_ecc_set_type ltc_ecc_sets[];
+
+int ecc_test(void);
+void ecc_sizes(int *low, int *high);
+int ecc_get_size(ecc_key *key);
+
+int ecc_make_key(prng_state *prng, int wprng, int keysize, ecc_key *key);
+int ecc_make_key_ex(prng_state *prng, int wprng, ecc_key *key, const ltc_ecc_set_type *dp);
+void ecc_free(ecc_key *key);
+
+int ecc_export(unsigned char *out, unsigned long *outlen, int type, ecc_key *key);
+int ecc_import(const unsigned char *in, unsigned long inlen, ecc_key *key);
+int ecc_import_ex(const unsigned char *in, unsigned long inlen, ecc_key *key, const ltc_ecc_set_type *dp);
+
+int ecc_ansi_x963_export(ecc_key *key, unsigned char *out, unsigned long *outlen);
+int ecc_ansi_x963_import(const unsigned char *in, unsigned long inlen, ecc_key *key);
+int ecc_ansi_x963_import_ex(const unsigned char *in, unsigned long inlen, ecc_key *key, ltc_ecc_set_type *dp);
+
+int ecc_shared_secret(ecc_key *private_key, ecc_key *public_key,
+ unsigned char *out, unsigned long *outlen);
+
+int ecc_encrypt_key(const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen,
+ prng_state *prng, int wprng, int hash,
+ ecc_key *key);
+
+int ecc_decrypt_key(const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen,
+ ecc_key *key);
+
+int ecc_sign_hash(const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen,
+ prng_state *prng, int wprng, ecc_key *key);
+
+int ecc_verify_hash(const unsigned char *sig, unsigned long siglen,
+ const unsigned char *hash, unsigned long hashlen,
+ int *stat, ecc_key *key);
+
+/* low level functions */
+ecc_point *ltc_ecc_new_point(void);
+void ltc_ecc_del_point(ecc_point *p);
+int ltc_ecc_is_valid_idx(int n);
+
+/* point ops (mp == montgomery digit) */
+#if !defined(LTC_MECC_ACCEL) || defined(LTM_LTC_DESC) || defined(GMP_LTC_DESC)
+/* R = 2P */
+int ltc_ecc_projective_dbl_point(ecc_point *P, ecc_point *R, void *modulus, void *mp);
+
+/* R = P + Q */
+int ltc_ecc_projective_add_point(ecc_point *P, ecc_point *Q, ecc_point *R, void *modulus, void *mp);
+#endif
+
+#if defined(LTC_MECC_FP)
+/* optimized point multiplication using fixed point cache (HAC algorithm 14.117) */
+int ltc_ecc_fp_mulmod(void *k, ecc_point *G, ecc_point *R, void *modulus, int map);
+
+/* functions for saving/loading/freeing/adding to fixed point cache */
+int ltc_ecc_fp_save_state(unsigned char **out, unsigned long *outlen);
+int ltc_ecc_fp_restore_state(unsigned char *in, unsigned long inlen);
+void ltc_ecc_fp_free(void);
+int ltc_ecc_fp_add_point(ecc_point *g, void *modulus, int lock);
+
+/* lock/unlock all points currently in fixed point cache */
+void ltc_ecc_fp_tablelock(int lock);
+#endif
+
+/* R = kG */
+int ltc_ecc_mulmod(void *k, ecc_point *G, ecc_point *R, void *modulus, int map);
+
+#ifdef LTC_ECC_SHAMIR
+/* kA*A + kB*B = C */
+int ltc_ecc_mul2add(ecc_point *A, void *kA,
+ ecc_point *B, void *kB,
+ ecc_point *C,
+ void *modulus);
+
+#ifdef LTC_MECC_FP
+/* Shamir's trick with optimized point multiplication using fixed point cache */
+int ltc_ecc_fp_mul2add(ecc_point *A, void *kA,
+ ecc_point *B, void *kB,
+ ecc_point *C, void *modulus);
+#endif
+
+#endif
+
+
+/* map P to affine from projective */
+int ltc_ecc_map(ecc_point *P, void *modulus, void *mp);
+
+#endif
+
+#ifdef LTC_MDSA
+
+/* Max diff between group and modulus size in bytes */
+#define LTC_MDSA_DELTA 512
+
+/* Max DSA group size in bytes (default allows 4k-bit groups) */
+#define LTC_MDSA_MAX_GROUP 512
+
+/** DSA key structure */
+typedef struct {
+ /** The key type, PK_PRIVATE or PK_PUBLIC */
+ int type;
+
+ /** The order of the sub-group used in octets */
+ int qord;
+
+ /** The generator */
+ void *g;
+
+ /** The prime used to generate the sub-group */
+ void *q;
+
+ /** The large prime that generats the field the contains the sub-group */
+ void *p;
+
+ /** The private key */
+ void *x;
+
+ /** The public key */
+ void *y;
+} dsa_key;
+
+int dsa_make_key(prng_state *prng, int wprng, int group_size, int modulus_size, dsa_key *key);
+void dsa_free(dsa_key *key);
+
+int dsa_sign_hash_raw(const unsigned char *in, unsigned long inlen,
+ void *r, void *s,
+ prng_state *prng, int wprng, dsa_key *key);
+
+int dsa_sign_hash(const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen,
+ prng_state *prng, int wprng, dsa_key *key);
+
+int dsa_verify_hash_raw( void *r, void *s,
+ const unsigned char *hash, unsigned long hashlen,
+ int *stat, dsa_key *key);
+
+int dsa_verify_hash(const unsigned char *sig, unsigned long siglen,
+ const unsigned char *hash, unsigned long hashlen,
+ int *stat, dsa_key *key);
+
+int dsa_encrypt_key(const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen,
+ prng_state *prng, int wprng, int hash,
+ dsa_key *key);
+
+int dsa_decrypt_key(const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen,
+ dsa_key *key);
+
+int dsa_import(const unsigned char *in, unsigned long inlen, dsa_key *key);
+int dsa_export(unsigned char *out, unsigned long *outlen, int type, dsa_key *key);
+int dsa_verify_key(dsa_key *key, int *stat);
+
+int dsa_shared_secret(void *private_key, void *base,
+ dsa_key *public_key,
+ unsigned char *out, unsigned long *outlen);
+#endif
+
+#ifdef LTC_DER
+/* DER handling */
+
+enum {
+ LTC_ASN1_EOL,
+ LTC_ASN1_BOOLEAN,
+ LTC_ASN1_INTEGER,
+ LTC_ASN1_SHORT_INTEGER,
+ LTC_ASN1_BIT_STRING,
+ LTC_ASN1_OCTET_STRING,
+ LTC_ASN1_NULL,
+ LTC_ASN1_OBJECT_IDENTIFIER,
+ LTC_ASN1_IA5_STRING,
+ LTC_ASN1_PRINTABLE_STRING,
+ LTC_ASN1_UTF8_STRING,
+ LTC_ASN1_UTCTIME,
+ LTC_ASN1_CHOICE,
+ LTC_ASN1_SEQUENCE,
+ LTC_ASN1_SET,
+ LTC_ASN1_SETOF
+};
+
+/** A LTC ASN.1 list type */
+typedef struct ltc_asn1_list_ {
+ /** The LTC ASN.1 enumerated type identifier */
+ int type;
+ /** The data to encode or place for decoding */
+ void *data;
+ /** The size of the input or resulting output */
+ unsigned long size;
+ /** The used flag, this is used by the CHOICE ASN.1 type to indicate which choice was made */
+ int used;
+ /** prev/next entry in the list */
+ struct ltc_asn1_list_ *prev, *next, *child, *parent;
+} ltc_asn1_list;
+
+#define LTC_SET_ASN1(list, index, Type, Data, Size) \
+ do { \
+ int LTC_MACRO_temp = (index); \
+ ltc_asn1_list *LTC_MACRO_list = (list); \
+ LTC_MACRO_list[LTC_MACRO_temp].type = (Type); \
+ LTC_MACRO_list[LTC_MACRO_temp].data = (void*)(Data); \
+ LTC_MACRO_list[LTC_MACRO_temp].size = (Size); \
+ LTC_MACRO_list[LTC_MACRO_temp].used = 0; \
+ } while (0);
+
+/* SEQUENCE */
+int der_encode_sequence_ex(ltc_asn1_list *list, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen, int type_of);
+
+#define der_encode_sequence(list, inlen, out, outlen) der_encode_sequence_ex(list, inlen, out, outlen, LTC_ASN1_SEQUENCE)
+
+int der_decode_sequence_ex(const unsigned char *in, unsigned long inlen,
+ ltc_asn1_list *list, unsigned long outlen, int ordered);
+
+#define der_decode_sequence(in, inlen, list, outlen) der_decode_sequence_ex(in, inlen, list, outlen, 1)
+
+int der_length_sequence(ltc_asn1_list *list, unsigned long inlen,
+ unsigned long *outlen);
+
+/* SET */
+#define der_decode_set(in, inlen, list, outlen) der_decode_sequence_ex(in, inlen, list, outlen, 0)
+#define der_length_set der_length_sequence
+int der_encode_set(ltc_asn1_list *list, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen);
+
+int der_encode_setof(ltc_asn1_list *list, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen);
+
+/* VA list handy helpers with triplets of <type, size, data> */
+int der_encode_sequence_multi(unsigned char *out, unsigned long *outlen, ...);
+int der_decode_sequence_multi(const unsigned char *in, unsigned long inlen, ...);
+
+/* FLEXI DECODER handle unknown list decoder */
+int der_decode_sequence_flexi(const unsigned char *in, unsigned long *inlen, ltc_asn1_list **out);
+void der_free_sequence_flexi(ltc_asn1_list *list);
+void der_sequence_free(ltc_asn1_list *in);
+
+/* BOOLEAN */
+int der_length_boolean(unsigned long *outlen);
+int der_encode_boolean(int in,
+ unsigned char *out, unsigned long *outlen);
+int der_decode_boolean(const unsigned char *in, unsigned long inlen,
+ int *out);
+/* INTEGER */
+int der_encode_integer(void *num, unsigned char *out, unsigned long *outlen);
+int der_decode_integer(const unsigned char *in, unsigned long inlen, void *num);
+int der_length_integer(void *num, unsigned long *len);
+
+/* INTEGER -- handy for 0..2^32-1 values */
+int der_decode_short_integer(const unsigned char *in, unsigned long inlen, unsigned long *num);
+int der_encode_short_integer(unsigned long num, unsigned char *out, unsigned long *outlen);
+int der_length_short_integer(unsigned long num, unsigned long *outlen);
+
+/* BIT STRING */
+int der_encode_bit_string(const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen);
+int der_decode_bit_string(const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen);
+int der_length_bit_string(unsigned long nbits, unsigned long *outlen);
+
+/* OCTET STRING */
+int der_encode_octet_string(const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen);
+int der_decode_octet_string(const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen);
+int der_length_octet_string(unsigned long noctets, unsigned long *outlen);
+
+/* OBJECT IDENTIFIER */
+int der_encode_object_identifier(unsigned long *words, unsigned long nwords,
+ unsigned char *out, unsigned long *outlen);
+int der_decode_object_identifier(const unsigned char *in, unsigned long inlen,
+ unsigned long *words, unsigned long *outlen);
+int der_length_object_identifier(unsigned long *words, unsigned long nwords, unsigned long *outlen);
+unsigned long der_object_identifier_bits(unsigned long x);
+
+/* IA5 STRING */
+int der_encode_ia5_string(const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen);
+int der_decode_ia5_string(const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen);
+int der_length_ia5_string(const unsigned char *octets, unsigned long noctets, unsigned long *outlen);
+
+int der_ia5_char_encode(int c);
+int der_ia5_value_decode(int v);
+
+/* Printable STRING */
+int der_encode_printable_string(const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen);
+int der_decode_printable_string(const unsigned char *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen);
+int der_length_printable_string(const unsigned char *octets, unsigned long noctets, unsigned long *outlen);
+
+int der_printable_char_encode(int c);
+int der_printable_value_decode(int v);
+
+/* UTF-8 */
+#if (defined(SIZE_MAX) || __STDC_VERSION__ >= 199901L || defined(WCHAR_MAX) || defined(_WCHAR_T) || defined(_WCHAR_T_DEFINED) || defined (__WCHAR_TYPE__)) && !defined(LTC_NO_WCHAR)
+#include <wchar.h>
+#else
+typedef ulong32 wchar_t;
+#endif
+
+int der_encode_utf8_string(const wchar_t *in, unsigned long inlen,
+ unsigned char *out, unsigned long *outlen);
+
+int der_decode_utf8_string(const unsigned char *in, unsigned long inlen,
+ wchar_t *out, unsigned long *outlen);
+unsigned long der_utf8_charsize(const wchar_t c);
+int der_length_utf8_string(const wchar_t *in, unsigned long noctets, unsigned long *outlen);
+
+
+/* CHOICE */
+int der_decode_choice(const unsigned char *in, unsigned long *inlen,
+ ltc_asn1_list *list, unsigned long outlen);
+
+/* UTCTime */
+typedef struct {
+ unsigned YY, /* year */
+ MM, /* month */
+ DD, /* day */
+ hh, /* hour */
+ mm, /* minute */
+ ss, /* second */
+ off_dir, /* timezone offset direction 0 == +, 1 == - */
+ off_hh, /* timezone offset hours */
+ off_mm; /* timezone offset minutes */
+} ltc_utctime;
+
+int der_encode_utctime(ltc_utctime *utctime,
+ unsigned char *out, unsigned long *outlen);
+
+int der_decode_utctime(const unsigned char *in, unsigned long *inlen,
+ ltc_utctime *out);
+
+int der_length_utctime(ltc_utctime *utctime, unsigned long *outlen);
+
+
+#endif
+
+/* $Source: /cvs/libtom/libtomcrypt/src/headers/tomcrypt_pk.h,v $ */
+/* $Revision: 1.81 $ */
+/* $Date: 2007/05/12 14:32:35 $ */
diff --git a/dep/CascLib/src/libtomcrypt/src/headers/tomcrypt_pkcs.h b/dep/CascLib/src/libtomcrypt/src/headers/tomcrypt_pkcs.h
new file mode 100644
index 00000000000..84fb82a6229
--- /dev/null
+++ b/dep/CascLib/src/libtomcrypt/src/headers/tomcrypt_pkcs.h
@@ -0,0 +1,89 @@
+/* LTC_PKCS Header Info */
+
+/* ===> LTC_PKCS #1 -- RSA Cryptography <=== */
+#ifdef LTC_PKCS_1
+
+enum ltc_pkcs_1_v1_5_blocks
+{
+ LTC_LTC_PKCS_1_EMSA = 1, /* Block type 1 (LTC_PKCS #1 v1.5 signature padding) */
+ LTC_LTC_PKCS_1_EME = 2 /* Block type 2 (LTC_PKCS #1 v1.5 encryption padding) */
+};
+
+enum ltc_pkcs_1_paddings
+{
+ LTC_LTC_PKCS_1_V1_5 = 1, /* LTC_PKCS #1 v1.5 padding (\sa ltc_pkcs_1_v1_5_blocks) */
+ LTC_LTC_PKCS_1_OAEP = 2, /* LTC_PKCS #1 v2.0 encryption padding */
+ LTC_LTC_PKCS_1_PSS = 3 /* LTC_PKCS #1 v2.1 signature padding */
+};
+
+int pkcs_1_mgf1( int hash_idx,
+ const unsigned char *seed, unsigned long seedlen,
+ unsigned char *mask, unsigned long masklen);
+
+int pkcs_1_i2osp(void *n, unsigned long modulus_len, unsigned char *out);
+int pkcs_1_os2ip(void *n, unsigned char *in, unsigned long inlen);
+
+/* *** v1.5 padding */
+int pkcs_1_v1_5_encode(const unsigned char *msg,
+ unsigned long msglen,
+ int block_type,
+ unsigned long modulus_bitlen,
+ prng_state *prng,
+ int prng_idx,
+ unsigned char *out,
+ unsigned long *outlen);
+
+int pkcs_1_v1_5_decode(const unsigned char *msg,
+ unsigned long msglen,
+ int block_type,
+ unsigned long modulus_bitlen,
+ unsigned char *out,
+ unsigned long *outlen,
+ int *is_valid);
+
+/* *** v2.1 padding */
+int pkcs_1_oaep_encode(const unsigned char *msg, unsigned long msglen,
+ const unsigned char *lparam, unsigned long lparamlen,
+ unsigned long modulus_bitlen, prng_state *prng,
+ int prng_idx, int hash_idx,
+ unsigned char *out, unsigned long *outlen);
+
+int pkcs_1_oaep_decode(const unsigned char *msg, unsigned long msglen,
+ const unsigned char *lparam, unsigned long lparamlen,
+ unsigned long modulus_bitlen, int hash_idx,
+ unsigned char *out, unsigned long *outlen,
+ int *res);
+
+int pkcs_1_pss_encode(const unsigned char *msghash, unsigned long msghashlen,
+ unsigned long saltlen, prng_state *prng,
+ int prng_idx, int hash_idx,
+ unsigned long modulus_bitlen,
+ unsigned char *out, unsigned long *outlen);
+
+int pkcs_1_pss_decode(const unsigned char *msghash, unsigned long msghashlen,
+ const unsigned char *sig, unsigned long siglen,
+ unsigned long saltlen, int hash_idx,
+ unsigned long modulus_bitlen, int *res);
+
+#endif /* LTC_PKCS_1 */
+
+/* ===> LTC_PKCS #5 -- Password Based Cryptography <=== */
+#ifdef LTC_PKCS_5
+
+/* Algorithm #1 (old) */
+int pkcs_5_alg1(const unsigned char *password, unsigned long password_len,
+ const unsigned char *salt,
+ int iteration_count, int hash_idx,
+ unsigned char *out, unsigned long *outlen);
+
+/* Algorithm #2 (new) */
+int pkcs_5_alg2(const unsigned char *password, unsigned long password_len,
+ const unsigned char *salt, unsigned long salt_len,
+ int iteration_count, int hash_idx,
+ unsigned char *out, unsigned long *outlen);
+
+#endif /* LTC_PKCS_5 */
+
+/* $Source: /cvs/libtom/libtomcrypt/src/headers/tomcrypt_pkcs.h,v $ */
+/* $Revision: 1.8 $ */
+/* $Date: 2007/05/12 14:32:35 $ */
diff --git a/dep/CascLib/src/libtomcrypt/src/headers/tomcrypt_prng.h b/dep/CascLib/src/libtomcrypt/src/headers/tomcrypt_prng.h
new file mode 100644
index 00000000000..f3e3e550e88
--- /dev/null
+++ b/dep/CascLib/src/libtomcrypt/src/headers/tomcrypt_prng.h
@@ -0,0 +1,199 @@
+/* ---- PRNG Stuff ---- */
+#ifdef LTC_YARROW
+struct yarrow_prng {
+ int cipher, hash;
+ unsigned char pool[MAXBLOCKSIZE];
+ symmetric_CTR ctr;
+ LTC_MUTEX_TYPE(prng_lock)
+};
+#endif
+
+#ifdef LTC_RC4
+struct rc4_prng {
+ int x, y;
+ unsigned char buf[256];
+};
+#endif
+
+#ifdef LTC_FORTUNA
+struct fortuna_prng {
+ hash_state pool[LTC_FORTUNA_POOLS]; /* the pools */
+
+ symmetric_key skey;
+
+ unsigned char K[32], /* the current key */
+ IV[16]; /* IV for CTR mode */
+
+ unsigned long pool_idx, /* current pool we will add to */
+ pool0_len, /* length of 0'th pool */
+ wd;
+
+ ulong64 reset_cnt; /* number of times we have reset */
+ LTC_MUTEX_TYPE(prng_lock)
+};
+#endif
+
+#ifdef LTC_SOBER128
+struct sober128_prng {
+ ulong32 R[17], /* Working storage for the shift register */
+ initR[17], /* saved register contents */
+ konst, /* key dependent constant */
+ sbuf; /* partial word encryption buffer */
+
+ int nbuf, /* number of part-word stream bits buffered */
+ flag, /* first add_entropy call or not? */
+ set; /* did we call add_entropy to set key? */
+
+};
+#endif
+
+typedef union Prng_state {
+ char dummy[1];
+#ifdef LTC_YARROW
+ struct yarrow_prng yarrow;
+#endif
+#ifdef LTC_RC4
+ struct rc4_prng rc4;
+#endif
+#ifdef LTC_FORTUNA
+ struct fortuna_prng fortuna;
+#endif
+#ifdef LTC_SOBER128
+ struct sober128_prng sober128;
+#endif
+} prng_state;
+
+/** PRNG descriptor */
+extern struct ltc_prng_descriptor {
+ /** Name of the PRNG */
+ char *name;
+ /** size in bytes of exported state */
+ int export_size;
+ /** Start a PRNG state
+ @param prng [out] The state to initialize
+ @return CRYPT_OK if successful
+ */
+ int (*start)(prng_state *prng);
+ /** Add entropy to the PRNG
+ @param in The entropy
+ @param inlen Length of the entropy (octets)\
+ @param prng The PRNG state
+ @return CRYPT_OK if successful
+ */
+ int (*add_entropy)(const unsigned char *in, unsigned long inlen, prng_state *prng);
+ /** Ready a PRNG state to read from
+ @param prng The PRNG state to ready
+ @return CRYPT_OK if successful
+ */
+ int (*ready)(prng_state *prng);
+ /** Read from the PRNG
+ @param out [out] Where to store the data
+ @param outlen Length of data desired (octets)
+ @param prng The PRNG state to read from
+ @return Number of octets read
+ */
+ unsigned long (*read)(unsigned char *out, unsigned long outlen, prng_state *prng);
+ /** Terminate a PRNG state
+ @param prng The PRNG state to terminate
+ @return CRYPT_OK if successful
+ */
+ int (*done)(prng_state *prng);
+ /** Export a PRNG state
+ @param out [out] The destination for the state
+ @param outlen [in/out] The max size and resulting size of the PRNG state
+ @param prng The PRNG to export
+ @return CRYPT_OK if successful
+ */
+ int (*pexport)(unsigned char *out, unsigned long *outlen, prng_state *prng);
+ /** Import a PRNG state
+ @param in The data to import
+ @param inlen The length of the data to import (octets)
+ @param prng The PRNG to initialize/import
+ @return CRYPT_OK if successful
+ */
+ int (*pimport)(const unsigned char *in, unsigned long inlen, prng_state *prng);
+ /** Self-test the PRNG
+ @return CRYPT_OK if successful, CRYPT_NOP if self-testing has been disabled
+ */
+ int (*test)(void);
+} prng_descriptor[];
+
+#ifdef LTC_YARROW
+int yarrow_start(prng_state *prng);
+int yarrow_add_entropy(const unsigned char *in, unsigned long inlen, prng_state *prng);
+int yarrow_ready(prng_state *prng);
+unsigned long yarrow_read(unsigned char *out, unsigned long outlen, prng_state *prng);
+int yarrow_done(prng_state *prng);
+int yarrow_export(unsigned char *out, unsigned long *outlen, prng_state *prng);
+int yarrow_import(const unsigned char *in, unsigned long inlen, prng_state *prng);
+int yarrow_test(void);
+extern const struct ltc_prng_descriptor yarrow_desc;
+#endif
+
+#ifdef LTC_FORTUNA
+int fortuna_start(prng_state *prng);
+int fortuna_add_entropy(const unsigned char *in, unsigned long inlen, prng_state *prng);
+int fortuna_ready(prng_state *prng);
+unsigned long fortuna_read(unsigned char *out, unsigned long outlen, prng_state *prng);
+int fortuna_done(prng_state *prng);
+int fortuna_export(unsigned char *out, unsigned long *outlen, prng_state *prng);
+int fortuna_import(const unsigned char *in, unsigned long inlen, prng_state *prng);
+int fortuna_test(void);
+extern const struct ltc_prng_descriptor fortuna_desc;
+#endif
+
+#ifdef LTC_RC4
+int rc4_start(prng_state *prng);
+int rc4_add_entropy(const unsigned char *in, unsigned long inlen, prng_state *prng);
+int rc4_ready(prng_state *prng);
+unsigned long rc4_read(unsigned char *out, unsigned long outlen, prng_state *prng);
+int rc4_done(prng_state *prng);
+int rc4_export(unsigned char *out, unsigned long *outlen, prng_state *prng);
+int rc4_import(const unsigned char *in, unsigned long inlen, prng_state *prng);
+int rc4_test(void);
+extern const struct ltc_prng_descriptor rc4_desc;
+#endif
+
+#ifdef LTC_SPRNG
+int sprng_start(prng_state *prng);
+int sprng_add_entropy(const unsigned char *in, unsigned long inlen, prng_state *prng);
+int sprng_ready(prng_state *prng);
+unsigned long sprng_read(unsigned char *out, unsigned long outlen, prng_state *prng);
+int sprng_done(prng_state *prng);
+int sprng_export(unsigned char *out, unsigned long *outlen, prng_state *prng);
+int sprng_import(const unsigned char *in, unsigned long inlen, prng_state *prng);
+int sprng_test(void);
+extern const struct ltc_prng_descriptor sprng_desc;
+#endif
+
+#ifdef LTC_SOBER128
+int sober128_start(prng_state *prng);
+int sober128_add_entropy(const unsigned char *in, unsigned long inlen, prng_state *prng);
+int sober128_ready(prng_state *prng);
+unsigned long sober128_read(unsigned char *out, unsigned long outlen, prng_state *prng);
+int sober128_done(prng_state *prng);
+int sober128_export(unsigned char *out, unsigned long *outlen, prng_state *prng);
+int sober128_import(const unsigned char *in, unsigned long inlen, prng_state *prng);
+int sober128_test(void);
+extern const struct ltc_prng_descriptor sober128_desc;
+#endif
+
+int find_prng(const char *name);
+int register_prng(const struct ltc_prng_descriptor *prng);
+int unregister_prng(const struct ltc_prng_descriptor *prng);
+int prng_is_valid(int idx);
+LTC_MUTEX_PROTO(ltc_prng_mutex)
+
+/* Slow RNG you **might** be able to use to seed a PRNG with. Be careful as this
+ * might not work on all platforms as planned
+ */
+unsigned long rng_get_bytes(unsigned char *out,
+ unsigned long outlen,
+ void (*callback)(void));
+
+int rng_make_prng(int bits, int wprng, prng_state *prng, void (*callback)(void));
+
+
+/* $Source: /cvs/libtom/libtomcrypt/src/headers/tomcrypt_prng.h,v $ */
+/* $Revision: 1.9 $ */
+/* $Date: 2007/05/12 14:32:35 $ */
diff --git a/dep/CascLib/src/libtomcrypt/src/misc/crypt_argchk.c b/dep/CascLib/src/libtomcrypt/src/misc/crypt_argchk.c
new file mode 100644
index 00000000000..537516d80d9
--- /dev/null
+++ b/dep/CascLib/src/libtomcrypt/src/misc/crypt_argchk.c
@@ -0,0 +1,30 @@
+/* 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"
+#include <signal.h>
+
+/**
+ @file crypt_argchk.c
+ Perform argument checking, Tom St Denis
+*/
+
+#if (ARGTYPE == 0)
+void crypt_argchk(char *v, char *s, int d)
+{
+ fprintf(stderr, "LTC_ARGCHK '%s' failure on line %d of file %s\n",
+ v, d, s);
+ (void)raise(SIGABRT);
+}
+#endif
+
+/* $Source: /cvs/libtom/libtomcrypt/src/misc/crypt/crypt_argchk.c,v $ */
+/* $Revision: 1.5 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/dep/CascLib/src/libtomcrypt/src/misc/crypt_hash_descriptor.c b/dep/CascLib/src/libtomcrypt/src/misc/crypt_hash_descriptor.c
new file mode 100644
index 00000000000..5925fd27302
--- /dev/null
+++ b/dep/CascLib/src/libtomcrypt/src/misc/crypt_hash_descriptor.c
@@ -0,0 +1,27 @@
+/* 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 crypt_hash_descriptor.c
+ Stores the hash descriptor table, Tom St Denis
+*/
+
+struct ltc_hash_descriptor hash_descriptor[TAB_SIZE] = {
+{ NULL, 0, 0, 0, { 0 }, 0, NULL, NULL, NULL, NULL, NULL }
+};
+
+LTC_MUTEX_GLOBAL(ltc_hash_mutex)
+
+
+/* $Source: /cvs/libtom/libtomcrypt/src/misc/crypt/crypt_hash_descriptor.c,v $ */
+/* $Revision: 1.10 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/dep/CascLib/src/libtomcrypt/src/misc/crypt_hash_is_valid.c b/dep/CascLib/src/libtomcrypt/src/misc/crypt_hash_is_valid.c
new file mode 100644
index 00000000000..8ed5105b56c
--- /dev/null
+++ b/dep/CascLib/src/libtomcrypt/src/misc/crypt_hash_is_valid.c
@@ -0,0 +1,36 @@
+/* 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 crypt_hash_is_valid.c
+ Determine if hash is valid, Tom St Denis
+*/
+
+/*
+ Test if a hash index is valid
+ @param idx The index of the hash to search for
+ @return CRYPT_OK if valid
+*/
+int hash_is_valid(int idx)
+{
+ LTC_MUTEX_LOCK(&ltc_hash_mutex);
+ if (idx < 0 || idx >= TAB_SIZE || hash_descriptor[idx].name == NULL) {
+ LTC_MUTEX_UNLOCK(&ltc_hash_mutex);
+ return CRYPT_INVALID_HASH;
+ }
+ LTC_MUTEX_UNLOCK(&ltc_hash_mutex);
+ return CRYPT_OK;
+}
+
+/* $Source: /cvs/libtom/libtomcrypt/src/misc/crypt/crypt_hash_is_valid.c,v $ */
+/* $Revision: 1.6 $ */
+/* $Date: 2006/12/28 01:27:24 $ */
diff --git a/dep/CascLib/src/libtomcrypt/src/misc/crypt_libc.c b/dep/CascLib/src/libtomcrypt/src/misc/crypt_libc.c
new file mode 100644
index 00000000000..bcc89f4f94d
--- /dev/null
+++ b/dep/CascLib/src/libtomcrypt/src/misc/crypt_libc.c
@@ -0,0 +1,43 @@
+/*****************************************************************************/
+/* crypt_libc.c Copyright (c) Ladislav Zezula 2010 */
+/*---------------------------------------------------------------------------*/
+/* Description: */
+/*---------------------------------------------------------------------------*/
+/* Date Ver Who Comment */
+/* -------- ---- --- ------- */
+/* 05.05.10 1.00 Lad The first version of crypt_libc.c */
+/*****************************************************************************/
+
+// LibTomCrypt header
+#include <stdlib.h>
+#include "../headers/tomcrypt.h"
+
+void * LibTomMalloc(size_t n)
+{
+ return malloc(n);
+}
+
+void * LibTomCalloc(size_t n, size_t s)
+{
+ return calloc(n, s);
+}
+
+void * LibTomRealloc(void *p, size_t n)
+{
+ return realloc(p, n);
+}
+
+void LibTomFree(void * p)
+{
+ free(p);
+}
+
+clock_t LibTomClock(void)
+{
+ return clock();
+}
+
+void LibTomQsort(void *base, size_t nmemb, size_t size, int(*compar)(const void *, const void *))
+{
+ qsort(base, nmemb, size, compar);
+}