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