diff --git a/bsx.cpp b/bsx.cpp
index d55b346c..88f27dc3 100644
--- a/bsx.cpp
+++ b/bsx.cpp
@@ -1023,11 +1023,19 @@ static bool8 BSX_LoadBIOS (void)
return (r);
}
+static bool8 is_BSX_BIOS (const uint8 *data, uint32 size)
+{
+ if (size == BIOS_SIZE && strncmp((char *) (data + 0x7FC0), "Satellaview BS-X ", 21) == 0)
+ return (TRUE);
+ else
+ return (FALSE);
+}
+
void S9xInitBSX (void)
{
Settings.BS = FALSE;
- if (!memcmp(&Memory.ROM[0x7FC0], "Satellaview BS-X ", 21))
+ if (is_BSX_BIOS(Memory.ROM,Memory.CalculatedSize))
{
// BS-X itself
@@ -1074,7 +1082,7 @@ void S9xInitBSX (void)
BSX.bootup = Settings.BSXBootup;
- if (!BSX_LoadBIOS())
+ if (!BSX_LoadBIOS() && !is_BSX_BIOS(BIOSROM,BIOS_SIZE))
{
BSX.bootup = FALSE;
memset(BIOSROM, 0, BIOS_SIZE);
diff --git a/conffile.cpp b/conffile.cpp
index dde03227..b6afe379 100644
--- a/conffile.cpp
+++ b/conffile.cpp
@@ -209,16 +209,16 @@ void ConfigFile::Clear(void){
}
bool ConfigFile::LoadFile(const char *filename){
- STREAM s;
+ FSTREAM s;
bool ret=false;
const char *n, *n2;
- if((s=OPEN_STREAM(filename, "r"))){
+ if((s=OPEN_FSTREAM(filename, "r"))){
n=filename;
n2=strrchr(n, '/'); if(n2!=NULL) n=n2+1;
n2=strrchr(n, '\\'); if(n2!=NULL) n=n2+1;
- LoadFile(new fReader(s), n);
- CLOSE_STREAM(s);
+ LoadFile(new fStream(s), n);
+ CLOSE_FSTREAM(s);
ret = true;
} else {
fprintf(stderr, "Couldn't open conffile ");
@@ -228,7 +228,7 @@ bool ConfigFile::LoadFile(const char *filename){
}
-void ConfigFile::LoadFile(Reader *r, const char *name){
+void ConfigFile::LoadFile(Stream *r, const char *name){
curConfigFile = this;
string l, key, val;
string section;
diff --git a/conffile.h b/conffile.h
index 24c8c20e..54339fd0 100644
--- a/conffile.h
+++ b/conffile.h
@@ -188,7 +188,6 @@
#include "unzip/unzip.h"
#endif
#include "snes9x.h"
-#include "reader.h"
#ifndef MAX
# define MAX(a,b) ((a) > (b)? (a) : (b))
@@ -203,7 +202,7 @@ class ConfigFile {
// return false on failure
bool LoadFile(const char *filename);
- void LoadFile(Reader *r, const char *name=NULL);
+ void LoadFile(Stream *r, const char *name=NULL);
// return false if key does not exist or is empty
bool Exists(const char *key);
diff --git a/gtk/Makefile.am b/gtk/Makefile.am
index 9f380914..277ad11e 100644
--- a/gtk/Makefile.am
+++ b/gtk/Makefile.am
@@ -159,7 +159,7 @@ snes9x_gtk_SOURCES += \
../dma.cpp \
../snes9x.cpp \
../globals.cpp \
- ../reader.cpp \
+ ../stream.cpp \
../conffile.cpp \
../bsx.cpp \
../logger.cpp \
diff --git a/libsnes/Makefile b/libsnes/Makefile
new file mode 100644
index 00000000..2038181d
--- /dev/null
+++ b/libsnes/Makefile
@@ -0,0 +1,53 @@
+ifeq ($(platform),)
+platform = unix
+ifeq ($(shell uname -a),)
+ platform = win
+else ifneq ($(findstring Darwin,$(shell uname -a)),)
+ platform = osx
+else ifneq ($(findstring MINGW,$(shell uname -a)),)
+ platform = win
+else ifneq ($(findstring win,$(shell uname -a)),)
+ platform = win
+endif
+endif
+
+ifeq ($(platform), unix)
+ TARGET := libsnes.so
+ fpic := -fPIC
+ SHARED := -shared -Wl,--version-script=link.T
+else ifeq ($(platform), osx)
+ TARGET := libsnes.dylib
+ fpic := -fPIC
+ SHARED := -dynamiclib
+else
+ TARGET := snes.dll
+ CC = gcc
+ CXX = g++
+ SHARED := -shared -static-libgcc -static-libstdc++ -s -Wl,--version-script=link.T
+ CXXFLAGS += -D__WIN32__ -D__WIN32_LIBSNES__
+endif
+
+OBJECTS = ../apu/apu.o ../apu/SNES_SPC.o ../apu/SNES_SPC_misc.o ../apu/SNES_SPC_state.o ../apu/SPC_DSP.o ../apu/SPC_Filter.o ../bsx.o ../c4.o ../c4emu.o ../cheats.o ../cheats2.o ../clip.o ../conffile.o ../controls.o ../cpu.o ../cpuexec.o ../cpuops.o ../crosshairs.o ../dma.o ../dsp.o ../dsp1.o ../dsp2.o ../dsp3.o ../dsp4.o ../fxinst.o ../fxemu.o ../gfx.o ../globals.o ../logger.o ../memmap.o ../movie.o ../obc1.o ../ppu.o ../stream.o ../sa1.o ../sa1cpu.o ../screenshot.o ../sdd1.o ../sdd1emu.o ../seta.o ../seta010.o ../seta011.o ../seta018.o ../snapshot.o ../snes9x.o ../spc7110.o ../srtc.o ../tile.o libsnes.o
+
+CXX = g++
+CC = gcc
+INCLUDES = -I. -I.. -I../apu/
+
+CXXFLAGS += -O3 -fomit-frame-pointer -fno-exceptions -fno-rtti -pedantic -Wall -W -Wno-unused-parameter $(fpic)
+CXXFLAGS += -DHAVE_STRINGS_H -DHAVE_STDINT_H -DRIGHTSHIFT_IS_SAR
+CFLAGS = $(CXXFLAGS)
+
+all: $(TARGET)
+
+$(TARGET): $(OBJECTS)
+ $(CXX) $(fpic) $(SHARED) $(INCLUDES) -o $@ $(OBJECTS) -lm
+
+%.o: %.cpp
+ $(CXX) $(INCLUDES) $(CXXFLAGS) -c -o $@ $<
+
+%.o: %.c
+ $(CC) $(INCLUDES) $(CFLAGS) -c -o $@ $<
+
+clean:
+ rm -f $(OBJECTS) $(TARGET)
+
diff --git a/libsnes/libsnes-win32.vcproj b/libsnes/libsnes-win32.vcproj
new file mode 100644
index 00000000..ee4f1dff
--- /dev/null
+++ b/libsnes/libsnes-win32.vcproj
@@ -0,0 +1,786 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/libsnes/libsnes.cpp b/libsnes/libsnes.cpp
new file mode 100644
index 00000000..3cf5b2ce
--- /dev/null
+++ b/libsnes/libsnes.cpp
@@ -0,0 +1,790 @@
+#include "libsnes.hpp"
+
+#include "snes9x.h"
+#include "memmap.h"
+#include "srtc.h"
+#include "apu/apu.h"
+#include "apu/bapu/snes/snes.hpp"
+#include "gfx.h"
+#include "snapshot.h"
+#include "controls.h"
+#include "cheats.h"
+#include "movie.h"
+#include "logger.h"
+#include "display.h"
+#include "conffile.h"
+#include
+#ifndef __WIN32__
+#include
+#endif
+#include
+#include
+#include
+
+
+static snes_video_refresh_t s9x_video_cb = NULL;
+static snes_audio_sample_t s9x_audio_cb = NULL;
+static snes_input_poll_t s9x_poller_cb = NULL;
+static snes_input_state_t s9x_input_state_cb = NULL;
+
+void snes_set_video_refresh(snes_video_refresh_t cb)
+{
+ s9x_video_cb = cb;
+}
+
+void snes_set_audio_sample(snes_audio_sample_t cb)
+{
+ s9x_audio_cb = cb;
+}
+
+void snes_set_input_poll(snes_input_poll_t cb)
+{
+ s9x_poller_cb = cb;
+}
+
+void snes_set_input_state(snes_input_state_t cb)
+{
+ s9x_input_state_cb = cb;
+}
+
+static snes_environment_t environ_cb;
+static bool use_overscan;
+void snes_set_environment(snes_environment_t cb)
+{
+ environ_cb = cb;
+}
+
+static void set_environ_timing()
+{
+ if (environ_cb)
+ {
+ snes_system_timing timing;
+ timing.sample_rate = 32040.5;
+ if (!Settings.PAL)
+ timing.fps = 21477272.0 / 357366.0;
+ else
+ timing.fps = 21281370.0 / 425568.0;
+
+ environ_cb(SNES_ENVIRONMENT_SET_TIMING, &timing);
+ }
+}
+
+static void S9xAudioCallback(void*)
+{
+ // Just pick a big buffer. We won't use it all.
+ static int16_t audio_buf[0x10000];
+
+ S9xFinalizeSamples();
+ size_t avail = S9xGetSampleCount();
+ S9xMixSamples((uint8*)audio_buf, avail);
+ for (size_t i = 0; i < avail; i+=2)
+ s9x_audio_cb((uint16_t)audio_buf[i], (uint16_t)audio_buf[i + 1]);
+}
+
+const char *snes_library_id()
+{
+ return "SNES9x v" VERSION;
+}
+
+unsigned snes_library_revision_major()
+{
+ return 1;
+}
+
+unsigned snes_library_revision_minor()
+{
+ return 3;
+}
+
+void snes_power()
+{
+ S9xReset();
+}
+
+void snes_reset()
+{
+ S9xMovieUpdateOnReset();
+ if (S9xMoviePlaying())
+ {
+ S9xMovieStop(true);
+ }
+ S9xSoftReset();
+}
+
+static unsigned snes_devices[2];
+void snes_set_controller_port_device(bool in_port, unsigned device)
+{
+ int port = in_port == SNES_PORT_1 ? 0 : 1;
+ switch (device)
+ {
+ case SNES_DEVICE_JOYPAD:
+ S9xSetController(port, CTL_JOYPAD, 0, 0, 0, 0);
+ snes_devices[port] = SNES_DEVICE_JOYPAD;
+ break;
+ case SNES_DEVICE_MULTITAP:
+ S9xSetController(port, CTL_MP5, 1, 2, 3, 4);
+ snes_devices[port] = SNES_DEVICE_MULTITAP;
+ break;
+ case SNES_DEVICE_MOUSE:
+ S9xSetController(port, CTL_MOUSE, 0, 0, 0, 0);
+ snes_devices[port] = SNES_DEVICE_MOUSE;
+ break;
+ case SNES_DEVICE_SUPER_SCOPE:
+ S9xSetController(port, CTL_SUPERSCOPE, 0, 0, 0, 0);
+ snes_devices[port] = SNES_DEVICE_SUPER_SCOPE;
+ break;
+ case SNES_DEVICE_JUSTIFIER:
+ S9xSetController(port, CTL_JUSTIFIER, 0, 0, 0, 0);
+ snes_devices[port] = SNES_DEVICE_JUSTIFIER;
+ break;
+ case SNES_DEVICE_JUSTIFIERS:
+ S9xSetController(port, CTL_JUSTIFIER, 1, 0, 0, 0);
+ snes_devices[port] = SNES_DEVICE_JUSTIFIERS;
+ break;
+ default:
+ fprintf(stderr, "[libsnes]: Invalid device!\n");
+ }
+}
+
+void snes_cheat_reset()
+{}
+
+void snes_cheat_set(unsigned, bool, const char*)
+{}
+
+bool snes_load_cartridge_bsx_slotted(
+ const char *, const uint8_t *rom_data, unsigned rom_size,
+ const char *, const uint8_t *bsx_data, unsigned bsx_size
+ )
+{
+ int loaded = Memory.LoadMultiCartMem(rom_data, rom_size, bsx_data, bsx_size, NULL, NULL);
+
+ if (!loaded)
+ {
+ fprintf(stderr, "[libsnes]: Sufami Turbo Rom loading failed...\n");
+ return false;
+ }
+
+ set_environ_timing();
+
+ return false;
+}
+
+bool snes_load_cartridge_bsx(
+ const char *rom_xml, const uint8_t *rom_data, unsigned rom_size,
+ const char *bsx_xml, const uint8_t *bsx_data, unsigned bsx_size
+ )
+{
+ if(bsx_data==NULL)
+ return snes_load_cartridge_normal(rom_xml,rom_data,rom_size);
+ memcpy(Memory.BIOSROM,rom_data,rom_size);
+ return snes_load_cartridge_normal(bsx_xml,bsx_data,bsx_size);
+}
+
+bool snes_load_cartridge_sufami_turbo(
+ const char *, const uint8_t *rom_data, unsigned rom_size,
+ const char *, const uint8_t *sta_data, unsigned sta_size,
+ const char *, const uint8_t *stb_data, unsigned stb_size
+ )
+{
+ int loaded = Memory.LoadMultiCartMem(sta_data, sta_size, stb_data, stb_size, rom_data, rom_size);
+
+ if (!loaded)
+ {
+ fprintf(stderr, "[libsnes]: Sufami Turbo Rom loading failed...\n");
+ return false;
+ }
+
+ set_environ_timing();
+
+ return true;
+}
+
+bool snes_load_cartridge_super_game_boy(
+ const char *, const uint8_t *, unsigned,
+ const char *, const uint8_t *, unsigned
+ )
+{
+ return false;
+}
+
+static void map_buttons();
+
+
+void snes_init()
+{
+ if (environ_cb)
+ {
+ if (!environ_cb(SNES_ENVIRONMENT_GET_OVERSCAN, &use_overscan))
+ use_overscan = false;
+
+ if (use_overscan)
+ {
+ snes_geometry geom = {256, 239, 512, 512};
+ environ_cb(SNES_ENVIRONMENT_SET_GEOMETRY, &geom);
+ unsigned pitch = 1024;
+ environ_cb(SNES_ENVIRONMENT_SET_PITCH, &pitch);
+ }
+ }
+
+ memset(&Settings, 0, sizeof(Settings));
+ Settings.MouseMaster = TRUE;
+ Settings.SuperScopeMaster = TRUE;
+ Settings.JustifierMaster = TRUE;
+ Settings.MultiPlayer5Master = TRUE;
+ Settings.FrameTimePAL = 20000;
+ Settings.FrameTimeNTSC = 16667;
+ Settings.SixteenBitSound = TRUE;
+ Settings.Stereo = TRUE;
+ Settings.SoundPlaybackRate = 32000;
+ Settings.SoundInputRate = 32000;
+ Settings.SupportHiRes = TRUE;
+ Settings.Transparency = TRUE;
+ Settings.AutoDisplayMessages = TRUE;
+ Settings.InitialInfoStringTimeout = 120;
+ Settings.HDMATimingHack = 100;
+ Settings.BlockInvalidVRAMAccessMaster = TRUE;
+ Settings.StopEmulation = TRUE;
+ Settings.WrongMovieStateProtection = TRUE;
+ Settings.DumpStreamsMaxFrames = -1;
+ Settings.StretchScreenshots = 0;
+ Settings.SnapshotScreenshots = FALSE;
+ Settings.SkipFrames = AUTO_FRAMERATE;
+ Settings.TurboSkipFrames = 15;
+ Settings.CartAName[0] = 0;
+ Settings.CartBName[0] = 0;
+ Settings.AutoSaveDelay = 1;
+
+ CPU.Flags = 0;
+
+ if (!Memory.Init() || !S9xInitAPU())
+ {
+ Memory.Deinit();
+ S9xDeinitAPU();
+ fprintf(stderr, "[libsnes]: Failed to init Memory or APU.\n");
+ exit(1);
+ }
+
+ S9xInitSound(16, 0);
+ S9xSetSoundMute(FALSE);
+ S9xSetSamplesAvailableCallback(S9xAudioCallback, NULL);
+
+ S9xSetRenderPixelFormat(RGB555);
+ GFX.Pitch = use_overscan ? 1024 : 2048;
+ GFX.Screen = (uint16*) calloc(1, GFX.Pitch * 512 * sizeof(uint16));
+ S9xGraphicsInit();
+
+ S9xInitInputDevices();
+ for (int i = 0; i < 2; i++)
+ {
+ S9xSetController(i, CTL_JOYPAD, i, 0, 0, 0);
+ snes_devices[i] = SNES_DEVICE_JOYPAD;
+ }
+
+ S9xUnmapAllControls();
+ map_buttons();
+
+}
+
+#define MAP_BUTTON(id, name) S9xMapButton((id), S9xGetCommandT((name)), false)
+#define MAKE_BUTTON(pad, btn) (((pad)<<4)|(btn))
+
+#define PAD_1 1
+#define PAD_2 2
+#define PAD_3 3
+#define PAD_4 4
+#define PAD_5 5
+
+#define BTN_B SNES_DEVICE_ID_JOYPAD_B
+#define BTN_Y SNES_DEVICE_ID_JOYPAD_Y
+#define BTN_SELECT SNES_DEVICE_ID_JOYPAD_SELECT
+#define BTN_START SNES_DEVICE_ID_JOYPAD_START
+#define BTN_UP SNES_DEVICE_ID_JOYPAD_UP
+#define BTN_DOWN SNES_DEVICE_ID_JOYPAD_DOWN
+#define BTN_LEFT SNES_DEVICE_ID_JOYPAD_LEFT
+#define BTN_RIGHT SNES_DEVICE_ID_JOYPAD_RIGHT
+#define BTN_A SNES_DEVICE_ID_JOYPAD_A
+#define BTN_X SNES_DEVICE_ID_JOYPAD_X
+#define BTN_L SNES_DEVICE_ID_JOYPAD_L
+#define BTN_R SNES_DEVICE_ID_JOYPAD_R
+#define BTN_FIRST BTN_B
+#define BTN_LAST BTN_R
+
+#define MOUSE_X SNES_DEVICE_ID_MOUSE_X
+#define MOUSE_Y SNES_DEVICE_ID_MOUSE_Y
+#define MOUSE_LEFT SNES_DEVICE_ID_MOUSE_LEFT
+#define MOUSE_RIGHT SNES_DEVICE_ID_MOUSE_RIGHT
+#define MOUSE_FIRST MOUSE_X
+#define MOUSE_LAST MOUSE_RIGHT
+
+#define SCOPE_X SNES_DEVICE_ID_SUPER_SCOPE_X
+#define SCOPE_Y SNES_DEVICE_ID_SUPER_SCOPE_Y
+#define SCOPE_TRIGGER SNES_DEVICE_ID_SUPER_SCOPE_TRIGGER
+#define SCOPE_CURSOR SNES_DEVICE_ID_SUPER_SCOPE_CURSOR
+#define SCOPE_TURBO SNES_DEVICE_ID_SUPER_SCOPE_TURBO
+#define SCOPE_PAUSE SNES_DEVICE_ID_SUPER_SCOPE_PAUSE
+#define SCOPE_FIRST SCOPE_X
+#define SCOPE_LAST SCOPE_PAUSE
+
+#define JUSTIFIER_X SNES_DEVICE_ID_JUSTIFIER_X
+#define JUSTIFIER_Y SNES_DEVICE_ID_JUSTIFIER_Y
+#define JUSTIFIER_TRIGGER SNES_DEVICE_ID_JUSTIFIER_TRIGGER
+#define JUSTIFIER_START SNES_DEVICE_ID_JUSTIFIER_START
+#define JUSTIFIER_FIRST JUSTIFIER_X
+#define JUSTIFIER_LAST JUSTIFIER_START
+
+#define BTN_POINTER (BTN_LAST + 1)
+#define BTN_POINTER2 (BTN_POINTER + 1)
+
+static void map_buttons()
+{
+ MAP_BUTTON(MAKE_BUTTON(PAD_1, BTN_A), "Joypad1 A");
+ MAP_BUTTON(MAKE_BUTTON(PAD_1, BTN_B), "Joypad1 B");
+ MAP_BUTTON(MAKE_BUTTON(PAD_1, BTN_X), "Joypad1 X");
+ MAP_BUTTON(MAKE_BUTTON(PAD_1, BTN_Y), "Joypad1 Y");
+ MAP_BUTTON(MAKE_BUTTON(PAD_1, BTN_SELECT), "{Joypad1 Select,Mouse1 L}");
+ MAP_BUTTON(MAKE_BUTTON(PAD_1, BTN_START), "{Joypad1 Start,Mouse1 R}");
+ MAP_BUTTON(MAKE_BUTTON(PAD_1, BTN_L), "Joypad1 L");
+ MAP_BUTTON(MAKE_BUTTON(PAD_1, BTN_R), "Joypad1 R");
+ MAP_BUTTON(MAKE_BUTTON(PAD_1, BTN_LEFT), "Joypad1 Left");
+ MAP_BUTTON(MAKE_BUTTON(PAD_1, BTN_RIGHT), "Joypad1 Right");
+ MAP_BUTTON(MAKE_BUTTON(PAD_1, BTN_UP), "Joypad1 Up");
+ MAP_BUTTON(MAKE_BUTTON(PAD_1, BTN_DOWN), "Joypad1 Down");
+ S9xMapPointer((BTN_POINTER), S9xGetCommandT("Pointer Mouse1+Superscope+Justifier1"), false);
+ S9xMapPointer((BTN_POINTER2), S9xGetCommandT("Pointer Mouse2"), false);
+
+ MAP_BUTTON(MAKE_BUTTON(PAD_2, BTN_A), "Joypad2 A");
+ MAP_BUTTON(MAKE_BUTTON(PAD_2, BTN_B), "Joypad2 B");
+ MAP_BUTTON(MAKE_BUTTON(PAD_2, BTN_X), "Joypad2 X");
+ MAP_BUTTON(MAKE_BUTTON(PAD_2, BTN_Y), "Joypad2 Y");
+ MAP_BUTTON(MAKE_BUTTON(PAD_2, BTN_SELECT), "{Joypad2 Select,Mouse2 L,Superscope Fire,Justifier1 Trigger}");
+ MAP_BUTTON(MAKE_BUTTON(PAD_2, BTN_START), "{Joypad2 Start,Mouse2 R,Superscope Cursor,Justifier1 Start}");
+ MAP_BUTTON(MAKE_BUTTON(PAD_2, BTN_L), "Joypad2 L");
+ MAP_BUTTON(MAKE_BUTTON(PAD_2, BTN_R), "Joypad2 R");
+ MAP_BUTTON(MAKE_BUTTON(PAD_2, BTN_LEFT), "Joypad2 Left");
+ MAP_BUTTON(MAKE_BUTTON(PAD_2, BTN_RIGHT), "Joypad2 Right");
+ MAP_BUTTON(MAKE_BUTTON(PAD_2, BTN_UP), "{Joypad2 Up,Superscope ToggleTurbo}");
+ MAP_BUTTON(MAKE_BUTTON(PAD_2, BTN_DOWN), "{Joypad2 Down,Superscope Pause}");
+
+ MAP_BUTTON(MAKE_BUTTON(PAD_3, BTN_A), "Joypad3 A");
+ MAP_BUTTON(MAKE_BUTTON(PAD_3, BTN_B), "Joypad3 B");
+ MAP_BUTTON(MAKE_BUTTON(PAD_3, BTN_X), "Joypad3 X");
+ MAP_BUTTON(MAKE_BUTTON(PAD_3, BTN_Y), "Joypad3 Y");
+ MAP_BUTTON(MAKE_BUTTON(PAD_3, BTN_SELECT), "Joypad3 Select");
+ MAP_BUTTON(MAKE_BUTTON(PAD_3, BTN_START), "Joypad3 Start");
+ MAP_BUTTON(MAKE_BUTTON(PAD_3, BTN_L), "Joypad3 L");
+ MAP_BUTTON(MAKE_BUTTON(PAD_3, BTN_R), "Joypad3 R");
+ MAP_BUTTON(MAKE_BUTTON(PAD_3, BTN_LEFT), "Joypad3 Left");
+ MAP_BUTTON(MAKE_BUTTON(PAD_3, BTN_RIGHT), "Joypad3 Right");
+ MAP_BUTTON(MAKE_BUTTON(PAD_3, BTN_UP), "Joypad3 Up");
+ MAP_BUTTON(MAKE_BUTTON(PAD_3, BTN_DOWN), "Joypad3 Down");
+
+ MAP_BUTTON(MAKE_BUTTON(PAD_4, BTN_A), "Joypad4 A");
+ MAP_BUTTON(MAKE_BUTTON(PAD_4, BTN_B), "Joypad4 B");
+ MAP_BUTTON(MAKE_BUTTON(PAD_4, BTN_X), "Joypad4 X");
+ MAP_BUTTON(MAKE_BUTTON(PAD_4, BTN_Y), "Joypad4 Y");
+ MAP_BUTTON(MAKE_BUTTON(PAD_4, BTN_SELECT), "Joypad4 Select");
+ MAP_BUTTON(MAKE_BUTTON(PAD_4, BTN_START), "Joypad4 Start");
+ MAP_BUTTON(MAKE_BUTTON(PAD_4, BTN_L), "Joypad4 L");
+ MAP_BUTTON(MAKE_BUTTON(PAD_4, BTN_R), "Joypad4 R");
+ MAP_BUTTON(MAKE_BUTTON(PAD_4, BTN_LEFT), "Joypad4 Left");
+ MAP_BUTTON(MAKE_BUTTON(PAD_4, BTN_RIGHT), "Joypad4 Right");
+ MAP_BUTTON(MAKE_BUTTON(PAD_4, BTN_UP), "Joypad4 Up");
+ MAP_BUTTON(MAKE_BUTTON(PAD_4, BTN_DOWN), "Joypad4 Down");
+
+ MAP_BUTTON(MAKE_BUTTON(PAD_5, BTN_A), "Joypad5 A");
+ MAP_BUTTON(MAKE_BUTTON(PAD_5, BTN_B), "Joypad5 B");
+ MAP_BUTTON(MAKE_BUTTON(PAD_5, BTN_X), "Joypad5 X");
+ MAP_BUTTON(MAKE_BUTTON(PAD_5, BTN_Y), "Joypad5 Y");
+ MAP_BUTTON(MAKE_BUTTON(PAD_5, BTN_SELECT), "Joypad5 Select");
+ MAP_BUTTON(MAKE_BUTTON(PAD_5, BTN_START), "Joypad5 Start");
+ MAP_BUTTON(MAKE_BUTTON(PAD_5, BTN_L), "Joypad5 L");
+ MAP_BUTTON(MAKE_BUTTON(PAD_5, BTN_R), "Joypad5 R");
+ MAP_BUTTON(MAKE_BUTTON(PAD_5, BTN_LEFT), "Joypad5 Left");
+ MAP_BUTTON(MAKE_BUTTON(PAD_5, BTN_RIGHT), "Joypad5 Right");
+ MAP_BUTTON(MAKE_BUTTON(PAD_5, BTN_UP), "Joypad5 Up");
+ MAP_BUTTON(MAKE_BUTTON(PAD_5, BTN_DOWN), "Joypad5 Down");
+
+}
+
+// libsnes uses relative values for analogue devices.
+// S9x seems to use absolute values, but do convert these into relative values in the core. (Why?!)
+// Hack around it. :)
+static int16_t snes_mouse_state[2][2] = {{0}, {0}};
+static int16_t snes_scope_state[2] = {0};
+static int16_t snes_justifier_state[2][2] = {{0}, {0}};
+static void report_buttons()
+{
+ int _x, _y;
+ for (int port = SNES_PORT_1; port <= SNES_PORT_2; port++)
+ {
+ switch (snes_devices[port])
+ {
+ case SNES_DEVICE_JOYPAD:
+ for (int i = BTN_FIRST; i <= BTN_LAST; i++)
+ S9xReportButton(MAKE_BUTTON(port + 1, i), s9x_input_state_cb(port == SNES_PORT_2, SNES_DEVICE_JOYPAD, 0, i));
+ break;
+
+ case SNES_DEVICE_MULTITAP:
+ for (int j = 0; j < 4; j++)
+ for (int i = BTN_FIRST; i <= BTN_LAST; i++)
+ S9xReportButton(MAKE_BUTTON(j + 2, i), s9x_input_state_cb(port == SNES_PORT_2, SNES_DEVICE_MULTITAP, j, i));
+ break;
+
+ case SNES_DEVICE_MOUSE:
+ _x = s9x_input_state_cb(port == SNES_PORT_2, SNES_DEVICE_MOUSE, 0, SNES_DEVICE_ID_MOUSE_X);
+ _y = s9x_input_state_cb(port == SNES_PORT_2, SNES_DEVICE_MOUSE, 0, SNES_DEVICE_ID_MOUSE_Y);
+ snes_mouse_state[port][0] += _x;
+ snes_mouse_state[port][1] += _y;
+ S9xReportPointer(BTN_POINTER + port, snes_mouse_state[port][0], snes_mouse_state[port][1]);
+ for (int i = MOUSE_LEFT; i <= MOUSE_LAST; i++)
+ S9xReportButton(MAKE_BUTTON(port + 1, i), s9x_input_state_cb(port == SNES_PORT_2, SNES_DEVICE_MOUSE, 0, i));
+ break;
+
+ case SNES_DEVICE_SUPER_SCOPE:
+ snes_scope_state[0] += s9x_input_state_cb(port == SNES_PORT_2, SNES_DEVICE_SUPER_SCOPE, 0, SNES_DEVICE_ID_SUPER_SCOPE_X);
+ snes_scope_state[1] += s9x_input_state_cb(port == SNES_PORT_2, SNES_DEVICE_SUPER_SCOPE, 0, SNES_DEVICE_ID_SUPER_SCOPE_Y);
+ S9xReportPointer(BTN_POINTER, snes_scope_state[0], snes_scope_state[1]);
+ for (int i = SCOPE_TRIGGER; i <= SCOPE_LAST; i++)
+ S9xReportButton(MAKE_BUTTON(port + 1, i), s9x_input_state_cb(port == SNES_PORT_2, SNES_DEVICE_SUPER_SCOPE, 0, i));
+ break;
+
+ case SNES_DEVICE_JUSTIFIER:
+ case SNES_DEVICE_JUSTIFIERS:
+ snes_justifier_state[0][0] += s9x_input_state_cb(port == SNES_PORT_2, SNES_DEVICE_JUSTIFIER, 0, SNES_DEVICE_ID_JUSTIFIER_X);
+ snes_justifier_state[0][1] += s9x_input_state_cb(port == SNES_PORT_2, SNES_DEVICE_JUSTIFIER, 0, SNES_DEVICE_ID_JUSTIFIER_Y);
+ S9xReportPointer(BTN_POINTER, snes_justifier_state[0][0], snes_justifier_state[0][1]);
+ for (int i = JUSTIFIER_TRIGGER; i <= JUSTIFIER_LAST; i++)
+ S9xReportButton(MAKE_BUTTON(port + 1, i), s9x_input_state_cb(port == SNES_PORT_2, SNES_DEVICE_JUSTIFIER, 0, i));
+ break;
+
+ default:
+ fprintf(stderr, "[libsnes]: Unknown device...\n");
+
+ }
+ }
+}
+
+bool snes_load_cartridge_normal(const char *, const uint8_t *rom_data, unsigned rom_size)
+{
+ int loaded = Memory.LoadROMMem(rom_data,rom_size);
+ if (!loaded)
+ {
+ fprintf(stderr, "[libsnes]: Rom loading failed...\n");
+ return false;
+ }
+
+ set_environ_timing();
+
+ return true;
+}
+
+void snes_run()
+{
+ s9x_poller_cb();
+ report_buttons();
+ S9xMainLoop();
+}
+
+void snes_term()
+{
+ S9xDeinitAPU();
+ Memory.Deinit();
+ S9xGraphicsDeinit();
+ S9xUnmapAllControls();
+}
+
+
+bool snes_get_region()
+{
+ return Settings.PAL ? SNES_REGION_PAL : SNES_REGION_NTSC;
+}
+
+uint8_t* snes_get_memory_data(unsigned type)
+{
+ uint8_t* data;
+
+ switch(type) {
+ case SNES_MEMORY_SUFAMI_TURBO_A_RAM:
+ case SNES_MEMORY_CARTRIDGE_RAM:
+ data = Memory.SRAM;
+ break;
+ case SNES_MEMORY_SUFAMI_TURBO_B_RAM:
+ data = Multi.sramB;
+ break;
+ case SNES_MEMORY_CARTRIDGE_RTC:
+ data = RTCData.reg;
+ break;
+ case SNES_MEMORY_WRAM:
+ data = Memory.RAM;
+ break;
+ case SNES_MEMORY_APURAM:
+ data = SNES::smp.apuram;
+ break;
+ case SNES_MEMORY_VRAM:
+ data = Memory.VRAM;
+ break;
+ case SNES_MEMORY_CGRAM:
+ data = (uint8_t*)PPU.CGDATA;
+ break;
+ case SNES_MEMORY_OAM:
+ data = PPU.OAMData;
+ break;
+ default:
+ data = NULL;
+ break;
+ }
+
+ return data;
+}
+
+void snes_unload_cartridge()
+{
+
+}
+
+unsigned snes_get_memory_size(unsigned type)
+{
+ unsigned size;
+
+ switch(type) {
+ case SNES_MEMORY_SUFAMI_TURBO_A_RAM:
+ case SNES_MEMORY_CARTRIDGE_RAM:
+ size = (unsigned) (Memory.SRAMSize ? (1 << (Memory.SRAMSize + 3)) * 128 : 0);
+ if (size > 0x20000)
+ size = 0x20000;
+ break;
+ case SNES_MEMORY_SUFAMI_TURBO_B_RAM:
+ size = (unsigned) (Multi.cartType && Multi.sramSizeB ? (1 << (Multi.sramSizeB + 3)) * 128 : 0);
+ break;
+ case SNES_MEMORY_CARTRIDGE_RTC:
+ size = (Settings.SRTC || Settings.SPC7110RTC)?20:0;
+ break;
+ case SNES_MEMORY_WRAM:
+ size = 128 * 1024;
+ break;
+ case SNES_MEMORY_VRAM:
+ case SNES_MEMORY_APURAM:
+ size = 64 * 1024;
+ break;
+ case SNES_MEMORY_CGRAM:
+ size = 512;
+ break;
+ case SNES_MEMORY_OAM:
+ size = 512 + 32;
+ break;
+ default:
+ size = 0;
+ break;
+ }
+
+ return size;
+}
+
+void snes_set_cartridge_basename(const char*)
+{}
+
+unsigned snes_serialize_size()
+{
+ return S9xFreezeSize();
+}
+
+bool snes_serialize(uint8_t *data, unsigned size)
+{
+ if (S9xFreezeGameMem(data,size) == FALSE)
+ return false;
+
+ return true;
+}
+
+bool snes_unserialize(const uint8_t* data, unsigned size)
+{
+ if (S9xUnfreezeGameMem(data,size) != SUCCESS)
+ return false;
+ return true;
+}
+
+// Pitch 2048 -> 1024, only done once per res-change.
+static void pack_frame(uint16_t *frame, int width, int height)
+{
+ for (int y = 1; y < height; y++)
+ {
+ uint16_t *src = frame + y * 1024;
+ uint16_t *dst = frame + y * 512;
+
+ memcpy(dst, src, width * sizeof(uint16_t));
+ }
+}
+
+// Pitch 1024 -> 2048, only done once per res-change.
+static void stretch_frame(uint16_t *frame, int width, int height)
+{
+ for (int y = height - 1; y >= 0; y--)
+ {
+ uint16_t *src = frame + y * 512;
+ uint16_t *dst = frame + y * 1024;
+
+ memcpy(dst, src, width * sizeof(uint16_t));
+ }
+}
+
+bool8 S9xDeinitUpdate(int width, int height)
+{
+ if (use_overscan)
+ {
+ if (height == 224)
+ {
+ memmove(GFX.Screen + (GFX.Pitch / 2) * 7, GFX.Screen, GFX.Pitch * height);
+ memset(GFX.Screen, 0x00, GFX.Pitch * 7);
+ memset(GFX.Screen + (GFX.Pitch / 2) * (7 + 224), 0, GFX.Pitch * 8);
+ height = 239;
+ }
+ else if (height == 448)
+ {
+ memmove(GFX.Screen + (GFX.Pitch / 2) * 15, GFX.Screen, GFX.Pitch * height);
+ memset(GFX.Screen, 0x00, GFX.Pitch * 15);
+ memset(GFX.Screen + (GFX.Pitch / 2) * (15 + 224), 0x00, GFX.Pitch * 17);
+ height = 478;
+ }
+ }
+ else // libsnes classic behavior
+ {
+ if (height == 448 || height == 478)
+ {
+ if (GFX.Pitch == 2048)
+ pack_frame(GFX.Screen, width, height);
+ GFX.Pitch = 1024;
+ }
+ else
+ {
+ if (GFX.Pitch == 1024)
+ stretch_frame(GFX.Screen, width, height);
+ GFX.Pitch = 2048;
+ }
+ }
+
+ s9x_video_cb(GFX.Screen, width, height);
+ return TRUE;
+}
+
+bool8 S9xContinueUpdate(int width, int height)
+{
+ return S9xDeinitUpdate(width, height);
+}
+
+// Dummy functions that should probably be implemented correctly later.
+void S9xParsePortConfig(ConfigFile&, int) {}
+void S9xSyncSpeed() {}
+//void S9xPollPointer(int, short*, short*) {}
+const char* S9xStringInput(const char* in) { return in; }
+const char* S9xGetFilename(const char* in, s9x_getdirtype) { return in; }
+const char* S9xGetDirectory(s9x_getdirtype) { return ""; }
+void S9xInitInputDevices() {}
+const char* S9xChooseFilename(unsigned char) { return ""; }
+void S9xHandlePortCommand(s9xcommand_t, short, short) {}
+bool S9xPollButton(unsigned int, bool*) { return false; }
+void S9xToggleSoundChannel(int) {}
+const char* S9xGetFilenameInc(const char* in, s9x_getdirtype) { return ""; }
+const char* S9xBasename(const char* in) { return in; }
+bool8 S9xInitUpdate() { return TRUE; }
+void S9xExtraUsage() {}
+bool8 S9xOpenSoundDevice() { return TRUE; }
+void S9xMessage(int, int, const char*) {}
+bool S9xPollAxis(unsigned int, short*) { return FALSE; }
+void S9xSetPalette() {}
+void S9xParseArg(char**, int&, int) {}
+void S9xExit() {}
+bool S9xPollPointer(unsigned int, short*, short*) { return false; }
+const char *S9xChooseMovieFilename(unsigned char) { return NULL; }
+
+bool8 S9xOpenSnapshotFile(const char* filepath, bool8 read_only, STREAM *file)
+{
+ if(read_only)
+ {
+ if((*file = OPEN_STREAM(filepath, "rb")) != 0)
+ {
+ return (TRUE);
+ }
+ }
+ else
+ {
+ if((*file = OPEN_STREAM(filepath, "wb")) != 0)
+ {
+ return (TRUE);
+ }
+ }
+ return (FALSE);
+}
+
+void S9xCloseSnapshotFile(STREAM file)
+{
+ CLOSE_STREAM(file);
+}
+
+void S9xAutoSaveSRAM()
+{
+ return;
+}
+
+#ifndef __WIN32__
+// S9x weirdness.
+void _splitpath (const char *path, char *drive, char *dir, char *fname, char *ext)
+{
+ *drive = 0;
+
+ const char *slash = strrchr(path, SLASH_CHAR),
+ *dot = strrchr(path, '.');
+
+ if (dot && slash && dot < slash)
+ dot = NULL;
+
+ if (!slash)
+ {
+ *dir = 0;
+
+ strcpy(fname, path);
+
+ if (dot)
+ {
+ fname[dot - path] = 0;
+ strcpy(ext, dot + 1);
+ }
+ else
+ *ext = 0;
+ }
+ else
+ {
+ strcpy(dir, path);
+ dir[slash - path] = 0;
+
+ strcpy(fname, slash + 1);
+
+ if (dot)
+ {
+ fname[dot - slash - 1] = 0;
+ strcpy(ext, dot + 1);
+ }
+ else
+ *ext = 0;
+ }
+}
+
+void _makepath (char *path, const char *, const char *dir, const char *fname, const char *ext)
+{
+ if (dir && *dir)
+ {
+ strcpy(path, dir);
+ strcat(path, SLASH_STR);
+ }
+ else
+ *path = 0;
+
+ strcat(path, fname);
+
+ if (ext && *ext)
+ {
+ strcat(path, ".");
+ strcat(path, ext);
+ }
+}
+#endif // __WIN32__
diff --git a/libsnes/libsnes.def b/libsnes/libsnes.def
new file mode 100644
index 00000000..c1017351
--- /dev/null
+++ b/libsnes/libsnes.def
@@ -0,0 +1,47 @@
+LIBRARY snes
+
+EXPORTS
+
+snes_library_id
+
+snes_library_revision_major
+snes_library_revision_minor
+
+snes_set_video_refresh
+snes_set_audio_sample
+snes_set_input_poll
+snes_set_input_state
+
+snes_set_environment
+
+snes_set_controller_port_device
+snes_set_cartridge_basename
+
+snes_init
+snes_term
+snes_power
+snes_reset
+snes_run
+
+snes_serialize_size
+snes_serialize
+snes_unserialize
+
+snes_cheat_reset
+snes_cheat_set
+
+snes_load_cartridge_normal
+
+snes_load_cartridge_bsx_slotted
+
+snes_load_cartridge_bsx
+
+snes_load_cartridge_sufami_turbo
+
+snes_load_cartridge_super_game_boy
+
+snes_unload_cartridge
+
+snes_get_region
+snes_get_memory_data
+snes_get_memory_size
\ No newline at end of file
diff --git a/libsnes/libsnes.hpp b/libsnes/libsnes.hpp
new file mode 100644
index 00000000..78a49816
--- /dev/null
+++ b/libsnes/libsnes.hpp
@@ -0,0 +1,1264 @@
+#ifndef LIBSNES_HPP
+#define LIBSNES_HPP
+
+#include "port.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// LIBSNES Super Nintendo emulation API
+//
+// Things you should know:
+// - Linking against libsnes requires a C++ compiler. It can be compiled with
+// a C99 compiler if you #include and if your C99 compiler's
+// bool type is compatible with the bool type used by the C++ compiler used
+// to compile libsnes.
+// - libsnes supports exactly one emulated SNES; if you want to run two SNESes
+// in a single process, you'll need to link against or dlopen() two
+// different copies of the library.
+//
+// Typical usage of the libsnes API looks like this:
+//
+// 1. Call snes_init() to initialize the library.
+// 2. Tell libsnes which callback should be called for each event (see the
+// documentation on the individual callback types below.
+// 3. Call one of the snes_load_cartridge_* functions to load cartridge data
+// into the emulated SNES.
+// 4. If the physical cart had any non-volatile storage, there may be data from
+// a previous emulation run that needs to be loaded. Find the storage buffer
+// by calling the snes_get_memory_* functions and load any saved data into
+// it.
+// 5. Call snes_set_controller_port_device() to connect appropriate controllers
+// to the emulated SNES.
+// 6. Call snes_get_region() to determine the intended screen refresh rate for
+// this cartridge..
+// 7. Call snes_run() to emulate a single frame. Before snes_run() returns, the
+// installed callbacks will be called - possibly multiple times.
+// 8. When you're done, call snes_term() to free all memory allocated
+// associated with the emulated SNES.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+// Constants {{{
+
+// These constants represent the two controller ports on the front of the SNES,
+// for use with the snes_set_controller_port_device() function and the
+// snes_input_state_t callback.
+#define SNES_PORT_1 0
+#define SNES_PORT_2 1
+
+// These constants represent the different kinds of controllers that can be
+// connected to a controller port, for use with the
+// snes_set_controller_port_device() function and the snes_input_state_t
+// callback.
+#define SNES_DEVICE_NONE 0
+#define SNES_DEVICE_JOYPAD 1
+#define SNES_DEVICE_MULTITAP 2
+#define SNES_DEVICE_MOUSE 3
+#define SNES_DEVICE_SUPER_SCOPE 4
+#define SNES_DEVICE_JUSTIFIER 5
+#define SNES_DEVICE_JUSTIFIERS 6
+
+// These constants represent the button and axis inputs on various controllers,
+// for use with the snes_input_state_t callback.
+#define SNES_DEVICE_ID_JOYPAD_B 0
+#define SNES_DEVICE_ID_JOYPAD_Y 1
+#define SNES_DEVICE_ID_JOYPAD_SELECT 2
+#define SNES_DEVICE_ID_JOYPAD_START 3
+#define SNES_DEVICE_ID_JOYPAD_UP 4
+#define SNES_DEVICE_ID_JOYPAD_DOWN 5
+#define SNES_DEVICE_ID_JOYPAD_LEFT 6
+#define SNES_DEVICE_ID_JOYPAD_RIGHT 7
+#define SNES_DEVICE_ID_JOYPAD_A 8
+#define SNES_DEVICE_ID_JOYPAD_X 9
+#define SNES_DEVICE_ID_JOYPAD_L 10
+#define SNES_DEVICE_ID_JOYPAD_R 11
+
+#define SNES_DEVICE_ID_MOUSE_X 0
+#define SNES_DEVICE_ID_MOUSE_Y 1
+#define SNES_DEVICE_ID_MOUSE_LEFT 2
+#define SNES_DEVICE_ID_MOUSE_RIGHT 3
+
+#define SNES_DEVICE_ID_SUPER_SCOPE_X 0
+#define SNES_DEVICE_ID_SUPER_SCOPE_Y 1
+#define SNES_DEVICE_ID_SUPER_SCOPE_TRIGGER 2
+#define SNES_DEVICE_ID_SUPER_SCOPE_CURSOR 3
+#define SNES_DEVICE_ID_SUPER_SCOPE_TURBO 4
+#define SNES_DEVICE_ID_SUPER_SCOPE_PAUSE 5
+
+#define SNES_DEVICE_ID_JUSTIFIER_X 0
+#define SNES_DEVICE_ID_JUSTIFIER_Y 1
+#define SNES_DEVICE_ID_JUSTIFIER_TRIGGER 2
+#define SNES_DEVICE_ID_JUSTIFIER_START 3
+
+// These constants will be returned by snes_get_region(), representing the
+// region of the last loaded cartridge.
+#define SNES_REGION_NTSC 0
+#define SNES_REGION_PAL 1
+
+// These constants represent the kinds of non-volatile memory a SNES cartridge
+// might have, for use with the snes_get_memory_* functions.
+#define SNES_MEMORY_CARTRIDGE_RAM 0
+#define SNES_MEMORY_CARTRIDGE_RTC 1
+#define SNES_MEMORY_BSX_RAM 2
+#define SNES_MEMORY_BSX_PRAM 3
+#define SNES_MEMORY_SUFAMI_TURBO_A_RAM 4
+#define SNES_MEMORY_SUFAMI_TURBO_B_RAM 5
+#define SNES_MEMORY_GAME_BOY_RAM 6
+#define SNES_MEMORY_GAME_BOY_RTC 7
+
+// These constants represent the various kinds of volatile storage the SNES
+// offers, to allow libsnes clients to implement things like cheat-searching
+// and certain kinds of debugging. They are for use with the snes_get_memory_*
+// functions.
+#define SNES_MEMORY_WRAM 100
+#define SNES_MEMORY_APURAM 101
+#define SNES_MEMORY_VRAM 102
+#define SNES_MEMORY_OAM 103
+#define SNES_MEMORY_CGRAM 104
+
+// SSNES extension. Not required to be implemented for a working implementation.
+#define SNES_ENVIRONMENT_GET_FULLPATH 0 // const char ** -- Full path of game loaded.
+#define SNES_ENVIRONMENT_SET_GEOMETRY 1 // const struct snes_geometry * -- Window geometry information for the system/game.
+#define SNES_ENVIRONMENT_SET_PITCH 2 // const unsigned * -- Pitch of game image.
+#define SNES_ENVIRONMENT_GET_OVERSCAN 3 // bool * -- Boolean value whether or not the implementation should use overscan.
+#define SNES_ENVIRONMENT_SET_TIMING 4 // const struct snes_system_timing * -- Set exact timings of the system.
+ // Used primarily for video recording.
+
+struct snes_geometry
+{
+ unsigned base_width; // Nominal video width of system.
+ unsigned base_height; // Nominal video height of system.
+ unsigned max_width; // Maximum possible width of system.
+ unsigned max_height; // Maximum possible height of system.
+};
+
+struct snes_system_timing
+{
+ double fps;
+ double sample_rate;
+};
+
+typedef bool (*snes_environment_t)(unsigned cmd, void *data);
+
+// Must be called before calling snes_init().
+void snes_set_environment(snes_environment_t);
+////
+
+
+////////////////////////////////////////////////////////////////////////////}}}
+
+///////////////////////////////////////////////////////////////////////////////
+// Callback types {{{
+//
+// In order to deliver controller input to the emulated SNES, and retrieve
+// video frames and audio samples, you will need to register callbacks.
+
+// snes_audio_sample_t:
+//
+// This callback delivers a stereo audio sample pair generated by the
+// emulated SNES.
+//
+// This function is called once for every audio frame (one sample from left
+// and right channels). The SNES generates audio samples at a rate of about
+// 32040Hz (varies from unit to unit).
+//
+// Because the SNES generates video at exactly 59.94fps and most computer
+// monitors only support a 60fps refresh rate, real-time emulation needs to
+// run slightly fast so that each computer frame displays one emulated SNES
+// frame. Because the emulation runs slightly fast, and because most
+// consumer audio hardware does not play audio at precisely the requested
+// sample rate, you'll likely need to let the end-user tweak the effective
+// sample rate by 100Hz or so in either direction.
+//
+// Although the parameters are declared as unsigned for historical reasons,
+// the data they contain is actually signed. To work with the audio (e.g.
+// resample), you will need to reinterpret the sample value:
+//
+// int16_t real_left = *(int16_t*)(&left);
+//
+// Parameters:
+//
+// left:
+// A signed 16-bit integer containing the next audio sample from the
+// left audio channel. Yes, it's declared as unsigned for historical
+// reasons.
+//
+// right:
+// A signed 16-bit integer containing the next audio sample from the
+// right audio channel. Yes, it's declared as unsigned for historical
+// reasons.
+//
+
+typedef void (*snes_audio_sample_t)(uint16_t left, uint16_t right);
+
+
+// snes_video_refresh_t:
+//
+// This callback delivers a single SNES frame, generated by the emulated
+// SNES. The same memory buffer may be re-used later, so take a copy of the
+// data if you want to refer to it after your callback returns.
+//
+// The framebuffer is an array of unsigned 16-bit pixels, in a somewhat
+// complicated format. A quick refresher on SNES video modes:
+// - The basic SNES video-mode renders 256 pixels per scanline for a total
+// of 224 scanlines.
+// - When "overscan" mode is enabled, the SNES renders a few extra
+// scanlines at the end of the frame, for a total of 239 scanlines.
+// - When "hi-res" mode is enabled, the SNES speeds up its pixel rendering
+// to fit 512 pixels per scanline.
+// - Normally the SNES renders its pixels to one field of the interlaced
+// NTSC signal, but if "interlaced" mode is enabled the SNES renders
+// a second set of scanlines inbetween the regular set, for a total of
+// 448 (normal) or 478 (overscan) scanlines.
+//
+// Thus, the framebuffer memory layout for a standard 256x240 frame looks
+// something like this (note that 'height' has been reduced to 4 or 8 for
+// these examples):
+//
+// 0 1024b
+// ,---------------------------------------.
+// |====== width ======|...................| -.
+// |.......................................| |
+// |===================|...................| |
+// |.......................................| +- height = 4
+// |===================|...................| |
+// |.......................................| |
+// |===================|...................| |
+// |.......................................| -'
+// `---------------------------------------'
+//
+// A hi-res frame would look like this:
+//
+// 0 1024b
+// ,---------------------------------------.
+// |================ width ================| -.
+// |.......................................| |
+// |=======================================| |
+// |.......................................| +- height = 4
+// |=======================================| |
+// |.......................................| |
+// |=======================================| |
+// |.......................................| -'
+// `---------------------------------------'
+//
+// An interlaced frame would look like this:
+//
+// 0 1024b
+// ,---------------------------------------.
+// |====== width ======|...................| -.
+// |===================|...................| |
+// |===================|...................| |
+// |===================|...................| +- height = 8
+// |===================|...................| |
+// |===================|...................| |
+// |===================|...................| |
+// |===================|...................| -'
+// `---------------------------------------'
+//
+// And of course a hi-res, interlaced frame would look like this:
+//
+// 0 1024b
+// ,---------------------------------------.
+// |================ width ================| -.
+// |=======================================| |
+// |=======================================| |
+// |=======================================| |+- height = 8
+// |=======================================| |
+// |=======================================| |
+// |=======================================| |
+// |=======================================| -'
+// `---------------------------------------'
+//
+// More succinctly:
+// - the buffer begins at the top-left of the frame
+// - the first "width" bytes contain the first scanline.
+// - if the emulated SNES is in an interlaced video-mode (that is, if the
+// "height" parameter" is 448 or 478) then the second scanline begins at
+// an offset of 1024 bytes (512 pixels) after the first.
+// - otherwise the second scanline begins at an offset of 2048 bytes (1024
+// pixels) after the first.
+// - there are "height" scanlines in total.
+//
+// Each pixel contains a 15-bit RGB tuple: 0RRRRRGGGGGBBBBB (XRGB1555)
+//
+// Example code:
+//
+// void pack_frame (uint16_t * restrict out, const uint16_t * restrict in,
+// unsigned width, unsigned height)
+// {
+// // Normally our pitch is 2048 bytes.
+// int pitch_pixels = 1024;
+// // If we have an interlaced mode, pitch is 1024 bytes.
+// if ( height == 448 || height == 478 )
+// pitch_pixels = 512;
+//
+// for ( int y = 0; y < height; y++ )
+// {
+// const uint16_t *src = in + y * pitch_pixels;
+// uint16_t *dst = out + y * width;
+//
+// memcpy(dst, src, width * sizeof(uint16_t));
+// }
+// }
+//
+// Parameters:
+//
+// data:
+// a pointer to the beginning of the framebuffer described above.
+//
+// width:
+// the width of the frame, in pixels.
+//
+// height:
+// the number of scanlines in the frame.
+
+typedef void (*snes_video_refresh_t)(const uint16_t *data, unsigned width,
+ unsigned height);
+
+// snes_input_poll_t:
+//
+// This callback requests that you poll your input devices for events, if
+// required.
+//
+// Generally called once per frame before the snes_input_state_t callback is
+// called.
+//
+
+typedef void (*snes_input_poll_t)(void);
+
+// snes_input_state_t:
+//
+// This callback asks for information about the state of a particular input.
+//
+// The callback may be called multiple times per frame with the same
+// parameters.
+//
+// The callback might not be called at all, if the software running in the
+// emulated SNES does not try to probe the controllers.
+//
+// The callback will not be called for a particular port if DEVICE_NONE is
+// connected to it.
+//
+// If you wish to emulate any kind of turbo-fire, etc. then you will need to
+// put that logic into this callback.
+//
+// Parameters:
+//
+// port:
+// One of the constants SNES_PORT_1 or SNES_PORT_2, describing which
+// controller port you should report.
+//
+// device:
+// One of the SNES_DEVICE_* constants describing which type of device
+// is currently connected to the given port.
+//
+// index:
+// A number describing which of the devices connected to the port is
+// being reported. It's only useful for SNES_DEVICE_MULTITAP and
+// SNES_DEVICE_JUSTIFIERS - for other device types, this parameter is
+// always 0.
+//
+// id:
+// One of the SNES_DEVICE_ID_* constants for the given device,
+// describing which button or axis is being reported (for
+// SNES_DEVICE_MULTITAP, use the SNES_DEVICE_ID_JOYPAD_* IDs; for
+// SNES_DEVICE_JUSTIFIERS use the SNES_DEVICE_ID_JUSTIFIER_* IDs.).
+//
+// Returns:
+//
+// An integer representing the state of the described button or axis.
+//
+// - If it represents a digital input such as SNES_DEVICE_ID_JOYPAD_B or
+// SNES_DEVICE_ID_MOUSE_LEFT), return 1 if the button is pressed, and
+// 0 otherwise.
+// - If "id" is SNES_DEVICE_ID_MOUSE_X or SNES_DEVICE_ID_MOUSE_Y then
+// return the relative movement of the mouse during the current frame;
+// values outside the range -127 to +127 will be clamped.
+// - If "id" is one of the light-gun axes (such as
+// SNES_DEVICE_ID_JUSTIFIER_Y or SNES_DEVICE_ID_SUPER_SCOPE_X), you
+// should return the relative movement of the pointing device during the
+// current frame.
+
+typedef int16_t (*snes_input_state_t)(bool port, unsigned device,
+ unsigned index, unsigned id);
+
+////////////////////////////////////////////////////////////////////////////}}}
+
+///////////////////////////////////////////////////////////////////////////////
+// libsnes setup {{{
+//
+// These functions are used to get information about and manipulate the libsnes
+// library itself, not the emulated SNES it implements.
+
+// snes_library_id:
+//
+// Returns a human readable string describing this libsnes implementation.
+// It is not supposed to be parsed or used in any other way than being
+// printed to screen on request by user or otherwise.
+//
+// Returns:
+//
+// A human-readable string describing this implementation.
+
+const char* snes_library_id(void);
+
+
+// snes_library_revision_major:
+//
+// Returns the major API version of this libsnes implementation.
+//
+// This number is increased every time there is a compatibility-breaking
+// change to the libsnes API. At startup, your program should call this
+// function and compare the return value to the major API version the
+// program was designed to work with. If they are different, your program
+// will (very likely) not work with this libsnes implementation.
+//
+// For example, if your program was designed to work with the libsnes API
+// whose major.minor revision was 1.5, and this function returns a major
+// version of 2, you have a problem.
+//
+// Returns:
+//
+// An integer, the major API version of this libsnes implementation.
+
+unsigned snes_library_revision_major(void);
+
+// snes_library_revision_minor:
+//
+// Returns the minor API version of this libsnes implementation.
+//
+// This number is increased every time there is a backwards-compatible
+// change to the libsnes API. At startup, your program should call this
+// function and compare the return value to the minor API version the
+// program was designed to work with. If the return value is less than the
+// expected minor version, your program will (very likely) not work with
+// this libsnes implementation.
+//
+// For example, if your program was designed to work with the libsnes API
+// whose major.minor revision was 1.5, and this libsnes implementation's
+// major.minor version is 1.3, it's probably missing features you require.
+// On the other hand, if this libsnes implementation's major.minor version
+// is 1.9, it probably has extra fancy features you don't need to worry
+// about.
+//
+// Returns:
+//
+// An integer, the minor API version of this libsnes implementation.
+
+unsigned snes_library_revision_minor(void);
+
+// snes_init:
+//
+// Initializes the libsnes implementation.
+//
+// This function must be called exactly once before any other library
+// functions are called.
+
+void snes_init(void);
+
+// snes_term:
+//
+// Shuts down the libsnes implementation.
+//
+// This function must be called exactly once. Once called, you should not
+// call any other libsnes functions besides (perhaps) snes_init().
+
+void snes_term(void);
+
+////////////////////////////////////////////////////////////////////////////}}}
+
+///////////////////////////////////////////////////////////////////////////////
+// Callback registration {{{
+//
+// Note that all callbacks should be set up before snes_run() is called for the
+// first time.
+
+// snes_set_video_refresh:
+//
+// Sets the callback that will receive new video frames.
+//
+// See the documentation for snes_video_refresh_t for details.
+//
+// Parameters:
+//
+// A pointer to a function matching the snes_video_refresh_t call
+// signature.
+
+void snes_set_video_refresh(snes_video_refresh_t);
+
+// snes_set_audio_sample
+//
+// Sets the callback that will receive new audio sample pairs.
+//
+// See the documentation for snes_audio_sample_t for details.
+//
+// Parameters:
+//
+// A pointer to a function matching the snes_audio_sample_t call
+// signature.
+
+void snes_set_audio_sample(snes_audio_sample_t);
+
+// snes_set_input_poll:
+//
+// Sets the callback that will be notified to poll input devices.
+//
+// See the documentation for snes_input_poll_t for details.
+//
+// Parameters:
+//
+// A pointer to a function matching the snes_input_poll_t call signature.
+
+void snes_set_input_poll(snes_input_poll_t);
+
+// snes_set_input_state:
+//
+// Sets the callback that will be used to read input device state.
+//
+// See the documentation for snes_input_state_t for details.
+//
+// Parameters:
+//
+// A pointer to a function matching the snes_input_state_t call signature.
+
+void snes_set_input_state(snes_input_state_t);
+
+////////////////////////////////////////////////////////////////////////////}}}
+
+///////////////////////////////////////////////////////////////////////////////
+// SNES operation {{{
+//
+// Functions for manipulating the emulated SNES.
+
+// snes_set_controller_port_device:
+//
+// Sets the input device connected to a given controller port.
+//
+// Connecting a device to a port implicitly removes any device previously
+// connected to that port. To remove a device without connecting a new one,
+// pass DEVICE_NONE as the device parameter. From this point onward, the
+// callback passed to set_input_state_cb() will be called with the
+// appropriate device, index and id parameters.
+//
+// If this function is never called, the default is to have a DEVICE_JOYPAD
+// connected to both ports.
+//
+// Calling this callback from inside the set_input_state_cb() has undefined
+// results, so don't do that.
+//
+// Parameters:
+//
+// port:
+// One of the constants SNES_PORT_1 or SNES_PORT_2, describing which
+// controller port is being configured.
+//
+// device:
+// One of the SNES_DEVICE_* constants describing which type of device
+// should be connected to the given port. Note that some devices can
+// only be connected to SNES_PORT_2. Attempting to connect
+// a port-2-only device to SNES_PORT_1 has undefined results.
+//
+// These devices work in either port:
+// - SNES_DEVICE_NONE: No device is connected to this port.
+// - SNES_DEVICE_JOYPAD: A standard SNES gamepad.
+// - SNES_DEVICE_MULTITAP: A multitap controller, which acts like
+// 4 SNES_DEVICE_JOYPADs. Your input state callback will be
+// passed "id" parameters between 0 and 3, inclusive.
+// - SNES_DEVICE_MOUSE: A SNES mouse controller, as shipped with
+// Mario Paint.
+//
+// These devices only work properly when connected to port 2:
+// - SNES_DEVICE_SUPER_SCOPE: A Nintendo Super Scope light-gun
+// device.
+// - SNES_DEVICE_JUSTIFIER: A Konami Justifier light-gun device.
+// - SNES_DEVICE_JUSTIFIERS: Two Konami Justifier light-gun
+// devices, daisy-chained together. Your input state callback
+// will be passed "id" parameters 0 and 1.
+
+void snes_set_controller_port_device(bool port, unsigned device);
+
+// snes_power:
+//
+// Turns the emulated console off and back on.
+//
+// This functionality is sometimes called "hard reset" and guarantees that
+// all hardware state is reset to a reasonable default.
+//
+// Before bsnes v070r07, this resets the controller ports to both contain
+// SNES_DEVICE_JOYPADs.
+//
+// This requires that a cartridge is loaded.
+
+void snes_power(void);
+
+// snes_reset:
+//
+// Presses the "reset" button on the emulated SNES.
+//
+// This functionality is sometimes called "soft reset". Most hardware state
+// is reset to a reasonable befault, but not all.
+//
+// As of bsnes v073r01, this function (as a side-effect) resets the
+// controller ports to both contain SNES_DEVICE_JOYPADs.
+//
+// This requires that a cartridge is loaded.
+
+void snes_reset(void);
+
+// snes_run():
+//
+// Runs the emulated SNES until the end of the next video frame.
+//
+// Usually causes each registered callback to be called before returning.
+//
+// This function will run as fast as possible. It is up to the caller to
+// make sure that the game runs at the intended speed.
+//
+// For optimal A/V sync, make sure that the audio callback never blocks for
+// longer than a frame (approx 16ms for NTSC, 20ms for PAL)
+//
+// Optimally, it should never block for more than a few ms at a time.
+
+void snes_run(void);
+
+// snes_get_region():
+//
+// Determines the intended frame-rate of the loaded cartridge.
+//
+// The two main SNES hardware variants are the US/Japan variant, designed
+// for NTSC output, and the European variant, designed for PAL output.
+// However, the world is not quite so tidy as that, and there are countries
+// like Brazil that use PAL output at NTSC frame-rates.
+//
+// For historical reasons this function is named snes_get_region(), but
+// effectively the only information you can reliably infer is the
+// frame-rate.
+//
+// Returns:
+//
+// One of the SNES_REGION_* constants. SNES_REGION_PAL means 50fps,
+// SNES_REGION_NTSC means 60fps.
+
+bool snes_get_region(void);
+
+////////////////////////////////////////////////////////////////////////////}}}
+
+///////////////////////////////////////////////////////////////////////////////
+// Save state support {{{
+//
+// libsnes has the ability to save the current emulation state and restore it
+// at a later time.
+//
+// Note 1: It is impossible to reliably restore the *exact* state, although the
+// difference is only a few cycles. If you demand the ability to reliably
+// restore state, call snes_serialize() after each frame to ensure the emulated
+// SNES is in a state that can be reliably restored.
+//
+// Note 2: The save state information is specific to a particular cartridge
+// loaded into a particular version of a particular libsnes implementation.
+// Unfortunately, there is not yet a way to determine whether a given save
+// state is compatible with a given libsnes implementation, other than by
+// loading it. However, if snes_serialize_size() does not match the size of an
+// old save state, that's a strong hint that something has incompatibly
+// changed.
+
+// snes_serialize_size:
+//
+// Determines the minimum size of a save state.
+//
+// This value can change depending on the features used by the loaded
+// cartridge, and the version of the libsnes implementation used.
+//
+// Returns:
+//
+// An integer representing the number of bytes required to store the
+// current emulation state.
+
+unsigned snes_serialize_size(void);
+
+// snes_serialize:
+//
+// Serialize the current emulation state to a buffer.
+//
+// If the allocated buffer is smaller than the size returned by
+// snes_serialize_size(), serialization will fail. If the allocated buffer
+// is larger, only the first snes_serialize_size() bytes will be written to.
+//
+// The resulting buffer may be stored, and later passed to
+// snes_unserialize() to restore the saved emulation state.
+//
+// Parameters:
+//
+// data:
+// A pointer to an allocated buffer of memory.
+//
+// size:
+// The size of the buffer pointed to by "data". Should be greater than
+// or equal to the value returned by snes_serialize_size().
+//
+// Returns:
+//
+// A boolean; True means the emulation state was serialized successfully,
+// False means a problem was encountered.
+
+bool snes_serialize(uint8_t *data, unsigned size);
+
+// snes_unserialize:
+//
+// Unserialize the emulation state from a buffer.
+//
+// If the serialization data in the buffer does not appear to be compatible
+// with the current libsnes implementation, the function returns False and
+// the current emulation state is not modified.
+//
+// Parameters:
+//
+// data:
+// A pointer to an allocated buffer of memory.
+//
+// size:
+// The size of the buffer pointed to by "data". Should be greater than
+// or equal to the value returned by snes_serialize_size().
+//
+// Returns:
+//
+// A boolean; True means the emulation state was loaded successfully,
+// False means a problem was encountered.
+
+bool snes_unserialize(const uint8_t *data, unsigned size);
+
+////////////////////////////////////////////////////////////////////////////}}}
+
+///////////////////////////////////////////////////////////////////////////////
+// Cheat support {{{
+//
+// libsnes does not include any kind of cheat management API; the intention is
+// that any change to the set of applied cheats will cause the containing
+// application to call snes_cheat_reset() then apply the new set of cheats with
+// snes_cheat_set().
+//
+// Any currently-applied cheats are discarded when a new cartridge is loaded.
+
+// snes_cheat_reset:
+//
+// Discards all cheat codes applied to the emulated SNES.
+
+void snes_cheat_reset(void);
+
+// snes_cheat_set:
+//
+// Apply a sequence of cheat codes to the emulated SNES.
+//
+// Since a "cheat code" is basically an instruction to override the value of
+// a particular byte in the SNES' memory, more complex cheats may require
+// several individual codes applied at once. There's no effective difference
+// between applying these codes in a group with one call to
+// snes_cheat_set(), or applying them one at a time with individual calls.
+// However, most cheat databases will have a collection of available cheats
+// for each game, where each item in the collection has a description and
+// a sequence of codes to be applied as a unit. This API makes it easy to
+// present the list of descriptions to the user, and apply each cheat the
+// user selects.
+//
+// Parameters:
+//
+// index:
+// The given cheat code will be stored at this index in the array of
+// applied cheats. If a cheat already exists at this location, it will
+// be replaced by the new cheat. If the index is larger than any
+// previously specififed index, the array will be resized to
+// accommodate.
+//
+// enabled:
+// True means that the cheat will actually be applied, False means
+// that the cheat will have no effect. There is no way to enable or
+// disable a cheat after it has been added, other than to call
+// snes_cheat_set() a second time with the same values for "index" and
+// "code".
+//
+// code:
+// A string containing a sequence of cheat codes separated by '+'
+// characters. Any spaces in the string will be removed before
+// parsing.
+//
+// Each code in the sequence must be in either GameGenie format
+// ("1234-ABCD") or ProActionReplay format ("1234AB:CD" or
+// "1234ABCD").
+
+void snes_cheat_set(unsigned index, bool enabled, const char *code);
+
+////////////////////////////////////////////////////////////////////////////}}}
+
+///////////////////////////////////////////////////////////////////////////////
+// Cartridge loading and unloading {{{
+//
+// Before calling snes_run(), a cartridge must be loaded into the emulated SNES
+// so that it has code to run.
+//
+// Loading a cartridge of any kind calls snes_cheat_reset() as a side-effect.
+
+// snes_load_cartridge_normal:
+//
+// Load a normal ROM image into the emulated SNES.
+//
+// Parameters:
+//
+// rom_xml:
+// A pointer to a null-terminated string containing an XML memory map
+// that describes where the ROM image is mapped into the SNES address
+// space, what special chips it uses (and where they're mapped), etc.
+//
+// If NULL, libsnes will guess a memory map. The guessed memory map
+// should be correct for all licenced games in all regions.
+//
+// rom_data:
+// A pointer to a byte array containing the uncompressed,
+// de-interleaved, headerless ROM image.
+//
+// rom_size:
+// The length of the rom_data array, in bytes.
+//
+// Returns:
+//
+// A boolean; True means the cartridge was loaded correctly, False means
+// an error occurred.
+
+bool snes_load_cartridge_normal(
+ const char *rom_xml, const uint8_t *rom_data, unsigned rom_size
+);
+
+// snes_load_cartridge_bsx:
+//
+// Load a BS-X base cart image, optionally with a memory pack.
+//
+// The Satellaview system, abbreviated "BS-X" for unclear reasons, was an
+// addon for the Super Famicom that connected it to the St. GIGA satellite
+// network. The network would broadcast games at a particular time, and
+// users could download them to replaceable memory packs.
+//
+// For more information, see http://en.wikipedia.org/wiki/Satellaview
+//
+// Parameters:
+//
+// rom_xml:
+// A pointer to a null-terminated string containing an XML memory map
+// that describes where the BS-X base cartridge ROM image is mapped
+// into the SNES address space.
+//
+// If NULL, libsnes will guess a memory map. The guessed memory map
+// should be correct for all known BS-X base cartridge images.
+//
+// rom_data:
+// A pointer to a byte array containing the uncompressed,
+// de-interleaved, headerless ROM image of the BS-X base cartridge.
+//
+// The BS-X base cartridge is named "BS-X - Sore wa Namae o Nusumareta
+// Machi no Monogatari" in some SNES game databases.
+//
+// rom_size:
+// The length of the rom_data array, in bytes.
+//
+// bsx_xml:
+// A pointer to a null-terminated string containing an XML memory map
+// that describes the BS-X memory pack.
+//
+// This parameter is currently ignored and should be passed as NULL.
+//
+// bsx_data:
+// A pointer to a byte array containing the uncompressed,
+// de-interleaved, headerless image of the BS-X memory-pack.
+//
+// If NULL, libsnes will behave as though no memory-pack were inserted
+// into the base cartridge.
+//
+// bsx_size:
+// The length of the bsx_data array, in bytes.
+//
+// Returns:
+//
+// A boolean; True means the cartridge was loaded correctly, False means
+// an error occurred.
+
+bool snes_load_cartridge_bsx(
+ const char *rom_xml, const uint8_t *rom_data, unsigned rom_size,
+ const char *bsx_xml, const uint8_t *bsx_data, unsigned bsx_size
+);
+
+// snes_load_cartridge_bsx_slotted:
+//
+// Load a BS-X slotted cartridge, optionally with a memory pack.
+//
+// A BS-X slotted cartridge is an ordinary SNES cartridge, with a slot in
+// the top that accepts the same memory packs used by the BS-X base
+// cartridge.
+//
+// Parameters:
+//
+// rom_xml:
+// A pointer to a null-terminated string containing an XML memory map
+// that describes where the ROM image is mapped into the SNES address
+// space, what special chips it uses (and where they're mapped), etc.
+//
+// If NULL, libsnes will guess a memory map. The guessed memory map
+// should be correct for all licenced games in all regions.
+//
+// rom_data:
+// A pointer to a byte array containing the uncompressed,
+// de-interleaved, headerless ROM image.
+//
+// rom_size:
+// The length of the rom_data array, in bytes.
+//
+// bsx_xml:
+// A pointer to a null-terminated string containing an XML memory map
+// that describes the BS-X memory pack.
+//
+// This parameter is currently ignored and should be passed as NULL.
+//
+// bsx_data:
+// A pointer to a byte array containing the uncompressed,
+// de-interleaved, headerless image of the BS-X memory-pack.
+//
+// If NULL, libsnes will behave as though no memory-pack were inserted
+// into the base cartridge.
+//
+// bsx_size:
+// The length of the bsx_data array, in bytes.
+//
+// Returns:
+//
+// A boolean; True means the cartridge was loaded correctly, False means
+// an error occurred.
+
+bool snes_load_cartridge_bsx_slotted(
+ const char *rom_xml, const uint8_t *rom_data, unsigned rom_size,
+ const char *bsx_xml, const uint8_t *bsx_data, unsigned bsx_size
+);
+
+// snes_load_cartridge_sufami_turbo:
+//
+// Load a SuFami Turbo base cart image, optionally with game packs.
+//
+// The SuFami Turbo was a cartridge available for the Super Famicom, created
+// by Bandai, with two slots in the top designed to accept special
+// mini-cartridges. The cartridge in Slot A was the cartridge that actually
+// ran, while the cartridge in Slot B was made available to the Slot
+// A cartridge, enabling sharing of save-game data or using characters from
+// one game in another.
+//
+// For more information, see: http://en.wikipedia.org/wiki/Sufami_Turbo
+//
+// Parameters:
+//
+// rom_xml:
+// A pointer to a null-terminated string containing an XML memory map
+// that describes where the SuFami Turbo base cartridge ROM image is
+// mapped into the SNES address space.
+//
+// If NULL, libsnes will guess a memory map. The guessed memory map
+// should be correct for all known SuFami Turbo base cartridge images.
+//
+// rom_data:
+// A pointer to a byte array containing the uncompressed,
+// de-interleaved, headerless ROM image of the SuFami Turbo base
+// cartridge.
+//
+// The SuFami Turbo base cartridge is named "Sufami Turbo" in some
+// SNES game databases.
+//
+// rom_size:
+// The length of the rom_data array, in bytes.
+//
+// sta_xml:
+// A pointer to a null-terminated string containing an XML memory map
+// that describes the Sufami Turbo cartridge in Slot A.
+//
+// This parameter is currently ignored and should be passed as NULL.
+//
+// sta_data:
+// A pointer to a byte array containing the uncompressed,
+// de-interleaved, headerless ROM image of the SuFami Turbo cartridge
+// in Slot A.
+//
+// This is the cartridge that will be executed by the SNES.
+//
+// If NULL, libsnes will behave as though no cartridge were inserted
+// into the Slot A.
+//
+// sta_size:
+// The length of the sta_data array, in bytes.
+//
+// stb_xml:
+// A pointer to a null-terminated string containing an XML memory map
+// that describes the Sufami Turbo cartridge in Slot B.
+//
+// This parameter is currently ignored and should be passed as NULL.
+//
+// stb_data:
+// A pointer to a byte array containing the uncompressed,
+// de-interleaved, headerless ROM image of the SuFami Turbo cartridge
+// in Slot B.
+//
+// The data in this cartridge will be made available to the cartridge
+// in Slot A.
+//
+// If NULL, libsnes will behave as though no cartridge were inserted
+// into Slot B.
+//
+// stb_size:
+// The length of the stb_data array, in bytes.
+//
+// Returns:
+//
+// A boolean; True means the cartridge was loaded correctly, False means
+// an error occurred.
+
+bool snes_load_cartridge_sufami_turbo(
+ const char *rom_xml, const uint8_t *rom_data, unsigned rom_size,
+ const char *sta_xml, const uint8_t *sta_data, unsigned sta_size,
+ const char *stb_xml, const uint8_t *stb_data, unsigned stb_size
+);
+
+// snes_load_cartridge_super_game_boy:
+//
+// Load a Super Game Boy base cart, optionally with a Gameboy cartridge.
+//
+// The Super Game Boy was a cartridge available for the Super Famicom and
+// Super Nintendo that accepted ordinary (original) Gameboy cartridges and
+// allowed the user to play them with a Super Nintendo controller, on a TV.
+// It extended the orginal Gameboy hardware in a few ways, including the
+// ability to display games in various palettes (rather than strictly
+// monochrome), to display a full-colour border image around the Gameboy
+// video output, or even run native SNES code to enhance the game.
+//
+// For more information, see: http://en.wikipedia.org/wiki/Super_Game_Boy
+//
+// Up until bsnes v073, loading Super Game Boy cartridges only works if the
+// libsupergameboy library from the bsnes release is installed. bsnes v074
+// includes a custom Gameboy emulation core, and external code is no longer
+// required.
+//
+// Parameters:
+//
+// rom_xml:
+// A pointer to a null-terminated string containing an XML memory map
+// that describes where the Super Game Boy base cartridge ROM image is
+// mapped into the SNES address space.
+//
+// If NULL, libsnes will guess a memory map. The guessed memory map
+// should be correct for all known Super Game Boy base cartridge
+// images.
+//
+// rom_data:
+// A pointer to a byte array containing the uncompressed,
+// de-interleaved, headerless ROM image of the Super Game Boy base
+// cartridge.
+//
+// Appropriate base cartridge images are named "Super Game Boy" or
+// "Super Game Boy 2" in some SNES game databases.
+//
+// rom_size:
+// The length of the rom_data array, in bytes.
+//
+// dmg_xml:
+// A pointer to a null-terminated string containing an XML memory map
+// that describes the inserted Gameboy cartridge.
+//
+// If NULL, libsnes will guess a memory map. The guesed memory map
+// should be correct for all licensed original Gameboy games in all
+// regions.
+//
+// dmg_data:
+// A pointer to a byte array containing the uncompressed, headerless
+// ROM image of the inserted Gameboy cartridge.
+//
+// If NULL, libsnes will behave as though no cartridge were inserted.
+//
+// dmg_size:
+// The length of the dmg_size array, in bytes.
+//
+// Returns:
+//
+// A boolean; True means the cartridge was loaded correctly, False means
+// an error occurred.
+
+bool snes_load_cartridge_super_game_boy(
+ const char *rom_xml, const uint8_t *rom_data, unsigned rom_size,
+ const char *dmg_xml, const uint8_t *dmg_data, unsigned dmg_size
+);
+
+// snes_set_cartridge_basename:
+//
+// Set the location and name of the loaded cartridge.
+//
+// libsnes uses this information to locate additional resources the
+// cartridge might require. Currently, these resources include:
+//
+// - The MSU-1 data pack and associated audio tracks, if the cartridge makes
+// use of bsnes' MSU-1 special-chip.
+// - The serial-port data receiving library, if the cartridge makes uses of
+// bsnes' serial-data-over-controller-port feature.
+//
+// Parameters:
+//
+// basename:
+// The path and basename of the loaded cartridge. For example, if the
+// full path to the loaded cartridge is "/path/to/filename.sfc", this
+// parameter should be set to "/path/to/filename".
+
+void snes_set_cartridge_basename(const char *basename);
+
+// snes_unload_cartridge:
+//
+// Unloads the currently loaded cartridge from the emulated SNES.
+//
+// You will be unable to call snes_run() until another cartridge is loaded.
+
+void snes_unload_cartridge(void);
+
+////////////////////////////////////////////////////////////////////////////}}}
+
+///////////////////////////////////////////////////////////////////////////////
+// Volatile and non-volatile storage {{{
+//
+// Certain SNES cartridges include non-volatile storage or other kinds of data
+// that would persist after the SNES is turned off. libsnes exposes this
+// information via the snes_get_memory_data() and snes_get_memory_size()
+// functions. Since version 1.2 of the libsnes API, libsnes also exposes the
+// contents of volatile storage such as WRAM and VRAM.
+//
+// After a cartridge is loaded, call snes_get_memory_size() and
+// snes_get_memory_data() with the various SNES_MEMORY_* constants to determine
+// which kinds of non-volatile storage the cartridge supports - unsupported
+// storage types will have a size of 0 and the data pointer NULL.
+//
+// If you have non-volatile storage data from a previous run, you can memcpy()
+// the data from your storage into the buffer described by the data and size
+// values before calling snes_run(). Do not load non-volatile storage data if
+// the size of the data you have is different from the size returned by
+// snes_get_memory_size().
+//
+// Before calling snes_unload_cartridge(), you should copy the contents of the
+// relevant storage buffers into a file (or some non-volatile storage of your
+// own) so that you can load it the next time you load the same cartridge into
+// the emulated SNES. Do not call free() on the storage buffers; they will be
+// handled by libsnes. Note: It is not necessary to store the contents of
+// volatile storage; the emulated SNES expects information in volatile storage
+// to be lost (hence the name 'volatile').
+//
+// Because non-volatile storage is read and written by the software running on
+// the emulated SNES, it should be compatible between different versions of
+// different emulators running on different platforms, unlike save states.
+//
+// The various kinds of non-volatile storage and their uses are:
+//
+// SNES_MEMORY_CARTRIDGE_RAM:
+// Standard battery-backed static RAM (SRAM). Traditionally, the SRAM for
+// a ROM image named "foo.sfc" is stored in a file named "foo.srm" beside
+// it.
+//
+// SNES_MEMORY_CARTRIDGE_RTC:
+// Real-time clock data. Traditionally, the RTC data for a ROM image named
+// "foo.sfc" is stored in a file named "foo.rtc" beside it.
+//
+// SNES_MEMORY_BSX_RAM:
+// RAM data used with the BS-X base cartridge.
+//
+// SNES_MEMORY_BSX_PRAM:
+// PRAM data used with the BS-X base cartridge.
+//
+// SNES_MEMORY_SUFAMI_TURBO_A_RAM:
+// RAM data stored in the mini-cartridge inserted into Slot A of the
+// SuFami Turbo base cartridge.
+//
+// SNES_MEMORY_SUFAMI_TURBO_B_RAM:
+// RAM data stored in the mini-cartridge inserted into Slot B of the
+// SuFami Turbo base cartridge.
+//
+// SNES_MEMORY_GAME_BOY_RAM:
+// Standard battery-backed static RAM (SRAM) in the Gameboy cartridge
+// inserted into the Super Game Boy base cartridge. Not all Gameboy games
+// have SRAM.
+//
+// SNES_MEMORY_GAME_BOY_RTC:
+// Real-time clock data in the Gameboy cartridge inserted into the Super
+// Game Boy base cartridge. Not all Gameboy games have an RTC.
+//
+// The various kinds of volatile storage are:
+//
+// SNES_MEMORY_WRAM:
+// Working RAM, accessible by the CPU. SNES software tends to keep runtime
+// information in here; games' life-bars and inventory contents and so
+// forth are in here somewhere.
+//
+// SNES_MEMORY_APURAM:
+// RAM accessible by the Audio Processing Unit. Contains audio samples,
+// music data and the code responsible for feeding the right notes to the
+// DSP at the right times.
+//
+// SNES_MEMORY_VRAM:
+// Video RAM. Stores almost everything related to video output, including
+// the patterns used for each tile and sprite, tilemaps for each
+// background. The exact format used depends on the current video mode of
+// the emulated SNES.
+//
+// SNES_MEMORY_OAM:
+// Object Attribute Memory. Stores the location, orientation and priority
+// of all the sprites the SNES displays.
+//
+// SNES_MEMORY_CGRAM:
+// Color Generator RAM. Contains the colour palettes used by tiles and
+// sprites. Each palette entry is stored in a 16-bit int, in the standard
+// XBGR1555 format.
+
+// snes_get_memory_data:
+//
+// Returns a pointer to the given non-volatile storage buffer.
+//
+// This requires that a cartridge is loaded.
+//
+// Parameters:
+//
+// id:
+// One of the SNES_MEMORY_* constants.
+//
+// Returns:
+//
+// A pointer to the memory buffer used for storing the given type of data.
+// The size of the buffer can be obtained from snes_get_memory_size().
+//
+// If NULL, the loaded cartridge does not store the given type of data.
+
+uint8_t* snes_get_memory_data(unsigned id);
+
+// snes_get_memory_size:
+//
+// Returns the size of the given non-volatile storage buffer.
+//
+// This requires that a cartridge is loaded.
+//
+// Parameters:
+//
+// id:
+// One of the SNES_MEMORY_* constants.
+//
+// Returns:
+//
+// The size of the memory buffer used for storing the given type of data.
+// A pointer to the buffer can be obtained from snes_get_memory_data().
+//
+// If 0, the loaded cartridge does not store the given type of data.
+
+unsigned snes_get_memory_size(unsigned id);
+
+////////////////////////////////////////////////////////////////////////////}}}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libsnes/link.T b/libsnes/link.T
new file mode 100644
index 00000000..432292c1
--- /dev/null
+++ b/libsnes/link.T
@@ -0,0 +1,4 @@
+{
+ global: snes_*;
+ local: *;
+};
diff --git a/loadzip.cpp b/loadzip.cpp
index 6ce8e7c8..1a92828a 100644
--- a/loadzip.cpp
+++ b/loadzip.cpp
@@ -185,10 +185,9 @@
#include "memmap.h"
-bool8 LoadZip (const char *zipname, int32 *TotalFileSize, int32 *headers, uint8 *buffer)
+bool8 LoadZip (const char *zipname, uint32 *TotalFileSize, uint8 *buffer)
{
*TotalFileSize = 0;
- *headers = 0;
unzFile file = unzOpen(zipname);
if (file == NULL)
@@ -196,7 +195,7 @@ bool8 LoadZip (const char *zipname, int32 *TotalFileSize, int32 *headers, uint8
// find largest file in zip file (under MAX_ROM_SIZE) or a file with extension .1
char filename[132];
- int filesize = 0;
+ uint32 filesize = 0;
int port = unzGoToFirstFile(file);
unz_file_info info;
@@ -212,7 +211,7 @@ bool8 LoadZip (const char *zipname, int32 *TotalFileSize, int32 *headers, uint8
continue;
}
- if ((int) info.uncompressed_size > filesize)
+ if (info.uncompressed_size > filesize)
{
strcpy(filename, name);
filesize = info.uncompressed_size;
@@ -259,7 +258,7 @@ bool8 LoadZip (const char *zipname, int32 *TotalFileSize, int32 *headers, uint8
{
assert(info.uncompressed_size <= CMemory::MAX_ROM_SIZE + 512);
- int FileSize = info.uncompressed_size;
+ uint32 FileSize = info.uncompressed_size;
int l = unzReadCurrentFile(file, ptr, FileSize);
if (unzCloseCurrentFile(file) == UNZ_CRCERROR)
@@ -274,7 +273,7 @@ bool8 LoadZip (const char *zipname, int32 *TotalFileSize, int32 *headers, uint8
return (FALSE);
}
- FileSize = (int) Memory.HeaderRemove((uint32) FileSize, *headers, ptr);
+ FileSize = Memory.HeaderRemove(FileSize, ptr);
ptr += FileSize;
*TotalFileSize += FileSize;
diff --git a/macosx/snes9x.xcodeproj/project.pbxproj b/macosx/snes9x.xcodeproj/project.pbxproj
index 176f07e6..37ab5032 100755
--- a/macosx/snes9x.xcodeproj/project.pbxproj
+++ b/macosx/snes9x.xcodeproj/project.pbxproj
@@ -36,7 +36,7 @@
CF047D54109D0E0600FD0754 /* pixform.h in Headers */ = {isa = PBXBuildFile; fileRef = EAE061C60526CCB900A80003 /* pixform.h */; };
CF047D55109D0E0600FD0754 /* port.h in Headers */ = {isa = PBXBuildFile; fileRef = EAE061C70526CCB900A80003 /* port.h */; };
CF047D56109D0E0600FD0754 /* ppu.h in Headers */ = {isa = PBXBuildFile; fileRef = EAE061C90526CCB900A80003 /* ppu.h */; };
- CF047D57109D0E0600FD0754 /* reader.h in Headers */ = {isa = PBXBuildFile; fileRef = EA809E9708F8D70D0072CDFB /* reader.h */; };
+ CF047D57109D0E0600FD0754 /* stream.h in Headers */ = {isa = PBXBuildFile; fileRef = EA809E9708F8D70D0072CDFB /* stream.h */; };
CF047D58109D0E0600FD0754 /* sa1.h in Headers */ = {isa = PBXBuildFile; fileRef = EAE061CC0526CCB900A80003 /* sa1.h */; };
CF047D59109D0E0600FD0754 /* sar.h in Headers */ = {isa = PBXBuildFile; fileRef = EAE061CE0526CCB900A80003 /* sar.h */; };
CF047D5A109D0E0600FD0754 /* screenshot.h in Headers */ = {isa = PBXBuildFile; fileRef = EAE061D00526CCB900A80003 /* screenshot.h */; };
@@ -145,7 +145,7 @@
CF047DC9109D0E0600FD0754 /* movie.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EA813E9A066F50A5004F99B5 /* movie.cpp */; };
CF047DCA109D0E0600FD0754 /* obc1.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EAE061C30526CCB900A80003 /* obc1.cpp */; };
CF047DCB109D0E0600FD0754 /* ppu.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EAE061C80526CCB900A80003 /* ppu.cpp */; };
- CF047DCC109D0E0600FD0754 /* reader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EA809E9F08F8D7530072CDFB /* reader.cpp */; };
+ CF047DCC109D0E0600FD0754 /* stream.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EA809E9F08F8D7530072CDFB /* stream.cpp */; };
CF047DCD109D0E0600FD0754 /* sa1.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EAE061CB0526CCB900A80003 /* sa1.cpp */; };
CF047DCE109D0E0600FD0754 /* sa1cpu.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EAE061CD0526CCB900A80003 /* sa1cpu.cpp */; };
CF047DCF109D0E0600FD0754 /* sdd1.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EAE061D10526CCB900A80003 /* sdd1.cpp */; };
@@ -237,7 +237,7 @@
CF0566A90CF98E7E00C7877C /* pixform.h in Headers */ = {isa = PBXBuildFile; fileRef = EAE061C60526CCB900A80003 /* pixform.h */; };
CF0566AA0CF98E7E00C7877C /* port.h in Headers */ = {isa = PBXBuildFile; fileRef = EAE061C70526CCB900A80003 /* port.h */; };
CF0566AB0CF98E7E00C7877C /* ppu.h in Headers */ = {isa = PBXBuildFile; fileRef = EAE061C90526CCB900A80003 /* ppu.h */; };
- CF0566AC0CF98E7E00C7877C /* reader.h in Headers */ = {isa = PBXBuildFile; fileRef = EA809E9708F8D70D0072CDFB /* reader.h */; };
+ CF0566AC0CF98E7E00C7877C /* stream.h in Headers */ = {isa = PBXBuildFile; fileRef = EA809E9708F8D70D0072CDFB /* stream.h */; };
CF0566AD0CF98E7E00C7877C /* sa1.h in Headers */ = {isa = PBXBuildFile; fileRef = EAE061CC0526CCB900A80003 /* sa1.h */; };
CF0566AE0CF98E7E00C7877C /* sar.h in Headers */ = {isa = PBXBuildFile; fileRef = EAE061CE0526CCB900A80003 /* sar.h */; };
CF0566AF0CF98E7E00C7877C /* screenshot.h in Headers */ = {isa = PBXBuildFile; fileRef = EAE061D00526CCB900A80003 /* screenshot.h */; };
@@ -333,7 +333,7 @@
CF0567180CF98E7E00C7877C /* movie.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EA813E9A066F50A5004F99B5 /* movie.cpp */; };
CF0567190CF98E7E00C7877C /* obc1.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EAE061C30526CCB900A80003 /* obc1.cpp */; };
CF05671A0CF98E7E00C7877C /* ppu.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EAE061C80526CCB900A80003 /* ppu.cpp */; };
- CF05671B0CF98E7E00C7877C /* reader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EA809E9F08F8D7530072CDFB /* reader.cpp */; };
+ CF05671B0CF98E7E00C7877C /* stream.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EA809E9F08F8D7530072CDFB /* stream.cpp */; };
CF05671C0CF98E7E00C7877C /* sa1.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EAE061CB0526CCB900A80003 /* sa1.cpp */; };
CF05671D0CF98E7E00C7877C /* sa1cpu.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EAE061CD0526CCB900A80003 /* sa1cpu.cpp */; };
CF05671E0CF98E7E00C7877C /* sdd1.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EAE061D10526CCB900A80003 /* sdd1.cpp */; };
@@ -424,7 +424,7 @@
CF2F462E1095EE72007D33FA /* pixform.h in Headers */ = {isa = PBXBuildFile; fileRef = EAE061C60526CCB900A80003 /* pixform.h */; };
CF2F462F1095EE72007D33FA /* port.h in Headers */ = {isa = PBXBuildFile; fileRef = EAE061C70526CCB900A80003 /* port.h */; };
CF2F46301095EE72007D33FA /* ppu.h in Headers */ = {isa = PBXBuildFile; fileRef = EAE061C90526CCB900A80003 /* ppu.h */; };
- CF2F46311095EE72007D33FA /* reader.h in Headers */ = {isa = PBXBuildFile; fileRef = EA809E9708F8D70D0072CDFB /* reader.h */; };
+ CF2F46311095EE72007D33FA /* stream.h in Headers */ = {isa = PBXBuildFile; fileRef = EA809E9708F8D70D0072CDFB /* stream.h */; };
CF2F46321095EE72007D33FA /* sa1.h in Headers */ = {isa = PBXBuildFile; fileRef = EAE061CC0526CCB900A80003 /* sa1.h */; };
CF2F46331095EE72007D33FA /* sar.h in Headers */ = {isa = PBXBuildFile; fileRef = EAE061CE0526CCB900A80003 /* sar.h */; };
CF2F46341095EE72007D33FA /* screenshot.h in Headers */ = {isa = PBXBuildFile; fileRef = EAE061D00526CCB900A80003 /* screenshot.h */; };
@@ -533,7 +533,7 @@
CF2F46A31095EE72007D33FA /* movie.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EA813E9A066F50A5004F99B5 /* movie.cpp */; };
CF2F46A41095EE72007D33FA /* obc1.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EAE061C30526CCB900A80003 /* obc1.cpp */; };
CF2F46A51095EE72007D33FA /* ppu.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EAE061C80526CCB900A80003 /* ppu.cpp */; };
- CF2F46A61095EE72007D33FA /* reader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EA809E9F08F8D7530072CDFB /* reader.cpp */; };
+ CF2F46A61095EE72007D33FA /* stream.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EA809E9F08F8D7530072CDFB /* stream.cpp */; };
CF2F46A71095EE72007D33FA /* sa1.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EAE061CB0526CCB900A80003 /* sa1.cpp */; };
CF2F46A81095EE72007D33FA /* sa1cpu.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EAE061CD0526CCB900A80003 /* sa1cpu.cpp */; };
CF2F46A91095EE72007D33FA /* sdd1.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EAE061D10526CCB900A80003 /* sdd1.cpp */; };
@@ -817,11 +817,11 @@
EA6E6C0E08F9734500CB3555 /* debug.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = debug.h; sourceTree = ""; };
EA809E9308F8D6C40072CDFB /* controls.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = controls.h; sourceTree = ""; };
EA809E9508F8D6E00072CDFB /* language.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = language.h; sourceTree = ""; };
- EA809E9708F8D70D0072CDFB /* reader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = reader.h; sourceTree = ""; };
+ EA809E9708F8D70D0072CDFB /* stream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = stream.h; sourceTree = ""; };
EA809E9908F8D7240072CDFB /* controls.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = controls.cpp; sourceTree = ""; };
EA809E9B08F8D72C0072CDFB /* crosshairs.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = crosshairs.cpp; sourceTree = ""; };
EA809E9D08F8D73A0072CDFB /* crosshairs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = crosshairs.h; sourceTree = ""; };
- EA809E9F08F8D7530072CDFB /* reader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = reader.cpp; sourceTree = ""; };
+ EA809E9F08F8D7530072CDFB /* stream.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = stream.cpp; sourceTree = ""; };
EA809F9D08F8F2190072CDFB /* mac-controls.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = "mac-controls.h"; sourceTree = ""; };
EA809FA108F8F2420072CDFB /* mac-controls.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = "mac-controls.cpp"; sourceTree = ""; };
EA813E86066F5076004F99B5 /* movie.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = movie.h; sourceTree = ""; };
@@ -1179,7 +1179,7 @@
EAE061C60526CCB900A80003 /* pixform.h */,
EAE061C70526CCB900A80003 /* port.h */,
EAE061C90526CCB900A80003 /* ppu.h */,
- EA809E9708F8D70D0072CDFB /* reader.h */,
+ EA809E9708F8D70D0072CDFB /* stream.h */,
EAE061CC0526CCB900A80003 /* sa1.h */,
EAE061CE0526CCB900A80003 /* sar.h */,
EAE061D00526CCB900A80003 /* screenshot.h */,
@@ -1222,7 +1222,7 @@
EA813E9A066F50A5004F99B5 /* movie.cpp */,
EAE061C30526CCB900A80003 /* obc1.cpp */,
EAE061C80526CCB900A80003 /* ppu.cpp */,
- EA809E9F08F8D7530072CDFB /* reader.cpp */,
+ EA809E9F08F8D7530072CDFB /* stream.cpp */,
EAE061CB0526CCB900A80003 /* sa1.cpp */,
EAE061CD0526CCB900A80003 /* sa1cpu.cpp */,
EAE061D10526CCB900A80003 /* sdd1.cpp */,
@@ -1384,7 +1384,7 @@
CF047D54109D0E0600FD0754 /* pixform.h in Headers */,
CF047D55109D0E0600FD0754 /* port.h in Headers */,
CF047D56109D0E0600FD0754 /* ppu.h in Headers */,
- CF047D57109D0E0600FD0754 /* reader.h in Headers */,
+ CF047D57109D0E0600FD0754 /* stream.h in Headers */,
CF047D58109D0E0600FD0754 /* sa1.h in Headers */,
CF047D59109D0E0600FD0754 /* sar.h in Headers */,
CF047D5A109D0E0600FD0754 /* screenshot.h in Headers */,
@@ -1503,7 +1503,7 @@
CF0566A90CF98E7E00C7877C /* pixform.h in Headers */,
CF0566AA0CF98E7E00C7877C /* port.h in Headers */,
CF0566AB0CF98E7E00C7877C /* ppu.h in Headers */,
- CF0566AC0CF98E7E00C7877C /* reader.h in Headers */,
+ CF0566AC0CF98E7E00C7877C /* stream.h in Headers */,
CF0566AD0CF98E7E00C7877C /* sa1.h in Headers */,
CF0566AE0CF98E7E00C7877C /* sar.h in Headers */,
CF0566AF0CF98E7E00C7877C /* screenshot.h in Headers */,
@@ -1622,7 +1622,7 @@
CF2F462E1095EE72007D33FA /* pixform.h in Headers */,
CF2F462F1095EE72007D33FA /* port.h in Headers */,
CF2F46301095EE72007D33FA /* ppu.h in Headers */,
- CF2F46311095EE72007D33FA /* reader.h in Headers */,
+ CF2F46311095EE72007D33FA /* stream.h in Headers */,
CF2F46321095EE72007D33FA /* sa1.h in Headers */,
CF2F46331095EE72007D33FA /* sar.h in Headers */,
CF2F46341095EE72007D33FA /* screenshot.h in Headers */,
@@ -1938,7 +1938,7 @@
CF047DC9109D0E0600FD0754 /* movie.cpp in Sources */,
CF047DCA109D0E0600FD0754 /* obc1.cpp in Sources */,
CF047DCB109D0E0600FD0754 /* ppu.cpp in Sources */,
- CF047DCC109D0E0600FD0754 /* reader.cpp in Sources */,
+ CF047DCC109D0E0600FD0754 /* stream.cpp in Sources */,
CF047DCD109D0E0600FD0754 /* sa1.cpp in Sources */,
CF047DCE109D0E0600FD0754 /* sa1cpu.cpp in Sources */,
CF047DCF109D0E0600FD0754 /* sdd1.cpp in Sources */,
@@ -2033,7 +2033,7 @@
CF0567180CF98E7E00C7877C /* movie.cpp in Sources */,
CF0567190CF98E7E00C7877C /* obc1.cpp in Sources */,
CF05671A0CF98E7E00C7877C /* ppu.cpp in Sources */,
- CF05671B0CF98E7E00C7877C /* reader.cpp in Sources */,
+ CF05671B0CF98E7E00C7877C /* stream.cpp in Sources */,
CF05671C0CF98E7E00C7877C /* sa1.cpp in Sources */,
CF05671D0CF98E7E00C7877C /* sa1cpu.cpp in Sources */,
CF05671E0CF98E7E00C7877C /* sdd1.cpp in Sources */,
@@ -2128,7 +2128,7 @@
CF2F46A31095EE72007D33FA /* movie.cpp in Sources */,
CF2F46A41095EE72007D33FA /* obc1.cpp in Sources */,
CF2F46A51095EE72007D33FA /* ppu.cpp in Sources */,
- CF2F46A61095EE72007D33FA /* reader.cpp in Sources */,
+ CF2F46A61095EE72007D33FA /* stream.cpp in Sources */,
CF2F46A71095EE72007D33FA /* sa1.cpp in Sources */,
CF2F46A81095EE72007D33FA /* sa1cpu.cpp in Sources */,
CF2F46A91095EE72007D33FA /* sdd1.cpp in Sources */,
diff --git a/memmap.cpp b/memmap.cpp
index bbbfae61..c2bbfed4 100644
--- a/memmap.cpp
+++ b/memmap.cpp
@@ -197,7 +197,6 @@
#include "controls.h"
#include "cheats.h"
#include "movie.h"
-#include "reader.h"
#include "display.h"
#ifndef SET_UI_COLOR
@@ -937,17 +936,17 @@ static void S9xDeinterleaveType1 (int, uint8 *);
static void S9xDeinterleaveType2 (int, uint8 *);
static void S9xDeinterleaveGD24 (int, uint8 *);
static bool8 allASCII (uint8 *, int);
-static bool8 is_SufamiTurbo_BIOS (uint8 *, uint32);
-static bool8 is_SufamiTurbo_Cart (uint8 *, uint32);
-static bool8 is_SameGame_BIOS (uint8 *, uint32);
-static bool8 is_SameGame_Add_On (uint8 *, uint32);
-static bool8 is_GNEXT_BIOS (uint8 *, uint32);
-static bool8 is_GNEXT_Add_On (uint8 *, uint32);
+static bool8 is_SufamiTurbo_BIOS (const uint8 *, uint32);
+static bool8 is_SufamiTurbo_Cart (const uint8 *, uint32);
+static bool8 is_SameGame_BIOS (const uint8 *, uint32);
+static bool8 is_SameGame_Add_On (const uint8 *, uint32);
+static bool8 is_GNEXT_BIOS (const uint8 *, uint32);
+static bool8 is_GNEXT_Add_On (const uint8 *, uint32);
static uint32 caCRC32 (uint8 *, uint32, uint32 crc32 = 0xffffffff);
static uint32 ReadUPSPointer (const uint8 *, unsigned &, unsigned);
-static bool8 ReadUPSPatch (Reader *, long, int32 &);
-static long ReadInt (Reader *, unsigned);
-static bool8 ReadIPSPatch (Reader *, long, int32 &);
+static bool8 ReadUPSPatch (Stream *, long, int32 &);
+static long ReadInt (Stream *, unsigned);
+static bool8 ReadIPSPatch (Stream *, long, int32 &);
#ifdef UNZIP_SUPPORT
static int unzFindExtension (unzFile &, const char *, bool restart = TRUE, bool print = TRUE);
#endif
@@ -1207,7 +1206,7 @@ static bool8 allASCII (uint8 *b, int size)
return (TRUE);
}
-static bool8 is_SufamiTurbo_BIOS (uint8 *data, uint32 size)
+static bool8 is_SufamiTurbo_BIOS (const uint8 *data, uint32 size)
{
if (size == 0x40000 &&
strncmp((char *) data, "BANDAI SFC-ADX", 14) == 0 && strncmp((char * ) (data + 0x10), "SFC-ADX BACKUP", 14) == 0)
@@ -1216,7 +1215,7 @@ static bool8 is_SufamiTurbo_BIOS (uint8 *data, uint32 size)
return (FALSE);
}
-static bool8 is_SufamiTurbo_Cart (uint8 *data, uint32 size)
+static bool8 is_SufamiTurbo_Cart (const uint8 *data, uint32 size)
{
if (size >= 0x80000 && size <= 0x100000 &&
strncmp((char *) data, "BANDAI SFC-ADX", 14) == 0 && strncmp((char * ) (data + 0x10), "SFC-ADX BACKUP", 14) != 0)
@@ -1225,7 +1224,7 @@ static bool8 is_SufamiTurbo_Cart (uint8 *data, uint32 size)
return (FALSE);
}
-static bool8 is_SameGame_BIOS (uint8 *data, uint32 size)
+static bool8 is_SameGame_BIOS (const uint8 *data, uint32 size)
{
if (size == 0x100000 && strncmp((char *) (data + 0xffc0), "Same Game Tsume Game", 20) == 0)
return (TRUE);
@@ -1233,7 +1232,7 @@ static bool8 is_SameGame_BIOS (uint8 *data, uint32 size)
return (FALSE);
}
-static bool8 is_SameGame_Add_On (uint8 *data, uint32 size)
+static bool8 is_SameGame_Add_On (const uint8 *data, uint32 size)
{
if (size == 0x80000)
return (TRUE);
@@ -1241,7 +1240,7 @@ static bool8 is_SameGame_Add_On (uint8 *data, uint32 size)
return (FALSE);
}
-static bool8 is_GNEXT_BIOS (uint8 *data, uint32 size)
+static bool8 is_GNEXT_BIOS (const uint8 *data, uint32 size)
{
if (size == 0x180000 && strncmp((char *) (data + 0x7fc0), "SFC SDGUNDAMGNEXT", 17) == 0)
return (TRUE);
@@ -1249,7 +1248,7 @@ static bool8 is_GNEXT_BIOS (uint8 *data, uint32 size)
return (FALSE);
}
-static bool8 is_GNEXT_Add_On (uint8 *data, uint32 size)
+static bool8 is_GNEXT_Add_On (const uint8 *data, uint32 size)
{
if (size == 0x80000)
return (TRUE);
@@ -1352,7 +1351,7 @@ int CMemory::ScoreLoROM (bool8 skip_header, int32 romoff)
return (score);
}
-uint32 CMemory::HeaderRemove (uint32 size, int32 &headerCount, uint8 *buf)
+uint32 CMemory::HeaderRemove (uint32 size, uint8 *buf)
{
uint32 calc_size = (size / 0x2000) * 0x2000;
@@ -1373,20 +1372,20 @@ uint32 CMemory::HeaderRemove (uint32 size, int32 &headerCount, uint8 *buf)
}
memmove(buf, buf + 512, calc_size);
- headerCount++;
+ HeaderCount++;
size -= 512;
}
return (size);
}
-uint32 CMemory::FileLoader (uint8 *buffer, const char *filename, int32 maxsize)
+uint32 CMemory::FileLoader (uint8 *buffer, const char *filename, uint32 maxsize)
{
// <- ROM size without header
// ** Memory.HeaderCount
// ** Memory.ROMFilename
- int32 totalSize = 0;
+ uint32 totalSize = 0;
char fname[PATH_MAX + 1];
char drive[_MAX_DRIVE + 1], dir[_MAX_DIR + 1], name[_MAX_FNAME + 1], exts[_MAX_EXT + 1];
char *ext;
@@ -1415,7 +1414,7 @@ uint32 CMemory::FileLoader (uint8 *buffer, const char *filename, int32 maxsize)
case FILE_ZIP:
{
#ifdef UNZIP_SUPPORT
- if (!LoadZip(fname, &totalSize, &HeaderCount, buffer))
+ if (!LoadZip(fname, &totalSize, buffer))
{
S9xMessage(S9X_ERROR, S9X_ROM_INFO, "Invalid Zip archive.");
return (0);
@@ -1439,7 +1438,7 @@ uint32 CMemory::FileLoader (uint8 *buffer, const char *filename, int32 maxsize)
return (0);
}
- totalSize = HeaderRemove(size, HeaderCount, buffer);
+ totalSize = HeaderRemove(size, buffer);
strcpy(ROMFilename, fname);
#else
@@ -1468,7 +1467,7 @@ uint32 CMemory::FileLoader (uint8 *buffer, const char *filename, int32 maxsize)
size = READ_STREAM(ptr, maxsize + 0x200 - (ptr - buffer), fp);
CLOSE_STREAM(fp);
- size = HeaderRemove(size, HeaderCount, ptr);
+ size = HeaderRemove(size, ptr);
totalSize += size;
ptr += size;
@@ -1511,32 +1510,56 @@ uint32 CMemory::FileLoader (uint8 *buffer, const char *filename, int32 maxsize)
return ((uint32) totalSize);
}
+bool8 CMemory::LoadROMMem (const uint8 *source, uint32 sourceSize)
+{
+ if(!source || sourceSize > MAX_ROM_SIZE)
+ return FALSE;
+
+ strcpy(ROMFilename,"MemoryROM");
+
+ do
+ {
+ memset(ROM,0, MAX_ROM_SIZE);
+ memset(&Multi, 0,sizeof(Multi));
+ memcpy(ROM,source,sourceSize);
+ }
+ while(!LoadROMInt(sourceSize));
+
+ return TRUE;
+}
+
bool8 CMemory::LoadROM (const char *filename)
{
- int retry_count = 0;
+ if(!filename || !*filename)
+ return FALSE;
- if (!filename || !*filename)
- return (FALSE);
+ int32 totalFileSize;
- memset(ROM, 0, MAX_ROM_SIZE);
- memset(&Multi, 0, sizeof(Multi));
-
-again:
+ do
+ {
+ memset(ROM,0, MAX_ROM_SIZE);
+ memset(&Multi, 0,sizeof(Multi));
+ totalFileSize = FileLoader(ROM, filename, MAX_ROM_SIZE);
+
+ if (!totalFileSize)
+ return (FALSE);
+
+ if (!Settings.NoPatch)
+ CheckForAnyPatch(filename, HeaderCount != 0, totalFileSize);
+ }
+ while(!LoadROMInt(totalFileSize));
+
+ return TRUE;
+}
+
+bool8 CMemory::LoadROMInt (int32 ROMfillSize)
+{
Settings.DisplayColor = BUILD_PIXEL(31, 31, 31);
SET_UI_COLOR(255, 255, 255);
CalculatedSize = 0;
ExtendedFormat = NOPE;
- int32 totalFileSize;
-
- totalFileSize = FileLoader(ROM, filename, MAX_ROM_SIZE);
- if (!totalFileSize)
- return (FALSE);
-
- if (!Settings.NoPatch)
- CheckForAnyPatch(filename, HeaderCount != 0, totalFileSize);
-
int hi_score, lo_score;
hi_score = ScoreHiROM(FALSE);
@@ -1546,15 +1569,15 @@ again:
((hi_score > lo_score && ScoreHiROM(TRUE) > hi_score) ||
(hi_score <= lo_score && ScoreLoROM(TRUE) > lo_score)))
{
- memmove(ROM, ROM + 512, totalFileSize - 512);
- totalFileSize -= 512;
+ memmove(ROM, ROM + 512, ROMfillSize - 512);
+ ROMfillSize -= 512;
S9xMessage(S9X_INFO, S9X_HEADER_WARNING, "Try 'force no-header' option if the game doesn't work");
// modifying ROM, so we need to rescore
hi_score = ScoreHiROM(FALSE);
lo_score = ScoreLoROM(FALSE);
}
- CalculatedSize = (totalFileSize / 0x2000) * 0x2000;
+ CalculatedSize = (ROMfillSize / 0x2000) * 0x2000;
if (CalculatedSize > 0x400000 &&
(ROM[0x7fd5] + (ROM[0x7fd6] << 8)) != 0x3423 && // exclude SA-1
@@ -1571,7 +1594,7 @@ again:
((ROM[0xfffc] + (ROM[0xfffd] << 8)) < 0x8000))
{
if (!Settings.ForceInterleaved && !Settings.ForceNotInterleaved)
- S9xDeinterleaveType1(totalFileSize, ROM);
+ S9xDeinterleaveType1(ROMfillSize, ROM);
}
// CalculatedSize is now set, so rescore
@@ -1699,14 +1722,10 @@ again:
if ((HiROM && (lo_score >= hi_score || hi_score < 0)) ||
(LoROM && (hi_score > lo_score || lo_score < 0)))
{
- if (retry_count == 0)
- {
- S9xMessage(S9X_INFO, S9X_ROM_CONFUSING_FORMAT_INFO, "ROM lied about its type! Trying again.");
- Settings.ForceNotInterleaved = TRUE;
- Settings.ForceInterleaved = FALSE;
- retry_count++;
- goto again;
- }
+ S9xMessage(S9X_INFO, S9X_ROM_CONFUSING_FORMAT_INFO, "ROM lied about its type! Trying again.");
+ Settings.ForceNotInterleaved = TRUE;
+ Settings.ForceInterleaved = FALSE;
+ return (FALSE);
}
}
@@ -1726,9 +1745,9 @@ again:
}
}
- if (strncmp(LastRomFilename, filename, PATH_MAX + 1))
+ if (strncmp(LastRomFilename, ROMFilename, PATH_MAX + 1))
{
- strncpy(LastRomFilename, filename, PATH_MAX + 1);
+ strncpy(LastRomFilename, ROMFilename, PATH_MAX + 1);
LastRomFilename[PATH_MAX] = 0;
}
@@ -1747,60 +1766,144 @@ again:
return (TRUE);
}
+bool8 CMemory::LoadMultiCartMem (const uint8 *sourceA, uint32 sourceASize,
+ const uint8 *sourceB, uint32 sourceBSize,
+ const uint8 *bios, uint32 biosSize)
+{
+ uint32 offset = 0;
+ ZeroMemory(ROM, MAX_ROM_SIZE);
+ ZeroMemory(&Multi, sizeof(Multi));
+
+ if(bios) {
+ if(!is_SufamiTurbo_BIOS(bios,biosSize))
+ return FALSE;
+
+ memcpy(ROM,bios,biosSize);
+ offset+=biosSize;
+ }
+
+ if(sourceA) {
+ memcpy(ROM + offset,sourceA,sourceASize);
+ Multi.cartOffsetA = offset;
+ Multi.cartSizeA = sourceASize;
+ offset += sourceASize;
+ strcpy(Multi.fileNameA,"MemCartA");
+ }
+
+ if(sourceB) {
+ memcpy(ROM + offset,sourceB,sourceBSize);
+ Multi.cartOffsetB = offset;
+ Multi.cartSizeB = sourceBSize;
+ offset += sourceBSize;
+ strcpy(Multi.fileNameB,"MemCartB");
+ }
+
+ return LoadMultiCartInt();
+}
+
bool8 CMemory::LoadMultiCart (const char *cartA, const char *cartB)
{
- bool8 r = TRUE;
-
- memset(ROM, 0, MAX_ROM_SIZE);
- memset(&Multi, 0, sizeof(Multi));
+ ZeroMemory(ROM, MAX_ROM_SIZE);
+ ZeroMemory(&Multi, sizeof(Multi));
Settings.DisplayColor = BUILD_PIXEL(31, 31, 31);
SET_UI_COLOR(255, 255, 255);
- CalculatedSize = 0;
- ExtendedFormat = NOPE;
+ if (cartB && cartB[0])
+ Multi.cartSizeB = FileLoader(ROM, cartB, MAX_ROM_SIZE);
+
+ if (Multi.cartSizeB) {
+ strcpy(Multi.fileNameB, cartB);
+
+ if(!Settings.NoPatch)
+ CheckForAnyPatch(cartB, HeaderCount != 0, Multi.cartSizeB);
+
+ Multi.cartOffsetB = 0x400000;
+ memcpy(ROM + Multi.cartOffsetB,ROM,Multi.cartSizeB);
+ }
if (cartA && cartA[0])
Multi.cartSizeA = FileLoader(ROM, cartA, MAX_ROM_SIZE);
- if (Multi.cartSizeA == 0)
- {
- if (cartB && cartB[0])
- Multi.cartSizeB = FileLoader(ROM, cartB, MAX_ROM_SIZE);
- }
+ if (Multi.cartSizeA) {
+ strcpy(Multi.fileNameA, cartA);
+
+ if(!Settings.NoPatch)
+ CheckForAnyPatch(cartA, HeaderCount != 0, Multi.cartSizeA);
+ }
+
+ return LoadMultiCartInt();
+}
+
+bool8 CMemory::LoadMultiCartInt ()
+{
+ bool8 r = TRUE;
+
+ CalculatedSize = 0;
+ ExtendedFormat = NOPE;
if (Multi.cartSizeA)
{
- if (is_SufamiTurbo_Cart(ROM, Multi.cartSizeA))
+ if (is_SufamiTurbo_Cart(ROM + Multi.cartOffsetA, Multi.cartSizeA))
Multi.cartType = 4;
else
- if (is_SameGame_BIOS(ROM, Multi.cartSizeA))
+ if (is_SameGame_BIOS(ROM + Multi.cartOffsetA, Multi.cartSizeA))
Multi.cartType = 3;
else
- if (is_GNEXT_BIOS(ROM, Multi.cartSizeA))
+ if (is_GNEXT_BIOS(ROM + Multi.cartOffsetA, Multi.cartSizeA))
Multi.cartType = 5;
}
else
if (Multi.cartSizeB)
{
- if (is_SufamiTurbo_Cart(ROM, Multi.cartSizeB))
+ if (is_SufamiTurbo_Cart(ROM + Multi.cartOffsetB, Multi.cartSizeB))
Multi.cartType = 4;
}
else
Multi.cartType = 4; // assuming BIOS only
+
+ if(Multi.cartType == 4 && Multi.cartOffsetA == 0) { // try to load bios from file
+ Multi.cartOffsetA = 0x40000;
+ if(Multi.cartSizeA)
+ memmove(ROM + Multi.cartOffsetA,ROM,Multi.cartOffsetB - Multi.cartOffsetA);
+ else // clear cart A so the bios can detect that it's not present
+ memset(ROM,0,Multi.cartOffsetB);
+
+ FILE *fp;
+ size_t size;
+ char path[PATH_MAX + 1];
+
+ strcpy(path, S9xGetDirectory(BIOS_DIR));
+ strcat(path, SLASH_STR);
+ strcat(path, "STBIOS.bin");
+
+ fp = fopen(path, "rb");
+ if (fp)
+ {
+ size = fread((void *) ROM, 1, 0x40000, fp);
+ fclose(fp);
+ if (!is_SufamiTurbo_BIOS(ROM, size))
+ return (FALSE);
+ }
+ else
+ return (FALSE);
+
+ strcpy(ROMFilename, path);
+ }
+
switch (Multi.cartType)
{
case 4:
- r = LoadSufamiTurbo(cartA, cartB);
+ r = LoadSufamiTurbo();
break;
case 3:
- r = LoadSameGame(cartA, cartB);
+ r = LoadSameGame();
break;
case 5:
- r = LoadGNEXT(cartA, cartB);
+ r = LoadGNEXT();
break;
default:
@@ -1813,7 +1916,13 @@ bool8 CMemory::LoadMultiCart (const char *cartA, const char *cartB)
return (FALSE);
}
- memset(&SNESGameFixes, 0, sizeof(SNESGameFixes));
+ if (Multi.cartSizeA)
+ strcpy(ROMFilename, Multi.fileNameA);
+ else
+ if (Multi.cartSizeB)
+ strcpy(ROMFilename, Multi.fileNameB);
+
+ ZeroMemory(&SNESGameFixes, sizeof(SNESGameFixes));
SNESGameFixes.SRAMInitialValue = 0x60;
S9xLoadCheatFile(S9xGetFilename(".cht", CHEAT_DIR));
@@ -1828,10 +1937,8 @@ bool8 CMemory::LoadMultiCart (const char *cartA, const char *cartB)
return (TRUE);
}
-bool8 CMemory::LoadSufamiTurbo (const char *cartA, const char *cartB)
+bool8 CMemory::LoadSufamiTurbo ()
{
- Multi.cartOffsetA = 0x100000;
- Multi.cartOffsetB = 0x200000;
Multi.sramA = SRAM;
Multi.sramB = SRAM + 0x10000;
@@ -1839,65 +1946,20 @@ bool8 CMemory::LoadSufamiTurbo (const char *cartA, const char *cartB)
{
Multi.sramSizeA = 4; // ROM[0x37]?
Multi.sramMaskA = Multi.sramSizeA ? ((1 << (Multi.sramSizeA + 3)) * 128 - 1) : 0;
-
- if (!Settings.NoPatch)
- CheckForAnyPatch(cartA, HeaderCount != 0, Multi.cartSizeA);
-
- strcpy(Multi.fileNameA, cartA);
- memcpy(ROM + Multi.cartOffsetA, ROM, Multi.cartSizeA);
}
- if (Multi.cartSizeA && !Multi.cartSizeB)
+ if (Multi.cartSizeB)
{
- if (cartB && cartB[0])
- Multi.cartSizeB = FileLoader(ROM, cartB, MAX_ROM_SIZE);
-
- if (Multi.cartSizeB)
- {
- if (!is_SufamiTurbo_Cart(ROM, Multi.cartSizeB))
- Multi.cartSizeB = 0;
- }
+ if (!is_SufamiTurbo_Cart(ROM + Multi.cartOffsetB, Multi.cartSizeB))
+ Multi.cartSizeB = 0;
}
if (Multi.cartSizeB)
{
Multi.sramSizeB = 4; // ROM[0x37]?
Multi.sramMaskB = Multi.sramSizeB ? ((1 << (Multi.sramSizeB + 3)) * 128 - 1) : 0;
-
- if (!Settings.NoPatch)
- CheckForAnyPatch(cartB, HeaderCount != 0, Multi.cartSizeB);
-
- strcpy(Multi.fileNameB, cartB);
- memcpy(ROM + Multi.cartOffsetB, ROM, Multi.cartSizeB);
}
- FILE *fp;
- size_t size;
- char path[PATH_MAX + 1];
-
- strcpy(path, S9xGetDirectory(BIOS_DIR));
- strcat(path, SLASH_STR);
- strcat(path, "STBIOS.bin");
-
- fp = fopen(path, "rb");
- if (fp)
- {
- size = fread((void *) ROM, 1, 0x40000, fp);
- fclose(fp);
- if (!is_SufamiTurbo_BIOS(ROM, size))
- return (FALSE);
- }
- else
- return (FALSE);
-
- if (Multi.cartSizeA)
- strcpy(ROMFilename, Multi.fileNameA);
- else
- if (Multi.cartSizeB)
- strcpy(ROMFilename, Multi.fileNameB);
- else
- strcpy(ROMFilename, path);
-
LoROM = TRUE;
HiROM = FALSE;
CalculatedSize = 0x40000;
@@ -1905,10 +1967,8 @@ bool8 CMemory::LoadSufamiTurbo (const char *cartA, const char *cartB)
return (TRUE);
}
-bool8 CMemory::LoadSameGame (const char *cartA, const char *cartB)
+bool8 CMemory::LoadSameGame ()
{
- Multi.cartOffsetA = 0;
- Multi.cartOffsetB = 0x200000;
Multi.sramA = SRAM;
Multi.sramB = NULL;
@@ -1917,24 +1977,12 @@ bool8 CMemory::LoadSameGame (const char *cartA, const char *cartB)
Multi.sramSizeB = 0;
Multi.sramMaskB = 0;
- if (!Settings.NoPatch)
- CheckForAnyPatch(cartA, HeaderCount != 0, Multi.cartSizeA);
-
- strcpy(Multi.fileNameA, cartA);
-
- if (cartB && cartB[0])
- Multi.cartSizeB = FileLoader(ROM + Multi.cartOffsetB, cartB, MAX_ROM_SIZE - Multi.cartOffsetB);
-
if (Multi.cartSizeB)
{
if (!is_SameGame_Add_On(ROM + Multi.cartOffsetB, Multi.cartSizeB))
Multi.cartSizeB = 0;
- else
- strcpy(Multi.fileNameB, cartB);
}
- strcpy(ROMFilename, Multi.fileNameA);
-
LoROM = FALSE;
HiROM = TRUE;
CalculatedSize = Multi.cartSizeA;
@@ -1942,10 +1990,8 @@ bool8 CMemory::LoadSameGame (const char *cartA, const char *cartB)
return (TRUE);
}
-bool8 CMemory::LoadGNEXT (const char *cartA, const char *cartB)
+bool8 CMemory::LoadGNEXT ()
{
- Multi.cartOffsetA = 0;
- Multi.cartOffsetB = 0x400000;
Multi.sramA = SRAM;
Multi.sramB = NULL;
@@ -1954,24 +2000,12 @@ bool8 CMemory::LoadGNEXT (const char *cartA, const char *cartB)
Multi.sramSizeB = 0;
Multi.sramMaskB = 0;
- if (!Settings.NoPatch)
- CheckForAnyPatch(cartA, HeaderCount != 0, Multi.cartSizeA);
-
- strcpy(Multi.fileNameA, cartA);
-
- if (cartB && cartB[0])
- Multi.cartSizeB = FileLoader(ROM + Multi.cartOffsetB, cartB, MAX_ROM_SIZE - Multi.cartOffsetB);
-
if (Multi.cartSizeB)
{
if (!is_GNEXT_Add_On(ROM + Multi.cartOffsetB, Multi.cartSizeB))
Multi.cartSizeB = 0;
- else
- strcpy(Multi.fileNameB, cartB);
}
- strcpy(ROMFilename, Multi.fileNameA);
-
LoROM = TRUE;
HiROM = FALSE;
CalculatedSize = Multi.cartSizeA;
@@ -3762,7 +3796,7 @@ static uint32 XPSdecode (const uint8 *data, unsigned &addr, unsigned size)
//no-header patching errors that result in IPS patches having a 50/50 chance of
//being applied correctly.
-static bool8 ReadUPSPatch (Reader *r, long, int32 &rom_size)
+static bool8 ReadUPSPatch (Stream *r, long, int32 &rom_size)
{
//Reader lacks size() and rewind(), so we need to read in the file to get its size
uint8 *data = new uint8[8 * 1024 * 1024]; //allocate a lot of memory, better safe than sorry ...
@@ -3844,7 +3878,7 @@ static bool8 ReadUPSPatch (Reader *r, long, int32 &rom_size)
//
// logic taken from http://byuu.org/programming/bps and the accompanying source
//
-static bool8 ReadBPSPatch (Reader *r, long, int32 &rom_size)
+static bool8 ReadBPSPatch (Stream *r, long, int32 &rom_size)
{
uint8 *data = new uint8[8 * 1024 * 1024]; //allocate a lot of memory, better safe than sorry ...
uint32 size = 0;
@@ -3935,7 +3969,7 @@ static bool8 ReadBPSPatch (Reader *r, long, int32 &rom_size)
}
}
-static long ReadInt (Reader *r, unsigned nbytes)
+static long ReadInt (Stream *r, unsigned nbytes)
{
long v = 0;
@@ -3950,7 +3984,7 @@ static long ReadInt (Reader *r, unsigned nbytes)
return (v);
}
-static bool8 ReadIPSPatch (Reader *r, long offset, int32 &rom_size)
+static bool8 ReadIPSPatch (Stream *r, long offset, int32 &rom_size)
{
const int32 IPS_EOF = 0x00454F46l;
int32 ofs;
@@ -4069,7 +4103,7 @@ void CMemory::CheckForAnyPatch (const char *rom_filename, bool8 header, int32 &r
if (Settings.NoPatch)
return;
- STREAM patch_file = NULL;
+ FSTREAM patch_file = NULL;
uint32 i;
long offset = header ? 512 : 0;
int ret;
@@ -4082,12 +4116,12 @@ void CMemory::CheckForAnyPatch (const char *rom_filename, bool8 header, int32 &r
// BPS
_makepath(fname, drive, dir, name, "bps");
- if ((patch_file = OPEN_STREAM(fname, "rb")) != NULL)
+ if ((patch_file = OPEN_FSTREAM(fname, "rb")) != NULL)
{
printf("Using BPS patch %s", fname);
- ret = ReadBPSPatch(new fReader(patch_file), 0, rom_size);
- CLOSE_STREAM(patch_file);
+ ret = ReadBPSPatch(new fStream(patch_file), 0, rom_size);
+ CLOSE_FSTREAM(patch_file);
if (ret)
{
@@ -4109,7 +4143,7 @@ void CMemory::CheckForAnyPatch (const char *rom_filename, bool8 header, int32 &r
{
printf(" in %s", rom_filename);
- ret = ReadBPSPatch(new unzReader(file), offset, rom_size);
+ ret = ReadBPSPatch(new unzStream(file), offset, rom_size);
unzCloseCurrentFile(file);
if (ret)
@@ -4123,12 +4157,12 @@ void CMemory::CheckForAnyPatch (const char *rom_filename, bool8 header, int32 &r
n = S9xGetFilename(".bps", IPS_DIR);
- if ((patch_file = OPEN_STREAM(n, "rb")) != NULL)
+ if ((patch_file = OPEN_FSTREAM(n, "rb")) != NULL)
{
printf("Using BPS patch %s", n);
- ret = ReadBPSPatch(new fReader(patch_file), 0, rom_size);
- CLOSE_STREAM(patch_file);
+ ret = ReadBPSPatch(new fStream(patch_file), 0, rom_size);
+ CLOSE_FSTREAM(patch_file);
if (ret)
{
@@ -4143,12 +4177,12 @@ void CMemory::CheckForAnyPatch (const char *rom_filename, bool8 header, int32 &r
_makepath(fname, drive, dir, name, "ups");
- if ((patch_file = OPEN_STREAM(fname, "rb")) != NULL)
+ if ((patch_file = OPEN_FSTREAM(fname, "rb")) != NULL)
{
printf("Using UPS patch %s", fname);
- ret = ReadUPSPatch(new fReader(patch_file), 0, rom_size);
- CLOSE_STREAM(patch_file);
+ ret = ReadUPSPatch(new fStream(patch_file), 0, rom_size);
+ CLOSE_FSTREAM(patch_file);
if (ret)
{
@@ -4170,7 +4204,7 @@ void CMemory::CheckForAnyPatch (const char *rom_filename, bool8 header, int32 &r
{
printf(" in %s", rom_filename);
- ret = ReadUPSPatch(new unzReader(file), offset, rom_size);
+ ret = ReadUPSPatch(new unzStream(file), offset, rom_size);
unzCloseCurrentFile(file);
if (ret)
@@ -4184,12 +4218,12 @@ void CMemory::CheckForAnyPatch (const char *rom_filename, bool8 header, int32 &r
n = S9xGetFilename(".ups", IPS_DIR);
- if ((patch_file = OPEN_STREAM(n, "rb")) != NULL)
+ if ((patch_file = OPEN_FSTREAM(n, "rb")) != NULL)
{
printf("Using UPS patch %s", n);
- ret = ReadUPSPatch(new fReader(patch_file), 0, rom_size);
- CLOSE_STREAM(patch_file);
+ ret = ReadUPSPatch(new fStream(patch_file), 0, rom_size);
+ CLOSE_FSTREAM(patch_file);
if (ret)
{
@@ -4204,12 +4238,12 @@ void CMemory::CheckForAnyPatch (const char *rom_filename, bool8 header, int32 &r
_makepath(fname, drive, dir, name, "ips");
- if ((patch_file = OPEN_STREAM(fname, "rb")) != NULL)
+ if ((patch_file = OPEN_FSTREAM(fname, "rb")) != NULL)
{
printf("Using IPS patch %s", fname);
- ret = ReadIPSPatch(new fReader(patch_file), offset, rom_size);
- CLOSE_STREAM(patch_file);
+ ret = ReadIPSPatch(new fStream(patch_file), offset, rom_size);
+ CLOSE_FSTREAM(patch_file);
if (ret)
{
@@ -4230,13 +4264,13 @@ void CMemory::CheckForAnyPatch (const char *rom_filename, bool8 header, int32 &r
snprintf(ips, 8, "%03d.ips", i);
_makepath(fname, drive, dir, name, ips);
- if (!(patch_file = OPEN_STREAM(fname, "rb")))
+ if (!(patch_file = OPEN_FSTREAM(fname, "rb")))
break;
printf("Using IPS patch %s", fname);
- ret = ReadIPSPatch(new fReader(patch_file), offset, rom_size);
- CLOSE_STREAM(patch_file);
+ ret = ReadIPSPatch(new fStream(patch_file), offset, rom_size);
+ CLOSE_FSTREAM(patch_file);
if (ret)
{
@@ -4266,13 +4300,13 @@ void CMemory::CheckForAnyPatch (const char *rom_filename, bool8 header, int32 &r
break;
_makepath(fname, drive, dir, name, ips);
- if (!(patch_file = OPEN_STREAM(fname, "rb")))
+ if (!(patch_file = OPEN_FSTREAM(fname, "rb")))
break;
printf("Using IPS patch %s", fname);
- ret = ReadIPSPatch(new fReader(patch_file), offset, rom_size);
- CLOSE_STREAM(patch_file);
+ ret = ReadIPSPatch(new fStream(patch_file), offset, rom_size);
+ CLOSE_FSTREAM(patch_file);
if (ret)
{
@@ -4300,13 +4334,13 @@ void CMemory::CheckForAnyPatch (const char *rom_filename, bool8 header, int32 &r
snprintf(ips, 4, "ip%d", i);
_makepath(fname, drive, dir, name, ips);
- if (!(patch_file = OPEN_STREAM(fname, "rb")))
+ if (!(patch_file = OPEN_FSTREAM(fname, "rb")))
break;
printf("Using IPS patch %s", fname);
- ret = ReadIPSPatch(new fReader(patch_file), offset, rom_size);
- CLOSE_STREAM(patch_file);
+ ret = ReadIPSPatch(new fStream(patch_file), offset, rom_size);
+ CLOSE_FSTREAM(patch_file);
if (ret)
{
@@ -4335,7 +4369,7 @@ void CMemory::CheckForAnyPatch (const char *rom_filename, bool8 header, int32 &r
{
printf(" in %s", rom_filename);
- ret = ReadIPSPatch(new unzReader(file), offset, rom_size);
+ ret = ReadIPSPatch(new unzStream(file), offset, rom_size);
unzCloseCurrentFile(file);
if (ret)
@@ -4362,7 +4396,7 @@ void CMemory::CheckForAnyPatch (const char *rom_filename, bool8 header, int32 &r
printf(" in %s", rom_filename);
- ret = ReadIPSPatch(new unzReader(file), offset, rom_size);
+ ret = ReadIPSPatch(new unzStream(file), offset, rom_size);
unzCloseCurrentFile(file);
if (ret)
@@ -4396,7 +4430,7 @@ void CMemory::CheckForAnyPatch (const char *rom_filename, bool8 header, int32 &r
printf(" in %s", rom_filename);
- ret = ReadIPSPatch(new unzReader(file), offset, rom_size);
+ ret = ReadIPSPatch(new unzStream(file), offset, rom_size);
unzCloseCurrentFile(file);
if (ret)
@@ -4428,7 +4462,7 @@ void CMemory::CheckForAnyPatch (const char *rom_filename, bool8 header, int32 &r
printf(" in %s", rom_filename);
- ret = ReadIPSPatch(new unzReader(file), offset, rom_size);
+ ret = ReadIPSPatch(new unzStream(file), offset, rom_size);
unzCloseCurrentFile(file);
if (ret)
@@ -4457,12 +4491,12 @@ void CMemory::CheckForAnyPatch (const char *rom_filename, bool8 header, int32 &r
n = S9xGetFilename(".ips", IPS_DIR);
- if ((patch_file = OPEN_STREAM(n, "rb")) != NULL)
+ if ((patch_file = OPEN_FSTREAM(n, "rb")) != NULL)
{
printf("Using IPS patch %s", n);
- ret = ReadIPSPatch(new fReader(patch_file), offset, rom_size);
- CLOSE_STREAM(patch_file);
+ ret = ReadIPSPatch(new fStream(patch_file), offset, rom_size);
+ CLOSE_FSTREAM(patch_file);
if (ret)
{
@@ -4483,13 +4517,13 @@ void CMemory::CheckForAnyPatch (const char *rom_filename, bool8 header, int32 &r
snprintf(ips, 9, ".%03d.ips", i);
n = S9xGetFilename(ips, IPS_DIR);
- if (!(patch_file = OPEN_STREAM(n, "rb")))
+ if (!(patch_file = OPEN_FSTREAM(n, "rb")))
break;
printf("Using IPS patch %s", n);
- ret = ReadIPSPatch(new fReader(patch_file), offset, rom_size);
- CLOSE_STREAM(patch_file);
+ ret = ReadIPSPatch(new fStream(patch_file), offset, rom_size);
+ CLOSE_FSTREAM(patch_file);
if (ret)
{
@@ -4519,13 +4553,13 @@ void CMemory::CheckForAnyPatch (const char *rom_filename, bool8 header, int32 &r
break;
n = S9xGetFilename(ips, IPS_DIR);
- if (!(patch_file = OPEN_STREAM(n, "rb")))
+ if (!(patch_file = OPEN_FSTREAM(n, "rb")))
break;
printf("Using IPS patch %s", n);
- ret = ReadIPSPatch(new fReader(patch_file), offset, rom_size);
- CLOSE_STREAM(patch_file);
+ ret = ReadIPSPatch(new fStream(patch_file), offset, rom_size);
+ CLOSE_FSTREAM(patch_file);
if (ret)
{
@@ -4553,13 +4587,13 @@ void CMemory::CheckForAnyPatch (const char *rom_filename, bool8 header, int32 &r
snprintf(ips, 5, ".ip%d", i);
n = S9xGetFilename(ips, IPS_DIR);
- if (!(patch_file = OPEN_STREAM(n, "rb")))
+ if (!(patch_file = OPEN_FSTREAM(n, "rb")))
break;
printf("Using IPS patch %s", n);
- ret = ReadIPSPatch(new fReader(patch_file), offset, rom_size);
- CLOSE_STREAM(patch_file);
+ ret = ReadIPSPatch(new fStream(patch_file), offset, rom_size);
+ CLOSE_FSTREAM(patch_file);
if (ret)
{
diff --git a/memmap.h b/memmap.h
index 4991ae83..0f943542 100644
--- a/memmap.h
+++ b/memmap.h
@@ -271,13 +271,18 @@ struct CMemory
int ScoreHiROM (bool8, int32 romoff = 0);
int ScoreLoROM (bool8, int32 romoff = 0);
- uint32 HeaderRemove (uint32, int32 &, uint8 *);
- uint32 FileLoader (uint8 *, const char *, int32);
+ uint32 HeaderRemove (uint32, uint8 *);
+ uint32 FileLoader (uint8 *, const char *, uint32);
+ uint32 MemLoader (uint8 *, const char*, uint32);
+ bool8 LoadROMMem (const uint8 *, uint32);
bool8 LoadROM (const char *);
+ bool8 LoadROMInt (int32);
+ bool8 LoadMultiCartMem (const uint8 *, uint32, const uint8 *, uint32, const uint8 *, uint32);
bool8 LoadMultiCart (const char *, const char *);
- bool8 LoadSufamiTurbo (const char *, const char *);
- bool8 LoadSameGame (const char *, const char *);
- bool8 LoadGNEXT (const char *, const char *);
+ bool8 LoadMultiCartInt ();
+ bool8 LoadSufamiTurbo ();
+ bool8 LoadSameGame ();
+ bool8 LoadGNEXT ();
bool8 LoadSRAM (const char *);
bool8 SaveSRAM (const char *);
void ClearSRAM (bool8 onlyNonSavedSRAM = 0);
@@ -361,7 +366,7 @@ extern CMemory Memory;
extern SMulti Multi;
void S9xAutoSaveSRAM (void);
-bool8 LoadZip(const char *, int32 *, int32 *, uint8 *);
+bool8 LoadZip(const char *, uint32 *, uint8 *);
enum s9xwrap_t
{
diff --git a/netplay.cpp b/netplay.cpp
index f0f15315..6e18291c 100644
--- a/netplay.cpp
+++ b/netplay.cpp
@@ -189,6 +189,8 @@
#include
#include
+#include "snes9x.h"
+
#ifdef __WIN32__
#include
#include
@@ -222,7 +224,6 @@
#include
#endif
-#include "snes9x.h"
#include "memmap.h"
#include "netplay.h"
#include "snapshot.h"
diff --git a/port.h b/port.h
index 067fa0ad..1e62b35b 100644
--- a/port.h
+++ b/port.h
@@ -202,7 +202,9 @@
#define RIGHTSHIFT_int8_IS_SAR
#define RIGHTSHIFT_int16_IS_SAR
#define RIGHTSHIFT_int32_IS_SAR
+#ifndef __WIN32_LIBSNES__
#define SNES_JOY_READ_CALLBACKS
+#endif //__WIN32_LIBSNES__
#endif
#ifdef __MACOSX__
@@ -227,27 +229,12 @@ typedef uint64_t uint64;
#else // HAVE_STDINT_H
#ifdef __WIN32__
typedef intptr_t pint;
-#else // __WIN32__
-#ifdef PTR_NOT_INT
-typedef long pint;
-#else
-typedef int pint;
-#endif
-#endif // __WIN32__
-#ifdef __WIN32__
-#ifdef __BORLANDC__
-#include
-#else
typedef signed char int8;
typedef unsigned char uint8;
typedef signed short int16;
typedef unsigned short uint16;
-#ifndef WSAAP
-// winsock2.h typedefs int32 as well
-typedef signed int int32;
-#endif
+typedef signed int int32;
typedef unsigned int uint32;
-#endif
typedef signed __int64 int64;
typedef unsigned __int64 uint64;
typedef int8 int8_t;
@@ -272,6 +259,11 @@ __extension__
#endif
typedef long long int64;
typedef unsigned long long uint64;
+#ifdef PTR_NOT_INT
+typedef long pint;
+#else // __PTR_NOT_INT
+typedef int pint;
+#endif // __PTR_NOT_INT
#endif // __WIN32__
#endif // HAVE_STDINT_H
#endif // snes9x_types_defined
@@ -305,15 +297,19 @@ typedef unsigned long long uint64;
void _splitpath (const char *, char *, char *, char *, char *);
void _makepath (char *, const char *, const char *, const char *, const char *);
#define S9xDisplayString DisplayStringFromBottom
-#else
+#else // __WIN32__
#define snprintf _snprintf
#define strcasecmp stricmp
#define strncasecmp strnicmp
+#ifndef __WIN32_LIBSNES__
void WinDisplayStringFromBottom(const char *string, int linesFromBottom, int pixelsFromLeft, bool allowWrap);
#define S9xDisplayString WinDisplayStringFromBottom
void SetInfoDlgColor(unsigned char, unsigned char, unsigned char);
#define SET_UI_COLOR(r,g,b) SetInfoDlgColor(r,g,b)
-#endif
+#else // __WIN32_LIBSNES__
+#define S9xDisplayString DisplayStringFromBottom
+#endif // __WIN32_LIBSNES__
+#endif // __WIN32__
#ifdef __DJGPP
#define SLASH_STR "\\"
diff --git a/server.cpp b/server.cpp
index fc2f3fa4..6a376132 100644
--- a/server.cpp
+++ b/server.cpp
@@ -190,6 +190,8 @@
#include
#endif
+#include "snes9x.h"
+
#ifdef __WIN32__
#include
@@ -219,7 +221,6 @@
#endif // !__WIN32__
-#include "snes9x.h"
#include "memmap.h"
#include "snapshot.h"
#include "netplay.h"
diff --git a/snapshot.cpp b/snapshot.cpp
index 17fa8e8c..0f2cc960 100644
--- a/snapshot.cpp
+++ b/snapshot.cpp
@@ -1169,6 +1169,21 @@ void S9xResetSaveTimer (bool8 dontsave)
t = time(NULL);
}
+uint32 S9xFreezeSize()
+{
+ nulStream stream;
+ S9xFreezeToStream(&stream);
+ return stream.size();
+}
+
+bool8 S9xFreezeGameMem (uint8 *buf, uint32 bufSize)
+{
+ memStream mStream(buf, bufSize);
+ S9xFreezeToStream(&mStream);
+
+ return (TRUE);
+}
+
bool8 S9xFreezeGame (const char *filename)
{
STREAM stream = NULL;
@@ -1194,6 +1209,14 @@ bool8 S9xFreezeGame (const char *filename)
return (FALSE);
}
+int S9xUnfreezeGameMem (const uint8 *buf, uint32 bufSize)
+{
+ memStream stream(buf, bufSize);
+ int result = S9xUnfreezeFromStream(&stream);
+
+ return result;
+}
+
bool8 S9xUnfreezeGame (const char *filename)
{
STREAM stream = NULL;
diff --git a/snapshot.h b/snapshot.h
index a522abae..88798a23 100644
--- a/snapshot.h
+++ b/snapshot.h
@@ -194,7 +194,10 @@
void S9xResetSaveTimer (bool8);
bool8 S9xFreezeGame (const char *);
+uint32 S9xFreezeSize (void);
+bool8 S9xFreezeGameMem (uint8 *,uint32);
bool8 S9xUnfreezeGame (const char *);
+int S9xUnfreezeGameMem (const uint8 *,uint32);
void S9xFreezeToStream (STREAM);
int S9xUnfreezeFromStream (STREAM);
diff --git a/snes9x.cpp b/snes9x.cpp
index 148073e8..4a84e70b 100644
--- a/snes9x.cpp
+++ b/snes9x.cpp
@@ -315,14 +315,14 @@ static void parse_crosshair_spec (enum crosscontrols ctl, const char *spec)
static bool try_load_config_file (const char *fname, ConfigFile &conf)
{
- STREAM fp;
+ FSTREAM fp;
- fp = OPEN_STREAM(fname, "r");
+ fp = OPEN_FSTREAM(fname, "r");
if (fp)
{
fprintf(stdout, "Reading config file %s.\n", fname);
- conf.LoadFile(new fReader(fp));
- CLOSE_STREAM(fp);
+ conf.LoadFile(new fStream(fp));
+ CLOSE_FSTREAM(fp);
return (true);
}
diff --git a/snes9x.h b/snes9x.h
index 4e09c0dd..97689baf 100644
--- a/snes9x.h
+++ b/snes9x.h
@@ -189,29 +189,42 @@
#ifdef ZLIB
#include
-#define STREAM gzFile
-#define READ_STREAM(p, l, s) gzread(s, p, l)
-#define WRITE_STREAM(p, l, s) gzwrite(s, p, l)
-#define GETS_STREAM(p, l, s) gzgets(s, p, l)
-#define GETC_STREAM(s) gzgetc(s)
-#define OPEN_STREAM(f, m) gzopen(f, m)
-#define REOPEN_STREAM(f, m) gzdopen(f, m)
-#define FIND_STREAM(f) gztell(f)
-#define REVERT_STREAM(f, o, s) gzseek(f, o, s)
-#define CLOSE_STREAM(s) gzclose(s)
+#define FSTREAM gzFile
+#define READ_FSTREAM(p, l, s) gzread(s, p, l)
+#define WRITE_FSTREAM(p, l, s) gzwrite(s, p, l)
+#define GETS_FSTREAM(p, l, s) gzgets(s, p, l)
+#define GETC_FSTREAM(s) gzgetc(s)
+#define OPEN_FSTREAM(f, m) gzopen(f, m)
+#define REOPEN_FSTREAM(f, m) gzdopen(f, m)
+#define FIND_FSTREAM(f) gztell(f)
+#define REVERT_FSTREAM(s, o, p) gzseek(s, o, p)
+#define CLOSE_FSTREAM(s) gzclose(s)
#else
-#define STREAM FILE *
-#define READ_STREAM(p, l, s) fread(p, 1, l, s)
-#define WRITE_STREAM(p, l, s) fwrite(p, 1, l, s)
-#define GETS_STREAM(p, l, s) fgets(p, l, s)
-#define GETC_STREAM(s) fgetc(s)
-#define OPEN_STREAM(f, m) fopen(f, m)
-#define REOPEN_STREAM(f, m) fdopen(f, m)
-#define FIND_STREAM(f) ftell(f)
-#define REVERT_STREAM(f, o, s) fseek(f, o, s)
-#define CLOSE_STREAM(s) fclose(s)
+#define FSTREAM FILE *
+#define READ_FSTREAM(p, l, s) fread(p, 1, l, s)
+#define WRITE_FSTREAM(p, l, s) fwrite(p, 1, l, s)
+#define GETS_FSTREAM(p, l, s) fgets(p, l, s)
+#define GETC_FSTREAM(s) fgetc(s)
+#define OPEN_FSTREAM(f, m) fopen(f, m)
+#define REOPEN_FSTREAM(f, m) fdopen(f, m)
+#define FIND_FSTREAM(s) ftell(s)
+#define REVERT_FSTREAM(s, o, p) fseek(s, o, p)
+#define CLOSE_FSTREAM(s) fclose(s)
#endif
+#include "stream.h"
+
+#define STREAM Stream *
+#define READ_STREAM(p, l, s) s->read(p,l)
+#define WRITE_STREAM(p, l, s) s->write(p,l)
+#define GETS_STREAM(p, l, s) s->gets(p,l)
+#define GETC_STREAM(s) s->get_char()
+#define OPEN_STREAM(f, m) openStreamFromFSTREAM(f, m)
+#define REOPEN_STREAM(f, m) reopenStreamFromFd(f, m)
+#define FIND_STREAM(s) s->pos()
+#define REVERT_STREAM(s, o, p) s->revert(p, o)
+#define CLOSE_STREAM(s) s->closeStream()
+
#define SNES_WIDTH 256
#define SNES_HEIGHT 224
#define SNES_HEIGHT_EXTENDED 239
diff --git a/reader.cpp b/stream.cpp
similarity index 64%
rename from reader.cpp
rename to stream.cpp
index 8ad1ed44..0d4082c4 100644
--- a/reader.cpp
+++ b/stream.cpp
@@ -183,24 +183,24 @@
#include "unzip.h"
#endif
#include "snes9x.h"
-#include "reader.h"
+#include "stream.h"
// Generic constructor/destructor
-Reader::Reader (void)
+Stream::Stream (void)
{
return;
}
-Reader::~Reader (void)
+Stream::~Stream (void)
{
return;
}
// Generic getline function, based on gets. Reimlpement if you can do better.
-char * Reader::getline (void)
+char * Stream::getline (void)
{
bool eof;
std::string ret;
@@ -212,7 +212,7 @@ char * Reader::getline (void)
return (strdup(ret.c_str()));
}
-std::string Reader::getline (bool &eof)
+std::string Stream::getline (bool &eof)
{
char buf[1024];
std::string ret;
@@ -235,50 +235,80 @@ std::string Reader::getline (bool &eof)
return (ret);
}
-// snes9x.h STREAM reader
+// snes9x.h FSTREAM Stream
-fReader::fReader (STREAM f)
+fStream::fStream (FSTREAM f)
{
fp = f;
}
-fReader::~fReader (void)
+fStream::~fStream (void)
{
return;
}
-int fReader::get_char (void)
+int fStream::get_char (void)
{
- return (GETC_STREAM(fp));
+ return (GETC_FSTREAM(fp));
}
-char * fReader::gets (char *buf, size_t len)
+char * fStream::gets (char *buf, size_t len)
{
- return (GETS_STREAM(buf, len, fp));
+ return (GETS_FSTREAM(buf, len, fp));
}
-size_t fReader::read (char *buf, size_t len)
+size_t fStream::read (void *buf, size_t len)
{
- return (READ_STREAM(buf, len, fp));
+ return (READ_FSTREAM(buf, len, fp));
}
-// unzip reader
+size_t fStream::write (void *buf, size_t len)
+{
+ return (WRITE_FSTREAM(buf, len, fp));
+}
+
+size_t fStream::pos (void)
+{
+ return (FIND_FSTREAM(fp));
+}
+
+size_t fStream::size (void)
+{
+ size_t sz;
+ REVERT_FSTREAM(fp,0L,SEEK_END);
+ sz = FIND_FSTREAM(fp);
+ REVERT_FSTREAM(fp,0L,SEEK_SET);
+ return sz;
+}
+
+int fStream::revert (size_t from, size_t offset)
+{
+ return (REVERT_FSTREAM(fp, from, offset));
+}
+
+void fStream::closeStream()
+{
+ CLOSE_FSTREAM(fp);
+ delete this;
+}
+
+// unzip Stream
#ifdef UNZIP_SUPPORT
-unzReader::unzReader (unzFile &v)
+unzStream::unzStream (unzFile &v)
{
file = v;
head = NULL;
numbytes = 0;
}
-unzReader::~unzReader (void)
+unzStream::~unzStream (void)
{
return;
}
-int unzReader::get_char (void)
+int unzStream::get_char (void)
{
unsigned char c;
@@ -297,7 +327,7 @@ int unzReader::get_char (void)
return ((int) c);
}
-char * unzReader::gets (char *buf, size_t len)
+char * unzStream::gets (char *buf, size_t len)
{
size_t i;
int c;
@@ -322,7 +352,7 @@ char * unzReader::gets (char *buf, size_t len)
return (buf);
}
-size_t unzReader::read (char *buf, size_t len)
+size_t unzStream::read (void *buf, size_t len)
{
if (len == 0)
return (len);
@@ -344,11 +374,219 @@ size_t unzReader::read (char *buf, size_t len)
numbytes = 0;
}
- int l = unzReadCurrentFile(file, buf + numread, len - numread);
+ int l = unzReadCurrentFile(file, (uint8 *)buf + numread, len - numread);
if (l > 0)
numread += l;
return (numread);
}
+// not supported
+size_t unzStream::write (void *buf, size_t len)
+{
+ return (0);
+}
+
+size_t unzStream::pos (void)
+{
+ return (unztell(file));
+}
+
+size_t unzStream::size (void)
+{
+ unz_file_info info;
+ unzGetCurrentFileInfo(file,&info,NULL,0,NULL,0,NULL,0);
+ return info.uncompressed_size;
+}
+
+// not supported
+int unzStream::revert (size_t from, size_t offset)
+{
+ return -1;
+}
+
+void unzStream::closeStream()
+{
+ unzCloseCurrentFile(file);
+ delete this;
+}
+
#endif
+
+// memory Stream
+
+memStream::memStream (uint8 *source, size_t sourceSize)
+{
+ mem = head = source;
+ msize = remaining = sourceSize;
+ readonly = false;
+}
+
+memStream::memStream (const uint8 *source, size_t sourceSize)
+{
+ mem = head = const_cast(source);
+ msize = remaining = sourceSize;
+ readonly = true;
+}
+
+memStream::~memStream (void)
+{
+ return;
+}
+
+int memStream::get_char (void)
+{
+ if(!remaining)
+ return EOF;
+
+ remaining--;
+ return *head++;
+}
+
+char * memStream::gets (char *buf, size_t len)
+{
+ size_t i;
+ int c;
+
+ for (i = 0; i < len - 1; i++)
+ {
+ c = get_char();
+ if (c == EOF)
+ {
+ if (i == 0)
+ return (NULL);
+ break;
+ }
+
+ buf[i] = (char) c;
+ if (buf[i] == '\n')
+ break;
+ }
+
+ buf[i] = '\0';
+
+ return (buf);
+}
+
+size_t memStream::read (void *buf, size_t len)
+{
+ size_t bytes = len < remaining ? len : remaining;
+ memcpy(buf,head,bytes);
+ head += bytes;
+ remaining -= bytes;
+
+ return bytes;
+}
+
+size_t memStream::write (void *buf, size_t len)
+{
+ if(readonly)
+ return 0;
+
+ size_t bytes = len < remaining ? len : remaining;
+ memcpy(head,buf,bytes);
+ head += bytes;
+ remaining -= bytes;
+
+ return bytes;
+}
+
+size_t memStream::pos (void)
+{
+ return msize - remaining;
+}
+
+size_t memStream::size (void)
+{
+ return msize;
+}
+
+int memStream::revert (size_t from, size_t offset)
+{
+ size_t pos = from + offset;
+
+ if(pos > msize)
+ return -1;
+
+ head = mem + pos;
+ remaining = msize - pos;
+
+ return 0;
+}
+
+void memStream::closeStream()
+{
+ delete [] mem;
+ delete this;
+}
+
+// dummy Stream
+
+nulStream::nulStream (void)
+{
+ bytes_written = 0;
+}
+
+nulStream::~nulStream (void)
+{
+ return;
+}
+
+int nulStream::get_char (void)
+{
+ return 0;
+}
+
+char * nulStream::gets (char *buf, size_t len)
+{
+ *buf = '\0';
+ return NULL;
+}
+
+size_t nulStream::read (void *buf, size_t len)
+{
+ return 0;
+}
+
+size_t nulStream::write (void *buf, size_t len)
+{
+ bytes_written += len;
+ return len;
+}
+
+size_t nulStream::pos (void)
+{
+ return 0;
+}
+
+size_t nulStream::size (void)
+{
+ return bytes_written;
+}
+
+int nulStream::revert (size_t from, size_t offset)
+{
+ bytes_written = from + offset;
+ return 0;
+}
+
+void nulStream::closeStream()
+{
+ delete this;
+}
+
+Stream *openStreamFromFSTREAM(const char* filename, const char* mode)
+{
+ FSTREAM f = OPEN_FSTREAM(filename,mode);
+ if(!f)
+ return NULL;
+ return new fStream(f);
+}
+
+Stream *reopenStreamFromFd(int fd, const char* mode)
+{
+ FSTREAM f = REOPEN_FSTREAM(fd,mode);
+ if(!f)
+ return NULL;
+ return new fStream(f);
+}
diff --git a/reader.h b/stream.h
similarity index 73%
rename from reader.h
rename to stream.h
index 80e92e4d..7a0e509a 100644
--- a/reader.h
+++ b/stream.h
@@ -176,46 +176,65 @@
***********************************************************************************/
-#ifndef _READER_H_
-#define _READER_H_
+#ifndef _STREAM_H_
+#define _STREAM_H_
-class Reader
+#include
+
+class Stream
{
public:
- Reader (void);
- virtual ~Reader (void);
+ Stream (void);
+ virtual ~Stream (void);
virtual int get_char (void) = 0;
virtual char * gets (char *, size_t) = 0;
virtual char * getline (void); // free() when done
virtual std::string getline (bool &);
- virtual size_t read (char *, size_t) = 0;
+ virtual size_t read (void *, size_t) = 0;
+ virtual size_t write (void *, size_t) = 0;
+ virtual size_t pos (void) = 0;
+ virtual size_t size (void) = 0;
+ virtual int revert (size_t from, size_t offset) = 0;
+ virtual void closeStream() = 0;
};
-class fReader : public Reader
+class fStream : public Stream
{
public:
- fReader (STREAM);
- virtual ~fReader (void);
+ fStream (FSTREAM);
+ virtual ~fStream (void);
virtual int get_char (void);
virtual char * gets (char *, size_t);
- virtual size_t read (char *, size_t);
+ virtual size_t read (void *, size_t);
+ virtual size_t write (void *, size_t);
+ virtual size_t pos (void);
+ virtual size_t size (void);
+ virtual int revert (size_t from, size_t offset);
+ virtual void closeStream();
private:
- STREAM fp;
+ FSTREAM fp;
};
#ifdef UNZIP_SUPPORT
+#include "unzip.h"
+
#define unz_BUFFSIZ 1024
-class unzReader : public Reader
+class unzStream : public Stream
{
public:
- unzReader (unzFile &);
- virtual ~unzReader (void);
+ unzStream (unzFile &);
+ virtual ~unzStream (void);
virtual int get_char (void);
virtual char * gets (char *, size_t);
- virtual size_t read (char *, size_t);
+ virtual size_t read (void *, size_t);
+ virtual size_t write (void *, size_t);
+ virtual size_t pos (void);
+ virtual size_t size (void);
+ virtual int revert (size_t from, size_t offset);
+ virtual void closeStream();
private:
unzFile file;
@@ -226,4 +245,52 @@ class unzReader : public Reader
#endif
+class memStream : public Stream
+{
+ public:
+ memStream (uint8 *,size_t);
+ memStream (const uint8 *,size_t);
+ virtual ~memStream (void);
+ virtual int get_char (void);
+ virtual char * gets (char *, size_t);
+ virtual size_t read (void *, size_t);
+ virtual size_t write (void *, size_t);
+ virtual size_t pos (void);
+ virtual size_t size (void);
+ virtual int revert (size_t from, size_t offset);
+ virtual void closeStream();
+
+ private:
+ uint8 *mem;
+ size_t msize;
+ size_t remaining;
+ uint8 *head;
+ bool readonly;
+};
+
+/* dummy stream that always reads 0 and writes nowhere
+ but counts bytes written
+*/
+class nulStream : public Stream
+{
+ public:
+ nulStream (void);
+ virtual ~nulStream (void);
+ virtual int get_char (void);
+ virtual char * gets (char *, size_t);
+ virtual size_t read (void *, size_t);
+ virtual size_t write (void *, size_t);
+ virtual size_t pos (void);
+ virtual size_t size (void);
+ virtual int revert (size_t from, size_t offset);
+ virtual void closeStream();
+
+ private:
+ size_t bytes_written;
+};
+
+Stream *openStreamFromFSTREAM(const char* filename, const char* mode);
+Stream *reopenStreamFromFd(int fd, const char* mode);
+
+
#endif
diff --git a/unix/Makefile.in b/unix/Makefile.in
index b19773bc..c7525aa5 100644
--- a/unix/Makefile.in
+++ b/unix/Makefile.in
@@ -7,7 +7,7 @@
OS = `uname -s -r -m|sed \"s/ /-/g\"|tr \"[A-Z]\" \"[a-z]\"|tr \"/()\" \"___\"`
BUILDDIR = .
-OBJECTS = ../apu/apu.o ../apu/bapu/dsp/sdsp.o ../apu/bapu/dsp/SPC_DSP.o ../apu/bapu/smp/smp.o ../apu/bapu/smp/smp_state.o ../bsx.o ../c4.o ../c4emu.o ../cheats.o ../cheats2.o ../clip.o ../conffile.o ../controls.o ../cpu.o ../cpuexec.o ../cpuops.o ../crosshairs.o ../dma.o ../dsp.o ../dsp1.o ../dsp2.o ../dsp3.o ../dsp4.o ../fxinst.o ../fxemu.o ../gfx.o ../globals.o ../logger.o ../memmap.o ../movie.o ../obc1.o ../ppu.o ../reader.o ../sa1.o ../sa1cpu.o ../screenshot.o ../sdd1.o ../sdd1emu.o ../seta.o ../seta010.o ../seta011.o ../seta018.o ../snapshot.o ../snes9x.o ../spc7110.o ../srtc.o ../tile.o ../filter/2xsai.o ../filter/blit.o ../filter/epx.o ../filter/hq2x.o ../filter/snes_ntsc.o unix.o x11.o
+OBJECTS = ../apu/apu.o ../apu/bapu/dsp/sdsp.o ../apu/bapu/dsp/SPC_DSP.o ../apu/bapu/smp/smp.o ../apu/bapu/smp/smp_state.o ../bsx.o ../c4.o ../c4emu.o ../cheats.o ../cheats2.o ../clip.o ../conffile.o ../controls.o ../cpu.o ../cpuexec.o ../cpuops.o ../crosshairs.o ../dma.o ../dsp.o ../dsp1.o ../dsp2.o ../dsp3.o ../dsp4.o ../fxinst.o ../fxemu.o ../gfx.o ../globals.o ../logger.o ../memmap.o ../movie.o ../obc1.o ../ppu.o ../stream.o ../sa1.o ../sa1cpu.o ../screenshot.o ../sdd1.o ../sdd1emu.o ../seta.o ../seta010.o ../seta011.o ../seta018.o ../snapshot.o ../snes9x.o ../spc7110.o ../srtc.o ../tile.o ../filter/2xsai.o ../filter/blit.o ../filter/epx.o ../filter/hq2x.o ../filter/snes_ntsc.o unix.o x11.o
DEFS = -DMITSHM
ifdef S9XDEBUGGER
diff --git a/win32/snes9xw.vcproj b/win32/snes9xw.vcproj
index 180ed704..27ea8e7c 100644
--- a/win32/snes9xw.vcproj
+++ b/win32/snes9xw.vcproj
@@ -2082,42 +2082,6 @@
/>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -2902,6 +2866,42 @@
/>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+