pakstuff.cpp 24 KB

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