Section pilot::BinaryFileHandler::nextSection() { Assertion(!_in_array, "nextSection() may not be called in an array!"); if (_section_start_pos != INVALID_SIZE && _section_end_pos != INVALID_SIZE) { cf_set_max_read_len(_cfp, 0); // There was a previous section auto current = (size_t)cftell(_cfp); if (current != _section_end_pos) { mprintf(("PLR => WARNING: Advancing to the next section. " SIZE_T_ARG " bytes were skipped!\n", _section_end_pos - current)); cfseek(_cfp, (int)_section_end_pos, CF_SEEK_SET); } _section_start_pos = INVALID_SIZE; _section_end_pos = INVALID_SIZE; } auto section_id = cfread_ushort(_cfp); auto size = cfread_uint(_cfp); if (size == 0) { return Section::Invalid; } _section_start_pos = (size_t)cftell(_cfp); _section_end_pos = _section_start_pos + size; cf_set_max_read_len(_cfp, size); return static_cast<Section>(section_id); }
void pilotfile::plr_read_controls() { int idx, list_size, list_axis; short id1, id2, id3; int axi, inv; list_size = (int)cfread_ushort(cfp); for (idx = 0; idx < list_size; idx++) { id1 = cfread_short(cfp); id2 = cfread_short(cfp); id3 = cfread_short(cfp); // unused, at the moment if (idx < CCFG_MAX) { Control_config[idx].key_id = id1; Control_config[idx].joy_id = id2; } } list_axis = cfread_int(cfp); for (idx = 0; idx < list_axis; idx++) { axi = cfread_int(cfp); inv = cfread_int(cfp); if (idx < NUM_JOY_AXIS_ACTIONS) { Axis_map_to[idx] = axi; Invert_axis[idx] = inv; } } }
void pilotfile::csg_read_controls() { int idx, list_size; short id1, id2, id3 __UNUSED; list_size = (int)cfread_ushort(cfp); for (idx = 0; idx < list_size; idx++) { id1 = cfread_short(cfp); id2 = cfread_short(cfp); id3 = cfread_short(cfp); // unused, at the moment if (idx < CCFG_MAX) { Control_config[idx].key_id = id1; Control_config[idx].joy_id = id2; } } }
void pilotfile_convert::csg_import_stats() { int list_size = 0; int idx; csg->stats.score = cfread_int(cfp); csg->stats.rank = cfread_int(cfp); csg->stats.assists = cfread_int(cfp); csg->stats.medals_earned = csg->medals_list; list_size = (int)csg->stats.medals_earned.size(); for (idx = 0; idx < list_size; idx++) { csg->stats.medals_earned[idx].val = cfread_int(cfp); } csg->stats.ship_kills = csg->ship_list; list_size = cfread_int(cfp); // NOTE: could be less, but never greater than if ( list_size > (int)csg->stats.ship_kills.size() ) { throw std::runtime_error("Data check failure (kills size)!"); } for (idx = 0; idx < list_size; idx++) { csg->stats.ship_kills[idx].val = (int)cfread_ushort(cfp); } csg->stats.kill_count = cfread_int(cfp); csg->stats.kill_count_ok = cfread_int(cfp); csg->stats.p_shots_fired = cfread_uint(cfp); csg->stats.s_shots_fired = cfread_uint(cfp); csg->stats.p_shots_hit = cfread_uint(cfp); csg->stats.s_shots_hit = cfread_uint(cfp); csg->stats.p_bonehead_hits = cfread_uint(cfp); csg->stats.s_bonehead_hits = cfread_uint(cfp); csg->stats.bonehead_kills = cfread_uint(cfp); }
void pilotfile_convert::plr_import_stats() { int idx; char name[35]; if (fver >= 242) { return; } // read everything, but we don't need any of it ... cfread_int(cfp); // score cfread_int(cfp); // rank cfread_int(cfp); // assists // medals for (idx = 0; idx < 18; idx++) { cfread_int(cfp); } // kills per ship int count = cfread_int(cfp); for (idx = 0; idx < count; idx++) { cfread_ushort(cfp); cfread_string_len(name, sizeof(name), cfp); } cfread_int(cfp); // kill_count cfread_int(cfp); // kill_count_ok cfread_uint(cfp); // p_shots_fired cfread_uint(cfp); // s_shots_fired cfread_uint(cfp); // p_shots_hit cfread_uint(cfp); // s_shots_hit cfread_uint(cfp); // p_bonehead_hits cfread_uint(cfp); // s_bonehead_hits cfread_uint(cfp); // bonehead_kills }
bool pilotfile::verify(const char *fname, int *rank) { player t_plr; // set player ptr first thing p = &t_plr; filename = fname; if ( filename.size() == 4 ) { mprintf(("PLR => Invalid filename '%s'!\n", filename.c_str())); return false; } cfp = cfopen((char*)filename.c_str(), "rb", CFILE_NORMAL, CF_TYPE_PLAYERS); if ( !cfp ) { mprintf(("PLR => Unable to open '%s'!\n", filename.c_str())); return false; } unsigned int plr_id = cfread_uint(cfp); if (plr_id != PLR_FILE_ID) { mprintf(("PLR => Invalid header id for '%s'!\n", filename.c_str())); plr_close(); return false; } // version, should be able to just ignore it ubyte plr_ver = cfread_ubyte(cfp); mprintf(("PLR => Verifying '%s' with version %d...\n", filename.c_str(), (int)plr_ver)); // the point of all this: read in the PLR contents while ( !m_have_flags && !cfeof(cfp) ) { ushort section_id = cfread_ushort(cfp); uint section_size = cfread_uint(cfp); size_t start_pos = cftell(cfp); // safety, to help protect against long reads cf_set_max_read_len(cfp, section_size); try { switch (section_id) { case Section::Flags: mprintf(("PLR => Parsing: Flags...\n")); m_have_flags = true; plr_read_flags(); break; default: break; } } catch (cfile::max_read_length &msg) { // read to max section size, move to next section, discarding // extra/unknown data mprintf(("PLR => (0x%04x) %s\n", section_id, msg.what())); } catch (const char *err) { mprintf(("PLR => ERROR: %s\n", err)); plr_close(); return false; } // reset safety catch cf_set_max_read_len(cfp, 0); // skip to next section (if not already there) size_t offset_pos = (start_pos + section_size) - cftell(cfp); if (offset_pos) { mprintf(("PLR => Warning: (0x%04x) Short read, information may have been lost!\n", section_id)); cfseek(cfp, offset_pos, CF_SEEK_CUR); } } if (rank) { *rank = p->stats.rank; } mprintf(("PLR => Verifying complete!\n")); // cleanup and return plr_close(); return true; }
bool pilotfile::load_player(const char *callsign, player *_p) { // if we're a standalone server in multiplayer, just fill in some bogus values // since we don't have a pilot file if ( (Game_mode & GM_MULTIPLAYER) && (Game_mode & GM_STANDALONE_SERVER) ) { Player->insignia_texture = -1; strcpy_s(Player->callsign, NOX("Standalone")); strcpy_s(Player->short_callsign, NOX("Standalone")); return true; } // set player ptr first thing p = _p; if ( !p ) { Assert( (Player_num >= 0) && (Player_num < MAX_PLAYERS) ); p = &Players[Player_num]; } filename = callsign; filename += ".plr"; if ( filename.size() == 4 ) { mprintf(("PLR => Invalid filename '%s'!\n", filename.c_str())); return false; } cfp = cfopen((char*)filename.c_str(), "rb", CFILE_NORMAL, CF_TYPE_PLAYERS); if ( !cfp ) { mprintf(("PLR => Unable to open '%s' for reading!\n", filename.c_str())); return false; } unsigned int plr_id = cfread_uint(cfp); if (plr_id != PLR_FILE_ID) { mprintf(("PLR => Invalid header id for '%s'!\n", filename.c_str())); plr_close(); return false; } // version, should be able to just ignore it version = cfread_ubyte(cfp); mprintf(("PLR => Loading '%s' with version %d...\n", filename.c_str(), version)); plr_reset_data(); // the point of all this: read in the PLR contents while ( !cfeof(cfp) ) { ushort section_id = cfread_ushort(cfp); uint section_size = cfread_uint(cfp); size_t start_pos = cftell(cfp); // safety, to help protect against long reads cf_set_max_read_len(cfp, section_size); try { switch (section_id) { case Section::Flags: mprintf(("PLR => Parsing: Flags...\n")); m_have_flags = true; plr_read_flags(); break; case Section::Info: mprintf(("PLR => Parsing: Info...\n")); m_have_info = true; plr_read_info(); break; case Section::Variables: mprintf(("PLR => Parsing: Variables...\n")); plr_read_variables(); break; case Section::HUD: mprintf(("PLR => Parsing: HUD...\n")); plr_read_hud(); break; case Section::Scoring: mprintf(("PLR => Parsing: Scoring...\n")); plr_read_stats(); break; case Section::ScoringMulti: mprintf(("PLR => Parsing: ScoringMulti...\n")); plr_read_stats_multi(); break; case Section::Multiplayer: mprintf(("PLR => Parsing: Multiplayer...\n")); plr_read_multiplayer(); break; case Section::Controls: mprintf(("PLR => Parsing: Controls...\n")); plr_read_controls(); break; case Section::Settings: mprintf(("PLR => Parsing: Settings...\n")); plr_read_settings(); break; default: mprintf(("PLR => Skipping unknown section 0x%04x!\n", section_id)); break; } } catch (cfile::max_read_length &msg) { // read to max section size, move to next section, discarding // extra/unknown data mprintf(("PLR => (0x%04x) %s\n", section_id, msg.what())); } catch (const char *err) { mprintf(("PLR => ERROR: %s\n", err)); plr_close(); return false; } // reset safety catch cf_set_max_read_len(cfp, 0); // skip to next section (if not already there) size_t offset_pos = (start_pos + section_size) - cftell(cfp); if (offset_pos) { cfseek(cfp, offset_pos, CF_SEEK_CUR); } } // restore the callsign into the Player structure strcpy_s(p->callsign, callsign); // restore the truncated callsign into Player structure pilot_set_short_callsign(p, SHORT_CALLSIGN_PIXEL_W); player_set_squad_bitmap(p, p->m_squad_filename, true); hud_squadmsg_save_keys(); // set last pilot os_config_write_string(NULL, "LastPlayer", (char*)callsign); mprintf(("PLR => Loading complete!\n")); // cleanup and return plr_close(); return true; }
void pilotfile::csg_read_loadout() { int j, count, ship_idx = -1, wep_idx = -1; size_t idx, list_size = 0; if ( !m_have_info ) { throw "Loadout before Info!"; } // base info cfread_string_len(Player_loadout.filename, MAX_FILENAME_LEN, cfp); cfread_string_len(Player_loadout.last_modified, DATE_TIME_LENGTH, cfp); // ship pool list_size = ship_list.size(); for (idx = 0; idx < list_size; idx++) { count = cfread_int(cfp); if (ship_list[idx].index >= 0) { Player_loadout.ship_pool[ship_list[idx].index] = count; } } // weapon pool list_size = weapon_list.size(); for (idx = 0; idx < list_size; idx++) { count = cfread_int(cfp); if (weapon_list[idx].index >= 0) { Player_loadout.weapon_pool[weapon_list[idx].index] = count; } } // player ship loadout list_size = (uint)cfread_ushort(cfp); for (uint i = 0; i < list_size; i++) { wss_unit *slot = NULL; if (i < MAX_WSS_SLOTS) { slot = &Player_loadout.unit_data[i]; } // ship ship_idx = cfread_int(cfp); if ( (ship_idx >= (int)ship_list.size()) || (ship_idx < -1) ) { // on the casts, assume that ship & weapon lists will never exceed ~2 billion mprintf(("CSG => Parse Warning: Invalid value for ship index (%d), emptying slot.\n", ship_idx)); ship_idx = -1; } if (slot) { if (ship_idx == -1) { // -1 means no ship in this slot slot->ship_class = -1; } else { slot->ship_class = ship_list[ship_idx].index; } } // primary weapons count = cfread_int(cfp); for (j = 0; j < count; j++) { wep_idx = cfread_int(cfp); if ( (wep_idx >= (int)weapon_list.size()) || (wep_idx < -1) ) { mprintf(("CSG => Parse Warning: Invalid value for primary weapon index (%d), emptying slot.\n", wep_idx)); wep_idx = -1; } if ( slot && (j < MAX_SHIP_PRIMARY_BANKS) ) { if (wep_idx == -1) { // -1 means no weapon in this slot slot->wep[j] = -1; } else { slot->wep[j] = weapon_list[wep_idx].index; } } int read_idx = cfread_int(cfp); if ( slot && (j < MAX_SHIP_PRIMARY_BANKS) ) { slot->wep_count[j] = read_idx; } } // secondary weapons count = cfread_int(cfp); for (j = 0; j < count; j++) { wep_idx = cfread_int(cfp); if ( (wep_idx >= (int)weapon_list.size()) || (wep_idx < -1) ) { mprintf(("CSG => Parse Warning: Invalid value for secondary weapon index (%d), emptying slot.\n", wep_idx)); wep_idx = -1; } if ( slot && (j < MAX_SHIP_SECONDARY_BANKS) ) { if (wep_idx == -1) { // -1 means no weapon in this slot slot->wep[j+MAX_SHIP_PRIMARY_BANKS] = -1; } else { slot->wep[j+MAX_SHIP_PRIMARY_BANKS] = weapon_list[wep_idx].index; } } int read_idx = cfread_int(cfp); if ( slot && (j < MAX_SHIP_SECONDARY_BANKS) ) { slot->wep_count[j+MAX_SHIP_PRIMARY_BANKS] = read_idx; } } } }
/* * get_csg_rank: this function is called from plr.cpp & is * tightly linked with pilotfile::verify() */ bool pilotfile::get_csg_rank(int *rank) { player t_csg; // set player ptr first thing p = &t_csg; // filename has already been set cfp = cfopen((char*)filename.c_str(), "rb", CFILE_NORMAL, CF_TYPE_PLAYERS); if ( !cfp ) { mprintf(("CSG => Unable to open '%s'!\n", filename.c_str())); return false; } unsigned int csg_id = cfread_uint(cfp); if (csg_id != CSG_FILE_ID) { mprintf(("CSG => Invalid header id for '%s'!\n", filename.c_str())); csg_close(); return false; } // version, now used csg_ver = cfread_ubyte(cfp); mprintf(("CSG => Get Rank from '%s' with version %d...\n", filename.c_str(), (int)csg_ver)); // the point of all this: read in the CSG contents while ( !m_have_flags && !cfeof(cfp) ) { ushort section_id = cfread_ushort(cfp); uint section_size = cfread_uint(cfp); size_t start_pos = cftell(cfp); size_t offset_pos; // safety, to help protect against long reads cf_set_max_read_len(cfp, section_size); try { switch (section_id) { case Section::Flags: mprintf(("CSG => Parsing: Flags...\n")); m_have_flags = true; csg_read_flags(); break; default: break; } } catch (cfile::max_read_length &msg) { // read to max section size, move to next section, discarding // extra/unknown data mprintf(("CSG => (0x%04x) %s\n", section_id, msg.what())); } catch (const char *err) { mprintf(("CSG => ERROR: %s\n", err)); csg_close(); return false; } // reset safety catch cf_set_max_read_len(cfp, 0); // skip to next section (if not already there) offset_pos = (start_pos + section_size) - cftell(cfp); if (offset_pos) { mprintf(("CSG => Warning: (0x%04x) Short read, information may have been lost!\n", section_id)); cfseek(cfp, (int)offset_pos, CF_SEEK_CUR); } } // this is what we came for... *rank = p->stats.rank; mprintf(("CSG => Get Rank complete!\n")); // cleanup & return csg_close(); return true; }
bool pilotfile::load_savefile(const char *campaign) { char base[_MAX_FNAME] = { '\0' }; std::ostringstream buf; if (Game_mode & GM_MULTIPLAYER) { return false; } if ( (campaign == NULL) || !strlen(campaign) ) { return false; } // set player ptr first thing Assert( (Player_num >= 0) && (Player_num < MAX_PLAYERS) ); p = &Players[Player_num]; // build up filename for the savefile... _splitpath((char*)campaign, NULL, NULL, base, NULL); buf << p->callsign << "." << base << ".csg"; filename = buf.str().c_str(); // if campaign file doesn't exist, abort so we don't load irrelevant data buf.str(std::string()); buf << base << FS_CAMPAIGN_FILE_EXT; if ( !cf_exists_full((char*)buf.str().c_str(), CF_TYPE_MISSIONS) ) { mprintf(("CSG => Unable to find campaign file '%s'!\n", buf.str().c_str())); return false; } // we need to reset this early, in case open fails and we need to create m_data_invalid = false; // open it, hopefully... cfp = cfopen((char*)filename.c_str(), "rb", CFILE_NORMAL, CF_TYPE_PLAYERS); if ( !cfp ) { mprintf(("CSG => Unable to open '%s' for reading!\n", filename.c_str())); return false; } unsigned int csg_id = cfread_uint(cfp); if (csg_id != CSG_FILE_ID) { mprintf(("CSG => Invalid header id for '%s'!\n", filename.c_str())); csg_close(); return false; } // version, now used csg_ver = cfread_ubyte(cfp); mprintf(("CSG => Loading '%s' with version %d...\n", filename.c_str(), (int)csg_ver)); csg_reset_data(); // the point of all this: read in the CSG contents while ( !cfeof(cfp) ) { ushort section_id = cfread_ushort(cfp); uint section_size = cfread_uint(cfp); size_t start_pos = cftell(cfp); // safety, to help protect against long reads cf_set_max_read_len(cfp, section_size); try { switch (section_id) { case Section::Flags: mprintf(("CSG => Parsing: Flags...\n")); m_have_flags = true; csg_read_flags(); break; case Section::Info: mprintf(("CSG => Parsing: Info...\n")); m_have_info = true; csg_read_info(); break; case Section::Variables: mprintf(("CSG => Parsing: Variables...\n")); csg_read_variables(); break; case Section::HUD: mprintf(("CSG => Parsing: HUD...\n")); csg_read_hud(); break; case Section::RedAlert: mprintf(("CSG => Parsing: RedAlert...\n")); csg_read_redalert(); break; case Section::Scoring: mprintf(("CSG => Parsing: Scoring...\n")); csg_read_stats(); break; case Section::Loadout: mprintf(("CSG => Parsing: Loadout...\n")); csg_read_loadout(); break; case Section::Techroom: mprintf(("CSG => Parsing: Techroom...\n")); csg_read_techroom(); break; case Section::Missions: mprintf(("CSG => Parsing: Missions...\n")); csg_read_missions(); break; case Section::Settings: mprintf(("CSG => Parsing: Settings...\n")); csg_read_settings(); break; case Section::Controls: mprintf(("CSG => Parsing: Controls...\n")); csg_read_controls(); break; case Section::Cutscenes: mprintf(("CSG => Parsing: Cutscenes...\n")); csg_read_cutscenes(); break; case Section::LastMissions: mprintf(("CSG => Parsing: Last Missions...\n")); csg_read_lastmissions(); break; default: mprintf(("CSG => Skipping unknown section 0x%04x!\n", section_id)); break; } } catch (cfile::max_read_length &msg) { // read to max section size, move to next section, discarding // extra/unknown data mprintf(("CSG => Warning: (0x%04x) %s\n", section_id, msg.what())); } catch (const char *err) { mprintf(("CSG => ERROR: %s\n", err)); csg_close(); return false; } // reset safety catch cf_set_max_read_len(cfp, 0); // skip to next section (if not already there) size_t offset_pos = (start_pos + section_size) - cftell(cfp); if (offset_pos) { mprintf(("CSG => Warning: (0x%04x) Short read, information may have been lost!\n", section_id)); cfseek(cfp, (int)offset_pos, CF_SEEK_CUR); } } // if the campaign (for whatever reason) doesn't have a squad image, use the multi one if (p->s_squad_filename[0] == '\0') { strcpy_s(p->s_squad_filename, p->m_squad_filename); } player_set_squad_bitmap(p, p->s_squad_filename, false); mprintf(("CSG => Loading complete!\n")); // cleanup and return csg_close(); return true; }
bool pilotfile::verify(const char *fname, int *rank, char *valid_language) { player t_plr; // set player ptr first thing p = &t_plr; filename = fname; if ( filename.size() == 4 ) { mprintf(("PLR => Invalid filename '%s'!\n", filename.c_str())); return false; } cfp = cfopen((char*)filename.c_str(), "rb", CFILE_NORMAL, CF_TYPE_PLAYERS); if ( !cfp ) { mprintf(("PLR => Unable to open '%s'!\n", filename.c_str())); return false; } unsigned int plr_id = cfread_uint(cfp); if (plr_id != PLR_FILE_ID) { mprintf(("PLR => Invalid header id for '%s'!\n", filename.c_str())); plr_close(); return false; } // version, now used version = cfread_ubyte(cfp); mprintf(("PLR => Verifying '%s' with version %d...\n", filename.c_str(), (int)version)); // the point of all this: read in the PLR contents while ( !(m_have_flags && m_have_info) && !cfeof(cfp) ) { ushort section_id = cfread_ushort(cfp); uint section_size = cfread_uint(cfp); size_t start_pos = cftell(cfp); // safety, to help protect against long reads cf_set_max_read_len(cfp, section_size); try { switch (section_id) { case Section::Flags: mprintf(("PLR => Parsing: Flags...\n")); m_have_flags = true; plr_read_flags(); break; // now reading the Info section to get the campaign // and be able to lookup the campaign rank case Section::Info: mprintf(("PLR => Parsing: Info...\n")); m_have_info = true; plr_read_info(); break; default: break; } } catch (cfile::max_read_length &msg) { // read to max section size, move to next section, discarding // extra/unknown data mprintf(("PLR => (0x%04x) %s\n", section_id, msg.what())); } catch (const char *err) { mprintf(("PLR => ERROR: %s\n", err)); plr_close(); return false; } // reset safety catch cf_set_max_read_len(cfp, 0); // skip to next section (if not already there) size_t offset_pos = (start_pos + section_size) - cftell(cfp); if (offset_pos) { mprintf(("PLR => Warning: (0x%04x) Short read, information may have been lost!\n", section_id)); cfseek(cfp, offset_pos, CF_SEEK_CUR); } } if (valid_language) { strncpy(valid_language, p->language, sizeof(p->language)); } // need to cleanup early to ensure everything is OK for use in the CSG next // also means we can't use *p from now on, use t_plr instead for a few vars plr_close(); if (rank) { // maybe get the rank from the CSG if ( !(Game_mode & GM_MULTIPLAYER) ) { // build the csg filename // since filename/fname was validated above, perform less safety checks here filename = fname; filename = filename.replace(filename.find_last_of('.')+1,filename.npos, t_plr.current_campaign); filename.append(".csg"); if (!this->get_csg_rank(rank)) { // if we failed to get the csg rank, default to multi rank *rank = t_plr.stats.rank; } } else { // if the CSG isn't valid, or for multi, use this rank *rank = t_plr.stats.rank; } } mprintf(("PLR => Verifying complete!\n")); return true; }