aboutsummaryrefslogtreecommitdiff
path: root/archive/hge/resource.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'archive/hge/resource.cpp')
-rw-r--r--archive/hge/resource.cpp394
1 files changed, 394 insertions, 0 deletions
diff --git a/archive/hge/resource.cpp b/archive/hge/resource.cpp
new file mode 100644
index 0000000..4937ee1
--- /dev/null
+++ b/archive/hge/resource.cpp
@@ -0,0 +1,394 @@
+/*
+** Haaf's Game Engine 1.8
+** Copyright (C) 2003-2007, Relish Games
+** hge.relishgames.com
+**
+** Core functions implementation: resources management
+*/
+
+#include "hge_impl.h"
+
+#include <zlib.h> // the system version is better here. HGE's is out of date.
+
+#define NOCRYPT
+//#define NOUNCRYPT
+#include "ZLIB/unzip.h"
+
+
+bool CALL HGE_Impl::Resource_AttachPack(const char *filename, const char *password)
+{
+ char *szName;
+ CResourceList *resItem=res;
+ unzFile zip;
+
+ szName=Resource_MakePath(filename);
+
+ while(resItem)
+ {
+ if(!strcmp(szName,resItem->filename)) return false;
+ resItem=resItem->next;
+ }
+
+ zip=unzOpen(szName);
+ if(!zip) {
+ System_Log("Unable to unzip: %s", szName);
+ return false;
+ }
+ unzClose(zip);
+
+ resItem=new CResourceList;
+ strcpy(resItem->filename, szName);
+ if(password) strcpy(resItem->password, password);
+ else resItem->password[0]=0;
+ resItem->next=res;
+ res=resItem;
+
+ return true;
+}
+
+void CALL HGE_Impl::Resource_RemovePack(const char *filename)
+{
+ char *szName;
+ CResourceList *resItem=res, *resPrev=0;
+
+ szName=Resource_MakePath(filename);
+
+ while(resItem)
+ {
+ if(!strcmp(szName,resItem->filename))
+ {
+ if(resPrev) resPrev->next=resItem->next;
+ else res=resItem->next;
+ delete resItem;
+ break;
+ }
+
+ resPrev=resItem;
+ resItem=resItem->next;
+ }
+}
+
+void CALL HGE_Impl::Resource_RemoveAllPacks()
+{
+ CResourceList *resItem=res, *resNextItem;
+
+ while(resItem)
+ {
+ resNextItem=resItem->next;
+ delete resItem;
+ resItem=resNextItem;
+ }
+
+ res=0;
+}
+
+void* CALL HGE_Impl::Resource_Load(const char *filename, DWORD *size)
+{
+ const char *res_err="Can't load resource: %s";
+
+ CResourceList *resItem=res;
+ char szName[_MAX_PATH];
+ char szZipName[_MAX_PATH];
+ unzFile zip;
+ unz_file_info file_info;
+ int done, i;
+ void *ptr;
+ FILE *hF;
+
+ if(filename[0]=='\\' || filename[0]=='/' || filename[1]==':') goto _fromfile; // skip absolute paths
+
+ // Load from pack
+
+ strcpy(szName,filename);
+ for(i=0; szName[i]; i++) { if(szName[i]=='/') szName[i]='\\'; }
+
+ while(resItem)
+ {
+ zip=unzOpen(resItem->filename);
+ done=unzGoToFirstFile(zip);
+ while(done==UNZ_OK)
+ {
+ unzGetCurrentFileInfo(zip, &file_info, szZipName, sizeof(szZipName), NULL, 0, NULL, 0);
+ for(i=0; szZipName[i]; i++) { if(szZipName[i]=='/') szZipName[i]='\\'; }
+ if(!strcmp(szName,szZipName))
+ {
+ if(unzOpenCurrentFilePassword(zip, resItem->password[0] ? resItem->password : 0) != UNZ_OK)
+ {
+ unzClose(zip);
+ sprintf(szName, res_err, filename);
+ _PostError(szName);
+ return 0;
+ }
+
+ ptr = malloc(file_info.uncompressed_size);
+ if(!ptr)
+ {
+ unzCloseCurrentFile(zip);
+ unzClose(zip);
+ sprintf(szName, res_err, filename);
+ _PostError(szName);
+ return 0;
+ }
+
+ if(unzReadCurrentFile(zip, ptr, file_info.uncompressed_size) < 0)
+ {
+ unzCloseCurrentFile(zip);
+ unzClose(zip);
+ free(ptr);
+ sprintf(szName, res_err, filename);
+ _PostError(szName);
+ return 0;
+ }
+ unzCloseCurrentFile(zip);
+ unzClose(zip);
+ if(size) *size=file_info.uncompressed_size;
+ return ptr;
+ }
+
+ done=unzGoToNextFile(zip);
+ }
+
+ unzClose(zip);
+ resItem=resItem->next;
+ }
+
+ // Load from file
+_fromfile:
+
+ hF = fopen(Resource_MakePath(filename), "rb");
+ if(hF == NULL)
+ {
+ sprintf(szName, res_err, filename);
+ _PostError(szName);
+ return 0;
+ }
+
+ struct stat statbuf;
+ if (fstat(fileno(hF), &statbuf) == -1)
+ {
+ fclose(hF);
+ sprintf(szName, res_err, filename);
+ _PostError(szName);
+ return 0;
+ }
+
+ file_info.uncompressed_size = statbuf.st_size;
+ ptr = malloc(file_info.uncompressed_size);
+ if(!ptr)
+ {
+ fclose(hF);
+ sprintf(szName, res_err, filename);
+ _PostError(szName);
+ return 0;
+ }
+ if(fread(ptr, file_info.uncompressed_size, 1, hF) != 1)
+ {
+ fclose(hF);
+ free(ptr);
+ sprintf(szName, res_err, filename);
+ _PostError(szName);
+ return 0;
+ }
+
+ fclose(hF);
+
+ if(size) *size=file_info.uncompressed_size;
+ return ptr;
+}
+
+
+void CALL HGE_Impl::Resource_Free(void *res)
+{
+ if(res) free(res);
+}
+
+// this is from PhysicsFS originally ( http://icculus.org/physfs/ )
+// (also zlib-licensed.)
+static int locateOneElement(char *buf)
+{
+ char *ptr = NULL;
+ DIR *dirp = NULL;
+ struct dirent *dent = NULL;
+
+ if (access(buf, F_OK) == 0)
+ return 1; /* quick rejection: exists in current case. */
+
+ ptr = strrchr(buf, '/'); /* find entry at end of path. */
+ if (ptr == NULL)
+ {
+ dirp = opendir(".");
+ ptr = buf;
+ }
+ else
+ {
+ *ptr = '\0';
+ dirp = opendir(buf);
+ *ptr = '/';
+ ptr++; /* point past dirsep to entry itself. */
+ }
+
+ while ((dent = readdir(dirp)) != NULL)
+ {
+ if (strcasecmp(dent->d_name, ptr) == 0)
+ {
+ strcpy(ptr, dent->d_name); /* found a match. Overwrite with this case. */
+ closedir(dirp);
+ return 1;
+ }
+ }
+
+ /* no match at all... */
+ closedir(dirp);
+ return 0;
+}
+
+static int locateCorrectCase(char *buf)
+{
+ char *ptr = buf;
+
+ while ((ptr = strchr(ptr + 1, '/')))
+ {
+ *ptr = '\0'; /* block this path section off */
+ if (!locateOneElement(buf))
+ {
+ *ptr = '/'; /* restore path separator */
+ return -2; /* missing element in path. */
+ }
+ *ptr = '/'; /* restore path separator */
+ }
+
+ /* check final element... */
+ return locateOneElement(buf) ? 0 : -1;
+}
+
+char* CALL HGE_Impl::Resource_MakePath(const char *filename)
+{
+ int i;
+
+ if(!filename)
+ strcpy(szTmpFilename, szAppPath);
+ else if(filename[0]=='\\' || filename[0]=='/' || filename[1]==':')
+ strcpy(szTmpFilename, filename);
+ else
+ {
+ strcpy(szTmpFilename, szAppPath);
+ if(filename) strcat(szTmpFilename, filename);
+ }
+
+ for(i=0; szTmpFilename[i]; i++) { if(szTmpFilename[i]=='\\') szTmpFilename[i]='/'; }
+
+ locateCorrectCase(szTmpFilename);
+
+ return szTmpFilename;
+}
+
+// !!! FIXME: kinda messy, and probably doesn't get all the corner cases right.
+bool HGE_Impl::_WildcardMatch(const char *str, const char *wildcard)
+{
+ if ((str == NULL) || (wildcard == NULL))
+ return false;
+
+ while ((*str) && (*wildcard))
+ {
+ const char wildch = *wildcard;
+ const char strch = *str;
+ if (wildch == '?')
+ ; // okay.
+ else if (wildch == '*')
+ {
+ do {
+ wildcard++;
+ } while (((*wildcard == '*') || (*wildcard == '?')) && (*wildcard != '\0'));
+ const char newwild = *wildcard;
+ if (newwild == '\0') return true;
+ const char *ptr = str;
+ while (*ptr) // find the greediest match possible...
+ {
+ if (*ptr == newwild)
+ str = ptr;
+ ptr++;
+ }
+ }
+ else if ( (toupper(strch)) != (toupper(wildch)) )
+ {
+ return false;
+ }
+
+ str++;
+ wildcard++;
+ }
+
+ while (*wildcard == '*')
+ wildcard++;
+
+ return ((*str == '\0') && (*wildcard == '\0'));
+}
+
+bool HGE_Impl::_PrepareFileEnum(const char *wildcard)
+{
+ if(hSearch) { closedir(hSearch); hSearch=0; }
+ char *madepath = Resource_MakePath(wildcard);
+ const char *fname = strrchr(madepath, '/');
+ const char *dir = NULL;
+ if (fname == NULL) {
+ dir = ".";
+ fname = madepath;
+ } else {
+ dir = madepath;
+ char *ptr = (char *) fname;
+ *ptr = '\0'; // split dir and filename.
+ fname++;
+ }
+
+ strcpy(szSearchDir, dir);
+ strcpy(szSearchWildcard, fname);
+
+ hSearch=opendir(dir);
+ return (hSearch!=0);
+}
+
+char *HGE_Impl::_DoEnumIteration(const bool wantdir)
+{
+ if(!hSearch) return 0;
+ while (true)
+ {
+ struct dirent *dent = readdir(hSearch);
+ if(dent == NULL) { closedir(hSearch); hSearch=0; return 0; }
+ if ((strcmp(dent->d_name, ".") == 0) || (strcmp(dent->d_name, "..") == 0))
+ continue;
+ if (!_WildcardMatch(dent->d_name, szSearchWildcard))
+ continue;
+ char fullpath[_MAX_PATH];
+ snprintf(fullpath, sizeof (fullpath), "%s/%s", szSearchDir, dent->d_name);
+ struct stat statbuf;
+ if (stat(fullpath, &statbuf) == -1) // this follows symlinks.
+ continue;
+ const bool isdir = ((S_ISDIR(statbuf.st_mode)) != 0);
+ if (isdir == wantdir) // this treats pipes, devs, etc, as "files" ...
+ {
+ strcpy(szSearchResult, dent->d_name);
+ return szSearchResult;
+ }
+ }
+ return 0;
+}
+
+char* CALL HGE_Impl::Resource_EnumFiles(const char *wildcard)
+{
+ if(wildcard)
+ {
+ if (!_PrepareFileEnum(wildcard))
+ return 0;
+ }
+ return _DoEnumIteration(false);
+}
+
+char* CALL HGE_Impl::Resource_EnumFolders(const char *wildcard)
+{
+ if(wildcard)
+ {
+ if (!_PrepareFileEnum(wildcard))
+ return 0;
+ }
+ return _DoEnumIteration(true);
+}