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




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