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