summaryrefslogtreecommitdiff
path: root/src/d_iwad.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/d_iwad.c')
-rw-r--r--src/d_iwad.c637
1 files changed, 637 insertions, 0 deletions
diff --git a/src/d_iwad.c b/src/d_iwad.c
new file mode 100644
index 00000000..6f7bff70
--- /dev/null
+++ b/src/d_iwad.c
@@ -0,0 +1,637 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 2006 Simon Howard
+//
+// This program 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.
+//
+// This program 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 this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+// Search for and locate an IWAD file, and initialise according
+// to the IWAD type.
+//
+//-----------------------------------------------------------------------------
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+
+#include "deh_str.h"
+#include "doomkeys.h"
+#include "d_iwad.h"
+#include "i_system.h"
+#include "m_argv.h"
+#include "m_config.h"
+#include "m_misc.h"
+#include "w_wad.h"
+#include "z_zone.h"
+
+// Array of locations to search for IWAD files
+//
+// "128 IWAD search directories should be enough for anybody".
+
+#define MAX_IWAD_DIRS 128
+
+static boolean iwad_dirs_built = false;
+static char *iwad_dirs[MAX_IWAD_DIRS];
+static int num_iwad_dirs = 0;
+
+static void AddIWADDir(char *dir)
+{
+ if (num_iwad_dirs < MAX_IWAD_DIRS)
+ {
+ iwad_dirs[num_iwad_dirs] = dir;
+ ++num_iwad_dirs;
+ }
+}
+
+// This is Windows-specific code that automatically finds the location
+// of installed IWAD files. The registry is inspected to find special
+// keys installed by the Windows installers for various CD versions
+// of Doom. From these keys we can deduce where to find an IWAD.
+
+#ifdef _WIN32
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+typedef struct
+{
+ HKEY root;
+ char *path;
+ char *value;
+} registry_value_t;
+
+#define UNINSTALLER_STRING "\\uninstl.exe /S "
+
+// Keys installed by the various CD editions. These are actually the
+// commands to invoke the uninstaller and look like this:
+//
+// C:\Program Files\Path\uninstl.exe /S C:\Program Files\Path
+//
+// With some munging we can find where Doom was installed.
+
+static registry_value_t uninstall_values[] =
+{
+ // Ultimate Doom, CD version (Depths of Doom trilogy)
+
+ {
+ HKEY_LOCAL_MACHINE,
+ "Software\\Microsoft\\Windows\\CurrentVersion\\"
+ "Uninstall\\Ultimate Doom for Windows 95",
+ "UninstallString",
+ },
+
+ // Doom II, CD version (Depths of Doom trilogy)
+
+ {
+ HKEY_LOCAL_MACHINE,
+ "Software\\Microsoft\\Windows\\CurrentVersion\\"
+ "Uninstall\\Doom II for Windows 95",
+ "UninstallString",
+ },
+
+ // Final Doom
+
+ {
+ HKEY_LOCAL_MACHINE,
+ "Software\\Microsoft\\Windows\\CurrentVersion\\"
+ "Uninstall\\Final Doom for Windows 95",
+ "UninstallString",
+ },
+
+ // Shareware version
+
+ {
+ HKEY_LOCAL_MACHINE,
+ "Software\\Microsoft\\Windows\\CurrentVersion\\"
+ "Uninstall\\Doom Shareware for Windows 95",
+ "UninstallString",
+ },
+};
+
+// Value installed by the Collector's Edition when it is installed
+
+static registry_value_t collectors_edition_value =
+{
+ HKEY_LOCAL_MACHINE,
+ "Software\\Activision\\DOOM Collector's Edition\\v1.0",
+ "INSTALLPATH",
+};
+
+// Subdirectories of the above install path, where IWADs are installed.
+
+static char *collectors_edition_subdirs[] =
+{
+ "Doom2",
+ "Final Doom",
+ "Ultimate Doom",
+};
+
+// Location where Steam is installed
+
+static registry_value_t steam_install_location =
+{
+ HKEY_LOCAL_MACHINE,
+ "Software\\Valve\\Steam",
+ "InstallPath",
+};
+
+// Subdirs of the steam install directory where IWADs are found
+
+static char *steam_install_subdirs[] =
+{
+ "steamapps\\common\\doom 2\\base",
+ "steamapps\\common\\final doom\\base",
+ "steamapps\\common\\ultimate doom\\base",
+};
+
+static char *GetRegistryString(registry_value_t *reg_val)
+{
+ HKEY key;
+ DWORD len;
+ DWORD valtype;
+ char *result;
+
+ // Open the key (directory where the value is stored)
+
+ if (RegOpenKeyEx(reg_val->root, reg_val->path, 0, KEY_READ, &key)
+ != ERROR_SUCCESS)
+ {
+ return NULL;
+ }
+
+ // Find the type and length of the string
+
+ if (RegQueryValueEx(key, reg_val->value, NULL, &valtype, NULL, &len)
+ != ERROR_SUCCESS)
+ {
+ return NULL;
+ }
+
+ // Only accept strings
+
+ if (valtype != REG_SZ)
+ {
+ return NULL;
+ }
+
+ // Allocate a buffer for the value and read the value
+
+ result = malloc(len);
+
+ if (RegQueryValueEx(key, reg_val->value, NULL, &valtype, (unsigned char *) result, &len)
+ != ERROR_SUCCESS)
+ {
+ free(result);
+ return NULL;
+ }
+
+ // Close the key
+
+ RegCloseKey(key);
+
+ return result;
+}
+
+// Check for the uninstall strings from the CD versions
+
+static void CheckUninstallStrings(void)
+{
+ unsigned int i;
+
+ for (i=0; i<arrlen(uninstall_values); ++i)
+ {
+ char *val;
+ char *path;
+ char *unstr;
+
+ val = GetRegistryString(&uninstall_values[i]);
+
+ if (val == NULL)
+ {
+ continue;
+ }
+
+ unstr = strstr(val, UNINSTALLER_STRING);
+
+ if (unstr == NULL)
+ {
+ free(val);
+ }
+ else
+ {
+ path = unstr + strlen(UNINSTALLER_STRING);
+
+ AddIWADDir(path);
+ }
+ }
+}
+
+// Check for Doom: Collector's Edition
+
+static void CheckCollectorsEdition(void)
+{
+ char *install_path;
+ char *subpath;
+ unsigned int i;
+
+ install_path = GetRegistryString(&collectors_edition_value);
+
+ if (install_path == NULL)
+ {
+ return;
+ }
+
+ for (i=0; i<arrlen(collectors_edition_subdirs); ++i)
+ {
+ subpath = malloc(strlen(install_path)
+ + strlen(collectors_edition_subdirs[i])
+ + 5);
+
+ sprintf(subpath, "%s\\%s", install_path, collectors_edition_subdirs[i]);
+
+ AddIWADDir(subpath);
+ }
+
+ free(install_path);
+}
+
+
+// Check for Doom downloaded via Steam
+
+static void CheckSteamEdition(void)
+{
+ char *install_path;
+ char *subpath;
+ size_t i;
+
+ install_path = GetRegistryString(&steam_install_location);
+
+ if (install_path == NULL)
+ {
+ return;
+ }
+
+ for (i=0; i<arrlen(steam_install_subdirs); ++i)
+ {
+ subpath = malloc(strlen(install_path)
+ + strlen(steam_install_subdirs[i]) + 5);
+
+ sprintf(subpath, "%s\\%s", install_path, steam_install_subdirs[i]);
+
+ AddIWADDir(subpath);
+ }
+}
+
+// Default install directories for DOS Doom
+
+static void CheckDOSDefaults(void)
+{
+ // These are the default install directories used by the deice
+ // installer program:
+
+ AddIWADDir("\\doom2"); // Doom II
+ AddIWADDir("\\plutonia"); // Final Doom
+ AddIWADDir("\\tnt");
+ AddIWADDir("\\doom_se"); // Ultimate Doom
+ AddIWADDir("\\doom"); // Shareware / Registered Doom
+ AddIWADDir("\\dooms"); // Shareware versions
+ AddIWADDir("\\doomsw");
+}
+
+#endif
+
+// Search a directory to try to find an IWAD
+// Returns the location of the IWAD if found, otherwise NULL.
+
+static char *SearchDirectoryForIWAD(char *dir, iwad_t *iwads,
+ GameMission_t *mission)
+{
+ size_t i;
+
+ for (i=0; iwads[i].name != NULL; ++i)
+ {
+ char *filename;
+ char *iwadname;
+
+ iwadname = DEH_String(iwads[i].name);
+
+ filename = malloc(strlen(dir) + strlen(iwadname) + 3);
+
+ if (!strcmp(dir, "."))
+ {
+ strcpy(filename, iwadname);
+ }
+ else
+ {
+ sprintf(filename, "%s%c%s", dir, DIR_SEPARATOR, iwadname);
+ }
+
+ if (M_FileExists(filename))
+ {
+ *mission = iwads[i].mission;
+
+ return filename;
+ }
+
+ free(filename);
+ }
+
+ return NULL;
+}
+
+// When given an IWAD with the '-iwad' parameter,
+// attempt to identify it by its name.
+
+static GameMission_t IdentifyIWADByName(char *name, iwad_t *iwads)
+{
+ size_t i;
+ GameMission_t mission;
+
+ mission = none;
+
+ for (i=0; iwads[i].name != NULL; ++i)
+ {
+ char *iwadname;
+
+ iwadname = DEH_String(iwads[i].name);
+
+ if (strlen(name) < strlen(iwadname))
+ continue;
+
+ // Check if it ends in this IWAD name.
+
+ if (!strcasecmp(name + strlen(name) - strlen(iwadname),
+ iwadname))
+ {
+ mission = iwads[i].mission;
+ break;
+ }
+ }
+
+ return mission;
+}
+
+//
+// Add directories from the list in the DOOMWADPATH environment variable.
+//
+
+static void AddDoomWadPath(void)
+{
+ char *doomwadpath;
+ char *p;
+
+ // Check the DOOMWADPATH environment variable.
+
+ doomwadpath = getenv("DOOMWADPATH");
+
+ if (doomwadpath == NULL)
+ {
+ return;
+ }
+
+ doomwadpath = strdup(doomwadpath);
+
+ // Add the initial directory
+
+ AddIWADDir(doomwadpath);
+
+ // Split into individual dirs within the list.
+
+ p = doomwadpath;
+
+ for (;;)
+ {
+ p = strchr(p, PATH_SEPARATOR);
+
+ if (p != NULL)
+ {
+ // Break at the separator and store the right hand side
+ // as another iwad dir
+
+ *p = '\0';
+ p += 1;
+
+ AddIWADDir(p);
+ }
+ else
+ {
+ break;
+ }
+ }
+}
+
+
+//
+// Build a list of IWAD files
+//
+
+static void BuildIWADDirList(void)
+{
+ char *doomwaddir;
+
+ if (iwad_dirs_built)
+ {
+ return;
+ }
+
+ // Look in the current directory. Doom always does this.
+
+ AddIWADDir(".");
+
+ // Add DOOMWADDIR if it is in the environment
+
+ doomwaddir = getenv("DOOMWADDIR");
+
+ if (doomwaddir != NULL)
+ {
+ AddIWADDir(doomwaddir);
+ }
+
+ // Add dirs from DOOMWADPATH
+
+ AddDoomWadPath();
+
+#ifdef _WIN32
+
+ // Search the registry and find where IWADs have been installed.
+
+ CheckUninstallStrings();
+ CheckCollectorsEdition();
+ CheckSteamEdition();
+ CheckDOSDefaults();
+
+#else
+
+ // Standard places where IWAD files are installed under Unix.
+
+ AddIWADDir("/usr/share/games/doom");
+ AddIWADDir("/usr/local/share/games/doom");
+
+#endif
+
+ // Don't run this function again.
+
+ iwad_dirs_built = true;
+}
+
+//
+// Searches WAD search paths for an WAD with a specific filename.
+//
+
+char *D_FindWADByName(char *name)
+{
+ char *buf;
+ int i;
+ boolean exists;
+
+ // Absolute path?
+
+ if (M_FileExists(name))
+ {
+ return name;
+ }
+
+ BuildIWADDirList();
+
+ // Search through all IWAD paths for a file with the given name.
+
+ for (i=0; i<num_iwad_dirs; ++i)
+ {
+ // Construct a string for the full path
+
+ buf = malloc(strlen(iwad_dirs[i]) + strlen(name) + 5);
+ sprintf(buf, "%s%c%s", iwad_dirs[i], DIR_SEPARATOR, name);
+
+ exists = M_FileExists(buf);
+
+ if (exists)
+ {
+ return buf;
+ }
+
+ free(buf);
+ }
+
+ // File not found
+
+ return NULL;
+}
+
+//
+// D_TryWADByName
+//
+// Searches for a WAD by its filename, or passes through the filename
+// if not found.
+//
+
+char *D_TryFindWADByName(char *filename)
+{
+ char *result;
+
+ result = D_FindWADByName(filename);
+
+ if (result != NULL)
+ {
+ return result;
+ }
+ else
+ {
+ return filename;
+ }
+}
+
+//
+// FindIWAD
+// Checks availability of IWAD files by name,
+// to determine whether registered/commercial features
+// should be executed (notably loading PWADs).
+//
+
+char *D_FindIWAD(iwad_t *iwads, GameMission_t *mission)
+{
+ char *result;
+ char *iwadfile;
+ int iwadparm;
+ int i;
+
+ // Check for the -iwad parameter
+
+ //!
+ // Specify an IWAD file to use.
+ //
+ // @arg <file>
+ //
+
+ iwadparm = M_CheckParm("-iwad");
+
+ if (iwadparm)
+ {
+ // Search through IWAD dirs for an IWAD with the given name.
+
+ iwadfile = myargv[iwadparm + 1];
+
+ result = D_FindWADByName(iwadfile);
+
+ if (result == NULL)
+ {
+ I_Error("IWAD file '%s' not found!", iwadfile);
+ }
+
+ *mission = IdentifyIWADByName(result, iwads);
+ }
+ else
+ {
+ // Search through the list and look for an IWAD
+
+ result = NULL;
+
+ BuildIWADDirList();
+
+ for (i=0; result == NULL && i<num_iwad_dirs; ++i)
+ {
+ result = SearchDirectoryForIWAD(iwad_dirs[i], iwads, mission);
+ }
+ }
+
+ return result;
+}
+
+// Clever hack: Setup can invoke Doom to determine which IWADs are installed.
+// Doom searches install paths and exits with the return code being a
+// bitmask of the installed IWAD files.
+
+void D_FindInstalledIWADs(iwad_t *iwads)
+{
+ unsigned int i;
+ int result;
+
+ BuildIWADDirList();
+
+ result = 0;
+
+ for (i=0; i<arrlen(iwads); ++i)
+ {
+ if (D_FindWADByName(iwads[i].name) != NULL)
+ {
+ result |= 1 << i;
+ }
+ }
+
+ exit(result);
+}
+