/* * 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 #endif #include "ops.h" #include "files/utils.h" #include "exceptions.h" #include #include #include #include #ifdef HAVE_SSTREAM #include 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 512 vector opcode_table_data(MAX_NO_OPCODES); vector > opcode_jumps; map uc_intrinsics; map > 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 tsm_tmp(strtol(k->second.c_str(), 0, 0), munge_offset); type_size_map.insert(pair >(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 keys = opdata.listkeys(opcodes_root); #if 1 for(vector::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::iterator op=opcode_table_data.begin(); op!=opcode_table_data.end(); op++) { for(unsigned int i=0; iparam_sizes.size(); i++) { if(op->param_sizes[i].second==true) // this is a calculated offset { opcode_jumps.push_back(std::pair(op->opcode, i+1)); // parameters are stored as base 1 } } } #if 0 std::cout << "Calculated Opcode pairs:" << std::endl; for(std::vector >::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(strtol(k->first.c_str(), 0, 0), k->second)); } /* To be depricated when I get the complex std::vector splitter online */ std::vector qnd_ocsplit(const std::string &s) { assert((s[0]=='{') && (s[s.size()-1]=='}')); std::vector 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 str2vec(const std::string &s) { std::vector 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 ¶m_types, std::vector > ¶m_sizes) { for(std::vector::const_iterator s=param_types.begin(); s!=param_types.end(); ++s) { map >::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(tsm->second.first, tsm->second.second)); } } /*std::vector str2vec(const std::string &s) { std::vector vs; // the resulting strings stack 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'); 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