diff --git a/game/sdl/sdlpackfile.cpp b/game/sdl/sdlpackfile.cpp index 2c08ca1..f305666 100644 --- a/game/sdl/sdlpackfile.cpp +++ b/game/sdl/sdlpackfile.cpp @@ -1,11 +1,30 @@ #include "game/sdl/sdlpackfile.h" #include "game/mempdbreader.h" +#include "game/sdl/hosthelpers.h" #include "inc/rip.h" #include #include +#include +#include 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::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::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::reverse_iterator it = m_vrnfo.rbegin(); + it != m_vrnfo.rend(); it++) { + + if ((*it)->pszPdb != NULL) + return (*it)->pszPdb; + } + return NULL; +} + } // namespace wi diff --git a/game/sdl/sdlpackfile.h b/game/sdl/sdlpackfile.h index ac3a7ed..e3fba15 100644 --- a/game/sdl/sdlpackfile.h +++ b/game/sdl/sdlpackfile.h @@ -3,14 +3,42 @@ #include "inc/basictypes.h" #include "mpshared/packfile.h" +#include +#include 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 m_vrnfo; }; } // namespace wi diff --git a/mpshared/packfile.cpp b/mpshared/packfile.cpp index a9778bc..0a16658 100644 --- a/mpshared/packfile.cpp +++ b/mpshared/packfile.cpp @@ -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); } diff --git a/mpshared/packfile.h b/mpshared/packfile.h index c4c7d9c..937b32b 100644 --- a/mpshared/packfile.h +++ b/mpshared/packfile.h @@ -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: