📄 sfilecompactarchive.cpp.svn-base
字号:
if(dwTransferred == dwBytes)
{
WriteFile(hFile, pbBlock, dwBytes, &dwTransferred, NULL);
dwCSize += dwTransferred;
if(dwTransferred != dwBytes)
nError = ERROR_DISK_FULL;
}
else
{
nError = ERROR_FILE_CORRUPT;
}
}
}
// Update file position in the block table
if(nError == ERROR_SUCCESS)
{
// At this point, number of bytes written should be exactly
// the same like the compressed file size. If it isn't, there's something wrong
// (maybe new archive version ?)
assert(dwCSize == pBlock->dwCSize);
// Update file pos in the block table
FilePos.QuadPart -= ha->MpqPos.QuadPart;
pBlockEx->wFilePosHigh = (USHORT)FilePos.HighPart;
pBlock->dwFilePos = FilePos.LowPart;
}
// Cleanup and return
if(pdwBlockPos2 != NULL)
FREEMEM(pdwBlockPos2);
if(pdwBlockPos != NULL)
FREEMEM(pdwBlockPos);
if(pbBlock != NULL)
FREEMEM(pbBlock);
return nError;
}
static int CopyNonMpqData(
HANDLE hSrcFile,
HANDLE hTrgFile,
LARGE_INTEGER & DataSizeToCopy)
{
LARGE_INTEGER DataSize = DataSizeToCopy;
DWORD dwTransferred;
DWORD dwToRead;
char DataBuffer[0x1000];
int nError = ERROR_SUCCESS;
while(DataSize.QuadPart > 0)
{
// Get the proper size of data
dwToRead = sizeof(DataBuffer);
if(DataSize.HighPart == 0 && DataSize.LowPart < dwToRead)
dwToRead = DataSize.LowPart;
// Read the source file
ReadFile(hSrcFile, DataBuffer, dwToRead, &dwTransferred, NULL);
if(dwTransferred != dwToRead)
{
nError = ERROR_CAN_NOT_COMPLETE;
break;
}
// Write to the target file
WriteFile(hTrgFile, DataBuffer, dwToRead, &dwTransferred, NULL);
if(dwTransferred != dwToRead)
{
nError = ERROR_DISK_FULL;
break;
}
// Decrement the number of data to be copied
DataSize.QuadPart -= dwTransferred;
}
return ERROR_SUCCESS;
}
// TODO: Test for archives > 4GB
static int CopyMpqFiles(HANDLE hFile, TMPQArchive * ha, DWORD * pFileSeeds)
{
TMPQBlockEx * pBlockEx;
TMPQBlock * pBlock;
DWORD dwSeed1;
DWORD dwIndex;
int nError = ERROR_SUCCESS;
// Walk through all files and write them to the destination MPQ archive
for(dwIndex = 0; dwIndex < ha->pHeader->dwBlockTableSize; dwIndex++)
{
pBlockEx = ha->pExtBlockTable + dwIndex;
pBlock = ha->pBlockTable + dwIndex;
dwSeed1 = pFileSeeds[dwIndex];
// Notify the caller about work
if(CompactCB != NULL)
CompactCB(lpUserData, CCB_COMPACTING_FILES, dwIndex, ha->pHeader->dwBlockTableSize);
// if(dwIndex == 0x1B9)
// DebugBreak();
// Copy all the file blocks
// Debug: Break at (dwIndex == 5973)
if(pBlock->dwFlags & MPQ_FILE_EXISTS)
{
nError = CopyMpqFileBlocks(hFile, ha, pBlockEx, pBlock, dwSeed1);
if(nError != ERROR_SUCCESS)
break;
}
}
// Cleanup and exit
return nError;
}
/*****************************************************************************/
/* Public functions */
/*****************************************************************************/
BOOL WINAPI SFileSetCompactCallback(HANDLE /* hMPQ */, COMPACTCB aCompactCB, void * lpData)
{
CompactCB = aCompactCB;
lpUserData = lpData;
return TRUE;
}
//-----------------------------------------------------------------------------
// Archive compacting (incomplete)
// TODO: Test for archives > 4GB
BOOL WINAPI SFileCompactArchive(HANDLE hMPQ, const char * szListFile, BOOL /* bReserved */)
{
TMPQArchive * ha = (TMPQArchive *)hMPQ;
HANDLE hFile = INVALID_HANDLE_VALUE;
DWORD * pFileSeeds = NULL;
char szTempFile[MAX_PATH] = "";
char * szTemp = NULL;
DWORD dwTransferred;
int nError = ERROR_SUCCESS;
// Test the valid parameters
if(!IsValidMpqHandle(ha))
nError = ERROR_INVALID_PARAMETER;
// Create the table with file seeds
if(nError == ERROR_SUCCESS)
{
if((pFileSeeds = ALLOCMEM(DWORD, ha->pHeader->dwBlockTableSize)) != NULL)
memset(pFileSeeds, 0, sizeof(DWORD) * ha->pHeader->dwBlockTableSize);
else
nError = ERROR_NOT_ENOUGH_MEMORY;
}
// First of all, we have to check of we are able to decrypt all files.
// If not, sorry, but the archive cannot be compacted.
if(nError == ERROR_SUCCESS)
nError = CheckIfAllFilesKnown(ha, szListFile, pFileSeeds);
// Get the temporary file name and create it
if(nError == ERROR_SUCCESS)
{
if(CompactCB != NULL)
CompactCB(lpUserData, CCB_COPYING_NON_MPQ_DATA, 0, 0);
strcpy(szTempFile, ha->szFileName);
if((szTemp = strrchr(szTempFile, '.')) != NULL)
strcpy(szTemp + 1, "mp_");
else
strcat(szTempFile, "_");
hFile = CreateFile(szTempFile, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, NULL);
if(hFile == INVALID_HANDLE_VALUE)
nError = GetLastError();
}
// Write the data before MPQ header (if any)
if(nError == ERROR_SUCCESS && ha->MpqPos.QuadPart > 0)
{
SetFilePointer(ha->hFile, 0, NULL, FILE_BEGIN);
if(ha->pShunt != NULL)
nError = CopyNonMpqData(ha->hFile, hFile, ha->ShuntPos);
else
nError = CopyNonMpqData(ha->hFile, hFile, ha->MpqPos);
}
// Write the MPQ shunt (if any)
if(nError == ERROR_SUCCESS && ha->pShunt != NULL)
{
BSWAP_TMPQSHUNT(ha->pShunt);
WriteFile(hFile, ha->pShunt, sizeof(TMPQShunt), &dwTransferred, NULL);
BSWAP_TMPQSHUNT(ha->pShunt);
if(dwTransferred != sizeof(TMPQShunt))
nError = ERROR_DISK_FULL;
}
// Write the data between MPQ shunt and the MPQ header (if any)
if(nError == ERROR_SUCCESS && ha->pShunt != NULL)
{
LARGE_INTEGER BytesToCopy;
BytesToCopy.QuadPart = ha->MpqPos.QuadPart - (ha->ShuntPos.QuadPart + sizeof(TMPQShunt));
nError = CopyNonMpqData(ha->hFile, hFile, BytesToCopy);
}
// Write the MPQ header
if(nError == ERROR_SUCCESS)
{
BSWAP_TMPQHEADER(ha->pHeader);
WriteFile(hFile, ha->pHeader, ha->pHeader->dwHeaderSize, &dwTransferred, NULL);
BSWAP_TMPQHEADER(ha->pHeader);
if(dwTransferred != ha->pHeader->dwHeaderSize)
nError = ERROR_DISK_FULL;
}
// Write the data between the header and between the first file
// For this, we have to determine where the first file begins
if(nError == ERROR_SUCCESS)
{
LARGE_INTEGER FirstFilePos;
LARGE_INTEGER TempPos;
TMPQBlockEx * pBlockEx = ha->pExtBlockTable;
TMPQBlock * pBlockEnd = ha->pBlockTable + ha->pHeader->dwBlockTableSize;
TMPQBlock * pBlock = ha->pBlockTable;
// Maximum file position
FirstFilePos.HighPart = 0x7FFFFFFF;
FirstFilePos.LowPart = 0xFFFFFFFF;
// Find the block with the least position in the MPQ
while(pBlock < pBlockEnd)
{
TempPos.HighPart = pBlockEx->wFilePosHigh;
TempPos.LowPart = pBlock->dwFilePos;
if(TempPos.QuadPart < FirstFilePos.QuadPart)
FirstFilePos = TempPos;
pBlockEx++;
pBlock++;
}
// Set the position in the source file right after the file header
TempPos.QuadPart = ha->MpqPos.QuadPart + ha->pHeader->dwHeaderSize;
SetFilePointer(ha->hFile, TempPos.LowPart, &TempPos.HighPart, FILE_BEGIN);
// Get the number of bytes to copy
FirstFilePos.QuadPart -= ha->pHeader->dwHeaderSize;
nError = CopyNonMpqData(ha->hFile, hFile, FirstFilePos);
}
// Now write all file blocks.
if(nError == ERROR_SUCCESS)
nError = CopyMpqFiles(hFile, ha, pFileSeeds);
// Now we need to update the tables positions
// (but only if the tables are at the end of the file)
if(nError == ERROR_SUCCESS)
{
LARGE_INTEGER RelativePos;
LARGE_INTEGER FilePos = {0};
// Set the hash table position
FilePos.LowPart = SetFilePointer(hFile, 0, &FilePos.HighPart, FILE_CURRENT);
RelativePos.QuadPart = FilePos.QuadPart - ha->MpqPos.QuadPart;
ha->pHeader->wHashTablePosHigh = (USHORT)RelativePos.HighPart;
ha->pHeader->dwHashTablePos = RelativePos.LowPart;
ha->HashTablePos = FilePos;
// Set the block table position
RelativePos.QuadPart += ha->pHeader->dwHashTableSize * sizeof(TMPQHash);
FilePos.QuadPart += ha->pHeader->dwHashTableSize * sizeof(TMPQHash);
ha->pHeader->wBlockTablePosHigh = (USHORT)RelativePos.HighPart;
ha->pHeader->dwBlockTablePos = RelativePos.LowPart;
ha->BlockTablePos = FilePos;
// Set the extended block table position
RelativePos.QuadPart += ha->pHeader->dwBlockTableSize * sizeof(TMPQBlock);
FilePos.QuadPart += ha->pHeader->dwBlockTableSize * sizeof(TMPQBlock);
if(ha->ExtBlockTablePos.QuadPart != 0)
{
ha->pHeader->ExtBlockTablePos = RelativePos;
ha->ExtBlockTablePos = FilePos;
RelativePos.QuadPart += ha->pHeader->dwBlockTableSize * sizeof(TMPQBlockEx);
FilePos.QuadPart += ha->pHeader->dwBlockTableSize * sizeof(TMPQBlockEx);
}
// Set the archive size
ha->pHeader->dwArchiveSize = RelativePos.LowPart;
ha->MpqSize = RelativePos;
}
// If succeeded, update the tables in the file
if(nError == ERROR_SUCCESS)
{
CloseHandle(ha->hFile);
ha->FilePointer.QuadPart = 0;
ha->hFile = hFile;
hFile = INVALID_HANDLE_VALUE;
nError = SaveMPQTables(ha);
}
// If all succeeded, switch the archives
if(nError == ERROR_SUCCESS)
{
if(CompactCB != NULL)
CompactCB(lpUserData, CCB_CLOSING_ARCHIVE, 0, 0);
if(!DeleteFile(ha->szFileName) || // Delete the old archive
!CloseHandle(ha->hFile) || // Close the new archive
!MoveFile(szTempFile, ha->szFileName)) // Rename the temporary archive
nError = GetLastError();
}
// Now open the freshly renamed archive file
if(nError == ERROR_SUCCESS)
{
ha->hFile = CreateFile(ha->szFileName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if(ha->hFile == INVALID_HANDLE_VALUE)
nError = GetLastError();
}
// Invalidate the positions of the archive
if(nError == ERROR_SUCCESS)
{
ha->FilePointer.QuadPart = 0;
ha->pLastFile = NULL;
ha->dwBlockPos = 0;
ha->dwBuffPos = 0;
}
// Cleanup and return
if(hFile != INVALID_HANDLE_VALUE)
CloseHandle(hFile);
if(pFileSeeds != NULL)
FREEMEM(pFileSeeds);
if(nError != ERROR_SUCCESS)
SetLastError(nError);
DeleteFile(szTempFile);
CompactCB = NULL;
return (nError == ERROR_SUCCESS);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -