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

📄 scommon.cpp.svn-base

📁 絲路server源碼 Silk Road server source
💻 SVN-BASE
📖 第 1 页 / 共 3 页
字号:
        }

        // Get pointers to both block entries of the file
        pBlockEx = ha->pExtBlockTable + pHash->dwBlockIndex;
        pBlock = ha->pBlockTable + pHash->dwBlockIndex;
        
        // Save the file size info
        pBlockEx->wFilePosHigh = (USHORT)RelativePos.HighPart;
        pBlock->dwFilePos = RelativePos.LowPart;
        pBlock->dwFSize   = GetFileSize(hFile, NULL);
        pBlock->dwFlags   = dwFlags | MPQ_FILE_EXISTS;

        // Create seed1 for file encryption
        if(szTemp != NULL)
            szArchivedName = szTemp + 1;

        if(dwFlags & MPQ_FILE_ENCRYPTED)
        {
            dwSeed1 = DecryptFileSeed(szArchivedName);
            
            if(dwFlags & MPQ_FILE_FIXSEED)
                dwSeed1 = (dwSeed1 + pBlock->dwFilePos) ^ pBlock->dwFSize;
        }
    }

    // Allocate buffer for the input data
    if(nError == ERROR_SUCCESS)
    {
        nBlocks = (pBlock->dwFSize / ha->dwBlockSize) + 1;
        if(pBlock->dwFSize % ha->dwBlockSize)
            nBlocks++;

        pBlock->dwCSize = 0;
        if((pbFileData = ALLOCMEM(BYTE, ha->dwBlockSize)) == NULL)
            nError = ERROR_NOT_ENOUGH_MEMORY;
        pbToWrite = pbFileData;
    }

    // Allocate buffers for the compressed data
    if(nError == ERROR_SUCCESS && (dwFlags & MPQ_FILE_COMPRESSED))
    {
        pdwBlockPos  = ALLOCMEM(DWORD, nBlocks + 1);
        pbCompressed = ALLOCMEM(BYTE, ha->dwBlockSize * 2);
        if(pdwBlockPos == NULL || pbCompressed == NULL)
            nError = ERROR_NOT_ENOUGH_MEMORY;
        pbToWrite = pbCompressed;
    }

    // Set the file position to the point where the file will be stored
    if(nError == ERROR_SUCCESS)
    {
        // Set the file pointer to file data position
        FilePos.QuadPart = ha->MpqPos.QuadPart + RelativePos.QuadPart;
        if(FilePos.QuadPart != ha->FilePointer.QuadPart)
        {
            SetFilePointer(ha->hFile, FilePos.LowPart, &FilePos.HighPart, FILE_BEGIN);
            ha->FilePointer = FilePos;
        }
    }

    // Write block positions (if the file will be compressed)
    if(nError == ERROR_SUCCESS && (dwFlags & MPQ_FILE_COMPRESSED))
    {
        dwBlockPosLen = nBlocks * sizeof(DWORD);
        if(dwFlags & MPQ_FILE_HAS_EXTRA)
            dwBlockPosLen += sizeof(DWORD);

        memset(pdwBlockPos, 0, dwBlockPosLen);
        pdwBlockPos[0] = dwBlockPosLen;
        
        // Write the block positions
        BSWAP_ARRAY32_UNSIGNED((DWORD *)pdwBlockPos, nBlocks);
        WriteFile(ha->hFile, pdwBlockPos, dwBlockPosLen, &dwTransferred, NULL);
        BSWAP_ARRAY32_UNSIGNED((DWORD *)pdwBlockPos, nBlocks);

        if(dwTransferred == dwBlockPosLen)
            pBlock->dwCSize += dwBlockPosLen;
        else
            nError = GetLastError();

        // Update the current position in the file
        ha->HashTablePos.QuadPart = FilePos.QuadPart + dwTransferred;
    }

    // Write all file blocks
    if(nError == ERROR_SUCCESS)
    {
        nCmp = nCmpFirst;

        SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
        for(nBlock = 0; nBlock < nBlocks-1; nBlock++)
        {
            DWORD dwInLength  = ha->dwBlockSize;
            DWORD dwOutLength = ha->dwBlockSize;

            // Load the block from the file
            ReadFile(hFile, pbFileData, ha->dwBlockSize, &dwInLength, NULL);
            if(dwInLength == 0)
                break;

            // Compress the block, if necessary
            dwOutLength = dwInLength;
            if(pBlock->dwFlags & MPQ_FILE_COMPRESSED)
            {
                // Should be enough for compression
                int nOutLength = ha->dwBlockSize * 2;
                int nCmpType = 0;

                if(pBlock->dwFlags & MPQ_FILE_COMPRESS_PKWARE)
                    Compress_pklib((char *)pbCompressed, &nOutLength, (char *)pbFileData, dwInLength, &nCmpType, 0);

                if(pBlock->dwFlags & MPQ_FILE_COMPRESS_MULTI)
                    SCompCompress((char *)pbCompressed, &nOutLength, (char *)pbFileData, dwInLength, nCmp, 0, nCmpLevel);

                // The compressed block size must NOT be the same or greater like
                // the original block size. If yes, do not compress the block
                // and store the data as-is.
                if(nOutLength >= (int)dwInLength)
                {
                    memcpy(pbCompressed, pbFileData, dwInLength);
                    nOutLength = dwInLength;
                }

                // Update block positions
                dwOutLength = nOutLength;
                pdwBlockPos[nBlock+1] = pdwBlockPos[nBlock] + dwOutLength;
                nCmp = nCmpNext;
            }

            // Encrypt the block, if necessary
            if(pBlock->dwFlags & MPQ_FILE_ENCRYPTED)
            {
                BSWAP_ARRAY32_UNSIGNED((DWORD *)pbToWrite, dwOutLength / sizeof(DWORD));
                EncryptMPQBlock((DWORD *)pbToWrite, dwOutLength, dwSeed1 + nBlock);
                BSWAP_ARRAY32_UNSIGNED((DWORD *)pbToWrite, dwOutLength / sizeof(DWORD));
            }
            
            // Write the block
            WriteFile(ha->hFile, pbToWrite, dwOutLength, &dwTransferred, NULL);
            if(dwTransferred != dwOutLength)
            {
                nError = ERROR_DISK_FULL;
                break;
            }

            // Update the hash table position and the compressed file size
            ha->HashTablePos.QuadPart += dwTransferred;
            pBlock->dwCSize += dwOutLength;
        }
    }

    // Now save the block positions
    if(nError == ERROR_SUCCESS && (pBlock->dwFlags & MPQ_FILE_COMPRESSED))
    {
        if(dwFlags & MPQ_FILE_HAS_EXTRA)
            pdwBlockPos[nBlocks] = pdwBlockPos[nBlocks-1];

        // If file is encrypted, block positions are also encrypted
        if(dwFlags & MPQ_FILE_ENCRYPTED)
            EncryptMPQBlock(pdwBlockPos, dwBlockPosLen, dwSeed1 - 1);
        
        // Set the position back to the block table
        SetFilePointer(ha->hFile, FilePos.LowPart, &FilePos.HighPart, FILE_BEGIN);
        
        // Write block positions to the archive
        BSWAP_ARRAY32_UNSIGNED((DWORD *)pdwBlockPos, nBlocks);
        WriteFile(ha->hFile, pdwBlockPos, dwBlockPosLen, &dwTransferred, NULL);
        if(dwTransferred != dwBlockPosLen)
            nError = ERROR_DISK_FULL;

        ha->FilePointer.QuadPart = ha->FilePointer.QuadPart + dwTransferred;
    }

    // If success, we have to change the settings
    // in MPQ header. If failed, we have to clean hash entry
    if(nError == ERROR_SUCCESS)
    {
        ha->pLastFile  = NULL;
        ha->dwBlockPos = 0;
        ha->dwBuffPos  = 0;
        ha->dwFlags   |= MPQ_FLAG_CHANGED;

        // Add new entry to the block table (if needed)
        if(pHash->dwBlockIndex >= ha->pHeader->dwBlockTableSize)
            ha->pHeader->dwBlockTableSize++;

        // Hash table size in the TMPQArchive is already set at this point
        RelativePos.QuadPart = ha->HashTablePos.QuadPart - ha->MpqPos.QuadPart;
        ha->pHeader->dwHashTablePos = RelativePos.LowPart;
        ha->pHeader->wHashTablePosHigh = (USHORT)RelativePos.HighPart;

        // Update block table pos
        RelativePos.QuadPart += (ha->pHeader->dwHashTableSize * sizeof(TMPQHash));
        ha->pHeader->wBlockTablePosHigh = (USHORT)RelativePos.HighPart;
        ha->pHeader->dwBlockTablePos = RelativePos.LowPart;
        ha->BlockTablePos.QuadPart = RelativePos.QuadPart + ha->MpqPos.QuadPart;

        // If the archive size exceeded 4GB, we have to use extended block table pos
        RelativePos.QuadPart += (ha->pHeader->dwBlockTableSize * sizeof(TMPQBlock));
        if(RelativePos.HighPart != 0)
        {
            ha->pHeader->ExtBlockTablePos = RelativePos;
            ha->ExtBlockTablePos.QuadPart = RelativePos.QuadPart + ha->MpqPos.QuadPart;

            RelativePos.QuadPart += (ha->pHeader->dwBlockTableSize * sizeof(TMPQBlockEx));
        }

        // Update archive size (only valid for version V1)
        ha->MpqSize = RelativePos;
        ha->pHeader->dwArchiveSize = ha->MpqSize.LowPart;
    }
    else
    {
        // Clear the hash table entry
        if(pHash != NULL)
            memset(pHash, 0xFF, sizeof(TMPQHash));
    }

    // Cleanup
    if(pbCompressed != NULL)
        FREEMEM(pbCompressed);
    if(pdwBlockPos != NULL)
        FREEMEM(pdwBlockPos);
    if(pbFileData != NULL)
        FREEMEM(pbFileData);
    if(pbReplaced != NULL)
        *pbReplaced = bReplaced;
    return nError;
}

int SetDataCompression(int nDataCompression)
{
    nDataCmp = nDataCompression;
    return 0;
}

// This method saves MPQ header, hash table and block table.
// TODO: Test for archives > 4GB
int SaveMPQTables(TMPQArchive * ha)
{
    BYTE * pbBuffer = NULL;
    DWORD dwBytes;
    DWORD dwWritten;
    DWORD dwBuffSize = max(ha->pHeader->dwHashTableSize, ha->pHeader->dwBlockTableSize);
    int   nError = ERROR_SUCCESS;

    // Allocate buffer for encrypted tables
    if(nError == ERROR_SUCCESS)
    {
        // Allocate temporary buffer for tables encryption
        pbBuffer = ALLOCMEM(BYTE, sizeof(TMPQHash) * dwBuffSize);
        if(pbBuffer == NULL)
            nError = ERROR_NOT_ENOUGH_MEMORY;
    }

    // Write the MPQ Header
    if(nError == ERROR_SUCCESS)
    {
        DWORD dwHeaderSize = ha->pHeader->dwHeaderSize;

        // Write the MPQ header
        SetFilePointer(ha->hFile, ha->MpqPos.LowPart, &ha->MpqPos.HighPart, FILE_BEGIN);

        // Convert to little endian for file save
        BSWAP_TMPQHEADER(ha->pHeader);
        WriteFile(ha->hFile, ha->pHeader, dwHeaderSize, &dwWritten, NULL);
        BSWAP_TMPQHEADER(ha->pHeader);

        if(dwWritten != ha->pHeader->dwHeaderSize)
            nError = ERROR_DISK_FULL;
    }

    // Write the hash table
    if(nError == ERROR_SUCCESS)
    {
        // Copy the hash table to temporary buffer
        dwBytes = ha->pHeader->dwHashTableSize * sizeof(TMPQHash);
        memcpy(pbBuffer, ha->pHashTable, dwBytes);

        // Convert to little endian for file save
        EncryptHashTable((DWORD *)pbBuffer, (BYTE *)"(hash table)", dwBytes >> 2);
        BSWAP_ARRAY32_UNSIGNED((DWORD *)pbBuffer, dwBytes / sizeof(DWORD));

        // Set the file pointer to the offset of the hash table and write it
        SetFilePointer(ha->hFile, ha->HashTablePos.LowPart, (PLONG)&ha->HashTablePos.HighPart, FILE_BEGIN);
        WriteFile(ha->hFile, pbBuffer, dwBytes, &dwWritten, NULL);
        if(dwWritten != dwBytes)
            nError = ERROR_DISK_FULL;
    }

    // Write the block table
    if(nError == ERROR_SUCCESS)
    {
        // Copy the block table to temporary buffer
        dwBytes = ha->pHeader->dwBlockTableSize * sizeof(TMPQBlock);
        memcpy(pbBuffer, ha->pBlockTable, dwBytes);

        // Encrypt the block table and write it to the file
        EncryptBlockTable((DWORD *)pbBuffer, (BYTE *)"(block table)", dwBytes >> 2);
        
        // Convert to little endian for file save
        BSWAP_ARRAY32_UNSIGNED((DWORD *)pbBuffer, dwBytes / sizeof(DWORD));
        WriteFile(ha->hFile, pbBuffer, dwBytes, &dwWritten, NULL);
        if(dwWritten != dwBytes)
            nError = ERROR_DISK_FULL;
    }

    // Write the extended block table
    if(nError == ERROR_SUCCESS && ha->pHeader->ExtBlockTablePos.QuadPart != 0)
    {
        // We expect format V2 or newer in this case
        assert(ha->pHeader->wFormatVersion >= MPQ_FORMAT_VERSION_2);

        // Copy the block table to temporary buffer
        dwBytes = ha->pHeader->dwBlockTableSize * sizeof(TMPQBlockEx);
        memcpy(pbBuffer, ha->pExtBlockTable, dwBytes);

        // Convert to little endian for file save
        BSWAP_ARRAY16_UNSIGNED((USHORT *)pbBuffer, dwBytes / sizeof(USHORT));
        WriteFile(ha->hFile, pbBuffer, dwBytes, &dwWritten, NULL);
        if(dwWritten != dwBytes)
            nError = ERROR_DISK_FULL;
    }


    // Set end of file here
    if(nError == ERROR_SUCCESS)
    {
        SetEndOfFile(ha->hFile);
    }

    // Cleanup and exit
    if(pbBuffer != NULL)
        FREEMEM(pbBuffer);
    return nError;
}

// Frees the MPQ archive
// TODO: Test for archives > 4GB
void FreeMPQArchive(TMPQArchive *& ha)
{
    if(ha != NULL)
    {
        FREEMEM(ha->pbBlockBuffer);
        FREEMEM(ha->pBlockTable);
        FREEMEM(ha->pExtBlockTable);
        FREEMEM(ha->pHashTable);
        if(ha->pListFile != NULL)
            SListFileFreeListFile(ha);

        if(ha->hFile != INVALID_HANDLE_VALUE)
            CloseHandle(ha->hFile);
        FREEMEM(ha);
        ha = NULL;
    }
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -