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 pilot::BinaryFileHandler::endSectionWrite() { Assertion(!_sectionOffsets.empty(), "No active section!"); auto previous_off = _sectionOffsets.back(); _sectionOffsets.pop_back(); if (previous_off.id == Section::Unnamed) { // ignore unnamed sections, these are only needed for JSON return; } size_t cur = (size_t) cftell(_cfp); Assert(cur >= previous_off.offset); size_t section_size = cur - previous_off.offset; if (section_size) { // go back to section size in file and write proper value cfseek(_cfp, (int) (cur - section_size - sizeof(int)), CF_SEEK_SET); cfwrite_int((int) section_size, _cfp); // go back to previous location for next section cfseek(_cfp, (int) cur, CF_SEEK_SET); } }
/* * @brief get next apng frame */ void apng_ani::next_frame() { _reading = false; // setup new frame (if frame doesn't already exist) // always do if not caching // don't do if caching & already have frame if (_cache == false || (_frames.size() <= current_frame)) { if (current_frame > 0) { if (_dispose_op == 1) { // clear previous frame region of output buffer to fully transparent black for (uint row = 0; row < _frameh; ++row) { memset(&frame.data.at((_y_offset+row) * _row_len + _x_offset * 4), 0, _framew * 4); } } else if (_dispose_op == 2) { // revert previous frames region of output buffer to previous contents for (uint row = 0; row < _frameh; ++row) { uint pos = (_y_offset+row) * _row_len + _x_offset * 4; memcpy(&frame.data.at(pos), &_frame_next.data.at(pos), _framew * 4); } } // default is to do nothing with output buffer } while (cftell(_cfp) < _frame_offsets.at(current_frame+1)) { _process_chunk(); } nprintf(("apng", "apng next_frame; new (%03i/%03u/%03i) (%u) (%u) %03u|%03u %03u|%03u (%02u) (%04f)\n", current_frame, static_cast<uint>(_frames.size()), nframes, _dispose_op, _blend_op, _framew, _x_offset, _frameh, _y_offset, static_cast<uint>(_frame_offsets.size()), frame.delay)); if (_got_IDAT && _processing_finish()) { _apng_failed("couldn't finish fdat apng frame"); } if (_dispose_op == 2) { // revert to previous; so save the current frame region for later for (uint row = 0; row < _frameh; ++row) { uint pos = (_y_offset+row) * _row_len + _x_offset * 4; memcpy(&_frame_next.data.at(pos), &frame.data.at(pos), _framew * 4); } } _compose_frame(); if (_cache == true) _frames.push_back(frame); } else { if (current_frame < nframes) { nprintf(("apng", "apng next_frame; used old (%03i/%03u)\n", current_frame, static_cast<uint>(_frames.size()))); frame = _frames.at(current_frame); } } ++current_frame; }
// given a valid XSTR() id#, lookup the string in tstrings.tbl, filling in out if found, nonzero on success int lcl_ext_lookup(char *out, int id) { char text[1024]; int ret; int pointer; Assert(Lcl_pointer_count >= 0); Assert(Lcl_pointers[0] >= 0); Assert(Lcl_pointers[Lcl_pointer_count - 1] >= 0); Assert(Lcl_ext_file != NULL); Assert(id >= 0); // seek to the closest pointer <= the id# we're looking for pointer = id / LCL_GRANULARITY; cfseek(Lcl_ext_file, Lcl_pointers[pointer], CF_SEEK_SET); // reset parsing vars and go to town Ts_current_state = TS_SCANNING; Ts_id_text_size = 0; Ts_text_size; memset(Ts_text, 0, PARSE_TEXT_STRING_LEN); memset(Ts_id_text, 0, PARSE_ID_STRING_LEN); while((cftell(Lcl_ext_file) < Lcl_pointers[Lcl_pointer_count - 1]) && cfgets(text, 1024, Lcl_ext_file)){ ret = lcl_ext_lookup_sub(text, out, id); // run the line parse function switch(ret & 0x0fffffff){ // error case 0 : Int3(); // should never get here - it means the string doens't exist in the table!! return 0; // success parsing the line - please continue case 1 : break; // found a matching string/id pair case 2 : // success if (Lcl_gr) { // this is because tstrings.tbl reads in as ANSI for some reason // opening tstrings with "rb" mode didnt seem to help, so its now still "rt" like before lcl_fix_umlauts(out, LCL_TO_ASCII); } return 1; // end of language found case 3 : Int3(); // should never get here - it means the string doens't exist in the table!! return 0; } } Int3(); // should never get here - it means the string doens't exist in the table!! return 0; }
void pilot::BinaryFileHandler::startSectionWrite(Section id) { if (id == Section::Unnamed) { _sectionOffsets.push_back({id, 0}); return; } cfwrite_ushort((ushort) id, _cfp); // to be updated when endSection() is called cfwrite_int(0, _cfp); // starting offset, for size of section _sectionOffsets.push_back({id, (size_t)cftell(_cfp)}); }
void pilotfile::startSection(Section::id section_id) { Assert( cfp ); const int zero = 0; cfwrite_ushort( (ushort)section_id, cfp ); // to be updated when endSection() is called cfwrite_int(zero, cfp); // starting offset, for size of section m_size_offset = cftell(cfp); }
unsigned int apng_ani::_read_chunk(_chunk_s& chunk) { _offset = cftell(_cfp); if (cfread(&chunk.data[0], 4, 1, _cfp) == 1) { chunk.size = png_get_uint_32(&chunk.data[0]) + 12; // reduce the amount of vector resizing if (chunk.size > _max_chunk_size) { _max_chunk_size = chunk.size; chunk.data.resize(chunk.size); } if (cfread(&chunk.data[4], chunk.size-4, 1, _cfp) == 1) { return *(uint*)(&chunk.data[4]); } } return 0; }
void pilotfile::endSection() { Assert( cfp ); Assert( m_size_offset > 0 ); size_t cur = cftell(cfp); Assert( cur >= m_size_offset ); size_t section_size = cur - m_size_offset; if (section_size) { // go back to section size in file and write proper value cfseek(cfp, cur - section_size - sizeof(int), CF_SEEK_SET); cfwrite_int((int)section_size, cfp); // go back to previous location for next section cfseek(cfp, cur, CF_SEEK_SET); } }
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; }
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_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; }
/* * 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; }
/** * @brief Load an animation. This stores the compressed data, which instances of the animation can reference. * Must be free'ed later with anim_free(). * * @param real_filename Filename of animation * @param cf_dir_type * @param file_mapped Whether to use memory-mapped file or not. * * @details Memory-mapped files will page in the animation from disk as it is needed, but performance is not as good. * @return Pointer to anim that is loaded if sucess, NULL if failure. */ anim *anim_load(char *real_filename, int cf_dir_type, int file_mapped) { anim *ptr; CFILE *fp; int count,idx; char name[_MAX_PATH]; Assert( real_filename != NULL ); strcpy_s( name, real_filename ); char *p = strchr( name, '.' ); if ( p ) { *p = 0; } strcat_s( name, ".ani" ); ptr = first_anim; while (ptr) { if (!stricmp(name, ptr->name)) break; ptr = ptr->next; } if (!ptr) { fp = cfopen(name, "rb", CFILE_NORMAL, cf_dir_type); if ( !fp ) return NULL; ptr = (anim *) vm_malloc(sizeof(anim)); Assert(ptr); ptr->flags = 0; ptr->next = first_anim; first_anim = ptr; Assert(strlen(name) < _MAX_PATH - 1); strcpy_s(ptr->name, name); ptr->instance_count = 0; ptr->width = 0; ptr->height = 0; ptr->total_frames = 0; ptr->keys = NULL; ptr->ref_count=0; anim_read_header(ptr, fp); if(ptr->num_keys > 0){ ptr->keys = (key_frame*)vm_malloc(sizeof(key_frame) * ptr->num_keys); Assert(ptr->keys != NULL); } // store how long the anim should take on playback (in seconds) ptr->time = i2fl(ptr->total_frames)/ptr->fps; for(idx=0;idx<ptr->num_keys;idx++){ ptr->keys[idx].frame_num = 0; cfread(&ptr->keys[idx].frame_num, 2, 1, fp); cfread(&ptr->keys[idx].offset, 4, 1, fp); ptr->keys[idx].frame_num = INTEL_INT( ptr->keys[idx].frame_num ); //-V570 ptr->keys[idx].offset = INTEL_INT( ptr->keys[idx].offset ); //-V570 } cfread(&count, 4, 1, fp); // size of compressed data count = INTEL_INT( count ); ptr->cfile_ptr = NULL; if ( file_mapped == PAGE_FROM_MEM) { // Try mapping the file to memory ptr->flags |= ANF_MEM_MAPPED; ptr->cfile_ptr = cfopen(name, "rb", CFILE_MEMORY_MAPPED, cf_dir_type); } // couldn't memory-map file... must be in a packfile, so stream manually if ( file_mapped && !ptr->cfile_ptr ) { ptr->flags &= ~ANF_MEM_MAPPED; ptr->flags |= ANF_STREAMED; ptr->cfile_ptr = cfopen(name, "rb", CFILE_NORMAL, cf_dir_type); } ptr->cache = NULL; // If it opened properly as mem-mapped (or streamed) if (ptr->cfile_ptr != NULL) { // VERY IMPORTANT STEP // Set the data pointer to the compressed data (which is not at the start of the // file). Use ftell() to find out how far we've already parsed into the file // int offset; offset = cftell(fp); ptr->file_offset = offset; if ( ptr->flags & ANF_STREAMED ) { ptr->data = NULL; ptr->cache_file_offset = ptr->file_offset; ptr->cache = (ubyte*)vm_malloc(ANI_STREAM_CACHE_SIZE+2); Assert(ptr->cache); cfseek(ptr->cfile_ptr, offset, CF_SEEK_SET); cfread(ptr->cache, ANI_STREAM_CACHE_SIZE, 1, ptr->cfile_ptr); } else { ptr->data = (ubyte*)cf_returndata(ptr->cfile_ptr) + offset; } } else { // Not a memory mapped file (or streamed) ptr->flags &= ~ANF_MEM_MAPPED; ptr->flags &= ~ANF_STREAMED; ptr->data = (ubyte *) vm_malloc(count); ptr->file_offset = -1; cfread(ptr->data, count, 1, fp); } cfclose(fp); // store screen signature, so we can tell if palette changes ptr->screen_sig = gr_screen.signature; anim_set_palette(ptr); } ptr->ref_count++; return ptr; }
// ----------------------------------------------------------------------------- //loads from an already-open file // returns 0=everything ok, 1=old version, -1=error int load_mine_data(CFILE *LoadFile) { int i, j; short tmap_xlate; int translate; char *temptr; int mine_start = cftell(LoadFile); fuelcen_reset(); for (i=0; i<MAX_TEXTURES; i++ ) tmap_times_used[i] = 0; #ifdef EDITOR // Create a new mine to initialize things. //texpage_goto_first(); create_new_mine(); #endif //===================== READ FILE INFO ======================== // These are the default values... version and fileinfo_sizeof // don't have defaults. mine_fileinfo.header_offset = -1; mine_fileinfo.header_size = sizeof(mine_header); mine_fileinfo.editor_offset = -1; mine_fileinfo.editor_size = sizeof(mine_editor); mine_fileinfo.vertex_offset = -1; mine_fileinfo.vertex_howmany = 0; mine_fileinfo.vertex_sizeof = sizeof(vms_vector); mine_fileinfo.segment_offset = -1; mine_fileinfo.segment_howmany = 0; mine_fileinfo.segment_sizeof = sizeof(segment); mine_fileinfo.newseg_verts_offset = -1; mine_fileinfo.newseg_verts_howmany = 0; mine_fileinfo.newseg_verts_sizeof = sizeof(vms_vector); mine_fileinfo.group_offset = -1; mine_fileinfo.group_howmany = 0; mine_fileinfo.group_sizeof = sizeof(group); mine_fileinfo.texture_offset = -1; mine_fileinfo.texture_howmany = 0; mine_fileinfo.texture_sizeof = 13; // num characters in a name mine_fileinfo.walls_offset = -1; mine_fileinfo.walls_howmany = 0; mine_fileinfo.walls_sizeof = sizeof(wall); mine_fileinfo.triggers_offset = -1; mine_fileinfo.triggers_howmany = 0; mine_fileinfo.triggers_sizeof = sizeof(trigger); mine_fileinfo.object_offset = -1; mine_fileinfo.object_howmany = 1; mine_fileinfo.object_sizeof = sizeof(object); // Read in mine_top_fileinfo to get size of saved fileinfo. memset( &mine_top_fileinfo, 0, sizeof(mine_top_fileinfo) ); if (cfseek( LoadFile, mine_start, SEEK_SET )) Error( "Error moving to top of file in gamemine.c" ); if (cfread( &mine_top_fileinfo, sizeof(mine_top_fileinfo), 1, LoadFile )!=1) Error( "Error reading mine_top_fileinfo in gamemine.c" ); if (mine_top_fileinfo.fileinfo_signature != 0x2884) return -1; // Check version number if (mine_top_fileinfo.fileinfo_version < COMPATIBLE_VERSION ) return -1; // Now, Read in the fileinfo if (cfseek( LoadFile, mine_start, SEEK_SET )) Error( "Error seeking to top of file in gamemine.c" ); if (cfread( &mine_fileinfo, mine_top_fileinfo.fileinfo_sizeof, 1, LoadFile )!=1) Error( "Error reading mine_fileinfo in gamemine.c" ); //===================== READ HEADER INFO ======================== // Set default values. mine_header.num_vertices = 0; mine_header.num_segments = 0; if (mine_fileinfo.header_offset > -1 ) { if (cfseek( LoadFile, mine_fileinfo.header_offset, SEEK_SET )) Error( "Error seeking to header_offset in gamemine.c" ); if (cfread( &mine_header, mine_fileinfo.header_size, 1, LoadFile )!=1) Error( "Error reading mine_header in gamemine.c" ); } //===================== READ EDITOR INFO ========================== // Set default values mine_editor.current_seg = 0; mine_editor.newsegment_offset = -1; // To be written mine_editor.newsegment_size = sizeof(segment); mine_editor.Curside = 0; mine_editor.Markedsegp = -1; mine_editor.Markedside = 0; if (mine_fileinfo.editor_offset > -1 ) { if (cfseek( LoadFile, mine_fileinfo.editor_offset, SEEK_SET )) Error( "Error seeking to editor_offset in gamemine.c" ); if (cfread( &mine_editor, mine_fileinfo.editor_size, 1, LoadFile )!=1) Error( "Error reading mine_editor in gamemine.c" ); } //===================== READ TEXTURE INFO ========================== if ( (mine_fileinfo.texture_offset > -1) && (mine_fileinfo.texture_howmany > 0)) { if (cfseek( LoadFile, mine_fileinfo.texture_offset, SEEK_SET )) Error( "Error seeking to texture_offset in gamemine.c" ); for (i=0; i< mine_fileinfo.texture_howmany; i++ ) { if (cfread( &old_tmap_list[i], mine_fileinfo.texture_sizeof, 1, LoadFile )!=1) Error( "Error reading old_tmap_list[i] in gamemine.c" ); } } //=============== GENERATE TEXTURE TRANSLATION TABLE =============== translate = 0; Assert (NumTextures < MAX_TEXTURES); { hashtable ht; hashtable_init( &ht, NumTextures ); // Remove all the file extensions in the textures list for (i=0;i<NumTextures;i++) { temptr = strchr(TmapInfo[i].filename, '.'); if (temptr) *temptr = '\0'; hashtable_insert( &ht, TmapInfo[i].filename, i ); } // For every texture, search through the texture list // to find a matching name. for (j=0;j<mine_fileinfo.texture_howmany;j++) { // Remove this texture name's extension temptr = strchr(old_tmap_list[j], '.'); if (temptr) *temptr = '\0'; tmap_xlate_table[j] = hashtable_search( &ht,old_tmap_list[j]); if (tmap_xlate_table[j] < 0 ) { //tmap_xlate_table[j] = 0; // mprintf( (0, "Couldn't find texture '%s'\n", old_tmap_list[j] )); ; } if (tmap_xlate_table[j] != j ) translate = 1; if (tmap_xlate_table[j] >= 0) tmap_times_used[tmap_xlate_table[j]]++; } { int count = 0; for (i=0; i<MAX_TEXTURES; i++ ) if (tmap_times_used[i]) count++; mprintf( (0, "This mine has %d unique textures in it (~%d KB)\n", count, (count*4096) /1024 )); } mprintf( (0, "Translate=%d\n", translate )); hashtable_free( &ht ); } //====================== READ VERTEX INFO ========================== // New check added to make sure we don't read in too many vertices. if ( mine_fileinfo.vertex_howmany > MAX_VERTICES ) { mprintf((0, "Num vertices exceeds maximum. Loading MAX %d vertices\n", MAX_VERTICES)); mine_fileinfo.vertex_howmany = MAX_VERTICES; } if ( (mine_fileinfo.vertex_offset > -1) && (mine_fileinfo.vertex_howmany > 0)) { if (cfseek( LoadFile, mine_fileinfo.vertex_offset, SEEK_SET )) Error( "Error seeking to vertex_offset in gamemine.c" ); for (i=0; i< mine_fileinfo.vertex_howmany; i++ ) { // Set the default values for this vertex Vertices[i].x = 1; Vertices[i].y = 1; Vertices[i].z = 1; if (cfread( &Vertices[i], mine_fileinfo.vertex_sizeof, 1, LoadFile )!=1) Error( "Error reading Vertices[i] in gamemine.c" ); } } //==================== READ SEGMENT INFO =========================== // New check added to make sure we don't read in too many segments. if ( mine_fileinfo.segment_howmany > MAX_SEGMENTS ) { mprintf((0, "Num segments exceeds maximum. Loading MAX %d segments\n", MAX_SEGMENTS)); mine_fileinfo.segment_howmany = MAX_SEGMENTS; } // [commented out by mk on 11/20/94 (weren't we supposed to hit final in October?) because it looks redundant. I think I'll test it now...] fuelcen_reset(); if ( (mine_fileinfo.segment_offset > -1) && (mine_fileinfo.segment_howmany > 0)) { if (cfseek( LoadFile, mine_fileinfo.segment_offset,SEEK_SET )) Error( "Error seeking to segment_offset in gamemine.c" ); Highest_segment_index = mine_fileinfo.segment_howmany-1; for (i=0; i< mine_fileinfo.segment_howmany; i++ ) { segment v16_seg; // Set the default values for this segment (clear to zero ) //memset( &Segments[i], 0, sizeof(segment) ); if (mine_top_fileinfo.fileinfo_version >= 16) { Assert(mine_fileinfo.segment_sizeof == sizeof(v16_seg)); if (cfread( &v16_seg, mine_fileinfo.segment_sizeof, 1, LoadFile )!=1) Error( "Error reading segments in gamemine.c" ); } else Error("Invalid mine version"); Segments[i] = v16_seg; Segments[i].objects = -1; #ifdef EDITOR Segments[i].group = -1; #endif if (mine_top_fileinfo.fileinfo_version < 15) { //used old uvl ranges int sn,uvln; for (sn=0;sn<MAX_SIDES_PER_SEGMENT;sn++) for (uvln=0;uvln<4;uvln++) { Segments[i].sides[sn].uvls[uvln].u /= 64; Segments[i].sides[sn].uvls[uvln].v /= 64; Segments[i].sides[sn].uvls[uvln].l /= 32; } } fuelcen_activate( &Segments[i], Segments[i].special ); if (translate == 1) for (j=0;j<MAX_SIDES_PER_SEGMENT;j++) { unsigned short orient; tmap_xlate = Segments[i].sides[j].tmap_num; Segments[i].sides[j].tmap_num = tmap_xlate_table[tmap_xlate]; if ((WALL_IS_DOORWAY(&Segments[i],j) & WID_RENDER_FLAG)) if (Segments[i].sides[j].tmap_num < 0) { mprintf( (0, "Couldn't find texture '%s' for Segment %d, side %d\n", old_tmap_list[tmap_xlate],i,j)); Int3(); Segments[i].sides[j].tmap_num = 0; } tmap_xlate = Segments[i].sides[j].tmap_num2 & 0x3FFF; orient = Segments[i].sides[j].tmap_num2 & (~0x3FFF); if (tmap_xlate != 0) { int xlated_tmap = tmap_xlate_table[tmap_xlate]; if ((WALL_IS_DOORWAY(&Segments[i],j) & WID_RENDER_FLAG)) if (xlated_tmap <= 0) { mprintf( (0, "Couldn't find texture '%s' for Segment %d, side %d\n", old_tmap_list[tmap_xlate],i,j)); Int3(); Segments[i].sides[j].tmap_num2 = 0; } Segments[i].sides[j].tmap_num2 = xlated_tmap | orient; } } } } //===================== READ NEWSEGMENT INFO ===================== #ifdef EDITOR { // Default segment created. vms_vector sizevec; med_create_new_segment(vm_vec_make(&sizevec,DEFAULT_X_SIZE,DEFAULT_Y_SIZE,DEFAULT_Z_SIZE)); // New_segment = Segments[0]; //memset( &New_segment, 0, sizeof(segment) ); } if (mine_editor.newsegment_offset > -1) { if (cfseek( LoadFile, mine_editor.newsegment_offset,SEEK_SET )) Error( "Error seeking to newsegment_offset in gamemine.c" ); if (cfread( &New_segment, mine_editor.newsegment_size,1,LoadFile )!=1) Error( "Error reading new_segment in gamemine.c" ); } if ( (mine_fileinfo.newseg_verts_offset > -1) && (mine_fileinfo.newseg_verts_howmany > 0)) { if (cfseek( LoadFile, mine_fileinfo.newseg_verts_offset, SEEK_SET )) Error( "Error seeking to newseg_verts_offset in gamemine.c" ); for (i=0; i< mine_fileinfo.newseg_verts_howmany; i++ ) { // Set the default values for this vertex Vertices[NEW_SEGMENT_VERTICES+i].x = 1; Vertices[NEW_SEGMENT_VERTICES+i].y = 1; Vertices[NEW_SEGMENT_VERTICES+i].z = 1; if (cfread( &Vertices[NEW_SEGMENT_VERTICES+i], mine_fileinfo.newseg_verts_sizeof,1,LoadFile )!=1) Error( "Error reading Vertices[NEW_SEGMENT_VERTICES+i] in gamemine.c" ); New_segment.verts[i] = NEW_SEGMENT_VERTICES+i; } } #endif //========================= UPDATE VARIABLES ====================== #ifdef EDITOR // Setting to Markedsegp to NULL ignores Curside and Markedside, which // we want to do when reading in an old file. Markedside = mine_editor.Markedside; Curside = mine_editor.Curside; for (i=0;i<10;i++) Groupside[i] = mine_editor.Groupside[i]; if ( mine_editor.current_seg != -1 ) Cursegp = mine_editor.current_seg + Segments; else Cursegp = NULL; if (mine_editor.Markedsegp != -1 ) Markedsegp = mine_editor.Markedsegp + Segments; else Markedsegp = NULL; num_groups = 0; current_group = -1; #endif Num_vertices = mine_fileinfo.vertex_howmany; Num_segments = mine_fileinfo.segment_howmany; Highest_vertex_index = Num_vertices-1; Highest_segment_index = Num_segments-1; reset_objects(1); //one object, the player #ifdef EDITOR Highest_vertex_index = MAX_SEGMENT_VERTICES-1; Highest_segment_index = MAX_SEGMENTS-1; set_vertex_counts(); Highest_vertex_index = Num_vertices-1; Highest_segment_index = Num_segments-1; warn_if_concave_segments(); #endif #ifdef EDITOR validate_segment_all(); #endif //create_local_segment_data(); //gamemine_find_textures(); if (mine_top_fileinfo.fileinfo_version < MINE_VERSION ) return 1; //old version else return 0; }
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; }
// ----------------------------------------------------------------------------- // saves to an already-open file int save_mine_data(CFILE * SaveFile) { int header_offset, editor_offset, vertex_offset, segment_offset, doors_offset, texture_offset, walls_offset, triggers_offset; //, links_offset; int newseg_verts_offset; int newsegment_offset; int i; med_compress_mine(); warn_if_concave_segments(); for (i=0;i<NumTextures;i++) strncpy(current_tmap_list[i], TmapInfo[i].filename, 13); //=================== Calculate offsets into file ================== header_offset = cftell(SaveFile) + sizeof(mine_fileinfo); editor_offset = header_offset + sizeof(mine_header); texture_offset = editor_offset + sizeof(mine_editor); vertex_offset = texture_offset + (13*NumTextures); segment_offset = vertex_offset + (sizeof(vms_vector)*Num_vertices); newsegment_offset = segment_offset + (sizeof(segment)*Num_segments); newseg_verts_offset = newsegment_offset + sizeof(segment); walls_offset = newseg_verts_offset + (sizeof(vms_vector)*8); triggers_offset = walls_offset + (sizeof(wall)*Num_walls); doors_offset = triggers_offset + (sizeof(trigger)*Num_triggers); //===================== SAVE FILE INFO ======================== mine_fileinfo.fileinfo_signature= 0x2884; mine_fileinfo.fileinfo_version = MINE_VERSION; mine_fileinfo.fileinfo_sizeof = sizeof(mine_fileinfo); mine_fileinfo.header_offset = header_offset; mine_fileinfo.header_size = sizeof(mine_header); mine_fileinfo.editor_offset = editor_offset; mine_fileinfo.editor_size = sizeof(mine_editor); mine_fileinfo.vertex_offset = vertex_offset; mine_fileinfo.vertex_howmany = Num_vertices; mine_fileinfo.vertex_sizeof = sizeof(vms_vector); mine_fileinfo.segment_offset = segment_offset; mine_fileinfo.segment_howmany = Num_segments; mine_fileinfo.segment_sizeof = sizeof(segment); mine_fileinfo.newseg_verts_offset = newseg_verts_offset; mine_fileinfo.newseg_verts_howmany = 8; mine_fileinfo.newseg_verts_sizeof = sizeof(vms_vector); mine_fileinfo.texture_offset = texture_offset; mine_fileinfo.texture_howmany = NumTextures; mine_fileinfo.texture_sizeof = 13; // num characters in a name mine_fileinfo.walls_offset = walls_offset; mine_fileinfo.walls_howmany = Num_walls; mine_fileinfo.walls_sizeof = sizeof(wall); mine_fileinfo.triggers_offset = triggers_offset; mine_fileinfo.triggers_howmany = Num_triggers; mine_fileinfo.triggers_sizeof = sizeof(trigger); // Write the fileinfo cfwrite( &mine_fileinfo, sizeof(mine_fileinfo), 1, SaveFile ); //===================== SAVE HEADER INFO ======================== mine_header.num_vertices = Num_vertices; mine_header.num_segments = Num_segments; // Write the editor info if (header_offset != cftell(SaveFile)) Error( "OFFSETS WRONG IN MINE.C!" ); cfwrite( &mine_header, sizeof(mine_header), 1, SaveFile ); //===================== SAVE EDITOR INFO ========================== mine_editor.current_seg = Cursegp - Segments; mine_editor.newsegment_offset = newsegment_offset; mine_editor.newsegment_size = sizeof(segment); // Next 3 vars added 10/07 by JAS mine_editor.Curside = Curside; if (Markedsegp) mine_editor.Markedsegp = Markedsegp - Segments; else mine_editor.Markedsegp = -1; mine_editor.Markedside = Markedside; for (i=0;i<10;i++) mine_editor.Groupsegp[i] = Groupsegp[i] - Segments; for (i=0;i<10;i++) mine_editor.Groupside[i] = Groupside[i]; if (editor_offset != cftell(SaveFile)) Error( "OFFSETS WRONG IN MINE.C!" ); cfwrite( &mine_editor, sizeof(mine_editor), 1, SaveFile ); //===================== SAVE TEXTURE INFO ========================== if (texture_offset != cftell(SaveFile)) Error( "OFFSETS WRONG IN MINE.C!" ); cfwrite( current_tmap_list, 13, NumTextures, SaveFile ); //===================== SAVE VERTEX INFO ========================== if (vertex_offset != cftell(SaveFile)) Error( "OFFSETS WRONG IN MINE.C!" ); cfwrite( Vertices, sizeof(vms_vector), Num_vertices, SaveFile ); //===================== SAVE SEGMENT INFO ========================= if (segment_offset != cftell(SaveFile)) Error( "OFFSETS WRONG IN MINE.C!" ); cfwrite( Segments, sizeof(segment), Num_segments, SaveFile ); //===================== SAVE NEWSEGMENT INFO ====================== if (newsegment_offset != cftell(SaveFile)) Error( "OFFSETS WRONG IN MINE.C!" ); cfwrite( &New_segment, sizeof(segment), 1, SaveFile ); if (newseg_verts_offset != cftell(SaveFile)) Error( "OFFSETS WRONG IN MINE.C!" ); cfwrite( &Vertices[New_segment.verts[0]], sizeof(vms_vector), 8, SaveFile ); //==================== CLOSE THE FILE ============================= return 0; }
/* * @brief Get info about the apng * @note Also validates the apng & sets it up to have frames read * * @retval PNG_ERROR_NONE (0), otherwise will raise exception */ int apng_ani::load_header() { char filename[MAX_FILENAME_LEN]; strcpy_s(filename, _filename.c_str()); char *p = strchr( filename, '.' ); if ( p != nullptr ) *p = 0; strcat_s( filename, ".png" ); _cfp = cfopen( filename , "rb" ); if ( _cfp == nullptr) { _apng_failed("couldn't open filename"); } _reading = true; ubyte sig[8]; if (cfread(sig, 8, 1, _cfp) != 1) { _apng_failed("cfread of png signature failed"); } if (png_sig_cmp(sig, 0, 8) != 0) { _apng_failed("file has invalid png signature"); } // setup chunk sizes before use _chunk_IHDR.data.resize(25); // fixed IHDR chunk size _chunk.data.resize(25); // match the other sizes, maybe waste up to 13 bytes (ooooh) _id = _read_chunk(_chunk_IHDR); if (_id != id_IHDR || _chunk_IHDR.size != 25) { _apng_failed("failed to read IHDR chunk"); } w = png_get_uint_32(&_chunk_IHDR.data[8]); h = png_get_uint_32(&_chunk_IHDR.data[12]); _row_len = w * 4; // setup frames & keep bm_create happy _image_size = _row_len * h; frame.data.reserve(_image_size); // alloc only once frame.data.assign(_image_size, 0); // all transparent black per spec frame.rows.resize(h); _frame_raw.data.resize(_image_size); _frame_raw.rows.resize(h); _frame_next.data.resize(_image_size); _frame_next.rows.resize(h); for (uint i = 0; i < h; ++i) { // everything is correctly sized above; avoid .at() error checks frame.rows[i] = &frame.data[i * _row_len]; _frame_raw.rows[i] = &_frame_raw.data[i * _row_len]; _frame_next.rows[i] = &_frame_next.data[i * _row_len]; } // read all data while (!cfeof(_cfp)) { _process_chunk(); } // should be at EOF; attach to _frame_offsets to make next_frame code simpler Assertion(cfeof(_cfp) != 0, "apng not at EOF, get a coder!"); _frame_offsets.push_back(cftell(_cfp)); // sanity checks if (anim_time <= 0.0f) { _apng_failed("animation duration <= 0.0f, bad data?"); } if (nframes < 1) { _apng_failed("animation didn't have any frames, is this a static png?"); } // back to start, including reset of _cfp so it can be used for the 1st frame _reading = false; if (cfseek(_cfp, _frame_offsets.at(0), CF_SEEK_SET) != 0) { _apng_failed("couldn't seek to 1st fcTL offset"); } return PNG_ERROR_NONE; }
// initialize the pointer array into tstrings.tbl (call from lcl_ext_open() ONLY) void lcl_ext_setup_pointers() { char language_string[128]; char line[1024]; char *tok; int string_count; int ret; int found_start = 0; // open the localization file lcl_ext_open(); if(Lcl_ext_file == NULL){ error_display(0, "Error opening externalization file! File likely does not exist or could not be found"); return; } // seek to the currently active language memset(language_string, 0, 128); strcpy(language_string, "#"); if(!stricmp(DEFAULT_LANGUAGE, Lcl_languages[Lcl_current_lang].lang_name)){ strcat(language_string, "default"); } else { strcat(language_string, Lcl_languages[Lcl_current_lang].lang_name); } memset(line, 0, 1024); // reset seek variables and begin Lcl_pointer_count = 0; while(cfgets(line, 1024, Lcl_ext_file)){ tok = strtok(line, " \n"); if(tok == NULL){ continue; } // if the language matches, we're good to start parsing strings if(!stricmp(language_string, tok)){ found_start = 1; break; } } // if we didn't find the language specified, error if(found_start <= 0){ error_display(0, "Could not find specified langauge in tstrings.tbl!\n"); lcl_ext_close(); return; } string_count = 0; while(cfgets(line, 1024, Lcl_ext_file)){ ret = lcl_ext_lookup_sub(line, NULL, -1); // do stuff switch(ret & 0x0fffffff){ // error case 0 : lcl_ext_close(); return; // end of language found case 3 : // mark one final pointer Lcl_pointers[Lcl_pointer_count++] = cftell(Lcl_ext_file) - strlen(line) - 1; lcl_ext_close(); return; } // the only other case we care about is the beginning of a new id# if(ret & (1<<31)){ if((string_count % LCL_GRANULARITY) == 0){ // mark the pointer down Lcl_pointers[Lcl_pointer_count++] = cftell(Lcl_ext_file) - strlen(line) - 1; // if we're out of pointer slots if(Lcl_pointer_count >= LCL_MAX_POINTERS){ error_display(0, "Out of pointer for tstrings.tbl lookup. Please increment LCL_MAX_POINTERS in localize.cpp"); lcl_ext_close(); return; } } // increment string count string_count++; } } // should never get here. we should always be exiting through case 3 (end of language section) of the above switch // statement Int3(); lcl_ext_close(); }
long ogg_cftell(void* cfile) { return cftell((CFILE*)cfile); }