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