-/*\r
-Copyright (C) 1999-2007 id Software, Inc. and contributors.\r
-For a list of contributors, see the accompanying CONTRIBUTORS file.\r
-\r
-This file is part of GtkRadiant.\r
-\r
-GtkRadiant is free software; you can redistribute it and/or modify\r
-it under the terms of the GNU General Public License as published by\r
-the Free Software Foundation; either version 2 of the License, or\r
-(at your option) any later version.\r
-\r
-GtkRadiant is distributed in the hope that it will be useful,\r
-but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
-GNU General Public License for more details.\r
-\r
-You should have received a copy of the GNU General Public License\r
-along with GtkRadiant; if not, write to the Free Software\r
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\r
-*/\r
-\r
-#include <stdio.h>\r
-#include <stdarg.h>\r
-#include <stdlib.h>\r
-#include <string.h>\r
-#if defined (__linux__) || defined (__APPLE__)\r
-#include <dirent.h>\r
-#endif\r
-#ifdef _WIN32\r
-#include <io.h>\r
-#endif\r
-#include "pakstuff.h"\r
-#include "unzip.h"\r
-#include "str.h"\r
-\r
-#ifndef TRUE\r
-#define TRUE 1\r
-#define FALSE 0\r
-#endif\r
-\r
-int m_nPAKIndex;\r
-FILE* pakfile[16];\r
-struct PACKDirectory pakdir;\r
-PACKDirPtr pakdirptr = &pakdir;\r
-UInt16 dirsize;\r
-bool pakopen = false;\r
-int f_type;\r
-DIRECTORY *paktextures = NULL;\r
-UInt32 PakColormapOffset;\r
-UInt32 PakColormapSize;\r
-DIRECTORY *dirhead = NULL;\r
-bool g_bPK3 = false;\r
-char g_strBasePaths[16][1024];\r
-int g_numBasePaths = 0;\r
-\r
-struct PK3FileInfo\r
-{\r
- unzFile m_zFile;\r
- char *m_pName;\r
- unz_s m_zInfo;\r
- long m_lSize;\r
- ~PK3FileInfo()\r
- {\r
- delete []m_pName;\r
- }\r
- bool operator ==(const PK3FileInfo& rhs) const { return strcmp(m_pName, rhs.m_pName) == 0; }\r
-};\r
-\r
-#define __PATHSEPERATOR '/'\r
-\r
-//#define LOG_PAKFAIL\r
-\r
-#ifdef LOG_PAKFAIL\r
-\r
-#if defined (__linux__) || defined (__APPLE__)\r
-#include <unistd.h>\r
-#include <pwd.h>\r
-#endif\r
-#include <sys/types.h>\r
-\r
-class LogFile\r
-{\r
-public:\r
- FILE *m_pFile;\r
- LogFile(const char* pName)\r
- {\r
-#if defined (__linux__) || defined (__APPLE__)\r
- // leo: use ~/.q3a/radiant/paklog instead of /tmp/paklog.txt\r
- char *home = NULL;\r
- \r
- home = getenv("HOME");\r
- if ( home == NULL )\r
- {\r
- uid_t id = getuid();\r
- struct passwd *pwd;\r
- \r
- setpwent();\r
- while( (pwd = getpwent()) != NULL )\r
- if( pwd->pw_uid == id )\r
- {\r
- home = pwd->pw_dir;\r
- break;\r
- }\r
- endpwent();\r
- }\r
-\r
- if (home != NULL)\r
- {\r
- char path[PATH_MAX];\r
- strcpy (path, home);\r
- if (path[strlen(path)-1] != '/')\r
- strcat (path, "/");\r
- strcat (path, ".q3a/radiant/paklog");\r
- m_pFile = fopen(path, "w");\r
- }\r
- else\r
-#endif\r
- m_pFile = fopen(pName, "w");\r
- }\r
- ~LogFile()\r
- {\r
- if (m_pFile)\r
- {\r
- fclose(m_pFile);\r
- }\r
- }\r
- void Log(const char *pFormat, ...)\r
- {\r
- if (m_pFile == NULL)\r
- return;\r
-\r
- va_list arg_ptr;\r
- va_start(arg_ptr, pFormat);\r
- fprintf(m_pFile, pFormat, arg_ptr);\r
- va_end(arg_ptr);\r
- }\r
-};\r
-\r
-LogFile g_LogFile("/tmp/paklog.txt");\r
-#endif\r
-\r
-template <class T> class StrPtr : public Str\r
-{\r
-protected:\r
- T* m_pPtr;\r
- StrPtr()\r
- {\r
- m_pPtr = NULL;\r
- }\r
-\r
- StrPtr(const char *pStr, T *p) : Str(pStr)\r
- {\r
- m_pPtr = p;\r
- }\r
-\r
- T* Ptr()\r
- {\r
- return m_pPtr;\r
- }\r
-\r
- T& Ref()\r
- {\r
- return *m_pPtr;\r
- }\r
- \r
-\r
-};\r
-// PtrList\r
-// a list of ptrs\r
-// \r
-template <class T> class PtrList\r
-{\r
-protected:\r
- T *m_pPtr;\r
- PtrList *m_pNext;\r
-\r
-public:\r
-\r
- PtrList()\r
- {\r
- m_pNext = NULL;\r
- m_pPtr = NULL;\r
- }\r
-\r
- PtrList(T *ip)\r
- {\r
- m_pNext = NULL;\r
- m_pPtr = ip;\r
- }\r
-\r
- virtual ~PtrList()\r
- {\r
- delete m_pPtr;\r
- }\r
-\r
- PtrList* Next()\r
- {\r
- return m_pNext;\r
- }\r
-\r
- void Add(T *ip)\r
- {\r
- PtrList *pl = this;\r
- while (pl && pl->m_pNext)\r
- {\r
- pl = pl->Next();\r
- }\r
- pl->m_pNext = new PtrList(ip);\r
- }\r
-\r
- void Remove()\r
- {\r
- PtrList *p = m_pNext;\r
- if (p)\r
- {\r
- while (p->m_pNext != this && p->m_pNext != NULL)\r
- {\r
- p = p->m_pNext;\r
- }\r
- if (p->m_pNext == this)\r
- {\r
- p->m_pNext = m_pNext;\r
- }\r
- }\r
- }\r
-\r
- virtual PtrList* Find(T *ip)\r
- {\r
- PtrList *p = m_pNext;\r
- while (p)\r
- {\r
- if (*p->m_pPtr == *ip)\r
- {\r
- return p;\r
- }\r
- p = p->m_pNext;\r
- }\r
- return NULL;\r
- }\r
-\r
- // remove vp from the list\r
- void Remove(T *ip)\r
- {\r
- PtrList *p = Find(ip);\r
- if (p)\r
- {\r
- p->Remove();\r
- }\r
- }\r
-\r
- T* Ptr()\r
- {\r
- return m_pPtr;\r
- }\r
-\r
- T& Ref()\r
- {\r
- return *m_pPtr;\r
- }\r
-\r
- void RemoveAll()\r
- {\r
- PtrList *p = m_pNext;\r
- while (p)\r
- {\r
- PtrList *p2 = p;\r
- p = p->m_pNext;\r
- delete p2;\r
- }\r
- }\r
-};\r
-\r
-\r
-typedef PtrList<unzFile> ZFileList;\r
-typedef PtrList<Str> StrList;\r
-typedef PtrList<PK3FileInfo> PK3List;\r
-\r
-\r
-StrList g_PK3TexturePaths;\r
-PK3List g_PK3Files;\r
-ZFileList g_zFiles;\r
-#define WORK_LEN 1024\r
-#define TEXTURE_PATH "textures"\r
-#define PATH_SEPERATORS "/\\:\0"\r
-\r
-/*\r
-char* __StrDup(char* pStr)\r
-{\r
- if (pStr == NULL)\r
- pStr = "";\r
-\r
- return strcpy(new char[strlen(pStr)+1], pStr); \r
-}\r
-\r
-char* __StrDup(const char* pStr)\r
-{ \r
- if (pStr == NULL)\r
- pStr = "";\r
-\r
- return strcpy(new char[strlen(pStr)+1], pStr); \r
-}\r
-*/\r
-\r
-#define MEM_BLOCKSIZE 4096\r
-void* __qblockmalloc(size_t nSize)\r
-{\r
- void *b;\r
- // round up to threshold\r
- int nAllocSize = nSize % MEM_BLOCKSIZE;\r
- if ( nAllocSize > 0)\r
- {\r
- nSize += MEM_BLOCKSIZE - nAllocSize;\r
- }\r
- b = malloc(nSize + 1);\r
- memset (b, 0, nSize);\r
- return b;\r
-}\r
-\r
-void* __qmalloc (size_t nSize)\r
-{\r
- void *b;\r
- b = malloc(nSize + 1);\r
- memset (b, 0, nSize);\r
- return b;\r
-}\r
-\r
-\r
-/*\r
-====================\r
-Extract file parts\r
-====================\r
-*/\r
-void __ExtractFilePath (const char *path, char *dest)\r
-{\r
- const char *src;\r
-\r
- src = path + strlen(path) - 1;\r
-\r
-//\r
-// back up until a \ or the start\r
-//\r
- while (src != path && *(src-1) != __PATHSEPERATOR)\r
- src--;\r
-\r
- memcpy (dest, path, src-path);\r
- dest[src-path] = 0;\r
-}\r
-\r
-void __ExtractFileName (const char *path, char *dest)\r
-{\r
- const char *src;\r
-\r
- src = path + strlen(path) - 1;\r
-\r
-//\r
-// back up until a \ or the start\r
-//\r
- while (src != path && *(src-1) != '/' \r
- && *(src-1) != '\\' )\r
- src--;\r
-\r
- while (*src)\r
- {\r
- *dest++ = *src++;\r
- }\r
- *dest = 0;\r
-}\r
-\r
-void __ExtractFileBase (const char *path, char *dest)\r
-{\r
- const char *src;\r
-\r
- src = path + strlen(path) - 1;\r
-\r
-//\r
-// back up until a \ or the start\r
-//\r
- while (src != path && *(src-1) != '/' \r
- && *(src-1) != '\\' )\r
- src--;\r
-\r
- while (*src && *src != '.')\r
- {\r
- *dest++ = *src++;\r
- }\r
- *dest = 0;\r
-}\r
-\r
-void __ExtractFileExtension (const char *path, char *dest)\r
-{\r
- const char *src;\r
-\r
- src = path + strlen(path) - 1;\r
-\r
-//\r
-// back up until a . or the start\r
-//\r
- while (src != path && *(src-1) != '.')\r
- src--;\r
- if (src == path)\r
- {\r
- *dest = 0; // no extension\r
- return;\r
- }\r
-\r
- strcpy (dest,src);\r
-}\r
-\r
-\r
-void __ConvertDOSToUnixName( char *dst, const char *src )\r
-{\r
- while ( *src )\r
- {\r
- if ( *src == '\\' )\r
- *dst = '/';\r
- else\r
- *dst = *src;\r
- dst++; src++;\r
- }\r
- *dst = 0;\r
-}\r
-\r
-\r
-\r
-\r
-\r
-static void AddSlash(Str& str)\r
-{\r
- int nLen = str.GetLength();\r
- if (nLen > 0)\r
- {\r
- if (str[nLen-1] != '\\' && str[nLen-1] != '/')\r
- str += '\\';\r
- }\r
-}\r
-\r
-static void FindReplace(Str& strContents, const char* pTag, const char* pValue)\r
-{\r
- if (strcmp(pTag, pValue) == 0)\r
- return;\r
- for (int nPos = strContents.Find(pTag); nPos >= 0; nPos = strContents.Find(pTag))\r
- {\r
- int nRightLen = strContents.GetLength() - strlen(pTag) - nPos;\r
- Str strLeft(strContents.Left(nPos));\r
- Str strRight(strContents.Right(nRightLen));\r
- strLeft += pValue;\r
- strLeft += strRight;\r
- strContents = strLeft;\r
- }\r
-}\r
-\r
-\r
-\r
-\r
-\r
-void ClearFileList(FILELIST **list)\r
-{\r
- FILELIST *temp;\r
-\r
- while(*list)\r
- {\r
- temp = *list;\r
- *list = (*list)->next;\r
- free(temp);\r
- }\r
-}\r
-\r
-void ClearDirList(DIRLIST **list)\r
-{\r
- DIRLIST *temp;\r
-\r
- while(*list)\r
- {\r
- temp = *list;\r
- *list = (*list)->next;\r
- free(temp);\r
- }\r
-}\r
-\r
-DIRECTORY *FindPakDir(DIRECTORY *dir, char *name)\r
-{\r
- DIRECTORY *currentPtr;\r
-\r
- for(currentPtr = dir; currentPtr; currentPtr = currentPtr->next)\r
- {\r
- if(!stricmp(name, currentPtr->name))\r
- {\r
- return currentPtr;\r
- }\r
- }\r
- return NULL;\r
-}\r
-\r
-\r
-// LoadPK3FileList\r
-// ---------------\r
-//\r
-// This gets passed a file mask which we want to remove as \r
-// we are only interested in the directory name and any given\r
-// extension. Only handles explicit filenames or *.something\r
-//\r
-bool LoadPK3FileList(FILELIST **filelist, const char *pattern)\r
-{\r
- char cSearch[WORK_LEN];\r
- __ConvertDOSToUnixName( cSearch, pattern );\r
- char cPath[WORK_LEN];\r
- char cExt[WORK_LEN];\r
- char cFile[WORK_LEN];\r
- char cWork[WORK_LEN];\r
- __ExtractFilePath(pattern, cPath);\r
- __ExtractFileName(pattern, cFile);\r
- __ExtractFileExtension(pattern, cExt);\r
- const char *pCompare = (strnicmp(cFile, "*.", 2) == 0) ? cExt : cFile;\r
-\r
- PK3List *p = g_PK3Files.Next();\r
- while (p != NULL)\r
- {\r
- // qualify the path\r
- PK3FileInfo *pKey = p->Ptr();\r
- if (strstr(pKey->m_pName, cPath) && strstr(pKey->m_pName, pCompare))\r
- {\r
- __ExtractFileName(pKey->m_pName, cWork); \r
- AddToFileListAlphabetized(filelist, cWork, 0, 0, false);\r
- }\r
- p = p->Next();\r
- }\r
- return (*filelist) != NULL;\r
-}\r
-\r
-bool GetPackFileList(FILELIST **filelist, char *pattern)\r
-{\r
- char *str1, *str2;\r
- int i;\r
- DIRECTORY *dummy = paktextures;\r
- FILELIST *temp;\r
-\r
- if (!pakopen)\r
- return false;\r
-\r
- if (g_bPK3)\r
- {\r
- return LoadPK3FileList(filelist, pattern);\r
- }\r
-\r
- str1 = pattern;\r
-\r
- for(i = 0; pattern[i] != '\0'; i++)\r
- {\r
- if(pattern[i] == '\\')\r
- pattern[i] = '/';\r
- }\r
-\r
- while(strchr(str1, '/'))\r
- {\r
- str2 = strchr(str1, '/');\r
- *str2++ = '\0';\r
- dummy = FindPakDir(dummy, str1);\r
- if(!dummy)\r
- return false;\r
- str1 = str2;\r
- }\r
- for(temp = dummy->files; temp; temp=temp->next)\r
- {\r
- AddToFileListAlphabetized(filelist, temp->filename, temp->offset, 0, false);\r
- }\r
- return true;\r
-}\r
-\r
-bool GetPackTextureDirs(DIRLIST **dirlist)\r
-{\r
- UInt16 i;\r
- char buf[57];\r
-\r
- if (!pakopen)\r
- return 1;\r
-\r
- if (g_bPK3)\r
- {\r
- StrList *pl = g_PK3TexturePaths.Next();\r
- while (pl != NULL)\r
- {\r
- AddToDirListAlphabetized(dirlist, pl->Ref(), 0);\r
- pl = pl->Next();\r
- }\r
- return true;\r
- }\r
-\r
- for (i = 0; i < dirsize; i++)\r
- {\r
- if(!strnicmp(pakdirptr[i].name, "textures", 8))\r
- {\r
- strncpy(buf, &(pakdirptr[i].name[9]), 46);\r
- if(strchr(buf, '\\'))\r
- *strchr(buf, '\\') = '\0';\r
- else if(strchr(buf, '/'))\r
- *strchr(buf, '/') = '\0';\r
- else\r
- buf[56] = '\0';\r
-\r
- if(strchr(buf, '.'))\r
- continue;\r
-\r
- AddToDirListAlphabetized(dirlist, buf, 0);\r
- }\r
- }\r
- return true;\r
-}\r
-\r
-bool AddToDirListAlphabetized(DIRLIST **list, char *dirname, int from)\r
-{\r
- DIRLIST *currentPtr, *previousPtr, *newPtr;\r
-\r
- strlwr(dirname);\r
- for(currentPtr = *list; currentPtr; currentPtr = currentPtr->next)\r
- {\r
- if(!stricmp(dirname, currentPtr->dirname))\r
- {\r
- return false;\r
- }\r
- }\r
- previousPtr = NULL;\r
- currentPtr = *list;\r
-\r
- if((newPtr = (DIRLIST *)__qmalloc(sizeof(DIRLIST))) == NULL)\r
- return false;\r
-\r
- strcpy(newPtr->dirname, dirname);\r
- newPtr->from = from;\r
-\r
- while(currentPtr != NULL && stricmp(dirname, currentPtr->dirname) > 0)\r
- {\r
- previousPtr = currentPtr;\r
- currentPtr = currentPtr->next;\r
- } //End while\r
- if(previousPtr == NULL)\r
- {\r
- newPtr->next = *list;\r
- *list = newPtr;\r
- } //End if\r
- else\r
- {\r
- previousPtr->next = newPtr;\r
- newPtr->next = currentPtr;\r
- } //End else\r
- return true;\r
-}\r
-\r
-bool AddToFileListAlphabetized(FILELIST **list, char *filename, UInt32 offset, UInt32 size, bool dirs)\r
-{\r
- FILELIST *currentPtr, *previousPtr, *newPtr;\r
-\r
- for(currentPtr = *list; currentPtr; currentPtr = currentPtr->next)\r
- {\r
- if(!stricmp(filename, currentPtr->filename))\r
- {\r
- return false;\r
- }\r
- }\r
- previousPtr = NULL;\r
- currentPtr = *list;\r
-\r
- if((newPtr = (FILELIST *)__qmalloc(sizeof(FILELIST))) == NULL)\r
- return false;\r
-\r
- strcpy(newPtr->filename, filename);\r
- newPtr->offset = offset;\r
- newPtr->size = size;\r
-\r
- while(currentPtr != NULL && stricmp(filename, currentPtr->filename) > 0)\r
- {\r
- previousPtr = currentPtr;\r
- currentPtr = currentPtr->next;\r
- } //End while\r
- if(previousPtr == NULL)\r
- {\r
- newPtr->next = *list;\r
- *list = newPtr;\r
- } //End if\r
- else\r
- {\r
- previousPtr->next = newPtr;\r
- newPtr->next = currentPtr;\r
- } //End else\r
- return true;\r
-}\r
-\r
-int PakLoadAnyFile(const char *filename, void **bufferptr)\r
-{\r
- char cWork[WORK_LEN];\r
- if (g_bPK3)\r
- {\r
- // leo: hack to be able to use pak files from multiple directories\r
- for (int i = 0; i < g_numBasePaths; i++)\r
- {\r
- PK3FileInfo *pInfo;\r
- Str strKey;\r
- // need to lookup the file without the base/texture path on it\r
- Str strBase(g_strBasePaths[i]);\r
- AddSlash(strBase);\r
- __ConvertDOSToUnixName(cWork, strBase);\r
- Str strFile(filename);\r
- __ConvertDOSToUnixName(strFile, strFile);\r
- strFile.MakeLower();\r
- strlwr(cWork);\r
- FindReplace(strFile, cWork, "");\r
-\r
- PK3FileInfo infoFind;\r
- infoFind.m_pName = __StrDup(strFile.GetBuffer());\r
- PK3List *pList = g_PK3Files.Find(&infoFind);\r
- if (pList)\r
- {\r
- pInfo = pList->Ptr();\r
- memcpy(pInfo->m_zFile, &pInfo->m_zInfo, sizeof(unz_s));\r
- if (unzOpenCurrentFile(pInfo->m_zFile) == UNZ_OK)\r
- {\r
- void *buffer = __qblockmalloc(pInfo->m_lSize+1);\r
- int n = unzReadCurrentFile(pInfo->m_zFile , buffer, pInfo->m_lSize);\r
- *bufferptr = buffer;\r
- unzCloseCurrentFile(pInfo->m_zFile);\r
- return n;\r
- }\r
- }\r
- }\r
-\r
-#ifdef LOG_PAKFAIL\r
- sprintf(cWork, "PAK failed on %s\n", filename);\r
- g_LogFile.Log(cWork);\r
-#endif\r
- return -1;\r
- }\r
-\r
- for (int i = 0; i < dirsize; i++)\r
- {\r
- if(!stricmp(filename, pakdirptr[i].name))\r
- {\r
- if (fseek(pakfile[m_nPAKIndex], pakdirptr[i].offset, SEEK_SET) >= 0)\r
- {\r
- void *buffer = __qmalloc (pakdirptr[i].size+1);\r
- ((char *)buffer)[pakdirptr[i].size] = 0;\r
- if (fread(buffer, 1, pakdirptr[i].size, pakfile[m_nPAKIndex]) == pakdirptr[i].size)\r
- {\r
- *bufferptr = buffer;\r
- return pakdirptr[i].size;\r
- }\r
- }\r
- }\r
- }\r
-#ifdef LOG_PAKFAIL\r
- sprintf(cWork, "PAK failed on %s\n", filename);\r
- g_LogFile.Log(cWork);\r
-#endif\r
- return -1;\r
-}\r
-\r
-\r
-\r
-DIRECTORY *AddPakDir(DIRECTORY **dir, char *name)\r
-{\r
- DIRECTORY *currentPtr, *previousPtr, *newPtr;\r
-\r
- for(currentPtr = *dir; currentPtr; currentPtr = currentPtr->next)\r
- {\r
- if(!stricmp(name, currentPtr->name))\r
- {\r
- return currentPtr;\r
- }\r
- }\r
- previousPtr = NULL;\r
- currentPtr = *dir;\r
-\r
- if((newPtr = (DIRECTORY *)__qmalloc(sizeof(DIRECTORY))) == NULL)\r
- return NULL;\r
-\r
- strcpy(newPtr->name, name);\r
- newPtr->files = NULL;\r
-\r
- while(currentPtr != NULL && stricmp(name, currentPtr->name) > 0)\r
- {\r
- previousPtr = currentPtr;\r
- currentPtr = currentPtr->next;\r
- }\r
- if(previousPtr == NULL)\r
- {\r
- newPtr->next = *dir;\r
- *dir = newPtr;\r
- }\r
- else\r
- {\r
- previousPtr->next = newPtr;\r
- newPtr->next = currentPtr;\r
- }\r
- return newPtr;\r
-}\r
-\r
-\r
-// OpenPK3\r
-// -------\r
-// Opens a PK3 ( or zip ) file and creates a list of filenames\r
-// and zip info structures\r
-// \r
-bool OpenPK3(const char *filename)\r
-{\r
- char cFilename[WORK_LEN];\r
- char cName[WORK_LEN];\r
- char cWork[WORK_LEN];\r
- unz_file_info zInfo;\r
- unzFile *zFile = new unzFile(unzOpen(filename));\r
- g_zFiles.Add(zFile);\r
- if (zFile != NULL)\r
- {\r
- int nStatus = unzGoToFirstFile(*zFile);\r
- while (nStatus == UNZ_OK)\r
- {\r
- cFilename[0] = '\0';\r
- unzGetCurrentFileInfo(*zFile, &zInfo, cFilename, WORK_LEN, NULL, 0, NULL, 0);\r
- strlwr(cFilename);\r
- __ConvertDOSToUnixName( cWork, cFilename);\r
- if (strstr(cWork, ".") != NULL)\r
- {\r
- PK3FileInfo *pInfo = new PK3FileInfo();\r
- pInfo->m_pName = __StrDup(cWork);\r
- memcpy(&pInfo->m_zInfo, (unz_s*)*zFile, sizeof(unz_s));\r
- pInfo->m_lSize = zInfo.uncompressed_size;\r
- pInfo->m_zFile = *zFile;\r
- g_PK3Files.Add(pInfo);\r
- }\r
- char *p = strstr(cFilename, TEXTURE_PATH);\r
- if (p != NULL)\r
- {\r
- // FIXME: path differences per os ?\r
- // catch solo directory entry\r
- if (strlen(p) > strlen(TEXTURE_PATH) + 1)\r
- {\r
- // skip textures + path seperator\r
- p += strlen(TEXTURE_PATH) + 1;\r
- int nEnd = strcspn(p, PATH_SEPERATORS);\r
- strncpy(cName, p, nEnd);\r
- cName[nEnd] = '\0';\r
-\r
- bool bFound = false;\r
- StrList *pl = g_PK3TexturePaths.Next();\r
- while (pl != NULL)\r
- {\r
- if (strcmpi(pl->Ref(), cName) == 0)\r
- {\r
- // already have this, continue\r
- bFound = true;\r
- break;\r
- }\r
- pl = pl->Next();\r
- }\r
- if (!bFound)\r
- {\r
- g_PK3TexturePaths.Add(new Str(cName));\r
- }\r
- }\r
- }\r
- nStatus = unzGoToNextFile(*zFile);\r
- }\r
- }\r
- return (zFile != NULL);\r
-}\r
-\r
-void closePK3(unzFile zf)\r
-{\r
- unzClose(zf);\r
-}\r
-\r
-void OpenPakFile(const char *filename)\r
-{\r
- if(!pakopen)\r
- paktextures = NULL;\r
-\r
- pakopen = g_bPK3 = OpenPK3(filename);\r
-}\r
-\r
-void ClearPaKDir(DIRECTORY **dir)\r
-{\r
- DIRECTORY *d1 = *dir, *d2;\r
-\r
- while(d1)\r
- {\r
- ClearFileList(&(d1->files));\r
- d2 = d1;\r
- d1 = d1->next;\r
- free(d2);\r
- }\r
-}\r
-\r
-void CleanUpPakDirs()\r
-{\r
- ClearPaKDir(&paktextures);\r
- paktextures = NULL;\r
- dirhead = NULL;\r
- g_PK3TexturePaths.RemoveAll();\r
- g_PK3Files.RemoveAll();\r
-}\r
-\r
-void ClosePakFile(void)\r
-{\r
- if(pakopen)\r
- {\r
- if (g_bPK3)\r
- {\r
- ZFileList *p = g_zFiles.Next();\r
- while (p != NULL)\r
- {\r
- unzFile uz = p->Ref();\r
- closePK3(uz);\r
- p = p->Next();\r
- }\r
- }\r
- else\r
- {\r
- fclose(pakfile[m_nPAKIndex]);\r
- }\r
- }\r
- pakopen = false;\r
- CleanUpPakDirs();\r
-}\r
-\r
-\r
-void WINAPI InitPakFile(const char * pBasePath, const char *pName)\r
-{\r
- if (g_numBasePaths == 0)\r
- {\r
- m_nPAKIndex = 0;\r
- pakopen = false;\r
- paktextures = NULL;\r
- }\r
- strcpy(g_strBasePaths[g_numBasePaths], pBasePath);\r
- g_numBasePaths++;\r
- \r
- if (pName == NULL)\r
- {\r
- //++timo FIXME: use some kind of compatibility lib here!\r
-#if defined (__linux__) || defined (__APPLE__)\r
- char cWork[WORK_LEN];\r
- struct dirent *dirlist;\r
- DIR *dir;\r
- \r
- dir = opendir (pBasePath);\r
- if (dir != NULL)\r
- {\r
- while ((dirlist = readdir (dir)) != NULL)\r
- {\r
- if (strstr (dirlist->d_name, ".pk3") == NULL)\r
- continue;\r
- sprintf(cWork, "%s/%s", pBasePath, dirlist->d_name);\r
- OpenPakFile(cWork);\r
- }\r
- closedir (dir);\r
- }\r
-#endif\r
-#ifdef _WIN32\r
- char cWork[WORK_LEN];\r
- Str strPath(pBasePath);\r
- AddSlash(strPath);\r
- strPath += "*.pk3";\r
- bool bGo = true;\r
- struct _finddata_t fileinfo;\r
- int handle = _findfirst (strPath, &fileinfo);\r
- if (handle != -1)\r
- {\r
- do\r
- {\r
- sprintf(cWork, "%s/%s", pBasePath, fileinfo.name);\r
- OpenPakFile(cWork);\r
- } while (_findnext( handle, &fileinfo ) != -1);\r
- _findclose (handle);\r
- }\r
-#endif\r
- }\r
- else\r
- {\r
- OpenPakFile(pName);\r
- }\r
-}\r
-\r
+/*
+Copyright (C) 1999-2007 id Software, Inc. and contributors.
+For a list of contributors, see the accompanying CONTRIBUTORS file.
+
+This file is part of GtkRadiant.
+
+GtkRadiant is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+GtkRadiant is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GtkRadiant; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#if defined (__linux__) || defined (__APPLE__)
+#include <dirent.h>
+#endif
+#ifdef _WIN32
+#include <io.h>
+#endif
+#include "pakstuff.h"
+#include "unzip.h"
+#include "str.h"
+
+#ifndef TRUE
+#define TRUE 1
+#define FALSE 0
+#endif
+
+int m_nPAKIndex;
+FILE* pakfile[16];
+struct PACKDirectory pakdir;
+PACKDirPtr pakdirptr = &pakdir;
+UInt16 dirsize;
+bool pakopen = false;
+int f_type;
+DIRECTORY *paktextures = NULL;
+UInt32 PakColormapOffset;
+UInt32 PakColormapSize;
+DIRECTORY *dirhead = NULL;
+bool g_bPK3 = false;
+char g_strBasePaths[16][1024];
+int g_numBasePaths = 0;
+
+struct PK3FileInfo
+{
+ unzFile m_zFile;
+ char *m_pName;
+ unz_s m_zInfo;
+ long m_lSize;
+ ~PK3FileInfo()
+ {
+ delete []m_pName;
+ }
+ bool operator ==(const PK3FileInfo& rhs) const { return strcmp(m_pName, rhs.m_pName) == 0; }
+};
+
+#define __PATHSEPERATOR '/'
+
+//#define LOG_PAKFAIL
+
+#ifdef LOG_PAKFAIL
+
+#if defined (__linux__) || defined (__APPLE__)
+#include <unistd.h>
+#include <pwd.h>
+#endif
+#include <sys/types.h>
+
+class LogFile
+{
+public:
+ FILE *m_pFile;
+ LogFile(const char* pName)
+ {
+#if defined (__linux__) || defined (__APPLE__)
+ // leo: use ~/.q3a/radiant/paklog instead of /tmp/paklog.txt
+ char *home = NULL;
+
+ home = getenv("HOME");
+ if ( home == NULL )
+ {
+ uid_t id = getuid();
+ struct passwd *pwd;
+
+ setpwent();
+ while( (pwd = getpwent()) != NULL )
+ if( pwd->pw_uid == id )
+ {
+ home = pwd->pw_dir;
+ break;
+ }
+ endpwent();
+ }
+
+ if (home != NULL)
+ {
+ char path[PATH_MAX];
+ strcpy (path, home);
+ if (path[strlen(path)-1] != '/')
+ strcat (path, "/");
+ strcat (path, ".q3a/radiant/paklog");
+ m_pFile = fopen(path, "w");
+ }
+ else
+#endif
+ m_pFile = fopen(pName, "w");
+ }
+ ~LogFile()
+ {
+ if (m_pFile)
+ {
+ fclose(m_pFile);
+ }
+ }
+ void Log(const char *pFormat, ...)
+ {
+ if (m_pFile == NULL)
+ return;
+
+ va_list arg_ptr;
+ va_start(arg_ptr, pFormat);
+ fprintf(m_pFile, pFormat, arg_ptr);
+ va_end(arg_ptr);
+ }
+};
+
+LogFile g_LogFile("/tmp/paklog.txt");
+#endif
+
+template <class T> class StrPtr : public Str
+{
+protected:
+ T* m_pPtr;
+ StrPtr()
+ {
+ m_pPtr = NULL;
+ }
+
+ StrPtr(const char *pStr, T *p) : Str(pStr)
+ {
+ m_pPtr = p;
+ }
+
+ T* Ptr()
+ {
+ return m_pPtr;
+ }
+
+ T& Ref()
+ {
+ return *m_pPtr;
+ }
+
+
+};
+// PtrList
+// a list of ptrs
+//
+template <class T> class PtrList
+{
+protected:
+ T *m_pPtr;
+ PtrList *m_pNext;
+
+public:
+
+ PtrList()
+ {
+ m_pNext = NULL;
+ m_pPtr = NULL;
+ }
+
+ PtrList(T *ip)
+ {
+ m_pNext = NULL;
+ m_pPtr = ip;
+ }
+
+ virtual ~PtrList()
+ {
+ delete m_pPtr;
+ }
+
+ PtrList* Next()
+ {
+ return m_pNext;
+ }
+
+ void Add(T *ip)
+ {
+ PtrList *pl = this;
+ while (pl && pl->m_pNext)
+ {
+ pl = pl->Next();
+ }
+ pl->m_pNext = new PtrList(ip);
+ }
+
+ void Remove()
+ {
+ PtrList *p = m_pNext;
+ if (p)
+ {
+ while (p->m_pNext != this && p->m_pNext != NULL)
+ {
+ p = p->m_pNext;
+ }
+ if (p->m_pNext == this)
+ {
+ p->m_pNext = m_pNext;
+ }
+ }
+ }
+
+ virtual PtrList* Find(T *ip)
+ {
+ PtrList *p = m_pNext;
+ while (p)
+ {
+ if (*p->m_pPtr == *ip)
+ {
+ return p;
+ }
+ p = p->m_pNext;
+ }
+ return NULL;
+ }
+
+ // remove vp from the list
+ void Remove(T *ip)
+ {
+ PtrList *p = Find(ip);
+ if (p)
+ {
+ p->Remove();
+ }
+ }
+
+ T* Ptr()
+ {
+ return m_pPtr;
+ }
+
+ T& Ref()
+ {
+ return *m_pPtr;
+ }
+
+ void RemoveAll()
+ {
+ PtrList *p = m_pNext;
+ while (p)
+ {
+ PtrList *p2 = p;
+ p = p->m_pNext;
+ delete p2;
+ }
+ }
+};
+
+
+typedef PtrList<unzFile> ZFileList;
+typedef PtrList<Str> StrList;
+typedef PtrList<PK3FileInfo> PK3List;
+
+
+StrList g_PK3TexturePaths;
+PK3List g_PK3Files;
+ZFileList g_zFiles;
+#define WORK_LEN 1024
+#define TEXTURE_PATH "textures"
+#define PATH_SEPERATORS "/\\:\0"
+
+/*
+char* __StrDup(char* pStr)
+{
+ if (pStr == NULL)
+ pStr = "";
+
+ return strcpy(new char[strlen(pStr)+1], pStr);
+}
+
+char* __StrDup(const char* pStr)
+{
+ if (pStr == NULL)
+ pStr = "";
+
+ return strcpy(new char[strlen(pStr)+1], pStr);
+}
+*/
+
+#define MEM_BLOCKSIZE 4096
+void* __qblockmalloc(size_t nSize)
+{
+ void *b;
+ // round up to threshold
+ int nAllocSize = nSize % MEM_BLOCKSIZE;
+ if ( nAllocSize > 0)
+ {
+ nSize += MEM_BLOCKSIZE - nAllocSize;
+ }
+ b = malloc(nSize + 1);
+ memset (b, 0, nSize);
+ return b;
+}
+
+void* __qmalloc (size_t nSize)
+{
+ void *b;
+ b = malloc(nSize + 1);
+ memset (b, 0, nSize);
+ return b;
+}
+
+
+/*
+====================
+Extract file parts
+====================
+*/
+void __ExtractFilePath (const char *path, char *dest)
+{
+ const char *src;
+
+ src = path + strlen(path) - 1;
+
+//
+// back up until a \ or the start
+//
+ while (src != path && *(src-1) != __PATHSEPERATOR)
+ src--;
+
+ memcpy (dest, path, src-path);
+ dest[src-path] = 0;
+}
+
+void __ExtractFileName (const char *path, char *dest)
+{
+ const char *src;
+
+ src = path + strlen(path) - 1;
+
+//
+// back up until a \ or the start
+//
+ while (src != path && *(src-1) != '/'
+ && *(src-1) != '\\' )
+ src--;
+
+ while (*src)
+ {
+ *dest++ = *src++;
+ }
+ *dest = 0;
+}
+
+void __ExtractFileBase (const char *path, char *dest)
+{
+ const char *src;
+
+ src = path + strlen(path) - 1;
+
+//
+// back up until a \ or the start
+//
+ while (src != path && *(src-1) != '/'
+ && *(src-1) != '\\' )
+ src--;
+
+ while (*src && *src != '.')
+ {
+ *dest++ = *src++;
+ }
+ *dest = 0;
+}
+
+void __ExtractFileExtension (const char *path, char *dest)
+{
+ const char *src;
+
+ src = path + strlen(path) - 1;
+
+//
+// back up until a . or the start
+//
+ while (src != path && *(src-1) != '.')
+ src--;
+ if (src == path)
+ {
+ *dest = 0; // no extension
+ return;
+ }
+
+ strcpy (dest,src);
+}
+
+
+void __ConvertDOSToUnixName( char *dst, const char *src )
+{
+ while ( *src )
+ {
+ if ( *src == '\\' )
+ *dst = '/';
+ else
+ *dst = *src;
+ dst++; src++;
+ }
+ *dst = 0;
+}
+
+
+
+
+
+static void AddSlash(Str& str)
+{
+ int nLen = str.GetLength();
+ if (nLen > 0)
+ {
+ if (str[nLen-1] != '\\' && str[nLen-1] != '/')
+ str += '\\';
+ }
+}
+
+static void FindReplace(Str& strContents, const char* pTag, const char* pValue)
+{
+ if (strcmp(pTag, pValue) == 0)
+ return;
+ for (int nPos = strContents.Find(pTag); nPos >= 0; nPos = strContents.Find(pTag))
+ {
+ int nRightLen = strContents.GetLength() - strlen(pTag) - nPos;
+ Str strLeft(strContents.Left(nPos));
+ Str strRight(strContents.Right(nRightLen));
+ strLeft += pValue;
+ strLeft += strRight;
+ strContents = strLeft;
+ }
+}
+
+
+
+
+
+void ClearFileList(FILELIST **list)
+{
+ FILELIST *temp;
+
+ while(*list)
+ {
+ temp = *list;
+ *list = (*list)->next;
+ free(temp);
+ }
+}
+
+void ClearDirList(DIRLIST **list)
+{
+ DIRLIST *temp;
+
+ while(*list)
+ {
+ temp = *list;
+ *list = (*list)->next;
+ free(temp);
+ }
+}
+
+DIRECTORY *FindPakDir(DIRECTORY *dir, char *name)
+{
+ DIRECTORY *currentPtr;
+
+ for(currentPtr = dir; currentPtr; currentPtr = currentPtr->next)
+ {
+ if(!stricmp(name, currentPtr->name))
+ {
+ return currentPtr;
+ }
+ }
+ return NULL;
+}
+
+
+// LoadPK3FileList
+// ---------------
+//
+// This gets passed a file mask which we want to remove as
+// we are only interested in the directory name and any given
+// extension. Only handles explicit filenames or *.something
+//
+bool LoadPK3FileList(FILELIST **filelist, const char *pattern)
+{
+ char cSearch[WORK_LEN];
+ __ConvertDOSToUnixName( cSearch, pattern );
+ char cPath[WORK_LEN];
+ char cExt[WORK_LEN];
+ char cFile[WORK_LEN];
+ char cWork[WORK_LEN];
+ __ExtractFilePath(pattern, cPath);
+ __ExtractFileName(pattern, cFile);
+ __ExtractFileExtension(pattern, cExt);
+ const char *pCompare = (strnicmp(cFile, "*.", 2) == 0) ? cExt : cFile;
+
+ PK3List *p = g_PK3Files.Next();
+ while (p != NULL)
+ {
+ // qualify the path
+ PK3FileInfo *pKey = p->Ptr();
+ if (strstr(pKey->m_pName, cPath) && strstr(pKey->m_pName, pCompare))
+ {
+ __ExtractFileName(pKey->m_pName, cWork);
+ AddToFileListAlphabetized(filelist, cWork, 0, 0, false);
+ }
+ p = p->Next();
+ }
+ return (*filelist) != NULL;
+}
+
+bool GetPackFileList(FILELIST **filelist, char *pattern)
+{
+ char *str1, *str2;
+ int i;
+ DIRECTORY *dummy = paktextures;
+ FILELIST *temp;
+
+ if (!pakopen)
+ return false;
+
+ if (g_bPK3)
+ {
+ return LoadPK3FileList(filelist, pattern);
+ }
+
+ str1 = pattern;
+
+ for(i = 0; pattern[i] != '\0'; i++)
+ {
+ if(pattern[i] == '\\')
+ pattern[i] = '/';
+ }
+
+ while(strchr(str1, '/'))
+ {
+ str2 = strchr(str1, '/');
+ *str2++ = '\0';
+ dummy = FindPakDir(dummy, str1);
+ if(!dummy)
+ return false;
+ str1 = str2;
+ }
+ for(temp = dummy->files; temp; temp=temp->next)
+ {
+ AddToFileListAlphabetized(filelist, temp->filename, temp->offset, 0, false);
+ }
+ return true;
+}
+
+bool GetPackTextureDirs(DIRLIST **dirlist)
+{
+ UInt16 i;
+ char buf[57];
+
+ if (!pakopen)
+ return 1;
+
+ if (g_bPK3)
+ {
+ StrList *pl = g_PK3TexturePaths.Next();
+ while (pl != NULL)
+ {
+ AddToDirListAlphabetized(dirlist, pl->Ref(), 0);
+ pl = pl->Next();
+ }
+ return true;
+ }
+
+ for (i = 0; i < dirsize; i++)
+ {
+ if(!strnicmp(pakdirptr[i].name, "textures", 8))
+ {
+ strncpy(buf, &(pakdirptr[i].name[9]), 46);
+ if(strchr(buf, '\\'))
+ *strchr(buf, '\\') = '\0';
+ else if(strchr(buf, '/'))
+ *strchr(buf, '/') = '\0';
+ else
+ buf[56] = '\0';
+
+ if(strchr(buf, '.'))
+ continue;
+
+ AddToDirListAlphabetized(dirlist, buf, 0);
+ }
+ }
+ return true;
+}
+
+bool AddToDirListAlphabetized(DIRLIST **list, char *dirname, int from)
+{
+ DIRLIST *currentPtr, *previousPtr, *newPtr;
+
+ strlwr(dirname);
+ for(currentPtr = *list; currentPtr; currentPtr = currentPtr->next)
+ {
+ if(!stricmp(dirname, currentPtr->dirname))
+ {
+ return false;
+ }
+ }
+ previousPtr = NULL;
+ currentPtr = *list;
+
+ if((newPtr = (DIRLIST *)__qmalloc(sizeof(DIRLIST))) == NULL)
+ return false;
+
+ strcpy(newPtr->dirname, dirname);
+ newPtr->from = from;
+
+ while(currentPtr != NULL && stricmp(dirname, currentPtr->dirname) > 0)
+ {
+ previousPtr = currentPtr;
+ currentPtr = currentPtr->next;
+ } //End while
+ if(previousPtr == NULL)
+ {
+ newPtr->next = *list;
+ *list = newPtr;
+ } //End if
+ else
+ {
+ previousPtr->next = newPtr;
+ newPtr->next = currentPtr;
+ } //End else
+ return true;
+}
+
+bool AddToFileListAlphabetized(FILELIST **list, char *filename, UInt32 offset, UInt32 size, bool dirs)
+{
+ FILELIST *currentPtr, *previousPtr, *newPtr;
+
+ for(currentPtr = *list; currentPtr; currentPtr = currentPtr->next)
+ {
+ if(!stricmp(filename, currentPtr->filename))
+ {
+ return false;
+ }
+ }
+ previousPtr = NULL;
+ currentPtr = *list;
+
+ if((newPtr = (FILELIST *)__qmalloc(sizeof(FILELIST))) == NULL)
+ return false;
+
+ strcpy(newPtr->filename, filename);
+ newPtr->offset = offset;
+ newPtr->size = size;
+
+ while(currentPtr != NULL && stricmp(filename, currentPtr->filename) > 0)
+ {
+ previousPtr = currentPtr;
+ currentPtr = currentPtr->next;
+ } //End while
+ if(previousPtr == NULL)
+ {
+ newPtr->next = *list;
+ *list = newPtr;
+ } //End if
+ else
+ {
+ previousPtr->next = newPtr;
+ newPtr->next = currentPtr;
+ } //End else
+ return true;
+}
+
+int PakLoadAnyFile(const char *filename, void **bufferptr)
+{
+ char cWork[WORK_LEN];
+ if (g_bPK3)
+ {
+ // leo: hack to be able to use pak files from multiple directories
+ for (int i = 0; i < g_numBasePaths; i++)
+ {
+ PK3FileInfo *pInfo;
+ Str strKey;
+ // need to lookup the file without the base/texture path on it
+ Str strBase(g_strBasePaths[i]);
+ AddSlash(strBase);
+ __ConvertDOSToUnixName(cWork, strBase);
+ Str strFile(filename);
+ __ConvertDOSToUnixName(strFile, strFile);
+ strFile.MakeLower();
+ strlwr(cWork);
+ FindReplace(strFile, cWork, "");
+
+ PK3FileInfo infoFind;
+ infoFind.m_pName = __StrDup(strFile.GetBuffer());
+ PK3List *pList = g_PK3Files.Find(&infoFind);
+ if (pList)
+ {
+ pInfo = pList->Ptr();
+ memcpy(pInfo->m_zFile, &pInfo->m_zInfo, sizeof(unz_s));
+ if (unzOpenCurrentFile(pInfo->m_zFile) == UNZ_OK)
+ {
+ void *buffer = __qblockmalloc(pInfo->m_lSize+1);
+ int n = unzReadCurrentFile(pInfo->m_zFile , buffer, pInfo->m_lSize);
+ *bufferptr = buffer;
+ unzCloseCurrentFile(pInfo->m_zFile);
+ return n;
+ }
+ }
+ }
+
+#ifdef LOG_PAKFAIL
+ sprintf(cWork, "PAK failed on %s\n", filename);
+ g_LogFile.Log(cWork);
+#endif
+ return -1;
+ }
+
+ for (int i = 0; i < dirsize; i++)
+ {
+ if(!stricmp(filename, pakdirptr[i].name))
+ {
+ if (fseek(pakfile[m_nPAKIndex], pakdirptr[i].offset, SEEK_SET) >= 0)
+ {
+ void *buffer = __qmalloc (pakdirptr[i].size+1);
+ ((char *)buffer)[pakdirptr[i].size] = 0;
+ if (fread(buffer, 1, pakdirptr[i].size, pakfile[m_nPAKIndex]) == pakdirptr[i].size)
+ {
+ *bufferptr = buffer;
+ return pakdirptr[i].size;
+ }
+ }
+ }
+ }
+#ifdef LOG_PAKFAIL
+ sprintf(cWork, "PAK failed on %s\n", filename);
+ g_LogFile.Log(cWork);
+#endif
+ return -1;
+}
+
+
+
+DIRECTORY *AddPakDir(DIRECTORY **dir, char *name)
+{
+ DIRECTORY *currentPtr, *previousPtr, *newPtr;
+
+ for(currentPtr = *dir; currentPtr; currentPtr = currentPtr->next)
+ {
+ if(!stricmp(name, currentPtr->name))
+ {
+ return currentPtr;
+ }
+ }
+ previousPtr = NULL;
+ currentPtr = *dir;
+
+ if((newPtr = (DIRECTORY *)__qmalloc(sizeof(DIRECTORY))) == NULL)
+ return NULL;
+
+ strcpy(newPtr->name, name);
+ newPtr->files = NULL;
+
+ while(currentPtr != NULL && stricmp(name, currentPtr->name) > 0)
+ {
+ previousPtr = currentPtr;
+ currentPtr = currentPtr->next;
+ }
+ if(previousPtr == NULL)
+ {
+ newPtr->next = *dir;
+ *dir = newPtr;
+ }
+ else
+ {
+ previousPtr->next = newPtr;
+ newPtr->next = currentPtr;
+ }
+ return newPtr;
+}
+
+
+// OpenPK3
+// -------
+// Opens a PK3 ( or zip ) file and creates a list of filenames
+// and zip info structures
+//
+bool OpenPK3(const char *filename)
+{
+ char cFilename[WORK_LEN];
+ char cName[WORK_LEN];
+ char cWork[WORK_LEN];
+ unz_file_info zInfo;
+ unzFile *zFile = new unzFile(unzOpen(filename));
+ g_zFiles.Add(zFile);
+ if (zFile != NULL)
+ {
+ int nStatus = unzGoToFirstFile(*zFile);
+ while (nStatus == UNZ_OK)
+ {
+ cFilename[0] = '\0';
+ unzGetCurrentFileInfo(*zFile, &zInfo, cFilename, WORK_LEN, NULL, 0, NULL, 0);
+ strlwr(cFilename);
+ __ConvertDOSToUnixName( cWork, cFilename);
+ if (strstr(cWork, ".") != NULL)
+ {
+ PK3FileInfo *pInfo = new PK3FileInfo();
+ pInfo->m_pName = __StrDup(cWork);
+ memcpy(&pInfo->m_zInfo, (unz_s*)*zFile, sizeof(unz_s));
+ pInfo->m_lSize = zInfo.uncompressed_size;
+ pInfo->m_zFile = *zFile;
+ g_PK3Files.Add(pInfo);
+ }
+ char *p = strstr(cFilename, TEXTURE_PATH);
+ if (p != NULL)
+ {
+ // FIXME: path differences per os ?
+ // catch solo directory entry
+ if (strlen(p) > strlen(TEXTURE_PATH) + 1)
+ {
+ // skip textures + path seperator
+ p += strlen(TEXTURE_PATH) + 1;
+ int nEnd = strcspn(p, PATH_SEPERATORS);
+ strncpy(cName, p, nEnd);
+ cName[nEnd] = '\0';
+
+ bool bFound = false;
+ StrList *pl = g_PK3TexturePaths.Next();
+ while (pl != NULL)
+ {
+ if (strcmpi(pl->Ref(), cName) == 0)
+ {
+ // already have this, continue
+ bFound = true;
+ break;
+ }
+ pl = pl->Next();
+ }
+ if (!bFound)
+ {
+ g_PK3TexturePaths.Add(new Str(cName));
+ }
+ }
+ }
+ nStatus = unzGoToNextFile(*zFile);
+ }
+ }
+ return (zFile != NULL);
+}
+
+void closePK3(unzFile zf)
+{
+ unzClose(zf);
+}
+
+void OpenPakFile(const char *filename)
+{
+ if(!pakopen)
+ paktextures = NULL;
+
+ pakopen = g_bPK3 = OpenPK3(filename);
+}
+
+void ClearPaKDir(DIRECTORY **dir)
+{
+ DIRECTORY *d1 = *dir, *d2;
+
+ while(d1)
+ {
+ ClearFileList(&(d1->files));
+ d2 = d1;
+ d1 = d1->next;
+ free(d2);
+ }
+}
+
+void CleanUpPakDirs()
+{
+ ClearPaKDir(&paktextures);
+ paktextures = NULL;
+ dirhead = NULL;
+ g_PK3TexturePaths.RemoveAll();
+ g_PK3Files.RemoveAll();
+}
+
+void ClosePakFile(void)
+{
+ if(pakopen)
+ {
+ if (g_bPK3)
+ {
+ ZFileList *p = g_zFiles.Next();
+ while (p != NULL)
+ {
+ unzFile uz = p->Ref();
+ closePK3(uz);
+ p = p->Next();
+ }
+ }
+ else
+ {
+ fclose(pakfile[m_nPAKIndex]);
+ }
+ }
+ pakopen = false;
+ CleanUpPakDirs();
+}
+
+
+void WINAPI InitPakFile(const char * pBasePath, const char *pName)
+{
+ if (g_numBasePaths == 0)
+ {
+ m_nPAKIndex = 0;
+ pakopen = false;
+ paktextures = NULL;
+ }
+ strcpy(g_strBasePaths[g_numBasePaths], pBasePath);
+ g_numBasePaths++;
+
+ if (pName == NULL)
+ {
+ //++timo FIXME: use some kind of compatibility lib here!
+#if defined (__linux__) || defined (__APPLE__)
+ char cWork[WORK_LEN];
+ struct dirent *dirlist;
+ DIR *dir;
+
+ dir = opendir (pBasePath);
+ if (dir != NULL)
+ {
+ while ((dirlist = readdir (dir)) != NULL)
+ {
+ if (strstr (dirlist->d_name, ".pk3") == NULL)
+ continue;
+ sprintf(cWork, "%s/%s", pBasePath, dirlist->d_name);
+ OpenPakFile(cWork);
+ }
+ closedir (dir);
+ }
+#endif
+#ifdef _WIN32
+ char cWork[WORK_LEN];
+ Str strPath(pBasePath);
+ AddSlash(strPath);
+ strPath += "*.pk3";
+ bool bGo = true;
+ struct _finddata_t fileinfo;
+ int handle = _findfirst (strPath, &fileinfo);
+ if (handle != -1)
+ {
+ do
+ {
+ sprintf(cWork, "%s/%s", pBasePath, fileinfo.name);
+ OpenPakFile(cWork);
+ } while (_findnext( handle, &fileinfo ) != -1);
+ _findclose (handle);
+ }
+#endif
+ }
+ else
+ {
+ OpenPakFile(pName);
+ }
+}
+