diff options
Diffstat (limited to 'src/d_iwad.c')
-rw-r--r-- | src/d_iwad.c | 637 |
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); +} + |