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