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




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