lsnes rr1-Δ10
[lsnes.git] / src / core / misc.cpp
blobd32b95a3c93e14f64531be1b117add72dd21d30c
1 #include "lsnes.hpp"
3 #include "core/memorymanip.hpp"
4 #include "core/misc.hpp"
5 #include "core/rom.hpp"
6 #include "core/threaddebug.hpp"
7 #include "core/window.hpp"
8 #include "library/sha256.hpp"
10 #include <sstream>
11 #include <iostream>
12 #include <iomanip>
13 #include <fstream>
14 #include <string>
15 #include <vector>
16 #include <algorithm>
17 #include <ctime>
18 #include <cstdlib>
19 #include <cstring>
20 #include <boost/filesystem.hpp>
22 namespace
24 std::string rseed;
25 uint64_t rcounter = 0;
26 bool reached_main_flag;
28 std::string get_random_hexstring_64(size_t index)
30 std::ostringstream str;
31 str << rseed << " " << time(NULL) << " " << (rcounter++) << " " << index;
32 std::string s = str.str();
33 std::vector<char> x;
34 x.resize(s.length());
35 std::copy(s.begin(), s.end(), x.begin());
36 return sha256::hash(reinterpret_cast<uint8_t*>(&x[0]), x.size());
39 std::string collect_identifying_information()
41 //TODO: Collect as much identifying information as possible.
42 std::ostringstream str;
43 time_t told = time(NULL);
44 time_t tnew;
45 uint64_t loops = 0;
46 uint64_t base = 0;
47 int cnt = 0;
48 while(cnt < 3) {
49 tnew = time(NULL);
50 if(tnew > told) {
51 told = tnew;
52 cnt++;
53 str << (loops - base) << " ";
54 base = loops;
56 loops++;
58 return str.str();
62 std::string get_random_hexstring(size_t length) throw(std::bad_alloc)
64 std::string out;
65 for(size_t i = 0; i < length; i += 64)
66 out = out + get_random_hexstring_64(i);
67 return out.substr(0, length);
70 void set_random_seed(const std::string& seed) throw(std::bad_alloc)
72 std::ostringstream str;
73 str << seed.length() << " " << seed;
74 rseed = str.str();
77 void set_random_seed() throw(std::bad_alloc)
79 //Try /dev/urandom first.
81 std::ifstream r("/dev/urandom", std::ios::binary);
82 if(r.is_open()) {
83 char buf[64];
84 r.read(buf, 64);
85 std::string s(buf, 64);
86 set_random_seed(s);
87 return;
90 //Fall back to time.
91 std::ostringstream str;
92 str << collect_identifying_information() << " " << time(NULL);
93 set_random_seed(str.str());
97 struct loaded_rom load_rom_from_commandline(std::vector<std::string> cmdline) throw(std::bad_alloc,
98 std::runtime_error)
100 struct rom_files f;
101 try {
102 f = rom_files(cmdline);
103 f.resolve_relative();
104 } catch(std::bad_alloc& e) {
105 OOM_panic();
106 } catch(std::exception& e) {
107 throw std::runtime_error(std::string("Can't resolve ROM files: ") + e.what());
109 messages << "ROM type: " << gtype::tostring(f.rtype, f.region) << std::endl;
110 if(f.rom != "") messages << name_subrom(f.rtype, 0) << " file: '" << f.rom << "'" << std::endl;
111 if(f.rom_xml != "") messages << name_subrom(f.rtype, 1) << " file: '" << f.rom_xml << "'"
112 << std::endl;
113 if(f.slota != "") messages << name_subrom(f.rtype, 2) << " file: '" << f.slota << "'" << std::endl;
114 if(f.slota_xml != "") messages << name_subrom(f.rtype, 3) << " file: '" << f.slota_xml << "'"
115 << std::endl;
116 if(f.slotb != "") messages << name_subrom(f.rtype, 4) << " file: '" << f.slotb << "'" << std::endl;
117 if(f.slotb_xml != "") messages << name_subrom(f.rtype, 5) << " file: '" << f.slotb_xml << "'"
118 << std::endl;
120 struct loaded_rom r;
121 try {
122 r = loaded_rom(f);
123 r.do_patch(cmdline);
124 } catch(std::bad_alloc& e) {
125 OOM_panic();
126 } catch(std::exception& e) {
127 throw std::runtime_error(std::string("Can't load ROM: ") + e.what());
130 std::string not_present = "N/A";
131 if(r.rom.valid) messages << name_subrom(f.rtype, 0) << " hash: " << r.rom.sha256 << std::endl;
132 if(r.rom_xml.valid) messages << name_subrom(f.rtype, 1) << " hash: " << r.rom_xml.sha256 << std::endl;
133 if(r.slota.valid) messages << name_subrom(f.rtype, 2) << " hash: " << r.slota.sha256 << std::endl;
134 if(r.slota_xml.valid) messages << name_subrom(f.rtype, 3) << " hash: " << r.slota_xml.sha256
135 << std::endl;
136 if(r.slotb.valid) messages << name_subrom(f.rtype, 4) << " hash: " << r.slotb.sha256 << std::endl;
137 if(r.slotb_xml.valid) messages << name_subrom(f.rtype, 5) << " hash: " << r.slotb_xml.sha256
138 << std::endl;
139 return r;
142 void dump_region_map() throw(std::bad_alloc)
144 std::vector<struct memory_region> regions = get_regions();
145 for(auto i : regions) {
146 std::ostringstream x;
147 x << std::setfill('0') << std::setw(16) << std::hex << i.baseaddr << "-";
148 x << std::setfill('0') << std::setw(16) << std::hex << i.lastaddr << " ";
149 x << std::setfill('0') << std::setw(16) << std::hex << i.size << " ";
150 messages << x.str() << (i.readonly ? "R-" : "RW") << (i.native_endian ? 'N' : 'L')
151 << (i.iospace ? 'I' : 'M') << " " << i.region_name << std::endl;
155 void fatal_error() throw()
157 platform::fatal_error();
158 std::cout << "PANIC: Fatal error, can't continue." << std::endl;
159 exit(1);
162 std::string get_config_path() throw(std::bad_alloc)
164 const char* tmp;
165 std::string basedir;
166 if((tmp = getenv("APPDATA"))) {
167 //If $APPDATA exists, it is the base directory
168 basedir = tmp;
169 } else if((tmp = getenv("XDG_CONFIG_HOME"))) {
170 //If $XDG_CONFIG_HOME exists, it is the base directory
171 basedir = tmp;
172 } else if((tmp = getenv("HOME"))) {
173 //If $HOME exists, the base directory is '.config' there.
174 basedir = std::string(tmp) + "/.config";
175 } else {
176 //Last chance: Return current directory.
177 return ".";
179 //Try to create 'lsnes'. If it exists (or is created) and is directory, great. Otherwise error out.
180 std::string lsnes_path = basedir + "/lsnes";
181 boost::filesystem::path p(lsnes_path);
182 if(!boost::filesystem::create_directories(p) && !boost::filesystem::is_directory(p)) {
183 messages << "FATAL: Can't create configuration directory '" << lsnes_path << "'" << std::endl;
184 fatal_error();
186 //Yes, this is racy, but portability is more important than being absolutely correct...
187 std::string tfile = lsnes_path + "/test";
188 remove(tfile.c_str());
189 FILE* x;
190 if(!(x = fopen(tfile.c_str(), "w+"))) {
191 messages << "FATAL: Configuration directory '" << lsnes_path << "' is not writable" << std::endl;
192 fatal_error();
194 fclose(x);
195 remove(tfile.c_str());
196 return lsnes_path;
199 extern const char* lsnesrc_file;
201 void create_lsnesrc()
203 std::string rcfile = get_config_path() + "/lsnes.rc";
204 std::ifstream x(rcfile.c_str());
205 if(x) {
206 x.close();
207 return;
209 std::ofstream y(rcfile.c_str());
210 if(!y) {
211 messages << "FATAL: lsnes.rc (" << rcfile << ") doesn't exist nor it can be created" << std::endl;
212 fatal_error();
214 y.write(lsnesrc_file, strlen(lsnesrc_file));
215 y.close();
219 void OOM_panic()
221 messages << "FATAL: Out of memory!" << std::endl;
222 fatal_error();
225 std::ostream& _messages()
227 return platform::out();
230 uint32_t gcd(uint32_t a, uint32_t b) throw()
232 if(b == 0)
233 return a;
234 else
235 return gcd(b, a % b);
238 std::string format_address(void* addr)
240 unsigned long x = (unsigned long)addr;
241 std::ostringstream y;
242 y << "0x" << std::hex << std::setfill('0') << std::setw(2 * sizeof(unsigned long)) << x;
243 return y.str();
246 bool in_global_ctors()
248 return !reached_main_flag;
251 void reached_main()
253 reached_main_flag = true;
254 init_threaded_malloc();
257 std::string bsnes_core_version;