DWORD WINAPI CascGetFileSize(HANDLE hFile, PDWORD pdwFileSizeHigh) { TCascFile * hf; int nError; CASCLIB_UNUSED(pdwFileSizeHigh); // Validate the file handle if((hf = IsValidFileHandle(hFile)) == NULL) { SetLastError(ERROR_INVALID_HANDLE); return CASC_INVALID_SIZE; } // Make sure that the file header area is loaded nError = EnsureHeaderAreaIsLoaded(hf); if(nError != ERROR_SUCCESS) { SetLastError(nError); return CASC_INVALID_SIZE; } // Give the file size to the caller if(pdwFileSizeHigh != NULL) *pdwFileSizeHigh = 0; return hf->FileSize; }
bool WINAPI SFileSetFileLocale(HANDLE hFile, LCID lcNewLocale) { TMPQArchive * ha; TFileEntry * pFileEntry; TMPQFile * hf = IsValidFileHandle(hFile); // Invalid handle => do nothing if(hf == NULL) { SetLastError(ERROR_INVALID_HANDLE); return false; } // Do not allow to rename files in MPQ open for read only ha = hf->ha; if(ha->dwFlags & MPQ_FLAG_READ_ONLY) { SetLastError(ERROR_ACCESS_DENIED); return false; } // Do not allow unnamed access if(hf->pFileEntry->szFileName == NULL) { SetLastError(ERROR_CAN_NOT_COMPLETE); return false; } // Do not allow to change locale of any internal file if(IsInternalMpqFileName(hf->pFileEntry->szFileName)) { SetLastError(ERROR_INTERNAL_FILE); return false; } // Do not allow changing file locales if there is no hash table if(hf->pHashEntry == NULL) { SetLastError(ERROR_NOT_SUPPORTED); return false; } // We have to check if the file+locale is not already there pFileEntry = GetFileEntryExact(ha, hf->pFileEntry->szFileName, lcNewLocale, NULL); if(pFileEntry != NULL) { SetLastError(ERROR_ALREADY_EXISTS); return false; } // Update the locale in the hash table entry hf->pHashEntry->lcLocale = (USHORT)lcNewLocale; ha->dwFlags |= MPQ_FLAG_CHANGED; return true; }
static void DumpIndexKey( FILE * fp, TCascStorage * hs, LPBYTE pbIndexKey, int nDumpLevel) { PCASC_INDEX_ENTRY pIndexEntry; TCascFile * hf; QUERY_KEY QueryKey; HANDLE hFile; BYTE HeaderArea[MAX_HEADER_AREA_SIZE]; char szBuffer[0x20]; QueryKey.pbData = pbIndexKey; QueryKey.cbData = MD5_HASH_SIZE; pIndexEntry = FindIndexEntry(hs, &QueryKey); if(pIndexEntry != NULL) { ULONGLONG FileOffset = ConvertBytesToInteger_5(pIndexEntry->FileOffsetBE); DWORD ArchIndex = (DWORD)(FileOffset >> 0x1E); DWORD FileSize = ConvertBytesToInteger_4_LE(pIndexEntry->FileSizeLE); // Mask the file offset FileOffset &= 0x3FFFFFFF; fprintf(fp, " data.%03u at 0x%08x (0x%lx bytes)\n", ArchIndex, (DWORD)FileOffset, FileSize); if(nDumpLevel > 2) { QueryKey.pbData = pIndexEntry->IndexKey; QueryKey.cbData = MD5_HASH_SIZE; if(CascOpenFileByIndexKey((HANDLE)hs, &QueryKey, 0, &hFile)) { // Make sure that the data file is open and frame header loaded CascGetFileSize(hFile, NULL); hf = IsValidFileHandle(hFile); assert(hf->pStream != NULL); // Read the header area FileOffset = hf->HeaderOffset - BLTE_HEADER_DELTA; FileStream_Read(hf->pStream, &FileOffset, HeaderArea, sizeof(HeaderArea)); CascCloseFile(hFile); // Dump the header area fprintf(fp, " FileSize: %X Rest: %s\n", ConvertBytesToInteger_4_LE(&HeaderArea[0x10]), StringFromBinary(&HeaderArea[0x14], 10, szBuffer)); } } }
bool WINAPI SFileCloseFile(HANDLE hFile) { TMPQFile * hf = (TMPQFile *)hFile; if (!IsValidFileHandle(hf)) { SetLastError(ERROR_INVALID_HANDLE); return false; } // Free the structure FreeMPQFile(hf); return true; }
bool WINAPI SFileGetFileName(HANDLE hFile, char * szFileName) { TMPQFile * hf = (TMPQFile *)hFile; // MPQ File handle int nError = ERROR_INVALID_HANDLE; // Pre-zero the output buffer if(szFileName != NULL) *szFileName = 0; // 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) { nError = CreatePseudoFileName(hFile, pFileEntry, szFileName); } else { if(szFileName != NULL) strcpy(szFileName, pFileEntry->szFileName); nError = ERROR_SUCCESS; } } } // For local files, copy the file name from the stream else { if(szFileName != NULL) { const TCHAR * szStreamName = FileStream_GetFileName(hf->pStream); CopyFileName(szFileName, szStreamName, _tcslen(szStreamName)); } nError = ERROR_SUCCESS; } } if(nError != ERROR_SUCCESS) SetLastError(nError); return (nError == ERROR_SUCCESS); }
bool WINAPI SFileSetFileLocale(HANDLE hFile, LCID lcNewLocale) { TMPQArchive * ha; TMPQFile * hf = (TMPQFile *)hFile; TMPQHash * pHashEnd; TMPQHash * pHash; // Invalid handle => do nothing if(!IsValidFileHandle(hf)) { SetLastError(ERROR_INVALID_HANDLE); return false; } // Do not allow to change locale of any internal file if(IsInternalMpqFileName(hf->szFileName)) { SetLastError(ERROR_INTERNAL_FILE); return false; } // Do not allow to rename files in MPQ open for read only ha = hf->ha; if(ha->dwFlags & MPQ_FLAG_READ_ONLY) { SetLastError(ERROR_ACCESS_DENIED); return false; } // If the file already has that locale, return OK if(hf->pHash->lcLocale == lcNewLocale) return true; // We have to check if the file+locale is not already there pHashEnd = ha->pHashTable + ha->pHeader->dwHashTableSize; for(pHash = ha->pHashTable; pHash < pHashEnd; pHash++) { if(pHash->dwName1 == hf->pHash->dwName1 && pHash->dwName2 == hf->pHash->dwName2 && pHash->lcLocale == lcNewLocale) { SetLastError(ERROR_ALREADY_EXISTS); return false; } } // Set the locale and return success hf->pHash->lcLocale = (USHORT)lcNewLocale; hf->ha->dwFlags |= MPQ_FLAG_CHANGED; return true; }
bool WINAPI SFileWriteFile( HANDLE hFile, const void * pvData, DWORD dwSize, DWORD dwCompression) { TMPQFile * hf = (TMPQFile *)hFile; int nError = ERROR_SUCCESS; // Check the proper parameters if(!IsValidFileHandle(hf)) nError = ERROR_INVALID_HANDLE; if(hf->bIsWriteHandle == false) nError = ERROR_INVALID_HANDLE; // Special checks for single unit files if(nError == ERROR_SUCCESS && (hf->pBlock->dwFlags & MPQ_FILE_SINGLE_UNIT)) { // // Note: Blizzard doesn't support single unit files // that are stored as encrypted or imploded. We will allow them here, // the calling application must ensure that such flag combination doesn't get here // // if(dwFlags & MPQ_FILE_IMPLODE) // nError = ERROR_INVALID_PARAMETER; // // if(dwFlags & MPQ_FILE_ENCRYPTED) // nError = ERROR_INVALID_PARAMETER; // Lossy compression is not allowed on single unit files if(dwCompression & LOSSY_COMPRESSION_MASK) nError = ERROR_INVALID_PARAMETER; } // Write the data to the file if(nError == ERROR_SUCCESS) nError = SFileAddFile_Write(hf, pvData, dwSize, dwCompression); // Deal with errors if(nError != ERROR_SUCCESS) SetLastError(nError); return (nError == ERROR_SUCCESS); }
BOOL WINAPI SFileSetFileLocale(HANDLE hFile, LCID lcNewLocale) { TMPQFile * hf = (TMPQFile *)hFile; // Invalid handle => do nothing if(IsValidFileHandle(hf) == FALSE || IsValidMpqHandle(hf->ha) == FALSE) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } // If the file has not been open for writing, do nothing. if(hf->ha->pListFile == NULL) return ERROR_ACCESS_DENIED; hf->pHash->lcLocale = (USHORT)lcNewLocale; hf->ha->dwFlags |= MPQ_FLAG_CHANGED; return TRUE; }
bool WINAPI SFileFinishFile(HANDLE hFile) { TMPQFile * hf = (TMPQFile *)hFile; int nError = ERROR_SUCCESS; // Check the proper parameters if(!IsValidFileHandle(hf)) nError = ERROR_INVALID_HANDLE; if(hf->bIsWriteHandle == false) nError = ERROR_INVALID_HANDLE; // Finish the file if(nError == ERROR_SUCCESS) nError = SFileAddFile_Finish(hf); // Deal with errors if(nError != ERROR_SUCCESS) SetLastError(nError); return (nError == ERROR_SUCCESS); }
int EXPORT_SYMBOL SFileGetFileName(void * hFile, char * szFileName) { TMPQFile * hf = (TMPQFile *)hFile; /* MPQ File handle */ int nError = 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) nError = CreatePseudoFileName(hFile, pFileEntry, szFileName); /* Copy the file name to the output buffer, if any */ if(pFileEntry->szFileName && szFileName) strcpy(szFileName, pFileEntry->szFileName); } } /* For local files, copy the file name from the stream */ else { if(szFileName != NULL) { const char * szStreamName = FileStream_GetFileName(hf->pStream); CopyFileName(szFileName, szStreamName, strlen(szStreamName)); } nError = ERROR_SUCCESS; } } if(nError != ERROR_SUCCESS) SetLastError(nError); return (nError == ERROR_SUCCESS); }
/////////////////////////////////////////////////////////////////////////////// // Compare BOOL CXZipTestDlg::Compare(LPCTSTR lpszFile1, LPCTSTR lpszFile2, BOOL *pbResult) { _ASSERTE(pbResult); if (!pbResult) return FALSE; *pbResult = FALSE; BOOL bCompare = FALSE; // TRUE = files identical // FALSE = files not identical BOOL bOp = TRUE; // TRUE = no API failures, compare completed // FALSE = file or memory API failed _ASSERTE(lpszFile1); _ASSERTE(lpszFile1[0] != _T('\0')); if (!lpszFile1 || lpszFile1[0] == _T('\0')) return FALSE; _ASSERTE(lpszFile2); _ASSERTE(lpszFile2[0] != _T('\0')); if (!lpszFile2 || lpszFile2[0] == _T('\0')) return FALSE; HANDLE hFile1 = NULL, hFile2 = NULL; TRACE(_T("opening '%s'"), lpszFile1); // open file 1 hFile1 = ::CreateFile(lpszFile1, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile1 == INVALID_HANDLE_VALUE) { TRACE(_T("ERROR: %s failed\n"), _T("CreateFile")); return FALSE; } TRACE(_T("opening '%s'"), lpszFile2); // open file 2 hFile2 = ::CreateFile(lpszFile2, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile2 == INVALID_HANDLE_VALUE) { TRACE(_T("ERROR: %s failed\n"), _T("CreateFile")); ::CloseHandle(hFile1); return FALSE; } DWORD dwFileSize1 = ::GetFileSize(hFile1, NULL); DWORD dwFileSize2 = ::GetFileSize(hFile2, NULL); if ((dwFileSize1 != INVALID_FILE_SIZE) && (dwFileSize2 != INVALID_FILE_SIZE)) { // continue if file sizes match if (dwFileSize1 == dwFileSize2) { BYTE * pBuf1 = new BYTE [COMPARE_BUF_SIZE]; _ASSERTE(pBuf1); BYTE * pBuf2 = new BYTE [COMPARE_BUF_SIZE]; _ASSERTE(pBuf2); if (pBuf1 && pBuf2) { while (dwFileSize1) { DWORD dwBytesRead1 = 0; BOOL bRet1 = ::ReadFile(hFile1, (LPVOID) pBuf1, COMPARE_BUF_SIZE, &dwBytesRead1, NULL); if (!bRet1) { TRACE(_T("ERROR: %s failed\n"), _T("ReadFile")); bOp = FALSE; break; } DWORD dwBytesRead2 = 0; BOOL bRet2 = ::ReadFile(hFile2, (LPVOID) pBuf2, COMPARE_BUF_SIZE, &dwBytesRead2, NULL); if (!bRet2) { TRACE(_T("ERROR: %s failed\n"), _T("ReadFile")); bOp = FALSE; break; } if (dwBytesRead1 != dwBytesRead2) { TRACE(_T("Compare failed ==> file Read sizes different\n")); break; } if (dwBytesRead1 == 0) { // Read ok, but nothing read TRACE(_T("Read %s ==> EOF reached.\n"), lpszFile1); bCompare = TRUE; break; } if (dwBytesRead2 == 0) { // Read ok, but nothing read TRACE(_T("Read %s ==> EOF reached.\n"), lpszFile2); bCompare = TRUE; break; } // do contents match? int nCmp = memcmp(pBuf1, pBuf2, dwBytesRead1); if (nCmp != 0) { TRACE(_T("Compare failed ==> file contents different\n")); break; } dwFileSize1 -= dwBytesRead1; } // while (dwFileSize1) if (dwFileSize1 == 0) bCompare = TRUE; if (pBuf1) delete [] pBuf1; if (pBuf2) delete [] pBuf2; } else { // memory allocation failed TRACE(_T("ERROR: memory allocation failure\n")); bOp = FALSE; } } else { TRACE(_T("Compare failed ==> file sizes different\n")); } } else { // GetFileSize failed TRACE(_T("ERROR: %s failed\n"), _T("GetFileSize")); bOp = FALSE; } if (IsValidFileHandle(hFile1)) ::CloseHandle(hFile1); if (IsValidFileHandle(hFile2)) ::CloseHandle(hFile2); *pbResult = bCompare; return bOp; }
bool WINAPI SFileReadFile(HANDLE hFile, void * pvBuffer, DWORD dwToRead, LPDWORD pdwRead, LPOVERLAPPED lpOverlapped) { TMPQFile * hf = (TMPQFile *)hFile; DWORD dwBytesRead = 0; // Number of bytes read int nError = ERROR_SUCCESS; // Always zero the result if(pdwRead != NULL) *pdwRead = 0; lpOverlapped = lpOverlapped; // Check valid parameters if(!IsValidFileHandle(hFile)) { SetLastError(ERROR_INVALID_HANDLE); return false; } if(pvBuffer == NULL) { SetLastError(ERROR_INVALID_PARAMETER); return false; } // If we didn't load the patch info yet, do it now if(hf->pFileEntry != NULL && (hf->pFileEntry->dwFlags & MPQ_FILE_PATCH_FILE) && hf->pPatchInfo == NULL) { nError = AllocatePatchInfo(hf, true); if(nError != ERROR_SUCCESS || hf->pPatchInfo == NULL) { SetLastError(nError); return false; } } // Clear the last used compression hf->dwCompression0 = 0; // If the file is local file, read the data directly from the stream if(hf->pStream != NULL) { nError = ReadMpqFileLocalFile(hf, pvBuffer, hf->dwFilePos, dwToRead, &dwBytesRead); } // If the file is a patch file, we have to read it special way else if(hf->hfPatch != NULL && (hf->pFileEntry->dwFlags & MPQ_FILE_PATCH_FILE) == 0) { nError = ReadMpqFilePatchFile(hf, pvBuffer, hf->dwFilePos, dwToRead, &dwBytesRead); } // If the archive is a MPK archive, we need special way to read the file else if(hf->ha->dwSubType == MPQ_SUBTYPE_MPK) { nError = ReadMpkFileSingleUnit(hf, pvBuffer, hf->dwFilePos, dwToRead, &dwBytesRead); } // If the file is single unit file, redirect it to read file else if(hf->pFileEntry->dwFlags & MPQ_FILE_SINGLE_UNIT) { nError = ReadMpqFileSingleUnit(hf, pvBuffer, hf->dwFilePos, dwToRead, &dwBytesRead); } // Otherwise read it as sector based MPQ file else { nError = ReadMpqFileSectorFile(hf, pvBuffer, hf->dwFilePos, dwToRead, &dwBytesRead); } // Increment the file position hf->dwFilePos += dwBytesRead; // Give the caller the number of bytes read if(pdwRead != NULL) *pdwRead = dwBytesRead; // If the read operation succeeded, but not full number of bytes was read, // set the last error to ERROR_HANDLE_EOF if(nError == ERROR_SUCCESS && (dwBytesRead < dwToRead)) nError = ERROR_HANDLE_EOF; // If something failed, set the last error value if(nError != ERROR_SUCCESS) SetLastError(nError); return (nError == ERROR_SUCCESS); }
bool WINAPI SFileReadFile(HANDLE hFile, void * pvBuffer, DWORD dwToRead, LPDWORD pdwRead, LPOVERLAPPED lpOverlapped) { TMPQFile * hf = (TMPQFile *)hFile; DWORD dwBytesRead = 0; // Number of bytes read int nError = ERROR_SUCCESS; // Keep compilers happy lpOverlapped = lpOverlapped; // Check valid parameters if(!IsValidFileHandle(hf)) { SetLastError(ERROR_INVALID_HANDLE); return false; } if(pvBuffer == NULL) { SetLastError(ERROR_INVALID_PARAMETER); return false; } // If the file is local file, read the data directly from the stream if(hf->pStream != NULL) { ULONGLONG FilePosition1; ULONGLONG FilePosition2; // Because stream I/O functions are designed to read // "all or nothing", we compare file position before and after, // and if they differ, we assume that number of bytes read // is the difference between them FileStream_GetPos(hf->pStream, FilePosition1); if(!FileStream_Read(hf->pStream, NULL, pvBuffer, dwToRead)) { // If not all bytes have been read, then return the number // of bytes read if((nError = GetLastError()) == ERROR_HANDLE_EOF) { FileStream_GetPos(hf->pStream, FilePosition2); dwBytesRead = (DWORD)(FilePosition2 - FilePosition1); } else { nError = GetLastError(); } } else { dwBytesRead = dwToRead; } } else { // If the file is a patch file, we have to read it special way if(hf->hfPatchFile != NULL && (hf->pFileEntry->dwFlags & MPQ_FILE_PATCH_FILE) == 0) { nError = ReadMpqFilePatchFile(hf, pvBuffer, dwToRead, &dwBytesRead); } // If the file is single unit file, redirect it to read file else if(hf->pFileEntry->dwFlags & MPQ_FILE_SINGLE_UNIT) { nError = ReadMpqFileSingleUnit(hf, pvBuffer, dwToRead, &dwBytesRead); } // Otherwise read it as sector based MPQ file else { nError = ReadMpqFile(hf, pvBuffer, dwToRead, &dwBytesRead); } } // Give the caller the number of bytes read if(pdwRead != NULL) *pdwRead = dwBytesRead; // If the read operation succeeded, but not full number of bytes was read, // set the last error to ERROR_HANDLE_EOF if(nError == ERROR_SUCCESS && (dwBytesRead < dwToRead)) nError = ERROR_HANDLE_EOF; // If something failed, set the last error value if(nError != ERROR_SUCCESS) SetLastError(nError); return (nError == ERROR_SUCCESS); }
bool WINAPI CascReadFile(HANDLE hFile, void * pvBuffer, DWORD dwBytesToRead, PDWORD pdwBytesRead) { PCASC_FILE_FRAME pFrame = NULL; ULONGLONG StreamSize; ULONGLONG FileOffset; TCascFile * hf; LPBYTE pbBuffer = (LPBYTE)pvBuffer; DWORD dwStartPointer = 0; DWORD dwFilePointer = 0; DWORD dwEndPointer = 0; DWORD dwFrameSize; bool bReadResult; 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 frames are not loaded yet, do it now if(nError == ERROR_SUCCESS) { nError = EnsureFrameHeadersLoaded(hf); } // If the file position is at or beyond end of file, do nothing if(nError == ERROR_SUCCESS && hf->FilePointer >= hf->FileSize) { *pdwBytesRead = 0; return ERROR_SUCCESS; } // Find the file frame where to read from if(nError == ERROR_SUCCESS) { // Get the frame pFrame = FindFileFrame(hf, hf->FilePointer); if(pFrame == NULL || pFrame->CompressedSize < 1) 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 pbFrameData = 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 pbFrameData = CASC_ALLOC(BYTE, pFrame->CompressedSize); if(pbFrameData == NULL) { nError = ERROR_NOT_ENOUGH_MEMORY; break; } // Load the raw file data to memory FileOffset = pFrame->FrameArchiveOffset; bReadResult = FileStream_Read(hf->pStream, &FileOffset, pbFrameData, pFrame->CompressedSize); // Note: The raw file data size could be less than expected // Happened in WoW build 19342 with the ROOT file. MD5 in the frame header // is zeroed, which means it should not be checked // Frame File: data.029 // Frame Offs: 0x013ED9F0 size 0x01325B32 // Frame End: 0x02713522 // File Size: 0x027134FC if(bReadResult == false && GetLastError() == ERROR_HANDLE_EOF && !IsValidMD5(pFrame->md5)) { // Get the size of the remaining file FileStream_GetSize(hf->pStream, &StreamSize); dwFrameSize = (DWORD)(StreamSize - FileOffset); // If the frame offset is before EOF and frame end is beyond EOF, correct it if(FileOffset < StreamSize && dwFrameSize < pFrame->CompressedSize) { memset(pbFrameData + dwFrameSize, 0, (pFrame->CompressedSize - dwFrameSize)); bReadResult = true; } } // If the read result failed, we cannot finish reading it if(bReadResult && VerifyDataBlockHash(pbFrameData, pFrame->CompressedSize, pFrame->md5)) { // Convert the source frame to the file cache nError = ProcessFileFrame(hf->pbFileCache, pFrame->FrameSize, pbFrameData, pFrame->CompressedSize, (DWORD)(pFrame - hf->pFrames)); if(nError == ERROR_SUCCESS) { // Set the start and end of the cache hf->CacheStart = dwFrameStart; hf->CacheEnd = dwFrameEnd; } } else { nError = ERROR_FILE_CORRUPT; } // Free the raw frame data CASC_FREE(pbFrameData); } // 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); }
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 frames are not loaded yet, do it now if(nError == ERROR_SUCCESS) { nError = EnsureFrameHeadersLoaded(hf); } // If the file position is at or beyond end of file, do nothing if(nError == ERROR_SUCCESS && hf->FilePointer >= hf->FileSize) { *pdwBytesRead = 0; return ERROR_SUCCESS; } // 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(!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); }
bool WINAPI SFileGetFileInfo( HANDLE hMpqOrFile, SFileInfoClass InfoClass, void * pvFileInfo, DWORD cbFileInfo, LPDWORD pcbLengthNeeded) { MPQ_SIGNATURE_INFO SignatureInfo; TMPQArchive * ha = NULL; TFileEntry * pFileEntry = NULL; ULONGLONG Int64Value = 0; ULONGLONG ByteOffset = 0; TMPQHash * pHash; TMPQFile * hf = NULL; void * pvSrcFileInfo = NULL; DWORD cbSrcFileInfo = 0; DWORD dwInt32Value = 0; int nInfoType = SFILE_INFO_TYPE_INVALID_HANDLE; int nError = ERROR_SUCCESS; switch(InfoClass) { case SFileMpqFileName: ha = IsValidMpqHandle(hMpqOrFile); if(ha != NULL) { pvSrcFileInfo = (void *)FileStream_GetFileName(ha->pStream); cbSrcFileInfo = (DWORD)(_tcslen((TCHAR *)pvSrcFileInfo) + 1) * sizeof(TCHAR); nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; } break; case SFileMpqStreamBitmap: ha = IsValidMpqHandle(hMpqOrFile); if(ha != NULL) return FileStream_GetBitmap(ha->pStream, pvFileInfo, cbFileInfo, pcbLengthNeeded); break; case SFileMpqUserDataOffset: ha = IsValidMpqHandle(hMpqOrFile); if(ha != NULL) { nInfoType = SFILE_INFO_TYPE_NOT_FOUND; if(ha->pUserData != NULL) { pvSrcFileInfo = &ha->UserDataPos; cbSrcFileInfo = sizeof(ULONGLONG); nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; } } break; case SFileMpqUserDataHeader: ha = IsValidMpqHandle(hMpqOrFile); if(ha != NULL) { nInfoType = SFILE_INFO_TYPE_NOT_FOUND; if(ha->pUserData != NULL) { ByteOffset = ha->UserDataPos; cbSrcFileInfo = sizeof(TMPQUserData); nInfoType = SFILE_INFO_TYPE_READ_FROM_FILE; } } break; case SFileMpqUserData: ha = IsValidMpqHandle(hMpqOrFile); if(ha != NULL) { nInfoType = SFILE_INFO_TYPE_NOT_FOUND; if(ha->pUserData != NULL) { ByteOffset = ha->UserDataPos + sizeof(TMPQUserData); cbSrcFileInfo = ha->pUserData->dwHeaderOffs - sizeof(TMPQUserData); nInfoType = SFILE_INFO_TYPE_READ_FROM_FILE; } } break; case SFileMpqHeaderOffset: ha = IsValidMpqHandle(hMpqOrFile); if(ha != NULL) { pvSrcFileInfo = &ha->MpqPos; cbSrcFileInfo = sizeof(ULONGLONG); nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; } break; case SFileMpqHeaderSize: ha = IsValidMpqHandle(hMpqOrFile); if(ha != NULL) { pvSrcFileInfo = &ha->pHeader->dwHeaderSize; cbSrcFileInfo = sizeof(DWORD); nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; } break; case SFileMpqHeader: ha = IsValidMpqHandle(hMpqOrFile); if(ha != NULL) { ByteOffset = ha->MpqPos; cbSrcFileInfo = ha->pHeader->dwHeaderSize; nInfoType = SFILE_INFO_TYPE_READ_FROM_FILE; } break; case SFileMpqHetTableOffset: ha = IsValidMpqHandle(hMpqOrFile); if(ha != NULL) { pvSrcFileInfo = &ha->pHeader->HetTablePos64; cbSrcFileInfo = sizeof(ULONGLONG); nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; } break; case SFileMpqHetTableSize: ha = IsValidMpqHandle(hMpqOrFile); if(ha != NULL) { pvSrcFileInfo = &ha->pHeader->HetTableSize64; cbSrcFileInfo = sizeof(ULONGLONG); nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; } break; case SFileMpqHetHeader: ha = IsValidMpqHandle(hMpqOrFile); if(ha != NULL) { nInfoType = SFILE_INFO_TYPE_NOT_FOUND; pvSrcFileInfo = LoadExtTable(ha, ha->pHeader->HetTablePos64, (size_t)ha->pHeader->HetTableSize64, HET_TABLE_SIGNATURE, MPQ_KEY_HASH_TABLE); if(pvSrcFileInfo != NULL) { cbSrcFileInfo = sizeof(TMPQHetHeader); nInfoType = SFILE_INFO_TYPE_ALLOCATED; } } break; case SFileMpqHetTable: ha = IsValidMpqHandle(hMpqOrFile); if(ha != NULL) { nInfoType = SFILE_INFO_TYPE_NOT_FOUND; pvSrcFileInfo = LoadHetTable(ha); if(pvSrcFileInfo != NULL) { cbSrcFileInfo = sizeof(void *); nInfoType = SFILE_INFO_TYPE_TABLE_POINTER; } } break; case SFileMpqBetTableOffset: ha = IsValidMpqHandle(hMpqOrFile); if(ha != NULL) { pvSrcFileInfo = &ha->pHeader->BetTablePos64; cbSrcFileInfo = sizeof(ULONGLONG); nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; } break; case SFileMpqBetTableSize: ha = IsValidMpqHandle(hMpqOrFile); if(ha != NULL) { pvSrcFileInfo = &ha->pHeader->BetTableSize64; cbSrcFileInfo = sizeof(ULONGLONG); nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; } break; case SFileMpqBetHeader: ha = IsValidMpqHandle(hMpqOrFile); if(ha != NULL) { nInfoType = SFILE_INFO_TYPE_NOT_FOUND; pvSrcFileInfo = LoadExtTable(ha, ha->pHeader->BetTablePos64, (size_t)ha->pHeader->BetTableSize64, BET_TABLE_SIGNATURE, MPQ_KEY_BLOCK_TABLE); if(pvSrcFileInfo != NULL) { // It is allowed for the caller to only require BET header. cbSrcFileInfo = sizeof(TMPQBetHeader) + ((TMPQBetHeader *)pvSrcFileInfo)->dwFlagCount * sizeof(DWORD); if(cbFileInfo == sizeof(TMPQBetHeader)) cbSrcFileInfo = sizeof(TMPQBetHeader); nInfoType = SFILE_INFO_TYPE_ALLOCATED; } } break; case SFileMpqBetTable: ha = IsValidMpqHandle(hMpqOrFile); if(ha != NULL) { nInfoType = SFILE_INFO_TYPE_NOT_FOUND; pvSrcFileInfo = LoadBetTable(ha); if(pvSrcFileInfo != NULL) { cbSrcFileInfo = sizeof(void *); nInfoType = SFILE_INFO_TYPE_TABLE_POINTER; } } break; case SFileMpqHashTableOffset: ha = IsValidMpqHandle(hMpqOrFile); if(ha != NULL) { Int64Value = MAKE_OFFSET64(ha->pHeader->wHashTablePosHi, ha->pHeader->dwHashTablePos); pvSrcFileInfo = &Int64Value; cbSrcFileInfo = sizeof(ULONGLONG); nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; } break; case SFileMpqHashTableSize64: ha = IsValidMpqHandle(hMpqOrFile); if(ha != NULL) { pvSrcFileInfo = &ha->pHeader->HashTableSize64; cbSrcFileInfo = sizeof(ULONGLONG); nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; } break; case SFileMpqHashTableSize: ha = IsValidMpqHandle(hMpqOrFile); if(ha != NULL) { pvSrcFileInfo = &ha->pHeader->dwHashTableSize; cbSrcFileInfo = sizeof(DWORD); nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; } break; case SFileMpqHashTable: ha = IsValidMpqHandle(hMpqOrFile); if(ha != NULL && ha->pHashTable != NULL) { pvSrcFileInfo = ha->pHashTable; cbSrcFileInfo = ha->dwHashTableSize * sizeof(TMPQHash); nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; } break; case SFileMpqBlockTableOffset: ha = IsValidMpqHandle(hMpqOrFile); if(ha != NULL) { Int64Value = MAKE_OFFSET64(ha->pHeader->wBlockTablePosHi, ha->pHeader->dwBlockTablePos); pvSrcFileInfo = &Int64Value; cbSrcFileInfo = sizeof(ULONGLONG); nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; } break; case SFileMpqBlockTableSize64: ha = IsValidMpqHandle(hMpqOrFile); if(ha != NULL) { pvSrcFileInfo = &ha->pHeader->BlockTableSize64; cbSrcFileInfo = sizeof(ULONGLONG); nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; } break; case SFileMpqBlockTableSize: ha = IsValidMpqHandle(hMpqOrFile); if(ha != NULL) { pvSrcFileInfo = &ha->pHeader->dwBlockTableSize; cbSrcFileInfo = sizeof(DWORD); nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; } break; case SFileMpqBlockTable: ha = IsValidMpqHandle(hMpqOrFile); if(ha != NULL) { nInfoType = SFILE_INFO_TYPE_NOT_FOUND; if(MAKE_OFFSET64(ha->pHeader->wBlockTablePosHi, ha->pHeader->dwBlockTablePos) != 0) { cbSrcFileInfo = ha->pHeader->dwBlockTableSize * sizeof(TMPQBlock); if(cbFileInfo >= cbSrcFileInfo) pvSrcFileInfo = LoadBlockTable(ha, true); nInfoType = SFILE_INFO_TYPE_ALLOCATED; } } break; case SFileMpqHiBlockTableOffset: ha = IsValidMpqHandle(hMpqOrFile); if(ha != NULL) { pvSrcFileInfo = &ha->pHeader->HiBlockTablePos64; cbSrcFileInfo = sizeof(ULONGLONG); nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; } break; case SFileMpqHiBlockTableSize64: ha = IsValidMpqHandle(hMpqOrFile); if(ha != NULL) { pvSrcFileInfo = &ha->pHeader->HiBlockTableSize64; cbSrcFileInfo = sizeof(ULONGLONG); nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; } break; case SFileMpqHiBlockTable: ha = IsValidMpqHandle(hMpqOrFile); if(ha != NULL) { nInfoType = SFILE_INFO_TYPE_NOT_FOUND; if(ha->pHeader->HiBlockTablePos64 && ha->pHeader->HiBlockTableSize64) { assert(false); } } break; case SFileMpqSignatures: ha = IsValidMpqHandle(hMpqOrFile); if(ha != NULL && QueryMpqSignatureInfo(ha, &SignatureInfo)) { pvSrcFileInfo = &SignatureInfo.SignatureTypes; cbSrcFileInfo = sizeof(DWORD); nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; } break; case SFileMpqStrongSignatureOffset: ha = IsValidMpqHandle(hMpqOrFile); if(ha != NULL) { nInfoType = SFILE_INFO_TYPE_NOT_FOUND; if(QueryMpqSignatureInfo(ha, &SignatureInfo) && (SignatureInfo.SignatureTypes & SIGNATURE_TYPE_STRONG)) { pvSrcFileInfo = &SignatureInfo.EndMpqData; cbSrcFileInfo = sizeof(ULONGLONG); nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; } } break; case SFileMpqStrongSignatureSize: ha = IsValidMpqHandle(hMpqOrFile); if(ha != NULL) { nInfoType = SFILE_INFO_TYPE_NOT_FOUND; if(QueryMpqSignatureInfo(ha, &SignatureInfo) && (SignatureInfo.SignatureTypes & SIGNATURE_TYPE_STRONG)) { dwInt32Value = MPQ_STRONG_SIGNATURE_SIZE + 4; pvSrcFileInfo = &dwInt32Value; cbSrcFileInfo = sizeof(DWORD); nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; } } break; case SFileMpqStrongSignature: ha = IsValidMpqHandle(hMpqOrFile); if(ha != NULL) { nInfoType = SFILE_INFO_TYPE_NOT_FOUND; if(QueryMpqSignatureInfo(ha, &SignatureInfo) && (SignatureInfo.SignatureTypes & SIGNATURE_TYPE_STRONG)) { pvSrcFileInfo = SignatureInfo.Signature; cbSrcFileInfo = MPQ_STRONG_SIGNATURE_SIZE + 4; nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; } } break; case SFileMpqArchiveSize64: ha = IsValidMpqHandle(hMpqOrFile); if(ha != NULL) { pvSrcFileInfo = &ha->pHeader->ArchiveSize64; cbSrcFileInfo = sizeof(DWORD); nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; } break; case SFileMpqArchiveSize: ha = IsValidMpqHandle(hMpqOrFile); if(ha != NULL) { pvSrcFileInfo = &ha->pHeader->dwArchiveSize; cbSrcFileInfo = sizeof(DWORD); nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; } break; case SFileMpqMaxFileCount: ha = IsValidMpqHandle(hMpqOrFile); if(ha != NULL) { pvSrcFileInfo = &ha->dwMaxFileCount; cbSrcFileInfo = sizeof(DWORD); nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; } break; case SFileMpqFileTableSize: ha = IsValidMpqHandle(hMpqOrFile); if(ha != NULL) { pvSrcFileInfo = &ha->dwFileTableSize; cbSrcFileInfo = sizeof(DWORD); nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; } break; case SFileMpqSectorSize: ha = IsValidMpqHandle(hMpqOrFile); if(ha != NULL) { pvSrcFileInfo = &ha->dwSectorSize; cbSrcFileInfo = sizeof(DWORD); nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; } break; case SFileMpqNumberOfFiles: ha = IsValidMpqHandle(hMpqOrFile); if(ha != NULL) { pvSrcFileInfo = &dwInt32Value; cbSrcFileInfo = sizeof(DWORD); dwInt32Value = GetMpqFileCount(ha); nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; } break; case SFileMpqRawChunkSize: ha = IsValidMpqHandle(hMpqOrFile); if(ha != NULL) { nInfoType = SFILE_INFO_TYPE_NOT_FOUND; if(ha->pHeader->dwRawChunkSize != 0) { pvSrcFileInfo = &ha->pHeader->dwRawChunkSize; cbSrcFileInfo = sizeof(DWORD); nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; } } break; case SFileMpqStreamFlags: ha = IsValidMpqHandle(hMpqOrFile); if(ha != NULL) { FileStream_GetFlags(ha->pStream, &dwInt32Value); pvSrcFileInfo = &dwInt32Value; cbSrcFileInfo = sizeof(DWORD); nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; } break; case SFileMpqFlags: ha = IsValidMpqHandle(hMpqOrFile); if(ha != NULL) { dwInt32Value = ha->dwFlags; pvSrcFileInfo = &dwInt32Value; cbSrcFileInfo = sizeof(DWORD); nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; } break; case SFileInfoPatchChain: hf = IsValidFileHandle(hMpqOrFile); if(hf != NULL) return GetFilePatchChain(hf, pvFileInfo, cbFileInfo, pcbLengthNeeded); break; case SFileInfoFileEntry: hf = IsValidFileHandle(hMpqOrFile); if(hf != NULL && hf->pFileEntry != NULL) { pvSrcFileInfo = pFileEntry = hf->pFileEntry; cbSrcFileInfo = sizeof(TFileEntry); if(pFileEntry->szFileName != NULL) cbSrcFileInfo += (DWORD)strlen(pFileEntry->szFileName) + 1; nInfoType = SFILE_INFO_TYPE_FILE_ENTRY; } break; case SFileInfoHashEntry: hf = IsValidFileHandle(hMpqOrFile); if(hf != NULL && hf->ha != NULL && hf->ha->pHashTable != NULL) { pvSrcFileInfo = hf->ha->pHashTable + hf->pFileEntry->dwHashIndex; cbSrcFileInfo = sizeof(TMPQHash); nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; } break; case SFileInfoHashIndex: hf = IsValidFileHandle(hMpqOrFile); if(hf != NULL && hf->pFileEntry != NULL) { pvSrcFileInfo = &hf->pFileEntry->dwHashIndex; cbSrcFileInfo = sizeof(DWORD); nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; } break; case SFileInfoNameHash1: hf = IsValidFileHandle(hMpqOrFile); if(hf != NULL && hf->ha != NULL && hf->ha->pHashTable != NULL) { pHash = hf->ha->pHashTable + hf->pFileEntry->dwHashIndex; pvSrcFileInfo = &pHash->dwName1; cbSrcFileInfo = sizeof(DWORD); nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; } break; case SFileInfoNameHash2: hf = IsValidFileHandle(hMpqOrFile); if(hf != NULL && hf->ha != NULL && hf->ha->pHashTable != NULL) { pHash = hf->ha->pHashTable + hf->pFileEntry->dwHashIndex; pvSrcFileInfo = &pHash->dwName2; cbSrcFileInfo = sizeof(DWORD); nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; } break; case SFileInfoNameHash3: hf = IsValidFileHandle(hMpqOrFile); if(hf != NULL && hf->pFileEntry != NULL) { pvSrcFileInfo = &hf->pFileEntry->FileNameHash; cbSrcFileInfo = sizeof(ULONGLONG); nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; } break; case SFileInfoLocale: hf = IsValidFileHandle(hMpqOrFile); if(hf != NULL && hf->pFileEntry != NULL) { dwInt32Value = hf->pFileEntry->lcLocale; pvSrcFileInfo = &dwInt32Value; cbSrcFileInfo = sizeof(DWORD); nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; } break; case SFileInfoFileIndex: hf = IsValidFileHandle(hMpqOrFile); if(hf != NULL && hf->ha != NULL && hf->pFileEntry != NULL) { dwInt32Value = (DWORD)(hf->pFileEntry - hf->ha->pFileTable); pvSrcFileInfo = &dwInt32Value; cbSrcFileInfo = sizeof(DWORD); nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; } break; case SFileInfoByteOffset: hf = IsValidFileHandle(hMpqOrFile); if(hf != NULL && hf->pFileEntry != NULL) { pvSrcFileInfo = &hf->pFileEntry->ByteOffset; cbSrcFileInfo = sizeof(ULONGLONG); nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; } break; case SFileInfoFileTime: hf = IsValidFileHandle(hMpqOrFile); if(hf != NULL && hf->pFileEntry != NULL) { pvSrcFileInfo = &hf->pFileEntry->FileTime; cbSrcFileInfo = sizeof(ULONGLONG); nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; } break; case SFileInfoFileSize: hf = IsValidFileHandle(hMpqOrFile); if(hf != NULL && hf->pFileEntry != NULL) { pvSrcFileInfo = &hf->pFileEntry->dwFileSize; cbSrcFileInfo = sizeof(DWORD); nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; } break; case SFileInfoCompressedSize: hf = IsValidFileHandle(hMpqOrFile); if(hf != NULL && hf->pFileEntry != NULL) { pvSrcFileInfo = &hf->pFileEntry->dwCmpSize; cbSrcFileInfo = sizeof(DWORD); nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; } break; case SFileInfoFlags: hf = IsValidFileHandle(hMpqOrFile); if(hf != NULL && hf->pFileEntry != NULL) { pvSrcFileInfo = &hf->pFileEntry->dwFlags; cbSrcFileInfo = sizeof(DWORD); nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; } break; case SFileInfoEncryptionKey: hf = IsValidFileHandle(hMpqOrFile); if(hf != NULL) { pvSrcFileInfo = &hf->dwFileKey; cbSrcFileInfo = sizeof(DWORD); nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; } break; case SFileInfoEncryptionKeyRaw: hf = IsValidFileHandle(hMpqOrFile); if(hf != NULL && hf->pFileEntry != NULL) { dwInt32Value = hf->dwFileKey; if(hf->pFileEntry->dwFlags & MPQ_FILE_FIX_KEY) dwInt32Value = (dwInt32Value ^ hf->pFileEntry->dwFileSize) - (DWORD)hf->MpqFilePos; pvSrcFileInfo = &dwInt32Value; cbSrcFileInfo = sizeof(DWORD); nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; } break; default: // Invalid info class SetLastError(ERROR_INVALID_PARAMETER); return false; } // If we validated the handle and info class, give as much info as possible if(nInfoType >= SFILE_INFO_TYPE_DIRECT_POINTER) { // Give the length needed, if wanted if(pcbLengthNeeded != NULL) pcbLengthNeeded[0] = cbSrcFileInfo; // If the caller entered an output buffer, the output size must also be entered if(pvFileInfo != NULL && cbFileInfo != 0) { // Check if there is enough space in the output buffer if(cbSrcFileInfo <= cbFileInfo) { switch(nInfoType) { case SFILE_INFO_TYPE_DIRECT_POINTER: case SFILE_INFO_TYPE_ALLOCATED: assert(pvSrcFileInfo != NULL); memcpy(pvFileInfo, pvSrcFileInfo, cbSrcFileInfo); break; case SFILE_INFO_TYPE_READ_FROM_FILE: if(!FileStream_Read(ha->pStream, &ByteOffset, pvFileInfo, cbSrcFileInfo)) nError = GetLastError(); break; case SFILE_INFO_TYPE_TABLE_POINTER: assert(pvSrcFileInfo != NULL); *(void **)pvFileInfo = pvSrcFileInfo; pvSrcFileInfo = NULL; break; case SFILE_INFO_TYPE_FILE_ENTRY: assert(pFileEntry != NULL); ConvertFileEntryToSelfRelative((TFileEntry *)pvFileInfo, pFileEntry); break; } } else { nError = ERROR_INSUFFICIENT_BUFFER; } } // Free the file info if needed if(nInfoType == SFILE_INFO_TYPE_ALLOCATED && pvSrcFileInfo != NULL) STORM_FREE(pvSrcFileInfo); if(nInfoType == SFILE_INFO_TYPE_TABLE_POINTER && pvSrcFileInfo != NULL) SFileFreeFileInfo(pvSrcFileInfo, InfoClass); } else { // Handle error cases if(nInfoType == SFILE_INFO_TYPE_INVALID_HANDLE) nError = ERROR_INVALID_HANDLE; if(nInfoType == SFILE_INFO_TYPE_NOT_FOUND) nError = ERROR_FILE_NOT_FOUND; } // Set the last error value, if needed if(nError != ERROR_SUCCESS) SetLastError(nError); return (nError == ERROR_SUCCESS); }
DWORD WINAPI SFileSetFilePointer(HANDLE hFile, LONG lFilePos, LONG * plFilePosHigh, DWORD dwMoveMethod) { TMPQFile * hf = (TMPQFile *)hFile; ULONGLONG FilePosition; ULONGLONG MoveOffset; ULONGLONG FileSize; DWORD dwFilePosHi; // If the hFile is not a valid file handle, return an error. if(!IsValidFileHandle(hf)) { SetLastError(ERROR_INVALID_HANDLE); return SFILE_INVALID_POS; } // Get the relative point where to move from switch(dwMoveMethod) { case FILE_BEGIN: FilePosition = 0; break; case FILE_CURRENT: if(hf->pStream != NULL) { FileStream_GetPos(hf->pStream, FilePosition); } else { FilePosition = hf->dwFilePos; } break; case FILE_END: if(hf->pStream != NULL) { FileStream_GetSize(hf->pStream, FilePosition); } else { FilePosition = hf->dwDataSize; } break; default: SetLastError(ERROR_INVALID_PARAMETER); return SFILE_INVALID_POS; } // Get the current file size if(hf->pStream != NULL) { FileStream_GetSize(hf->pStream, FileSize); } else { FileSize = hf->dwDataSize; } // 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 go before the begin of the file FilePosition += MoveOffset; if(FilePosition < 0) FilePosition = 0; // Now apply the file pointer to the file if(hf->pStream != NULL) { // Apply the new file position if(!FileStream_Read(hf->pStream, &FilePosition, NULL, 0)) return SFILE_INVALID_POS; // Return the new file position if(plFilePosHigh != NULL) *plFilePosHigh = (LONG)(FilePosition >> 32); return (DWORD)FilePosition; } else { // Files in MPQ can't be bigger than 4 GB. // We don't allow to go past 4 GB if(FilePosition >> 32)
// 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; }