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

📄 sfileopenarchive.cpp

📁 絲路server源碼 Silk Road server source
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/*****************************************************************************/
/* SFileOpenArchive.cpp                       Copyright Ladislav Zezula 1999 */
/*                                                                           */
/* Author : Ladislav Zezula                                                  */
/* E-mail : ladik@zezula.net                                                 */
/* WWW    : www.zezula.net                                                   */
/*---------------------------------------------------------------------------*/
/*                       Archive functions of Storm.dll                      */
/*---------------------------------------------------------------------------*/
/*   Date    Ver   Who  Comment                                              */
/* --------  ----  ---  -------                                              */
/* xx.xx.xx  1.00  Lad  The first version of SFileOpenArchive.cpp            */
/* 19.11.03  1.01  Dan  Big endian handling                                  */
/*****************************************************************************/

#define __STORMLIB_SELF__
#include "StormLib.h"
#include "SCommon.h"

/*****************************************************************************/
/* Local functions                                                           */
/*****************************************************************************/

static BOOL IsAviFile(TMPQHeader * pHeader)
{
    DWORD * AviHdr = (DWORD *)pHeader;

    // Test for 'RIFF', 'AVI ' or 'LIST'
    return (AviHdr[0] == 'FFIR' && AviHdr[2] == ' IVA' && AviHdr[3] == 'TSIL');
}

// This function gets the right positions of the hash table and the block table.
// TODO: Test for archives > 4GB
static int RelocateMpqTablePositions(TMPQArchive * ha)
{
    TMPQHeader2 * pHeader = ha->pHeader;
    LARGE_INTEGER FileSize;
    LARGE_INTEGER TempSize;

    // Get the size of the file
    FileSize.LowPart = GetFileSize(ha->hFile, (LPDWORD)&FileSize.HighPart);

    // Set the proper hash table position
    ha->HashTablePos.HighPart = pHeader->wHashTablePosHigh;
    ha->HashTablePos.LowPart = pHeader->dwHashTablePos;
    ha->HashTablePos.QuadPart += ha->MpqPos.QuadPart;
    if(ha->HashTablePos.QuadPart > FileSize.QuadPart)
        return ERROR_BAD_FORMAT;

    // Set the proper block table position
    ha->BlockTablePos.HighPart = pHeader->wBlockTablePosHigh;
    ha->BlockTablePos.LowPart = pHeader->dwBlockTablePos;
    ha->BlockTablePos.QuadPart += ha->MpqPos.QuadPart;
    if(ha->BlockTablePos.QuadPart > FileSize.QuadPart)
        return ERROR_BAD_FORMAT;

    // Set the proper position of the extended block table
    if(pHeader->ExtBlockTablePos.QuadPart != 0)
    {
        ha->ExtBlockTablePos = pHeader->ExtBlockTablePos;
        ha->ExtBlockTablePos.QuadPart += ha->MpqPos.QuadPart;
        if(ha->ExtBlockTablePos.QuadPart > FileSize.QuadPart)
            return ERROR_BAD_FORMAT;
    }

    // Size of MPQ archive is computed as the biggest of
    // (EndOfBlockTable, EndOfHashTable, EndOfExtBlockTable)
    TempSize.QuadPart = ha->HashTablePos.QuadPart + (pHeader->dwHashTableSize * sizeof(TMPQHash));
    if(TempSize.QuadPart > ha->MpqSize.QuadPart)
        ha->MpqSize = TempSize;
    TempSize.QuadPart = ha->BlockTablePos.QuadPart + (pHeader->dwBlockTableSize * sizeof(TMPQBlock));
    if(TempSize.QuadPart > ha->MpqSize.QuadPart)
        ha->MpqSize = TempSize;
    TempSize.QuadPart = ha->ExtBlockTablePos.QuadPart + (pHeader->dwBlockTableSize * sizeof(TMPQBlockEx));
    if(TempSize.QuadPart > ha->MpqSize.QuadPart)
        ha->MpqSize = TempSize;
    
    // MPQ size does not include the bytes before MPQ header
    ha->MpqSize.QuadPart -= ha->MpqPos.QuadPart;
    return ERROR_SUCCESS;
}


/*****************************************************************************/
/* Public functions                                                          */
/*****************************************************************************/

//-----------------------------------------------------------------------------
// SFileGetLocale and SFileSetLocale
// Set the locale for all neewly opened archives and files

LCID WINAPI SFileGetLocale()
{
    return lcLocale;
}

LCID WINAPI SFileSetLocale(LCID lcNewLocale)
{
    lcLocale = lcNewLocale;
    return lcLocale;
}

//-----------------------------------------------------------------------------
// SFileOpenArchiveEx (not a public function !!!)
//
//   szFileName - MPQ archive file name to open
//   dwPriority - When SFileOpenFileEx called, this contains the search priority for searched archives
//   dwFlags    - If contains MPQ_OPEN_NO_LISTFILE, then the internal list file will not be used.
//   phMPQ      - Pointer to store open archive handle

BOOL SFileOpenArchiveEx(
    const char * szMpqName,
    DWORD dwPriority,
    DWORD dwFlags,
    HANDLE * phMPQ,
    DWORD dwAccessMode)
{
    LARGE_INTEGER TempPos;
    TMPQArchive * ha = NULL;            // Archive handle
    HANDLE hFile = INVALID_HANDLE_VALUE;// Opened archive file handle
    DWORD dwMaxBlockIndex = 0;          // Maximum value of block entry
    DWORD dwBlockTableSize = 0;         // Block table size.
    DWORD dwTransferred;                // Number of bytes read
    DWORD dwBytes = 0;                  // Number of bytes to read
    int nError = ERROR_SUCCESS;   

    // Check the right parameters
    if(nError == ERROR_SUCCESS)
    {
        if(szMpqName == NULL || *szMpqName == 0 || phMPQ == NULL)
            nError = ERROR_INVALID_PARAMETER;
    }

    // Ensure that StormBuffer is allocated
    if(nError == ERROR_SUCCESS)
        nError = PrepareStormBuffer();

    // Open the MPQ archive file
    if(nError == ERROR_SUCCESS)
    {
        hFile = CreateFile(szMpqName, dwAccessMode, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
        if(hFile == INVALID_HANDLE_VALUE)
            nError = GetLastError();
    }
    
    // Allocate the MPQhandle
    if(nError == ERROR_SUCCESS)
    {
        if((ha = ALLOCMEM(TMPQArchive, 1)) == NULL)
            nError = ERROR_NOT_ENOUGH_MEMORY;
    }

    // Initialize handle structure and allocate structure for MPQ header
    if(nError == ERROR_SUCCESS)
    {
        memset(ha, 0, sizeof(TMPQArchive));
        strncpy(ha->szFileName, szMpqName, strlen(szMpqName));
        ha->hFile      = hFile;
        ha->dwPriority = dwPriority;
        ha->pHeader    = &ha->Header;
        ha->pListFile  = NULL;
        hFile = INVALID_HANDLE_VALUE;
    }

    // Find the offset of MPQ header within the file
    if(nError == ERROR_SUCCESS)
    {
        LARGE_INTEGER SearchPos = {0};
        LARGE_INTEGER MpqPos = {0};
        DWORD dwHeaderID;

        for(;;)
        {
            // Invalidate the MPQ ID and read the eventual header
            SetFilePointer(ha->hFile, MpqPos.LowPart, &MpqPos.HighPart, FILE_BEGIN);
            ReadFile(ha->hFile, ha->pHeader, sizeof(TMPQHeader2), &dwTransferred, NULL);
            dwHeaderID = BSWAP_INT32_UNSIGNED(ha->pHeader->dwID);

            // Special check : Some MPQs are actually AVI files, only with
            // changed extension.
            if(MpqPos.QuadPart == 0 && IsAviFile(ha->pHeader))
            {
                nError = ERROR_AVI_FILE;
                break;
            }

            // If different number of bytes read, break the loop
            if(dwTransferred != sizeof(TMPQHeader2))
            {
                nError = ERROR_BAD_FORMAT;
                break;
            }

            // If there is the MPQ shunt signature, process it
            if(dwHeaderID == ID_MPQ_SHUNT && ha->pShunt == NULL)
            {
                // Fill the shunt header
                ha->ShuntPos = MpqPos;
                ha->pShunt = &ha->Shunt;
                memcpy(ha->pShunt, ha->pHeader, sizeof(TMPQShunt));
                BSWAP_TMPQSHUNT(ha->pShunt);

                // Set the MPQ pos and repeat the search
                MpqPos.QuadPart = SearchPos.QuadPart + ha->pShunt->dwHeaderPos;
                continue;
            }

            // There must be MPQ header signature
            if(dwHeaderID == ID_MPQ)
            {
                BSWAP_TMPQHEADER(ha->pHeader);

                // Save the position where the MPQ header has been found
                ha->MpqPos = MpqPos;

                // If valid signature has been found, break the loop
                if(ha->pHeader->wFormatVersion == MPQ_FORMAT_VERSION_1)
                {
                    // W3M Map Protectors set some garbage value into the "dwHeaderSize"
                    // field of MPQ header. This value is apparently ignored by Storm.dll
                    if(ha->pHeader->dwHeaderSize != sizeof(TMPQHeader) &&
                       ha->pHeader->dwHeaderSize != sizeof(TMPQHeader2))
                    {
                        ha->dwFlags |= MPQ_FLAG_PROTECTED;
                        ha->pHeader->dwHeaderSize = sizeof(TMPQHeader);
                    }

                    if(ha->pHeader->dwHashTablePos < ha->pHeader->dwArchiveSize &&
                       ha->pHeader->dwBlockTablePos < ha->pHeader->dwArchiveSize)
                    {
                        break;
                    }
                }

                if(ha->pHeader->wFormatVersion == MPQ_FORMAT_VERSION_2)
                {
                    break;
                }

                nError = ERROR_NOT_SUPPORTED;
                break;
            }

            // If a MPQ shunt already has been found, 
            // and no MPQ header was at potision pointed by the shunt,
            // then the archive is corrupt
            if(ha->pShunt != NULL)
            {
                nError = ERROR_BAD_FORMAT;

⌨️ 快捷键说明

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