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




1 /* License information for this code is in license.txt */
3 #define WIN32_LEAN_AND_MEAN
5 // Includes
6 #include <windows.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <ctype.h>
10 #ifdef _USRDLL
11 #include <shellapi.h>
12 #endif
14 #include "../SComp/SComp.h"
16 #include "SFmpqInternal.h"
17 #include "MpqCrypt.h"
18 #include "MpqHashTable.h"
19 #include "MpqBlockTable.h"
20 #include "SFmpqapi.h"
21 #include "SFUtil.h"
22 #include "SFTypes.h"
24 struct SFMPQAPIMODULE {
25         SFMPQAPIMODULE();
26         ~SFMPQAPIMODULE();
27 } SFMpqApi;
29 #ifndef _WIN32
30 #define SFMPQ_STATIC
31 #endif
33 #if defined(SFMPQ_STATIC) || !defined(SFMPQAPI_EXPORTS)
34 #define DllMain SFMpqMain
36 struct SFMPQLIBMODULE {
37         SFMPQLIBMODULE();
38         ~SFMPQLIBMODULE();
39 } SFMpqLib;
41 BOOL APIENTRY DllMain(HINSTANCE hInstDLL, DWORD  ul_reason_for_call, LPVOID lpReserved);
43 SFMPQLIBMODULE::SFMPQLIBMODULE()
44 {
45         SFMpqMain(0,DLL_PROCESS_ATTACH,0);
46 }
48 SFMPQLIBMODULE::~SFMPQLIBMODULE()
49 {
50         SFMpqDestroy();
51         SFMpqMain(0,DLL_PROCESS_DETACH,0);
52 }
54 #endif
56 LCID LocaleID = 0;
57 WORD wCreationVersion = 0;
58 BOOL SFMpqInit = FALSE;
59 HINSTANCE hStorm = 0;
60 #ifdef _USRDLL
61 HINSTANCE hSFMpqInstance = 0;
62 #endif
64 #define SFMPQ_CURRENT_VERSION {1,0,8,1}
66 SFMPQVERSION SFMpqVersion = SFMPQ_CURRENT_VERSION;
67 LPCSTR SFMpqVersionString = "ShadowFlare MPQ API Library v1.08";
68 float MpqVersion = 2.00;
70 // Class to simulate _alloca for cross-compiler compatibility
71 class TempAlloc {
72 public:
73         TempAlloc();
74         ~TempAlloc();
75         TempAlloc(unsigned long int AllocSize);
76         void * Alloc(unsigned long int AllocSize);
77         void *lpAllocAddress;
78 };
80 LPCSTR ID_MPQ = "MPQ\x1A";
81 LPCSTR ID_BN3 = "BN3\x1A";
82 LPCSTR ID_RIFF = "RIFF";
83 LPCSTR ID_WAVE = "WAVEfmt ";
84 LPCSTR INTERNAL_LISTFILE = "(listfile)";
85 LPCSTR INTERNAL_FILES = "(attributes)\n(listfile)\n(signature)";
86 LPCSTR Storm_dll = "Storm.dll";
87 LPCSTR UNKNOWN_OUT = "~unknowns\\unknown_%08x";
88 LPCSTR UNKNOWN_IN = "~unknowns\\unknown_%x";
89 LPCSTR UNKNOWN_CMP = "~unknowns\\unknown_";
90 #define UNKNOWN_LEN 18
92 LCID availLocales[7] = {0x0000,0x0407,0x0409,0x040A,0x040C,0x0410,0x0416};
93 #define nLocales 7
95 #define MAX_MPQ_PATH 260;
97 MPQARCHIVE **lpOpenMpq = 0;
98 DWORD dwOpenMpqCount = 0;
99 MPQARCHIVE * FirstLastMpq[2] = {0,0};
100 MPQFILE **lpOpenFile = 0;
101 DWORD dwOpenFileCount = 0;
102 MPQFILE * FirstLastFile[2] = {0,0};
104 char StormBasePath[MAX_PATH+1];
106 #define UNSUPPORTED_COMPRESSION   (0xFF ^ (0x40 | 0x80 | 0x01 | 0x02 | 0x08 | 0x10))
107 #define UNSUPPORTED_DECOMPRESSION (0xFF ^ (0x40 | 0x80 | 0x01 | 0x02 | 0x08 | 0x10))
109 typedef BOOL (WINAPI* funcSCompCompress)(LPVOID lpvDestinationMem, LPDWORD lpdwCompressedSize, LPVOID lpvSourceMem, DWORD dwDecompressedSize, DWORD dwCompressionType, DWORD dwCompressionSubType, DWORD dwWAVQuality);
110 typedef BOOL (WINAPI* funcSCompDecompress)(LPVOID lpvDestinationMem, LPDWORD lpdwDecompressedSize, LPVOID lpvSourceMem, DWORD dwCompressedSize);
111 funcSCompCompress stormSCompCompress = 0;
112 funcSCompDecompress stormSCompDecompress = 0;
114 void LoadStorm();
115 void FreeStorm();
117 BOOL WINAPI MpqOpenArchiveEx(LPCSTR lpFileName, DWORD dwPriority, DWORD dwFlags, MPQHANDLE *hMPQ, DWORD dwFlags2, DWORD dwMaximumFilesInArchive, DWORD dwBlockSize);
118 UInt64 WINAPI SFileFindMpqHeaderEx(HANDLE hFile, UInt64 qwStart = 0, UInt64 qwLength = 0);
119 DWORD GetFullPath(LPCSTR lpFileName, char *lpBuffer, DWORD dwBufferLength);
120 MPQHANDLE GetHashTableEntry(MPQHANDLE hMPQ, LPCSTR lpFileName, LCID FileLocale);
121 MPQHANDLE GetHashTableEntryOfHash(MPQHANDLE hMPQ, DWORD dwTablePos, DWORD dwNameHashA, DWORD dwNameHashB, LCID FileLocale);
122 MPQHANDLE GetFreeHashTableEntry(MPQHANDLE hMPQ, LPCSTR lpFileName, LCID FileLocale, BOOL ReturnExisting);
123 BOOL SearchOpenArchives(LPCSTR lpFileName, MPQHANDLE *hMPQ, MPQHANDLE *hFile);
124 void SortOpenArchivesByPriority();
125 DWORD GetHandleType(MPQHANDLE hFile);
126 BOOL AddToInternalListing(MPQHANDLE hMPQ, LPCSTR lpFileName);
127 BOOL RemoveFromInternalListing(MPQHANDLE hMPQ, LPCSTR lpFileName);
128 DWORD DetectFileSeedEx(MPQARCHIVE * mpqOpenArc, HASHTABLEENTRY * lpHashEntry, LPCSTR * lplpFileName);
130 BOOL APIENTRY DllMain( HINSTANCE hInstDLL, 
131                        DWORD  ul_reason_for_call, 
132                        LPVOID lpReserved
133                                          )
135 #ifdef _WIN32
136         char *lpExeName,*buffer;DWORD slen;
137 #endif
138         DWORD dwLastCount;
140 #ifdef _USRDLL
141         hSFMpqInstance = hInstDLL;
142 #endif
144     switch (ul_reason_for_call)
145         {
146                 case DLL_PROCESS_ATTACH:
147                         InitCryptTable();
148                         dwHashTableKey = HashString("(hash table)",HASH_KEY);
149                         dwBlockTableKey = HashString("(block table)",HASH_KEY);
150 #ifdef _WIN32
151                         lpExeName = (char *)SFAlloc(MAX_PATH+1);
152                         if (lpExeName) {
153                                 slen = GetModuleFileName(0,lpExeName,MAX_PATH);
154                                 lpExeName[slen] = 0;
155                                 buffer = lpExeName+strlen(lpExeName);
156                                 while (*buffer!='\\') {*buffer = 0;buffer--;}
157                                 SFileSetBasePath(lpExeName);
158                                 SFFree(lpExeName);
159                         }
160 #else
161                         SFileSetBasePath("./");
162 #endif
163                         break;
164                 case DLL_THREAD_ATTACH:
165                         break;
166                 case DLL_THREAD_DETACH:
167                         break;
168                 case DLL_PROCESS_DETACH:
169                         if (lpOpenFile) {
170                                 while (dwOpenFileCount>0) {
171                                         dwLastCount = dwOpenFileCount;
172                                         SFileCloseFile((MPQHANDLE)lpOpenFile[dwOpenFileCount-1]);
173                                         if (dwLastCount==dwOpenFileCount) dwOpenFileCount--;
174                                 }
176                                 SFFree(lpOpenFile);
177                         }
179                         if (lpOpenMpq) {
180                                 while (dwOpenMpqCount>0) {
181                                         dwLastCount = dwOpenMpqCount;
182                                         SFileCloseArchive((MPQHANDLE)lpOpenMpq[dwOpenMpqCount-1]);
183                                         if (dwLastCount==dwOpenMpqCount) dwOpenMpqCount--;
184                                 }
186                                 SFFree(lpOpenMpq);
187                         }
188                         break;
189     }
191     return TRUE;
194 TempAlloc::TempAlloc()
196         lpAllocAddress = 0;
199 TempAlloc::TempAlloc(unsigned long int AllocSize)
201         lpAllocAddress = SFAlloc(AllocSize);
204 TempAlloc::~TempAlloc()
206         if (lpAllocAddress) {
207                 SFFree(lpAllocAddress);
208                 lpAllocAddress = 0;
209         }
212 void * TempAlloc::Alloc(unsigned long int AllocSize)
214         lpAllocAddress = SFAlloc(AllocSize);
215         return lpAllocAddress;
218 SFMPQAPIMODULE::SFMPQAPIMODULE()
220         //LoadStorm();
223 SFMPQAPIMODULE::~SFMPQAPIMODULE()
225         FreeStorm();
228 BOOL SFMPQAPI WINAPI SFileDestroy() {
229         return TRUE;
232 void SFMPQAPI WINAPI StormDestroy() {
235 void SFMPQAPI WINAPI SFMpqDestroy() {
236         //FreeStorm();
239 BOOL SFMPQAPI WINAPI MpqInitialize()
241         return (SFMpqInit=TRUE);
244 LPCSTR SFMPQAPI WINAPI MpqGetVersionString()
246         return SFMpqVersionString;
249 float SFMPQAPI WINAPI MpqGetVersion()
251         return MpqVersion;
254 LPCSTR SFMPQAPI WINAPI SFMpqGetVersionString()
256         return SFMpqVersionString;
259 DWORD  SFMPQAPI WINAPI SFMpqGetVersionString2(LPCSTR lpBuffer, DWORD dwBufferLength)
261         if (!lpBuffer) {
262                 SetLastError(ERROR_INVALID_PARAMETER);
263                 return strlen(SFMpqVersionString)+1;
264         }
266         DWORD slen = strlen(SFMpqVersionString)+1;
268         if (dwBufferLength>=slen) memcpy((void *)lpBuffer,SFMpqVersionString,slen);
269         else memcpy((void *)lpBuffer,SFMpqVersionString,dwBufferLength);
271         return slen;
274 SFMPQVERSION SFMPQAPI WINAPI SFMpqGetVersion()
276         return SFMpqVersion;
279 void SFMPQAPI WINAPI AboutSFMpq()
281 #ifdef _USRDLL
282         if (hSFMpqInstance) {
283                 char szAboutPage[MAX_PATH+13];
284                 strcpy(szAboutPage,"res://");
285                 GetModuleFileName(hSFMpqInstance,szAboutPage+6,MAX_PATH);
286                 strcat(szAboutPage,"/about");
287                 ShellExecute(0,0,szAboutPage,0,0,SW_SHOWNORMAL);
288         }
289 #endif
292 BOOL MpqWriteHeaders(MPQARCHIVE *mpqOpenArc)
294         DWORD nIOLen;
295         BOOL bReturnVal = FALSE;
297         SFSetFilePointer(mpqOpenArc->hFile, mpqOpenArc->qwMPQStart, FILE_BEGIN);
298         bReturnVal = WriteFile(mpqOpenArc->hFile, &mpqOpenArc->MpqHeader, sizeof(MPQHEADER), &nIOLen, 0);
300         if (bReturnVal && mpqOpenArc->MpqHeader.wVersion > 0) {
301                 bReturnVal = WriteFile(mpqOpenArc->hFile, &mpqOpenArc->MpqHeader_Ex, sizeof(MPQHEADER_EX), &nIOLen, 0);
302         }
304         return bReturnVal;
307 BOOL MpqWriteNewArchive(MPQARCHIVE *mpqOpenArc)
309         DWORD nIOLen;
311         memcpy(&mpqOpenArc->MpqHeader.dwMPQID,ID_MPQ,4);
312         mpqOpenArc->MpqHeader.wVersion = wCreationVersion;
314         if (mpqOpenArc->MpqHeader.wVersion == 0)
315                 mpqOpenArc->MpqHeader.dwHeaderSize = sizeof(MPQHEADER);
316         else
317                 mpqOpenArc->MpqHeader.dwHeaderSize = sizeof(MPQHEADER) + sizeof(MPQHEADER_EX);
318         mpqOpenArc->dwHeaderSize = mpqOpenArc->MpqHeader.dwHeaderSize;
320         if (mpqOpenArc->MpqHeader.wBlockSize & 0xFFFF0000)
321                 mpqOpenArc->MpqHeader.wBlockSize = DEFAULT_BLOCK_SIZE;
322         DWORD i;
323         for (i=1;i<mpqOpenArc->MpqHeader.dwHashTableSize;i*=2) {}
324         mpqOpenArc->MpqHeader.dwHashTableSize = i;
325         mpqOpenArc->MpqHeader.dwBlockTableSize = 0;
326         mpqOpenArc->MpqHeader.dwHashTableOffset = mpqOpenArc->dwHeaderSize;
327         mpqOpenArc->MpqHeader.dwBlockTableOffset = mpqOpenArc->dwHeaderSize + mpqOpenArc->MpqHeader.dwHashTableSize * sizeof(HASHTABLEENTRY);
328         mpqOpenArc->MpqHeader_Ex.qwExtendedBlockOffsetTable = 0;
329         mpqOpenArc->MpqHeader_Ex.wHashTableOffsetHigh = 0;
330         mpqOpenArc->MpqHeader_Ex.wBlockTableOffsetHigh = 0;
331         mpqOpenArc->MpqHeader.dwMPQSize = mpqOpenArc->dwHeaderSize + mpqOpenArc->MpqHeader.dwHashTableSize * sizeof(HASHTABLEENTRY);
333         if (!MpqWriteHeaders(mpqOpenArc))
334                 return FALSE;
336         mpqOpenArc->lpHashTable = (HASHTABLEENTRY *)SFAlloc(sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize);
337         if (!mpqOpenArc->lpHashTable) {
338                 return FALSE;
339         }
340         memset(mpqOpenArc->lpHashTable, 0xFF, sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize);
341         EncryptData((LPBYTE)mpqOpenArc->lpHashTable, sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize, dwHashTableKey);
342         if (!WriteFile(mpqOpenArc->hFile, mpqOpenArc->lpHashTable, sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize, &nIOLen, 0)) {
343                 return FALSE;
344         }
346         return TRUE;
349 BOOL MpqReadExistingArchive(MPQARCHIVE *mpqOpenArc)
351         DWORD nIOLen;
353         SFSetFilePointer(mpqOpenArc->hFile, mpqOpenArc->qwMPQStart, FILE_BEGIN);
354         if (!ReadFile(mpqOpenArc->hFile, &mpqOpenArc->MpqHeader, sizeof(MPQHEADER), &nIOLen, 0))
355                 return FALSE;
357         if (mpqOpenArc->MpqHeader.wVersion > 0) {
358                 mpqOpenArc->dwHeaderSize = sizeof(MPQHEADER) + sizeof(MPQHEADER_EX);
359                 if (!ReadFile(mpqOpenArc->hFile, &mpqOpenArc->MpqHeader_Ex, sizeof(MPQHEADER_EX), &nIOLen, 0))
360                         return FALSE;
361         }
362         else {
363                 mpqOpenArc->dwHeaderSize = sizeof(MPQHEADER);
364                 memset(&mpqOpenArc->MpqHeader_Ex, 0, sizeof(MPQHEADER_EX));
365         }
367         mpqOpenArc->lpHashTable = (HASHTABLEENTRY *)SFAlloc(sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize);
368         if (!mpqOpenArc->lpHashTable)
369                 return FALSE;
371         if (mpqOpenArc->MpqHeader.dwBlockTableSize) {
372                 mpqOpenArc->lpBlockTable = (BLOCKTABLEENTRY *)SFAlloc((sizeof(BLOCKTABLEENTRY) + sizeof(UInt16)) * mpqOpenArc->MpqHeader.dwBlockTableSize);
373                 mpqOpenArc->lpFileOffsetsHigh = (UInt16 *)(mpqOpenArc->lpBlockTable + mpqOpenArc->MpqHeader.dwBlockTableSize);
374                 if (!mpqOpenArc->lpBlockTable)
375                         return FALSE;
376         }
378         SFSetFilePointer(mpqOpenArc->hFile, mpqOpenArc->qwMPQStart + MakeUInt64(mpqOpenArc->MpqHeader.dwHashTableOffset, mpqOpenArc->MpqHeader_Ex.wHashTableOffsetHigh), FILE_BEGIN);
379         if (!ReadFile(mpqOpenArc->hFile, mpqOpenArc->lpHashTable, sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize, &nIOLen, 0))
380                 return FALSE;
382         if (mpqOpenArc->MpqHeader.dwBlockTableSize) {
383                 SFSetFilePointer(mpqOpenArc->hFile, mpqOpenArc->qwMPQStart + MakeUInt64(mpqOpenArc->MpqHeader.dwBlockTableOffset, mpqOpenArc->MpqHeader_Ex.wBlockTableOffsetHigh), FILE_BEGIN);
384                 if (!ReadFile(mpqOpenArc->hFile, mpqOpenArc->lpBlockTable, sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize, &nIOLen, 0))
385                         return FALSE;
387                 if (mpqOpenArc->MpqHeader_Ex.qwExtendedBlockOffsetTable) {
388                         SFSetFilePointer(mpqOpenArc->hFile, mpqOpenArc->qwMPQStart + mpqOpenArc->MpqHeader_Ex.qwExtendedBlockOffsetTable, FILE_BEGIN);
389                         if (!ReadFile(mpqOpenArc->hFile, mpqOpenArc->lpFileOffsetsHigh, sizeof(WORD) * mpqOpenArc->MpqHeader.dwBlockTableSize, &nIOLen, 0))
390                                 return FALSE;
391                 }
392         }
394         return TRUE;
397 BOOL MpqOpenArchiveInit(MPQARCHIVE *mpqOpenArc, LPCSTR lpFileName, DWORD dwPriority, DWORD dwFlags1, DWORD dwFlags2, DWORD dwExtraFlags)
399         /*mpqOpenArc->lpFileName = (char *)SFAlloc(strlen(lpFileName)+1);
400         if(!mpqOpenArc->lpFileName)
401                 return FALSE;*/
402         DecryptData((LPBYTE)mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,dwHashTableKey);
403         if (mpqOpenArc->lpBlockTable) DecryptData((LPBYTE)mpqOpenArc->lpBlockTable,sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize,dwBlockTableKey);
404         mpqOpenArc->lpFileName = mpqOpenArc->szFileName;
405         strncpy(mpqOpenArc->lpFileName,lpFileName,259);
406         if (FirstLastMpq[1]) FirstLastMpq[1]->lpNextArc = mpqOpenArc;
407         mpqOpenArc->lpNextArc = (MPQARCHIVE *)FirstLastMpq;
408         mpqOpenArc->lpPrevArc = (MPQARCHIVE *)FirstLastMpq[1];
409         if (!FirstLastMpq[0]) {
410                 mpqOpenArc->lpPrevArc = (MPQARCHIVE *)0xEAFC5E23;
411                 FirstLastMpq[0] = mpqOpenArc;
412         }
413         FirstLastMpq[1] = mpqOpenArc;
414         mpqOpenArc->dwFlags1 = dwFlags1;
415         mpqOpenArc->dwPriority = dwPriority;
416         mpqOpenArc->lpLastReadFile = 0;
417         mpqOpenArc->dwUnk = 0;
418         mpqOpenArc->dwBlockSize = 512 << mpqOpenArc->MpqHeader.wBlockSize;
419         mpqOpenArc->lpLastReadBlock = 0;
420         mpqOpenArc->dwBufferSize = 0;
421         mpqOpenArc->qwMPQEnd = mpqOpenArc->qwMPQStart + mpqOpenArc->MpqHeader.dwMPQSize;
422         mpqOpenArc->lpMPQHeader = &mpqOpenArc->MpqHeader;
423         mpqOpenArc->qwReadOffset = mpqOpenArc->qwMPQEnd;
424         mpqOpenArc->dwRefCount = 1;
425         mpqOpenArc->dwFlags = dwFlags2;
426         mpqOpenArc->dwExtraFlags = dwExtraFlags;
428         return TRUE;
431 BOOL WINAPI MpqOpenArchiveEx(LPCSTR lpFileName, DWORD dwPriority, DWORD dwFlags, MPQHANDLE *hMPQ, DWORD dwFlags2, DWORD dwMaximumFilesInArchive, DWORD dwBlockSize)
433         if (!lpFileName || !hMPQ) {
434                 SetLastError(ERROR_INVALID_PARAMETER);
435                 if (hMPQ) *hMPQ = (MPQHANDLE)INVALID_HANDLE_VALUE;
436                 return FALSE;
437         }
438         *hMPQ = (MPQHANDLE)INVALID_HANDLE_VALUE;
439         if (!*lpFileName) {
440                 SetLastError(ERROR_INVALID_PARAMETER);
441                 return FALSE;
442         }
444         DWORD dwFlags1 = 0;
446 #ifdef _WIN32
447         char RootPath[4];
448         memset(RootPath,0,4);
449         if (memcmp(lpFileName+1,":\\",2)==0) memcpy(RootPath,lpFileName,3);
450         else {
451                 char CurDir[MAX_PATH];
452                 GetCurrentDirectory(MAX_PATH,CurDir);
453                 memcpy(RootPath,CurDir,3);
454         }
455         if (GetDriveType(RootPath)==DRIVE_CDROM)
456                 dwFlags1 |= 2;
457         else if (dwFlags&2)
458                 dwFlags1 |= 1;
459         if (dwFlags & SFILE_OPEN_CD_ROM_FILE)
460                 if (!(dwFlags1&2)) {return FALSE;}
461 #endif
463         DWORD dwCreateFlags,dwAccessFlags,dwShareFlags;
464         if (dwFlags2 & MOAU_OPEN_ALWAYS) dwCreateFlags = OPEN_ALWAYS;
465         else if (dwFlags2 & MOAU_CREATE_ALWAYS) dwCreateFlags = CREATE_ALWAYS;
466         else if (dwFlags2 & MOAU_OPEN_EXISTING) dwCreateFlags = OPEN_EXISTING;
467         else dwCreateFlags = CREATE_NEW;
468         if (dwFlags2 & MOAU_READ_ONLY) {
469                 if (!(dwFlags2 & MOAU_OPEN_EXISTING)) {
470                         SetLastError(MPQ_ERROR_BAD_OPEN_MODE);
471                         return FALSE;
472                 }
473                 dwAccessFlags = GENERIC_READ;
474                 if (dwFlags2 & SFILE_OPEN_ALLOW_WRITE) dwFlags2 = dwFlags2^SFILE_OPEN_ALLOW_WRITE;
475         }
476         else {
477                 dwAccessFlags = GENERIC_READ|GENERIC_WRITE;
478                 dwFlags2 = dwFlags2|SFILE_OPEN_ALLOW_WRITE;
479         }
480         if (dwAccessFlags & GENERIC_WRITE)
481                 dwShareFlags = 0;
482         else
483                 dwShareFlags = FILE_SHARE_READ;
484         HANDLE hFile;
485         hFile = CreateFile(lpFileName,dwAccessFlags,dwShareFlags,0,dwCreateFlags,0,0);
486         TempAlloc NewAlloc;
487         if (hFile==INVALID_HANDLE_VALUE) {
488                 DWORD namelen = GetFullPath(lpFileName,0,0);
489                 char *namebuffer = (char *)NewAlloc.Alloc(namelen);
490                 GetFullPath(lpFileName,namebuffer,namelen);
491                 lpFileName = namebuffer;
492                 hFile = CreateFile(lpFileName,dwAccessFlags,dwShareFlags,0,dwCreateFlags,0,0);
493         }
494         if (hFile!=INVALID_HANDLE_VALUE)
495         {
496                 MPQARCHIVE **lpnOpenMpq = (MPQARCHIVE **)SFAlloc(sizeof(MPQARCHIVE *) * (dwOpenMpqCount+1));
497                 if (!lpnOpenMpq) {
498                         CloseHandle(hFile);
499                         return FALSE;
500                 }
501                 MPQARCHIVE *mpqOpenArc;
502                 if (SFGetFileSize(hFile)==0 && !(dwFlags2 & MOAU_READ_ONLY))
503                 {
504                         mpqOpenArc = (MPQARCHIVE *)SFAlloc(sizeof(MPQARCHIVE));
505                         if (!mpqOpenArc) {
506                                 SFFree(lpnOpenMpq);
507                                 CloseHandle(hFile);
508                                 return FALSE;
509                         }
511                         mpqOpenArc->hFile = hFile;
512                         mpqOpenArc->qwMPQStart = 0;
513                         mpqOpenArc->MpqHeader.dwHashTableSize = dwMaximumFilesInArchive;
514                         mpqOpenArc->MpqHeader.wBlockSize = (WORD)dwBlockSize;
516                         if (!MpqWriteNewArchive(mpqOpenArc)) {
517                                 if (mpqOpenArc->lpHashTable) SFFree(mpqOpenArc->lpHashTable);
518                                 SFFree(mpqOpenArc);
519                                 SFFree(lpnOpenMpq);
520                                 CloseHandle(hFile);
521                                 return FALSE;
522                         }
523                 }
524                 else
525                 {
526                         UInt64 qwMpqStart = SFileFindMpqHeaderEx(hFile);
527                         if (qwMpqStart == (UInt64)-1) {
528                                 SFFree(lpnOpenMpq);
529                                 CloseHandle(hFile);
530                                 SetLastError(MPQ_ERROR_MPQ_INVALID);
531                                 return FALSE;
532                         }
533                         mpqOpenArc = (MPQARCHIVE *)SFAlloc(sizeof(MPQARCHIVE));
534                         if (!mpqOpenArc) {
535                                 SFFree(lpnOpenMpq);
536                                 CloseHandle(hFile);
537                                 return FALSE;
538                         }
540                         mpqOpenArc->hFile = hFile;
541                         mpqOpenArc->qwMPQStart = qwMpqStart;
543                         if (!MpqReadExistingArchive(mpqOpenArc)) {
544                                 if (mpqOpenArc->lpBlockTable) SFFree(mpqOpenArc->lpBlockTable);
545                                 if (mpqOpenArc->lpHashTable) SFFree(mpqOpenArc->lpHashTable);
546                                 SFFree(mpqOpenArc);
547                                 SFFree(lpnOpenMpq);
548                                 CloseHandle(hFile);
549                                 return FALSE;
550                         }
551                 }
553                 if (!MpqOpenArchiveInit(mpqOpenArc, lpFileName, dwPriority, dwFlags1, dwFlags2, 0)) {
554                         if (mpqOpenArc->lpBlockTable) SFFree(mpqOpenArc->lpBlockTable);
555                         SFFree(mpqOpenArc->lpHashTable);
556                         SFFree(mpqOpenArc);
557                         SFFree(lpnOpenMpq);
558                         CloseHandle(hFile);
559                         return FALSE;
560                 }
562                 memcpy(lpnOpenMpq,lpOpenMpq,sizeof(MPQARCHIVE *) * dwOpenMpqCount);
563                 lpnOpenMpq[dwOpenMpqCount] = mpqOpenArc;
564                 if (lpOpenMpq) SFFree(lpOpenMpq);
565                 lpOpenMpq = lpnOpenMpq;
566                 dwOpenMpqCount++;
567                 if (dwOpenMpqCount>1) SortOpenArchivesByPriority();
568                 *hMPQ = (MPQHANDLE)mpqOpenArc;
570                 return TRUE;
571         }
572         else {
573                 if (dwFlags2&MOAU_OPEN_EXISTING) SetLastError(ERROR_FILE_NOT_FOUND);
574                 else if (dwFlags2&MOAU_CREATE_NEW) SetLastError(ERROR_ALREADY_EXISTS);
575                 *hMPQ = (MPQHANDLE)INVALID_HANDLE_VALUE;
576                 return FALSE;
577         }
580 BOOL SFMPQAPI WINAPI SFileOpenFileAsArchive(MPQHANDLE hSourceMPQ, LPCSTR lpFileName, DWORD dwPriority, DWORD dwFlags, MPQHANDLE *hMPQ)
582         if (!lpFileName || !hMPQ) {
583                 SetLastError(ERROR_INVALID_PARAMETER);
584                 if (hMPQ) *hMPQ = (MPQHANDLE)INVALID_HANDLE_VALUE;
585                 return FALSE;
586         }
587         *hMPQ = (MPQHANDLE)INVALID_HANDLE_VALUE;
588         if (!*lpFileName) {
589                 SetLastError(ERROR_INVALID_PARAMETER);
590                 return FALSE;
591         }
593         HANDLE hFile;
594         if (SFileOpenFileEx(hSourceMPQ,lpFileName,1,&hFile))
595         {
596                 MPQFILE mpqArcFile;
597                 mpqArcFile = *(MPQFILE *)hFile;
598                 SFileCloseFile(hFile);
599                 if (mpqArcFile.hFile != INVALID_HANDLE_VALUE)
600                         return SFileOpenArchive(lpFileName,dwPriority,dwFlags,hMPQ);
601                 hFile = mpqArcFile.lpParentArc->hFile;
602                 MPQARCHIVE **lpnOpenMpq = (MPQARCHIVE **)SFAlloc(sizeof(MPQARCHIVE *) * (dwOpenMpqCount+1));
603                 if (!lpnOpenMpq) {
604                         return FALSE;
605                 }
606                 MPQARCHIVE *mpqOpenArc;
607                 UInt64 qwMpqStart = mpqArcFile.lpParentArc->qwMPQStart + MakeUInt64(mpqArcFile.lpBlockEntry->dwFileOffset, mpqArcFile.wFileOffsetHigh);
608                 UInt64 flen = mpqArcFile.lpBlockEntry->dwFullSize;
609                 qwMpqStart = SFileFindMpqHeaderEx(hFile, qwMpqStart, flen);
610                 if (qwMpqStart == (UInt64)-1) {
611                         SFFree(lpnOpenMpq);
612                         SetLastError(MPQ_ERROR_MPQ_INVALID);
613                         return FALSE;
614                 }
615                 mpqOpenArc = (MPQARCHIVE *)SFAlloc(sizeof(MPQARCHIVE));
616                 if (!mpqOpenArc) {
617                         SFFree(lpnOpenMpq);
618                         return FALSE;
619                 }
621                 mpqOpenArc->hFile = hFile;
622                 mpqOpenArc->qwMPQStart = qwMpqStart;
624                 if (!MpqReadExistingArchive(mpqOpenArc)) {
625                         if (mpqOpenArc->lpBlockTable) SFFree(mpqOpenArc->lpBlockTable);
626                         if (mpqOpenArc->lpHashTable) SFFree(mpqOpenArc->lpHashTable);
627                         SFFree(mpqOpenArc);
628                         SFFree(lpnOpenMpq);
629                         return FALSE;
630                 }
632                 if (!MpqOpenArchiveInit(mpqOpenArc, lpFileName, dwPriority, 0, dwFlags, 1)) {
633                         if (mpqOpenArc->lpBlockTable) SFFree(mpqOpenArc->lpBlockTable);
634                         SFFree(mpqOpenArc->lpHashTable);
635                         SFFree(mpqOpenArc);
636                         SFFree(lpnOpenMpq);
637                         return FALSE;
638                 }
640                 memcpy(lpnOpenMpq,lpOpenMpq,sizeof(MPQARCHIVE *) * dwOpenMpqCount);
641                 lpnOpenMpq[dwOpenMpqCount] = mpqOpenArc;
642                 if (lpOpenMpq) SFFree(lpOpenMpq);
643                 lpOpenMpq = lpnOpenMpq;
644                 dwOpenMpqCount++;
645                 if (dwOpenMpqCount>1) SortOpenArchivesByPriority();
646                 *hMPQ = (MPQHANDLE)mpqOpenArc;
648                 return TRUE;
649         }
650         else {
651                 *hMPQ = (MPQHANDLE)INVALID_HANDLE_VALUE;
652                 return FALSE;
653         }
656 BOOL SFMPQAPI WINAPI SFileOpenArchive(LPCSTR lpFileName, DWORD dwPriority, DWORD dwFlags, MPQHANDLE *hMPQ)
658         if (dwFlags & SFILE_OPEN_ALLOW_WRITE) {
659                 return MpqOpenArchiveEx(lpFileName,dwPriority,dwFlags ^ SFILE_OPEN_ALLOW_WRITE,hMPQ,MOAU_OPEN_EXISTING,0,USE_DEFAULT_BLOCK_SIZE);
660         }
661         else {
662                 return MpqOpenArchiveEx(lpFileName,dwPriority,dwFlags,hMPQ,MOAU_OPEN_EXISTING|MOAU_READ_ONLY,0,USE_DEFAULT_BLOCK_SIZE);
663         }
666 BOOL SFMPQAPI WINAPI SFileCloseArchive(MPQHANDLE hMPQ)
668         if (hMPQ==0) {
669                 SetLastError(ERROR_INVALID_PARAMETER);
670                 return FALSE;
671         }
673         MPQARCHIVE *mpqOpenArc = (MPQARCHIVE *)hMPQ;
674         if (dwOpenMpqCount==0) return FALSE;
675         if (memcmp(&mpqOpenArc->MpqHeader.dwMPQID,ID_MPQ,4)!=0 && memcmp(&mpqOpenArc->MpqHeader.dwMPQID,ID_BN3,4)!=0) return FALSE;
676         if (!(mpqOpenArc->dwExtraFlags & 1)) CloseHandle(mpqOpenArc->hFile);
677         //SFFree(mpqOpenArc->lpFileName);
678         SFFree(mpqOpenArc->lpHashTable);
679         if(mpqOpenArc->lpBlockTable) SFFree(mpqOpenArc->lpBlockTable);
680         if ((DWORD)mpqOpenArc->lpNextArc!=(DWORD)FirstLastMpq)
681                 mpqOpenArc->lpNextArc->lpPrevArc = mpqOpenArc->lpPrevArc;
682         if ((DWORD)mpqOpenArc->lpPrevArc!=0xEAFC5E23)
683                 mpqOpenArc->lpPrevArc->lpNextArc = mpqOpenArc->lpNextArc;
684         if (mpqOpenArc==FirstLastMpq[0])
685                 FirstLastMpq[0] = mpqOpenArc->lpNextArc;
686         if ((DWORD)FirstLastMpq[0]==(DWORD)FirstLastMpq)
687                 FirstLastMpq[0] = 0;
688         if (mpqOpenArc==FirstLastMpq[1])
689                 FirstLastMpq[1] = mpqOpenArc->lpPrevArc;
690         if ((DWORD)FirstLastMpq[1]==0xEAFC5E23)
691                 FirstLastMpq[1] = 0;
692         SFFree(mpqOpenArc);
693         if (!lpOpenMpq) return TRUE;
694         if (dwOpenMpqCount-1==0) {
695                 SFFree(lpOpenMpq);
696                 lpOpenMpq = 0;
697                 dwOpenMpqCount--;
698                 return TRUE;
699         }
700         else if (dwOpenMpqCount==0) return FALSE;
701         MPQARCHIVE **lpnOpenMpq = (MPQARCHIVE **)SFAlloc(sizeof(MPQARCHIVE *) * (dwOpenMpqCount-1));
702         if (lpnOpenMpq) {
703                 for (DWORD i=0,j=0;i<dwOpenMpqCount;i++) {
704                         if ((MPQHANDLE)lpOpenMpq[i]!=hMPQ) {
705                                 memcpy(&lpnOpenMpq[j],&lpOpenMpq[i],sizeof(MPQARCHIVE *));
706                                 j++;
707                         }
708                 }
709                 SFFree(lpOpenMpq);
710                 lpOpenMpq = lpnOpenMpq;
711                 dwOpenMpqCount--;
712         }
713         else {
714                 for (DWORD i=0,j=0;i<dwOpenMpqCount;i++) {
715                         if ((MPQHANDLE)lpOpenMpq[i]==hMPQ) {
716                                 lpOpenMpq[i] = (MPQARCHIVE *)0;
717                         }
718                         else {
719                                 if (i!=j) memcpy(&lpOpenMpq[j],&lpOpenMpq[i],sizeof(MPQARCHIVE *));
720                                 j++;
721                         }
722                 }
723                 dwOpenMpqCount--;
724         }
725         return TRUE;
728 BOOL SFMPQAPI WINAPI SFileGetArchiveName(MPQHANDLE hMPQ, LPCSTR lpBuffer, DWORD dwBufferLength)
730         if (hMPQ==0 || lpBuffer==0) {
731                 SetLastError(ERROR_INVALID_PARAMETER);
732                 return FALSE;
733         }
735         DWORD dwhType = GetHandleType(hMPQ);
736         char *lpFileName;
737         if (dwhType==SFILE_TYPE_MPQ) lpFileName = ((MPQARCHIVE *)hMPQ)->lpFileName;
738         else if (dwhType==SFILE_TYPE_FILE) lpFileName = ((MPQFILE *)hMPQ)->lpFileName;
739         else return FALSE;
740         DWORD slen = strlen(lpFileName)+1;
741         if (dwBufferLength>=slen) memcpy((void *)lpBuffer,lpFileName,slen);
742         else memcpy((void *)lpBuffer,lpFileName,dwBufferLength);
743         return TRUE;
746 BOOL SFMPQAPI WINAPI SFileOpenFile(LPCSTR lpFileName, MPQHANDLE *hFile)
748         return SFileOpenFileEx(0,lpFileName,SFILE_SEARCH_CURRENT_ONLY,hFile);
751 BOOL WINAPI IsHexDigit(char nChar)
753         switch (nChar) {
754                 case '0':
755                 case '1':
756                 case '2':
757                 case '3':
758                 case '4':
759                 case '5':
760                 case '6':
761                 case '7':
762                 case '8':
763                 case '9':
764                 case 'A':
765                 case 'a':
766                 case 'B':
767                 case 'b':
768                 case 'C':
769                 case 'c':
770                 case 'D':
771                 case 'd':
772                 case 'E':
773                 case 'e':
774                 case 'F':
775                 case 'f':
776                         return TRUE;
777                 default:
778                         return FALSE;
779         }
780         return FALSE;
783 BOOL SFMPQAPI WINAPI SFileOpenFileEx(MPQHANDLE hMPQ, LPCSTR lpFileName, DWORD dwSearchScope, MPQHANDLE *hFile)
785         if (!lpFileName || !hFile) {
786                 SetLastError(ERROR_INVALID_PARAMETER);
787                 return FALSE;
788         }
789         if (!*lpFileName) {
790                 SetLastError(ERROR_INVALID_PARAMETER);
791                 return FALSE;
792         }
794         /*char szFileName[260];
795         if (hMPQ!=0) {
796                 if ((DWORD)lpFileName<((MPQARCHIVE *)hMPQ)->MpqHeader.dwHashTableSize) {
797                         sprintf(szFileName,UNKNOWN_OUT,(DWORD)lpFileName);
798                         lpFileName = szFileName;
799                         dwSearchScope = SFILE_SEARCH_CURRENT_ONLY;
800                 }
801         }
802         else {
803                 for (DWORD i=0;i<dwOpenMpqCount;i++) {
804                         if ((DWORD)lpFileName<lpOpenMpq[i]->MpqHeader.dwHashTableSize) {
805                                 SetLastError(ERROR_INVALID_PARAMETER);
806                                 return FALSE;
807                         }
808                 }
809         }*/
811         MPQFILE **lpnOpenFile = (MPQFILE **)SFAlloc(sizeof(MPQFILE *) * (dwOpenFileCount+1));
812         if (!lpnOpenFile) return FALSE;
814         MPQFILE *mpqOpenFile = (MPQFILE *)SFAlloc(sizeof(MPQFILE));
815         if (!mpqOpenFile) {
816                 SFFree(lpnOpenFile);
817                 return FALSE;
818         }
819         BOOL bFileOnDisk=FALSE;
820         MPQHANDLE hnMPQ,hnFile;
821         TempAlloc NewAlloc;
822         if (dwSearchScope==SFILE_SEARCH_CURRENT_ONLY) {
823                 if (hMPQ) {
824                         if (memicmp(lpFileName,UNKNOWN_CMP,UNKNOWN_LEN)==0 && IsHexDigit(lpFileName[UNKNOWN_LEN])) {
825                                 DWORD dwHashIndex;
826                                 sscanf(lpFileName,UNKNOWN_IN,&dwHashIndex);
827                                 hnFile = (HANDLE)&((MPQARCHIVE *)hMPQ)->lpHashTable[dwHashIndex];
828                                 if ((((HASHTABLEENTRY *)hnFile)->dwBlockTableIndex&0xFFFFFFFE)==0xFFFFFFFE)
829                                 {
830                                         SFFree(mpqOpenFile);
831                                         SFFree(lpnOpenFile);
832                                         SetLastError(ERROR_FILE_NOT_FOUND);
833                                         return FALSE;
834                                 }
835                         }
836                         else hnFile = GetHashTableEntry(hMPQ,lpFileName,LocaleID);
837                         hnMPQ = hMPQ;
838                 }
839                 else {
840                         SearchOpenArchives(lpFileName,&hnMPQ,&hnFile);
841                 }
842         }
843         else {
844                 SearchOpenArchives(lpFileName,&hnMPQ,&hnFile);
845                 if (!hnFile) {
846                         hnMPQ = 0;
847                         DWORD namelen = GetFullPath(lpFileName,0,0);
848                         char *namebuffer = (char *)NewAlloc.Alloc(namelen);
849                         GetFullPath(lpFileName,namebuffer,namelen);
850                         lpFileName = namebuffer;
851                         hnFile = CreateFile(lpFileName,GENERIC_READ,FILE_SHARE_READ,0,OPEN_EXISTING,0,0);
852                         if (hnFile==INVALID_HANDLE_VALUE) hnFile=0;
853                         else bFileOnDisk = TRUE;
854                 }
855         }
856         if (hnMPQ) {
857                 if(!((MPQARCHIVE *)hnMPQ)->lpBlockTable) {
858                         SFFree(mpqOpenFile);
859                         SFFree(lpnOpenFile);
860                         SetLastError(ERROR_FILE_NOT_FOUND);
861                         return FALSE;
862                 }
863         }
864         if (!hnFile) {
865                 SFFree(mpqOpenFile);
866                 SFFree(lpnOpenFile);
867                 SetLastError(ERROR_FILE_NOT_FOUND);
868                 return FALSE;
869         }
870         mpqOpenFile->lpFileName = (char *)SFAlloc(strlen(lpFileName)+1);
871         if (!mpqOpenFile->lpFileName) {
872                 SFFree(mpqOpenFile);
873                 SFFree(lpnOpenFile);
874                 return FALSE;
875         }
876         if (hnMPQ) {
877                 if (!(((MPQARCHIVE *)hnMPQ)->lpBlockTable[((HASHTABLEENTRY *)hnFile)->dwBlockTableIndex].dwFlags & MAFA_EXISTS)) {
878                         SFFree(mpqOpenFile->lpFileName);
879                         SFFree(mpqOpenFile);
880                         SFFree(lpnOpenFile);
881                         SetLastError(ERROR_FILE_INVALID);
882                         return FALSE;
883                 }
884         }
885         strcpy(mpqOpenFile->lpFileName,lpFileName);
886         if (!bFileOnDisk) {
887                 mpqOpenFile->lpParentArc = (MPQARCHIVE *)hnMPQ;
888                 mpqOpenFile->hFile = INVALID_HANDLE_VALUE;
889                 mpqOpenFile->lpHashEntry = (HASHTABLEENTRY *)hnFile;
890                 mpqOpenFile->lpBlockEntry = &((MPQARCHIVE *)hnMPQ)->lpBlockTable[mpqOpenFile->lpHashEntry->dwBlockTableIndex];
891                 mpqOpenFile->wFileOffsetHigh = ((MPQARCHIVE *)hnMPQ)->lpFileOffsetsHigh[mpqOpenFile->lpHashEntry->dwBlockTableIndex];
892                 mpqOpenFile->lpParentArc->dwRefCount++;
893                 if (mpqOpenFile->lpBlockEntry->dwFlags&MAFA_ENCRYPT) {
894                         LPSTR lpOldNameBuffer = mpqOpenFile->lpFileName;
895                         if (memicmp(mpqOpenFile->lpFileName,UNKNOWN_CMP,UNKNOWN_LEN)==0 && IsHexDigit(mpqOpenFile->lpFileName[UNKNOWN_LEN]))
896                                 mpqOpenFile->lpFileName = 0;
897                         mpqOpenFile->dwCryptKey = DetectFileSeedEx(mpqOpenFile->lpParentArc,mpqOpenFile->lpHashEntry,(LPCSTR *)&mpqOpenFile->lpFileName);
898                         if (memicmp(lpFileName,UNKNOWN_CMP,UNKNOWN_LEN)==0 && IsHexDigit(lpFileName[UNKNOWN_LEN])) {
899                                 if (!mpqOpenFile->lpFileName)
900                                         mpqOpenFile->lpFileName = lpOldNameBuffer;
901                                 else
902                                         SFFree(lpOldNameBuffer);
903                         }
904                         if (mpqOpenFile->dwCryptKey==0) {
905                                 SFFree(mpqOpenFile->lpFileName);
906                                 SFFree(mpqOpenFile);
907                                 SFFree(lpnOpenFile);
908                                 SetLastError(ERROR_FILE_INVALID);
909                                 return FALSE;
910                         }
911                 }
912         }
913         else {
914                 mpqOpenFile->hFile = hnFile;
915         }
916         strncpy(mpqOpenFile->szFileName,mpqOpenFile->lpFileName,259);
917         *hFile = (MPQHANDLE)mpqOpenFile;
918         memcpy(lpnOpenFile,lpOpenFile,sizeof(MPQFILE *) * dwOpenFileCount);
919         lpnOpenFile[dwOpenFileCount] = mpqOpenFile;
920         if (lpOpenFile) SFFree(lpOpenFile);
921         lpOpenFile = lpnOpenFile;
922         dwOpenFileCount++;
923         return TRUE;
926 BOOL SFMPQAPI WINAPI SFileCloseFile(MPQHANDLE hFile)
928         if (!hFile) {
929                 SetLastError(ERROR_INVALID_PARAMETER);
930                 return FALSE;
931         }
933         MPQFILE *mpqOpenFile = (MPQFILE *)hFile;
935         if (dwOpenFileCount==0) return FALSE;
936         SFFree(mpqOpenFile->lpFileName);
937         if (mpqOpenFile->lpdwBlockOffsets) SFFree(mpqOpenFile->lpdwBlockOffsets);
938         if (mpqOpenFile->hFile == INVALID_HANDLE_VALUE) mpqOpenFile->lpParentArc->dwRefCount--;
940         SFFree(mpqOpenFile);
941         if (lpOpenFile==0) return TRUE;
942         if (dwOpenFileCount-1==0) {
943                 SFFree(lpOpenFile);
944                 lpOpenFile = (MPQFILE **)0;
945                 dwOpenFileCount--;
946                 return TRUE;
947         }
948         else if (dwOpenFileCount==0) return FALSE;
949         MPQFILE **lpnOpenFile = (MPQFILE **)SFAlloc(sizeof(MPQFILE *) * (dwOpenFileCount-1));
950         if (lpnOpenFile) {
951                 for (DWORD i=0,j=0;i<dwOpenFileCount;i++) {
952                         if ((MPQHANDLE)lpOpenFile[i]!=hFile) {
953                                 memcpy(&lpnOpenFile[j],&lpOpenFile[i],sizeof(MPQFILE *));
954                                 j++;
955                         }
956                 }
957                 SFFree(lpOpenFile);
958                 lpOpenFile = lpnOpenFile;
959                 dwOpenFileCount--;
960         }
961         else {
962                 for (DWORD i=0,j=0;i<dwOpenFileCount;i++) {
963                         if ((MPQHANDLE)lpOpenFile[i]==hFile) {
964                                 lpOpenFile[i] = (MPQFILE *)0;
965                         }
966                         else {
967                                 if (i!=j) memcpy(&lpOpenFile[j],&lpOpenFile[i],sizeof(MPQFILE *));
968                                 j++;
969                         }
970                 }
971                 dwOpenFileCount--;
972         }
973         return TRUE;
976 DWORD SFMPQAPI WINAPI SFileGetFileSize(MPQHANDLE hFile, LPDWORD lpFileSizeHigh)
978         if (!hFile) {
979                 SetLastError(ERROR_INVALID_PARAMETER);
980                 return (DWORD)-1;
981         }
983         MPQFILE *mpqOpenFile = (MPQFILE *)hFile;
984         if (mpqOpenFile->hFile == INVALID_HANDLE_VALUE) {
985                 if (lpFileSizeHigh) *lpFileSizeHigh = 0;
986                 return mpqOpenFile->lpBlockEntry->dwFullSize;
987         }
988         else return GetFileSize(mpqOpenFile->hFile,lpFileSizeHigh);
991 BOOL SFMPQAPI WINAPI SFileGetFileArchive(MPQHANDLE hFile, MPQHANDLE *hMPQ)
993         if (!hFile || !hMPQ) {
994                 SetLastError(ERROR_INVALID_PARAMETER);
995                 return FALSE;
996         }
998         if (((MPQFILE *)hFile)->hFile == INVALID_HANDLE_VALUE) {
999                 *hMPQ = (MPQHANDLE)((MPQFILE *)hFile)->lpParentArc;
1000                 return TRUE;
1001         }
1002         else {
1003                 SetLastError(ERROR_INVALID_PARAMETER);
1004                 return FALSE;
1005         }
1008 BOOL SFMPQAPI WINAPI SFileGetFileName(MPQHANDLE hFile, LPCSTR lpBuffer, DWORD dwBufferLength)
1010         return SFileGetArchiveName(hFile,lpBuffer,dwBufferLength);
1013 DWORD SFMPQAPI WINAPI SFileGetFileInfo(MPQHANDLE hFile, DWORD dwInfoType)
1015         if (!hFile) {
1016                 SetLastError(ERROR_INVALID_PARAMETER);
1017                 return (DWORD)-1;
1018         }
1019         if (dwInfoType==0) {
1020                 SetLastError(ERROR_UNKNOWN_PROPERTY);
1021                 return (DWORD)-1;
1022         }
1024         DWORD dwhType = GetHandleType(hFile);
1025         if (dwhType==SFILE_TYPE_FILE)
1026         {
1027                 MPQFILE *mpqOpenFile = (MPQFILE *)hFile;
1028                 if (mpqOpenFile->hFile == INVALID_HANDLE_VALUE) {
1029                         MPQARCHIVE *mpqOpenArc = mpqOpenFile->lpParentArc;
1030                         switch (dwInfoType) {
1031                         case SFILE_INFO_BLOCK_SIZE:
1032                                 return mpqOpenArc->MpqHeader.wBlockSize;
1033                         case SFILE_INFO_HASH_TABLE_SIZE:
1034                                 return mpqOpenArc->MpqHeader.dwHashTableSize;
1035                         case SFILE_INFO_NUM_FILES:
1036                                 return mpqOpenArc->MpqHeader.dwBlockTableSize;
1037                         case SFILE_INFO_TYPE:
1038                                 return SFILE_TYPE_FILE;
1039                         case SFILE_INFO_SIZE:
1040                                 return mpqOpenFile->lpBlockEntry->dwFullSize;
1041                         case SFILE_INFO_COMPRESSED_SIZE:
1042                                 return mpqOpenFile->lpBlockEntry->dwCompressedSize;
1043                         case SFILE_INFO_FLAGS:
1044                                 return mpqOpenFile->lpBlockEntry->dwFlags;
1045                         case SFILE_INFO_PARENT:
1046                                 return (DWORD)mpqOpenFile->lpParentArc;
1047                         case SFILE_INFO_POSITION:
1048                                 return mpqOpenFile->dwFilePointer;
1049                         case SFILE_INFO_LOCALEID:
1050                                 return mpqOpenFile->lpHashEntry->lcLocale;
1051                         case SFILE_INFO_PRIORITY:
1052                                 return mpqOpenArc->dwPriority;
1053                         case SFILE_INFO_HASH_INDEX:
1054                                 return ((UIntPtr)mpqOpenFile->lpHashEntry-(UIntPtr)mpqOpenArc->lpHashTable)/sizeof(HASHTABLEENTRY);
1055                         case SFILE_INFO_BLOCK_INDEX:
1056                                 return mpqOpenFile->lpHashEntry->dwBlockTableIndex;
1057                         default:
1058                                 SetLastError(ERROR_UNKNOWN_PROPERTY);
1059                                 return (DWORD)-1;
1060                         }
1061                 }
1062                 else {
1063                         switch (dwInfoType) {
1064                         case SFILE_INFO_TYPE:
1065                                 return SFILE_TYPE_FILE;
1066                         case SFILE_INFO_SIZE:
1067                                 return SFGetFileSize(mpqOpenFile->hFile);
1068                         case SFILE_INFO_COMPRESSED_SIZE:
1069                                 return SFGetFileSize(mpqOpenFile->hFile);
1070 #ifdef _WIN32
1071                         case SFILE_INFO_FLAGS:
1072                                 return GetFileAttributes(mpqOpenFile->lpFileName);
1073 #endif
1074                         case SFILE_INFO_POSITION:
1075                                 return SFSetFilePointer(mpqOpenFile->hFile,0,FILE_CURRENT);
1076                         default:
1077                                 SetLastError(ERROR_UNKNOWN_PROPERTY);
1078                                 return (DWORD)-1;
1080                         }
1081                 }
1082         }
1083         else if (dwhType==SFILE_TYPE_MPQ)
1084         {
1085                 MPQARCHIVE *mpqOpenArc = (MPQARCHIVE *)hFile;
1086                 switch (dwInfoType) {
1087                 case SFILE_INFO_BLOCK_SIZE:
1088                         return mpqOpenArc->MpqHeader.wBlockSize;
1089                 case SFILE_INFO_HASH_TABLE_SIZE:
1090                         return mpqOpenArc->MpqHeader.dwHashTableSize;
1091                 case SFILE_INFO_NUM_FILES:
1092                         return mpqOpenArc->MpqHeader.dwBlockTableSize;
1093                 case SFILE_INFO_TYPE:
1094                         return SFILE_TYPE_MPQ;
1095                 case SFILE_INFO_SIZE:
1096                         return mpqOpenArc->MpqHeader.dwMPQSize;
1097                 case SFILE_INFO_PRIORITY:
1098                         return mpqOpenArc->dwPriority;
1099                 default:
1100                         SetLastError(ERROR_UNKNOWN_PROPERTY);
1101                         return (DWORD)-1;
1102                 }
1103         }
1104         SetLastError(ERROR_INVALID_PARAMETER);
1105         return (DWORD)-1;
1108 DWORD SFMPQAPI WINAPI SFileSetFilePointer(MPQHANDLE hFile, long lDistanceToMove, PLONG lplDistanceToMoveHigh, DWORD dwMoveMethod)
1110         if (!hFile) {
1111                 SetLastError(ERROR_INVALID_PARAMETER);
1112                 return (DWORD)-1;
1113         }
1115         MPQFILE *mpqOpenFile = (MPQFILE *)hFile;
1116         if (mpqOpenFile->hFile == INVALID_HANDLE_VALUE) {
1117                 long fsz = mpqOpenFile->lpBlockEntry->dwFullSize;
1118                 long cpos = mpqOpenFile->dwFilePointer;
1119                 switch (dwMoveMethod) {
1120                 case FILE_BEGIN:
1121                         if (lDistanceToMove<0 || lDistanceToMove>fsz) return (DWORD)-1;
1122                         mpqOpenFile->dwFilePointer = lDistanceToMove;
1123                         break;
1124                 case FILE_CURRENT:
1125                         if (lDistanceToMove<cpos || cpos+lDistanceToMove>fsz) return (DWORD)-1;
1126                         mpqOpenFile->dwFilePointer += lDistanceToMove;
1127                         break;
1129                 case FILE_END:
1130                         if (lDistanceToMove<fsz || lDistanceToMove>0) return (DWORD)-1;
1131                         mpqOpenFile->dwFilePointer = fsz+lDistanceToMove;
1132                         break;
1133                 default:
1134                         if (lDistanceToMove<0 || lDistanceToMove>fsz) return (DWORD)-1;
1135                         mpqOpenFile->dwFilePointer = lDistanceToMove;
1136                 }
1137                 if (lplDistanceToMoveHigh!=0) *lplDistanceToMoveHigh = 0;
1138                 return mpqOpenFile->dwFilePointer;
1139         }
1140         else return SetFilePointer(mpqOpenFile->hFile,lDistanceToMove,lplDistanceToMoveHigh,dwMoveMethod);
1144 BOOL SFMPQAPI WINAPI SFileReadFile(MPQHANDLE hFile,LPVOID lpBuffer,DWORD nNumberOfBytesToRead,LPDWORD lpNumberOfBytesRead,LPOVERLAPPED lpOverlapped)
1146         if (!hFile || !lpBuffer) {
1147                 SetLastError(ERROR_INVALID_PARAMETER);
1148                 return FALSE;
1149         }
1151         MPQFILE *mpqOpenFile = (MPQFILE *)hFile;
1152         if (mpqOpenFile->hFile != INVALID_HANDLE_VALUE) {
1153                 DWORD tsz=0;
1154                 BOOL RetVal = ReadFile(mpqOpenFile->hFile,lpBuffer,nNumberOfBytesToRead,&tsz,lpOverlapped);
1155                 if (lpNumberOfBytesRead) *lpNumberOfBytesRead = tsz;
1156                 return RetVal;
1157         }
1158         if (lpOverlapped)
1159                 if (lpOverlapped->Internal || lpOverlapped->InternalHigh || lpOverlapped->Offset || lpOverlapped->OffsetHigh || lpOverlapped->hEvent)
1160                         SFileSetFilePointer(hFile,lpOverlapped->Offset,(long *)&lpOverlapped->OffsetHigh,FILE_BEGIN);
1161         if (nNumberOfBytesToRead==0) {
1162                 if (lpNumberOfBytesRead) *lpNumberOfBytesRead = 0;
1163                 if (lpOverlapped) lpOverlapped->InternalHigh = 0;
1164                 return TRUE;
1165         }
1166         MPQARCHIVE *mpqOpenArc = mpqOpenFile->lpParentArc;
1168         if (mpqOpenFile->dwFilePointer>mpqOpenFile->lpBlockEntry->dwFullSize) return FALSE;
1169         if (mpqOpenFile->dwFilePointer==mpqOpenFile->lpBlockEntry->dwFullSize)
1170         {
1171                 if (lpNumberOfBytesRead) *lpNumberOfBytesRead = 0;
1172                 if (lpOverlapped) lpOverlapped->InternalHigh = 0;
1173                 return TRUE;
1174         }
1175         DWORD nBytesRead,TotalBytesRead=0;
1176         DWORD BlockIndex = mpqOpenFile->lpHashEntry->dwBlockTableIndex;
1177         if (mpqOpenFile->dwFilePointer+nNumberOfBytesToRead>mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize) nNumberOfBytesToRead = mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize-mpqOpenFile->dwFilePointer;
1178         DWORD blockSize = 512 << mpqOpenArc->MpqHeader.wBlockSize;
1179         DWORD dwBlockStart = mpqOpenFile->dwFilePointer - (mpqOpenFile->dwFilePointer % blockSize);
1180     DWORD blockNum = dwBlockStart / blockSize;
1181     DWORD nBlocks  = (mpqOpenFile->dwFilePointer+nNumberOfBytesToRead) / blockSize;
1182     if((mpqOpenFile->dwFilePointer+nNumberOfBytesToRead) % blockSize)
1183                 nBlocks++;
1184         DWORD TotalBlocks = mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize / blockSize;
1185         if(mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize % blockSize)
1186                 TotalBlocks++;
1187         DWORD dwBlockPos = mpqOpenFile->dwFilePointer % blockSize;
1188         DWORD dwBlockPosEnd = (mpqOpenFile->dwFilePointer+nNumberOfBytesToRead) % blockSize;
1189         if (dwBlockPosEnd==0) dwBlockPosEnd = blockSize;
1190         void *blkBuffer = SFAlloc(blockSize);
1191         if (!blkBuffer) {
1192                 if (lpNumberOfBytesRead) *lpNumberOfBytesRead = 0;
1193                 if (lpOverlapped) lpOverlapped->InternalHigh = 0;
1194                 return FALSE;
1195         }
1196         void *blk16Buffer = SFAlloc(blockSize * 16);
1197         if (!blk16Buffer) {
1198                 SFFree(blkBuffer);
1199                 if (lpNumberOfBytesRead) *lpNumberOfBytesRead = 0;
1200                 if (lpOverlapped) lpOverlapped->InternalHigh = 0;
1201                 return FALSE;
1202         }
1203         DWORD dwCryptKey = mpqOpenFile->dwCryptKey;
1204         //if (mpqOpenArc->lpBlockTable[BlockIndex].dwFlags & MAFA_ENCRYPT) dwCryptKey = HashString(mpqOpenFile->lpFileName,HASH_KEY);
1205         //if (mpqOpenArc->lpBlockTable[BlockIndex].dwFlags & MAFA_MODCRYPTKEY) dwCryptKey = (dwCryptKey + mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset) ^ mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize;
1206         DWORD HeaderLength=0;
1207         if (memcmp(&mpqOpenArc->MpqHeader.dwMPQID,ID_BN3,4)==0)
1208         {
1209                 SFSetFilePointer(mpqOpenArc->hFile, mpqOpenArc->qwMPQStart + MakeUInt64(mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset, mpqOpenArc->lpFileOffsetsHigh[BlockIndex]), FILE_BEGIN);
1210                 ReadFile(mpqOpenArc->hFile,&HeaderLength,4,&nBytesRead,0);
1211         }
1212         DWORD i;
1213         if (!mpqOpenFile->lpdwBlockOffsets)
1214         {
1215                 DWORD *dwBlockPtrTable = (DWORD *)SFAlloc((TotalBlocks+1)*4);
1216                 if (!dwBlockPtrTable) {
1218                         SFFree(blk16Buffer);
1219                         SFFree(blkBuffer);
1220                         if (lpNumberOfBytesRead) *lpNumberOfBytesRead = 0;
1221                         if (lpOverlapped) lpOverlapped->InternalHigh = 0;
1222                         return FALSE;
1223                 }
1224                 if ((mpqOpenArc->lpBlockTable[BlockIndex].dwFlags & MAFA_COMPRESS) || (mpqOpenArc->lpBlockTable[BlockIndex].dwFlags & MAFA_COMPRESS2))
1225                 {
1226                         SFSetFilePointer(mpqOpenArc->hFile, mpqOpenArc->qwMPQStart + MakeUInt64(mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset, mpqOpenArc->lpFileOffsetsHigh[BlockIndex]) + HeaderLength, FILE_BEGIN);
1227                         ReadFile(mpqOpenArc->hFile,dwBlockPtrTable,(TotalBlocks+1)*4,&nBytesRead,0);
1228                         if (mpqOpenArc->lpBlockTable[BlockIndex].dwFlags & MAFA_ENCRYPT) {
1229                                 DecryptData((LPBYTE)dwBlockPtrTable,(TotalBlocks+1)*4,dwCryptKey-1);
1230                         }
1231                 }
1232                 else
1233                 {
1234                         for (i=0;i<TotalBlocks+1;i++) {
1235                                 if (i<TotalBlocks) dwBlockPtrTable[i] = i * blockSize;
1236                                 else dwBlockPtrTable[i] = mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize;
1237                         }
1238                 }
1239                 mpqOpenFile->lpdwBlockOffsets = dwBlockPtrTable;
1240         }
1241         BYTE *compbuffer = (BYTE *)SFAlloc(blockSize+3);
1242         if (!compbuffer) {
1243                 SFFree(blk16Buffer);
1244                 SFFree(blkBuffer);
1245                 if (lpNumberOfBytesRead) *lpNumberOfBytesRead = 0;
1246                 if (lpOverlapped) lpOverlapped->InternalHigh = 0;
1247                 return FALSE;
1248         }
1249         DWORD blk=0,blki=0;
1250         for (i=blockNum;i<nBlocks;i++) {
1251                 if (blk==0) {
1252                         SFSetFilePointer(mpqOpenArc->hFile, mpqOpenArc->qwMPQStart + MakeUInt64(mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset, mpqOpenArc->lpFileOffsetsHigh[BlockIndex]) + HeaderLength + mpqOpenFile->lpdwBlockOffsets[i], FILE_BEGIN);
1253                         blki=i;
1254                         if (i+16>nBlocks) {
1255                                 if (ReadFile(mpqOpenArc->hFile,blk16Buffer,mpqOpenFile->lpdwBlockOffsets[nBlocks]-mpqOpenFile->lpdwBlockOffsets[i],&nBytesRead,0)==0) {
1256                                         SFFree(compbuffer);
1257                                         SFFree(blk16Buffer);
1258                                         SFFree(blkBuffer);
1259                                         if (lpNumberOfBytesRead) *lpNumberOfBytesRead = TotalBytesRead;
1260                                         if (lpOverlapped) lpOverlapped->InternalHigh = TotalBytesRead;
1261                                         return FALSE;
1262                                 }
1264                         }
1265                         else {
1266                                 if (ReadFile(mpqOpenArc->hFile,blk16Buffer,mpqOpenFile->lpdwBlockOffsets[i+16]-mpqOpenFile->lpdwBlockOffsets[i],&nBytesRead,0)==0) {
1267                                         SFFree(compbuffer);
1268                                         SFFree(blk16Buffer);
1269                                         SFFree(blkBuffer);
1270                                         if (lpNumberOfBytesRead) *lpNumberOfBytesRead = TotalBytesRead;
1271                                         if (lpOverlapped) lpOverlapped->InternalHigh = TotalBytesRead;
1272                                         return FALSE;
1273                                 }
1274                         }
1275                 }
1276                 memcpy(blkBuffer,((char *)blk16Buffer)+(mpqOpenFile->lpdwBlockOffsets[blki+blk]-mpqOpenFile->lpdwBlockOffsets[blki]),mpqOpenFile->lpdwBlockOffsets[i+1]-mpqOpenFile->lpdwBlockOffsets[i]);
1277                 if (mpqOpenArc->lpBlockTable[BlockIndex].dwFlags & MAFA_ENCRYPT)
1278                 {
1279                         DecryptData((LPBYTE)blkBuffer,mpqOpenFile->lpdwBlockOffsets[i+1]-mpqOpenFile->lpdwBlockOffsets[i],dwCryptKey+i);
1280                 }
1281                 if (i==TotalBlocks-1 && (mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize % blockSize)!=0) blockSize=mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize % blockSize;
1282                 DWORD outLength=blockSize;
1283                 if ((mpqOpenFile->lpdwBlockOffsets[i+1]-mpqOpenFile->lpdwBlockOffsets[i])!=blockSize)
1284                 {
1285                         if (mpqOpenArc->lpBlockTable[BlockIndex].dwFlags & MAFA_COMPRESS)
1286                         {
1287                                 BYTE *compdata = compbuffer;
1288                                 memcpy(compdata,(char *)blkBuffer,mpqOpenFile->lpdwBlockOffsets[i+1]-mpqOpenFile->lpdwBlockOffsets[i]);
1289                                 if (compdata[0]&UNSUPPORTED_DECOMPRESSION) {
1290                                         LoadStorm();
1291                                         if (stormSCompDecompress)
1292                                                 stormSCompDecompress(blkBuffer, &outLength, compdata, mpqOpenFile->lpdwBlockOffsets[i+1]-mpqOpenFile->lpdwBlockOffsets[i]);
1293                                 }
1294                                 else {
1295                                         SCompDecompress(blkBuffer, &outLength, compdata, mpqOpenFile->lpdwBlockOffsets[i+1]-mpqOpenFile->lpdwBlockOffsets[i]);
1296                                 }
1297                         }
1298                         else if (mpqOpenArc->lpBlockTable[BlockIndex].dwFlags & MAFA_COMPRESS2)
1299                         {
1300                                 BYTE *compdata = compbuffer;
1301                                 compdata[0] = 0x08;
1302                                 memcpy(compdata+1,(char *)blkBuffer,mpqOpenFile->lpdwBlockOffsets[i+1]-mpqOpenFile->lpdwBlockOffsets[i]);
1303                                 SCompDecompress(blkBuffer, &outLength, compdata, mpqOpenFile->lpdwBlockOffsets[i+1]-mpqOpenFile->lpdwBlockOffsets[i]+1);
1304                         }
1305                 }
1306                 if (i==blockNum) {
1307                         if (nNumberOfBytesToRead > blockSize-dwBlockPos) {
1308                                 memcpy(lpBuffer,(char *)blkBuffer+dwBlockPos,blockSize-dwBlockPos);
1309                                 TotalBytesRead+=blockSize-dwBlockPos;
1310                                 mpqOpenFile->dwFilePointer += blockSize-dwBlockPos;
1311                                 nNumberOfBytesToRead-=blockSize-dwBlockPos;
1312                         }
1313                         else {
1314                                 memcpy(lpBuffer,(char *)blkBuffer+dwBlockPos,nNumberOfBytesToRead);
1315                                 TotalBytesRead+=nNumberOfBytesToRead;
1316                                 mpqOpenFile->dwFilePointer += nNumberOfBytesToRead;
1317                                 nNumberOfBytesToRead-=nNumberOfBytesToRead;
1318                         }
1319                 }
1320                 else if (i==nBlocks-1) {
1321                         if (nNumberOfBytesToRead > dwBlockPosEnd) {
1322                                 memcpy((char *)lpBuffer+TotalBytesRead,blkBuffer,dwBlockPosEnd);
1323                                 TotalBytesRead+=dwBlockPosEnd;
1324                                 mpqOpenFile->dwFilePointer += dwBlockPosEnd;
1325                                 nNumberOfBytesToRead-=dwBlockPosEnd;
1326                         }
1327                         else {
1328                                 memcpy((char *)lpBuffer+TotalBytesRead,blkBuffer,nNumberOfBytesToRead);
1329                                 TotalBytesRead+=nNumberOfBytesToRead;
1330                                 mpqOpenFile->dwFilePointer += nNumberOfBytesToRead;
1331                                 nNumberOfBytesToRead-=nNumberOfBytesToRead;
1332                         }
1333                 }
1334                 else {
1335                         if (nNumberOfBytesToRead > blockSize) {
1336                                 memcpy((char *)lpBuffer+TotalBytesRead,blkBuffer,blockSize);
1337                                 TotalBytesRead+=blockSize;
1338                                 mpqOpenFile->dwFilePointer += blockSize;
1339                                 nNumberOfBytesToRead-=blockSize;
1340                         }
1341                         else {
1342                                 memcpy((char *)lpBuffer+TotalBytesRead,blkBuffer,nNumberOfBytesToRead);
1343                                 TotalBytesRead+=nNumberOfBytesToRead;
1344                                 mpqOpenFile->dwFilePointer += nNumberOfBytesToRead;
1345                                 nNumberOfBytesToRead-=nNumberOfBytesToRead;
1346                         }
1347                 }
1348                 blk = (blk+1) % 16;
1349         }
1350         SFFree(compbuffer);
1351         SFFree(blk16Buffer);
1352         SFFree(blkBuffer);
1353         if (lpNumberOfBytesRead) *lpNumberOfBytesRead = TotalBytesRead;
1354         if (lpOverlapped) lpOverlapped->InternalHigh = TotalBytesRead;
1355         return TRUE;
1358 LCID SFMPQAPI WINAPI SFileSetLocale(LCID nNewLocale)
1360         return (LocaleID = nNewLocale);
1363 BOOL SFMPQAPI WINAPI SFileGetBasePath(LPCSTR lpBuffer, DWORD dwBufferLength)
1365         if (lpBuffer==0) {
1366                 SetLastError(ERROR_INVALID_PARAMETER);
1367                 return FALSE;
1368         }
1370         DWORD slen = strlen(StormBasePath)+1;
1371         if (dwBufferLength>=slen) memcpy((void *)lpBuffer,StormBasePath,slen);
1372         else memcpy((void *)lpBuffer,StormBasePath,dwBufferLength);
1373         return TRUE;
1376 BOOL SFMPQAPI WINAPI SFileSetBasePath(LPCSTR lpNewBasePath)
1378         if (!lpNewBasePath) {
1379                 SetLastError(ERROR_INVALID_PARAMETER);
1380                 return FALSE;
1381         }
1382         if (!*lpNewBasePath) {
1383                 SetLastError(ERROR_INVALID_PARAMETER);
1384                 return FALSE;
1385         }
1387         DWORD slen = strlen(lpNewBasePath)+1;
1388         if (slen>MAX_PATH+1) return FALSE;
1389         else if (slen==MAX_PATH+1)
1390                 if (lpNewBasePath[MAX_PATH-1]!='\\' && lpNewBasePath[MAX_PATH-1]!='/') return FALSE;
1391         TempAlloc NewAlloc;
1392         char *buffer = (char *)NewAlloc.Alloc(slen+1);
1393         memcpy(buffer,lpNewBasePath,slen);
1394         char *npath;
1395 #ifdef _WIN32
1396         for (npath=buffer;npath[0]!=0;npath++)
1397                 if (npath[0]=='/') npath[0]='\\';
1398         if (npath[-1]!='\\') {
1399                 npath[0]='\\';
1400                 npath[1]=0;
1401                 slen+=1;
1402         }
1403 #else
1404         for (npath=buffer;npath[0]!=0;npath++)
1405                 if (npath[0]=='\\') npath[0]='/';
1406         if (npath[-1]!='/') {
1407                 npath[0]='/';
1408                 npath[1]=0;
1409                 slen+=1;
1410         }
1411 #endif
1412 #ifdef _WIN32
1413         DWORD attrib = GetFileAttributes(buffer);
1414         if ((attrib&FILE_ATTRIBUTE_DIRECTORY)==0 || attrib==0xFFFFFFFF) return FALSE;
1415 #endif
1417         memcpy(StormBasePath,buffer,slen);
1418         return TRUE;
1421 BOOL SFMPQAPI WINAPI SFileSetArchivePriority(MPQHANDLE hMPQ, DWORD dwPriority)
1423         if (!hMPQ) {
1424                 SetLastError(ERROR_INVALID_PARAMETER);
1425                 return FALSE;
1426         }
1428         MPQARCHIVE *mpqOpenArc = (MPQARCHIVE *)hMPQ;
1429         mpqOpenArc->dwPriority = dwPriority;
1430         if (dwOpenMpqCount>1) SortOpenArchivesByPriority();
1431         return TRUE;
1434 int StringICompare(const void *arg1,const void *arg2)
1436         return stricmp(*(char **)arg1,*(char **)arg2);
1439 BOOL SFMPQAPI WINAPI SFileListFiles(MPQHANDLE hMPQ, LPCSTR lpFileLists, FILELISTENTRY *lpListBuffer, DWORD dwFlags)
1441         if (!hMPQ || !lpListBuffer) {
1442                 SetLastError(ERROR_INVALID_PARAMETER);
1443                 return FALSE;
1444         }
1446         MPQARCHIVE *mpqOpenArc = (MPQARCHIVE *)hMPQ;
1447         DWORD i,tsz;
1449         if (memcmp(&mpqOpenArc->MpqHeader.dwMPQID,ID_BN3,4)==0)
1450         {
1451                 for (i=0;i<mpqOpenArc->MpqHeader.dwHashTableSize;i++) {
1452                         lpListBuffer[i].dwFileExists = 0;
1453                         lpListBuffer[i].szFileName[0] = 0;
1454                         if ((mpqOpenArc->lpHashTable[i].dwBlockTableIndex&0xFFFFFFFE)!=0xFFFFFFFE && mpqOpenArc->lpHashTable[i].dwBlockTableIndex < mpqOpenArc->MpqHeader.dwBlockTableSize) {
1455                                 lpListBuffer[i].lcLocale = mpqOpenArc->lpHashTable[i].lcLocale;
1456                                 DWORD dwBlockIndex = mpqOpenArc->lpHashTable[i].dwBlockTableIndex;
1457                                 lpListBuffer[i].dwCompressedSize = mpqOpenArc->lpBlockTable[dwBlockIndex].dwCompressedSize;
1458                                 lpListBuffer[i].dwFullSize = mpqOpenArc->lpBlockTable[dwBlockIndex].dwFullSize;
1459                                 lpListBuffer[i].dwFlags = mpqOpenArc->lpBlockTable[dwBlockIndex].dwFlags;
1460                                 if (dwFlags & SFILE_LIST_FLAG_UNKNOWN)
1461                                         lpListBuffer[i].dwFileExists = 1;
1462                                 else
1463                                         lpListBuffer[i].dwFileExists=0xFFFFFFFF;
1464                                 SFSetFilePointer(mpqOpenArc->hFile, mpqOpenArc->qwMPQStart + MakeUInt64(mpqOpenArc->lpBlockTable[dwBlockIndex].dwFileOffset, mpqOpenArc->lpFileOffsetsHigh[dwBlockIndex]) + 0x40, FILE_BEGIN);
1465                                 ReadFile(mpqOpenArc->hFile,lpListBuffer[i].szFileName,260,&tsz,0);
1467                                 if (mpqOpenArc->lpHashTable[i].dwNameHashA==HashString(lpListBuffer[i].szFileName,HASH_NAME_A) && mpqOpenArc->lpHashTable[i].dwNameHashB==HashString(lpListBuffer[i].szFileName,HASH_NAME_B)) {
1468                                         if (dwFlags&SFILE_LIST_ONLY_UNKNOWN && !(dwFlags&SFILE_LIST_ONLY_KNOWN)) {
1469                                                 lpListBuffer[i].dwFileExists = 0;
1470                                         }
1471                                 }
1472                                 else {
1473                                         sprintf(lpListBuffer[i].szFileName,UNKNOWN_OUT,i);
1474                                         if (dwFlags & SFILE_LIST_FLAG_UNKNOWN) {
1475                                                 lpListBuffer[i].dwFileExists |= 2;
1476                                         }
1478                                         if (dwFlags&SFILE_LIST_ONLY_KNOWN) {
1479                                                 lpListBuffer[i].dwFileExists = 0;
1480                                         }
1481                                 }
1482                         }
1483                 }
1485                 return TRUE;
1486         }
1488         char **lpNameBuffers=0;
1490         char **lpNames=0,szNull[1]={0},*lpFLCopy;
1491         DWORD *lpdwNameHashA=0,*lpdwNameHashB=0;
1492         DWORD dwListNameHashA,dwListNameHashB;
1493         DWORD j;
1494         lpFLCopy = (char *)lpFileLists;
1495         DWORD dwExtLists=0,dwIntLists=0;
1496         if (!lpFLCopy) lpFLCopy=szNull;
1497         char *lpLines;
1498         for (lpLines=lpFLCopy;lpLines;lpLines=nextline(lpLines)) {
1499                 if (!*lpLines) break;
1500                 dwExtLists++;
1501         }
1502         dwListNameHashA = HashString(INTERNAL_LISTFILE,HASH_NAME_A);
1503         dwListNameHashB = HashString(INTERNAL_LISTFILE,HASH_NAME_B);
1504         for (i=0;i<mpqOpenArc->MpqHeader.dwHashTableSize;i++) {
1505                 if (mpqOpenArc->lpHashTable[i].dwNameHashA==dwListNameHashA && mpqOpenArc->lpHashTable[i].dwNameHashB==dwListNameHashB && (mpqOpenArc->lpHashTable[i].dwBlockTableIndex&0xFFFFFFFE)!=0xFFFFFFFE) {
1506                         dwIntLists++;
1507                 }
1508         }
1509         lpNameBuffers = (char **)SFAlloc((1+dwExtLists+dwIntLists)*sizeof(char *));
1510         if (dwExtLists) {
1511                 lpFLCopy = strdup(lpFLCopy);
1512                 i=0;
1513                 for (lpLines=lpFLCopy;lpLines;lpLines=nextline(lpLines)) {
1514                         if (!*lpLines) break;
1515                         lpNameBuffers[i+1] = lpLines;
1516                         i++;
1517                 }
1518                 for (i=0;i<dwExtLists;i++) {
1519                         lpNameBuffers[i+1][strlnlen(lpNameBuffers[i+1])]=0;
1520                 }
1521                 qsort(lpNameBuffers+1,dwExtLists,sizeof(char *),StringICompare);
1522                 for (i=0;i<dwExtLists-1;i++) {
1523                         if (stricmp(lpNameBuffers[i+1],lpNameBuffers[i+2])==0) {
1524                                 memmove(&lpNameBuffers[i+1],&lpNameBuffers[i+2],(dwExtLists-(i+1))*sizeof(char *));
1525                                 dwExtLists--;
1526                         }
1527                 }
1528         }
1529         if (dwIntLists) {
1530                 dwIntLists = 0;
1531                 for (i=0;i<mpqOpenArc->MpqHeader.dwHashTableSize;i++) {
1532                         if (mpqOpenArc->lpHashTable[i].dwNameHashA==dwListNameHashA && mpqOpenArc->lpHashTable[i].dwNameHashB==dwListNameHashB && (mpqOpenArc->lpHashTable[i].dwBlockTableIndex&0xFFFFFFFE)!=0xFFFFFFFE) {
1533                                 lpNameBuffers[1+dwExtLists+dwIntLists] = (char *)i;
1534                                 dwIntLists++;
1535                         }
1536                 }
1537         }
1538         DWORD dwLines=0,dwOldLines=0,dwTotalLines=0;
1539         DWORD fsz;
1540         HANDLE hFile;
1541         DWORD dwListCryptKey = HashString(INTERNAL_LISTFILE,HASH_KEY);
1542         for (i=0;i<1+dwExtLists+dwIntLists;i++) {
1543                 if (i==0) {
1544                         fsz = strlen(INTERNAL_FILES);
1545                         lpNameBuffers[i] = (char *)SFAlloc(fsz+1);
1546                         memcpy(lpNameBuffers[i],INTERNAL_FILES,fsz);
1547                         lpNameBuffers[i][fsz]=0;
1548                 }
1549                 else if (i<1+dwExtLists) {
1550                         if (!(dwFlags&SFILE_LIST_MEMORY_LIST)) {
1551                                 hFile = CreateFile(lpNameBuffers[i],GENERIC_READ,FILE_SHARE_READ,0,OPEN_EXISTING,0,0);
1552                                 if (hFile!=INVALID_HANDLE_VALUE) {
1553                                         fsz = SFGetFileSize(hFile);
1554                                         SFSetFilePointer(hFile,0,FILE_BEGIN);
1555                                         lpNameBuffers[i] = (char *)SFAlloc(fsz+1);
1556                                         ReadFile(hFile,lpNameBuffers[i],fsz,&tsz,0);
1557                                         CloseHandle(hFile);
1558                                         lpNameBuffers[i][fsz]=0;
1559                                 }
1560                                 else lpNameBuffers[i]=0;
1561                         }
1562                         else {
1563                                 dwTotalLines++;
1564                                 continue;
1565                         }
1566                 }
1567                 else {
1568                         MPQFILE thisFile;
1569                         memset(&thisFile,0,sizeof(MPQFILE));
1570                         thisFile.lpParentArc = (MPQARCHIVE *)hMPQ;
1571                         thisFile.hFile = INVALID_HANDLE_VALUE;
1572                         thisFile.lpHashEntry = &mpqOpenArc->lpHashTable[(DWORD)lpNameBuffers[i]];
1573                         thisFile.lpBlockEntry = &mpqOpenArc->lpBlockTable[thisFile.lpHashEntry->dwBlockTableIndex];
1574                         thisFile.lpFileName = thisFile.szFileName;
1575                         strcpy(thisFile.lpFileName,INTERNAL_LISTFILE);
1576                         thisFile.dwFilePointer = 0;
1577                         thisFile.lpdwBlockOffsets = 0;
1578                         BLOCKTABLEENTRY *lpBlockEntry = thisFile.lpBlockEntry;
1579                         if (lpBlockEntry->dwFlags & MAFA_ENCRYPT) {
1580                                 thisFile.dwCryptKey = dwListCryptKey;
1581                                 if (lpBlockEntry->dwFlags & MAFA_MODCRYPTKEY)
1582                                         thisFile.dwCryptKey = (thisFile.dwCryptKey + lpBlockEntry->dwFileOffset) ^ lpBlockEntry->dwFullSize;
1583                         }
1584                         fsz = lpBlockEntry->dwFullSize;
1585                         lpNameBuffers[i] = (char *)SFAlloc(fsz+1);
1586                         SFileReadFile(&thisFile,lpNameBuffers[i],fsz,0,0);
1587                         if (thisFile.lpdwBlockOffsets) SFFree(thisFile.lpdwBlockOffsets);
1588                         lpNameBuffers[i][fsz]=0;
1589                 }
1590                 for (lpLines=lpNameBuffers[i];lpLines;lpLines=nextline(lpLines)) {
1591                         if (!*lpLines) break;
1592                         dwTotalLines++;
1593                 }
1594         }
1595         lpNames = (char **)SFAlloc(dwTotalLines*sizeof(char *));
1596         for (i=0;i<1+dwExtLists+dwIntLists;i++) {
1597                 dwOldLines=dwLines;
1598                 for (lpLines=lpNameBuffers[i];lpLines;lpLines=nextline(lpLines)) {
1599                         if (!*lpLines) break;
1600                         lpNames[dwLines] = lpLines;
1601                         dwLines++;
1602                 }
1603                 for (j=dwOldLines;j<dwLines;j++) {
1604                         lpNames[j][strlnlen(lpNames[j])]=0;
1605                 }
1606         }
1607         qsort(lpNames,dwTotalLines,sizeof(char *),StringICompare);
1608         for (i=0;i<dwTotalLines-1;i++) {
1609                 if (stricmp(lpNames[i],lpNames[i+1])==0) {
1610                         memmove(&lpNames[i],&lpNames[i+1],(dwTotalLines-(i+1))*sizeof(char *));
1611                         dwTotalLines--;
1612                 }
1613         }
1614         if (dwTotalLines) {
1615                 lpdwNameHashA = (DWORD *)SFAlloc(dwTotalLines*sizeof(DWORD));
1616                 lpdwNameHashB = (DWORD *)SFAlloc(dwTotalLines*sizeof(DWORD));
1617                 for (i=0;i<dwTotalLines;i++) {
1618                         lpdwNameHashA[i] = HashString(lpNames[i],HASH_NAME_A);
1619                         lpdwNameHashB[i] = HashString(lpNames[i],HASH_NAME_B);
1620                 }
1621         }
1622         for (i=0;i<mpqOpenArc->MpqHeader.dwHashTableSize;i++) {
1623                 lpListBuffer[i].dwFileExists = 0;
1624                 lpListBuffer[i].szFileName[0] = 0;
1625                 if ((mpqOpenArc->lpHashTable[i].dwBlockTableIndex&0xFFFFFFFE)!=0xFFFFFFFE && mpqOpenArc->lpHashTable[i].dwBlockTableIndex < mpqOpenArc->MpqHeader.dwBlockTableSize) {
1626                         lpListBuffer[i].lcLocale = mpqOpenArc->lpHashTable[i].lcLocale;
1627                         DWORD dwBlockIndex = mpqOpenArc->lpHashTable[i].dwBlockTableIndex;
1628                         lpListBuffer[i].dwCompressedSize = mpqOpenArc->lpBlockTable[dwBlockIndex].dwCompressedSize;
1629                         lpListBuffer[i].dwFullSize = mpqOpenArc->lpBlockTable[dwBlockIndex].dwFullSize;
1630                         lpListBuffer[i].dwFlags = mpqOpenArc->lpBlockTable[dwBlockIndex].dwFlags;
1631                         if (dwFlags & SFILE_LIST_FLAG_UNKNOWN)
1632                                 lpListBuffer[i].dwFileExists = 1;
1633                         else
1634                                 lpListBuffer[i].dwFileExists=0xFFFFFFFF;
1635                         for (j=0;j<dwTotalLines;j++) {
1636                                 if (mpqOpenArc->lpHashTable[i].dwNameHashA==lpdwNameHashA[j] && mpqOpenArc->lpHashTable[i].dwNameHashB==lpdwNameHashB[j]) {
1637                                         strncpy(lpListBuffer[i].szFileName,lpNames[j],260);
1638                                         if (dwFlags&SFILE_LIST_ONLY_UNKNOWN && !(dwFlags&SFILE_LIST_ONLY_KNOWN)) {
1639                                                 lpListBuffer[i].dwFileExists = 0;
1640                                         }
1641                                         break;
1642                                 }
1643                                 if (j+1==dwTotalLines) {
1644                                         sprintf(lpListBuffer[i].szFileName,UNKNOWN_OUT,i);
1645                                         if (dwFlags & SFILE_LIST_FLAG_UNKNOWN) {
1646                                                 lpListBuffer[i].dwFileExists |= 2;
1647                                         }
1649                                         if (dwFlags&SFILE_LIST_ONLY_KNOWN) {
1650                                                 lpListBuffer[i].dwFileExists = 0;
1651                                         }
1652                                 }
1653                         }
1654                 }
1655         }
1656         if (lpNameBuffers) {
1657                 for (i=0;i<1+dwExtLists+dwIntLists;i++) {
1658                         if (i>=1 && i<1+dwExtLists) {
1659                                 if ((dwFlags&SFILE_LIST_MEMORY_LIST)) {
1660                                         continue;
1661                                 }
1662                         }
1663                         if (lpNameBuffers[i]) SFFree(lpNameBuffers[i]);
1664                 }
1665                 SFFree(lpNameBuffers);
1666         }
1667         if (dwExtLists) SFFree(lpFLCopy);
1668         if (lpdwNameHashA) SFFree(lpdwNameHashA);
1669         if (lpdwNameHashB) SFFree(lpdwNameHashB);
1670         return TRUE;
1673 MPQHANDLE SFMPQAPI WINAPI MpqOpenArchiveForUpdate(LPCSTR lpFileName, DWORD dwFlags, DWORD dwMaximumFilesInArchive)
1675         MPQHANDLE hMPQ;
1677         MpqOpenArchiveEx(lpFileName,0,0,&hMPQ,dwFlags,dwMaximumFilesInArchive,USE_DEFAULT_BLOCK_SIZE);
1678         return hMPQ;
1681 MPQHANDLE SFMPQAPI WINAPI MpqOpenArchiveForUpdateEx(LPCSTR lpFileName, DWORD dwFlags, DWORD dwMaximumFilesInArchive, DWORD dwBlockSize)
1683         MPQHANDLE hMPQ;
1685         MpqOpenArchiveEx(lpFileName,0,0,&hMPQ,dwFlags,dwMaximumFilesInArchive,dwBlockSize);
1686         return hMPQ;
1689 DWORD SFMPQAPI WINAPI MpqCloseUpdatedArchive(MPQHANDLE hMPQ, DWORD dwUnknown2)
1691         return SFileCloseArchive(hMPQ);
1694 BOOL SFMPQAPI WINAPI MpqAddFileToArchiveEx(MPQHANDLE hMPQ, LPCSTR lpSourceFileName, LPCSTR lpDestFileName, DWORD dwFlags, DWORD dwCompressionType, DWORD dwCompressLevel)
1696         if (!hMPQ || !lpSourceFileName || !lpDestFileName) {
1697                 SetLastError(ERROR_INVALID_PARAMETER);
1698                 return FALSE;
1699         }
1700         if (!*lpSourceFileName || !*lpDestFileName) {
1701                 SetLastError(ERROR_INVALID_PARAMETER);
1702                 return FALSE;
1703         }
1705         if (!(((MPQARCHIVE *)hMPQ)->dwFlags&SFILE_OPEN_ALLOW_WRITE)) {
1706                 SetLastError(ERROR_ACCESS_DENIED);
1707                 return FALSE;
1708         }
1709         BOOL ReplaceExisting;
1710         if (dwFlags&MAFA_REPLACE_EXISTING) {
1711                 dwFlags = dwFlags^MAFA_REPLACE_EXISTING;
1712                 ReplaceExisting = TRUE;
1713         }
1714         else ReplaceExisting = FALSE;
1715         MPQHANDLE hFile = GetFreeHashTableEntry(hMPQ,lpDestFileName,LocaleID,ReplaceExisting);
1716         if (!hFile) return FALSE;
1717         HANDLE haFile = CreateFile(lpSourceFileName,GENERIC_READ,FILE_SHARE_READ,0,OPEN_EXISTING,0,0);
1718         if (haFile==INVALID_HANDLE_VALUE) return FALSE;
1719         DWORD fsz = SFGetFileSize(haFile),tsz;
1720         DWORD ucfsz = fsz;
1721         BOOL IsBNcache = FALSE;char *buffer,*hbuffer;
1722         MPQARCHIVE *mpqOpenArc = (MPQARCHIVE *)hMPQ;
1723         DWORD blockSize = 512 << mpqOpenArc->MpqHeader.wBlockSize;
1724         DWORD TotalBlocks = fsz / blockSize;
1725         if(fsz % blockSize)
1726                 TotalBlocks++;
1727         DWORD ptsz = 0;
1728         if (dwFlags&MAFA_COMPRESS || dwFlags&MAFA_COMPRESS2) ptsz = (TotalBlocks+1)*4;
1729         if (memcmp(&mpqOpenArc->MpqHeader.dwMPQID,ID_BN3,4)==0)
1730         {
1731                 IsBNcache = TRUE;
1732                 hbuffer = (char *)SFAlloc(fsz+324+ptsz);
1733                 if (!hbuffer) {
1734                         CloseHandle(haFile);
1735                         return FALSE;
1736                 }
1737                 hbuffer[0] = (char)0x44;
1738                 hbuffer[1] = (char)0x01;
1739                 DWORD lpFileNameLength = strlen(lpDestFileName);
1740                 if (lpFileNameLength<=260) memcpy(hbuffer+64,lpDestFileName,lpFileNameLength);
1741                 else strncpy(hbuffer+64,lpDestFileName,260);
1742                 buffer = hbuffer+324;
1743         }
1744         else buffer = (char *)SFAlloc(fsz+ptsz);
1745         if (!buffer && fsz!=0) {
1746                 CloseHandle(haFile);
1747                 return FALSE;
1748         }
1749         if (fsz!=0) {
1750                 if (ReadFile(haFile,buffer,fsz,&tsz,0)==0) {
1751                         SFFree(buffer);
1752                         CloseHandle(haFile);
1753                         return FALSE;
1754                 }
1755         }
1756         else {
1757                 if (dwFlags&MAFA_COMPRESS) dwFlags = dwFlags^MAFA_COMPRESS;
1758                 if (dwFlags&MAFA_COMPRESS2) dwFlags = dwFlags^MAFA_COMPRESS2;
1759                 if (dwFlags&MAFA_ENCRYPT) dwFlags = dwFlags^MAFA_ENCRYPT;
1760                 if (dwFlags&MAFA_MODCRYPTKEY) dwFlags = dwFlags^MAFA_MODCRYPTKEY;
1761         }
1762         CloseHandle(haFile);
1763         DWORD i;
1764         DWORD *dwBlkpt = (DWORD *)SFAlloc((TotalBlocks+1)*4);
1765         if (!dwBlkpt) {
1766                 SFFree(buffer);
1767                 return FALSE;
1768         }
1769         if ((dwFlags & MAFA_COMPRESS) || (dwFlags & MAFA_COMPRESS2))
1770         {
1771                 DWORD dwCompressionSubType = 0;
1773                 if ((dwCompressionType&0x40 || dwCompressionType&0x80) && (memcmp(buffer,ID_RIFF,4)!=0 || memcmp(buffer+8,ID_WAVE,8)!=0 || buffer[20]!=1 || buffer[34]!=16)) {
1774                         dwCompressionType = 0x08;
1775                         dwCompressLevel = 0;
1776                 }
1777                 if (dwCompressionType&0x40 || dwCompressionType&0x80) {
1778                         switch (dwCompressLevel) {
1779                                 case MAWA_QUALITY_HIGH:
1780                                         dwCompressLevel = 1;
1781                                         break;
1782                                 case MAWA_QUALITY_LOW:
1783                                         dwCompressLevel = 3;
1784                                         break;
1785                                 default:
1786                                         dwCompressLevel = 0;
1787                         }
1788                 }
1789                 else if (dwCompressionType&0x01 || dwCompressionType&0x08 || ((dwFlags & MAFA_COMPRESS)!=MAFA_COMPRESS && (dwFlags & MAFA_COMPRESS2)==MAFA_COMPRESS2)) {
1790                         dwCompressionSubType = dwCompressLevel;
1791                         dwCompressLevel = 0;
1792                 }
1793                 else if (dwCompressionType&0x02) {
1794                         dwCompressionSubType = 1;
1795                 }
1797                 DWORD LastOffset=ptsz;
1798                 BYTE *compbuffer = (BYTE *)SFAlloc(blockSize);
1799                 if (!compbuffer) {
1800                         SFFree(dwBlkpt);
1801                         SFFree(buffer);
1802                         return FALSE;
1803                 }
1804                 char *outbuffer = (char *)SFAlloc(blockSize);
1805                 if (!outbuffer) {
1806                         SFFree(compbuffer);
1807                         SFFree(dwBlkpt);
1808                         SFFree(buffer);
1809                         return FALSE;
1810                 }
1811                 char *newbuffer = (char *)SFAlloc(fsz+ptsz);
1812                 if (!newbuffer) {
1813                         SFFree(outbuffer);
1814                         SFFree(compbuffer);
1815                         SFFree(dwBlkpt);
1816                         SFFree(buffer);
1817                         return FALSE;
1818                 }
1819                 DWORD CurPos=0;
1820                 for (i=0;i<TotalBlocks;i++) {
1821                         dwBlkpt[i] = LastOffset;
1822                         if (i==TotalBlocks-1 && (ucfsz % blockSize)!=0) blockSize=ucfsz % blockSize;
1823                         DWORD outLength=blockSize;
1824                         BYTE *compdata = compbuffer;
1825                         char *oldoutbuffer = outbuffer;
1826                         if (dwFlags & MAFA_COMPRESS)
1827                         {
1828                                 memcpy(compdata,(char *)buffer+CurPos,blockSize);
1829                                 if (i==0 && (dwCompressionType&0x40 || dwCompressionType&0x80)) {
1830                                         if (SCompCompress(outbuffer, &outLength, compdata, blockSize, 0x08, 0, 0)==0)
1831                                                 outLength=blockSize;
1832                                 }
1833                                 else
1834                                 {
1835                                         if (dwCompressionType&UNSUPPORTED_COMPRESSION) {
1836                                                 LoadStorm();
1837                                                 if (stormSCompCompress) {
1838                                                         if (stormSCompCompress(outbuffer, &outLength, compdata, blockSize, dwCompressionType, dwCompressionSubType, dwCompressLevel)==0)
1839                                                                 outLength=blockSize;
1840                                                 }
1841                                         }
1842                                         else {
1843                                                 if (SCompCompress(outbuffer, &outLength, compdata, blockSize, dwCompressionType, dwCompressionSubType, dwCompressLevel)==0)
1844                                                         outLength=blockSize;
1845                                         }
1846                                 }
1847                         }
1848                         else if (dwFlags & MAFA_COMPRESS2)
1849                         {
1850                                 memcpy(compdata,(char *)buffer+CurPos,blockSize);
1851                                 if (SCompCompress(outbuffer, &outLength, compdata, blockSize, 0x08, dwCompressionSubType, 0)==0) {
1852                                         outLength=blockSize;
1853                                 }
1854                                 else {
1855                                         outbuffer++;
1856                                         outLength--;
1857                                 }
1858                         }
1859                         else
1860                         {
1861                                 memcpy(compdata,(char *)buffer+CurPos,blockSize);
1862                         }
1863                         if (outLength>=blockSize)
1864                         {
1865                                 memcpy((char *)newbuffer+LastOffset,compdata,blockSize);
1866                                 LastOffset+=blockSize;
1867                         }
1868                         else {
1869                                 memcpy((char *)newbuffer+LastOffset,outbuffer,outLength);
1870                                 LastOffset+=outLength;
1871                         }
1872                         outbuffer = oldoutbuffer;
1873                         CurPos += blockSize;
1874                 }
1875                 fsz = LastOffset;
1876                 dwBlkpt[TotalBlocks] = fsz;
1877                 memcpy(newbuffer,dwBlkpt,ptsz);
1879                 SFFree(outbuffer);
1880                 SFFree(compbuffer);
1881                 memcpy(buffer,newbuffer,fsz);
1882                 SFFree(newbuffer);
1883         }
1884         else
1885         {
1886                 for (i=0;i<TotalBlocks+1;i++) {
1887                         if (i<TotalBlocks) dwBlkpt[i] = i * blockSize;
1888                         else dwBlkpt[i] = ucfsz;
1889                 }
1890         }
1891         if (IsBNcache==TRUE)
1892         {
1893                 buffer = hbuffer;
1894                 fsz += 324;
1895         }
1896         HASHTABLEENTRY *hashEntry = (HASHTABLEENTRY *)hFile;
1897         BOOL IsNewBlockEntry = FALSE;DWORD OldBlockTableSize = sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize;
1898         if ((hashEntry->dwBlockTableIndex&0xFFFFFFFE)==0xFFFFFFFE)
1899         {
1900                 BLOCKTABLEENTRY *lpnBlockTable;
1901                 lpnBlockTable = (BLOCKTABLEENTRY *)SFAlloc((sizeof(BLOCKTABLEENTRY) + sizeof(UInt16)) * (mpqOpenArc->MpqHeader.dwBlockTableSize + 1));
1902                 if(!lpnBlockTable) {
1903                         SFFree(buffer);
1904                         return FALSE;
1905                 }
1906                 if (mpqOpenArc->lpBlockTable) {
1907                         memcpy(lpnBlockTable,mpqOpenArc->lpBlockTable,sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize);
1908                         memcpy(lpnBlockTable + mpqOpenArc->MpqHeader.dwBlockTableSize + 1, mpqOpenArc->lpFileOffsetsHigh, sizeof(UInt16) * mpqOpenArc->MpqHeader.dwBlockTableSize);
1909                 }
1910                 mpqOpenArc->MpqHeader.dwBlockTableSize++;
1911                 if (mpqOpenArc->lpBlockTable) SFFree(mpqOpenArc->lpBlockTable);
1912                 mpqOpenArc->lpBlockTable = lpnBlockTable;
1913                 mpqOpenArc->lpFileOffsetsHigh = (UInt16 *)(mpqOpenArc->lpBlockTable + mpqOpenArc->MpqHeader.dwBlockTableSize);
1914                 IsNewBlockEntry = TRUE;
1915         }
1916         DWORD BlockIndex = mpqOpenArc->MpqHeader.dwBlockTableSize - 1;
1917         if ((hashEntry->dwBlockTableIndex&0xFFFFFFFE)==0xFFFFFFFE)
1918         {
1919                 hashEntry->dwNameHashA = HashString(lpDestFileName,HASH_NAME_A);
1920                 hashEntry->dwNameHashB = HashString(lpDestFileName,HASH_NAME_B);
1921                 hashEntry->lcLocale = LocaleID;
1922                 hashEntry->dwBlockTableIndex = BlockIndex;
1923                 mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset = 0;
1925         }
1926         else
1927         {
1928                 BlockIndex = hashEntry->dwBlockTableIndex;
1929         }
1930         if (mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset==0 || mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize<fsz)
1931         {
1932                 if (mpqOpenArc->MpqHeader.dwHashTableOffset+(mpqOpenArc->MpqHeader.dwHashTableSize * sizeof(HASHTABLEENTRY))+OldBlockTableSize==mpqOpenArc->MpqHeader.dwMPQSize)
1933                 {
1934                         if (mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset+mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize==mpqOpenArc->MpqHeader.dwHashTableOffset)
1935                         {
1936                                 mpqOpenArc->MpqHeader.dwHashTableOffset += fsz-mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize;
1937                                 mpqOpenArc->MpqHeader.dwBlockTableOffset += fsz-mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize;
1938                                 mpqOpenArc->MpqHeader.dwMPQSize += fsz-mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize;
1939                                 if (IsNewBlockEntry==TRUE) mpqOpenArc->MpqHeader.dwMPQSize += sizeof(BLOCKTABLEENTRY);
1940                         }
1941                         else
1942                         {
1943                                 mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset = mpqOpenArc->MpqHeader.dwHashTableOffset;
1944                                 mpqOpenArc->MpqHeader.dwHashTableOffset += fsz;
1945                                 mpqOpenArc->MpqHeader.dwBlockTableOffset += fsz;
1946                                 mpqOpenArc->MpqHeader.dwMPQSize += fsz;
1947                                 if (IsNewBlockEntry==TRUE) mpqOpenArc->MpqHeader.dwMPQSize += sizeof(BLOCKTABLEENTRY);
1948                         }
1949                 }
1950                 else if (mpqOpenArc->MpqHeader.dwBlockTableOffset+OldBlockTableSize==mpqOpenArc->MpqHeader.dwMPQSize)
1951                 {
1952                         if (mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset+mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize==mpqOpenArc->MpqHeader.dwBlockTableOffset)
1953                         {
1954                                 mpqOpenArc->MpqHeader.dwBlockTableOffset += fsz-mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize;
1955                                 mpqOpenArc->MpqHeader.dwMPQSize += fsz-mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize;
1956                                 if (IsNewBlockEntry==TRUE) mpqOpenArc->MpqHeader.dwMPQSize += sizeof(BLOCKTABLEENTRY);
1957                         }
1958                         else
1959                         {
1960                                 mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset = mpqOpenArc->MpqHeader.dwBlockTableOffset;
1961                                 mpqOpenArc->MpqHeader.dwBlockTableOffset += fsz;
1962                                 mpqOpenArc->MpqHeader.dwMPQSize += fsz;
1963                                 if (IsNewBlockEntry==TRUE) mpqOpenArc->MpqHeader.dwMPQSize += sizeof(BLOCKTABLEENTRY);
1964                         }
1965                 }
1966                 else
1967                 {
1968                         if (mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset+mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize==mpqOpenArc->MpqHeader.dwMPQSize)
1969                         {
1970                                 mpqOpenArc->MpqHeader.dwBlockTableOffset = mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset+fsz;
1971                                 mpqOpenArc->MpqHeader.dwMPQSize = mpqOpenArc->MpqHeader.dwBlockTableOffset+OldBlockTableSize;
1972                                 if (IsNewBlockEntry==TRUE) mpqOpenArc->MpqHeader.dwMPQSize += sizeof(BLOCKTABLEENTRY);
1973                         }
1974                         else
1975                         {
1976                                 mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset = mpqOpenArc->MpqHeader.dwMPQSize;
1977                                 mpqOpenArc->MpqHeader.dwBlockTableOffset = mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset+fsz;
1978                                 mpqOpenArc->MpqHeader.dwMPQSize = mpqOpenArc->MpqHeader.dwBlockTableOffset+OldBlockTableSize;
1979                                 if (IsNewBlockEntry==TRUE) mpqOpenArc->MpqHeader.dwMPQSize += sizeof(BLOCKTABLEENTRY);
1980                         }
1981                 }
1982         }
1983         mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize = fsz;
1984         mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize = ucfsz;
1985         mpqOpenArc->lpBlockTable[BlockIndex].dwFlags = dwFlags|MAFA_EXISTS;
1986         MpqWriteHeaders(mpqOpenArc);
1987         if (dwFlags & MAFA_ENCRYPT) {
1988                 DWORD dwCryptKey;
1989                 if (dwFlags&MAFA_ENCRYPT) dwCryptKey = HashString(lpDestFileName,HASH_KEY);
1990                 if (dwFlags&MAFA_MODCRYPTKEY) dwCryptKey = (dwCryptKey + mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset) ^ mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize;
1991                 DWORD blockSize = 512 << mpqOpenArc->MpqHeader.wBlockSize;
1992                 DWORD TotalBlocks = mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize / blockSize;
1993                 if(mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize % blockSize)
1994                         TotalBlocks++;
1995                 DWORD dwBlockEnd = mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize % blockSize;
1996                 if (dwBlockEnd==0) dwBlockEnd = blockSize;
1997                 if ((dwFlags & MAFA_COMPRESS)==MAFA_COMPRESS || (dwFlags & MAFA_COMPRESS2)==MAFA_COMPRESS2) {
1998                         EncryptData((LPBYTE)buffer,ptsz,dwCryptKey-1);
1999                 }
2000                 for (DWORD i=0;i<TotalBlocks;i++) {
2001                         EncryptData((LPBYTE)buffer+dwBlkpt[i],dwBlkpt[i+1]-dwBlkpt[i],dwCryptKey);
2002                         dwCryptKey++;
2003                 }
2004         }
2005         SFFree(dwBlkpt);
2006         SFSetFilePointer(mpqOpenArc->hFile, mpqOpenArc->qwMPQStart + MakeUInt64(mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset, mpqOpenArc->lpFileOffsetsHigh[BlockIndex]), FILE_BEGIN);
2007         WriteFile(mpqOpenArc->hFile,buffer,fsz,&tsz,0);
2008         SFFree(buffer);
2009         WriteHashTable(mpqOpenArc);
2010         WriteBlockTable(mpqOpenArc);
2011         AddToInternalListing(hMPQ,lpDestFileName);
2013         return TRUE;
2016 BOOL SFMPQAPI WINAPI MpqAddFileToArchive(MPQHANDLE hMPQ, LPCSTR lpSourceFileName, LPCSTR lpDestFileName, DWORD dwFlags)
2018         return MpqAddFileToArchiveEx(hMPQ,lpSourceFileName,lpDestFileName,dwFlags,0x08,0);
2021 BOOL SFMPQAPI WINAPI MpqAddWaveToArchive(MPQHANDLE hMPQ, LPCSTR lpSourceFileName, LPCSTR lpDestFileName, DWORD dwFlags, DWORD dwQuality)
2023         return MpqAddFileToArchiveEx(hMPQ,lpSourceFileName,lpDestFileName,dwFlags,0x81,dwQuality);
2026 BOOL SFMPQAPI WINAPI MpqAddFileFromBufferEx(MPQHANDLE hMPQ, LPVOID lpBuffer, DWORD dwLength, LPCSTR lpFileName, DWORD dwFlags, DWORD dwCompressionType, DWORD dwCompressLevel)
2028         if (!hMPQ || !lpBuffer || !lpFileName) {
2029                 SetLastError(ERROR_INVALID_PARAMETER);
2030                 return FALSE;
2031         }
2032         if (!*lpFileName) {
2033                 SetLastError(ERROR_INVALID_PARAMETER);
2034                 return FALSE;
2035         }
2037         if (!(((MPQARCHIVE *)hMPQ)->dwFlags&SFILE_OPEN_ALLOW_WRITE)) {
2038                 SetLastError(ERROR_ACCESS_DENIED);
2039                 return FALSE;
2040         }
2041         BOOL ReplaceExisting;
2042         if (dwFlags&MAFA_REPLACE_EXISTING) {
2043                 dwFlags = dwFlags^MAFA_REPLACE_EXISTING;
2044                 ReplaceExisting = TRUE;
2046         }
2047         else ReplaceExisting = FALSE;
2048         MPQHANDLE hFile = GetFreeHashTableEntry(hMPQ,lpFileName,LocaleID,ReplaceExisting);
2049         if (hFile==0) return FALSE;
2050         DWORD fsz = dwLength,tsz;
2051         DWORD ucfsz = fsz;
2052         BOOL IsBNcache = FALSE;char *buffer,*hbuffer;
2053         MPQARCHIVE *mpqOpenArc = (MPQARCHIVE *)hMPQ;
2054         DWORD blockSize = 512 << mpqOpenArc->MpqHeader.wBlockSize;
2055         DWORD TotalBlocks = fsz / blockSize;
2056         if(fsz % blockSize)
2057                 TotalBlocks++;
2058         DWORD ptsz = 0;
2059         if (dwFlags&MAFA_COMPRESS || dwFlags&MAFA_COMPRESS2) ptsz = (TotalBlocks+1)*4;
2060         if (memcmp(&mpqOpenArc->MpqHeader.dwMPQID,ID_BN3,4)==0)
2061         {
2062                 IsBNcache = TRUE;
2063                 hbuffer = (char *)SFAlloc(fsz+324+ptsz);
2064                 if (hbuffer==0) {
2065                         return FALSE;
2066                 }
2067                 hbuffer[0] = (char)0x44;
2068                 hbuffer[1] = (char)0x01;
2069                 DWORD lpFileNameLength = strlen(lpFileName);
2070                 if (lpFileNameLength<=260) memcpy(hbuffer+64,lpFileName,lpFileNameLength);
2071                 else strncpy(hbuffer+64,lpFileName,260);
2072                 buffer = hbuffer+324;
2073         }
2074         else buffer = (char *)SFAlloc(fsz+ptsz);
2075         if (buffer==0 && fsz!=0) {
2076                 return FALSE;
2077         }
2078         if (fsz!=0) memcpy(buffer,lpBuffer,fsz);
2079         else {
2080                 if (dwFlags&MAFA_COMPRESS) dwFlags = dwFlags^MAFA_COMPRESS;
2081                 if (dwFlags&MAFA_COMPRESS2) dwFlags = dwFlags^MAFA_COMPRESS2;
2082                 if (dwFlags&MAFA_ENCRYPT) dwFlags = dwFlags^MAFA_ENCRYPT;
2083                 if (dwFlags&MAFA_MODCRYPTKEY) dwFlags = dwFlags^MAFA_MODCRYPTKEY;
2084         }
2085         DWORD i;
2086         DWORD *dwBlkpt = (DWORD *)SFAlloc((TotalBlocks+1)*4);
2088         if (dwBlkpt==0) {
2089                 SFFree(buffer);
2090                 return FALSE;
2091         }
2092         if ((dwFlags & MAFA_COMPRESS)==MAFA_COMPRESS || (dwFlags & MAFA_COMPRESS2)==MAFA_COMPRESS2)
2093         {
2094                 DWORD dwCompressionSubType = 0;
2096                 if ((dwCompressionType&0x40 || dwCompressionType&0x80) && (memcmp(buffer,ID_RIFF,4)!=0 || memcmp(buffer+8,ID_WAVE,8)!=0 || buffer[20]!=1 || buffer[34]!=16)) {
2097                         dwCompressionType = 0x08;
2098                         dwCompressLevel = 0;
2099                 }
2100                 if (dwCompressionType&0x40 || dwCompressionType&0x80) {
2101                         switch (dwCompressLevel) {
2102                                 case MAWA_QUALITY_HIGH:
2103                                         dwCompressLevel = 1;
2104                                         break;
2105                                 case MAWA_QUALITY_LOW:
2106                                         dwCompressLevel = 3;
2107                                         break;
2108                                 default:
2109                                         dwCompressLevel = 0;
2110                         }
2111                 }
2112                 else if (dwCompressionType&0x01 || dwCompressionType&0x08 || ((dwFlags & MAFA_COMPRESS)!=MAFA_COMPRESS && (dwFlags & MAFA_COMPRESS2)==MAFA_COMPRESS2)) {
2113                         dwCompressionSubType = dwCompressLevel;
2114                         dwCompressLevel = 0;
2115                 }
2116                 else if (dwCompressionType&0x02) {
2117                         dwCompressionSubType = 1;
2118                 }
2120                 DWORD LastOffset=ptsz;
2121                 BYTE *compbuffer = (BYTE *)SFAlloc(blockSize);
2122                 if (compbuffer==0) {
2123                         SFFree(dwBlkpt);
2124                         SFFree(buffer);
2125                         return FALSE;
2126                 }
2128                 char *outbuffer = (char *)SFAlloc(blockSize);
2129                 if (outbuffer==0) {
2130                         SFFree(compbuffer);
2131                         SFFree(dwBlkpt);
2132                         SFFree(buffer);
2133                         return FALSE;
2134                 }
2135                 char *newbuffer = (char *)SFAlloc(fsz+ptsz);
2136                 if (newbuffer==0) {
2137                         SFFree(outbuffer);
2138                         SFFree(compbuffer);
2139                         SFFree(dwBlkpt);
2140                         SFFree(buffer);
2141                         return FALSE;
2142                 }
2143                 DWORD CurPos=0;
2144                 for (i=0;i<TotalBlocks;i++) {
2145                         dwBlkpt[i] = LastOffset;
2146                         if (i==TotalBlocks-1 && (ucfsz % blockSize)!=0) blockSize=ucfsz % blockSize;
2147                         DWORD outLength=blockSize;
2148                         BYTE *compdata = compbuffer;
2149                         if (dwFlags & MAFA_COMPRESS)
2150                         {
2151                                 memcpy(compdata,(char *)buffer+CurPos,blockSize);
2152                                 if (i==0 && (dwCompressionType&0x40 || dwCompressionType&0x80)) {
2153                                         if (SCompCompress(outbuffer, &outLength, compdata, blockSize, 0x08, 0, 0)==0)
2154                                                 outLength=blockSize;
2155                                 }
2156                                 else
2157                                 {
2158                                         if (dwCompressionType&UNSUPPORTED_COMPRESSION) {
2159                                                 LoadStorm();
2160                                                 if (stormSCompCompress!=0) {
2161                                                         if (stormSCompCompress(outbuffer, &outLength, compdata, blockSize, dwCompressionType, dwCompressionSubType, dwCompressLevel)==0)
2162                                                                 outLength=blockSize;
2163                                                 }
2164                                         }
2165                                         else {
2166                                                 if (SCompCompress(outbuffer, &outLength, compdata, blockSize, dwCompressionType, dwCompressionSubType, dwCompressLevel)==0)
2167                                                         outLength=blockSize;
2168                                         }
2169                                 }
2170                         }
2171                         else if (dwFlags & MAFA_COMPRESS2)
2172                         {
2173                                 memcpy(compdata,(char *)buffer+CurPos,blockSize);
2174                                 if (SCompCompress(outbuffer, &outLength, compdata, blockSize, 0x08, dwCompressionSubType, 0)==0) {
2175                                         outLength=blockSize;
2176                                 }
2177                                 else {
2178                                         outbuffer++;
2179                                         outLength--;
2180                                 }
2181                         }
2182                         else
2183                         {
2184                                 memcpy(compdata,(char *)buffer+CurPos,blockSize);
2185                         }
2186                         if (outLength>=blockSize)
2187                         {
2188                                 memcpy((char *)newbuffer+LastOffset,compdata,blockSize);
2189                                 LastOffset+=blockSize;
2190                         }
2191                         else {
2192                                 memcpy((char *)newbuffer+LastOffset,outbuffer,outLength);
2193                                 LastOffset+=outLength;
2194                         }
2195                         CurPos += blockSize;
2196                 }
2197                 fsz = LastOffset;
2198                 dwBlkpt[TotalBlocks] = fsz;
2199                 memcpy(newbuffer,dwBlkpt,ptsz);
2200                 SFFree(outbuffer);
2201                 SFFree(compbuffer);
2202                 memcpy(buffer,newbuffer,fsz);
2203                 SFFree(newbuffer);
2204         }
2205         else
2206         {
2207                 for (i=0;i<TotalBlocks+1;i++) {
2208                         if (i<TotalBlocks) dwBlkpt[i] = i * blockSize;
2209                         else dwBlkpt[i] = ucfsz;
2210                 }
2211         }
2212         if (IsBNcache==TRUE)
2213         {
2214                 buffer = hbuffer;
2215                 fsz += 324;
2216         }
2217         HASHTABLEENTRY *hashEntry = (HASHTABLEENTRY *)hFile;
2219         BOOL IsNewBlockEntry = FALSE;DWORD OldBlockTableSize = sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize;
2220         if ((hashEntry->dwBlockTableIndex&0xFFFFFFFE)==0xFFFFFFFE)
2221         {
2222                 BLOCKTABLEENTRY *lpnBlockTable;
2223                 lpnBlockTable = (BLOCKTABLEENTRY *)SFAlloc((sizeof(BLOCKTABLEENTRY) + sizeof(UInt16)) * (mpqOpenArc->MpqHeader.dwBlockTableSize + 1));
2224                 if(!lpnBlockTable) {
2225                         SFFree(buffer);
2226                         return FALSE;
2227                 }
2228                 if (mpqOpenArc->lpBlockTable) {
2229                         memcpy(lpnBlockTable,mpqOpenArc->lpBlockTable,sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize);
2230                         memcpy(lpnBlockTable + mpqOpenArc->MpqHeader.dwBlockTableSize + 1, mpqOpenArc->lpFileOffsetsHigh, sizeof(UInt16) * mpqOpenArc->MpqHeader.dwBlockTableSize);
2231                 }
2232                 mpqOpenArc->MpqHeader.dwBlockTableSize++;
2233                 if (mpqOpenArc->lpBlockTable) SFFree(mpqOpenArc->lpBlockTable);
2234                 mpqOpenArc->lpBlockTable = lpnBlockTable;
2235                 mpqOpenArc->lpFileOffsetsHigh = (UInt16 *)(mpqOpenArc->lpBlockTable + mpqOpenArc->MpqHeader.dwBlockTableSize);
2236                 IsNewBlockEntry = TRUE;
2237         }
2238         DWORD BlockIndex = mpqOpenArc->MpqHeader.dwBlockTableSize - 1;
2239         if ((hashEntry->dwBlockTableIndex&0xFFFFFFFE)==0xFFFFFFFE)
2240         {
2241                 hashEntry->dwNameHashA = HashString(lpFileName,HASH_NAME_A);
2242                 hashEntry->dwNameHashB = HashString(lpFileName,HASH_NAME_B);
2243                 hashEntry->lcLocale = LocaleID;
2244                 hashEntry->dwBlockTableIndex = BlockIndex;
2245                 mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset = 0;
2246         }
2247         else
2248         {
2249                 BlockIndex = hashEntry->dwBlockTableIndex;
2250         }
2251         if (mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset==0 || mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize<fsz)
2252         {
2253                 if (mpqOpenArc->MpqHeader.dwHashTableOffset+(mpqOpenArc->MpqHeader.dwHashTableSize * sizeof(HASHTABLEENTRY))+OldBlockTableSize==mpqOpenArc->MpqHeader.dwMPQSize)
2254                 {
2255                         if (mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset+mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize==mpqOpenArc->MpqHeader.dwHashTableOffset)
2256                         {
2257                                 mpqOpenArc->MpqHeader.dwHashTableOffset += fsz-mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize;
2258                                 mpqOpenArc->MpqHeader.dwBlockTableOffset += fsz-mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize;
2259                                 mpqOpenArc->MpqHeader.dwMPQSize += fsz-mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize;
2260                                 if (IsNewBlockEntry==TRUE) mpqOpenArc->MpqHeader.dwMPQSize += sizeof(BLOCKTABLEENTRY);
2261                         }
2262                         else
2263                         {
2264                                 mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset = mpqOpenArc->MpqHeader.dwHashTableOffset;
2265                                 mpqOpenArc->MpqHeader.dwHashTableOffset += fsz;
2266                                 mpqOpenArc->MpqHeader.dwBlockTableOffset += fsz;
2267                                 mpqOpenArc->MpqHeader.dwMPQSize += fsz;
2268                                 if (IsNewBlockEntry==TRUE) mpqOpenArc->MpqHeader.dwMPQSize += sizeof(BLOCKTABLEENTRY);
2269                         }
2270                 }
2271                 else if (mpqOpenArc->MpqHeader.dwBlockTableOffset+OldBlockTableSize==mpqOpenArc->MpqHeader.dwMPQSize)
2272                 {
2273                         if (mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset+mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize==mpqOpenArc->MpqHeader.dwBlockTableOffset)
2274                         {
2275                                 mpqOpenArc->MpqHeader.dwBlockTableOffset += fsz-mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize;
2276                                 mpqOpenArc->MpqHeader.dwMPQSize += fsz-mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize;
2277                                 if (IsNewBlockEntry==TRUE) mpqOpenArc->MpqHeader.dwMPQSize += sizeof(BLOCKTABLEENTRY);
2278                         }
2279                         else
2280                         {
2281                                 mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset = mpqOpenArc->MpqHeader.dwBlockTableOffset;
2282                                 mpqOpenArc->MpqHeader.dwBlockTableOffset += fsz;
2283                                 mpqOpenArc->MpqHeader.dwMPQSize += fsz;
2284                                 if (IsNewBlockEntry==TRUE) mpqOpenArc->MpqHeader.dwMPQSize += sizeof(BLOCKTABLEENTRY);
2285                         }
2286                 }
2287                 else
2288                 {
2289                         if (mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset+mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize==mpqOpenArc->MpqHeader.dwMPQSize)
2290                         {
2291                                 mpqOpenArc->MpqHeader.dwBlockTableOffset = mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset+fsz;
2292                                 mpqOpenArc->MpqHeader.dwMPQSize = mpqOpenArc->MpqHeader.dwBlockTableOffset+OldBlockTableSize;
2293                                 if (IsNewBlockEntry==TRUE) mpqOpenArc->MpqHeader.dwMPQSize += sizeof(BLOCKTABLEENTRY);
2294                         }
2295                         else
2296                         {
2297                                 mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset = mpqOpenArc->MpqHeader.dwMPQSize;
2298                                 mpqOpenArc->MpqHeader.dwBlockTableOffset = mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset+fsz;
2299                                 mpqOpenArc->MpqHeader.dwMPQSize = mpqOpenArc->MpqHeader.dwBlockTableOffset+OldBlockTableSize;
2300                                 if (IsNewBlockEntry==TRUE) mpqOpenArc->MpqHeader.dwMPQSize += sizeof(BLOCKTABLEENTRY);
2301                         }
2302                 }
2303         }
2304         mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize = fsz;
2305         mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize = ucfsz;
2306         mpqOpenArc->lpBlockTable[BlockIndex].dwFlags = dwFlags|MAFA_EXISTS;
2307         MpqWriteHeaders(mpqOpenArc);
2308         if (dwFlags & MAFA_ENCRYPT) {
2309                 DWORD dwCryptKey;
2310                 if (dwFlags&MAFA_ENCRYPT) dwCryptKey = HashString(lpFileName,HASH_KEY);
2311                 if (dwFlags&MAFA_MODCRYPTKEY) dwCryptKey = (dwCryptKey + mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset) ^ mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize;
2312                 DWORD blockSize = 512 << mpqOpenArc->MpqHeader.wBlockSize;
2313                 DWORD TotalBlocks = mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize / blockSize;
2315                 if(mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize % blockSize)
2316                         TotalBlocks++;
2317                 DWORD dwBlockEnd = mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize % blockSize;
2318                 if (dwBlockEnd==0) dwBlockEnd = blockSize;
2319                 if ((dwFlags & MAFA_COMPRESS)==MAFA_COMPRESS || (dwFlags & MAFA_COMPRESS2)==MAFA_COMPRESS2) {
2320                         EncryptData((LPBYTE)buffer,ptsz,dwCryptKey-1);
2321                 }
2322                 for (DWORD i=0;i<TotalBlocks;i++) {
2323                         EncryptData((LPBYTE)buffer+dwBlkpt[i],dwBlkpt[i+1]-dwBlkpt[i],dwCryptKey);
2324                         dwCryptKey++;
2325                 }
2326         }
2327         SFFree(dwBlkpt);
2328         SFSetFilePointer(mpqOpenArc->hFile, mpqOpenArc->qwMPQStart + MakeUInt64(mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset, mpqOpenArc->lpFileOffsetsHigh[BlockIndex]), FILE_BEGIN);
2329         WriteFile(mpqOpenArc->hFile,buffer,fsz,&tsz,0);
2330         SFFree(buffer);
2331         WriteHashTable(mpqOpenArc);
2332         WriteBlockTable(mpqOpenArc);
2333         AddToInternalListing(hMPQ,lpFileName);
2334         return TRUE;
2337 BOOL SFMPQAPI WINAPI MpqAddFileFromBuffer(MPQHANDLE hMPQ, LPVOID lpBuffer, DWORD dwLength, LPCSTR lpFileName, DWORD dwFlags)
2339         return MpqAddFileFromBufferEx(hMPQ,lpBuffer,dwLength,lpFileName,dwFlags,0x08,0);
2342 BOOL SFMPQAPI WINAPI MpqAddWaveFromBuffer(MPQHANDLE hMPQ, LPVOID lpBuffer, DWORD dwLength, LPCSTR lpFileName, DWORD dwFlags, DWORD dwQuality)
2344         return MpqAddFileFromBufferEx(hMPQ,lpBuffer,dwLength,lpFileName,dwFlags,0x81,dwQuality);
2347 BOOL SFMPQAPI WINAPI MpqRenameFile(MPQHANDLE hMPQ, LPCSTR lpcOldFileName, LPCSTR lpcNewFileName)
2349         return MpqRenameAndSetFileLocale(hMPQ,lpcOldFileName,lpcNewFileName,LocaleID,LocaleID);
2352 BOOL SFMPQAPI WINAPI MpqRenameAndSetFileLocale(MPQHANDLE hMPQ, LPCSTR lpcOldFileName, LPCSTR lpcNewFileName, LCID nOldLocale, LCID nNewLocale)
2354         if (!hMPQ || !lpcOldFileName || !lpcNewFileName) {
2355                 SetLastError(ERROR_INVALID_PARAMETER);
2356                 return FALSE;
2357         }
2358         if (!*lpcNewFileName) {
2359                 SetLastError(ERROR_INVALID_PARAMETER);
2360                 return FALSE;
2361         }
2363         if (!(((MPQARCHIVE *)hMPQ)->dwFlags&SFILE_OPEN_ALLOW_WRITE)) {
2364                 SetLastError(ERROR_ACCESS_DENIED);
2365                 return FALSE;
2366         }
2367         if (stricmp(lpcOldFileName,lpcNewFileName)==0) {
2368                 SetLastError(ERROR_INVALID_PARAMETER);
2369                 return FALSE;
2370         }
2371         MPQARCHIVE *mpqOpenArc = (MPQARCHIVE *)hMPQ;
2372         HASHTABLEENTRY *oldHashEntry = (HASHTABLEENTRY *)GetHashTableEntry(hMPQ,lpcOldFileName,nOldLocale);
2373         if (oldHashEntry==0) {
2374                 SetLastError(MPQ_ERROR_FILE_NOT_FOUND);
2375                 return FALSE;
2376         }
2377         if (oldHashEntry->lcLocale!=nOldLocale) {
2378                 SetLastError(MPQ_ERROR_FILE_NOT_FOUND);
2379                 return FALSE;
2380         }
2381         HASHTABLEENTRY *newHashEntry = (HASHTABLEENTRY *)GetFreeHashTableEntry(hMPQ,lpcNewFileName,nNewLocale,TRUE);
2382         if ((newHashEntry->dwBlockTableIndex&0xFFFFFFFE)!=0xFFFFFFFE)
2383                 return FALSE;
2384         if (newHashEntry==0) newHashEntry = oldHashEntry;
2385         DWORD tsz;
2386         newHashEntry->dwNameHashA = HashString(lpcNewFileName,HASH_NAME_A);
2387         newHashEntry->dwNameHashB = HashString(lpcNewFileName,HASH_NAME_B);
2388         newHashEntry->lcLocale = nNewLocale;
2389         newHashEntry->dwBlockTableIndex = oldHashEntry->dwBlockTableIndex;
2390         DWORD BlockIndex = oldHashEntry->dwBlockTableIndex;
2391         if (mpqOpenArc->lpBlockTable[BlockIndex].dwFlags & MAFA_ENCRYPT)
2392         {
2393                 DWORD dwOldCryptKey = HashString(lpcOldFileName,HASH_KEY);
2394                 DWORD dwNewCryptKey = HashString(lpcNewFileName,HASH_KEY);
2395                 if (mpqOpenArc->lpBlockTable[BlockIndex].dwFlags & MAFA_MODCRYPTKEY) {
2396                         dwOldCryptKey = (dwOldCryptKey + mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset) ^ mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize;
2398                         dwNewCryptKey = (dwNewCryptKey + mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset) ^ mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize;
2399                 }
2400                 if (dwOldCryptKey!=dwNewCryptKey)
2401                 {
2402                         DWORD HeaderLength=0;
2403                         if (memcmp(&mpqOpenArc->MpqHeader.dwMPQID,ID_BN3,4)==0)
2404                         {
2405                                 SFSetFilePointer(mpqOpenArc->hFile, mpqOpenArc->qwMPQStart + MakeUInt64(mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset, mpqOpenArc->lpFileOffsetsHigh[BlockIndex]), FILE_BEGIN);
2406                                 ReadFile(mpqOpenArc->hFile,&HeaderLength,4,&tsz,0);
2408                         }
2409                         DWORD blockSize = 512 << mpqOpenArc->MpqHeader.wBlockSize;
2410                         DWORD TotalBlocks = mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize / blockSize;
2411                         if(mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize % blockSize)
2412                                 TotalBlocks++;
2413                         DWORD *dwBlockPtrTable = (DWORD *)SFAlloc((TotalBlocks+1)*4);
2414                         if (dwBlockPtrTable==0) {
2415                                 return FALSE;
2416                         }
2417                         DWORD i;
2418                         if ((mpqOpenArc->lpBlockTable[BlockIndex].dwFlags & MAFA_COMPRESS)==MAFA_COMPRESS || (mpqOpenArc->lpBlockTable[BlockIndex].dwFlags & MAFA_COMPRESS2)==MAFA_COMPRESS2)
2419                         {
2420                                 SFSetFilePointer(mpqOpenArc->hFile, mpqOpenArc->qwMPQStart + MakeUInt64(mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset, mpqOpenArc->lpFileOffsetsHigh[BlockIndex]) + HeaderLength, FILE_BEGIN);
2421                                 ReadFile(mpqOpenArc->hFile,dwBlockPtrTable,(TotalBlocks+1)*4,&tsz,0);
2422                                 DecryptData((LPBYTE)dwBlockPtrTable,(TotalBlocks+1)*4,dwOldCryptKey-1);
2423                                 char *EncryptedTable = (char *)SFAlloc((TotalBlocks+1)*4);
2424                                 if (EncryptedTable==0) {
2425                                         SFFree(dwBlockPtrTable);
2426                                         return FALSE;
2427                                 }
2428                                 memcpy(EncryptedTable,dwBlockPtrTable,(TotalBlocks+1)*4);
2429                                 EncryptData((LPBYTE)EncryptedTable,(TotalBlocks+1)*4,dwNewCryptKey-1);
2430                                 SFSetFilePointer(mpqOpenArc->hFile, mpqOpenArc->qwMPQStart + MakeUInt64(mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset, mpqOpenArc->lpFileOffsetsHigh[BlockIndex]) + HeaderLength, FILE_BEGIN);
2431                                 WriteFile(mpqOpenArc->hFile,EncryptedTable,(TotalBlocks+1)*4,&tsz,0);
2432                                 SFFree(EncryptedTable);
2433                         }
2434                         else
2435                         {
2436                                 for (i=0;i<TotalBlocks+1;i++) {
2437                                         if (i<TotalBlocks) dwBlockPtrTable[i] = i * blockSize;
2438                                         else dwBlockPtrTable[i] = mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize;
2439                                 }
2440                         }
2441                         char *blkBuffer = (char *)SFAlloc(blockSize);
2442                         if (blkBuffer==0) {
2443                                 EncryptData((LPBYTE)dwBlockPtrTable,(TotalBlocks+1)*4,dwOldCryptKey-1);
2444                                 SFSetFilePointer(mpqOpenArc->hFile, mpqOpenArc->qwMPQStart + MakeUInt64(mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset, mpqOpenArc->lpFileOffsetsHigh[BlockIndex]) + HeaderLength, FILE_BEGIN);
2445                                 WriteFile(mpqOpenArc->hFile,dwBlockPtrTable,(TotalBlocks+1)*4,&tsz,0);
2446                                 SFFree(dwBlockPtrTable);
2447                                 return FALSE;
2448                         }
2449                         for (i=0;i<TotalBlocks;i++) {
2450                                 SFSetFilePointer(mpqOpenArc->hFile, mpqOpenArc->qwMPQStart + MakeUInt64(mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset, mpqOpenArc->lpFileOffsetsHigh[BlockIndex]) + HeaderLength + dwBlockPtrTable[i], FILE_BEGIN);
2451                                 if (ReadFile(mpqOpenArc->hFile,blkBuffer,dwBlockPtrTable[i+1]-dwBlockPtrTable[i],&tsz,0)==0) {
2452                                         EncryptData((LPBYTE)dwBlockPtrTable,(TotalBlocks+1)*4,dwOldCryptKey-1);
2453                                         SFSetFilePointer(mpqOpenArc->hFile, mpqOpenArc->qwMPQStart + MakeUInt64(mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset, mpqOpenArc->lpFileOffsetsHigh[BlockIndex]) + HeaderLength, FILE_BEGIN);
2454                                         WriteFile(mpqOpenArc->hFile,dwBlockPtrTable,(TotalBlocks+1)*4,&tsz,0);
2455                                         SFFree(dwBlockPtrTable);
2456                                         SFFree(blkBuffer);
2457                                         return FALSE;
2458                                 }
2459                                 DecryptData((LPBYTE)blkBuffer,dwBlockPtrTable[i+1]-dwBlockPtrTable[i],dwOldCryptKey+i);
2460                                 EncryptData((LPBYTE)blkBuffer,dwBlockPtrTable[i+1]-dwBlockPtrTable[i],dwNewCryptKey+i);
2461                                 SFSetFilePointer(mpqOpenArc->hFile, mpqOpenArc->qwMPQStart + MakeUInt64(mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset, mpqOpenArc->lpFileOffsetsHigh[BlockIndex]) + HeaderLength + dwBlockPtrTable[i], FILE_BEGIN);
2462                                 WriteFile(mpqOpenArc->hFile,blkBuffer,dwBlockPtrTable[i+1]-dwBlockPtrTable[i],&tsz,0);
2463                         }
2464                         SFFree(dwBlockPtrTable);
2465                         SFFree(blkBuffer);
2466                 }
2467         }
2468         if (oldHashEntry!=newHashEntry) {
2469                 oldHashEntry->dwNameHashA = 0xFFFFFFFF;
2470                 oldHashEntry->dwNameHashB = 0xFFFFFFFF;
2471                 oldHashEntry->lcLocale = 0xFFFFFFFF;
2472                 oldHashEntry->dwBlockTableIndex = 0xFFFFFFFE;
2473                 WriteHashTable(mpqOpenArc);
2474         }
2475         LCID dwOldLocale=LocaleID;
2476         LocaleID=nOldLocale;
2477         RemoveFromInternalListing(hMPQ,lpcOldFileName);
2479         LocaleID=nNewLocale;
2480         AddToInternalListing(hMPQ,lpcNewFileName);
2481         LocaleID=dwOldLocale;
2482         return TRUE;
2485 BOOL SFMPQAPI WINAPI MpqDeleteFile(MPQHANDLE hMPQ, LPCSTR lpFileName)
2487         return MpqDeleteFileWithLocale(hMPQ,lpFileName,LocaleID);
2490 BOOL SFMPQAPI WINAPI MpqDeleteFileWithLocale(MPQHANDLE hMPQ, LPCSTR lpFileName, LCID nLocale)
2492         if (!hMPQ || !lpFileName) {
2493                 SetLastError(ERROR_INVALID_PARAMETER);
2494                 return FALSE;
2495         }
2497         if (!(((MPQARCHIVE *)hMPQ)->dwFlags&SFILE_OPEN_ALLOW_WRITE)) {
2499                 SetLastError(ERROR_ACCESS_DENIED);
2500                 return FALSE;
2501         }
2502         MPQARCHIVE *mpqOpenArc = (MPQARCHIVE *)hMPQ;
2503         HASHTABLEENTRY *hashEntry = (HASHTABLEENTRY *)GetHashTableEntry(hMPQ,lpFileName,nLocale);
2504         if (hashEntry==0) {
2505                 SetLastError(MPQ_ERROR_FILE_NOT_FOUND);
2506                 return FALSE;
2507         }
2508         if (hashEntry->lcLocale!=nLocale) return FALSE;
2509         hashEntry->dwNameHashA = 0xFFFFFFFF;
2510         hashEntry->dwNameHashB = 0xFFFFFFFF;
2511         hashEntry->lcLocale = 0xFFFFFFFF;
2512         hashEntry->dwBlockTableIndex = 0xFFFFFFFE;
2513         WriteHashTable(mpqOpenArc);
2514         LCID dwOldLocale=LocaleID;
2515         LocaleID=nLocale;
2516         RemoveFromInternalListing(hMPQ,lpFileName);
2517         LocaleID=dwOldLocale;
2518         return TRUE;
2521 BOOL SFMPQAPI WINAPI MpqCompactArchive(MPQHANDLE hMPQ)
2523         if (!hMPQ) {
2524                 SetLastError(ERROR_INVALID_PARAMETER);
2525                 return FALSE;
2526         }
2528         if (!(((MPQARCHIVE *)hMPQ)->dwFlags&SFILE_OPEN_ALLOW_WRITE)) {
2529                 SetLastError(ERROR_ACCESS_DENIED);
2530                 return FALSE;
2531         }
2532         MPQARCHIVE *mpqOpenArc = (MPQARCHIVE *)hMPQ;
2533         TempAlloc NewAlloc;
2534         char *lpFileName = (char *)NewAlloc.Alloc(strlen(mpqOpenArc->lpFileName)+13);
2535         sprintf(lpFileName,"%s.compact",mpqOpenArc->lpFileName);
2536         HANDLE hFile = CreateFile(lpFileName,GENERIC_READ|GENERIC_WRITE,0,0,CREATE_NEW,0,0);
2537         UInt64 i;
2538         if (hFile==INVALID_HANDLE_VALUE) {
2539                 for (i=0;i<10000;i++) {
2540                         sprintf(lpFileName,"%s.compact.%04ld",mpqOpenArc->lpFileName,i);
2542                         hFile = CreateFile(lpFileName,GENERIC_READ|GENERIC_WRITE,0,0,CREATE_NEW,0,0);
2543                         if (hFile!=INVALID_HANDLE_VALUE) break;
2544                 }
2545                 if (i==10000) return FALSE;
2546         }
2547         UInt64 qwLastOffset = mpqOpenArc->dwHeaderSize;
2548         DWORD tsz;
2549         char *buffer = (char *)SFAlloc(65536);
2550         if (buffer==0) {
2551                 CloseHandle(hFile);
2552                 DeleteFile(lpFileName);
2553                 return FALSE;
2554         }
2555         HASHTABLEENTRY *lpHashTable = (HASHTABLEENTRY *)SFAlloc(sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize);
2556         if (lpHashTable==0) {
2557                 SFFree(buffer);
2558                 CloseHandle(hFile);
2559                 DeleteFile(lpFileName);
2560                 return FALSE;
2561         }
2562         BLOCKTABLEENTRY *lpBlockTable = (BLOCKTABLEENTRY *)SFAlloc((sizeof(BLOCKTABLEENTRY) + sizeof(UInt16)) * mpqOpenArc->MpqHeader.dwBlockTableSize);
2563         UInt16 *lpdwFileOffsetsHigh = (UInt16 *)(lpBlockTable + mpqOpenArc->MpqHeader.dwBlockTableSize);
2564         if(mpqOpenArc->lpBlockTable!=0) {
2565                 if (lpBlockTable==0) {
2566                         SFFree(lpHashTable);
2567                         SFFree(buffer);
2568                         CloseHandle(hFile);
2569                         DeleteFile(lpFileName);
2571                         return FALSE;
2572                 }
2573         }
2574         DWORD j=0,nBlkOffset=0,ReadSize=0;
2575         memcpy(lpHashTable,mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize);
2576         for (i=0;i<mpqOpenArc->MpqHeader.dwBlockTableSize;i++) {
2577                 for (j=0;j<mpqOpenArc->MpqHeader.dwHashTableSize;j++) {
2578                         if (lpHashTable[j].dwBlockTableIndex==(i-nBlkOffset)) break;
2579                 }
2580                 if (j<mpqOpenArc->MpqHeader.dwHashTableSize) {
2581                         memcpy(&lpBlockTable[i-nBlkOffset],&mpqOpenArc->lpBlockTable[i],sizeof(BLOCKTABLEENTRY));
2582                         SplitUInt64(lpBlockTable[i-nBlkOffset].dwFileOffset, lpdwFileOffsetsHigh[i-nBlkOffset], qwLastOffset);
2583                         qwLastOffset += mpqOpenArc->lpBlockTable[i].dwCompressedSize;
2584                         DWORD dwWritten=FALSE;
2585                         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))
2586                         {
2587                                 DWORD HeaderLength=0;
2588                                 if (memcmp(&mpqOpenArc->MpqHeader.dwMPQID,ID_BN3,4)==0)
2589                                 {
2590                                         SFSetFilePointer(mpqOpenArc->hFile, mpqOpenArc->qwMPQStart + MakeUInt64(mpqOpenArc->lpBlockTable[i].dwFileOffset, mpqOpenArc->lpFileOffsetsHigh[i]), FILE_BEGIN);
2591                                         ReadFile(mpqOpenArc->hFile,&HeaderLength,4,&tsz,0);
2592                                 }
2593                                 DWORD blockSize = 512 << mpqOpenArc->MpqHeader.wBlockSize;
2594                                 DWORD TotalBlocks = mpqOpenArc->lpBlockTable[i].dwFullSize / blockSize;
2595                                 if(mpqOpenArc->lpBlockTable[i].dwFullSize % blockSize)
2596                                         TotalBlocks++;
2597                                 DWORD *dwBlockPtrTable = (DWORD *)SFAlloc((TotalBlocks+1)*4);
2598                                 if (dwBlockPtrTable==0) {
2599                                         SFFree(lpBlockTable);
2600                                         SFFree(lpHashTable);
2601                                         SFFree(buffer);
2602                                         CloseHandle(hFile);
2603                                         DeleteFile(lpFileName);
2604                                         return FALSE;
2605                                 }
2606                                 SFSetFilePointer(mpqOpenArc->hFile, mpqOpenArc->qwMPQStart + MakeUInt64(mpqOpenArc->lpBlockTable[i].dwFileOffset, mpqOpenArc->lpFileOffsetsHigh[i]) + HeaderLength, FILE_BEGIN);
2607                                 ReadFile(mpqOpenArc->hFile,dwBlockPtrTable,(TotalBlocks+1)*4,&tsz,0);
2608                                 DWORD dwOldCryptKey = DetectFileSeed(dwBlockPtrTable,(TotalBlocks+1)*4,blockSize);
2609                                 DWORD dwNewCryptKey = (dwOldCryptKey ^ mpqOpenArc->lpBlockTable[i].dwFullSize) - mpqOpenArc->lpBlockTable[i].dwFileOffset;
2610                                 dwNewCryptKey = (dwNewCryptKey + lpBlockTable[i-nBlkOffset].dwFileOffset) ^ lpBlockTable[i-nBlkOffset].dwFullSize;
2611                                 if (dwOldCryptKey==0) {
2612                                         DWORD dwNameHashA = HashString(INTERNAL_LISTFILE,HASH_NAME_A);
2613                                         DWORD dwNameHashB = HashString(INTERNAL_LISTFILE,HASH_NAME_B);
2614                                         if (lpHashTable[j].dwNameHashA==dwNameHashA && lpHashTable[j].dwNameHashB==dwNameHashB) {
2615                                                 dwOldCryptKey = HashString(INTERNAL_LISTFILE,HASH_KEY);
2616                                                 dwNewCryptKey = dwOldCryptKey;
2617                                                 dwOldCryptKey = (dwOldCryptKey + mpqOpenArc->lpBlockTable[i].dwFileOffset) ^ mpqOpenArc->lpBlockTable[i].dwFullSize;
2618                                                 dwNewCryptKey = (dwNewCryptKey + lpBlockTable[i-nBlkOffset].dwFileOffset) ^ lpBlockTable[i-nBlkOffset].dwFullSize;
2619                                         }
2620                                         else {
2621                                                 HANDLE hlFile;
2622                                                 DWORD fsz;
2623                                                 char *listbuffer;
2624                                                 LCID lcOldLocale = LocaleID;
2625                                                 for (DWORD lcn=0;lcn<nLocales;lcn++) {
2626                                                         LocaleID = availLocales[lcn];
2627                                                         if (SFileOpenFileEx(hMPQ,INTERNAL_LISTFILE,0,&hlFile)!=0) {
2628                                                                 if (((MPQFILE *)hlFile)->lpHashEntry->lcLocale==0 && LocaleID!=0) {
2630                                                                         SFileCloseFile(hlFile);
2631                                                                         continue;
2632                                                                 }
2633                                                                 fsz = SFileGetFileSize(hlFile,0);
2634                                                                 if (fsz>0) {
2635                                                                         listbuffer = (char *)SFAlloc(fsz+1);
2636                                                                         if (listbuffer==0) {
2637                                                                                 SFileCloseFile(hlFile);
2638                                                                                 continue;
2639                                                                         }
2640                                                                         if (SFileReadFile(hlFile,listbuffer,fsz,0,0)==0) {
2641                                                                                 SFFree(listbuffer);
2642                                                                                 listbuffer = 0;
2643                                                                         }
2644                                                                 }
2645                                                                 SFileCloseFile(hlFile);
2646                                                                 if (listbuffer!=0) {
2647                                                                         char *listline;
2648                                                                         for (listline=listbuffer;listline!=0;listline=nextline(listline)) {
2649                                                                                 if (listline[0]==0) break;
2650                                                                                 DWORD lnlen=strlnlen(listline);
2651                                                                                 char prevchar=listline[lnlen];
2652                                                                                 listline[lnlen]=0;
2653                                                                                 dwNameHashA = HashString(listline,HASH_NAME_A);
2654                                                                                 dwNameHashB = HashString(listline,HASH_NAME_B);
2655                                                                                 if (lpHashTable[j].dwNameHashA==dwNameHashA && lpHashTable[j].dwNameHashB==dwNameHashB) {
2656                                                                                         dwOldCryptKey = HashString(listline,HASH_KEY);
2657                                                                                         dwNewCryptKey = dwOldCryptKey;
2658                                                                                         dwOldCryptKey = (dwOldCryptKey + mpqOpenArc->lpBlockTable[i].dwFileOffset) ^ mpqOpenArc->lpBlockTable[i].dwFullSize;
2659                                                                                         dwNewCryptKey = (dwNewCryptKey + lpBlockTable[i-nBlkOffset].dwFileOffset) ^ lpBlockTable[i-nBlkOffset].dwFullSize;
2660                                                                                         break;
2661                                                                                 }
2662                                                                                 listline[lnlen]=prevchar;
2663                                                                         }
2664                                                                         if (listline!=0) {
2665                                                                                 if (listline[0]!=0) {
2666                                                                                         SFFree(listbuffer);
2667                                                                                         break;
2668                                                                                 }
2669                                                                         }
2670                                                                         SFFree(listbuffer);
2671                                                                 }
2672                                                         }
2673                                                 }
2674                                                 LocaleID = lcOldLocale;
2675                                         }
2676                                 }
2677                                 if (dwOldCryptKey!=dwNewCryptKey)
2678                                 {
2679                                         DecryptData((LPBYTE)dwBlockPtrTable,(TotalBlocks+1)*4,dwOldCryptKey-1);
2680                                         char *EncryptedTable = (char *)SFAlloc((TotalBlocks+1)*4);
2681                                         if (EncryptedTable==0) {
2682                                                 SFFree(dwBlockPtrTable);
2683                                                 SFFree(lpBlockTable);
2684                                                 SFFree(lpHashTable);
2685                                                 SFFree(buffer);
2686                                                 CloseHandle(hFile);
2687                                                 DeleteFile(lpFileName);
2688                                                 return FALSE;
2689                                         }
2690                                         memcpy(EncryptedTable,dwBlockPtrTable,(TotalBlocks+1)*4);
2691                                         EncryptData((LPBYTE)EncryptedTable,(TotalBlocks+1)*4,dwNewCryptKey-1);
2692                                         SFSetFilePointer(hFile, MakeUInt64(lpBlockTable[i-nBlkOffset].dwFileOffset, lpdwFileOffsetsHigh[i-nBlkOffset]) + HeaderLength, FILE_BEGIN);
2693                                         WriteFile(hFile,EncryptedTable,(TotalBlocks+1)*4,&tsz,0);
2694                                         SFFree(EncryptedTable);
2695                                         char *blkBuffer = (char *)SFAlloc(blockSize);
2696                                         if (blkBuffer==0) {
2697                                                 SFFree(dwBlockPtrTable);
2698                                                 SFFree(lpBlockTable);
2699                                                 SFFree(lpHashTable);
2700                                                 SFFree(buffer);
2701                                                 CloseHandle(hFile);
2702                                                 DeleteFile(lpFileName);
2703                                                 return FALSE;
2704                                         }
2705                                         for (DWORD k=0;k<TotalBlocks;k++) {
2706                                                 SFSetFilePointer(mpqOpenArc->hFile, mpqOpenArc->qwMPQStart + MakeUInt64(mpqOpenArc->lpBlockTable[i].dwFileOffset, mpqOpenArc->lpFileOffsetsHigh[i]) + HeaderLength + dwBlockPtrTable[k], FILE_BEGIN);
2707                                                 if (ReadFile(mpqOpenArc->hFile,blkBuffer,dwBlockPtrTable[k+1]-dwBlockPtrTable[k],&tsz,0)==0) {
2708                                                         SFFree(dwBlockPtrTable);
2709                                                         SFFree(blkBuffer);
2710                                                         SFFree(lpBlockTable);
2711                                                         SFFree(lpHashTable);
2712                                                         SFFree(buffer);
2713                                                         CloseHandle(hFile);
2714                                                         DeleteFile(lpFileName);
2715                                                         return FALSE;
2716                                                 }
2717                                                 DecryptData((LPBYTE)blkBuffer,dwBlockPtrTable[k+1]-dwBlockPtrTable[k],dwOldCryptKey+k);
2718                                                 EncryptData((LPBYTE)blkBuffer,dwBlockPtrTable[k+1]-dwBlockPtrTable[k],dwNewCryptKey+k);
2719                                                 SFSetFilePointer(hFile, MakeUInt64(lpBlockTable[i-nBlkOffset].dwFileOffset, lpdwFileOffsetsHigh[i-nBlkOffset]) + HeaderLength + dwBlockPtrTable[k], FILE_BEGIN);
2720                                                 WriteFile(hFile,blkBuffer,dwBlockPtrTable[k+1]-dwBlockPtrTable[k],&tsz,0);
2721                                         }
2722                                         SFFree(blkBuffer);
2723                                         dwWritten = TRUE;
2724                                 }
2725                                 SFFree(dwBlockPtrTable);
2726                         }
2727                         else if (mpqOpenArc->lpBlockTable[i].dwFlags&MAFA_ENCRYPT && mpqOpenArc->lpBlockTable[i].dwFlags&MAFA_MODCRYPTKEY)
2728                         {
2729                                 DWORD HeaderLength=0;
2730                                 if (memcmp(&mpqOpenArc->MpqHeader.dwMPQID,ID_BN3,4)==0)
2732                                 {
2733                                         SFSetFilePointer(mpqOpenArc->hFile, mpqOpenArc->qwMPQStart + MakeUInt64(mpqOpenArc->lpBlockTable[i].dwFileOffset, mpqOpenArc->lpFileOffsetsHigh[i]), FILE_BEGIN);
2734                                         ReadFile(mpqOpenArc->hFile,&HeaderLength,4,&tsz,0);
2735                                 }
2736                                 DWORD blockSize = 512 << mpqOpenArc->MpqHeader.wBlockSize;
2737                                 DWORD TotalBlocks = mpqOpenArc->lpBlockTable[i].dwFullSize / blockSize;
2738                                 if(mpqOpenArc->lpBlockTable[i].dwFullSize % blockSize)
2739                                         TotalBlocks++;
2740                                 DWORD dwNameHashA = HashString(INTERNAL_LISTFILE,HASH_NAME_A);
2741                                 DWORD dwNameHashB = HashString(INTERNAL_LISTFILE,HASH_NAME_B);
2742                                 DWORD dwOldCryptKey=0;
2743                                 DWORD dwNewCryptKey=0;
2744                                 if (lpHashTable[j].dwNameHashA==dwNameHashA && lpHashTable[j].dwNameHashB==dwNameHashB) {
2745                                         dwOldCryptKey = HashString(INTERNAL_LISTFILE,HASH_KEY);
2746                                         dwNewCryptKey = dwOldCryptKey;
2747                                         dwOldCryptKey = (dwOldCryptKey + mpqOpenArc->lpBlockTable[i].dwFileOffset) ^ mpqOpenArc->lpBlockTable[i].dwFullSize;
2748                                         dwNewCryptKey = (dwNewCryptKey + lpBlockTable[i-nBlkOffset].dwFileOffset) ^ lpBlockTable[i-nBlkOffset].dwFullSize;
2749                                 }
2750                                 else {
2751                                         HANDLE hlFile;
2752                                         DWORD fsz;
2754                                         char *listbuffer;
2755                                         LCID lcOldLocale = LocaleID;
2756                                         for (DWORD lcn=0;lcn<nLocales;lcn++) {
2757                                                 LocaleID = availLocales[lcn];
2758                                                 if (SFileOpenFileEx(hMPQ,INTERNAL_LISTFILE,0,&hlFile)!=0) {
2759                                                         if (((MPQFILE *)hlFile)->lpHashEntry->lcLocale==0 && LocaleID!=0) {
2760                                                                 SFileCloseFile(hlFile);
2761                                                                 continue;
2762                                                         }
2763                                                         fsz = SFileGetFileSize(hlFile,0);
2764                                                         if (fsz>0) {
2765                                                                 listbuffer = (char *)SFAlloc(fsz+1);
2766                                                                 if (listbuffer==0) {
2767                                                                         SFileCloseFile(hlFile);
2768                                                                         continue;
2769                                                                 }
2770                                                                 if (SFileReadFile(hlFile,listbuffer,fsz,0,0)==0) {
2771                                                                         SFFree(listbuffer);
2772                                                                         listbuffer = 0;
2773                                                                 }
2774                                                         }
2775                                                         SFileCloseFile(hlFile);
2776                                                         if (listbuffer!=0) {
2777                                                                 char *listline;
2778                                                                 for (listline=listbuffer;listline!=0;listline=nextline(listline)) {
2779                                                                         if (listline[0]==0) break;
2780                                                                         DWORD lnlen=strlnlen(listline);
2781                                                                         char prevchar=listline[lnlen];
2782                                                                         listline[lnlen]=0;
2783                                                                         dwNameHashA = HashString(listline,HASH_NAME_A);
2784                                                                         dwNameHashB = HashString(listline,HASH_NAME_B);
2785                                                                         if (lpHashTable[j].dwNameHashA==dwNameHashA && lpHashTable[j].dwNameHashB==dwNameHashB) {
2786                                                                                 dwOldCryptKey = HashString(listline,HASH_KEY);
2787                                                                                 dwNewCryptKey = dwOldCryptKey;
2788                                                                                 dwOldCryptKey = (dwOldCryptKey + mpqOpenArc->lpBlockTable[i].dwFileOffset) ^ mpqOpenArc->lpBlockTable[i].dwFullSize;
2789                                                                                 dwNewCryptKey = (dwNewCryptKey + lpBlockTable[i-nBlkOffset].dwFileOffset) ^ lpBlockTable[i-nBlkOffset].dwFullSize;
2790                                                                                 break;
2791                                                                         }
2792                                                                         listline[lnlen]=prevchar;
2793                                                                 }
2794                                                                 if (listline!=0) {
2795                                                                         if (listline[0]!=0) {
2796                                                                                 SFFree(listbuffer);
2797                                                                                 break;
2798                                                                         }
2799                                                                 }
2800                                                                 SFFree(listbuffer);
2801                                                         }
2802                                                 }
2803                                         }
2804                                         LocaleID = lcOldLocale;
2805                                 }
2806                                 if (dwOldCryptKey!=dwNewCryptKey)
2807                                 {
2808                                         char *blkBuffer = (char *)SFAlloc(blockSize);
2809                                         if (blkBuffer==0) {
2810                                                 SFFree(lpBlockTable);
2811                                                 SFFree(lpHashTable);
2812                                                 SFFree(buffer);
2813                                                 CloseHandle(hFile);
2814                                                 DeleteFile(lpFileName);
2815                                                 return FALSE;
2816                                         }
2817                                         for (DWORD k=0;k<mpqOpenArc->lpBlockTable[i].dwFullSize;k+=blockSize) {
2818                                                 SFSetFilePointer(mpqOpenArc->hFile, mpqOpenArc->qwMPQStart + MakeUInt64(mpqOpenArc->lpBlockTable[i].dwFileOffset, mpqOpenArc->lpFileOffsetsHigh[i]) + HeaderLength + k, FILE_BEGIN);
2819                                                 if (k+blockSize>mpqOpenArc->lpBlockTable[i].dwFullSize) blockSize = mpqOpenArc->lpBlockTable[i].dwFullSize % blockSize;
2820                                                 if (ReadFile(mpqOpenArc->hFile,blkBuffer,blockSize,&tsz,0)==0) {
2821                                                         SFFree(blkBuffer);
2822                                                         SFFree(lpBlockTable);
2823                                                         SFFree(lpHashTable);
2824                                                         SFFree(buffer);
2825                                                         CloseHandle(hFile);
2826                                                         DeleteFile(lpFileName);
2827                                                         return FALSE;
2829                                                 }
2830                                                 DecryptData((LPBYTE)blkBuffer,blockSize,dwOldCryptKey+k);
2831                                                 EncryptData((LPBYTE)blkBuffer,blockSize,dwNewCryptKey+k);
2832                                                 SFSetFilePointer(hFile, MakeUInt64(lpBlockTable[i-nBlkOffset].dwFileOffset, lpdwFileOffsetsHigh[i-nBlkOffset]) + HeaderLength + k, FILE_BEGIN);
2833                                                 WriteFile(hFile,blkBuffer,blockSize,&tsz,0);
2834                                         }
2835                                         SFFree(blkBuffer);
2836                                         dwWritten = TRUE;
2837                                 }
2838                         }
2839                         if (dwWritten==FALSE) {
2840                                 ReadSize = 65536;
2841                                 for (j=0;j<mpqOpenArc->lpBlockTable[i].dwCompressedSize;j+=65536) {
2842                                         SFSetFilePointer(mpqOpenArc->hFile, mpqOpenArc->qwMPQStart + MakeUInt64(mpqOpenArc->lpBlockTable[i].dwFileOffset, mpqOpenArc->lpFileOffsetsHigh[i]) + j, FILE_BEGIN);
2843                                         SFSetFilePointer(hFile, MakeUInt64(lpBlockTable[i-nBlkOffset].dwFileOffset, lpdwFileOffsetsHigh[i-nBlkOffset]) + j, FILE_BEGIN);
2844                                         if (j+65536>mpqOpenArc->lpBlockTable[i].dwCompressedSize) ReadSize = mpqOpenArc->lpBlockTable[i].dwCompressedSize-j;
2845                                         if (ReadFile(mpqOpenArc->hFile,buffer,ReadSize,&tsz,0)==0) {
2846                                                 SFFree(lpBlockTable);
2847                                                 SFFree(lpHashTable);
2848                                                 SFFree(buffer);
2849                                                 CloseHandle(hFile);
2850                                                 DeleteFile(lpFileName);
2851                                                 return FALSE;
2852                                         }
2853                                         if (WriteFile(hFile,buffer,ReadSize,&tsz,0)==0) {
2854                                                 SFFree(lpBlockTable);
2855                                                 SFFree(lpHashTable);
2856                                                 SFFree(buffer);
2857                                                 CloseHandle(hFile);
2858                                                 DeleteFile(lpFileName);
2859                                                 return FALSE;
2860                                         }
2861                                 }
2862                         }
2863                 }
2864                 else {
2865                         for (j=0;j<mpqOpenArc->MpqHeader.dwHashTableSize;j++) {
2866                                 if ((lpHashTable[j].dwBlockTableIndex&0xFFFFFFFE)!=0xFFFFFFFE)
2867                                         if (lpHashTable[j].dwBlockTableIndex>(i-nBlkOffset)) lpHashTable[j].dwBlockTableIndex--;
2868                         }
2869                         nBlkOffset++;
2870                 }
2871         }
2872         mpqOpenArc->MpqHeader.dwBlockTableSize -= nBlkOffset;
2873         SplitUInt64(mpqOpenArc->MpqHeader.dwHashTableOffset, mpqOpenArc->MpqHeader_Ex.wHashTableOffsetHigh, qwLastOffset);
2874         qwLastOffset += mpqOpenArc->MpqHeader.dwHashTableSize * sizeof(HASHTABLEENTRY);
2875         SplitUInt64(mpqOpenArc->MpqHeader.dwBlockTableOffset, mpqOpenArc->MpqHeader_Ex.wBlockTableOffsetHigh, qwLastOffset);
2876         qwLastOffset += mpqOpenArc->MpqHeader.dwBlockTableSize * sizeof(BLOCKTABLEENTRY);
2877         if (mpqOpenArc->MpqHeader_Ex.qwExtendedBlockOffsetTable) {
2878                 mpqOpenArc->MpqHeader_Ex.qwExtendedBlockOffsetTable = qwLastOffset;
2879                 qwLastOffset += mpqOpenArc->MpqHeader.dwBlockTableSize * sizeof(UInt16);
2880         }
2881         mpqOpenArc->MpqHeader.dwMPQSize = (UInt32)qwLastOffset;
2882         SFFree(mpqOpenArc->lpHashTable);
2883         mpqOpenArc->lpHashTable = lpHashTable;
2884         if(mpqOpenArc->lpBlockTable!=0) {
2885                 SFFree(mpqOpenArc->lpBlockTable);
2886                 mpqOpenArc->lpBlockTable = (BLOCKTABLEENTRY *)SFAlloc(mpqOpenArc->MpqHeader.dwBlockTableSize * (sizeof(BLOCKTABLEENTRY) + sizeof(UInt16)));
2887                 mpqOpenArc->lpFileOffsetsHigh = (UInt16 *)(mpqOpenArc->lpBlockTable + mpqOpenArc->MpqHeader.dwBlockTableSize);
2888                 if (mpqOpenArc->lpBlockTable==0) {
2889                         mpqOpenArc->lpBlockTable = lpBlockTable;
2890                         mpqOpenArc->lpFileOffsetsHigh = lpdwFileOffsetsHigh;
2891                 }
2892                 else {
2893                         memcpy(mpqOpenArc->lpBlockTable, lpBlockTable, mpqOpenArc->MpqHeader.dwBlockTableSize * (sizeof(BLOCKTABLEENTRY) + sizeof(UInt16)));
2894                         SFFree(lpBlockTable);
2895                 }
2896         }
2897         SFSetFilePointer(mpqOpenArc->hFile, mpqOpenArc->qwMPQStart + qwLastOffset, FILE_BEGIN);
2898         SetEndOfFile(mpqOpenArc->hFile);
2899         MpqWriteHeaders(mpqOpenArc);
2900         mpqOpenArc->MpqHeader.dwHeaderSize = mpqOpenArc->dwHeaderSize;
2901         qwLastOffset = mpqOpenArc->dwHeaderSize;
2902         ReadSize = 65536;
2903         for (i=qwLastOffset;i<MakeUInt64(mpqOpenArc->MpqHeader.dwHashTableOffset, mpqOpenArc->MpqHeader_Ex.wHashTableOffsetHigh);i+=65536) {
2904                 SFSetFilePointer(mpqOpenArc->hFile,mpqOpenArc->qwMPQStart+i,FILE_BEGIN);
2905                 SFSetFilePointer(hFile,i,FILE_BEGIN);
2906                 if (i+65536>MakeUInt64(mpqOpenArc->MpqHeader.dwHashTableOffset, mpqOpenArc->MpqHeader_Ex.wHashTableOffsetHigh)) ReadSize = MakeUInt64(mpqOpenArc->MpqHeader.dwHashTableOffset, mpqOpenArc->MpqHeader_Ex.wHashTableOffsetHigh)-i;
2907                 ReadFile(hFile,buffer,ReadSize,&tsz,0);
2908                 WriteFile(mpqOpenArc->hFile,buffer,ReadSize,&tsz,0);
2909         }
2910         SFFree(buffer);
2911         CloseHandle(hFile);
2912         DeleteFile(lpFileName);
2913         WriteHashTable(mpqOpenArc);
2914         WriteBlockTable(mpqOpenArc);
2915         return TRUE;
2918 BOOL SFMPQAPI WINAPI MpqSetFileLocale(MPQHANDLE hMPQ, LPCSTR lpFileName, LCID nOldLocale, LCID nNewLocale)
2920         if (!hMPQ || !lpFileName) {
2921                 SetLastError(ERROR_INVALID_PARAMETER);
2922                 return FALSE;
2923         }
2925         if (!(((MPQARCHIVE *)hMPQ)->dwFlags&SFILE_OPEN_ALLOW_WRITE)) {
2926                 SetLastError(ERROR_ACCESS_DENIED);
2927                 return FALSE;
2928         }
2929         if (nOldLocale==nNewLocale) return FALSE;
2930         MPQARCHIVE *mpqOpenArc = (MPQARCHIVE *)hMPQ;
2931         HASHTABLEENTRY *hashEntry = (HASHTABLEENTRY *)GetHashTableEntry(hMPQ,lpFileName,nOldLocale);
2932         if (hashEntry==0) return FALSE;
2933         if (hashEntry->lcLocale!=nOldLocale) return FALSE;
2934         hashEntry->lcLocale = nNewLocale;
2936         WriteHashTable(mpqOpenArc);
2937         LCID dwOldLocale=LocaleID;
2938         LocaleID=nOldLocale;
2939         RemoveFromInternalListing(hMPQ,lpFileName);
2941         LocaleID=nNewLocale;
2942         AddToInternalListing(hMPQ,lpFileName);
2943         LocaleID=dwOldLocale;
2944         return TRUE;
2947 BOOL SFMPQAPI WINAPI MpqCreateArchiveVersion(WORD wVersion)
2949         if (wVersion > 1) return FALSE;
2951         wCreationVersion = wVersion;
2952         return TRUE;
2955 DWORD SFMPQAPI WINAPI SFileFindMpqHeader(HANDLE hFile)
2957         if (hFile == INVALID_HANDLE_VALUE) {
2958                 SetLastError(ERROR_INVALID_PARAMETER);
2959                 return 0xFFFFFFFF;
2960         }
2962         DWORD dwHandleType = GetHandleType((MPQHANDLE)hFile);
2963         if (dwHandleType == SFILE_TYPE_FILE) {
2964                 MPQFILE *mpqOpenFile = (MPQFILE *)hFile;
2965                 if (mpqOpenFile->hFile == INVALID_HANDLE_VALUE) {
2966                         return mpqOpenFile->lpParentArc->qwMPQStart;
2967                 }
2968                 else {
2969                         hFile = mpqOpenFile->hFile;
2970                 }
2971         }
2972         else if (dwHandleType == SFILE_TYPE_MPQ) {
2973                 return ((MPQARCHIVE *)hFile)->qwMPQStart;
2974         }
2976         UInt64 FileLen = SFGetFileSize(hFile);
2977         if (FileLen >= 0xFFFFFFFF) FileLen = 0xFFFFFFFE;
2978         char pbuf[sizeof(MPQHEADER)];
2979         DWORD tsz;
2980         for (DWORD i=0;i<FileLen;i+=512)
2981         {
2982                 SFSetFilePointer(hFile,i,FILE_BEGIN);
2983                 if (ReadFile(hFile,pbuf,sizeof(MPQHEADER),&tsz,0)==0) return 0xFFFFFFFF;
2984                 if (tsz<sizeof(MPQHEADER)) return 0xFFFFFFFF;
2985                 if (memcmp(pbuf,ID_MPQ,4)==0 || memcmp(pbuf,ID_BN3,4)==0)
2986                 {
2987                         // Storm no longer does this, so mpq api shouldn't either
2988                         /*FileLen -= i;
2989                         if (memcmp(pbuf+8,&FileLen,4)==0)
2990                                 return i;
2991                         else
2992                                 FileLen += i;*/
2993                         return i;
2994                 }
2995         }
2996         return 0xFFFFFFFF;
2999 UInt64 WINAPI SFileFindMpqHeaderEx(HANDLE hFile, UInt64 qwStart, UInt64 qwLength)
3001         if (hFile == INVALID_HANDLE_VALUE) {
3002                 SetLastError(ERROR_INVALID_PARAMETER);
3003                 return (UInt64)-1;
3004         }
3005         UInt64 FileLen = SFGetFileSize(hFile);
3006         if (FileLen == (UInt64)-1 || qwStart >= FileLen || qwStart + qwLength > FileLen) return (UInt64)-1;
3007         if (qwLength == 0) qwLength = FileLen - qwStart;
3008         char pbuf[sizeof(MPQHEADER)];
3009         DWORD tsz;
3010         for (UInt64 i=qwStart;i<qwStart+qwLength && i<FileLen;i+=512)
3011         {
3012                 SFSetFilePointer(hFile,i,FILE_BEGIN);
3013                 if (ReadFile(hFile,pbuf,sizeof(MPQHEADER),&tsz,0)==0) return (UInt64)-1;
3014                 if (i+tsz>qwStart+qwLength) tsz = (qwStart+qwLength)-i;
3015                 if (tsz<sizeof(MPQHEADER)) return (UInt64)-1;
3016                 if (memcmp(pbuf,ID_MPQ,4)==0 || memcmp(pbuf,ID_BN3,4)==0)
3017                 {
3018                         // Storm no longer does this, so mpq api shouldn't either
3019                         /*FileLen -= i;
3020                         if (memcmp(pbuf+8,&FileLen,4)==0)
3021                                 return i;
3022                         else
3023                                 FileLen += i;*/
3024                         return i;
3025                 }
3026         }
3027         return (UInt64)-1;
3030 DWORD GetFullPath(LPCSTR lpFileName, char *lpBuffer, DWORD dwBufferLength)
3032         if (!lpFileName) return (DWORD)-1;
3033         DWORD slen = strlen(lpFileName);
3034         if (memcmp(lpFileName+1,":\\",2)==0) {
3035                 if (slen+1>dwBufferLength) return slen+1;
3036                 memcpy(lpBuffer,lpFileName,slen+1);
3037         }
3038 #ifdef _WIN32
3039         else if (lpFileName[0]=='\\') {
3040 #else
3041         else if (lpFileName[0]=='/') {
3042 #endif
3043                 if (slen+3>dwBufferLength) return slen+3;
3044                 memcpy(lpBuffer,StormBasePath,2);
3045                 memcpy(lpBuffer+2,lpFileName,slen+1);
3046         }
3047         else {
3048                 DWORD sbslen = strlen(StormBasePath);
3049                 if (sbslen+slen+1>dwBufferLength) return sbslen+slen+1;
3050                 memcpy(lpBuffer,StormBasePath,sbslen);
3051                 memcpy(lpBuffer+sbslen,lpFileName,slen);
3052                 lpBuffer[sbslen+slen]=0;
3053         }
3054         return 0;
3057 MPQHANDLE GetHashTableEntry(MPQHANDLE hMPQ, LPCSTR lpFileName, LCID FileLocale)
3059         if (!hMPQ || !lpFileName) return 0;
3060         MPQARCHIVE *mpqOpenArc = (MPQARCHIVE *)hMPQ;
3061         DWORD dwTablePos = HashString(lpFileName,HASH_POSITION) % mpqOpenArc->MpqHeader.dwHashTableSize;
3062         DWORD dwNameHashA = HashString(lpFileName,HASH_NAME_A);
3063         DWORD dwNameHashB = HashString(lpFileName,HASH_NAME_B);
3064         StartTableSearch:
3065         DWORD i=dwTablePos;
3066         do
3067         {
3068                 if (mpqOpenArc->lpHashTable[i].dwBlockTableIndex==0xFFFFFFFF)
3069                 {
3070                         break;
3071                 }
3072                 else if (mpqOpenArc->lpHashTable[i].dwNameHashA==dwNameHashA && mpqOpenArc->lpHashTable[i].dwNameHashB==dwNameHashB && mpqOpenArc->lpHashTable[i].lcLocale==FileLocale && mpqOpenArc->lpHashTable[i].dwBlockTableIndex!=0xFFFFFFFE)
3073                 {
3074                         return (MPQHANDLE)&mpqOpenArc->lpHashTable[i];
3075                 }
3076                 i = (i + 1) % mpqOpenArc->MpqHeader.dwHashTableSize;
3077         } while (i!=dwTablePos);
3078         if (FileLocale!=0) {FileLocale=0;goto StartTableSearch;}
3079         return 0;
3082 MPQHANDLE GetHashTableEntryOfHash(MPQHANDLE hMPQ, DWORD dwTablePos, DWORD dwNameHashA, DWORD dwNameHashB, LCID FileLocale)
3084         if (!hMPQ) return 0;
3085         MPQARCHIVE *mpqOpenArc = (MPQARCHIVE *)hMPQ;
3086         StartTableSearch:
3087         DWORD i=dwTablePos;
3088         do
3089         {
3090                 if (mpqOpenArc->lpHashTable[i].dwBlockTableIndex==0xFFFFFFFF)
3091                 {
3092                         break;
3093                 }
3094                 else if (mpqOpenArc->lpHashTable[i].dwNameHashA==dwNameHashA && mpqOpenArc->lpHashTable[i].dwNameHashB==dwNameHashB && mpqOpenArc->lpHashTable[i].lcLocale==FileLocale && mpqOpenArc->lpHashTable[i].dwBlockTableIndex!=0xFFFFFFFE)
3095                 {
3096                         return (MPQHANDLE)&mpqOpenArc->lpHashTable[i];
3097                 }
3098                 i = (i + 1) % mpqOpenArc->MpqHeader.dwHashTableSize;
3099         } while (i!=dwTablePos);
3100         if (FileLocale!=0) {FileLocale=0;goto StartTableSearch;}
3101         return 0;
3104 MPQHANDLE GetFreeHashTableEntry(MPQHANDLE hMPQ, LPCSTR lpFileName, LCID FileLocale, BOOL ReturnExisting)
3106         if (!hMPQ || !lpFileName) return 0;
3107         MPQARCHIVE *mpqOpenArc = (MPQARCHIVE *)hMPQ;
3108         DWORD dwTablePos = HashString(lpFileName,HASH_POSITION) % mpqOpenArc->MpqHeader.dwHashTableSize;
3109         DWORD dwNameHashA = HashString(lpFileName,HASH_NAME_A);
3110         DWORD dwNameHashB = HashString(lpFileName,HASH_NAME_B);
3111         DWORD i=dwTablePos, nFirstFree = 0xFFFFFFFF;
3112         do
3113         {
3114                 if ((mpqOpenArc->lpHashTable[i].dwBlockTableIndex&0xFFFFFFFE)==0xFFFFFFFE && (nFirstFree == 0xFFFFFFFF || mpqOpenArc->lpHashTable[i].dwBlockTableIndex == 0xFFFFFFFF))
3115                 {
3116                         if (mpqOpenArc->lpHashTable[i].dwBlockTableIndex == 0xFFFFFFFF)
3117                         {
3118                                 if (nFirstFree == 0xFFFFFFFF)
3119                                         return (MPQHANDLE)&mpqOpenArc->lpHashTable[i];
3120                                 else
3121                                         return (MPQHANDLE)&mpqOpenArc->lpHashTable[nFirstFree];
3122                         }
3123                         else nFirstFree = i;
3124                 }
3125                 else if (mpqOpenArc->lpHashTable[i].dwNameHashA==dwNameHashA && mpqOpenArc->lpHashTable[i].dwNameHashB==dwNameHashB && mpqOpenArc->lpHashTable[i].lcLocale==FileLocale)
3126                 {
3127                         if (ReturnExisting!=FALSE)
3128                                 return (MPQHANDLE)&mpqOpenArc->lpHashTable[i];
3129                         else {
3130                                 SetLastError(MPQ_ERROR_ALREADY_EXISTS);
3131                                 return 0;
3132                         }
3133                 }
3134                 i = (i + 1) % mpqOpenArc->MpqHeader.dwHashTableSize;
3135         } while (i!=dwTablePos);
3136         SetLastError(MPQ_ERROR_HASH_TABLE_FULL);
3137         return 0;
3140 BOOL SearchOpenArchives(LPCSTR lpFileName, MPQHANDLE *hMPQ, MPQHANDLE *hFile)
3142         MPQHANDLE hnMPQ,hnFile,hndMPQ = 0,hndFile = 0;
3144         DWORD dwTablePos = HashString(lpFileName,HASH_POSITION);
3145         DWORD dwNameHashA = HashString(lpFileName,HASH_NAME_A);
3146         DWORD dwNameHashB = HashString(lpFileName,HASH_NAME_B);
3148         for (DWORD i=0;i<dwOpenMpqCount;i++) {
3149                 hnMPQ = (MPQHANDLE)lpOpenMpq[i];
3150                 hnFile = GetHashTableEntryOfHash(hnMPQ,dwTablePos % lpOpenMpq[i]->MpqHeader.dwHashTableSize,dwNameHashA,dwNameHashB,LocaleID);
3152                 if (hnFile!=0) {
3153                         if (((HASHTABLEENTRY *)hnFile)->lcLocale == LocaleID) {
3154                                 *hMPQ = hnMPQ;
3155                                 *hFile = hnFile;
3156                                 return TRUE;
3157                         }
3158                         else if (hndMPQ == 0 || hndFile == 0) {
3159                                 hndMPQ = hnMPQ;
3160                                 hndFile = hnFile;
3161                         }
3162                 }
3163         }
3165         if (hndMPQ != 0 && hndFile != 0) {
3166                 *hMPQ = hndMPQ;
3167                 *hFile = hndFile;
3168                 return TRUE;
3169         }
3171         *hMPQ = 0;
3172         *hFile = 0;
3173         return FALSE;
3176 void SortOpenArchivesByPriority()
3178         MPQARCHIVE *hMPQ1,*hMPQ2;
3179         for (DWORD i=1;i<dwOpenMpqCount;i++) {
3180                 do {
3181                         hMPQ1 = lpOpenMpq[i-1];
3182                         hMPQ2 = lpOpenMpq[i];
3183                         if (hMPQ2->dwPriority > hMPQ1->dwPriority) {
3184                                 lpOpenMpq[i-1] = hMPQ2;
3185                                 lpOpenMpq[i] = hMPQ1;
3186                                 i--;
3187                         }
3188                 } while (hMPQ2->dwPriority > hMPQ1->dwPriority && i>0);
3189         }
3192 DWORD GetHandleType(MPQHANDLE hFile)
3194         DWORD i;
3195         for (i=0;i<dwOpenFileCount;i++) {
3196                 if ((MPQHANDLE)lpOpenFile[i]==hFile) return SFILE_TYPE_FILE;
3197         }
3198         for (i=0;i<dwOpenMpqCount;i++) {
3199                 if ((MPQHANDLE)lpOpenMpq[i]==hFile) return SFILE_TYPE_MPQ;
3200         }
3201         return 0;
3204 BOOL AddToInternalListing(MPQHANDLE hMPQ, LPCSTR lpFileName)
3206         MPQARCHIVE *mpqOpenArc = (MPQARCHIVE *)hMPQ;
3207         if ((mpqOpenArc->dwFlags & MOAU_MAINTAIN_LISTFILE)==MOAU_MAINTAIN_LISTFILE && stricmp(lpFileName,INTERNAL_LISTFILE)!=0)
3208         {
3209                 MPQHANDLE hlFile;char *buffer=0;DWORD fsz,lsz;
3210                 lsz = strlen(lpFileName);
3211                 if (SFileOpenFileEx(hMPQ,INTERNAL_LISTFILE,0,&hlFile)!=0) {
3212                         if (((MPQFILE *)hlFile)->lpHashEntry->lcLocale==LocaleID) {
3213                                 fsz = SFileGetFileSize(hlFile,0);
3214                                 if (fsz==0) {
3215                                         SFileCloseFile(hlFile);
3216                                         goto AddFileName;
3217                                 }
3218                                 buffer = (char *)SFAlloc(fsz+lsz+2);
3219                                 if (buffer==0) {
3220                                         SFileCloseFile(hlFile);
3221                                         return FALSE;
3222                                 }
3223                                 if (SFileReadFile(hlFile,buffer,fsz,0,0)==0) {
3224                                         SFFree(buffer);
3225                                         buffer = 0;
3226                                 }
3227                                 buffer[fsz]=0;
3228                         }
3229                         SFileCloseFile(hlFile);
3230                 }
3231                 AddFileName:
3232                 if (buffer==0) {
3233                         fsz = 0;
3234                         buffer = (char *)SFAlloc(lsz+2);
3235                         buffer[0]=0;
3236                 }
3237                 else {
3238                         char *buffercopy = strlwr(strdup(buffer));
3239                         char *lwrFileName = strlwr(strdup(lpFileName));
3240                         char *subbuffer=buffer;
3241                         while ((subbuffer=strstr(subbuffer,lpFileName))!=NULL && subbuffer[0]!=0) {
3242                                 if (subbuffer==buffer && subbuffer[lsz]==0) {
3243                                         SFFree(lwrFileName);
3244                                         SFFree(buffercopy);
3245                                         SFFree(buffer);
3246                                         return TRUE;
3247                                 }
3248                                 else if (subbuffer==buffer && (subbuffer[lsz]=='\n' || subbuffer[lsz]=='\r')) {
3249                                         SFFree(lwrFileName);
3250                                         SFFree(buffercopy);
3251                                         SFFree(buffer);
3252                                         return TRUE;
3253                                 }
3254                                 else if (((subbuffer-1)[0]=='\n' || (subbuffer-1)[0]=='\r') && subbuffer[lsz]==0) {
3255                                         SFFree(lwrFileName);
3256                                         SFFree(buffercopy);
3257                                         SFFree(buffer);
3258                                         return TRUE;
3259                                 }
3260                                 else if (((subbuffer-1)[0]=='\n' || (subbuffer-1)[0]=='\r') && (subbuffer[lsz]=='\n' || subbuffer[lsz]=='\r')) {
3261                                         SFFree(lwrFileName);
3262                                         SFFree(buffercopy);
3263                                         SFFree(buffer);
3264                                         return TRUE;
3265                                 }
3266                                 subbuffer++;
3267                         }
3268                         SFFree(lwrFileName);
3269                         SFFree(buffercopy);
3270                 }
3271                 memcpy(buffer+fsz,lpFileName,lsz);
3272                 memcpy(buffer+fsz+lsz,"\r\n",2);
3273                 //LCID dwOldLocale=LocaleID;
3274                 //LocaleID=0;
3275                 MpqAddFileFromBuffer(hMPQ,buffer,fsz+lsz+2,INTERNAL_LISTFILE,MAFA_COMPRESS|MAFA_ENCRYPT|MAFA_MODCRYPTKEY|MAFA_REPLACE_EXISTING);
3276                 //LocaleID=dwOldLocale;
3277                 SFFree(buffer);
3278         }
3279         return TRUE;
3282 BOOL RemoveFromInternalListing(MPQHANDLE hMPQ, LPCSTR lpFileName)
3284         MPQARCHIVE *mpqOpenArc = (MPQARCHIVE *)hMPQ;
3285         if ((mpqOpenArc->dwFlags & MOAU_MAINTAIN_LISTFILE)==MOAU_MAINTAIN_LISTFILE && stricmp(lpFileName,INTERNAL_LISTFILE)!=0)
3286         {
3287                 MPQHANDLE hlFile;char *buffer=0;DWORD fsz,lsz;
3288                 lsz = strlen(lpFileName);
3289                 if (SFileOpenFileEx(hMPQ,INTERNAL_LISTFILE,0,&hlFile)!=0) {
3290                         if (((MPQFILE *)hlFile)->lpHashEntry->lcLocale==LocaleID) {
3291                                 fsz = SFileGetFileSize(hlFile,0);
3292                                 if (fsz==0) {
3293                                         SFileCloseFile(hlFile);
3295                                         return FALSE;
3296                                 }
3298                                 buffer = (char *)SFAlloc(fsz+1);
3299                                 if (buffer==0) {
3300                                         SFileCloseFile(hlFile);
3301                                         return FALSE;
3302                                 }
3303                                 buffer[fsz] = 0;
3304                                 if (SFileReadFile(hlFile,buffer,fsz,0,0)==0) {
3305                                         SFFree(buffer);
3306                                         buffer = 0;
3307                                 }
3308                         }
3309                         SFileCloseFile(hlFile);
3310                 }
3311                 if (buffer==0) {
3312                         return FALSE;
3313                 }
3314                 else {
3315                         buffer[fsz]=0;
3316                         char *buffercopy = strlwr(strdup(buffer));
3317                         char *lwrFileName = strlwr(strdup(lpFileName));
3318                         char *subbuffer=buffer;
3320                         while ((subbuffer=strstr(subbuffer,lpFileName))!=NULL && subbuffer[0]!=0) {
3321                                 if (subbuffer==buffer && subbuffer[lsz]==0) {
3322                                         SFFree(lwrFileName);
3323                                         SFFree(buffercopy);
3324                                         //LCID dwOldLocale=LocaleID;
3325                                         //LocaleID=0;
3326                                         MpqAddFileFromBuffer(hMPQ,(LPVOID)"\x00",0,INTERNAL_LISTFILE,MAFA_COMPRESS|MAFA_ENCRYPT|MAFA_MODCRYPTKEY|MAFA_REPLACE_EXISTING);
3327                                         //LocaleID=dwOldLocale;
3328                                         SFFree(buffer);
3329                                         return TRUE;
3330                                 }
3331                                 else if (subbuffer==buffer && (subbuffer[lsz]=='\n' || subbuffer[lsz]=='\r')) {
3332                                         SFFree(lwrFileName);
3333                                         SFFree(buffercopy);
3334                                         if (subbuffer[lsz+1]=='\n' || subbuffer[lsz+1]=='\r') lsz++;
3335                                         memcpy(subbuffer,subbuffer+lsz+1,strlen(subbuffer+lsz+1));
3336                                         //LCID dwOldLocale=LocaleID;
3337                                         //LocaleID=0;
3338                                         MpqAddFileFromBuffer(hMPQ,buffer,fsz-lsz-1,INTERNAL_LISTFILE,MAFA_COMPRESS|MAFA_ENCRYPT|MAFA_MODCRYPTKEY|MAFA_REPLACE_EXISTING);
3339                                         //LocaleID=dwOldLocale;
3340                                         SFFree(buffer);
3341                                         return TRUE;
3342                                 }
3343                                 else if (((subbuffer-1)[0]=='\n' || (subbuffer-1)[0]=='\r') && subbuffer[lsz]==0) {
3344                                         SFFree(lwrFileName);
3345                                         SFFree(buffercopy);
3346                                         //LCID dwOldLocale=LocaleID;
3347                                         //LocaleID=0;
3348                                         MpqAddFileFromBuffer(hMPQ,buffer,fsz-lsz,INTERNAL_LISTFILE,MAFA_COMPRESS|MAFA_ENCRYPT|MAFA_MODCRYPTKEY|MAFA_REPLACE_EXISTING);
3349                                         //LocaleID=dwOldLocale;
3350                                         SFFree(buffer);
3351                                         return TRUE;
3352                                 }
3353                                 else if (((subbuffer-1)[0]=='\n' || (subbuffer-1)[0]=='\r') && (subbuffer[lsz]=='\n' || subbuffer[lsz]=='\r')) {
3354                                         SFFree(lwrFileName);
3355                                         SFFree(buffercopy);
3356                                         if ((subbuffer-2)[0]=='\n' || (subbuffer-2)[0]=='\r') {subbuffer--;lsz++;}
3357                                         memcpy(subbuffer-1,subbuffer+lsz,strlen(subbuffer+lsz));
3358                                         //LCID dwOldLocale=LocaleID;
3359                                         //LocaleID=0;
3360                                         MpqAddFileFromBuffer(hMPQ,buffer,fsz-lsz-1,INTERNAL_LISTFILE,MAFA_COMPRESS|MAFA_ENCRYPT|MAFA_MODCRYPTKEY|MAFA_REPLACE_EXISTING);
3361                                         //LocaleID=dwOldLocale;
3362                                         SFFree(buffer);
3363                                         return TRUE;
3364                                 }
3365                                 subbuffer++;
3366                         }
3367                         SFFree(lwrFileName);
3368                         SFFree(buffercopy);
3369                 }
3370                 SFFree(buffer);
3371         }
3372         return TRUE;
3375 DWORD DetectFileSeedEx(MPQARCHIVE * mpqOpenArc, HASHTABLEENTRY * lpHashEntry, LPCSTR * lplpFileName)
3377         if (mpqOpenArc==0 || lpHashEntry==0) return 0;
3378         DWORD dwCryptKey=0;
3379         LPCSTR lpFileName = *lplpFileName;
3380         DWORD dwBlockIndex = lpHashEntry->dwBlockTableIndex;
3381         if (lpFileName)
3382         {
3383                 dwCryptKey = HashString(lpFileName,HASH_KEY);
3384                 if (mpqOpenArc->lpBlockTable[dwBlockIndex].dwFlags&MAFA_MODCRYPTKEY)
3385                         dwCryptKey = (dwCryptKey + mpqOpenArc->lpBlockTable[dwBlockIndex].dwFileOffset) ^ mpqOpenArc->lpBlockTable[dwBlockIndex].dwFullSize;
3386         }
3387         else
3388         {
3389                 DWORD dwNameHashA = HashString(INTERNAL_LISTFILE,HASH_NAME_A);
3390                 DWORD dwNameHashB = HashString(INTERNAL_LISTFILE,HASH_NAME_B);
3391                 if (lpHashEntry->dwNameHashA==dwNameHashA && lpHashEntry->dwNameHashB==dwNameHashB) {
3392                         dwCryptKey = HashString(INTERNAL_LISTFILE,HASH_KEY);
3393                         if (mpqOpenArc->lpBlockTable[dwBlockIndex].dwFlags&MAFA_MODCRYPTKEY)
3394                                 dwCryptKey = (dwCryptKey + mpqOpenArc->lpBlockTable[dwBlockIndex].dwFileOffset) ^ mpqOpenArc->lpBlockTable[dwBlockIndex].dwFullSize;
3395                         *lplpFileName = (char *)SFAlloc(strlen(INTERNAL_LISTFILE)+1);
3396                         if (*lplpFileName)
3397                                 strcpy((LPSTR)*lplpFileName,INTERNAL_LISTFILE);
3398                 }
3399                 else {
3400                         HANDLE hlFile,hMPQ=(HANDLE)mpqOpenArc;
3401                         DWORD fsz;
3402                         char *listbuffer;
3403                         LCID lcOldLocale = LocaleID;
3404                         for (DWORD lcn=0;lcn<nLocales;lcn++) {
3405                                 LocaleID = availLocales[lcn];
3406                                 if (SFileOpenFileEx(hMPQ,INTERNAL_LISTFILE,0,&hlFile)!=0) {
3407                                         if (((MPQFILE *)hlFile)->lpHashEntry->lcLocale==0 && LocaleID!=0) {
3408                                                 SFileCloseFile(hlFile);
3409                                                 continue;
3410                                         }
3411                                         fsz = SFileGetFileSize(hlFile,0);
3412                                         if (fsz>0) {
3413                                                 listbuffer = (char *)SFAlloc(fsz+1);
3414                                                 if (listbuffer==0) {
3415                                                         SFileCloseFile(hlFile);
3416                                                         continue;
3417                                                 }
3418                                                 if (SFileReadFile(hlFile,listbuffer,fsz,0,0)==0) {
3419                                                         SFFree(listbuffer);
3420                                                         listbuffer = 0;
3421                                                 }
3422                                         }
3423                                         SFileCloseFile(hlFile);
3424                                         if (listbuffer!=0) {
3425                                                 char *listline;
3426                                                 for (listline=listbuffer;listline!=0;listline=nextline(listline)) {
3427                                                         if (listline[0]==0) break;
3428                                                         DWORD lnlen=strlnlen(listline);
3429                                                         char prevchar=listline[lnlen];
3430                                                         listline[lnlen]=0;
3431                                                         dwNameHashA = HashString(listline,HASH_NAME_A);
3432                                                         dwNameHashB = HashString(listline,HASH_NAME_B);
3433                                                         if (lpHashEntry->dwNameHashA==dwNameHashA && lpHashEntry->dwNameHashB==dwNameHashB) {
3434                                                                 dwCryptKey = HashString(listline,HASH_KEY);
3435                                                                 if (mpqOpenArc->lpBlockTable[dwBlockIndex].dwFlags&MAFA_MODCRYPTKEY)
3436                                                                         dwCryptKey = (dwCryptKey + mpqOpenArc->lpBlockTable[dwBlockIndex].dwFileOffset) ^ mpqOpenArc->lpBlockTable[dwBlockIndex].dwFullSize;
3437                                                                 *lplpFileName = (char *)SFAlloc(strlen(listline)+1);
3438                                                                 if (*lplpFileName)
3439                                                                         strcpy((LPSTR)*lplpFileName,listline);
3440                                                                 break;
3441                                                         }
3442                                                         listline[lnlen]=prevchar;
3443                                                 }
3444                                                 if (listline!=0) {
3445                                                         if (listline[0]!=0) {
3446                                                                 SFFree(listbuffer);
3447                                                                 break;
3448                                                         }
3449                                                 }
3450                                                 SFFree(listbuffer);
3451                                         }
3452                                 }
3453                         }
3454                         LocaleID = lcOldLocale;
3455                 }
3456                 if (dwCryptKey==0 && (mpqOpenArc->lpBlockTable[dwBlockIndex].dwFlags&MAFA_COMPRESS || mpqOpenArc->lpBlockTable[dwBlockIndex].dwFlags&MAFA_COMPRESS2))
3457                 {
3458                         DWORD HeaderLength=0,tsz;
3459                         if (memcmp(&mpqOpenArc->MpqHeader.dwMPQID,ID_BN3,4)==0)
3460                         {
3461                                 SFSetFilePointer(mpqOpenArc->hFile, mpqOpenArc->qwMPQStart + MakeUInt64(mpqOpenArc->lpBlockTable[dwBlockIndex].dwFileOffset, mpqOpenArc->lpFileOffsetsHigh[dwBlockIndex]), FILE_BEGIN);
3462                                 ReadFile(mpqOpenArc->hFile,&HeaderLength,4,&tsz,0);
3463                         }
3464                         DWORD blockSize = 512 << mpqOpenArc->MpqHeader.wBlockSize;
3465                         DWORD TotalBlocks = mpqOpenArc->lpBlockTable[dwBlockIndex].dwFullSize / blockSize;
3466                         if(mpqOpenArc->lpBlockTable[dwBlockIndex].dwFullSize % blockSize)
3467                                 TotalBlocks++;
3468                         DWORD *dwBlockPtrTable = (DWORD *)SFAlloc((TotalBlocks+1)*4);
3469                         if (dwBlockPtrTable==0)
3470                                 return 0;
3471                         SFSetFilePointer(mpqOpenArc->hFile, mpqOpenArc->qwMPQStart + MakeUInt64(mpqOpenArc->lpBlockTable[dwBlockIndex].dwFileOffset, mpqOpenArc->lpFileOffsetsHigh[dwBlockIndex]) + HeaderLength, FILE_BEGIN);
3472                         ReadFile(mpqOpenArc->hFile,dwBlockPtrTable,(TotalBlocks+1)*4,&tsz,0);
3473                         dwCryptKey = DetectFileSeed(dwBlockPtrTable,(TotalBlocks+1)*4,blockSize);
3475                         SFFree(dwBlockPtrTable);
3476                 }
3477         }
3478         return dwCryptKey;
3481 long SFMPQAPI __inline SFMpqCompareVersion()
3483         SFMPQVERSION ExeVersion = SFMPQ_CURRENT_VERSION;
3484         SFMPQVERSION DllVersion = SFMpqGetVersion();
3485         if (DllVersion.Major>ExeVersion.Major) return 1;
3486         else if (DllVersion.Major<ExeVersion.Major) return -1;
3487         if (DllVersion.Minor>ExeVersion.Minor) return 1;
3488         else if (DllVersion.Minor<ExeVersion.Minor) return -1;
3489         if (DllVersion.Revision>ExeVersion.Revision) return 1;
3490         else if (DllVersion.Revision<ExeVersion.Revision) return -1;
3491         if (DllVersion.Subrevision>ExeVersion.Subrevision) return 1;
3492         else if (DllVersion.Subrevision<ExeVersion.Subrevision) return -1;
3493         return 0;
3496 void LoadStorm()
3498 #ifdef _WIN32
3499         if (hStorm!=0) return;
3500         hStorm = LoadLibrary(Storm_dll);
3501         /*if (hStorm==0) {
3502                 HKEY hKey;
3503                 LPSTR lpDllPath;
3504                 DWORD dwStrLen;
3505                 if (RegOpenKeyEx(HKEY_CURRENT_USER,"Software\\Blizzard Entertainment\\Warcraft III",0,KEY_QUERY_VALUE,&hKey)!=ERROR_SUCCESS)
3506                         if (RegOpenKeyEx(HKEY_USERS,".Default\\Software\\Blizzard Entertainment\\Warcraft III",0,KEY_QUERY_VALUE,&hKey)!=ERROR_SUCCESS)
3507                                 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,"Software\\Blizzard Entertainment\\Warcraft III",0,KEY_QUERY_VALUE,&hKey)!=ERROR_SUCCESS)
3508                                         return;
3509                 RegQueryValueEx(hKey,"InstallPath",0,0,0,&dwStrLen);
3510                 lpDllPath = (LPSTR)SFAlloc(dwStrLen+11);
3511                 if (lpDllPath) {
3512                         memset(lpDllPath,0,dwStrLen+11);
3513                         RegQueryValueEx(hKey,"InstallPath",0,0,(LPBYTE)lpDllPath,&dwStrLen);
3514                         LPSTR lpLastBSlash = strrchr(lpDllPath,'\\');
3515                         if (lpLastBSlash) {
3516                                 if (lpLastBSlash[1]!=0) lpLastBSlash[strlen(lpLastBSlash)]='\\';
3517                                 strcat(lpLastBSlash,Storm_dll);
3518                                 hStorm = LoadLibrary(lpDllPath);
3519                         }
3520                         SFFree(lpDllPath);
3521                 }
3522                 RegCloseKey(hKey);
3523         }*/
3524         if (hStorm==0) return;
3526         unsigned int wSCCOrdinal=0xAC30;
3527         wSCCOrdinal>>=4;
3528         wSCCOrdinal/=5;
3529         unsigned int wSCDcOrdinal=0xAC80;
3530         wSCDcOrdinal>>=4;
3531         wSCDcOrdinal/=5;
3533         stormSCompCompress = (funcSCompCompress)GetProcAddress(hStorm,(LPCSTR)wSCCOrdinal);
3534         stormSCompDecompress = (funcSCompDecompress)GetProcAddress(hStorm,(LPCSTR)wSCDcOrdinal);
3535 #endif
3538 void FreeStorm()
3540 #ifdef _WIN32
3541         if (hStorm==0) return;
3542         FreeLibrary(hStorm);
3543         hStorm = 0;
3545         stormSCompCompress = 0;
3546         stormSCompDecompress = 0;
3547 #endif