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
109#define UNSUPPORTED_COMPRESSION (0xFF ^ (0x40 | 0x80 | 0x01 | 0x02 | 0x08))
110#define UNSUPPORTED_DECOMPRESSION (0xFF ^ (0x40 | 0x80 | 0x01 | 0x02 | 0x08))
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;
1529 lpListBuffer[i].dwFileExists=0xFFFFFFFF;
1530 SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->lpBlockTable[dwBlockIndex].dwFileOffset+0x40,0,FILE_BEGIN);
1531 ReadFile(mpqOpenArc->hFile,lpListBuffer[i].szFileName,260,&tsz,0);
1532
1533 if (mpqOpenArc->lpHashTable[i].dwNameHashA==HashString(lpListBuffer[i].szFileName,HASH_NAME_A) && mpqOpenArc->lpHashTable[i].dwNameHashB==HashString(lpListBuffer[i].szFileName,HASH_NAME_B)) {
1534 if (dwFlags&SFILE_LIST_ONLY_UNKNOWN && !(dwFlags&SFILE_LIST_ONLY_KNOWN)) {
1535 lpListBuffer[i].dwFileExists = 0;
1536 }
1537 }
1538 else {
1539 sprintf(lpListBuffer[i].szFileName,UNKNOWN_OUT,i);
1540 if (dwFlags&SFILE_LIST_ONLY_KNOWN) {
1541 lpListBuffer[i].dwFileExists = 0;
1542 }
1543 }
1544 }
1545 }
1546
1547 return TRUE;
1548 }
1549
1550 char **lpNameBuffers=0;
1551
1552 char **lpNames=0,szNull[1]={0},*lpFLCopy;
1553 DWORD *lpdwNameHashA=0,*lpdwNameHashB=0;
1554 DWORD dwListNameHashA,dwListNameHashB;
1555 DWORD j;
1556 lpFLCopy = (char *)lpFileLists;
1557 DWORD dwExtLists=0,dwIntLists=0;
1558 if (!lpFLCopy) lpFLCopy=szNull;
1559 char *lpLines;
1560 for (lpLines=lpFLCopy;lpLines;lpLines=nextline(lpLines)) {
1561 if (!*lpLines) break;
1562 dwExtLists++;
1563 }
1564 dwListNameHashA = HashString(INTERNAL_LISTFILE,HASH_NAME_A);
1565 dwListNameHashB = HashString(INTERNAL_LISTFILE,HASH_NAME_B);
1566 for (i=0;i<mpqOpenArc->MpqHeader.dwHashTableSize;i++) {
1567 if (mpqOpenArc->lpHashTable[i].dwNameHashA==dwListNameHashA && mpqOpenArc->lpHashTable[i].dwNameHashB==dwListNameHashB && (mpqOpenArc->lpHashTable[i].dwBlockTableIndex&0xFFFFFFFE)!=0xFFFFFFFE) {
1568 dwIntLists++;
1569 }
1570 }
1571 lpNameBuffers = (char **)SFAlloc((1+dwExtLists+dwIntLists)*sizeof(char *));
1572 if (dwExtLists) {
1573 lpFLCopy = strdup(lpFLCopy);
1574 i=0;
1575 for (lpLines=lpFLCopy;lpLines;lpLines=nextline(lpLines)) {
1576 if (!*lpLines) break;
1577 lpNameBuffers[i+1] = lpLines;
1578 i++;
1579 }
1580 for (i=0;i<dwExtLists;i++) {
1581 lpNameBuffers[i+1][strlnlen(lpNameBuffers[i+1])]=0;
1582 }
1583 qsort(lpNameBuffers+1,dwExtLists,sizeof(char *),StringICompare);
1584 for (i=0;i<dwExtLists-1;i++) {
1585 if (stricmp(lpNameBuffers[i+1],lpNameBuffers[i+2])==0) {
1586 memmove(&lpNameBuffers[i+1],&lpNameBuffers[i+2],(dwExtLists-(i+1))*sizeof(char *));
1587 dwExtLists--;
1588 }
1589 }
1590 }
1591 if (dwIntLists) {
1592 dwIntLists = 0;
1593 for (i=0;i<mpqOpenArc->MpqHeader.dwHashTableSize;i++) {
1594 if (mpqOpenArc->lpHashTable[i].dwNameHashA==dwListNameHashA && mpqOpenArc->lpHashTable[i].dwNameHashB==dwListNameHashB && (mpqOpenArc->lpHashTable[i].dwBlockTableIndex&0xFFFFFFFE)!=0xFFFFFFFE) {
1595 lpNameBuffers[1+dwExtLists+dwIntLists] = (char *)i;
1596 dwIntLists++;
1597 }
1598 }
1599 }
1600 DWORD dwLines=0,dwOldLines=0,dwTotalLines=0;
1601 DWORD fsz;
1602 HANDLE hFile;
1603 DWORD dwListCryptKey = HashString(INTERNAL_LISTFILE,HASH_KEY);
1604 for (i=0;i<1+dwExtLists+dwIntLists;i++) {
1605 if (i==0) {
1606 fsz = strlen(INTERNAL_FILES);
1607 lpNameBuffers[i] = (char *)SFAlloc(fsz+1);
1608 memcpy(lpNameBuffers[i],INTERNAL_FILES,fsz);
1609 lpNameBuffers[i][fsz]=0;
1610 }
1611 else if (i<1+dwExtLists) {
1612 if (!(dwFlags&SFILE_LIST_MEMORY_LIST)) {
1613 hFile = CreateFile(lpNameBuffers[i],GENERIC_READ,FILE_SHARE_READ,0,OPEN_EXISTING,0,0);
1614 if (hFile!=INVALID_HANDLE_VALUE) {
1615 fsz = GetFileSize(hFile,0);
1616 SetFilePointer(hFile,0,0,FILE_BEGIN);
1617 lpNameBuffers[i] = (char *)SFAlloc(fsz+1);
1618 ReadFile(hFile,lpNameBuffers[i],fsz,&tsz,0);
1619 CloseHandle(hFile);
1620 lpNameBuffers[i][fsz]=0;
1621 }
1622 else lpNameBuffers[i]=0;
1623 }
1624 else {
1625 dwTotalLines++;
1626 continue;
1627 }
1628 }
1629 else {
1630 MPQFILE thisFile;
1631 memset(&thisFile,0,sizeof(MPQFILE));
1632 thisFile.lpParentArc = (MPQARCHIVE *)hMPQ;
1633 thisFile.hFile = INVALID_HANDLE_VALUE;
1634 thisFile.lpHashEntry = &mpqOpenArc->lpHashTable[(DWORD)lpNameBuffers[i]];
1635 thisFile.lpBlockEntry = &mpqOpenArc->lpBlockTable[thisFile.lpHashEntry->dwBlockTableIndex];
1636 thisFile.lpFileName = thisFile.szFileName;
1637 strcpy(thisFile.lpFileName,INTERNAL_LISTFILE);
1638 thisFile.dwFilePointer = 0;
1639 thisFile.lpdwBlockOffsets = 0;
1640 BLOCKTABLEENTRY *lpBlockEntry = thisFile.lpBlockEntry;
1641 if (lpBlockEntry->dwFlags & MAFA_ENCRYPT) {
1642 thisFile.dwCryptKey = dwListCryptKey;
1643 if (lpBlockEntry->dwFlags & MAFA_MODCRYPTKEY)
1644 thisFile.dwCryptKey = (thisFile.dwCryptKey + lpBlockEntry->dwFileOffset) ^ lpBlockEntry->dwFullSize;
1645 }
1646 fsz = lpBlockEntry->dwFullSize;
1647 lpNameBuffers[i] = (char *)SFAlloc(fsz+1);
1648 SFileReadFile(&thisFile,lpNameBuffers[i],fsz,0,0);
1649 if (thisFile.lpdwBlockOffsets) SFFree(thisFile.lpdwBlockOffsets);
1650 lpNameBuffers[i][fsz]=0;
1651 }
1652 for (lpLines=lpNameBuffers[i];lpLines;lpLines=nextline(lpLines)) {
1653 if (!*lpLines) break;
1654 dwTotalLines++;
1655 }
1656 }
1657 lpNames = (char **)SFAlloc(dwTotalLines*sizeof(char *));
1658 for (i=0;i<1+dwExtLists+dwIntLists;i++) {
1659 dwOldLines=dwLines;
1660 for (lpLines=lpNameBuffers[i];lpLines;lpLines=nextline(lpLines)) {
1661 if (!*lpLines) break;
1662 lpNames[dwLines] = lpLines;
1663 dwLines++;
1664 }
1665 for (j=dwOldLines;j<dwLines;j++) {
1666 lpNames[j][strlnlen(lpNames[j])]=0;
1667 }
1668 }
1669 qsort(lpNames,dwTotalLines,sizeof(char *),StringICompare);
1670 for (i=0;i<dwTotalLines-1;i++) {
1671 if (stricmp(lpNames[i],lpNames[i+1])==0) {
1672 memmove(&lpNames[i],&lpNames[i+1],(dwTotalLines-(i+1))*sizeof(char *));
1673 dwTotalLines--;
1674 }
1675 }
1676 if (dwTotalLines) {
1677 lpdwNameHashA = (DWORD *)SFAlloc(dwTotalLines*sizeof(DWORD));
1678 lpdwNameHashB = (DWORD *)SFAlloc(dwTotalLines*sizeof(DWORD));
1679 for (i=0;i<dwTotalLines;i++) {
1680 lpdwNameHashA[i] = HashString(lpNames[i],HASH_NAME_A);
1681 lpdwNameHashB[i] = HashString(lpNames[i],HASH_NAME_B);
1682 }
1683 }
1684 for (i=0;i<mpqOpenArc->MpqHeader.dwHashTableSize;i++) {
1685 lpListBuffer[i].dwFileExists = 0;
1686 lpListBuffer[i].szFileName[0] = 0;
7a5243c7 1687 if ((mpqOpenArc->lpHashTable[i].dwBlockTableIndex&0xFFFFFFFE)!=0xFFFFFFFE && mpqOpenArc->lpHashTable[i].dwBlockTableIndex < mpqOpenArc->MpqHeader.dwBlockTableSize) {
7df24e1f 1688 lpListBuffer[i].lcLocale = mpqOpenArc->lpHashTable[i].lcLocale;
1689 DWORD dwBlockIndex = mpqOpenArc->lpHashTable[i].dwBlockTableIndex;
1690 lpListBuffer[i].dwCompressedSize = mpqOpenArc->lpBlockTable[dwBlockIndex].dwCompressedSize;
1691 lpListBuffer[i].dwFullSize = mpqOpenArc->lpBlockTable[dwBlockIndex].dwFullSize;
1692 lpListBuffer[i].dwFlags = mpqOpenArc->lpBlockTable[dwBlockIndex].dwFlags;
1693 lpListBuffer[i].dwFileExists=0xFFFFFFFF;
1694 for (j=0;j<dwTotalLines;j++) {
1695 if (mpqOpenArc->lpHashTable[i].dwNameHashA==lpdwNameHashA[j] && mpqOpenArc->lpHashTable[i].dwNameHashB==lpdwNameHashB[j]) {
1696 strncpy(lpListBuffer[i].szFileName,lpNames[j],260);
1697 if (dwFlags&SFILE_LIST_ONLY_UNKNOWN && !(dwFlags&SFILE_LIST_ONLY_KNOWN)) {
1698 lpListBuffer[i].dwFileExists = 0;
1699 }
1700 break;
1701 }
1702 if (j+1==dwTotalLines) {
1703 sprintf(lpListBuffer[i].szFileName,UNKNOWN_OUT,i);
1704 if (dwFlags&SFILE_LIST_ONLY_KNOWN) {
1705 lpListBuffer[i].dwFileExists = 0;
1706 }
1707 }
1708 }
1709 }
1710 }
1711 if (lpNameBuffers) {
1712 for (i=0;i<1+dwExtLists+dwIntLists;i++) {
1713 if (i>=1 && i<1+dwExtLists) {
1714 if ((dwFlags&SFILE_LIST_MEMORY_LIST)) {
1715 continue;
1716 }
1717 }
1718 if (lpNameBuffers[i]) SFFree(lpNameBuffers[i]);
1719 }
1720 SFFree(lpNameBuffers);
1721 }
1722 if (dwExtLists) SFFree(lpFLCopy);
1723 if (lpdwNameHashA) SFFree(lpdwNameHashA);
1724 if (lpdwNameHashB) SFFree(lpdwNameHashB);
1725 return TRUE;
1726}
1727
1728MPQHANDLE SFMPQAPI WINAPI MpqOpenArchiveForUpdate(LPCSTR lpFileName, DWORD dwFlags, DWORD dwMaximumFilesInArchive)
1729{
1730 MPQHANDLE hMPQ;
1731
1732 MpqOpenArchiveEx(lpFileName,0,0,&hMPQ,dwFlags,dwMaximumFilesInArchive,USE_DEFAULT_BLOCK_SIZE);
1733 return hMPQ;
1734}
1735
1736MPQHANDLE SFMPQAPI WINAPI MpqOpenArchiveForUpdateEx(LPCSTR lpFileName, DWORD dwFlags, DWORD dwMaximumFilesInArchive, DWORD dwBlockSize)
1737{
1738 MPQHANDLE hMPQ;
1739
1740 MpqOpenArchiveEx(lpFileName,0,0,&hMPQ,dwFlags,dwMaximumFilesInArchive,dwBlockSize);
1741 return hMPQ;
1742}
1743
1744DWORD SFMPQAPI WINAPI MpqCloseUpdatedArchive(MPQHANDLE hMPQ, DWORD dwUnknown2)
1745{
1746 return SFileCloseArchive(hMPQ);
1747}
1748
1749BOOL SFMPQAPI WINAPI MpqAddFileToArchiveEx(MPQHANDLE hMPQ, LPCSTR lpSourceFileName, LPCSTR lpDestFileName, DWORD dwFlags, DWORD dwCompressionType, DWORD dwCompressLevel)
1750{
1751 if (!hMPQ || !lpSourceFileName || !lpDestFileName) {
1752 SetLastError(ERROR_INVALID_PARAMETER);
1753 return FALSE;
1754 }
1755 if (!*lpSourceFileName || !*lpDestFileName) {
1756 SetLastError(ERROR_INVALID_PARAMETER);
1757 return FALSE;
1758 }
1759
1760 if (!(((MPQARCHIVE *)hMPQ)->dwFlags&SFILE_OPEN_ALLOW_WRITE)) {
1761 SetLastError(ERROR_ACCESS_DENIED);
1762 return FALSE;
1763 }
1764 BOOL ReplaceExisting;
1765 if (dwFlags&MAFA_REPLACE_EXISTING) {
1766 dwFlags = dwFlags^MAFA_REPLACE_EXISTING;
1767 ReplaceExisting = TRUE;
1768 }
1769 else ReplaceExisting = FALSE;
1770 MPQHANDLE hFile = GetFreeHashTableEntry(hMPQ,lpDestFileName,LocaleID,ReplaceExisting);
1771 if (!hFile) return FALSE;
1772 HANDLE haFile = CreateFile(lpSourceFileName,GENERIC_READ,FILE_SHARE_READ,0,OPEN_EXISTING,0,0);
1773 if (haFile==INVALID_HANDLE_VALUE) return FALSE;
1774 DWORD fsz = GetFileSize(haFile,0),tsz;
1775 DWORD ucfsz = fsz;
1776 BOOL IsBNcache = FALSE;char *buffer,*hbuffer;
1777 MPQARCHIVE *mpqOpenArc = (MPQARCHIVE *)hMPQ;
1778 DWORD blockSize = 512 << mpqOpenArc->MpqHeader.wBlockSize;
1779 DWORD TotalBlocks = fsz / blockSize;
1780 if(fsz % blockSize)
1781 TotalBlocks++;
1782 DWORD ptsz = 0;
1783 if (dwFlags&MAFA_COMPRESS || dwFlags&MAFA_COMPRESS2) ptsz = (TotalBlocks+1)*4;
1784 if (memcmp(&mpqOpenArc->MpqHeader.dwMPQID,ID_BN3,4)==0)
1785 {
1786 IsBNcache = TRUE;
1787 hbuffer = (char *)SFAlloc(fsz+324+ptsz);
1788 if (!hbuffer) {
1789 CloseHandle(haFile);
1790 return FALSE;
1791 }
1792 hbuffer[0] = (char)0x44;
1793 hbuffer[1] = (char)0x01;
1794 DWORD lpFileNameLength = strlen(lpDestFileName);
1795 if (lpFileNameLength<=260) memcpy(hbuffer+64,lpDestFileName,lpFileNameLength);
1796 else strncpy(hbuffer+64,lpDestFileName,260);
1797 buffer = hbuffer+324;
1798 }
1799 else buffer = (char *)SFAlloc(fsz+ptsz);
1800 if (!buffer && fsz!=0) {
1801 CloseHandle(haFile);
1802 return FALSE;
1803 }
1804 if (fsz!=0) {
1805 if (ReadFile(haFile,buffer,fsz,&tsz,0)==0) {
1806 SFFree(buffer);
1807 CloseHandle(haFile);
1808 return FALSE;
1809 }
1810 }
1811 else {
1812 if (dwFlags&MAFA_COMPRESS) dwFlags = dwFlags^MAFA_COMPRESS;
1813 if (dwFlags&MAFA_COMPRESS2) dwFlags = dwFlags^MAFA_COMPRESS2;
1814 if (dwFlags&MAFA_ENCRYPT) dwFlags = dwFlags^MAFA_ENCRYPT;
1815 if (dwFlags&MAFA_MODCRYPTKEY) dwFlags = dwFlags^MAFA_MODCRYPTKEY;
1816 }
1817 CloseHandle(haFile);
1818 DWORD i;
1819 DWORD *dwBlkpt = (DWORD *)SFAlloc((TotalBlocks+1)*4);
1820 if (!dwBlkpt) {
1821 SFFree(buffer);
1822 return FALSE;
1823 }
1824 if ((dwFlags & MAFA_COMPRESS) || (dwFlags & MAFA_COMPRESS2))
1825 {
1826 DWORD dwCompressionSubType = 0;
1827
1828 if ((dwCompressionType&0x40 || dwCompressionType&0x80) && (memcmp(buffer,ID_RIFF,4)!=0 || memcmp(buffer+8,ID_WAVE,8)!=0 || buffer[20]!=1 || buffer[34]!=16)) {
1829 dwCompressionType = 0x08;
1830 dwCompressLevel = 0;
1831 }
1832 if (dwCompressionType&0x40 || dwCompressionType&0x80) {
1833 switch (dwCompressLevel) {
1834 case MAWA_QUALITY_HIGH:
1835 dwCompressLevel = 1;
1836 break;
1837 case MAWA_QUALITY_LOW:
1838 dwCompressLevel = 3;
1839 break;
1840 default:
1841 dwCompressLevel = 0;
1842 }
1843 }
1844 else if (dwCompressionType&0x01 || dwCompressionType&0x08 || ((dwFlags & MAFA_COMPRESS)!=MAFA_COMPRESS && (dwFlags & MAFA_COMPRESS2)==MAFA_COMPRESS2)) {
1845 dwCompressionSubType = dwCompressLevel;
1846 dwCompressLevel = 0;
1847 }
1848 else if (dwCompressionType&0x02) {
1849 dwCompressionSubType = 1;
1850 }
1851
1852 DWORD LastOffset=ptsz;
1853 BYTE *compbuffer = (BYTE *)SFAlloc(blockSize);
1854 if (!compbuffer) {
1855 SFFree(dwBlkpt);
1856 SFFree(buffer);
1857 return FALSE;
1858 }
1859 char *outbuffer = (char *)SFAlloc(blockSize);
1860 if (!outbuffer) {
1861 SFFree(compbuffer);
1862 SFFree(dwBlkpt);
1863 SFFree(buffer);
1864 return FALSE;
1865 }
1866 char *newbuffer = (char *)SFAlloc(fsz+ptsz);
1867 if (!newbuffer) {
1868 SFFree(outbuffer);
1869 SFFree(compbuffer);
1870 SFFree(dwBlkpt);
1871 SFFree(buffer);
1872 return FALSE;
1873 }
1874 DWORD CurPos=0;
1875 for (i=0;i<TotalBlocks;i++) {
1876 dwBlkpt[i] = LastOffset;
1877 if (i==TotalBlocks-1 && (ucfsz % blockSize)!=0) blockSize=ucfsz % blockSize;
1878 DWORD outLength=blockSize;
1879 BYTE *compdata = compbuffer;
1880 char *oldoutbuffer = outbuffer;
1881 if (dwFlags & MAFA_COMPRESS)
1882 {
1883 memcpy(compdata,(char *)buffer+CurPos,blockSize);
1884 if (i==0 && (dwCompressionType&0x40 || dwCompressionType&0x80)) {
1885 if (SCompCompress(outbuffer, &outLength, compdata, blockSize, 0x08, 0, 0)==0)
1886 outLength=blockSize;
1887 }
1888 else
1889 {
1890 if (dwCompressionType&UNSUPPORTED_COMPRESSION) {
1891 LoadStorm();
1892 if (stormSCompCompress) {
1893 if (stormSCompCompress(outbuffer, &outLength, compdata, blockSize, dwCompressionType, dwCompressionSubType, dwCompressLevel)==0)
1894 outLength=blockSize;
1895 }
1896 }
1897 else {
1898 if (SCompCompress(outbuffer, &outLength, compdata, blockSize, dwCompressionType, dwCompressionSubType, dwCompressLevel)==0)
1899 outLength=blockSize;
1900 }
1901 }
1902 }
1903 else if (dwFlags & MAFA_COMPRESS2)
1904 {
1905 memcpy(compdata,(char *)buffer+CurPos,blockSize);
1906 if (SCompCompress(outbuffer, &outLength, compdata, blockSize, 0x08, dwCompressionSubType, 0)==0) {
1907 outLength=blockSize;
1908 }
1909 else {
1910 outbuffer++;
1911 outLength--;
1912 }
1913 }
1914 else
1915 {
1916 memcpy(compdata,(char *)buffer+CurPos,blockSize);
1917 }
1918 if (outLength>=blockSize)
1919 {
1920 memcpy((char *)newbuffer+LastOffset,compdata,blockSize);
1921 LastOffset+=blockSize;
1922 }
1923 else {
1924 memcpy((char *)newbuffer+LastOffset,outbuffer,outLength);
1925 LastOffset+=outLength;
1926 }
1927 outbuffer = oldoutbuffer;
1928 CurPos += blockSize;
1929 }
1930 fsz = LastOffset;
1931 dwBlkpt[TotalBlocks] = fsz;
1932 memcpy(newbuffer,dwBlkpt,ptsz);
1933
1934 SFFree(outbuffer);
1935 SFFree(compbuffer);
1936 memcpy(buffer,newbuffer,fsz);
1937 SFFree(newbuffer);
1938 }
1939 else
1940 {
1941 for (i=0;i<TotalBlocks+1;i++) {
1942 if (i<TotalBlocks) dwBlkpt[i] = i * blockSize;
1943 else dwBlkpt[i] = ucfsz;
1944 }
1945 }
1946 if (IsBNcache==TRUE)
1947 {
1948 buffer = hbuffer;
1949 fsz += 324;
1950 }
1951 HASHTABLEENTRY *hashEntry = (HASHTABLEENTRY *)hFile;
1952 BOOL IsNewBlockEntry = FALSE;DWORD OldBlockTableSize = sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize;
1953 if ((hashEntry->dwBlockTableIndex&0xFFFFFFFE)==0xFFFFFFFE)
1954 {
1955 BLOCKTABLEENTRY *lpnBlockTable;
1956 lpnBlockTable = (BLOCKTABLEENTRY *)SFAlloc(sizeof(BLOCKTABLEENTRY) * (mpqOpenArc->MpqHeader.dwBlockTableSize + 1));
1957 if(!lpnBlockTable) {
1958 SFFree(buffer);
1959 return FALSE;
1960 }
1961 if (mpqOpenArc->lpBlockTable) memcpy(lpnBlockTable,mpqOpenArc->lpBlockTable,sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize);
1962 mpqOpenArc->MpqHeader.dwBlockTableSize++;
1963 if (mpqOpenArc->lpBlockTable) SFFree(mpqOpenArc->lpBlockTable);
1964 mpqOpenArc->lpBlockTable = lpnBlockTable;
1965 IsNewBlockEntry = TRUE;
1966 }
1967 DWORD BlockIndex = mpqOpenArc->MpqHeader.dwBlockTableSize - 1;
1968 if ((hashEntry->dwBlockTableIndex&0xFFFFFFFE)==0xFFFFFFFE)
1969 {
1970 hashEntry->dwNameHashA = HashString(lpDestFileName,HASH_NAME_A);
1971 hashEntry->dwNameHashB = HashString(lpDestFileName,HASH_NAME_B);
1972 hashEntry->lcLocale = LocaleID;
1973 hashEntry->dwBlockTableIndex = BlockIndex;
1974 mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset = 0;
1975
1976 }
1977 else
1978 {
1979 BlockIndex = hashEntry->dwBlockTableIndex;
1980 }
1981 if (mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset==0 || mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize<fsz)
1982 {
1983 if (mpqOpenArc->MpqHeader.dwHashTableOffset+(mpqOpenArc->MpqHeader.dwHashTableSize * sizeof(HASHTABLEENTRY))+OldBlockTableSize==mpqOpenArc->MpqHeader.dwMPQSize)
1984 {
1985 if (mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset+mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize==mpqOpenArc->MpqHeader.dwHashTableOffset)
1986 {
1987 mpqOpenArc->MpqHeader.dwHashTableOffset += fsz-mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize;
1988 mpqOpenArc->MpqHeader.dwBlockTableOffset += fsz-mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize;
1989 mpqOpenArc->MpqHeader.dwMPQSize += fsz-mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize;
1990 if (IsNewBlockEntry==TRUE) mpqOpenArc->MpqHeader.dwMPQSize += sizeof(BLOCKTABLEENTRY);
1991 }
1992 else
1993 {
1994 mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset = mpqOpenArc->MpqHeader.dwHashTableOffset;
1995 mpqOpenArc->MpqHeader.dwHashTableOffset += fsz;
1996 mpqOpenArc->MpqHeader.dwBlockTableOffset += fsz;
1997 mpqOpenArc->MpqHeader.dwMPQSize += fsz;
1998 if (IsNewBlockEntry==TRUE) mpqOpenArc->MpqHeader.dwMPQSize += sizeof(BLOCKTABLEENTRY);
1999 }
2000 }
2001 else if (mpqOpenArc->MpqHeader.dwBlockTableOffset+OldBlockTableSize==mpqOpenArc->MpqHeader.dwMPQSize)
2002 {
2003 if (mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset+mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize==mpqOpenArc->MpqHeader.dwBlockTableOffset)
2004 {
2005 mpqOpenArc->MpqHeader.dwBlockTableOffset += fsz-mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize;
2006 mpqOpenArc->MpqHeader.dwMPQSize += fsz-mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize;
2007 if (IsNewBlockEntry==TRUE) mpqOpenArc->MpqHeader.dwMPQSize += sizeof(BLOCKTABLEENTRY);
2008 }
2009 else
2010 {
2011 mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset = mpqOpenArc->MpqHeader.dwBlockTableOffset;
2012 mpqOpenArc->MpqHeader.dwBlockTableOffset += fsz;
2013 mpqOpenArc->MpqHeader.dwMPQSize += fsz;
2014 if (IsNewBlockEntry==TRUE) mpqOpenArc->MpqHeader.dwMPQSize += sizeof(BLOCKTABLEENTRY);
2015 }
2016 }
2017 else
2018 {
2019 if (mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset+mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize==mpqOpenArc->MpqHeader.dwMPQSize)
2020 {
2021 mpqOpenArc->MpqHeader.dwBlockTableOffset = mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset+fsz;
2022 mpqOpenArc->MpqHeader.dwMPQSize = mpqOpenArc->MpqHeader.dwBlockTableOffset+OldBlockTableSize;
2023 if (IsNewBlockEntry==TRUE) mpqOpenArc->MpqHeader.dwMPQSize += sizeof(BLOCKTABLEENTRY);
2024 }
2025 else
2026 {
2027 mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset = mpqOpenArc->MpqHeader.dwMPQSize;
2028 mpqOpenArc->MpqHeader.dwBlockTableOffset = mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset+fsz;
2029 mpqOpenArc->MpqHeader.dwMPQSize = mpqOpenArc->MpqHeader.dwBlockTableOffset+OldBlockTableSize;
2030 if (IsNewBlockEntry==TRUE) mpqOpenArc->MpqHeader.dwMPQSize += sizeof(BLOCKTABLEENTRY);
2031 }
2032 }
2033 }
2034 mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize = fsz;
2035 mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize = ucfsz;
2036 mpqOpenArc->lpBlockTable[BlockIndex].dwFlags = dwFlags|MAFA_EXISTS;
2037 DWORD dwFileOffset = mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset;
2038 SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart,0,FILE_BEGIN);
95d2f3da 2039 WriteFile(mpqOpenArc->hFile,&mpqOpenArc->MpqHeader,sizeof(MPQHEADER),&tsz,0);
7df24e1f 2040 if (dwFlags & MAFA_ENCRYPT) {
2041 DWORD dwCryptKey;
2042 if (dwFlags&MAFA_ENCRYPT) dwCryptKey = HashString(lpDestFileName,HASH_KEY);
2043 if (dwFlags&MAFA_MODCRYPTKEY) dwCryptKey = (dwCryptKey + mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset) ^ mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize;
2044 DWORD blockSize = 512 << mpqOpenArc->MpqHeader.wBlockSize;
2045 DWORD TotalBlocks = mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize / blockSize;
2046 if(mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize % blockSize)
2047 TotalBlocks++;
2048 DWORD dwBlockEnd = mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize % blockSize;
2049 if (dwBlockEnd==0) dwBlockEnd = blockSize;
2050 if ((dwFlags & MAFA_COMPRESS)==MAFA_COMPRESS || (dwFlags & MAFA_COMPRESS2)==MAFA_COMPRESS2) {
2051 EncryptData((LPBYTE)buffer,ptsz,dwCryptKey-1);
2052 }
2053 for (DWORD i=0;i<TotalBlocks;i++) {
2054 EncryptData((LPBYTE)buffer+dwBlkpt[i],dwBlkpt[i+1]-dwBlkpt[i],dwCryptKey);
2055 dwCryptKey++;
2056 }
2057 }
2058 SFFree(dwBlkpt);
2059 SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+dwFileOffset,0,FILE_BEGIN);
2060 WriteFile(mpqOpenArc->hFile,buffer,fsz,&tsz,0);
2061 SFFree(buffer);
2062 buffer = (char *)SFAlloc(sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize);
2063 if (buffer) {
2064 memcpy(buffer,mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize);
2065 EncryptData((LPBYTE)buffer,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,dwHashTableKey);
2066 SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->MpqHeader.dwHashTableOffset,0,FILE_BEGIN);
2067 WriteFile(mpqOpenArc->hFile,buffer,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,&tsz,0);
2068 SFFree(buffer);
2069 }
2070 else {
2071 EncryptData((LPBYTE)mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,dwHashTableKey);
2072 SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->MpqHeader.dwHashTableOffset,0,FILE_BEGIN);
2073 WriteFile(mpqOpenArc->hFile,mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,&tsz,0);
2074 DecryptData((LPBYTE)mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,dwHashTableKey);
2075 }
2076 buffer = (char *)SFAlloc(sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize);
2077 if (buffer) {
2078 memcpy(buffer,mpqOpenArc->lpBlockTable,sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize);
2079 EncryptData((LPBYTE)buffer,sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize,dwBlockTableKey);
2080 SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->MpqHeader.dwBlockTableOffset,0,FILE_BEGIN);
2081 WriteFile(mpqOpenArc->hFile,buffer,sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize,&tsz,0);
2082 SFFree(buffer);
2083 }
2084 else {
2085 EncryptData((LPBYTE)mpqOpenArc->lpBlockTable,sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize,dwBlockTableKey);
2086 SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->MpqHeader.dwBlockTableOffset,0,FILE_BEGIN);
2087 WriteFile(mpqOpenArc->hFile,mpqOpenArc->lpBlockTable,sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize,&tsz,0);
2088 DecryptData((LPBYTE)mpqOpenArc->lpBlockTable,sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize,dwBlockTableKey);
2089 }
2090 AddToInternalListing(hMPQ,lpDestFileName);
2091
2092 return TRUE;
2093}
2094
2095BOOL SFMPQAPI WINAPI MpqAddFileToArchive(MPQHANDLE hMPQ, LPCSTR lpSourceFileName, LPCSTR lpDestFileName, DWORD dwFlags)
2096{
2097 return MpqAddFileToArchiveEx(hMPQ,lpSourceFileName,lpDestFileName,dwFlags,0x08,0);
2098}
2099
2100BOOL SFMPQAPI WINAPI MpqAddWaveToArchive(MPQHANDLE hMPQ, LPCSTR lpSourceFileName, LPCSTR lpDestFileName, DWORD dwFlags, DWORD dwQuality)
2101{
2102 return MpqAddFileToArchiveEx(hMPQ,lpSourceFileName,lpDestFileName,dwFlags,0x81,dwQuality);
2103}
2104
2105BOOL SFMPQAPI WINAPI MpqAddFileFromBufferEx(MPQHANDLE hMPQ, LPVOID lpBuffer, DWORD dwLength, LPCSTR lpFileName, DWORD dwFlags, DWORD dwCompressionType, DWORD dwCompressLevel)
2106{
2107 if (!hMPQ || !lpBuffer || !lpFileName) {
2108 SetLastError(ERROR_INVALID_PARAMETER);
2109 return FALSE;
2110 }
2111 if (!*lpFileName) {
2112 SetLastError(ERROR_INVALID_PARAMETER);
2113 return FALSE;
2114 }
2115
2116 if (!(((MPQARCHIVE *)hMPQ)->dwFlags&SFILE_OPEN_ALLOW_WRITE)) {
2117 SetLastError(ERROR_ACCESS_DENIED);
2118 return FALSE;
2119 }
2120 BOOL ReplaceExisting;
2121 if (dwFlags&MAFA_REPLACE_EXISTING) {
2122 dwFlags = dwFlags^MAFA_REPLACE_EXISTING;
2123 ReplaceExisting = TRUE;
2124
2125 }
2126 else ReplaceExisting = FALSE;
2127 MPQHANDLE hFile = GetFreeHashTableEntry(hMPQ,lpFileName,LocaleID,ReplaceExisting);
2128 if (hFile==0) return FALSE;
2129 DWORD fsz = dwLength,tsz;
2130 DWORD ucfsz = fsz;
2131 BOOL IsBNcache = FALSE;char *buffer,*hbuffer;
2132 MPQARCHIVE *mpqOpenArc = (MPQARCHIVE *)hMPQ;
2133 DWORD blockSize = 512 << mpqOpenArc->MpqHeader.wBlockSize;
2134 DWORD TotalBlocks = fsz / blockSize;
2135 if(fsz % blockSize)
2136 TotalBlocks++;
2137 DWORD ptsz = 0;
2138 if (dwFlags&MAFA_COMPRESS || dwFlags&MAFA_COMPRESS2) ptsz = (TotalBlocks+1)*4;
2139 if (memcmp(&mpqOpenArc->MpqHeader.dwMPQID,ID_BN3,4)==0)
2140 {
2141 IsBNcache = TRUE;
2142 hbuffer = (char *)SFAlloc(fsz+324+ptsz);
2143 if (hbuffer==0) {
2144 return FALSE;
2145 }
2146 hbuffer[0] = (char)0x44;
2147 hbuffer[1] = (char)0x01;
2148 DWORD lpFileNameLength = strlen(lpFileName);
2149 if (lpFileNameLength<=260) memcpy(hbuffer+64,lpFileName,lpFileNameLength);
2150 else strncpy(hbuffer+64,lpFileName,260);
2151 buffer = hbuffer+324;
2152 }
2153 else buffer = (char *)SFAlloc(fsz+ptsz);
2154 if (buffer==0 && fsz!=0) {
2155 return FALSE;
2156 }
2157 if (fsz!=0) memcpy(buffer,lpBuffer,fsz);
2158 else {
2159 if (dwFlags&MAFA_COMPRESS) dwFlags = dwFlags^MAFA_COMPRESS;
2160 if (dwFlags&MAFA_COMPRESS2) dwFlags = dwFlags^MAFA_COMPRESS2;
2161 if (dwFlags&MAFA_ENCRYPT) dwFlags = dwFlags^MAFA_ENCRYPT;
2162 if (dwFlags&MAFA_MODCRYPTKEY) dwFlags = dwFlags^MAFA_MODCRYPTKEY;
2163 }
2164 DWORD i;
2165 DWORD *dwBlkpt = (DWORD *)SFAlloc((TotalBlocks+1)*4);
2166
2167 if (dwBlkpt==0) {
2168 SFFree(buffer);
2169 return FALSE;
2170 }
2171 if ((dwFlags & MAFA_COMPRESS)==MAFA_COMPRESS || (dwFlags & MAFA_COMPRESS2)==MAFA_COMPRESS2)
2172 {
2173 DWORD dwCompressionSubType = 0;
2174
2175 if ((dwCompressionType&0x40 || dwCompressionType&0x80) && (memcmp(buffer,ID_RIFF,4)!=0 || memcmp(buffer+8,ID_WAVE,8)!=0 || buffer[20]!=1 || buffer[34]!=16)) {
2176 dwCompressionType = 0x08;
2177 dwCompressLevel = 0;
2178 }
2179 if (dwCompressionType&0x40 || dwCompressionType&0x80) {
2180 switch (dwCompressLevel) {
2181 case MAWA_QUALITY_HIGH:
2182 dwCompressLevel = 1;
2183 break;
2184 case MAWA_QUALITY_LOW:
2185 dwCompressLevel = 3;
2186 break;
2187 default:
2188 dwCompressLevel = 0;
2189 }
2190 }
2191 else if (dwCompressionType&0x01 || dwCompressionType&0x08 || ((dwFlags & MAFA_COMPRESS)!=MAFA_COMPRESS && (dwFlags & MAFA_COMPRESS2)==MAFA_COMPRESS2)) {
2192 dwCompressionSubType = dwCompressLevel;
2193 dwCompressLevel = 0;
2194 }
2195 else if (dwCompressionType&0x02) {
2196 dwCompressionSubType = 1;
2197 }
2198
2199 DWORD LastOffset=ptsz;
2200 BYTE *compbuffer = (BYTE *)SFAlloc(blockSize);
2201 if (compbuffer==0) {
2202 SFFree(dwBlkpt);
2203 SFFree(buffer);
2204 return FALSE;
2205 }
2206
2207 char *outbuffer = (char *)SFAlloc(blockSize);
2208 if (outbuffer==0) {
2209 SFFree(compbuffer);
2210 SFFree(dwBlkpt);
2211 SFFree(buffer);
2212 return FALSE;
2213 }
2214 char *newbuffer = (char *)SFAlloc(fsz+ptsz);
2215 if (newbuffer==0) {
2216 SFFree(outbuffer);
2217 SFFree(compbuffer);
2218 SFFree(dwBlkpt);
2219 SFFree(buffer);
2220 return FALSE;
2221 }
2222 DWORD CurPos=0;
2223 for (i=0;i<TotalBlocks;i++) {
2224 dwBlkpt[i] = LastOffset;
2225 if (i==TotalBlocks-1 && (ucfsz % blockSize)!=0) blockSize=ucfsz % blockSize;
2226 DWORD outLength=blockSize;
2227 BYTE *compdata = compbuffer;
2228 if (dwFlags & MAFA_COMPRESS)
2229 {
2230 memcpy(compdata,(char *)buffer+CurPos,blockSize);
2231 if (i==0 && (dwCompressionType&0x40 || dwCompressionType&0x80)) {
2232 if (SCompCompress(outbuffer, &outLength, compdata, blockSize, 0x08, 0, 0)==0)
2233 outLength=blockSize;
2234 }
2235 else
2236 {
2237 if (dwCompressionType&UNSUPPORTED_COMPRESSION) {
2238 LoadStorm();
2239 if (stormSCompCompress!=0) {
2240 if (stormSCompCompress(outbuffer, &outLength, compdata, blockSize, dwCompressionType, dwCompressionSubType, dwCompressLevel)==0)
2241 outLength=blockSize;
2242 }
2243 }
2244 else {
2245 if (SCompCompress(outbuffer, &outLength, compdata, blockSize, dwCompressionType, dwCompressionSubType, dwCompressLevel)==0)
2246 outLength=blockSize;
2247 }
2248 }
2249 }
2250 else if (dwFlags & MAFA_COMPRESS2)
2251 {
2252 memcpy(compdata,(char *)buffer+CurPos,blockSize);
2253 if (SCompCompress(outbuffer, &outLength, compdata, blockSize, 0x08, dwCompressionSubType, 0)==0) {
2254 outLength=blockSize;
2255 }
2256 else {
2257 outbuffer++;
2258 outLength--;
2259 }
2260 }
2261 else
2262 {
2263 memcpy(compdata,(char *)buffer+CurPos,blockSize);
2264 }
2265 if (outLength>=blockSize)
2266 {
2267 memcpy((char *)newbuffer+LastOffset,compdata,blockSize);
2268 LastOffset+=blockSize;
2269 }
2270 else {
2271 memcpy((char *)newbuffer+LastOffset,outbuffer,outLength);
2272 LastOffset+=outLength;
2273 }
2274 CurPos += blockSize;
2275 }
2276 fsz = LastOffset;
2277 dwBlkpt[TotalBlocks] = fsz;
2278 memcpy(newbuffer,dwBlkpt,ptsz);
2279 SFFree(outbuffer);
2280 SFFree(compbuffer);
2281 memcpy(buffer,newbuffer,fsz);
2282 SFFree(newbuffer);
2283 }
2284 else
2285 {
2286 for (i=0;i<TotalBlocks+1;i++) {
2287 if (i<TotalBlocks) dwBlkpt[i] = i * blockSize;
2288 else dwBlkpt[i] = ucfsz;
2289 }
2290 }
2291 if (IsBNcache==TRUE)
2292 {
2293 buffer = hbuffer;
2294 fsz += 324;
2295 }
2296 HASHTABLEENTRY *hashEntry = (HASHTABLEENTRY *)hFile;
2297
2298 BOOL IsNewBlockEntry = FALSE;DWORD OldBlockTableSize = sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize;
2299 if ((hashEntry->dwBlockTableIndex&0xFFFFFFFE)==0xFFFFFFFE)
2300 {
2301 BLOCKTABLEENTRY *lpnBlockTable;
2302 lpnBlockTable = (BLOCKTABLEENTRY *)SFAlloc(sizeof(BLOCKTABLEENTRY) * (mpqOpenArc->MpqHeader.dwBlockTableSize + 1));
2303 if(lpnBlockTable==0) {
2304 SFFree(buffer);
2305 return FALSE;
2306 }
2307 if (mpqOpenArc->lpBlockTable!=0) memcpy(lpnBlockTable,mpqOpenArc->lpBlockTable,sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize);
2308 mpqOpenArc->MpqHeader.dwBlockTableSize++;
2309 if (mpqOpenArc->lpBlockTable!=0) SFFree(mpqOpenArc->lpBlockTable);
2310 mpqOpenArc->lpBlockTable = lpnBlockTable;
2311 IsNewBlockEntry = TRUE;
2312 }
2313 DWORD BlockIndex = mpqOpenArc->MpqHeader.dwBlockTableSize - 1;
2314 if ((hashEntry->dwBlockTableIndex&0xFFFFFFFE)==0xFFFFFFFE)
2315 {
2316 hashEntry->dwNameHashA = HashString(lpFileName,HASH_NAME_A);
2317 hashEntry->dwNameHashB = HashString(lpFileName,HASH_NAME_B);
2318 hashEntry->lcLocale = LocaleID;
2319 hashEntry->dwBlockTableIndex = BlockIndex;
2320 mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset = 0;
2321 }
2322 else
2323 {
2324 BlockIndex = hashEntry->dwBlockTableIndex;
2325 }
2326 if (mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset==0 || mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize<fsz)
2327 {
2328 if (mpqOpenArc->MpqHeader.dwHashTableOffset+(mpqOpenArc->MpqHeader.dwHashTableSize * sizeof(HASHTABLEENTRY))+OldBlockTableSize==mpqOpenArc->MpqHeader.dwMPQSize)
2329 {
2330 if (mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset+mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize==mpqOpenArc->MpqHeader.dwHashTableOffset)
2331 {
2332 mpqOpenArc->MpqHeader.dwHashTableOffset += fsz-mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize;
2333 mpqOpenArc->MpqHeader.dwBlockTableOffset += fsz-mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize;
2334 mpqOpenArc->MpqHeader.dwMPQSize += fsz-mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize;
2335 if (IsNewBlockEntry==TRUE) mpqOpenArc->MpqHeader.dwMPQSize += sizeof(BLOCKTABLEENTRY);
2336 }
2337 else
2338 {
2339 mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset = mpqOpenArc->MpqHeader.dwHashTableOffset;
2340 mpqOpenArc->MpqHeader.dwHashTableOffset += fsz;
2341 mpqOpenArc->MpqHeader.dwBlockTableOffset += fsz;
2342 mpqOpenArc->MpqHeader.dwMPQSize += fsz;
2343 if (IsNewBlockEntry==TRUE) mpqOpenArc->MpqHeader.dwMPQSize += sizeof(BLOCKTABLEENTRY);
2344 }
2345 }
2346 else if (mpqOpenArc->MpqHeader.dwBlockTableOffset+OldBlockTableSize==mpqOpenArc->MpqHeader.dwMPQSize)
2347 {
2348 if (mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset+mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize==mpqOpenArc->MpqHeader.dwBlockTableOffset)
2349 {
2350 mpqOpenArc->MpqHeader.dwBlockTableOffset += fsz-mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize;
2351 mpqOpenArc->MpqHeader.dwMPQSize += fsz-mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize;
2352 if (IsNewBlockEntry==TRUE) mpqOpenArc->MpqHeader.dwMPQSize += sizeof(BLOCKTABLEENTRY);
2353 }
2354 else
2355 {
2356 mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset = mpqOpenArc->MpqHeader.dwBlockTableOffset;
2357 mpqOpenArc->MpqHeader.dwBlockTableOffset += fsz;
2358 mpqOpenArc->MpqHeader.dwMPQSize += fsz;
2359 if (IsNewBlockEntry==TRUE) mpqOpenArc->MpqHeader.dwMPQSize += sizeof(BLOCKTABLEENTRY);
2360 }
2361 }
2362 else
2363 {
2364 if (mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset+mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize==mpqOpenArc->MpqHeader.dwMPQSize)
2365 {
2366 mpqOpenArc->MpqHeader.dwBlockTableOffset = mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset+fsz;
2367 mpqOpenArc->MpqHeader.dwMPQSize = mpqOpenArc->MpqHeader.dwBlockTableOffset+OldBlockTableSize;
2368 if (IsNewBlockEntry==TRUE) mpqOpenArc->MpqHeader.dwMPQSize += sizeof(BLOCKTABLEENTRY);
2369 }
2370 else
2371 {
2372 mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset = mpqOpenArc->MpqHeader.dwMPQSize;
2373 mpqOpenArc->MpqHeader.dwBlockTableOffset = mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset+fsz;
2374 mpqOpenArc->MpqHeader.dwMPQSize = mpqOpenArc->MpqHeader.dwBlockTableOffset+OldBlockTableSize;
2375 if (IsNewBlockEntry==TRUE) mpqOpenArc->MpqHeader.dwMPQSize += sizeof(BLOCKTABLEENTRY);
2376 }
2377 }
2378 }
2379 mpqOpenArc->lpBlockTable[BlockIndex].dwCompressedSize = fsz;
2380 mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize = ucfsz;
2381 mpqOpenArc->lpBlockTable[BlockIndex].dwFlags = dwFlags|MAFA_EXISTS;
2382 DWORD dwFileOffset = mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset;
2383 SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart,0,FILE_BEGIN);
95d2f3da 2384 WriteFile(mpqOpenArc->hFile,&mpqOpenArc->MpqHeader,sizeof(MPQHEADER),&tsz,0);
7df24e1f 2385 if (dwFlags & MAFA_ENCRYPT) {
2386 DWORD dwCryptKey;
2387 if (dwFlags&MAFA_ENCRYPT) dwCryptKey = HashString(lpFileName,HASH_KEY);
2388 if (dwFlags&MAFA_MODCRYPTKEY) dwCryptKey = (dwCryptKey + mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset) ^ mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize;
2389 DWORD blockSize = 512 << mpqOpenArc->MpqHeader.wBlockSize;
2390 DWORD TotalBlocks = mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize / blockSize;
2391
2392 if(mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize % blockSize)
2393 TotalBlocks++;
2394 DWORD dwBlockEnd = mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize % blockSize;
2395 if (dwBlockEnd==0) dwBlockEnd = blockSize;
2396 if ((dwFlags & MAFA_COMPRESS)==MAFA_COMPRESS || (dwFlags & MAFA_COMPRESS2)==MAFA_COMPRESS2) {
2397 EncryptData((LPBYTE)buffer,ptsz,dwCryptKey-1);
2398 }
2399 for (DWORD i=0;i<TotalBlocks;i++) {
2400 EncryptData((LPBYTE)buffer+dwBlkpt[i],dwBlkpt[i+1]-dwBlkpt[i],dwCryptKey);
2401 dwCryptKey++;
2402 }
2403 }
2404 SFFree(dwBlkpt);
2405 SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+dwFileOffset,0,FILE_BEGIN);
2406 WriteFile(mpqOpenArc->hFile,buffer,fsz,&tsz,0);
2407 SFFree(buffer);
2408 buffer = (char *)SFAlloc(sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize);
2409 if (buffer!=0) {
2410 memcpy(buffer,mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize);
2411 EncryptData((LPBYTE)buffer,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,dwHashTableKey);
2412 SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->MpqHeader.dwHashTableOffset,0,FILE_BEGIN);
2413 WriteFile(mpqOpenArc->hFile,buffer,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,&tsz,0);
2414 SFFree(buffer);
2415 }
2416 else {
2417 EncryptData((LPBYTE)mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,dwHashTableKey);
2418 SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->MpqHeader.dwHashTableOffset,0,FILE_BEGIN);
2419 WriteFile(mpqOpenArc->hFile,mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,&tsz,0);
2420 DecryptData((LPBYTE)mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,dwHashTableKey);
2421 }
2422 buffer = (char *)SFAlloc(sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize);
2423 if (buffer!=0) {
2424 memcpy(buffer,mpqOpenArc->lpBlockTable,sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize);
2425 EncryptData((LPBYTE)buffer,sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize,dwBlockTableKey);
2426 SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->MpqHeader.dwBlockTableOffset,0,FILE_BEGIN);
2427 WriteFile(mpqOpenArc->hFile,buffer,sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize,&tsz,0);
2428 SFFree(buffer);
2429 }
2430 else {
2431 EncryptData((LPBYTE)mpqOpenArc->lpBlockTable,sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize,dwBlockTableKey);
2432 SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->MpqHeader.dwBlockTableOffset,0,FILE_BEGIN);
2433 WriteFile(mpqOpenArc->hFile,mpqOpenArc->lpBlockTable,sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize,&tsz,0);
2434 DecryptData((LPBYTE)mpqOpenArc->lpBlockTable,sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize,dwBlockTableKey);
2435 }
2436 AddToInternalListing(hMPQ,lpFileName);
2437 return TRUE;
2438}
2439
2440BOOL SFMPQAPI WINAPI MpqAddFileFromBuffer(MPQHANDLE hMPQ, LPVOID lpBuffer, DWORD dwLength, LPCSTR lpFileName, DWORD dwFlags)
2441{
2442 return MpqAddFileFromBufferEx(hMPQ,lpBuffer,dwLength,lpFileName,dwFlags,0x08,0);
2443}
2444
2445BOOL SFMPQAPI WINAPI MpqAddWaveFromBuffer(MPQHANDLE hMPQ, LPVOID lpBuffer, DWORD dwLength, LPCSTR lpFileName, DWORD dwFlags, DWORD dwQuality)
2446{
2447 return MpqAddFileFromBufferEx(hMPQ,lpBuffer,dwLength,lpFileName,dwFlags,0x81,dwQuality);
2448}
2449
2450BOOL SFMPQAPI WINAPI MpqRenameFile(MPQHANDLE hMPQ, LPCSTR lpcOldFileName, LPCSTR lpcNewFileName)
2451{
2452 return MpqRenameAndSetFileLocale(hMPQ,lpcOldFileName,lpcNewFileName,LocaleID,LocaleID);
2453}
2454
2455BOOL SFMPQAPI WINAPI MpqRenameAndSetFileLocale(MPQHANDLE hMPQ, LPCSTR lpcOldFileName, LPCSTR lpcNewFileName, LCID nOldLocale, LCID nNewLocale)
2456{
2457 if (!hMPQ || !lpcOldFileName || !lpcNewFileName) {
2458 SetLastError(ERROR_INVALID_PARAMETER);
2459 return FALSE;
2460 }
2461 if (!*lpcNewFileName) {
2462 SetLastError(ERROR_INVALID_PARAMETER);
2463 return FALSE;
2464 }
2465
2466 if (!(((MPQARCHIVE *)hMPQ)->dwFlags&SFILE_OPEN_ALLOW_WRITE)) {
2467 SetLastError(ERROR_ACCESS_DENIED);
2468 return FALSE;
2469 }
2470 if (stricmp(lpcOldFileName,lpcNewFileName)==0) {
2471 SetLastError(ERROR_INVALID_PARAMETER);
2472 return FALSE;
2473 }
2474 MPQARCHIVE *mpqOpenArc = (MPQARCHIVE *)hMPQ;
2475 HASHTABLEENTRY *oldHashEntry = (HASHTABLEENTRY *)GetHashTableEntry(hMPQ,lpcOldFileName,nOldLocale);
2476 if (oldHashEntry==0) {
2477 SetLastError(MPQ_ERROR_FILE_NOT_FOUND);
2478 return FALSE;
2479 }
2480 if (oldHashEntry->lcLocale!=nOldLocale) {
2481 SetLastError(MPQ_ERROR_FILE_NOT_FOUND);
2482 return FALSE;
2483 }
2484 HASHTABLEENTRY *newHashEntry = (HASHTABLEENTRY *)GetFreeHashTableEntry(hMPQ,lpcNewFileName,nNewLocale,TRUE);
2485 if ((newHashEntry->dwBlockTableIndex&0xFFFFFFFE)!=0xFFFFFFFE)
2486 return FALSE;
2487 if (newHashEntry==0) newHashEntry = oldHashEntry;
2488 DWORD tsz;
2489 newHashEntry->dwNameHashA = HashString(lpcNewFileName,HASH_NAME_A);
2490 newHashEntry->dwNameHashB = HashString(lpcNewFileName,HASH_NAME_B);
2491 newHashEntry->lcLocale = nNewLocale;
2492 newHashEntry->dwBlockTableIndex = oldHashEntry->dwBlockTableIndex;
2493 DWORD BlockIndex = oldHashEntry->dwBlockTableIndex;
2494 if (mpqOpenArc->lpBlockTable[BlockIndex].dwFlags & MAFA_ENCRYPT)
2495 {
2496 DWORD dwOldCryptKey = HashString(lpcOldFileName,HASH_KEY);
2497 DWORD dwNewCryptKey = HashString(lpcNewFileName,HASH_KEY);
2498 if (mpqOpenArc->lpBlockTable[BlockIndex].dwFlags & MAFA_MODCRYPTKEY) {
2499 dwOldCryptKey = (dwOldCryptKey + mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset) ^ mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize;
2500
2501 dwNewCryptKey = (dwNewCryptKey + mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset) ^ mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize;
2502 }
2503 if (dwOldCryptKey!=dwNewCryptKey)
2504 {
2505 DWORD HeaderLength=0;
2506 if (memcmp(&mpqOpenArc->MpqHeader.dwMPQID,ID_BN3,4)==0)
2507 {
2508 SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset,0,FILE_BEGIN);
2509 ReadFile(mpqOpenArc->hFile,&HeaderLength,4,&tsz,0);
2510
2511 }
2512 DWORD blockSize = 512 << mpqOpenArc->MpqHeader.wBlockSize;
2513 DWORD TotalBlocks = mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize / blockSize;
2514 if(mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize % blockSize)
2515 TotalBlocks++;
2516 DWORD *dwBlockPtrTable = (DWORD *)SFAlloc((TotalBlocks+1)*4);
2517 if (dwBlockPtrTable==0) {
2518 return FALSE;
2519 }
2520 DWORD i;
2521 if ((mpqOpenArc->lpBlockTable[BlockIndex].dwFlags & MAFA_COMPRESS)==MAFA_COMPRESS || (mpqOpenArc->lpBlockTable[BlockIndex].dwFlags & MAFA_COMPRESS2)==MAFA_COMPRESS2)
2522 {
2523 SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset+HeaderLength,0,FILE_BEGIN);
2524 ReadFile(mpqOpenArc->hFile,dwBlockPtrTable,(TotalBlocks+1)*4,&tsz,0);
2525 DecryptData((LPBYTE)dwBlockPtrTable,(TotalBlocks+1)*4,dwOldCryptKey-1);
2526 char *EncryptedTable = (char *)SFAlloc((TotalBlocks+1)*4);
2527 if (EncryptedTable==0) {
2528 SFFree(dwBlockPtrTable);
2529 return FALSE;
2530 }
2531 memcpy(EncryptedTable,dwBlockPtrTable,(TotalBlocks+1)*4);
2532 EncryptData((LPBYTE)EncryptedTable,(TotalBlocks+1)*4,dwNewCryptKey-1);
2533 SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset+HeaderLength,0,FILE_BEGIN);
2534 WriteFile(mpqOpenArc->hFile,EncryptedTable,(TotalBlocks+1)*4,&tsz,0);
2535 SFFree(EncryptedTable);
2536 }
2537 else
2538 {
2539 for (i=0;i<TotalBlocks+1;i++) {
2540 if (i<TotalBlocks) dwBlockPtrTable[i] = i * blockSize;
2541 else dwBlockPtrTable[i] = mpqOpenArc->lpBlockTable[BlockIndex].dwFullSize;
2542 }
2543 }
2544 char *blkBuffer = (char *)SFAlloc(blockSize);
2545 if (blkBuffer==0) {
2546 EncryptData((LPBYTE)dwBlockPtrTable,(TotalBlocks+1)*4,dwOldCryptKey-1);
2547 SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset+HeaderLength,0,FILE_BEGIN);
2548 WriteFile(mpqOpenArc->hFile,dwBlockPtrTable,(TotalBlocks+1)*4,&tsz,0);
2549 SFFree(dwBlockPtrTable);
2550 return FALSE;
2551 }
2552 for (i=0;i<TotalBlocks;i++) {
2553 SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset+HeaderLength+dwBlockPtrTable[i],0,FILE_BEGIN);
2554 if (ReadFile(mpqOpenArc->hFile,blkBuffer,dwBlockPtrTable[i+1]-dwBlockPtrTable[i],&tsz,0)==0) {
2555 EncryptData((LPBYTE)dwBlockPtrTable,(TotalBlocks+1)*4,dwOldCryptKey-1);
2556 SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset+HeaderLength,0,FILE_BEGIN);
2557 WriteFile(mpqOpenArc->hFile,dwBlockPtrTable,(TotalBlocks+1)*4,&tsz,0);
2558 SFFree(dwBlockPtrTable);
2559 SFFree(blkBuffer);
2560 return FALSE;
2561 }
2562 DecryptData((LPBYTE)blkBuffer,dwBlockPtrTable[i+1]-dwBlockPtrTable[i],dwOldCryptKey+i);
2563 EncryptData((LPBYTE)blkBuffer,dwBlockPtrTable[i+1]-dwBlockPtrTable[i],dwNewCryptKey+i);
2564 SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->lpBlockTable[BlockIndex].dwFileOffset+HeaderLength+dwBlockPtrTable[i],0,FILE_BEGIN);
2565 WriteFile(mpqOpenArc->hFile,blkBuffer,dwBlockPtrTable[i+1]-dwBlockPtrTable[i],&tsz,0);
2566 }
2567 SFFree(dwBlockPtrTable);
2568 SFFree(blkBuffer);
2569 }
2570 }
2571 if (oldHashEntry!=newHashEntry) {
2572 oldHashEntry->dwNameHashA = 0xFFFFFFFF;
2573 oldHashEntry->dwNameHashB = 0xFFFFFFFF;
2574 oldHashEntry->lcLocale = 0xFFFFFFFF;
2575 oldHashEntry->dwBlockTableIndex = 0xFFFFFFFE;
2576 char *buffer = (char *)SFAlloc(sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize);
2577 if (buffer!=0) {
2578 memcpy(buffer,mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize);
2579 EncryptData((LPBYTE)buffer,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,dwHashTableKey);
2580 SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->MpqHeader.dwHashTableOffset,0,FILE_BEGIN);
2581 WriteFile(mpqOpenArc->hFile,buffer,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,&tsz,0);
2582 SFFree(buffer);
2583 }
2584 else {
2585 EncryptData((LPBYTE)mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,dwHashTableKey);
2586 SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->MpqHeader.dwHashTableOffset,0,FILE_BEGIN);
2587 WriteFile(mpqOpenArc->hFile,mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,&tsz,0);
2588 DecryptData((LPBYTE)mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,dwHashTableKey);
2589 }
2590 }
2591 LCID dwOldLocale=LocaleID;
2592 LocaleID=nOldLocale;
2593 RemoveFromInternalListing(hMPQ,lpcOldFileName);
2594
2595 LocaleID=nNewLocale;
2596 AddToInternalListing(hMPQ,lpcNewFileName);
2597 LocaleID=dwOldLocale;
2598 return TRUE;
2599}
2600
2601BOOL SFMPQAPI WINAPI MpqDeleteFile(MPQHANDLE hMPQ, LPCSTR lpFileName)
2602{
2603 return MpqDeleteFileWithLocale(hMPQ,lpFileName,LocaleID);
2604}
2605
2606BOOL SFMPQAPI WINAPI MpqDeleteFileWithLocale(MPQHANDLE hMPQ, LPCSTR lpFileName, LCID nLocale)
2607{
2608 if (!hMPQ || !lpFileName) {
2609 SetLastError(ERROR_INVALID_PARAMETER);
2610 return FALSE;
2611 }
2612
2613 if (!(((MPQARCHIVE *)hMPQ)->dwFlags&SFILE_OPEN_ALLOW_WRITE)) {
2614
2615 SetLastError(ERROR_ACCESS_DENIED);
2616 return FALSE;
2617 }
2618 MPQARCHIVE *mpqOpenArc = (MPQARCHIVE *)hMPQ;
2619 HASHTABLEENTRY *hashEntry = (HASHTABLEENTRY *)GetHashTableEntry(hMPQ,lpFileName,nLocale);
2620 if (hashEntry==0) {
2621 SetLastError(MPQ_ERROR_FILE_NOT_FOUND);
2622 return FALSE;
2623 }
2624 if (hashEntry->lcLocale!=nLocale) return FALSE;
2625 hashEntry->dwNameHashA = 0xFFFFFFFF;
2626 hashEntry->dwNameHashB = 0xFFFFFFFF;
2627 hashEntry->lcLocale = 0xFFFFFFFF;
2628 hashEntry->dwBlockTableIndex = 0xFFFFFFFE;
2629 DWORD tsz;
2630 char *buffer = (char *)SFAlloc(sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize);
2631 if (buffer!=0) {
2632 memcpy(buffer,mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize);
2633 EncryptData((LPBYTE)buffer,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,dwHashTableKey);
2634 SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->MpqHeader.dwHashTableOffset,0,FILE_BEGIN);
2635
2636 WriteFile(mpqOpenArc->hFile,buffer,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,&tsz,0);
2637 SFFree(buffer);
2638 }
2639 else {
2640 EncryptData((LPBYTE)mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,dwHashTableKey);
2641 SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->MpqHeader.dwHashTableOffset,0,FILE_BEGIN);
2642 WriteFile(mpqOpenArc->hFile,mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,&tsz,0);
2643 DecryptData((LPBYTE)mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,dwHashTableKey);
2644 }
2645 LCID dwOldLocale=LocaleID;
2646 LocaleID=nLocale;
2647 RemoveFromInternalListing(hMPQ,lpFileName);
2648 LocaleID=dwOldLocale;
2649 return TRUE;
2650}
2651
2652BOOL SFMPQAPI WINAPI MpqCompactArchive(MPQHANDLE hMPQ)
2653{
2654 if (!hMPQ) {
2655 SetLastError(ERROR_INVALID_PARAMETER);
2656 return FALSE;
2657 }
2658
2659 if (!(((MPQARCHIVE *)hMPQ)->dwFlags&SFILE_OPEN_ALLOW_WRITE)) {
2660 SetLastError(ERROR_ACCESS_DENIED);
2661 return FALSE;
2662 }
2663 MPQARCHIVE *mpqOpenArc = (MPQARCHIVE *)hMPQ;
2664 TempAlloc NewAlloc;
2665 char *lpFileName = (char *)NewAlloc.Alloc(strlen(mpqOpenArc->lpFileName)+13);
2666 sprintf(lpFileName,"%s.compact",mpqOpenArc->lpFileName);
2667 HANDLE hFile = CreateFile(lpFileName,GENERIC_READ|GENERIC_WRITE,0,0,CREATE_NEW,0,0);
2668 DWORD i;
2669 if (hFile==INVALID_HANDLE_VALUE) {
2670 for (i=0;i<10000;i++) {
2671 sprintf(lpFileName,"%s.compact.%04ld",mpqOpenArc->lpFileName,i);
2672
2673 hFile = CreateFile(lpFileName,GENERIC_READ|GENERIC_WRITE,0,0,CREATE_NEW,0,0);
2674 if (hFile!=INVALID_HANDLE_VALUE) break;
2675 }
2676 if (i==10000) return FALSE;
2677 }
95d2f3da 2678 DWORD dwLastOffset = sizeof(MPQHEADER),tsz;
7df24e1f 2679 char *buffer = (char *)SFAlloc(65536);
2680 if (buffer==0) {
2681 CloseHandle(hFile);
2682 DeleteFile(lpFileName);
2683 return FALSE;
2684 }
2685 HASHTABLEENTRY *lpHashTable = (HASHTABLEENTRY *)SFAlloc(sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize);
2686 if (lpHashTable==0) {
2687 SFFree(buffer);
2688 CloseHandle(hFile);
2689 DeleteFile(lpFileName);
2690 return FALSE;
2691 }
2692 BLOCKTABLEENTRY *lpBlockTable = (BLOCKTABLEENTRY *)SFAlloc(sizeof(BLOCKTABLEENTRY) * mpqOpenArc->MpqHeader.dwBlockTableSize);
2693 if(mpqOpenArc->lpBlockTable!=0) {
2694 if (lpBlockTable==0) {
2695 SFFree(lpHashTable);
2696 SFFree(buffer);
2697 CloseHandle(hFile);
2698 DeleteFile(lpFileName);
2699
2700 return FALSE;
2701 }
2702 }
2703 DWORD j=0,nBlkOffset=0,ReadSize=0;
2704 memcpy(lpHashTable,mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize);
2705 for (i=0;i<mpqOpenArc->MpqHeader.dwBlockTableSize;i++) {
2706 for (j=0;j<mpqOpenArc->MpqHeader.dwHashTableSize;j++) {
2707 if (lpHashTable[j].dwBlockTableIndex==(i-nBlkOffset)) break;
2708 }
2709 if (j<mpqOpenArc->MpqHeader.dwHashTableSize) {
2710 memcpy(&lpBlockTable[i-nBlkOffset],&mpqOpenArc->lpBlockTable[i],sizeof(BLOCKTABLEENTRY));
2711 lpBlockTable[i-nBlkOffset].dwFileOffset = dwLastOffset;
2712 dwLastOffset += mpqOpenArc->lpBlockTable[i].dwCompressedSize;
2713 DWORD dwWritten=FALSE;
2714 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))
2715 {
2716 DWORD HeaderLength=0;
2717 if (memcmp(&mpqOpenArc->MpqHeader.dwMPQID,ID_BN3,4)==0)
2718 {
2719 SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->lpBlockTable[i].dwFileOffset,0,FILE_BEGIN);
2720 ReadFile(mpqOpenArc->hFile,&HeaderLength,4,&tsz,0);
2721 }
2722 DWORD blockSize = 512 << mpqOpenArc->MpqHeader.wBlockSize;
2723 DWORD TotalBlocks = mpqOpenArc->lpBlockTable[i].dwFullSize / blockSize;
2724 if(mpqOpenArc->lpBlockTable[i].dwFullSize % blockSize)
2725 TotalBlocks++;
2726 DWORD *dwBlockPtrTable = (DWORD *)SFAlloc((TotalBlocks+1)*4);
2727 if (dwBlockPtrTable==0) {
2728 SFFree(lpBlockTable);
2729 SFFree(lpHashTable);
2730 SFFree(buffer);
2731 CloseHandle(hFile);
2732 DeleteFile(lpFileName);
2733 return FALSE;
2734 }
2735 SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->lpBlockTable[i].dwFileOffset+HeaderLength,0,FILE_BEGIN);
2736 ReadFile(mpqOpenArc->hFile,dwBlockPtrTable,(TotalBlocks+1)*4,&tsz,0);
2737 DWORD dwOldCryptKey = DetectFileSeed(dwBlockPtrTable,(TotalBlocks+1)*4,blockSize);
2738 DWORD dwNewCryptKey = (dwOldCryptKey ^ mpqOpenArc->lpBlockTable[i].dwFullSize) - mpqOpenArc->lpBlockTable[i].dwFileOffset;
2739 dwNewCryptKey = (dwNewCryptKey + lpBlockTable[i-nBlkOffset].dwFileOffset) ^ lpBlockTable[i-nBlkOffset].dwFullSize;
2740 if (dwOldCryptKey==0) {
2741 DWORD dwNameHashA = HashString(INTERNAL_LISTFILE,HASH_NAME_A);
2742 DWORD dwNameHashB = HashString(INTERNAL_LISTFILE,HASH_NAME_B);
2743 if (lpHashTable[j].dwNameHashA==dwNameHashA && lpHashTable[j].dwNameHashB==dwNameHashB) {
2744 dwOldCryptKey = HashString(INTERNAL_LISTFILE,HASH_KEY);
2745 dwNewCryptKey = dwOldCryptKey;
2746 dwOldCryptKey = (dwOldCryptKey + mpqOpenArc->lpBlockTable[i].dwFileOffset) ^ mpqOpenArc->lpBlockTable[i].dwFullSize;
2747 dwNewCryptKey = (dwNewCryptKey + lpBlockTable[i-nBlkOffset].dwFileOffset) ^ lpBlockTable[i-nBlkOffset].dwFullSize;
2748 }
2749 else {
2750 HANDLE hlFile;
2751 DWORD fsz;
2752 char *listbuffer;
2753 LCID lcOldLocale = LocaleID;
2754 for (DWORD lcn=0;lcn<nLocales;lcn++) {
2755 LocaleID = availLocales[lcn];
2756 if (SFileOpenFileEx(hMPQ,INTERNAL_LISTFILE,0,&hlFile)!=0) {
2757 if (((MPQFILE *)hlFile)->lpHashEntry->lcLocale==0 && LocaleID!=0) {
2758
2759 SFileCloseFile(hlFile);
2760 continue;
2761 }
2762 fsz = SFileGetFileSize(hlFile,0);
2763 if (fsz>0) {
2764 listbuffer = (char *)SFAlloc(fsz+1);
2765 if (listbuffer==0) {
2766 SFileCloseFile(hlFile);
2767 continue;
2768 }
2769 if (SFileReadFile(hlFile,listbuffer,fsz,0,0)==0) {
2770 SFFree(listbuffer);
2771 listbuffer = 0;
2772 }
2773 }
2774 SFileCloseFile(hlFile);
2775 if (listbuffer!=0) {
2776 char *listline;
2777 for (listline=listbuffer;listline!=0;listline=nextline(listline)) {
2778 if (listline[0]==0) break;
2779 DWORD lnlen=strlnlen(listline);
2780 char prevchar=listline[lnlen];
2781 listline[lnlen]=0;
2782 dwNameHashA = HashString(listline,HASH_NAME_A);
2783 dwNameHashB = HashString(listline,HASH_NAME_B);
2784 if (lpHashTable[j].dwNameHashA==dwNameHashA && lpHashTable[j].dwNameHashB==dwNameHashB) {
2785 dwOldCryptKey = HashString(listline,HASH_KEY);
2786 dwNewCryptKey = dwOldCryptKey;
2787 dwOldCryptKey = (dwOldCryptKey + mpqOpenArc->lpBlockTable[i].dwFileOffset) ^ mpqOpenArc->lpBlockTable[i].dwFullSize;
2788 dwNewCryptKey = (dwNewCryptKey + lpBlockTable[i-nBlkOffset].dwFileOffset) ^ lpBlockTable[i-nBlkOffset].dwFullSize;
2789 break;
2790 }
2791 listline[lnlen]=prevchar;
2792 }
2793 if (listline!=0) {
2794 if (listline[0]!=0) {
2795 SFFree(listbuffer);
2796 break;
2797 }
2798 }
2799 SFFree(listbuffer);
2800 }
2801 }
2802 }
2803 LocaleID = lcOldLocale;
2804 }
2805 }
2806 if (dwOldCryptKey!=dwNewCryptKey)
2807 {
2808 DecryptData((LPBYTE)dwBlockPtrTable,(TotalBlocks+1)*4,dwOldCryptKey-1);
2809 char *EncryptedTable = (char *)SFAlloc((TotalBlocks+1)*4);
2810 if (EncryptedTable==0) {
2811 SFFree(dwBlockPtrTable);
2812 SFFree(lpBlockTable);
2813 SFFree(lpHashTable);
2814 SFFree(buffer);
2815 CloseHandle(hFile);
2816 DeleteFile(lpFileName);
2817 return FALSE;
2818 }
2819 memcpy(EncryptedTable,dwBlockPtrTable,(TotalBlocks+1)*4);
2820 EncryptData((LPBYTE)EncryptedTable,(TotalBlocks+1)*4,dwNewCryptKey-1);
2821 SetFilePointer(hFile,lpBlockTable[i-nBlkOffset].dwFileOffset+HeaderLength,0,FILE_BEGIN);
2822 WriteFile(hFile,EncryptedTable,(TotalBlocks+1)*4,&tsz,0);
2823 SFFree(EncryptedTable);
2824 char *blkBuffer = (char *)SFAlloc(blockSize);
2825 if (blkBuffer==0) {
2826 SFFree(dwBlockPtrTable);
2827 SFFree(lpBlockTable);
2828 SFFree(lpHashTable);
2829 SFFree(buffer);
2830 CloseHandle(hFile);
2831 DeleteFile(lpFileName);
2832 return FALSE;
2833 }
2834 for (DWORD k=0;k<TotalBlocks;k++) {
2835 SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->lpBlockTable[i].dwFileOffset+HeaderLength+dwBlockPtrTable[k],0,FILE_BEGIN);
2836 if (ReadFile(mpqOpenArc->hFile,blkBuffer,dwBlockPtrTable[k+1]-dwBlockPtrTable[k],&tsz,0)==0) {
2837 SFFree(dwBlockPtrTable);
2838 SFFree(blkBuffer);
2839 SFFree(lpBlockTable);
2840 SFFree(lpHashTable);
2841 SFFree(buffer);
2842 CloseHandle(hFile);
2843 DeleteFile(lpFileName);
2844 return FALSE;
2845 }
2846 DecryptData((LPBYTE)blkBuffer,dwBlockPtrTable[k+1]-dwBlockPtrTable[k],dwOldCryptKey+k);
2847 EncryptData((LPBYTE)blkBuffer,dwBlockPtrTable[k+1]-dwBlockPtrTable[k],dwNewCryptKey+k);
2848 SetFilePointer(hFile,lpBlockTable[i-nBlkOffset].dwFileOffset+HeaderLength+dwBlockPtrTable[k],0,FILE_BEGIN);
2849 WriteFile(hFile,blkBuffer,dwBlockPtrTable[k+1]-dwBlockPtrTable[k],&tsz,0);
2850 }
2851 SFFree(blkBuffer);
2852 dwWritten = TRUE;
2853 }
2854 SFFree(dwBlockPtrTable);
2855 }
2856 else if (mpqOpenArc->lpBlockTable[i].dwFlags&MAFA_ENCRYPT && mpqOpenArc->lpBlockTable[i].dwFlags&MAFA_MODCRYPTKEY)
2857 {
2858 DWORD HeaderLength=0;
2859 if (memcmp(&mpqOpenArc->MpqHeader.dwMPQID,ID_BN3,4)==0)
2860
2861 {
2862 SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->lpBlockTable[i].dwFileOffset,0,FILE_BEGIN);
2863 ReadFile(mpqOpenArc->hFile,&HeaderLength,4,&tsz,0);
2864 }
2865 DWORD blockSize = 512 << mpqOpenArc->MpqHeader.wBlockSize;
2866 DWORD TotalBlocks = mpqOpenArc->lpBlockTable[i].dwFullSize / blockSize;
2867 if(mpqOpenArc->lpBlockTable[i].dwFullSize % blockSize)
2868 TotalBlocks++;
2869 DWORD dwNameHashA = HashString(INTERNAL_LISTFILE,HASH_NAME_A);
2870 DWORD dwNameHashB = HashString(INTERNAL_LISTFILE,HASH_NAME_B);
2871 DWORD dwOldCryptKey=0;
2872 DWORD dwNewCryptKey=0;
2873 if (lpHashTable[j].dwNameHashA==dwNameHashA && lpHashTable[j].dwNameHashB==dwNameHashB) {
2874 dwOldCryptKey = HashString(INTERNAL_LISTFILE,HASH_KEY);
2875 dwNewCryptKey = dwOldCryptKey;
2876 dwOldCryptKey = (dwOldCryptKey + mpqOpenArc->lpBlockTable[i].dwFileOffset) ^ mpqOpenArc->lpBlockTable[i].dwFullSize;
2877 dwNewCryptKey = (dwNewCryptKey + lpBlockTable[i-nBlkOffset].dwFileOffset) ^ lpBlockTable[i-nBlkOffset].dwFullSize;
2878 }
2879 else {
2880 HANDLE hlFile;
2881 DWORD fsz;
2882
2883 char *listbuffer;
2884 LCID lcOldLocale = LocaleID;
2885 for (DWORD lcn=0;lcn<nLocales;lcn++) {
2886 LocaleID = availLocales[lcn];
2887 if (SFileOpenFileEx(hMPQ,INTERNAL_LISTFILE,0,&hlFile)!=0) {
2888 if (((MPQFILE *)hlFile)->lpHashEntry->lcLocale==0 && LocaleID!=0) {
2889 SFileCloseFile(hlFile);
2890 continue;
2891 }
2892 fsz = SFileGetFileSize(hlFile,0);
2893 if (fsz>0) {
2894 listbuffer = (char *)SFAlloc(fsz+1);
2895 if (listbuffer==0) {
2896 SFileCloseFile(hlFile);
2897 continue;
2898 }
2899 if (SFileReadFile(hlFile,listbuffer,fsz,0,0)==0) {
2900 SFFree(listbuffer);
2901 listbuffer = 0;
2902 }
2903 }
2904 SFileCloseFile(hlFile);
2905 if (listbuffer!=0) {
2906 char *listline;
2907 for (listline=listbuffer;listline!=0;listline=nextline(listline)) {
2908 if (listline[0]==0) break;
2909 DWORD lnlen=strlnlen(listline);
2910 char prevchar=listline[lnlen];
2911 listline[lnlen]=0;
2912 dwNameHashA = HashString(listline,HASH_NAME_A);
2913 dwNameHashB = HashString(listline,HASH_NAME_B);
2914 if (lpHashTable[j].dwNameHashA==dwNameHashA && lpHashTable[j].dwNameHashB==dwNameHashB) {
2915 dwOldCryptKey = HashString(listline,HASH_KEY);
2916 dwNewCryptKey = dwOldCryptKey;
2917 dwOldCryptKey = (dwOldCryptKey + mpqOpenArc->lpBlockTable[i].dwFileOffset) ^ mpqOpenArc->lpBlockTable[i].dwFullSize;
2918 dwNewCryptKey = (dwNewCryptKey + lpBlockTable[i-nBlkOffset].dwFileOffset) ^ lpBlockTable[i-nBlkOffset].dwFullSize;
2919 break;
2920 }
2921 listline[lnlen]=prevchar;
2922 }
2923 if (listline!=0) {
2924 if (listline[0]!=0) {
2925 SFFree(listbuffer);
2926 break;
2927 }
2928 }
2929 SFFree(listbuffer);
2930 }
2931 }
2932 }
2933 LocaleID = lcOldLocale;
2934 }
2935 if (dwOldCryptKey!=dwNewCryptKey)
2936 {
2937 char *blkBuffer = (char *)SFAlloc(blockSize);
2938 if (blkBuffer==0) {
2939 SFFree(lpBlockTable);
2940 SFFree(lpHashTable);
2941 SFFree(buffer);
2942 CloseHandle(hFile);
2943 DeleteFile(lpFileName);
2944 return FALSE;
2945 }
2946 for (DWORD k=0;k<mpqOpenArc->lpBlockTable[i].dwFullSize;k+=blockSize) {
2947 SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->lpBlockTable[i].dwFileOffset+HeaderLength+k,0,FILE_BEGIN);
2948 if (k+blockSize>mpqOpenArc->lpBlockTable[i].dwFullSize) blockSize = mpqOpenArc->lpBlockTable[i].dwFullSize % blockSize;
2949 if (ReadFile(mpqOpenArc->hFile,blkBuffer,blockSize,&tsz,0)==0) {
2950 SFFree(blkBuffer);
2951 SFFree(lpBlockTable);
2952 SFFree(lpHashTable);
2953 SFFree(buffer);
2954 CloseHandle(hFile);
2955 DeleteFile(lpFileName);
2956 return FALSE;
2957
2958 }
2959 DecryptData((LPBYTE)blkBuffer,blockSize,dwOldCryptKey+k);
2960 EncryptData((LPBYTE)blkBuffer,blockSize,dwNewCryptKey+k);
2961 SetFilePointer(hFile,lpBlockTable[i-nBlkOffset].dwFileOffset+HeaderLength+k,0,FILE_BEGIN);
2962 WriteFile(hFile,blkBuffer,blockSize,&tsz,0);
2963 }
2964 SFFree(blkBuffer);
2965 dwWritten = TRUE;
2966 }
2967 }
2968 if (dwWritten==FALSE) {
2969 ReadSize = 65536;
2970 for (j=0;j<mpqOpenArc->lpBlockTable[i].dwCompressedSize;j+=65536) {
2971 SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->lpBlockTable[i].dwFileOffset+j,0,FILE_BEGIN);
2972 SetFilePointer(hFile,lpBlockTable[i-nBlkOffset].dwFileOffset+j,0,FILE_BEGIN);
2973 if (j+65536>mpqOpenArc->lpBlockTable[i].dwCompressedSize) ReadSize = mpqOpenArc->lpBlockTable[i].dwCompressedSize-j;
2974 if (ReadFile(mpqOpenArc->hFile,buffer,ReadSize,&tsz,0)==0) {
2975 SFFree(lpBlockTable);
2976 SFFree(lpHashTable);
2977 SFFree(buffer);
2978 CloseHandle(hFile);
2979 DeleteFile(lpFileName);
2980 return FALSE;
2981 }
2982 if (WriteFile(hFile,buffer,ReadSize,&tsz,0)==0) {
2983 SFFree(lpBlockTable);
2984 SFFree(lpHashTable);
2985 SFFree(buffer);
2986 CloseHandle(hFile);
2987 DeleteFile(lpFileName);
2988 return FALSE;
2989 }
2990 }
2991 }
2992 }
2993 else {
2994 for (j=0;j<mpqOpenArc->MpqHeader.dwHashTableSize;j++) {
2995 if ((lpHashTable[j].dwBlockTableIndex&0xFFFFFFFE)!=0xFFFFFFFE)
2996 if (lpHashTable[j].dwBlockTableIndex>(i-nBlkOffset)) lpHashTable[j].dwBlockTableIndex--;
2997 }
2998 nBlkOffset++;
2999 }
3000 }
3001 mpqOpenArc->MpqHeader.dwBlockTableSize -= nBlkOffset;
3002 mpqOpenArc->MpqHeader.dwHashTableOffset = dwLastOffset;
3003 dwLastOffset += mpqOpenArc->MpqHeader.dwHashTableSize * sizeof(HASHTABLEENTRY);
3004 mpqOpenArc->MpqHeader.dwBlockTableOffset = dwLastOffset;
3005 dwLastOffset += mpqOpenArc->MpqHeader.dwBlockTableSize * sizeof(BLOCKTABLEENTRY);
3006 mpqOpenArc->MpqHeader.dwMPQSize = dwLastOffset;
3007 SFFree(mpqOpenArc->lpHashTable);
3008 mpqOpenArc->lpHashTable = lpHashTable;
3009 if(mpqOpenArc->lpBlockTable!=0) {
3010 SFFree(mpqOpenArc->lpBlockTable);
3011 mpqOpenArc->lpBlockTable = (BLOCKTABLEENTRY *)SFAlloc(mpqOpenArc->MpqHeader.dwBlockTableSize * sizeof(BLOCKTABLEENTRY));
3012 if (mpqOpenArc->lpBlockTable==0) {
3013 mpqOpenArc->lpBlockTable = lpBlockTable;
3014 }
3015 else {
3016 memcpy(mpqOpenArc->lpBlockTable,lpBlockTable,mpqOpenArc->MpqHeader.dwBlockTableSize * sizeof(BLOCKTABLEENTRY));
3017 SFFree(lpBlockTable);
3018 }
3019 }
3020 SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+dwLastOffset,0,FILE_BEGIN);
3021 SetEndOfFile(mpqOpenArc->hFile);
3022 SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart,0,FILE_BEGIN);
95d2f3da 3023 mpqOpenArc->MpqHeader.dwHeaderSize = sizeof(MPQHEADER);
7df24e1f 3024 WriteFile(mpqOpenArc->hFile,&mpqOpenArc->MpqHeader,sizeof(MPQHEADER),&tsz,0);
95d2f3da 3025 dwLastOffset = sizeof(MPQHEADER);
7df24e1f 3026 ReadSize = 65536;
3027 for (i=dwLastOffset;i<mpqOpenArc->MpqHeader.dwHashTableOffset;i+=65536) {
3028 SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+i,0,FILE_BEGIN);
3029 SetFilePointer(hFile,i,0,FILE_BEGIN);
3030 if (i+65536>mpqOpenArc->MpqHeader.dwHashTableOffset) ReadSize = mpqOpenArc->MpqHeader.dwHashTableOffset-i;
3031 ReadFile(hFile,buffer,ReadSize,&tsz,0);
3032 WriteFile(mpqOpenArc->hFile,buffer,ReadSize,&tsz,0);
3033 }
3034 SFFree(buffer);
3035 CloseHandle(hFile);
3036 DeleteFile(lpFileName);
3037 EncryptData((BYTE *)mpqOpenArc->lpHashTable,mpqOpenArc->MpqHeader.dwHashTableSize * sizeof(HASHTABLEENTRY),dwHashTableKey);
3038 SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->MpqHeader.dwHashTableOffset,0,FILE_BEGIN);
3039 WriteFile(mpqOpenArc->hFile,mpqOpenArc->lpHashTable,mpqOpenArc->MpqHeader.dwHashTableSize * sizeof(HASHTABLEENTRY),&tsz,0);
3040 DecryptData((BYTE *)mpqOpenArc->lpHashTable,mpqOpenArc->MpqHeader.dwHashTableSize * sizeof(HASHTABLEENTRY),dwHashTableKey);
3041 if(mpqOpenArc->lpBlockTable!=0) {
3042 EncryptData((BYTE *)mpqOpenArc->lpBlockTable,mpqOpenArc->MpqHeader.dwBlockTableSize * sizeof(BLOCKTABLEENTRY),dwBlockTableKey);
3043 SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->MpqHeader.dwBlockTableOffset,0,FILE_BEGIN);
3044 WriteFile(mpqOpenArc->hFile,mpqOpenArc->lpBlockTable,mpqOpenArc->MpqHeader.dwBlockTableSize * sizeof(BLOCKTABLEENTRY),&tsz,0);
3045 DecryptData((BYTE *)mpqOpenArc->lpBlockTable,mpqOpenArc->MpqHeader.dwBlockTableSize * sizeof(BLOCKTABLEENTRY),dwBlockTableKey);
3046 }
3047 return TRUE;
3048}
3049
3050BOOL SFMPQAPI WINAPI MpqSetFileLocale(MPQHANDLE hMPQ, LPCSTR lpFileName, LCID nOldLocale, LCID nNewLocale)
3051{
3052 if (!hMPQ || !lpFileName) {
3053 SetLastError(ERROR_INVALID_PARAMETER);
3054 return FALSE;
3055 }
3056
3057 if (!(((MPQARCHIVE *)hMPQ)->dwFlags&SFILE_OPEN_ALLOW_WRITE)) {
3058 SetLastError(ERROR_ACCESS_DENIED);
3059 return FALSE;
3060 }
3061 if (nOldLocale==nNewLocale) return FALSE;
3062 MPQARCHIVE *mpqOpenArc = (MPQARCHIVE *)hMPQ;
3063 HASHTABLEENTRY *hashEntry = (HASHTABLEENTRY *)GetHashTableEntry(hMPQ,lpFileName,nOldLocale);
3064 if (hashEntry==0) return FALSE;
3065 if (hashEntry->lcLocale!=nOldLocale) return FALSE;
3066 hashEntry->lcLocale = nNewLocale;
3067 DWORD tsz;
3068
3069 char *buffer = (char *)SFAlloc(sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize);
3070 if (buffer!=0) {
3071 memcpy(buffer,mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize);
3072 EncryptData((LPBYTE)buffer,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,dwHashTableKey);
3073 SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->MpqHeader.dwHashTableOffset,0,FILE_BEGIN);
3074 WriteFile(mpqOpenArc->hFile,buffer,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,&tsz,0);
3075 SFFree(buffer);
3076 }
3077 else {
3078 EncryptData((LPBYTE)mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,dwHashTableKey);
3079 SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->MpqHeader.dwHashTableOffset,0,FILE_BEGIN);
3080 WriteFile(mpqOpenArc->hFile,mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,&tsz,0);
3081 DecryptData((LPBYTE)mpqOpenArc->lpHashTable,sizeof(HASHTABLEENTRY) * mpqOpenArc->MpqHeader.dwHashTableSize,dwHashTableKey);
3082 }
3083 LCID dwOldLocale=LocaleID;
3084 LocaleID=nOldLocale;
3085 RemoveFromInternalListing(hMPQ,lpFileName);
3086
3087 LocaleID=nNewLocale;
3088 AddToInternalListing(hMPQ,lpFileName);
3089 LocaleID=dwOldLocale;
3090 return TRUE;
3091}
3092
3093DWORD SFMPQAPI WINAPI SFileFindMpqHeader(HANDLE hFile)
3094{
3095 if (hFile == INVALID_HANDLE_VALUE) {
3096 SetLastError(ERROR_INVALID_PARAMETER);
3097 return 0xFFFFFFFF;
3098 }
3099 DWORD FileLen = GetFileSize(hFile,0);
3100 char pbuf[sizeof(MPQHEADER)];
3101 DWORD tsz;
3102 for (DWORD i=0;i<FileLen;i+=512)
3103 {
3104 SetFilePointer(hFile,i,0,FILE_BEGIN);
3105 if (ReadFile(hFile,pbuf,sizeof(MPQHEADER),&tsz,0)==0) return 0xFFFFFFFF;
3106 if (tsz<sizeof(MPQHEADER)) return 0xFFFFFFFF;
3107 if (memcmp(pbuf,ID_MPQ,4)==0 || memcmp(pbuf,ID_BN3,4)==0)
3108 {
3109 // Storm no longer does this, so mpq api shouldn't either
3110 /*FileLen -= i;
3111 if (memcmp(pbuf+8,&FileLen,4)==0)
3112 return i;
3113 else
3114 FileLen += i;*/
3115 return i;
3116 }
3117 }
3118 return 0xFFFFFFFF;
3119}
3120
3121DWORD WINAPI FindMpqHeaderAtLocation(HANDLE hFile, DWORD dwStart, DWORD dwLength)
3122{
3123 if (hFile == INVALID_HANDLE_VALUE) {
3124 SetLastError(ERROR_INVALID_PARAMETER);
3125 return 0xFFFFFFFF;
3126 }
3127 char pbuf[sizeof(MPQHEADER)];
3128 DWORD tsz;
3129 for (DWORD i=dwStart;i<dwStart+dwLength;i+=512)
3130 {
3131 SetFilePointer(hFile,i,0,FILE_BEGIN);
3132 if (ReadFile(hFile,pbuf,sizeof(MPQHEADER),&tsz,0)==0) return 0xFFFFFFFF;
3133 if (i+tsz>dwStart+dwLength) tsz = (dwStart+dwLength)-i;
3134 if (tsz<sizeof(MPQHEADER)) return 0xFFFFFFFF;
3135 if (memcmp(pbuf,ID_MPQ,4)==0 || memcmp(pbuf,ID_BN3,4)==0)
3136 {
3137 // Storm no longer does this, so mpq api shouldn't either
3138 /*FileLen -= i;
3139 if (memcmp(pbuf+8,&FileLen,4)==0)
3140 return i;
3141 else
3142 FileLen += i;*/
3143 return i;
3144 }
3145 }
3146 return 0xFFFFFFFF;
3147}
3148
3149DWORD GetFullPath(LPCSTR lpFileName, char *lpBuffer, DWORD dwBufferLength)
3150{
3151 if (!lpFileName) return (DWORD)-1;
3152 DWORD slen = strlen(lpFileName);
3153 if (memcmp(lpFileName+1,":\\",2)==0) {
3154 if (slen+1>dwBufferLength) return slen+1;
3155 memcpy(lpBuffer,lpFileName,slen+1);
3156 }
3157#ifdef _WIN32
3158 else if (lpFileName[0]=='\\') {
3159#else
3160 else if (lpFileName[0]=='/') {
3161#endif
3162 if (slen+3>dwBufferLength) return slen+3;
3163 memcpy(lpBuffer,StormBasePath,2);
3164 memcpy(lpBuffer+2,lpFileName,slen+1);
3165 }
3166 else {
3167 DWORD sbslen = strlen(StormBasePath);
3168 if (sbslen+slen+1>dwBufferLength) return sbslen+slen+1;
3169 memcpy(lpBuffer,StormBasePath,sbslen);
3170 memcpy(lpBuffer+sbslen,lpFileName,slen);
3171 lpBuffer[sbslen+slen]=0;
3172 }
3173 return 0;
3174}
3175
3176MPQHANDLE GetHashTableEntry(MPQHANDLE hMPQ, LPCSTR lpFileName, LCID FileLocale)
3177{
3178 if (!hMPQ || !lpFileName) return 0;
3179 MPQARCHIVE *mpqOpenArc = (MPQARCHIVE *)hMPQ;
3180 DWORD dwTablePos = HashString(lpFileName,HASH_POSITION) % mpqOpenArc->MpqHeader.dwHashTableSize;
3181 DWORD dwNameHashA = HashString(lpFileName,HASH_NAME_A);
3182 DWORD dwNameHashB = HashString(lpFileName,HASH_NAME_B);
3183 StartTableSearch:
3184 DWORD i=dwTablePos;
3185 do
3186 {
3187 if (mpqOpenArc->lpHashTable[i].dwBlockTableIndex==0xFFFFFFFF)
3188 {
3189 break;
3190 }
3191 else if (mpqOpenArc->lpHashTable[i].dwNameHashA==dwNameHashA && mpqOpenArc->lpHashTable[i].dwNameHashB==dwNameHashB && mpqOpenArc->lpHashTable[i].lcLocale==FileLocale && mpqOpenArc->lpHashTable[i].dwBlockTableIndex!=0xFFFFFFFE)
3192 {
3193 return (MPQHANDLE)&mpqOpenArc->lpHashTable[i];
3194 }
3195 i = (i + 1) % mpqOpenArc->MpqHeader.dwHashTableSize;
3196 } while (i!=dwTablePos);
3197 if (FileLocale!=0) {FileLocale=0;goto StartTableSearch;}
3198 return 0;
3199}
3200
3201MPQHANDLE GetHashTableEntryOfHash(MPQHANDLE hMPQ, DWORD dwTablePos, DWORD dwNameHashA, DWORD dwNameHashB, LCID FileLocale)
3202{
3203 if (!hMPQ) return 0;
3204 MPQARCHIVE *mpqOpenArc = (MPQARCHIVE *)hMPQ;
3205 StartTableSearch:
3206 DWORD i=dwTablePos;
3207 do
3208 {
3209 if (mpqOpenArc->lpHashTable[i].dwBlockTableIndex==0xFFFFFFFF)
3210 {
3211 break;
3212 }
3213 else if (mpqOpenArc->lpHashTable[i].dwNameHashA==dwNameHashA && mpqOpenArc->lpHashTable[i].dwNameHashB==dwNameHashB && mpqOpenArc->lpHashTable[i].lcLocale==FileLocale && mpqOpenArc->lpHashTable[i].dwBlockTableIndex!=0xFFFFFFFE)
3214 {
3215 return (MPQHANDLE)&mpqOpenArc->lpHashTable[i];
3216 }
3217 i = (i + 1) % mpqOpenArc->MpqHeader.dwHashTableSize;
3218 } while (i!=dwTablePos);
3219 if (FileLocale!=0) {FileLocale=0;goto StartTableSearch;}
3220 return 0;
3221}
3222
3223MPQHANDLE GetFreeHashTableEntry(MPQHANDLE hMPQ, LPCSTR lpFileName, LCID FileLocale, BOOL ReturnExisting)
3224{
3225 if (!hMPQ || !lpFileName) return 0;
3226 MPQARCHIVE *mpqOpenArc = (MPQARCHIVE *)hMPQ;
3227 DWORD dwTablePos = HashString(lpFileName,HASH_POSITION) % mpqOpenArc->MpqHeader.dwHashTableSize;
3228 DWORD dwNameHashA = HashString(lpFileName,HASH_NAME_A);
3229 DWORD dwNameHashB = HashString(lpFileName,HASH_NAME_B);
46511c53 3230 DWORD i=dwTablePos, nFirstFree = 0xFFFFFFFF;
7df24e1f 3231 do
3232 {
46511c53 3233 if ((mpqOpenArc->lpHashTable[i].dwBlockTableIndex&0xFFFFFFFE)==0xFFFFFFFE && nFirstFree == 0xFFFFFFFF)
7df24e1f 3234 {
46511c53 3235 if (mpqOpenArc->lpHashTable[i].dwBlockTableIndex == 0xFFFFFFFF)
3236 {
3237 if (nFirstFree == 0xFFFFFFFF)
3238 return (MPQHANDLE)&mpqOpenArc->lpHashTable[i];
3239 else
3240 return (MPQHANDLE)&mpqOpenArc->lpHashTable[nFirstFree];
3241 }
3242 else nFirstFree = i;
7df24e1f 3243 }
3244 else if (mpqOpenArc->lpHashTable[i].dwNameHashA==dwNameHashA && mpqOpenArc->lpHashTable[i].dwNameHashB==dwNameHashB && mpqOpenArc->lpHashTable[i].lcLocale==FileLocale)
3245 {
3246 if (ReturnExisting!=FALSE)
3247 return (MPQHANDLE)&mpqOpenArc->lpHashTable[i];
3248 else {
3249 SetLastError(MPQ_ERROR_ALREADY_EXISTS);
3250 return 0;
3251 }
3252 }
3253 i = (i + 1) % mpqOpenArc->MpqHeader.dwHashTableSize;
3254 } while (i!=dwTablePos);
3255 SetLastError(MPQ_ERROR_HASH_TABLE_FULL);
3256 return 0;
3257}
3258
3259BOOL SearchOpenArchives(LPCSTR lpFileName, MPQHANDLE *hMPQ, MPQHANDLE *hFile)
3260{
3261 MPQHANDLE hnMPQ,hnFile,hndMPQ = 0,hndFile = 0;
3262
3263 DWORD dwTablePos = HashString(lpFileName,HASH_POSITION);
3264 DWORD dwNameHashA = HashString(lpFileName,HASH_NAME_A);
3265 DWORD dwNameHashB = HashString(lpFileName,HASH_NAME_B);
3266
3267 for (DWORD i=0;i<dwOpenMpqCount;i++) {
3268 hnMPQ = (MPQHANDLE)lpOpenMpq[i];
3269 hnFile = GetHashTableEntryOfHash(hnMPQ,dwTablePos % lpOpenMpq[i]->MpqHeader.dwHashTableSize,dwNameHashA,dwNameHashB,LocaleID);
3270
3271 if (hnFile!=0) {
3272 if (((HASHTABLEENTRY *)hnFile)->lcLocale == LocaleID) {
3273 *hMPQ = hnMPQ;
3274 *hFile = hnFile;
3275 return TRUE;
3276 }
3277 else if (hndMPQ == 0 || hndFile == 0) {
3278 hndMPQ = hnMPQ;
3279 hndFile = hnFile;
3280 }
3281 }
3282 }
3283
3284 if (hndMPQ != 0 && hndFile != 0) {
3285 *hMPQ = hndMPQ;
3286 *hFile = hndFile;
3287 return TRUE;
3288 }
3289
3290 *hMPQ = 0;
3291 *hFile = 0;
3292 return FALSE;
3293}
3294
3295void SortOpenArchivesByPriority()
3296{
3297 MPQARCHIVE *hMPQ1,*hMPQ2;
3298 for (DWORD i=1;i<dwOpenMpqCount;i++) {
3299 do {
3300 hMPQ1 = lpOpenMpq[i-1];
3301 hMPQ2 = lpOpenMpq[i];
3302 if (hMPQ2->dwPriority > hMPQ1->dwPriority) {
3303 lpOpenMpq[i-1] = hMPQ2;
3304 lpOpenMpq[i] = hMPQ1;
3305 i--;
3306 }
3307 } while (hMPQ2->dwPriority > hMPQ1->dwPriority && i>0);
3308 }
3309}
3310
3311DWORD GetHandleType(MPQHANDLE hFile)
3312{
3313 DWORD i;
3314 for (i=0;i<dwOpenFileCount;i++) {
3315 if ((MPQHANDLE)lpOpenFile[i]==hFile) return SFILE_TYPE_FILE;
3316 }
3317 for (i=0;i<dwOpenMpqCount;i++) {
3318 if ((MPQHANDLE)lpOpenMpq[i]==hFile) return SFILE_TYPE_MPQ;
3319 }
3320 return 0;
3321}
3322
3323BOOL AddToInternalListing(MPQHANDLE hMPQ, LPCSTR lpFileName)
3324{
3325 MPQARCHIVE *mpqOpenArc = (MPQARCHIVE *)hMPQ;
3326 if ((mpqOpenArc->dwFlags & MOAU_MAINTAIN_LISTFILE)==MOAU_MAINTAIN_LISTFILE && stricmp(lpFileName,INTERNAL_LISTFILE)!=0)
3327 {
3328 MPQHANDLE hlFile;char *buffer=0;DWORD fsz,lsz;
3329 lsz = strlen(lpFileName);
3330 if (SFileOpenFileEx(hMPQ,INTERNAL_LISTFILE,0,&hlFile)!=0) {
3331 if (((MPQFILE *)hlFile)->lpHashEntry->lcLocale==LocaleID) {
3332 fsz = SFileGetFileSize(hlFile,0);
3333 if (fsz==0) {
3334 SFileCloseFile(hlFile);
3335 goto AddFileName;
3336 }
3337 buffer = (char *)SFAlloc(fsz+lsz+2);
3338 if (buffer==0) {
3339 SFileCloseFile(hlFile);
3340 return FALSE;
3341 }
3342 if (SFileReadFile(hlFile,buffer,fsz,0,0)==0) {
3343 SFFree(buffer);
3344 buffer = 0;
3345 }
3346 buffer[fsz]=0;
3347 }
3348 SFileCloseFile(hlFile);
3349 }
3350 AddFileName:
3351 if (buffer==0) {
3352 fsz = 0;
3353 buffer = (char *)SFAlloc(lsz+2);
3354 buffer[0]=0;
3355 }
3356 else {
3357 char *buffercopy = strlwr(strdup(buffer));
3358 char *lwrFileName = strlwr(strdup(lpFileName));
3359 char *subbuffer=buffer;
3360 while ((subbuffer=strstr(subbuffer,lpFileName))!=NULL && subbuffer[0]!=0) {
3361 if (subbuffer==buffer && subbuffer[lsz]==0) {
3362 SFFree(lwrFileName);
3363 SFFree(buffercopy);
3364 SFFree(buffer);
3365 return TRUE;
3366 }
3367 else if (subbuffer==buffer && (subbuffer[lsz]=='\n' || subbuffer[lsz]=='\r')) {
3368 SFFree(lwrFileName);
3369 SFFree(buffercopy);
3370 SFFree(buffer);
3371 return TRUE;
3372 }
3373 else if (((subbuffer-1)[0]=='\n' || (subbuffer-1)[0]=='\r') && subbuffer[lsz]==0) {
3374 SFFree(lwrFileName);
3375 SFFree(buffercopy);
3376 SFFree(buffer);
3377 return TRUE;
3378 }
3379 else if (((subbuffer-1)[0]=='\n' || (subbuffer-1)[0]=='\r') && (subbuffer[lsz]=='\n' || subbuffer[lsz]=='\r')) {
3380 SFFree(lwrFileName);
3381 SFFree(buffercopy);
3382 SFFree(buffer);
3383 return TRUE;
3384 }
3385 subbuffer++;
3386 }
3387 SFFree(lwrFileName);
3388 SFFree(buffercopy);
3389 }
3390 memcpy(buffer+fsz,lpFileName,lsz);
3391 memcpy(buffer+fsz+lsz,"\r\n",2);
3392 //LCID dwOldLocale=LocaleID;
3393 //LocaleID=0;
3394 MpqAddFileFromBuffer(hMPQ,buffer,fsz+lsz+2,INTERNAL_LISTFILE,MAFA_COMPRESS|MAFA_ENCRYPT|MAFA_MODCRYPTKEY|MAFA_REPLACE_EXISTING);
3395 //LocaleID=dwOldLocale;
3396 SFFree(buffer);
3397 }
3398 return TRUE;
3399}
3400
3401BOOL RemoveFromInternalListing(MPQHANDLE hMPQ, LPCSTR lpFileName)
3402{
3403 MPQARCHIVE *mpqOpenArc = (MPQARCHIVE *)hMPQ;
3404 if ((mpqOpenArc->dwFlags & MOAU_MAINTAIN_LISTFILE)==MOAU_MAINTAIN_LISTFILE && stricmp(lpFileName,INTERNAL_LISTFILE)!=0)
3405 {
3406 MPQHANDLE hlFile;char *buffer=0;DWORD fsz,lsz;
3407 lsz = strlen(lpFileName);
3408 if (SFileOpenFileEx(hMPQ,INTERNAL_LISTFILE,0,&hlFile)!=0) {
3409 if (((MPQFILE *)hlFile)->lpHashEntry->lcLocale==LocaleID) {
3410 fsz = SFileGetFileSize(hlFile,0);
3411 if (fsz==0) {
3412 SFileCloseFile(hlFile);
3413
3414 return FALSE;
3415 }
3416
3417 buffer = (char *)SFAlloc(fsz+1);
3418 if (buffer==0) {
3419 SFileCloseFile(hlFile);
3420 return FALSE;
3421 }
3422 buffer[fsz] = 0;
3423 if (SFileReadFile(hlFile,buffer,fsz,0,0)==0) {
3424 SFFree(buffer);
3425 buffer = 0;
3426 }
3427 }
3428 SFileCloseFile(hlFile);
3429 }
3430 if (buffer==0) {
3431 return FALSE;
3432 }
3433 else {
3434 buffer[fsz]=0;
3435 char *buffercopy = strlwr(strdup(buffer));
3436 char *lwrFileName = strlwr(strdup(lpFileName));
3437 char *subbuffer=buffer;
3438
3439 while ((subbuffer=strstr(subbuffer,lpFileName))!=NULL && subbuffer[0]!=0) {
3440 if (subbuffer==buffer && subbuffer[lsz]==0) {
3441 SFFree(lwrFileName);
3442 SFFree(buffercopy);
3443 //LCID dwOldLocale=LocaleID;
3444 //LocaleID=0;
3445 MpqAddFileFromBuffer(hMPQ,(LPVOID)"\x00",0,INTERNAL_LISTFILE,MAFA_COMPRESS|MAFA_ENCRYPT|MAFA_MODCRYPTKEY|MAFA_REPLACE_EXISTING);
3446 //LocaleID=dwOldLocale;
3447 SFFree(buffer);
3448 return TRUE;
3449 }
3450 else if (subbuffer==buffer && (subbuffer[lsz]=='\n' || subbuffer[lsz]=='\r')) {
3451 SFFree(lwrFileName);
3452 SFFree(buffercopy);
3453 if (subbuffer[lsz+1]=='\n' || subbuffer[lsz+1]=='\r') lsz++;
3454 memcpy(subbuffer,subbuffer+lsz+1,strlen(subbuffer+lsz+1));
3455 //LCID dwOldLocale=LocaleID;
3456 //LocaleID=0;
3457 MpqAddFileFromBuffer(hMPQ,buffer,fsz-lsz-1,INTERNAL_LISTFILE,MAFA_COMPRESS|MAFA_ENCRYPT|MAFA_MODCRYPTKEY|MAFA_REPLACE_EXISTING);
3458 //LocaleID=dwOldLocale;
3459 SFFree(buffer);
3460 return TRUE;
3461 }
3462 else if (((subbuffer-1)[0]=='\n' || (subbuffer-1)[0]=='\r') && subbuffer[lsz]==0) {
3463 SFFree(lwrFileName);
3464 SFFree(buffercopy);
3465 //LCID dwOldLocale=LocaleID;
3466 //LocaleID=0;
3467 MpqAddFileFromBuffer(hMPQ,buffer,fsz-lsz,INTERNAL_LISTFILE,MAFA_COMPRESS|MAFA_ENCRYPT|MAFA_MODCRYPTKEY|MAFA_REPLACE_EXISTING);
3468 //LocaleID=dwOldLocale;
3469 SFFree(buffer);
3470 return TRUE;
3471 }
3472 else if (((subbuffer-1)[0]=='\n' || (subbuffer-1)[0]=='\r') && (subbuffer[lsz]=='\n' || subbuffer[lsz]=='\r')) {
3473 SFFree(lwrFileName);
3474 SFFree(buffercopy);
3475 if ((subbuffer-2)[0]=='\n' || (subbuffer-2)[0]=='\r') {subbuffer--;lsz++;}
3476 memcpy(subbuffer-1,subbuffer+lsz,strlen(subbuffer+lsz));
3477 //LCID dwOldLocale=LocaleID;
3478 //LocaleID=0;
3479 MpqAddFileFromBuffer(hMPQ,buffer,fsz-lsz-1,INTERNAL_LISTFILE,MAFA_COMPRESS|MAFA_ENCRYPT|MAFA_MODCRYPTKEY|MAFA_REPLACE_EXISTING);
3480 //LocaleID=dwOldLocale;
3481 SFFree(buffer);
3482 return TRUE;
3483 }
3484 subbuffer++;
3485 }
3486 SFFree(lwrFileName);
3487 SFFree(buffercopy);
3488 }
3489 SFFree(buffer);
3490 }
3491 return TRUE;
3492}
3493
3494size_t strlnlen(const char *strline)
3495{
3496 if (strline==0) return 0;
3497 const char *strcr = strchr(strline,'\r');
3498 const char *strlf = strchr(strline,'\n');
3499 if (strcr==0 && strlf==0) return strlen(strline);
3500 if (strcr!=0 && (strcr<strlf || strlf==0)) return strcr-strline;
3501 if (strlf!=0 && (strlf<strcr || strcr==0)) return strlf-strline;
3502 return strlen(strline);
3503}
3504
3505char *nextline(const char *strline)
3506{
3507 if (strline==0) return 0;
3508 const char *strcr = strchr(strline,'\r');
3509 const char *strlf = strchr(strline,'\n');
3510 if (strcr==0 && strlf==0) return 0;
3511 const char *streol;
3512 if (strcr!=0 && (strcr<strlf || strlf==0)) streol = strcr;
3513 if (strlf!=0 && (strlf<strcr || strcr==0)) streol = strlf;
3514 do {
3515 streol++;
3516 } while (streol[0]=='\r' || streol[0]=='\n');
3517 if (streol[0]==0) return 0;
3518 return (char *)streol;
3519}
3520
3521// The InitCryptTable, HashString, DecryptData, and DetectFileKey are
3522// based on the versions in StormLib which were written by Ladislav
3523// Zezula, but may have been modified somewhat by Quantam or ShadowFlare.
3524BOOL InitCryptTable()
3525{
3526 DWORD seed = 0x00100001;
3527 DWORD index1 = 0;
3528 DWORD index2 = 0;
3529 int i;
3530
3531 if (!bCryptTableInit)
3532 {
3533 for(index1 = 0; index1 < 0x100; index1++)
3534 {
3535 for(index2 = index1, i = 0; i < 5; i++, index2 += 0x100)
3536 {
3537 DWORD temp1, temp2;
3538
3539 seed = (seed * 125 + 3) % 0x2AAAAB;
3540 temp1 = (seed & 0xFFFF) << 0x10;
3541
3542 seed = (seed * 125 + 3) % 0x2AAAAB;
3543 temp2 = (seed & 0xFFFF);
3544
3545 dwCryptTable[index2] = (temp1 | temp2);
3546 }
3547 }
3548
3549 bCryptTableInit = TRUE;
3550 }
3551
3552 return TRUE;
3553}
3554
3555DWORD HashString(LPCSTR lpszString, DWORD dwHashType)
3556{
3557 DWORD seed1 = 0x7FED7FED;
3558 DWORD seed2 = 0xEEEEEEEE;
3559 int ch;
3560
3561 char szNull = 0;
3562 if (!lpszString)
3563 lpszString = &szNull;
3564
3565 if (dwHashType==HASH_KEY)
3566 while (strchr(lpszString,'\\')!=NULL) lpszString = strchr(lpszString,'\\')+1;
3567 while (*lpszString != 0)
3568 {
3569 ch = toupper(*lpszString++);
3570
3571 seed1 = dwCryptTable[(dwHashType << 8) + ch] ^ (seed1 + seed2);
3572 seed2 = ch + seed1 + seed2 + (seed2 << 5) + 3;
3573 }
3574
3575 return seed1;
3576}
3577
3578// The EncryptData function is based on the DecryptData function by
3579// Ladislav Zezula, but adapted by Quantam to encrypt rather than decrypt.
3580BOOL EncryptData(LPBYTE lpbyBuffer, DWORD dwLength, DWORD dwKey)
3581{
3582 LPDWORD lpdwBuffer = (LPDWORD)lpbyBuffer;
3583 DWORD seed = 0xEEEEEEEE;
3584 DWORD ch;
3585
3586 if (!lpbyBuffer)
3587 return FALSE;
3588
3589 // Round to DWORDs
3590 dwLength >>= 2;
3591
3592 while(dwLength-- > 0)
3593
3594 {
3595 seed += dwCryptTable[0x400 + (dwKey & 0xFF)];
3596 ch = *lpdwBuffer ^ (dwKey + seed);
3597
3598 dwKey = ((~dwKey << 0x15) + 0x11111111) | (dwKey >> 0x0B);
3599 seed = *lpdwBuffer + seed + (seed << 5) + 3;
3600
3601 *lpdwBuffer++ = ch;
3602 }
3603
3604 return TRUE;
3605}
3606
3607BOOL DecryptData(LPBYTE lpbyBuffer, DWORD dwLength, DWORD dwKey)
3608{
3609 LPDWORD lpdwBuffer = (LPDWORD)lpbyBuffer;
3610 DWORD seed = 0xEEEEEEEE;
3611 DWORD ch;
3612
3613 if (!lpbyBuffer)
3614 return FALSE;
3615
3616 // Round to DWORDs
3617 dwLength >>= 2;
3618
3619 while(dwLength-- > 0)
3620 {
3621 seed += dwCryptTable[0x400 + (dwKey & 0xFF)];
3622 ch = *lpdwBuffer ^ (dwKey + seed);
3623
3624 dwKey = ((~dwKey << 0x15) + 0x11111111) | (dwKey >> 0x0B);
3625 seed = ch + seed + (seed << 5) + 3;
3626
3627 *lpdwBuffer++ = ch;
3628 }
3629
3630 return TRUE;
3631}
3632
3633//-----------------------------------------------------------------------------
3634// Functions tries to get file decryption key. The trick comes from block
3635// positions which are stored at the begin of each compressed file. We know the
3636// file size, that means we know number of blocks that means we know the first
3637// DWORD value in block position. And if we know encrypted and decrypted value,
3638// we can find the decryption key !!!
3639//
3640// hf - MPQ file handle
3641// block - DWORD array of block positions
3642// ch - Decrypted value of the first block pos
3643
3644static DWORD DetectFileSeed(DWORD * block, DWORD decrypted, DWORD blocksize)
3645{
3646 DWORD saveSeed1;
3647 DWORD temp = *block ^ decrypted; // temp = seed1 + seed2
3648 // temp = seed1 + stormBuffer[0x400 + (seed1 & 0xFF)] + 0xEEEEEEEE
3649 temp -= 0xEEEEEEEE; // temp = seed1 + stormBuffer[0x400 + (seed1 & 0xFF)]
3650
3651
3652 for(int i = 0; i < 0x100; i++) // Try all 256 possibilities
3653 {
3654 DWORD seed1;
3655 DWORD seed2 = 0xEEEEEEEE;
3656 DWORD ch;
3657
3658 // Try the first DWORD (We exactly know the value)
3659 seed1 = temp - dwCryptTable[0x400 + i];
3660 seed2 += dwCryptTable[0x400 + (seed1 & 0xFF)];
3661 ch = block[0] ^ (seed1 + seed2);
3662
3663 if(ch != decrypted)
3664 continue;
3665
3666 saveSeed1 = seed1 + 1;
3667
3668 // If OK, continue and test the second value. We don't know exactly the value,
3669 // but we know that the second one has a value less than or equal to the
3670 // size of the block position table plus the block size
3671 seed1 = ((~seed1 << 0x15) + 0x11111111) | (seed1 >> 0x0B);
3672 seed2 = ch + seed2 + (seed2 << 5) + 3;
3673
3674 seed2 += dwCryptTable[0x400 + (seed1 & 0xFF)];
3675 ch = block[1] ^ (seed1 + seed2);
3676
3677 if(ch <= decrypted + blocksize)
3678 return saveSeed1;
3679 }
3680 return 0;
3681}
3682
3683DWORD DetectFileSeedEx(MPQARCHIVE * mpqOpenArc, HASHTABLEENTRY * lpHashEntry, LPCSTR * lplpFileName)
3684{
3685 if (mpqOpenArc==0 || lpHashEntry==0) return 0;
3686 DWORD dwCryptKey=0;
3687 LPCSTR lpFileName = *lplpFileName;
3688 DWORD dwBlockIndex = lpHashEntry->dwBlockTableIndex;
3689 if (lpFileName)
3690 {
3691 dwCryptKey = HashString(lpFileName,HASH_KEY);
3692 if (mpqOpenArc->lpBlockTable[dwBlockIndex].dwFlags&MAFA_MODCRYPTKEY)
3693 dwCryptKey = (dwCryptKey + mpqOpenArc->lpBlockTable[dwBlockIndex].dwFileOffset) ^ mpqOpenArc->lpBlockTable[dwBlockIndex].dwFullSize;
3694 }
3695 else
3696 {
3697 DWORD dwNameHashA = HashString(INTERNAL_LISTFILE,HASH_NAME_A);
3698 DWORD dwNameHashB = HashString(INTERNAL_LISTFILE,HASH_NAME_B);
3699 if (lpHashEntry->dwNameHashA==dwNameHashA && lpHashEntry->dwNameHashB==dwNameHashB) {
3700 dwCryptKey = HashString(INTERNAL_LISTFILE,HASH_KEY);
3701 if (mpqOpenArc->lpBlockTable[dwBlockIndex].dwFlags&MAFA_MODCRYPTKEY)
3702 dwCryptKey = (dwCryptKey + mpqOpenArc->lpBlockTable[dwBlockIndex].dwFileOffset) ^ mpqOpenArc->lpBlockTable[dwBlockIndex].dwFullSize;
3703 *lplpFileName = (char *)SFAlloc(strlen(INTERNAL_LISTFILE)+1);
3704 if (*lplpFileName)
3705 strcpy((LPSTR)*lplpFileName,INTERNAL_LISTFILE);
3706 }
3707 else {
3708 HANDLE hlFile,hMPQ=(HANDLE)mpqOpenArc;
3709 DWORD fsz;
3710 char *listbuffer;
3711 LCID lcOldLocale = LocaleID;
3712 for (DWORD lcn=0;lcn<nLocales;lcn++) {
3713 LocaleID = availLocales[lcn];
3714 if (SFileOpenFileEx(hMPQ,INTERNAL_LISTFILE,0,&hlFile)!=0) {
3715 if (((MPQFILE *)hlFile)->lpHashEntry->lcLocale==0 && LocaleID!=0) {
3716 SFileCloseFile(hlFile);
3717 continue;
3718 }
3719 fsz = SFileGetFileSize(hlFile,0);
3720 if (fsz>0) {
3721 listbuffer = (char *)SFAlloc(fsz+1);
3722 if (listbuffer==0) {
3723 SFileCloseFile(hlFile);
3724 continue;
3725 }
3726 if (SFileReadFile(hlFile,listbuffer,fsz,0,0)==0) {
3727 SFFree(listbuffer);
3728 listbuffer = 0;
3729 }
3730 }
3731 SFileCloseFile(hlFile);
3732 if (listbuffer!=0) {
3733 char *listline;
3734 for (listline=listbuffer;listline!=0;listline=nextline(listline)) {
3735 if (listline[0]==0) break;
3736 DWORD lnlen=strlnlen(listline);
3737 char prevchar=listline[lnlen];
3738 listline[lnlen]=0;
3739 dwNameHashA = HashString(listline,HASH_NAME_A);
3740 dwNameHashB = HashString(listline,HASH_NAME_B);
3741 if (lpHashEntry->dwNameHashA==dwNameHashA && lpHashEntry->dwNameHashB==dwNameHashB) {
3742 dwCryptKey = HashString(listline,HASH_KEY);
3743 if (mpqOpenArc->lpBlockTable[dwBlockIndex].dwFlags&MAFA_MODCRYPTKEY)
3744 dwCryptKey = (dwCryptKey + mpqOpenArc->lpBlockTable[dwBlockIndex].dwFileOffset) ^ mpqOpenArc->lpBlockTable[dwBlockIndex].dwFullSize;
3745 *lplpFileName = (char *)SFAlloc(strlen(listline)+1);
3746 if (*lplpFileName)
3747 strcpy((LPSTR)*lplpFileName,listline);
3748 break;
3749 }
3750 listline[lnlen]=prevchar;
3751 }
3752 if (listline!=0) {
3753 if (listline[0]!=0) {
3754 SFFree(listbuffer);
3755 break;
3756 }
3757 }
3758 SFFree(listbuffer);
3759 }
3760 }
3761 }
3762 LocaleID = lcOldLocale;
3763 }
3764 if (dwCryptKey==0 && (mpqOpenArc->lpBlockTable[dwBlockIndex].dwFlags&MAFA_COMPRESS || mpqOpenArc->lpBlockTable[dwBlockIndex].dwFlags&MAFA_COMPRESS2))
3765 {
3766 DWORD HeaderLength=0,tsz;
3767 if (memcmp(&mpqOpenArc->MpqHeader.dwMPQID,ID_BN3,4)==0)
3768 {
3769 SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->lpBlockTable[dwBlockIndex].dwFileOffset,0,FILE_BEGIN);
3770 ReadFile(mpqOpenArc->hFile,&HeaderLength,4,&tsz,0);
3771 }
3772 DWORD blockSize = 512 << mpqOpenArc->MpqHeader.wBlockSize;
3773 DWORD TotalBlocks = mpqOpenArc->lpBlockTable[dwBlockIndex].dwFullSize / blockSize;
3774 if(mpqOpenArc->lpBlockTable[dwBlockIndex].dwFullSize % blockSize)
3775 TotalBlocks++;
3776 DWORD *dwBlockPtrTable = (DWORD *)SFAlloc((TotalBlocks+1)*4);
3777 if (dwBlockPtrTable==0)
3778 return 0;
3779 SetFilePointer(mpqOpenArc->hFile,mpqOpenArc->dwMPQStart+mpqOpenArc->lpBlockTable[dwBlockIndex].dwFileOffset+HeaderLength,0,FILE_BEGIN);
3780 ReadFile(mpqOpenArc->hFile,dwBlockPtrTable,(TotalBlocks+1)*4,&tsz,0);
3781 dwCryptKey = DetectFileSeed(dwBlockPtrTable,(TotalBlocks+1)*4,blockSize);
3782
3783 SFFree(dwBlockPtrTable);
3784 }
3785 }
3786 return dwCryptKey;
3787}
3788
3789long SFMPQAPI __inline SFMpqCompareVersion()
3790{
3791 SFMPQVERSION ExeVersion = SFMPQ_CURRENT_VERSION;
3792 SFMPQVERSION DllVersion = SFMpqGetVersion();
3793 if (DllVersion.Major>ExeVersion.Major) return 1;
3794 else if (DllVersion.Major<ExeVersion.Major) return -1;
3795 if (DllVersion.Minor>ExeVersion.Minor) return 1;
3796 else if (DllVersion.Minor<ExeVersion.Minor) return -1;
3797 if (DllVersion.Revision>ExeVersion.Revision) return 1;
3798 else if (DllVersion.Revision<ExeVersion.Revision) return -1;
3799 if (DllVersion.Subrevision>ExeVersion.Subrevision) return 1;
3800 else if (DllVersion.Subrevision<ExeVersion.Subrevision) return -1;
3801 return 0;
3802}
3803
3804void LoadStorm()
3805{
3806#ifdef _WIN32
3807 if (hStorm!=0) return;
3808 hStorm = LoadLibrary(Storm_dll);
3809 /*if (hStorm==0) {
3810 HKEY hKey;
3811 LPSTR lpDllPath;
3812 DWORD dwStrLen;
3813 if (RegOpenKeyEx(HKEY_CURRENT_USER,"Software\\Blizzard Entertainment\\Warcraft III",0,KEY_QUERY_VALUE,&hKey)!=ERROR_SUCCESS)
3814 if (RegOpenKeyEx(HKEY_USERS,".Default\\Software\\Blizzard Entertainment\\Warcraft III",0,KEY_QUERY_VALUE,&hKey)!=ERROR_SUCCESS)
3815 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,"Software\\Blizzard Entertainment\\Warcraft III",0,KEY_QUERY_VALUE,&hKey)!=ERROR_SUCCESS)
3816 return;
3817 RegQueryValueEx(hKey,"InstallPath",0,0,0,&dwStrLen);
3818 lpDllPath = (LPSTR)SFAlloc(dwStrLen+11);
3819 if (lpDllPath) {
3820 memset(lpDllPath,0,dwStrLen+11);
3821 RegQueryValueEx(hKey,"InstallPath",0,0,(LPBYTE)lpDllPath,&dwStrLen);
3822 LPSTR lpLastBSlash = strrchr(lpDllPath,'\\');
3823 if (lpLastBSlash) {
3824 if (lpLastBSlash[1]!=0) lpLastBSlash[strlen(lpLastBSlash)]='\\';
3825 strcat(lpLastBSlash,Storm_dll);
3826 hStorm = LoadLibrary(lpDllPath);
3827 }
3828 SFFree(lpDllPath);
3829 }
3830 RegCloseKey(hKey);
3831 }*/
3832 if (hStorm==0) return;
3833
3834 unsigned int wSCCOrdinal=0xAC30;
3835 wSCCOrdinal>>=4;
3836 wSCCOrdinal/=5;
3837 unsigned int wSCDcOrdinal=0xAC80;
3838 wSCDcOrdinal>>=4;
3839 wSCDcOrdinal/=5;
3840
3841 stormSCompCompress = (funcSCompCompress)GetProcAddress(hStorm,(LPCSTR)wSCCOrdinal);
3842 stormSCompDecompress = (funcSCompDecompress)GetProcAddress(hStorm,(LPCSTR)wSCDcOrdinal);
3843#endif
3844}
3845
3846void FreeStorm()
3847{
3848#ifdef _WIN32
3849 if (hStorm==0) return;
3850 FreeLibrary(hStorm);
3851 hStorm = 0;
3852
3853 stormSCompCompress = 0;
3854 stormSCompDecompress = 0;
3855#endif
3856}
3857