Exemplo n.º 1
0
// Adds a name into the list of all names. For each locale in the MPQ,
// one entry will be created
// If the file name is already there, does nothing.
static int SListFileCreateNodeForAllLocales(TMPQArchive * ha, const char * szFileName)
{
    TMPQHeader * pHeader = ha->pHeader;
    TFileEntry * pFileEntry;
    TMPQHash * pFirstHash;
    TMPQHash * pHash;
    bool bNameEntryCreated = false;

    // If we have HET table, use that one
    if(ha->pHetTable != NULL)
    {
        pFileEntry = GetFileEntryAny(ha, szFileName);
        if(pFileEntry != NULL)
        {
            // Allocate file name for the file entry
            AllocateFileName(pFileEntry, szFileName);
            bNameEntryCreated = true;
        }

        return ERROR_SUCCESS;
    }

    // If we have hash table, we use it
    if(bNameEntryCreated == false && ha->pHashTable != NULL)
    {
        // Look for the first hash table entry for the file
        pFirstHash = pHash = GetFirstHashEntry(ha, szFileName);

        // Go while we found something
        while(pHash != NULL)
        {
            // Is it a valid file table index ?
            if(pHash->dwBlockIndex < pHeader->dwBlockTableSize)
            {
                // Allocate file name for the file entry
                AllocateFileName(ha->pFileTable + pHash->dwBlockIndex, szFileName);
                bNameEntryCreated = true;
            }

            // Now find the next language version of the file
            pHash = GetNextHashEntry(ha, pFirstHash, pHash);
        }
    }

    return ERROR_CAN_NOT_COMPLETE;
}
Exemplo n.º 2
0
static int CreatePseudoFileName(void * hFile, TFileEntry * pFileEntry, char * szFileName)
{
    TMPQFile * hf = (TMPQFile *)hFile;  /* MPQ File handle */
    uint32_t FirstBytes[2] = {0, 0};       /* The first 4 bytes of the file */
    size_t dwBytesRead = 0;
    size_t dwFilePos;                    /* Saved file position */

    /* Read the first 2 uint32_ts bytes from the file */
    dwFilePos = SFileSetFilePointer(hFile, 0, NULL, SEEK_CUR);   
    SFileReadFile(hFile, FirstBytes, sizeof(FirstBytes), &dwBytesRead);
    SFileSetFilePointer(hFile, dwFilePos, NULL, SEEK_SET);

    /* If we read at least 8 bytes */
    if(dwBytesRead == sizeof(FirstBytes))
    {
        size_t i;
        
        /* Make sure that the array is properly BSWAP-ed */
        BSWAP_ARRAY32_UNSIGNED(FirstBytes, sizeof(FirstBytes));

        /* Try to guess file extension from those 2 ints */
        for(i = 0; data2ext[i].szExt != NULL; i++)
        {
            if((FirstBytes[0] & data2ext[i].dwOffset00Mask) == data2ext[i].dwOffset00Data &&
               (FirstBytes[1] & data2ext[i].dwOffset04Mask) == data2ext[i].dwOffset04Data)
            {
                char szPseudoName[20] = "";    

                /* Format the pseudo-name */
                sprintf(szPseudoName, "File%08u.%s", (unsigned int)(pFileEntry - hf->ha->pFileTable), data2ext[i].szExt);

                /* Save the pseudo-name in the file entry as well */
                AllocateFileName(hf->ha, pFileEntry, szPseudoName);

                /* If the caller wants to copy the file name, do it */
                if(szFileName != NULL)
                    strcpy(szFileName, szPseudoName);
                return ERROR_SUCCESS;
            }
        }
    }

    return ERROR_CAN_NOT_COMPLETE;
}
Exemplo n.º 3
0
void LoadFileTimesAndSizes(
    BOOL        fUseSuckDATFile
) {
    CHAR        cPath[MAX_PATH];
    FILEHEADER  fileheader;
    int         iCount;

    //
    // Initialize the tree root
    //
    fnRoot = AllocateFileName();

    fnRoot->fnParent.mem_ptr  = NULL;
    fnRoot->fnChild.mem_ptr   = NULL;
    fnRoot->fnSibling.mem_ptr = NULL;
    strcpy( fnRoot->cFileName, "<ROOT>" );

    // Look for SUCK.DAT

    if ( fUseSuckDATFile ) {
        SuckDATFile = fopen( SUCK_DAT_FILE, "rb" );
    } else {
        SuckDATFile == NULL;
    }

    if ( SuckDATFile != NULL ) {
        //
        // If file exists, then load the data from it.
        //
        printf("Loading Previous Statistics...\n");

        iCount = fread( &fileheader, sizeof(fileheader), 1, SuckDATFile );

        if ( iCount != 1 ) {
            printf("Error reading SUCK.DAT file, remove and restart\n");
            exit(1);
        }

        EnumDATFileData( fnRoot, fileheader.fnRoot.disk_ptr );

        fclose( SuckDATFile );

    }
}
Exemplo n.º 4
0
static int CreatePseudoFileName(HANDLE hFile, TFileEntry * pFileEntry, char * szFileName)
{
    TMPQFile * hf = (TMPQFile *)hFile;  // MPQ File handle
    DWORD FirstBytes[2] = {0, 0};       // The first 4 bytes of the file
    DWORD dwBytesRead = 0;
    DWORD dwFilePos;                    // Saved file position

    // Read the first 2 DWORDs bytes from the file
    dwFilePos = SFileSetFilePointer(hFile, 0, NULL, FILE_CURRENT);   
    SFileReadFile(hFile, FirstBytes, sizeof(FirstBytes), &dwBytesRead, NULL);
    SFileSetFilePointer(hFile, dwFilePos, NULL, FILE_BEGIN);

    // If we read at least 8 bytes
    if(dwBytesRead == sizeof(FirstBytes))
    {
        // Make sure that the array is properly BSWAP-ed
        BSWAP_ARRAY32_UNSIGNED(FirstBytes, sizeof(FirstBytes));

        // Try to guess file extension from those 2 DWORDs
        for(size_t i = 0; data2ext[i].szExt != NULL; i++)
        {
            if((FirstBytes[0] & data2ext[i].dwOffset00Mask) == data2ext[i].dwOffset00Data &&
               (FirstBytes[1] & data2ext[i].dwOffset04Mask) == data2ext[i].dwOffset04Data)
            {
                char szPseudoName[20] = "";    

                // Format the pseudo-name
                sprintf(szPseudoName, "File%08u.%s", (unsigned int)(pFileEntry - hf->ha->pFileTable), data2ext[i].szExt);

                // Save the pseudo-name in the file entry as well
                AllocateFileName(hf->ha, pFileEntry, szPseudoName);

                // If the caller wants to copy the file name, do it
                if(szFileName != NULL)
                    strcpy(szFileName, szPseudoName);
                return ERROR_SUCCESS;
            }
        }
    }

    return ERROR_CAN_NOT_COMPLETE;
}
Exemplo n.º 5
0
bool WINAPI SFileOpenFileEx(HANDLE hMpq, const char * szFileName, DWORD dwSearchScope, HANDLE * phFile)
{
    TMPQArchive * ha = (TMPQArchive *)hMpq;
    TFileEntry  * pFileEntry = NULL;
    TMPQFile    * hf = NULL;
    DWORD dwFileIndex = 0;
    bool bOpenByIndex = false;
    int nError = ERROR_SUCCESS;

    // Don't accept NULL pointer to file handle
    if(phFile == NULL)
        nError = ERROR_INVALID_PARAMETER;

    // Prepare the file opening
    if(nError == ERROR_SUCCESS)
    {
        switch(dwSearchScope)
        {
            case SFILE_OPEN_FROM_MPQ:
            case SFILE_OPEN_BASE_FILE:
                
                if(!IsValidMpqHandle(ha))
                {
                    nError = ERROR_INVALID_HANDLE;
                    break;
                }

                if(szFileName == NULL || *szFileName == 0)
                {
                    nError = ERROR_INVALID_PARAMETER;
                    break;
                }

                // Check the pseudo-file name
                if(IsPseudoFileName(szFileName, &dwFileIndex))
                {
                    pFileEntry = GetFileEntryByIndex(ha, dwFileIndex);
                    bOpenByIndex = true;
                    if(pFileEntry == NULL)
                        nError = ERROR_FILE_NOT_FOUND;
                }
                else
                {
                    // If this MPQ is a patched archive, open the file as patched
                    if(ha->haPatch == NULL || dwSearchScope == SFILE_OPEN_BASE_FILE)
                    {
                        // Otherwise, open the file from *this* MPQ
                        pFileEntry = GetFileEntryLocale(ha, szFileName, lcFileLocale);
                        if(pFileEntry == NULL)
                            nError = ERROR_FILE_NOT_FOUND;
                    }
                    else
                    {
                        return OpenPatchedFile(hMpq, szFileName, 0, phFile);
                    }
                }
                break;

            case SFILE_OPEN_ANY_LOCALE:

                // This open option is reserved for opening MPQ internal listfile.
                // No argument validation. Tries to open file with neutral locale first,
                // then any other available.
                pFileEntry = GetFileEntryAny(ha, szFileName);
                if(pFileEntry == NULL)
                    nError = ERROR_FILE_NOT_FOUND;
                break;

            case SFILE_OPEN_LOCAL_FILE:

                if(szFileName == NULL || *szFileName == 0)
                {
                    nError = ERROR_INVALID_PARAMETER;
                    break;
                }

                return OpenLocalFile(szFileName, phFile); 

            default:

                // Don't accept any other value
                nError = ERROR_INVALID_PARAMETER;
                break;
        }

        // Quick return if something failed
        if(nError != ERROR_SUCCESS)
        {
            SetLastError(nError);
            return false;
        }
    }

    // Test if the file was not already deleted.
    if(nError == ERROR_SUCCESS)
    {
        if((pFileEntry->dwFlags & MPQ_FILE_EXISTS) == 0)
            nError = ERROR_FILE_NOT_FOUND;
        if(pFileEntry->dwFlags & ~MPQ_FILE_VALID_FLAGS)
            nError = ERROR_NOT_SUPPORTED;
    }

    // Allocate file handle
    if(nError == ERROR_SUCCESS)
    {
        if((hf = STORM_ALLOC(TMPQFile, 1)) == NULL)
            nError = ERROR_NOT_ENOUGH_MEMORY;
    }

    // Initialize file handle
    if(nError == ERROR_SUCCESS)
    {
        memset(hf, 0, sizeof(TMPQFile));
        hf->pFileEntry = pFileEntry;
        hf->dwMagic = ID_MPQ_FILE;
        hf->ha = ha;

        hf->MpqFilePos   = pFileEntry->ByteOffset;
        hf->RawFilePos   = ha->MpqPos + hf->MpqFilePos;
        hf->dwDataSize   = pFileEntry->dwFileSize;

        // If the MPQ has sector CRC enabled, enable if for the file
        if(ha->dwFlags & MPQ_FLAG_CHECK_SECTOR_CRC)
            hf->bCheckSectorCRCs = true;

        // If we know the real file name, copy it to the file entry
        if(bOpenByIndex == false)
        {
            // If there is no file name yet, allocate it
            AllocateFileName(pFileEntry, szFileName);

            // If the file is encrypted, we should detect the file key
            if(pFileEntry->dwFlags & MPQ_FILE_ENCRYPTED)
            {
                hf->dwFileKey = DecryptFileKey(szFileName,
                                               pFileEntry->ByteOffset,
                                               pFileEntry->dwFileSize,
                                               pFileEntry->dwFlags);
            }
        }
        else
        {
            // Try to auto-detect the file name
            if(!SFileGetFileName(hf, NULL))
                nError = GetLastError();
        }
    }

    // If the file is actually a patch file, we have to load the patch file header
    if(nError == ERROR_SUCCESS && pFileEntry->dwFlags & MPQ_FILE_PATCH_FILE)
    {
        assert(hf->pPatchInfo == NULL);
        nError = AllocatePatchInfo(hf, true);
    }

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

    *phFile = hf;
    return (nError == ERROR_SUCCESS);
}
Exemplo n.º 6
0
bool WINAPI SFileOpenFileEx(HANDLE hMpq, const char * szFileName, DWORD dwSearchScope, HANDLE * PtrFile)
{
    TMPQArchive * ha = IsValidMpqHandle(hMpq);
    TFileEntry  * pFileEntry = NULL;
    TMPQFile    * hf = NULL;
    DWORD dwHashIndex = HASH_ENTRY_FREE;
    DWORD dwFileIndex = 0;
    bool bOpenByIndex = false;
    int nError = ERROR_SUCCESS;

    // Don't accept NULL pointer to file handle
    if(szFileName == NULL || *szFileName == 0)
        nError = ERROR_INVALID_PARAMETER;

    // When opening a file from MPQ, the handle must be valid
    if(dwSearchScope != SFILE_OPEN_LOCAL_FILE && ha == NULL)
        nError = ERROR_INVALID_HANDLE;

    // When not checking for existence, the pointer to file handle must be valid
    if(dwSearchScope != SFILE_OPEN_CHECK_EXISTS && PtrFile == NULL)
        nError = ERROR_INVALID_PARAMETER;

    // Prepare the file opening
    if(nError == ERROR_SUCCESS)
    {
        switch(dwSearchScope)
        {
            case SFILE_OPEN_FROM_MPQ:
            case SFILE_OPEN_BASE_FILE:
            case SFILE_OPEN_CHECK_EXISTS:
                
                // Check the pseudo-file name
                if((bOpenByIndex = IsPseudoFileName(szFileName, &dwFileIndex)) == true)
                {
                    // Get the file entry for the file
                    if(dwFileIndex > ha->dwFileTableSize)
                        break;
                    pFileEntry = ha->pFileTable + dwFileIndex;
                }
                else
                {
                    // If this MPQ has no patches, open the file from this MPQ directly
                    if(ha->haPatch == NULL || dwSearchScope == SFILE_OPEN_BASE_FILE)
                    {
                        pFileEntry = GetFileEntryLocale2(ha, szFileName, lcFileLocale, &dwHashIndex);
                    }

                    // If this MPQ is a patched archive, open the file as patched
                    else
                    {
                        return OpenPatchedFile(hMpq, szFileName, PtrFile);
                    }
                }
                break;

            case SFILE_OPEN_ANY_LOCALE:

                // This open option is reserved for opening MPQ internal listfile.
                // No argument validation. Tries to open file with neutral locale first,
                // then any other available.
                pFileEntry = GetFileEntryLocale2(ha, szFileName, 0, &dwHashIndex);
                break;

            case SFILE_OPEN_LOCAL_FILE:

                // Open a local file
                return OpenLocalFile(szFileName, PtrFile); 

            default:

                // Don't accept any other value
                nError = ERROR_INVALID_PARAMETER;
                break;
        }
    }

    // Check whether the file really exists in the MPQ
    if(nError == ERROR_SUCCESS)
    {
        if(pFileEntry == NULL || (pFileEntry->dwFlags & MPQ_FILE_EXISTS) == 0)
            nError = ERROR_FILE_NOT_FOUND;

        // Ignore unknown loading flags (example: MPQ_2016_v1_WME4_4.w3x)
//      if(pFileEntry != NULL && pFileEntry->dwFlags & ~MPQ_FILE_VALID_FLAGS)
//          nError = ERROR_NOT_SUPPORTED;
    }

    // Did the caller just wanted to know if the file exists?
    if(nError == ERROR_SUCCESS && dwSearchScope != SFILE_OPEN_CHECK_EXISTS)
    {
        // Allocate file handle
        hf = CreateFileHandle(ha, pFileEntry);
        if(hf != NULL)
        {
            // Get the hash index for the file
            if(ha->pHashTable != NULL && dwHashIndex == HASH_ENTRY_FREE)
                dwHashIndex = FindHashIndex(ha, dwFileIndex);
            if(dwHashIndex != HASH_ENTRY_FREE)
                hf->pHashEntry = ha->pHashTable + dwHashIndex;
            hf->dwHashIndex = dwHashIndex;

            // If the MPQ has sector CRC enabled, enable if for the file
            if(ha->dwFlags & MPQ_FLAG_CHECK_SECTOR_CRC)
                hf->bCheckSectorCRCs = true;

            // If we know the real file name, copy it to the file entry
            if(bOpenByIndex == false)
            {
                // If there is no file name yet, allocate it
                AllocateFileName(ha, pFileEntry, szFileName);

                // If the file is encrypted, we should detect the file key
                if(pFileEntry->dwFlags & MPQ_FILE_ENCRYPTED)
                {
                    hf->dwFileKey = DecryptFileKey(szFileName,
                                                   pFileEntry->ByteOffset,
                                                   pFileEntry->dwFileSize,
                                                   pFileEntry->dwFlags);
                }
            }
        }
        else
        {
            nError = ERROR_NOT_ENOUGH_MEMORY;
        }
    }

    // Give the file entry
    if(PtrFile != NULL)
        PtrFile[0] = hf;

    // Return error code
    if(nError != ERROR_SUCCESS)
        SetLastError(nError);
    return (nError == ERROR_SUCCESS);
}
Exemplo n.º 7
0
void EnumDATFileData(
    FILENAME    *fnParent,
    DWORD       dwDiskPtr
) {
    FILENAME    fnDiskName;
    FILENAME    *fnChild = &fnDiskName;
    FILENAME    *fnCurrent;
    int         iSeek;
    int         iCount;

    //
    // Read in this level from the DAT file
    //
    while ( dwDiskPtr != 0 ) {

        // Seek to this entry

        iSeek = fseek( SuckDATFile, dwDiskPtr, SEEK_SET );

        if ( iSeek != 0 ) {
            printf("SUCK.DAT seek error, remove and restart\n");
            exit(3);
        }

        // Read in this entry

        iCount = fread( (void *)fnChild, sizeof(FILENAME), 1, SuckDATFile );
        if ( iCount != 1 ) {
            printf("SUCK.DAT read error, remove and restart\n");
            exit(4);
        }

#ifdef SEE_EM
printf("Reading record [%s], at %08lX Child %08lX Sib %08lX\n", fnChild->cFileName, dwDiskPtr, fnChild->fnChild.disk_ptr, fnChild->fnSibling.disk_ptr );
printf("Size = %d\n", fnChild->dwFileSizeLow );
#endif

        //
        // Add this file node to the tree
        //

        fnCurrent = AllocateFileName();


        fnCurrent->dwStatus          = fnChild->dwStatus;
        fnCurrent->dwCopy            = 0;

        fnCurrent->fnParent.mem_ptr  = fnParent;
        fnCurrent->fnChild.mem_ptr   = NULL;

        fnCurrent->fnSibling.mem_ptr = fnParent->fnChild.mem_ptr;

        fnCurrent->dwFileSizeLow     = 0;
        fnCurrent->dwFileSizeHigh    = 0;
        fnCurrent->ftFileTime        = ftZero;
        fnCurrent->dwDATFileSizeLow  = fnChild->dwFileSizeLow;
        fnCurrent->dwDATFileSizeHigh = fnChild->dwFileSizeHigh;
        fnCurrent->ftDATFileTime     = fnChild->ftFileTime;

        fnCurrent->dwFileNameLen     = fnChild->dwFileNameLen;
        strcpy( fnCurrent->cFileName, fnChild->cFileName );

        fnParent->fnChild.mem_ptr = fnCurrent;

        if ( (fnCurrent->dwStatus & DIRECTORY) == DIRECTORY ) {
            nDirectories++;
            //
            // Load this directories children
            //
            EnumDATFileData( fnCurrent, fnChild->fnChild.disk_ptr );
        } else {
            fnCurrent->dwStatus = 0;
            nFiles++;
        }

        // Move to next sibling at this level

        dwDiskPtr = fnChild->fnSibling.disk_ptr;
    }
}
Exemplo n.º 8
0
VOID AddFile(
    FILENAME            *fn,
    LPWIN32_FIND_DATA   lpwfd,
    DWORD               mask
) {
    CHAR        *pdest;
    CHAR        *psrc;
    INT         count;
    INT         maximum;
    FILENAME    *fnCurrent;
    FILENAME    *fnChild;
    DWORD       dwFileNameLen;
    CHAR        NewName[MAX_FILENAME_LENGTH+1];
    FILENAME    *fnChildOriginally;

    if ( *lpwfd->cFileName == '.' ) {
        return;
    }

    dwFileNameLen = strlen(lpwfd->cFileName);
    if (dwFileNameLen > MAX_FILENAME_LENGTH) {
        fprintf(stderr, "File name %s too long (%u > %u), complain to BobDay\n",
                lpwfd->cFileName, dwFileNameLen, MAX_FILENAME_LENGTH);
        return;
    }

    strcpy( NewName, lpwfd->cFileName );

    fnChild = fn->fnChild.mem_ptr;
    fnChildOriginally = fnChild;

    while ( fnChild ) {
        if ( fnChild->dwFileNameLen == dwFileNameLen &&
             !strcmp(NewName, fnChild->cFileName)
           ) {
            fnChild->dwStatus |= mask;           // Atomic instruction
            if ( fnChild->ftFileTime.dwLowDateTime == ftZero.dwLowDateTime
                 && fnChild->ftFileTime.dwHighDateTime == ftZero.dwHighDateTime ) {
                EnterCriticalSection( &cs );
                fnChild->dwFileSizeLow     = lpwfd->nFileSizeLow;
                fnChild->dwFileSizeHigh    = lpwfd->nFileSizeHigh;
                fnChild->ftFileTime        = lpwfd->ftLastWriteTime;
                LeaveCriticalSection( &cs );
            }
            nDuplicates++;
            return;
        }

        fnChild = fnChild->fnSibling.mem_ptr;
    }

    // Probably not there...  Enter the critical section now to prove it

    EnterCriticalSection( &cs );

    // Most common case, nobody has changed this directory at all.

    if ( fn->fnChild.mem_ptr != fnChildOriginally ) {

        // Otherwise, make another scan inside the critical section.

        fnChild = fn->fnChild.mem_ptr;

        while ( fnChild ) {
            if ( fnChild->dwFileNameLen == dwFileNameLen &&
                 !strcmp(NewName, fnChild->cFileName)
               ) {
                fnChild->dwStatus |= mask;           // Atomic instruction
                nDuplicates++;
                LeaveCriticalSection( &cs );
                return;
            }

            fnChild = fnChild->fnSibling.mem_ptr;
        }

    }

    fnCurrent = AllocateFileName();

    strcpy( fnCurrent->cFileName, NewName );
    fnCurrent->dwFileNameLen     = dwFileNameLen;
    fnCurrent->dwFileSizeLow     = lpwfd->nFileSizeLow;
    fnCurrent->dwFileSizeHigh    = lpwfd->nFileSizeHigh;
    fnCurrent->ftFileTime        = lpwfd->ftLastWriteTime;
    fnCurrent->dwDATFileSizeLow  = 0;
    fnCurrent->dwDATFileSizeHigh = 0;
    fnCurrent->ftDATFileTime     = ftZero;

    fnCurrent->dwCopy         = 0;

    fnCurrent->fnParent.mem_ptr  = fn;
    fnCurrent->fnChild.mem_ptr   = NULL;

    fnCurrent->fnSibling.mem_ptr = fn->fnChild.mem_ptr;
    fn->fnChild.mem_ptr = fnCurrent;

    if ( lpwfd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) {
        fnCurrent->dwStatus = DIRECTORY;
        nDirectories++;
    } else {
        fnCurrent->dwStatus = 0;
        nFiles++;
    }
    fnCurrent->dwStatus |= mask;

#ifdef SEE_EM
    { char text[MAX_FILENAME_LENGTH+1];
      memcpy( text, fnCurrent->cFileName, MAX_FILENAME_LENGTH );
      text[MAX_FILENAME_LENGTH] = '\0';

      if ( fnCurrent->dwStatus & DIRECTORY ) {
          printf("Munged  DirName = %08lX:[%s]\n", fnCurrent, text );
      } else {
          printf("Munged FileName = %08lX:[%s]\n", fnCurrent, text );
      }
    }
#endif
    LeaveCriticalSection( &cs );

}