void GameDatabase::DeleteGame(const size_t index, const bool reload) { wxString file = FilePath::Data(DataFileGames); wxString keyfile = FilePath::Data(DataFileGameKeys); size_t size = NumGames(); // If there's only one game in the file, just delete the files. if(1 == size) { wxRemoveFile(file); wxRemoveFile(keyfile); } else { // If this is not the last game in the file, we'll have to extricate // it. if(index != (size - 1)) { // Get two temp file names to use for the atomic deletion. wxString tempfile, tempkeyfile; tempfile = wxFileName::CreateTempFileName(swGame); tempkeyfile = wxFileName::CreateTempFileName(swKeys); wxFileInputStream db(file); wxFileOutputStream tempdb(tempfile); wxFileOutputStream tempkey(tempkeyfile); size_t totalLength = db.GetSize(); size_t offset = 0; // Run through all the games in the db and save them to a temp file, // except for the one being deleted, then copy that temp file to the // desired file. for(size_t i = 0; i < size; i++) { //calculate the size of this data chunk size_t chunk; if(i < (size - 1)) { chunk = mOffsets[i + 1] - mOffsets[i]; } else { chunk = totalLength - mOffsets[i]; } // Just copy raw data instead of loading and adding. boost::scoped_array<wxUint8> bytes(new wxUint8[chunk]); db.Read(bytes.get(), chunk); // Skip the one we're deleting. if(i != index) { tempdb.Write(bytes.get(), chunk); tempkey.Write(&offset, 4); offset += chunk; } } // Copy the temp files onto the real files. wxCopyFile(tempfile, file); wxCopyFile(tempkeyfile, keyfile); } // Otherwise, we can just truncate the file. else { wxFile in(file, wxFile::read); size_t chunk = mOffsets[index]; boost::scoped_array<wxUint8> bytes(new wxUint8[chunk]); in.Read(bytes.get(), chunk); in.Close(); // Now just write them back out. wxFile out(file, wxFile::write); out.Write(bytes.get(), chunk); out.Close(); // Repeat with the key file. in.Open(keyfile, wxFile::read); chunk = in.Length() - sizeof(size_t); bytes.reset(new wxUint8[chunk]); in.Read(bytes.get(), chunk); in.Close(); out.Open(keyfile, wxFile::write); out.Write(bytes.get(), chunk); out.Close(); } } if(true == reload) { InitializeDatabase(); } }
/* ================== Host_Game_f ================== */ void Host_Game_f (void) { int i; unsigned int path_id; searchpath_t *search = com_searchpaths; pack_t *pak; char pakfile[MAX_OSPATH]; //FIXME: it's confusing to use this string for two different things if (Cmd_Argc() > 1) { if (!registered.value) //disable command for shareware quake { Con_Printf("You must have the registered version to use modified games\n"); return; } if (strstr(Cmd_Argv(1), "..")) { Con_Printf ("Relative pathnames are not allowed.\n"); return; } q_strlcpy (pakfile, va("%s/%s", host_parms->basedir, Cmd_Argv(1)), sizeof(pakfile)); if (!Q_strcasecmp(pakfile, com_gamedir)) //no change { Con_Printf("\"game\" is already \"%s\"\n", COM_SkipPath(com_gamedir)); return; } com_modified = true; //Kill the server CL_Disconnect (); Host_ShutdownServer(true); //Write config file Host_WriteConfiguration (); //Kill the extra game if it is loaded if (NumGames(com_searchpaths) > 1 + com_nummissionpacks) KillGameDir(com_searchpaths); q_strlcpy (com_gamedir, pakfile, sizeof(com_gamedir)); if (Q_strcasecmp(Cmd_Argv(1), GAMENAME)) //game is not id1 { // assign a path_id to this game directory if (com_searchpaths) path_id = com_searchpaths->path_id << 1; else path_id = 1U; search = (searchpath_t *) Z_Malloc(sizeof(searchpath_t)); search->path_id = path_id; q_strlcpy (search->filename, pakfile, sizeof(search->filename)); search->next = com_searchpaths; com_searchpaths = search; //Load the paks if any are found: for (i = 0; ; i++) { q_snprintf (pakfile, sizeof(pakfile), "%s/pak%i.pak", com_gamedir, i); pak = COM_LoadPackFile (pakfile); if (!pak) break; search = (searchpath_t *) Z_Malloc(sizeof(searchpath_t)); search->path_id = path_id; search->pack = pak; search->next = com_searchpaths; com_searchpaths = search; } } //clear out and reload appropriate data Cache_Flush (); if (!isDedicated) { TexMgr_NewGame (); Draw_NewGame (); R_NewGame (); } ExtraMaps_NewGame (); //Cbuf_InsertText ("exec quake.rc\n"); Con_Printf("\"game\" changed to \"%s\"\n", COM_SkipPath(com_gamedir)); } else //Diplay the current gamedir Con_Printf("\"game\" is \"%s\"\n", COM_SkipPath(com_gamedir)); }