📄 sfilereadfile.cpp
字号:
if(dwToCopy > dwToRead)
dwToCopy = dwToRead;
memcpy(pbBuffer, ha->pbBlockBuffer, dwToCopy);
dwBytesRead += dwToCopy;
ha->dwBuffPos = dwToCopy;
}
// Return what we've read
return dwBytesRead;
}
//-----------------------------------------------------------------------------
// SFileReadFile
// TODO: Test for archives > 4GB
BOOL WINAPI SFileReadFile(HANDLE hFile, VOID * lpBuffer, DWORD dwToRead, DWORD * pdwRead, LPOVERLAPPED lpOverlapped)
{
TMPQFile * hf = (TMPQFile *)hFile;
DWORD dwBytes = 0; // Number of bytes (for everything)
int nError = ERROR_SUCCESS;
// Zero the number of bytes read
if(pdwRead != NULL)
*pdwRead = 0;
// Check valid parameters
if(nError == ERROR_SUCCESS)
{
if(hf == NULL || lpBuffer == NULL)
nError = ERROR_INVALID_PARAMETER;
}
// If direct access to the file, use Win32 for reading
if(nError == ERROR_SUCCESS && hf->hFile != INVALID_HANDLE_VALUE)
{
DWORD dwTransferred;
ReadFile(hf->hFile, lpBuffer, dwToRead, &dwTransferred, lpOverlapped);
if(dwTransferred < dwToRead)
{
SetLastError(ERROR_HANDLE_EOF);
return FALSE;
}
if(pdwRead != NULL)
*pdwRead = dwTransferred;
return TRUE;
}
// Read all the bytes available in the buffer (If any)
if(nError == ERROR_SUCCESS)
{
if(dwToRead > 0)
{
dwBytes = ReadMPQFile(hf, hf->dwFilePos, (BYTE *)lpBuffer, dwToRead);
if(dwBytes == (DWORD)-1)
{
SetLastError(ERROR_CAN_NOT_COMPLETE);
return FALSE;
}
hf->ha->pLastFile = hf;
hf->dwFilePos += dwBytes;
}
if(pdwRead != NULL)
*pdwRead = dwBytes;
}
// Check number of bytes read. If not OK, return FALSE.
if(dwBytes < dwToRead)
{
SetLastError(ERROR_HANDLE_EOF);
return FALSE;
}
return TRUE;
}
//-----------------------------------------------------------------------------
// SFileGetFilePos
//
// Returns position of archive file in the archive (relative to begin of file)
// TODO: Test for archives > 4GB
DWORD WINAPI SFileGetFilePos(HANDLE hFile, DWORD * pdwFilePosHigh)
{
TMPQFile * hf = (TMPQFile *)hFile;
if(pdwFilePosHigh != NULL)
*pdwFilePosHigh = 0;
if(hf == NULL)
{
SetLastError(ERROR_INVALID_PARAMETER);
return (DWORD)-1;
}
// If opened as plain file, ...
if(hf->hFile != INVALID_HANDLE_VALUE)
return 0;
// If opened from archive, return file size
if(pdwFilePosHigh != NULL)
*pdwFilePosHigh = hf->MpqFilePos.HighPart;
return hf->MpqFilePos.LowPart;
}
//-----------------------------------------------------------------------------
// SFileGetFileSize
// TODO: Test for archives > 4GB
DWORD WINAPI SFileGetFileSize(HANDLE hFile, DWORD * pdwFileSizeHigh)
{
TMPQFile * hf = (TMPQFile *)hFile;
if(pdwFileSizeHigh != NULL)
*pdwFileSizeHigh = 0;
if(hf == NULL)
{
SetLastError(ERROR_INVALID_PARAMETER);
return (DWORD)-1;
}
// If opened as plain file, ...
if(hf->hFile != INVALID_HANDLE_VALUE)
return GetFileSize(hf->hFile, pdwFileSizeHigh);
// If opened from archive, return file size
return hf->pBlock->dwFSize;
}
// TODO: Test for archives > 4GB
DWORD WINAPI SFileSetFilePointer(HANDLE hFile, LONG lFilePos, LONG * pdwFilePosHigh, DWORD dwMethod)
{
TMPQArchive * ha;
TMPQFile * hf = (TMPQFile *)hFile;
if(hf == NULL || (pdwFilePosHigh != NULL && *pdwFilePosHigh != 0))
{
SetLastError(ERROR_INVALID_PARAMETER);
return (DWORD)-1;
}
// If opened as plain file, call Win32 API
if(hf->hFile != INVALID_HANDLE_VALUE)
return SetFilePointer(hf->hFile, lFilePos, pdwFilePosHigh, dwMethod);
ha = hf->ha;
switch(dwMethod)
{
case FILE_BEGIN:
// Cannot set pointer before begin of file
if(-lFilePos > (LONG)hf->dwFilePos)
hf->dwFilePos = 0;
else
hf->dwFilePos = lFilePos;
break;
case FILE_CURRENT:
// Cannot set pointer before begin of file
if(-lFilePos > (LONG)hf->dwFilePos)
hf->dwFilePos = 0;
else
hf->dwFilePos += lFilePos;
break;
case FILE_END:
// Cannot set file position before begin of file
if(-lFilePos >= (LONG)hf->pBlock->dwFSize)
hf->dwFilePos = 0;
else
hf->dwFilePos = hf->pBlock->dwFSize + lFilePos;
break;
default:
return ERROR_INVALID_PARAMETER;
}
if(hf == ha->pLastFile && (hf->dwFilePos & ~(ha->dwBlockSize - 1)) == ha->dwBlockPos)
ha->dwBuffPos = hf->dwFilePos & (ha->dwBlockSize - 1);
else
{
ha->pLastFile = NULL;
ha->dwBuffPos = 0;
}
return hf->dwFilePos;
}
//-----------------------------------------------------------------------------
// Tries to retrieve the file name
static TID2Ext id2ext[] =
{
{0x1A51504D, "mpq"}, // MPQ archive header ID ('MPQ\x1A')
{0x46464952, "wav"}, // WAVE header 'RIFF'
{0x324B4D53, "smk"}, // Old "Smacker Video" files 'SMK2'
{0x694B4942, "bik"}, // Bink video files (new)
{0x0801050A, "pcx"}, // PCX images used in Diablo I
{0x544E4F46, "fnt"}, // Font files used in Diablo II
{0x6D74683C, "html"}, // HTML '<htm'
{0x4D54483C, "html"}, // HTML '<HTM
{0x216F6F57, "tbl"}, // Table files
{0x31504C42, "blp"}, // BLP textures
{0x32504C42, "blp"}, // BLP textures (v2)
{0x584C444D, "mdx"}, // MDX files
{0x45505954, "pud"}, // Warcraft II maps
{0x38464947, "gif"}, // GIF images 'GIF8'
{0x3032444D, "m2"}, // WoW ??? .m2
{0x43424457, "dbc"}, // ??? .dbc
{0x47585053, "bls"}, // WoW pixel shaders
{0, NULL} // Terminator
};
// TODO: Test for archives > 4GB
BOOL WINAPI SFileGetFileName(HANDLE hFile, char * szFileName)
{
TMPQFile * hf = (TMPQFile *)hFile; // MPQ File handle
char * szExt = "xxx"; // Default extension
DWORD dwFirstBytes[2]; // The first 4 bytes of the file
DWORD dwFilePos; // Saved file position
int nError = ERROR_SUCCESS;
int i;
// Pre-zero the output buffer
if(szFileName != NULL)
*szFileName = 0;
// Check valid parameters
if(nError == ERROR_SUCCESS)
{
if(hf == NULL || szFileName == NULL)
nError = ERROR_INVALID_PARAMETER;
}
// If the file name is already filled, return it.
if(nError == ERROR_SUCCESS && *hf->szFileName != 0)
{
if(szFileName != hf->szFileName)
strcpy(szFileName, hf->szFileName);
return TRUE;
}
if(nError == ERROR_SUCCESS)
{
if(hf->dwFileIndex == (DWORD)-1)
nError = ERROR_CAN_NOT_COMPLETE;
}
// Read the first 8 bytes from the file
if(nError == ERROR_SUCCESS)
{
dwFirstBytes[0] = dwFirstBytes[1] = 0;
dwFilePos = SFileSetFilePointer(hf, 0, NULL, FILE_CURRENT);
if(!SFileReadFile(hFile, &dwFirstBytes, sizeof(dwFirstBytes), NULL))
nError = GetLastError();
BSWAP_ARRAY32_UNSIGNED(dwFirstBytes, sizeof(dwFirstBytes) / sizeof(DWORD));
SFileSetFilePointer(hf, dwFilePos, NULL, FILE_BEGIN);
}
if(nError == ERROR_SUCCESS)
{
if((dwFirstBytes[0] & 0x0000FFFF) == ID_EXE)
szExt = "exe";
else if(dwFirstBytes[0] == 0x00000006 && dwFirstBytes[1] == 0x00000001)
szExt = "dc6";
else
{
for(i = 0; id2ext[i].szExt != NULL; i++)
{
if(id2ext[i].dwID == dwFirstBytes[0])
{
szExt = id2ext[i].szExt;
break;
}
}
}
// Create the file name
sprintf(hf->szFileName, "File%08lu.%s", hf->dwFileIndex, szExt);
if(szFileName != hf->szFileName)
strcpy(szFileName, hf->szFileName);
}
return (nError == ERROR_SUCCESS);
}
//-----------------------------------------------------------------------------
// Retrieves an information about an archive or about a file within the archive
//
// hMpqOrFile - Handle to an MPQ archive or to a file
// dwInfoType - Information to obtain
// TODO: Test for archives > 4GB
DWORD_PTR WINAPI SFileGetFileInfo(HANDLE hMpqOrFile, DWORD dwInfoType)
{
TMPQArchive * ha = (TMPQArchive *)hMpqOrFile;
TMPQFile * hf = (TMPQFile *)hMpqOrFile;
TMPQBlock * pBlockEnd;
TMPQBlock * pBlock;
DWORD dwFileCount = 0;
DWORD dwSeed;
switch(dwInfoType)
{
case SFILE_INFO_ARCHIVE_SIZE:
if(IsValidMpqHandle(ha))
return ha->pHeader->dwArchiveSize;
break;
case SFILE_INFO_HASH_TABLE_SIZE: // Size of the hash table
if(IsValidMpqHandle(ha))
return ha->pHeader->dwHashTableSize;
break;
case SFILE_INFO_BLOCK_TABLE_SIZE: // Size of the hash table
if(IsValidMpqHandle(ha))
return ha->pHeader->dwBlockTableSize;
break;
case SFILE_INFO_BLOCK_SIZE:
if(IsValidMpqHandle(ha))
return ha->dwBlockSize;
break;
case SFILE_INFO_HASH_TABLE:
if(IsValidMpqHandle(ha))
return (DWORD_PTR)ha->pHashTable;
break;
case SFILE_INFO_BLOCK_TABLE:
if(IsValidMpqHandle(ha))
return (DWORD_PTR)ha->pBlockTable;
break;
case SFILE_INFO_NUM_FILES:
if(IsValidMpqHandle(ha))
{
pBlockEnd = ha->pBlockTable + ha->pHeader->dwBlockTableSize;
for(pBlock = ha->pBlockTable; pBlock < pBlockEnd; pBlock++)
{
if(pBlock->dwFlags & MPQ_FILE_EXISTS)
dwFileCount++;
}
return dwFileCount;
}
break;
case SFILE_INFO_HASH_INDEX:
if(IsValidFileHandle(hf))
return hf->dwHashIndex;
break;
case SFILE_INFO_CODENAME1:
if(IsValidFileHandle(hf))
return hf->pHash->dwName1;
break;
case SFILE_INFO_CODENAME2:
if(IsValidFileHandle(hf))
return hf->pHash->dwName2;
break;
case SFILE_INFO_LOCALEID:
if(IsValidFileHandle(hf))
return hf->pHash->lcLocale;
break;
case SFILE_INFO_BLOCKINDEX:
if(IsValidFileHandle(hf))
return hf->dwFileIndex;
break;
case SFILE_INFO_FILE_SIZE:
if(IsValidFileHandle(hf))
return hf->pBlock->dwFSize;
break;
case SFILE_INFO_COMPRESSED_SIZE:
if(IsValidFileHandle(hf))
return hf->pBlock->dwCSize;
break;
case SFILE_INFO_FLAGS:
if(IsValidFileHandle(hf))
return hf->pBlock->dwFlags;
break;
case SFILE_INFO_POSITION:
if(IsValidFileHandle(hf))
return hf->pBlock->dwFilePos;
break;
case SFILE_INFO_SEED:
if(IsValidFileHandle(hf))
return hf->dwSeed1;
break;
case SFILE_INFO_SEED_UNFIXED:
if(IsValidFileHandle(hf))
{
dwSeed = hf->dwSeed1;
if(hf->pBlock->dwFlags & MPQ_FILE_FIXSEED)
dwSeed = (dwSeed ^ hf->pBlock->dwFSize) - (DWORD)(hf->MpqFilePos.QuadPart - hf->ha->MpqPos.QuadPart);
return dwSeed;
}
break;
}
// Unknown parameter or invalid handle
SetLastError(ERROR_INVALID_PARAMETER);
return 0xFFFFFFFF;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -