Current News
Archived News
Search News
Discussion Forum


Old Forum
Install Programs More Downloads...
Troubleshooting
Source Code
Format Specs.
Misc. Information
Non-SF Stuff
Links




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