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