⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sfilecompactarchive.cpp.svn-base

📁 絲路server源碼 Silk Road server source
💻 SVN-BASE
📖 第 1 页 / 共 2 页
字号:
            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 + -