3 #include "core/command.hpp"
4 #include "core/controller.hpp"
5 #include "core/memorymanip.hpp"
6 #include "core/misc.hpp"
7 #include "core/rom.hpp"
8 #include "core/rrdata.hpp"
9 #include "core/settings.hpp"
10 #include "core/window.hpp"
11 #include "library/sha256.hpp"
12 #include "library/string.hpp"
24 #include <boost/filesystem.hpp>
26 #ifdef USE_LIBGCRYPT_SHA256
33 uint64_t rcounter
= 0;
34 bool reached_main_flag
;
36 std::string
get_random_hexstring_64(size_t index
)
38 std::ostringstream str
;
39 str
<< rseed
<< " " << time(NULL
) << " " << (rcounter
++) << " " << index
;
40 std::string s
= str
.str();
43 std::copy(s
.begin(), s
.end(), x
.begin());
44 return sha256::hash(reinterpret_cast<uint8_t*>(&x
[0]), x
.size());
47 std::string
collect_identifying_information()
49 //TODO: Collect as much identifying information as possible.
50 std::ostringstream str
;
51 time_t told
= time(NULL
);
61 str
<< (loops
- base
) << " ";
69 char endian_char(int e
)
78 //% is intentionally missing.
79 const char* allowed_filename_chars
= "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
80 "^&'@{}[],$?!-#().+~_";
81 const char* hexes
= "0123456789ABCDEF";
84 std::string
safe_filename(const std::string
& str
)
87 for(size_t i
= 0; i
< str
.length(); i
++) {
88 unsigned char ch
= static_cast<unsigned char>(str
[i
]);
89 if(strchr(allowed_filename_chars
, ch
))
92 o
<< "%" << hexes
[ch
/ 16] << hexes
[ch
% 16];
97 std::string
get_random_hexstring(size_t length
) throw(std::bad_alloc
)
100 for(size_t i
= 0; i
< length
; i
+= 64)
101 out
= out
+ get_random_hexstring_64(i
);
102 return out
.substr(0, length
);
105 void set_random_seed(const std::string
& seed
) throw(std::bad_alloc
)
107 std::ostringstream str
;
108 str
<< seed
.length() << " " << seed
;
110 rrdata
.set_internal(random_rrdata());
113 void set_random_seed() throw(std::bad_alloc
)
115 //Try /dev/urandom first.
117 std::ifstream
r("/dev/urandom", std::ios::binary
);
121 std::string
s(buf
, 64);
126 //If libgcrypt is available, use that.
127 #ifdef USE_LIBGCRYPT_SHA256
130 gcry_randomize((unsigned char*)buf
, sizeof(buf
), GCRY_STRONG_RANDOM
);
131 std::string
s(buf
, sizeof(buf
));
137 std::ostringstream str
;
138 str
<< collect_identifying_information() << " " << time(NULL
);
139 set_random_seed(str
.str());
143 struct loaded_rom
load_rom_from_commandline(std::vector
<std::string
> cmdline
) throw(std::bad_alloc
,
148 for(auto i
: cmdline
) {
149 if(!(optp
= regex("--rom=(.+)", i
)))
157 } catch(std::bad_alloc
& e
) {
159 } catch(std::exception
& e
) {
160 throw std::runtime_error(std::string("Can't load ROM: ") + e
.what());
163 std::string not_present
= "N/A";
164 for(size_t i
= 0; i
< ROM_SLOT_COUNT
; i
++) {
165 std::string romname
= "UNKNOWN ROM";
166 std::string xmlname
= "UNKNOWN XML";
167 if(i
< r
.rtype
->get_image_count()) {
168 romname
= (r
.rtype
->get_image_info(i
).hname
== "ROM") ? std::string("ROM") :
169 (r
.rtype
->get_image_info(i
).hname
+ " ROM");
170 xmlname
= r
.rtype
->get_image_info(i
).hname
+ " XML";
172 if(r
.romimg
[i
].data
) messages
<< romname
<< " hash: " << r
.romimg
[i
].sha_256
.read() << std::endl
;
173 if(r
.romxml
[i
].data
) messages
<< xmlname
<< " hash: " << r
.romxml
[i
].sha_256
.read() << std::endl
;
178 void dump_region_map() throw(std::bad_alloc
)
180 std::list
<struct memory_region
*> regions
= lsnes_memory
.get_regions();
181 for(auto i
: regions
) {
182 std::ostringstream x
;
183 x
<< std::setfill('0') << std::setw(16) << std::hex
<< i
->base
<< "-";
184 x
<< std::setfill('0') << std::setw(16) << std::hex
<< i
->last_address() << " ";
185 x
<< std::setfill('0') << std::setw(16) << std::hex
<< i
->size
<< " ";
186 messages
<< x
.str() << (i
->readonly
? "R-" : "RW") << endian_char(i
->endian
)
187 << (i
->special
? 'I' : 'M') << " " << i
->name
<< std::endl
;
191 void fatal_error() throw()
193 platform::fatal_error();
194 std::cout
<< "PANIC: Fatal error, can't continue." << std::endl
;
198 std::string
get_config_path() throw(std::bad_alloc
)
202 if((tmp
= getenv("APPDATA"))) {
203 //If $APPDATA exists, it is the base directory
205 } else if((tmp
= getenv("XDG_CONFIG_HOME"))) {
206 //If $XDG_CONFIG_HOME exists, it is the base directory
208 } else if((tmp
= getenv("HOME"))) {
209 //If $HOME exists, the base directory is '.config' there.
210 basedir
= std::string(tmp
) + "/.config";
212 //Last chance: Return current directory.
215 //Try to create 'lsnes'. If it exists (or is created) and is directory, great. Otherwise error out.
216 std::string lsnes_path
= basedir
+ "/lsnes";
217 boost::filesystem::path
p(lsnes_path
);
218 if(!boost::filesystem::create_directories(p
) && !boost::filesystem::is_directory(p
)) {
219 messages
<< "FATAL: Can't create configuration directory '" << lsnes_path
<< "'" << std::endl
;
222 //Yes, this is racy, but portability is more important than being absolutely correct...
223 std::string tfile
= lsnes_path
+ "/test";
224 remove(tfile
.c_str());
226 if(!(x
= fopen(tfile
.c_str(), "w+"))) {
227 messages
<< "FATAL: Configuration directory '" << lsnes_path
<< "' is not writable" << std::endl
;
231 remove(tfile
.c_str());
237 messages
<< "FATAL: Out of memory!" << std::endl
;
241 std::ostream
& messages_relay_class::getstream() { return platform::out(); }
242 messages_relay_class messages
;
244 uint32_t gcd(uint32_t a
, uint32_t b
) throw()
249 return gcd(b
, a
% b
);
252 std::string
format_address(void* addr
)
254 unsigned long x
= (unsigned long)addr
;
255 std::ostringstream y
;
256 y
<< "0x" << std::hex
<< std::setfill('0') << std::setw(2 * sizeof(unsigned long)) << x
;
260 bool in_global_ctors()
262 return !reached_main_flag
;
267 new_core_flag
= false; //We'll process the static cores anyway.
268 reached_main_flag
= true;
269 lsnes_cmd
.set_oom_panic(OOM_panic
);
270 lsnes_cmd
.set_output(platform::out());
273 std::string
mangle_name(const std::string
& orig
)
275 std::ostringstream out
;
282 out
<< "\xE2\x8F\xBF";
284 out
<< "\xE2\x8B\xBF";
293 function_ptr_command
<const std::string
&> macro_test(lsnes_cmd
, "test-macro", "", "",
294 [](const std::string
& args
) throw(std::bad_alloc
, std::runtime_error
) {
295 regex_results r
= regex("([0-9]+)[ \t](.*)", args
);
297 messages
<< "Bad syntax" << std::endl
;
300 unsigned ctrl
= parse_value
<unsigned>(r
[1]);
301 auto pcid
= controls
.lcid_to_pcid(ctrl
);
303 messages
<< "Bad controller" << std::endl
;
307 const port_controller
* _ctrl
= controls
.get_blank().porttypes().port_type(pcid
.first
).
308 controller_info
->get(pcid
.second
);
310 messages
<< "No controller data for controller" << std::endl
;
313 controller_macro_data
mdata(r
[2].c_str(), controller_macro_data::make_descriptor(*_ctrl
), 0);
314 messages
<< "Macro: " << mdata
.dump(*_ctrl
) << std::endl
;
315 } catch(std::exception
& e
) {
316 messages
<< "Exception: " << e
.what() << std::endl
;