ops.cc
来自「一个制作3d游戏的源程序」· CC 代码 · 共 401 行
CC
401 行
/* * Copyright (C) 2001-2002 The Exult Team * * 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. */#ifdef HAVE_CONFIG_H #include <config.h>#endif#include "ops.h"#include "files/utils.h"#include "exceptions.h"#include <cstdlib>#include <iomanip>#include <fstream>#include <stack>#ifdef HAVE_SSTREAM#include <sstream>using std::stringstream;#endif/*** head2data#ifndef __STRING #if defined __STDC__ && __STDC__ #define __STRING(x) #x #else #define __STRING(x) "x" #endif#endif*/using std::vector;using std::ifstream;using std::cout;using std::endl;using std::string;using std::cerr;using std::ends;using std::setw;using std::setfill;using std::setbase;using std::pair;using std::map;#define MAX_NO_OPCODES 512vector<UCOpcodeData> opcode_table_data(MAX_NO_OPCODES);vector<pair<unsigned int, unsigned int> > opcode_jumps;map<unsigned int, string> uc_intrinsics;map<string, pair<unsigned int, bool> > type_size_map;void ucxtInit::init(const Configuration &config, const UCOptions &options){ datadir = get_datadir(config, options); misc_data = "u7misc.data"; misc_root = "misc"; opcodes_data = "u7opcodes.data"; opcodes_root = "opcodes"; bg_intrinsics_data = "u7bgintrinsics.data"; bg_intrinsics_root = "intrinsics"; si_intrinsics_data = "u7siintrinsics.data"; si_intrinsics_root = "intrinsics"; if(options.verbose) cout << "Initing misc..." << endl; misc(); if(options.verbose) cout << "Initing opcodes..." << endl; opcodes(); if(options.verbose) cout << "Initing intrinsics..." << endl; if(options.game_bg()) intrinsics(bg_intrinsics_data, bg_intrinsics_root); else if(options.game_si()) intrinsics(si_intrinsics_data, si_intrinsics_root);}string ucxtInit::get_datadir(const Configuration &config, const UCOptions &options){ string datadir; // just to handle if people are going to compile with makefile.unix, unsupported, but occasionally useful #ifdef HAVE_CONFIG_H if(options.noconf == false) config.value("config/ucxt/root", datadir, EXULT_DATADIR); #else if(options.noconf == false) config.value("config/ucxt/root", datadir, "data/"); #endif if(datadir.size() && datadir[datadir.size()-1]!='/' && datadir[datadir.size()-1]!='\\') datadir+='/'; if(options.verbose) cout << "datadir: " << datadir << endl; return datadir;}void ucxtInit::misc(){ Configuration miscdata(datadir + misc_data, misc_root); Configuration::KeyTypeList om; miscdata.getsubkeys(om, misc_root + "/offset_munge"); Configuration::KeyTypeList st; miscdata.getsubkeys(st, misc_root + "/size_type"); // For each size type (small/long/byte/etc.) for(typeof(st.begin()) k=st.begin(); k!=st.end(); ++k) { bool munge_offset=false; const string tmpstr(k->first + "/"); /* ... we need to find out if we should munge it's parameter that is, it's some sort of goto target (like offset) or such */ for(typeof(om.begin()) m=om.begin(); m!=om.end(); ++m) if(m->first.size()-1==k->first.size()) if(m->first==tmpstr)// if(m->first.compare(0, m->first.size()-1, k->first, 0, k->first.size())==0) munge_offset=true; // once we've got it, add it to the map pair<unsigned int, bool> tsm_tmp(strtol(k->second.c_str(), 0, 0), munge_offset); type_size_map.insert(pair<string, pair<unsigned int, bool> >(k->first, tsm_tmp)); }}/* constructs the usecode tables from datafiles in the /ucxt hierachy */void ucxtInit::opcodes(){ Configuration opdata(datadir + opcodes_data, opcodes_root); vector<string> keys = opdata.listkeys(opcodes_root); #if 1 for(vector<string>::iterator key=keys.begin(); key!=keys.end(); ++key) { if((*key)[0]!='!') { Configuration::KeyTypeList ktl; opdata.getsubkeys(ktl, *key); if(ktl.size()) { unsigned int i = strtol(key->substr(key->find_first_of("0")).c_str(), 0, 0); opcode_table_data[i] = UCOpcodeData(i, ktl); } } } #else string ucxtroot(datadir + "opcodes.txt"); std::ifstream file; try { U7open(file, ucxtroot.c_str(), true); } catch (const file_open_exception& e) { cerr << e.what() << ". exiting." << endl; exit(1); } std::string s; while(!file.eof()) { getline(file, s); if(s.size() && s[0]=='>') { UCOpcodeData uco(str2vec(s)); assert(uco.opcode<MAX_NO_OPCODES); opcode_table_data[uco.opcode] = uco; } } file.close(); #endif /* Create an {opcode, parameter_index} array of all opcodes that execute a 'jump' statement */ for(std::vector<UCOpcodeData>::iterator op=opcode_table_data.begin(); op!=opcode_table_data.end(); op++) { for(unsigned int i=0; i<op->param_sizes.size(); i++) { if(op->param_sizes[i].second==true) // this is a calculated offset { opcode_jumps.push_back(std::pair<unsigned int, unsigned int>(op->opcode, i+1)); // parameters are stored as base 1 } } } #if 0 std::cout << "Calculated Opcode pairs:" << std::endl; for(std::vector<std::pair<unsigned int, unsigned int> >::iterator i=opcode_jumps.begin(); i!=opcode_jumps.end(); i++) std::cout << setw(4) << i->first << '\t' << setw(4) << i->second << std::endl; #endif}void ucxtInit::intrinsics(const string &intrinsic_data, const string &intrinsic_root){ Configuration intdata(datadir + intrinsic_data, intrinsic_root); Configuration::KeyTypeList ktl; intdata.getsubkeys(ktl, intrinsic_root); for(Configuration::KeyTypeList::iterator k=ktl.begin(); k!=ktl.end(); k++) uc_intrinsics.insert(pair<unsigned int, string>(strtol(k->first.c_str(), 0, 0), k->second));}/* To be depricated when I get the complex std::vector<std::string> splitter online */std::vector<std::string> qnd_ocsplit(const std::string &s){ assert((s[0]=='{') && (s[s.size()-1]=='}')); std::vector<std::string> vs; std::string tstr; for(std::string::const_iterator i=s.begin(); i!=s.end(); ++i) { if(*i==',') { vs.push_back(tstr); tstr=""; } else if(*i=='{' || *i=='}') { /* nothing */ } else tstr+=*i; } if(tstr.size()) vs.push_back(tstr); return vs;}std::vector<std::string> str2vec(const std::string &s){ std::vector<std::string> vs; unsigned int lasti=0; // if it's empty return null if(s.size()==0) return vs; bool indquote=false; for(unsigned int i=0; i<s.size(); i++) { if(s[i]=='"') indquote = !indquote; else if(isspace(s[i]) && (!indquote)) { if(lasti!=i) { if((s[lasti]=='"') && (s[i-1]=='"')) { if((lasti+1)!=(lasti-1)) vs.push_back(s.substr(lasti+1, i-lasti-2)); } else vs.push_back(s.substr(lasti, i-lasti)); } lasti=i+1; } if(i==s.size()-1) { if((s[lasti]=='"') && (s[i]=='"')) { if((lasti+1)!=(lasti-1)) vs.push_back(s.substr(lasti+1, i-lasti-2)); } else vs.push_back(s.substr(lasti, i-lasti+1)); } } #if 0 //test for(unsigned int i=0; i<vs.size(); i++) std::cout << "\t\"" << vs[i] << "\"" << std::endl; #endif ///test return vs;}void map_type_size(const std::vector<std::string> ¶m_types, std::vector<std::pair<unsigned int, bool> > ¶m_sizes){ for(std::vector<std::string>::const_iterator s=param_types.begin(); s!=param_types.end(); ++s) { map<string, pair<unsigned int, bool> >::iterator tsm(type_size_map.find(*s)); if(tsm==type_size_map.end()) { cerr << "error: No size type `" << *s << "`" << endl; assert(tsm!=type_size_map.end()); } param_sizes.push_back(std::pair<unsigned int, bool>(tsm->second.first, tsm->second.second)); }}/*std::vector<std::string> str2vec(const std::string &s){ std::vector<std::string> vs; // the resulting strings stack<char> vbound; // the "bounding" chars used to deonte collections of characters unsigned int lasti=0; std::string currstr; // the current string, gets appended to vs // if it's empty return null if(s.size()==0) return vs; for(unsigned int i=0; i<s.size(); i++) { bool pushback=false; // do we push the currstr onto the vector now? char c = s[i]; switch(c) {*/ // let's start with the openings... /* the general pricipal, since we strip the outermost enclosures, is to only append the "bounding" characters if they're NOT the outer most. NOTE: A subtle exception is the boundaries on the outermost set of bounding chars has the same effect as isspace(), YHBW *//* case '{': if(vs.size()) currstr+=c; vbound.push('}'); break; //case '[': if(vs.size()) currstr+=c; vbound.push(']'); break; //case '(': if(vs.size()) currstr+=c; vbound.push(')'); break; //case '<': if(vs.size()) currstr+=c; vbound.push('>'); break; // now the closures... case '}': if(vbound.top()=='}') vbound.pop(); if(vbound.size()==0) pushback=true; else currstr+=c; break; //case ']': // break; //case ')': // break; //case '>': // break; // now the ones that have the pretentiousness of being both // opening and closing causes case '\"': if(vs.size()) currstr+=c; vbound.push('\"'); break; case '\'': if(vs.size()) currstr+=c; vbound.push('\''); break; case '\"': if(vbound.top()=='\"') vbound.pop(); else vbound.push('\"'); if(vbound.size()==0) pushback=true; else currstr+=c; break; case '\'': if(vbound.top()=='\'') vbound.pop(); if(vbound.size()==0) pushback=true; else currstr+=c; break; // not to emulate isspace(); case ' ': // ze space case '\f': // form-feed case '\n': // newline case '\r': // carriage return case '\t': // horizontal tab case '\v': // vertical tab pushback=true; break; } if(pushback) { if(currstr.size()) vs.push_back(currstr); currstr=""; } } #if 1 //test for(unsigned int i=0; i<vs.size(); i++) std::cout << "\t\"" << vs[i] << "\"" << std::endl; #endif ///test return vs;}*/
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?