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