mirror of
https://github.com/bsnes-emu/bsnes.git
synced 2025-09-19 06:11:44 +02:00
Compare commits
1 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
0114e10ede |
24
readme.txt
24
readme.txt
@@ -1,5 +1,5 @@
|
||||
bsnes
|
||||
Version: 0.035
|
||||
Version: 0.036
|
||||
Author: byuu
|
||||
|
||||
========
|
||||
@@ -38,9 +38,9 @@ If you wish to have multiple configuration profiles for the same user, you will
|
||||
need to make copies of the bsnes executable, and use each one in single-user
|
||||
mode.
|
||||
|
||||
==================
|
||||
Known Limitations:
|
||||
==================
|
||||
====================
|
||||
Known Limitation(s):
|
||||
====================
|
||||
|
||||
S-CPU
|
||||
- Multiply / divide register delays not implemented
|
||||
@@ -60,6 +60,16 @@ Hardware Bugs
|
||||
- S-CPU.r1 HDMA crashing bug not emulated
|
||||
- S-CPU<>S-SMP communication bus conflicts not emulated
|
||||
|
||||
===============
|
||||
Known Issue(s):
|
||||
===============
|
||||
|
||||
On Windows, attempting to load a ZIP, GZ or JMA compressed archive with
|
||||
non-ANSI characters in the filename will fail. This is because Windows
|
||||
requires UTF-16 encoding, but these libraries only work with UTF-8.
|
||||
Note that loading uncompressed images (SMC, SFC, etc) with non-ANSI characters
|
||||
works properly on all platforms.
|
||||
|
||||
=====================
|
||||
Unsupported Hardware:
|
||||
=====================
|
||||
@@ -89,9 +99,9 @@ SETA RISC CPU used by Quick-move Shogi Match with Nidan Rank-holder Morita 2
|
||||
Super Gameboy
|
||||
Cartridge passthrough used for playing Gameboy games
|
||||
|
||||
========================
|
||||
Unsupported Controllers:
|
||||
========================
|
||||
==========================
|
||||
Unsupported Controller(s):
|
||||
==========================
|
||||
|
||||
Mouse
|
||||
Super Scope
|
||||
|
@@ -1,4 +1,4 @@
|
||||
#define BSNES_VERSION "0.035"
|
||||
#define BSNES_VERSION "0.036"
|
||||
#define BSNES_TITLE "bsnes v" BSNES_VERSION
|
||||
|
||||
#define BUSCORE sBus
|
||||
@@ -24,6 +24,7 @@
|
||||
#include <nall/bit.hpp>
|
||||
#include <nall/config.hpp>
|
||||
#include <nall/detect.hpp>
|
||||
#include <nall/file.hpp>
|
||||
#include <nall/function.hpp>
|
||||
#include <nall/modulo.hpp>
|
||||
#include <nall/new.hpp>
|
||||
@@ -41,3 +42,9 @@ void alert(const char*, ...);
|
||||
void dprintf(const char*, ...);
|
||||
|
||||
#include "interface.h"
|
||||
|
||||
//helper: disable access to FILE, when possible (GZIP / JMA require it)
|
||||
//reason: Windows fopen() does not support UTF-8 filenames; use nall::file instead.
|
||||
#if !defined(GZIP_SUPPORT) && !defined(JMA_SUPPORT)
|
||||
#define FILE FILE_deprecated
|
||||
#endif
|
||||
|
@@ -89,7 +89,7 @@ void Cartridge::load_end() {
|
||||
memory::stBrom.write_protect(true);
|
||||
memory::stBram.write_protect(false);
|
||||
|
||||
if(fexists(get_cheat_filename(cart.fn, "cht"))) {
|
||||
if(file::exists(get_cheat_filename(cart.fn, "cht"))) {
|
||||
cheat.clear();
|
||||
cheat.load(cheatfn);
|
||||
}
|
||||
@@ -122,7 +122,7 @@ bool Cartridge::unload() {
|
||||
char fn[PATH_MAX];
|
||||
strcpy(fn, cart.fn);
|
||||
modify_extension(fn, "cht");
|
||||
if(cheat.count() > 0 || fexists(get_cheat_filename(cart.fn, "cht"))) {
|
||||
if(cheat.count() > 0 || file::exists(get_cheat_filename(cart.fn, "cht"))) {
|
||||
cheat.save(cheatfn);
|
||||
cheat.clear();
|
||||
}
|
||||
|
@@ -1,27 +1,27 @@
|
||||
#ifdef CART_CPP
|
||||
|
||||
#include "../reader/filereader.h"
|
||||
|
||||
#if defined(GZIP_SUPPORT)
|
||||
#include "../reader/gzreader.h"
|
||||
#include "../reader/zipreader.h"
|
||||
#endif
|
||||
|
||||
#if defined(JMA_SUPPORT)
|
||||
#include "../reader/jmareader.h"
|
||||
#endif
|
||||
|
||||
char* Cartridge::modify_extension(char *filename, const char *extension) {
|
||||
int i;
|
||||
for(i = strlen(filename); i >= 0; i--) {
|
||||
if(filename[i] == '.') break;
|
||||
if(filename[i] == '/') break;
|
||||
if(filename[i] == '\\') break;
|
||||
}
|
||||
if(i > 0 && filename[i] == '.') filename[i] = 0;
|
||||
strcat(filename, ".");
|
||||
strcat(filename, extension);
|
||||
return filename;
|
||||
#include "../reader/filereader.h"
|
||||
|
||||
#if defined(GZIP_SUPPORT)
|
||||
#include "../reader/gzreader.h"
|
||||
#include "../reader/zipreader.h"
|
||||
#endif
|
||||
|
||||
#if defined(JMA_SUPPORT)
|
||||
#include "../reader/jmareader.h"
|
||||
#endif
|
||||
|
||||
char* Cartridge::modify_extension(char *filename, const char *extension) {
|
||||
int i;
|
||||
for(i = strlen(filename); i >= 0; i--) {
|
||||
if(filename[i] == '.') break;
|
||||
if(filename[i] == '/') break;
|
||||
if(filename[i] == '\\') break;
|
||||
}
|
||||
if(i > 0 && filename[i] == '.') filename[i] = 0;
|
||||
strcat(filename, ".");
|
||||
strcat(filename, extension);
|
||||
return filename;
|
||||
}
|
||||
|
||||
//remove directory information and file extension ("/foo/bar.ext" -> "bar")
|
||||
@@ -46,39 +46,39 @@ char* Cartridge::get_base_filename(char *filename) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return filename;
|
||||
}
|
||||
|
||||
char* Cartridge::get_path_filename(char *filename, const char *path, const char *source, const char *extension) {
|
||||
strcpy(filename, source);
|
||||
for(char *p = filename; *p; p++) { if(*p == '\\') *p = '/'; }
|
||||
}
|
||||
|
||||
char* Cartridge::get_path_filename(char *filename, const char *path, const char *source, const char *extension) {
|
||||
strcpy(filename, source);
|
||||
for(char *p = filename; *p; p++) { if(*p == '\\') *p = '/'; }
|
||||
modify_extension(filename, extension);
|
||||
|
||||
//override path with user-specified folder, if one was defined
|
||||
|
||||
//override path with user-specified folder, if one was defined
|
||||
if(*path) {
|
||||
lstring part;
|
||||
split(part, "/", filename);
|
||||
string fn = path;
|
||||
if(strend(fn, "/") == false) strcat(fn, "/");
|
||||
strcat(fn, part[count(part) - 1]);
|
||||
strcpy(filename, fn);
|
||||
|
||||
//resolve relative path, if found
|
||||
if(strbegin(fn, "./") == true) {
|
||||
ltrim(fn, "./");
|
||||
strcpy(filename, config::path.base);
|
||||
strcat(filename, fn);
|
||||
}
|
||||
}
|
||||
|
||||
return filename;
|
||||
lstring part;
|
||||
split(part, "/", filename);
|
||||
string fn = path;
|
||||
if(strend(fn, "/") == false) strcat(fn, "/");
|
||||
strcat(fn, part[count(part) - 1]);
|
||||
strcpy(filename, fn);
|
||||
|
||||
//resolve relative path, if found
|
||||
if(strbegin(fn, "./") == true) {
|
||||
ltrim(fn, "./");
|
||||
strcpy(filename, config::path.base);
|
||||
strcat(filename, fn);
|
||||
}
|
||||
}
|
||||
|
||||
return filename;
|
||||
}
|
||||
|
||||
char* Cartridge::get_patch_filename(const char *source, const char *extension) {
|
||||
return get_path_filename(patchfn, config::path.patch, source, extension);
|
||||
}
|
||||
}
|
||||
|
||||
char* Cartridge::get_save_filename(const char *source, const char *extension) {
|
||||
return get_path_filename(savefn, config::path.save, source, extension);
|
||||
@@ -87,61 +87,65 @@ char* Cartridge::get_save_filename(const char *source, const char *extension) {
|
||||
char* Cartridge::get_cheat_filename(const char *source, const char *extension) {
|
||||
return get_path_filename(cheatfn, config::path.cheat, source, extension);
|
||||
}
|
||||
|
||||
bool Cartridge::load_file(const char *fn, uint8 *&data, uint &size, CompressionMode compression) {
|
||||
if(fexists(fn) == false) return false;
|
||||
|
||||
bool Cartridge::load_file(const char *fn, uint8 *&data, uint &size, CompressionMode compression) {
|
||||
if(file::exists(fn) == false) return false;
|
||||
|
||||
Reader::Type filetype = Reader::Normal;
|
||||
if(compression == CompressionInspect) filetype = Reader::detect(fn, true);
|
||||
if(compression == CompressionAuto) filetype = Reader::detect(fn, config::file.autodetect_type);
|
||||
|
||||
switch(filetype) {
|
||||
|
||||
switch(filetype) {
|
||||
default:
|
||||
dprintf("* Warning: filetype detected as unsupported compression type.");
|
||||
dprintf("* Will attempt to load as uncompressed file -- may fail.");
|
||||
case Reader::Normal: {
|
||||
FileReader ff(fn);
|
||||
if(!ff.ready()) {
|
||||
alert("Error loading image file (%s)!", fn);
|
||||
return false;
|
||||
}
|
||||
size = ff.size();
|
||||
data = ff.read();
|
||||
} break;
|
||||
|
||||
#ifdef GZIP_SUPPORT
|
||||
case Reader::GZIP: {
|
||||
GZReader gf(fn);
|
||||
if(!gf.ready()) {
|
||||
alert("Error loading image file (%s)!", fn);
|
||||
return false;
|
||||
}
|
||||
size = gf.size();
|
||||
data = gf.read();
|
||||
} break;
|
||||
|
||||
case Reader::ZIP: {
|
||||
ZipReader zf(fn);
|
||||
size = zf.size();
|
||||
data = zf.read();
|
||||
} break;
|
||||
#endif
|
||||
|
||||
#ifdef JMA_SUPPORT
|
||||
case Reader::JMA: {
|
||||
try {
|
||||
JMAReader jf(fn);
|
||||
size = jf.size();
|
||||
data = jf.read();
|
||||
} catch(JMA::jma_errors jma_error) {
|
||||
alert("Error loading image file (%s)!", fn);
|
||||
return false;
|
||||
}
|
||||
} break;
|
||||
#endif
|
||||
}
|
||||
|
||||
return true;
|
||||
dprintf("* Will attempt to load as uncompressed file -- may fail.");
|
||||
case Reader::Normal: {
|
||||
FileReader ff(fn);
|
||||
if(!ff.ready()) {
|
||||
alert("Error loading image file (%s)!", fn);
|
||||
return false;
|
||||
}
|
||||
size = ff.size();
|
||||
data = ff.read();
|
||||
} break;
|
||||
|
||||
#ifdef GZIP_SUPPORT
|
||||
case Reader::GZIP: {
|
||||
GZReader gf(fn);
|
||||
if(!gf.ready()) {
|
||||
alert("Error loading image file (%s)!", fn);
|
||||
return false;
|
||||
}
|
||||
size = gf.size();
|
||||
data = gf.read();
|
||||
} break;
|
||||
|
||||
case Reader::ZIP: {
|
||||
ZipReader zf(fn);
|
||||
if(!zf.ready()) {
|
||||
alert("Error loading image file (%s)!", fn);
|
||||
return false;
|
||||
}
|
||||
size = zf.size();
|
||||
data = zf.read();
|
||||
} break;
|
||||
#endif
|
||||
|
||||
#ifdef JMA_SUPPORT
|
||||
case Reader::JMA: {
|
||||
try {
|
||||
JMAReader jf(fn);
|
||||
size = jf.size();
|
||||
data = jf.read();
|
||||
} catch(JMA::jma_errors jma_error) {
|
||||
alert("Error loading image file (%s)!", fn);
|
||||
return false;
|
||||
}
|
||||
} break;
|
||||
#endif
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Cartridge::apply_patch(const uint8_t *pdata, const unsigned psize, uint8_t *&data, unsigned &size) {
|
||||
@@ -156,7 +160,7 @@ bool Cartridge::apply_patch(const uint8_t *pdata, const unsigned psize, uint8_t
|
||||
if(result == ups::input_crc32_invalid) apply = true;
|
||||
if(result == ups::output_crc32_invalid) apply = true;
|
||||
}
|
||||
|
||||
|
||||
//if patch application was successful, replace old data, size with new data, size
|
||||
if(apply == true) {
|
||||
delete[] data;
|
||||
@@ -164,16 +168,16 @@ bool Cartridge::apply_patch(const uint8_t *pdata, const unsigned psize, uint8_t
|
||||
memcpy(data, outdata, outsize);
|
||||
}
|
||||
|
||||
if(outdata) delete[] outdata;
|
||||
if(outdata) delete[] outdata;
|
||||
return apply;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool Cartridge::save_file(const char *fn, uint8 *data, uint size) {
|
||||
FILE *fp = fopen(fn, "wb");
|
||||
if(!fp) return false;
|
||||
fwrite(data, 1, size, fp);
|
||||
fclose(fp);
|
||||
file fp;
|
||||
if(!fp.open(fn, file::mode_write)) return false;
|
||||
fp.write(data, size);
|
||||
fp.close();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
#endif //ifdef CART_CPP
|
||||
|
@@ -147,7 +147,7 @@ bool Cheat::read(uint32 addr, uint8 &data) {
|
||||
* update_cheat_status() will scan to see if any codes are
|
||||
* enabled. if any are, make sure the cheat system is on.
|
||||
* otherwise, turn cheat system off to speed up emulation.
|
||||
*****/
|
||||
*****/
|
||||
|
||||
void Cheat::update_cheat_status() {
|
||||
for(unsigned i = 0; i < cheat_count; i++) {
|
||||
@@ -295,15 +295,15 @@ bool Cheat::load(const char *fn) {
|
||||
}
|
||||
|
||||
bool Cheat::save(const char *fn) {
|
||||
FILE *fp = fopen(fn, "wb");
|
||||
if(!fp) return false;
|
||||
file fp;
|
||||
if(!fp.open(fn, file::mode_write)) return false;
|
||||
for(unsigned i = 0; i < cheat_count; i++) {
|
||||
fprintf(fp, "%9s = %8s, \"%s\"\r\n",
|
||||
index[i].code,
|
||||
index[i].enabled ? "enabled" : "disabled",
|
||||
index[i].desc);
|
||||
fp.print(string()
|
||||
<< index[i].code << " = "
|
||||
<< (index[i].enabled ? "enabled" : "disabled") << ", \""
|
||||
<< index[i].desc << "\"\r\n");
|
||||
}
|
||||
fclose(fp);
|
||||
fp.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@@ -150,7 +150,7 @@ void sCPU::cycle_edge() {
|
||||
if(hdma_enabled_channels()) {
|
||||
dma_add_clocks(8 - dma_counter()); //DMA sync
|
||||
status.hdma_mode == 0 ? hdma_init() : hdma_run();
|
||||
status.dma_state = DMA_CPUsync;
|
||||
if(!dma_enabled_channels()) status.dma_state = DMA_CPUsync;
|
||||
}
|
||||
}
|
||||
|
||||
|
175
src/lib/bbase.h
175
src/lib/bbase.h
@@ -1,24 +1,24 @@
|
||||
/*
|
||||
bbase : version 0.14 ~byuu (2008-04-16)
|
||||
bbase : version 0.15 ~byuu (2008-09-14)
|
||||
license: public domain
|
||||
*/
|
||||
|
||||
#ifndef BBASE_H
|
||||
#define BBASE_H
|
||||
|
||||
#include <nall/stdint.hpp>
|
||||
typedef int8_t int8;
|
||||
typedef int16_t int16;
|
||||
typedef int32_t int32;
|
||||
typedef int64_t int64;
|
||||
typedef uint8_t uint8;
|
||||
typedef uint16_t uint16;
|
||||
typedef uint32_t uint32;
|
||||
typedef uint64_t uint64;
|
||||
typedef unsigned int uint;
|
||||
|
||||
#include <algorithm>
|
||||
using std::min;
|
||||
#define BBASE_H
|
||||
|
||||
#include <nall/stdint.hpp>
|
||||
typedef int8_t int8;
|
||||
typedef int16_t int16;
|
||||
typedef int32_t int32;
|
||||
typedef int64_t int64;
|
||||
typedef uint8_t uint8;
|
||||
typedef uint16_t uint16;
|
||||
typedef uint32_t uint32;
|
||||
typedef uint64_t uint64;
|
||||
typedef unsigned int uint;
|
||||
|
||||
#include <algorithm>
|
||||
using std::min;
|
||||
using std::max;
|
||||
|
||||
#include <assert.h>
|
||||
@@ -41,7 +41,7 @@ using std::max;
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
//disable libc deprecation warnings in MSVC 2k5+
|
||||
//disable libc deprecation warnings in MSVC 2k5+
|
||||
#pragma warning(disable:4996)
|
||||
|
||||
#define NOMINMAX
|
||||
@@ -52,17 +52,10 @@ using std::max;
|
||||
#if defined(_MSC_VER) || defined(__MINGW32__)
|
||||
#define getcwd _getcwd
|
||||
#define ftruncate _chsize
|
||||
#define mkdir _mkdir
|
||||
#define putenv _putenv
|
||||
#define rmdir _rmdir
|
||||
#define vsnprintf _vsnprintf
|
||||
#define vsnprintf _vsnprintf
|
||||
#define usleep(n) Sleep(n / 1000)
|
||||
|
||||
static char *realpath(const char *file_name, char *resolved_name) {
|
||||
return _fullpath(resolved_name, file_name, PATH_MAX);
|
||||
}
|
||||
#else
|
||||
#define mkdir(path) (mkdir)(path, 0755);
|
||||
#endif
|
||||
|
||||
/*****
|
||||
@@ -87,22 +80,29 @@ using std::max;
|
||||
* OS localization
|
||||
*****/
|
||||
|
||||
//userpath(output) retrieves path to user's home folder
|
||||
//output must be at least as large as PATH_MAX
|
||||
|
||||
#if defined(_MSC_VER) || defined(__MINGW32__)
|
||||
static char *userpath(char *output) {
|
||||
strcpy(output, "."); //failsafe
|
||||
SHGetFolderPath(0, CSIDL_APPDATA | CSIDL_FLAG_CREATE, 0, 0, output);
|
||||
static char* realpath(const char *file_name, char *resolved_name) {
|
||||
wchar_t filename[PATH_MAX] = L"";
|
||||
_wfullpath(filename, utf16(file_name), PATH_MAX);
|
||||
strcpy(resolved_name, utf8(filename));
|
||||
return resolved_name;
|
||||
}
|
||||
|
||||
static char* userpath(char *output) {
|
||||
wchar_t path[PATH_MAX] = L"."; //failsafe
|
||||
SHGetFolderPathW(0, CSIDL_APPDATA | CSIDL_FLAG_CREATE, 0, 0, path);
|
||||
strcpy(output, utf8(path));
|
||||
return output;
|
||||
}
|
||||
#define mkdir(path) _wmkdir(utf16(path))
|
||||
#else
|
||||
static char *userpath(char *output) {
|
||||
static char* userpath(char *output) {
|
||||
strcpy(output, "."); //failsafe
|
||||
struct passwd *userinfo = getpwuid(getuid());
|
||||
if(userinfo) { strcpy(output, userinfo->pw_dir); }
|
||||
return output;
|
||||
}
|
||||
#define mkdir(path) (mkdir)(path, 0755);
|
||||
#endif
|
||||
|
||||
template<int min, int max, typename T> inline T minmax(const T x) {
|
||||
@@ -113,93 +113,48 @@ template<int min, int max, typename T> inline T minmax(const T x) {
|
||||
* endian wrappers
|
||||
*****/
|
||||
|
||||
#ifndef ARCH_MSB
|
||||
//little-endian: uint8[] { 0x01, 0x02, 0x03, 0x04 } == 0x04030201
|
||||
#define order_lsb2(a,b) a,b
|
||||
#define order_lsb3(a,b,c) a,b,c
|
||||
#define order_lsb4(a,b,c,d) a,b,c,d
|
||||
#define order_lsb5(a,b,c,d,e) a,b,c,d,e
|
||||
#define order_lsb6(a,b,c,d,e,f) a,b,c,d,e,f
|
||||
#define order_lsb7(a,b,c,d,e,f,g) a,b,c,d,e,f,g
|
||||
#define order_lsb8(a,b,c,d,e,f,g,h) a,b,c,d,e,f,g,h
|
||||
#define order_msb2(a,b) b,a
|
||||
#define order_msb3(a,b,c) c,b,a
|
||||
#define order_msb4(a,b,c,d) d,c,b,a
|
||||
#define order_msb5(a,b,c,d,e) e,d,c,b,a
|
||||
#define order_msb6(a,b,c,d,e,f) f,e,d,c,b,a
|
||||
#define order_msb7(a,b,c,d,e,f,g) g,f,e,d,c,b,a
|
||||
#define order_msb8(a,b,c,d,e,f,g,h) h,g,f,e,d,c,b,a
|
||||
#else
|
||||
//big-endian: uint8[] { 0x01, 0x02, 0x03, 0x04 } == 0x01020304
|
||||
#define order_lsb2(a,b) b,a
|
||||
#define order_lsb3(a,b,c) c,b,a
|
||||
#define order_lsb4(a,b,c,d) d,c,b,a
|
||||
#define order_lsb5(a,b,c,d,e) e,d,c,b,a
|
||||
#define order_lsb6(a,b,c,d,e,f) f,e,d,c,b,a
|
||||
#define order_lsb7(a,b,c,d,e,f,g) g,f,e,d,c,b,a
|
||||
#define order_lsb8(a,b,c,d,e,f,g,h) h,g,f,e,d,c,b,a
|
||||
#define order_msb2(a,b) a,b
|
||||
#define order_msb3(a,b,c) a,b,c
|
||||
#define order_msb4(a,b,c,d) a,b,c,d
|
||||
#define order_msb5(a,b,c,d,e) a,b,c,d,e
|
||||
#define order_msb6(a,b,c,d,e,f) a,b,c,d,e,f
|
||||
#define order_msb7(a,b,c,d,e,f,g) a,b,c,d,e,f,g
|
||||
#define order_msb8(a,b,c,d,e,f,g,h) a,b,c,d,e,f,g,h
|
||||
#ifndef ARCH_MSB
|
||||
//little-endian: uint8[] { 0x01, 0x02, 0x03, 0x04 } == 0x04030201
|
||||
#define order_lsb2(a,b) a,b
|
||||
#define order_lsb3(a,b,c) a,b,c
|
||||
#define order_lsb4(a,b,c,d) a,b,c,d
|
||||
#define order_lsb5(a,b,c,d,e) a,b,c,d,e
|
||||
#define order_lsb6(a,b,c,d,e,f) a,b,c,d,e,f
|
||||
#define order_lsb7(a,b,c,d,e,f,g) a,b,c,d,e,f,g
|
||||
#define order_lsb8(a,b,c,d,e,f,g,h) a,b,c,d,e,f,g,h
|
||||
#define order_msb2(a,b) b,a
|
||||
#define order_msb3(a,b,c) c,b,a
|
||||
#define order_msb4(a,b,c,d) d,c,b,a
|
||||
#define order_msb5(a,b,c,d,e) e,d,c,b,a
|
||||
#define order_msb6(a,b,c,d,e,f) f,e,d,c,b,a
|
||||
#define order_msb7(a,b,c,d,e,f,g) g,f,e,d,c,b,a
|
||||
#define order_msb8(a,b,c,d,e,f,g,h) h,g,f,e,d,c,b,a
|
||||
#else
|
||||
//big-endian: uint8[] { 0x01, 0x02, 0x03, 0x04 } == 0x01020304
|
||||
#define order_lsb2(a,b) b,a
|
||||
#define order_lsb3(a,b,c) c,b,a
|
||||
#define order_lsb4(a,b,c,d) d,c,b,a
|
||||
#define order_lsb5(a,b,c,d,e) e,d,c,b,a
|
||||
#define order_lsb6(a,b,c,d,e,f) f,e,d,c,b,a
|
||||
#define order_lsb7(a,b,c,d,e,f,g) g,f,e,d,c,b,a
|
||||
#define order_lsb8(a,b,c,d,e,f,g,h) h,g,f,e,d,c,b,a
|
||||
#define order_msb2(a,b) a,b
|
||||
#define order_msb3(a,b,c) a,b,c
|
||||
#define order_msb4(a,b,c,d) a,b,c,d
|
||||
#define order_msb5(a,b,c,d,e) a,b,c,d,e
|
||||
#define order_msb6(a,b,c,d,e,f) a,b,c,d,e,f
|
||||
#define order_msb7(a,b,c,d,e,f,g) a,b,c,d,e,f,g
|
||||
#define order_msb8(a,b,c,d,e,f,g,h) a,b,c,d,e,f,g,h
|
||||
#endif
|
||||
|
||||
/*****
|
||||
* libc extensions
|
||||
*****/
|
||||
|
||||
|
||||
//pseudo-random number generator
|
||||
static unsigned prng() {
|
||||
static unsigned n = 0;
|
||||
return n = (n >> 1) ^ (((n & 1) - 1) & 0xedb88320);
|
||||
}
|
||||
|
||||
static uint64 fget(FILE *fp, unsigned length = 1) {
|
||||
uint64 data = 0;
|
||||
for(unsigned i = 0; i < length; i++) {
|
||||
data |= fgetc(fp) << (i << 3);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
static void fput(FILE *fp, uint64 data, unsigned length = 1) {
|
||||
for(unsigned i = 0; i < length; i++) {
|
||||
fputc(data >> (i << 3), fp);
|
||||
}
|
||||
}
|
||||
|
||||
static bool fexists(const char *fn) {
|
||||
FILE *fp = fopen(fn, "rb");
|
||||
if(!fp) return false;
|
||||
fclose(fp);
|
||||
fp = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
static unsigned fsize(FILE *fp) {
|
||||
if(!fp) return 0;
|
||||
unsigned pos = ftell(fp);
|
||||
fseek(fp, 0, SEEK_END);
|
||||
unsigned size = ftell(fp);
|
||||
fseek(fp, pos, SEEK_SET);
|
||||
return size;
|
||||
}
|
||||
|
||||
static unsigned fsize(const char *fn) {
|
||||
FILE *fp = fopen(fn, "rb");
|
||||
if(!fp) return 0;
|
||||
fseek(fp, 0, SEEK_END);
|
||||
unsigned size = ftell(fp);
|
||||
fclose(fp);
|
||||
fp = 0;
|
||||
return size;
|
||||
}
|
||||
|
||||
static int fresize(FILE *fp, long size) {
|
||||
return ftruncate(fileno(fp), size);
|
||||
}
|
||||
|
||||
#endif //ifndef BBASE_H
|
||||
|
@@ -1,6 +0,0 @@
|
||||
mingw32-g++ -c test/test.cpp -I. -I../
|
||||
mingw32-g++ -c hiro.cpp -I. -I../
|
||||
mingw32-g++ -c ../nall/string.cpp -I. -I../
|
||||
mingw32-g++ test.o hiro.o string.o -o test_app.exe -lkernel32 -luser32 -lgdi32 -ladvapi32 -lcomctl32 -lcomdlg32
|
||||
@pause
|
||||
@del *.o
|
@@ -1,6 +0,0 @@
|
||||
clear
|
||||
g++ -c test/test.cpp -I. -I../
|
||||
g++ -c hiro.cpp `pkg-config --cflags gtk+-2.0` -I. -I../
|
||||
g++ -c ../nall/string.cpp -I. -I../
|
||||
g++ test.o hiro.o string.o -o test_app `pkg-config --libs gtk+-2.0` -lXtst
|
||||
rm *.o
|
@@ -4,11 +4,14 @@
|
||||
using nall::min;
|
||||
using nall::max;
|
||||
|
||||
#include <nall/utf8.hpp>
|
||||
using nall::utf8;
|
||||
using nall::utf16;
|
||||
|
||||
namespace libhiro {
|
||||
|
||||
LRESULT CALLBACK phiro_wndproc(HWND, UINT, WPARAM, LPARAM);
|
||||
|
||||
#include "utf.cpp"
|
||||
#include "keymap.cpp"
|
||||
#include "widget.cpp"
|
||||
#include "window.cpp"
|
||||
|
@@ -2,6 +2,7 @@
|
||||
#define NALL_CONFIG_HPP
|
||||
|
||||
#include <nall/array.hpp>
|
||||
#include <nall/file.hpp>
|
||||
#include <nall/stdint.hpp>
|
||||
#include <nall/string.hpp>
|
||||
|
||||
@@ -13,7 +14,7 @@ class configuration {
|
||||
public:
|
||||
array<setting*> list;
|
||||
|
||||
bool load(const char *fn) const;
|
||||
bool load(const char *fn);
|
||||
bool save(const char *fn) const;
|
||||
void add(setting *setting_) { list.add(setting_); }
|
||||
};
|
||||
@@ -116,28 +117,17 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
inline bool configuration::load(const char *fn) const {
|
||||
FILE *fp = fopen(fn, "rb");
|
||||
if(!fp) return false;
|
||||
|
||||
string data;
|
||||
lstring line, part, subpart;
|
||||
|
||||
inline bool configuration::load(const char *fn) {
|
||||
//load the config file into memory
|
||||
fseek(fp, 0, SEEK_END);
|
||||
int size = ftell(fp);
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
char *buffer = (char*)malloc(size + 1);
|
||||
fread(buffer, 1, size, fp);
|
||||
fclose(fp);
|
||||
buffer[size] = 0;
|
||||
strcpy(data, buffer);
|
||||
free(buffer);
|
||||
string data;
|
||||
if(!fread(data, fn)) return false;
|
||||
|
||||
//split the file into lines
|
||||
replace(data, "\r\n", "\n");
|
||||
qreplace(data, "\t", "");
|
||||
qreplace(data, " ", "");
|
||||
|
||||
lstring line, part, subpart;
|
||||
split(line, "\n", data);
|
||||
|
||||
for(unsigned i = 0; i < count(line); i++) {
|
||||
@@ -157,8 +147,8 @@ inline bool configuration::load(const char *fn) const {
|
||||
}
|
||||
|
||||
inline bool configuration::save(const char *fn) const {
|
||||
FILE *fp = fopen(fn, "wb");
|
||||
if(!fp) return false;
|
||||
file fp;
|
||||
if(!fp.open(fn, file::mode_write)) return false;
|
||||
|
||||
for(unsigned i = 0; i < list.size(); i++) {
|
||||
string data;
|
||||
@@ -166,18 +156,20 @@ inline bool configuration::save(const char *fn) const {
|
||||
strcpy(data, list[i]->description);
|
||||
replace(data, "\r\n", "\n");
|
||||
split(line, "\n", data);
|
||||
|
||||
string temp;
|
||||
for(unsigned l = 0; l < count(line); l++) {
|
||||
if(line[l] != "") fprintf(fp, "# %s\r\n", (const char*)line[l]);
|
||||
if(line[l] != "") fp.print(string() << "# " << line[l] << "\r\n");
|
||||
}
|
||||
|
||||
string default_, value_;
|
||||
list[i]->get_default(default_);
|
||||
fprintf(fp, "# (default = %s)\r\n", (const char*)default_);
|
||||
fp.print(string() << "# (default = " << default_ << ")\r\n");
|
||||
list[i]->get(value_);
|
||||
fprintf(fp, "%s = %s\r\n\r\n", list[i]->name, (const char*)value_);
|
||||
fp.print(string() << list[i]->name << " = " << value_ << "\r\n\r\n");
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
fp.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@@ -5,6 +5,7 @@
|
||||
#include <string.h>
|
||||
|
||||
#include <nall/stdint.hpp>
|
||||
#include <nall/utf8.hpp>
|
||||
#include <nall/utility.hpp>
|
||||
|
||||
namespace nall {
|
||||
@@ -69,6 +70,11 @@ public:
|
||||
while(length--) write(*buffer++);
|
||||
}
|
||||
|
||||
void print(const char *string) {
|
||||
if(!string) return;
|
||||
while(*string) write(*string++);
|
||||
}
|
||||
|
||||
void flush() {
|
||||
buffer_flush();
|
||||
fflush(fp);
|
||||
@@ -112,13 +118,38 @@ public:
|
||||
return file_offset >= file_size;
|
||||
}
|
||||
|
||||
static bool exists(const char *fn) {
|
||||
#if !defined(_WIN32)
|
||||
FILE *fp = fopen(fn, "rb");
|
||||
#else
|
||||
FILE *fp = _wfopen(utf16(fn), L"rb");
|
||||
#endif
|
||||
if(fp) {
|
||||
fclose(fp);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool open() {
|
||||
return fp;
|
||||
}
|
||||
|
||||
bool open(const char *fn, FileMode mode) {
|
||||
if(fp) return false;
|
||||
|
||||
switch(file_mode = mode) {
|
||||
#if !defined(_WIN32)
|
||||
case mode_read: fp = fopen(fn, "rb"); break;
|
||||
case mode_write: fp = fopen(fn, "wb+"); break; //need read permission for buffering
|
||||
case mode_readwrite: fp = fopen(fn, "rb+"); break;
|
||||
case mode_writeread: fp = fopen(fn, "wb+"); break;
|
||||
#else
|
||||
case mode_read: fp = _wfopen(utf16(fn), L"rb"); break;
|
||||
case mode_write: fp = _wfopen(utf16(fn), L"wb+"); break;
|
||||
case mode_readwrite: fp = _wfopen(utf16(fn), L"rb+"); break;
|
||||
case mode_writeread: fp = _wfopen(utf16(fn), L"wb+"); break;
|
||||
#endif
|
||||
}
|
||||
if(!fp) return false;
|
||||
buffer_offset = -1; //invalidate buffer
|
||||
|
@@ -2,6 +2,7 @@
|
||||
#define NALL_FILEMAP_HPP
|
||||
|
||||
#include <nall/stdint.hpp>
|
||||
#include <nall/utf8.hpp>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -72,7 +73,7 @@ private:
|
||||
break;
|
||||
}
|
||||
|
||||
p_filehandle = CreateFile(filename, desired_access, FILE_SHARE_READ, NULL,
|
||||
p_filehandle = CreateFileW(utf16(filename), desired_access, FILE_SHARE_READ, NULL,
|
||||
creation_disposition, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if(p_filehandle == INVALID_HANDLE_VALUE) return false;
|
||||
|
||||
|
82
src/lib/nall/serial.hpp
Normal file
82
src/lib/nall/serial.hpp
Normal file
@@ -0,0 +1,82 @@
|
||||
#ifndef NALL_SERIAL_HPP
|
||||
#define NALL_SERIAL_HPP
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <fcntl.h>
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <nall/stdint.hpp>
|
||||
|
||||
namespace nall {
|
||||
|
||||
class serial {
|
||||
public:
|
||||
//-1 on error, otherwise return bytes read
|
||||
int read(uint8_t *data, unsigned length) {
|
||||
if(port_open == false) return -1;
|
||||
return ::read(port, (void*)data, length);
|
||||
}
|
||||
|
||||
//-1 on error, otherwise return bytes written
|
||||
int write(const uint8_t *data, unsigned length) {
|
||||
if(port_open == false) return -1;
|
||||
return ::write(port, (void*)data, length);
|
||||
}
|
||||
|
||||
bool open(const char *portname, unsigned rate) {
|
||||
close();
|
||||
|
||||
port = ::open(portname, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK);
|
||||
if(port == -1) return false;
|
||||
|
||||
if(ioctl(port, TIOCEXCL) == -1) { close(); return false; }
|
||||
if(fcntl(port, F_SETFL, 0) == -1) { close(); return false; }
|
||||
if(tcgetattr(port, &original_attr) == -1) { close(); return false; }
|
||||
|
||||
termios attr = original_attr;
|
||||
cfmakeraw(&attr);
|
||||
cfsetspeed(&attr, rate);
|
||||
|
||||
attr.c_lflag &=~ (ECHO | ECHONL | ISIG | ICANON | IEXTEN);
|
||||
attr.c_iflag &=~ (BRKINT | PARMRK | INPCK | ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXOFF | IXANY);
|
||||
attr.c_iflag |= (IGNBRK | IGNPAR);
|
||||
attr.c_oflag &=~ (OPOST);
|
||||
attr.c_cflag &=~ (CSIZE | CSTOPB | PARENB);
|
||||
attr.c_cflag |= (CS8 | CREAD | CLOCAL);
|
||||
attr.c_cc[VTIME] = attr.c_cc[VMIN] = 0;
|
||||
|
||||
if(tcsetattr(port, TCSANOW, &attr) == -1) { close(); return false; }
|
||||
return port_open = true;
|
||||
}
|
||||
|
||||
void close() {
|
||||
if(port != -1) {
|
||||
tcdrain(port);
|
||||
if(port_open == true) {
|
||||
tcsetattr(port, TCSANOW, &original_attr);
|
||||
port_open = false;
|
||||
}
|
||||
::close(port);
|
||||
port = -1;
|
||||
}
|
||||
}
|
||||
|
||||
serial() {
|
||||
port = -1;
|
||||
port_open = false;
|
||||
}
|
||||
|
||||
~serial() {
|
||||
close();
|
||||
}
|
||||
|
||||
private:
|
||||
int port;
|
||||
bool port_open;
|
||||
termios original_attr;
|
||||
};
|
||||
|
||||
} //namespace nall
|
||||
|
||||
#endif //ifndef NALL_SERIAL_HPP
|
@@ -4,15 +4,15 @@
|
||||
namespace nall {
|
||||
|
||||
template<typename T> inline void swap(T &x, T &y) {
|
||||
T z = x;
|
||||
T temp = x;
|
||||
x = y;
|
||||
y = z;
|
||||
y = temp;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void sort(T list[], unsigned length) {
|
||||
for(unsigned d = 0; d < length; d++) {
|
||||
unsigned min = d;
|
||||
unsigned min = d;
|
||||
for(unsigned s = d + 1; s < length; s++) {
|
||||
if(list[s] < list[min]) { min = s; }
|
||||
}
|
||||
@@ -22,10 +22,10 @@ void sort(T list[], unsigned length) {
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T, typename Tcmp>
|
||||
void sort(T list[], unsigned length, Tcmp comparator) {
|
||||
template<typename T, typename Comparator>
|
||||
void sort(T list[], unsigned length, Comparator comparator) {
|
||||
for(unsigned d = 0; d < length; d++) {
|
||||
unsigned min = d;
|
||||
unsigned min = d;
|
||||
for(unsigned s = d + 1; s < length; s++) {
|
||||
if(comparator(list[s], list[min]) == true) { min = s; }
|
||||
}
|
||||
|
@@ -4,6 +4,7 @@
|
||||
#include <math.h>
|
||||
#include <nall/algorithm.hpp>
|
||||
#include <nall/static.hpp>
|
||||
#include <nall/utf8.hpp>
|
||||
|
||||
#include <nall/string.hpp>
|
||||
#include <nall/string/class.cpp>
|
||||
|
@@ -63,7 +63,7 @@ string& string::operator=(const string &str) {
|
||||
}
|
||||
|
||||
string& string::operator<<(int num) {
|
||||
string temp(num);
|
||||
string temp(num);
|
||||
strcat(*this, temp);
|
||||
return *this;
|
||||
}
|
||||
@@ -147,7 +147,7 @@ size_t strlcat(nall::string &dest, const char *src, size_t length) {
|
||||
}
|
||||
|
||||
nall::string substr(const char *src, size_t start, size_t length) {
|
||||
nall::string dest;
|
||||
nall::string dest;
|
||||
if(length == 0) { //copy entire string
|
||||
strcpy(dest, src + start);
|
||||
} else { //copy partial string
|
||||
@@ -171,28 +171,28 @@ nall::string& trim_once (nall::string &str, const char *key) { trim_once (str(),
|
||||
/* arithmetic <> string */
|
||||
|
||||
nall::string strhex(uintmax_t value) {
|
||||
nall::string temp;
|
||||
nall::string temp;
|
||||
temp.reserve(strhex(0, value));
|
||||
strhex(temp(), value);
|
||||
return temp;
|
||||
}
|
||||
|
||||
nall::string strdec(intmax_t value) {
|
||||
nall::string temp;
|
||||
nall::string temp;
|
||||
temp.reserve(strdec(0, value));
|
||||
strdec(temp(), value);
|
||||
return temp;
|
||||
}
|
||||
|
||||
nall::string strbin(uintmax_t value) {
|
||||
nall::string temp;
|
||||
nall::string temp;
|
||||
temp.reserve(strbin(0, value));
|
||||
strbin(temp(), value);
|
||||
return temp;
|
||||
}
|
||||
|
||||
nall::string strdouble(double value) {
|
||||
nall::string temp;
|
||||
nall::string temp;
|
||||
temp.reserve(strdouble(0, value));
|
||||
strdouble(temp(), value);
|
||||
return temp;
|
||||
@@ -203,13 +203,17 @@ nall::string temp;
|
||||
bool fread(nall::string &str, const char *filename) {
|
||||
strcpy(str, "");
|
||||
|
||||
FILE *fp = fopen(filename, "rb");
|
||||
#if !defined(_WIN32)
|
||||
FILE *fp = fopen(filename, "rb");
|
||||
#else
|
||||
FILE *fp = _wfopen(nall::utf16(filename), L"rb");
|
||||
#endif
|
||||
if(!fp)return false;
|
||||
|
||||
fseek(fp, 0, SEEK_END);
|
||||
size_t size = ftell(fp);
|
||||
size_t size = ftell(fp);
|
||||
rewind(fp);
|
||||
char *fdata = (char*)malloc(size + 1);
|
||||
char *fdata = (char*)malloc(size + 1);
|
||||
fread(fdata, 1, size, fp);
|
||||
fclose(fp);
|
||||
fdata[size] = 0;
|
||||
|
@@ -5,6 +5,7 @@
|
||||
|
||||
#include <nall/algorithm.hpp>
|
||||
#include <nall/crc32.hpp>
|
||||
#include <nall/file.hpp>
|
||||
#include <nall/new.hpp>
|
||||
#include <nall/stdint.hpp>
|
||||
|
||||
@@ -25,8 +26,7 @@ public:
|
||||
};
|
||||
|
||||
ups::result create(const char *patch_fn, const uint8_t *x_data, unsigned x_size, const uint8_t *y_data, unsigned y_size) {
|
||||
fp = fopen(patch_fn, "wb");
|
||||
if(!fp) return patch_unwritable;
|
||||
if(!fp.open(patch_fn, file::mode_write)) return patch_unwritable;
|
||||
|
||||
crc32 = ~0;
|
||||
uint32_t x_crc32 = crc32_calculate(x_data, x_size);
|
||||
@@ -77,7 +77,7 @@ public:
|
||||
uint32_t p_crc32 = ~crc32;
|
||||
for(unsigned i = 0; i < 4; i++) write(p_crc32 >> (i << 3));
|
||||
|
||||
fclose(fp);
|
||||
fp.close();
|
||||
return ok;
|
||||
}
|
||||
|
||||
@@ -147,7 +147,7 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
FILE *fp;
|
||||
file fp;
|
||||
uint32_t crc32;
|
||||
const uint8_t *p_buffer;
|
||||
|
||||
@@ -158,7 +158,7 @@ private:
|
||||
}
|
||||
|
||||
void write(uint8_t n) {
|
||||
fputc(n, fp);
|
||||
fp.write(n);
|
||||
crc32 = crc32_adjust(crc32, n);
|
||||
}
|
||||
|
||||
|
@@ -1,6 +1,18 @@
|
||||
/*****
|
||||
* UTF-8 to UTF-16
|
||||
*****/
|
||||
#ifndef NALL_UTF8_HPP
|
||||
#define NALL_UTF8_HPP
|
||||
|
||||
#include <nall/new.hpp>
|
||||
|
||||
//UTF-8 <> UTF-16 conversion
|
||||
//used only for Win32; Linux, etc use UTF-8 internally
|
||||
|
||||
#if defined(_WIN32)
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
namespace nall {
|
||||
|
||||
//UTF-8 to UTF-16
|
||||
class utf16 {
|
||||
public:
|
||||
operator wchar_t*() {
|
||||
@@ -26,9 +38,7 @@ private:
|
||||
wchar_t *buffer;
|
||||
};
|
||||
|
||||
/*****
|
||||
* UTF-16 to UTF-8
|
||||
*****/
|
||||
//UTF-16 to UTF-8
|
||||
class utf8 {
|
||||
public:
|
||||
operator char*() {
|
||||
@@ -53,3 +63,9 @@ public:
|
||||
private:
|
||||
char *buffer;
|
||||
};
|
||||
|
||||
} //namespace nall
|
||||
|
||||
#endif //if defined(_WIN32)
|
||||
|
||||
#endif //ifndef NALL_UTF8_HPP
|
@@ -3,7 +3,7 @@
|
||||
#include "filereader.h"
|
||||
|
||||
unsigned FileReader::size() {
|
||||
return filesize;
|
||||
return fp.size();
|
||||
}
|
||||
|
||||
//This function will allocate memory even if open() fails.
|
||||
@@ -15,44 +15,35 @@ uint8_t* FileReader::read(unsigned length) {
|
||||
|
||||
if(length == 0) {
|
||||
//read the entire file into RAM
|
||||
data = new(zeromemory) uint8_t[filesize];
|
||||
if(fp) fread(data, 1, filesize, fp);
|
||||
} else if(length > filesize) {
|
||||
data = new(zeromemory) uint8_t[fp.size()];
|
||||
if(fp.open()) fp.read(data, fp.size());
|
||||
} else if(length > fp.size()) {
|
||||
//read the entire file into RAM, pad the rest with 0x00s
|
||||
data = new(zeromemory) uint8_t[length];
|
||||
if(fp) fread(data, 1, filesize, fp);
|
||||
if(fp.open()) fp.read(data, fp.size());
|
||||
} else { //filesize >= length
|
||||
//read only what was requested
|
||||
data = new(zeromemory) uint8_t[length];
|
||||
if(fp) fread(data, 1, length, fp);
|
||||
if(fp.open()) fp.read(data, length);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
bool FileReader::ready() {
|
||||
return (fp != 0);
|
||||
return fp.open();
|
||||
}
|
||||
|
||||
FileReader::FileReader(const char *fn) {
|
||||
fp = fopen(fn, "rb");
|
||||
if(!fp) return;
|
||||
|
||||
fseek(fp, 0, SEEK_END);
|
||||
filesize = ftell(fp);
|
||||
rewind(fp);
|
||||
if(!fp.open(fn, file::mode_read)) return;
|
||||
|
||||
//empty file?
|
||||
if(filesize == 0) {
|
||||
fclose(fp);
|
||||
fp = 0;
|
||||
if(fp.size() == 0) {
|
||||
fp.close();
|
||||
}
|
||||
}
|
||||
|
||||
FileReader::~FileReader() {
|
||||
if(fp) {
|
||||
fclose(fp);
|
||||
fp = 0;
|
||||
}
|
||||
if(fp.open()) fp.close();
|
||||
}
|
||||
|
||||
#endif //ifdef READER_CPP
|
||||
|
@@ -8,6 +8,5 @@ public:
|
||||
~FileReader();
|
||||
|
||||
private:
|
||||
FILE *fp;
|
||||
unsigned filesize;
|
||||
file fp;
|
||||
};
|
||||
|
@@ -13,13 +13,13 @@
|
||||
#endif
|
||||
|
||||
Reader::Type Reader::detect(const char *fn, bool inspectheader) {
|
||||
FILE *fp = fopen(fn, "rb");
|
||||
if(!fp) return Unknown;
|
||||
file fp;
|
||||
if(!fp.open(fn, file::mode_read)) return Unknown;
|
||||
|
||||
uint8_t p[8];
|
||||
memset(p, 0, sizeof p);
|
||||
fread(p, 1, 8, fp);
|
||||
fclose(fp);
|
||||
fp.read(p, 8);
|
||||
fp.close();
|
||||
|
||||
if(inspectheader == true) {
|
||||
//inspect file header to determine type
|
||||
|
@@ -1,52 +1,57 @@
|
||||
#ifdef READER_CPP
|
||||
|
||||
#include "zipreader.h"
|
||||
|
||||
unsigned ZipReader::size() {
|
||||
return filesize;
|
||||
}
|
||||
|
||||
#define MAXROM 0x800000
|
||||
|
||||
uint8_t* ZipReader::read(unsigned length) {
|
||||
uint8_t *data = 0;
|
||||
#include "zipreader.h"
|
||||
|
||||
if(!filesize) return 0;
|
||||
unsigned ZipReader::size() {
|
||||
return filesize;
|
||||
}
|
||||
|
||||
if(length <= filesize) {
|
||||
//read the entire file into RAM
|
||||
data = new(zeromemory) uint8_t[filesize];
|
||||
unzReadCurrentFile(zipfile, data, filesize);
|
||||
} else if(length > filesize) {
|
||||
//read the entire file into RAM, pad the rest with 0x00s
|
||||
data = new(zeromemory) uint8_t[length];
|
||||
unzReadCurrentFile(zipfile, data, filesize);
|
||||
#define MAXROM 0x800000
|
||||
|
||||
uint8_t* ZipReader::read(unsigned length) {
|
||||
uint8_t *data = 0;
|
||||
|
||||
if(!filesize) return 0;
|
||||
|
||||
if(length <= filesize) {
|
||||
//read the entire file into RAM
|
||||
data = new(zeromemory) uint8_t[filesize];
|
||||
unzReadCurrentFile(zipfile, data, filesize);
|
||||
} else if(length > filesize) {
|
||||
//read the entire file into RAM, pad the rest with 0x00s
|
||||
data = new(zeromemory) uint8_t[length];
|
||||
unzReadCurrentFile(zipfile, data, filesize);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
ZipReader::ZipReader(const char *fn) : filesize(0) {
|
||||
unz_file_info cFileInfo; //Create variable to hold info for a compressed file
|
||||
char cFileName[sizeof(cname)];
|
||||
|
||||
if(zipfile = unzOpen(fn)) { //Open zip file
|
||||
for(int cFile = unzGoToFirstFile(zipfile); cFile == UNZ_OK; cFile = unzGoToNextFile(zipfile)) {
|
||||
//Gets info on current file, and places it in cFileInfo
|
||||
unzGetCurrentFileInfo(zipfile, &cFileInfo, cFileName, sizeof(cname), 0, 0, 0, 0);
|
||||
|
||||
if((cFileInfo.uncompressed_size <= MAXROM+512) && (cFileInfo.uncompressed_size > filesize)) {
|
||||
strcpy(cname, cFileName);
|
||||
filesize = cFileInfo.uncompressed_size;
|
||||
}
|
||||
}
|
||||
|
||||
if(filesize) {
|
||||
unzLocateFile(zipfile, cname, 1);
|
||||
unzOpenCurrentFile(zipfile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
bool ZipReader::ready() {
|
||||
return zipready;
|
||||
}
|
||||
|
||||
ZipReader::ZipReader(const char *fn) : filesize(0), zipready(false) {
|
||||
unz_file_info cFileInfo; //Create variable to hold info for a compressed file
|
||||
char cFileName[sizeof(cname)];
|
||||
|
||||
if(zipfile = unzOpen(fn)) { //Open zip file
|
||||
for(int cFile = unzGoToFirstFile(zipfile); cFile == UNZ_OK; cFile = unzGoToNextFile(zipfile)) {
|
||||
//Gets info on current file, and places it in cFileInfo
|
||||
unzGetCurrentFileInfo(zipfile, &cFileInfo, cFileName, sizeof(cname), 0, 0, 0, 0);
|
||||
|
||||
if((cFileInfo.uncompressed_size <= MAXROM+512) && (cFileInfo.uncompressed_size > filesize)) {
|
||||
strcpy(cname, cFileName);
|
||||
filesize = cFileInfo.uncompressed_size;
|
||||
}
|
||||
}
|
||||
|
||||
if(filesize) {
|
||||
unzLocateFile(zipfile, cname, 1);
|
||||
unzOpenCurrentFile(zipfile);
|
||||
zipready = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ZipReader::~ZipReader() {
|
||||
if(zipfile) {
|
||||
|
@@ -7,12 +7,14 @@ class ZipReader : public Reader {
|
||||
public:
|
||||
unsigned size();
|
||||
uint8_t* read(unsigned length = 0);
|
||||
bool ready();
|
||||
|
||||
ZipReader(const char *fn);
|
||||
~ZipReader();
|
||||
|
||||
private:
|
||||
unzFile zipfile;
|
||||
uint32 filesize;
|
||||
char cname[4096];
|
||||
~ZipReader();
|
||||
|
||||
private:
|
||||
unzFile zipfile;
|
||||
uint32 filesize;
|
||||
bool zipready;
|
||||
char cname[4096];
|
||||
};
|
||||
|
@@ -4,8 +4,10 @@
|
||||
|
||||
void SNES::Audio::update(uint16 l_sample, uint16 r_sample) {
|
||||
if(pcmfp) {
|
||||
fput(pcmfp, l_sample, 2);
|
||||
fput(pcmfp, r_sample, 2);
|
||||
fputc(l_sample >> 0, pcmfp);
|
||||
fputc(l_sample >> 8, pcmfp);
|
||||
fputc(r_sample >> 0, pcmfp);
|
||||
fputc(r_sample >> 8, pcmfp);
|
||||
}
|
||||
|
||||
snesinterface.audio_sample(l_sample, r_sample);
|
||||
|
@@ -109,7 +109,7 @@ struct Audio {
|
||||
static integral_setting synchronize;
|
||||
} audio;
|
||||
integral_setting Audio::output_frequency(config(), "audio.output_frequency", "Sound card audio output frequency", integral_setting::decimal, 48000);
|
||||
integral_setting Audio::input_frequency(config(), "audio.input_frequency", "Emulator audio input frequency", integral_setting::decimal, 31960);
|
||||
integral_setting Audio::input_frequency(config(), "audio.input_frequency", "Emulator audio input frequency", integral_setting::decimal, 32000);
|
||||
integral_setting Audio::latency(config(), "audio.latency", "Sound card latency (in ms)", integral_setting::decimal, 100);
|
||||
integral_setting Audio::volume(config(), "audio.volume", "Audio volume (10 - 100)", integral_setting::decimal, 100);
|
||||
integral_setting Audio::mute(config(), "audio.mute", "Mute audio playback", integral_setting::boolean, false);
|
||||
|
@@ -302,6 +302,7 @@ bool load_rom(char *fn) {
|
||||
);
|
||||
}
|
||||
|
||||
//File -> Load ROM action
|
||||
void load_rom() {
|
||||
char fn[PATH_MAX];
|
||||
if(load_rom(fn) == false) return;
|
||||
@@ -311,8 +312,9 @@ void load_rom() {
|
||||
void load_cart_normal(const char *filename) {
|
||||
if(!filename || !*filename) return;
|
||||
|
||||
if(cartridge.loaded() == true) cartridge.unload();
|
||||
unload_rom();
|
||||
cartridge.load_cart_normal(filename);
|
||||
if(cartridge.loaded() == false) return;
|
||||
|
||||
app.pause = false;
|
||||
snes.power();
|
||||
@@ -338,8 +340,9 @@ void load_cart_normal(const char *filename) {
|
||||
void load_cart_bsx(const char *base, const char *slot) {
|
||||
if(!base || !*base) return;
|
||||
|
||||
if(cartridge.loaded() == true) cartridge.unload();
|
||||
unload_rom();
|
||||
cartridge.load_cart_bsx(base, slot);
|
||||
if(cartridge.loaded() == false) return;
|
||||
|
||||
app.pause = false;
|
||||
snes.power();
|
||||
@@ -357,8 +360,9 @@ void load_cart_bsx(const char *base, const char *slot) {
|
||||
void load_cart_bsc(const char *base, const char *slot) {
|
||||
if(!base || !*base) return;
|
||||
|
||||
if(cartridge.loaded() == true) cartridge.unload();
|
||||
unload_rom();
|
||||
cartridge.load_cart_bsc(base, slot);
|
||||
if(cartridge.loaded() == false) return;
|
||||
|
||||
app.pause = false;
|
||||
snes.power();
|
||||
@@ -376,8 +380,9 @@ void load_cart_bsc(const char *base, const char *slot) {
|
||||
void load_cart_st(const char *base, const char *slotA, const char *slotB) {
|
||||
if(!base || !*base) return;
|
||||
|
||||
if(cartridge.loaded() == true) cartridge.unload();
|
||||
unload_rom();
|
||||
cartridge.load_cart_st(base, slotA, slotB);
|
||||
if(cartridge.loaded() == false) return;
|
||||
|
||||
app.pause = false;
|
||||
snes.power();
|
||||
@@ -393,11 +398,12 @@ void load_cart_st(const char *base, const char *slotA, const char *slotB) {
|
||||
}
|
||||
|
||||
void unload_rom() {
|
||||
if(cartridge.loaded() == true) {
|
||||
cartridge.unload();
|
||||
video.clear();
|
||||
audio.clear();
|
||||
}
|
||||
if(cartridge.loaded() == false) return;
|
||||
|
||||
cartridge.unload();
|
||||
video.clear();
|
||||
audio.clear();
|
||||
|
||||
window_main.menu_file_unload.disable();
|
||||
window_main.menu_file_reset.disable();
|
||||
window_main.menu_file_power.disable();
|
||||
|
@@ -1,47 +1,47 @@
|
||||
namespace event {
|
||||
|
||||
void keydown(uint16_t);
|
||||
void keyup(uint16_t);
|
||||
|
||||
struct VideoSettings {
|
||||
uint mode;
|
||||
bool synchronize;
|
||||
bool aspect_correction;
|
||||
uint region;
|
||||
uint multiplier;
|
||||
uint hardware_filter;
|
||||
uint software_filter;
|
||||
} video_settings;
|
||||
void load_video_settings();
|
||||
|
||||
void update_aspect_correction(bool);
|
||||
void update_multiplier(uint);
|
||||
void update_region(uint);
|
||||
void update_hardware_filter(uint);
|
||||
void update_software_filter(uint);
|
||||
|
||||
void update_frameskip(int);
|
||||
void update_emulation_speed(int);
|
||||
|
||||
void update_controller_port1(int);
|
||||
void update_controller_port2(int);
|
||||
|
||||
void keyup(uint16_t);
|
||||
|
||||
struct VideoSettings {
|
||||
uint mode;
|
||||
bool synchronize;
|
||||
bool aspect_correction;
|
||||
uint region;
|
||||
uint multiplier;
|
||||
uint hardware_filter;
|
||||
uint software_filter;
|
||||
} video_settings;
|
||||
void load_video_settings();
|
||||
|
||||
void update_aspect_correction(bool);
|
||||
void update_multiplier(uint);
|
||||
void update_region(uint);
|
||||
void update_hardware_filter(uint);
|
||||
void update_software_filter(uint);
|
||||
|
||||
void update_frameskip(int);
|
||||
void update_emulation_speed(int);
|
||||
|
||||
void update_controller_port1(int);
|
||||
void update_controller_port2(int);
|
||||
|
||||
void update_video_settings();
|
||||
void update_opacity();
|
||||
void toggle_fullscreen();
|
||||
void toggle_fullscreen();
|
||||
void toggle_menubar();
|
||||
void toggle_statusbar();
|
||||
|
||||
bool load_rom(char*);
|
||||
void load_rom();
|
||||
void load_cart_normal(const char*);
|
||||
void load_cart_bsx(const char*, const char*);
|
||||
void load_cart_bsc(const char*, const char*);
|
||||
void load_cart_st(const char*, const char*, const char*);
|
||||
void unload_rom();
|
||||
void reset();
|
||||
void toggle_statusbar();
|
||||
|
||||
bool load_rom(char*);
|
||||
void load_rom();
|
||||
void load_cart_normal(const char*);
|
||||
void load_cart_bsx(const char*, const char*);
|
||||
void load_cart_bsc(const char*, const char*);
|
||||
void load_cart_st(const char*, const char*, const char*);
|
||||
void unload_rom();
|
||||
void reset();
|
||||
void power();
|
||||
|
||||
void quit();
|
||||
|
||||
void quit();
|
||||
|
||||
} //namespace event
|
||||
|
@@ -55,6 +55,7 @@ void dprintf(const char *s, ...) {
|
||||
va_start(args, s);
|
||||
vsprintf(str, s, args);
|
||||
va_end(args);
|
||||
|
||||
fprintf(stdout, "%s\r\n", str);
|
||||
}
|
||||
|
||||
@@ -89,7 +90,7 @@ void set_config_filenames() {
|
||||
//locate bsnes.cfg
|
||||
strcpy(filename, config::path.base);
|
||||
strcat(filename, "bsnes.cfg");
|
||||
if(!fexists(filename)) {
|
||||
if(!file::exists(filename)) {
|
||||
strcpy(filename, config::path.user);
|
||||
strcat(filename, ".bsnes");
|
||||
mkdir(filename);
|
||||
@@ -100,7 +101,7 @@ void set_config_filenames() {
|
||||
//locate locale.cfg
|
||||
strcpy(filename, config::path.base);
|
||||
strcat(filename, "locale.cfg");
|
||||
if(!fexists(filename)) {
|
||||
if(!file::exists(filename)) {
|
||||
strcpy(filename, config::path.user);
|
||||
strcat(filename, ".bsnes");
|
||||
mkdir(filename);
|
||||
@@ -136,18 +137,26 @@ void run() {
|
||||
|
||||
#if defined(PLATFORM_WIN)
|
||||
int __stdcall WinMain(HINSTANCE, HINSTANCE, LPSTR, int) {
|
||||
int argc = __argc;
|
||||
char **argv = __argv;
|
||||
//On Windows, argv[] is in 7-bit ANSI format, UTF-8 chars are converted to '?'s.
|
||||
//Need argv[] to be in UTF-8 format to properly determine realpath() and default image filepaths.
|
||||
//To do this, parse command line in UTF-16, and then convert to UTF-8.
|
||||
int argc;
|
||||
wchar_t **wargv = CommandLineToArgvW(GetCommandLineW(), &argc);
|
||||
char **argv = new char*[argc];
|
||||
for(unsigned i = 0; i < argc; i++) {
|
||||
argv[i] = new(zeromemory) char[PATH_MAX];
|
||||
strcpy(argv[i], utf8(wargv[i]));
|
||||
}
|
||||
#else
|
||||
int main(int argc, char *argv[]) {
|
||||
#endif
|
||||
/*
|
||||
#endif /*
|
||||
|
||||
int main(int argc, char *argv[]) { */
|
||||
get_paths(argv[0]);
|
||||
set_config_filenames();
|
||||
|
||||
config::config().load(config::bsnes_cfg);
|
||||
if(fexists(config::bsnes_cfg) == false) {
|
||||
if(file::exists(config::bsnes_cfg) == false) {
|
||||
//in case program crashes on first run, save config file
|
||||
//settings, so that they can be modified by hand ...
|
||||
config::config().save(config::bsnes_cfg);
|
||||
@@ -159,12 +168,14 @@ int main(int argc, char *argv[]) { */
|
||||
if(app.term == true) goto app_term;
|
||||
snes.init();
|
||||
|
||||
if(argc >= 2 && fexists(argv[1])) {
|
||||
if(argc >= 2 && file::exists(argv[1])) {
|
||||
cartridge.load_cart_normal(argv[1]);
|
||||
snes.power();
|
||||
window_main.menu_file_unload.enable();
|
||||
window_main.menu_file_reset.enable();
|
||||
window_main.menu_file_power.enable();
|
||||
if(cartridge.loaded()) {
|
||||
snes.power();
|
||||
window_main.menu_file_unload.enable();
|
||||
window_main.menu_file_reset.enable();
|
||||
window_main.menu_file_power.enable();
|
||||
}
|
||||
}
|
||||
|
||||
while(app.term == false) run();
|
||||
|
Reference in New Issue
Block a user