static bool CheckConfigFileVariable( TCascStorage * hs, // Pointer to storage structure const char * szLinePtr, // Pointer to the begin of the line const char * szLineEnd, // Pointer to the end of the line const char * szVarName, // Pointer to the variable to check PARSE_VARIABLE PfnParseProc, // Pointer to the parsing function void * pvParseParam) // Pointer to the parameter passed to parsing function { char szVariableName[MAX_VAR_NAME]; // Capture the variable from the line szLinePtr = CaptureSingleString(szLinePtr, szLineEnd, szVariableName, sizeof(szVariableName)); if (szLinePtr == NULL) return false; // Verify whether this is the variable if (!CheckWildCard(szVariableName, szVarName)) return false; // Skip the spaces and '=' while (szLinePtr < szLineEnd && (IsWhiteSpace(szLinePtr) || szLinePtr[0] == '=')) szLinePtr++; // Call the parsing function only if there is some data if (szLinePtr >= szLineEnd) return false; return (PfnParseProc(hs, szVariableName, szLinePtr, szLineEnd, pvParseParam) == ERROR_SUCCESS); }
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((DWORD)nError); return nLength; }
bool WINAPI SListFileFindNextFile(HANDLE hFind, SFILE_FIND_DATA * lpFindFileData) { TListFileCache * pCache = (TListFileCache *)hFind; size_t nLength; bool bResult = false; int nError = ERROR_SUCCESS; for(;;) { // Read the (next) line nLength = ReadListFileLine(pCache, lpFindFileData->cFileName, sizeof(lpFindFileData->cFileName)); if(nLength == 0) { nError = ERROR_NO_MORE_FILES; break; } // If some mask entered, check it if(CheckWildCard(lpFindFileData->cFileName, pCache->szMask)) { bResult = true; break; } } if(nError != ERROR_SUCCESS) SetLastError(nError); return bResult; }
size_t ListFile_GetNext(void * pvListFile, const char * szMask, char * szBuffer, size_t nMaxChars) { size_t nLength = 0; int nError = ERROR_SUCCESS; // Check for parameters for(;;) { // Read the (next) line nLength = ListFile_GetNextLine(pvListFile, 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; }
bool CheckWildCard(const char * szString, const char * szWildCard) { const char * szWildCardPtr; for(;;) { // If there is '?' in the wildcard, we skip one char while(szWildCard[0] == '?') { if(szString[0] == 0) return false; szWildCard++; szString++; } // Handle '*' szWildCardPtr = szWildCard; if(szWildCardPtr[0] != 0) { if(szWildCardPtr[0] == '*') { szWildCardPtr++; if(szWildCardPtr[0] == '*') continue; if(szWildCardPtr[0] == 0) return true; if(AsciiToUpperTable[szWildCardPtr[0]] == AsciiToUpperTable[szString[0]]) { if(CheckWildCard(szString, szWildCardPtr)) return true; } } else { if(AsciiToUpperTable[szWildCardPtr[0]] != AsciiToUpperTable[szString[0]]) return false; szWildCard = szWildCardPtr + 1; } if(szString[0] == 0) return false; szString++; } else { return (szString[0] == 0) ? true : false; } } }
static bool DoMPQSearch_FileEntry( TMPQSearch * hs, SFILE_FIND_DATA * lpFindFileData, TMPQArchive * ha, TMPQHash * pHashEntry, TFileEntry * pFileEntry) { TFileEntry * pPatchEntry; HANDLE hFile = NULL; const char * szFileName; size_t nPrefixLength = (ha->pPatchPrefix != NULL) ? ha->pPatchPrefix->nLength : 0; DWORD dwBlockIndex; char szNameBuff[MAX_PATH]; // Is it a file but not a patch file? if((pFileEntry->dwFlags & hs->dwFlagMask) == MPQ_FILE_EXISTS) { // Now we have to check if this file was not enumerated before if(!FileWasFoundBefore(ha, hs, pFileEntry)) { // if(pFileEntry != NULL && !_stricmp(pFileEntry->szFileName, "TriggerLibs\\NativeLib.galaxy")) // DebugBreak(); // Find a patch to this file pPatchEntry = FindPatchEntry(ha, pFileEntry); if(pPatchEntry == NULL) pPatchEntry = pFileEntry; // Prepare the block index dwBlockIndex = (DWORD)(pFileEntry - ha->pFileTable); // Get the file name. If it's not known, we will create pseudo-name szFileName = pFileEntry->szFileName; if(szFileName == NULL) { // Open the file by its pseudo-name. sprintf(szNameBuff, "File%08u.xxx", (unsigned int)dwBlockIndex); if(SFileOpenFileEx((HANDLE)hs->ha, szNameBuff, SFILE_OPEN_BASE_FILE, &hFile)) { SFileGetFileName(hFile, szNameBuff); szFileName = szNameBuff; SFileCloseFile(hFile); } } // If the file name is still NULL, we cannot include the file to search results if(szFileName != NULL) { // Check the file name against the wildcard if(CheckWildCard(szFileName + nPrefixLength, hs->szSearchMask)) { // Fill the found entry. hash entry and block index are taken from the base MPQ lpFindFileData->dwHashIndex = HASH_ENTRY_FREE; lpFindFileData->dwBlockIndex = dwBlockIndex; lpFindFileData->dwFileSize = pPatchEntry->dwFileSize; lpFindFileData->dwFileFlags = pPatchEntry->dwFlags; lpFindFileData->dwCompSize = pPatchEntry->dwCmpSize; lpFindFileData->lcLocale = 0; // pPatchEntry->lcLocale; // Fill the filetime lpFindFileData->dwFileTimeHi = (DWORD)(pPatchEntry->FileTime >> 32); lpFindFileData->dwFileTimeLo = (DWORD)(pPatchEntry->FileTime); // Fill-in the entries from hash table entry, if given if(pHashEntry != NULL) { lpFindFileData->dwHashIndex = (DWORD)(pHashEntry - ha->pHashTable); lpFindFileData->lcLocale = pHashEntry->lcLocale; } // Fill the file name and plain file name StringCopyA(lpFindFileData->cFileName, szFileName + nPrefixLength, MAX_PATH-1); lpFindFileData->szPlainName = (char *)GetPlainFileName(lpFindFileData->cFileName); return true; } } }
// Performs one MPQ search static int DoMPQSearch(TMPQSearch * hs, SFILE_FIND_DATA * lpFindFileData) { TMPQArchive * ha = hs->ha; TFileEntry * pFileTableEnd; TFileEntry * pPatchEntry; TFileEntry * pFileEntry; const char * szFileName; HANDLE hFile; char szPseudoName[20]; DWORD dwBlockIndex; size_t nPrefixLength; // Start searching with base MPQ while(ha != NULL) { // Now parse the file entry table in order to get all files. pFileTableEnd = ha->pFileTable + ha->dwFileTableSize; pFileEntry = ha->pFileTable + hs->dwNextIndex; // Get the length of the patch prefix (0 if none) nPrefixLength = strlen(ha->szPatchPrefix); // Parse the file table while(pFileEntry < pFileTableEnd) { // Increment the next index for subsequent search hs->dwNextIndex++; // Is it a file and not a patch file? if((pFileEntry->dwFlags & hs->dwFlagMask) == MPQ_FILE_EXISTS) { // Now we have to check if this file was not enumerated before if(!FileWasFoundBefore(ha, hs, pFileEntry)) { // Find a patch to this file pPatchEntry = FindPatchEntry(ha, pFileEntry); if(pPatchEntry == NULL) pPatchEntry = pFileEntry; // Prepare the block index dwBlockIndex = (DWORD)(pFileEntry - ha->pFileTable); // Get the file name. If it's not known, we will create pseudo-name szFileName = pFileEntry->szFileName; if(szFileName == NULL) { // Open the file by its pseudo-name. // This also generates the file name with a proper extension sprintf(szPseudoName, "File%08u.xxx", dwBlockIndex); if(SFileOpenFileEx((HANDLE)hs->ha, szPseudoName, SFILE_OPEN_BASE_FILE, &hFile)) { szFileName = (pFileEntry->szFileName != NULL) ? pFileEntry->szFileName : szPseudoName; SFileCloseFile(hFile); } } // Check the file name against the wildcard if(CheckWildCard(szFileName + nPrefixLength, hs->szSearchMask)) { // Fill the found entry lpFindFileData->dwHashIndex = pPatchEntry->dwHashIndex; lpFindFileData->dwBlockIndex = dwBlockIndex; lpFindFileData->dwFileSize = pPatchEntry->dwFileSize; lpFindFileData->dwFileFlags = pPatchEntry->dwFlags; lpFindFileData->dwCompSize = pPatchEntry->dwCmpSize; lpFindFileData->lcLocale = pPatchEntry->lcLocale; // Fill the filetime lpFindFileData->dwFileTimeHi = (DWORD)(pPatchEntry->FileTime >> 32); lpFindFileData->dwFileTimeLo = (DWORD)(pPatchEntry->FileTime); // Fill the file name and plain file name strcpy(lpFindFileData->cFileName, szFileName + nPrefixLength); lpFindFileData->szPlainName = (char *)GetPlainFileNameA(lpFindFileData->cFileName); return ERROR_SUCCESS; } } } pFileEntry++; }
HANDLE WINAPI SListFileFindFirstFile(HANDLE hMpq, const char * szListFile, const char * szMask, SFILE_FIND_DATA * lpFindFileData) { TListFileCache * pCache = NULL; HANDLE hListFile = NULL; size_t nLength = 0; DWORD dwSearchScope = SFILE_OPEN_LOCAL_FILE; int nError = ERROR_SUCCESS; // Initialize the structure with zeros memset(lpFindFileData, 0, sizeof(SFILE_FIND_DATA)); // If the szListFile is NULL, it means we have to open internal listfile if(szListFile == NULL) { // Use SFILE_OPEN_ANY_LOCALE for listfile. This will allow us to load // the listfile even if there is only non-neutral version of the listfile in the MPQ dwSearchScope = SFILE_OPEN_ANY_LOCALE; szListFile = LISTFILE_NAME; } // Open the local/internal listfile if(!SFileOpenFileEx(hMpq, szListFile, dwSearchScope, &hListFile)) nError = GetLastError(); // Load the listfile to cache if(nError == ERROR_SUCCESS) { pCache = CreateListFileCache(hListFile, szMask); if(pCache == NULL) nError = ERROR_FILE_CORRUPT; } // Perform file search if(nError == ERROR_SUCCESS) { for(;;) { // Read the (next) line nLength = ReadListFileLine(pCache, lpFindFileData->cFileName, sizeof(lpFindFileData->cFileName)); if(nLength == 0) { nError = ERROR_NO_MORE_FILES; break; } // If some mask entered, check it if(CheckWildCard(lpFindFileData->cFileName, pCache->szMask)) break; } } // Cleanup & exit if(nError != ERROR_SUCCESS) { memset(lpFindFileData, 0, sizeof(SFILE_FIND_DATA)); SetLastError(nError); } if(pCache != NULL) FreeListFileCache(pCache); if(hListFile != NULL) SFileCloseFile(hListFile); return (HANDLE)pCache; }
// Performs one MPQ search static int DoMPQSearch(TMPQSearch * hs, SFILE_FIND_DATA * lpFindFileData) { TMPQArchive * ha = hs->ha; TFileEntry * pFileTableEnd; TFileEntry * pFileEntry; const char * szFileName; char szPseudoName[20]; DWORD dwBlockIndex; size_t nPrefixLength; // Do that for all files in the patch chain while(ha != NULL) { // Now parse the file entry table in order to get all files. pFileTableEnd = ha->pFileTable + ha->dwFileTableSize; pFileEntry = ha->pFileTable + hs->dwNextIndex; // Get the start and end of the hash table nPrefixLength = strlen(ha->szPatchPrefix); // Parse the file table while(pFileEntry < pFileTableEnd) { // Increment the next index for subsequent search hs->dwNextIndex++; // Does the block exist ? if(pFileEntry->dwFlags & MPQ_FILE_EXISTS) { // Prepare the block index dwBlockIndex = (DWORD)(pFileEntry - ha->pFileTable); // Get the file name. If it's not known, we will create pseudo-name szFileName = pFileEntry->szFileName; if(szFileName == NULL) { HANDLE hFile; // Open the file by index in order to check if the file exists if(SFileOpenFileEx((HANDLE)hs->ha, (char *)(DWORD_PTR)dwBlockIndex, SFILE_OPEN_BY_INDEX, &hFile)) SFileCloseFile(hFile); // If the name was retrieved, use that one. Otherwise, just use generic pseudo-name szFileName = pFileEntry->szFileName; if(szFileName == NULL) { sprintf(szPseudoName, "File%08u.xxx", dwBlockIndex); szFileName = szPseudoName; } } // If we are already in the patch MPQ, we skip all files // that don't have the appropriate patch prefix and are patch files if(ha->haBase != NULL) { // If the file has different patch prefix, don't report it if(nPrefixLength != 0 && _strnicmp(szFileName, ha->szPatchPrefix, nPrefixLength)) goto __SkipThisFile; // // We need to properly handle the following case: // // 1) Base MPQ file doesn't contain the desired file // 2) First patch MPQ contains the file with MPQ_FILE_PATCH_FILE // 3) Second patch contains full version of the file (MPQ_FILE_PATCH_FILE is not set) // if(IsBaseFileMissing(ha, szFileName, szFileName + nPrefixLength, pFileEntry->lcLocale)) goto __SkipThisFile; } // Check the file name. if(CheckWildCard(szFileName, hs->szSearchMask)) { // Fill the found entry lpFindFileData->dwHashIndex = pFileEntry->dwHashIndex; lpFindFileData->dwBlockIndex = dwBlockIndex; lpFindFileData->dwFileSize = pFileEntry->dwFileSize; lpFindFileData->dwFileFlags = pFileEntry->dwFlags; lpFindFileData->dwCompSize = pFileEntry->dwCmpSize; lpFindFileData->lcLocale = pFileEntry->lcLocale; // Fill the filetime lpFindFileData->dwFileTimeHi = (DWORD)(pFileEntry->FileTime >> 32); lpFindFileData->dwFileTimeLo = (DWORD)(pFileEntry->FileTime); // Fill the file name and plain file name strcpy(lpFindFileData->cFileName, szFileName + nPrefixLength); lpFindFileData->szPlainName = (char *)GetPlainFileName(lpFindFileData->cFileName); return ERROR_SUCCESS; } } // Move to the next file entry __SkipThisFile: pFileEntry++; }