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