pakstuff.cpp (24419B)
1 /* 2 =========================================================================== 3 Copyright (C) 1999-2005 Id Software, Inc. 4 5 This file is part of Quake III Arena source code. 6 7 Quake III Arena source code is free software; you can redistribute it 8 and/or modify it under the terms of the GNU General Public License as 9 published by the Free Software Foundation; either version 2 of the License, 10 or (at your option) any later version. 11 12 Quake III Arena source code is distributed in the hope that it will be 13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with Foobar; if not, write to the Free Software 19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 =========================================================================== 21 */ 22 23 #include <stdio.h> 24 #include <stdarg.h> 25 #include <stdlib.h> 26 #include <string.h> 27 #include <windows.h> 28 #include "io.h" 29 #include "pakstuff.h" 30 #include "unzip.h" 31 //#include "cmdlib.h" 32 #include "str.h" 33 34 int m_nPAKIndex; 35 FILE* pakfile[16]; 36 struct PACKDirectory pakdir; 37 PACKDirPtr pakdirptr = &pakdir; 38 UInt16 dirsize; 39 boolean pakopen = false; 40 int f_type; 41 DIRECTORY *paktextures = NULL; 42 boolean HavePakColormap; 43 UInt32 PakColormapOffset; 44 UInt32 PakColormapSize; 45 DIRECTORY *dirhead = NULL; 46 boolean g_bPK3 = false; 47 char g_strBasePath[1024]; 48 49 struct PK3FileInfo 50 { 51 unzFile m_zFile; 52 char *m_pName; 53 unz_s m_zInfo; 54 long m_lSize; 55 ~PK3FileInfo() 56 { 57 delete []m_pName; 58 } 59 bool operator ==(const PK3FileInfo& rhs) const { return strcmp(m_pName, rhs.m_pName) == 0; } 60 }; 61 62 #define __PATHSEPERATOR '/' 63 64 #define LOG_PAKFAIL 65 66 #ifdef LOG_PAKFAIL 67 68 class LogFile 69 { 70 public: 71 FILE *m_pFile; 72 LogFile(const char* pName) 73 { 74 m_pFile = fopen(pName, "w"); 75 } 76 ~LogFile() 77 { 78 if (m_pFile) 79 { 80 fclose(m_pFile); 81 } 82 } 83 void Log(const char *pFormat, ...) 84 { 85 va_list arg_ptr; 86 va_start(arg_ptr, pFormat); 87 fprintf(m_pFile, pFormat, arg_ptr); 88 va_end(arg_ptr); 89 } 90 }; 91 92 LogFile g_LogFile("c:\\paklog.txt"); 93 #endif 94 95 template <class T> class StrPtr : public Str 96 { 97 protected: 98 T* m_pPtr; 99 StrPtr() 100 { 101 m_pPtr = NULL; 102 } 103 104 StrPtr(const char *pStr, T *p) : Str(pStr) 105 { 106 m_pPtr = p; 107 } 108 109 T* Ptr() 110 { 111 return m_pPtr; 112 } 113 114 T& Ref() 115 { 116 return *m_pPtr; 117 } 118 119 120 }; 121 // PtrList 122 // a list of ptrs 123 // 124 template <class T> class PtrList 125 { 126 protected: 127 T *m_pPtr; 128 PtrList *m_pNext; 129 130 public: 131 132 PtrList() 133 { 134 m_pNext = NULL; 135 m_pPtr = NULL; 136 } 137 138 PtrList(T *ip) 139 { 140 m_pNext = NULL; 141 m_pPtr = ip; 142 } 143 144 ~PtrList() 145 { 146 delete m_pPtr; 147 } 148 149 PtrList* Next() 150 { 151 return m_pNext; 152 } 153 154 void Add(T *ip) 155 { 156 PtrList *pl = this; 157 while (pl && pl->m_pNext) 158 { 159 pl = pl->Next(); 160 } 161 pl->m_pNext = new PtrList(ip); 162 } 163 164 void Remove() 165 { 166 PtrList *p = m_pNext; 167 if (p) 168 { 169 while (p->m_pNext != this && p->m_pNext != NULL) 170 { 171 p = p->m_pNext; 172 } 173 if (p->m_pNext == this) 174 { 175 p->m_pNext = m_pNext; 176 } 177 } 178 } 179 180 virtual PtrList* Find(T *ip) 181 { 182 PtrList *p = m_pNext; 183 while (p) 184 { 185 if (*p->m_pPtr == *ip) 186 { 187 return p; 188 } 189 p = p->m_pNext; 190 } 191 return NULL; 192 } 193 194 // remove vp from the list 195 void Remove(T *ip) 196 { 197 PtrList *p = Find(ip); 198 if (p) 199 { 200 p->Remove(); 201 } 202 } 203 204 T* Ptr() 205 { 206 return m_pPtr; 207 } 208 209 T& Ref() 210 { 211 return *m_pPtr; 212 } 213 214 void RemoveAll() 215 { 216 PtrList *p = m_pNext; 217 while (p) 218 { 219 PtrList *p2 = p; 220 p = p->m_pNext; 221 delete p2; 222 } 223 } 224 }; 225 226 227 typedef PtrList<unzFile> ZFileList; 228 typedef PtrList<Str> StrList; 229 typedef PtrList<PK3FileInfo> PK3List; 230 231 232 StrList g_PK3TexturePaths; 233 PK3List g_PK3Files; 234 ZFileList g_zFiles; 235 #define WORK_LEN 1024 236 #define TEXTURE_PATH "textures" 237 #define PATH_SEPERATORS "/\\:\0" 238 239 240 char* __StrDup(char* pStr) 241 { 242 if (pStr) 243 { 244 return strcpy(new char[strlen(pStr)+1], pStr); 245 } 246 return NULL; 247 } 248 249 char* __StrDup(const char* pStr) 250 { 251 if (pStr) 252 { 253 return strcpy(new char[strlen(pStr)+1], pStr); 254 } 255 return NULL; 256 } 257 258 #define MEM_BLOCKSIZE 4096 259 void* __qblockmalloc(size_t nSize) 260 { 261 void *b; 262 // round up to threshold 263 int nAllocSize = nSize % MEM_BLOCKSIZE; 264 if ( nAllocSize > 0) 265 { 266 nSize += MEM_BLOCKSIZE - nAllocSize; 267 } 268 b = malloc(nSize + 1); 269 memset (b, 0, nSize); 270 return b; 271 } 272 273 void* __qmalloc (size_t nSize) 274 { 275 void *b; 276 b = malloc(nSize + 1); 277 memset (b, 0, nSize); 278 return b; 279 } 280 281 282 /* 283 ==================== 284 Extract file parts 285 ==================== 286 */ 287 void __ExtractFilePath (const char *path, char *dest) 288 { 289 const char *src; 290 291 src = path + strlen(path) - 1; 292 293 // 294 // back up until a \ or the start 295 // 296 while (src != path && *(src-1) != __PATHSEPERATOR) 297 src--; 298 299 memcpy (dest, path, src-path); 300 dest[src-path] = 0; 301 } 302 303 void __ExtractFileName (const char *path, char *dest) 304 { 305 const char *src; 306 307 src = path + strlen(path) - 1; 308 309 // 310 // back up until a \ or the start 311 // 312 while (src != path && *(src-1) != '/' 313 && *(src-1) != '\\' ) 314 src--; 315 316 while (*src) 317 { 318 *dest++ = *src++; 319 } 320 *dest = 0; 321 } 322 323 void __ExtractFileBase (const char *path, char *dest) 324 { 325 const char *src; 326 327 src = path + strlen(path) - 1; 328 329 // 330 // back up until a \ or the start 331 // 332 while (src != path && *(src-1) != '/' 333 && *(src-1) != '\\' ) 334 src--; 335 336 while (*src && *src != '.') 337 { 338 *dest++ = *src++; 339 } 340 *dest = 0; 341 } 342 343 void __ExtractFileExtension (const char *path, char *dest) 344 { 345 const char *src; 346 347 src = path + strlen(path) - 1; 348 349 // 350 // back up until a . or the start 351 // 352 while (src != path && *(src-1) != '.') 353 src--; 354 if (src == path) 355 { 356 *dest = 0; // no extension 357 return; 358 } 359 360 strcpy (dest,src); 361 } 362 363 364 void __ConvertDOSToUnixName( char *dst, const char *src ) 365 { 366 while ( *src ) 367 { 368 if ( *src == '\\' ) 369 *dst = '/'; 370 else 371 *dst = *src; 372 dst++; src++; 373 } 374 *dst = 0; 375 } 376 377 378 379 380 381 void AddSlash(Str& str) 382 { 383 int nLen = str.GetLength(); 384 if (nLen > 0) 385 { 386 if (str[nLen-1] != '\\' && str[nLen-1] != '/') 387 str += '\\'; 388 } 389 } 390 391 void FindReplace(Str& strContents, const char* pTag, const char* pValue) 392 { 393 if (strcmp(pTag, pValue) == 0) 394 return; 395 for (int nPos = strContents.Find(pTag); nPos >= 0; nPos = strContents.Find(pTag)) 396 { 397 int nRightLen = strContents.GetLength() - strlen(pTag) - nPos; 398 Str strLeft(strContents.Left(nPos)); 399 Str strRight(strContents.Right(nRightLen)); 400 strLeft += pValue; 401 strLeft += strRight; 402 strContents = strLeft; 403 } 404 } 405 406 407 408 409 410 void ProgError(char *errstr, ...) 411 { 412 va_list args; 413 414 va_start(args, errstr); 415 printf("\nProgram Error: *** "); 416 vprintf(errstr, args); 417 printf(" ***\n"); 418 va_end(args); 419 exit(5); 420 } 421 422 boolean ReadBytes(FILE *file, void *addr, UInt32 size) 423 { 424 while (size > 0x8000) 425 { 426 if (fread(addr, 1, 0x8000, file) != 0x8000) 427 return false; 428 addr = (char *)addr + 0x8000; 429 size -= 0x8000; 430 } 431 if (fread(addr, 1, size, file) != size) 432 return false; 433 return true; 434 } 435 int ReadMagic(FILE *file) 436 { 437 UInt8 buf[4]; 438 439 if (ReadBytes(file, buf, 4) == FALSE) 440 return FTYPE_ERROR; 441 if (!strncmp(reinterpret_cast<const char*>(&buf[0]), "IWAD", 4)) 442 return FTYPE_IWAD; 443 if (!strncmp(reinterpret_cast<const char*>(&buf[0]), "PWAD", 4)) 444 return FTYPE_PWAD; 445 if (!strncmp(reinterpret_cast<const char*>(&buf[0]), "PACK", 4)) 446 return FTYPE_PACK; 447 if (!strncmp(reinterpret_cast<const char*>(&buf[0]), "WAD2", 4)) 448 return FTYPE_WAD2; 449 if (buf[0] == 0x17 && buf[1] == 0 && buf[2] == 0 && buf[3] == 0) 450 return FTYPE_BSP; 451 if (!strncmp(reinterpret_cast<const char*>(&buf[0]), "IDPO", 4)) 452 return FTYPE_MODEL; 453 if (!strncmp(reinterpret_cast<const char*>(&buf[0]), "IDSP", 4)) 454 return FTYPE_SPRITE; 455 if (!strncmp(reinterpret_cast<const char*>(&buf[0]), "RIFF", 4)) 456 return FTYPE_WAV; 457 if (!strncmp(reinterpret_cast<const char*>(&buf[0]), ".snd", 4)) 458 return FTYPE_AU; 459 if (buf[0] == 'P') 460 { 461 if (buf[1] == '1') 462 return FTYPE_PBM_ASC; 463 if (buf[1] == '2') 464 return FTYPE_PGM_ASC; 465 if (buf[1] == '3') 466 return FTYPE_PPM_ASC; 467 if (buf[1] == '4') 468 return FTYPE_PBM_RAW; 469 if (buf[1] == '5') 470 return FTYPE_PGM_RAW; 471 if (buf[1] == '6') 472 return FTYPE_PPM_RAW; 473 } 474 if (buf[0] == 'B' && buf[1] == 'M') 475 return FTYPE_BMP; 476 if (!strncmp(reinterpret_cast<const char*>(&buf[0]), "GIF8", 4)) 477 return FTYPE_GIF; 478 if (buf[0] == 0x0a && buf[1] == 0x05 && buf[2] == 0x01 && buf[3] == 0x08) 479 return FTYPE_PCX; 480 return FTYPE_UNKNOWN; 481 } 482 FILE *OpenFileReadMagic(const char *filename, int *ftype_r) 483 { 484 FILE *f; 485 486 *ftype_r = FTYPE_ERROR; 487 if ((f = fopen(filename, "rb")) == NULL) 488 return NULL; 489 *ftype_r = ReadMagic(f); 490 if (*ftype_r == FTYPE_ERROR) 491 { 492 fclose(f); 493 return NULL; 494 } 495 return f; 496 } 497 boolean WriteBytes(FILE *file, void *addr, UInt32 size) 498 { 499 while (size > 0x8000) 500 { 501 if (fwrite(addr, 1, 0x8000, file) != 0x8000) 502 return FALSE; 503 addr = (char *)addr + 0x8000; 504 size -= 0x8000; 505 } 506 if (fwrite(addr, 1, size, file) != size) 507 return FALSE; 508 return TRUE; 509 } 510 char *ConvertFilePath(char *filename) 511 { 512 char *cp; 513 514 if (filename == NULL) 515 ProgError("BUG: cannot convert a NULL pathname"); 516 for (cp = filename; *cp; cp++) 517 if (*cp == '/' || *cp == '\\') 518 { 519 #ifdef QEU_DOS 520 *cp = '\\'; 521 #else 522 *cp = '/'; 523 #endif 524 } 525 return filename; 526 } 527 528 /* 529 * Read the PACK directory into memory. The optional offset to the 530 * start of the PACK file is given in "offset". The number of files in 531 * the directory is returned in *dirsize_r. 532 */ 533 PACKDirPtr ReadPACKDirectory(FILE *packfile, UInt32 offset, UInt16 *dirsize_r) 534 { 535 PACKDirPtr dir; 536 UInt32 pos, size; 537 UInt16 max, i; 538 539 *dirsize_r = 0; 540 if (packfile == NULL) 541 return NULL; 542 if ((fseek(packfile, offset, SEEK_SET) < 0) 543 || (ReadMagic(packfile) != FTYPE_PACK) 544 || (ReadInt32(packfile, &pos) == FALSE) 545 || (ReadInt32(packfile, &size) == FALSE) 546 || (size == 0L) 547 || (size / sizeof(struct PACKDirectory) > 65535L) 548 || (fseek(packfile, offset + pos, SEEK_SET) < 0)) 549 return NULL; 550 dir = (PACKDirPtr)__qmalloc(size); 551 max = (UInt16)(size / sizeof(struct PACKDirectory)); 552 for (i = 0; i < max; i++) 553 { 554 if (ReadBytes(packfile, &dir[i], sizeof(struct PACKDirectory)) == FALSE) 555 { 556 free(dir); 557 return NULL; 558 } 559 ConvertFilePath(dir[i].name); 560 dir[i].offset = SwapInt32(dir[i].offset); 561 dir[i].size = SwapInt32(dir[i].size); 562 } 563 *dirsize_r = max; 564 return dir; 565 } 566 567 /* 568 * Print the contents of the PACK directory in "outf". 569 */ 570 void DumpPACKDirectory(FILE *outf, PACKDirPtr dir, UInt16 dirsize) 571 { 572 UInt16 i; 573 UInt32 sum; 574 char buf[57]; 575 576 if (outf == NULL || dir == NULL || dirsize == 0) 577 return; 578 fprintf(outf, "num offset size file name\n"); 579 fprintf(outf, " (hex) (dec)\n"); 580 sum = 0L; 581 for (i = 0; i < dirsize; i++) 582 { 583 if(!strnicmp(dir[i].name, "textures", 8)) 584 { 585 strncpy(buf, dir[i].name, 56); 586 buf[56] = '\0'; 587 fprintf(outf, "%3u 0x%08lx %6ld %s\n", 588 i, dir[i].offset, dir[i].size, buf); 589 sum += dir[i].size; 590 } 591 } 592 fprintf(outf, "\nTotal size for %3u entries: %7lu bytes.\n", dirsize, sum); 593 fprintf(outf, "Size of the PACK directory: %7lu bytes.\n", 594 (UInt32)dirsize * (UInt32)sizeof(struct PACKDirectory)); 595 fprintf(outf, "Total (header + data + dir): %7lu bytes.\n", 596 12L + sum + (UInt32)dirsize * (UInt32)sizeof(struct PACKDirectory)); 597 } 598 599 void ClearFileList(FILELIST **list) 600 { 601 FILELIST *temp; 602 603 while(*list) 604 { 605 temp = *list; 606 *list = (*list)->next; 607 free(temp); 608 } 609 } 610 611 void ClearDirList(DIRLIST **list) 612 { 613 DIRLIST *temp; 614 615 while(*list) 616 { 617 temp = *list; 618 *list = (*list)->next; 619 free(temp); 620 } 621 } 622 623 DIRECTORY *FindPakDir(DIRECTORY *dir, char *name) 624 { 625 DIRECTORY *currentPtr; 626 627 for(currentPtr = dir; currentPtr; currentPtr = currentPtr->next) 628 { 629 if(!stricmp(name, currentPtr->name)) 630 { 631 return currentPtr; 632 } 633 } 634 return NULL; 635 } 636 637 638 // LoadPK3FileList 639 // --------------- 640 // 641 // This gets passed a file mask which we want to remove as 642 // we are only interested in the directory name and any given 643 // extension. Only handles explicit filenames or *.something 644 // 645 boolean LoadPK3FileList(FILELIST **filelist, const char *pattern) 646 { 647 char cSearch[WORK_LEN]; 648 __ConvertDOSToUnixName( cSearch, pattern ); 649 char cPath[WORK_LEN]; 650 char cExt[WORK_LEN]; 651 char cFile[WORK_LEN]; 652 char cWork[WORK_LEN]; 653 __ExtractFilePath(pattern, cPath); 654 __ExtractFileName(pattern, cFile); 655 __ExtractFileExtension(pattern, cExt); 656 const char *pCompare = (strnicmp(cFile, "*.", 2) == 0) ? cExt : cFile; 657 strcpy(cWork, cPath); 658 sprintf(cPath, "textures/%s", cWork); 659 660 PK3List *p = g_PK3Files.Next(); 661 while (p != NULL) 662 { 663 // qualify the path 664 PK3FileInfo *pKey = p->Ptr(); 665 if (strstr(pKey->m_pName, cPath) && strstr(pKey->m_pName, pCompare)) 666 { 667 __ExtractFileName(pKey->m_pName, cWork); 668 AddToFileListAlphabetized(filelist, cWork, 0, 0, false); 669 } 670 p = p->Next(); 671 } 672 return (*filelist) != NULL; 673 } 674 675 boolean GetPackFileList(FILELIST **filelist, char *pattern) 676 { 677 char *str1, *str2; 678 int i; 679 DIRECTORY *dummy = paktextures; 680 FILELIST *temp; 681 682 if (!pakopen) 683 return false; 684 685 if (g_bPK3) 686 { 687 return LoadPK3FileList(filelist, pattern); 688 } 689 690 str1 = pattern; 691 692 for(i = 0; pattern[i] != '\0'; i++) 693 { 694 if(pattern[i] == '\\') 695 pattern[i] = '/'; 696 } 697 698 while(strchr(str1, '/')) 699 { 700 str2 = strchr(str1, '/'); 701 *str2++ = '\0'; 702 dummy = FindPakDir(dummy, str1); 703 if(!dummy) 704 return false; 705 str1 = str2; 706 } 707 for(temp = dummy->files; temp; temp=temp->next) 708 { 709 AddToFileListAlphabetized(filelist, temp->filename, temp->offset, 0, false); 710 } 711 return true; 712 } 713 714 boolean GetPackTextureDirs(DIRLIST **dirlist) 715 { 716 UInt16 i; 717 char buf[57]; 718 719 if (!pakopen) 720 return 1; 721 722 if (g_bPK3) 723 { 724 StrList *pl = g_PK3TexturePaths.Next(); 725 while (pl != NULL) 726 { 727 AddToDirListAlphabetized(dirlist, pl->Ref(), 0); 728 pl = pl->Next(); 729 } 730 return true; 731 } 732 733 for (i = 0; i < dirsize; i++) 734 { 735 if(!strnicmp(pakdirptr[i].name, "textures", 8)) 736 { 737 strncpy(buf, &(pakdirptr[i].name[9]), 46); 738 if(strchr(buf, '\\')) 739 *strchr(buf, '\\') = '\0'; 740 else if(strchr(buf, '/')) 741 *strchr(buf, '/') = '\0'; 742 else 743 buf[56] = '\0'; 744 745 if(strchr(buf, '.')) 746 continue; 747 748 AddToDirListAlphabetized(dirlist, buf, 0); 749 } 750 } 751 return true; 752 } 753 754 boolean AddToDirListAlphabetized(DIRLIST **list, char *dirname, int from) 755 { 756 DIRLIST *currentPtr, *previousPtr, *newPtr; 757 758 strlwr(dirname); 759 for(currentPtr = *list; currentPtr; currentPtr = currentPtr->next) 760 { 761 if(!stricmp(dirname, currentPtr->dirname)) 762 { 763 return false; 764 } 765 } 766 previousPtr = NULL; 767 currentPtr = *list; 768 769 if((newPtr = (DIRLIST *)__qmalloc(sizeof(DIRLIST))) == NULL) 770 return false; 771 772 strcpy(newPtr->dirname, dirname); 773 newPtr->from = from; 774 775 while(currentPtr != NULL && stricmp(dirname, currentPtr->dirname) > 0) 776 { 777 previousPtr = currentPtr; 778 currentPtr = currentPtr->next; 779 } //End while 780 if(previousPtr == NULL) 781 { 782 newPtr->next = *list; 783 *list = newPtr; 784 } //End if 785 else 786 { 787 previousPtr->next = newPtr; 788 newPtr->next = currentPtr; 789 } //End else 790 return true; 791 } 792 793 boolean AddToFileListAlphabetized(FILELIST **list, char *filename, UInt32 offset, UInt32 size, boolean dirs) 794 { 795 FILELIST *currentPtr, *previousPtr, *newPtr; 796 797 for(currentPtr = *list; currentPtr; currentPtr = currentPtr->next) 798 { 799 if(!stricmp(filename, currentPtr->filename)) 800 { 801 return false; 802 } 803 } 804 previousPtr = NULL; 805 currentPtr = *list; 806 807 if((newPtr = (FILELIST *)__qmalloc(sizeof(FILELIST))) == NULL) 808 return false; 809 810 strcpy(newPtr->filename, filename); 811 newPtr->offset = offset; 812 newPtr->size = size; 813 814 while(currentPtr != NULL && stricmp(filename, currentPtr->filename) > 0) 815 { 816 previousPtr = currentPtr; 817 currentPtr = currentPtr->next; 818 } //End while 819 if(previousPtr == NULL) 820 { 821 newPtr->next = *list; 822 *list = newPtr; 823 } //End if 824 else 825 { 826 previousPtr->next = newPtr; 827 newPtr->next = currentPtr; 828 } //End else 829 return true; 830 } 831 832 boolean PakLoadFile(const char *filename, void **bufferptr) 833 { 834 FILELIST *p = NULL; 835 DIRECTORY *dummy; 836 void *buffer; 837 char *str1, *str2; 838 839 if(!pakopen) 840 return false; 841 842 Str str(filename); 843 __ConvertDOSToUnixName(str, str); 844 845 dummy = paktextures; 846 str1 = str; 847 848 while(strchr(str1, '/')) 849 { 850 str2 = strchr(str1, '/'); 851 *str2++ = '\0'; 852 dummy = FindPakDir(dummy, str1); 853 if(!dummy) 854 return false; 855 str1 = str2; 856 } 857 858 // FIXME: add error handling routines 859 for(p = dummy->files; p; p = p->next) 860 { 861 if(!stricmp(str1, p->filename)) 862 { 863 if (fseek(pakfile[m_nPAKIndex], p->offset, SEEK_SET) < 0) 864 { 865 //Sys_Printf("Unexpected EOF in pakfile\n"); 866 return false; 867 } 868 if((buffer = __qmalloc(p->size+5)) == NULL) 869 //Error("Could not allocate memory"); 870 871 if(fread(buffer, 1, p->size, pakfile[m_nPAKIndex]) != p->size) 872 { 873 //Sys_Printf("Error reading %s from pak\n", str1); 874 free(buffer); 875 return false; 876 } 877 *bufferptr = buffer; 878 return true; 879 } 880 } 881 return false; 882 } 883 884 int PakLoadAnyFile(const char *filename, void **bufferptr) 885 { 886 char cWork[WORK_LEN]; 887 if (g_bPK3) 888 { 889 PK3FileInfo *pInfo; 890 Str strKey; 891 // need to lookup the file without the base/texture path on it 892 Str strBase(g_strBasePath); 893 AddSlash(strBase); 894 __ConvertDOSToUnixName(cWork, strBase); 895 Str strFile(filename); 896 __ConvertDOSToUnixName(strFile, strFile); 897 strFile.MakeLower(); 898 strlwr(cWork); 899 FindReplace(strFile, cWork, ""); 900 901 PK3FileInfo infoFind; 902 infoFind.m_pName = __StrDup(strFile.GetBuffer()); 903 PK3List *pList = g_PK3Files.Find(&infoFind); 904 if (pList) 905 { 906 pInfo = pList->Ptr(); 907 memcpy(pInfo->m_zFile, &pInfo->m_zInfo, sizeof(unz_s)); 908 if (unzOpenCurrentFile(pInfo->m_zFile) == UNZ_OK) 909 { 910 void *buffer = __qblockmalloc(pInfo->m_lSize+1); 911 int n = unzReadCurrentFile(pInfo->m_zFile , buffer, pInfo->m_lSize); 912 *bufferptr = buffer; 913 unzCloseCurrentFile(pInfo->m_zFile); 914 return n; 915 } 916 } 917 #ifdef LOG_PAKFAIL 918 sprintf(cWork, "PAK failed on %s\n", filename); 919 g_LogFile.Log(cWork); 920 #endif 921 return -1; 922 } 923 924 for (int i = 0; i < dirsize; i++) 925 { 926 if(!stricmp(filename, pakdirptr[i].name)) 927 { 928 if (fseek(pakfile[m_nPAKIndex], pakdirptr[i].offset, SEEK_SET) >= 0) 929 { 930 void *buffer = __qmalloc (pakdirptr[i].size+1); 931 ((char *)buffer)[pakdirptr[i].size] = 0; 932 if (fread(buffer, 1, pakdirptr[i].size, pakfile[m_nPAKIndex]) == pakdirptr[i].size) 933 { 934 *bufferptr = buffer; 935 return pakdirptr[i].size; 936 } 937 } 938 } 939 } 940 #ifdef LOG_PAKFAIL 941 sprintf(cWork, "PAK failed on %s\n", filename); 942 g_LogFile.Log(cWork); 943 #endif 944 return -1; 945 } 946 947 948 949 DIRECTORY *AddPakDir(DIRECTORY **dir, char *name) 950 { 951 DIRECTORY *currentPtr, *previousPtr, *newPtr; 952 953 for(currentPtr = *dir; currentPtr; currentPtr = currentPtr->next) 954 { 955 if(!stricmp(name, currentPtr->name)) 956 { 957 return currentPtr; 958 } 959 } 960 previousPtr = NULL; 961 currentPtr = *dir; 962 963 if((newPtr = (DIRECTORY *)__qmalloc(sizeof(DIRECTORY))) == NULL) 964 return NULL; 965 966 strcpy(newPtr->name, name); 967 newPtr->files = NULL; 968 969 while(currentPtr != NULL && stricmp(name, currentPtr->name) > 0) 970 { 971 previousPtr = currentPtr; 972 currentPtr = currentPtr->next; 973 } 974 if(previousPtr == NULL) 975 { 976 newPtr->next = *dir; 977 *dir = newPtr; 978 } 979 else 980 { 981 previousPtr->next = newPtr; 982 newPtr->next = currentPtr; 983 } 984 return newPtr; 985 } 986 987 988 // OpenPK3 989 // ------- 990 // Opens a PK3 ( or zip ) file and creates a list of filenames 991 // and zip info structures 992 // 993 boolean OpenPK3(const char *filename) 994 { 995 char cFilename[WORK_LEN]; 996 char cName[WORK_LEN]; 997 char cWork[WORK_LEN]; 998 unz_file_info zInfo; 999 unzFile *zFile = new unzFile(unzOpen(filename)); 1000 g_zFiles.Add(zFile); 1001 if (zFile != NULL) 1002 { 1003 int nStatus = unzGoToFirstFile(*zFile); 1004 while (nStatus == UNZ_OK) 1005 { 1006 cFilename[0] = '\0'; 1007 unzGetCurrentFileInfo(*zFile, &zInfo, cFilename, WORK_LEN, NULL, 0, NULL, 0); 1008 strlwr(cFilename); 1009 __ConvertDOSToUnixName( cWork, cFilename); 1010 if (strstr(cWork, ".") != NULL) 1011 { 1012 PK3FileInfo *pInfo = new PK3FileInfo(); 1013 pInfo->m_pName = __StrDup(cWork); 1014 memcpy(&pInfo->m_zInfo, (unz_s*)*zFile, sizeof(unz_s)); 1015 pInfo->m_lSize = zInfo.uncompressed_size; 1016 pInfo->m_zFile = *zFile; 1017 g_PK3Files.Add(pInfo); 1018 } 1019 char *p = strstr(cFilename, TEXTURE_PATH); 1020 if (p != NULL) 1021 { 1022 // FIXME: path differences per os ? 1023 // catch solo directory entry 1024 if (strlen(p) > strlen(TEXTURE_PATH) + 1) 1025 { 1026 // skip textures + path seperator 1027 p += strlen(TEXTURE_PATH) + 1; 1028 int nEnd = strcspn(p, PATH_SEPERATORS); 1029 strncpy(cName, p, nEnd); 1030 cName[nEnd] = '\0'; 1031 1032 boolean bFound = false; 1033 StrList *pl = g_PK3TexturePaths.Next(); 1034 while (pl != NULL) 1035 { 1036 if (strcmpi(pl->Ref(), cName) == 0) 1037 { 1038 // already have this, continue 1039 bFound = true; 1040 break; 1041 } 1042 pl = pl->Next(); 1043 } 1044 if (!bFound) 1045 { 1046 g_PK3TexturePaths.Add(new Str(cName)); 1047 } 1048 } 1049 } 1050 nStatus = unzGoToNextFile(*zFile); 1051 } 1052 } 1053 return (zFile != NULL); 1054 } 1055 1056 void closePK3(unzFile zf) 1057 { 1058 unzClose(zf); 1059 } 1060 1061 void OpenPakFile(const char *filename) 1062 { 1063 int i; 1064 char *str1, *str2; 1065 DIRECTORY *dummy; 1066 1067 if(!pakopen) 1068 paktextures = NULL; 1069 1070 HavePakColormap = false; 1071 1072 Str strTest(filename); 1073 strTest.MakeLower(); 1074 if (strTest.Find("pk3") >= 0 || strTest.Find("zip") >= 0) 1075 { 1076 pakopen = g_bPK3 = OpenPK3(filename); 1077 return; 1078 } 1079 1080 1081 if((pakfile[m_nPAKIndex] = OpenFileReadMagic(filename, &f_type)) == NULL) 1082 { 1083 //FIXME: error routine 1084 //Sys_Printf("ERROR: Could not open %s", filename); 1085 return; 1086 } 1087 if(f_type != FTYPE_PACK) 1088 { 1089 //Sys_Printf("ERROR: %s is not a valid pack file", filename); 1090 if(f_type != FTYPE_ERROR) 1091 fclose(pakfile[m_nPAKIndex]); 1092 return; 1093 } 1094 pakdirptr = ReadPACKDirectory(pakfile[m_nPAKIndex], 0, &dirsize); 1095 if (pakdirptr == NULL) 1096 { 1097 //Sys_Printf("ERROR: Could not read pack directory", filename); 1098 fclose(pakfile[m_nPAKIndex]); 1099 return; 1100 } 1101 if (dirsize == 0) 1102 { 1103 fclose(pakfile[m_nPAKIndex]); 1104 return; 1105 } 1106 for (i = 0; i < dirsize; i++) 1107 { 1108 if(!strnicmp("textures/", pakdirptr[i].name, 9)) 1109 { 1110 dummy = paktextures; 1111 str1 = pakdirptr[i].name+9; 1112 while(strchr(str1, '/')) 1113 { 1114 str2 = strchr(str1, '/'); 1115 *str2++ = '\0'; 1116 dummy = AddPakDir(dummy==paktextures?&paktextures:&dummy, str1); 1117 str1 = str2; 1118 } 1119 1120 AddToFileListAlphabetized(&(dummy->files), str1, pakdirptr[i].offset, pakdirptr[i].size, true); 1121 } 1122 else if(!strnicmp("pics/colormap.pcx", pakdirptr[i].name, 17)) 1123 { 1124 HavePakColormap = true; 1125 PakColormapOffset = pakdirptr[i].offset; 1126 PakColormapSize = pakdirptr[i].size; 1127 } 1128 } 1129 pakopen = true; 1130 1131 } 1132 1133 void ClearPaKDir(DIRECTORY **dir) 1134 { 1135 DIRECTORY *d1 = *dir, *d2; 1136 1137 while(d1) 1138 { 1139 ClearFileList(&(d1->files)); 1140 d2 = d1; 1141 d1 = d1->next; 1142 free(d2); 1143 } 1144 } 1145 1146 void CleanUpPakDirs() 1147 { 1148 ClearPaKDir(&paktextures); 1149 paktextures = NULL; 1150 dirhead = NULL; 1151 g_PK3TexturePaths.RemoveAll(); 1152 g_PK3Files.RemoveAll(); 1153 } 1154 1155 void ClosePakFile(void) 1156 { 1157 if(pakopen) 1158 { 1159 if (g_bPK3) 1160 { 1161 ZFileList *p = g_zFiles.Next(); 1162 while (p != NULL) 1163 { 1164 unzFile uz = p->Ref(); 1165 closePK3(uz); 1166 p = p->Next(); 1167 } 1168 } 1169 else 1170 { 1171 fclose(pakfile[m_nPAKIndex]); 1172 } 1173 } 1174 pakopen = false; 1175 CleanUpPakDirs(); 1176 } 1177 1178 1179 void WINAPI InitPakFile(const char * pBasePath, const char *pName) 1180 { 1181 m_nPAKIndex = 0; 1182 pakopen = false; 1183 paktextures = NULL; 1184 strcpy(g_strBasePath, pBasePath); 1185 if (pName == NULL) 1186 { 1187 char cWork[WORK_LEN]; 1188 Str strPath(pBasePath); 1189 AddSlash(strPath); 1190 strPath += "*.pk3"; 1191 bool bGo = true; 1192 struct _finddata_t fileinfo; 1193 int handle = _findfirst (strPath, &fileinfo); 1194 if (handle != -1) 1195 { 1196 do 1197 { 1198 sprintf(cWork, "%s\\%s", pBasePath, fileinfo.name); 1199 OpenPakFile(cWork); 1200 } while (_findnext( handle, &fileinfo ) != -1); 1201 _findclose (handle); 1202 } 1203 } 1204 else 1205 { 1206 OpenPakFile(pName); 1207 } 1208 } 1209