forked from LeenkxTeam/LNXSDK
		
	
		
			
	
	
		
			470 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			470 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
|  | #ifndef HX_CFFI_H
 | ||
|  | #define HX_CFFI_H
 | ||
|  | 
 | ||
|  | // 410 - adds gc_try_unblocking
 | ||
|  | #define HX_CFFI_API_VERSION 410
 | ||
|  | 
 | ||
|  | #ifdef HXCPP_JS_PRIME
 | ||
|  | #include <emscripten/bind.h>
 | ||
|  | using namespace emscripten; | ||
|  | 
 | ||
|  | typedef struct emscripten::val value; | ||
|  | typedef struct _vkind  *vkind; | ||
|  | typedef struct _buffer  *buffer; | ||
|  | #define HAVE_NEKO_TYPES 1
 | ||
|  | #endif
 | ||
|  | 
 | ||
|  | #include "OS.h"
 | ||
|  | #include <stdio.h>
 | ||
|  | #include <stdlib.h>
 | ||
|  | #include <string.h>
 | ||
|  | #if defined(BLACKBERRY)
 | ||
|  | using namespace std; | ||
|  | #endif
 | ||
|  | // --- Register functions (primitives) ----
 | ||
|  | 
 | ||
|  | #ifdef STATIC_LINK
 | ||
|  | 
 | ||
|  | #define DEFINE_PRIM_MULT(func) \
 | ||
|  | int __reg_##func = hx_register_prim(#func "__MULT",(void *)(&func)); \ | ||
|  | 
 | ||
|  | #define DEFINE_PRIM(func,nargs) \
 | ||
|  | int __reg_##func = hx_register_prim(#func "__" #nargs,(void *)(&func)); \ | ||
|  | 
 | ||
|  | 
 | ||
|  | #define DEFINE_PRIM_MULT_NATIVE(func,ext) \
 | ||
|  | int __reg_##func = hx_register_prim(#func "__MULT",(void *)(&func)) + \ | ||
|  |                    hx_register_prim(#func "__"  #ext,(void *)(&func##_##ext)) ;  | ||
|  | 
 | ||
|  | #define DEFINE_PRIM_NATIVE(func,nargs,ext) \
 | ||
|  | int __reg_##func = hx_register_prim(#func "__" #nargs,(void *)(&func)) + \ | ||
|  |                    hx_register_prim(#func "__" #ext,(void *)(&func##_##ext)) ;  | ||
|  | 
 | ||
|  | 
 | ||
|  | #define DEFINE_LIB_PRIM_MULT(lib,func) \
 | ||
|  | int __reg_##func = hx_register_prim(lib "_" #func "__MULT",(void *)(&func)); \ | ||
|  | 
 | ||
|  | #define DEFINE_LIB_PRIM(lib,func,nargs) \
 | ||
|  | int __reg_##func = hx_register_prim(lib "_" #func "__" #nargs,(void *)(&func)); \ | ||
|  | 
 | ||
|  | 
 | ||
|  | #elif defined(HXCPP_JS_PRIME)
 | ||
|  | 
 | ||
|  | //#define DEFINE_PRIM_MULT(func) EMSCRIPTEN_BINDINGS(func) { function(#func, &func); }
 | ||
|  | //TODO
 | ||
|  | #define DEFINE_PRIM_MULT(func)
 | ||
|  | 
 | ||
|  | #define DEFINE_PRIM(func,nargs) EMSCRIPTEN_BINDINGS(func) { function(#func, &func); }
 | ||
|  | 
 | ||
|  | 
 | ||
|  | #else
 | ||
|  | 
 | ||
|  | 
 | ||
|  | #define DEFINE_PRIM_MULT(func) extern "C" { \
 | ||
|  |   EXPORT void *func##__MULT() { return (void*)(&func); } \ | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | #define DEFINE_PRIM(func,nargs) extern "C" { \
 | ||
|  |   EXPORT void *func##__##nargs() { return (void*)(&func); } \ | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | #define DEFINE_PRIM_MULT_NATIVE(func,ext) extern "C" { \
 | ||
|  |   EXPORT void *func##__MULT() { return (void*)(&func); } \ | ||
|  |   EXPORT void *func##__##ext() { return (void*)(&func##_##ext); } \ | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | #define DEFINE_PRIM_NATIVE(func,nargs,ext) extern "C" { \
 | ||
|  |   EXPORT void *func##__##nargs() { return (void*)(&func); } \ | ||
|  |   EXPORT void *func##__##ext() { return (void*)(&func##_##ext); } \ | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | #define DEFINE_LIB_PRIM_MULT(lib,func) extern "C" { \
 | ||
|  |   EXPORT void *func##__MULT() { return (void*)(&func); } \ | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | #define DEFINE_LIB_PRIM(lib,func,nargs) extern "C" { \
 | ||
|  |   EXPORT void *func##__##nargs() { return (void*)(&func); } \ | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | #endif // !STATIC_LINK
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  |   | ||
|  | #define DEFFUNC_0(ret,name) DEFFUNC(name,ret, (), ())
 | ||
|  | #define DEFFUNC_1(ret,name,t1) DEFFUNC(name,ret, (t1 a1), (a1))
 | ||
|  | #define DEFFUNC_2(ret,name,t1,t2) DEFFUNC(name,ret, (t1 a1, t2 a2), (a1,a2))
 | ||
|  | #define DEFFUNC_3(ret,name,t1,t2,t3) DEFFUNC(name,ret, (t1 a1, t2 a2, t3 a3), (a1,a2,a3))
 | ||
|  | #define DEFFUNC_4(ret,name,t1,t2,t3,t4) DEFFUNC(name,ret, (t1 a1, t2 a2, t3 a3, t4 a4), (a1,a2,a3,a4))
 | ||
|  | #define DEFFUNC_5(ret,name,t1,t2,t3,t4,t5) DEFFUNC(name,ret, (t1 a1, t2 a2, t3 a3, t4 a4,t5 a5), (a1,a2,a3,a4,a5))
 | ||
|  |   | ||
|  | 
 | ||
|  | enum hxValueType | ||
|  | { | ||
|  |    valtUnknown = -1, | ||
|  |    valtInt = 0xff, | ||
|  |    valtNull = 0, | ||
|  |    valtFloat = 1, | ||
|  |    valtBool = 2, | ||
|  |    valtString = 3, | ||
|  |    valtObject = 4, | ||
|  |    valtArray = 5, | ||
|  |    valtFunction = 6, | ||
|  |    valtEnum, | ||
|  |    valtClass, | ||
|  |    valtRoot = 0xff, | ||
|  |    valtAbstractBase = 0x100, | ||
|  | }; | ||
|  | 
 | ||
|  | namespace hx | ||
|  | { | ||
|  | enum StringEncoding | ||
|  | { | ||
|  |    StringAscii, | ||
|  |    StringUtf8, | ||
|  |    StringUtf16 | ||
|  | }; | ||
|  | } | ||
|  | 
 | ||
|  | // val_fun_nargs may return a special value
 | ||
|  | enum { faNotFunction = -2, faVarArgs=-1, faArgs0=0 /* ... */ }; | ||
|  | 
 | ||
|  | typedef int field; | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | #ifdef IMPLEMENT_API
 | ||
|  | #include "CFFILoader.h"
 | ||
|  | #endif
 | ||
|  | 
 | ||
|  | 
 | ||
|  | #if !defined(HAVE_NEKO_TYPES)
 | ||
|  | #ifdef HXCPP_NATIVE_CFFI_VALUE
 | ||
|  | namespace hx { class Object; } | ||
|  | typedef hx::Object _value; | ||
|  | #else
 | ||
|  | struct _value; | ||
|  | #endif
 | ||
|  | typedef _value *value; | ||
|  | typedef struct _vkind  *vkind; | ||
|  | typedef struct _buffer  *buffer; | ||
|  | #endif
 | ||
|  | 
 | ||
|  | typedef buffer cffiByteBuffer; | ||
|  | 
 | ||
|  | typedef struct _gcroot  *gcroot; | ||
|  | 
 | ||
|  | typedef void (*hxFinalizer)(value v); | ||
|  | typedef void (*hxPtrFinalizer)(void *v); | ||
|  | 
 | ||
|  | typedef void (__hx_field_iter)(value v,field f,void *); | ||
|  | 
 | ||
|  | #define hx_failure(msg)		hx_fail(msg,__FILE__,__LINE__)
 | ||
|  | 
 | ||
|  | #ifndef IGNORE_CFFI_API_H
 | ||
|  | 
 | ||
|  | 
 | ||
|  | #ifndef IMPLEMENT_API
 | ||
|  |   | ||
|  | #if defined(STATIC_LINK) || defined(HXCPP_JS_PRIME)
 | ||
|  | 
 | ||
|  | #define DEFFUNC(name,ret,def_args,call_args) \
 | ||
|  | extern "C" ret name def_args; | ||
|  | 
 | ||
|  | 
 | ||
|  | #else
 | ||
|  | 
 | ||
|  | #define DEFFUNC(name,ret,def_args,call_args) \
 | ||
|  | typedef ret (*FUNC_##name) def_args; \ | ||
|  | extern FUNC_##name name; | ||
|  | 
 | ||
|  | #endif
 | ||
|  | 
 | ||
|  | #endif
 | ||
|  |   | ||
|  | 
 | ||
|  | #include "CFFIAPI.h"
 | ||
|  | 
 | ||
|  | 
 | ||
|  | #ifdef WANT_DYNALLOC_ALLOC_BYTES
 | ||
|  | void *DynAlloc::allocBytes(size_t n) | ||
|  | { | ||
|  |    return hx_alloc((int)n); | ||
|  | } | ||
|  | #endif
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | #define DEFINE_KIND(name) extern "C" { vkind name = 0; }
 | ||
|  | 
 | ||
|  | #ifdef STATIC_LINK
 | ||
|  | #	define DEFINE_ENTRY_POINT(name)
 | ||
|  | #else
 | ||
|  | #	define DEFINE_ENTRY_POINT(name) extern "C" {  void name(); EXPORT void *__neko_entry_point() { return (void *)&name; } }
 | ||
|  | #endif
 | ||
|  | 
 | ||
|  | #ifdef HEADER_IMPORTS
 | ||
|  | #	define H_EXTERN IMPORT
 | ||
|  | #else
 | ||
|  | #	define H_EXTERN EXPORT
 | ||
|  | #endif
 | ||
|  | 
 | ||
|  | #define DECLARE_PRIM(func,nargs) extern "C" {  H_EXTERN void *func##__##nargs(); }
 | ||
|  | #define DECLARE_KIND(name) extern "C" {  H_EXTERN extern vkind name; }
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | // --- Helpers ----------------------------------------------------------------
 | ||
|  | 
 | ||
|  | // Check type...
 | ||
|  | inline bool val_is_null(value inVal) { return val_type(inVal)==valtNull; } | ||
|  | inline bool val_is_int(value inVal) { return val_type(inVal)==valtInt; } | ||
|  | inline bool val_is_bool(value inVal) { return val_type(inVal)==valtBool; } | ||
|  | inline bool val_is_float(value inVal) { return val_type(inVal)==valtFloat; } | ||
|  | inline bool val_is_string(value inVal) { return val_type(inVal)==valtString; } | ||
|  | inline bool val_is_function(value inVal) { return val_type(inVal)==valtFunction; } | ||
|  | inline bool val_is_array(value inVal) { return val_type(inVal)==valtArray; } | ||
|  | inline bool val_is_abstract(value inVal) { return val_type(inVal)>=valtAbstractBase; } | ||
|  | inline bool val_is_kind(value inVal,vkind inKind) { return val_to_kind(inVal,inKind)!=0; } | ||
|  | 
 | ||
|  | inline bool val_is_number(value inVal) | ||
|  | { | ||
|  | 	int t = val_type(inVal); | ||
|  | 	return t==valtInt || t==valtFloat; | ||
|  | } | ||
|  | inline bool val_is_object(value inVal) | ||
|  | { | ||
|  | 	int t = val_type(inVal); | ||
|  | 	return t==valtObject || t==valtEnum ||t==valtClass; | ||
|  | } | ||
|  | 
 | ||
|  | class AutoGCBlocking | ||
|  | { | ||
|  | public: | ||
|  | 	inline AutoGCBlocking(bool inSoftUnlock=false) : | ||
|  |       mSoftUnlock(inSoftUnlock), mLocked( gc_try_blocking() ) {  } | ||
|  | 	inline ~AutoGCBlocking() { Close(); } | ||
|  | 	inline void Close() | ||
|  |    { | ||
|  |       if (mLocked) | ||
|  |       { | ||
|  |          if (mSoftUnlock) | ||
|  |             gc_try_unblocking(); | ||
|  |          else | ||
|  |             gc_exit_blocking(); | ||
|  |       } | ||
|  |       mLocked = false; | ||
|  |    } | ||
|  | 
 | ||
|  | 	bool mLocked; | ||
|  | 	bool mSoftUnlock; | ||
|  | }; | ||
|  | 
 | ||
|  | class AutoGCUnblocking | ||
|  | { | ||
|  | public: | ||
|  | 	AutoGCUnblocking() : mUnlocked( gc_try_unblocking() ) {  } | ||
|  | 	~AutoGCUnblocking() { Close(); } | ||
|  | 	void Close() { if (mUnlocked) gc_enter_blocking(); mUnlocked = false; } | ||
|  | 
 | ||
|  | 	bool mUnlocked; | ||
|  | }; | ||
|  | 
 | ||
|  | 
 | ||
|  | class AutoGCRoot | ||
|  | { | ||
|  | public: | ||
|  |    AutoGCRoot(value inValue) | ||
|  |    { | ||
|  | 		mRoot = 0; | ||
|  | 		mPtr = alloc_root(); | ||
|  | 		if (mPtr) | ||
|  | 			*mPtr = inValue; | ||
|  | 		else | ||
|  | 			mRoot = create_root(inValue); | ||
|  |    } | ||
|  | 
 | ||
|  |   ~AutoGCRoot() | ||
|  |    { | ||
|  | 		if (mPtr) | ||
|  | 			free_root(mPtr); | ||
|  | 		else if (mRoot) | ||
|  |          destroy_root(mRoot); | ||
|  |    } | ||
|  |    value get()const { return mPtr ? *mPtr : query_root(mRoot); } | ||
|  |    void set(value inValue) | ||
|  | 	{  | ||
|  | 		if (mPtr) | ||
|  | 			*mPtr = inValue; | ||
|  | 		else | ||
|  | 		{ | ||
|  | 			if (mRoot) destroy_root(mRoot); | ||
|  | 			mRoot = create_root(inValue); | ||
|  | 		} | ||
|  | 	} | ||
|  |     | ||
|  | private: | ||
|  |    value *mPtr; | ||
|  |    gcroot mRoot; | ||
|  |    AutoGCRoot(const AutoGCRoot &); | ||
|  |    void operator=(const AutoGCRoot &); | ||
|  | }; | ||
|  | 
 | ||
|  | struct CffiBytes | ||
|  | { | ||
|  |    CffiBytes( unsigned char *inData=0, int inLength=0) : data(inData), length(inLength) {} | ||
|  | 
 | ||
|  |    unsigned char *data; | ||
|  |    int length; | ||
|  | }; | ||
|  | 
 | ||
|  | inline CffiBytes getByteData(value inValue) | ||
|  | { | ||
|  |    static field bField = 0; | ||
|  |    static field lengthField = 0; | ||
|  |    if (bField==0) | ||
|  |    { | ||
|  |       bField = val_id("b"); | ||
|  |       lengthField = val_id("length"); | ||
|  |    } | ||
|  | 
 | ||
|  |    if (val_is_object(inValue)) | ||
|  |    { | ||
|  |       value b = val_field(inValue, bField); | ||
|  |       value len = val_field(inValue, lengthField); | ||
|  |       if (val_is_string(b) && val_is_int(len)) | ||
|  |          return CffiBytes( (unsigned char *)val_string(b), val_int(len) ); | ||
|  |       if (val_is_buffer(b) && val_is_int(len)) | ||
|  |          return CffiBytes( (unsigned char *)buffer_data(val_to_buffer(b)), val_int(len) ); | ||
|  |    } | ||
|  |    else if (val_is_buffer(inValue)) | ||
|  |    { | ||
|  |       value len = val_field(inValue, lengthField); | ||
|  |       if (val_is_int(len)) | ||
|  |       { | ||
|  |          buffer b = val_to_buffer(inValue); | ||
|  |          return CffiBytes( (unsigned char *)buffer_data(b), val_int(len) ); | ||
|  |       } | ||
|  |    } | ||
|  |    return CffiBytes(); | ||
|  | } | ||
|  | 
 | ||
|  | inline bool resizeByteData(value inValue, int inNewLen) | ||
|  | { | ||
|  |    if (!val_is_object(inValue)) | ||
|  |       return false; | ||
|  | 
 | ||
|  |    static field bField = 0; | ||
|  |    static field lengthField = 0; | ||
|  |    if (bField==0) | ||
|  |    { | ||
|  |       bField = val_id("b"); | ||
|  |       lengthField = val_id("length"); | ||
|  |    } | ||
|  |    value len = val_field(inValue, lengthField); | ||
|  |    if (!val_is_int(len)) | ||
|  |       return false; | ||
|  |    int oldLen = val_int(len); | ||
|  |    value b = val_field(inValue, bField); | ||
|  |    if (val_is_string(b)) | ||
|  |    { | ||
|  |       if (inNewLen>oldLen) | ||
|  |       { | ||
|  |          value newString = alloc_raw_string(inNewLen); | ||
|  |          memcpy( (char *)val_string(newString), val_string(b), inNewLen); | ||
|  |          alloc_field(inValue, bField, newString ); | ||
|  |       } | ||
|  |       alloc_field(inValue, lengthField, alloc_int(inNewLen) ); | ||
|  |    } | ||
|  |    else if (val_is_buffer(b)) | ||
|  |    { | ||
|  |       cffiByteBuffer buf = val_to_buffer(b); | ||
|  |       buffer_set_size(buf,inNewLen); | ||
|  |       alloc_field(inValue, lengthField, alloc_int(inNewLen) ); | ||
|  |    } | ||
|  |    else | ||
|  |       return false; | ||
|  | 
 | ||
|  |    return true; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | #define val_null alloc_null()
 | ||
|  | 
 | ||
|  | #define bfailure(x) val_throw(buffer_to_string(x))
 | ||
|  | 
 | ||
|  | #define copy_string(str,len) alloc_string_len(str,len)
 | ||
|  | 
 | ||
|  | 
 | ||
|  | // The "Check" macros throw an error if assumtion is false
 | ||
|  | #define val_check_kind(v,t)	if( !val_is_kind(v,t) ) hx_failure("invalid kind");
 | ||
|  | #define val_check_function(f,n) if( !val_is_function(f) || (val_fun_nargs(f) != (n) && val_fun_nargs(f) != faVarArgs) ) hx_failure("Bad function");
 | ||
|  | #define val_check(v,t)		if( !val_is_##t(v) ) hx_failure("type not " #t);
 | ||
|  | 
 | ||
|  | // The "Get" function will return or force an error
 | ||
|  | inline bool val_get_bool(value inVal) {  val_check(inVal,bool); return val_bool(inVal); } | ||
|  | inline int val_get_int(value inVal) {  val_check(inVal,int); return val_int(inVal); } | ||
|  | inline double val_get_double(value inVal) {  val_check(inVal,number); return val_number(inVal); } | ||
|  | inline const char *val_get_string(value inVal) {  val_check(inVal,string); return val_string(inVal); } | ||
|  | inline void *val_get_handle(value inVal,vkind inKind) | ||
|  |   {  val_check_kind(inVal,inKind); return val_to_kind(inVal,inKind); } | ||
|  | 
 | ||
|  | 
 | ||
|  | inline value alloc_string(const char *inStr) | ||
|  | { | ||
|  |    const char *end = inStr; | ||
|  |    while(*end) end++; | ||
|  |    return alloc_string_len(inStr,(int)(end-inStr)); | ||
|  | } | ||
|  | 
 | ||
|  | inline value alloc_wstring(const wchar_t *inStr) | ||
|  | { | ||
|  |    const wchar_t *end = inStr; | ||
|  |    while(*end) end++; | ||
|  |    return alloc_wstring_len(inStr,(int)(end-inStr)); | ||
|  | } | ||
|  | 
 | ||
|  | inline void hxcpp_unscramble(const unsigned char *bytes, int len, const char *key, unsigned char *dest) | ||
|  | { | ||
|  |    int keyLen = 0; | ||
|  |    while(key[keyLen]) | ||
|  |       keyLen++; | ||
|  |    int state = 0; | ||
|  |    //state = ((state + key[i]) ^ ch) & 0xff);
 | ||
|  |    for(int i=0;i<len;i++) | ||
|  |    { | ||
|  |       dest[i] = ( (state + key[i%keyLen]) ^ bytes[i] ) & 0xff; | ||
|  |       state = bytes[i]; | ||
|  |    } | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | //additional glue for easier neko modules compilation
 | ||
|  | #define val_true    alloc_bool(true)
 | ||
|  | #define val_false    alloc_bool(false)
 | ||
|  | inline void neko_error() { hx_error(); } | ||
|  | 
 | ||
|  | 
 | ||
|  | // Conservative marking within a buffer is not yet supported.
 | ||
|  | //inline void * alloc(int i) { return hx_alloc(i); }
 | ||
|  | 
 | ||
|  | // The bytes themselves will be GC'd, but not the pointers contained within.
 | ||
|  | inline void * alloc_private(int i) { return hx_alloc(i); } | ||
|  | 
 | ||
|  | // You should use alloc_buffer_len/buffer_data instead
 | ||
|  | //value alloc_empty_string(int len) { }
 | ||
|  | 
 | ||
|  | 
 | ||
|  | #endif
 | ||
|  | 
 | ||
|  | 
 | ||
|  | #endif
 |