mirror of
https://github.com/0ldsk00l/nestopia.git
synced 2025-04-02 10:31:51 -04:00
781 lines
18 KiB
C++
781 lines
18 KiB
C++
/*
|
|
NEStopia / Linux
|
|
Port by R. Belmont
|
|
|
|
auxio.cpp - handles movie and state I/O
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <iostream>
|
|
#include <fstream>
|
|
#include <vector>
|
|
|
|
#include "core/api/NstApiEmulator.hpp"
|
|
#include "core/api/NstApiVideo.hpp"
|
|
#include "core/api/NstApiSound.hpp"
|
|
#include "core/api/NstApiInput.hpp"
|
|
#include "core/api/NstApiMachine.hpp"
|
|
#include "core/api/NstApiUser.hpp"
|
|
#include "core/api/NstApiNsf.hpp"
|
|
#include "core/api/NstApiMovie.hpp"
|
|
#include "core/api/NstApiFds.hpp"
|
|
#include "core/api/NstApiCartridge.hpp"
|
|
#include "oss.h"
|
|
#include "settings.h"
|
|
#include "unzip.h"
|
|
|
|
extern "C" {
|
|
#include <gtk/gtk.h>
|
|
|
|
#include "7zCrc.h"
|
|
#include "7zIn.h"
|
|
#include "7zExtract.h"
|
|
#include "7zAlloc.h"
|
|
|
|
#include "interface.h"
|
|
//#include "callbacks.h"
|
|
}
|
|
|
|
#define MAX_ITEMS (512)
|
|
|
|
extern Nes::Api::Emulator emulator;
|
|
extern GtkWidget *mainwindow;
|
|
extern char rootname[512];
|
|
|
|
static std::ifstream *moviePlayFile, *fdsBiosFile, *nstDBFile;
|
|
static std::fstream *movieRecFile;
|
|
|
|
static bool run_picker, cancelled;
|
|
static GtkTreeStore *treestore;
|
|
static GtkTreeIter treeiters[MAX_ITEMS];
|
|
static GtkCellRenderer *renderer;
|
|
static GtkTreeViewColumn *column;
|
|
static GtkTreeSelection *selection;
|
|
|
|
static int find_current_selection(void)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < MAX_ITEMS; i++)
|
|
{
|
|
if (gtk_tree_selection_iter_is_selected(selection, &treeiters[i]))
|
|
{
|
|
return i;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
void on_archok_clicked(GtkButton *button, gpointer user_data)
|
|
{
|
|
run_picker = false;
|
|
}
|
|
|
|
void on_archcancel_clicked(GtkButton *button, gpointer user_data)
|
|
{
|
|
run_picker = false;
|
|
cancelled = true;
|
|
}
|
|
|
|
void on_archselect_destroyed(GtkButton *button, gpointer user_data)
|
|
{
|
|
run_picker = false;
|
|
}
|
|
|
|
static gint check_list_double(GtkWidget *widget, GdkEventButton *event, gpointer func_data)
|
|
{
|
|
if (event->type==GDK_2BUTTON_PRESS)
|
|
{
|
|
run_picker = false;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
void auxio_init(void)
|
|
{
|
|
moviePlayFile = NULL;
|
|
movieRecFile = NULL;
|
|
fdsBiosFile = NULL;
|
|
nstDBFile = NULL;
|
|
}
|
|
|
|
void auxio_do_state_save(void)
|
|
{
|
|
Nes::Api::Machine machine( emulator );
|
|
GtkWidget *dialog;
|
|
char defname[512];
|
|
|
|
defname[0] = '\0';
|
|
strcpy(defname, rootname);
|
|
strcat(defname, ".nst");
|
|
|
|
dialog = gtk_file_chooser_dialog_new ("Save state (.nst)",
|
|
GTK_WINDOW(mainwindow),
|
|
GTK_FILE_CHOOSER_ACTION_SAVE,
|
|
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
|
|
GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
|
|
NULL);
|
|
|
|
gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), defname);
|
|
|
|
if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
|
|
{
|
|
char *filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
|
|
|
|
std::ofstream stateFile( filename, std::ifstream::out|std::ifstream::binary );
|
|
|
|
if (stateFile.is_open())
|
|
{
|
|
machine.SaveState(stateFile);
|
|
}
|
|
|
|
g_free (filename);
|
|
}
|
|
|
|
gtk_widget_destroy(dialog);
|
|
}
|
|
|
|
void auxio_do_state_load(void)
|
|
{
|
|
Nes::Api::Machine machine( emulator );
|
|
GtkWidget *dialog;
|
|
GtkFileFilter *filter;
|
|
|
|
dialog = gtk_file_chooser_dialog_new ("Load state (.nst)",
|
|
GTK_WINDOW(mainwindow),
|
|
GTK_FILE_CHOOSER_ACTION_OPEN,
|
|
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
|
|
GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
|
|
NULL);
|
|
|
|
filter = gtk_file_filter_new();
|
|
gtk_file_filter_set_name(filter, "Nestopia save states");
|
|
gtk_file_filter_add_pattern(filter, "*.nst");
|
|
gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
|
|
|
|
if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
|
|
{
|
|
char *filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
|
|
|
|
std::ifstream stateFile( filename, std::ifstream::in|std::ifstream::binary );
|
|
|
|
if (stateFile.is_open())
|
|
{
|
|
machine.LoadState(stateFile);
|
|
}
|
|
|
|
g_free (filename);
|
|
}
|
|
|
|
gtk_widget_destroy(dialog);
|
|
}
|
|
|
|
void auxio_do_movie_save(void)
|
|
{
|
|
Nes::Api::Machine machine( emulator );
|
|
Nes::Api::Movie movie( emulator );
|
|
GtkWidget *dialog;
|
|
char defname[512];
|
|
|
|
defname[0] = '\0';
|
|
strcpy(defname, rootname);
|
|
strcat(defname, ".nsv");
|
|
|
|
if (movieRecFile)
|
|
{
|
|
delete movieRecFile;
|
|
movieRecFile = NULL;
|
|
}
|
|
|
|
dialog = gtk_file_chooser_dialog_new ("Save a movie (.nsv)",
|
|
GTK_WINDOW(mainwindow),
|
|
GTK_FILE_CHOOSER_ACTION_SAVE,
|
|
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
|
|
GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
|
|
NULL);
|
|
|
|
gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), defname);
|
|
|
|
if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
|
|
{
|
|
char *filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
|
|
|
|
movieRecFile = new std::fstream(filename, std::ifstream::out|std::ifstream::binary);
|
|
|
|
if (movieRecFile->is_open())
|
|
{
|
|
movie.Record((std::iostream&)*movieRecFile, Nes::Api::Movie::CLEAN);
|
|
}
|
|
else
|
|
{
|
|
delete movieRecFile;
|
|
movieRecFile = NULL;
|
|
}
|
|
|
|
g_free (filename);
|
|
}
|
|
|
|
gtk_widget_destroy(dialog);
|
|
}
|
|
|
|
void auxio_do_movie_load(void)
|
|
{
|
|
Nes::Api::Machine machine( emulator );
|
|
Nes::Api::Movie movie( emulator );
|
|
GtkWidget *dialog;
|
|
GtkFileFilter *filter;
|
|
|
|
if (moviePlayFile)
|
|
{
|
|
delete moviePlayFile;
|
|
moviePlayFile = NULL;
|
|
}
|
|
|
|
dialog = gtk_file_chooser_dialog_new ("Load a movie (.nsv)",
|
|
GTK_WINDOW(mainwindow),
|
|
GTK_FILE_CHOOSER_ACTION_OPEN,
|
|
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
|
|
GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
|
|
NULL);
|
|
|
|
filter = gtk_file_filter_new();
|
|
gtk_file_filter_set_name(filter, "Nestopia movies");
|
|
gtk_file_filter_add_pattern(filter, "*.nsv");
|
|
gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
|
|
|
|
if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
|
|
{
|
|
char *filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
|
|
|
|
moviePlayFile = new std::ifstream( filename, std::ifstream::in|std::ifstream::binary );
|
|
|
|
if (moviePlayFile->is_open())
|
|
{
|
|
movie.Play(*moviePlayFile);
|
|
}
|
|
else
|
|
{
|
|
delete moviePlayFile;
|
|
moviePlayFile = NULL;
|
|
}
|
|
|
|
g_free (filename);
|
|
}
|
|
|
|
gtk_widget_destroy(dialog);
|
|
}
|
|
|
|
void auxio_do_movie_stop(void)
|
|
{
|
|
Nes::Api::Movie movie( emulator );
|
|
|
|
if (movieRecFile || moviePlayFile)
|
|
{
|
|
movie.Stop();
|
|
movie.Eject();
|
|
|
|
if (movieRecFile)
|
|
{
|
|
delete movieRecFile;
|
|
movieRecFile = NULL;
|
|
}
|
|
|
|
if (moviePlayFile)
|
|
{
|
|
delete moviePlayFile;
|
|
moviePlayFile = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
void auxio_set_fds_bios(void)
|
|
{
|
|
Nes::Api::Fds fds( emulator );
|
|
char dirname[1024], *home;
|
|
|
|
if (fdsBiosFile)
|
|
{
|
|
return;
|
|
}
|
|
|
|
home = getenv("HOME");
|
|
sprintf(dirname, "%s/.nestopia/disksys.rom", home);
|
|
|
|
fdsBiosFile = new std::ifstream(dirname, std::ifstream::in|std::ifstream::binary);
|
|
|
|
if (fdsBiosFile->is_open())
|
|
{
|
|
fds.SetBIOS(fdsBiosFile);
|
|
}
|
|
else
|
|
{
|
|
std::cout << "Couldn't find ~/.nestopia/disksys.rom\nDisk System games will not work\n";
|
|
delete fdsBiosFile;
|
|
fdsBiosFile = NULL;
|
|
}
|
|
}
|
|
|
|
void auxio_shutdown(void)
|
|
{
|
|
if (nstDBFile)
|
|
{
|
|
delete nstDBFile;
|
|
nstDBFile = NULL;
|
|
}
|
|
|
|
if (fdsBiosFile)
|
|
{
|
|
delete fdsBiosFile;
|
|
fdsBiosFile = NULL;
|
|
}
|
|
}
|
|
|
|
static int checkExtension(char *filename)
|
|
{
|
|
int nlen;
|
|
|
|
nlen = strlen(filename);
|
|
|
|
if ((!strcasecmp(&filename[nlen-4], ".nes")) ||
|
|
(!strcasecmp(&filename[nlen-4], ".fds")) ||
|
|
(!strcasecmp(&filename[nlen-4], ".nsf")) ||
|
|
(!strcasecmp(&filename[nlen-4], ".unf")) ||
|
|
(!strcasecmp(&filename[nlen-5], ".unif"))||
|
|
(!strcasecmp(&filename[nlen-4], ".xml")))
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
typedef FILE *MY_FILE_HANDLE;
|
|
|
|
size_t MyReadFile(MY_FILE_HANDLE file, void *data, size_t size)
|
|
{
|
|
if (size == 0)
|
|
return 0;
|
|
return fread(data, 1, size, file);
|
|
}
|
|
|
|
typedef struct _CFileInStream
|
|
{
|
|
ISzInStream InStream;
|
|
MY_FILE_HANDLE File;
|
|
} CFileInStream;
|
|
|
|
|
|
#define kBufferSize (1 << 12)
|
|
Byte g_Buffer[kBufferSize];
|
|
|
|
SRes SzFileReadImp(void *object, void **buffer, size_t *size)
|
|
{
|
|
CFileInStream *s = (CFileInStream *)object;
|
|
if (*size > kBufferSize)
|
|
*size = kBufferSize;
|
|
*size = MyReadFile(s->File, g_Buffer, *size);
|
|
*buffer = g_Buffer;
|
|
return SZ_OK;
|
|
}
|
|
|
|
SRes SzFileSeekImp(void *object, CFileSize pos, ESzSeek origin)
|
|
{
|
|
CFileInStream *s = (CFileInStream *)object;
|
|
|
|
int moveMethod;
|
|
int res;
|
|
switch (origin)
|
|
{
|
|
case SZ_SEEK_SET: moveMethod = SEEK_SET; break;
|
|
case SZ_SEEK_CUR: moveMethod = SEEK_CUR; break;
|
|
case SZ_SEEK_END: moveMethod = SEEK_END; break;
|
|
default: return SZ_ERROR_PARAM;
|
|
}
|
|
res = fseek(s->File, (long)pos, moveMethod );
|
|
return (res == 0) ? SZ_OK : SZ_ERROR_FAIL;
|
|
}
|
|
|
|
int auxio_load_archive(const char *filename, unsigned char **dataout, int *datasize, int *dataoffset, const char *filetoload, char *outname)
|
|
{
|
|
FILE *f;
|
|
unsigned char idbuf[4];
|
|
int filesFound = 0;
|
|
std::vector<char *> filelist; // list of files we can load in this archive
|
|
|
|
// default case: outname is filename
|
|
if (outname)
|
|
{
|
|
strcpy(outname, filename);
|
|
}
|
|
|
|
f = fopen(filename, "rb");
|
|
|
|
if (!f)
|
|
{
|
|
return 0; // no good
|
|
}
|
|
|
|
fread(idbuf, 4, 1, f);
|
|
fclose(f);
|
|
|
|
// printf("ID bytes %c %c %x %x\n", idbuf[0], idbuf[1], idbuf[2], idbuf[3]);
|
|
|
|
if ((idbuf[0] == 'P') && (idbuf[1] == 'K') && (idbuf[2] == 0x03) && (idbuf[3] == 0x04))
|
|
{ // it's zip
|
|
unzFile zipArchive;
|
|
char file_name[1024];
|
|
unz_file_info info;
|
|
int nlen;
|
|
int ret = 0;
|
|
|
|
zipArchive = unzOpen(filename);
|
|
|
|
if (!zipArchive)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
unzGoToFirstFile(zipArchive);
|
|
|
|
for (;;)
|
|
{
|
|
if (unzGetCurrentFileInfo(zipArchive, &info, file_name, 1024, NULL, 0, NULL, 0) == UNZ_OK)
|
|
{
|
|
if (filetoload != NULL)
|
|
{
|
|
if (!strcasecmp(filetoload, file_name))
|
|
{
|
|
int length;
|
|
unsigned char *buffer;
|
|
|
|
unzOpenCurrentFile(zipArchive);
|
|
|
|
length = info.uncompressed_size;
|
|
buffer = (unsigned char *)malloc(length);
|
|
|
|
ret = unzReadCurrentFile(zipArchive, buffer, length);
|
|
|
|
if (ret != length)
|
|
{
|
|
free(buffer);
|
|
return 0;
|
|
}
|
|
|
|
unzCloseCurrentFile(zipArchive);
|
|
unzClose(zipArchive);
|
|
|
|
*datasize = length;
|
|
*dataout = buffer;
|
|
*dataoffset = 0;
|
|
|
|
return 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (checkExtension(file_name))
|
|
{
|
|
char *tmpstr;
|
|
|
|
tmpstr = (char *)malloc(strlen(file_name)+1);
|
|
strcpy(tmpstr, file_name);
|
|
|
|
// add to the file list
|
|
filelist.push_back(tmpstr);
|
|
filesFound++;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
|
|
ret = unzGoToNextFile(zipArchive);
|
|
|
|
if (ret == UNZ_END_OF_LIST_OF_FILE)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (ret != UNZ_OK)
|
|
{
|
|
unzClose(zipArchive);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
unzClose(zipArchive);
|
|
}
|
|
else if ((idbuf[0] == '7') && (idbuf[1] == 'z') && (idbuf[2] == 0xbc) && (idbuf[3] == 0xaf))
|
|
{ // it's 7zip
|
|
CFileInStream archiveStream;
|
|
SRes res;
|
|
CSzArEx db; /* 7z archive database structure */
|
|
ISzAlloc allocImp; /* memory functions for main pool */
|
|
ISzAlloc allocTempImp; /* memory functions for temporary pool */
|
|
|
|
archiveStream.File = fopen(filename, "rb");
|
|
if (!archiveStream.File)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
archiveStream.InStream.Read = SzFileReadImp;
|
|
archiveStream.InStream.Seek = SzFileSeekImp;
|
|
|
|
allocImp.Alloc = SzAlloc;
|
|
allocImp.Free = SzFree;
|
|
|
|
allocTempImp.Alloc = SzAllocTemp;
|
|
allocTempImp.Free = SzFreeTemp;
|
|
|
|
// init 7zip internals
|
|
CrcGenerateTable();
|
|
SzArEx_Init(&db);
|
|
|
|
res = SzArEx_Open(&db, &archiveStream.InStream, &allocImp, &allocTempImp);
|
|
if (res == SZ_OK)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < db.db.NumFiles; i++)
|
|
{
|
|
CSzFileItem *item = db.db.Files + i;
|
|
|
|
if (!item->IsDirectory)
|
|
{
|
|
if (filetoload != NULL)
|
|
{
|
|
if (!strcasecmp(filetoload, item->Name))
|
|
{
|
|
UInt32 blockIndex = 0xFFFFFFFF; /* it can have any value before first call (if outBuffer = 0) */
|
|
Byte *outBuffer = 0; /* it must be 0 before first call for each new archive. */
|
|
size_t outBufferSize = 0; /* it can have any value before first call (if outBuffer = 0) */
|
|
size_t offset;
|
|
size_t outSizeProcessed;
|
|
|
|
res = SzAr_Extract(&db, &archiveStream.InStream, i,
|
|
&blockIndex, &outBuffer, &outBufferSize,
|
|
&offset, &outSizeProcessed,
|
|
&allocImp, &allocTempImp);
|
|
|
|
if (res == SZ_OK)
|
|
{
|
|
SzArEx_Free(&db, &allocImp);
|
|
fclose(archiveStream.File);
|
|
|
|
*datasize = (int)outBufferSize;
|
|
*dataout = (unsigned char *)outBuffer;
|
|
*dataoffset = (int)offset;
|
|
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
std::cout << "Error extracting 7zip!\n";
|
|
}
|
|
}
|
|
}
|
|
|
|
if (checkExtension(item->Name))
|
|
{
|
|
char *tmpstr;
|
|
|
|
tmpstr = (char *)malloc(strlen(item->Name)+1);
|
|
strcpy(tmpstr, item->Name);
|
|
|
|
// add to the file list
|
|
filelist.push_back(tmpstr);
|
|
filesFound++;
|
|
}
|
|
}
|
|
}
|
|
|
|
SzArEx_Free(&db, &allocImp);
|
|
fclose(archiveStream.File);
|
|
}
|
|
}
|
|
else if ((idbuf[0] == 'R') && (idbuf[1] == 'a') && (idbuf[2] == 'r') && (idbuf[3] == '!'))
|
|
{ // it's rar
|
|
|
|
}
|
|
|
|
// if we found any files and weren't forced to load them, handle accordingly
|
|
if (filesFound)
|
|
{
|
|
// only 1 file found, just run it
|
|
if (filesFound == 1)
|
|
{
|
|
char fname[512];
|
|
|
|
strcpy(fname, filelist[0]);
|
|
|
|
free(filelist[0]);
|
|
filelist.clear();
|
|
|
|
strcpy(outname, fname);
|
|
|
|
return auxio_load_archive(filename, dataout, datasize, dataoffset, fname, NULL);
|
|
}
|
|
else // multiple files we can handle found, give the user a choice
|
|
{
|
|
int sel;
|
|
char fname[512];
|
|
|
|
GtkWidget *archselect = gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
|
gtk_window_set_title(GTK_WINDOW (archselect), "Pick game in archive");
|
|
gtk_window_set_modal(GTK_WINDOW (archselect), TRUE);
|
|
|
|
GtkWidget *archbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
|
|
gtk_container_add(GTK_CONTAINER(archselect), archbox);
|
|
gtk_widget_show(archbox);
|
|
|
|
GtkWidget *scrolledwindow = gtk_scrolled_window_new(NULL, NULL);
|
|
gtk_box_pack_start(GTK_BOX(archbox), scrolledwindow, TRUE, TRUE, 0);
|
|
gtk_widget_set_size_request(scrolledwindow, 340, 340);
|
|
gtk_widget_show(scrolledwindow);
|
|
|
|
GtkWidget *buttonbox = gtk_widget_new(GTK_TYPE_BOX, "halign", GTK_ALIGN_END, NULL);
|
|
gtk_box_pack_start(GTK_BOX(archbox), buttonbox, FALSE, TRUE, 0);
|
|
gtk_widget_show(buttonbox);
|
|
|
|
GtkWidget *archtree = gtk_tree_view_new();
|
|
gtk_container_add(GTK_CONTAINER (scrolledwindow), archtree);
|
|
gtk_tree_view_set_fixed_height_mode(GTK_TREE_VIEW (archtree), FALSE);
|
|
g_signal_connect(G_OBJECT(archtree), "button_press_event", G_CALLBACK(check_list_double), NULL);
|
|
gtk_widget_show(archtree);
|
|
|
|
// set up our tree store
|
|
treestore = gtk_tree_store_new(1, G_TYPE_STRING);
|
|
|
|
// attach the store to the tree
|
|
gtk_tree_view_set_model(GTK_TREE_VIEW(archtree), GTK_TREE_MODEL(treestore));
|
|
|
|
for (int fn = 0; fn < filelist.size(); fn++)
|
|
{
|
|
gtk_tree_store_insert(treestore, &treeiters[fn], NULL, 999999);
|
|
gtk_tree_store_set(treestore, &treeiters[fn], 0, filelist[fn], -1);
|
|
}
|
|
|
|
// create a cell renderer using the stock text one
|
|
renderer = gtk_cell_renderer_text_new();
|
|
|
|
// create a display column using the renderer
|
|
column = gtk_tree_view_column_new_with_attributes ("NES file",
|
|
renderer,
|
|
"text", 0,
|
|
NULL);
|
|
|
|
// add the display column and renderer to the tree view
|
|
gtk_tree_view_append_column(GTK_TREE_VIEW (archtree), column);
|
|
|
|
GtkWidget *archcancel = gtk_widget_new(GTK_TYPE_BUTTON, "label", GTK_STOCK_CANCEL, "halign", GTK_ALIGN_END, "margin-top", 8, "margin-bottom", 8, "margin-right", 8, NULL);
|
|
gtk_button_set_use_stock(GTK_BUTTON(archcancel), TRUE);
|
|
gtk_box_pack_start(GTK_BOX(buttonbox), archcancel, FALSE, FALSE, 0);
|
|
gtk_widget_show(archcancel);
|
|
|
|
GtkWidget *archok = gtk_widget_new(GTK_TYPE_BUTTON, "label", GTK_STOCK_OK, "halign", GTK_ALIGN_END, "margin-top", 8, "margin-bottom", 8, "margin-right", 8, NULL);
|
|
gtk_button_set_use_stock(GTK_BUTTON(archok), TRUE);
|
|
gtk_box_pack_start(GTK_BOX(buttonbox), archok, FALSE, FALSE, 0);
|
|
gtk_widget_show(archok);
|
|
|
|
// get the selection object too
|
|
selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(archtree));
|
|
|
|
g_signal_connect(G_OBJECT(archcancel), "clicked",
|
|
G_CALLBACK(on_archcancel_clicked), NULL);
|
|
|
|
g_signal_connect(G_OBJECT(archok), "clicked",
|
|
G_CALLBACK(on_archok_clicked), NULL);
|
|
|
|
g_signal_connect(G_OBJECT(archselect), "destroy",
|
|
G_CALLBACK(on_archselect_destroyed), NULL);
|
|
|
|
gtk_widget_show(archselect);
|
|
|
|
run_picker = true;
|
|
cancelled = false;
|
|
|
|
while (run_picker)
|
|
{
|
|
gtk_main_iteration_do(TRUE);
|
|
}
|
|
|
|
sel = find_current_selection();
|
|
|
|
gtk_widget_destroy(archselect);
|
|
|
|
// was something picked?
|
|
if ((sel != -1) && (!cancelled))
|
|
{
|
|
strcpy(fname, filelist[sel]);
|
|
}
|
|
|
|
// free all the temp filenames
|
|
for (int fn = 0; fn < filelist.size(); fn++)
|
|
{
|
|
free(filelist[fn]);
|
|
}
|
|
|
|
// and wipe the vector
|
|
filelist.clear();
|
|
|
|
if ((sel != -1) && (!cancelled))
|
|
{
|
|
if (outname)
|
|
{
|
|
strcpy(outname, fname);
|
|
}
|
|
|
|
return auxio_load_archive(filename, dataout, datasize, dataoffset, fname, NULL);
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void auxio_load_db(void)
|
|
{
|
|
Nes::Api::Cartridge::Database database( emulator );
|
|
char dirname[1024], datadirname[1024], *pwd;
|
|
|
|
if (nstDBFile)
|
|
{
|
|
return;
|
|
}
|
|
|
|
pwd = getenv("PWD");
|
|
sprintf(dirname, "%s/NstDatabase.xml", pwd);
|
|
sprintf(datadirname, "%s/NstDatabase.xml", DATADIR);
|
|
|
|
nstDBFile = new std::ifstream(datadirname, std::ifstream::in|std::ifstream::binary);
|
|
|
|
if (nstDBFile->is_open())
|
|
{
|
|
database.Load(*nstDBFile);
|
|
database.Enable(true);
|
|
}
|
|
else
|
|
{
|
|
printf("NstDatabase.xml not found in %s\n", DATADIR);
|
|
nstDBFile = new std::ifstream(dirname, std::ifstream::in|std::ifstream::binary);
|
|
|
|
if (nstDBFile->is_open())
|
|
{
|
|
database.Load(*nstDBFile);
|
|
database.Enable(true);
|
|
}
|
|
else
|
|
{
|
|
printf("NstDatabase.xml not found in %s\nPAL detection and auto-ROM-fixing will be disabled\n", pwd);
|
|
delete nstDBFile;
|
|
nstDBFile = NULL;
|
|
}
|
|
}
|
|
}
|
|
|