Code Search for Developers
 
 
  

SFileOpenFileEx.cpp from MaNGOS at Krugle


Show SFileOpenFileEx.cpp syntax highlighted

/*****************************************************************************/
/* SFileOpenFileEx.cpp                    Copyright (c) Ladislav Zezula 2003 */
/*---------------------------------------------------------------------------*/
/* Description :                                                             */
/*---------------------------------------------------------------------------*/
/*   Date    Ver   Who  Comment                                              */
/* --------  ----  ---  -------                                              */
/* xx.xx.99  1.00  Lad  The first version of SFileOpenFileEx.cpp             */
/*****************************************************************************/

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

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

// TODO: Test for archives > 4GB
static BOOL OpenLocalFile(const char * szFileName, HANDLE * phFile)
{
    TMPQFile * hf = NULL;
    HANDLE hFile = CreateFile(szFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);

    if(hFile != INVALID_HANDLE_VALUE)
    {
        // Allocate and initialize file handle
        size_t nHandleSize = sizeof(TMPQFile) + strlen(szFileName); 
        if((hf = (TMPQFile *)ALLOCMEM(char, nHandleSize)) != NULL)
        {
            memset(hf, 0, nHandleSize);
            strcpy(hf->szFileName, szFileName);
            hf->hFile = hFile;
            *phFile   = hf;
            return TRUE;
        }
        else
            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
    }
    *phFile = NULL;
    return FALSE;
}

// TODO: Test for archives > 4GB
static void FreeMPQFile(TMPQFile *& hf)
{
    if(hf != NULL)
    {
        if(hf->hFile != INVALID_HANDLE_VALUE)
            CloseHandle(hf->hFile);
        if(hf->pdwBlockPos != NULL)
            FREEMEM(hf->pdwBlockPos);
        if(hf->pbFileBuffer != NULL)
            FREEMEM(hf->pbFileBuffer);
        FREEMEM(hf);
        hf = NULL;
    }
}

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

//-----------------------------------------------------------------------------
// SFileEnumLocales enums all locale versions within MPQ. 
// Functions fills all available language identifiers on a file into the buffer
// pointed by plcLocales. There must be enough entries to copy the localed,
// otherwise the function returns ERROR_INSUFFICIENT_BUFFER.

// TODO: Test for archives > 4GB
int WINAPI SFileEnumLocales(
    HANDLE hMPQ,
    const char * szFileName,
    LCID * plcLocales,
    DWORD * pdwMaxLocales,
    DWORD dwSearchScope)
{
    TMPQArchive * ha = (TMPQArchive *)hMPQ;
    TMPQHash * pHash = NULL;
    TMPQHash * pHashEnd = NULL;
    DWORD dwLocales = 0;
    int nError = ERROR_SUCCESS;

    // Test the parameters
    if(nError == ERROR_SUCCESS)
    {
        if(!IsValidMpqHandle(ha) || pdwMaxLocales == NULL)
            nError = ERROR_INVALID_PARAMETER;
        if(dwSearchScope == SFILE_OPEN_BY_INDEX && (DWORD_PTR)szFileName > ha->pHeader->dwBlockTableSize)
            nError = ERROR_INVALID_PARAMETER;
        if(dwSearchScope != SFILE_OPEN_BY_INDEX && *szFileName == 0)
            nError = ERROR_INVALID_PARAMETER;
    }

    // Retrieve the hash entry for the required file
    if(nError == ERROR_SUCCESS)
    {
        pHashEnd = ha->pHashTable + ha->pHeader->dwHashTableSize;

        if(dwSearchScope == SFILE_OPEN_BY_INDEX)
        {
            for(pHash = ha->pHashTable; pHash < pHashEnd; pHash++)
            {
                if(pHash->dwBlockIndex == (DWORD_PTR)szFileName)
                    break;
            }
            if(pHash == pHashEnd)
                pHash = NULL;
        }
        else
            pHash = GetHashEntry(ha, szFileName);
    }

    // If the file was not found, sorry
    if(nError == ERROR_SUCCESS)
    {
        if(pHash == NULL)
            nError = ERROR_FILE_NOT_FOUND;
    }

    // Count the entries which correspond to the same file name
    if(nError == ERROR_SUCCESS)
    {
        TMPQHash * pSaveHash = pHash;
        DWORD dwName1 = pHash->dwName1;
        DWORD dwName2 = pHash->dwName2;

        // For nameless access, return 1 locale always
        if(dwSearchScope == SFILE_OPEN_BY_INDEX)
            dwLocales++;
        else
        {
            while(pHash < pHashEnd && pHash->dwName1 == dwName1 && pHash->dwName2 == dwName2)
            {
                dwLocales++;
                pHash++;
            }
        }

        pHash = pSaveHash;
    }

    // Test if there is enough space to copy the locales
    if(nError == ERROR_SUCCESS)
    {
        DWORD dwMaxLocales = *pdwMaxLocales;

        *pdwMaxLocales = dwLocales;
        if(dwMaxLocales < dwLocales)
            nError = ERROR_INSUFFICIENT_BUFFER;
    }

    // Fill all the locales
    if(nError == ERROR_SUCCESS)
    {
        for(DWORD i = 0; i < dwLocales; i++, pHash++)
            *plcLocales++ = (LCID)pHash->lcLocale;
    }
    return nError;
}

//-----------------------------------------------------------------------------
// SFileHasFile
//
//   hMPQ          - Handle of opened MPQ archive
//   szFileName    - Name of file to look for

// TODO: Test for archives > 4GB
BOOL WINAPI SFileHasFile(HANDLE hMPQ, char * szFileName)
{
    TMPQArchive * ha = (TMPQArchive *)hMPQ;
    int nError = ERROR_SUCCESS;

    if(nError == ERROR_SUCCESS)
    {
        if(ha == NULL)
            nError = ERROR_INVALID_PARAMETER;
        if(*szFileName == 0)
            nError = ERROR_INVALID_PARAMETER;
    }

    // Prepare the file opening
    if(nError == ERROR_SUCCESS)
    {
        if(GetHashEntryEx(ha, szFileName, lcLocale) == NULL)
        {
            nError = ERROR_FILE_NOT_FOUND;
        }
    }

    // Cleanup
    if(nError != ERROR_SUCCESS)
    {
        SetLastError(nError);
    }

    return (nError == ERROR_SUCCESS);
}


//-----------------------------------------------------------------------------
// SFileOpenFileEx
//
//   hMPQ          - Handle of opened MPQ archive
//   szFileName    - Name of file to open
//   dwSearchScope - Where to search
//   phFile        - Pointer to store opened file handle

// TODO: Test for archives > 4GB
BOOL WINAPI SFileOpenFileEx(HANDLE hMPQ, const char * szFileName, DWORD dwSearchScope, HANDLE * phFile)
{
    LARGE_INTEGER FilePos;
    TMPQArchive * ha = (TMPQArchive *)hMPQ;
    TMPQFile    * hf = NULL;
    TMPQHash    * pHash  = NULL;        // Hash table index
    TMPQBlock   * pBlock = NULL;        // File block
    TMPQBlockEx * pBlockEx = NULL;
    DWORD dwHashIndex  = 0;             // Hash table index
    DWORD dwBlockIndex = (DWORD)-1;     // Found table index
    size_t nHandleSize = 0;             // Memory space necessary to allocate TMPQHandle
    int nError = ERROR_SUCCESS;

#ifdef _DEBUG    
    // Due to increasing numbers of files in MPQs, I had to change the behavior
    // of opening by file index. Now, the SFILE_OPEN_BY_INDEX value of dwSearchScope
    // must be entered. This check will allow to find code places that are incompatible
    // with the new behavior.
    if(dwSearchScope != SFILE_OPEN_BY_INDEX && szFileName != NULL)
    {
        assert((DWORD_PTR)szFileName > 0x10000);
    }
#endif

    if(nError == ERROR_SUCCESS)
    {
        if(ha == NULL && dwSearchScope == SFILE_OPEN_FROM_MPQ)
            nError = ERROR_INVALID_PARAMETER;
        if(phFile == NULL)
            nError = ERROR_INVALID_PARAMETER;
        if(dwSearchScope == SFILE_OPEN_BY_INDEX && (DWORD_PTR)szFileName > ha->pHeader->dwBlockTableSize)
            nError = ERROR_INVALID_PARAMETER;
        if(dwSearchScope != SFILE_OPEN_BY_INDEX && (szFileName == NULL || *szFileName == 0))
            nError = ERROR_INVALID_PARAMETER;
    }

    // Prepare the file opening
    if(nError == ERROR_SUCCESS)
    {
        // When the file is given by number, ...
        if(dwSearchScope == SFILE_OPEN_BY_INDEX)
        {
            TMPQHash * pHashEnd = ha->pHashTable + ha->pHeader->dwHashTableSize;

            // Set handle size to be sizeof(TMPQFile) + length of FileXXXXXXXX.xxx
            nHandleSize  = sizeof(TMPQFile) + 20;
            for(pHash = ha->pHashTable; pHash < pHashEnd; pHash++)
            {
                if((DWORD_PTR)szFileName == pHash->dwBlockIndex)
                {
                    dwHashIndex  = (DWORD)(pHash - ha->pHashTable);
                    dwBlockIndex = pHash->dwBlockIndex;
                    break;
                }
            }
        }
        else
        {
            // If we have to open a disk file
            if(dwSearchScope == SFILE_OPEN_LOCAL_FILE)
                return OpenLocalFile(szFileName, phFile);

            nHandleSize = sizeof(TMPQFile) + strlen(szFileName);
            if((pHash = GetHashEntryEx(ha, szFileName, lcLocale)) != NULL)
            {
                dwHashIndex  = (DWORD)(pHash - ha->pHashTable);
                dwBlockIndex = pHash->dwBlockIndex;
            }
        }
    }

    // Get block index from file name and test it
    if(nError == ERROR_SUCCESS)
    {
        // If index was not found, or is greater than number of files, exit.
        if(dwBlockIndex == (DWORD)-1 || dwBlockIndex > ha->pHeader->dwBlockTableSize)
            nError = ERROR_FILE_NOT_FOUND;
    }

    // Get block and test if the file was not already deleted.
    if(nError == ERROR_SUCCESS)
    {
        // Get both block tables and file position
        pBlockEx = ha->pExtBlockTable + dwBlockIndex;
        pBlock = ha->pBlockTable + dwBlockIndex;
        FilePos.HighPart = pBlockEx->wFilePosHigh;
        FilePos.LowPart = pBlock->dwFilePos;

        if(FilePos.QuadPart > ha->MpqSize.QuadPart ||
           pBlock->dwCSize > ha->MpqSize.QuadPart)
            nError = ERROR_FILE_CORRUPT;
        if((pBlock->dwFlags & MPQ_FILE_EXISTS) == 0)
            nError = ERROR_FILE_NOT_FOUND;
        if(pBlock->dwFlags & ~MPQ_FILE_VALID_FLAGS)
            nError = ERROR_NOT_SUPPORTED;
    }

    // Allocate file handle
    if(nError == ERROR_SUCCESS)
    {
        if((hf = (TMPQFile *)ALLOCMEM(char, nHandleSize)) == NULL)
            nError = ERROR_NOT_ENOUGH_MEMORY;
    }

    // Initialize file handle
    if(nError == ERROR_SUCCESS)
    {
        memset(hf, 0, nHandleSize);
        hf->hFile    = INVALID_HANDLE_VALUE;
        hf->ha       = ha;
        hf->pBlockEx = pBlockEx;
        hf->pBlock   = pBlock;
        hf->nBlocks  = (hf->pBlock->dwFSize + ha->dwBlockSize - 1) / ha->dwBlockSize;
        hf->pHash    = pHash;
        
        hf->MpqFilePos.HighPart = pBlockEx->wFilePosHigh;
        hf->MpqFilePos.LowPart = pBlock->dwFilePos;
        hf->MpqFilePos.QuadPart += ha->MpqPos.QuadPart;

        hf->dwHashIndex = dwHashIndex;
        hf->dwFileIndex = dwBlockIndex; 

        // Allocate buffers for decompression.
        if(hf->pBlock->dwFlags & MPQ_FILE_COMPRESSED)
        {
            // Allocate buffer for block positions. At the begin of file are stored
            // DWORDs holding positions of each block relative from begin of file in the archive
            // As for newer MPQs, there may be one additional entry in the block table
            // (if the MPQ_FILE_HAS_EXTRA flag is set).
            // Allocate the buffer to include this DWORD as well
            
            if((hf->pdwBlockPos = ALLOCMEM(DWORD, hf->nBlocks + 2)) == NULL)
                nError = ERROR_NOT_ENOUGH_MEMORY;
        }
        
        // Decrypt file seed. Cannot be used if the file is given by index
        if(dwSearchScope != SFILE_OPEN_BY_INDEX)
        {
            if(hf->pBlock->dwFlags & MPQ_FILE_ENCRYPTED)
            {
                const char * szTemp = strrchr(szFileName, '\\');

                strcpy(hf->szFileName, szFileName);
                if(szTemp != NULL)
                    szFileName = szTemp + 1;
                hf->dwSeed1 = DecryptFileSeed((char *)szFileName);

                if(hf->pBlock->dwFlags & MPQ_FILE_FIXSEED)
                {
                    hf->dwSeed1 = (hf->dwSeed1 + hf->pBlock->dwFilePos) ^ hf->pBlock->dwFSize;
                }
            }
        }
        else
        {
            // If the file is encrypted and not compressed, we cannot detect the file seed
            if(SFileGetFileName(hf, hf->szFileName) == FALSE)
                nError = GetLastError();
        }
    }

    // Cleanup
    if(nError != ERROR_SUCCESS)
    {
        FreeMPQFile(hf);
        SetLastError(nError);
    }

    *phFile = hf;
    return (nError == ERROR_SUCCESS);
}

//-----------------------------------------------------------------------------
// BOOL SFileCloseFile(HANDLE hFile);

// TODO: Test for archives > 4GB
BOOL WINAPI SFileCloseFile(HANDLE hFile)
{
    TMPQFile * hf = (TMPQFile *)hFile;
    
    if(!IsValidFileHandle(hf))
    {
        SetLastError(ERROR_INVALID_PARAMETER);
        return FALSE;
    }

    // Set the last accessed file in the archive
    if(hf->ha != NULL)
        hf->ha->pLastFile = NULL;

    // Free the structure
    FreeMPQFile(hf);
    return TRUE;
}




See more files for this project here

MaNGOS

MaNGOS is an object-oriented Massively Multiplayer Online Role-Playing Game Server (MMORPGS). It\'s an educational project, to help developers get familar with large scale C++ and C# development projects.

Project homepage: http://sourceforge.net/projects/mangos
Programming language(s): C,C++,SQL
License: gpl2

  bzip2/
    CHANGES
    LICENSE
    Makefile
    Makefile-libbz2_so
    README
    README.COMPILATION.PROBLEMS
    README.XML.STUFF
    Y2K_INFO
    blocksort.c
    bz-common.xsl
    bz-fo.xsl
    bz-html.xsl
    bzdiff
    bzdiff.1
    bzgrep
    bzgrep.1
    bzip.css
    bzip2.1
    bzip2.1.preformatted
    bzip2.c
    bzip2.txt
    bzip2recover.c
    bzlib.c
    bzlib.h
    bzlib_private.h
    bzmore
    bzmore.1
    compress.c
    crctable.c
    decompress.c
    dlltest.c
    dlltest.dsp
    entities.xml
    format.pl
    huffman.c
    libbz2.def
    libbz2.dsp
    makefile.msc
    manual.html
    manual.pdf
    manual.ps
    manual.xml
    mk251.c
    randtable.c
    sample1.bz2
    sample1.ref
    sample2.bz2
    sample2.ref
    sample3.bz2
    sample3.ref
    spewG.c
    unzcrash.c
    words0
    words1
    words2
    words3
    xmlproc.sh
  huffman/
    huff.cpp
    huff.h
  pklib/
    crc32.c
    crc32_pk.c
    explode.c
    implode.c
    pklib.h
  wave/
    wave.cpp
    wave.h
  zlib/
    amiga/
    contrib/
    msdos/
    nt/
    os2/
    ChangeLog
    FAQ
    INDEX
    Makefile
    Makefile.in
    Makefile.riscos
    README
    adler32.c
    algorithm.txt
    compress.c
    configure
    crc32.c
    deflate.c
    deflate.h
    descrip.mms
    example.c
    gzio.c
    infblock.c
    infblock.h
    infcodes.c
    infcodes.h
    inffast.c
    inffast.h
    inffixed.h
    inflate.c
    inftrees.c
    inftrees.h
    infutil.c
    infutil.h
    maketree.c
    minigzip.c
    trees.c
    trees.h
    uncompr.c
    zconf.h
    zlib.3
    zlib.h
    zlib.html
    zmemory.c
    zutil.c
    zutil.h
  GfxDecode.cpp
  Makefile
  SCommon.cpp
  SCommon.h
  SCompression.cpp
  SFileCompactArchive.cpp
  SFileCreateArchiveEx.cpp
  SFileExtractFile.cpp
  SFileFindFile.cpp
  SFileOpenArchive.cpp
  SFileOpenFileEx.cpp
  SFileReadFile.cpp
  SListFile.cpp
  StormDll.h
  StormLib.h
  StormPort.h
  StormPortLinux.cpp
  StormPortMac.cpp