mirror of
https://github.com/spiffcode/hostile-takeover.git
synced 2026-04-15 01:01:29 -06:00
Update SdlPackFile I/O
SdlPackFile can now push and pop directories using host file I/O. This allows for reading from directories as though they were .pdbs (like the htdata2432 dir) while maintaining the pushed hierarchy. pdbs can still be used.
This commit is contained in:
parent
2ef0ab5ae8
commit
5d7e0ddf3c
@ -1,11 +1,30 @@
|
||||
#include "game/sdl/sdlpackfile.h"
|
||||
#include "game/mempdbreader.h"
|
||||
#include "game/sdl/hosthelpers.h"
|
||||
#include "inc/rip.h"
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <dirent.h>
|
||||
#include <iostream>
|
||||
|
||||
namespace wi {
|
||||
|
||||
bool FileIsOpen(File *pfil) {
|
||||
if (pfil != NULL)
|
||||
if (pfil->prnfo != NULL)
|
||||
if (pfil->prnfo->cOpen > 0)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
SdlPackFileReader::~SdlPackFileReader()
|
||||
{
|
||||
while (Pop())
|
||||
;
|
||||
}
|
||||
|
||||
PdbReader *SdlPackFileReader::OpenPdb(const char *pszDir,
|
||||
const char *pszFn) {
|
||||
// Load data from this directory
|
||||
@ -15,8 +34,10 @@ PdbReader *SdlPackFileReader::OpenPdb(const char *pszDir,
|
||||
strcpy(szT, pszDir);
|
||||
strcat(szT, "/");
|
||||
strcat(szT, pszFn);
|
||||
} else {
|
||||
} else if (pszFn != NULL) {
|
||||
strcpy(szT, pszFn);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
// PdbReader over memory
|
||||
@ -49,4 +70,255 @@ bool SdlPackFileReader::DeletePdb(const char *pszDir, const char *pszFn) {
|
||||
return true;
|
||||
}
|
||||
|
||||
File *SdlPackFileReader::fopen(const char *pszFn, const char *pszMode) {
|
||||
if (pszFn == NULL)
|
||||
return NULL;
|
||||
|
||||
// Only support read binary mode
|
||||
|
||||
if (strcmp(pszMode, "rb") != 0)
|
||||
return NULL;
|
||||
|
||||
// Go through the reader infos in reverse order
|
||||
|
||||
for (std::vector<SdlReaderInfo *>::reverse_iterator it = m_vrnfo.rbegin(); it != m_vrnfo.rend(); it++) {
|
||||
|
||||
// Is this reader a pdb?
|
||||
|
||||
if ((*it)->pszPdb != NULL) {
|
||||
if (!strchr(pszFn, '/') && strlen(pszFn) <= kcbFilename) {
|
||||
File *pfil = PackFileReader::fopen(pszFn, pszMode);
|
||||
if (pfil != NULL)
|
||||
return pfil;
|
||||
}
|
||||
|
||||
// If couldn't load from pdb, continute to next reader
|
||||
continue;
|
||||
}
|
||||
|
||||
// Not pdb, load from dir
|
||||
|
||||
char pszFnFull[PATH_MAX];
|
||||
sprintf(pszFnFull, "%s/%s", (*it)->pszDir, pszFn);
|
||||
|
||||
// Open with host I/O
|
||||
|
||||
File *pfil = new File();
|
||||
pfil->pvData = HostOpenFile(pszFnFull, kfOfRead);
|
||||
if (!pfil->pvData)
|
||||
continue;
|
||||
|
||||
// Set prevalent info
|
||||
|
||||
HostSeekFile(pfil->pvData, 0, kfSeekEnd);
|
||||
pfil->cbTotal = HostTellFile(pfil->pvData);
|
||||
HostSeekFile(pfil->pvData, 0, kfSeekSet);
|
||||
|
||||
return pfil;
|
||||
}
|
||||
|
||||
LOG() << "can't find file " << pszFn;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int SdlPackFileReader::fclose(File *pfil) {
|
||||
if (!FileIsOpen(pfil))
|
||||
HostCloseFile(pfil->pvData);
|
||||
|
||||
if (FileIsOpen(pfil))
|
||||
PackFileReader::fclose(pfil);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
dword SdlPackFileReader::fread(void *pv, dword cb, int c, File *pfil) {
|
||||
if (FileIsOpen(pfil))
|
||||
return PackFileReader::fread(pv, cb, c, pfil);
|
||||
|
||||
dword cbT = cb * c;
|
||||
dword cbR = c * HostReadFile(pv, c, cb, pfil->pvData);
|
||||
cbT -= cbR;
|
||||
return cbT == 0 ? c : cbR / cb;
|
||||
}
|
||||
|
||||
int SdlPackFileReader::fseek(File *pfil, int off, int nOrigin) {
|
||||
if (FileIsOpen(pfil))
|
||||
return PackFileReader::fseek(pfil, off, nOrigin);
|
||||
|
||||
return HostSeekFile(pfil->pvData, off, nOrigin) != -1 ? 0 : -1;
|
||||
}
|
||||
|
||||
dword SdlPackFileReader::ftell(File *pfil) {
|
||||
if (FileIsOpen(pfil))
|
||||
return PackFileReader::ftell(pfil);
|
||||
|
||||
return HostTellFile(pfil->pvData);
|
||||
}
|
||||
|
||||
bool SdlPackFileReader::EnumFiles(Enum *penm, int key, char *pszFn, int cbFn) {
|
||||
// PACKENUM_LAST will enum the top pdb
|
||||
// PACKENUM_FIRST will endum the bottom dir
|
||||
|
||||
if (key == PACKENUM_LAST)
|
||||
return PackFileReader::EnumFiles(penm, key, pszFn, cbFn);
|
||||
|
||||
if (key != PACKENUM_FIRST)
|
||||
return false;
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
return HostHelpers::EnumFiles(penm, key, pszFn, cbFn);
|
||||
#else
|
||||
if (penm->m_pvNext == (void *)kEnmFirst) {
|
||||
DIR *dir;
|
||||
dir = opendir(BottomDir());
|
||||
|
||||
penm->m_pvNext = (void *)dir;
|
||||
penm->m_dwUser = 0;
|
||||
}
|
||||
|
||||
DIR *dir = (DIR *)penm->m_pvNext;
|
||||
struct dirent *ent;
|
||||
if ((ent = readdir(dir)) != NULL) {
|
||||
strncpyz(pszFn, ent->d_name, cbFn);
|
||||
penm->m_dwUser++;
|
||||
return true;
|
||||
}
|
||||
closedir(dir);
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void *SdlPackFileReader::MapFile(const char *pszFn, FileMap *pfmap, dword *pcb) {
|
||||
if (!strchr(pszFn, '/') && strlen(pszFn) <= kcbFilename) {
|
||||
void *pv = PackFileReader::MapFile(pszFn, pfmap, pcb);
|
||||
if (pv != NULL)
|
||||
return pv;
|
||||
}
|
||||
|
||||
byte *pb = NULL;
|
||||
File *pfil = this->fopen(pszFn, "rb");
|
||||
if (pfil == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
this->fseek(pfil, 0, SEEK_END);
|
||||
dword cb = ftell(pfil);
|
||||
this->fseek(pfil, 0, SEEK_SET);
|
||||
pb = new byte[cb];
|
||||
if (pb == NULL) {
|
||||
this->fclose(pfil);
|
||||
return NULL;
|
||||
}
|
||||
if (this->fread(pb, cb, 1, pfil) != 1) {
|
||||
this->fclose(pfil);
|
||||
return NULL;
|
||||
}
|
||||
pfmap->pbAlloced = pb;
|
||||
if (pcb != NULL) {
|
||||
*pcb = cb;
|
||||
}
|
||||
this->fclose(pfil);
|
||||
|
||||
return pb;
|
||||
}
|
||||
|
||||
void SdlPackFileReader::UnmapFile(FileMap *pfmap) {
|
||||
if (pfmap != NULL)
|
||||
if (pfmap->prnfo != NULL)
|
||||
if (pfmap->prnfo->cOpen > 0)
|
||||
PackFileReader::UnmapFile(pfmap);
|
||||
|
||||
if (pfmap->pbAlloced != NULL)
|
||||
delete[] pfmap->pbAlloced;
|
||||
}
|
||||
|
||||
bool SdlPackFileReader::Push(const char *pszDir, const char *pszFn) {
|
||||
if (pszDir == NULL && pszFn == NULL)
|
||||
return false;
|
||||
|
||||
SdlReaderInfo *prnfo = new SdlReaderInfo();
|
||||
|
||||
prnfo->pszDir = NULL;
|
||||
if (pszDir != NULL)
|
||||
prnfo->pszDir = AllocString(pszDir);
|
||||
|
||||
prnfo->pszPdb = NULL;
|
||||
if (pszFn != NULL)
|
||||
prnfo->pszPdb = AllocString(pszFn);
|
||||
|
||||
// If we have pszFn then we are pushing a pdb
|
||||
|
||||
if (pszFn != NULL) {
|
||||
bool fSuccess = PackFileReader::Push(pszDir, pszFn);
|
||||
if (fSuccess)
|
||||
m_vrnfo.push_back(prnfo);
|
||||
return fSuccess;
|
||||
}
|
||||
|
||||
// Push the dir if it exists
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
wi::HostHelpers::DirExists(prnfo->pszDir);
|
||||
#else
|
||||
DIR *pdir;
|
||||
if ((pdir = opendir(pszDir)) == NULL) {
|
||||
return false;
|
||||
} else {
|
||||
closedir(pdir);
|
||||
}
|
||||
#endif
|
||||
|
||||
m_vrnfo.push_back(prnfo);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SdlPackFileReader::Pop() {
|
||||
|
||||
// Anything to pop?
|
||||
|
||||
if (m_vrnfo.empty())
|
||||
return false;
|
||||
|
||||
// Pop an actual pdb?
|
||||
|
||||
bool fPdbRet = false;
|
||||
bool fPdb = false;
|
||||
if (m_vrnfo.back()->pszPdb != NULL) {
|
||||
fPdb = true;
|
||||
fPdbRet = PackFileReader::Pop();
|
||||
}
|
||||
|
||||
// Pdb pop fail?
|
||||
|
||||
if (fPdb && !fPdbRet)
|
||||
return false;
|
||||
|
||||
// Either a dir, or a successfully poped pdb, pop it off the vector
|
||||
|
||||
delete[] m_vrnfo.back()->pszDir;
|
||||
delete[] m_vrnfo.back()->pszPdb;
|
||||
m_vrnfo.pop_back();
|
||||
return true;
|
||||
}
|
||||
|
||||
char *SdlPackFileReader::BottomDir() {
|
||||
for (std::vector<SdlReaderInfo *>::reverse_iterator it = m_vrnfo.rbegin();
|
||||
it != m_vrnfo.rend(); it++) {
|
||||
|
||||
if ((*it)->pszDir != NULL && (*it)->pszPdb == NULL)
|
||||
return (*it)->pszDir;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *SdlPackFileReader::BottomPdb() {
|
||||
for (std::vector<SdlReaderInfo *>::reverse_iterator it = m_vrnfo.rbegin();
|
||||
it != m_vrnfo.rend(); it++) {
|
||||
|
||||
if ((*it)->pszPdb != NULL)
|
||||
return (*it)->pszPdb;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
} // namespace wi
|
||||
|
||||
@ -3,14 +3,42 @@
|
||||
|
||||
#include "inc/basictypes.h"
|
||||
#include "mpshared/packfile.h"
|
||||
#include <stdio.h>
|
||||
#include <vector>
|
||||
|
||||
namespace wi {
|
||||
|
||||
struct SdlReaderInfo {
|
||||
char *pszDir;
|
||||
char *pszPdb;
|
||||
};
|
||||
|
||||
class SdlPackFileReader : public PackFileReader
|
||||
{
|
||||
public:
|
||||
~SdlPackFileReader();
|
||||
|
||||
virtual File *fopen(const char *pszFn, const char *pszMode);
|
||||
virtual int fclose(File *pfil);
|
||||
virtual dword fread(void *pv, dword cb, int c, File *pfil);
|
||||
virtual int fseek(File *pfil, int off, int nOrigin);
|
||||
virtual dword ftell(File *pfil);
|
||||
|
||||
virtual bool EnumFiles(Enum *penm, int key, char *pszFn, int cbFn);
|
||||
virtual void *MapFile(const char *pszFn, FileMap *pfmap, dword *pcb = NULL);
|
||||
virtual void UnmapFile(FileMap *pfmap);
|
||||
|
||||
virtual bool Push(const char *pszDir, const char *pszFn);
|
||||
virtual bool Pop();
|
||||
|
||||
char *BottomDir();
|
||||
char *BottomPdb();
|
||||
|
||||
private:
|
||||
virtual PdbReader *OpenPdb(const char *pszDir, const char *pszFn);
|
||||
virtual bool DeletePdb(const char *pszDir, const char *pszFn);
|
||||
|
||||
std::vector<SdlReaderInfo *> m_vrnfo;
|
||||
};
|
||||
|
||||
} // namespace wi
|
||||
|
||||
@ -72,7 +72,9 @@ File *PackFileReader::fopen(const char *pszFn, const char *pszMode)
|
||||
ReaderInfo *prnfo;
|
||||
DirEntry dir;
|
||||
if (!FindDirEntry(pszFn, &dir, &prnfo)) {
|
||||
#if !defined(SDL)
|
||||
LOG() << "can't find dir entry " << pszFn;
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -362,6 +364,7 @@ void PackFileReader::UnmapFile(FileMap *pfmap)
|
||||
pfmap->prnfo->cOpen--;
|
||||
if (pfmap->pbAlloced != NULL) {
|
||||
delete[] pfmap->pbAlloced;
|
||||
pfmap->pbAlloced = NULL;
|
||||
} else {
|
||||
pfmap->prnfo->ppdbReader->UnmapRecord(pfmap->nRec, pfmap->pvCookie);
|
||||
}
|
||||
|
||||
@ -99,6 +99,7 @@ struct File
|
||||
byte cRecs;
|
||||
word nRecFirst;
|
||||
word acb[1];
|
||||
void *pvData;
|
||||
};
|
||||
|
||||
// Used for MapFile / UnmapFile
|
||||
@ -122,20 +123,20 @@ public:
|
||||
PackFileReader();
|
||||
~PackFileReader();
|
||||
|
||||
File *fopen(const char *pszFn, const char *pszMode);
|
||||
int fclose(File *pfil);
|
||||
dword fread(void *pv, dword cb, int c, File *pfil);
|
||||
int fseek(File *pfil, int off, int nOrigin);
|
||||
dword ftell(File *pfil);
|
||||
bool EnumFiles(Enum *penm, int key, char *pszFn, int cbFn);
|
||||
void *MapFile(const char *pszFn, FileMap *pfmap, dword *pcb = NULL);
|
||||
void UnmapFile(FileMap *pfmap);
|
||||
virtual File *fopen(const char *pszFn, const char *pszMode);
|
||||
virtual int fclose(File *pfil);
|
||||
virtual dword fread(void *pv, dword cb, int c, File *pfil);
|
||||
virtual int fseek(File *pfil, int off, int nOrigin);
|
||||
virtual dword ftell(File *pfil);
|
||||
virtual bool EnumFiles(Enum *penm, int key, char *pszFn, int cbFn);
|
||||
virtual void *MapFile(const char *pszFn, FileMap *pfmap, dword *pcb = NULL);
|
||||
virtual void UnmapFile(FileMap *pfmap);
|
||||
bool HashFile(const char *pszFn, byte *hash);
|
||||
bool GetPdbName(const char *pszFn, char *pszPdb, int cbPdb,
|
||||
char *pszDir = NULL, int cbDir = 0);
|
||||
|
||||
bool Push(const char *pszDir, const char *pszFn);
|
||||
bool Pop();
|
||||
virtual bool Push(const char *pszDir, const char *pszFn);
|
||||
virtual bool Pop();
|
||||
bool Delete(const char *pszDir, const char *pszFn);
|
||||
|
||||
private:
|
||||
|
||||
Loading…
Reference in New Issue
Block a user