Detect appended data to the DP executable.
authordivverent <divverent@d7cf8633-e32d-0410-b094-e92efae38249>
Sun, 28 Feb 2010 19:10:37 +0000 (19:10 +0000)
committerdivverent <divverent@d7cf8633-e32d-0410-b094-e92efae38249>
Sun, 28 Feb 2010 19:10:37 +0000 (19:10 +0000)
If it's a pk3, it is added FIRST (TODO: should this be LAST) into the search path.
If it contains a darkplaces.opt text file, its contents are parsed and used as extra command line arguments.

git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@10034 d7cf8633-e32d-0410-b094-e92efae38249

common.c
common.h
fs.c
fs.h
host.c
sys.h
sys_linux.c
sys_sdl.c
sys_shared.c
sys_win.c

index ad5f5ab..a9b21b6 100644 (file)
--- a/common.c
+++ b/common.c
@@ -33,6 +33,7 @@ cvar_t cmdline = {0, "cmdline","0", "contains commandline the engine was launche
 char com_token[MAX_INPUTLINE];
 int com_argc;
 const char **com_argv;
+int com_selffd = -1;
 
 gamemode_t gamemode;
 const char *gamename;
index 45cf7de..4c7165c 100644 (file)
--- a/common.h
+++ b/common.h
@@ -204,6 +204,7 @@ int COM_ParseToken_Console(const char **datapointer);
 
 extern int com_argc;
 extern const char **com_argv;
+extern int com_selffd;
 
 int COM_CheckParm (const char *parm);
 void COM_Init (void);
diff --git a/fs.c b/fs.c
index cbcf7c0..c9e6d56 100644 (file)
--- a/fs.c
+++ b/fs.c
@@ -232,6 +232,7 @@ typedef struct pk3_endOfCentralDir_s
        unsigned int cdir_size;                 ///< size of the central directory
        unsigned int cdir_offset;               ///< with respect to the starting disk number
        unsigned short comment_size;
+       fs_offset_t prepended_garbage;
 } pk3_endOfCentralDir_t;
 
 
@@ -327,6 +328,7 @@ const char *const fs_checkgamedir_missing = "missing";
 char fs_userdir[MAX_OSPATH];
 char fs_gamedir[MAX_OSPATH];
 char fs_basedir[MAX_OSPATH];
+static pack_t *fs_selfpack = NULL;
 
 // list of active game directories (empty if not running a mod)
 int fs_numgamedirs = 0;
@@ -527,6 +529,8 @@ qboolean PK3_GetEndOfCentralDir (const char *packfile, int packhandle, pk3_endOf
        eocd->cdir_size = LittleLong (eocd->cdir_size);
        eocd->cdir_offset = LittleLong (eocd->cdir_offset);
        eocd->comment_size = LittleShort (eocd->comment_size);
+       eocd->prepended_garbage = filesize - (ind + ZIP_END_CDIR_SIZE) - eocd->cdir_offset - eocd->cdir_size; // this detects "SFX" zip files
+       eocd->cdir_offset += eocd->prepended_garbage;
 
        Mem_Free (buffer);
 
@@ -620,7 +624,7 @@ int PK3_BuildFileList (pack_t *pack, const pk3_endOfCentralDir_t *eocd)
                                        flags = PACKFILE_FLAG_DEFLATED;
                                else
                                        flags = 0;
-                               offset = BuffLittleLong (&ptr[42]);
+                               offset = BuffLittleLong (&ptr[42]) + eocd->prepended_garbage;
                                packsize = BuffLittleLong (&ptr[20]);
                                realsize = BuffLittleLong (&ptr[24]);
 
@@ -661,21 +665,12 @@ FS_LoadPackPK3
 Create a package entry associated with a PK3 file
 ====================
 */
-pack_t *FS_LoadPackPK3 (const char *packfile)
+pack_t *FS_LoadPackPK3FromFD (const char *packfile, int packhandle)
 {
-       int packhandle;
        pk3_endOfCentralDir_t eocd;
        pack_t *pack;
        int real_nb_files;
 
-#if _MSC_VER >= 1400
-       _sopen_s(&packhandle, packfile, O_RDONLY | O_BINARY, _SH_DENYNO, _S_IREAD | _S_IWRITE);
-#else
-       packhandle = open (packfile, O_RDONLY | O_BINARY);
-#endif
-       if (packhandle < 0)
-               return NULL;
-
        if (! PK3_GetEndOfCentralDir (packfile, packhandle, &eocd))
        {
                Con_Printf ("%s is not a PK3 file\n", packfile);
@@ -722,6 +717,18 @@ pack_t *FS_LoadPackPK3 (const char *packfile)
        Con_DPrintf("Added packfile %s (%i files)\n", packfile, real_nb_files);
        return pack;
 }
+pack_t *FS_LoadPackPK3 (const char *packfile)
+{
+       int packhandle;
+#if _MSC_VER >= 1400
+       _sopen_s(&packhandle, packfile, O_RDONLY | O_BINARY, _SH_DENYNO, _S_IREAD | _S_IWRITE);
+#else
+       packhandle = open (packfile, O_RDONLY | O_BINARY);
+#endif
+       if (packhandle < 0)
+               return NULL;
+       return FS_LoadPackPK3FromFD(packfile, packhandle);
+}
 
 
 /*
@@ -1251,7 +1258,7 @@ void FS_ClearSearchPath (void)
        {
                searchpath_t *search = fs_searchpaths;
                fs_searchpaths = search->next;
-               if (search->pack)
+               if (search->pack && search->pack != fs_selfpack)
                {
                        if(!search->pack->vpack)
                        {
@@ -1267,6 +1274,18 @@ void FS_ClearSearchPath (void)
        }
 }
 
+static void FS_AddSelfPack(void)
+{
+       if(fs_selfpack)
+       {
+               searchpath_t *search;
+               search = Mem_Alloc(fs_mempool, sizeof(searchpath_t));
+               search->next = fs_searchpaths;
+               search->pack = fs_selfpack;
+               fs_searchpaths = search;
+       }
+}
+
 
 /*
 ================
@@ -1313,6 +1332,9 @@ void FS_Rescan (void)
        }
        Cvar_SetQuick(&cvar_fs_gamedir, gamedirbuf); // so QC or console code can query it
 
+       // add back the selfpack as new first item
+       FS_AddSelfPack();
+
        // set the default screenshot name to either the mod name or the
        // gamemode screenshot name
        if (strcmp(com_modname, gamedirname1))
@@ -1577,6 +1599,56 @@ static void FS_ListGameDirs(void)
        }
 }
 
+/*
+================
+FS_Init_SelfPack
+================
+*/
+void FS_Init_SelfPack (void)
+{
+       PK3_OpenLibrary ();
+       fs_mempool = Mem_AllocPool("file management", 0, NULL);
+       if(com_selffd >= 0)
+       {
+               fs_selfpack = FS_LoadPackPK3FromFD(com_argv[0], com_selffd);
+               if(fs_selfpack)
+               {
+                       char *buf, *q;
+                       const char *p;
+                       FS_AddSelfPack();
+                       buf = (char *) FS_LoadFile("darkplaces.opt", tempmempool, true, NULL);
+                       if(buf)
+                       {
+                               const char **new_argv;
+                               int i = 0;
+                               int args_left = 256;
+                               if(com_argc == 0)
+                               {
+                                       com_argv[0] = "dummy";
+                                       com_argv[1] = NULL;
+                                       com_argc = 1;
+                               }
+                               new_argv = Mem_Alloc(fs_mempool, sizeof(*com_argv) * (com_argc + args_left + 1));
+                               p = buf;
+                               while(COM_ParseToken_Console(&p))
+                               {
+                                       if(i >= args_left)
+                                               break;
+                                       q = Mem_Alloc(fs_mempool, strlen(com_token) + 1);
+                                       strlcpy(q, com_token, strlen(com_token) + 1);
+                                       new_argv[i+1] = q;
+                                       ++i;
+                               }
+                               new_argv[0] = com_argv[0];
+                               memcpy(&new_argv[i+2], &com_argv[1], sizeof(*com_argv) * com_argc);
+                               com_argv = new_argv;
+                               com_argc = com_argc + i;
+                       }
+                       Mem_Free(buf);
+               }
+       }
+}
+
 /*
 ================
 FS_Init
@@ -1604,8 +1676,6 @@ void FS_Init (void)
        // don't care for the result; if it fails, %USERPROFILE% will be used instead
 #endif
 
-       fs_mempool = Mem_AllocPool("file management", 0, NULL);
-
        // Add the personal game directory
        if((i = COM_CheckParm("-userdir")) && i < com_argc - 1)
        {
@@ -1694,8 +1764,6 @@ void FS_Init (void)
 #endif
 #endif
 
-       PK3_OpenLibrary ();
-
        // -basedir <path>
        // Overrides the system supplied base directory (under GAMENAME)
 // COMMANDLINEOPTION: Filesystem: -basedir <path> chooses what base directory the game data is in, inside this there should be a data directory for the game (for example id1)
@@ -1782,16 +1850,9 @@ void FS_Shutdown (void)
 #endif
 }
 
-/*
-====================
-FS_SysOpen
-
-Internal function used to create a qfile_t and open the relevant non-packed file on disk
-====================
-*/
-static qfile_t* FS_SysOpen (const char* filepath, const char* mode, qboolean nonblocking)
+int FS_SysOpenFD(const char *filepath, const char *mode, qboolean nonblocking)
 {
-       qfile_t* file;
+       int handle;
        int mod, opt;
        unsigned int ind;
 
@@ -1812,7 +1873,7 @@ static qfile_t* FS_SysOpen (const char* filepath, const char* mode, qboolean non
                        break;
                default:
                        Con_Printf ("FS_SysOpen(%s, %s): invalid mode\n", filepath, mode);
-                       return NULL;
+                       return -1;
        }
        for (ind = 1; mode[ind] != '\0'; ind++)
        {
@@ -1833,15 +1894,28 @@ static qfile_t* FS_SysOpen (const char* filepath, const char* mode, qboolean non
        if (nonblocking)
                opt |= O_NONBLOCK;
 
-       file = (qfile_t *)Mem_Alloc (fs_mempool, sizeof (*file));
-       memset (file, 0, sizeof (*file));
-       file->ungetc = EOF;
-
 #if _MSC_VER >= 1400
-       _sopen_s(&file->handle, filepath, mod | opt, _SH_DENYNO, _S_IREAD | _S_IWRITE);
+       _sopen_s(&handle, filepath, mod | opt, _SH_DENYNO, _S_IREAD | _S_IWRITE);
 #else
-       file->handle = open (filepath, mod | opt, 0666);
+       handle = open (filepath, mod | opt, 0666);
 #endif
+       return handle;
+}
+
+/*
+====================
+FS_SysOpen
+
+Internal function used to create a qfile_t and open the relevant non-packed file on disk
+====================
+*/
+static qfile_t* FS_SysOpen (const char* filepath, const char* mode, qboolean nonblocking)
+{
+       qfile_t* file;
+
+       file = (qfile_t *)Mem_Alloc (fs_mempool, sizeof (*file));
+       file->ungetc = EOF;
+       file->handle = FS_SysOpenFD(filepath, mode, nonblocking);
        if (file->handle < 0)
        {
                Mem_Free (file);
@@ -1851,7 +1925,7 @@ static qfile_t* FS_SysOpen (const char* filepath, const char* mode, qboolean non
        file->real_length = lseek (file->handle, 0, SEEK_END);
 
        // For files opened in append mode, we start at the end of the file
-       if (mod & O_APPEND)
+       if (mode[0] == 'a')
                file->position = file->real_length;
        else
                lseek (file->handle, 0, SEEK_SET);
diff --git a/fs.h b/fs.h
index 78909aa..65ee54e 100644 (file)
--- a/fs.h
+++ b/fs.h
@@ -57,6 +57,7 @@ extern char fs_gamedirs[MAX_GAMEDIRS][MAX_QPATH];
 
 qboolean FS_AddPack(const char *pakfile, qboolean *already_loaded, qboolean keep_plain_dirs); // already_loaded may be NULL if caller does not care
 const char *FS_WhichPack(const char *filename);
+int FS_SysOpenFD(const char *filepath, const char *mode, qboolean nonblocking);
 qfile_t* FS_OpenRealFile (const char* filepath, const char* mode, qboolean quiet);
 qfile_t* FS_OpenVirtualFile (const char* filepath, qboolean quiet);
 qfile_t* FS_FileFromData (const unsigned char *data, const size_t size, qboolean quiet);
diff --git a/host.c b/host.c
index f90173f..e51b391 100644 (file)
--- a/host.c
+++ b/host.c
@@ -1006,6 +1006,7 @@ qboolean sys_nostdout = false;
 extern void u8_Init(void);
 extern void Render_Init(void);
 extern void Mathlib_Init(void);
+extern void FS_Init_SelfPack(void);
 extern void FS_Init(void);
 extern void FS_Shutdown(void);
 extern void PR_Cmd_Init(void);
@@ -1083,6 +1084,9 @@ static void Host_Init (void)
        // initialize console window (only used by sys_win.c)
        Sys_InitConsole();
 
+       // initialize the self-pack (must be before COM_InitGameType as it may add command line options)
+       FS_Init_SelfPack();
+
        // detect gamemode from commandline options or executable name
        COM_InitGameType();
 
diff --git a/sys.h b/sys.h
index 5a9831a..37fcc80 100644 (file)
--- a/sys.h
+++ b/sys.h
@@ -86,6 +86,8 @@ void Sys_AllowProfiling (qboolean enable);
 
 double Sys_DoubleTime (void);
 
+void Sys_ProvideSelfFD (void);
+
 char *Sys_ConsoleInput (void);
 
 /// called to yield for a little bit so as not to hog cpu when paused or debugging
index 269d2b9..167121a 100644 (file)
@@ -146,6 +146,7 @@ int main (int argc, char **argv)
 
        com_argc = argc;
        com_argv = (const char **)argv;
+       Sys_ProvideSelfFD();
 
 #ifdef FNDELAY
        fcntl(0, F_SETFL, fcntl (0, F_GETFL, 0) | FNDELAY);
index d0efa83..724eb79 100644 (file)
--- a/sys_sdl.c
+++ b/sys_sdl.c
@@ -168,6 +168,7 @@ int main (int argc, char *argv[])
 
        com_argc = argc;
        com_argv = (const char **)argv;
+       Sys_ProvideSelfFD();
 
 #ifndef WIN32
        fcntl(0, F_SETFL, fcntl (0, F_GETFL, 0) | FNDELAY);
index b2a712f..3b83a49 100644 (file)
@@ -421,3 +421,57 @@ void Sys_Sleep(int microseconds)
                printf("%d %d # debugsleep\n", microseconds, (unsigned int)(t * 1000000));
        }
 }
+
+const char *Sys_FindInPATH(const char *name, char namesep, const char *PATH, char pathsep, char *buf, size_t bufsize)
+{
+       const char *p = PATH;
+       const char *q;
+       if(p && name)
+       {
+               while((q = strchr(p, ':')))
+               {
+                       dpsnprintf(buf, bufsize, "%.*s%c%s", (int)(q-p), p, namesep, name);
+                       if(FS_SysFileExists(buf))
+                               return buf;
+                       p = q + 1;
+               }
+               if(!q) // none found - try the last item
+               {
+                       dpsnprintf(buf, bufsize, "%s%c%s", p, namesep, name);
+                       if(FS_SysFileExists(buf))
+                               return buf;
+               }
+       }
+       return name;
+}
+
+const char *Sys_FindExecutableName(void)
+{
+#if defined(WIN32)
+       return com_argv[0];
+#else
+       static char exenamebuf[MAX_OSPATH+1];
+       ssize_t n = -1;
+#if defined(__FreeBSD__)
+       n = readlink("/proc/curproc/file", exenamebuf, sizeof(exenamebuf)-1);
+#elif defined(__linux__)
+       n = readlink("/proc/self/exe", exenamebuf, sizeof(exenamebuf)-1);
+#endif
+       if(n > 0 && (size_t)(n) < sizeof(exenamebuf))
+       {
+               exenamebuf[n] = 0;
+               return exenamebuf;
+       }
+       if(strchr(com_argv[0], '/'))
+               return com_argv[0]; // possibly a relative path
+       else
+               return Sys_FindInPATH(com_argv[0], '/', getenv("PATH"), ':', exenamebuf, sizeof(exenamebuf));
+#endif
+}
+
+void Sys_ProvideSelfFD(void)
+{
+       if(com_selffd != -1)
+               return;
+       com_selffd = FS_SysOpenFD(Sys_FindExecutableName(), "rb", false);
+}
index 2ed54ab..4adaf69 100644 (file)
--- a/sys_win.c
+++ b/sys_win.c
@@ -355,6 +355,8 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin
                }
        }
 
+       Sys_ProvideSelfFD();
+
        Host_Main();
 
        /* return success of application */