Current News
Archived News
Search News
Discussion Forum


Old Forum
Install Programs More Downloads...
Troubleshooting
Source Code
Format Specs.
Misc. Information
Non-SF Stuff
Links




index 3c7d4fa..694d730 100644 (file)
@@ -4,7 +4,6 @@
 
 // Includes
 #include <windows.h>
-#include <malloc.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <ctype.h>
 
 #include "../SComp/SComp.h"
 
+#include "SFmpqInternal.h"
+#include "MpqCrypt.h"
+#include "MpqHashTable.h"
+#include "MpqBlockTable.h"
 #include "SFmpqapi.h"
+#include "SFUtil.h"
+#include "SFTypes.h"
 
 struct SFMPQAPIMODULE {
        SFMPQAPIMODULE();
@@ -49,6 +54,7 @@ SFMPQLIBMODULE::~SFMPQLIBMODULE()
 #endif
 
 LCID LocaleID = 0;
+WORD wCreationVersion = 0;
 BOOL SFMpqInit = FALSE;
 HINSTANCE hStorm = 0;
 #ifdef _USRDLL
@@ -88,15 +94,6 @@ LCID availLocales[7] = {0x0000,0x0407,0x0409,0x040A,0x040C,0x0410,0x0416};
 
 #define MAX_MPQ_PATH 260;
 
-#define HASH_POSITION 0
-#define HASH_NAME_A 1
-#define HASH_NAME_B 2
-#define HASH_KEY 3
-
-BOOL bCryptTableInit = FALSE;
-DWORD dwCryptTable[0x500];
-DWORD dwHashTableKey;
-DWORD dwBlockTableKey;
 MPQARCHIVE **lpOpenMpq = 0;
 DWORD dwOpenMpqCount = 0;
 MPQARCHIVE * FirstLastMpq[2] = {0,0};
@@ -106,9 +103,6 @@ MPQFILE * FirstLastFile[2] = {0,0};
 
 char StormBasePath[MAX_PATH+1];
 
-#define UNSUPPORTED_COMPRESSION   (0xFF ^ (0x40 | 0x80 | 0x01 | 0x02 | 0x08 | 0x10))
-#define UNSUPPORTED_DECOMPRESSION (0xFF ^ (0x40 | 0x80 | 0x01 | 0x02 | 0x08 | 0x10))
-
 typedef BOOL (WINAPI* funcSCompCompress)(LPVOID lpvDestinationMem, LPDWORD lpdwCompressedSize, LPVOID lpvSourceMem, DWORD dwDecompressedSize, DWORD dwCompressionType, DWORD dwCompressionSubType, DWORD dwWAVQuality);
 typedef BOOL (WINAPI* funcSCompDecompress)(LPVOID lpvDestinationMem, LPDWORD lpdwDecompressedSize, LPVOID lpvSourceMem, DWORD dwCompressedSize);
 funcSCompCompress stormSCompCompress = 0;
@@ -117,11 +111,8 @@ funcSCompDecompress stormSCompDecompress = 0;
 void LoadStorm();
 void FreeStorm();
 
-LPVOID WINAPI SFAlloc(DWORD dwSize);
-void WINAPI SFFree(LPVOID lpvMemory);
-void WINAPI SFMemZero(LPVOID lpvDestination, DWORD dwLength);
 BOOL WINAPI MpqOpenArchiveEx(LPCSTR lpFileName, DWORD dwPriority, DWORD dwFlags, MPQHANDLE *hMPQ, DWORD dwFlags2, DWORD dwMaximumFilesInArchive, DWORD dwBlockSize);
-DWORD WINAPI FindMpqHeaderAtLocation(HANDLE hFile, DWORD dwStart, DWORD dwLength);
+UInt64 WINAPI SFileFindMpqHeaderEx(HANDLE hFile, UInt64 qwStart = 0, UInt64 qwLength = 0);
 DWORD GetFullPath(LPCSTR lpFileName, char *lpBuffer, DWORD dwBufferLength);
 MPQHANDLE GetHashTableEntry(MPQHANDLE hMPQ, LPCSTR lpFileName, LCID FileLocale);
 MPQHANDLE GetHashTableEntryOfHash(MPQHANDLE hMPQ, DWORD dwTablePos, DWORD dwNameHashA, DWORD dwNameHashB, LCID FileLocale);
@@ -131,13 +122,6 @@ void SortOpenArchivesByPriority();
 DWORD GetHandleType(MPQHANDLE hFile);
 BOOL AddToInternalListing(MPQHANDLE hMPQ, LPCSTR lpFileName);
 BOOL RemoveFromInternalListing(MPQHANDLE hMPQ, LPCSTR lpFileName);
-size_t strlnlen(const char *strline);
-char *nextline(const char *strline);
-BOOL InitCryptTable();
-DWORD HashString(LPCSTR lpszString, DWORD dwHashType);
-BOOL EncryptData(LPBYTE lpbyBuffer, DWORD dwLength, DWORD dwKey);
-BOOL DecryptData(LPBYTE lpbyBuffer, DWORD dwLength, DWORD dwKey);
-static DWORD DetectFileSeed(DWORD * block, DWORD decrypted, DWORD blocksize);
 DWORD DetectFileSeedEx(MPQARCHIVE * mpqOpenArc, HASHTABLEENTRY * lpHashEntry, LPCSTR * lplpFileName);
 
 BOOL APIENTRY DllMain( HINSTANCE hInstDLL, 
@@ -204,38 +188,6 @@ BOOL APIENTRY DllMain( HINSTANCE hInstDLL,
     return TRUE;
 }
 
-LPVOID WINAPI SFAlloc(DWORD dwSize)
-{
-       LPVOID lpMemory = malloc(dwSize);
-       if (lpMemory) SFMemZero(lpMemory,dwSize);
-       return lpMemory;
-}
-
-void WINAPI SFFree(LPVOID lpvMemory)
-{
-       if (lpvMemory) free(lpvMemory);
-}
-
-void WINAPI SFMemZero(LPVOID lpvDestination, DWORD dwLength)
-{
-       DWORD dwPrevLen = dwLength;
-       LPDWORD lpdwDestination = (LPDWORD)lpvDestination;
-       LPBYTE lpbyDestination;
-
-       dwLength >>= 2;
-
-       while (dwLength--)
-               *lpdwDestination++ = 0;
-
-       lpbyDestination = (LPBYTE)lpdwDestination;
-
-       dwLength = dwPrevLen;
-       dwLength &= 3;
-
-       while (dwLength--)
-               *lpbyDestination++ = 0;
-}
-
 TempAlloc::TempAlloc()
 {
        lpAllocAddress = 0;
@@ -334,18 +286,155 @@ void SFMPQAPI WINAPI AboutSFMpq()
 #endif
 }
 
-BOOL WINAPI MpqOpenArchiveEx(LPCSTR lpFileName, DWORD dwPriority, DWORD dwFlags, MPQHANDLE *hMPQ, DWORD dwFlags2, DWORD dwMaximumFilesInArchive, DWORD dwBlockSize)
+BOOL MpqWriteHeaders(MPQARCHIVE *mpqOpenArc)
+{
+       DWORD nIOLen;
+       BOOL bReturnVal = FALSE;
+
+       SFSetFilePointer(mpqOpenArc->hFile, mpqOpenArc->qwMPQStart, FILE_BEGIN);
+       bReturnVal = WriteFile(mpqOpenArc->hFile, &mpqOpenArc->MpqHeader, sizeof(MPQHEADER), &nIOLen, 0);
+
+       if (bReturnVal && mpqOpenArc->MpqHeader.wVersion > 0) {
+               bReturnVal = WriteFile(mpqOpenArc->hFile, &mpqOpenArc->MpqHeader_Ex, sizeof(MPQHEADER_EX), &nIOLen, 0);
+       }
+
+       return bReturnVal;
+}
+
+BOOL MpqWriteNewArchive(MPQARCHIVE *mpqOpenArc)
 {
-       DWORD flen,tsz;
+       DWORD nIOLen;
+
+       memcpy(&mpqOpenArc->MpqHeader.dwMPQID,ID_MPQ,4);
+       mpqOpenArc->MpqHeader.wVersion = wCreationVersion;
+
+       if (mpqOpenArc->MpqHeader.wVersion == 0)
+               mpqOpenArc->MpqHeader.dwHeaderSize = sizeof(MPQHEADER);
+       else
+               mpqOpenArc->MpqHeader.dwHeaderSize = sizeof(MPQHEADER) + sizeof(MPQHEADER_EX);
+       mpqOpenArc->dwHeaderSize = mpqOpenArc->MpqHeader.dwHeaderSize;
 
+       if (mpqOpenArc->MpqHeader.wBlockSize & 0xFFFF0000)
+               mpqOpenArc->MpqHeader.wBlockSize = DEFAULT_BLOCK_SIZE;
+       DWORD i;
+       for (i=1;i<mpqOpenArc->MpqHeader.dwHashTableSize;i*=2) {}
+       mpqOpenArc->MpqHeader.dwHashTableSize = i;
+       mpqOpenArc->MpqHeader.dwBlockTableSize = 0;
+       mpqOpenArc->MpqHeader.dwHashTableOffset = mpqOpenArc->dwHeaderSize;
+       mpqOpenArc->MpqHeader.dwBlockTableOffset = mpqOpenArc->dwHeaderSize + mpqOpenArc->MpqHeader.dwHashTableSize * sizeof(HASHTABLEENTRY);
+       mpqOpenArc->MpqHeader_Ex.qwExtendedBlockOffsetTable = 0;
+       mpqOpenArc->MpqHeader_Ex.wHashTableOffsetHigh = 0;
+       mpqOpenArc->MpqHeader_Ex.wBlockTableOffsetHigh = 0;
+       mpqOpenArc->MpqHeader.dwMPQSize = mpqOpenArc->dwHeaderSize + mpqOpenArc->MpqHeader.dwHashTableSize * sizeof(HASHTABLEENTRY);
+
+       if (!MpqWriteHeaders(mpqOpenArc))
+               return FALSE;
+
+       mpqOpenArc->lpHashTable = (HASHTABLEENTRY *)SFAlloc(sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize);
+       if (!mpqOpenArc->lpHashTable) {
+               return FALSE;
+       }
+       memset(mpqOpenArc->lpHashTable, 0xFF, sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize);
+       EncryptData((LPBYTE)mpqOpenArc->lpHashTable, sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize, dwHashTableKey);
+       if (!WriteFile(mpqOpenArc->hFile, mpqOpenArc->lpHashTable, sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize, &nIOLen, 0)) {
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+BOOL MpqReadExistingArchive(MPQARCHIVE *mpqOpenArc)
+{
+       DWORD nIOLen;
+
+       SFSetFilePointer(mpqOpenArc->hFile, mpqOpenArc->qwMPQStart, FILE_BEGIN);
+       if (!ReadFile(mpqOpenArc->hFile, &mpqOpenArc->MpqHeader, sizeof(MPQHEADER), &nIOLen, 0))
+               return FALSE;
+
+       if (mpqOpenArc->MpqHeader.wVersion > 0) {
+               mpqOpenArc->dwHeaderSize = sizeof(MPQHEADER) + sizeof(MPQHEADER_EX);
+               if (!ReadFile(mpqOpenArc->hFile, &mpqOpenArc->MpqHeader_Ex, sizeof(MPQHEADER_EX), &nIOLen, 0))
+                       return FALSE;
+       }
+       else {
+               mpqOpenArc->dwHeaderSize = sizeof(MPQHEADER);
+               memset(&mpqOpenArc->MpqHeader_Ex, 0, sizeof(MPQHEADER_EX));
+       }
+
+       mpqOpenArc->lpHashTable = (HASHTABLEENTRY *)SFAlloc(sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize);
+       if (!mpqOpenArc->lpHashTable)
+               return FALSE;
+
+       if (mpqOpenArc->MpqHeader.dwBlockTableSize) {
+               mpqOpenArc->lpBlockTable = (BLOCKTABLEENTRY *)SFAlloc((sizeof(BLOCKTABLEENTRY) + sizeof(UInt16)) * mpqOpenArc->MpqHeader.dwBlockTableSize);
+               mpqOpenArc->lpFileOffsetsHigh = (UInt16 *)(mpqOpenArc->lpBlockTable + mpqOpenArc->MpqHeader.dwBlockTableSize);
+               if (!mpqOpenArc->lpBlockTable)
+                       return FALSE;
+       }
+
+       SFSetFilePointer(mpqOpenArc->hFile, mpqOpenArc->qwMPQStart + MakeUInt64(mpqOpenArc->MpqHeader.dwHashTableOffset, mpqOpenArc->MpqHeader_Ex.wHashTableOffsetHigh), FILE_BEGIN);
+       if (!ReadFile(mpqOpenArc->hFile, mpqOpenArc->lpHashTable, sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize, &nIOLen, 0))
+               return FALSE;
+
+       if (mpqOpenArc->MpqHeader.dwBlockTableSize) {
+               SFSetFilePointer(mpqOpenArc->hFile, mpqOpenArc->qwMPQStart + MakeUInt64(mpqOpenArc->MpqHeader.dwBlockTableOffset, mpqOpenArc->MpqHeader_Ex.wBlockTableOffsetHigh), FILE_BEGIN);
+               if (!ReadFile(mpqOpenArc->hFile, mpqOpenArc->lpBlockTable, sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize, &nIOLen, 0))
+                       return FALSE;
+
+               if (mpqOpenArc->MpqHeader_Ex.qwExtendedBlockOffsetTable) {
+                       SFSetFilePointer(mpqOpenArc->hFile, mpqOpenArc->qwMPQStart + mpqOpenArc->MpqHeader_Ex.qwExtendedBlockOffsetTable, FILE_BEGIN);
+                       if (!ReadFile(mpqOpenArc->hFile, mpqOpenArc->lpFileOffsetsHigh, sizeof(WORD) * mpqOpenArc->MpqHeader.dwBlockTableSize, &nIOLen, 0))
+                               return FALSE;
+               }
+       }
+
+       return TRUE;
+}
+
+BOOL MpqOpenArchiveInit(MPQARCHIVE *mpqOpenArc, LPCSTR lpFileName, DWORD dwPriority, DWORD dwFlags1, DWORD dwFlags2, DWORD dwExtraFlags)
+{
+       /*mpqOpenArc->lpFileName = (char *)SFAlloc(strlen(lpFileName)+1);
+       if(!mpqOpenArc->lpFileName)
+               return FALSE;*/
+       DecryptData((LPBYTE)mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,dwHashTableKey);
+       if (mpqOpenArc->lpBlockTable) DecryptData((LPBYTE)mpqOpenArc->lpBlockTable,sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize,dwBlockTableKey);
+       mpqOpenArc->lpFileName = mpqOpenArc->szFileName;
+       strncpy(mpqOpenArc->lpFileName,lpFileName,259);
+       if (FirstLastMpq[1]) FirstLastMpq[1]->lpNextArc = mpqOpenArc;
+       mpqOpenArc->lpNextArc = (MPQARCHIVE *)FirstLastMpq;
+       mpqOpenArc->lpPrevArc = (MPQARCHIVE *)FirstLastMpq[1];
+       if (!FirstLastMpq[0]) {
+               mpqOpenArc->lpPrevArc = (MPQARCHIVE *)0xEAFC5E23;
+               FirstLastMpq[0] = mpqOpenArc;
+       }
+       FirstLastMpq[1] = mpqOpenArc;
+       mpqOpenArc->dwFlags1 = dwFlags1;
+       mpqOpenArc->dwPriority = dwPriority;
+       mpqOpenArc->lpLastReadFile = 0;
+       mpqOpenArc->dwUnk = 0;
+       mpqOpenArc->dwBlockSize = 512 << mpqOpenArc->MpqHeader.wBlockSize;
+       mpqOpenArc->lpLastReadBlock = 0;
+       mpqOpenArc->dwBufferSize = 0;
+       mpqOpenArc->qwMPQEnd = mpqOpenArc->qwMPQStart + mpqOpenArc->MpqHeader.dwMPQSize;
+       mpqOpenArc->lpMPQHeader = &mpqOpenArc->MpqHeader;
+       mpqOpenArc->qwReadOffset = mpqOpenArc->qwMPQEnd;
+       mpqOpenArc->dwRefCount = 1;
+       mpqOpenArc->dwFlags = dwFlags2;
+       mpqOpenArc->dwExtraFlags = dwExtraFlags;
+
+       return TRUE;
+}
+
+BOOL WINAPI MpqOpenArchiveEx(LPCSTR lpFileName, DWORD dwPriority, DWORD dwFlags, MPQHANDLE *hMPQ, DWORD dwFlags2, DWORD dwMaximumFilesInArchive, DWORD dwBlockSize)
+{
        if (!lpFileName || !hMPQ) {
                SetLastError(ERROR_INVALID_PARAMETER);
-               if (hMPQ) *hMPQ = 0;
+               if (hMPQ) *hMPQ = (MPQHANDLE)INVALID_HANDLE_VALUE;
                return FALSE;
        }
+       *hMPQ = (MPQHANDLE)INVALID_HANDLE_VALUE;
        if (!*lpFileName) {
                SetLastError(ERROR_INVALID_PARAMETER);
-               *hMPQ = 0;
                return FALSE;
        }
 
@@ -365,7 +454,7 @@ BOOL WINAPI MpqOpenArchiveEx(LPCSTR lpFileName, DWORD dwPriority, DWORD dwFlags,
        else if (dwFlags&2)
                dwFlags1 |= 1;
        if (dwFlags & SFILE_OPEN_CD_ROM_FILE)
-               if (!(dwFlags1&2)) {*hMPQ = 0;return FALSE;}
+               if (!(dwFlags1&2)) {return FALSE;}
 #endif
 
        DWORD dwCreateFlags,dwAccessFlags,dwShareFlags;
@@ -376,7 +465,6 @@ BOOL WINAPI MpqOpenArchiveEx(LPCSTR lpFileName, DWORD dwPriority, DWORD dwFlags,
        if (dwFlags2 & MOAU_READ_ONLY) {
                if (!(dwFlags2 & MOAU_OPEN_EXISTING)) {
                        SetLastError(MPQ_ERROR_BAD_OPEN_MODE);
-                       *hMPQ = 0;
                        return FALSE;
                }
                dwAccessFlags = GENERIC_READ;
@@ -403,169 +491,71 @@ BOOL WINAPI MpqOpenArchiveEx(LPCSTR lpFileName, DWORD dwPriority, DWORD dwFlags,
        if (hFile!=INVALID_HANDLE_VALUE)
        {
                MPQARCHIVE **lpnOpenMpq = (MPQARCHIVE **)SFAlloc(sizeof(MPQARCHIVE *) * (dwOpenMpqCount+1));
-               if (lpnOpenMpq==0) {
+               if (!lpnOpenMpq) {
                        CloseHandle(hFile);
-                       *hMPQ = 0;
                        return FALSE;
                }
-               DWORD dwMpqStart;
                MPQARCHIVE *mpqOpenArc;
-               if (GetFileSize(hFile,0)==0 && !(dwFlags2 & MOAU_READ_ONLY))
+               if (SFGetFileSize(hFile)==0 && !(dwFlags2 & MOAU_READ_ONLY))
                {
-                       dwMpqStart = 0;
                        mpqOpenArc = (MPQARCHIVE *)SFAlloc(sizeof(MPQARCHIVE));
                        if (!mpqOpenArc) {
                                SFFree(lpnOpenMpq);
                                CloseHandle(hFile);
-                               *hMPQ = 0;
                                return FALSE;
                        }
-                       memcpy(&mpqOpenArc->MpqHeader.dwMPQID,ID_MPQ,4);
-                       mpqOpenArc->MpqHeader.dwHeaderSize = sizeof(MPQHEADER);
-                       mpqOpenArc->MpqHeader.wUnused0C = 0;
-                       if (dwBlockSize & 0xFFFF0000)
-                               mpqOpenArc->MpqHeader.wBlockSize = DEFAULT_BLOCK_SIZE;
-                       else
-                               mpqOpenArc->MpqHeader.wBlockSize = (WORD)dwBlockSize;
-                       DWORD i;
-                       for (i=1;i<dwMaximumFilesInArchive;i*=2) {}
-                       dwMaximumFilesInArchive = i;
+
+                       mpqOpenArc->hFile = hFile;
+                       mpqOpenArc->qwMPQStart = 0;
                        mpqOpenArc->MpqHeader.dwHashTableSize = dwMaximumFilesInArchive;
-                       mpqOpenArc->MpqHeader.dwBlockTableSize = 0;
-                       mpqOpenArc->MpqHeader.dwHashTableOffset = mpqOpenArc->MpqHeader.dwHeaderSize;
-                       mpqOpenArc->MpqHeader.dwBlockTableOffset = mpqOpenArc->MpqHeader.dwHeaderSize + mpqOpenArc->MpqHeader.dwHashTableSize * sizeof(HASHTABLEENTRY);
-                       mpqOpenArc->MpqHeader.dwMPQSize = mpqOpenArc->MpqHeader.dwHeaderSize + mpqOpenArc->MpqHeader.dwHashTableSize * sizeof(HASHTABLEENTRY);
-                       if(WriteFile(hFile,&mpqOpenArc->MpqHeader,mpqOpenArc->MpqHeader.dwHeaderSize,&tsz,0)==0) {
-                               SFFree(lpnOpenMpq);
-                               SFFree(mpqOpenArc);
-                               CloseHandle(hFile);
-                               *hMPQ = 0;
-                               return FALSE;
-                       }
-                       flen = mpqOpenArc->MpqHeader.dwMPQSize;
-                       mpqOpenArc->lpHashTable = (HASHTABLEENTRY *)SFAlloc(sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize);
-                       if(!mpqOpenArc->lpHashTable) {
-                               SFFree(lpnOpenMpq);
+                       mpqOpenArc->MpqHeader.wBlockSize = (WORD)dwBlockSize;
+
+                       if (!MpqWriteNewArchive(mpqOpenArc)) {
+                               if (mpqOpenArc->lpHashTable) SFFree(mpqOpenArc->lpHashTable);
                                SFFree(mpqOpenArc);
-                               CloseHandle(hFile);
-                               *hMPQ = 0;
-                               return FALSE;
-                       }
-                       memset(mpqOpenArc->lpHashTable,0xFF,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize);
-                       EncryptData((LPBYTE)mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,dwHashTableKey);
-                       if(WriteFile(hFile,mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,&tsz,0)==0) {
-                               SFFree(mpqOpenArc->lpHashTable);
                                SFFree(lpnOpenMpq);
-                               SFFree(mpqOpenArc);
                                CloseHandle(hFile);
-                               *hMPQ = 0;
                                return FALSE;
                        }
                }
                else
                {
-                       dwMpqStart = SFileFindMpqHeader(hFile);
-                       if (dwMpqStart==0xFFFFFFFF) {
+                       UInt64 qwMpqStart = SFileFindMpqHeaderEx(hFile);
+                       if (qwMpqStart == (UInt64)-1) {
                                SFFree(lpnOpenMpq);
                                CloseHandle(hFile);
                                SetLastError(MPQ_ERROR_MPQ_INVALID);
-                               *hMPQ = 0;
                                return FALSE;
                        }
-                       flen = GetFileSize(hFile,0);
                        mpqOpenArc = (MPQARCHIVE *)SFAlloc(sizeof(MPQARCHIVE));
                        if (!mpqOpenArc) {
                                SFFree(lpnOpenMpq);
                                CloseHandle(hFile);
-                               *hMPQ = 0;
-                               return FALSE;
-                       }
-                       SetFilePointer(hFile,dwMpqStart,0,FILE_BEGIN);
-                       if(ReadFile(hFile,&mpqOpenArc->MpqHeader,sizeof(MPQHEADER),&tsz,0)==0) {
-                               SFFree(lpnOpenMpq);
-                               SFFree(mpqOpenArc);
-                               CloseHandle(hFile);
-                               *hMPQ = 0;
                                return FALSE;
                        }
-                       mpqOpenArc->lpHashTable = (HASHTABLEENTRY *)SFAlloc(sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize);
-                       if(!mpqOpenArc->lpHashTable) {
-                               SFFree(lpnOpenMpq);
+
+                       mpqOpenArc->hFile = hFile;
+                       mpqOpenArc->qwMPQStart = qwMpqStart;
+
+                       if (!MpqReadExistingArchive(mpqOpenArc)) {
+                               if (mpqOpenArc->lpBlockTable) SFFree(mpqOpenArc->lpBlockTable);
+                               if (mpqOpenArc->lpHashTable) SFFree(mpqOpenArc->lpHashTable);
                                SFFree(mpqOpenArc);
-                               CloseHandle(hFile);
-                               *hMPQ = 0;
-                               return FALSE;
-                       }
-                       if (mpqOpenArc->MpqHeader.dwBlockTableSize!=0) {
-                               mpqOpenArc->lpBlockTable = (BLOCKTABLEENTRY *)SFAlloc(sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize);
-                               if(!mpqOpenArc->lpBlockTable) {
-                                       SFFree(mpqOpenArc->lpHashTable);
-                                       SFFree(lpnOpenMpq);
-                                       SFFree(mpqOpenArc);
-                                       CloseHandle(hFile);
-                                       *hMPQ = 0;
-                                       return FALSE;
-                               }
-                       }
-                       SetFilePointer(hFile,dwMpqStart+mpqOpenArc->MpqHeader.dwHashTableOffset,0,FILE_BEGIN);
-                       if(ReadFile(hFile,mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,&tsz,0)==0) {
-                               if(mpqOpenArc->lpBlockTable) SFFree(mpqOpenArc->lpBlockTable);
-                               SFFree(mpqOpenArc->lpHashTable);
                                SFFree(lpnOpenMpq);
-                               SFFree(mpqOpenArc);
                                CloseHandle(hFile);
-                               *hMPQ = 0;
                                return FALSE;
                        }
-                       if (mpqOpenArc->MpqHeader.dwBlockTableSize!=0) {
-                               SetFilePointer(hFile,dwMpqStart+mpqOpenArc->MpqHeader.dwBlockTableOffset,0,FILE_BEGIN);
-                               if(ReadFile(hFile,mpqOpenArc->lpBlockTable,sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize,&tsz,0)==0) {
-                                       SFFree(mpqOpenArc->lpBlockTable);
-                                       SFFree(mpqOpenArc->lpHashTable);
-                                       SFFree(lpnOpenMpq);
-                                       SFFree(mpqOpenArc);
-                                       CloseHandle(hFile);
-                                       *hMPQ = 0;
-                                       return FALSE;
-                               }
-                       }
                }
-               /*mpqOpenArc->lpFileName = (char *)SFAlloc(strlen(lpFileName)+1);
-               if(!mpqOpenArc->lpFileName) {
-                       if(mpqOpenArc->lpBlockTable) SFFree(mpqOpenArc->lpBlockTable);
+
+               if (!MpqOpenArchiveInit(mpqOpenArc, lpFileName, dwPriority, dwFlags1, dwFlags2, 0)) {
+                       if (mpqOpenArc->lpBlockTable) SFFree(mpqOpenArc->lpBlockTable);
                        SFFree(mpqOpenArc->lpHashTable);
-                       SFFree(lpnOpenMpq);
                        SFFree(mpqOpenArc);
+                       SFFree(lpnOpenMpq);
                        CloseHandle(hFile);
-                       *hMPQ = 0;
                        return FALSE;
-               }*/
-               DecryptData((LPBYTE)mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,dwHashTableKey);
-               if (mpqOpenArc->lpBlockTable) DecryptData((LPBYTE)mpqOpenArc->lpBlockTable,sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize,dwBlockTableKey);
-               mpqOpenArc->lpFileName = mpqOpenArc->szFileName;
-               strncpy(mpqOpenArc->lpFileName,lpFileName,259);
-               if (FirstLastMpq[1]) FirstLastMpq[1]->lpNextArc = mpqOpenArc;
-               mpqOpenArc->lpNextArc = (MPQARCHIVE *)FirstLastMpq;
-               mpqOpenArc->lpPrevArc = (MPQARCHIVE *)FirstLastMpq[1];
-               if (!FirstLastMpq[0]) {
-                       mpqOpenArc->lpPrevArc = (MPQARCHIVE *)0xEAFC5E23;
-                       FirstLastMpq[0] = mpqOpenArc;
-               }
-               FirstLastMpq[1] = mpqOpenArc;
-               mpqOpenArc->hFile = hFile;
-               mpqOpenArc->dwFlags1 = dwFlags1;
-               mpqOpenArc->dwPriority = dwPriority;
-               mpqOpenArc->lpLastReadFile = 0;
-               mpqOpenArc->dwUnk = 0;
-               mpqOpenArc->dwBlockSize = 512 << mpqOpenArc->MpqHeader.wBlockSize;
-               mpqOpenArc->lpLastReadBlock = 0;
-               mpqOpenArc->dwBufferSize = 0;
-               mpqOpenArc->dwMPQStart = dwMpqStart;
-               mpqOpenArc->lpMPQHeader = &mpqOpenArc->MpqHeader;
-               mpqOpenArc->dwReadOffset = flen;
-               mpqOpenArc->dwRefCount = 1;
-               mpqOpenArc->dwFlags = dwFlags2;
-               mpqOpenArc->dwExtraFlags = 0;
+               }
+
                memcpy(lpnOpenMpq,lpOpenMpq,sizeof(MPQARCHIVE *) * dwOpenMpqCount);
                lpnOpenMpq[dwOpenMpqCount] = mpqOpenArc;
                if (lpOpenMpq) SFFree(lpOpenMpq);
@@ -573,6 +563,7 @@ BOOL WINAPI MpqOpenArchiveEx(LPCSTR lpFileName, DWORD dwPriority, DWORD dwFlags,
                dwOpenMpqCount++;
                if (dwOpenMpqCount>1) SortOpenArchivesByPriority();
                *hMPQ = (MPQHANDLE)mpqOpenArc;
+
                return TRUE;
        }
        else {
@@ -585,16 +576,14 @@ BOOL WINAPI MpqOpenArchiveEx(LPCSTR lpFileName, DWORD dwPriority, DWORD dwFlags,
 
 BOOL SFMPQAPI WINAPI SFileOpenFileAsArchive(MPQHANDLE hSourceMPQ, LPCSTR lpFileName, DWORD dwPriority, DWORD dwFlags, MPQHANDLE *hMPQ)
 {
-       DWORD flen,tsz;
-
        if (!lpFileName || !hMPQ) {
                SetLastError(ERROR_INVALID_PARAMETER);
-               if (hMPQ) *hMPQ = 0;
+               if (hMPQ) *hMPQ = (MPQHANDLE)INVALID_HANDLE_VALUE;
                return FALSE;
        }
+       *hMPQ = (MPQHANDLE)INVALID_HANDLE_VALUE;
        if (!*lpFileName) {
                SetLastError(ERROR_INVALID_PARAMETER);
-               *hMPQ = 0;
                return FALSE;
        }
 
@@ -609,105 +598,42 @@ BOOL SFMPQAPI WINAPI SFileOpenFileAsArchive(MPQHANDLE hSourceMPQ, LPCSTR lpFileN
                hFile = mpqArcFile.lpParentArc->hFile;
                MPQARCHIVE **lpnOpenMpq = (MPQARCHIVE **)SFAlloc(sizeof(MPQARCHIVE *) * (dwOpenMpqCount+1));
                if (!lpnOpenMpq) {
-                       *hMPQ = 0;
                        return FALSE;
                }
-               DWORD dwMpqStart;
                MPQARCHIVE *mpqOpenArc;
-               dwMpqStart = mpqArcFile.lpBlockEntry->dwFileOffset;
-               flen = mpqArcFile.lpBlockEntry->dwFullSize;
-               dwMpqStart = FindMpqHeaderAtLocation(hFile,dwMpqStart,flen);
-               if (dwMpqStart==0xFFFFFFFF) {
+               UInt64 qwMpqStart = mpqArcFile.lpParentArc->qwMPQStart + MakeUInt64(mpqArcFile.lpBlockEntry->dwFileOffset, mpqArcFile.wFileOffsetHigh);
+               UInt64 flen = mpqArcFile.lpBlockEntry->dwFullSize;
+               qwMpqStart = SFileFindMpqHeaderEx(hFile, qwMpqStart, flen);
+               if (qwMpqStart == (UInt64)-1) {
                        SFFree(lpnOpenMpq);
                        SetLastError(MPQ_ERROR_MPQ_INVALID);
-                       *hMPQ = 0;
                        return FALSE;
                }
                mpqOpenArc = (MPQARCHIVE *)SFAlloc(sizeof(MPQARCHIVE));
                if (!mpqOpenArc) {
                        SFFree(lpnOpenMpq);
-                       *hMPQ = 0;
                        return FALSE;
                }
-               SetFilePointer(hFile,dwMpqStart,0,FILE_BEGIN);
-               if(ReadFile(hFile,&mpqOpenArc->MpqHeader,sizeof(MPQHEADER),&tsz,0)==0) {
-                       SFFree(lpnOpenMpq);
+
+               mpqOpenArc->hFile = hFile;
+               mpqOpenArc->qwMPQStart = qwMpqStart;
+
+               if (!MpqReadExistingArchive(mpqOpenArc)) {
+                       if (mpqOpenArc->lpBlockTable) SFFree(mpqOpenArc->lpBlockTable);
+                       if (mpqOpenArc->lpHashTable) SFFree(mpqOpenArc->lpHashTable);
                        SFFree(mpqOpenArc);
-                       *hMPQ = 0;
-                       return FALSE;
-               }
-               mpqOpenArc->lpHashTable = (HASHTABLEENTRY *)SFAlloc(sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize);
-               if(!mpqOpenArc->lpHashTable) {
                        SFFree(lpnOpenMpq);
-                       SFFree(mpqOpenArc);
-                       *hMPQ = 0;
                        return FALSE;
                }
-               if (mpqOpenArc->MpqHeader.dwBlockTableSize!=0) {
-                       mpqOpenArc->lpBlockTable = (BLOCKTABLEENTRY *)SFAlloc(sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize);
-                       if(!mpqOpenArc->lpBlockTable) {
-                               SFFree(mpqOpenArc->lpHashTable);
-                               SFFree(lpnOpenMpq);
-                               SFFree(mpqOpenArc);
-                               *hMPQ = 0;
-                               return FALSE;
-                       }
-               }
-               SetFilePointer(hFile,dwMpqStart+mpqOpenArc->MpqHeader.dwHashTableOffset,0,FILE_BEGIN);
-               if(ReadFile(hFile,mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,&tsz,0)==0) {
-                       if(mpqOpenArc->lpBlockTable) SFFree(mpqOpenArc->lpBlockTable);
+
+               if (!MpqOpenArchiveInit(mpqOpenArc, lpFileName, dwPriority, 0, dwFlags, 1)) {
+                       if (mpqOpenArc->lpBlockTable) SFFree(mpqOpenArc->lpBlockTable);
                        SFFree(mpqOpenArc->lpHashTable);
-                       SFFree(lpnOpenMpq);
                        SFFree(mpqOpenArc);
-                       *hMPQ = 0;
-                       return FALSE;
-               }
-               if (mpqOpenArc->MpqHeader.dwBlockTableSize!=0) {
-                       SetFilePointer(hFile,dwMpqStart+mpqOpenArc->MpqHeader.dwBlockTableOffset,0,FILE_BEGIN);
-                       if(ReadFile(hFile,mpqOpenArc->lpBlockTable,sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize,&tsz,0)==0) {
-                               SFFree(mpqOpenArc->lpBlockTable);
-                               SFFree(mpqOpenArc->lpHashTable);
-                               SFFree(lpnOpenMpq);
-                               SFFree(mpqOpenArc);
-                               *hMPQ = 0;
-                               return FALSE;
-                       }
-               }
-               /*mpqOpenArc->lpFileName = (char *)SFAlloc(strlen(lpFileName)+1);
-               if(!mpqOpenArc->lpFileName) {
-                       if(mpqOpenArc->lpBlockTable) SFFree(mpqOpenArc->lpBlockTable);
-                       SFFree(mpqOpenArc->lpHashTable);
                        SFFree(lpnOpenMpq);
-                       SFFree(mpqOpenArc);
-                       *hMPQ = 0;
                        return FALSE;
-               }*/
-               DecryptData((LPBYTE)mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,dwHashTableKey);
-               if (mpqOpenArc->lpBlockTable) DecryptData((LPBYTE)mpqOpenArc->lpBlockTable,sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize,dwBlockTableKey);
-               mpqOpenArc->lpFileName = mpqOpenArc->szFileName;
-               strncpy(mpqOpenArc->lpFileName,lpFileName,259);
-               if (FirstLastMpq[1]) FirstLastMpq[1]->lpNextArc = mpqOpenArc;
-               mpqOpenArc->lpNextArc = (MPQARCHIVE *)FirstLastMpq;
-               mpqOpenArc->lpPrevArc = (MPQARCHIVE *)FirstLastMpq[1];
-               if (!FirstLastMpq[0]) {
-                       mpqOpenArc->lpPrevArc = (MPQARCHIVE *)0xEAFC5E23;
-                       FirstLastMpq[0] = mpqOpenArc;
-               }
-               FirstLastMpq[1] = mpqOpenArc;
-               mpqOpenArc->hFile = hFile;
-               mpqOpenArc->dwFlags1 = 0;
-               mpqOpenArc->dwPriority = dwPriority;
-               mpqOpenArc->lpLastReadFile = 0;
-               mpqOpenArc->dwUnk = 0;
-               mpqOpenArc->dwBlockSize = 512 << mpqOpenArc->MpqHeader.wBlockSize;
-               mpqOpenArc->lpLastReadBlock = 0;
-               mpqOpenArc->dwBufferSize = 0;
-               mpqOpenArc->dwMPQStart = dwMpqStart;
-               mpqOpenArc->lpMPQHeader = &mpqOpenArc->MpqHeader;
-               mpqOpenArc->dwReadOffset = flen;
-               mpqOpenArc->dwRefCount = 1;
-               mpqOpenArc->dwFlags = dwFlags;
-               mpqOpenArc->dwExtraFlags = 1;
+               }
+
                memcpy(lpnOpenMpq,lpOpenMpq,sizeof(MPQARCHIVE *) * dwOpenMpqCount);
                lpnOpenMpq[dwOpenMpqCount] = mpqOpenArc;
                if (lpOpenMpq) SFFree(lpOpenMpq);
@@ -715,6 +641,7 @@ BOOL SFMPQAPI WINAPI SFileOpenFileAsArchive(MPQHANDLE hSourceMPQ, LPCSTR lpFileN
                dwOpenMpqCount++;
                if (dwOpenMpqCount>1) SortOpenArchivesByPriority();
                *hMPQ = (MPQHANDLE)mpqOpenArc;
+
                return TRUE;
        }
        else {
@@ -958,6 +885,7 @@ BOOL SFMPQAPI WINAPI SFileOpenFileEx(MPQHANDLE hMPQ, LPCSTR lpFileName, DWORD dw
                mpqOpenFile->hFile = INVALID_HANDLE_VALUE;
                mpqOpenFile->lpHashEntry = (HASHTABLEENTRY *)hnFile;
                mpqOpenFile->lpBlockEntry = &((MPQARCHIVE *)hnMPQ)->lpBlockTable[mpqOpenFile->lpHashEntry->dwBlockTableIndex];
+               mpqOpenFile->wFileOffsetHigh = ((MPQARCHIVE *)hnMPQ)->lpFileOffsetsHigh[mpqOpenFile->lpHashEntry->dwBlockTableIndex];
                mpqOpenFile->lpParentArc->dwRefCount++;
                if (mpqOpenFile->lpBlockEntry->dwFlags&MAFA_ENCRYPT) {
                        LPSTR lpOldNameBuffer = mpqOpenFile->lpFileName;
@@ -1120,7 +1048,7 @@ DWORD SFMPQAPI WINAPI SFileGetFileInfo(MPQHANDLE hFile, DWORD dwInfoType)
                        case SFILE_INFO_PRIORITY:
                                return mpqOpenArc->dwPriority;
                        case SFILE_INFO_HASH_INDEX:
-                               return ((DWORD)mpqOpenFile->lpHashEntry-(DWORD)mpqOpenArc->lpHashTable)/sizeof(HASHTABLEENTRY);
+                               return ((UIntPtr)mpqOpenFile->lpHashEntry-(UIntPtr)mpqOpenArc->lpHashTable)/sizeof(HASHTABLEENTRY);
                        case SFILE_INFO_BLOCK_INDEX:
                                return mpqOpenFile->lpHashEntry->dwBlockTableIndex;
                        default:
@@ -1133,15 +1061,15 @@ DWORD SFMPQAPI WINAPI SFileGetFileInfo(MPQHANDLE hFile, DWORD dwInfoType)
                        case SFILE_INFO_TYPE:
                                return SFILE_TYPE_FILE;
                        case SFILE_INFO_SIZE:
-                               return GetFileSize(mpqOpenFile->hFile,0);
+                               return SFGetFileSize(mpqOpenFile->hFile);
                        case SFILE_INFO_COMPRESSED_SIZE:
-                               return GetFileSize(mpqOpenFile->hFile,0);
+                               return SFGetFileSize(mpqOpenFile->hFile);
 #ifdef _WIN32
                        case SFILE_INFO_FLAGS:
                                return GetFileAttributes(mpqOpenFile->lpFileName);
 #endif
                        case SFILE_INFO_POSITION:
-                               return SetFilePointer(mpqOpenFile->hFile,0,0,FILE_CURRENT);
+                               return SFSetFilePointer(mpqOpenFile->hFile,0,FILE_CURRENT);
                        default:
                                SetLastError(ERROR_UNKNOWN_PROPERTY);
                                return (DWORD)-1;
@@ -1174,7 +1102,7 @@ DWORD SFMPQAPI WINAPI SFileGetFileInfo(MPQHANDLE hFile, DWORD dwInfoType)
        return (DWORD)-1;
 }
 
-DWORD SFMPQAPI WINAPI SFileSetFilePointer(MPQHANDLE hFile, long lDistanceToMove, PLONG lplDistanceToMoveHigh, DWORD dwMoveMethod)
+DWORD SFMPQAPI WINAPI SFileSetFilePointer(MPQHANDLE hFile, LONG lDistanceToMove, PLONG lplDistanceToMoveHigh, DWORD dwMoveMethod)
 {
        if (!hFile) {
                SetLastError(ERROR_INVALID_PARAMETER);
@@ -1186,21 +1114,18 @@ DWORD SFMPQAPI WINAPI SFileSetFilePointer(MPQHANDLE hFile, long lDistanceToMove,
                long fsz = mpqOpenFile->lpBlockEntry->dwFullSize;
                long cpos = mpqOpenFile->dwFilePointer;
                switch (dwMoveMethod) {
-               case FILE_BEGIN:
-                       if (lDistanceToMove<0 || lDistanceToMove>fsz) return (DWORD)-1;
-                       mpqOpenFile->dwFilePointer = lDistanceToMove;
-                       break;
                case FILE_CURRENT:
-                       if (lDistanceToMove<cpos || cpos+lDistanceToMove>fsz) return (DWORD)-1;
+                       if (cpos + lDistanceToMove < 0 || cpos + lDistanceToMove > fsz) return (DWORD)-1;
                        mpqOpenFile->dwFilePointer += lDistanceToMove;
                        break;
 
                case FILE_END:
-                       if (lDistanceToMove<fsz || lDistanceToMove>0) return (DWORD)-1;
-                       mpqOpenFile->dwFilePointer = fsz+lDistanceToMove;
+                       if (fsz + lDistanceToMove < 0 || lDistanceToMove > 0) return (DWORD)-1;
+                       mpqOpenFile->dwFilePointer = fsz + lDistanceToMove;
                        break;
+               case FILE_BEGIN:
                default:
-                       if (lDistanceToMove<0 || lDistanceToMove>fsz) return (DWORD)-1;
+                       if (lDistanceToMove < 0 || lDistanceToMove > fsz) return (DWORD)-1;
                        mpqOpenFile->dwFilePointer = lDistanceToMove;
                }
                if (lplDistanceToMoveHigh!=0) *lplDistanceToMoveHigh = 0;
@@ -1226,7 +1151,7 @@ BOOL SFMPQAPI WINAPI SFileReadFile(MPQHANDLE hFile,LPVOID lpBuffer,DWORD nNumber
        }
        if (lpOverlapped)
                if (lpOverlapped->Internal || lpOverlapped->InternalHigh || lpOverlapped->Offset || lpOverlapped->OffsetHigh || lpOverlapped->hEvent)
-                       SFileSetFilePointer(hFile,lpOverlapped->Offset,(long *)&lpOverlapped->OffsetHigh,FILE_BEGIN);
+                       SFileSetFilePointer(hFile,lpOverlapped->Offset,(LONG *)&lpOverlapped->OffsetHigh,FILE_BEGIN);
        if (nNumberOfBytesToRead==0) {
                if (lpNumberOfBytesRead) *lpNumberOfBytesRead = 0;
                if (lpOverlapped) lpOverlapped->InternalHigh = 0;
@@ -1245,6 +1170,8 @@ BOOL SFMPQAPI WINAPI SFileReadFile(MPQHANDLE hFile,LPVOID lpBuffer,DWORD nNumber
        DWORD BlockIndex = mpqOpenFile->lpHashEntry->dwBlockTableIndex;
        if (mpqOpenFile->dwFilePointer+nNumberOfBytesToRead>mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize) nNumberOfBytesToRead = mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize-mpqOpenFile->dwFilePointer;
        DWORD blockSize = 512 << mpqOpenArc->MpqHeader.wBlockSize;
+       if (mpqOpenArc->lpBlockTable[BlockIndex].dwFlags & MAFA_SINGLEBLOCK)
+               blockSize = mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize;
        DWORD dwBlockStart = mpqOpenFile->dwFilePointer - (mpqOpenFile->dwFilePointer % blockSize);
     DWORD blockNum = dwBlockStart / blockSize;
     DWORD nBlocks  = (mpqOpenFile->dwFilePointer+nNumberOfBytesToRead) / blockSize;
@@ -1262,12 +1189,18 @@ BOOL SFMPQAPI WINAPI SFileReadFile(MPQHANDLE hFile,LPVOID lpBuffer,DWORD nNumber
                if (lpOverlapped) lpOverlapped->InternalHigh = 0;
                return FALSE;
        }
-       void *blk16Buffer = SFAlloc(blockSize * 16);
-       if (!blk16Buffer) {
-               SFFree(blkBuffer);
-               if (lpNumberOfBytesRead) *lpNumberOfBytesRead = 0;
-               if (lpOverlapped) lpOverlapped->InternalHigh = 0;
-               return FALSE;
+       DWORD nBufferCount;
+       for (nBufferCount = 1; nBufferCount < nBlocks - blockNum && blockSize * nBufferCount < 65536; nBufferCount *= 2) {}
+       if (nBufferCount > nBlocks - blockNum) nBufferCount = nBlocks - blockNum;
+       void *blkLargeBuffer = NULL;
+       if (nBufferCount > 1) {
+               blkLargeBuffer = SFAlloc(blockSize * nBufferCount);
+               if (!blkLargeBuffer) {
+                       SFFree(blkBuffer);
+                       if (lpNumberOfBytesRead) *lpNumberOfBytesRead = 0;
+                       if (lpOverlapped) lpOverlapped->InternalHigh = 0;
+                       return FALSE;
+               }
        }
        DWORD dwCryptKey = mpqOpenFile->dwCryptKey;
        //if (mpqOpenArc->lpBlockTable[BlockIndex].dwFlags & MAFA_ENCRYPT) dwCryptKey = HashString(mpqOpenFile->lpFileName,HASH_KEY);
@@ -1275,7 +1208,7 @@ BOOL SFMPQAPI WINAPI SFileReadFile(MPQHANDLE hFile,LPVOID lpBuffer,DWORD nNumber
        DWORD HeaderLength=0;
        if (memcmp(&mpqOpenArc->MpqHeader.dwMPQID,ID_BN3,4)==0)
        {
-               SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset,0,FILE_BEGIN);
+               SFSetFilePointer(mpqOpenArc->hFile, mpqOpenArc->qwMPQStart + MakeUInt64(mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset, mpqOpenArc->lpFileOffsetsHigh[BlockIndex]), FILE_BEGIN);
                ReadFile(mpqOpenArc->hFile,&HeaderLength,4,&nBytesRead,0);
        }
        DWORD i;
@@ -1284,15 +1217,15 @@ BOOL SFMPQAPI WINAPI SFileReadFile(MPQHANDLE hFile,LPVOID lpBuffer,DWORD nNumber
                DWORD *dwBlockPtrTable = (DWORD *)SFAlloc((TotalBlocks+1)*4);
                if (!dwBlockPtrTable) {
 
-                       SFFree(blk16Buffer);
+                       if (blkLargeBuffer) SFFree(blkLargeBuffer);
                        SFFree(blkBuffer);
                        if (lpNumberOfBytesRead) *lpNumberOfBytesRead = 0;
                        if (lpOverlapped) lpOverlapped->InternalHigh = 0;
                        return FALSE;
                }
-               if ((mpqOpenArc->lpBlockTable[BlockIndex].dwFlags & MAFA_COMPRESS) || (mpqOpenArc->lpBlockTable[BlockIndex].dwFlags & MAFA_COMPRESS2))
+               if (((mpqOpenArc->lpBlockTable[BlockIndex].dwFlags & MAFA_COMPRESS) || (mpqOpenArc->lpBlockTable[BlockIndex].dwFlags & MAFA_COMPRESS2)) && !(mpqOpenArc->lpBlockTable[BlockIndex].dwFlags & MAFA_SINGLEBLOCK))
                {
-                       SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset+HeaderLength,0,FILE_BEGIN);
+                       SFSetFilePointer(mpqOpenArc->hFile, mpqOpenArc->qwMPQStart + MakeUInt64(mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset, mpqOpenArc->lpFileOffsetsHigh[BlockIndex]) + HeaderLength, FILE_BEGIN);
                        ReadFile(mpqOpenArc->hFile,dwBlockPtrTable,(TotalBlocks+1)*4,&nBytesRead,0);
                        if (mpqOpenArc->lpBlockTable[BlockIndex].dwFlags & MAFA_ENCRYPT) {
                                DecryptData((LPBYTE)dwBlockPtrTable,(TotalBlocks+1)*4,dwCryptKey-1);
@@ -1302,28 +1235,31 @@ BOOL SFMPQAPI WINAPI SFileReadFile(MPQHANDLE hFile,LPVOID lpBuffer,DWORD nNumber
                {
                        for (i=0;i<TotalBlocks+1;i++) {
                                if (i<TotalBlocks) dwBlockPtrTable[i] = i * blockSize;
-                               else dwBlockPtrTable[i] = mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize;
+                               else dwBlockPtrTable[i] = mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize - HeaderLength;
                        }
                }
                mpqOpenFile->lpdwBlockOffsets = dwBlockPtrTable;
        }
-       BYTE *compbuffer = (BYTE *)SFAlloc(blockSize+3);
-       if (!compbuffer) {
-               SFFree(blk16Buffer);
-               SFFree(blkBuffer);
-               if (lpNumberOfBytesRead) *lpNumberOfBytesRead = 0;
-               if (lpOverlapped) lpOverlapped->InternalHigh = 0;
-               return FALSE;
+       BYTE *compbuffer = NULL;
+       if ((mpqOpenArc->lpBlockTable[BlockIndex].dwFlags & MAFA_COMPRESS) || (mpqOpenArc->lpBlockTable[BlockIndex].dwFlags & MAFA_COMPRESS2)) {
+               compbuffer = (BYTE *)SFAlloc(blockSize+3);
+               if (!compbuffer) {
+                       if (blkLargeBuffer) SFFree(blkLargeBuffer);
+                       SFFree(blkBuffer);
+                       if (lpNumberOfBytesRead) *lpNumberOfBytesRead = 0;
+                       if (lpOverlapped) lpOverlapped->InternalHigh = 0;
+                       return FALSE;
+               }
        }
        DWORD blk=0,blki=0;
        for (i=blockNum;i<nBlocks;i++) {
-               if (blk==0) {
-                       SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset+HeaderLength+mpqOpenFile->lpdwBlockOffsets[i],0,FILE_BEGIN);
+               if (blk==0 && blkLargeBuffer) {
+                       SFSetFilePointer(mpqOpenArc->hFile, mpqOpenArc->qwMPQStart + MakeUInt64(mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset, mpqOpenArc->lpFileOffsetsHigh[BlockIndex]) + HeaderLength + mpqOpenFile->lpdwBlockOffsets[i], FILE_BEGIN);
                        blki=i;
-                       if (i+16>nBlocks) {
-                               if (ReadFile(mpqOpenArc->hFile,blk16Buffer,mpqOpenFile->lpdwBlockOffsets[nBlocks]-mpqOpenFile->lpdwBlockOffsets[i],&nBytesRead,0)==0) {
-                                       SFFree(compbuffer);
-                                       SFFree(blk16Buffer);
+                       if (i+nBufferCount>nBlocks) {
+                               if (ReadFile(mpqOpenArc->hFile,blkLargeBuffer,mpqOpenFile->lpdwBlockOffsets[nBlocks]-mpqOpenFile->lpdwBlockOffsets[i],&nBytesRead,0)==0) {
+                                       if (compbuffer) SFFree(compbuffer);
+                                       SFFree(blkLargeBuffer);
                                        SFFree(blkBuffer);
                                        if (lpNumberOfBytesRead) *lpNumberOfBytesRead = TotalBytesRead;
                                        if (lpOverlapped) lpOverlapped->InternalHigh = TotalBytesRead;
@@ -1332,9 +1268,9 @@ BOOL SFMPQAPI WINAPI SFileReadFile(MPQHANDLE hFile,LPVOID lpBuffer,DWORD nNumber
 
                        }
                        else {
-                               if (ReadFile(mpqOpenArc->hFile,blk16Buffer,mpqOpenFile->lpdwBlockOffsets[i+16]-mpqOpenFile->lpdwBlockOffsets[i],&nBytesRead,0)==0) {
-                                       SFFree(compbuffer);
-                                       SFFree(blk16Buffer);
+                               if (ReadFile(mpqOpenArc->hFile,blkLargeBuffer,mpqOpenFile->lpdwBlockOffsets[i+nBufferCount]-mpqOpenFile->lpdwBlockOffsets[i],&nBytesRead,0)==0) {
+                                       if (compbuffer) SFFree(compbuffer);
+                                       SFFree(blkLargeBuffer);
                                        SFFree(blkBuffer);
                                        if (lpNumberOfBytesRead) *lpNumberOfBytesRead = TotalBytesRead;
                                        if (lpOverlapped) lpOverlapped->InternalHigh = TotalBytesRead;
@@ -1342,7 +1278,20 @@ BOOL SFMPQAPI WINAPI SFileReadFile(MPQHANDLE hFile,LPVOID lpBuffer,DWORD nNumber
                                }
                        }
                }
-               memcpy(blkBuffer,((char *)blk16Buffer)+(mpqOpenFile->lpdwBlockOffsets[blki+blk]-mpqOpenFile->lpdwBlockOffsets[blki]),mpqOpenFile->lpdwBlockOffsets[i+1]-mpqOpenFile->lpdwBlockOffsets[i]);
+               if (blkLargeBuffer) {
+                       memcpy(blkBuffer,((char *)blkLargeBuffer)+(mpqOpenFile->lpdwBlockOffsets[blki+blk]-mpqOpenFile->lpdwBlockOffsets[blki]),mpqOpenFile->lpdwBlockOffsets[i+1]-mpqOpenFile->lpdwBlockOffsets[i]);
+               }
+               else {
+                       SFSetFilePointer(mpqOpenArc->hFile, mpqOpenArc->qwMPQStart + MakeUInt64(mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset, mpqOpenArc->lpFileOffsetsHigh[BlockIndex]) + HeaderLength + mpqOpenFile->lpdwBlockOffsets[i], FILE_BEGIN);
+                       blki=i;
+                       if (ReadFile(mpqOpenArc->hFile,blkBuffer,mpqOpenFile->lpdwBlockOffsets[i+1]-mpqOpenFile->lpdwBlockOffsets[i],&nBytesRead,0)==0) {
+                               if (compbuffer) SFFree(compbuffer);
+                               SFFree(blkBuffer);
+                               if (lpNumberOfBytesRead) *lpNumberOfBytesRead = TotalBytesRead;
+                               if (lpOverlapped) lpOverlapped->InternalHigh = TotalBytesRead;
+                               return FALSE;
+                       }
+               }
                if (mpqOpenArc->lpBlockTable[BlockIndex].dwFlags & MAFA_ENCRYPT)
                {
                        DecryptData((LPBYTE)blkBuffer,mpqOpenFile->lpdwBlockOffsets[i+1]-mpqOpenFile->lpdwBlockOffsets[i],dwCryptKey+i);
@@ -1414,10 +1363,10 @@ BOOL SFMPQAPI WINAPI SFileReadFile(MPQHANDLE hFile,LPVOID lpBuffer,DWORD nNumber
                                nNumberOfBytesToRead-=nNumberOfBytesToRead;
                        }
                }
-               blk = (blk+1) % 16;
+               blk = (blk+1) % nBufferCount;
        }
-       SFFree(compbuffer);
-       SFFree(blk16Buffer);
+       if (compbuffer) SFFree(compbuffer);
+       if (blkLargeBuffer) SFFree(blkLargeBuffer);
        SFFree(blkBuffer);
        if (lpNumberOfBytesRead) *lpNumberOfBytesRead = TotalBytesRead;
        if (lpOverlapped) lpOverlapped->InternalHigh = TotalBytesRead;
@@ -1526,8 +1475,11 @@ BOOL SFMPQAPI WINAPI SFileListFiles(MPQHANDLE hMPQ, LPCSTR lpFileLists, FILELIST
                                lpListBuffer[i].dwCompressedSize = mpqOpenArc->lpBlockTable[dwBlockIndex].dwCompressedSize;
                                lpListBuffer[i].dwFullSize = mpqOpenArc->lpBlockTable[dwBlockIndex].dwFullSize;
                                lpListBuffer[i].dwFlags = mpqOpenArc->lpBlockTable[dwBlockIndex].dwFlags;
-                               lpListBuffer[i].dwFileExists=0xFFFFFFFF;
-                               SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->lpBlockTable[dwBlockIndex].dwFileOffset+0x40,0,FILE_BEGIN);
+                               if (dwFlags & SFILE_LIST_FLAG_UNKNOWN)
+                                       lpListBuffer[i].dwFileExists = 1;
+                               else
+                                       lpListBuffer[i].dwFileExists=0xFFFFFFFF;
+                               SFSetFilePointer(mpqOpenArc->hFile, mpqOpenArc->qwMPQStart + MakeUInt64(mpqOpenArc->lpBlockTable[dwBlockIndex].dwFileOffset, mpqOpenArc->lpFileOffsetsHigh[dwBlockIndex]) + 0x40, FILE_BEGIN);
                                ReadFile(mpqOpenArc->hFile,lpListBuffer[i].szFileName,260,&tsz,0);
 
                                if (mpqOpenArc->lpHashTable[i].dwNameHashA==HashString(lpListBuffer[i].szFileName,HASH_NAME_A) && mpqOpenArc->lpHashTable[i].dwNameHashB==HashString(lpListBuffer[i].szFileName,HASH_NAME_B)) {
@@ -1537,6 +1489,10 @@ BOOL SFMPQAPI WINAPI SFileListFiles(MPQHANDLE hMPQ, LPCSTR lpFileLists, FILELIST
                                }
                                else {
                                        sprintf(lpListBuffer[i].szFileName,UNKNOWN_OUT,i);
+                                       if (dwFlags & SFILE_LIST_FLAG_UNKNOWN) {
+                                               lpListBuffer[i].dwFileExists |= 2;
+                                       }
+
                                        if (dwFlags&SFILE_LIST_ONLY_KNOWN) {
                                                lpListBuffer[i].dwFileExists = 0;
                                        }
@@ -1612,8 +1568,8 @@ BOOL SFMPQAPI WINAPI SFileListFiles(MPQHANDLE hMPQ, LPCSTR lpFileLists, FILELIST
                        if (!(dwFlags&SFILE_LIST_MEMORY_LIST)) {
                                hFile = CreateFile(lpNameBuffers[i],GENERIC_READ,FILE_SHARE_READ,0,OPEN_EXISTING,0,0);
                                if (hFile!=INVALID_HANDLE_VALUE) {
-                                       fsz = GetFileSize(hFile,0);
-                                       SetFilePointer(hFile,0,0,FILE_BEGIN);
+                                       fsz = SFGetFileSize(hFile);
+                                       SFSetFilePointer(hFile,0,FILE_BEGIN);
                                        lpNameBuffers[i] = (char *)SFAlloc(fsz+1);
                                        ReadFile(hFile,lpNameBuffers[i],fsz,&tsz,0);
                                        CloseHandle(hFile);
@@ -1690,7 +1646,10 @@ BOOL SFMPQAPI WINAPI SFileListFiles(MPQHANDLE hMPQ, LPCSTR lpFileLists, FILELIST
                        lpListBuffer[i].dwCompressedSize = mpqOpenArc->lpBlockTable[dwBlockIndex].dwCompressedSize;
                        lpListBuffer[i].dwFullSize = mpqOpenArc->lpBlockTable[dwBlockIndex].dwFullSize;
                        lpListBuffer[i].dwFlags = mpqOpenArc->lpBlockTable[dwBlockIndex].dwFlags;
-                       lpListBuffer[i].dwFileExists=0xFFFFFFFF;
+                       if (dwFlags & SFILE_LIST_FLAG_UNKNOWN)
+                               lpListBuffer[i].dwFileExists = 1;
+                       else
+                               lpListBuffer[i].dwFileExists=0xFFFFFFFF;
                        for (j=0;j<dwTotalLines;j++) {
                                if (mpqOpenArc->lpHashTable[i].dwNameHashA==lpdwNameHashA[j] && mpqOpenArc->lpHashTable[i].dwNameHashB==lpdwNameHashB[j]) {
                                        strncpy(lpListBuffer[i].szFileName,lpNames[j],260);
@@ -1701,6 +1660,10 @@ BOOL SFMPQAPI WINAPI SFileListFiles(MPQHANDLE hMPQ, LPCSTR lpFileLists, FILELIST
                                }
                                if (j+1==dwTotalLines) {
                                        sprintf(lpListBuffer[i].szFileName,UNKNOWN_OUT,i);
+                                       if (dwFlags & SFILE_LIST_FLAG_UNKNOWN) {
+                                               lpListBuffer[i].dwFileExists |= 2;
+                                       }
+
                                        if (dwFlags&SFILE_LIST_ONLY_KNOWN) {
                                                lpListBuffer[i].dwFileExists = 0;
                                        }
@@ -1771,7 +1734,7 @@ BOOL SFMPQAPI WINAPI MpqAddFileToArchiveEx(MPQHANDLE hMPQ, LPCSTR lpSourceFileNa
        if (!hFile) return FALSE;
        HANDLE haFile = CreateFile(lpSourceFileName,GENERIC_READ,FILE_SHARE_READ,0,OPEN_EXISTING,0,0);
        if (haFile==INVALID_HANDLE_VALUE) return FALSE;
-       DWORD fsz = GetFileSize(haFile,0),tsz;
+       DWORD fsz = SFGetFileSize(haFile),tsz;
        DWORD ucfsz = fsz;
        BOOL IsBNcache = FALSE;char *buffer,*hbuffer;
        MPQARCHIVE *mpqOpenArc = (MPQARCHIVE *)hMPQ;
@@ -1953,15 +1916,19 @@ BOOL SFMPQAPI WINAPI MpqAddFileToArchiveEx(MPQHANDLE hMPQ, LPCSTR lpSourceFileNa
        if ((hashEntry->dwBlockTableIndex&0xFFFFFFFE)==0xFFFFFFFE)
        {
                BLOCKTABLEENTRY *lpnBlockTable;
-               lpnBlockTable = (BLOCKTABLEENTRY *)SFAlloc(sizeof(BLOCKTABLEENTRY) * (mpqOpenArc->MpqHeader.dwBlockTableSize + 1));
+               lpnBlockTable = (BLOCKTABLEENTRY *)SFAlloc((sizeof(BLOCKTABLEENTRY) + sizeof(UInt16)) * (mpqOpenArc->MpqHeader.dwBlockTableSize + 1));
                if(!lpnBlockTable) {
                        SFFree(buffer);
                        return FALSE;
                }
-               if (mpqOpenArc->lpBlockTable) memcpy(lpnBlockTable,mpqOpenArc->lpBlockTable,sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize);
+               if (mpqOpenArc->lpBlockTable) {
+                       memcpy(lpnBlockTable,mpqOpenArc->lpBlockTable,sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize);
+                       memcpy(lpnBlockTable + mpqOpenArc->MpqHeader.dwBlockTableSize + 1, mpqOpenArc->lpFileOffsetsHigh, sizeof(UInt16) * mpqOpenArc->MpqHeader.dwBlockTableSize);
+               }
                mpqOpenArc->MpqHeader.dwBlockTableSize++;
                if (mpqOpenArc->lpBlockTable) SFFree(mpqOpenArc->lpBlockTable);
                mpqOpenArc->lpBlockTable = lpnBlockTable;
+               mpqOpenArc->lpFileOffsetsHigh = (UInt16 *)(mpqOpenArc->lpBlockTable + mpqOpenArc->MpqHeader.dwBlockTableSize);
                IsNewBlockEntry = TRUE;
        }
        DWORD BlockIndex = mpqOpenArc->MpqHeader.dwBlockTableSize - 1;
@@ -2034,9 +2001,7 @@ BOOL SFMPQAPI WINAPI MpqAddFileToArchiveEx(MPQHANDLE hMPQ, LPCSTR lpSourceFileNa
        mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize = fsz;
        mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize = ucfsz;
        mpqOpenArc->lpBlockTable[BlockIndex].dwFlags = dwFlags|MAFA_EXISTS;
-       DWORD dwFileOffset = mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset;
-       SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart,0,FILE_BEGIN);
-       WriteFile(mpqOpenArc->hFile,&mpqOpenArc->MpqHeader,sizeof(MPQHEADER),&tsz,0);
+       MpqWriteHeaders(mpqOpenArc);
        if (dwFlags & MAFA_ENCRYPT) {
                DWORD dwCryptKey;
                if (dwFlags&MAFA_ENCRYPT) dwCryptKey = HashString(lpDestFileName,HASH_KEY);
@@ -2056,37 +2021,11 @@ BOOL SFMPQAPI WINAPI MpqAddFileToArchiveEx(MPQHANDLE hMPQ, LPCSTR lpSourceFileNa
                }
        }
        SFFree(dwBlkpt);
-       SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+dwFileOffset,0,FILE_BEGIN);
+       SFSetFilePointer(mpqOpenArc->hFile, mpqOpenArc->qwMPQStart + MakeUInt64(mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset, mpqOpenArc->lpFileOffsetsHigh[BlockIndex]), FILE_BEGIN);
        WriteFile(mpqOpenArc->hFile,buffer,fsz,&tsz,0);
        SFFree(buffer);
-       buffer = (char *)SFAlloc(sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize);
-       if (buffer) {
-               memcpy(buffer,mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize);
-               EncryptData((LPBYTE)buffer,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,dwHashTableKey);
-               SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->MpqHeader.dwHashTableOffset,0,FILE_BEGIN);
-               WriteFile(mpqOpenArc->hFile,buffer,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,&tsz,0);
-               SFFree(buffer);
-       }
-       else {
-               EncryptData((LPBYTE)mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,dwHashTableKey);
-               SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->MpqHeader.dwHashTableOffset,0,FILE_BEGIN);
-               WriteFile(mpqOpenArc->hFile,mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,&tsz,0);
-               DecryptData((LPBYTE)mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,dwHashTableKey);
-       }
-       buffer = (char *)SFAlloc(sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize);
-       if (buffer) {
-               memcpy(buffer,mpqOpenArc->lpBlockTable,sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize);
-               EncryptData((LPBYTE)buffer,sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize,dwBlockTableKey);
-               SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->MpqHeader.dwBlockTableOffset,0,FILE_BEGIN);
-               WriteFile(mpqOpenArc->hFile,buffer,sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize,&tsz,0);
-               SFFree(buffer);
-       }
-       else {
-               EncryptData((LPBYTE)mpqOpenArc->lpBlockTable,sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize,dwBlockTableKey);
-               SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->MpqHeader.dwBlockTableOffset,0,FILE_BEGIN);
-               WriteFile(mpqOpenArc->hFile,mpqOpenArc->lpBlockTable,sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize,&tsz,0);
-               DecryptData((LPBYTE)mpqOpenArc->lpBlockTable,sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize,dwBlockTableKey);
-       }
+       WriteHashTable(mpqOpenArc);
+       WriteBlockTable(mpqOpenArc);
        AddToInternalListing(hMPQ,lpDestFileName);
 
        return TRUE;
@@ -2225,6 +2164,7 @@ BOOL SFMPQAPI WINAPI MpqAddFileFromBufferEx(MPQHANDLE hMPQ, LPVOID lpBuffer, DWO
                        if (i==TotalBlocks-1 && (ucfsz % blockSize)!=0) blockSize=ucfsz % blockSize;
                        DWORD outLength=blockSize;
                        BYTE *compdata = compbuffer;
+                       char *oldoutbuffer = outbuffer;
                        if (dwFlags & MAFA_COMPRESS)
                        {
                                memcpy(compdata,(char *)buffer+CurPos,blockSize);
@@ -2271,6 +2211,7 @@ BOOL SFMPQAPI WINAPI MpqAddFileFromBufferEx(MPQHANDLE hMPQ, LPVOID lpBuffer, DWO
                                memcpy((char *)newbuffer+LastOffset,outbuffer,outLength);
                                LastOffset+=outLength;
                        }
+                       outbuffer = oldoutbuffer;
                        CurPos += blockSize;
                }
                fsz = LastOffset;
@@ -2299,15 +2240,19 @@ BOOL SFMPQAPI WINAPI MpqAddFileFromBufferEx(MPQHANDLE hMPQ, LPVOID lpBuffer, DWO
        if ((hashEntry->dwBlockTableIndex&0xFFFFFFFE)==0xFFFFFFFE)
        {
                BLOCKTABLEENTRY *lpnBlockTable;
-               lpnBlockTable = (BLOCKTABLEENTRY *)SFAlloc(sizeof(BLOCKTABLEENTRY) * (mpqOpenArc->MpqHeader.dwBlockTableSize + 1));
-               if(lpnBlockTable==0) {
+               lpnBlockTable = (BLOCKTABLEENTRY *)SFAlloc((sizeof(BLOCKTABLEENTRY) + sizeof(UInt16)) * (mpqOpenArc->MpqHeader.dwBlockTableSize + 1));
+               if(!lpnBlockTable) {
                        SFFree(buffer);
                        return FALSE;
                }
-               if (mpqOpenArc->lpBlockTable!=0) memcpy(lpnBlockTable,mpqOpenArc->lpBlockTable,sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize);
+               if (mpqOpenArc->lpBlockTable) {
+                       memcpy(lpnBlockTable,mpqOpenArc->lpBlockTable,sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize);
+                       memcpy(lpnBlockTable + mpqOpenArc->MpqHeader.dwBlockTableSize + 1, mpqOpenArc->lpFileOffsetsHigh, sizeof(UInt16) * mpqOpenArc->MpqHeader.dwBlockTableSize);
+               }
                mpqOpenArc->MpqHeader.dwBlockTableSize++;
-               if (mpqOpenArc->lpBlockTable!=0) SFFree(mpqOpenArc->lpBlockTable);
+               if (mpqOpenArc->lpBlockTable) SFFree(mpqOpenArc->lpBlockTable);
                mpqOpenArc->lpBlockTable = lpnBlockTable;
+               mpqOpenArc->lpFileOffsetsHigh = (UInt16 *)(mpqOpenArc->lpBlockTable + mpqOpenArc->MpqHeader.dwBlockTableSize);
                IsNewBlockEntry = TRUE;
        }
        DWORD BlockIndex = mpqOpenArc->MpqHeader.dwBlockTableSize - 1;
@@ -2379,9 +2324,7 @@ BOOL SFMPQAPI WINAPI MpqAddFileFromBufferEx(MPQHANDLE hMPQ, LPVOID lpBuffer, DWO
        mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize = fsz;
        mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize = ucfsz;
        mpqOpenArc->lpBlockTable[BlockIndex].dwFlags = dwFlags|MAFA_EXISTS;
-       DWORD dwFileOffset = mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset;
-       SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart,0,FILE_BEGIN);
-       WriteFile(mpqOpenArc->hFile,&mpqOpenArc->MpqHeader,sizeof(MPQHEADER),&tsz,0);
+       MpqWriteHeaders(mpqOpenArc);
        if (dwFlags & MAFA_ENCRYPT) {
                DWORD dwCryptKey;
                if (dwFlags&MAFA_ENCRYPT) dwCryptKey = HashString(lpFileName,HASH_KEY);
@@ -2402,37 +2345,11 @@ BOOL SFMPQAPI WINAPI MpqAddFileFromBufferEx(MPQHANDLE hMPQ, LPVOID lpBuffer, DWO
                }
        }
        SFFree(dwBlkpt);
-       SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+dwFileOffset,0,FILE_BEGIN);
+       SFSetFilePointer(mpqOpenArc->hFile, mpqOpenArc->qwMPQStart + MakeUInt64(mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset, mpqOpenArc->lpFileOffsetsHigh[BlockIndex]), FILE_BEGIN);
        WriteFile(mpqOpenArc->hFile,buffer,fsz,&tsz,0);
        SFFree(buffer);
-       buffer = (char *)SFAlloc(sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize);
-       if (buffer!=0) {
-               memcpy(buffer,mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize);
-               EncryptData((LPBYTE)buffer,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,dwHashTableKey);
-               SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->MpqHeader.dwHashTableOffset,0,FILE_BEGIN);
-               WriteFile(mpqOpenArc->hFile,buffer,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,&tsz,0);
-               SFFree(buffer);
-       }
-       else {
-               EncryptData((LPBYTE)mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,dwHashTableKey);
-               SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->MpqHeader.dwHashTableOffset,0,FILE_BEGIN);
-               WriteFile(mpqOpenArc->hFile,mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,&tsz,0);
-               DecryptData((LPBYTE)mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,dwHashTableKey);
-       }
-       buffer = (char *)SFAlloc(sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize);
-       if (buffer!=0) {
-               memcpy(buffer,mpqOpenArc->lpBlockTable,sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize);
-               EncryptData((LPBYTE)buffer,sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize,dwBlockTableKey);
-               SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->MpqHeader.dwBlockTableOffset,0,FILE_BEGIN);
-               WriteFile(mpqOpenArc->hFile,buffer,sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize,&tsz,0);
-               SFFree(buffer);
-       }
-       else {
-               EncryptData((LPBYTE)mpqOpenArc->lpBlockTable,sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize,dwBlockTableKey);
-               SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->MpqHeader.dwBlockTableOffset,0,FILE_BEGIN);
-               WriteFile(mpqOpenArc->hFile,mpqOpenArc->lpBlockTable,sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize,&tsz,0);
-               DecryptData((LPBYTE)mpqOpenArc->lpBlockTable,sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize,dwBlockTableKey);
-       }
+       WriteHashTable(mpqOpenArc);
+       WriteBlockTable(mpqOpenArc);
        AddToInternalListing(hMPQ,lpFileName);
        return TRUE;
 }
@@ -2505,7 +2422,7 @@ BOOL SFMPQAPI WINAPI MpqRenameAndSetFileLocale(MPQHANDLE hMPQ, LPCSTR lpcOldFile
                        DWORD HeaderLength=0;
                        if (memcmp(&mpqOpenArc->MpqHeader.dwMPQID,ID_BN3,4)==0)
                        {
-                               SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset,0,FILE_BEGIN);
+                               SFSetFilePointer(mpqOpenArc->hFile, mpqOpenArc->qwMPQStart + MakeUInt64(mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset, mpqOpenArc->lpFileOffsetsHigh[BlockIndex]), FILE_BEGIN);
                                ReadFile(mpqOpenArc->hFile,&HeaderLength,4,&tsz,0);
 
                        }
@@ -2520,7 +2437,7 @@ BOOL SFMPQAPI WINAPI MpqRenameAndSetFileLocale(MPQHANDLE hMPQ, LPCSTR lpcOldFile
                        DWORD i;
                        if ((mpqOpenArc->lpBlockTable[BlockIndex].dwFlags & MAFA_COMPRESS)==MAFA_COMPRESS || (mpqOpenArc->lpBlockTable[BlockIndex].dwFlags & MAFA_COMPRESS2)==MAFA_COMPRESS2)
                        {
-                               SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset+HeaderLength,0,FILE_BEGIN);
+                               SFSetFilePointer(mpqOpenArc->hFile, mpqOpenArc->qwMPQStart + MakeUInt64(mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset, mpqOpenArc->lpFileOffsetsHigh[BlockIndex]) + HeaderLength, FILE_BEGIN);
                                ReadFile(mpqOpenArc->hFile,dwBlockPtrTable,(TotalBlocks+1)*4,&tsz,0);
                                DecryptData((LPBYTE)dwBlockPtrTable,(TotalBlocks+1)*4,dwOldCryptKey-1);
                                char *EncryptedTable = (char *)SFAlloc((TotalBlocks+1)*4);
@@ -2530,7 +2447,7 @@ BOOL SFMPQAPI WINAPI MpqRenameAndSetFileLocale(MPQHANDLE hMPQ, LPCSTR lpcOldFile
                                }
                                memcpy(EncryptedTable,dwBlockPtrTable,(TotalBlocks+1)*4);
                                EncryptData((LPBYTE)EncryptedTable,(TotalBlocks+1)*4,dwNewCryptKey-1);
-                               SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset+HeaderLength,0,FILE_BEGIN);
+                               SFSetFilePointer(mpqOpenArc->hFile, mpqOpenArc->qwMPQStart + MakeUInt64(mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset, mpqOpenArc->lpFileOffsetsHigh[BlockIndex]) + HeaderLength, FILE_BEGIN);
                                WriteFile(mpqOpenArc->hFile,EncryptedTable,(TotalBlocks+1)*4,&tsz,0);
                                SFFree(EncryptedTable);
                        }
@@ -2544,16 +2461,16 @@ BOOL SFMPQAPI WINAPI MpqRenameAndSetFileLocale(MPQHANDLE hMPQ, LPCSTR lpcOldFile
                        char *blkBuffer = (char *)SFAlloc(blockSize);
                        if (blkBuffer==0) {
                                EncryptData((LPBYTE)dwBlockPtrTable,(TotalBlocks+1)*4,dwOldCryptKey-1);
-                               SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset+HeaderLength,0,FILE_BEGIN);
+                               SFSetFilePointer(mpqOpenArc->hFile, mpqOpenArc->qwMPQStart + MakeUInt64(mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset, mpqOpenArc->lpFileOffsetsHigh[BlockIndex]) + HeaderLength, FILE_BEGIN);
                                WriteFile(mpqOpenArc->hFile,dwBlockPtrTable,(TotalBlocks+1)*4,&tsz,0);
                                SFFree(dwBlockPtrTable);
                                return FALSE;
                        }
                        for (i=0;i<TotalBlocks;i++) {
-                               SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset+HeaderLength+dwBlockPtrTable[i],0,FILE_BEGIN);
+                               SFSetFilePointer(mpqOpenArc->hFile, mpqOpenArc->qwMPQStart + MakeUInt64(mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset, mpqOpenArc->lpFileOffsetsHigh[BlockIndex]) + HeaderLength + dwBlockPtrTable[i], FILE_BEGIN);
                                if (ReadFile(mpqOpenArc->hFile,blkBuffer,dwBlockPtrTable[i+1]-dwBlockPtrTable[i],&tsz,0)==0) {
                                        EncryptData((LPBYTE)dwBlockPtrTable,(TotalBlocks+1)*4,dwOldCryptKey-1);
-                                       SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset+HeaderLength,0,FILE_BEGIN);
+                                       SFSetFilePointer(mpqOpenArc->hFile, mpqOpenArc->qwMPQStart + MakeUInt64(mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset, mpqOpenArc->lpFileOffsetsHigh[BlockIndex]) + HeaderLength, FILE_BEGIN);
                                        WriteFile(mpqOpenArc->hFile,dwBlockPtrTable,(TotalBlocks+1)*4,&tsz,0);
                                        SFFree(dwBlockPtrTable);
                                        SFFree(blkBuffer);
@@ -2561,7 +2478,7 @@ BOOL SFMPQAPI WINAPI MpqRenameAndSetFileLocale(MPQHANDLE hMPQ, LPCSTR lpcOldFile
                                }
                                DecryptData((LPBYTE)blkBuffer,dwBlockPtrTable[i+1]-dwBlockPtrTable[i],dwOldCryptKey+i);
                                EncryptData((LPBYTE)blkBuffer,dwBlockPtrTable[i+1]-dwBlockPtrTable[i],dwNewCryptKey+i);
-                               SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset+HeaderLength+dwBlockPtrTable[i],0,FILE_BEGIN);
+                               SFSetFilePointer(mpqOpenArc->hFile, mpqOpenArc->qwMPQStart + MakeUInt64(mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset, mpqOpenArc->lpFileOffsetsHigh[BlockIndex]) + HeaderLength + dwBlockPtrTable[i], FILE_BEGIN);
                                WriteFile(mpqOpenArc->hFile,blkBuffer,dwBlockPtrTable[i+1]-dwBlockPtrTable[i],&tsz,0);
                        }
                        SFFree(dwBlockPtrTable);
@@ -2573,20 +2490,7 @@ BOOL SFMPQAPI WINAPI MpqRenameAndSetFileLocale(MPQHANDLE hMPQ, LPCSTR lpcOldFile
                oldHashEntry->dwNameHashB = 0xFFFFFFFF;
                oldHashEntry->lcLocale = 0xFFFFFFFF;
                oldHashEntry->dwBlockTableIndex = 0xFFFFFFFE;
-               char *buffer = (char *)SFAlloc(sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize);
-               if (buffer!=0) {
-                       memcpy(buffer,mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize);
-                       EncryptData((LPBYTE)buffer,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,dwHashTableKey);
-                       SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->MpqHeader.dwHashTableOffset,0,FILE_BEGIN);
-                       WriteFile(mpqOpenArc->hFile,buffer,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,&tsz,0);
-                       SFFree(buffer);
-               }
-               else {
-                       EncryptData((LPBYTE)mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,dwHashTableKey);
-                       SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->MpqHeader.dwHashTableOffset,0,FILE_BEGIN);
-                       WriteFile(mpqOpenArc->hFile,mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,&tsz,0);
-                       DecryptData((LPBYTE)mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,dwHashTableKey);
-               }
+               WriteHashTable(mpqOpenArc);
        }
        LCID dwOldLocale=LocaleID;
        LocaleID=nOldLocale;
@@ -2626,22 +2530,7 @@ BOOL SFMPQAPI WINAPI MpqDeleteFileWithLocale(MPQHANDLE hMPQ, LPCSTR lpFileName,
        hashEntry->dwNameHashB = 0xFFFFFFFF;
        hashEntry->lcLocale = 0xFFFFFFFF;
        hashEntry->dwBlockTableIndex = 0xFFFFFFFE;
-       DWORD tsz;
-       char *buffer = (char *)SFAlloc(sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize);
-       if (buffer!=0) {
-               memcpy(buffer,mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize);
-               EncryptData((LPBYTE)buffer,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,dwHashTableKey);
-               SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->MpqHeader.dwHashTableOffset,0,FILE_BEGIN);
-
-               WriteFile(mpqOpenArc->hFile,buffer,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,&tsz,0);
-               SFFree(buffer);
-       }
-       else {
-               EncryptData((LPBYTE)mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,dwHashTableKey);
-               SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->MpqHeader.dwHashTableOffset,0,FILE_BEGIN);
-               WriteFile(mpqOpenArc->hFile,mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,&tsz,0);
-               DecryptData((LPBYTE)mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,dwHashTableKey);
-       }
+       WriteHashTable(mpqOpenArc);
        LCID dwOldLocale=LocaleID;
        LocaleID=nLocale;
        RemoveFromInternalListing(hMPQ,lpFileName);
@@ -2665,17 +2554,19 @@ BOOL SFMPQAPI WINAPI MpqCompactArchive(MPQHANDLE hMPQ)
        char *lpFileName = (char *)NewAlloc.Alloc(strlen(mpqOpenArc->lpFileName)+13);
        sprintf(lpFileName,"%s.compact",mpqOpenArc->lpFileName);
        HANDLE hFile = CreateFile(lpFileName,GENERIC_READ|GENERIC_WRITE,0,0,CREATE_NEW,0,0);
-       DWORD i;
+       UInt64 i;
        if (hFile==INVALID_HANDLE_VALUE) {
-               for (i=0;i<10000;i++) {
-                       sprintf(lpFileName,"%s.compact.%04ld",mpqOpenArc->lpFileName,i);
+               int filenum = 0;
+               for (filenum=0;filenum<10000;filenum++) {
+                       sprintf(lpFileName,"%s.compact.%04d",mpqOpenArc->lpFileName,filenum);
 
                        hFile = CreateFile(lpFileName,GENERIC_READ|GENERIC_WRITE,0,0,CREATE_NEW,0,0);
                        if (hFile!=INVALID_HANDLE_VALUE) break;
                }
-               if (i==10000) return FALSE;
+               if (filenum==10000) return FALSE;
        }
-       DWORD dwLastOffset = sizeof(MPQHEADER),tsz;
+       UInt64 qwLastOffset = mpqOpenArc->dwHeaderSize;
+       DWORD tsz;
        char *buffer = (char *)SFAlloc(65536);
        if (buffer==0) {
                CloseHandle(hFile);
@@ -2689,7 +2580,8 @@ BOOL SFMPQAPI WINAPI MpqCompactArchive(MPQHANDLE hMPQ)
                DeleteFile(lpFileName);
                return FALSE;
        }
-       BLOCKTABLEENTRY *lpBlockTable = (BLOCKTABLEENTRY *)SFAlloc(sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize);
+       BLOCKTABLEENTRY *lpBlockTable = (BLOCKTABLEENTRY *)SFAlloc((sizeof(BLOCKTABLEENTRY) + sizeof(UInt16)) * mpqOpenArc->MpqHeader.dwBlockTableSize);
+       UInt16 *lpdwFileOffsetsHigh = (UInt16 *)(lpBlockTable + mpqOpenArc->MpqHeader.dwBlockTableSize);
        if(mpqOpenArc->lpBlockTable!=0) {
                if (lpBlockTable==0) {
                        SFFree(lpHashTable);
@@ -2708,15 +2600,15 @@ BOOL SFMPQAPI WINAPI MpqCompactArchive(MPQHANDLE hMPQ)
                }
                if (j<mpqOpenArc->MpqHeader.dwHashTableSize) {
                        memcpy(&lpBlockTable[i-nBlkOffset],&mpqOpenArc->lpBlockTable[i],sizeof(BLOCKTABLEENTRY));
-                       lpBlockTable[i-nBlkOffset].dwFileOffset = dwLastOffset;
-                       dwLastOffset += mpqOpenArc->lpBlockTable[i].dwCompressedSize;
+                       SplitUInt64(lpBlockTable[i-nBlkOffset].dwFileOffset, lpdwFileOffsetsHigh[i-nBlkOffset], qwLastOffset);
+                       qwLastOffset += mpqOpenArc->lpBlockTable[i].dwCompressedSize;
                        DWORD dwWritten=FALSE;
                        if (mpqOpenArc->lpBlockTable[i].dwFlags&MAFA_ENCRYPT && mpqOpenArc->lpBlockTable[i].dwFlags&MAFA_MODCRYPTKEY && (mpqOpenArc->lpBlockTable[i].dwFlags&MAFA_COMPRESS || mpqOpenArc->lpBlockTable[i].dwFlags&MAFA_COMPRESS2))
                        {
                                DWORD HeaderLength=0;
                                if (memcmp(&mpqOpenArc->MpqHeader.dwMPQID,ID_BN3,4)==0)
                                {
-                                       SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->lpBlockTable[i].dwFileOffset,0,FILE_BEGIN);
+                                       SFSetFilePointer(mpqOpenArc->hFile, mpqOpenArc->qwMPQStart + MakeUInt64(mpqOpenArc->lpBlockTable[i].dwFileOffset, mpqOpenArc->lpFileOffsetsHigh[i]), FILE_BEGIN);
                                        ReadFile(mpqOpenArc->hFile,&HeaderLength,4,&tsz,0);
                                }
                                DWORD blockSize = 512 << mpqOpenArc->MpqHeader.wBlockSize;
@@ -2732,7 +2624,7 @@ BOOL SFMPQAPI WINAPI MpqCompactArchive(MPQHANDLE hMPQ)
                                        DeleteFile(lpFileName);
                                        return FALSE;
                                }
-                               SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->lpBlockTable[i].dwFileOffset+HeaderLength,0,FILE_BEGIN);
+                               SFSetFilePointer(mpqOpenArc->hFile, mpqOpenArc->qwMPQStart + MakeUInt64(mpqOpenArc->lpBlockTable[i].dwFileOffset, mpqOpenArc->lpFileOffsetsHigh[i]) + HeaderLength, FILE_BEGIN);
                                ReadFile(mpqOpenArc->hFile,dwBlockPtrTable,(TotalBlocks+1)*4,&tsz,0);
                                DWORD dwOldCryptKey = DetectFileSeed(dwBlockPtrTable,(TotalBlocks+1)*4,blockSize);
                                DWORD dwNewCryptKey = (dwOldCryptKey ^ mpqOpenArc->lpBlockTable[i].dwFullSize) - mpqOpenArc->lpBlockTable[i].dwFileOffset;
@@ -2818,7 +2710,7 @@ BOOL SFMPQAPI WINAPI MpqCompactArchive(MPQHANDLE hMPQ)
                                        }
                                        memcpy(EncryptedTable,dwBlockPtrTable,(TotalBlocks+1)*4);
                                        EncryptData((LPBYTE)EncryptedTable,(TotalBlocks+1)*4,dwNewCryptKey-1);
-                                       SetFilePointer(hFile,lpBlockTable[i-nBlkOffset].dwFileOffset+HeaderLength,0,FILE_BEGIN);
+                                       SFSetFilePointer(hFile, MakeUInt64(lpBlockTable[i-nBlkOffset].dwFileOffset, lpdwFileOffsetsHigh[i-nBlkOffset]) + HeaderLength, FILE_BEGIN);
                                        WriteFile(hFile,EncryptedTable,(TotalBlocks+1)*4,&tsz,0);
                                        SFFree(EncryptedTable);
                                        char *blkBuffer = (char *)SFAlloc(blockSize);
@@ -2832,7 +2724,7 @@ BOOL SFMPQAPI WINAPI MpqCompactArchive(MPQHANDLE hMPQ)
                                                return FALSE;
                                        }
                                        for (DWORD k=0;k<TotalBlocks;k++) {
-                                               SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->lpBlockTable[i].dwFileOffset+HeaderLength+dwBlockPtrTable[k],0,FILE_BEGIN);
+                                               SFSetFilePointer(mpqOpenArc->hFile, mpqOpenArc->qwMPQStart + MakeUInt64(mpqOpenArc->lpBlockTable[i].dwFileOffset, mpqOpenArc->lpFileOffsetsHigh[i]) + HeaderLength + dwBlockPtrTable[k], FILE_BEGIN);
                                                if (ReadFile(mpqOpenArc->hFile,blkBuffer,dwBlockPtrTable[k+1]-dwBlockPtrTable[k],&tsz,0)==0) {
                                                        SFFree(dwBlockPtrTable);
                                                        SFFree(blkBuffer);
@@ -2845,7 +2737,7 @@ BOOL SFMPQAPI WINAPI MpqCompactArchive(MPQHANDLE hMPQ)
                                                }
                                                DecryptData((LPBYTE)blkBuffer,dwBlockPtrTable[k+1]-dwBlockPtrTable[k],dwOldCryptKey+k);
                                                EncryptData((LPBYTE)blkBuffer,dwBlockPtrTable[k+1]-dwBlockPtrTable[k],dwNewCryptKey+k);
-                                               SetFilePointer(hFile,lpBlockTable[i-nBlkOffset].dwFileOffset+HeaderLength+dwBlockPtrTable[k],0,FILE_BEGIN);
+                                               SFSetFilePointer(hFile, MakeUInt64(lpBlockTable[i-nBlkOffset].dwFileOffset, lpdwFileOffsetsHigh[i-nBlkOffset]) + HeaderLength + dwBlockPtrTable[k], FILE_BEGIN);
                                                WriteFile(hFile,blkBuffer,dwBlockPtrTable[k+1]-dwBlockPtrTable[k],&tsz,0);
                                        }
                                        SFFree(blkBuffer);
@@ -2859,7 +2751,7 @@ BOOL SFMPQAPI WINAPI MpqCompactArchive(MPQHANDLE hMPQ)
                                if (memcmp(&mpqOpenArc->MpqHeader.dwMPQID,ID_BN3,4)==0)
 
                                {
-                                       SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->lpBlockTable[i].dwFileOffset,0,FILE_BEGIN);
+                                       SFSetFilePointer(mpqOpenArc->hFile, mpqOpenArc->qwMPQStart + MakeUInt64(mpqOpenArc->lpBlockTable[i].dwFileOffset, mpqOpenArc->lpFileOffsetsHigh[i]), FILE_BEGIN);
                                        ReadFile(mpqOpenArc->hFile,&HeaderLength,4,&tsz,0);
                                }
                                DWORD blockSize = 512 << mpqOpenArc->MpqHeader.wBlockSize;
@@ -2944,7 +2836,7 @@ BOOL SFMPQAPI WINAPI MpqCompactArchive(MPQHANDLE hMPQ)
                                                return FALSE;
                                        }
                                        for (DWORD k=0;k<mpqOpenArc->lpBlockTable[i].dwFullSize;k+=blockSize) {
-                                               SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->lpBlockTable[i].dwFileOffset+HeaderLength+k,0,FILE_BEGIN);
+                                               SFSetFilePointer(mpqOpenArc->hFile, mpqOpenArc->qwMPQStart + MakeUInt64(mpqOpenArc->lpBlockTable[i].dwFileOffset, mpqOpenArc->lpFileOffsetsHigh[i]) + HeaderLength + k, FILE_BEGIN);
                                                if (k+blockSize>mpqOpenArc->lpBlockTable[i].dwFullSize) blockSize = mpqOpenArc->lpBlockTable[i].dwFullSize % blockSize;
                                                if (ReadFile(mpqOpenArc->hFile,blkBuffer,blockSize,&tsz,0)==0) {
                                                        SFFree(blkBuffer);
@@ -2958,7 +2850,7 @@ BOOL SFMPQAPI WINAPI MpqCompactArchive(MPQHANDLE hMPQ)
                                                }
                                                DecryptData((LPBYTE)blkBuffer,blockSize,dwOldCryptKey+k);
                                                EncryptData((LPBYTE)blkBuffer,blockSize,dwNewCryptKey+k);
-                                               SetFilePointer(hFile,lpBlockTable[i-nBlkOffset].dwFileOffset+HeaderLength+k,0,FILE_BEGIN);
+                                               SFSetFilePointer(hFile, MakeUInt64(lpBlockTable[i-nBlkOffset].dwFileOffset, lpdwFileOffsetsHigh[i-nBlkOffset]) + HeaderLength + k, FILE_BEGIN);
                                                WriteFile(hFile,blkBuffer,blockSize,&tsz,0);
                                        }
                                        SFFree(blkBuffer);
@@ -2968,8 +2860,8 @@ BOOL SFMPQAPI WINAPI MpqCompactArchive(MPQHANDLE hMPQ)
                        if (dwWritten==FALSE) {
                                ReadSize = 65536;
                                for (j=0;j<mpqOpenArc->lpBlockTable[i].dwCompressedSize;j+=65536) {
-                                       SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->lpBlockTable[i].dwFileOffset+j,0,FILE_BEGIN);
-                                       SetFilePointer(hFile,lpBlockTable[i-nBlkOffset].dwFileOffset+j,0,FILE_BEGIN);
+                                       SFSetFilePointer(mpqOpenArc->hFile, mpqOpenArc->qwMPQStart + MakeUInt64(mpqOpenArc->lpBlockTable[i].dwFileOffset, mpqOpenArc->lpFileOffsetsHigh[i]) + j, FILE_BEGIN);
+                                       SFSetFilePointer(hFile, MakeUInt64(lpBlockTable[i-nBlkOffset].dwFileOffset, lpdwFileOffsetsHigh[i-nBlkOffset]) + j, FILE_BEGIN);
                                        if (j+65536>mpqOpenArc->lpBlockTable[i].dwCompressedSize) ReadSize = mpqOpenArc->lpBlockTable[i].dwCompressedSize-j;
                                        if (ReadFile(mpqOpenArc->hFile,buffer,ReadSize,&tsz,0)==0) {
                                                SFFree(lpBlockTable);
@@ -2999,51 +2891,48 @@ BOOL SFMPQAPI WINAPI MpqCompactArchive(MPQHANDLE hMPQ)
                }
        }
        mpqOpenArc->MpqHeader.dwBlockTableSize -= nBlkOffset;
-       mpqOpenArc->MpqHeader.dwHashTableOffset = dwLastOffset;
-       dwLastOffset += mpqOpenArc->MpqHeader.dwHashTableSize * sizeof(HASHTABLEENTRY);
-       mpqOpenArc->MpqHeader.dwBlockTableOffset = dwLastOffset;
-       dwLastOffset += mpqOpenArc->MpqHeader.dwBlockTableSize * sizeof(BLOCKTABLEENTRY);
-       mpqOpenArc->MpqHeader.dwMPQSize = dwLastOffset;
+       SplitUInt64(mpqOpenArc->MpqHeader.dwHashTableOffset, mpqOpenArc->MpqHeader_Ex.wHashTableOffsetHigh, qwLastOffset);
+       qwLastOffset += mpqOpenArc->MpqHeader.dwHashTableSize * sizeof(HASHTABLEENTRY);
+       SplitUInt64(mpqOpenArc->MpqHeader.dwBlockTableOffset, mpqOpenArc->MpqHeader_Ex.wBlockTableOffsetHigh, qwLastOffset);
+       qwLastOffset += mpqOpenArc->MpqHeader.dwBlockTableSize * sizeof(BLOCKTABLEENTRY);
+       if (mpqOpenArc->MpqHeader_Ex.qwExtendedBlockOffsetTable) {
+               mpqOpenArc->MpqHeader_Ex.qwExtendedBlockOffsetTable = qwLastOffset;
+               qwLastOffset += mpqOpenArc->MpqHeader.dwBlockTableSize * sizeof(UInt16);
+       }
+       mpqOpenArc->MpqHeader.dwMPQSize = (UInt32)qwLastOffset;
        SFFree(mpqOpenArc->lpHashTable);
        mpqOpenArc->lpHashTable = lpHashTable;
        if(mpqOpenArc->lpBlockTable!=0) {
                SFFree(mpqOpenArc->lpBlockTable);
-               mpqOpenArc->lpBlockTable = (BLOCKTABLEENTRY *)SFAlloc(mpqOpenArc->MpqHeader.dwBlockTableSize * sizeof(BLOCKTABLEENTRY));
+               mpqOpenArc->lpBlockTable = (BLOCKTABLEENTRY *)SFAlloc(mpqOpenArc->MpqHeader.dwBlockTableSize * (sizeof(BLOCKTABLEENTRY) + sizeof(UInt16)));
+               mpqOpenArc->lpFileOffsetsHigh = (UInt16 *)(mpqOpenArc->lpBlockTable + mpqOpenArc->MpqHeader.dwBlockTableSize);
                if (mpqOpenArc->lpBlockTable==0) {
                        mpqOpenArc->lpBlockTable = lpBlockTable;
+                       mpqOpenArc->lpFileOffsetsHigh = lpdwFileOffsetsHigh;
                }
                else {
-                       memcpy(mpqOpenArc->lpBlockTable,lpBlockTable,mpqOpenArc->MpqHeader.dwBlockTableSize * sizeof(BLOCKTABLEENTRY));
+                       memcpy(mpqOpenArc->lpBlockTable, lpBlockTable, mpqOpenArc->MpqHeader.dwBlockTableSize * (sizeof(BLOCKTABLEENTRY) + sizeof(UInt16)));
                        SFFree(lpBlockTable);
                }
        }
-       SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+dwLastOffset,0,FILE_BEGIN);
+       SFSetFilePointer(mpqOpenArc->hFile, mpqOpenArc->qwMPQStart + qwLastOffset, FILE_BEGIN);
        SetEndOfFile(mpqOpenArc->hFile);
-       SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart,0,FILE_BEGIN);
-       mpqOpenArc->MpqHeader.dwHeaderSize = sizeof(MPQHEADER);
-       WriteFile(mpqOpenArc->hFile,&mpqOpenArc->MpqHeader,sizeof(MPQHEADER),&tsz,0);
-       dwLastOffset = sizeof(MPQHEADER);
+       MpqWriteHeaders(mpqOpenArc);
+       mpqOpenArc->MpqHeader.dwHeaderSize = mpqOpenArc->dwHeaderSize;
+       qwLastOffset = mpqOpenArc->dwHeaderSize;
        ReadSize = 65536;
-       for (i=dwLastOffset;i<mpqOpenArc->MpqHeader.dwHashTableOffset;i+=65536) {
-               SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+i,0,FILE_BEGIN);
-               SetFilePointer(hFile,i,0,FILE_BEGIN);
-               if (i+65536>mpqOpenArc->MpqHeader.dwHashTableOffset) ReadSize = mpqOpenArc->MpqHeader.dwHashTableOffset-i;
+       for (i=qwLastOffset;i<MakeUInt64(mpqOpenArc->MpqHeader.dwHashTableOffset, mpqOpenArc->MpqHeader_Ex.wHashTableOffsetHigh);i+=65536) {
+               SFSetFilePointer(mpqOpenArc->hFile,mpqOpenArc->qwMPQStart+i,FILE_BEGIN);
+               SFSetFilePointer(hFile,i,FILE_BEGIN);
+               if (i+65536>MakeUInt64(mpqOpenArc->MpqHeader.dwHashTableOffset, mpqOpenArc->MpqHeader_Ex.wHashTableOffsetHigh)) ReadSize = MakeUInt64(mpqOpenArc->MpqHeader.dwHashTableOffset, mpqOpenArc->MpqHeader_Ex.wHashTableOffsetHigh)-i;
                ReadFile(hFile,buffer,ReadSize,&tsz,0);
                WriteFile(mpqOpenArc->hFile,buffer,ReadSize,&tsz,0);
        }
        SFFree(buffer);
        CloseHandle(hFile);
        DeleteFile(lpFileName);
-       EncryptData((BYTE *)mpqOpenArc->lpHashTable,mpqOpenArc->MpqHeader.dwHashTableSize * sizeof(HASHTABLEENTRY),dwHashTableKey);
-       SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->MpqHeader.dwHashTableOffset,0,FILE_BEGIN);
-       WriteFile(mpqOpenArc->hFile,mpqOpenArc->lpHashTable,mpqOpenArc->MpqHeader.dwHashTableSize * sizeof(HASHTABLEENTRY),&tsz,0);
-       DecryptData((BYTE *)mpqOpenArc->lpHashTable,mpqOpenArc->MpqHeader.dwHashTableSize * sizeof(HASHTABLEENTRY),dwHashTableKey);
-       if(mpqOpenArc->lpBlockTable!=0) {
-               EncryptData((BYTE *)mpqOpenArc->lpBlockTable,mpqOpenArc->MpqHeader.dwBlockTableSize * sizeof(BLOCKTABLEENTRY),dwBlockTableKey);
-               SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->MpqHeader.dwBlockTableOffset,0,FILE_BEGIN);
-               WriteFile(mpqOpenArc->hFile,mpqOpenArc->lpBlockTable,mpqOpenArc->MpqHeader.dwBlockTableSize * sizeof(BLOCKTABLEENTRY),&tsz,0);
-               DecryptData((BYTE *)mpqOpenArc->lpBlockTable,mpqOpenArc->MpqHeader.dwBlockTableSize * sizeof(BLOCKTABLEENTRY),dwBlockTableKey);
-       }
+       WriteHashTable(mpqOpenArc);
+       WriteBlockTable(mpqOpenArc);
        return TRUE;
 }
 
@@ -3064,22 +2953,8 @@ BOOL SFMPQAPI WINAPI MpqSetFileLocale(MPQHANDLE hMPQ, LPCSTR lpFileName, LCID nO
        if (hashEntry==0) return FALSE;
        if (hashEntry->lcLocale!=nOldLocale) return FALSE;
        hashEntry->lcLocale = nNewLocale;
-       DWORD tsz;
 
-       char *buffer = (char *)SFAlloc(sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize);
-       if (buffer!=0) {
-               memcpy(buffer,mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize);
-               EncryptData((LPBYTE)buffer,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,dwHashTableKey);
-               SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->MpqHeader.dwHashTableOffset,0,FILE_BEGIN);
-               WriteFile(mpqOpenArc->hFile,buffer,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,&tsz,0);
-               SFFree(buffer);
-       }
-       else {
-               EncryptData((LPBYTE)mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,dwHashTableKey);
-               SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->MpqHeader.dwHashTableOffset,0,FILE_BEGIN);
-               WriteFile(mpqOpenArc->hFile,mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,&tsz,0);
-               DecryptData((LPBYTE)mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,dwHashTableKey);
-       }
+       WriteHashTable(mpqOpenArc);
        LCID dwOldLocale=LocaleID;
        LocaleID=nOldLocale;
        RemoveFromInternalListing(hMPQ,lpFileName);
@@ -3090,18 +2965,42 @@ BOOL SFMPQAPI WINAPI MpqSetFileLocale(MPQHANDLE hMPQ, LPCSTR lpFileName, LCID nO
        return TRUE;
 }
 
+BOOL SFMPQAPI WINAPI MpqCreateArchiveVersion(WORD wVersion)
+{
+       if (wVersion > 1) return FALSE;
+
+       wCreationVersion = wVersion;
+       return TRUE;
+}
+
 DWORD SFMPQAPI WINAPI SFileFindMpqHeader(HANDLE hFile)
 {
        if (hFile == INVALID_HANDLE_VALUE) {
                SetLastError(ERROR_INVALID_PARAMETER);
                return 0xFFFFFFFF;
        }
-       DWORD FileLen = GetFileSize(hFile,0);
+
+       DWORD dwHandleType = GetHandleType((MPQHANDLE)hFile);
+       if (dwHandleType == SFILE_TYPE_FILE) {
+               MPQFILE *mpqOpenFile = (MPQFILE *)hFile;
+               if (mpqOpenFile->hFile == INVALID_HANDLE_VALUE) {
+                       return mpqOpenFile->lpParentArc->qwMPQStart;
+               }
+               else {
+                       hFile = mpqOpenFile->hFile;
+               }
+       }
+       else if (dwHandleType == SFILE_TYPE_MPQ) {
+               return ((MPQARCHIVE *)hFile)->qwMPQStart;
+       }
+
+       UInt64 FileLen = SFGetFileSize(hFile);
+       if (FileLen >= 0xFFFFFFFF) FileLen = 0xFFFFFFFE;
        char pbuf[sizeof(MPQHEADER)];
        DWORD tsz;
        for (DWORD i=0;i<FileLen;i+=512)
        {
-               SetFilePointer(hFile,i,0,FILE_BEGIN);
+               SFSetFilePointer(hFile,i,FILE_BEGIN);
                if (ReadFile(hFile,pbuf,sizeof(MPQHEADER),&tsz,0)==0) return 0xFFFFFFFF;
                if (tsz<sizeof(MPQHEADER)) return 0xFFFFFFFF;
                if (memcmp(pbuf,ID_MPQ,4)==0 || memcmp(pbuf,ID_BN3,4)==0)
@@ -3118,20 +3017,23 @@ DWORD SFMPQAPI WINAPI SFileFindMpqHeader(HANDLE hFile)
        return 0xFFFFFFFF;
 }
 
-DWORD WINAPI FindMpqHeaderAtLocation(HANDLE hFile, DWORD dwStart, DWORD dwLength)
+UInt64 WINAPI SFileFindMpqHeaderEx(HANDLE hFile, UInt64 qwStart, UInt64 qwLength)
 {
        if (hFile == INVALID_HANDLE_VALUE) {
                SetLastError(ERROR_INVALID_PARAMETER);
-               return 0xFFFFFFFF;
+               return (UInt64)-1;
        }
+       UInt64 FileLen = SFGetFileSize(hFile);
+       if (FileLen == (UInt64)-1 || qwStart >= FileLen || qwStart + qwLength > FileLen) return (UInt64)-1;
+       if (qwLength == 0) qwLength = FileLen - qwStart;
        char pbuf[sizeof(MPQHEADER)];
        DWORD tsz;
-       for (DWORD i=dwStart;i<dwStart+dwLength;i+=512)
+       for (UInt64 i=qwStart;i<qwStart+qwLength && i<FileLen;i+=512)
        {
-               SetFilePointer(hFile,i,0,FILE_BEGIN);
-               if (ReadFile(hFile,pbuf,sizeof(MPQHEADER),&tsz,0)==0) return 0xFFFFFFFF;
-               if (i+tsz>dwStart+dwLength) tsz = (dwStart+dwLength)-i;
-               if (tsz<sizeof(MPQHEADER)) return 0xFFFFFFFF;
+               SFSetFilePointer(hFile,i,FILE_BEGIN);
+               if (ReadFile(hFile,pbuf,sizeof(MPQHEADER),&tsz,0)==0) return (UInt64)-1;
+               if (i+tsz>qwStart+qwLength) tsz = (qwStart+qwLength)-i;
+               if (tsz<sizeof(MPQHEADER)) return (UInt64)-1;
                if (memcmp(pbuf,ID_MPQ,4)==0 || memcmp(pbuf,ID_BN3,4)==0)
                {
                        // Storm no longer does this, so mpq api shouldn't either
@@ -3143,7 +3045,7 @@ DWORD WINAPI FindMpqHeaderAtLocation(HANDLE hFile, DWORD dwStart, DWORD dwLength
                        return i;
                }
        }
-       return 0xFFFFFFFF;
+       return (UInt64)-1;
 }
 
 DWORD GetFullPath(LPCSTR lpFileName, char *lpBuffer, DWORD dwBufferLength)
@@ -3230,16 +3132,19 @@ MPQHANDLE GetFreeHashTableEntry(MPQHANDLE hMPQ, LPCSTR lpFileName, LCID FileLoca
        DWORD i=dwTablePos, nFirstFree = 0xFFFFFFFF;
        do
        {
-               if ((mpqOpenArc->lpHashTable[i].dwBlockTableIndex&0xFFFFFFFE)==0xFFFFFFFE && nFirstFree == 0xFFFFFFFF)
+               if ((mpqOpenArc->lpHashTable[i].dwBlockTableIndex&0xFFFFFFFE)==0xFFFFFFFE)
                {
-                       if (mpqOpenArc->lpHashTable[i].dwBlockTableIndex == 0xFFFFFFFF)
+                       if (nFirstFree == 0xFFFFFFFF || mpqOpenArc->lpHashTable[i].dwBlockTableIndex == 0xFFFFFFFF)
                        {
-                               if (nFirstFree == 0xFFFFFFFF)
-                                       return (MPQHANDLE)&mpqOpenArc->lpHashTable[i];
-                               else
-                                       return (MPQHANDLE)&mpqOpenArc->lpHashTable[nFirstFree];
+                               if (mpqOpenArc->lpHashTable[i].dwBlockTableIndex == 0xFFFFFFFF)
+                               {
+                                       if (nFirstFree == 0xFFFFFFFF)
+                                               return (MPQHANDLE)&mpqOpenArc->lpHashTable[i];
+                                       else
+                                               return (MPQHANDLE)&mpqOpenArc->lpHashTable[nFirstFree];
+                               }
+                               else nFirstFree = i;
                        }
-                       else nFirstFree = i;
                }
                else if (mpqOpenArc->lpHashTable[i].dwNameHashA==dwNameHashA && mpqOpenArc->lpHashTable[i].dwNameHashB==dwNameHashB && mpqOpenArc->lpHashTable[i].lcLocale==FileLocale)
                {
@@ -3252,6 +3157,8 @@ MPQHANDLE GetFreeHashTableEntry(MPQHANDLE hMPQ, LPCSTR lpFileName, LCID FileLoca
                }
                i = (i + 1) % mpqOpenArc->MpqHeader.dwHashTableSize;
        } while (i!=dwTablePos);
+       if (nFirstFree != 0xFFFFFFFF)
+               return (MPQHANDLE)&mpqOpenArc->lpHashTable[nFirstFree];
        SetLastError(MPQ_ERROR_HASH_TABLE_FULL);
        return 0;
 }
@@ -3491,195 +3398,6 @@ BOOL RemoveFromInternalListing(MPQHANDLE hMPQ, LPCSTR lpFileName)
        return TRUE;
 }
 
-size_t strlnlen(const char *strline)
-{
-       if (strline==0) return 0;
-       const char *strcr = strchr(strline,'\r');
-       const char *strlf = strchr(strline,'\n');
-       if (strcr==0 && strlf==0) return strlen(strline);
-       if (strcr!=0 && (strcr<strlf || strlf==0)) return strcr-strline;
-       if (strlf!=0 && (strlf<strcr || strcr==0)) return strlf-strline;
-       return strlen(strline);
-}
-
-char *nextline(const char *strline)
-{
-       if (strline==0) return 0;
-       const char *strcr = strchr(strline,'\r');
-       const char *strlf = strchr(strline,'\n');
-       if (strcr==0 && strlf==0) return 0;
-       const char *streol;
-       if (strcr!=0 && (strcr<strlf || strlf==0)) streol = strcr;
-       if (strlf!=0 && (strlf<strcr || strcr==0)) streol = strlf;
-       do {
-               streol++;
-       } while (streol[0]=='\r' || streol[0]=='\n');
-       if (streol[0]==0) return 0;
-       return (char *)streol;
-}
-
-// The InitCryptTable, HashString, DecryptData, and DetectFileKey are
-// based on the versions in StormLib which were written by Ladislav 
-// Zezula, but may have been modified somewhat by Quantam or ShadowFlare.
-BOOL InitCryptTable()
-{
-       DWORD seed   = 0x00100001;
-       DWORD index1 = 0;
-       DWORD index2 = 0;
-       int   i;
-               
-       if (!bCryptTableInit)
-       {
-                for(index1 = 0; index1 < 0x100; index1++)
-                {
-                         for(index2 = index1, i = 0; i < 5; i++, index2 += 0x100)
-                         {
-                                       DWORD temp1, temp2;
-               
-                                       seed  = (seed * 125 + 3) % 0x2AAAAB;
-                                       temp1 = (seed & 0xFFFF) << 0x10;
-               
-                                       seed  = (seed * 125 + 3) % 0x2AAAAB;
-                                       temp2 = (seed & 0xFFFF);
-               
-                                       dwCryptTable[index2] = (temp1 | temp2);
-                         }
-                }
-
-               bCryptTableInit = TRUE;
-       }
-
-       return TRUE;
-}
-
-DWORD HashString(LPCSTR lpszString, DWORD dwHashType)
-{
-    DWORD  seed1 = 0x7FED7FED;
-    DWORD  seed2 = 0xEEEEEEEE;
-    int    ch;
-
-       char szNull = 0;
-       if (!lpszString)
-               lpszString = &szNull;
-
-       if (dwHashType==HASH_KEY)
-               while (strchr(lpszString,'\\')!=NULL) lpszString = strchr(lpszString,'\\')+1;
-    while (*lpszString != 0)
-    {
-        ch = toupper(*lpszString++);
-
-        seed1 = dwCryptTable[(dwHashType << 8) + ch] ^ (seed1 + seed2);
-        seed2 = ch + seed1 + seed2 + (seed2 << 5) + 3;
-    }
-
-    return seed1;
-}
-
-// The EncryptData function is based on the DecryptData function by
-// Ladislav Zezula, but adapted by Quantam to encrypt rather than decrypt.
-BOOL EncryptData(LPBYTE lpbyBuffer, DWORD dwLength, DWORD dwKey)
-{
-    LPDWORD lpdwBuffer = (LPDWORD)lpbyBuffer;
-    DWORD seed = 0xEEEEEEEE;
-    DWORD ch;
-
-       if (!lpbyBuffer)
-               return FALSE;
-
-    // Round to DWORDs
-    dwLength >>= 2;
-
-    while(dwLength-- > 0)
-
-    {
-        seed += dwCryptTable[0x400 + (dwKey & 0xFF)];
-        ch = *lpdwBuffer ^ (dwKey + seed);
-
-        dwKey = ((~dwKey << 0x15) + 0x11111111) | (dwKey >> 0x0B);
-        seed = *lpdwBuffer + seed + (seed << 5) + 3;
-
-               *lpdwBuffer++ = ch;
-    }
-
-        return TRUE;
-}
-
-BOOL DecryptData(LPBYTE lpbyBuffer, DWORD dwLength, DWORD dwKey)
-{
-       LPDWORD lpdwBuffer = (LPDWORD)lpbyBuffer;
-    DWORD seed = 0xEEEEEEEE;
-    DWORD ch;
-
-       if (!lpbyBuffer)
-               return FALSE;
-
-    // Round to DWORDs
-    dwLength >>= 2;
-
-    while(dwLength-- > 0)
-    {
-        seed += dwCryptTable[0x400 + (dwKey & 0xFF)];
-        ch = *lpdwBuffer ^ (dwKey + seed);
-
-        dwKey = ((~dwKey << 0x15) + 0x11111111) | (dwKey >> 0x0B);
-        seed = ch + seed + (seed << 5) + 3;
-
-               *lpdwBuffer++ = ch;
-    }
-
-        return TRUE;
-}
-
-//-----------------------------------------------------------------------------
-// Functions tries to get file decryption key. The trick comes from block
-// positions which are stored at the begin of each compressed file. We know the
-// file size, that means we know number of blocks that means we know the first
-// DWORD value in block position. And if we know encrypted and decrypted value,
-// we can find the decryption key !!!
-//
-// hf    - MPQ file handle
-// block - DWORD array of block positions
-// ch    - Decrypted value of the first block pos
-
-static DWORD DetectFileSeed(DWORD * block, DWORD decrypted, DWORD blocksize)
-{
-    DWORD saveSeed1;
-    DWORD temp = *block ^ decrypted;    // temp = seed1 + seed2
-                                        // temp = seed1 + stormBuffer[0x400 + (seed1 & 0xFF)] + 0xEEEEEEEE
-    temp -= 0xEEEEEEEE;                 // temp = seed1 + stormBuffer[0x400 + (seed1 & 0xFF)]
-    
-
-    for(int i = 0; i < 0x100; i++)      // Try all 256 possibilities
-    {
-        DWORD seed1;
-        DWORD seed2 = 0xEEEEEEEE;
-        DWORD ch;
-
-        // Try the first DWORD (We exactly know the value)
-        seed1  = temp - dwCryptTable[0x400 + i];
-        seed2 += dwCryptTable[0x400 + (seed1 & 0xFF)];
-        ch     = block[0] ^ (seed1 + seed2);
-
-        if(ch != decrypted)
-            continue;
-
-        saveSeed1 = seed1 + 1;
-
-        // If OK, continue and test the second value. We don't know exactly the value,
-        // but we know that the second one has a value less than or equal to the
-               // size of the block position table plus the block size
-        seed1  = ((~seed1 << 0x15) + 0x11111111) | (seed1 >> 0x0B);
-        seed2  = ch + seed2 + (seed2 << 5) + 3;
-
-        seed2 += dwCryptTable[0x400 + (seed1 & 0xFF)];
-        ch     = block[1] ^ (seed1 + seed2);
-
-        if(ch <= decrypted + blocksize)
-            return saveSeed1;
-    }
-    return 0;
-}
-
 DWORD DetectFileSeedEx(MPQARCHIVE * mpqOpenArc, HASHTABLEENTRY * lpHashEntry, LPCSTR * lplpFileName)
 {
        if (mpqOpenArc==0 || lpHashEntry==0) return 0;
@@ -3707,7 +3425,7 @@ DWORD DetectFileSeedEx(MPQARCHIVE * mpqOpenArc, HASHTABLEENTRY * lpHashEntry, LP
                else {
                        HANDLE hlFile,hMPQ=(HANDLE)mpqOpenArc;
                        DWORD fsz;
-                       char *listbuffer;
+                       char *listbuffer = 0;
                        LCID lcOldLocale = LocaleID;
                        for (DWORD lcn=0;lcn<nLocales;lcn++) {
                                LocaleID = availLocales[lcn];
@@ -3730,7 +3448,7 @@ DWORD DetectFileSeedEx(MPQARCHIVE * mpqOpenArc, HASHTABLEENTRY * lpHashEntry, LP
                                        }
                                        SFileCloseFile(hlFile);
                                        if (listbuffer!=0) {
-                                               char *listline;
+                                               char *listline = 0;
                                                for (listline=listbuffer;listline!=0;listline=nextline(listline)) {
                                                        if (listline[0]==0) break;
                                                        DWORD lnlen=strlnlen(listline);
@@ -3766,7 +3484,7 @@ DWORD DetectFileSeedEx(MPQARCHIVE * mpqOpenArc, HASHTABLEENTRY * lpHashEntry, LP
                        DWORD HeaderLength=0,tsz;
                        if (memcmp(&mpqOpenArc->MpqHeader.dwMPQID,ID_BN3,4)==0)
                        {
-                               SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->lpBlockTable[dwBlockIndex].dwFileOffset,0,FILE_BEGIN);
+                               SFSetFilePointer(mpqOpenArc->hFile, mpqOpenArc->qwMPQStart + MakeUInt64(mpqOpenArc->lpBlockTable[dwBlockIndex].dwFileOffset, mpqOpenArc->lpFileOffsetsHigh[dwBlockIndex]), FILE_BEGIN);
                                ReadFile(mpqOpenArc->hFile,&HeaderLength,4,&tsz,0);
                        }
                        DWORD blockSize = 512 << mpqOpenArc->MpqHeader.wBlockSize;
@@ -3776,7 +3494,7 @@ DWORD DetectFileSeedEx(MPQARCHIVE * mpqOpenArc, HASHTABLEENTRY * lpHashEntry, LP
                        DWORD *dwBlockPtrTable = (DWORD *)SFAlloc((TotalBlocks+1)*4);
                        if (dwBlockPtrTable==0)
                                return 0;
-                       SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->lpBlockTable[dwBlockIndex].dwFileOffset+HeaderLength,0,FILE_BEGIN);
+                       SFSetFilePointer(mpqOpenArc->hFile, mpqOpenArc->qwMPQStart + MakeUInt64(mpqOpenArc->lpBlockTable[dwBlockIndex].dwFileOffset, mpqOpenArc->lpFileOffsetsHigh[dwBlockIndex]) + HeaderLength, FILE_BEGIN);
                        ReadFile(mpqOpenArc->hFile,dwBlockPtrTable,(TotalBlocks+1)*4,&tsz,0);
                        dwCryptKey = DetectFileSeed(dwBlockPtrTable,(TotalBlocks+1)*4,blockSize);