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




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