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