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