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