static bool VerifyFile( const std::string &filename, std::string &base_filename, std::string &full_filename, const std::string &hash = "") { std::string ext; M_ExtractFileExtension(filename, ext); base_filename = D_CleanseFileName(filename); if (base_filename.empty()) return false; // is there an exact match for the filename and hash? full_filename = BaseFileSearch(base_filename, "." + ext, hash); if (!full_filename.empty()) return true; // is there a file with matching name even if the hash is incorrect? full_filename = BaseFileSearch(base_filename, "." + ext); if (full_filename.empty()) return false; // if it's an IWAD, check if we have a valid alternative hash std::string found_hash = W_MD5(full_filename); if (W_IsIWAD(base_filename, found_hash)) return true; return false; }
// // denis - BaseFileSearchDir // Check single paths for a given file with a possible extension // Case insensitive, but returns actual file name // std::string BaseFileSearchDir(std::string dir, std::string file, std::string ext, std::string hash = "") { std::string found; if(dir[dir.length() - 1] != PATHSEPCHAR) dir += PATHSEP; std::transform(hash.begin(), hash.end(), hash.begin(), toupper); std::string dothash = "."; if(hash.length()) dothash += hash; else dothash = ""; // denis - list files in the directory of interest, case-desensitize // then see if wanted wad is listed #ifdef UNIX // denis - todo -find a way to deal with dir="./" and file="DIR/DIR/FILE.WAD" struct dirent **namelist = 0; int n = scandir(dir.c_str(), &namelist, 0, alphasort); for(int i = 0; i < n && namelist[i]; i++) { std::string d_name = namelist[i]->d_name; M_Free(namelist[i]); if(!found.length()) { if(d_name == "." || d_name == "..") continue; std::string tmp = d_name; std::transform(tmp.begin(), tmp.end(), tmp.begin(), toupper); if(file == tmp || (file + ext) == tmp || (file + dothash) == tmp || (file + ext + dothash) == tmp) { std::string local_file = (dir + d_name).c_str(); std::string local_hash = W_MD5(local_file.c_str()); if(!hash.length() || hash == local_hash) { found = d_name; } else if(hash.length()) { Printf (PRINT_HIGH, "WAD at %s does not match required copy\n", local_file.c_str()); Printf (PRINT_HIGH, "Local MD5: %s\n", local_hash.c_str()); Printf (PRINT_HIGH, "Required MD5: %s\n\n", hash.c_str()); } } } } M_Free(namelist); #else if(dir[dir.length() - 1] != PATHSEPCHAR) dir += PATHSEP; std::string all_ext = dir + "*"; //all_ext += ext; WIN32_FIND_DATA FindFileData; HANDLE hFind = FindFirstFile(all_ext.c_str(), &FindFileData); DWORD dwError = GetLastError(); if (hFind == INVALID_HANDLE_VALUE) { Printf (PRINT_HIGH, "FindFirstFile failed for %s\n", all_ext.c_str()); Printf (PRINT_HIGH, "GetLastError: %d\n", dwError); return ""; } while (true) { if(!FindNextFile(hFind, &FindFileData)) { dwError = GetLastError(); if(dwError != ERROR_NO_MORE_FILES) Printf (PRINT_HIGH, "FindNextFile failed. GetLastError: %d\n", dwError); break; } if(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) continue; std::string tmp = FindFileData.cFileName; std::transform(tmp.begin(), tmp.end(), tmp.begin(), toupper); if(file == tmp || (file + ext) == tmp || (file + dothash) == tmp || (file + ext + dothash) == tmp) { std::string local_file = (dir + FindFileData.cFileName).c_str(); std::string local_hash = W_MD5(local_file.c_str()); if(!hash.length() || hash == local_hash) { found = FindFileData.cFileName; break; } else if(hash.length()) { Printf (PRINT_HIGH, "WAD at %s does not match required copy\n", local_file.c_str()); Printf (PRINT_HIGH, "Local MD5: %s\n", local_hash.c_str()); Printf (PRINT_HIGH, "Required MD5: %s\n\n", hash.c_str()); } } } FindClose(hFind); #endif return found; }
std::string W_AddFile (std::string filename) { wadinfo_t header; lumpinfo_t* lump_p; size_t i; FILE *handle; size_t length; size_t startlump; size_t res; filelump_t* fileinfo; filelump_t singleinfo; FixPathSeparator (filename); std::string name = filename; M_AppendExtension (name, ".wad"); // open the file if ( (handle = fopen (filename.c_str(), "rb")) == NULL) { Printf (PRINT_HIGH, " couldn't open %s\n", filename.c_str()); return ""; } Printf (PRINT_HIGH, "adding %s\n", filename.c_str()); startlump = numlumps; res = fread (&header, sizeof(header), 1, handle); header.identification = LELONG(header.identification); if (header.identification != IWAD_ID && header.identification != PWAD_ID) { // raw lump file fileinfo = &singleinfo; singleinfo.filepos = 0; singleinfo.size = M_FileLength(handle); M_ExtractFileBase (filename, name); numlumps++; Printf (PRINT_HIGH, " (single lump)\n", header.numlumps); } else { // WAD file header.numlumps = LELONG(header.numlumps); header.infotableofs = LELONG(header.infotableofs); length = header.numlumps*sizeof(filelump_t); if(length > (unsigned)M_FileLength(handle)) { Printf (PRINT_HIGH, " bad number of lumps for %s\n", filename.c_str()); fclose(handle); return ""; } fileinfo = (filelump_t *)Z_Malloc (length, PU_STATIC, 0); fseek (handle, header.infotableofs, SEEK_SET); res = fread (fileinfo, length, 1, handle); numlumps += header.numlumps; Printf (PRINT_HIGH, " (%d lumps)\n", header.numlumps); } // Fill in lumpinfo lumpinfo = (lumpinfo_t *)Realloc (lumpinfo, numlumps*sizeof(lumpinfo_t)); if (!lumpinfo) I_Error ("Couldn't realloc lumpinfo"); lump_p = &lumpinfo[startlump]; for (i=startlump ; i<numlumps ; i++,lump_p++, fileinfo++) { lump_p->handle = handle; lump_p->position = LELONG(fileinfo->filepos); lump_p->size = LELONG(fileinfo->size); strncpy (lump_p->name, fileinfo->name, 8); // W_CheckNumForName needs all lump names in upper case std::transform(lump_p->name, lump_p->name+8, lump_p->name, toupper); } return W_MD5(filename); }
// // denis - BaseFileSearchDir // Check single paths for a given file with a possible extension // Case insensitive, but returns actual file name // std::string BaseFileSearchDir(std::string dir, std::string file, std::string ext, std::string hash = "") { std::string found; if(dir[dir.length() - 1] != PATHSEPCHAR) dir += PATHSEP; std::transform(hash.begin(), hash.end(), hash.begin(), toupper); std::string dothash = "."; if(hash.length()) dothash += hash; else dothash = ""; // denis - list files in the directory of interest, case-desensitize // then see if wanted wad is listed #ifdef UNIX struct dirent **namelist = 0; int n = scandir(dir.c_str(), &namelist, 0, alphasort); for(int i = 0; i < n && namelist[i]; i++) { std::string d_name = namelist[i]->d_name; M_Free(namelist[i]); if(!found.length()) { if(d_name == "." || d_name == "..") continue; std::string tmp = d_name; std::transform(tmp.begin(), tmp.end(), tmp.begin(), toupper); if(file == tmp || (file + ext) == tmp || (file + dothash) == tmp || (file + ext + dothash) == tmp) { std::string local_file = (dir + d_name).c_str(); std::string local_hash = W_MD5(local_file.c_str()); if(!hash.length() || hash == local_hash) { found = d_name; } else if(hash.length()) { Printf (PRINT_HIGH, "WAD at %s does not match required copy\n", local_file.c_str()); Printf (PRINT_HIGH, "Local MD5: %s\n", local_hash.c_str()); Printf (PRINT_HIGH, "Required MD5: %s\n\n", hash.c_str()); } } } } M_Free(namelist); #else std::string all_ext = dir + "*"; //all_ext += ext; WIN32_FIND_DATA FindFileData; HANDLE hFind = FindFirstFile(all_ext.c_str(), &FindFileData); DWORD dwError = GetLastError(); if (hFind == INVALID_HANDLE_VALUE) { Printf (PRINT_HIGH, "FindFirstFile failed for %s\n", all_ext.c_str()); Printf (PRINT_HIGH, "GetLastError: %d\n", dwError); return ""; } do { if(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) continue; std::string tmp = FindFileData.cFileName; std::transform(tmp.begin(), tmp.end(), tmp.begin(), toupper); if(file == tmp || (file + ext) == tmp || (file + dothash) == tmp || (file + ext + dothash) == tmp) { std::string local_file = (dir + FindFileData.cFileName).c_str(); std::string local_hash = W_MD5(local_file.c_str()); if(!hash.length() || hash == local_hash) { found = FindFileData.cFileName; break; } else if(hash.length()) { Printf (PRINT_HIGH, "WAD at %s does not match required copy\n", local_file.c_str()); Printf (PRINT_HIGH, "Local MD5: %s\n", local_hash.c_str()); Printf (PRINT_HIGH, "Required MD5: %s\n\n", hash.c_str()); } } } while(FindNextFile(hFind, &FindFileData)); dwError = GetLastError(); // Note: As documented, FindNextFile sets ERROR_NO_MORE_FILES as the error // code, but when this function "fails" it does not set it we have to assume // that it completed successfully (this is actually bad practice, because // it says in the docs that it does not set ERROR_SUCCESS, even though // GetLastError returns 0) WTF DO WE DO?! if(dwError != ERROR_SUCCESS && dwError != ERROR_NO_MORE_FILES) Printf (PRINT_HIGH, "FindNextFile failed. GetLastError: %d\n", dwError); FindClose(hFind); #endif return found; }
std::vector<size_t> D_DoomWadReboot( const std::vector<std::string> &wadnames, const std::vector<std::string> &patch_files, std::vector<std::string> needhashes ) { std::vector<size_t> fails; size_t i; // already loaded these? if (lastWadRebootSuccess && !wadhashes.empty() && needhashes == std::vector<std::string>(wadhashes.begin()+1, wadhashes.end())) { // fast track if files have not been changed // denis - todo - actually check the file timestamps Printf (PRINT_HIGH, "Currently loaded WADs match server checksum\n\n"); return std::vector<size_t>(); } // assume failure lastWadRebootSuccess = false; if (modifiedgame && (gameinfo.flags & GI_SHAREWARE)) I_Error ("\nYou cannot switch WAD with the shareware version. Register!"); if(gamestate == GS_LEVEL) G_ExitLevel(0, 0); AM_Stop(); S_Stop(); DThinker::DestroyAllThinkers(); // Close all open WAD files W_Close(); // [ML] 9/11/10: Reset custom wad level information from MAPINFO et al. // I have never used memset, I hope I am not invoking satan by doing this :( if (wadlevelinfos) { for (i = 0; i < numwadlevelinfos; i++) if (wadlevelinfos[i].snapshot) { delete wadlevelinfos[i].snapshot; wadlevelinfos[i].snapshot = NULL; } memset(wadlevelinfos,0,sizeof(wadlevelinfos)); numwadlevelinfos = 0; } if (wadclusterinfos) { memset(wadclusterinfos,0,sizeof(wadclusterinfos)); numwadclusterinfos = 0; } // Restart the memory manager Z_Init(); gamestate_t oldgamestate = gamestate; gamestate = GS_STARTUP; // prevent console from trying to use nonexistant font wadfiles.clear(); modifiedgame = false; std::string custwad; if(wadnames.empty() == false) custwad = wadnames[0]; D_AddDefWads(custwad); for(i = 0; i < wadnames.size(); i++) { std::string tmp = wadnames[i]; // strip absolute paths, as they present a security risk FixPathSeparator(tmp); size_t slash = tmp.find_last_of(PATHSEPCHAR); if(slash != std::string::npos) tmp = tmp.substr(slash + 1, tmp.length() - slash); // [Russell] - Generate a hash if it doesn't exist already if (needhashes[i].empty()) needhashes[i] = W_MD5(tmp); std::string file = BaseFileSearch(tmp, ".wad", needhashes[i]); if(file.length()) wadfiles.push_back(file); else { Printf (PRINT_HIGH, "could not find WAD: %s\n", tmp.c_str()); fails.push_back(i); } } if(wadnames.size() > 1) modifiedgame = true; wadhashes = W_InitMultipleFiles (wadfiles); UndoDehPatch(); // [RH] Initialize localizable strings. GStrings.ResetStrings (); GStrings.Compact (); D_DoDefDehackedPatch(patch_files); //gotconback = false; //C_InitConsole(DisplayWidth, DisplayHeight, true); HU_Init (); if(!(DefaultPalette = InitPalettes("PLAYPAL"))) I_Error("Could not reinitialize palette"); V_InitPalette(); G_SetLevelStrings (); G_ParseMapInfo (); G_ParseMusInfo (); S_ParseSndInfo(); M_Init(); R_Init(); P_InitEffects(); // [ML] Do this here so we don't have to put particle crap in server P_Init(); S_Init (snd_sfxvolume, snd_musicvolume); ST_Init(); // preserve state lastWadRebootSuccess = fails.empty(); gamestate = oldgamestate; // GS_STARTUP would prevent netcode connecting properly return fails; }
// // W_AddFile // // All files are optional, but at least one file must be found // (PWAD, if all required lumps are present). // Files with a .wad extension are wadlink files with multiple lumps. // Other files are single lumps with the base filename for the lump name. // // Map reloads are supported through WAD reload so no need for vanilla tilde // reload hack here // std::string W_AddFile(std::string filename) { FILE* handle; filelump_t* fileinfo; FixPathSeparator(filename); if ( (handle = fopen(filename.c_str(), "rb")) == NULL) { Printf(PRINT_HIGH, "couldn't open %s\n", filename.c_str()); return ""; } Printf(PRINT_HIGH, "adding %s", filename.c_str()); size_t newlumps; wadinfo_t header; fread(&header, sizeof(header), 1, handle); header.identification = LELONG(header.identification); if (header.identification != IWAD_ID && header.identification != PWAD_ID) { // raw lump file std::string lumpname; M_ExtractFileBase(filename, lumpname); fileinfo = new filelump_t[1]; fileinfo->filepos = 0; fileinfo->size = M_FileLength(handle); std::transform(lumpname.c_str(), lumpname.c_str() + 8, fileinfo->name, toupper); newlumps = 1; Printf(PRINT_HIGH, " (single lump)\n"); } else { // WAD file header.numlumps = LELONG(header.numlumps); header.infotableofs = LELONG(header.infotableofs); size_t length = header.numlumps * sizeof(filelump_t); if (length > (unsigned)M_FileLength(handle)) { Printf(PRINT_HIGH, "\nbad number of lumps for %s\n", filename.c_str()); fclose(handle); return ""; } fileinfo = new filelump_t[header.numlumps]; fseek(handle, header.infotableofs, SEEK_SET); fread(fileinfo, length, 1, handle); // convert from little-endian to target arch and capitalize lump name for (int i = 0; i < header.numlumps; i++) { fileinfo[i].filepos = LELONG(fileinfo[i].filepos); fileinfo[i].size = LELONG(fileinfo[i].size); std::transform(fileinfo[i].name, fileinfo[i].name + 8, fileinfo[i].name, toupper); } newlumps = header.numlumps; Printf(PRINT_HIGH, " (%d lumps)\n", header.numlumps); } W_AddLumps(handle, fileinfo, newlumps, false); delete [] fileinfo; return W_MD5(filename); }
// // D_DoDefDehackedPatch // // [Russell] - Change the meaning, this will load multiple patch files if // specified void D_DoDefDehackedPatch (const std::vector<std::string> &newpatchfiles) { DArgs files; BOOL noDef = false; BOOL chexLoaded = false; QWORD i; if (!newpatchfiles.empty()) { std::string f; std::string ext; // we want the extension of the file for (i = 0; i < newpatchfiles.size(); i++) { if (M_ExtractFileExtension(newpatchfiles[i], ext)) { f = BaseFileSearch(newpatchfiles[i], ext); if (f.length()) { if (DoDehPatch (f.c_str(), false)) { std::string Filename; M_ExtractFileName(f, Filename); patchfiles.push_back(Filename); } noDef = true; } } } } else // [Russell] - Only load if newpatchfiles is empty { // try .deh files on command line files = Args.GatherFiles ("-deh", ".deh", false); if (files.NumArgs()) { for (i = 0; i < files.NumArgs(); i++) { std::string f = BaseFileSearch (files.GetArg (i), ".DEH"); if (f.length()) { if (DoDehPatch (f.c_str(), false)) { std::string Filename; M_ExtractFileName(f, Filename); patchfiles.push_back(Filename); } if (!strncmp(files.GetArg(i),"chex.deh", 8)) chexLoaded = true; } } noDef = true; } if (gamemode == retail_chex && !multiplayer && !chexLoaded) Printf(PRINT_HIGH,"Warning: chex.deh not loaded, experience may differ from the original!\n"); // remove the old arguments files.FlushArgs(); // try .bex files on command line files = Args.GatherFiles ("-bex", ".bex", false); if (files.NumArgs()) { for (i = 0; i < files.NumArgs(); i++) { std::string f = BaseFileSearch (files.GetArg (i), ".BEX"); if (f.length()) { if (DoDehPatch (f.c_str(), false)) { std::string Filename; M_ExtractFileName(f, Filename); patchfiles.push_back(Filename); } } } noDef = true; } } // try default patches if (!noDef) DoDehPatch (NULL, true); // See if there's a patch in a PWAD for (size_t i = 0; i < patchfiles.size(); i++) patchhashes.push_back(W_MD5(patchfiles[i])); }