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 "SFmpqapi.h"
18 struct SFMPQAPIMODULE {
19         SFMPQAPIMODULE();
20         ~SFMPQAPIMODULE();
21 } SFMpqApi;
23 #ifndef _WIN32
24 #define SFMPQ_STATIC
25 #endif
27 #if defined(SFMPQ_STATIC) || !defined(SFMPQAPI_EXPORTS)
28 #define DllMain SFMpqMain
30 struct SFMPQLIBMODULE {
31         SFMPQLIBMODULE();
32         ~SFMPQLIBMODULE();
33 } SFMpqLib;
35 BOOL APIENTRY DllMain(HINSTANCE hInstDLL, DWORD  ul_reason_for_call, LPVOID lpReserved);
37 SFMPQLIBMODULE::SFMPQLIBMODULE()
38 {
39         SFMpqMain(0,DLL_PROCESS_ATTACH,0);
40 }
42 SFMPQLIBMODULE::~SFMPQLIBMODULE()
43 {
44         SFMpqDestroy();
45         SFMpqMain(0,DLL_PROCESS_DETACH,0);
46 }
48 #endif
50 LCID LocaleID = 0;
51 BOOL SFMpqInit = FALSE;
52 HINSTANCE hStorm = 0;
53 #ifdef _USRDLL
54 HINSTANCE hSFMpqInstance = 0;
55 #endif
57 #define SFMPQ_CURRENT_VERSION {1,0,8,1}
59 SFMPQVERSION SFMpqVersion = SFMPQ_CURRENT_VERSION;
60 LPCSTR SFMpqVersionString = "ShadowFlare MPQ API Library v1.08";
61 float MpqVersion = 2.00;
63 // Class to simulate _alloca for cross-compiler compatibility
64 class TempAlloc {
65 public:
66         TempAlloc();
67         ~TempAlloc();
68         TempAlloc(unsigned long int AllocSize);
69         void * Alloc(unsigned long int AllocSize);
70         void *lpAllocAddress;
71 };
73 LPCSTR ID_MPQ = "MPQ\x1A";
74 LPCSTR ID_BN3 = "BN3\x1A";
75 LPCSTR ID_RIFF = "RIFF";
76 LPCSTR ID_WAVE = "WAVEfmt ";
77 LPCSTR INTERNAL_LISTFILE = "(listfile)";
78 LPCSTR INTERNAL_FILES = "(attributes)\n(listfile)\n(signature)";
79 LPCSTR Storm_dll = "Storm.dll";
80 LPCSTR UNKNOWN_OUT = "~unknowns\\unknown_%08x";
81 LPCSTR UNKNOWN_IN = "~unknowns\\unknown_%x";
82 LPCSTR UNKNOWN_CMP = "~unknowns\\unknown_";
83 #define UNKNOWN_LEN 18
85 LCID availLocales[7] = {0x0000,0x0407,0x0409,0x040A,0x040C,0x0410,0x0416};
86 #define nLocales 7
88 #define MAX_MPQ_PATH 260;
90 #define HASH_POSITION 0
91 #define HASH_NAME_A 1
92 #define HASH_NAME_B 2
93 #define HASH_KEY 3
95 BOOL bCryptTableInit = FALSE;
96 DWORD dwCryptTable[0x500];
97 DWORD dwHashTableKey;
98 DWORD dwBlockTableKey;
99 MPQARCHIVE **lpOpenMpq = 0;
100 DWORD dwOpenMpqCount = 0;
101 MPQARCHIVE * FirstLastMpq[2] = {0,0};
102 MPQFILE **lpOpenFile = 0;
103 DWORD dwOpenFileCount = 0;
104 MPQFILE * FirstLastFile[2] = {0,0};
106 char StormBasePath[MAX_PATH+1];
108 #define UNSUPPORTED_COMPRESSION   (0xFF ^ (0x40 | 0x80 | 0x01 | 0x02 | 0x08 | 0x10))
109 #define UNSUPPORTED_DECOMPRESSION (0xFF ^ (0x40 | 0x80 | 0x01 | 0x02 | 0x08 | 0x10))
111 typedef BOOL (WINAPI* funcSCompCompress)(LPVOID lpvDestinationMem, LPDWORD lpdwCompressedSize, LPVOID lpvSourceMem, DWORD dwDecompressedSize, DWORD dwCompressionType, DWORD dwCompressionSubType, DWORD dwWAVQuality);
112 typedef BOOL (WINAPI* funcSCompDecompress)(LPVOID lpvDestinationMem, LPDWORD lpdwDecompressedSize, LPVOID lpvSourceMem, DWORD dwCompressedSize);
113 funcSCompCompress stormSCompCompress = 0;
114 funcSCompDecompress stormSCompDecompress = 0;
116 void LoadStorm();
117 void FreeStorm();
119 LPVOID WINAPI SFAlloc(DWORD dwSize);
120 void WINAPI SFFree(LPVOID lpvMemory);
121 void WINAPI SFMemZero(LPVOID lpvDestination, DWORD dwLength);
122 BOOL WINAPI MpqOpenArchiveEx(LPCSTR lpFileName, DWORD dwPriority, DWORD dwFlags, MPQHANDLE *hMPQ, DWORD dwFlags2, DWORD dwMaximumFilesInArchive, DWORD dwBlockSize);
123 DWORD WINAPI FindMpqHeaderAtLocation(HANDLE hFile, DWORD dwStart, DWORD dwLength);
124 DWORD GetFullPath(LPCSTR lpFileName, char *lpBuffer, DWORD dwBufferLength);
125 MPQHANDLE GetHashTableEntry(MPQHANDLE hMPQ, LPCSTR lpFileName, LCID FileLocale);
126 MPQHANDLE GetHashTableEntryOfHash(MPQHANDLE hMPQ, DWORD dwTablePos, DWORD dwNameHashA, DWORD dwNameHashB, LCID FileLocale);
127 MPQHANDLE GetFreeHashTableEntry(MPQHANDLE hMPQ, LPCSTR lpFileName, LCID FileLocale, BOOL ReturnExisting);
128 BOOL SearchOpenArchives(LPCSTR lpFileName, MPQHANDLE *hMPQ, MPQHANDLE *hFile);
129 void SortOpenArchivesByPriority();
130 DWORD GetHandleType(MPQHANDLE hFile);
131 BOOL AddToInternalListing(MPQHANDLE hMPQ, LPCSTR lpFileName);
132 BOOL RemoveFromInternalListing(MPQHANDLE hMPQ, LPCSTR lpFileName);
133 size_t strlnlen(const char *strline);
134 char *nextline(const char *strline);
135 BOOL InitCryptTable();
136 DWORD HashString(LPCSTR lpszString, DWORD dwHashType);
137 BOOL EncryptData(LPBYTE lpbyBuffer, DWORD dwLength, DWORD dwKey);
138 BOOL DecryptData(LPBYTE lpbyBuffer, DWORD dwLength, DWORD dwKey);
139 static DWORD DetectFileSeed(DWORD * block, DWORD decrypted, DWORD blocksize);
140 DWORD DetectFileSeedEx(MPQARCHIVE * mpqOpenArc, HASHTABLEENTRY * lpHashEntry, LPCSTR * lplpFileName);
142 BOOL APIENTRY DllMain( HINSTANCE hInstDLL, 
143                        DWORD  ul_reason_for_call, 
144                        LPVOID lpReserved
145                                          )
147 #ifdef _WIN32
148         char *lpExeName,*buffer;DWORD slen;
149 #endif
150         DWORD dwLastCount;
152 #ifdef _USRDLL
153         hSFMpqInstance = hInstDLL;
154 #endif
156     switch (ul_reason_for_call)
157         {
158                 case DLL_PROCESS_ATTACH:
159                         InitCryptTable();
160                         dwHashTableKey = HashString("(hash table)",HASH_KEY);
161                         dwBlockTableKey = HashString("(block table)",HASH_KEY);
162 #ifdef _WIN32
163                         lpExeName = (char *)SFAlloc(MAX_PATH+1);
164                         if (lpExeName) {
165                                 slen = GetModuleFileName(0,lpExeName,MAX_PATH);
166                                 lpExeName[slen] = 0;
167                                 buffer = lpExeName+strlen(lpExeName);
168                                 while (*buffer!='\\') {*buffer = 0;buffer--;}
169                                 SFileSetBasePath(lpExeName);
170                                 SFFree(lpExeName);
171                         }
172 #else
173                         SFileSetBasePath("./");
174 #endif
175                         break;
176                 case DLL_THREAD_ATTACH:
177                         break;
178                 case DLL_THREAD_DETACH:
179                         break;
180                 case DLL_PROCESS_DETACH:
181                         if (lpOpenFile) {
182                                 while (dwOpenFileCount>0) {
183                                         dwLastCount = dwOpenFileCount;
184                                         SFileCloseFile((MPQHANDLE)lpOpenFile[dwOpenFileCount-1]);
185                                         if (dwLastCount==dwOpenFileCount) dwOpenFileCount--;
186                                 }
188                                 SFFree(lpOpenFile);
189                         }
191                         if (lpOpenMpq) {
192                                 while (dwOpenMpqCount>0) {
193                                         dwLastCount = dwOpenMpqCount;
194                                         SFileCloseArchive((MPQHANDLE)lpOpenMpq[dwOpenMpqCount-1]);
195                                         if (dwLastCount==dwOpenMpqCount) dwOpenMpqCount--;
196                                 }
198                                 SFFree(lpOpenMpq);
199                         }
200                         break;
201     }
203     return TRUE;
206 LPVOID WINAPI SFAlloc(DWORD dwSize)
208         LPVOID lpMemory = malloc(dwSize);
209         if (lpMemory) SFMemZero(lpMemory,dwSize);
210         return lpMemory;
213 void WINAPI SFFree(LPVOID lpvMemory)
215         if (lpvMemory) free(lpvMemory);
218 void WINAPI SFMemZero(LPVOID lpvDestination, DWORD dwLength)
220         DWORD dwPrevLen = dwLength;
221         LPDWORD lpdwDestination = (LPDWORD)lpvDestination;
222         LPBYTE lpbyDestination;
224         dwLength >>= 2;
226         while (dwLength--)
227                 *lpdwDestination++ = 0;
229         lpbyDestination = (LPBYTE)lpdwDestination;
231         dwLength = dwPrevLen;
232         dwLength &= 3;
234         while (dwLength--)
235                 *lpbyDestination++ = 0;
238 TempAlloc::TempAlloc()
240         lpAllocAddress = 0;
243 TempAlloc::TempAlloc(unsigned long int AllocSize)
245         lpAllocAddress = SFAlloc(AllocSize);
248 TempAlloc::~TempAlloc()
250         if (lpAllocAddress) {
251                 SFFree(lpAllocAddress);
252                 lpAllocAddress = 0;
253         }
256 void * TempAlloc::Alloc(unsigned long int AllocSize)
258         lpAllocAddress = SFAlloc(AllocSize);
259         return lpAllocAddress;
262 SFMPQAPIMODULE::SFMPQAPIMODULE()
264         //LoadStorm();
267 SFMPQAPIMODULE::~SFMPQAPIMODULE()
269         FreeStorm();
272 BOOL SFMPQAPI WINAPI SFileDestroy() {
273         return TRUE;
276 void SFMPQAPI WINAPI StormDestroy() {
279 void SFMPQAPI WINAPI SFMpqDestroy() {
280         //FreeStorm();
283 BOOL SFMPQAPI WINAPI MpqInitialize()
285         return (SFMpqInit=TRUE);
288 LPCSTR SFMPQAPI WINAPI MpqGetVersionString()
290         return SFMpqVersionString;
293 float SFMPQAPI WINAPI MpqGetVersion()
295         return MpqVersion;
298 LPCSTR SFMPQAPI WINAPI SFMpqGetVersionString()
300         return SFMpqVersionString;
303 DWORD  SFMPQAPI WINAPI SFMpqGetVersionString2(LPCSTR lpBuffer, DWORD dwBufferLength)
305         if (!lpBuffer) {
306                 SetLastError(ERROR_INVALID_PARAMETER);
307                 return strlen(SFMpqVersionString)+1;
308         }
310         DWORD slen = strlen(SFMpqVersionString)+1;
312         if (dwBufferLength>=slen) memcpy((void *)lpBuffer,SFMpqVersionString,slen);
313         else memcpy((void *)lpBuffer,SFMpqVersionString,dwBufferLength);
315         return slen;
318 SFMPQVERSION SFMPQAPI WINAPI SFMpqGetVersion()
320         return SFMpqVersion;
323 void SFMPQAPI WINAPI AboutSFMpq()
325 #ifdef _USRDLL
326         if (hSFMpqInstance) {
327                 char szAboutPage[MAX_PATH+13];
328                 strcpy(szAboutPage,"res://");
329                 GetModuleFileName(hSFMpqInstance,szAboutPage+6,MAX_PATH);
330                 strcat(szAboutPage,"/about");
331                 ShellExecute(0,0,szAboutPage,0,0,SW_SHOWNORMAL);
332         }
333 #endif
336 BOOL WINAPI MpqOpenArchiveEx(LPCSTR lpFileName, DWORD dwPriority, DWORD dwFlags, MPQHANDLE *hMPQ, DWORD dwFlags2, DWORD dwMaximumFilesInArchive, DWORD dwBlockSize)
338         DWORD flen,tsz;
340         if (!lpFileName || !hMPQ) {
341                 SetLastError(ERROR_INVALID_PARAMETER);
342                 if (hMPQ) *hMPQ = 0;
343                 return FALSE;
344         }
345         if (!*lpFileName) {
346                 SetLastError(ERROR_INVALID_PARAMETER);
347                 *hMPQ = 0;
348                 return FALSE;
349         }
351         DWORD dwFlags1 = 0;
353 #ifdef _WIN32
354         char RootPath[4];
355         memset(RootPath,0,4);
356         if (memcmp(lpFileName+1,":\\",2)==0) memcpy(RootPath,lpFileName,3);
357         else {
358                 char CurDir[MAX_PATH];
359                 GetCurrentDirectory(MAX_PATH,CurDir);
360                 memcpy(RootPath,CurDir,3);
361         }
362         if (GetDriveType(RootPath)==DRIVE_CDROM)
363                 dwFlags1 |= 2;
364         else if (dwFlags&2)
365                 dwFlags1 |= 1;
366         if (dwFlags & SFILE_OPEN_CD_ROM_FILE)
367                 if (!(dwFlags1&2)) {*hMPQ = 0;return FALSE;}
368 #endif
370         DWORD dwCreateFlags,dwAccessFlags,dwShareFlags;
371         if (dwFlags2 & MOAU_OPEN_ALWAYS) dwCreateFlags = OPEN_ALWAYS;
372         else if (dwFlags2 & MOAU_CREATE_ALWAYS) dwCreateFlags = CREATE_ALWAYS;
373         else if (dwFlags2 & MOAU_OPEN_EXISTING) dwCreateFlags = OPEN_EXISTING;
374         else dwCreateFlags = CREATE_NEW;
375         if (dwFlags2 & MOAU_READ_ONLY) {
376                 if (!(dwFlags2 & MOAU_OPEN_EXISTING)) {
377                         SetLastError(MPQ_ERROR_BAD_OPEN_MODE);
378                         *hMPQ = 0;
379                         return FALSE;
380                 }
381                 dwAccessFlags = GENERIC_READ;
382                 if (dwFlags2 & SFILE_OPEN_ALLOW_WRITE) dwFlags2 = dwFlags2^SFILE_OPEN_ALLOW_WRITE;
383         }
384         else {
385                 dwAccessFlags = GENERIC_READ|GENERIC_WRITE;
386                 dwFlags2 = dwFlags2|SFILE_OPEN_ALLOW_WRITE;
387         }
388         if (dwAccessFlags & GENERIC_WRITE)
389                 dwShareFlags = 0;
390         else
391                 dwShareFlags = FILE_SHARE_READ;
392         HANDLE hFile;
393         hFile = CreateFile(lpFileName,dwAccessFlags,dwShareFlags,0,dwCreateFlags,0,0);
394         TempAlloc NewAlloc;
395         if (hFile==INVALID_HANDLE_VALUE) {
396                 DWORD namelen = GetFullPath(lpFileName,0,0);
397                 char *namebuffer = (char *)NewAlloc.Alloc(namelen);
398                 GetFullPath(lpFileName,namebuffer,namelen);
399                 lpFileName = namebuffer;
400                 hFile = CreateFile(lpFileName,dwAccessFlags,dwShareFlags,0,dwCreateFlags,0,0);
401         }
402         if (hFile!=INVALID_HANDLE_VALUE)
403         {
404                 MPQARCHIVE **lpnOpenMpq = (MPQARCHIVE **)SFAlloc(sizeof(MPQARCHIVE *) * (dwOpenMpqCount+1));
405                 if (lpnOpenMpq==0) {
406                         CloseHandle(hFile);
407                         *hMPQ = 0;
408                         return FALSE;
409                 }
410                 DWORD dwMpqStart;
411                 MPQARCHIVE *mpqOpenArc;
412                 if (GetFileSize(hFile,0)==0 && !(dwFlags2 & MOAU_READ_ONLY))
413                 {
414                         dwMpqStart = 0;
415                         mpqOpenArc = (MPQARCHIVE *)SFAlloc(sizeof(MPQARCHIVE));
416                         if (!mpqOpenArc) {
417                                 SFFree(lpnOpenMpq);
418                                 CloseHandle(hFile);
419                                 *hMPQ = 0;
420                                 return FALSE;
421                         }
422                         memcpy(&mpqOpenArc->MpqHeader.dwMPQID,ID_MPQ,4);
423                         mpqOpenArc->MpqHeader.dwHeaderSize = sizeof(MPQHEADER);
424                         mpqOpenArc->MpqHeader.wUnused0C = 0;
425                         if (dwBlockSize & 0xFFFF0000)
426                                 mpqOpenArc->MpqHeader.wBlockSize = DEFAULT_BLOCK_SIZE;
427                         else
428                                 mpqOpenArc->MpqHeader.wBlockSize = (WORD)dwBlockSize;
429                         DWORD i;
430                         for (i=1;i<dwMaximumFilesInArchive;i*=2) {}
431                         dwMaximumFilesInArchive = i;
432                         mpqOpenArc->MpqHeader.dwHashTableSize = dwMaximumFilesInArchive;
433                         mpqOpenArc->MpqHeader.dwBlockTableSize = 0;
434                         mpqOpenArc->MpqHeader.dwHashTableOffset = mpqOpenArc->MpqHeader.dwHeaderSize;
435                         mpqOpenArc->MpqHeader.dwBlockTableOffset = mpqOpenArc->MpqHeader.dwHeaderSize + mpqOpenArc->MpqHeader.dwHashTableSize * sizeof(HASHTABLEENTRY);
436                         mpqOpenArc->MpqHeader.dwMPQSize = mpqOpenArc->MpqHeader.dwHeaderSize + mpqOpenArc->MpqHeader.dwHashTableSize * sizeof(HASHTABLEENTRY);
437                         if(WriteFile(hFile,&mpqOpenArc->MpqHeader,mpqOpenArc->MpqHeader.dwHeaderSize,&tsz,0)==0) {
438                                 SFFree(lpnOpenMpq);
439                                 SFFree(mpqOpenArc);
440                                 CloseHandle(hFile);
441                                 *hMPQ = 0;
442                                 return FALSE;
443                         }
444                         flen = mpqOpenArc->MpqHeader.dwMPQSize;
445                         mpqOpenArc->lpHashTable = (HASHTABLEENTRY *)SFAlloc(sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize);
446                         if(!mpqOpenArc->lpHashTable) {
447                                 SFFree(lpnOpenMpq);
448                                 SFFree(mpqOpenArc);
449                                 CloseHandle(hFile);
450                                 *hMPQ = 0;
451                                 return FALSE;
452                         }
453                         memset(mpqOpenArc->lpHashTable,0xFF,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize);
454                         EncryptData((LPBYTE)mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,dwHashTableKey);
455                         if(WriteFile(hFile,mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,&tsz,0)==0) {
456                                 SFFree(mpqOpenArc->lpHashTable);
457                                 SFFree(lpnOpenMpq);
458                                 SFFree(mpqOpenArc);
459                                 CloseHandle(hFile);
460                                 *hMPQ = 0;
461                                 return FALSE;
462                         }
463                 }
464                 else
465                 {
466                         dwMpqStart = SFileFindMpqHeader(hFile);
467                         if (dwMpqStart==0xFFFFFFFF) {
468                                 SFFree(lpnOpenMpq);
469                                 CloseHandle(hFile);
470                                 SetLastError(MPQ_ERROR_MPQ_INVALID);
471                                 *hMPQ = 0;
472                                 return FALSE;
473                         }
474                         flen = GetFileSize(hFile,0);
475                         mpqOpenArc = (MPQARCHIVE *)SFAlloc(sizeof(MPQARCHIVE));
476                         if (!mpqOpenArc) {
477                                 SFFree(lpnOpenMpq);
478                                 CloseHandle(hFile);
479                                 *hMPQ = 0;
480                                 return FALSE;
481                         }
482                         SetFilePointer(hFile,dwMpqStart,0,FILE_BEGIN);
483                         if(ReadFile(hFile,&mpqOpenArc->MpqHeader,sizeof(MPQHEADER),&tsz,0)==0) {
484                                 SFFree(lpnOpenMpq);
485                                 SFFree(mpqOpenArc);
486                                 CloseHandle(hFile);
487                                 *hMPQ = 0;
488                                 return FALSE;
489                         }
490                         mpqOpenArc->lpHashTable = (HASHTABLEENTRY *)SFAlloc(sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize);
491                         if(!mpqOpenArc->lpHashTable) {
492                                 SFFree(lpnOpenMpq);
493                                 SFFree(mpqOpenArc);
494                                 CloseHandle(hFile);
495                                 *hMPQ = 0;
496                                 return FALSE;
497                         }
498                         if (mpqOpenArc->MpqHeader.dwBlockTableSize!=0) {
499                                 mpqOpenArc->lpBlockTable = (BLOCKTABLEENTRY *)SFAlloc(sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize);
500                                 if(!mpqOpenArc->lpBlockTable) {
501                                         SFFree(mpqOpenArc->lpHashTable);
502                                         SFFree(lpnOpenMpq);
503                                         SFFree(mpqOpenArc);
504                                         CloseHandle(hFile);
505                                         *hMPQ = 0;
506                                         return FALSE;
507                                 }
508                         }
509                         SetFilePointer(hFile,dwMpqStart+mpqOpenArc->MpqHeader.dwHashTableOffset,0,FILE_BEGIN);
510                         if(ReadFile(hFile,mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,&tsz,0)==0) {
511                                 if(mpqOpenArc->lpBlockTable) SFFree(mpqOpenArc->lpBlockTable);
512                                 SFFree(mpqOpenArc->lpHashTable);
513                                 SFFree(lpnOpenMpq);
514                                 SFFree(mpqOpenArc);
515                                 CloseHandle(hFile);
516                                 *hMPQ = 0;
517                                 return FALSE;
518                         }
519                         if (mpqOpenArc->MpqHeader.dwBlockTableSize!=0) {
520                                 SetFilePointer(hFile,dwMpqStart+mpqOpenArc->MpqHeader.dwBlockTableOffset,0,FILE_BEGIN);
521                                 if(ReadFile(hFile,mpqOpenArc->lpBlockTable,sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize,&tsz,0)==0) {
522                                         SFFree(mpqOpenArc->lpBlockTable);
523                                         SFFree(mpqOpenArc->lpHashTable);
524                                         SFFree(lpnOpenMpq);
525                                         SFFree(mpqOpenArc);
526                                         CloseHandle(hFile);
527                                         *hMPQ = 0;
528                                         return FALSE;
529                                 }
530                         }
531                 }
532                 /*mpqOpenArc->lpFileName = (char *)SFAlloc(strlen(lpFileName)+1);
533                 if(!mpqOpenArc->lpFileName) {
534                         if(mpqOpenArc->lpBlockTable) SFFree(mpqOpenArc->lpBlockTable);
535                         SFFree(mpqOpenArc->lpHashTable);
536                         SFFree(lpnOpenMpq);
537                         SFFree(mpqOpenArc);
538                         CloseHandle(hFile);
539                         *hMPQ = 0;
540                         return FALSE;
541                 }*/
542                 DecryptData((LPBYTE)mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,dwHashTableKey);
543                 if (mpqOpenArc->lpBlockTable) DecryptData((LPBYTE)mpqOpenArc->lpBlockTable,sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize,dwBlockTableKey);
544                 mpqOpenArc->lpFileName = mpqOpenArc->szFileName;
545                 strncpy(mpqOpenArc->lpFileName,lpFileName,259);
546                 if (FirstLastMpq[1]) FirstLastMpq[1]->lpNextArc = mpqOpenArc;
547                 mpqOpenArc->lpNextArc = (MPQARCHIVE *)FirstLastMpq;
548                 mpqOpenArc->lpPrevArc = (MPQARCHIVE *)FirstLastMpq[1];
549                 if (!FirstLastMpq[0]) {
550                         mpqOpenArc->lpPrevArc = (MPQARCHIVE *)0xEAFC5E23;
551                         FirstLastMpq[0] = mpqOpenArc;
552                 }
553                 FirstLastMpq[1] = mpqOpenArc;
554                 mpqOpenArc->hFile = hFile;
555                 mpqOpenArc->dwFlags1 = dwFlags1;
556                 mpqOpenArc->dwPriority = dwPriority;
557                 mpqOpenArc->lpLastReadFile = 0;
558                 mpqOpenArc->dwUnk = 0;
559                 mpqOpenArc->dwBlockSize = 512 << mpqOpenArc->MpqHeader.wBlockSize;
560                 mpqOpenArc->lpLastReadBlock = 0;
561                 mpqOpenArc->dwBufferSize = 0;
562                 mpqOpenArc->dwMPQStart = dwMpqStart;
563                 mpqOpenArc->lpMPQHeader = &mpqOpenArc->MpqHeader;
564                 mpqOpenArc->dwReadOffset = flen;
565                 mpqOpenArc->dwRefCount = 1;
566                 mpqOpenArc->dwFlags = dwFlags2;
567                 mpqOpenArc->dwExtraFlags = 0;
568                 memcpy(lpnOpenMpq,lpOpenMpq,sizeof(MPQARCHIVE *) * dwOpenMpqCount);
569                 lpnOpenMpq[dwOpenMpqCount] = mpqOpenArc;
570                 if (lpOpenMpq) SFFree(lpOpenMpq);
571                 lpOpenMpq = lpnOpenMpq;
572                 dwOpenMpqCount++;
573                 if (dwOpenMpqCount>1) SortOpenArchivesByPriority();
574                 *hMPQ = (MPQHANDLE)mpqOpenArc;
575                 return TRUE;
576         }
577         else {
578                 if (dwFlags2&MOAU_OPEN_EXISTING) SetLastError(ERROR_FILE_NOT_FOUND);
579                 else if (dwFlags2&MOAU_CREATE_NEW) SetLastError(ERROR_ALREADY_EXISTS);
580                 *hMPQ = (MPQHANDLE)INVALID_HANDLE_VALUE;
581                 return FALSE;
582         }
585 BOOL SFMPQAPI WINAPI SFileOpenFileAsArchive(MPQHANDLE hSourceMPQ, LPCSTR lpFileName, DWORD dwPriority, DWORD dwFlags, MPQHANDLE *hMPQ)
587         DWORD flen,tsz;
589         if (!lpFileName || !hMPQ) {
590                 SetLastError(ERROR_INVALID_PARAMETER);
591                 if (hMPQ) *hMPQ = 0;
592                 return FALSE;
593         }
594         if (!*lpFileName) {
595                 SetLastError(ERROR_INVALID_PARAMETER);
596                 *hMPQ = 0;
597                 return FALSE;
598         }
600         HANDLE hFile;
601         if (SFileOpenFileEx(hSourceMPQ,lpFileName,1,&hFile))
602         {
603                 MPQFILE mpqArcFile;
604                 mpqArcFile = *(MPQFILE *)hFile;
605                 SFileCloseFile(hFile);
606                 if (mpqArcFile.hFile != INVALID_HANDLE_VALUE)
607                         return SFileOpenArchive(lpFileName,dwPriority,dwFlags,hMPQ);
608                 hFile = mpqArcFile.lpParentArc->hFile;
609                 MPQARCHIVE **lpnOpenMpq = (MPQARCHIVE **)SFAlloc(sizeof(MPQARCHIVE *) * (dwOpenMpqCount+1));
610                 if (!lpnOpenMpq) {
611                         *hMPQ = 0;
612                         return FALSE;
613                 }
614                 DWORD dwMpqStart;
615                 MPQARCHIVE *mpqOpenArc;
616                 dwMpqStart = mpqArcFile.lpBlockEntry->dwFileOffset;
617                 flen = mpqArcFile.lpBlockEntry->dwFullSize;
618                 dwMpqStart = FindMpqHeaderAtLocation(hFile,dwMpqStart,flen);
619                 if (dwMpqStart==0xFFFFFFFF) {
620                         SFFree(lpnOpenMpq);
621                         SetLastError(MPQ_ERROR_MPQ_INVALID);
622                         *hMPQ = 0;
623                         return FALSE;
624                 }
625                 mpqOpenArc = (MPQARCHIVE *)SFAlloc(sizeof(MPQARCHIVE));
626                 if (!mpqOpenArc) {
627                         SFFree(lpnOpenMpq);
628                         *hMPQ = 0;
629                         return FALSE;
630                 }
631                 SetFilePointer(hFile,dwMpqStart,0,FILE_BEGIN);
632                 if(ReadFile(hFile,&mpqOpenArc->MpqHeader,sizeof(MPQHEADER),&tsz,0)==0) {
633                         SFFree(lpnOpenMpq);
634                         SFFree(mpqOpenArc);
635                         *hMPQ = 0;
636                         return FALSE;
637                 }
638                 mpqOpenArc->lpHashTable = (HASHTABLEENTRY *)SFAlloc(sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize);
639                 if(!mpqOpenArc->lpHashTable) {
640                         SFFree(lpnOpenMpq);
641                         SFFree(mpqOpenArc);
642                         *hMPQ = 0;
643                         return FALSE;
644                 }
645                 if (mpqOpenArc->MpqHeader.dwBlockTableSize!=0) {
646                         mpqOpenArc->lpBlockTable = (BLOCKTABLEENTRY *)SFAlloc(sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize);
647                         if(!mpqOpenArc->lpBlockTable) {
648                                 SFFree(mpqOpenArc->lpHashTable);
649                                 SFFree(lpnOpenMpq);
650                                 SFFree(mpqOpenArc);
651                                 *hMPQ = 0;
652                                 return FALSE;
653                         }
654                 }
655                 SetFilePointer(hFile,dwMpqStart+mpqOpenArc->MpqHeader.dwHashTableOffset,0,FILE_BEGIN);
656                 if(ReadFile(hFile,mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,&tsz,0)==0) {
657                         if(mpqOpenArc->lpBlockTable) SFFree(mpqOpenArc->lpBlockTable);
658                         SFFree(mpqOpenArc->lpHashTable);
659                         SFFree(lpnOpenMpq);
660                         SFFree(mpqOpenArc);
661                         *hMPQ = 0;
662                         return FALSE;
663                 }
664                 if (mpqOpenArc->MpqHeader.dwBlockTableSize!=0) {
665                         SetFilePointer(hFile,dwMpqStart+mpqOpenArc->MpqHeader.dwBlockTableOffset,0,FILE_BEGIN);
666                         if(ReadFile(hFile,mpqOpenArc->lpBlockTable,sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize,&tsz,0)==0) {
667                                 SFFree(mpqOpenArc->lpBlockTable);
668                                 SFFree(mpqOpenArc->lpHashTable);
669                                 SFFree(lpnOpenMpq);
670                                 SFFree(mpqOpenArc);
671                                 *hMPQ = 0;
672                                 return FALSE;
673                         }
674                 }
675                 /*mpqOpenArc->lpFileName = (char *)SFAlloc(strlen(lpFileName)+1);
676                 if(!mpqOpenArc->lpFileName) {
677                         if(mpqOpenArc->lpBlockTable) SFFree(mpqOpenArc->lpBlockTable);
678                         SFFree(mpqOpenArc->lpHashTable);
679                         SFFree(lpnOpenMpq);
680                         SFFree(mpqOpenArc);
681                         *hMPQ = 0;
682                         return FALSE;
683                 }*/
684                 DecryptData((LPBYTE)mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,dwHashTableKey);
685                 if (mpqOpenArc->lpBlockTable) DecryptData((LPBYTE)mpqOpenArc->lpBlockTable,sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize,dwBlockTableKey);
686                 mpqOpenArc->lpFileName = mpqOpenArc->szFileName;
687                 strncpy(mpqOpenArc->lpFileName,lpFileName,259);
688                 if (FirstLastMpq[1]) FirstLastMpq[1]->lpNextArc = mpqOpenArc;
689                 mpqOpenArc->lpNextArc = (MPQARCHIVE *)FirstLastMpq;
690                 mpqOpenArc->lpPrevArc = (MPQARCHIVE *)FirstLastMpq[1];
691                 if (!FirstLastMpq[0]) {
692                         mpqOpenArc->lpPrevArc = (MPQARCHIVE *)0xEAFC5E23;
693                         FirstLastMpq[0] = mpqOpenArc;
694                 }
695                 FirstLastMpq[1] = mpqOpenArc;
696                 mpqOpenArc->hFile = hFile;
697                 mpqOpenArc->dwFlags1 = 0;
698                 mpqOpenArc->dwPriority = dwPriority;
699                 mpqOpenArc->lpLastReadFile = 0;
700                 mpqOpenArc->dwUnk = 0;
701                 mpqOpenArc->dwBlockSize = 512 << mpqOpenArc->MpqHeader.wBlockSize;
702                 mpqOpenArc->lpLastReadBlock = 0;
703                 mpqOpenArc->dwBufferSize = 0;
704                 mpqOpenArc->dwMPQStart = dwMpqStart;
705                 mpqOpenArc->lpMPQHeader = &mpqOpenArc->MpqHeader;
706                 mpqOpenArc->dwReadOffset = flen;
707                 mpqOpenArc->dwRefCount = 1;
708                 mpqOpenArc->dwFlags = dwFlags;
709                 mpqOpenArc->dwExtraFlags = 1;
710                 memcpy(lpnOpenMpq,lpOpenMpq,sizeof(MPQARCHIVE *) * dwOpenMpqCount);
711                 lpnOpenMpq[dwOpenMpqCount] = mpqOpenArc;
712                 if (lpOpenMpq) SFFree(lpOpenMpq);
713                 lpOpenMpq = lpnOpenMpq;
714                 dwOpenMpqCount++;
715                 if (dwOpenMpqCount>1) SortOpenArchivesByPriority();
716                 *hMPQ = (MPQHANDLE)mpqOpenArc;
717                 return TRUE;
718         }
719         else {
720                 *hMPQ = (MPQHANDLE)INVALID_HANDLE_VALUE;
721                 return FALSE;
722         }
725 BOOL SFMPQAPI WINAPI SFileOpenArchive(LPCSTR lpFileName, DWORD dwPriority, DWORD dwFlags, MPQHANDLE *hMPQ)
727         if (dwFlags & SFILE_OPEN_ALLOW_WRITE) {
728                 return MpqOpenArchiveEx(lpFileName,dwPriority,dwFlags ^ SFILE_OPEN_ALLOW_WRITE,hMPQ,MOAU_OPEN_EXISTING,0,USE_DEFAULT_BLOCK_SIZE);
729         }
730         else {
731                 return MpqOpenArchiveEx(lpFileName,dwPriority,dwFlags,hMPQ,MOAU_OPEN_EXISTING|MOAU_READ_ONLY,0,USE_DEFAULT_BLOCK_SIZE);
732         }
735 BOOL SFMPQAPI WINAPI SFileCloseArchive(MPQHANDLE hMPQ)
737         if (hMPQ==0) {
738                 SetLastError(ERROR_INVALID_PARAMETER);
739                 return FALSE;
740         }
742         MPQARCHIVE *mpqOpenArc = (MPQARCHIVE *)hMPQ;
743         if (dwOpenMpqCount==0) return FALSE;
744         if (memcmp(&mpqOpenArc->MpqHeader.dwMPQID,ID_MPQ,4)!=0 && memcmp(&mpqOpenArc->MpqHeader.dwMPQID,ID_BN3,4)!=0) return FALSE;
745         if (!(mpqOpenArc->dwExtraFlags & 1)) CloseHandle(mpqOpenArc->hFile);
746         //SFFree(mpqOpenArc->lpFileName);
747         SFFree(mpqOpenArc->lpHashTable);
748         if(mpqOpenArc->lpBlockTable) SFFree(mpqOpenArc->lpBlockTable);
749         if ((DWORD)mpqOpenArc->lpNextArc!=(DWORD)FirstLastMpq)
750                 mpqOpenArc->lpNextArc->lpPrevArc = mpqOpenArc->lpPrevArc;
751         if ((DWORD)mpqOpenArc->lpPrevArc!=0xEAFC5E23)
752                 mpqOpenArc->lpPrevArc->lpNextArc = mpqOpenArc->lpNextArc;
753         if (mpqOpenArc==FirstLastMpq[0])
754                 FirstLastMpq[0] = mpqOpenArc->lpNextArc;
755         if ((DWORD)FirstLastMpq[0]==(DWORD)FirstLastMpq)
756                 FirstLastMpq[0] = 0;
757         if (mpqOpenArc==FirstLastMpq[1])
758                 FirstLastMpq[1] = mpqOpenArc->lpPrevArc;
759         if ((DWORD)FirstLastMpq[1]==0xEAFC5E23)
760                 FirstLastMpq[1] = 0;
761         SFFree(mpqOpenArc);
762         if (!lpOpenMpq) return TRUE;
763         if (dwOpenMpqCount-1==0) {
764                 SFFree(lpOpenMpq);
765                 lpOpenMpq = 0;
766                 dwOpenMpqCount--;
767                 return TRUE;
768         }
769         else if (dwOpenMpqCount==0) return FALSE;
770         MPQARCHIVE **lpnOpenMpq = (MPQARCHIVE **)SFAlloc(sizeof(MPQARCHIVE *) * (dwOpenMpqCount-1));
771         if (lpnOpenMpq) {
772                 for (DWORD i=0,j=0;i<dwOpenMpqCount;i++) {
773                         if ((MPQHANDLE)lpOpenMpq[i]!=hMPQ) {
774                                 memcpy(&lpnOpenMpq[j],&lpOpenMpq[i],sizeof(MPQARCHIVE *));
775                                 j++;
776                         }
777                 }
778                 SFFree(lpOpenMpq);
779                 lpOpenMpq = lpnOpenMpq;
780                 dwOpenMpqCount--;
781         }
782         else {
783                 for (DWORD i=0,j=0;i<dwOpenMpqCount;i++) {
784                         if ((MPQHANDLE)lpOpenMpq[i]==hMPQ) {
785                                 lpOpenMpq[i] = (MPQARCHIVE *)0;
786                         }
787                         else {
788                                 if (i!=j) memcpy(&lpOpenMpq[j],&lpOpenMpq[i],sizeof(MPQARCHIVE *));
789                                 j++;
790                         }
791                 }
792                 dwOpenMpqCount--;
793         }
794         return TRUE;
797 BOOL SFMPQAPI WINAPI SFileGetArchiveName(MPQHANDLE hMPQ, LPCSTR lpBuffer, DWORD dwBufferLength)
799         if (hMPQ==0 || lpBuffer==0) {
800                 SetLastError(ERROR_INVALID_PARAMETER);
801                 return FALSE;
802         }
804         DWORD dwhType = GetHandleType(hMPQ);
805         char *lpFileName;
806         if (dwhType==SFILE_TYPE_MPQ) lpFileName = ((MPQARCHIVE *)hMPQ)->lpFileName;
807         else if (dwhType==SFILE_TYPE_FILE) lpFileName = ((MPQFILE *)hMPQ)->lpFileName;
808         else return FALSE;
809         DWORD slen = strlen(lpFileName)+1;
810         if (dwBufferLength>=slen) memcpy((void *)lpBuffer,lpFileName,slen);
811         else memcpy((void *)lpBuffer,lpFileName,dwBufferLength);
812         return TRUE;
815 BOOL SFMPQAPI WINAPI SFileOpenFile(LPCSTR lpFileName, MPQHANDLE *hFile)
817         return SFileOpenFileEx(0,lpFileName,SFILE_SEARCH_CURRENT_ONLY,hFile);
820 BOOL WINAPI IsHexDigit(char nChar)
822         switch (nChar) {
823                 case '0':
824                 case '1':
825                 case '2':
826                 case '3':
827                 case '4':
828                 case '5':
829                 case '6':
830                 case '7':
831                 case '8':
832                 case '9':
833                 case 'A':
834                 case 'a':
835                 case 'B':
836                 case 'b':
837                 case 'C':
838                 case 'c':
839                 case 'D':
840                 case 'd':
841                 case 'E':
842                 case 'e':
843                 case 'F':
844                 case 'f':
845                         return TRUE;
846                 default:
847                         return FALSE;
848         }
849         return FALSE;
852 BOOL SFMPQAPI WINAPI SFileOpenFileEx(MPQHANDLE hMPQ, LPCSTR lpFileName, DWORD dwSearchScope, MPQHANDLE *hFile)
854         if (!lpFileName || !hFile) {
855                 SetLastError(ERROR_INVALID_PARAMETER);
856                 return FALSE;
857         }
858         if (!*lpFileName) {
859                 SetLastError(ERROR_INVALID_PARAMETER);
860                 return FALSE;
861         }
863         /*char szFileName[260];
864         if (hMPQ!=0) {
865                 if ((DWORD)lpFileName<((MPQARCHIVE *)hMPQ)->MpqHeader.dwHashTableSize) {
866                         sprintf(szFileName,UNKNOWN_OUT,(DWORD)lpFileName);
867                         lpFileName = szFileName;
868                         dwSearchScope = SFILE_SEARCH_CURRENT_ONLY;
869                 }
870         }
871         else {
872                 for (DWORD i=0;i<dwOpenMpqCount;i++) {
873                         if ((DWORD)lpFileName<lpOpenMpq[i]->MpqHeader.dwHashTableSize) {
874                                 SetLastError(ERROR_INVALID_PARAMETER);
875                                 return FALSE;
876                         }
877                 }
878         }*/
880         MPQFILE **lpnOpenFile = (MPQFILE **)SFAlloc(sizeof(MPQFILE *) * (dwOpenFileCount+1));
881         if (!lpnOpenFile) return FALSE;
883         MPQFILE *mpqOpenFile = (MPQFILE *)SFAlloc(sizeof(MPQFILE));
884         if (!mpqOpenFile) {
885                 SFFree(lpnOpenFile);
886                 return FALSE;
887         }
888         BOOL bFileOnDisk=FALSE;
889         MPQHANDLE hnMPQ,hnFile;
890         TempAlloc NewAlloc;
891         if (dwSearchScope==SFILE_SEARCH_CURRENT_ONLY) {
892                 if (hMPQ) {
893                         if (memicmp(lpFileName,UNKNOWN_CMP,UNKNOWN_LEN)==0 && IsHexDigit(lpFileName[UNKNOWN_LEN])) {
894                                 DWORD dwHashIndex;
895                                 sscanf(lpFileName,UNKNOWN_IN,&dwHashIndex);
896                                 hnFile = (HANDLE)&((MPQARCHIVE *)hMPQ)->lpHashTable[dwHashIndex];
897                                 if ((((HASHTABLEENTRY *)hnFile)->dwBlockTableIndex&0xFFFFFFFE)==0xFFFFFFFE)
898                                 {
899                                         SFFree(mpqOpenFile);
900                                         SFFree(lpnOpenFile);
901                                         SetLastError(ERROR_FILE_NOT_FOUND);
902                                         return FALSE;
903                                 }
904                         }
905                         else hnFile = GetHashTableEntry(hMPQ,lpFileName,LocaleID);
906                         hnMPQ = hMPQ;
907                 }
908                 else {
909                         SearchOpenArchives(lpFileName,&hnMPQ,&hnFile);
910                 }
911         }
912         else {
913                 SearchOpenArchives(lpFileName,&hnMPQ,&hnFile);
914                 if (!hnFile) {
915                         hnMPQ = 0;
916                         DWORD namelen = GetFullPath(lpFileName,0,0);
917                         char *namebuffer = (char *)NewAlloc.Alloc(namelen);
918                         GetFullPath(lpFileName,namebuffer,namelen);
919                         lpFileName = namebuffer;
920                         hnFile = CreateFile(lpFileName,GENERIC_READ,FILE_SHARE_READ,0,OPEN_EXISTING,0,0);
921                         if (hnFile==INVALID_HANDLE_VALUE) hnFile=0;
922                         else bFileOnDisk = TRUE;
923                 }
924         }
925         if (hnMPQ) {
926                 if(!((MPQARCHIVE *)hnMPQ)->lpBlockTable) {
927                         SFFree(mpqOpenFile);
928                         SFFree(lpnOpenFile);
929                         SetLastError(ERROR_FILE_NOT_FOUND);
930                         return FALSE;
931                 }
932         }
933         if (!hnFile) {
934                 SFFree(mpqOpenFile);
935                 SFFree(lpnOpenFile);
936                 SetLastError(ERROR_FILE_NOT_FOUND);
937                 return FALSE;
938         }
939         mpqOpenFile->lpFileName = (char *)SFAlloc(strlen(lpFileName)+1);
940         if (!mpqOpenFile->lpFileName) {
941                 SFFree(mpqOpenFile);
942                 SFFree(lpnOpenFile);
943                 return FALSE;
944         }
945         if (hnMPQ) {
946                 if (!(((MPQARCHIVE *)hnMPQ)->lpBlockTable[((HASHTABLEENTRY *)hnFile)->dwBlockTableIndex].dwFlags & MAFA_EXISTS)) {
947                         SFFree(mpqOpenFile->lpFileName);
948                         SFFree(mpqOpenFile);
949                         SFFree(lpnOpenFile);
950                         SetLastError(ERROR_FILE_INVALID);
951                         return FALSE;
952                 }
953         }
954         strcpy(mpqOpenFile->lpFileName,lpFileName);
955         if (!bFileOnDisk) {
956                 mpqOpenFile->lpParentArc = (MPQARCHIVE *)hnMPQ;
957                 mpqOpenFile->hFile = INVALID_HANDLE_VALUE;
958                 mpqOpenFile->lpHashEntry = (HASHTABLEENTRY *)hnFile;
959                 mpqOpenFile->lpBlockEntry = &((MPQARCHIVE *)hnMPQ)->lpBlockTable[mpqOpenFile->lpHashEntry->dwBlockTableIndex];
960                 mpqOpenFile->lpParentArc->dwRefCount++;
961                 if (mpqOpenFile->lpBlockEntry->dwFlags&MAFA_ENCRYPT) {
962                         LPSTR lpOldNameBuffer = mpqOpenFile->lpFileName;
963                         if (memicmp(mpqOpenFile->lpFileName,UNKNOWN_CMP,UNKNOWN_LEN)==0 && IsHexDigit(mpqOpenFile->lpFileName[UNKNOWN_LEN]))
964                                 mpqOpenFile->lpFileName = 0;
965                         mpqOpenFile->dwCryptKey = DetectFileSeedEx(mpqOpenFile->lpParentArc,mpqOpenFile->lpHashEntry,(LPCSTR *)&mpqOpenFile->lpFileName);
966                         if (memicmp(lpFileName,UNKNOWN_CMP,UNKNOWN_LEN)==0 && IsHexDigit(lpFileName[UNKNOWN_LEN])) {
967                                 if (!mpqOpenFile->lpFileName)
968                                         mpqOpenFile->lpFileName = lpOldNameBuffer;
969                                 else
970                                         SFFree(lpOldNameBuffer);
971                         }
972                         if (mpqOpenFile->dwCryptKey==0) {
973                                 SFFree(mpqOpenFile->lpFileName);
974                                 SFFree(mpqOpenFile);
975                                 SFFree(lpnOpenFile);
976                                 SetLastError(ERROR_FILE_INVALID);
977                                 return FALSE;
978                         }
979                 }
980         }
981         else {
982                 mpqOpenFile->hFile = hnFile;
983         }
984         strncpy(mpqOpenFile->szFileName,mpqOpenFile->lpFileName,259);
985         *hFile = (MPQHANDLE)mpqOpenFile;
986         memcpy(lpnOpenFile,lpOpenFile,sizeof(MPQFILE *) * dwOpenFileCount);
987         lpnOpenFile[dwOpenFileCount] = mpqOpenFile;
988         if (lpOpenFile) SFFree(lpOpenFile);
989         lpOpenFile = lpnOpenFile;
990         dwOpenFileCount++;
991         return TRUE;
994 BOOL SFMPQAPI WINAPI SFileCloseFile(MPQHANDLE hFile)
996         if (!hFile) {
997                 SetLastError(ERROR_INVALID_PARAMETER);
998                 return FALSE;
999         }
1001         MPQFILE *mpqOpenFile = (MPQFILE *)hFile;
1003         if (dwOpenFileCount==0) return FALSE;
1004         SFFree(mpqOpenFile->lpFileName);
1005         if (mpqOpenFile->lpdwBlockOffsets) SFFree(mpqOpenFile->lpdwBlockOffsets);
1006         if (mpqOpenFile->hFile == INVALID_HANDLE_VALUE) mpqOpenFile->lpParentArc->dwRefCount--;
1008         SFFree(mpqOpenFile);
1009         if (lpOpenFile==0) return TRUE;
1010         if (dwOpenFileCount-1==0) {
1011                 SFFree(lpOpenFile);
1012                 lpOpenFile = (MPQFILE **)0;
1013                 dwOpenFileCount--;
1014                 return TRUE;
1015         }
1016         else if (dwOpenFileCount==0) return FALSE;
1017         MPQFILE **lpnOpenFile = (MPQFILE **)SFAlloc(sizeof(MPQFILE *) * (dwOpenFileCount-1));
1018         if (lpnOpenFile) {
1019                 for (DWORD i=0,j=0;i<dwOpenFileCount;i++) {
1020                         if ((MPQHANDLE)lpOpenFile[i]!=hFile) {
1021                                 memcpy(&lpnOpenFile[j],&lpOpenFile[i],sizeof(MPQFILE *));
1022                                 j++;
1023                         }
1024                 }
1025                 SFFree(lpOpenFile);
1026                 lpOpenFile = lpnOpenFile;
1027                 dwOpenFileCount--;
1028         }
1029         else {
1030                 for (DWORD i=0,j=0;i<dwOpenFileCount;i++) {
1031                         if ((MPQHANDLE)lpOpenFile[i]==hFile) {
1032                                 lpOpenFile[i] = (MPQFILE *)0;
1033                         }
1034                         else {
1035                                 if (i!=j) memcpy(&lpOpenFile[j],&lpOpenFile[i],sizeof(MPQFILE *));
1036                                 j++;
1037                         }
1038                 }
1039                 dwOpenFileCount--;
1040         }
1041         return TRUE;
1044 DWORD SFMPQAPI WINAPI SFileGetFileSize(MPQHANDLE hFile, LPDWORD lpFileSizeHigh)
1046         if (!hFile) {
1047                 SetLastError(ERROR_INVALID_PARAMETER);
1048                 return (DWORD)-1;
1049         }
1051         MPQFILE *mpqOpenFile = (MPQFILE *)hFile;
1052         if (mpqOpenFile->hFile == INVALID_HANDLE_VALUE) {
1053                 if (lpFileSizeHigh) *lpFileSizeHigh = 0;
1054                 return mpqOpenFile->lpBlockEntry->dwFullSize;
1055         }
1056         else return GetFileSize(mpqOpenFile->hFile,lpFileSizeHigh);
1059 BOOL SFMPQAPI WINAPI SFileGetFileArchive(MPQHANDLE hFile, MPQHANDLE *hMPQ)
1061         if (!hFile || !hMPQ) {
1062                 SetLastError(ERROR_INVALID_PARAMETER);
1063                 return FALSE;
1064         }
1066         if (((MPQFILE *)hFile)->hFile == INVALID_HANDLE_VALUE) {
1067                 *hMPQ = (MPQHANDLE)((MPQFILE *)hFile)->lpParentArc;
1068                 return TRUE;
1069         }
1070         else {
1071                 SetLastError(ERROR_INVALID_PARAMETER);
1072                 return FALSE;
1073         }
1076 BOOL SFMPQAPI WINAPI SFileGetFileName(MPQHANDLE hFile, LPCSTR lpBuffer, DWORD dwBufferLength)
1078         return SFileGetArchiveName(hFile,lpBuffer,dwBufferLength);
1081 DWORD SFMPQAPI WINAPI SFileGetFileInfo(MPQHANDLE hFile, DWORD dwInfoType)
1083         if (!hFile) {
1084                 SetLastError(ERROR_INVALID_PARAMETER);
1085                 return (DWORD)-1;
1086         }
1087         if (dwInfoType==0) {
1088                 SetLastError(ERROR_UNKNOWN_PROPERTY);
1089                 return (DWORD)-1;
1090         }
1092         DWORD dwhType = GetHandleType(hFile);
1093         if (dwhType==SFILE_TYPE_FILE)
1094         {
1095                 MPQFILE *mpqOpenFile = (MPQFILE *)hFile;
1096                 if (mpqOpenFile->hFile == INVALID_HANDLE_VALUE) {
1097                         MPQARCHIVE *mpqOpenArc = mpqOpenFile->lpParentArc;
1098                         switch (dwInfoType) {
1099                         case SFILE_INFO_BLOCK_SIZE:
1100                                 return mpqOpenArc->MpqHeader.wBlockSize;
1101                         case SFILE_INFO_HASH_TABLE_SIZE:
1102                                 return mpqOpenArc->MpqHeader.dwHashTableSize;
1103                         case SFILE_INFO_NUM_FILES:
1104                                 return mpqOpenArc->MpqHeader.dwBlockTableSize;
1105                         case SFILE_INFO_TYPE:
1106                                 return SFILE_TYPE_FILE;
1107                         case SFILE_INFO_SIZE:
1108                                 return mpqOpenFile->lpBlockEntry->dwFullSize;
1109                         case SFILE_INFO_COMPRESSED_SIZE:
1110                                 return mpqOpenFile->lpBlockEntry->dwCompressedSize;
1111                         case SFILE_INFO_FLAGS:
1112                                 return mpqOpenFile->lpBlockEntry->dwFlags;
1113                         case SFILE_INFO_PARENT:
1114                                 return (DWORD)mpqOpenFile->lpParentArc;
1115                         case SFILE_INFO_POSITION:
1116                                 return mpqOpenFile->dwFilePointer;
1117                         case SFILE_INFO_LOCALEID:
1118                                 return mpqOpenFile->lpHashEntry->lcLocale;
1119                         case SFILE_INFO_PRIORITY:
1120                                 return mpqOpenArc->dwPriority;
1121                         case SFILE_INFO_HASH_INDEX:
1122                                 return ((DWORD)mpqOpenFile->lpHashEntry-(DWORD)mpqOpenArc->lpHashTable)/sizeof(HASHTABLEENTRY);
1123                         case SFILE_INFO_BLOCK_INDEX:
1124                                 return mpqOpenFile->lpHashEntry->dwBlockTableIndex;
1125                         default:
1126                                 SetLastError(ERROR_UNKNOWN_PROPERTY);
1127                                 return (DWORD)-1;
1128                         }
1129                 }
1130                 else {
1131                         switch (dwInfoType) {
1132                         case SFILE_INFO_TYPE:
1133                                 return SFILE_TYPE_FILE;
1134                         case SFILE_INFO_SIZE:
1135                                 return GetFileSize(mpqOpenFile->hFile,0);
1136                         case SFILE_INFO_COMPRESSED_SIZE:
1137                                 return GetFileSize(mpqOpenFile->hFile,0);
1138 #ifdef _WIN32
1139                         case SFILE_INFO_FLAGS:
1140                                 return GetFileAttributes(mpqOpenFile->lpFileName);
1141 #endif
1142                         case SFILE_INFO_POSITION:
1143                                 return SetFilePointer(mpqOpenFile->hFile,0,0,FILE_CURRENT);
1144                         default:
1145                                 SetLastError(ERROR_UNKNOWN_PROPERTY);
1146                                 return (DWORD)-1;
1148                         }
1149                 }
1150         }
1151         else if (dwhType==SFILE_TYPE_MPQ)
1152         {
1153                 MPQARCHIVE *mpqOpenArc = (MPQARCHIVE *)hFile;
1154                 switch (dwInfoType) {
1155                 case SFILE_INFO_BLOCK_SIZE:
1156                         return mpqOpenArc->MpqHeader.wBlockSize;
1157                 case SFILE_INFO_HASH_TABLE_SIZE:
1158                         return mpqOpenArc->MpqHeader.dwHashTableSize;
1159                 case SFILE_INFO_NUM_FILES:
1160                         return mpqOpenArc->MpqHeader.dwBlockTableSize;
1161                 case SFILE_INFO_TYPE:
1162                         return SFILE_TYPE_MPQ;
1163                 case SFILE_INFO_SIZE:
1164                         return mpqOpenArc->MpqHeader.dwMPQSize;
1165                 case SFILE_INFO_PRIORITY:
1166                         return mpqOpenArc->dwPriority;
1167                 default:
1168                         SetLastError(ERROR_UNKNOWN_PROPERTY);
1169                         return (DWORD)-1;
1170                 }
1171         }
1172         SetLastError(ERROR_INVALID_PARAMETER);
1173         return (DWORD)-1;
1176 DWORD SFMPQAPI WINAPI SFileSetFilePointer(MPQHANDLE hFile, long lDistanceToMove, PLONG lplDistanceToMoveHigh, DWORD dwMoveMethod)
1178         if (!hFile) {
1179                 SetLastError(ERROR_INVALID_PARAMETER);
1180                 return (DWORD)-1;
1181         }
1183         MPQFILE *mpqOpenFile = (MPQFILE *)hFile;
1184         if (mpqOpenFile->hFile == INVALID_HANDLE_VALUE) {
1185                 long fsz = mpqOpenFile->lpBlockEntry->dwFullSize;
1186                 long cpos = mpqOpenFile->dwFilePointer;
1187                 switch (dwMoveMethod) {
1188                 case FILE_BEGIN:
1189                         if (lDistanceToMove<0 || lDistanceToMove>fsz) return (DWORD)-1;
1190                         mpqOpenFile->dwFilePointer = lDistanceToMove;
1191                         break;
1192                 case FILE_CURRENT:
1193                         if (lDistanceToMove<cpos || cpos+lDistanceToMove>fsz) return (DWORD)-1;
1194                         mpqOpenFile->dwFilePointer += lDistanceToMove;
1195                         break;
1197                 case FILE_END:
1198                         if (lDistanceToMove<fsz || lDistanceToMove>0) return (DWORD)-1;
1199                         mpqOpenFile->dwFilePointer = fsz+lDistanceToMove;
1200                         break;
1201                 default:
1202                         if (lDistanceToMove<0 || lDistanceToMove>fsz) return (DWORD)-1;
1203                         mpqOpenFile->dwFilePointer = lDistanceToMove;
1204                 }
1205                 if (lplDistanceToMoveHigh!=0) *lplDistanceToMoveHigh = 0;
1206                 return mpqOpenFile->dwFilePointer;
1207         }
1208         else return SetFilePointer(mpqOpenFile->hFile,lDistanceToMove,lplDistanceToMoveHigh,dwMoveMethod);
1212 BOOL SFMPQAPI WINAPI SFileReadFile(MPQHANDLE hFile,LPVOID lpBuffer,DWORD nNumberOfBytesToRead,LPDWORD lpNumberOfBytesRead,LPOVERLAPPED lpOverlapped)
1214         if (!hFile || !lpBuffer) {
1215                 SetLastError(ERROR_INVALID_PARAMETER);
1216                 return FALSE;
1217         }
1219         MPQFILE *mpqOpenFile = (MPQFILE *)hFile;
1220         if (mpqOpenFile->hFile != INVALID_HANDLE_VALUE) {
1221                 DWORD tsz=0;
1222                 BOOL RetVal = ReadFile(mpqOpenFile->hFile,lpBuffer,nNumberOfBytesToRead,&tsz,lpOverlapped);
1223                 if (lpNumberOfBytesRead) *lpNumberOfBytesRead = tsz;
1224                 return RetVal;
1225         }
1226         if (lpOverlapped)
1227                 if (lpOverlapped->Internal || lpOverlapped->InternalHigh || lpOverlapped->Offset || lpOverlapped->OffsetHigh || lpOverlapped->hEvent)
1228                         SFileSetFilePointer(hFile,lpOverlapped->Offset,(long *)&lpOverlapped->OffsetHigh,FILE_BEGIN);
1229         if (nNumberOfBytesToRead==0) {
1230                 if (lpNumberOfBytesRead) *lpNumberOfBytesRead = 0;
1231                 if (lpOverlapped) lpOverlapped->InternalHigh = 0;
1232                 return TRUE;
1233         }
1234         MPQARCHIVE *mpqOpenArc = mpqOpenFile->lpParentArc;
1236         if (mpqOpenFile->dwFilePointer>mpqOpenFile->lpBlockEntry->dwFullSize) return FALSE;
1237         if (mpqOpenFile->dwFilePointer==mpqOpenFile->lpBlockEntry->dwFullSize)
1238         {
1239                 if (lpNumberOfBytesRead) *lpNumberOfBytesRead = 0;
1240                 if (lpOverlapped) lpOverlapped->InternalHigh = 0;
1241                 return TRUE;
1242         }
1243         DWORD nBytesRead,TotalBytesRead=0;
1244         DWORD BlockIndex = mpqOpenFile->lpHashEntry->dwBlockTableIndex;
1245         if (mpqOpenFile->dwFilePointer+nNumberOfBytesToRead>mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize) nNumberOfBytesToRead = mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize-mpqOpenFile->dwFilePointer;
1246         DWORD blockSize = 512 << mpqOpenArc->MpqHeader.wBlockSize;
1247         DWORD dwBlockStart = mpqOpenFile->dwFilePointer - (mpqOpenFile->dwFilePointer % blockSize);
1248     DWORD blockNum = dwBlockStart / blockSize;
1249     DWORD nBlocks  = (mpqOpenFile->dwFilePointer+nNumberOfBytesToRead) / blockSize;
1250     if((mpqOpenFile->dwFilePointer+nNumberOfBytesToRead) % blockSize)
1251                 nBlocks++;
1252         DWORD TotalBlocks = mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize / blockSize;
1253         if(mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize % blockSize)
1254                 TotalBlocks++;
1255         DWORD dwBlockPos = mpqOpenFile->dwFilePointer % blockSize;
1256         DWORD dwBlockPosEnd = (mpqOpenFile->dwFilePointer+nNumberOfBytesToRead) % blockSize;
1257         if (dwBlockPosEnd==0) dwBlockPosEnd = blockSize;
1258         void *blkBuffer = SFAlloc(blockSize);
1259         if (!blkBuffer) {
1260                 if (lpNumberOfBytesRead) *lpNumberOfBytesRead = 0;
1261                 if (lpOverlapped) lpOverlapped->InternalHigh = 0;
1262                 return FALSE;
1263         }
1264         void *blk16Buffer = SFAlloc(blockSize * 16);
1265         if (!blk16Buffer) {
1266                 SFFree(blkBuffer);
1267                 if (lpNumberOfBytesRead) *lpNumberOfBytesRead = 0;
1268                 if (lpOverlapped) lpOverlapped->InternalHigh = 0;
1269                 return FALSE;
1270         }
1271         DWORD dwCryptKey = mpqOpenFile->dwCryptKey;
1272         //if (mpqOpenArc->lpBlockTable[BlockIndex].dwFlags & MAFA_ENCRYPT) dwCryptKey = HashString(mpqOpenFile->lpFileName,HASH_KEY);
1273         //if (mpqOpenArc->lpBlockTable[BlockIndex].dwFlags & MAFA_MODCRYPTKEY) dwCryptKey = (dwCryptKey + mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset) ^ mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize;
1274         DWORD HeaderLength=0;
1275         if (memcmp(&mpqOpenArc->MpqHeader.dwMPQID,ID_BN3,4)==0)
1276         {
1277                 SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset,0,FILE_BEGIN);
1278                 ReadFile(mpqOpenArc->hFile,&HeaderLength,4,&nBytesRead,0);
1279         }
1280         DWORD i;
1281         if (!mpqOpenFile->lpdwBlockOffsets)
1282         {
1283                 DWORD *dwBlockPtrTable = (DWORD *)SFAlloc((TotalBlocks+1)*4);
1284                 if (!dwBlockPtrTable) {
1286                         SFFree(blk16Buffer);
1287                         SFFree(blkBuffer);
1288                         if (lpNumberOfBytesRead) *lpNumberOfBytesRead = 0;
1289                         if (lpOverlapped) lpOverlapped->InternalHigh = 0;
1290                         return FALSE;
1291                 }
1292                 if ((mpqOpenArc->lpBlockTable[BlockIndex].dwFlags & MAFA_COMPRESS) || (mpqOpenArc->lpBlockTable[BlockIndex].dwFlags & MAFA_COMPRESS2))
1293                 {
1294                         SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset+HeaderLength,0,FILE_BEGIN);
1295                         ReadFile(mpqOpenArc->hFile,dwBlockPtrTable,(TotalBlocks+1)*4,&nBytesRead,0);
1296                         if (mpqOpenArc->lpBlockTable[BlockIndex].dwFlags & MAFA_ENCRYPT) {
1297                                 DecryptData((LPBYTE)dwBlockPtrTable,(TotalBlocks+1)*4,dwCryptKey-1);
1298                         }
1299                 }
1300                 else
1301                 {
1302                         for (i=0;i<TotalBlocks+1;i++) {
1303                                 if (i<TotalBlocks) dwBlockPtrTable[i] = i * blockSize;
1304                                 else dwBlockPtrTable[i] = mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize;
1305                         }
1306                 }
1307                 mpqOpenFile->lpdwBlockOffsets = dwBlockPtrTable;
1308         }
1309         BYTE *compbuffer = (BYTE *)SFAlloc(blockSize+3);
1310         if (!compbuffer) {
1311                 SFFree(blk16Buffer);
1312                 SFFree(blkBuffer);
1313                 if (lpNumberOfBytesRead) *lpNumberOfBytesRead = 0;
1314                 if (lpOverlapped) lpOverlapped->InternalHigh = 0;
1315                 return FALSE;
1316         }
1317         DWORD blk=0,blki=0;
1318         for (i=blockNum;i<nBlocks;i++) {
1319                 if (blk==0) {
1320                         SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset+HeaderLength+mpqOpenFile->lpdwBlockOffsets[i],0,FILE_BEGIN);
1321                         blki=i;
1322                         if (i+16>nBlocks) {
1323                                 if (ReadFile(mpqOpenArc->hFile,blk16Buffer,mpqOpenFile->lpdwBlockOffsets[nBlocks]-mpqOpenFile->lpdwBlockOffsets[i],&nBytesRead,0)==0) {
1324                                         SFFree(compbuffer);
1325                                         SFFree(blk16Buffer);
1326                                         SFFree(blkBuffer);
1327                                         if (lpNumberOfBytesRead) *lpNumberOfBytesRead = TotalBytesRead;
1328                                         if (lpOverlapped) lpOverlapped->InternalHigh = TotalBytesRead;
1329                                         return FALSE;
1330                                 }
1332                         }
1333                         else {
1334                                 if (ReadFile(mpqOpenArc->hFile,blk16Buffer,mpqOpenFile->lpdwBlockOffsets[i+16]-mpqOpenFile->lpdwBlockOffsets[i],&nBytesRead,0)==0) {
1335                                         SFFree(compbuffer);
1336                                         SFFree(blk16Buffer);
1337                                         SFFree(blkBuffer);
1338                                         if (lpNumberOfBytesRead) *lpNumberOfBytesRead = TotalBytesRead;
1339                                         if (lpOverlapped) lpOverlapped->InternalHigh = TotalBytesRead;
1340                                         return FALSE;
1341                                 }
1342                         }
1343                 }
1344                 memcpy(blkBuffer,((char *)blk16Buffer)+(mpqOpenFile->lpdwBlockOffsets[blki+blk]-mpqOpenFile->lpdwBlockOffsets[blki]),mpqOpenFile->lpdwBlockOffsets[i+1]-mpqOpenFile->lpdwBlockOffsets[i]);
1345                 if (mpqOpenArc->lpBlockTable[BlockIndex].dwFlags & MAFA_ENCRYPT)
1346                 {
1347                         DecryptData((LPBYTE)blkBuffer,mpqOpenFile->lpdwBlockOffsets[i+1]-mpqOpenFile->lpdwBlockOffsets[i],dwCryptKey+i);
1348                 }
1349                 if (i==TotalBlocks-1 && (mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize % blockSize)!=0) blockSize=mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize % blockSize;
1350                 DWORD outLength=blockSize;
1351                 if ((mpqOpenFile->lpdwBlockOffsets[i+1]-mpqOpenFile->lpdwBlockOffsets[i])!=blockSize)
1352                 {
1353                         if (mpqOpenArc->lpBlockTable[BlockIndex].dwFlags & MAFA_COMPRESS)
1354                         {
1355                                 BYTE *compdata = compbuffer;
1356                                 memcpy(compdata,(char *)blkBuffer,mpqOpenFile->lpdwBlockOffsets[i+1]-mpqOpenFile->lpdwBlockOffsets[i]);
1357                                 if (compdata[0]&UNSUPPORTED_DECOMPRESSION) {
1358                                         LoadStorm();
1359                                         if (stormSCompDecompress)
1360                                                 stormSCompDecompress(blkBuffer, &outLength, compdata, mpqOpenFile->lpdwBlockOffsets[i+1]-mpqOpenFile->lpdwBlockOffsets[i]);
1361                                 }
1362                                 else {
1363                                         SCompDecompress(blkBuffer, &outLength, compdata, mpqOpenFile->lpdwBlockOffsets[i+1]-mpqOpenFile->lpdwBlockOffsets[i]);
1364                                 }
1365                         }
1366                         else if (mpqOpenArc->lpBlockTable[BlockIndex].dwFlags & MAFA_COMPRESS2)
1367                         {
1368                                 BYTE *compdata = compbuffer;
1369                                 compdata[0] = 0x08;
1370                                 memcpy(compdata+1,(char *)blkBuffer,mpqOpenFile->lpdwBlockOffsets[i+1]-mpqOpenFile->lpdwBlockOffsets[i]);
1371                                 SCompDecompress(blkBuffer, &outLength, compdata, mpqOpenFile->lpdwBlockOffsets[i+1]-mpqOpenFile->lpdwBlockOffsets[i]+1);
1372                         }
1373                 }
1374                 if (i==blockNum) {
1375                         if (nNumberOfBytesToRead > blockSize-dwBlockPos) {
1376                                 memcpy(lpBuffer,(char *)blkBuffer+dwBlockPos,blockSize-dwBlockPos);
1377                                 TotalBytesRead+=blockSize-dwBlockPos;
1378                                 mpqOpenFile->dwFilePointer += blockSize-dwBlockPos;
1379                                 nNumberOfBytesToRead-=blockSize-dwBlockPos;
1380                         }
1381                         else {
1382                                 memcpy(lpBuffer,(char *)blkBuffer+dwBlockPos,nNumberOfBytesToRead);
1383                                 TotalBytesRead+=nNumberOfBytesToRead;
1384                                 mpqOpenFile->dwFilePointer += nNumberOfBytesToRead;
1385                                 nNumberOfBytesToRead-=nNumberOfBytesToRead;
1386                         }
1387                 }
1388                 else if (i==nBlocks-1) {
1389                         if (nNumberOfBytesToRead > dwBlockPosEnd) {
1390                                 memcpy((char *)lpBuffer+TotalBytesRead,blkBuffer,dwBlockPosEnd);
1391                                 TotalBytesRead+=dwBlockPosEnd;
1392                                 mpqOpenFile->dwFilePointer += dwBlockPosEnd;
1393                                 nNumberOfBytesToRead-=dwBlockPosEnd;
1394                         }
1395                         else {
1396                                 memcpy((char *)lpBuffer+TotalBytesRead,blkBuffer,nNumberOfBytesToRead);
1397                                 TotalBytesRead+=nNumberOfBytesToRead;
1398                                 mpqOpenFile->dwFilePointer += nNumberOfBytesToRead;
1399                                 nNumberOfBytesToRead-=nNumberOfBytesToRead;
1400                         }
1401                 }
1402                 else {
1403                         if (nNumberOfBytesToRead > blockSize) {
1404                                 memcpy((char *)lpBuffer+TotalBytesRead,blkBuffer,blockSize);
1405                                 TotalBytesRead+=blockSize;
1406                                 mpqOpenFile->dwFilePointer += blockSize;
1407                                 nNumberOfBytesToRead-=blockSize;
1408                         }
1409                         else {
1410                                 memcpy((char *)lpBuffer+TotalBytesRead,blkBuffer,nNumberOfBytesToRead);
1411                                 TotalBytesRead+=nNumberOfBytesToRead;
1412                                 mpqOpenFile->dwFilePointer += nNumberOfBytesToRead;
1413                                 nNumberOfBytesToRead-=nNumberOfBytesToRead;
1414                         }
1415                 }
1416                 blk = (blk+1) % 16;
1417         }
1418         SFFree(compbuffer);
1419         SFFree(blk16Buffer);
1420         SFFree(blkBuffer);
1421         if (lpNumberOfBytesRead) *lpNumberOfBytesRead = TotalBytesRead;
1422         if (lpOverlapped) lpOverlapped->InternalHigh = TotalBytesRead;
1423         return TRUE;
1426 LCID SFMPQAPI WINAPI SFileSetLocale(LCID nNewLocale)
1428         return (LocaleID = nNewLocale);
1431 BOOL SFMPQAPI WINAPI SFileGetBasePath(LPCSTR lpBuffer, DWORD dwBufferLength)
1433         if (lpBuffer==0) {
1434                 SetLastError(ERROR_INVALID_PARAMETER);
1435                 return FALSE;
1436         }
1438         DWORD slen = strlen(StormBasePath)+1;
1439         if (dwBufferLength>=slen) memcpy((void *)lpBuffer,StormBasePath,slen);
1440         else memcpy((void *)lpBuffer,StormBasePath,dwBufferLength);
1441         return TRUE;
1444 BOOL SFMPQAPI WINAPI SFileSetBasePath(LPCSTR lpNewBasePath)
1446         if (!lpNewBasePath) {
1447                 SetLastError(ERROR_INVALID_PARAMETER);
1448                 return FALSE;
1449         }
1450         if (!*lpNewBasePath) {
1451                 SetLastError(ERROR_INVALID_PARAMETER);
1452                 return FALSE;
1453         }
1455         DWORD slen = strlen(lpNewBasePath)+1;
1456         if (slen>MAX_PATH+1) return FALSE;
1457         else if (slen==MAX_PATH+1)
1458                 if (lpNewBasePath[MAX_PATH-1]!='\\' && lpNewBasePath[MAX_PATH-1]!='/') return FALSE;
1459         TempAlloc NewAlloc;
1460         char *buffer = (char *)NewAlloc.Alloc(slen+1);
1461         memcpy(buffer,lpNewBasePath,slen);
1462         char *npath;
1463 #ifdef _WIN32
1464         for (npath=buffer;npath[0]!=0;npath++)
1465                 if (npath[0]=='/') npath[0]='\\';
1466         if (npath[-1]!='\\') {
1467                 npath[0]='\\';
1468                 npath[1]=0;
1469                 slen+=1;
1470         }
1471 #else
1472         for (npath=buffer;npath[0]!=0;npath++)
1473                 if (npath[0]=='\\') npath[0]='/';
1474         if (npath[-1]!='/') {
1475                 npath[0]='/';
1476                 npath[1]=0;
1477                 slen+=1;
1478         }
1479 #endif
1480 #ifdef _WIN32
1481         DWORD attrib = GetFileAttributes(buffer);
1482         if ((attrib&FILE_ATTRIBUTE_DIRECTORY)==0 || attrib==0xFFFFFFFF) return FALSE;
1483 #endif
1485         memcpy(StormBasePath,buffer,slen);
1486         return TRUE;
1489 BOOL SFMPQAPI WINAPI SFileSetArchivePriority(MPQHANDLE hMPQ, DWORD dwPriority)
1491         if (!hMPQ) {
1492                 SetLastError(ERROR_INVALID_PARAMETER);
1493                 return FALSE;
1494         }
1496         MPQARCHIVE *mpqOpenArc = (MPQARCHIVE *)hMPQ;
1497         mpqOpenArc->dwPriority = dwPriority;
1498         if (dwOpenMpqCount>1) SortOpenArchivesByPriority();
1499         return TRUE;
1502 int StringICompare(const void *arg1,const void *arg2)
1504         return stricmp(*(char **)arg1,*(char **)arg2);
1507 BOOL SFMPQAPI WINAPI SFileListFiles(MPQHANDLE hMPQ, LPCSTR lpFileLists, FILELISTENTRY *lpListBuffer, DWORD dwFlags)
1509         if (!hMPQ || !lpListBuffer) {
1510                 SetLastError(ERROR_INVALID_PARAMETER);
1511                 return FALSE;
1512         }
1514         MPQARCHIVE *mpqOpenArc = (MPQARCHIVE *)hMPQ;
1515         DWORD i,tsz;
1517         if (memcmp(&mpqOpenArc->MpqHeader.dwMPQID,ID_BN3,4)==0)
1518         {
1519                 for (i=0;i<mpqOpenArc->MpqHeader.dwHashTableSize;i++) {
1520                         lpListBuffer[i].dwFileExists = 0;
1521                         lpListBuffer[i].szFileName[0] = 0;
1522                         if ((mpqOpenArc->lpHashTable[i].dwBlockTableIndex&0xFFFFFFFE)!=0xFFFFFFFE && mpqOpenArc->lpHashTable[i].dwBlockTableIndex < mpqOpenArc->MpqHeader.dwBlockTableSize) {
1523                                 lpListBuffer[i].lcLocale = mpqOpenArc->lpHashTable[i].lcLocale;
1524                                 DWORD dwBlockIndex = mpqOpenArc->lpHashTable[i].dwBlockTableIndex;
1525                                 lpListBuffer[i].dwCompressedSize = mpqOpenArc->lpBlockTable[dwBlockIndex].dwCompressedSize;
1526                                 lpListBuffer[i].dwFullSize = mpqOpenArc->lpBlockTable[dwBlockIndex].dwFullSize;
1527                                 lpListBuffer[i].dwFlags = mpqOpenArc->lpBlockTable[dwBlockIndex].dwFlags;
1528                                 if (dwFlags & SFILE_LIST_FLAG_UNKNOWN)
1529                                         lpListBuffer[i].dwFileExists = 1;
1530                                 else
1531                                         lpListBuffer[i].dwFileExists=0xFFFFFFFF;
1532                                 SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->lpBlockTable[dwBlockIndex].dwFileOffset+0x40,0,FILE_BEGIN);
1533                                 ReadFile(mpqOpenArc->hFile,lpListBuffer[i].szFileName,260,&tsz,0);
1535                                 if (mpqOpenArc->lpHashTable[i].dwNameHashA==HashString(lpListBuffer[i].szFileName,HASH_NAME_A) && mpqOpenArc->lpHashTable[i].dwNameHashB==HashString(lpListBuffer[i].szFileName,HASH_NAME_B)) {
1536                                         if (dwFlags&SFILE_LIST_ONLY_UNKNOWN && !(dwFlags&SFILE_LIST_ONLY_KNOWN)) {
1537                                                 lpListBuffer[i].dwFileExists = 0;
1538                                         }
1539                                 }
1540                                 else {
1541                                         sprintf(lpListBuffer[i].szFileName,UNKNOWN_OUT,i);
1542                                         if (dwFlags & SFILE_LIST_FLAG_UNKNOWN) {
1543                                                 lpListBuffer[i].dwFileExists |= 2;
1544                                         }
1546                                         if (dwFlags&SFILE_LIST_ONLY_KNOWN) {
1547                                                 lpListBuffer[i].dwFileExists = 0;
1548                                         }
1549                                 }
1550                         }
1551                 }
1553                 return TRUE;
1554         }
1556         char **lpNameBuffers=0;
1558         char **lpNames=0,szNull[1]={0},*lpFLCopy;
1559         DWORD *lpdwNameHashA=0,*lpdwNameHashB=0;
1560         DWORD dwListNameHashA,dwListNameHashB;
1561         DWORD j;
1562         lpFLCopy = (char *)lpFileLists;
1563         DWORD dwExtLists=0,dwIntLists=0;
1564         if (!lpFLCopy) lpFLCopy=szNull;
1565         char *lpLines;
1566         for (lpLines=lpFLCopy;lpLines;lpLines=nextline(lpLines)) {
1567                 if (!*lpLines) break;
1568                 dwExtLists++;
1569         }
1570         dwListNameHashA = HashString(INTERNAL_LISTFILE,HASH_NAME_A);
1571         dwListNameHashB = HashString(INTERNAL_LISTFILE,HASH_NAME_B);
1572         for (i=0;i<mpqOpenArc->MpqHeader.dwHashTableSize;i++) {
1573                 if (mpqOpenArc->lpHashTable[i].dwNameHashA==dwListNameHashA && mpqOpenArc->lpHashTable[i].dwNameHashB==dwListNameHashB && (mpqOpenArc->lpHashTable[i].dwBlockTableIndex&0xFFFFFFFE)!=0xFFFFFFFE) {
1574                         dwIntLists++;
1575                 }
1576         }
1577         lpNameBuffers = (char **)SFAlloc((1+dwExtLists+dwIntLists)*sizeof(char *));
1578         if (dwExtLists) {
1579                 lpFLCopy = strdup(lpFLCopy);
1580                 i=0;
1581                 for (lpLines=lpFLCopy;lpLines;lpLines=nextline(lpLines)) {
1582                         if (!*lpLines) break;
1583                         lpNameBuffers[i+1] = lpLines;
1584                         i++;
1585                 }
1586                 for (i=0;i<dwExtLists;i++) {
1587                         lpNameBuffers[i+1][strlnlen(lpNameBuffers[i+1])]=0;
1588                 }
1589                 qsort(lpNameBuffers+1,dwExtLists,sizeof(char *),StringICompare);
1590                 for (i=0;i<dwExtLists-1;i++) {
1591                         if (stricmp(lpNameBuffers[i+1],lpNameBuffers[i+2])==0) {
1592                                 memmove(&lpNameBuffers[i+1],&lpNameBuffers[i+2],(dwExtLists-(i+1))*sizeof(char *));
1593                                 dwExtLists--;
1594                         }
1595                 }
1596         }
1597         if (dwIntLists) {
1598                 dwIntLists = 0;
1599                 for (i=0;i<mpqOpenArc->MpqHeader.dwHashTableSize;i++) {
1600                         if (mpqOpenArc->lpHashTable[i].dwNameHashA==dwListNameHashA && mpqOpenArc->lpHashTable[i].dwNameHashB==dwListNameHashB && (mpqOpenArc->lpHashTable[i].dwBlockTableIndex&0xFFFFFFFE)!=0xFFFFFFFE) {
1601                                 lpNameBuffers[1+dwExtLists+dwIntLists] = (char *)i;
1602                                 dwIntLists++;
1603                         }
1604                 }
1605         }
1606         DWORD dwLines=0,dwOldLines=0,dwTotalLines=0;
1607         DWORD fsz;
1608         HANDLE hFile;
1609         DWORD dwListCryptKey = HashString(INTERNAL_LISTFILE,HASH_KEY);
1610         for (i=0;i<1+dwExtLists+dwIntLists;i++) {
1611                 if (i==0) {
1612                         fsz = strlen(INTERNAL_FILES);
1613                         lpNameBuffers[i] = (char *)SFAlloc(fsz+1);
1614                         memcpy(lpNameBuffers[i],INTERNAL_FILES,fsz);
1615                         lpNameBuffers[i][fsz]=0;
1616                 }
1617                 else if (i<1+dwExtLists) {
1618                         if (!(dwFlags&SFILE_LIST_MEMORY_LIST)) {
1619                                 hFile = CreateFile(lpNameBuffers[i],GENERIC_READ,FILE_SHARE_READ,0,OPEN_EXISTING,0,0);
1620                                 if (hFile!=INVALID_HANDLE_VALUE) {
1621                                         fsz = GetFileSize(hFile,0);
1622                                         SetFilePointer(hFile,0,0,FILE_BEGIN);
1623                                         lpNameBuffers[i] = (char *)SFAlloc(fsz+1);
1624                                         ReadFile(hFile,lpNameBuffers[i],fsz,&tsz,0);
1625                                         CloseHandle(hFile);
1626                                         lpNameBuffers[i][fsz]=0;
1627                                 }
1628                                 else lpNameBuffers[i]=0;
1629                         }
1630                         else {
1631                                 dwTotalLines++;
1632                                 continue;
1633                         }
1634                 }
1635                 else {
1636                         MPQFILE thisFile;
1637                         memset(&thisFile,0,sizeof(MPQFILE));
1638                         thisFile.lpParentArc = (MPQARCHIVE *)hMPQ;
1639                         thisFile.hFile = INVALID_HANDLE_VALUE;
1640                         thisFile.lpHashEntry = &mpqOpenArc->lpHashTable[(DWORD)lpNameBuffers[i]];
1641                         thisFile.lpBlockEntry = &mpqOpenArc->lpBlockTable[thisFile.lpHashEntry->dwBlockTableIndex];
1642                         thisFile.lpFileName = thisFile.szFileName;
1643                         strcpy(thisFile.lpFileName,INTERNAL_LISTFILE);
1644                         thisFile.dwFilePointer = 0;
1645                         thisFile.lpdwBlockOffsets = 0;
1646                         BLOCKTABLEENTRY *lpBlockEntry = thisFile.lpBlockEntry;
1647                         if (lpBlockEntry->dwFlags & MAFA_ENCRYPT) {
1648                                 thisFile.dwCryptKey = dwListCryptKey;
1649                                 if (lpBlockEntry->dwFlags & MAFA_MODCRYPTKEY)
1650                                         thisFile.dwCryptKey = (thisFile.dwCryptKey + lpBlockEntry->dwFileOffset) ^ lpBlockEntry->dwFullSize;
1651                         }
1652                         fsz = lpBlockEntry->dwFullSize;
1653                         lpNameBuffers[i] = (char *)SFAlloc(fsz+1);
1654                         SFileReadFile(&thisFile,lpNameBuffers[i],fsz,0,0);
1655                         if (thisFile.lpdwBlockOffsets) SFFree(thisFile.lpdwBlockOffsets);
1656                         lpNameBuffers[i][fsz]=0;
1657                 }
1658                 for (lpLines=lpNameBuffers[i];lpLines;lpLines=nextline(lpLines)) {
1659                         if (!*lpLines) break;
1660                         dwTotalLines++;
1661                 }
1662         }
1663         lpNames = (char **)SFAlloc(dwTotalLines*sizeof(char *));
1664         for (i=0;i<1+dwExtLists+dwIntLists;i++) {
1665                 dwOldLines=dwLines;
1666                 for (lpLines=lpNameBuffers[i];lpLines;lpLines=nextline(lpLines)) {
1667                         if (!*lpLines) break;
1668                         lpNames[dwLines] = lpLines;
1669                         dwLines++;
1670                 }
1671                 for (j=dwOldLines;j<dwLines;j++) {
1672                         lpNames[j][strlnlen(lpNames[j])]=0;
1673                 }
1674         }
1675         qsort(lpNames,dwTotalLines,sizeof(char *),StringICompare);
1676         for (i=0;i<dwTotalLines-1;i++) {
1677                 if (stricmp(lpNames[i],lpNames[i+1])==0) {
1678                         memmove(&lpNames[i],&lpNames[i+1],(dwTotalLines-(i+1))*sizeof(char *));
1679                         dwTotalLines--;
1680                 }
1681         }
1682         if (dwTotalLines) {
1683                 lpdwNameHashA = (DWORD *)SFAlloc(dwTotalLines*sizeof(DWORD));
1684                 lpdwNameHashB = (DWORD *)SFAlloc(dwTotalLines*sizeof(DWORD));
1685                 for (i=0;i<dwTotalLines;i++) {
1686                         lpdwNameHashA[i] = HashString(lpNames[i],HASH_NAME_A);
1687                         lpdwNameHashB[i] = HashString(lpNames[i],HASH_NAME_B);
1688                 }
1689         }
1690         for (i=0;i<mpqOpenArc->MpqHeader.dwHashTableSize;i++) {
1691                 lpListBuffer[i].dwFileExists = 0;
1692                 lpListBuffer[i].szFileName[0] = 0;
1693                 if ((mpqOpenArc->lpHashTable[i].dwBlockTableIndex&0xFFFFFFFE)!=0xFFFFFFFE && mpqOpenArc->lpHashTable[i].dwBlockTableIndex < mpqOpenArc->MpqHeader.dwBlockTableSize) {
1694                         lpListBuffer[i].lcLocale = mpqOpenArc->lpHashTable[i].lcLocale;
1695                         DWORD dwBlockIndex = mpqOpenArc->lpHashTable[i].dwBlockTableIndex;
1696                         lpListBuffer[i].dwCompressedSize = mpqOpenArc->lpBlockTable[dwBlockIndex].dwCompressedSize;
1697                         lpListBuffer[i].dwFullSize = mpqOpenArc->lpBlockTable[dwBlockIndex].dwFullSize;
1698                         lpListBuffer[i].dwFlags = mpqOpenArc->lpBlockTable[dwBlockIndex].dwFlags;
1699                         if (dwFlags & SFILE_LIST_FLAG_UNKNOWN)
1700                                 lpListBuffer[i].dwFileExists = 1;
1701                         else
1702                                 lpListBuffer[i].dwFileExists=0xFFFFFFFF;
1703                         for (j=0;j<dwTotalLines;j++) {
1704                                 if (mpqOpenArc->lpHashTable[i].dwNameHashA==lpdwNameHashA[j] && mpqOpenArc->lpHashTable[i].dwNameHashB==lpdwNameHashB[j]) {
1705                                         strncpy(lpListBuffer[i].szFileName,lpNames[j],260);
1706                                         if (dwFlags&SFILE_LIST_ONLY_UNKNOWN && !(dwFlags&SFILE_LIST_ONLY_KNOWN)) {
1707                                                 lpListBuffer[i].dwFileExists = 0;
1708                                         }
1709                                         break;
1710                                 }
1711                                 if (j+1==dwTotalLines) {
1712                                         sprintf(lpListBuffer[i].szFileName,UNKNOWN_OUT,i);
1713                                         if (dwFlags & SFILE_LIST_FLAG_UNKNOWN) {
1714                                                 lpListBuffer[i].dwFileExists |= 2;
1715                                         }
1717                                         if (dwFlags&SFILE_LIST_ONLY_KNOWN) {
1718                                                 lpListBuffer[i].dwFileExists = 0;
1719                                         }
1720                                 }
1721                         }
1722                 }
1723         }
1724         if (lpNameBuffers) {
1725                 for (i=0;i<1+dwExtLists+dwIntLists;i++) {
1726                         if (i>=1 && i<1+dwExtLists) {
1727                                 if ((dwFlags&SFILE_LIST_MEMORY_LIST)) {
1728                                         continue;
1729                                 }
1730                         }
1731                         if (lpNameBuffers[i]) SFFree(lpNameBuffers[i]);
1732                 }
1733                 SFFree(lpNameBuffers);
1734         }
1735         if (dwExtLists) SFFree(lpFLCopy);
1736         if (lpdwNameHashA) SFFree(lpdwNameHashA);
1737         if (lpdwNameHashB) SFFree(lpdwNameHashB);
1738         return TRUE;
1741 MPQHANDLE SFMPQAPI WINAPI MpqOpenArchiveForUpdate(LPCSTR lpFileName, DWORD dwFlags, DWORD dwMaximumFilesInArchive)
1743         MPQHANDLE hMPQ;
1745         MpqOpenArchiveEx(lpFileName,0,0,&hMPQ,dwFlags,dwMaximumFilesInArchive,USE_DEFAULT_BLOCK_SIZE);
1746         return hMPQ;
1749 MPQHANDLE SFMPQAPI WINAPI MpqOpenArchiveForUpdateEx(LPCSTR lpFileName, DWORD dwFlags, DWORD dwMaximumFilesInArchive, DWORD dwBlockSize)
1751         MPQHANDLE hMPQ;
1753         MpqOpenArchiveEx(lpFileName,0,0,&hMPQ,dwFlags,dwMaximumFilesInArchive,dwBlockSize);
1754         return hMPQ;
1757 DWORD SFMPQAPI WINAPI MpqCloseUpdatedArchive(MPQHANDLE hMPQ, DWORD dwUnknown2)
1759         return SFileCloseArchive(hMPQ);
1762 BOOL SFMPQAPI WINAPI MpqAddFileToArchiveEx(MPQHANDLE hMPQ, LPCSTR lpSourceFileName, LPCSTR lpDestFileName, DWORD dwFlags, DWORD dwCompressionType, DWORD dwCompressLevel)
1764         if (!hMPQ || !lpSourceFileName || !lpDestFileName) {
1765                 SetLastError(ERROR_INVALID_PARAMETER);
1766                 return FALSE;
1767         }
1768         if (!*lpSourceFileName || !*lpDestFileName) {
1769                 SetLastError(ERROR_INVALID_PARAMETER);
1770                 return FALSE;
1771         }
1773         if (!(((MPQARCHIVE *)hMPQ)->dwFlags&SFILE_OPEN_ALLOW_WRITE)) {
1774                 SetLastError(ERROR_ACCESS_DENIED);
1775                 return FALSE;
1776         }
1777         BOOL ReplaceExisting;
1778         if (dwFlags&MAFA_REPLACE_EXISTING) {
1779                 dwFlags = dwFlags^MAFA_REPLACE_EXISTING;
1780                 ReplaceExisting = TRUE;
1781         }
1782         else ReplaceExisting = FALSE;
1783         MPQHANDLE hFile = GetFreeHashTableEntry(hMPQ,lpDestFileName,LocaleID,ReplaceExisting);
1784         if (!hFile) return FALSE;
1785         HANDLE haFile = CreateFile(lpSourceFileName,GENERIC_READ,FILE_SHARE_READ,0,OPEN_EXISTING,0,0);
1786         if (haFile==INVALID_HANDLE_VALUE) return FALSE;
1787         DWORD fsz = GetFileSize(haFile,0),tsz;
1788         DWORD ucfsz = fsz;
1789         BOOL IsBNcache = FALSE;char *buffer,*hbuffer;
1790         MPQARCHIVE *mpqOpenArc = (MPQARCHIVE *)hMPQ;
1791         DWORD blockSize = 512 << mpqOpenArc->MpqHeader.wBlockSize;
1792         DWORD TotalBlocks = fsz / blockSize;
1793         if(fsz % blockSize)
1794                 TotalBlocks++;
1795         DWORD ptsz = 0;
1796         if (dwFlags&MAFA_COMPRESS || dwFlags&MAFA_COMPRESS2) ptsz = (TotalBlocks+1)*4;
1797         if (memcmp(&mpqOpenArc->MpqHeader.dwMPQID,ID_BN3,4)==0)
1798         {
1799                 IsBNcache = TRUE;
1800                 hbuffer = (char *)SFAlloc(fsz+324+ptsz);
1801                 if (!hbuffer) {
1802                         CloseHandle(haFile);
1803                         return FALSE;
1804                 }
1805                 hbuffer[0] = (char)0x44;
1806                 hbuffer[1] = (char)0x01;
1807                 DWORD lpFileNameLength = strlen(lpDestFileName);
1808                 if (lpFileNameLength<=260) memcpy(hbuffer+64,lpDestFileName,lpFileNameLength);
1809                 else strncpy(hbuffer+64,lpDestFileName,260);
1810                 buffer = hbuffer+324;
1811         }
1812         else buffer = (char *)SFAlloc(fsz+ptsz);
1813         if (!buffer && fsz!=0) {
1814                 CloseHandle(haFile);
1815                 return FALSE;
1816         }
1817         if (fsz!=0) {
1818                 if (ReadFile(haFile,buffer,fsz,&tsz,0)==0) {
1819                         SFFree(buffer);
1820                         CloseHandle(haFile);
1821                         return FALSE;
1822                 }
1823         }
1824         else {
1825                 if (dwFlags&MAFA_COMPRESS) dwFlags = dwFlags^MAFA_COMPRESS;
1826                 if (dwFlags&MAFA_COMPRESS2) dwFlags = dwFlags^MAFA_COMPRESS2;
1827                 if (dwFlags&MAFA_ENCRYPT) dwFlags = dwFlags^MAFA_ENCRYPT;
1828                 if (dwFlags&MAFA_MODCRYPTKEY) dwFlags = dwFlags^MAFA_MODCRYPTKEY;
1829         }
1830         CloseHandle(haFile);
1831         DWORD i;
1832         DWORD *dwBlkpt = (DWORD *)SFAlloc((TotalBlocks+1)*4);
1833         if (!dwBlkpt) {
1834                 SFFree(buffer);
1835                 return FALSE;
1836         }
1837         if ((dwFlags & MAFA_COMPRESS) || (dwFlags & MAFA_COMPRESS2))
1838         {
1839                 DWORD dwCompressionSubType = 0;
1841                 if ((dwCompressionType&0x40 || dwCompressionType&0x80) && (memcmp(buffer,ID_RIFF,4)!=0 || memcmp(buffer+8,ID_WAVE,8)!=0 || buffer[20]!=1 || buffer[34]!=16)) {
1842                         dwCompressionType = 0x08;
1843                         dwCompressLevel = 0;
1844                 }
1845                 if (dwCompressionType&0x40 || dwCompressionType&0x80) {
1846                         switch (dwCompressLevel) {
1847                                 case MAWA_QUALITY_HIGH:
1848                                         dwCompressLevel = 1;
1849                                         break;
1850                                 case MAWA_QUALITY_LOW:
1851                                         dwCompressLevel = 3;
1852                                         break;
1853                                 default:
1854                                         dwCompressLevel = 0;
1855                         }
1856                 }
1857                 else if (dwCompressionType&0x01 || dwCompressionType&0x08 || ((dwFlags & MAFA_COMPRESS)!=MAFA_COMPRESS && (dwFlags & MAFA_COMPRESS2)==MAFA_COMPRESS2)) {
1858                         dwCompressionSubType = dwCompressLevel;
1859                         dwCompressLevel = 0;
1860                 }
1861                 else if (dwCompressionType&0x02) {
1862                         dwCompressionSubType = 1;
1863                 }
1865                 DWORD LastOffset=ptsz;
1866                 BYTE *compbuffer = (BYTE *)SFAlloc(blockSize);
1867                 if (!compbuffer) {
1868                         SFFree(dwBlkpt);
1869                         SFFree(buffer);
1870                         return FALSE;
1871                 }
1872                 char *outbuffer = (char *)SFAlloc(blockSize);
1873                 if (!outbuffer) {
1874                         SFFree(compbuffer);
1875                         SFFree(dwBlkpt);
1876                         SFFree(buffer);
1877                         return FALSE;
1878                 }
1879                 char *newbuffer = (char *)SFAlloc(fsz+ptsz);
1880                 if (!newbuffer) {
1881                         SFFree(outbuffer);
1882                         SFFree(compbuffer);
1883                         SFFree(dwBlkpt);
1884                         SFFree(buffer);
1885                         return FALSE;
1886                 }
1887                 DWORD CurPos=0;
1888                 for (i=0;i<TotalBlocks;i++) {
1889                         dwBlkpt[i] = LastOffset;
1890                         if (i==TotalBlocks-1 && (ucfsz % blockSize)!=0) blockSize=ucfsz % blockSize;
1891                         DWORD outLength=blockSize;
1892                         BYTE *compdata = compbuffer;
1893                         char *oldoutbuffer = outbuffer;
1894                         if (dwFlags & MAFA_COMPRESS)
1895                         {
1896                                 memcpy(compdata,(char *)buffer+CurPos,blockSize);
1897                                 if (i==0 && (dwCompressionType&0x40 || dwCompressionType&0x80)) {
1898                                         if (SCompCompress(outbuffer, &outLength, compdata, blockSize, 0x08, 0, 0)==0)
1899                                                 outLength=blockSize;
1900                                 }
1901                                 else
1902                                 {
1903                                         if (dwCompressionType&UNSUPPORTED_COMPRESSION) {
1904                                                 LoadStorm();
1905                                                 if (stormSCompCompress) {
1906                                                         if (stormSCompCompress(outbuffer, &outLength, compdata, blockSize, dwCompressionType, dwCompressionSubType, dwCompressLevel)==0)
1907                                                                 outLength=blockSize;
1908                                                 }
1909                                         }
1910                                         else {
1911                                                 if (SCompCompress(outbuffer, &outLength, compdata, blockSize, dwCompressionType, dwCompressionSubType, dwCompressLevel)==0)
1912                                                         outLength=blockSize;
1913                                         }
1914                                 }
1915                         }
1916                         else if (dwFlags & MAFA_COMPRESS2)
1917                         {
1918                                 memcpy(compdata,(char *)buffer+CurPos,blockSize);
1919                                 if (SCompCompress(outbuffer, &outLength, compdata, blockSize, 0x08, dwCompressionSubType, 0)==0) {
1920                                         outLength=blockSize;
1921                                 }
1922                                 else {
1923                                         outbuffer++;
1924                                         outLength--;
1925                                 }
1926                         }
1927                         else
1928                         {
1929                                 memcpy(compdata,(char *)buffer+CurPos,blockSize);
1930                         }
1931                         if (outLength>=blockSize)
1932                         {
1933                                 memcpy((char *)newbuffer+LastOffset,compdata,blockSize);
1934                                 LastOffset+=blockSize;
1935                         }
1936                         else {
1937                                 memcpy((char *)newbuffer+LastOffset,outbuffer,outLength);
1938                                 LastOffset+=outLength;
1939                         }
1940                         outbuffer = oldoutbuffer;
1941                         CurPos += blockSize;
1942                 }
1943                 fsz = LastOffset;
1944                 dwBlkpt[TotalBlocks] = fsz;
1945                 memcpy(newbuffer,dwBlkpt,ptsz);
1947                 SFFree(outbuffer);
1948                 SFFree(compbuffer);
1949                 memcpy(buffer,newbuffer,fsz);
1950                 SFFree(newbuffer);
1951         }
1952         else
1953         {
1954                 for (i=0;i<TotalBlocks+1;i++) {
1955                         if (i<TotalBlocks) dwBlkpt[i] = i * blockSize;
1956                         else dwBlkpt[i] = ucfsz;
1957                 }
1958         }
1959         if (IsBNcache==TRUE)
1960         {
1961                 buffer = hbuffer;
1962                 fsz += 324;
1963         }
1964         HASHTABLEENTRY *hashEntry = (HASHTABLEENTRY *)hFile;
1965         BOOL IsNewBlockEntry = FALSE;DWORD OldBlockTableSize = sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize;
1966         if ((hashEntry->dwBlockTableIndex&0xFFFFFFFE)==0xFFFFFFFE)
1967         {
1968                 BLOCKTABLEENTRY *lpnBlockTable;
1969                 lpnBlockTable = (BLOCKTABLEENTRY *)SFAlloc(sizeof(BLOCKTABLEENTRY) * (mpqOpenArc->MpqHeader.dwBlockTableSize + 1));
1970                 if(!lpnBlockTable) {
1971                         SFFree(buffer);
1972                         return FALSE;
1973                 }
1974                 if (mpqOpenArc->lpBlockTable) memcpy(lpnBlockTable,mpqOpenArc->lpBlockTable,sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize);
1975                 mpqOpenArc->MpqHeader.dwBlockTableSize++;
1976                 if (mpqOpenArc->lpBlockTable) SFFree(mpqOpenArc->lpBlockTable);
1977                 mpqOpenArc->lpBlockTable = lpnBlockTable;
1978                 IsNewBlockEntry = TRUE;
1979         }
1980         DWORD BlockIndex = mpqOpenArc->MpqHeader.dwBlockTableSize - 1;
1981         if ((hashEntry->dwBlockTableIndex&0xFFFFFFFE)==0xFFFFFFFE)
1982         {
1983                 hashEntry->dwNameHashA = HashString(lpDestFileName,HASH_NAME_A);
1984                 hashEntry->dwNameHashB = HashString(lpDestFileName,HASH_NAME_B);
1985                 hashEntry->lcLocale = LocaleID;
1986                 hashEntry->dwBlockTableIndex = BlockIndex;
1987                 mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset = 0;
1989         }
1990         else
1991         {
1992                 BlockIndex = hashEntry->dwBlockTableIndex;
1993         }
1994         if (mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset==0 || mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize<fsz)
1995         {
1996                 if (mpqOpenArc->MpqHeader.dwHashTableOffset+(mpqOpenArc->MpqHeader.dwHashTableSize * sizeof(HASHTABLEENTRY))+OldBlockTableSize==mpqOpenArc->MpqHeader.dwMPQSize)
1997                 {
1998                         if (mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset+mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize==mpqOpenArc->MpqHeader.dwHashTableOffset)
1999                         {
2000                                 mpqOpenArc->MpqHeader.dwHashTableOffset += fsz-mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize;
2001                                 mpqOpenArc->MpqHeader.dwBlockTableOffset += fsz-mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize;
2002                                 mpqOpenArc->MpqHeader.dwMPQSize += fsz-mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize;
2003                                 if (IsNewBlockEntry==TRUE) mpqOpenArc->MpqHeader.dwMPQSize += sizeof(BLOCKTABLEENTRY);
2004                         }
2005                         else
2006                         {
2007                                 mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset = mpqOpenArc->MpqHeader.dwHashTableOffset;
2008                                 mpqOpenArc->MpqHeader.dwHashTableOffset += fsz;
2009                                 mpqOpenArc->MpqHeader.dwBlockTableOffset += fsz;
2010                                 mpqOpenArc->MpqHeader.dwMPQSize += fsz;
2011                                 if (IsNewBlockEntry==TRUE) mpqOpenArc->MpqHeader.dwMPQSize += sizeof(BLOCKTABLEENTRY);
2012                         }
2013                 }
2014                 else if (mpqOpenArc->MpqHeader.dwBlockTableOffset+OldBlockTableSize==mpqOpenArc->MpqHeader.dwMPQSize)
2015                 {
2016                         if (mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset+mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize==mpqOpenArc->MpqHeader.dwBlockTableOffset)
2017                         {
2018                                 mpqOpenArc->MpqHeader.dwBlockTableOffset += fsz-mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize;
2019                                 mpqOpenArc->MpqHeader.dwMPQSize += fsz-mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize;
2020                                 if (IsNewBlockEntry==TRUE) mpqOpenArc->MpqHeader.dwMPQSize += sizeof(BLOCKTABLEENTRY);
2021                         }
2022                         else
2023                         {
2024                                 mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset = mpqOpenArc->MpqHeader.dwBlockTableOffset;
2025                                 mpqOpenArc->MpqHeader.dwBlockTableOffset += fsz;
2026                                 mpqOpenArc->MpqHeader.dwMPQSize += fsz;
2027                                 if (IsNewBlockEntry==TRUE) mpqOpenArc->MpqHeader.dwMPQSize += sizeof(BLOCKTABLEENTRY);
2028                         }
2029                 }
2030                 else
2031                 {
2032                         if (mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset+mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize==mpqOpenArc->MpqHeader.dwMPQSize)
2033                         {
2034                                 mpqOpenArc->MpqHeader.dwBlockTableOffset = mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset+fsz;
2035                                 mpqOpenArc->MpqHeader.dwMPQSize = mpqOpenArc->MpqHeader.dwBlockTableOffset+OldBlockTableSize;
2036                                 if (IsNewBlockEntry==TRUE) mpqOpenArc->MpqHeader.dwMPQSize += sizeof(BLOCKTABLEENTRY);
2037                         }
2038                         else
2039                         {
2040                                 mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset = mpqOpenArc->MpqHeader.dwMPQSize;
2041                                 mpqOpenArc->MpqHeader.dwBlockTableOffset = mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset+fsz;
2042                                 mpqOpenArc->MpqHeader.dwMPQSize = mpqOpenArc->MpqHeader.dwBlockTableOffset+OldBlockTableSize;
2043                                 if (IsNewBlockEntry==TRUE) mpqOpenArc->MpqHeader.dwMPQSize += sizeof(BLOCKTABLEENTRY);
2044                         }
2045                 }
2046         }
2047         mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize = fsz;
2048         mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize = ucfsz;
2049         mpqOpenArc->lpBlockTable[BlockIndex].dwFlags = dwFlags|MAFA_EXISTS;
2050         DWORD dwFileOffset = mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset;
2051         SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart,0,FILE_BEGIN);
2052         WriteFile(mpqOpenArc->hFile,&mpqOpenArc->MpqHeader,sizeof(MPQHEADER),&tsz,0);
2053         if (dwFlags & MAFA_ENCRYPT) {
2054                 DWORD dwCryptKey;
2055                 if (dwFlags&MAFA_ENCRYPT) dwCryptKey = HashString(lpDestFileName,HASH_KEY);
2056                 if (dwFlags&MAFA_MODCRYPTKEY) dwCryptKey = (dwCryptKey + mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset) ^ mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize;
2057                 DWORD blockSize = 512 << mpqOpenArc->MpqHeader.wBlockSize;
2058                 DWORD TotalBlocks = mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize / blockSize;
2059                 if(mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize % blockSize)
2060                         TotalBlocks++;
2061                 DWORD dwBlockEnd = mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize % blockSize;
2062                 if (dwBlockEnd==0) dwBlockEnd = blockSize;
2063                 if ((dwFlags & MAFA_COMPRESS)==MAFA_COMPRESS || (dwFlags & MAFA_COMPRESS2)==MAFA_COMPRESS2) {
2064                         EncryptData((LPBYTE)buffer,ptsz,dwCryptKey-1);
2065                 }
2066                 for (DWORD i=0;i<TotalBlocks;i++) {
2067                         EncryptData((LPBYTE)buffer+dwBlkpt[i],dwBlkpt[i+1]-dwBlkpt[i],dwCryptKey);
2068                         dwCryptKey++;
2069                 }
2070         }
2071         SFFree(dwBlkpt);
2072         SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+dwFileOffset,0,FILE_BEGIN);
2073         WriteFile(mpqOpenArc->hFile,buffer,fsz,&tsz,0);
2074         SFFree(buffer);
2075         buffer = (char *)SFAlloc(sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize);
2076         if (buffer) {
2077                 memcpy(buffer,mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize);
2078                 EncryptData((LPBYTE)buffer,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,dwHashTableKey);
2079                 SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->MpqHeader.dwHashTableOffset,0,FILE_BEGIN);
2080                 WriteFile(mpqOpenArc->hFile,buffer,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,&tsz,0);
2081                 SFFree(buffer);
2082         }
2083         else {
2084                 EncryptData((LPBYTE)mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,dwHashTableKey);
2085                 SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->MpqHeader.dwHashTableOffset,0,FILE_BEGIN);
2086                 WriteFile(mpqOpenArc->hFile,mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,&tsz,0);
2087                 DecryptData((LPBYTE)mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,dwHashTableKey);
2088         }
2089         buffer = (char *)SFAlloc(sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize);
2090         if (buffer) {
2091                 memcpy(buffer,mpqOpenArc->lpBlockTable,sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize);
2092                 EncryptData((LPBYTE)buffer,sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize,dwBlockTableKey);
2093                 SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->MpqHeader.dwBlockTableOffset,0,FILE_BEGIN);
2094                 WriteFile(mpqOpenArc->hFile,buffer,sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize,&tsz,0);
2095                 SFFree(buffer);
2096         }
2097         else {
2098                 EncryptData((LPBYTE)mpqOpenArc->lpBlockTable,sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize,dwBlockTableKey);
2099                 SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->MpqHeader.dwBlockTableOffset,0,FILE_BEGIN);
2100                 WriteFile(mpqOpenArc->hFile,mpqOpenArc->lpBlockTable,sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize,&tsz,0);
2101                 DecryptData((LPBYTE)mpqOpenArc->lpBlockTable,sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize,dwBlockTableKey);
2102         }
2103         AddToInternalListing(hMPQ,lpDestFileName);
2105         return TRUE;
2108 BOOL SFMPQAPI WINAPI MpqAddFileToArchive(MPQHANDLE hMPQ, LPCSTR lpSourceFileName, LPCSTR lpDestFileName, DWORD dwFlags)
2110         return MpqAddFileToArchiveEx(hMPQ,lpSourceFileName,lpDestFileName,dwFlags,0x08,0);
2113 BOOL SFMPQAPI WINAPI MpqAddWaveToArchive(MPQHANDLE hMPQ, LPCSTR lpSourceFileName, LPCSTR lpDestFileName, DWORD dwFlags, DWORD dwQuality)
2115         return MpqAddFileToArchiveEx(hMPQ,lpSourceFileName,lpDestFileName,dwFlags,0x81,dwQuality);
2118 BOOL SFMPQAPI WINAPI MpqAddFileFromBufferEx(MPQHANDLE hMPQ, LPVOID lpBuffer, DWORD dwLength, LPCSTR lpFileName, DWORD dwFlags, DWORD dwCompressionType, DWORD dwCompressLevel)
2120         if (!hMPQ || !lpBuffer || !lpFileName) {
2121                 SetLastError(ERROR_INVALID_PARAMETER);
2122                 return FALSE;
2123         }
2124         if (!*lpFileName) {
2125                 SetLastError(ERROR_INVALID_PARAMETER);
2126                 return FALSE;
2127         }
2129         if (!(((MPQARCHIVE *)hMPQ)->dwFlags&SFILE_OPEN_ALLOW_WRITE)) {
2130                 SetLastError(ERROR_ACCESS_DENIED);
2131                 return FALSE;
2132         }
2133         BOOL ReplaceExisting;
2134         if (dwFlags&MAFA_REPLACE_EXISTING) {
2135                 dwFlags = dwFlags^MAFA_REPLACE_EXISTING;
2136                 ReplaceExisting = TRUE;
2138         }
2139         else ReplaceExisting = FALSE;
2140         MPQHANDLE hFile = GetFreeHashTableEntry(hMPQ,lpFileName,LocaleID,ReplaceExisting);
2141         if (hFile==0) return FALSE;
2142         DWORD fsz = dwLength,tsz;
2143         DWORD ucfsz = fsz;
2144         BOOL IsBNcache = FALSE;char *buffer,*hbuffer;
2145         MPQARCHIVE *mpqOpenArc = (MPQARCHIVE *)hMPQ;
2146         DWORD blockSize = 512 << mpqOpenArc->MpqHeader.wBlockSize;
2147         DWORD TotalBlocks = fsz / blockSize;
2148         if(fsz % blockSize)
2149                 TotalBlocks++;
2150         DWORD ptsz = 0;
2151         if (dwFlags&MAFA_COMPRESS || dwFlags&MAFA_COMPRESS2) ptsz = (TotalBlocks+1)*4;
2152         if (memcmp(&mpqOpenArc->MpqHeader.dwMPQID,ID_BN3,4)==0)
2153         {
2154                 IsBNcache = TRUE;
2155                 hbuffer = (char *)SFAlloc(fsz+324+ptsz);
2156                 if (hbuffer==0) {
2157                         return FALSE;
2158                 }
2159                 hbuffer[0] = (char)0x44;
2160                 hbuffer[1] = (char)0x01;
2161                 DWORD lpFileNameLength = strlen(lpFileName);
2162                 if (lpFileNameLength<=260) memcpy(hbuffer+64,lpFileName,lpFileNameLength);
2163                 else strncpy(hbuffer+64,lpFileName,260);
2164                 buffer = hbuffer+324;
2165         }
2166         else buffer = (char *)SFAlloc(fsz+ptsz);
2167         if (buffer==0 && fsz!=0) {
2168                 return FALSE;
2169         }
2170         if (fsz!=0) memcpy(buffer,lpBuffer,fsz);
2171         else {
2172                 if (dwFlags&MAFA_COMPRESS) dwFlags = dwFlags^MAFA_COMPRESS;
2173                 if (dwFlags&MAFA_COMPRESS2) dwFlags = dwFlags^MAFA_COMPRESS2;
2174                 if (dwFlags&MAFA_ENCRYPT) dwFlags = dwFlags^MAFA_ENCRYPT;
2175                 if (dwFlags&MAFA_MODCRYPTKEY) dwFlags = dwFlags^MAFA_MODCRYPTKEY;
2176         }
2177         DWORD i;
2178         DWORD *dwBlkpt = (DWORD *)SFAlloc((TotalBlocks+1)*4);
2180         if (dwBlkpt==0) {
2181                 SFFree(buffer);
2182                 return FALSE;
2183         }
2184         if ((dwFlags & MAFA_COMPRESS)==MAFA_COMPRESS || (dwFlags & MAFA_COMPRESS2)==MAFA_COMPRESS2)
2185         {
2186                 DWORD dwCompressionSubType = 0;
2188                 if ((dwCompressionType&0x40 || dwCompressionType&0x80) && (memcmp(buffer,ID_RIFF,4)!=0 || memcmp(buffer+8,ID_WAVE,8)!=0 || buffer[20]!=1 || buffer[34]!=16)) {
2189                         dwCompressionType = 0x08;
2190                         dwCompressLevel = 0;
2191                 }
2192                 if (dwCompressionType&0x40 || dwCompressionType&0x80) {
2193                         switch (dwCompressLevel) {
2194                                 case MAWA_QUALITY_HIGH:
2195                                         dwCompressLevel = 1;
2196                                         break;
2197                                 case MAWA_QUALITY_LOW:
2198                                         dwCompressLevel = 3;
2199                                         break;
2200                                 default:
2201                                         dwCompressLevel = 0;
2202                         }
2203                 }
2204                 else if (dwCompressionType&0x01 || dwCompressionType&0x08 || ((dwFlags & MAFA_COMPRESS)!=MAFA_COMPRESS && (dwFlags & MAFA_COMPRESS2)==MAFA_COMPRESS2)) {
2205                         dwCompressionSubType = dwCompressLevel;
2206                         dwCompressLevel = 0;
2207                 }
2208                 else if (dwCompressionType&0x02) {
2209                         dwCompressionSubType = 1;
2210                 }
2212                 DWORD LastOffset=ptsz;
2213                 BYTE *compbuffer = (BYTE *)SFAlloc(blockSize);
2214                 if (compbuffer==0) {
2215                         SFFree(dwBlkpt);
2216                         SFFree(buffer);
2217                         return FALSE;
2218                 }
2220                 char *outbuffer = (char *)SFAlloc(blockSize);
2221                 if (outbuffer==0) {
2222                         SFFree(compbuffer);
2223                         SFFree(dwBlkpt);
2224                         SFFree(buffer);
2225                         return FALSE;
2226                 }
2227                 char *newbuffer = (char *)SFAlloc(fsz+ptsz);
2228                 if (newbuffer==0) {
2229                         SFFree(outbuffer);
2230                         SFFree(compbuffer);
2231                         SFFree(dwBlkpt);
2232                         SFFree(buffer);
2233                         return FALSE;
2234                 }
2235                 DWORD CurPos=0;
2236                 for (i=0;i<TotalBlocks;i++) {
2237                         dwBlkpt[i] = LastOffset;
2238                         if (i==TotalBlocks-1 && (ucfsz % blockSize)!=0) blockSize=ucfsz % blockSize;
2239                         DWORD outLength=blockSize;
2240                         BYTE *compdata = compbuffer;
2241                         if (dwFlags & MAFA_COMPRESS)
2242                         {
2243                                 memcpy(compdata,(char *)buffer+CurPos,blockSize);
2244                                 if (i==0 && (dwCompressionType&0x40 || dwCompressionType&0x80)) {
2245                                         if (SCompCompress(outbuffer, &outLength, compdata, blockSize, 0x08, 0, 0)==0)
2246                                                 outLength=blockSize;
2247                                 }
2248                                 else
2249                                 {
2250                                         if (dwCompressionType&UNSUPPORTED_COMPRESSION) {
2251                                                 LoadStorm();
2252                                                 if (stormSCompCompress!=0) {
2253                                                         if (stormSCompCompress(outbuffer, &outLength, compdata, blockSize, dwCompressionType, dwCompressionSubType, dwCompressLevel)==0)
2254                                                                 outLength=blockSize;
2255                                                 }
2256                                         }
2257                                         else {
2258                                                 if (SCompCompress(outbuffer, &outLength, compdata, blockSize, dwCompressionType, dwCompressionSubType, dwCompressLevel)==0)
2259                                                         outLength=blockSize;
2260                                         }
2261                                 }
2262                         }
2263                         else if (dwFlags & MAFA_COMPRESS2)
2264                         {
2265                                 memcpy(compdata,(char *)buffer+CurPos,blockSize);
2266                                 if (SCompCompress(outbuffer, &outLength, compdata, blockSize, 0x08, dwCompressionSubType, 0)==0) {
2267                                         outLength=blockSize;
2268                                 }
2269                                 else {
2270                                         outbuffer++;
2271                                         outLength--;
2272                                 }
2273                         }
2274                         else
2275                         {
2276                                 memcpy(compdata,(char *)buffer+CurPos,blockSize);
2277                         }
2278                         if (outLength>=blockSize)
2279                         {
2280                                 memcpy((char *)newbuffer+LastOffset,compdata,blockSize);
2281                                 LastOffset+=blockSize;
2282                         }
2283                         else {
2284                                 memcpy((char *)newbuffer+LastOffset,outbuffer,outLength);
2285                                 LastOffset+=outLength;
2286                         }
2287                         CurPos += blockSize;
2288                 }
2289                 fsz = LastOffset;
2290                 dwBlkpt[TotalBlocks] = fsz;
2291                 memcpy(newbuffer,dwBlkpt,ptsz);
2292                 SFFree(outbuffer);
2293                 SFFree(compbuffer);
2294                 memcpy(buffer,newbuffer,fsz);
2295                 SFFree(newbuffer);
2296         }
2297         else
2298         {
2299                 for (i=0;i<TotalBlocks+1;i++) {
2300                         if (i<TotalBlocks) dwBlkpt[i] = i * blockSize;
2301                         else dwBlkpt[i] = ucfsz;
2302                 }
2303         }
2304         if (IsBNcache==TRUE)
2305         {
2306                 buffer = hbuffer;
2307                 fsz += 324;
2308         }
2309         HASHTABLEENTRY *hashEntry = (HASHTABLEENTRY *)hFile;
2311         BOOL IsNewBlockEntry = FALSE;DWORD OldBlockTableSize = sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize;
2312         if ((hashEntry->dwBlockTableIndex&0xFFFFFFFE)==0xFFFFFFFE)
2313         {
2314                 BLOCKTABLEENTRY *lpnBlockTable;
2315                 lpnBlockTable = (BLOCKTABLEENTRY *)SFAlloc(sizeof(BLOCKTABLEENTRY) * (mpqOpenArc->MpqHeader.dwBlockTableSize + 1));
2316                 if(lpnBlockTable==0) {
2317                         SFFree(buffer);
2318                         return FALSE;
2319                 }
2320                 if (mpqOpenArc->lpBlockTable!=0) memcpy(lpnBlockTable,mpqOpenArc->lpBlockTable,sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize);
2321                 mpqOpenArc->MpqHeader.dwBlockTableSize++;
2322                 if (mpqOpenArc->lpBlockTable!=0) SFFree(mpqOpenArc->lpBlockTable);
2323                 mpqOpenArc->lpBlockTable = lpnBlockTable;
2324                 IsNewBlockEntry = TRUE;
2325         }
2326         DWORD BlockIndex = mpqOpenArc->MpqHeader.dwBlockTableSize - 1;
2327         if ((hashEntry->dwBlockTableIndex&0xFFFFFFFE)==0xFFFFFFFE)
2328         {
2329                 hashEntry->dwNameHashA = HashString(lpFileName,HASH_NAME_A);
2330                 hashEntry->dwNameHashB = HashString(lpFileName,HASH_NAME_B);
2331                 hashEntry->lcLocale = LocaleID;
2332                 hashEntry->dwBlockTableIndex = BlockIndex;
2333                 mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset = 0;
2334         }
2335         else
2336         {
2337                 BlockIndex = hashEntry->dwBlockTableIndex;
2338         }
2339         if (mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset==0 || mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize<fsz)
2340         {
2341                 if (mpqOpenArc->MpqHeader.dwHashTableOffset+(mpqOpenArc->MpqHeader.dwHashTableSize * sizeof(HASHTABLEENTRY))+OldBlockTableSize==mpqOpenArc->MpqHeader.dwMPQSize)
2342                 {
2343                         if (mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset+mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize==mpqOpenArc->MpqHeader.dwHashTableOffset)
2344                         {
2345                                 mpqOpenArc->MpqHeader.dwHashTableOffset += fsz-mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize;
2346                                 mpqOpenArc->MpqHeader.dwBlockTableOffset += fsz-mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize;
2347                                 mpqOpenArc->MpqHeader.dwMPQSize += fsz-mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize;
2348                                 if (IsNewBlockEntry==TRUE) mpqOpenArc->MpqHeader.dwMPQSize += sizeof(BLOCKTABLEENTRY);
2349                         }
2350                         else
2351                         {
2352                                 mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset = mpqOpenArc->MpqHeader.dwHashTableOffset;
2353                                 mpqOpenArc->MpqHeader.dwHashTableOffset += fsz;
2354                                 mpqOpenArc->MpqHeader.dwBlockTableOffset += fsz;
2355                                 mpqOpenArc->MpqHeader.dwMPQSize += fsz;
2356                                 if (IsNewBlockEntry==TRUE) mpqOpenArc->MpqHeader.dwMPQSize += sizeof(BLOCKTABLEENTRY);
2357                         }
2358                 }
2359                 else if (mpqOpenArc->MpqHeader.dwBlockTableOffset+OldBlockTableSize==mpqOpenArc->MpqHeader.dwMPQSize)
2360                 {
2361                         if (mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset+mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize==mpqOpenArc->MpqHeader.dwBlockTableOffset)
2362                         {
2363                                 mpqOpenArc->MpqHeader.dwBlockTableOffset += fsz-mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize;
2364                                 mpqOpenArc->MpqHeader.dwMPQSize += fsz-mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize;
2365                                 if (IsNewBlockEntry==TRUE) mpqOpenArc->MpqHeader.dwMPQSize += sizeof(BLOCKTABLEENTRY);
2366                         }
2367                         else
2368                         {
2369                                 mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset = mpqOpenArc->MpqHeader.dwBlockTableOffset;
2370                                 mpqOpenArc->MpqHeader.dwBlockTableOffset += fsz;
2371                                 mpqOpenArc->MpqHeader.dwMPQSize += fsz;
2372                                 if (IsNewBlockEntry==TRUE) mpqOpenArc->MpqHeader.dwMPQSize += sizeof(BLOCKTABLEENTRY);
2373                         }
2374                 }
2375                 else
2376                 {
2377                         if (mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset+mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize==mpqOpenArc->MpqHeader.dwMPQSize)
2378                         {
2379                                 mpqOpenArc->MpqHeader.dwBlockTableOffset = mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset+fsz;
2380                                 mpqOpenArc->MpqHeader.dwMPQSize = mpqOpenArc->MpqHeader.dwBlockTableOffset+OldBlockTableSize;
2381                                 if (IsNewBlockEntry==TRUE) mpqOpenArc->MpqHeader.dwMPQSize += sizeof(BLOCKTABLEENTRY);
2382                         }
2383                         else
2384                         {
2385                                 mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset = mpqOpenArc->MpqHeader.dwMPQSize;
2386                                 mpqOpenArc->MpqHeader.dwBlockTableOffset = mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset+fsz;
2387                                 mpqOpenArc->MpqHeader.dwMPQSize = mpqOpenArc->MpqHeader.dwBlockTableOffset+OldBlockTableSize;
2388                                 if (IsNewBlockEntry==TRUE) mpqOpenArc->MpqHeader.dwMPQSize += sizeof(BLOCKTABLEENTRY);
2389                         }
2390                 }
2391         }
2392         mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize = fsz;
2393         mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize = ucfsz;
2394         mpqOpenArc->lpBlockTable[BlockIndex].dwFlags = dwFlags|MAFA_EXISTS;
2395         DWORD dwFileOffset = mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset;
2396         SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart,0,FILE_BEGIN);
2397         WriteFile(mpqOpenArc->hFile,&mpqOpenArc->MpqHeader,sizeof(MPQHEADER),&tsz,0);
2398         if (dwFlags & MAFA_ENCRYPT) {
2399                 DWORD dwCryptKey;
2400                 if (dwFlags&MAFA_ENCRYPT) dwCryptKey = HashString(lpFileName,HASH_KEY);
2401                 if (dwFlags&MAFA_MODCRYPTKEY) dwCryptKey = (dwCryptKey + mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset) ^ mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize;
2402                 DWORD blockSize = 512 << mpqOpenArc->MpqHeader.wBlockSize;
2403                 DWORD TotalBlocks = mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize / blockSize;
2405                 if(mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize % blockSize)
2406                         TotalBlocks++;
2407                 DWORD dwBlockEnd = mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize % blockSize;
2408                 if (dwBlockEnd==0) dwBlockEnd = blockSize;
2409                 if ((dwFlags & MAFA_COMPRESS)==MAFA_COMPRESS || (dwFlags & MAFA_COMPRESS2)==MAFA_COMPRESS2) {
2410                         EncryptData((LPBYTE)buffer,ptsz,dwCryptKey-1);
2411                 }
2412                 for (DWORD i=0;i<TotalBlocks;i++) {
2413                         EncryptData((LPBYTE)buffer+dwBlkpt[i],dwBlkpt[i+1]-dwBlkpt[i],dwCryptKey);
2414                         dwCryptKey++;
2415                 }
2416         }
2417         SFFree(dwBlkpt);
2418         SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+dwFileOffset,0,FILE_BEGIN);
2419         WriteFile(mpqOpenArc->hFile,buffer,fsz,&tsz,0);
2420         SFFree(buffer);
2421         buffer = (char *)SFAlloc(sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize);
2422         if (buffer!=0) {
2423                 memcpy(buffer,mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize);
2424                 EncryptData((LPBYTE)buffer,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,dwHashTableKey);
2425                 SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->MpqHeader.dwHashTableOffset,0,FILE_BEGIN);
2426                 WriteFile(mpqOpenArc->hFile,buffer,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,&tsz,0);
2427                 SFFree(buffer);
2428         }
2429         else {
2430                 EncryptData((LPBYTE)mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,dwHashTableKey);
2431                 SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->MpqHeader.dwHashTableOffset,0,FILE_BEGIN);
2432                 WriteFile(mpqOpenArc->hFile,mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,&tsz,0);
2433                 DecryptData((LPBYTE)mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,dwHashTableKey);
2434         }
2435         buffer = (char *)SFAlloc(sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize);
2436         if (buffer!=0) {
2437                 memcpy(buffer,mpqOpenArc->lpBlockTable,sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize);
2438                 EncryptData((LPBYTE)buffer,sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize,dwBlockTableKey);
2439                 SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->MpqHeader.dwBlockTableOffset,0,FILE_BEGIN);
2440                 WriteFile(mpqOpenArc->hFile,buffer,sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize,&tsz,0);
2441                 SFFree(buffer);
2442         }
2443         else {
2444                 EncryptData((LPBYTE)mpqOpenArc->lpBlockTable,sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize,dwBlockTableKey);
2445                 SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->MpqHeader.dwBlockTableOffset,0,FILE_BEGIN);
2446                 WriteFile(mpqOpenArc->hFile,mpqOpenArc->lpBlockTable,sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize,&tsz,0);
2447                 DecryptData((LPBYTE)mpqOpenArc->lpBlockTable,sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize,dwBlockTableKey);
2448         }
2449         AddToInternalListing(hMPQ,lpFileName);
2450         return TRUE;
2453 BOOL SFMPQAPI WINAPI MpqAddFileFromBuffer(MPQHANDLE hMPQ, LPVOID lpBuffer, DWORD dwLength, LPCSTR lpFileName, DWORD dwFlags)
2455         return MpqAddFileFromBufferEx(hMPQ,lpBuffer,dwLength,lpFileName,dwFlags,0x08,0);
2458 BOOL SFMPQAPI WINAPI MpqAddWaveFromBuffer(MPQHANDLE hMPQ, LPVOID lpBuffer, DWORD dwLength, LPCSTR lpFileName, DWORD dwFlags, DWORD dwQuality)
2460         return MpqAddFileFromBufferEx(hMPQ,lpBuffer,dwLength,lpFileName,dwFlags,0x81,dwQuality);
2463 BOOL SFMPQAPI WINAPI MpqRenameFile(MPQHANDLE hMPQ, LPCSTR lpcOldFileName, LPCSTR lpcNewFileName)
2465         return MpqRenameAndSetFileLocale(hMPQ,lpcOldFileName,lpcNewFileName,LocaleID,LocaleID);
2468 BOOL SFMPQAPI WINAPI MpqRenameAndSetFileLocale(MPQHANDLE hMPQ, LPCSTR lpcOldFileName, LPCSTR lpcNewFileName, LCID nOldLocale, LCID nNewLocale)
2470         if (!hMPQ || !lpcOldFileName || !lpcNewFileName) {
2471                 SetLastError(ERROR_INVALID_PARAMETER);
2472                 return FALSE;
2473         }
2474         if (!*lpcNewFileName) {
2475                 SetLastError(ERROR_INVALID_PARAMETER);
2476                 return FALSE;
2477         }
2479         if (!(((MPQARCHIVE *)hMPQ)->dwFlags&SFILE_OPEN_ALLOW_WRITE)) {
2480                 SetLastError(ERROR_ACCESS_DENIED);
2481                 return FALSE;
2482         }
2483         if (stricmp(lpcOldFileName,lpcNewFileName)==0) {
2484                 SetLastError(ERROR_INVALID_PARAMETER);
2485                 return FALSE;
2486         }
2487         MPQARCHIVE *mpqOpenArc = (MPQARCHIVE *)hMPQ;
2488         HASHTABLEENTRY *oldHashEntry = (HASHTABLEENTRY *)GetHashTableEntry(hMPQ,lpcOldFileName,nOldLocale);
2489         if (oldHashEntry==0) {
2490                 SetLastError(MPQ_ERROR_FILE_NOT_FOUND);
2491                 return FALSE;
2492         }
2493         if (oldHashEntry->lcLocale!=nOldLocale) {
2494                 SetLastError(MPQ_ERROR_FILE_NOT_FOUND);
2495                 return FALSE;
2496         }
2497         HASHTABLEENTRY *newHashEntry = (HASHTABLEENTRY *)GetFreeHashTableEntry(hMPQ,lpcNewFileName,nNewLocale,TRUE);
2498         if ((newHashEntry->dwBlockTableIndex&0xFFFFFFFE)!=0xFFFFFFFE)
2499                 return FALSE;
2500         if (newHashEntry==0) newHashEntry = oldHashEntry;
2501         DWORD tsz;
2502         newHashEntry->dwNameHashA = HashString(lpcNewFileName,HASH_NAME_A);
2503         newHashEntry->dwNameHashB = HashString(lpcNewFileName,HASH_NAME_B);
2504         newHashEntry->lcLocale = nNewLocale;
2505         newHashEntry->dwBlockTableIndex = oldHashEntry->dwBlockTableIndex;
2506         DWORD BlockIndex = oldHashEntry->dwBlockTableIndex;
2507         if (mpqOpenArc->lpBlockTable[BlockIndex].dwFlags & MAFA_ENCRYPT)
2508         {
2509                 DWORD dwOldCryptKey = HashString(lpcOldFileName,HASH_KEY);
2510                 DWORD dwNewCryptKey = HashString(lpcNewFileName,HASH_KEY);
2511                 if (mpqOpenArc->lpBlockTable[BlockIndex].dwFlags & MAFA_MODCRYPTKEY) {
2512                         dwOldCryptKey = (dwOldCryptKey + mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset) ^ mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize;
2514                         dwNewCryptKey = (dwNewCryptKey + mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset) ^ mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize;
2515                 }
2516                 if (dwOldCryptKey!=dwNewCryptKey)
2517                 {
2518                         DWORD HeaderLength=0;
2519                         if (memcmp(&mpqOpenArc->MpqHeader.dwMPQID,ID_BN3,4)==0)
2520                         {
2521                                 SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset,0,FILE_BEGIN);
2522                                 ReadFile(mpqOpenArc->hFile,&HeaderLength,4,&tsz,0);
2524                         }
2525                         DWORD blockSize = 512 << mpqOpenArc->MpqHeader.wBlockSize;
2526                         DWORD TotalBlocks = mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize / blockSize;
2527                         if(mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize % blockSize)
2528                                 TotalBlocks++;
2529                         DWORD *dwBlockPtrTable = (DWORD *)SFAlloc((TotalBlocks+1)*4);
2530                         if (dwBlockPtrTable==0) {
2531                                 return FALSE;
2532                         }
2533                         DWORD i;
2534                         if ((mpqOpenArc->lpBlockTable[BlockIndex].dwFlags & MAFA_COMPRESS)==MAFA_COMPRESS || (mpqOpenArc->lpBlockTable[BlockIndex].dwFlags & MAFA_COMPRESS2)==MAFA_COMPRESS2)
2535                         {
2536                                 SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset+HeaderLength,0,FILE_BEGIN);
2537                                 ReadFile(mpqOpenArc->hFile,dwBlockPtrTable,(TotalBlocks+1)*4,&tsz,0);
2538                                 DecryptData((LPBYTE)dwBlockPtrTable,(TotalBlocks+1)*4,dwOldCryptKey-1);
2539                                 char *EncryptedTable = (char *)SFAlloc((TotalBlocks+1)*4);
2540                                 if (EncryptedTable==0) {
2541                                         SFFree(dwBlockPtrTable);
2542                                         return FALSE;
2543                                 }
2544                                 memcpy(EncryptedTable,dwBlockPtrTable,(TotalBlocks+1)*4);
2545                                 EncryptData((LPBYTE)EncryptedTable,(TotalBlocks+1)*4,dwNewCryptKey-1);
2546                                 SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset+HeaderLength,0,FILE_BEGIN);
2547                                 WriteFile(mpqOpenArc->hFile,EncryptedTable,(TotalBlocks+1)*4,&tsz,0);
2548                                 SFFree(EncryptedTable);
2549                         }
2550                         else
2551                         {
2552                                 for (i=0;i<TotalBlocks+1;i++) {
2553                                         if (i<TotalBlocks) dwBlockPtrTable[i] = i * blockSize;
2554                                         else dwBlockPtrTable[i] = mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize;
2555                                 }
2556                         }
2557                         char *blkBuffer = (char *)SFAlloc(blockSize);
2558                         if (blkBuffer==0) {
2559                                 EncryptData((LPBYTE)dwBlockPtrTable,(TotalBlocks+1)*4,dwOldCryptKey-1);
2560                                 SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset+HeaderLength,0,FILE_BEGIN);
2561                                 WriteFile(mpqOpenArc->hFile,dwBlockPtrTable,(TotalBlocks+1)*4,&tsz,0);
2562                                 SFFree(dwBlockPtrTable);
2563                                 return FALSE;
2564                         }
2565                         for (i=0;i<TotalBlocks;i++) {
2566                                 SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset+HeaderLength+dwBlockPtrTable[i],0,FILE_BEGIN);
2567                                 if (ReadFile(mpqOpenArc->hFile,blkBuffer,dwBlockPtrTable[i+1]-dwBlockPtrTable[i],&tsz,0)==0) {
2568                                         EncryptData((LPBYTE)dwBlockPtrTable,(TotalBlocks+1)*4,dwOldCryptKey-1);
2569                                         SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset+HeaderLength,0,FILE_BEGIN);
2570                                         WriteFile(mpqOpenArc->hFile,dwBlockPtrTable,(TotalBlocks+1)*4,&tsz,0);
2571                                         SFFree(dwBlockPtrTable);
2572                                         SFFree(blkBuffer);
2573                                         return FALSE;
2574                                 }
2575                                 DecryptData((LPBYTE)blkBuffer,dwBlockPtrTable[i+1]-dwBlockPtrTable[i],dwOldCryptKey+i);
2576                                 EncryptData((LPBYTE)blkBuffer,dwBlockPtrTable[i+1]-dwBlockPtrTable[i],dwNewCryptKey+i);
2577                                 SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset+HeaderLength+dwBlockPtrTable[i],0,FILE_BEGIN);
2578                                 WriteFile(mpqOpenArc->hFile,blkBuffer,dwBlockPtrTable[i+1]-dwBlockPtrTable[i],&tsz,0);
2579                         }
2580                         SFFree(dwBlockPtrTable);
2581                         SFFree(blkBuffer);
2582                 }
2583         }
2584         if (oldHashEntry!=newHashEntry) {
2585                 oldHashEntry->dwNameHashA = 0xFFFFFFFF;
2586                 oldHashEntry->dwNameHashB = 0xFFFFFFFF;
2587                 oldHashEntry->lcLocale = 0xFFFFFFFF;
2588                 oldHashEntry->dwBlockTableIndex = 0xFFFFFFFE;
2589                 char *buffer = (char *)SFAlloc(sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize);
2590                 if (buffer!=0) {
2591                         memcpy(buffer,mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize);
2592                         EncryptData((LPBYTE)buffer,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,dwHashTableKey);
2593                         SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->MpqHeader.dwHashTableOffset,0,FILE_BEGIN);
2594                         WriteFile(mpqOpenArc->hFile,buffer,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,&tsz,0);
2595                         SFFree(buffer);
2596                 }
2597                 else {
2598                         EncryptData((LPBYTE)mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,dwHashTableKey);
2599                         SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->MpqHeader.dwHashTableOffset,0,FILE_BEGIN);
2600                         WriteFile(mpqOpenArc->hFile,mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,&tsz,0);
2601                         DecryptData((LPBYTE)mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,dwHashTableKey);
2602                 }
2603         }
2604         LCID dwOldLocale=LocaleID;
2605         LocaleID=nOldLocale;
2606         RemoveFromInternalListing(hMPQ,lpcOldFileName);
2608         LocaleID=nNewLocale;
2609         AddToInternalListing(hMPQ,lpcNewFileName);
2610         LocaleID=dwOldLocale;
2611         return TRUE;
2614 BOOL SFMPQAPI WINAPI MpqDeleteFile(MPQHANDLE hMPQ, LPCSTR lpFileName)
2616         return MpqDeleteFileWithLocale(hMPQ,lpFileName,LocaleID);
2619 BOOL SFMPQAPI WINAPI MpqDeleteFileWithLocale(MPQHANDLE hMPQ, LPCSTR lpFileName, LCID nLocale)
2621         if (!hMPQ || !lpFileName) {
2622                 SetLastError(ERROR_INVALID_PARAMETER);
2623                 return FALSE;
2624         }
2626         if (!(((MPQARCHIVE *)hMPQ)->dwFlags&SFILE_OPEN_ALLOW_WRITE)) {
2628                 SetLastError(ERROR_ACCESS_DENIED);
2629                 return FALSE;
2630         }
2631         MPQARCHIVE *mpqOpenArc = (MPQARCHIVE *)hMPQ;
2632         HASHTABLEENTRY *hashEntry = (HASHTABLEENTRY *)GetHashTableEntry(hMPQ,lpFileName,nLocale);
2633         if (hashEntry==0) {
2634                 SetLastError(MPQ_ERROR_FILE_NOT_FOUND);
2635                 return FALSE;
2636         }
2637         if (hashEntry->lcLocale!=nLocale) return FALSE;
2638         hashEntry->dwNameHashA = 0xFFFFFFFF;
2639         hashEntry->dwNameHashB = 0xFFFFFFFF;
2640         hashEntry->lcLocale = 0xFFFFFFFF;
2641         hashEntry->dwBlockTableIndex = 0xFFFFFFFE;
2642         DWORD tsz;
2643         char *buffer = (char *)SFAlloc(sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize);
2644         if (buffer!=0) {
2645                 memcpy(buffer,mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize);
2646                 EncryptData((LPBYTE)buffer,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,dwHashTableKey);
2647                 SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->MpqHeader.dwHashTableOffset,0,FILE_BEGIN);
2649                 WriteFile(mpqOpenArc->hFile,buffer,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,&tsz,0);
2650                 SFFree(buffer);
2651         }
2652         else {
2653                 EncryptData((LPBYTE)mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,dwHashTableKey);
2654                 SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->MpqHeader.dwHashTableOffset,0,FILE_BEGIN);
2655                 WriteFile(mpqOpenArc->hFile,mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,&tsz,0);
2656                 DecryptData((LPBYTE)mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,dwHashTableKey);
2657         }
2658         LCID dwOldLocale=LocaleID;
2659         LocaleID=nLocale;
2660         RemoveFromInternalListing(hMPQ,lpFileName);
2661         LocaleID=dwOldLocale;
2662         return TRUE;
2665 BOOL SFMPQAPI WINAPI MpqCompactArchive(MPQHANDLE hMPQ)
2667         if (!hMPQ) {
2668                 SetLastError(ERROR_INVALID_PARAMETER);
2669                 return FALSE;
2670         }
2672         if (!(((MPQARCHIVE *)hMPQ)->dwFlags&SFILE_OPEN_ALLOW_WRITE)) {
2673                 SetLastError(ERROR_ACCESS_DENIED);
2674                 return FALSE;
2675         }
2676         MPQARCHIVE *mpqOpenArc = (MPQARCHIVE *)hMPQ;
2677         TempAlloc NewAlloc;
2678         char *lpFileName = (char *)NewAlloc.Alloc(strlen(mpqOpenArc->lpFileName)+13);
2679         sprintf(lpFileName,"%s.compact",mpqOpenArc->lpFileName);
2680         HANDLE hFile = CreateFile(lpFileName,GENERIC_READ|GENERIC_WRITE,0,0,CREATE_NEW,0,0);
2681         DWORD i;
2682         if (hFile==INVALID_HANDLE_VALUE) {
2683                 for (i=0;i<10000;i++) {
2684                         sprintf(lpFileName,"%s.compact.%04ld",mpqOpenArc->lpFileName,i);
2686                         hFile = CreateFile(lpFileName,GENERIC_READ|GENERIC_WRITE,0,0,CREATE_NEW,0,0);
2687                         if (hFile!=INVALID_HANDLE_VALUE) break;
2688                 }
2689                 if (i==10000) return FALSE;
2690         }
2691         DWORD dwLastOffset = sizeof(MPQHEADER),tsz;
2692         char *buffer = (char *)SFAlloc(65536);
2693         if (buffer==0) {
2694                 CloseHandle(hFile);
2695                 DeleteFile(lpFileName);
2696                 return FALSE;
2697         }
2698         HASHTABLEENTRY *lpHashTable = (HASHTABLEENTRY *)SFAlloc(sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize);
2699         if (lpHashTable==0) {
2700                 SFFree(buffer);
2701                 CloseHandle(hFile);
2702                 DeleteFile(lpFileName);
2703                 return FALSE;
2704         }
2705         BLOCKTABLEENTRY *lpBlockTable = (BLOCKTABLEENTRY *)SFAlloc(sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize);
2706         if(mpqOpenArc->lpBlockTable!=0) {
2707                 if (lpBlockTable==0) {
2708                         SFFree(lpHashTable);
2709                         SFFree(buffer);
2710                         CloseHandle(hFile);
2711                         DeleteFile(lpFileName);
2713                         return FALSE;
2714                 }
2715         }
2716         DWORD j=0,nBlkOffset=0,ReadSize=0;
2717         memcpy(lpHashTable,mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize);
2718         for (i=0;i<mpqOpenArc->MpqHeader.dwBlockTableSize;i++) {
2719                 for (j=0;j<mpqOpenArc->MpqHeader.dwHashTableSize;j++) {
2720                         if (lpHashTable[j].dwBlockTableIndex==(i-nBlkOffset)) break;
2721                 }
2722                 if (j<mpqOpenArc->MpqHeader.dwHashTableSize) {
2723                         memcpy(&lpBlockTable[i-nBlkOffset],&mpqOpenArc->lpBlockTable[i],sizeof(BLOCKTABLEENTRY));
2724                         lpBlockTable[i-nBlkOffset].dwFileOffset = dwLastOffset;
2725                         dwLastOffset += mpqOpenArc->lpBlockTable[i].dwCompressedSize;
2726                         DWORD dwWritten=FALSE;
2727                         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))
2728                         {
2729                                 DWORD HeaderLength=0;
2730                                 if (memcmp(&mpqOpenArc->MpqHeader.dwMPQID,ID_BN3,4)==0)
2731                                 {
2732                                         SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->lpBlockTable[i].dwFileOffset,0,FILE_BEGIN);
2733                                         ReadFile(mpqOpenArc->hFile,&HeaderLength,4,&tsz,0);
2734                                 }
2735                                 DWORD blockSize = 512 << mpqOpenArc->MpqHeader.wBlockSize;
2736                                 DWORD TotalBlocks = mpqOpenArc->lpBlockTable[i].dwFullSize / blockSize;
2737                                 if(mpqOpenArc->lpBlockTable[i].dwFullSize % blockSize)
2738                                         TotalBlocks++;
2739                                 DWORD *dwBlockPtrTable = (DWORD *)SFAlloc((TotalBlocks+1)*4);
2740                                 if (dwBlockPtrTable==0) {
2741                                         SFFree(lpBlockTable);
2742                                         SFFree(lpHashTable);
2743                                         SFFree(buffer);
2744                                         CloseHandle(hFile);
2745                                         DeleteFile(lpFileName);
2746                                         return FALSE;
2747                                 }
2748                                 SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->lpBlockTable[i].dwFileOffset+HeaderLength,0,FILE_BEGIN);
2749                                 ReadFile(mpqOpenArc->hFile,dwBlockPtrTable,(TotalBlocks+1)*4,&tsz,0);
2750                                 DWORD dwOldCryptKey = DetectFileSeed(dwBlockPtrTable,(TotalBlocks+1)*4,blockSize);
2751                                 DWORD dwNewCryptKey = (dwOldCryptKey ^ mpqOpenArc->lpBlockTable[i].dwFullSize) - mpqOpenArc->lpBlockTable[i].dwFileOffset;
2752                                 dwNewCryptKey = (dwNewCryptKey + lpBlockTable[i-nBlkOffset].dwFileOffset) ^ lpBlockTable[i-nBlkOffset].dwFullSize;
2753                                 if (dwOldCryptKey==0) {
2754                                         DWORD dwNameHashA = HashString(INTERNAL_LISTFILE,HASH_NAME_A);
2755                                         DWORD dwNameHashB = HashString(INTERNAL_LISTFILE,HASH_NAME_B);
2756                                         if (lpHashTable[j].dwNameHashA==dwNameHashA && lpHashTable[j].dwNameHashB==dwNameHashB) {
2757                                                 dwOldCryptKey = HashString(INTERNAL_LISTFILE,HASH_KEY);
2758                                                 dwNewCryptKey = dwOldCryptKey;
2759                                                 dwOldCryptKey = (dwOldCryptKey + mpqOpenArc->lpBlockTable[i].dwFileOffset) ^ mpqOpenArc->lpBlockTable[i].dwFullSize;
2760                                                 dwNewCryptKey = (dwNewCryptKey + lpBlockTable[i-nBlkOffset].dwFileOffset) ^ lpBlockTable[i-nBlkOffset].dwFullSize;
2761                                         }
2762                                         else {
2763                                                 HANDLE hlFile;
2764                                                 DWORD fsz;
2765                                                 char *listbuffer;
2766                                                 LCID lcOldLocale = LocaleID;
2767                                                 for (DWORD lcn=0;lcn<nLocales;lcn++) {
2768                                                         LocaleID = availLocales[lcn];
2769                                                         if (SFileOpenFileEx(hMPQ,INTERNAL_LISTFILE,0,&hlFile)!=0) {
2770                                                                 if (((MPQFILE *)hlFile)->lpHashEntry->lcLocale==0 && LocaleID!=0) {
2772                                                                         SFileCloseFile(hlFile);
2773                                                                         continue;
2774                                                                 }
2775                                                                 fsz = SFileGetFileSize(hlFile,0);
2776                                                                 if (fsz>0) {
2777                                                                         listbuffer = (char *)SFAlloc(fsz+1);
2778                                                                         if (listbuffer==0) {
2779                                                                                 SFileCloseFile(hlFile);
2780                                                                                 continue;
2781                                                                         }
2782                                                                         if (SFileReadFile(hlFile,listbuffer,fsz,0,0)==0) {
2783                                                                                 SFFree(listbuffer);
2784                                                                                 listbuffer = 0;
2785                                                                         }
2786                                                                 }
2787                                                                 SFileCloseFile(hlFile);
2788                                                                 if (listbuffer!=0) {
2789                                                                         char *listline;
2790                                                                         for (listline=listbuffer;listline!=0;listline=nextline(listline)) {
2791                                                                                 if (listline[0]==0) break;
2792                                                                                 DWORD lnlen=strlnlen(listline);
2793                                                                                 char prevchar=listline[lnlen];
2794                                                                                 listline[lnlen]=0;
2795                                                                                 dwNameHashA = HashString(listline,HASH_NAME_A);
2796                                                                                 dwNameHashB = HashString(listline,HASH_NAME_B);
2797                                                                                 if (lpHashTable[j].dwNameHashA==dwNameHashA && lpHashTable[j].dwNameHashB==dwNameHashB) {
2798                                                                                         dwOldCryptKey = HashString(listline,HASH_KEY);
2799                                                                                         dwNewCryptKey = dwOldCryptKey;
2800                                                                                         dwOldCryptKey = (dwOldCryptKey + mpqOpenArc->lpBlockTable[i].dwFileOffset) ^ mpqOpenArc->lpBlockTable[i].dwFullSize;
2801                                                                                         dwNewCryptKey = (dwNewCryptKey + lpBlockTable[i-nBlkOffset].dwFileOffset) ^ lpBlockTable[i-nBlkOffset].dwFullSize;
2802                                                                                         break;
2803                                                                                 }
2804                                                                                 listline[lnlen]=prevchar;
2805                                                                         }
2806                                                                         if (listline!=0) {
2807                                                                                 if (listline[0]!=0) {
2808                                                                                         SFFree(listbuffer);
2809                                                                                         break;
2810                                                                                 }
2811                                                                         }
2812                                                                         SFFree(listbuffer);
2813                                                                 }
2814                                                         }
2815                                                 }
2816                                                 LocaleID = lcOldLocale;
2817                                         }
2818                                 }
2819                                 if (dwOldCryptKey!=dwNewCryptKey)
2820                                 {
2821                                         DecryptData((LPBYTE)dwBlockPtrTable,(TotalBlocks+1)*4,dwOldCryptKey-1);
2822                                         char *EncryptedTable = (char *)SFAlloc((TotalBlocks+1)*4);
2823                                         if (EncryptedTable==0) {
2824                                                 SFFree(dwBlockPtrTable);
2825                                                 SFFree(lpBlockTable);
2826                                                 SFFree(lpHashTable);
2827                                                 SFFree(buffer);
2828                                                 CloseHandle(hFile);
2829                                                 DeleteFile(lpFileName);
2830                                                 return FALSE;
2831                                         }
2832                                         memcpy(EncryptedTable,dwBlockPtrTable,(TotalBlocks+1)*4);
2833                                         EncryptData((LPBYTE)EncryptedTable,(TotalBlocks+1)*4,dwNewCryptKey-1);
2834                                         SetFilePointer(hFile,lpBlockTable[i-nBlkOffset].dwFileOffset+HeaderLength,0,FILE_BEGIN);
2835                                         WriteFile(hFile,EncryptedTable,(TotalBlocks+1)*4,&tsz,0);
2836                                         SFFree(EncryptedTable);
2837                                         char *blkBuffer = (char *)SFAlloc(blockSize);
2838                                         if (blkBuffer==0) {
2839                                                 SFFree(dwBlockPtrTable);
2840                                                 SFFree(lpBlockTable);
2841                                                 SFFree(lpHashTable);
2842                                                 SFFree(buffer);
2843                                                 CloseHandle(hFile);
2844                                                 DeleteFile(lpFileName);
2845                                                 return FALSE;
2846                                         }
2847                                         for (DWORD k=0;k<TotalBlocks;k++) {
2848                                                 SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->lpBlockTable[i].dwFileOffset+HeaderLength+dwBlockPtrTable[k],0,FILE_BEGIN);
2849                                                 if (ReadFile(mpqOpenArc->hFile,blkBuffer,dwBlockPtrTable[k+1]-dwBlockPtrTable[k],&tsz,0)==0) {
2850                                                         SFFree(dwBlockPtrTable);
2851                                                         SFFree(blkBuffer);
2852                                                         SFFree(lpBlockTable);
2853                                                         SFFree(lpHashTable);
2854                                                         SFFree(buffer);
2855                                                         CloseHandle(hFile);
2856                                                         DeleteFile(lpFileName);
2857                                                         return FALSE;
2858                                                 }
2859                                                 DecryptData((LPBYTE)blkBuffer,dwBlockPtrTable[k+1]-dwBlockPtrTable[k],dwOldCryptKey+k);
2860                                                 EncryptData((LPBYTE)blkBuffer,dwBlockPtrTable[k+1]-dwBlockPtrTable[k],dwNewCryptKey+k);
2861                                                 SetFilePointer(hFile,lpBlockTable[i-nBlkOffset].dwFileOffset+HeaderLength+dwBlockPtrTable[k],0,FILE_BEGIN);
2862                                                 WriteFile(hFile,blkBuffer,dwBlockPtrTable[k+1]-dwBlockPtrTable[k],&tsz,0);
2863                                         }
2864                                         SFFree(blkBuffer);
2865                                         dwWritten = TRUE;
2866                                 }
2867                                 SFFree(dwBlockPtrTable);
2868                         }
2869                         else if (mpqOpenArc->lpBlockTable[i].dwFlags&MAFA_ENCRYPT && mpqOpenArc->lpBlockTable[i].dwFlags&MAFA_MODCRYPTKEY)
2870                         {
2871                                 DWORD HeaderLength=0;
2872                                 if (memcmp(&mpqOpenArc->MpqHeader.dwMPQID,ID_BN3,4)==0)
2874                                 {
2875                                         SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->lpBlockTable[i].dwFileOffset,0,FILE_BEGIN);
2876                                         ReadFile(mpqOpenArc->hFile,&HeaderLength,4,&tsz,0);
2877                                 }
2878                                 DWORD blockSize = 512 << mpqOpenArc->MpqHeader.wBlockSize;
2879                                 DWORD TotalBlocks = mpqOpenArc->lpBlockTable[i].dwFullSize / blockSize;
2880                                 if(mpqOpenArc->lpBlockTable[i].dwFullSize % blockSize)
2881                                         TotalBlocks++;
2882                                 DWORD dwNameHashA = HashString(INTERNAL_LISTFILE,HASH_NAME_A);
2883                                 DWORD dwNameHashB = HashString(INTERNAL_LISTFILE,HASH_NAME_B);
2884                                 DWORD dwOldCryptKey=0;
2885                                 DWORD dwNewCryptKey=0;
2886                                 if (lpHashTable[j].dwNameHashA==dwNameHashA && lpHashTable[j].dwNameHashB==dwNameHashB) {
2887                                         dwOldCryptKey = HashString(INTERNAL_LISTFILE,HASH_KEY);
2888                                         dwNewCryptKey = dwOldCryptKey;
2889                                         dwOldCryptKey = (dwOldCryptKey + mpqOpenArc->lpBlockTable[i].dwFileOffset) ^ mpqOpenArc->lpBlockTable[i].dwFullSize;
2890                                         dwNewCryptKey = (dwNewCryptKey + lpBlockTable[i-nBlkOffset].dwFileOffset) ^ lpBlockTable[i-nBlkOffset].dwFullSize;
2891                                 }
2892                                 else {
2893                                         HANDLE hlFile;
2894                                         DWORD fsz;
2896                                         char *listbuffer;
2897                                         LCID lcOldLocale = LocaleID;
2898                                         for (DWORD lcn=0;lcn<nLocales;lcn++) {
2899                                                 LocaleID = availLocales[lcn];
2900                                                 if (SFileOpenFileEx(hMPQ,INTERNAL_LISTFILE,0,&hlFile)!=0) {
2901                                                         if (((MPQFILE *)hlFile)->lpHashEntry->lcLocale==0 && LocaleID!=0) {
2902                                                                 SFileCloseFile(hlFile);
2903                                                                 continue;
2904                                                         }
2905                                                         fsz = SFileGetFileSize(hlFile,0);
2906                                                         if (fsz>0) {
2907                                                                 listbuffer = (char *)SFAlloc(fsz+1);
2908                                                                 if (listbuffer==0) {
2909                                                                         SFileCloseFile(hlFile);
2910                                                                         continue;
2911                                                                 }
2912                                                                 if (SFileReadFile(hlFile,listbuffer,fsz,0,0)==0) {
2913                                                                         SFFree(listbuffer);
2914                                                                         listbuffer = 0;
2915                                                                 }
2916                                                         }
2917                                                         SFileCloseFile(hlFile);
2918                                                         if (listbuffer!=0) {
2919                                                                 char *listline;
2920                                                                 for (listline=listbuffer;listline!=0;listline=nextline(listline)) {
2921                                                                         if (listline[0]==0) break;
2922                                                                         DWORD lnlen=strlnlen(listline);
2923                                                                         char prevchar=listline[lnlen];
2924                                                                         listline[lnlen]=0;
2925                                                                         dwNameHashA = HashString(listline,HASH_NAME_A);
2926                                                                         dwNameHashB = HashString(listline,HASH_NAME_B);
2927                                                                         if (lpHashTable[j].dwNameHashA==dwNameHashA && lpHashTable[j].dwNameHashB==dwNameHashB) {
2928                                                                                 dwOldCryptKey = HashString(listline,HASH_KEY);
2929                                                                                 dwNewCryptKey = dwOldCryptKey;
2930                                                                                 dwOldCryptKey = (dwOldCryptKey + mpqOpenArc->lpBlockTable[i].dwFileOffset) ^ mpqOpenArc->lpBlockTable[i].dwFullSize;
2931                                                                                 dwNewCryptKey = (dwNewCryptKey + lpBlockTable[i-nBlkOffset].dwFileOffset) ^ lpBlockTable[i-nBlkOffset].dwFullSize;
2932                                                                                 break;
2933                                                                         }
2934                                                                         listline[lnlen]=prevchar;
2935                                                                 }
2936                                                                 if (listline!=0) {
2937                                                                         if (listline[0]!=0) {
2938                                                                                 SFFree(listbuffer);
2939                                                                                 break;
2940                                                                         }
2941                                                                 }
2942                                                                 SFFree(listbuffer);
2943                                                         }
2944                                                 }
2945                                         }
2946                                         LocaleID = lcOldLocale;
2947                                 }
2948                                 if (dwOldCryptKey!=dwNewCryptKey)
2949                                 {
2950                                         char *blkBuffer = (char *)SFAlloc(blockSize);
2951                                         if (blkBuffer==0) {
2952                                                 SFFree(lpBlockTable);
2953                                                 SFFree(lpHashTable);
2954                                                 SFFree(buffer);
2955                                                 CloseHandle(hFile);
2956                                                 DeleteFile(lpFileName);
2957                                                 return FALSE;
2958                                         }
2959                                         for (DWORD k=0;k<mpqOpenArc->lpBlockTable[i].dwFullSize;k+=blockSize) {
2960                                                 SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->lpBlockTable[i].dwFileOffset+HeaderLength+k,0,FILE_BEGIN);
2961                                                 if (k+blockSize>mpqOpenArc->lpBlockTable[i].dwFullSize) blockSize = mpqOpenArc->lpBlockTable[i].dwFullSize % blockSize;
2962                                                 if (ReadFile(mpqOpenArc->hFile,blkBuffer,blockSize,&tsz,0)==0) {
2963                                                         SFFree(blkBuffer);
2964                                                         SFFree(lpBlockTable);
2965                                                         SFFree(lpHashTable);
2966                                                         SFFree(buffer);
2967                                                         CloseHandle(hFile);
2968                                                         DeleteFile(lpFileName);
2969                                                         return FALSE;
2971                                                 }
2972                                                 DecryptData((LPBYTE)blkBuffer,blockSize,dwOldCryptKey+k);
2973                                                 EncryptData((LPBYTE)blkBuffer,blockSize,dwNewCryptKey+k);
2974                                                 SetFilePointer(hFile,lpBlockTable[i-nBlkOffset].dwFileOffset+HeaderLength+k,0,FILE_BEGIN);
2975                                                 WriteFile(hFile,blkBuffer,blockSize,&tsz,0);
2976                                         }
2977                                         SFFree(blkBuffer);
2978                                         dwWritten = TRUE;
2979                                 }
2980                         }
2981                         if (dwWritten==FALSE) {
2982                                 ReadSize = 65536;
2983                                 for (j=0;j<mpqOpenArc->lpBlockTable[i].dwCompressedSize;j+=65536) {
2984                                         SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->lpBlockTable[i].dwFileOffset+j,0,FILE_BEGIN);
2985                                         SetFilePointer(hFile,lpBlockTable[i-nBlkOffset].dwFileOffset+j,0,FILE_BEGIN);
2986                                         if (j+65536>mpqOpenArc->lpBlockTable[i].dwCompressedSize) ReadSize = mpqOpenArc->lpBlockTable[i].dwCompressedSize-j;
2987                                         if (ReadFile(mpqOpenArc->hFile,buffer,ReadSize,&tsz,0)==0) {
2988                                                 SFFree(lpBlockTable);
2989                                                 SFFree(lpHashTable);
2990                                                 SFFree(buffer);
2991                                                 CloseHandle(hFile);
2992                                                 DeleteFile(lpFileName);
2993                                                 return FALSE;
2994                                         }
2995                                         if (WriteFile(hFile,buffer,ReadSize,&tsz,0)==0) {
2996                                                 SFFree(lpBlockTable);
2997                                                 SFFree(lpHashTable);
2998                                                 SFFree(buffer);
2999                                                 CloseHandle(hFile);
3000                                                 DeleteFile(lpFileName);
3001                                                 return FALSE;
3002                                         }
3003                                 }
3004                         }
3005                 }
3006                 else {
3007                         for (j=0;j<mpqOpenArc->MpqHeader.dwHashTableSize;j++) {
3008                                 if ((lpHashTable[j].dwBlockTableIndex&0xFFFFFFFE)!=0xFFFFFFFE)
3009                                         if (lpHashTable[j].dwBlockTableIndex>(i-nBlkOffset)) lpHashTable[j].dwBlockTableIndex--;
3010                         }
3011                         nBlkOffset++;
3012                 }
3013         }
3014         mpqOpenArc->MpqHeader.dwBlockTableSize -= nBlkOffset;
3015         mpqOpenArc->MpqHeader.dwHashTableOffset = dwLastOffset;
3016         dwLastOffset += mpqOpenArc->MpqHeader.dwHashTableSize * sizeof(HASHTABLEENTRY);
3017         mpqOpenArc->MpqHeader.dwBlockTableOffset = dwLastOffset;
3018         dwLastOffset += mpqOpenArc->MpqHeader.dwBlockTableSize * sizeof(BLOCKTABLEENTRY);
3019         mpqOpenArc->MpqHeader.dwMPQSize = dwLastOffset;
3020         SFFree(mpqOpenArc->lpHashTable);
3021         mpqOpenArc->lpHashTable = lpHashTable;
3022         if(mpqOpenArc->lpBlockTable!=0) {
3023                 SFFree(mpqOpenArc->lpBlockTable);
3024                 mpqOpenArc->lpBlockTable = (BLOCKTABLEENTRY *)SFAlloc(mpqOpenArc->MpqHeader.dwBlockTableSize * sizeof(BLOCKTABLEENTRY));
3025                 if (mpqOpenArc->lpBlockTable==0) {
3026                         mpqOpenArc->lpBlockTable = lpBlockTable;
3027                 }
3028                 else {
3029                         memcpy(mpqOpenArc->lpBlockTable,lpBlockTable,mpqOpenArc->MpqHeader.dwBlockTableSize * sizeof(BLOCKTABLEENTRY));
3030                         SFFree(lpBlockTable);
3031                 }
3032         }
3033         SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+dwLastOffset,0,FILE_BEGIN);
3034         SetEndOfFile(mpqOpenArc->hFile);
3035         SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart,0,FILE_BEGIN);
3036         mpqOpenArc->MpqHeader.dwHeaderSize = sizeof(MPQHEADER);
3037         WriteFile(mpqOpenArc->hFile,&mpqOpenArc->MpqHeader,sizeof(MPQHEADER),&tsz,0);
3038         dwLastOffset = sizeof(MPQHEADER);
3039         ReadSize = 65536;
3040         for (i=dwLastOffset;i<mpqOpenArc->MpqHeader.dwHashTableOffset;i+=65536) {
3041                 SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+i,0,FILE_BEGIN);
3042                 SetFilePointer(hFile,i,0,FILE_BEGIN);
3043                 if (i+65536>mpqOpenArc->MpqHeader.dwHashTableOffset) ReadSize = mpqOpenArc->MpqHeader.dwHashTableOffset-i;
3044                 ReadFile(hFile,buffer,ReadSize,&tsz,0);
3045                 WriteFile(mpqOpenArc->hFile,buffer,ReadSize,&tsz,0);
3046         }
3047         SFFree(buffer);
3048         CloseHandle(hFile);
3049         DeleteFile(lpFileName);
3050         EncryptData((BYTE *)mpqOpenArc->lpHashTable,mpqOpenArc->MpqHeader.dwHashTableSize * sizeof(HASHTABLEENTRY),dwHashTableKey);
3051         SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->MpqHeader.dwHashTableOffset,0,FILE_BEGIN);
3052         WriteFile(mpqOpenArc->hFile,mpqOpenArc->lpHashTable,mpqOpenArc->MpqHeader.dwHashTableSize * sizeof(HASHTABLEENTRY),&tsz,0);
3053         DecryptData((BYTE *)mpqOpenArc->lpHashTable,mpqOpenArc->MpqHeader.dwHashTableSize * sizeof(HASHTABLEENTRY),dwHashTableKey);
3054         if(mpqOpenArc->lpBlockTable!=0) {
3055                 EncryptData((BYTE *)mpqOpenArc->lpBlockTable,mpqOpenArc->MpqHeader.dwBlockTableSize * sizeof(BLOCKTABLEENTRY),dwBlockTableKey);
3056                 SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->MpqHeader.dwBlockTableOffset,0,FILE_BEGIN);
3057                 WriteFile(mpqOpenArc->hFile,mpqOpenArc->lpBlockTable,mpqOpenArc->MpqHeader.dwBlockTableSize * sizeof(BLOCKTABLEENTRY),&tsz,0);
3058                 DecryptData((BYTE *)mpqOpenArc->lpBlockTable,mpqOpenArc->MpqHeader.dwBlockTableSize * sizeof(BLOCKTABLEENTRY),dwBlockTableKey);
3059         }
3060         return TRUE;
3063 BOOL SFMPQAPI WINAPI MpqSetFileLocale(MPQHANDLE hMPQ, LPCSTR lpFileName, LCID nOldLocale, LCID nNewLocale)
3065         if (!hMPQ || !lpFileName) {
3066                 SetLastError(ERROR_INVALID_PARAMETER);
3067                 return FALSE;
3068         }
3070         if (!(((MPQARCHIVE *)hMPQ)->dwFlags&SFILE_OPEN_ALLOW_WRITE)) {
3071                 SetLastError(ERROR_ACCESS_DENIED);
3072                 return FALSE;
3073         }
3074         if (nOldLocale==nNewLocale) return FALSE;
3075         MPQARCHIVE *mpqOpenArc = (MPQARCHIVE *)hMPQ;
3076         HASHTABLEENTRY *hashEntry = (HASHTABLEENTRY *)GetHashTableEntry(hMPQ,lpFileName,nOldLocale);
3077         if (hashEntry==0) return FALSE;
3078         if (hashEntry->lcLocale!=nOldLocale) return FALSE;
3079         hashEntry->lcLocale = nNewLocale;
3080         DWORD tsz;
3082         char *buffer = (char *)SFAlloc(sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize);
3083         if (buffer!=0) {
3084                 memcpy(buffer,mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize);
3085                 EncryptData((LPBYTE)buffer,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,dwHashTableKey);
3086                 SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->MpqHeader.dwHashTableOffset,0,FILE_BEGIN);
3087                 WriteFile(mpqOpenArc->hFile,buffer,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,&tsz,0);
3088                 SFFree(buffer);
3089         }
3090         else {
3091                 EncryptData((LPBYTE)mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,dwHashTableKey);
3092                 SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->MpqHeader.dwHashTableOffset,0,FILE_BEGIN);
3093                 WriteFile(mpqOpenArc->hFile,mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,&tsz,0);
3094                 DecryptData((LPBYTE)mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,dwHashTableKey);
3095         }
3096         LCID dwOldLocale=LocaleID;
3097         LocaleID=nOldLocale;
3098         RemoveFromInternalListing(hMPQ,lpFileName);
3100         LocaleID=nNewLocale;
3101         AddToInternalListing(hMPQ,lpFileName);
3102         LocaleID=dwOldLocale;
3103         return TRUE;
3106 DWORD SFMPQAPI WINAPI SFileFindMpqHeader(HANDLE hFile)
3108         if (hFile == INVALID_HANDLE_VALUE) {
3109                 SetLastError(ERROR_INVALID_PARAMETER);
3110                 return 0xFFFFFFFF;
3111         }
3112         DWORD FileLen = GetFileSize(hFile,0);
3113         char pbuf[sizeof(MPQHEADER)];
3114         DWORD tsz;
3115         for (DWORD i=0;i<FileLen;i+=512)
3116         {
3117                 SetFilePointer(hFile,i,0,FILE_BEGIN);
3118                 if (ReadFile(hFile,pbuf,sizeof(MPQHEADER),&tsz,0)==0) return 0xFFFFFFFF;
3119                 if (tsz<sizeof(MPQHEADER)) return 0xFFFFFFFF;
3120                 if (memcmp(pbuf,ID_MPQ,4)==0 || memcmp(pbuf,ID_BN3,4)==0)
3121                 {
3122                         // Storm no longer does this, so mpq api shouldn't either
3123                         /*FileLen -= i;
3124                         if (memcmp(pbuf+8,&FileLen,4)==0)
3125                                 return i;
3126                         else
3127                                 FileLen += i;*/
3128                         return i;
3129                 }
3130         }
3131         return 0xFFFFFFFF;
3134 DWORD WINAPI FindMpqHeaderAtLocation(HANDLE hFile, DWORD dwStart, DWORD dwLength)
3136         if (hFile == INVALID_HANDLE_VALUE) {
3137                 SetLastError(ERROR_INVALID_PARAMETER);
3138                 return 0xFFFFFFFF;
3139         }
3140         char pbuf[sizeof(MPQHEADER)];
3141         DWORD tsz;
3142         for (DWORD i=dwStart;i<dwStart+dwLength;i+=512)
3143         {
3144                 SetFilePointer(hFile,i,0,FILE_BEGIN);
3145                 if (ReadFile(hFile,pbuf,sizeof(MPQHEADER),&tsz,0)==0) return 0xFFFFFFFF;
3146                 if (i+tsz>dwStart+dwLength) tsz = (dwStart+dwLength)-i;
3147                 if (tsz<sizeof(MPQHEADER)) return 0xFFFFFFFF;
3148                 if (memcmp(pbuf,ID_MPQ,4)==0 || memcmp(pbuf,ID_BN3,4)==0)
3149                 {
3150                         // Storm no longer does this, so mpq api shouldn't either
3151                         /*FileLen -= i;
3152                         if (memcmp(pbuf+8,&FileLen,4)==0)
3153                                 return i;
3154                         else
3155                                 FileLen += i;*/
3156                         return i;
3157                 }
3158         }
3159         return 0xFFFFFFFF;
3162 DWORD GetFullPath(LPCSTR lpFileName, char *lpBuffer, DWORD dwBufferLength)
3164         if (!lpFileName) return (DWORD)-1;
3165         DWORD slen = strlen(lpFileName);
3166         if (memcmp(lpFileName+1,":\\",2)==0) {
3167                 if (slen+1>dwBufferLength) return slen+1;
3168                 memcpy(lpBuffer,lpFileName,slen+1);
3169         }
3170 #ifdef _WIN32
3171         else if (lpFileName[0]=='\\') {
3172 #else
3173         else if (lpFileName[0]=='/') {
3174 #endif
3175                 if (slen+3>dwBufferLength) return slen+3;
3176                 memcpy(lpBuffer,StormBasePath,2);
3177                 memcpy(lpBuffer+2,lpFileName,slen+1);
3178         }
3179         else {
3180                 DWORD sbslen = strlen(StormBasePath);
3181                 if (sbslen+slen+1>dwBufferLength) return sbslen+slen+1;
3182                 memcpy(lpBuffer,StormBasePath,sbslen);
3183                 memcpy(lpBuffer+sbslen,lpFileName,slen);
3184                 lpBuffer[sbslen+slen]=0;
3185         }
3186         return 0;
3189 MPQHANDLE GetHashTableEntry(MPQHANDLE hMPQ, LPCSTR lpFileName, LCID FileLocale)
3191         if (!hMPQ || !lpFileName) return 0;
3192         MPQARCHIVE *mpqOpenArc = (MPQARCHIVE *)hMPQ;
3193         DWORD dwTablePos = HashString(lpFileName,HASH_POSITION) % mpqOpenArc->MpqHeader.dwHashTableSize;
3194         DWORD dwNameHashA = HashString(lpFileName,HASH_NAME_A);
3195         DWORD dwNameHashB = HashString(lpFileName,HASH_NAME_B);
3196         StartTableSearch:
3197         DWORD i=dwTablePos;
3198         do
3199         {
3200                 if (mpqOpenArc->lpHashTable[i].dwBlockTableIndex==0xFFFFFFFF)
3201                 {
3202                         break;
3203                 }
3204                 else if (mpqOpenArc->lpHashTable[i].dwNameHashA==dwNameHashA && mpqOpenArc->lpHashTable[i].dwNameHashB==dwNameHashB && mpqOpenArc->lpHashTable[i].lcLocale==FileLocale && mpqOpenArc->lpHashTable[i].dwBlockTableIndex!=0xFFFFFFFE)
3205                 {
3206                         return (MPQHANDLE)&mpqOpenArc->lpHashTable[i];
3207                 }
3208                 i = (i + 1) % mpqOpenArc->MpqHeader.dwHashTableSize;
3209         } while (i!=dwTablePos);
3210         if (FileLocale!=0) {FileLocale=0;goto StartTableSearch;}
3211         return 0;
3214 MPQHANDLE GetHashTableEntryOfHash(MPQHANDLE hMPQ, DWORD dwTablePos, DWORD dwNameHashA, DWORD dwNameHashB, LCID FileLocale)
3216         if (!hMPQ) return 0;
3217         MPQARCHIVE *mpqOpenArc = (MPQARCHIVE *)hMPQ;
3218         StartTableSearch:
3219         DWORD i=dwTablePos;
3220         do
3221         {
3222                 if (mpqOpenArc->lpHashTable[i].dwBlockTableIndex==0xFFFFFFFF)
3223                 {
3224                         break;
3225                 }
3226                 else if (mpqOpenArc->lpHashTable[i].dwNameHashA==dwNameHashA && mpqOpenArc->lpHashTable[i].dwNameHashB==dwNameHashB && mpqOpenArc->lpHashTable[i].lcLocale==FileLocale && mpqOpenArc->lpHashTable[i].dwBlockTableIndex!=0xFFFFFFFE)
3227                 {
3228                         return (MPQHANDLE)&mpqOpenArc->lpHashTable[i];
3229                 }
3230                 i = (i + 1) % mpqOpenArc->MpqHeader.dwHashTableSize;
3231         } while (i!=dwTablePos);
3232         if (FileLocale!=0) {FileLocale=0;goto StartTableSearch;}
3233         return 0;
3236 MPQHANDLE GetFreeHashTableEntry(MPQHANDLE hMPQ, LPCSTR lpFileName, LCID FileLocale, BOOL ReturnExisting)
3238         if (!hMPQ || !lpFileName) return 0;
3239         MPQARCHIVE *mpqOpenArc = (MPQARCHIVE *)hMPQ;
3240         DWORD dwTablePos = HashString(lpFileName,HASH_POSITION) % mpqOpenArc->MpqHeader.dwHashTableSize;
3241         DWORD dwNameHashA = HashString(lpFileName,HASH_NAME_A);
3242         DWORD dwNameHashB = HashString(lpFileName,HASH_NAME_B);
3243         DWORD i=dwTablePos, nFirstFree = 0xFFFFFFFF;
3244         do
3245         {
3246                 if ((mpqOpenArc->lpHashTable[i].dwBlockTableIndex&0xFFFFFFFE)==0xFFFFFFFE && (nFirstFree == 0xFFFFFFFF || mpqOpenArc->lpHashTable[i].dwBlockTableIndex == 0xFFFFFFFF))
3247                 {
3248                         if (mpqOpenArc->lpHashTable[i].dwBlockTableIndex == 0xFFFFFFFF)
3249                         {
3250                                 if (nFirstFree == 0xFFFFFFFF)
3251                                         return (MPQHANDLE)&mpqOpenArc->lpHashTable[i];
3252                                 else
3253                                         return (MPQHANDLE)&mpqOpenArc->lpHashTable[nFirstFree];
3254                         }
3255                         else nFirstFree = i;
3256                 }
3257                 else if (mpqOpenArc->lpHashTable[i].dwNameHashA==dwNameHashA && mpqOpenArc->lpHashTable[i].dwNameHashB==dwNameHashB && mpqOpenArc->lpHashTable[i].lcLocale==FileLocale)
3258                 {
3259                         if (ReturnExisting!=FALSE)
3260                                 return (MPQHANDLE)&mpqOpenArc->lpHashTable[i];
3261                         else {
3262                                 SetLastError(MPQ_ERROR_ALREADY_EXISTS);
3263                                 return 0;
3264                         }
3265                 }
3266                 i = (i + 1) % mpqOpenArc->MpqHeader.dwHashTableSize;
3267         } while (i!=dwTablePos);
3268         SetLastError(MPQ_ERROR_HASH_TABLE_FULL);
3269         return 0;
3272 BOOL SearchOpenArchives(LPCSTR lpFileName, MPQHANDLE *hMPQ, MPQHANDLE *hFile)
3274         MPQHANDLE hnMPQ,hnFile,hndMPQ = 0,hndFile = 0;
3276         DWORD dwTablePos = HashString(lpFileName,HASH_POSITION);
3277         DWORD dwNameHashA = HashString(lpFileName,HASH_NAME_A);
3278         DWORD dwNameHashB = HashString(lpFileName,HASH_NAME_B);
3280         for (DWORD i=0;i<dwOpenMpqCount;i++) {
3281                 hnMPQ = (MPQHANDLE)lpOpenMpq[i];
3282                 hnFile = GetHashTableEntryOfHash(hnMPQ,dwTablePos % lpOpenMpq[i]->MpqHeader.dwHashTableSize,dwNameHashA,dwNameHashB,LocaleID);
3284                 if (hnFile!=0) {
3285                         if (((HASHTABLEENTRY *)hnFile)->lcLocale == LocaleID) {
3286                                 *hMPQ = hnMPQ;
3287                                 *hFile = hnFile;
3288                                 return TRUE;
3289                         }
3290                         else if (hndMPQ == 0 || hndFile == 0) {
3291                                 hndMPQ = hnMPQ;
3292                                 hndFile = hnFile;
3293                         }
3294                 }
3295         }
3297         if (hndMPQ != 0 && hndFile != 0) {
3298                 *hMPQ = hndMPQ;
3299                 *hFile = hndFile;
3300                 return TRUE;
3301         }
3303         *hMPQ = 0;
3304         *hFile = 0;
3305         return FALSE;
3308 void SortOpenArchivesByPriority()
3310         MPQARCHIVE *hMPQ1,*hMPQ2;
3311         for (DWORD i=1;i<dwOpenMpqCount;i++) {
3312                 do {
3313                         hMPQ1 = lpOpenMpq[i-1];
3314                         hMPQ2 = lpOpenMpq[i];
3315                         if (hMPQ2->dwPriority > hMPQ1->dwPriority) {
3316                                 lpOpenMpq[i-1] = hMPQ2;
3317                                 lpOpenMpq[i] = hMPQ1;
3318                                 i--;
3319                         }
3320                 } while (hMPQ2->dwPriority > hMPQ1->dwPriority && i>0);
3321         }
3324 DWORD GetHandleType(MPQHANDLE hFile)
3326         DWORD i;
3327         for (i=0;i<dwOpenFileCount;i++) {
3328                 if ((MPQHANDLE)lpOpenFile[i]==hFile) return SFILE_TYPE_FILE;
3329         }
3330         for (i=0;i<dwOpenMpqCount;i++) {
3331                 if ((MPQHANDLE)lpOpenMpq[i]==hFile) return SFILE_TYPE_MPQ;
3332         }
3333         return 0;
3336 BOOL AddToInternalListing(MPQHANDLE hMPQ, LPCSTR lpFileName)
3338         MPQARCHIVE *mpqOpenArc = (MPQARCHIVE *)hMPQ;
3339         if ((mpqOpenArc->dwFlags & MOAU_MAINTAIN_LISTFILE)==MOAU_MAINTAIN_LISTFILE && stricmp(lpFileName,INTERNAL_LISTFILE)!=0)
3340         {
3341                 MPQHANDLE hlFile;char *buffer=0;DWORD fsz,lsz;
3342                 lsz = strlen(lpFileName);
3343                 if (SFileOpenFileEx(hMPQ,INTERNAL_LISTFILE,0,&hlFile)!=0) {
3344                         if (((MPQFILE *)hlFile)->lpHashEntry->lcLocale==LocaleID) {
3345                                 fsz = SFileGetFileSize(hlFile,0);
3346                                 if (fsz==0) {
3347                                         SFileCloseFile(hlFile);
3348                                         goto AddFileName;
3349                                 }
3350                                 buffer = (char *)SFAlloc(fsz+lsz+2);
3351                                 if (buffer==0) {
3352                                         SFileCloseFile(hlFile);
3353                                         return FALSE;
3354                                 }
3355                                 if (SFileReadFile(hlFile,buffer,fsz,0,0)==0) {
3356                                         SFFree(buffer);
3357                                         buffer = 0;
3358                                 }
3359                                 buffer[fsz]=0;
3360                         }
3361                         SFileCloseFile(hlFile);
3362                 }
3363                 AddFileName:
3364                 if (buffer==0) {
3365                         fsz = 0;
3366                         buffer = (char *)SFAlloc(lsz+2);
3367                         buffer[0]=0;
3368                 }
3369                 else {
3370                         char *buffercopy = strlwr(strdup(buffer));
3371                         char *lwrFileName = strlwr(strdup(lpFileName));
3372                         char *subbuffer=buffer;
3373                         while ((subbuffer=strstr(subbuffer,lpFileName))!=NULL && subbuffer[0]!=0) {
3374                                 if (subbuffer==buffer && subbuffer[lsz]==0) {
3375                                         SFFree(lwrFileName);
3376                                         SFFree(buffercopy);
3377                                         SFFree(buffer);
3378                                         return TRUE;
3379                                 }
3380                                 else if (subbuffer==buffer && (subbuffer[lsz]=='\n' || subbuffer[lsz]=='\r')) {
3381                                         SFFree(lwrFileName);
3382                                         SFFree(buffercopy);
3383                                         SFFree(buffer);
3384                                         return TRUE;
3385                                 }
3386                                 else if (((subbuffer-1)[0]=='\n' || (subbuffer-1)[0]=='\r') && subbuffer[lsz]==0) {
3387                                         SFFree(lwrFileName);
3388                                         SFFree(buffercopy);
3389                                         SFFree(buffer);
3390                                         return TRUE;
3391                                 }
3392                                 else if (((subbuffer-1)[0]=='\n' || (subbuffer-1)[0]=='\r') && (subbuffer[lsz]=='\n' || subbuffer[lsz]=='\r')) {
3393                                         SFFree(lwrFileName);
3394                                         SFFree(buffercopy);
3395                                         SFFree(buffer);
3396                                         return TRUE;
3397                                 }
3398                                 subbuffer++;
3399                         }
3400                         SFFree(lwrFileName);
3401                         SFFree(buffercopy);
3402                 }
3403                 memcpy(buffer+fsz,lpFileName,lsz);
3404                 memcpy(buffer+fsz+lsz,"\r\n",2);
3405                 //LCID dwOldLocale=LocaleID;
3406                 //LocaleID=0;
3407                 MpqAddFileFromBuffer(hMPQ,buffer,fsz+lsz+2,INTERNAL_LISTFILE,MAFA_COMPRESS|MAFA_ENCRYPT|MAFA_MODCRYPTKEY|MAFA_REPLACE_EXISTING);
3408                 //LocaleID=dwOldLocale;
3409                 SFFree(buffer);
3410         }
3411         return TRUE;
3414 BOOL RemoveFromInternalListing(MPQHANDLE hMPQ, LPCSTR lpFileName)
3416         MPQARCHIVE *mpqOpenArc = (MPQARCHIVE *)hMPQ;
3417         if ((mpqOpenArc->dwFlags & MOAU_MAINTAIN_LISTFILE)==MOAU_MAINTAIN_LISTFILE && stricmp(lpFileName,INTERNAL_LISTFILE)!=0)
3418         {
3419                 MPQHANDLE hlFile;char *buffer=0;DWORD fsz,lsz;
3420                 lsz = strlen(lpFileName);
3421                 if (SFileOpenFileEx(hMPQ,INTERNAL_LISTFILE,0,&hlFile)!=0) {
3422                         if (((MPQFILE *)hlFile)->lpHashEntry->lcLocale==LocaleID) {
3423                                 fsz = SFileGetFileSize(hlFile,0);
3424                                 if (fsz==0) {
3425                                         SFileCloseFile(hlFile);
3427                                         return FALSE;
3428                                 }
3430                                 buffer = (char *)SFAlloc(fsz+1);
3431                                 if (buffer==0) {
3432                                         SFileCloseFile(hlFile);
3433                                         return FALSE;
3434                                 }
3435                                 buffer[fsz] = 0;
3436                                 if (SFileReadFile(hlFile,buffer,fsz,0,0)==0) {
3437                                         SFFree(buffer);
3438                                         buffer = 0;
3439                                 }
3440                         }
3441                         SFileCloseFile(hlFile);
3442                 }
3443                 if (buffer==0) {
3444                         return FALSE;
3445                 }
3446                 else {
3447                         buffer[fsz]=0;
3448                         char *buffercopy = strlwr(strdup(buffer));
3449                         char *lwrFileName = strlwr(strdup(lpFileName));
3450                         char *subbuffer=buffer;
3452                         while ((subbuffer=strstr(subbuffer,lpFileName))!=NULL && subbuffer[0]!=0) {
3453                                 if (subbuffer==buffer && subbuffer[lsz]==0) {
3454                                         SFFree(lwrFileName);
3455                                         SFFree(buffercopy);
3456                                         //LCID dwOldLocale=LocaleID;
3457                                         //LocaleID=0;
3458                                         MpqAddFileFromBuffer(hMPQ,(LPVOID)"\x00",0,INTERNAL_LISTFILE,MAFA_COMPRESS|MAFA_ENCRYPT|MAFA_MODCRYPTKEY|MAFA_REPLACE_EXISTING);
3459                                         //LocaleID=dwOldLocale;
3460                                         SFFree(buffer);
3461                                         return TRUE;
3462                                 }
3463                                 else if (subbuffer==buffer && (subbuffer[lsz]=='\n' || subbuffer[lsz]=='\r')) {
3464                                         SFFree(lwrFileName);
3465                                         SFFree(buffercopy);
3466                                         if (subbuffer[lsz+1]=='\n' || subbuffer[lsz+1]=='\r') lsz++;
3467                                         memcpy(subbuffer,subbuffer+lsz+1,strlen(subbuffer+lsz+1));
3468                                         //LCID dwOldLocale=LocaleID;
3469                                         //LocaleID=0;
3470                                         MpqAddFileFromBuffer(hMPQ,buffer,fsz-lsz-1,INTERNAL_LISTFILE,MAFA_COMPRESS|MAFA_ENCRYPT|MAFA_MODCRYPTKEY|MAFA_REPLACE_EXISTING);
3471                                         //LocaleID=dwOldLocale;
3472                                         SFFree(buffer);
3473                                         return TRUE;
3474                                 }
3475                                 else if (((subbuffer-1)[0]=='\n' || (subbuffer-1)[0]=='\r') && subbuffer[lsz]==0) {
3476                                         SFFree(lwrFileName);
3477                                         SFFree(buffercopy);
3478                                         //LCID dwOldLocale=LocaleID;
3479                                         //LocaleID=0;
3480                                         MpqAddFileFromBuffer(hMPQ,buffer,fsz-lsz,INTERNAL_LISTFILE,MAFA_COMPRESS|MAFA_ENCRYPT|MAFA_MODCRYPTKEY|MAFA_REPLACE_EXISTING);
3481                                         //LocaleID=dwOldLocale;
3482                                         SFFree(buffer);
3483                                         return TRUE;
3484                                 }
3485                                 else if (((subbuffer-1)[0]=='\n' || (subbuffer-1)[0]=='\r') && (subbuffer[lsz]=='\n' || subbuffer[lsz]=='\r')) {
3486                                         SFFree(lwrFileName);
3487                                         SFFree(buffercopy);
3488                                         if ((subbuffer-2)[0]=='\n' || (subbuffer-2)[0]=='\r') {subbuffer--;lsz++;}
3489                                         memcpy(subbuffer-1,subbuffer+lsz,strlen(subbuffer+lsz));
3490                                         //LCID dwOldLocale=LocaleID;
3491                                         //LocaleID=0;
3492                                         MpqAddFileFromBuffer(hMPQ,buffer,fsz-lsz-1,INTERNAL_LISTFILE,MAFA_COMPRESS|MAFA_ENCRYPT|MAFA_MODCRYPTKEY|MAFA_REPLACE_EXISTING);
3493                                         //LocaleID=dwOldLocale;
3494                                         SFFree(buffer);
3495                                         return TRUE;
3496                                 }
3497                                 subbuffer++;
3498                         }
3499                         SFFree(lwrFileName);
3500                         SFFree(buffercopy);
3501                 }
3502                 SFFree(buffer);
3503         }
3504         return TRUE;
3507 size_t strlnlen(const char *strline)
3509         if (strline==0) return 0;
3510         const char *strcr = strchr(strline,'\r');
3511         const char *strlf = strchr(strline,'\n');
3512         if (strcr==0 && strlf==0) return strlen(strline);
3513         if (strcr!=0 && (strcr<strlf || strlf==0)) return strcr-strline;
3514         if (strlf!=0 && (strlf<strcr || strcr==0)) return strlf-strline;
3515         return strlen(strline);
3518 char *nextline(const char *strline)
3520         if (strline==0) return 0;
3521         const char *strcr = strchr(strline,'\r');
3522         const char *strlf = strchr(strline,'\n');
3523         if (strcr==0 && strlf==0) return 0;
3524         const char *streol;
3525         if (strcr!=0 && (strcr<strlf || strlf==0)) streol = strcr;
3526         if (strlf!=0 && (strlf<strcr || strcr==0)) streol = strlf;
3527         do {
3528                 streol++;
3529         } while (streol[0]=='\r' || streol[0]=='\n');
3530         if (streol[0]==0) return 0;
3531         return (char *)streol;
3534 // The InitCryptTable, HashString, DecryptData, and DetectFileKey are
3535 // based on the versions in StormLib which were written by Ladislav 
3536 // Zezula, but may have been modified somewhat by Quantam or ShadowFlare.
3537 BOOL InitCryptTable()
3539         DWORD seed   = 0x00100001;
3540         DWORD index1 = 0;
3541         DWORD index2 = 0;
3542         int   i;
3543                 
3544         if (!bCryptTableInit)
3545         {
3546                  for(index1 = 0; index1 < 0x100; index1++)
3547                  {
3548                           for(index2 = index1, i = 0; i < 5; i++, index2 += 0x100)
3549                           {
3550                                         DWORD temp1, temp2;
3551                 
3552                                         seed  = (seed * 125 + 3) % 0x2AAAAB;
3553                                         temp1 = (seed & 0xFFFF) << 0x10;
3554                 
3555                                         seed  = (seed * 125 + 3) % 0x2AAAAB;
3556                                         temp2 = (seed & 0xFFFF);
3557                 
3558                                         dwCryptTable[index2] = (temp1 | temp2);
3559                           }
3560                  }
3562                 bCryptTableInit = TRUE;
3563         }
3565         return TRUE;
3568 DWORD HashString(LPCSTR lpszString, DWORD dwHashType)
3570     DWORD  seed1 = 0x7FED7FED;
3571     DWORD  seed2 = 0xEEEEEEEE;
3572     int    ch;
3574         char szNull = 0;
3575         if (!lpszString)
3576                 lpszString = &szNull;
3578         if (dwHashType==HASH_KEY)
3579                 while (strchr(lpszString,'\\')!=NULL) lpszString = strchr(lpszString,'\\')+1;
3580     while (*lpszString != 0)
3581     {
3582         ch = toupper(*lpszString++);
3584         seed1 = dwCryptTable[(dwHashType << 8) + ch] ^ (seed1 + seed2);
3585         seed2 = ch + seed1 + seed2 + (seed2 << 5) + 3;
3586     }
3588     return seed1;
3591 // The EncryptData function is based on the DecryptData function by
3592 // Ladislav Zezula, but adapted by Quantam to encrypt rather than decrypt.
3593 BOOL EncryptData(LPBYTE lpbyBuffer, DWORD dwLength, DWORD dwKey)
3595     LPDWORD lpdwBuffer = (LPDWORD)lpbyBuffer;
3596     DWORD seed = 0xEEEEEEEE;
3597     DWORD ch;
3599         if (!lpbyBuffer)
3600                 return FALSE;
3602     // Round to DWORDs
3603     dwLength >>= 2;
3605     while(dwLength-- > 0)
3607     {
3608         seed += dwCryptTable[0x400 + (dwKey & 0xFF)];
3609         ch = *lpdwBuffer ^ (dwKey + seed);
3611         dwKey = ((~dwKey << 0x15) + 0x11111111) | (dwKey >> 0x0B);
3612         seed = *lpdwBuffer + seed + (seed << 5) + 3;
3614                 *lpdwBuffer++ = ch;
3615     }
3617          return TRUE;
3620 BOOL DecryptData(LPBYTE lpbyBuffer, DWORD dwLength, DWORD dwKey)
3622         LPDWORD lpdwBuffer = (LPDWORD)lpbyBuffer;
3623     DWORD seed = 0xEEEEEEEE;
3624     DWORD ch;
3626         if (!lpbyBuffer)
3627                 return FALSE;
3629     // Round to DWORDs
3630     dwLength >>= 2;
3632     while(dwLength-- > 0)
3633     {
3634         seed += dwCryptTable[0x400 + (dwKey & 0xFF)];
3635         ch = *lpdwBuffer ^ (dwKey + seed);
3637         dwKey = ((~dwKey << 0x15) + 0x11111111) | (dwKey >> 0x0B);
3638         seed = ch + seed + (seed << 5) + 3;
3640                 *lpdwBuffer++ = ch;
3641     }
3643          return TRUE;
3646 //-----------------------------------------------------------------------------
3647 // Functions tries to get file decryption key. The trick comes from block
3648 // positions which are stored at the begin of each compressed file. We know the
3649 // file size, that means we know number of blocks that means we know the first
3650 // DWORD value in block position. And if we know encrypted and decrypted value,
3651 // we can find the decryption key !!!
3652 //
3653 // hf    - MPQ file handle
3654 // block - DWORD array of block positions
3655 // ch    - Decrypted value of the first block pos
3657 static DWORD DetectFileSeed(DWORD * block, DWORD decrypted, DWORD blocksize)
3659     DWORD saveSeed1;
3660     DWORD temp = *block ^ decrypted;    // temp = seed1 + seed2
3661                                         // temp = seed1 + stormBuffer[0x400 + (seed1 & 0xFF)] + 0xEEEEEEEE
3662     temp -= 0xEEEEEEEE;                 // temp = seed1 + stormBuffer[0x400 + (seed1 & 0xFF)]
3663     
3665     for(int i = 0; i < 0x100; i++)      // Try all 256 possibilities
3666     {
3667         DWORD seed1;
3668         DWORD seed2 = 0xEEEEEEEE;
3669         DWORD ch;
3671         // Try the first DWORD (We exactly know the value)
3672         seed1  = temp - dwCryptTable[0x400 + i];
3673         seed2 += dwCryptTable[0x400 + (seed1 & 0xFF)];
3674         ch     = block[0] ^ (seed1 + seed2);
3676         if(ch != decrypted)
3677             continue;
3679         saveSeed1 = seed1 + 1;
3681         // If OK, continue and test the second value. We don't know exactly the value,
3682         // but we know that the second one has a value less than or equal to the
3683                 // size of the block position table plus the block size
3684         seed1  = ((~seed1 << 0x15) + 0x11111111) | (seed1 >> 0x0B);
3685         seed2  = ch + seed2 + (seed2 << 5) + 3;
3687         seed2 += dwCryptTable[0x400 + (seed1 & 0xFF)];
3688         ch     = block[1] ^ (seed1 + seed2);
3690         if(ch <= decrypted + blocksize)
3691             return saveSeed1;
3692     }
3693     return 0;
3696 DWORD DetectFileSeedEx(MPQARCHIVE * mpqOpenArc, HASHTABLEENTRY * lpHashEntry, LPCSTR * lplpFileName)
3698         if (mpqOpenArc==0 || lpHashEntry==0) return 0;
3699         DWORD dwCryptKey=0;
3700         LPCSTR lpFileName = *lplpFileName;
3701         DWORD dwBlockIndex = lpHashEntry->dwBlockTableIndex;
3702         if (lpFileName)
3703         {
3704                 dwCryptKey = HashString(lpFileName,HASH_KEY);
3705                 if (mpqOpenArc->lpBlockTable[dwBlockIndex].dwFlags&MAFA_MODCRYPTKEY)
3706                         dwCryptKey = (dwCryptKey + mpqOpenArc->lpBlockTable[dwBlockIndex].dwFileOffset) ^ mpqOpenArc->lpBlockTable[dwBlockIndex].dwFullSize;
3707         }
3708         else
3709         {
3710                 DWORD dwNameHashA = HashString(INTERNAL_LISTFILE,HASH_NAME_A);
3711                 DWORD dwNameHashB = HashString(INTERNAL_LISTFILE,HASH_NAME_B);
3712                 if (lpHashEntry->dwNameHashA==dwNameHashA && lpHashEntry->dwNameHashB==dwNameHashB) {
3713                         dwCryptKey = HashString(INTERNAL_LISTFILE,HASH_KEY);
3714                         if (mpqOpenArc->lpBlockTable[dwBlockIndex].dwFlags&MAFA_MODCRYPTKEY)
3715                                 dwCryptKey = (dwCryptKey + mpqOpenArc->lpBlockTable[dwBlockIndex].dwFileOffset) ^ mpqOpenArc->lpBlockTable[dwBlockIndex].dwFullSize;
3716                         *lplpFileName = (char *)SFAlloc(strlen(INTERNAL_LISTFILE)+1);
3717                         if (*lplpFileName)
3718                                 strcpy((LPSTR)*lplpFileName,INTERNAL_LISTFILE);
3719                 }
3720                 else {
3721                         HANDLE hlFile,hMPQ=(HANDLE)mpqOpenArc;
3722                         DWORD fsz;
3723                         char *listbuffer;
3724                         LCID lcOldLocale = LocaleID;
3725                         for (DWORD lcn=0;lcn<nLocales;lcn++) {
3726                                 LocaleID = availLocales[lcn];
3727                                 if (SFileOpenFileEx(hMPQ,INTERNAL_LISTFILE,0,&hlFile)!=0) {
3728                                         if (((MPQFILE *)hlFile)->lpHashEntry->lcLocale==0 && LocaleID!=0) {
3729                                                 SFileCloseFile(hlFile);
3730                                                 continue;
3731                                         }
3732                                         fsz = SFileGetFileSize(hlFile,0);
3733                                         if (fsz>0) {
3734                                                 listbuffer = (char *)SFAlloc(fsz+1);
3735                                                 if (listbuffer==0) {
3736                                                         SFileCloseFile(hlFile);
3737                                                         continue;
3738                                                 }
3739                                                 if (SFileReadFile(hlFile,listbuffer,fsz,0,0)==0) {
3740                                                         SFFree(listbuffer);
3741                                                         listbuffer = 0;
3742                                                 }
3743                                         }
3744                                         SFileCloseFile(hlFile);
3745                                         if (listbuffer!=0) {
3746                                                 char *listline;
3747                                                 for (listline=listbuffer;listline!=0;listline=nextline(listline)) {
3748                                                         if (listline[0]==0) break;
3749                                                         DWORD lnlen=strlnlen(listline);
3750                                                         char prevchar=listline[lnlen];
3751                                                         listline[lnlen]=0;
3752                                                         dwNameHashA = HashString(listline,HASH_NAME_A);
3753                                                         dwNameHashB = HashString(listline,HASH_NAME_B);
3754                                                         if (lpHashEntry->dwNameHashA==dwNameHashA && lpHashEntry->dwNameHashB==dwNameHashB) {
3755                                                                 dwCryptKey = HashString(listline,HASH_KEY);
3756                                                                 if (mpqOpenArc->lpBlockTable[dwBlockIndex].dwFlags&MAFA_MODCRYPTKEY)
3757                                                                         dwCryptKey = (dwCryptKey + mpqOpenArc->lpBlockTable[dwBlockIndex].dwFileOffset) ^ mpqOpenArc->lpBlockTable[dwBlockIndex].dwFullSize;
3758                                                                 *lplpFileName = (char *)SFAlloc(strlen(listline)+1);
3759                                                                 if (*lplpFileName)
3760                                                                         strcpy((LPSTR)*lplpFileName,listline);
3761                                                                 break;
3762                                                         }
3763                                                         listline[lnlen]=prevchar;
3764                                                 }
3765                                                 if (listline!=0) {
3766                                                         if (listline[0]!=0) {
3767                                                                 SFFree(listbuffer);
3768                                                                 break;
3769                                                         }
3770                                                 }
3771                                                 SFFree(listbuffer);
3772                                         }
3773                                 }
3774                         }
3775                         LocaleID = lcOldLocale;
3776                 }
3777                 if (dwCryptKey==0 && (mpqOpenArc->lpBlockTable[dwBlockIndex].dwFlags&MAFA_COMPRESS || mpqOpenArc->lpBlockTable[dwBlockIndex].dwFlags&MAFA_COMPRESS2))
3778                 {
3779                         DWORD HeaderLength=0,tsz;
3780                         if (memcmp(&mpqOpenArc->MpqHeader.dwMPQID,ID_BN3,4)==0)
3781                         {
3782                                 SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->lpBlockTable[dwBlockIndex].dwFileOffset,0,FILE_BEGIN);
3783                                 ReadFile(mpqOpenArc->hFile,&HeaderLength,4,&tsz,0);
3784                         }
3785                         DWORD blockSize = 512 << mpqOpenArc->MpqHeader.wBlockSize;
3786                         DWORD TotalBlocks = mpqOpenArc->lpBlockTable[dwBlockIndex].dwFullSize / blockSize;
3787                         if(mpqOpenArc->lpBlockTable[dwBlockIndex].dwFullSize % blockSize)
3788                                 TotalBlocks++;
3789                         DWORD *dwBlockPtrTable = (DWORD *)SFAlloc((TotalBlocks+1)*4);
3790                         if (dwBlockPtrTable==0)
3791                                 return 0;
3792                         SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->lpBlockTable[dwBlockIndex].dwFileOffset+HeaderLength,0,FILE_BEGIN);
3793                         ReadFile(mpqOpenArc->hFile,dwBlockPtrTable,(TotalBlocks+1)*4,&tsz,0);
3794                         dwCryptKey = DetectFileSeed(dwBlockPtrTable,(TotalBlocks+1)*4,blockSize);
3796                         SFFree(dwBlockPtrTable);
3797                 }
3798         }
3799         return dwCryptKey;
3802 long SFMPQAPI __inline SFMpqCompareVersion()
3804         SFMPQVERSION ExeVersion = SFMPQ_CURRENT_VERSION;
3805         SFMPQVERSION DllVersion = SFMpqGetVersion();
3806         if (DllVersion.Major>ExeVersion.Major) return 1;
3807         else if (DllVersion.Major<ExeVersion.Major) return -1;
3808         if (DllVersion.Minor>ExeVersion.Minor) return 1;
3809         else if (DllVersion.Minor<ExeVersion.Minor) return -1;
3810         if (DllVersion.Revision>ExeVersion.Revision) return 1;
3811         else if (DllVersion.Revision<ExeVersion.Revision) return -1;
3812         if (DllVersion.Subrevision>ExeVersion.Subrevision) return 1;
3813         else if (DllVersion.Subrevision<ExeVersion.Subrevision) return -1;
3814         return 0;
3817 void LoadStorm()
3819 #ifdef _WIN32
3820         if (hStorm!=0) return;
3821         hStorm = LoadLibrary(Storm_dll);
3822         /*if (hStorm==0) {
3823                 HKEY hKey;
3824                 LPSTR lpDllPath;
3825                 DWORD dwStrLen;
3826                 if (RegOpenKeyEx(HKEY_CURRENT_USER,"Software\\Blizzard Entertainment\\Warcraft III",0,KEY_QUERY_VALUE,&hKey)!=ERROR_SUCCESS)
3827                         if (RegOpenKeyEx(HKEY_USERS,".Default\\Software\\Blizzard Entertainment\\Warcraft III",0,KEY_QUERY_VALUE,&hKey)!=ERROR_SUCCESS)
3828                                 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,"Software\\Blizzard Entertainment\\Warcraft III",0,KEY_QUERY_VALUE,&hKey)!=ERROR_SUCCESS)
3829                                         return;
3830                 RegQueryValueEx(hKey,"InstallPath",0,0,0,&dwStrLen);
3831                 lpDllPath = (LPSTR)SFAlloc(dwStrLen+11);
3832                 if (lpDllPath) {
3833                         memset(lpDllPath,0,dwStrLen+11);
3834                         RegQueryValueEx(hKey,"InstallPath",0,0,(LPBYTE)lpDllPath,&dwStrLen);
3835                         LPSTR lpLastBSlash = strrchr(lpDllPath,'\\');
3836                         if (lpLastBSlash) {
3837                                 if (lpLastBSlash[1]!=0) lpLastBSlash[strlen(lpLastBSlash)]='\\';
3838                                 strcat(lpLastBSlash,Storm_dll);
3839                                 hStorm = LoadLibrary(lpDllPath);
3840                         }
3841                         SFFree(lpDllPath);
3842                 }
3843                 RegCloseKey(hKey);
3844         }*/
3845         if (hStorm==0) return;
3847         unsigned int wSCCOrdinal=0xAC30;
3848         wSCCOrdinal>>=4;
3849         wSCCOrdinal/=5;
3850         unsigned int wSCDcOrdinal=0xAC80;
3851         wSCDcOrdinal>>=4;
3852         wSCDcOrdinal/=5;
3854         stormSCompCompress = (funcSCompCompress)GetProcAddress(hStorm,(LPCSTR)wSCCOrdinal);
3855         stormSCompDecompress = (funcSCompDecompress)GetProcAddress(hStorm,(LPCSTR)wSCDcOrdinal);
3856 #endif
3859 void FreeStorm()
3861 #ifdef _WIN32
3862         if (hStorm==0) return;
3863         FreeLibrary(hStorm);
3864         hStorm = 0;
3866         stormSCompCompress = 0;
3867         stormSCompDecompress = 0;
3868 #endif