diff options
| author | Nicholas Estelami <NEstelami@users.noreply.github.com> | 2022-06-01 16:05:05 -0400 |
|---|---|---|
| committer | Nicholas Estelami <NEstelami@users.noreply.github.com> | 2022-06-16 20:35:52 -0400 |
| commit | b3e299dbdee829c12ada556a1c3aa1f109a0e05b (patch) | |
| tree | a6e647da673ba7df9389cb1f382a11fc8350bc23 /StormLib/src/SFileGetFileInfo.cpp | |
| parent | 941c19f2c33a0d1af75a10a64fe0905387d1e440 (diff) | |
Replaced StormLib .lib files with source code.
Some modifications to handle backslashes and forward slashes, along with some optimizations to speed up OTR generation.
Diffstat (limited to 'StormLib/src/SFileGetFileInfo.cpp')
| -rw-r--r-- | StormLib/src/SFileGetFileInfo.cpp | 607 |
1 files changed, 607 insertions, 0 deletions
diff --git a/StormLib/src/SFileGetFileInfo.cpp b/StormLib/src/SFileGetFileInfo.cpp new file mode 100644 index 000000000..28edfe0bf --- /dev/null +++ b/StormLib/src/SFileGetFileInfo.cpp @@ -0,0 +1,607 @@ +/*****************************************************************************/ +/* SFileGetFileInfo.cpp Copyright (c) Ladislav Zezula 2013 */ +/*---------------------------------------------------------------------------*/ +/* Description: */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 30.11.13 1.00 Lad The first version of SFileGetFileInfo.cpp */ +/*****************************************************************************/ + +#define __STORMLIB_SELF__ +#include "StormLib.h" +#include "StormCommon.h" + +//----------------------------------------------------------------------------- +// Local functions + +static DWORD GetMpqFileCount(TMPQArchive * ha) +{ + TFileEntry * pFileTableEnd; + TFileEntry * pFileEntry; + DWORD dwFileCount = 0; + + // Go through all open MPQs, including patches + while(ha != NULL) + { + // Only count files that are not patch files + pFileTableEnd = ha->pFileTable + ha->dwFileTableSize; + for(pFileEntry = ha->pFileTable; pFileEntry < pFileTableEnd; pFileEntry++) + { + // If the file is patch file and this is not primary archive, skip it + // BUGBUG: This errorneously counts non-patch files that are in both + // base MPQ and in patches, and increases the number of files by cca 50% + if((pFileEntry->dwFlags & (MPQ_FILE_EXISTS | MPQ_FILE_PATCH_FILE)) == MPQ_FILE_EXISTS) + dwFileCount++; + } + + // Move to the next patch archive + ha = ha->haPatch; + } + + return dwFileCount; +} + +static bool GetInfo_ReturdwErrCode(DWORD dwErrCode) +{ + SetLastError(dwErrCode); + return false; +} + +static bool GetInfo_BufferCheck(void * pvFileInfo, DWORD cbFileInfo, DWORD cbData, LPDWORD pcbLengthNeeded) +{ + // Give the length needed to store the info + if(pcbLengthNeeded != NULL) + pcbLengthNeeded[0] = cbData; + + // Check for sufficient buffer + if(cbData > cbFileInfo) + return GetInfo_ReturdwErrCode(ERROR_INSUFFICIENT_BUFFER); + + // If the buffer size is sufficient, check for valid user buffer + if(pvFileInfo == NULL) + return GetInfo_ReturdwErrCode(ERROR_INVALID_PARAMETER); + + // Buffers and sizes are OK, we are ready to proceed file copying + return true; +} + +static bool GetInfo(void * pvFileInfo, DWORD cbFileInfo, const void * pvData, DWORD cbData, LPDWORD pcbLengthNeeded) +{ + // Verify buffer pointer and buffer size + if(!GetInfo_BufferCheck(pvFileInfo, cbFileInfo, cbData, pcbLengthNeeded)) + return false; + + // Copy the data to the caller-supplied buffer + memcpy(pvFileInfo, pvData, cbData); + return true; +} + +static bool GetInfo_Allocated(void * pvFileInfo, DWORD cbFileInfo, void * pvData, DWORD cbData, LPDWORD pcbLengthNeeded) +{ + bool bResult; + + // Verify buffer pointer and buffer size + if((bResult = GetInfo_BufferCheck(pvFileInfo, cbFileInfo, cbData, pcbLengthNeeded)) != false) + memcpy(pvFileInfo, pvData, cbData); + + // Copy the data to the user buffer + STORM_FREE(pvData); + return bResult; +} + +static bool GetInfo_TablePointer(void * pvFileInfo, DWORD cbFileInfo, void * pvTablePointer, SFileInfoClass InfoClass, LPDWORD pcbLengthNeeded) +{ + // Verify buffer pointer and buffer size + if(!GetInfo_BufferCheck(pvFileInfo, cbFileInfo, sizeof(void *), pcbLengthNeeded)) + { + SFileFreeFileInfo(pvTablePointer, InfoClass); + return false; + } + + // The user buffer receives pointer to the table. + // When done, the caller needs to call SFileFreeFileInfo on it + *(void **)pvFileInfo = pvTablePointer; + return true; +} + +static bool GetInfo_ReadFromFile(void * pvFileInfo, DWORD cbFileInfo, TFileStream * pStream, ULONGLONG ByteOffset, DWORD cbData, LPDWORD pcbLengthNeeded) +{ + // Verify buffer pointer and buffer size + if(!GetInfo_BufferCheck(pvFileInfo, cbFileInfo, cbData, pcbLengthNeeded)) + return false; + + return FileStream_Read(pStream, &ByteOffset, pvFileInfo, cbData); +} + +static bool GetInfo_FileEntry(void * pvFileInfo, DWORD cbFileInfo, TFileEntry * pFileEntry, LPDWORD pcbLengthNeeded) +{ + LPBYTE pbFileInfo = (LPBYTE)pvFileInfo; + DWORD cbSrcFileInfo = sizeof(TFileEntry); + DWORD cbFileName = 1; + + // The file name belongs to the file entry + if(pFileEntry->szFileName) + cbFileName = (DWORD)strlen(pFileEntry->szFileName) + 1; + cbSrcFileInfo += cbFileName; + + // Verify buffer pointer and buffer size + if(!GetInfo_BufferCheck(pvFileInfo, cbFileInfo, cbSrcFileInfo, pcbLengthNeeded)) + return false; + + // Copy the file entry + memcpy(pbFileInfo, pFileEntry, sizeof(TFileEntry)); + pbFileInfo += sizeof(TFileEntry); + pbFileInfo[0] = 0; + + // Copy the file name + if(pFileEntry->szFileName) + memcpy(pbFileInfo, pFileEntry->szFileName, cbFileName); + return true; +} + +static bool GetInfo_PatchChain(TMPQFile * hf, void * pvFileInfo, DWORD cbFileInfo, LPDWORD pcbLengthNeeded) +{ + TMPQFile * hfTemp; + LPCTSTR szPatchName; + LPTSTR szFileInfo = (LPTSTR)pvFileInfo; + size_t cchCharsNeeded = 1; + size_t nLength; + + // Patch chain is only supported on MPQ files. Local files are not supported. + if(hf->pStream != NULL) + return GetInfo_ReturdwErrCode(ERROR_INVALID_PARAMETER); + + // Calculate the necessary length of the multi-string + for(hfTemp = hf; hfTemp != NULL; hfTemp = hfTemp->hfPatch) + cchCharsNeeded += _tcslen(FileStream_GetFileName(hfTemp->ha->pStream)) + 1; + + // Verify whether the caller gave us valid buffer with enough size + if(!GetInfo_BufferCheck(pvFileInfo, cbFileInfo, (DWORD)(cchCharsNeeded * sizeof(TCHAR)), pcbLengthNeeded)) + return false; + + // Copy each patch name + for(hfTemp = hf; hfTemp != NULL; hfTemp = hfTemp->hfPatch) + { + // Get the file name and its length + szPatchName = FileStream_GetFileName(hfTemp->ha->pStream); + nLength = _tcslen(szPatchName) + 1; + + // Copy the file name + memcpy(szFileInfo, szPatchName, nLength * sizeof(TCHAR)); + szFileInfo += nLength; + } + + // Make it multi-string + szFileInfo[0] = 0; + return true; +} + +//----------------------------------------------------------------------------- +// Retrieves an information about an archive or about a file within the archive +// +// hMpqOrFile - Handle to an MPQ archive or to a file +// InfoClass - Information to obtain +// pvFileInfo - Pointer to buffer to store the information +// cbFileInfo - Size of the buffer pointed by pvFileInfo +// pcbLengthNeeded - Receives number of bytes necessary to store the information + +bool WINAPI SFileGetFileInfo( + HANDLE hMpqOrFile, + SFileInfoClass InfoClass, + void * pvFileInfo, + DWORD cbFileInfo, + LPDWORD pcbLengthNeeded) +{ + MPQ_SIGNATURE_INFO SignatureInfo; + const TCHAR * szSrcFileInfo; + TMPQArchive * ha = NULL; + TFileEntry * pFileEntry = NULL; + TMPQHeader * pHeader = NULL; + ULONGLONG Int64Value = 0; + TMPQFile * hf = NULL; + void * pvSrcFileInfo = NULL; + DWORD cbSrcFileInfo = 0; + DWORD dwInt32Value = 0; + + // Validate archive/file handle + if((int)InfoClass <= (int)SFileMpqFlags) + { + if((ha = IsValidMpqHandle(hMpqOrFile)) == NULL) + return GetInfo_ReturdwErrCode(ERROR_INVALID_HANDLE); + pHeader = ha->pHeader; + } + else + { + if((hf = IsValidFileHandle(hMpqOrFile)) == NULL) + return GetInfo_ReturdwErrCode(ERROR_INVALID_HANDLE); + pFileEntry = hf->pFileEntry; + } + + // Return info-class-specific data + switch(InfoClass) + { + case SFileMpqFileName: + szSrcFileInfo = FileStream_GetFileName(ha->pStream); + cbSrcFileInfo = (DWORD)((_tcslen(szSrcFileInfo) + 1) * sizeof(TCHAR)); + return GetInfo(pvFileInfo, cbFileInfo, szSrcFileInfo, cbSrcFileInfo, pcbLengthNeeded); + + case SFileMpqStreamBitmap: + return FileStream_GetBitmap(ha->pStream, pvFileInfo, cbFileInfo, pcbLengthNeeded); + + case SFileMpqUserDataOffset: + return GetInfo(pvFileInfo, cbFileInfo, &ha->UserDataPos, sizeof(ULONGLONG), pcbLengthNeeded); + + case SFileMpqUserDataHeader: + if(ha->pUserData == NULL) + return GetInfo_ReturdwErrCode(ERROR_INVALID_PARAMETER); + return GetInfo_ReadFromFile(pvFileInfo, cbFileInfo, ha->pStream, ha->UserDataPos, sizeof(TMPQUserData), pcbLengthNeeded); + + case SFileMpqUserData: + if(ha->pUserData == NULL) + return GetInfo_ReturdwErrCode(ERROR_INVALID_PARAMETER); + return GetInfo_ReadFromFile(pvFileInfo, cbFileInfo, ha->pStream, ha->UserDataPos + sizeof(TMPQUserData), ha->pUserData->dwHeaderOffs - sizeof(TMPQUserData), pcbLengthNeeded); + + case SFileMpqHeaderOffset: + return GetInfo(pvFileInfo, cbFileInfo, &ha->MpqPos, sizeof(ULONGLONG), pcbLengthNeeded); + + case SFileMpqHeaderSize: + return GetInfo(pvFileInfo, cbFileInfo, &pHeader->dwHeaderSize, sizeof(DWORD), pcbLengthNeeded); + + case SFileMpqHeader: + return GetInfo_ReadFromFile(pvFileInfo, cbFileInfo, ha->pStream, ha->MpqPos, pHeader->dwHeaderSize, pcbLengthNeeded); + + case SFileMpqHetTableOffset: + return GetInfo(pvFileInfo, cbFileInfo, &pHeader->HetTablePos64, sizeof(ULONGLONG), pcbLengthNeeded); + + case SFileMpqHetTableSize: + return GetInfo(pvFileInfo, cbFileInfo, &pHeader->HetTableSize64, sizeof(ULONGLONG), pcbLengthNeeded); + + case SFileMpqHetHeader: + pvSrcFileInfo = LoadExtTable(ha, pHeader->HetTablePos64, (size_t)pHeader->HetTableSize64, HET_TABLE_SIGNATURE, MPQ_KEY_HASH_TABLE); + if(pvSrcFileInfo == NULL) + return GetInfo_ReturdwErrCode(ERROR_FILE_NOT_FOUND); + return GetInfo_Allocated(pvFileInfo, cbFileInfo, pvSrcFileInfo, sizeof(TMPQHetHeader), pcbLengthNeeded); + + case SFileMpqHetTable: + if((pvSrcFileInfo = LoadHetTable(ha)) == NULL) + return GetInfo_ReturdwErrCode(ERROR_NOT_ENOUGH_MEMORY); + return GetInfo_TablePointer(pvFileInfo, cbFileInfo, pvSrcFileInfo, InfoClass, pcbLengthNeeded); + + case SFileMpqBetTableOffset: + return GetInfo(pvFileInfo, cbFileInfo, &pHeader->BetTablePos64, sizeof(ULONGLONG), pcbLengthNeeded); + + case SFileMpqBetTableSize: + return GetInfo(pvFileInfo, cbFileInfo, &pHeader->BetTableSize64, sizeof(ULONGLONG), pcbLengthNeeded); + + case SFileMpqBetHeader: + + // Retrieve the table and its size + pvSrcFileInfo = LoadExtTable(ha, pHeader->BetTablePos64, (size_t)pHeader->BetTableSize64, BET_TABLE_SIGNATURE, MPQ_KEY_BLOCK_TABLE); + if(pvSrcFileInfo == NULL) + return GetInfo_ReturdwErrCode(ERROR_FILE_NOT_FOUND); + cbSrcFileInfo = sizeof(TMPQBetHeader) + ((TMPQBetHeader *)pvSrcFileInfo)->dwFlagCount * sizeof(DWORD); + + // It is allowed for the caller to only require BET header + if(cbFileInfo == sizeof(TMPQBetHeader)) + cbSrcFileInfo = sizeof(TMPQBetHeader); + return GetInfo_Allocated(pvFileInfo, cbFileInfo, pvSrcFileInfo, cbSrcFileInfo, pcbLengthNeeded); + + case SFileMpqBetTable: + if((pvSrcFileInfo = LoadBetTable(ha)) == NULL) + return GetInfo_ReturdwErrCode(ERROR_NOT_ENOUGH_MEMORY); + return GetInfo_TablePointer(pvFileInfo, cbFileInfo, pvSrcFileInfo, InfoClass, pcbLengthNeeded); + + case SFileMpqHashTableOffset: + Int64Value = MAKE_OFFSET64(pHeader->wHashTablePosHi, pHeader->dwHashTablePos); + return GetInfo(pvFileInfo, cbFileInfo, &Int64Value, sizeof(ULONGLONG), pcbLengthNeeded); + + case SFileMpqHashTableSize64: + return GetInfo(pvFileInfo, cbFileInfo, &pHeader->HashTableSize64, sizeof(ULONGLONG), pcbLengthNeeded); + + case SFileMpqHashTableSize: + return GetInfo(pvFileInfo, cbFileInfo, &pHeader->dwHashTableSize, sizeof(DWORD), pcbLengthNeeded); + + case SFileMpqHashTable: + cbSrcFileInfo = pHeader->dwHashTableSize * sizeof(TMPQHash); + return GetInfo(pvFileInfo, cbFileInfo, ha->pHashTable, cbSrcFileInfo, pcbLengthNeeded); + + case SFileMpqBlockTableOffset: + Int64Value = MAKE_OFFSET64(pHeader->wBlockTablePosHi, pHeader->dwBlockTablePos); + return GetInfo(pvFileInfo, cbFileInfo, &Int64Value, sizeof(ULONGLONG), pcbLengthNeeded); + + case SFileMpqBlockTableSize64: + return GetInfo(pvFileInfo, cbFileInfo, &pHeader->BlockTableSize64, sizeof(ULONGLONG), pcbLengthNeeded); + + case SFileMpqBlockTableSize: + return GetInfo(pvFileInfo, cbFileInfo, &pHeader->dwBlockTableSize, sizeof(DWORD), pcbLengthNeeded); + + case SFileMpqBlockTable: + if(MAKE_OFFSET64(pHeader->wBlockTablePosHi, pHeader->dwBlockTablePos) >= ha->FileSize) + return GetInfo_ReturdwErrCode(ERROR_FILE_NOT_FOUND); + cbSrcFileInfo = pHeader->dwBlockTableSize * sizeof(TMPQBlock); + pvSrcFileInfo = LoadBlockTable(ha, true); + return GetInfo_Allocated(pvFileInfo, cbFileInfo, pvSrcFileInfo, cbSrcFileInfo, pcbLengthNeeded); + + case SFileMpqHiBlockTableOffset: + return GetInfo(pvFileInfo, cbFileInfo, &pHeader->HiBlockTablePos64, sizeof(ULONGLONG), pcbLengthNeeded); + + case SFileMpqHiBlockTableSize64: + return GetInfo(pvFileInfo, cbFileInfo, &pHeader->HiBlockTableSize64, sizeof(ULONGLONG), pcbLengthNeeded); + + case SFileMpqHiBlockTable: + return GetInfo_ReturdwErrCode(ERROR_FILE_NOT_FOUND); + + case SFileMpqSignatures: + if(!QueryMpqSignatureInfo(ha, &SignatureInfo)) + return GetInfo_ReturdwErrCode(ERROR_FILE_NOT_FOUND); + return GetInfo(pvFileInfo, cbFileInfo, &SignatureInfo.SignatureTypes, sizeof(DWORD), pcbLengthNeeded); + + case SFileMpqStrongSignatureOffset: + if(QueryMpqSignatureInfo(ha, &SignatureInfo) == false || (SignatureInfo.SignatureTypes & SIGNATURE_TYPE_STRONG) == 0) + return GetInfo_ReturdwErrCode(ERROR_FILE_NOT_FOUND); + return GetInfo(pvFileInfo, cbFileInfo, &SignatureInfo.EndMpqData, sizeof(ULONGLONG), pcbLengthNeeded); + + case SFileMpqStrongSignatureSize: + if(QueryMpqSignatureInfo(ha, &SignatureInfo) == false || (SignatureInfo.SignatureTypes & SIGNATURE_TYPE_STRONG) == 0) + return GetInfo_ReturdwErrCode(ERROR_FILE_NOT_FOUND); + dwInt32Value = MPQ_STRONG_SIGNATURE_SIZE + 4; + return GetInfo(pvFileInfo, cbFileInfo, &dwInt32Value, sizeof(DWORD), pcbLengthNeeded); + + case SFileMpqStrongSignature: + if(QueryMpqSignatureInfo(ha, &SignatureInfo) == false || (SignatureInfo.SignatureTypes & SIGNATURE_TYPE_STRONG) == 0) + return GetInfo_ReturdwErrCode(ERROR_FILE_NOT_FOUND); + return GetInfo(pvFileInfo, cbFileInfo, SignatureInfo.Signature, MPQ_STRONG_SIGNATURE_SIZE + 4, pcbLengthNeeded); + + case SFileMpqArchiveSize64: + return GetInfo(pvFileInfo, cbFileInfo, &pHeader->ArchiveSize64, sizeof(ULONGLONG), pcbLengthNeeded); + + case SFileMpqArchiveSize: + return GetInfo(pvFileInfo, cbFileInfo, &pHeader->dwArchiveSize, sizeof(DWORD), pcbLengthNeeded); + + case SFileMpqMaxFileCount: + return GetInfo(pvFileInfo, cbFileInfo, &ha->dwMaxFileCount, sizeof(DWORD), pcbLengthNeeded); + + case SFileMpqFileTableSize: + return GetInfo(pvFileInfo, cbFileInfo, &ha->dwFileTableSize, sizeof(DWORD), pcbLengthNeeded); + + case SFileMpqSectorSize: + return GetInfo(pvFileInfo, cbFileInfo, &ha->dwSectorSize, sizeof(DWORD), pcbLengthNeeded); + + case SFileMpqNumberOfFiles: + dwInt32Value = GetMpqFileCount(ha); + return GetInfo(pvFileInfo, cbFileInfo, &dwInt32Value, sizeof(DWORD), pcbLengthNeeded); + + case SFileMpqRawChunkSize: + if(pHeader->dwRawChunkSize == 0) + return GetInfo_ReturdwErrCode(ERROR_FILE_NOT_FOUND); + return GetInfo(pvFileInfo, cbFileInfo, &pHeader->dwRawChunkSize, sizeof(DWORD), pcbLengthNeeded); + + case SFileMpqStreamFlags: + FileStream_GetFlags(ha->pStream, &dwInt32Value); + return GetInfo(pvFileInfo, cbFileInfo, &dwInt32Value, sizeof(DWORD), pcbLengthNeeded); + + case SFileMpqFlags: + return GetInfo(pvFileInfo, cbFileInfo, &ha->dwFlags, sizeof(DWORD), pcbLengthNeeded); + + case SFileInfoPatchChain: + return GetInfo_PatchChain(hf, pvFileInfo, cbFileInfo, pcbLengthNeeded); + + case SFileInfoFileEntry: + if(pFileEntry == NULL) + return GetInfo_ReturdwErrCode(ERROR_FILE_NOT_FOUND); + return GetInfo_FileEntry(pvFileInfo, cbFileInfo, pFileEntry, pcbLengthNeeded); + + case SFileInfoHashEntry: + return GetInfo(pvFileInfo, cbFileInfo, hf->pHashEntry, sizeof(TMPQHash), pcbLengthNeeded); + + case SFileInfoHashIndex: + return GetInfo(pvFileInfo, cbFileInfo, &hf->dwHashIndex, sizeof(DWORD), pcbLengthNeeded); + + case SFileInfoNameHash1: + return GetInfo(pvFileInfo, cbFileInfo, &hf->pHashEntry->dwName1, sizeof(DWORD), pcbLengthNeeded); + + case SFileInfoNameHash2: + return GetInfo(pvFileInfo, cbFileInfo, &hf->pHashEntry->dwName2, sizeof(DWORD), pcbLengthNeeded); + + case SFileInfoNameHash3: + return GetInfo(pvFileInfo, cbFileInfo, &pFileEntry->FileNameHash, sizeof(ULONGLONG), pcbLengthNeeded); + + case SFileInfoLocale: + dwInt32Value = hf->pHashEntry->lcLocale; + return GetInfo(pvFileInfo, cbFileInfo, &dwInt32Value, sizeof(DWORD), pcbLengthNeeded); + + case SFileInfoFileIndex: + dwInt32Value = (DWORD)(pFileEntry - hf->ha->pFileTable); + return GetInfo(pvFileInfo, cbFileInfo, &dwInt32Value, sizeof(DWORD), pcbLengthNeeded); + + case SFileInfoByteOffset: + return GetInfo(pvFileInfo, cbFileInfo, &pFileEntry->ByteOffset, sizeof(ULONGLONG), pcbLengthNeeded); + + case SFileInfoFileTime: + return GetInfo(pvFileInfo, cbFileInfo, &pFileEntry->FileTime, sizeof(ULONGLONG), pcbLengthNeeded); + + case SFileInfoFileSize: + return GetInfo(pvFileInfo, cbFileInfo, &pFileEntry->dwFileSize, sizeof(DWORD), pcbLengthNeeded); + + case SFileInfoCompressedSize: + return GetInfo(pvFileInfo, cbFileInfo, &pFileEntry->dwCmpSize, sizeof(DWORD), pcbLengthNeeded); + + case SFileInfoFlags: + return GetInfo(pvFileInfo, cbFileInfo, &pFileEntry->dwFlags, sizeof(DWORD), pcbLengthNeeded); + + case SFileInfoEncryptionKey: + return GetInfo(pvFileInfo, cbFileInfo, &hf->dwFileKey, sizeof(DWORD), pcbLengthNeeded); + + case SFileInfoEncryptionKeyRaw: + dwInt32Value = hf->dwFileKey; + if(pFileEntry->dwFlags & MPQ_FILE_FIX_KEY) + dwInt32Value = (dwInt32Value ^ pFileEntry->dwFileSize) - (DWORD)hf->MpqFilePos; + return GetInfo(pvFileInfo, cbFileInfo, &dwInt32Value, sizeof(DWORD), pcbLengthNeeded); + + case SFileInfoCRC32: + return GetInfo(pvFileInfo, cbFileInfo, &hf->pFileEntry->dwCrc32, sizeof(DWORD), pcbLengthNeeded); + } + + // Invalid info class + return GetInfo_ReturdwErrCode(ERROR_INVALID_PARAMETER); +} + +bool WINAPI SFileFreeFileInfo(void * pvFileInfo, SFileInfoClass InfoClass) +{ + switch(InfoClass) + { + case SFileMpqHetTable: + FreeHetTable((TMPQHetTable *)pvFileInfo); + return true; + + case SFileMpqBetTable: + FreeBetTable((TMPQBetTable *)pvFileInfo); + return true; + + default: + break; + } + + SetLastError(ERROR_INVALID_PARAMETER); + return false; +} + +//----------------------------------------------------------------------------- +// Tries to retrieve the file name + +struct TFileHeader2Ext +{ + DWORD dwOffset00Data; // Required data at offset 00 (32-bits) + DWORD dwOffset00Mask; // Mask for data at offset 00 (32 bits). 0 = data are ignored + DWORD dwOffset04Data; // Required data at offset 04 (32-bits) + DWORD dwOffset04Mask; // Mask for data at offset 04 (32 bits). 0 = data are ignored + const char * szExt; // Supplied extension, if the condition is true +}; + +static TFileHeader2Ext data2ext[] = +{ + {0x00005A4D, 0x0000FFFF, 0x00000000, 0x00000000, "exe"}, // EXE files + {0x00000006, 0xFFFFFFFF, 0x00000001, 0xFFFFFFFF, "dc6"}, // EXE files + {0x1A51504D, 0xFFFFFFFF, 0x00000000, 0x00000000, "mpq"}, // MPQ archive header ID ('MPQ\x1A') + {0x46464952, 0xFFFFFFFF, 0x00000000, 0x00000000, "wav"}, // WAVE header 'RIFF' + {0x324B4D53, 0xFFFFFFFF, 0x00000000, 0x00000000, "smk"}, // Old "Smacker Video" files 'SMK2' + {0x694B4942, 0xFFFFFFFF, 0x00000000, 0x00000000, "bik"}, // Bink video files (new) + {0x0801050A, 0xFFFFFFFF, 0x00000000, 0x00000000, "pcx"}, // PCX images used in Diablo I + {0x544E4F46, 0xFFFFFFFF, 0x00000000, 0x00000000, "fnt"}, // Font files used in Diablo II + {0x6D74683C, 0xFFFFFFFF, 0x00000000, 0x00000000, "html"}, // HTML '<htm' + {0x4D54483C, 0xFFFFFFFF, 0x00000000, 0x00000000, "html"}, // HTML '<HTM + {0x216F6F57, 0xFFFFFFFF, 0x00000000, 0x00000000, "tbl"}, // Table files + {0x31504C42, 0xFFFFFFFF, 0x00000000, 0x00000000, "blp"}, // BLP textures + {0x32504C42, 0xFFFFFFFF, 0x00000000, 0x00000000, "blp"}, // BLP textures (v2) + {0x584C444D, 0xFFFFFFFF, 0x00000000, 0x00000000, "mdx"}, // MDX files + {0x45505954, 0xFFFFFFFF, 0x00000000, 0x00000000, "pud"}, // Warcraft II maps + {0x38464947, 0xFFFFFFFF, 0x00000000, 0x00000000, "gif"}, // GIF images 'GIF8' + {0x3032444D, 0xFFFFFFFF, 0x00000000, 0x00000000, "m2"}, // WoW ??? .m2 + {0x43424457, 0xFFFFFFFF, 0x00000000, 0x00000000, "dbc"}, // ??? .dbc + {0x47585053, 0xFFFFFFFF, 0x00000000, 0x00000000, "bls"}, // WoW pixel shaders + {0xE0FFD8FF, 0xFFFFFFFF, 0x00000000, 0x00000000, "jpg"}, // JPEG image + {0x503B4449, 0xFFFFFFFF, 0x3B4C5857, 0xFFFFFFFF, "slk"}, // SLK file (usually starts with "ID;PWXL;N;E") + {0x61754C1B, 0xFFFFFFFF, 0x00000000, 0x00000000, "lua"}, // Compiled LUA files + {0x20534444, 0xFFFFFFFF, 0x00000000, 0x00000000, "dds"}, // DDS textures + {0x43614C66, 0xFFFFFFFF, 0x00000000, 0x00000000, "flac"}, // FLAC sound files + {0x0000FBFF, 0x0000FFFF, 0x00000000, 0x00000000, "mp3"}, // MP3 sound files + {0x0000F3FF, 0x0000FFFF, 0x00000000, 0x00000000, "mp3"}, // MP3 sound files + {0x0000F2FF, 0x0000FFFF, 0x00000000, 0x00000000, "mp3"}, // MP3 sound files + {0x00334449, 0x00FFFFFF, 0x00000000, 0x00000000, "mp3"}, // MP3 sound files + {0x57334D48, 0xFFFFFFFF, 0x00000000, 0x00000000, "w3x"}, // Warcraft III map files, can also be w3m + {0x6F643357, 0xFFFFFFFF, 0x00000000, 0x00000000, "doo"}, // Warcraft III doodad files + {0x21453357, 0xFFFFFFFF, 0x00000000, 0x00000000, "w3e"}, // Warcraft III environment files + {0x5733504D, 0xFFFFFFFF, 0x00000000, 0x00000000, "wpm"}, // Warcraft III pathing map files + {0x21475457, 0xFFFFFFFF, 0x00000000, 0x00000000, "wtg"}, // Warcraft III trigger files + {0x00000000, 0x00000000, 0x00000000, 0x00000000, "xxx"}, // Default extension + {0, 0, 0, 0, NULL} // Terminator +}; + +static DWORD CreatePseudoFileName(HANDLE hFile, TFileEntry * pFileEntry, char * szFileName) +{ + TMPQFile * hf = (TMPQFile *)hFile; // MPQ File handle + DWORD FirstBytes[2] = {0, 0}; // The first 4 bytes of the file + DWORD dwBytesRead = 0; + DWORD dwFilePos; // Saved file position + char szPseudoName[20]; + + // Read the first 2 DWORDs bytes from the file + dwFilePos = SFileSetFilePointer(hFile, 0, NULL, FILE_CURRENT); + SFileReadFile(hFile, FirstBytes, sizeof(FirstBytes), &dwBytesRead, NULL); + SFileSetFilePointer(hFile, dwFilePos, NULL, FILE_BEGIN); + + // If we read at least 8 bytes + if(dwBytesRead == sizeof(FirstBytes)) + { + // Make sure that the array is properly BSWAP-ed + BSWAP_ARRAY32_UNSIGNED(FirstBytes, sizeof(FirstBytes)); + + // Try to guess file extension from those 2 DWORDs + for(size_t i = 0; data2ext[i].szExt != NULL; i++) + { + if((FirstBytes[0] & data2ext[i].dwOffset00Mask) == data2ext[i].dwOffset00Data && + (FirstBytes[1] & data2ext[i].dwOffset04Mask) == data2ext[i].dwOffset04Data) + { + // Format the pseudo-name + StringCreatePseudoFileName(szPseudoName, _countof(szPseudoName), (unsigned int)(pFileEntry - hf->ha->pFileTable), data2ext[i].szExt); + + // Save the pseudo-name in the file entry as well + AllocateFileName(hf->ha, pFileEntry, szPseudoName); + + // If the caller wants to copy the file name, do it + if(szFileName != NULL) + strcpy(szFileName, szPseudoName); + return ERROR_SUCCESS; + } + } + } + + return ERROR_CAN_NOT_COMPLETE; +} + +bool WINAPI SFileGetFileName(HANDLE hFile, char * szFileName) +{ + TMPQFile * hf = (TMPQFile *)hFile; // MPQ File handle + DWORD dwErrCode = ERROR_INVALID_HANDLE; + + // Check valid parameters + if(IsValidFileHandle(hFile)) + { + TFileEntry * pFileEntry = hf->pFileEntry; + + // For MPQ files, retrieve the file name from the file entry + if(hf->pStream == NULL) + { + if(pFileEntry != NULL) + { + // If the file name is not there yet, create a pseudo name + if(pFileEntry->szFileName == NULL) + dwErrCode = CreatePseudoFileName(hFile, pFileEntry, szFileName); + + // Copy the file name to the output buffer, if any + if(pFileEntry->szFileName && szFileName) + { + strcpy(szFileName, pFileEntry->szFileName); + dwErrCode = ERROR_SUCCESS; + } + } + } + + // For local files, copy the file name from the stream + else + { + if(szFileName != NULL) + { + const TCHAR * szStreamName = FileStream_GetFileName(hf->pStream); + StringCopy(szFileName, MAX_PATH, szStreamName); + } + dwErrCode = ERROR_SUCCESS; + } + } + + if(dwErrCode != ERROR_SUCCESS) + SetLastError(dwErrCode); + return (dwErrCode == ERROR_SUCCESS); +} + |
