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); pVarBlob->cbData = (DWORD)((szLinePtr - szLineBegin) / 2); return ConvertStringToBinary(szLineBegin, (size_t)(szLinePtr - szLineBegin), pVarBlob->pbData); } // Initialize the blob pVarBlob->pbData = CASC_ALLOC(BYTE, (szLinePtr - szLineBegin) + 1); pVarBlob->cbData = (DWORD)(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; }
// Parses single line from Overwatch. // The line structure is: "#MD5|CHUNK_ID|FILENAME|INSTALLPATH" // The line has all preceding spaces removed int ParseRootFileLine(const char * szLinePtr, const char * szLineEnd, PQUERY_KEY PtrEncodingKey, char * szFileName, size_t nMaxChars) { size_t nLength; int nError; // Check the MD5 (aka encoding key) if(szLinePtr[MD5_STRING_SIZE] != '|') return ERROR_BAD_FORMAT; // Convert the encoding key to binary PtrEncodingKey->cbData = MD5_HASH_SIZE; nError = ConvertStringToBinary(szLinePtr, MD5_STRING_SIZE, PtrEncodingKey->pbData); if(nError != ERROR_SUCCESS) return nError; // Skip the MD5 szLinePtr += MD5_STRING_SIZE+1; // Skip the chunk ID szLinePtr = SkipInfoVariable(szLinePtr, szLineEnd); // Get the archived file name szLineEnd = SkipInfoVariable(szLinePtr, szLineEnd); nLength = (size_t)(szLineEnd - szLinePtr - 1); // Get the file name if(nLength > nMaxChars) return ERROR_INSUFFICIENT_BUFFER; memcpy(szFileName, szLinePtr, nLength); szFileName[nLength] = 0; return ERROR_SUCCESS; }
static const char * CaptureSingleHash(const char * szDataPtr, const char * szDataEnd, LPBYTE HashValue, size_t HashLength) { const char * szHashString; size_t HashStringLength = HashLength * 2; // Skip all whitespaces while (szDataPtr < szDataEnd && IsWhiteSpace(szDataPtr)) szDataPtr++; szHashString = szDataPtr; // Count all hash characters for (size_t i = 0; i < HashStringLength; i++) { if (szDataPtr >= szDataEnd || isxdigit(szDataPtr[0]) == 0) return NULL; szDataPtr++; } // There must be a separator or end-of-string if (szDataPtr > szDataEnd || IsWhiteSpace(szDataPtr) == false) return NULL; // Give the values ConvertStringToBinary(szHashString, HashStringLength, HashValue); return szDataPtr; }
static int LoadBlobArray( PQUERY_KEY pBlob, const char * szLineBegin, const char * szLineEnd, DWORD dwMaxBlobs) { LPBYTE pbBufferEnd = pBlob->pbData + pBlob->cbData; LPBYTE pbBuffer = pBlob->pbData; int nError = ERROR_SUCCESS; // Sanity check assert(pBlob->pbData != NULL); assert(pBlob->cbData != 0); // Until we find an end of the line while(szLineBegin < szLineEnd && dwMaxBlobs > 0) { const char * szBlobEnd = szLineBegin; // Find the end of the text blob while(szBlobEnd < szLineEnd && IsValueSeparator(szBlobEnd) == false) szBlobEnd++; // Verify the length of the found blob if((szBlobEnd - szLineBegin) != MD5_STRING_SIZE) return ERROR_BAD_FORMAT; // Verify if there is enough space in the buffer if((pbBufferEnd - pbBuffer) < MD5_HASH_SIZE) return ERROR_NOT_ENOUGH_MEMORY; // Perform the conversion nError = ConvertStringToBinary(szLineBegin, MD5_STRING_SIZE, pbBuffer); if(nError != ERROR_SUCCESS) return nError; // Move pointers pbBuffer += MD5_HASH_SIZE; dwMaxBlobs--; // Skip the separator while(szBlobEnd < szLineEnd && IsValueSeparator(szBlobEnd)) szBlobEnd++; szLineBegin = szBlobEnd; } return nError; }
static bool IsFileDataIdName(const char * szFileName) { BYTE BinaryValue[4]; // File name must begin with "File", case insensitive if(AsciiToUpperTable_BkSlash[szFileName[0]] == 'F' && AsciiToUpperTable_BkSlash[szFileName[1]] == 'I' && AsciiToUpperTable_BkSlash[szFileName[2]] == 'L' && AsciiToUpperTable_BkSlash[szFileName[3]] == 'E') { // Then, 8 hexadecimal digits must follow if(ConvertStringToBinary(szFileName + 4, 8, BinaryValue) == ERROR_SUCCESS) { // Must be followed by an extension or end-of-string return (szFileName[0x0C] == 0 || szFileName[0x0C] == '.'); } } return false; }
// Parses single line from Overwatch. int ParseRootFileLine(const char * szLinePtr, const char * szLineEnd, int nFileNameIndex, PQUERY_KEY PtrEncodingKey, char * szFileName, size_t nMaxChars) { int nIndex = 0; int nError; // Extract the MD5 (aka encoding key) if(szLinePtr[MD5_STRING_SIZE] != '|') return ERROR_BAD_FORMAT; // Convert the encoding key to binary PtrEncodingKey->cbData = MD5_HASH_SIZE; nError = ConvertStringToBinary(szLinePtr, MD5_STRING_SIZE, PtrEncodingKey->pbData); if(nError != ERROR_SUCCESS) return nError; // Skip the variable szLinePtr += MD5_STRING_SIZE + 1; nIndex = 1; // Skip the variables until we find the file name while(szLinePtr < szLineEnd && nIndex < nFileNameIndex) { if(szLinePtr[0] == '|') nIndex++; szLinePtr++; } // Extract the file name while(szLinePtr < szLineEnd && szLinePtr[0] != '|' && nMaxChars > 1) { *szFileName++ = *szLinePtr++; nMaxChars--; } *szFileName = 0; return ERROR_SUCCESS; }
static LPBYTE WowHandler_GetKey(TRootHandler_WoW6 * pRootHandler, const char * szFileName) { PCASC_FILE_ENTRY pFileEntry; DWORD FileDataId; BYTE FileDataIdLE[4]; // Open by FileDataId. The file name must be as following: // File########.xxx, where '#' are hexa-decimal numbers (case insensitive). // Extension is ignored in that case if(IsFileDataIdName(szFileName)) { ConvertStringToBinary(szFileName + 4, 8, FileDataIdLE); FileDataId = ConvertBytesToInteger_4(FileDataIdLE); pFileEntry = FindRootEntry(pRootHandler->FileTable, FileDataId); } else { // Find by the file name hash pFileEntry = FindRootEntry(pRootHandler->pRootMap, szFileName, NULL); } return (pFileEntry != NULL) ? pFileEntry->EncodingKey.Value : NULL; }