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




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