Move files around a lot
[lsnes.git] / src / core / misc.cpp
blob51c029670231b17beded172f93b0500d68ad2a2d
1 #include "lsnes.hpp"
3 #include "core/memorymanip.hpp"
4 #include "core/misc.hpp"
5 #include "core/rom.hpp"
6 #include "core/window.hpp"
8 #include <sstream>
9 #include <iostream>
10 #include <iomanip>
11 #include <fstream>
12 #include <string>
13 #include <vector>
14 #include <algorithm>
15 #include <ctime>
16 #include <cstdlib>
17 #include <cstring>
18 #include <boost/filesystem.hpp>
20 #ifdef NO_TIME_INTERCEPT
21 time_t __real_time(time_t* t)
23 return time(t);
25 #endif
27 namespace
29 std::string rseed;
30 uint64_t rcounter = 0;
32 std::string get_random_hexstring_64(size_t index)
34 std::ostringstream str;
35 str << rseed << " " << __real_time(NULL) << " " << (rcounter++) << " " << index;
36 std::string s = str.str();
37 std::vector<char> x;
38 x.resize(s.length());
39 std::copy(s.begin(), s.end(), x.begin());
40 return sha256::hash(reinterpret_cast<uint8_t*>(&x[0]), x.size());
43 std::string collect_identifying_information()
45 //TODO: Collect as much identifying information as possible.
46 std::ostringstream str;
47 time_t told = __real_time(NULL);
48 time_t tnew;
49 uint64_t loops = 0;
50 uint64_t base = 0;
51 int cnt = 0;
52 while(cnt < 3) {
53 tnew = __real_time(NULL);
54 if(tnew > told) {
55 told = tnew;
56 cnt++;
57 str << (loops - base) << " ";
58 base = loops;
60 loops++;
62 return str.str();
66 std::string get_random_hexstring(size_t length) throw(std::bad_alloc)
68 std::string out;
69 for(size_t i = 0; i < length; i += 64)
70 out = out + get_random_hexstring_64(i);
71 return out.substr(0, length);
74 void set_random_seed(const std::string& seed) throw(std::bad_alloc)
76 std::ostringstream str;
77 str << seed.length() << " " << seed;
78 rseed = str.str();
81 void set_random_seed() throw(std::bad_alloc)
83 //Try /dev/urandom first.
85 std::ifstream r("/dev/urandom", std::ios::binary);
86 if(r.is_open()) {
87 char buf[64];
88 r.read(buf, 64);
89 std::string s(buf, 64);
90 set_random_seed(s);
91 return;
94 //Fall back to time.
95 std::ostringstream str;
96 str << collect_identifying_information() << " " << __real_time(NULL);
97 set_random_seed(str.str());
100 //VERY dirty hack.
101 namespace foobar
103 #include <nall/sha256.hpp>
105 using foobar::nall::sha256_ctx;
106 using foobar::nall::sha256_init;
107 using foobar::nall::sha256_final;
108 using foobar::nall::sha256_hash;
109 using foobar::nall::sha256_chunk;
112 * \brief Opaque internal state of SHA256
114 struct sha256_opaque
117 * \brief Opaque internal state structure of SHA256
119 sha256_ctx shactx;
122 sha256::sha256() throw(std::bad_alloc)
124 opaque = new sha256_opaque();
125 finished = false;
126 sha256_init(&opaque->shactx);
129 sha256::~sha256() throw()
131 delete opaque;
134 void sha256::write(const uint8_t* data, size_t datalen) throw()
136 sha256_chunk(&opaque->shactx, data, datalen);
139 void sha256::read(uint8_t* hashout) throw()
141 if(!finished)
142 sha256_final(&opaque->shactx);
143 finished = true;
144 sha256_hash(&opaque->shactx, hashout);
147 std::string sha256::read() throw(std::bad_alloc)
149 uint8_t b[32];
150 read(b);
151 return sha256::tostring(b);
154 void sha256::hash(uint8_t* hashout, const uint8_t* data, size_t datalen) throw()
156 sha256 s;
157 s.write(data, datalen);
158 s.read(hashout);
161 std::string sha256::tostring(const uint8_t* hashout) throw(std::bad_alloc)
163 std::ostringstream str;
164 for(unsigned i = 0; i < 32; i++)
165 str << std::hex << std::setw(2) << std::setfill('0') << (unsigned)hashout[i];
166 return str.str();
169 struct loaded_rom load_rom_from_commandline(std::vector<std::string> cmdline) throw(std::bad_alloc,
170 std::runtime_error)
172 struct rom_files f;
173 try {
174 f = rom_files(cmdline);
175 f.resolve_relative();
176 } catch(std::bad_alloc& e) {
177 OOM_panic();
178 } catch(std::exception& e) {
179 throw std::runtime_error(std::string("Can't resolve ROM files: ") + e.what());
181 messages << "ROM type: " << gtype::tostring(f.rtype, f.region) << std::endl;
182 if(f.rom != "") messages << name_subrom(f.rtype, 0) << " file: '" << f.rom << "'" << std::endl;
183 if(f.rom_xml != "") messages << name_subrom(f.rtype, 1) << " file: '" << f.rom_xml << "'"
184 << std::endl;
185 if(f.slota != "") messages << name_subrom(f.rtype, 2) << " file: '" << f.slota << "'" << std::endl;
186 if(f.slota_xml != "") messages << name_subrom(f.rtype, 3) << " file: '" << f.slota_xml << "'"
187 << std::endl;
188 if(f.slotb != "") messages << name_subrom(f.rtype, 4) << " file: '" << f.slotb << "'" << std::endl;
189 if(f.slotb_xml != "") messages << name_subrom(f.rtype, 5) << " file: '" << f.slotb_xml << "'"
190 << std::endl;
192 struct loaded_rom r;
193 try {
194 r = loaded_rom(f);
195 r.do_patch(cmdline);
196 } catch(std::bad_alloc& e) {
197 OOM_panic();
198 } catch(std::exception& e) {
199 throw std::runtime_error(std::string("Can't load ROM: ") + e.what());
202 std::string not_present = "N/A";
203 if(r.rom.valid) messages << name_subrom(f.rtype, 0) << " hash: " << r.rom.sha256 << std::endl;
204 if(r.rom_xml.valid) messages << name_subrom(f.rtype, 1) << " hash: " << r.rom_xml.sha256 << std::endl;
205 if(r.slota.valid) messages << name_subrom(f.rtype, 2) << " hash: " << r.slota.sha256 << std::endl;
206 if(r.slota_xml.valid) messages << name_subrom(f.rtype, 3) << " hash: " << r.slota_xml.sha256
207 << std::endl;
208 if(r.slotb.valid) messages << name_subrom(f.rtype, 4) << " hash: " << r.slotb.sha256 << std::endl;
209 if(r.slotb_xml.valid) messages << name_subrom(f.rtype, 5) << " hash: " << r.slotb_xml.sha256
210 << std::endl;
211 return r;
214 void dump_region_map() throw(std::bad_alloc)
216 std::vector<struct memory_region> regions = get_regions();
217 for(auto i : regions) {
218 char buf[256];
219 sprintf(buf, "Region: %08X-%08X %08X %s%c %s", i.baseaddr, i.lastaddr, i.size,
220 i.readonly ? "R-" : "RW", i.native_endian ? 'N' : 'B', i.region_name.c_str());
221 messages << buf << std::endl;
225 void fatal_error() throw()
227 window::fatal_error();
228 std::cout << "PANIC: Fatal error, can't continue." << std::endl;
229 exit(1);
232 std::string get_config_path() throw(std::bad_alloc)
234 const char* tmp;
235 std::string basedir;
236 if((tmp = getenv("APPDATA"))) {
237 //If $APPDATA exists, it is the base directory
238 basedir = tmp;
239 } else if((tmp = getenv("XDG_CONFIG_HOME"))) {
240 //If $XDG_CONFIG_HOME exists, it is the base directory
241 basedir = tmp;
242 } else if((tmp = getenv("HOME"))) {
243 //If $HOME exists, the base directory is '.config' there.
244 basedir = std::string(tmp) + "/.config";
245 } else {
246 //Last chance: Return current directory.
247 return ".";
249 //Try to create 'lsnes'. If it exists (or is created) and is directory, great. Otherwise error out.
250 std::string lsnes_path = basedir + "/lsnes";
251 boost::filesystem::path p(lsnes_path);
252 if(!boost::filesystem::create_directories(p) && !boost::filesystem::is_directory(p)) {
253 messages << "FATAL: Can't create configuration directory '" << lsnes_path << "'" << std::endl;
254 fatal_error();
256 //Yes, this is racy, but portability is more important than being absolutely correct...
257 std::string tfile = lsnes_path + "/test";
258 remove(tfile.c_str());
259 FILE* x;
260 if(!(x = fopen(tfile.c_str(), "w+"))) {
261 messages << "FATAL: Configuration directory '" << lsnes_path << "' is not writable" << std::endl;
262 fatal_error();
264 fclose(x);
265 remove(tfile.c_str());
266 return lsnes_path;
269 extern const char* lsnesrc_file;
271 void create_lsnesrc()
273 std::string rcfile = get_config_path() + "/lsnes.rc";
274 std::ifstream x(rcfile.c_str());
275 if(x) {
276 x.close();
277 return;
279 std::ofstream y(rcfile.c_str());
280 if(!y) {
281 messages << "FATAL: lsnes.rc (" << rcfile << ") doesn't exist nor it can be created" << std::endl;
282 fatal_error();
284 y.write(lsnesrc_file, strlen(lsnesrc_file));
285 y.close();
289 void OOM_panic()
291 messages << "FATAL: Out of memory!" << std::endl;
292 fatal_error();
295 std::ostream& _messages()
297 return window::out();
300 uint32_t gcd(uint32_t a, uint32_t b) throw()
302 if(b == 0)
303 return a;
304 else
305 return gcd(b, a % b);
308 std::string bsnes_core_version;
309 std::string lsnes_version = "0-β19";