2015-02-15 17:52:27 +00:00
/*
2015-10-22 05:13:26 +00:00
* Apple // emulator for *ix
2015-02-15 17:52:27 +00:00
*
* This software package is subject to the GNU General Public License
2015-10-22 05:13:26 +00:00
* version 3 or later ( your choice ) as published by the Free Software
2015-02-15 17:52:27 +00:00
* Foundation .
*
2015-10-22 05:13:26 +00:00
* Copyright 2015 Aaron Culliney
2015-02-15 17:52:27 +00:00
*
*/
2015-02-16 04:08:01 +00:00
# include "common.h"
2015-03-01 05:48:08 +00:00
# include "androidkeys.h"
2017-05-21 21:58:55 +00:00
# include "json_parse_private.h"
2015-02-15 17:52:27 +00:00
2015-07-11 21:37:41 +00:00
# include <cpu-features.h>
2015-03-23 01:53:13 +00:00
# include <jni.h>
2015-06-28 19:49:26 +00:00
unsigned long android_deviceSampleRateHz = 0 ;
2015-07-05 01:14:21 +00:00
unsigned long android_monoBufferSubmitSizeSamples = 0 ;
unsigned long android_stereoBufferSubmitSizeSamples = 0 ;
2015-09-26 21:58:09 +00:00
bool android_armArch = false ;
bool android_armArchV7A = false ;
bool android_arm64Arch = false ;
bool android_x86 = false ;
bool android_x86_64 = false ;
2015-07-11 21:37:41 +00:00
bool android_armNeonEnabled = false ;
bool android_x86SSSE3Enabled = false ;
2015-06-28 19:49:26 +00:00
2015-04-02 02:59:38 +00:00
enum {
ANDROID_ACTION_DOWN = 0x0 ,
ANDROID_ACTION_UP = 0x1 ,
ANDROID_ACTION_MOVE = 0x2 ,
ANDROID_ACTION_CANCEL = 0x3 ,
ANDROID_ACTION_POINTER_DOWN = 0x5 ,
ANDROID_ACTION_POINTER_UP = 0x6 ,
} ;
2015-10-04 20:39:57 +00:00
typedef enum lifecycle_seq_t {
APP_RUNNING = 0 ,
APP_REQUESTED_SHUTDOWN ,
APP_FINISHED ,
} lifecycle_seq_t ;
static lifecycle_seq_t appState = APP_RUNNING ;
2015-09-12 22:33:22 +00:00
2015-03-14 22:42:02 +00:00
# if TESTING
2016-04-13 05:24:04 +00:00
static void _start_tests ( void ) {
2015-03-14 22:42:02 +00:00
char * local_argv [ ] = {
" -f " ,
NULL
} ;
int local_argc = 0 ;
for ( char * * p = & local_argv [ 0 ] ; * p ! = NULL ; p + + ) {
+ + local_argc ;
}
2016-10-03 00:31:49 +00:00
2016-04-13 05:24:04 +00:00
# if TEST_CPU
2015-09-07 06:43:26 +00:00
// Currently this test is the only one that runs as a black screen
2015-03-14 22:42:02 +00:00
extern int test_cpu ( int , char * [ ] ) ;
test_cpu ( local_argc , local_argv ) ;
2016-05-08 19:33:00 +00:00
kill ( getpid ( ) , SIGKILL ) ; // and we're done ...
2016-10-03 00:31:49 +00:00
# endif
cpu_pause ( ) ;
emulator_start ( ) ;
while ( cpu_thread_id = = 0 ) {
sleep ( 1 ) ;
}
cpu_resume ( ) ;
# if TEST_DISK
2016-04-13 05:24:04 +00:00
extern void test_disk ( int , char * [ ] ) ;
2015-03-14 22:42:02 +00:00
test_disk ( local_argc , local_argv ) ;
2016-07-24 00:23:36 +00:00
# elif TEST_DISPLAY
extern void test_display ( int , char * [ ] ) ;
test_display ( local_argc , local_argv ) ;
2016-04-13 05:24:04 +00:00
# elif TEST_PREFS
extern void test_prefs ( int , char * [ ] ) ;
test_prefs ( local_argc , local_argv ) ;
2016-07-24 00:23:36 +00:00
# elif TEST_TRACE
extern void test_trace ( int , char * [ ] ) ;
test_trace ( local_argc , local_argv ) ;
2016-10-16 02:29:15 +00:00
# elif TEST_UI
extern void test_ui ( int , char * [ ] ) ;
test_ui ( local_argc , local_argv ) ;
2016-07-24 00:23:36 +00:00
# elif TEST_VM
extern void test_vm ( int , char * [ ] ) ;
test_vm ( local_argc , local_argv ) ;
2016-10-03 00:31:49 +00:00
# elif TEST_CPU
// handled above ...
2015-03-14 22:42:02 +00:00
# else
# error "OOPS, no tests specified"
# endif
}
# endif
2015-09-19 06:04:30 +00:00
static inline int _androidTouchEvent2InterfaceEvent ( jint action ) {
2015-04-02 02:59:38 +00:00
switch ( action ) {
case ANDROID_ACTION_DOWN :
return TOUCH_DOWN ;
case ANDROID_ACTION_MOVE :
return TOUCH_MOVE ;
case ANDROID_ACTION_UP :
return TOUCH_UP ;
case ANDROID_ACTION_POINTER_DOWN :
return TOUCH_POINTER_DOWN ;
case ANDROID_ACTION_POINTER_UP :
return TOUCH_POINTER_UP ;
case ANDROID_ACTION_CANCEL :
return TOUCH_CANCEL ;
default :
LOG ( " Unknown Android event : %d " , action ) ;
return TOUCH_CANCEL ;
}
}
2015-11-02 03:26:34 +00:00
static void discover_cpu_family ( void ) {
2015-11-01 21:43:09 +00:00
LOG ( " Discovering CPU family... " ) ;
AndroidCpuFamily family = android_getCpuFamily ( ) ;
uint64_t features = android_getCpuFeatures ( ) ;
if ( family = = ANDROID_CPU_FAMILY_X86 ) {
2015-11-29 22:35:01 +00:00
android_x86 = true ;
2015-11-01 21:43:09 +00:00
if ( features & ANDROID_CPU_X86_FEATURE_SSSE3 ) {
LOG ( " nANDROID_CPU_X86_FEATURE_SSSE3 " ) ;
android_x86SSSE3Enabled = true ;
}
if ( features & ANDROID_CPU_X86_FEATURE_MOVBE ) {
LOG ( " ANDROID_CPU_X86_FEATURE_MOVBE " ) ;
}
if ( features & ANDROID_CPU_X86_FEATURE_POPCNT ) {
LOG ( " ANDROID_CPU_X86_FEATURE_POPCNT " ) ;
}
} else if ( family = = ANDROID_CPU_FAMILY_ARM ) {
if ( features & ANDROID_CPU_ARM_FEATURE_ARMv7 ) {
LOG ( " ANDROID_CPU_ARM_FEATURE_ARMv7 " ) ;
android_armArchV7A = true ;
} else {
LOG ( " !!! NOT ANDROID_CPU_ARM_FEATURE_ARMv7 " ) ;
android_armArch = true ;
}
if ( features & ANDROID_CPU_ARM_FEATURE_VFPv3 ) {
LOG ( " ANDROID_CPU_ARM_FEATURE_VFPv3 " ) ;
}
if ( features & ANDROID_CPU_ARM_FEATURE_NEON ) {
LOG ( " ANDROID_CPU_ARM_FEATURE_NEON " ) ;
android_armNeonEnabled = true ;
}
if ( features & ANDROID_CPU_ARM_FEATURE_LDREX_STREX ) {
LOG ( " ANDROID_CPU_ARM_FEATURE_LDREX_STREX " ) ;
}
} else if ( family = = ANDROID_CPU_FAMILY_ARM64 ) {
# warning FIXME TODO ...
//android_arm64Arch = true;
android_armArchV7A = true ;
}
}
2015-11-02 03:26:34 +00:00
// ----------------------------------------------------------------------------
// JNI functions
2015-12-20 20:53:17 +00:00
void Java_org_deadc0de_apple2ix_Apple2Activity_nativeOnCreate ( JNIEnv * env , jclass cls , jstring j_dataDir , jint sampleRate , jint monoBufferSize , jint stereoBufferSize ) {
2015-02-23 19:19:41 +00:00
const char * dataDir = ( * env ) - > GetStringUTFChars ( env , j_dataDir , 0 ) ;
2015-04-15 04:48:55 +00:00
// Android lifecycle can call onCreate() multiple times...
if ( data_dir ) {
LOG ( " IGNORING multiple calls to nativeOnCreate ... " ) ;
return ;
}
2015-11-02 03:26:34 +00:00
discover_cpu_family ( ) ;
2015-09-27 22:04:10 +00:00
// Do not remove this deadc0de ... it forces a runtime load-library/link error on Gingerbread devices if we have
// incorrectly compiled the app against a later version of the NDK!!!
2015-09-27 21:30:20 +00:00
int pagesize = getpagesize ( ) ;
LOG ( " PAGESIZE IS : %d " , pagesize ) ;
2016-02-26 05:43:54 +00:00
data_dir = STRDUP ( dataDir ) ;
2015-09-26 22:20:54 +00:00
if ( crashHandler & & crashHandler - > init ) {
crashHandler - > init ( data_dir ) ;
2015-09-19 18:47:36 +00:00
}
2016-04-13 05:16:01 +00:00
char * home = NULL ;
ASPRINTF ( & home , " HOME=%s " , data_dir ) ;
if ( home ) {
putenv ( home ) ;
2016-04-13 05:24:04 +00:00
LEAK ( home ) ;
2016-04-13 05:16:01 +00:00
}
2015-09-19 18:47:36 +00:00
( * env ) - > ReleaseStringUTFChars ( env , j_dataDir , dataDir ) ;
LOG ( " data_dir : %s " , data_dir ) ;
2015-06-28 19:49:26 +00:00
android_deviceSampleRateHz = ( unsigned long ) sampleRate ;
2015-07-05 01:14:21 +00:00
android_monoBufferSubmitSizeSamples = ( unsigned long ) monoBufferSize ;
android_stereoBufferSubmitSizeSamples = ( unsigned long ) stereoBufferSize ;
2015-06-28 19:49:26 +00:00
2015-12-20 07:48:16 +00:00
joydriver_setClampBeyondRadius ( true ) ;
2016-01-24 17:29:47 +00:00
//#define DO_CPU65_TRACING 1
# if DO_CPU65_TRACING
# warning !!!!!!!!!! this will quickly eat up disk space !!!!!!!!!!
char * trfile = NULL ;
2016-02-26 05:43:54 +00:00
ASPRINTF ( & trfile , " %s/%s " , data_dir , " cpu_trace.txt " ) ;
2016-01-24 17:29:47 +00:00
cpu65_trace_begin ( trfile ) ;
2016-02-26 05:43:54 +00:00
FREE ( trfile ) ;
2016-01-24 17:29:47 +00:00
# endif
2016-04-13 05:24:04 +00:00
# if TESTING
_start_tests ( ) ;
2016-10-03 00:31:49 +00:00
# else
cpu_pause ( ) ;
2016-04-13 05:24:04 +00:00
emulator_start ( ) ;
2016-10-03 00:31:49 +00:00
# endif
2015-02-25 00:03:21 +00:00
}
2015-02-19 00:18:38 +00:00
2016-04-06 05:04:57 +00:00
void Java_org_deadc0de_apple2ix_Apple2View_nativeGraphicsInitialized ( JNIEnv * env , jclass cls ) {
LOG ( " ... " ) ;
_video_setRenderThread ( pthread_self ( ) ) ; // by definition, this method is called on the render thread ...
2016-04-17 19:08:11 +00:00
video_shutdown ( ) ;
2016-02-06 21:13:31 +00:00
video_init ( ) ;
2015-02-15 17:52:27 +00:00
}
2016-04-06 05:04:57 +00:00
jboolean Java_org_deadc0de_apple2ix_Apple2Activity_nativeEmulationResume ( JNIEnv * env , jclass cls ) {
2015-07-28 05:36:39 +00:00
if ( ! cpu_isPaused ( ) ) {
2016-04-06 05:04:57 +00:00
return false ;
2015-03-11 21:42:57 +00:00
}
2015-09-19 18:47:36 +00:00
LOG ( " ... " ) ;
2015-10-31 21:01:47 +00:00
cpu_resume ( ) ;
2016-04-06 05:04:57 +00:00
return true ;
2015-02-15 17:52:27 +00:00
}
2016-04-06 05:04:57 +00:00
jboolean Java_org_deadc0de_apple2ix_Apple2Activity_nativeEmulationPause ( JNIEnv * env , jclass cls ) {
2015-10-04 20:39:57 +00:00
if ( appState ! = APP_RUNNING ) {
2016-04-06 05:04:57 +00:00
return false ;
2015-09-12 22:33:22 +00:00
}
2015-12-12 07:42:57 +00:00
2016-01-24 17:29:47 +00:00
# if DO_CPU65_TRACING
cpu65_trace_checkpoint ( ) ;
# endif
2015-12-12 07:42:57 +00:00
disk6_flush ( 0 ) ;
disk6_flush ( 1 ) ;
2015-07-28 05:36:39 +00:00
if ( cpu_isPaused ( ) ) {
2016-04-06 05:04:57 +00:00
return false ;
2015-03-11 21:42:57 +00:00
}
2015-09-19 18:47:36 +00:00
LOG ( " ... " ) ;
2015-07-05 01:17:04 +00:00
2015-09-13 21:24:17 +00:00
cpu_pause ( ) ;
2016-04-06 05:04:57 +00:00
prefs_save ( ) ;
return true ;
2015-02-15 17:52:27 +00:00
}
2015-11-01 18:14:40 +00:00
void Java_org_deadc0de_apple2ix_Apple2View_nativeRender ( JNIEnv * env , jclass cls ) {
2015-10-04 21:21:28 +00:00
SCOPE_TRACE_VIDEO ( " nativeRender " ) ;
2015-10-04 20:39:57 +00:00
if ( UNLIKELY ( appState ! = APP_RUNNING ) ) {
if ( appState = = APP_REQUESTED_SHUTDOWN ) {
appState = APP_FINISHED ;
emulator_shutdown ( ) ;
}
2015-06-07 04:18:27 +00:00
return ;
}
2016-02-15 04:40:51 +00:00
//#define FPS_LOG 1
2015-02-25 00:03:21 +00:00
# if FPS_LOG
static uint32_t prevCount = 0 ;
static uint32_t idleCount = 0 ;
idleCount + + ;
static struct timespec prev = { 0 } ;
struct timespec now ;
clock_gettime ( CLOCK_MONOTONIC , & now ) ;
if ( now . tv_sec ! = prev . tv_sec ) {
2015-08-22 06:41:53 +00:00
LOG ( " FPS : %u " , idleCount - prevCount ) ;
2015-02-25 00:03:21 +00:00
prevCount = idleCount ;
prev = now ;
}
# endif
2016-02-06 21:13:31 +00:00
video_render ( ) ;
2015-02-25 00:03:21 +00:00
}
2016-04-17 18:26:35 +00:00
void Java_org_deadc0de_apple2ix_Apple2Activity_nativeReboot ( JNIEnv * env , jclass cls , jint resetState ) {
2015-09-19 18:47:36 +00:00
LOG ( " ... " ) ;
2016-04-17 18:26:35 +00:00
if ( resetState ) {
2016-04-17 19:51:23 +00:00
// joystick button settings should be balanced by c_joystick_reset() triggered on CPU thread
2016-04-17 18:26:35 +00:00
if ( resetState = = 1 ) {
joy_button0 = 0xff ;
joy_button1 = 0x0 ;
} else {
joy_button0 = 0x0 ;
joy_button1 = 0xff ;
}
}
cpu65_interrupt ( ResetSig ) ;
2015-03-11 21:42:57 +00:00
}
2015-12-20 20:53:17 +00:00
void Java_org_deadc0de_apple2ix_Apple2Activity_nativeOnQuit ( JNIEnv * env , jclass cls ) {
2015-10-04 20:39:57 +00:00
appState = APP_REQUESTED_SHUTDOWN ;
2015-09-12 22:33:22 +00:00
2015-09-19 18:47:36 +00:00
LOG ( " ... " ) ;
2015-03-11 21:42:57 +00:00
2016-01-24 17:29:47 +00:00
# if DO_CPU65_TRACING
cpu65_trace_end ( ) ;
# endif
2015-07-05 01:17:04 +00:00
cpu_resume ( ) ;
2015-03-11 21:42:57 +00:00
}
2015-12-20 20:11:12 +00:00
void Java_org_deadc0de_apple2ix_Apple2Activity_nativeOnKeyDown ( JNIEnv * env , jclass cls , jint keyCode , jint metaState ) {
2015-10-04 20:39:57 +00:00
if ( UNLIKELY ( appState ! = APP_RUNNING ) ) {
2015-09-12 22:33:22 +00:00
return ;
}
2015-03-01 05:48:08 +00:00
android_keycode_to_emulator ( keyCode , metaState , true ) ;
}
2015-12-20 20:11:12 +00:00
void Java_org_deadc0de_apple2ix_Apple2Activity_nativeOnKeyUp ( JNIEnv * env , jclass cls , jint keyCode , jint metaState ) {
2015-10-04 20:39:57 +00:00
if ( UNLIKELY ( appState ! = APP_RUNNING ) ) {
2015-09-12 22:33:22 +00:00
return ;
}
2015-03-01 05:48:08 +00:00
android_keycode_to_emulator ( keyCode , metaState , false ) ;
}
2015-03-14 22:42:02 +00:00
2015-12-20 07:48:16 +00:00
void Java_org_deadc0de_apple2ix_Apple2View_nativeOnJoystickMove ( JNIEnv * env , jclass cls , jint x , jint y ) {
joydriver_setAxisValue ( ( uint8_t ) x , ( uint8_t ) y ) ;
}
2015-12-20 06:57:08 +00:00
jlong Java_org_deadc0de_apple2ix_Apple2View_nativeOnTouch ( JNIEnv * env , jclass cls , jint action , jint pointerCount , jint pointerIndex , jfloatArray xCoords , jfloatArray yCoords ) {
2015-08-22 06:41:53 +00:00
//LOG(": %d/%d/%d :", action, pointerCount, pointerIndex);
2015-10-04 21:21:28 +00:00
SCOPE_TRACE_TOUCH ( " nativeOnTouch " ) ;
2015-10-04 20:39:57 +00:00
if ( UNLIKELY ( appState ! = APP_RUNNING ) ) {
2015-07-31 04:36:22 +00:00
return 0x0LL ;
2015-06-07 04:18:27 +00:00
}
2015-04-02 02:59:38 +00:00
jfloat * x_coords = ( * env ) - > GetFloatArrayElements ( env , xCoords , 0 ) ;
jfloat * y_coords = ( * env ) - > GetFloatArrayElements ( env , yCoords , 0 ) ;
2015-09-19 06:04:30 +00:00
int joyaction = _androidTouchEvent2InterfaceEvent ( action ) ;
2015-04-02 02:59:38 +00:00
//for (unsigned int i=0; i<pointerCount; i++) {
// LOG("\t[%f,%f]", x_coords[i], y_coords[i]);
//}
2015-07-31 04:36:22 +00:00
int64_t flags = interface_onTouchEvent ( joyaction , pointerCount , pointerIndex , x_coords , y_coords ) ;
2015-04-02 02:59:38 +00:00
( * env ) - > ReleaseFloatArrayElements ( env , xCoords , x_coords , 0 ) ;
( * env ) - > ReleaseFloatArrayElements ( env , yCoords , y_coords , 0 ) ;
2015-07-31 04:36:22 +00:00
return flags ;
2015-03-14 22:42:02 +00:00
}
2017-05-21 21:58:55 +00:00
jstring Java_org_deadc0de_apple2ix_Apple2DisksMenu_nativeChooseDisk ( JNIEnv * env , jclass cls , jstring jJsonString ) {
2016-04-13 05:24:04 +00:00
# if TESTING
2017-05-21 21:58:55 +00:00
return NULL ;
2016-04-13 05:24:04 +00:00
# endif
2015-10-31 06:15:53 +00:00
assert ( cpu_isPaused ( ) & & " considered dangerous to insert disk image when CPU thread is running " ) ;
2017-05-21 21:58:55 +00:00
const char * jsonString = ( * env ) - > GetStringUTFChars ( env , jJsonString , NULL ) ;
JSON_ref jsonData = NULL ;
bool ret = json_createFromString ( jsonString , & jsonData ) ;
assert ( ret > 0 ) ;
( * env ) - > ReleaseStringUTFChars ( env , jJsonString , jsonString ) ; jsonString = NULL ;
char * path = NULL ;
json_mapCopyStringValue ( jsonData , " disk " , & path ) ;
json_unescapeSlashes ( & path ) ;
assert ( path ! = NULL ) ;
assert ( strlen ( path ) > 0 ) ;
bool readOnly = true ;
json_mapParseBoolValue ( jsonData , " readOnly " , & readOnly ) ;
long fd = - 1 ;
bool createdFd = false ;
if ( ! json_mapParseLongValue ( jsonData , " fd " , & fd , 10 ) ) {
createdFd = true ;
TEMP_FAILURE_RETRY ( fd = open ( path , readOnly ? O_RDONLY : O_RDWR ) ) ;
if ( fd = = - 1 ) {
LOG ( " OOPS could not open disk path : %s " , path ) ;
2015-04-08 05:40:22 +00:00
}
2017-05-21 21:58:55 +00:00
}
long drive = - 1 ;
json_mapParseLongValue ( jsonData , " drive " , & drive , 10 ) ;
assert ( drive = = 0 | | drive = = 1 ) ;
bool inserted = true ;
const char * err = disk6_insert ( fd , drive , path , readOnly ) ;
if ( err ) {
char * diskImageUnreadable = " Disk Image Unreadable " ;
unsigned int cols = strlen ( diskImageUnreadable ) ;
video_animations - > animation_showMessage ( diskImageUnreadable , cols , 1 ) ;
inserted = false ;
2015-04-08 05:40:22 +00:00
} else {
2016-02-07 05:23:40 +00:00
video_animations - > animation_showDiskChosen ( drive ) ;
2017-05-29 17:24:30 +00:00
// possibly override was_gzipped, if specified in args ...
bool wasGzipped = false ;
if ( json_mapParseBoolValue ( jsonData , " wasGzipped " , & wasGzipped ) ) {
disk6 . disk [ drive ] . was_gzipped = wasGzipped ;
}
2015-04-08 05:40:22 +00:00
}
2017-05-21 21:58:55 +00:00
2017-05-29 17:24:30 +00:00
// remember if image was gzipped
prefs_setBoolValue ( PREF_DOMAIN_VM , drive = = 0 ? PREF_DISK_DRIVEA_GZ : PREF_DISK_DRIVEB_GZ , disk6 . disk [ drive ] . was_gzipped ) ; // HACK FIXME TODO ... refactor : this is erased on the Java side when we resume emulation
json_mapSetBoolValue ( jsonData , " wasGzipped " , disk6 . disk [ drive ] . was_gzipped ) ;
2017-05-21 21:58:55 +00:00
json_mapSetBoolValue ( jsonData , " inserted " , inserted ) ;
if ( createdFd ) {
TEMP_FAILURE_RETRY ( close ( fd ) ) ;
fd = - 1 ;
}
if ( path ) {
FREE ( path ) ;
}
jsonString = ( ( JSON_s * ) jsonData ) - > jsonString ;
jstring jstr = ( * env ) - > NewStringUTF ( env , jsonString ) ;
json_destroy ( & jsonData ) ;
LOG ( " : (fd:%d, %s, %s, %s) " , ( int ) fd , path , drive ? " drive A " : " drive B " , readOnly ? " read only " : " read/write " ) ;
return jstr ;
2015-04-08 05:40:22 +00:00
}
2016-04-06 05:04:57 +00:00
void Java_org_deadc0de_apple2ix_Apple2DisksMenu_nativeEjectDisk ( JNIEnv * env , jclass cls , jboolean driveA ) {
2017-05-21 21:58:55 +00:00
# if TESTING
return ;
# endif
2015-09-19 18:47:36 +00:00
LOG ( " ... " ) ;
2017-05-21 21:58:55 +00:00
disk6_eject ( driveA ? 0 : 1 ) ;
2015-08-22 21:16:56 +00:00
}
2015-12-20 20:53:17 +00:00
void Java_org_deadc0de_apple2ix_Apple2Activity_nativeSaveState ( JNIEnv * env , jclass cls , jstring jPath ) {
2015-11-23 03:04:46 +00:00
const char * path = ( * env ) - > GetStringUTFChars ( env , jPath , NULL ) ;
2015-12-20 06:57:08 +00:00
assert ( cpu_isPaused ( ) & & " considered dangerous to save state when CPU thread is running " ) ;
2015-11-23 03:04:46 +00:00
LOG ( " : (%s) " , path ) ;
if ( ! emulator_saveState ( path ) ) {
LOG ( " OOPS, could not save emulator state " ) ;
}
( * env ) - > ReleaseStringUTFChars ( env , jPath , path ) ;
}
2017-05-21 21:58:55 +00:00
jstring Java_org_deadc0de_apple2ix_Apple2Activity_nativeLoadState ( JNIEnv * env , jclass cls , jstring jJsonString ) {
assert ( cpu_isPaused ( ) & & " considered dangerous to load state when CPU thread is running " ) ;
const char * jsonString = ( * env ) - > GetStringUTFChars ( env , jJsonString , NULL ) ;
LOG ( " : %s " , jsonString ) ;
JSON_ref jsonData = NULL ;
int ret = json_createFromString ( jsonString , & jsonData ) ;
assert ( ret > 0 ) ;
( * env ) - > ReleaseStringUTFChars ( env , jJsonString , jsonString ) ; jsonString = NULL ;
char * path = NULL ;
json_mapCopyStringValue ( jsonData , " stateFile " , & path ) ;
json_unescapeSlashes ( & path ) ;
bool readOnlyA = true ;
json_mapParseBoolValue ( jsonData , " readOnlyA " , & readOnlyA ) ;
bool createdFdA = false ;
long fdA = - 1 ;
if ( ! json_mapParseLongValue ( jsonData , " fdA " , & fdA , 10 ) ) {
char * pathA = NULL ;
json_mapCopyStringValue ( jsonData , " diskA " , & pathA ) ;
json_unescapeSlashes ( & pathA ) ;
2017-05-29 17:24:30 +00:00
TEMP_FAILURE_RETRY ( fdA = open ( pathA , readOnlyA ? O_RDONLY : O_RDWR ) ) ;
if ( fdA = = - 1 ) {
LOG ( " OOPS could not open disk path %s " , pathA ) ;
}
2017-05-21 21:58:55 +00:00
createdFdA = fdA > 0 ;
FREE ( pathA ) ;
}
bool readOnlyB = true ;
json_mapParseBoolValue ( jsonData , " readOnlyB " , & readOnlyB ) ;
bool createdFdB = false ;
long fdB = - 1 ;
if ( ! json_mapParseLongValue ( jsonData , " fdB " , & fdB , 10 ) ) {
char * pathB = NULL ;
json_mapCopyStringValue ( jsonData , " diskB " , & pathB ) ;
json_unescapeSlashes ( & pathB ) ;
2017-05-29 17:24:30 +00:00
TEMP_FAILURE_RETRY ( fdB = open ( pathB , readOnlyB ? O_RDONLY : O_RDWR ) ) ;
if ( fdB = = - 1 ) {
LOG ( " OOPS could not open disk path %s " , pathB ) ;
}
2017-05-21 21:58:55 +00:00
createdFdB = fdB > 0 ;
FREE ( pathB ) ;
}
bool loadStateSuccess = true ;
2017-05-29 17:24:30 +00:00
if ( emulator_loadState ( path , ( int ) fdA , ( int ) fdB ) ) {
json_mapSetBoolValue ( jsonData , " wasGzippedA " , disk6 . disk [ 0 ] . was_gzipped ) ;
json_mapSetBoolValue ( jsonData , " wasGzippedB " , disk6 . disk [ 1 ] . was_gzipped ) ;
} else {
2017-05-21 21:58:55 +00:00
loadStateSuccess = false ;
LOG ( " OOPS, could not load emulator state " ) ;
2017-05-29 17:24:30 +00:00
// FIXME TODO : should show invalid state animation here ...
2017-05-21 21:58:55 +00:00
}
if ( createdFdA ) {
TEMP_FAILURE_RETRY ( close ( fdA ) ) ;
}
if ( createdFdB ) {
TEMP_FAILURE_RETRY ( close ( fdB ) ) ;
}
json_mapSetBoolValue ( jsonData , " loadStateSuccess " , loadStateSuccess ) ;
jsonString = ( ( JSON_s * ) jsonData ) - > jsonString ;
jstring jstr = ( * env ) - > NewStringUTF ( env , jsonString ) ;
FREE ( path ) ;
json_destroy ( & jsonData ) ;
return jstr ;
}
jstring Java_org_deadc0de_apple2ix_Apple2Activity_nativeStateExtractDiskPaths ( JNIEnv * env , jclass cls , jstring jPath ) {
2015-11-23 03:04:46 +00:00
const char * path = ( * env ) - > GetStringUTFChars ( env , jPath , NULL ) ;
2015-12-20 06:57:08 +00:00
assert ( cpu_isPaused ( ) & & " considered dangerous to save state when CPU thread is running " ) ;
2015-11-23 03:04:46 +00:00
LOG ( " : (%s) " , path ) ;
2017-05-21 21:58:55 +00:00
JSON_ref jsonData ;
2017-06-07 09:21:48 +00:00
bool ret = json_createFromString ( " {} " , & jsonData ) ;
assert ( ret > = 0 & & " should be able to create JSON " ) ;
2017-05-21 21:58:55 +00:00
if ( ! emulator_stateExtractDiskPaths ( path , & jsonData ) ) {
LOG ( " OOPS, could not extract disk paths from emulator state file " ) ;
2015-11-23 03:04:46 +00:00
}
2017-05-21 21:58:55 +00:00
char * jsonString = ( ( JSON_s * ) jsonData ) - > jsonString ;
jstring jstr = ( * env ) - > NewStringUTF ( env , jsonString ) ;
json_destroy ( & jsonData ) ;
2015-12-12 19:42:33 +00:00
2017-06-07 09:21:48 +00:00
( * env ) - > ReleaseStringUTFChars ( env , jPath , path ) ;
2015-12-12 19:42:33 +00:00
return jstr ;
2015-11-23 03:04:46 +00:00
}
2016-04-06 05:04:57 +00:00
void Java_org_deadc0de_apple2ix_Apple2Preferences_nativePrefsSync ( JNIEnv * env , jclass cls , jstring jDomain ) {
const char * domain = NULL ;
if ( jDomain ) {
domain = ( * env ) - > GetStringUTFChars ( env , jDomain , 0 ) ;
}
LOG ( " ... domain: %s " , domain ) ;
prefs_load ( ) ;
prefs_sync ( domain ) ;
if ( jDomain ) {
( * env ) - > ReleaseStringUTFChars ( env , jDomain , domain ) ;
}
}