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