331 lines
		
	
	
		
			8.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			331 lines
		
	
	
		
			8.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
|  | #ifndef HX_CFFI_LOADER_H
 | ||
|  | #define HX_CFFI_LOADER_H
 | ||
|  | 
 | ||
|  | /*
 | ||
|  |   This file will only be incuded in one cpp file in the ndll library - | ||
|  |     the one with IMPLEMENT_API #defined. | ||
|  | 
 | ||
|  |   The other files will refer to the val_ functions via the "extern" in CFFI.h | ||
|  | 
 | ||
|  |   For dynamic linking, a macro (DEFFUNC) implements the "val_..." functions as function pointers, | ||
|  |    and the cpp code calls these function pointers directly. | ||
|  |   The pointers starts off as function pointers to bootstrap code, so when they are first called | ||
|  |    the bootstrap uses the "ResolveProc" to find the correct version of the function for the particular | ||
|  |    platform, and replaces the function pointer with this value. Subsequent calls then go directly | ||
|  |    to the correct fucntion. | ||
|  | 
 | ||
|  |   The ResolveProc can come from: | ||
|  |    Explicitly setting - the proc is set when a dll is loaded into the hxcpp exe | ||
|  |    Via 'GetProcAddress' on the exe - if symbols are needed and the proc has not been set | ||
|  |    Internal implementation (CFFINekoLoader) - when linking agaist a neko process. | ||
|  |     - Old code used to find this in NekoApi.dll, but the glue code is now built into each ndll directly. | ||
|  | 
 | ||
|  |   For static linking, the functions are resolved at link time. | ||
|  | 
 | ||
|  |   For HXCPP_JS_PRIME, these functions are implemented in CFFIJsPrime | ||
|  | */ | ||
|  | 
 | ||
|  | #ifdef ANDROID
 | ||
|  | #include <android/log.h>
 | ||
|  | #endif
 | ||
|  | 
 | ||
|  | #ifdef NEKO_WINDOWS
 | ||
|  | #include <windows.h>
 | ||
|  | #include <stdio.h>
 | ||
|  | // Stoopid windows ...
 | ||
|  | #ifdef RegisterClass
 | ||
|  | #undef RegisterClass
 | ||
|  | #endif
 | ||
|  | #ifdef abs
 | ||
|  | #undef abs
 | ||
|  | #endif
 | ||
|  | 
 | ||
|  | #else // NOT NEKO_WINDOWS
 | ||
|  | 
 | ||
|  | #ifdef NEKO_LINUX
 | ||
|  | #define EXT "dso"
 | ||
|  | #define NEKO_EXT "so"
 | ||
|  | //#define __USE_GNU 1
 | ||
|  | 
 | ||
|  | #elif defined(HX_MACOS)
 | ||
|  | #include <mach-o/dyld.h>
 | ||
|  | #define EXT "dylib"
 | ||
|  | #define NEKO_EXT "dylib"
 | ||
|  | 
 | ||
|  | #else
 | ||
|  | #if defined(EMSCRIPTEN)
 | ||
|  | #define EXT "ll"
 | ||
|  | #else
 | ||
|  | #define EXT "so"
 | ||
|  | #endif
 | ||
|  | 
 | ||
|  | #endif
 | ||
|  | 
 | ||
|  | #include <dlfcn.h>
 | ||
|  | #include <stdio.h>
 | ||
|  | #include <stdlib.h>
 | ||
|  | #include <memory.h>
 | ||
|  | 
 | ||
|  | 
 | ||
|  | #endif
 | ||
|  | #if defined(BLACKBERRY)
 | ||
|  | using namespace std; | ||
|  | #endif
 | ||
|  | typedef void *(*ResolveProc)(const char *inName); | ||
|  | static ResolveProc sResolveProc = 0; | ||
|  | 
 | ||
|  | extern "C" { | ||
|  | EXPORT void hx_set_loader(ResolveProc inProc) | ||
|  | { | ||
|  |    #ifdef ANDROID
 | ||
|  |    __android_log_print(ANDROID_LOG_INFO, "haxe plugin", "Got Load Proc %p", inProc ); | ||
|  |    #endif
 | ||
|  |    sResolveProc = inProc; | ||
|  | } | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | #ifdef HXCPP_JS_PRIME // { js prime
 | ||
|  | 
 | ||
|  | #define DEFFUNC(name,ret,def_args,call_args) \
 | ||
|  | extern "C" ret name def_args; | ||
|  | 
 | ||
|  | #include "CFFIJsPrime.h"
 | ||
|  | 
 | ||
|  | #elif defined(STATIC_LINK)  // js prime }   { not js prime, static link
 | ||
|  | 
 | ||
|  | #define DEFFUNC(name,ret,def_args,call_args) \
 | ||
|  | extern "C" ret name def_args; | ||
|  | 
 | ||
|  | #else  // static link }   { Dynamic link
 | ||
|  | 
 | ||
|  |    #ifdef NEKO_COMPATIBLE
 | ||
|  | 
 | ||
|  |       #include "CFFINekoLoader.h"
 | ||
|  | 
 | ||
|  |    #endif // NEKO_COMPATIBLE
 | ||
|  | 
 | ||
|  | 
 | ||
|  |    // This code will get run when the library is compiled against a newer version of hxcpp,
 | ||
|  |    //  and the application code uses an older version.
 | ||
|  |    bool default_val_is_buffer(void *inBuffer) | ||
|  |    { | ||
|  |       typedef void *(ValToBufferFunc)(void *); | ||
|  |       static ValToBufferFunc *valToBuffer = 0; | ||
|  |       if (!valToBuffer) | ||
|  |          valToBuffer = (ValToBufferFunc *)sResolveProc("val_to_buffer"); | ||
|  | 
 | ||
|  |       if (valToBuffer) | ||
|  |          return valToBuffer(inBuffer)!=0; | ||
|  | 
 | ||
|  |       return false; | ||
|  |    } | ||
|  | 
 | ||
|  |    // Neko, old cpp and js_prime are all utf8 based - and go through here
 | ||
|  |    #ifdef HXCPP_PRIME
 | ||
|  |    struct DynAlloc : public hx::IStringAlloc | ||
|  |    { | ||
|  |       #define WANT_DYNALLOC_ALLOC_BYTES
 | ||
|  |       void *allocBytes(size_t n); | ||
|  |    }; | ||
|  | 
 | ||
|  | 
 | ||
|  |    HxString default_string_wchar(const wchar_t *src,int len) | ||
|  |    { | ||
|  |       hx::strbuf buf; | ||
|  |       const char *str = cffi::to_utf8(src,len,&buf); | ||
|  |       return HxString(str,len); | ||
|  |    } | ||
|  |    HxString default_string_utf8(const char *str,int len) | ||
|  |    { | ||
|  |       return HxString(str,len); | ||
|  |    } | ||
|  |    HxString default_string_utf16(const char16_t *src,int len) | ||
|  |    { | ||
|  |       hx::strbuf buf; | ||
|  |       const char *str = cffi::to_utf8(src,len,&buf); | ||
|  |       return HxString(str,len); | ||
|  |    } | ||
|  | 
 | ||
|  |    const char *default_to_utf8(const HxString &str,hx::IStringAlloc *alloc) | ||
|  |    { | ||
|  |       return str.c_str(); | ||
|  |    } | ||
|  |    const wchar_t *default_to_wchar(const HxString &str,hx::IStringAlloc *alloc) | ||
|  |    { | ||
|  |       DynAlloc d; | ||
|  |       if (!alloc) | ||
|  |          alloc = &d; | ||
|  |       return cffi::from_utf8<wchar_t>(str.c_str(),str.size(),alloc); | ||
|  |    } | ||
|  |    const char16_t *default_to_utf16(const HxString &str,hx::IStringAlloc *alloc) | ||
|  |    { | ||
|  |       DynAlloc d; | ||
|  |       if (!alloc) | ||
|  |          alloc = &d; | ||
|  |       return cffi::from_utf8<char16_t>(str.c_str(),str.size(),alloc); | ||
|  |    } | ||
|  |    #endif
 | ||
|  | 
 | ||
|  | 
 | ||
|  |    hx::StringEncoding default_get_encoding(void *inPtr) { return hx::StringUtf8; } | ||
|  | 
 | ||
|  |    void * default_alloc_empty_string(int) { return 0; } | ||
|  | 
 | ||
|  |    // Do nothing on earlier versions of hxcpp that do not know what to do
 | ||
|  |    void default_gc_change_managed_memory(int,const char *) { } | ||
|  | 
 | ||
|  |    void *ResolveDefault(const char *inName) | ||
|  |    { | ||
|  |       void *result = sResolveProc(inName); | ||
|  |       if (result) | ||
|  |          return result; | ||
|  |       if (!strcmp(inName,"val_is_buffer")) | ||
|  |          return (void *)default_val_is_buffer; | ||
|  |       if (!strcmp(inName,"alloc_empty_string")) | ||
|  |          return (void *)default_alloc_empty_string; | ||
|  |       if (!strcmp(inName,"gc_change_managed_memory")) | ||
|  |          return (void *)default_gc_change_managed_memory; | ||
|  |       if (!strcmp(inName,"hxs_encoding")) | ||
|  |          return (void *)default_get_encoding; | ||
|  |       #ifdef HXCPP_PRIME
 | ||
|  |       if (!strcmp(inName,"alloc_hxs_wchar")) | ||
|  |          return (void *)default_string_wchar; | ||
|  |       if (!strcmp(inName,"alloc_hxs_utf16")) | ||
|  |          return (void *)default_string_utf16; | ||
|  |       if (!strcmp(inName,"alloc_hxs_utf8")) | ||
|  |          return (void *)default_string_utf8; | ||
|  |       if (!strcmp(inName,"hxs_utf8")) | ||
|  |          return (void *)default_to_utf8; | ||
|  |       if (!strcmp(inName,"hxs_utf16")) | ||
|  |          return (void *)default_to_utf16; | ||
|  |       if (!strcmp(inName,"hxs_wchar")) | ||
|  |          return (void *)default_to_wchar; | ||
|  |       #endif
 | ||
|  | 
 | ||
|  |       return 0; | ||
|  |    } | ||
|  | 
 | ||
|  |    #ifdef NEKO_WINDOWS // {
 | ||
|  | 
 | ||
|  |    void *LoadFunc(const char *inName) | ||
|  |    { | ||
|  |       #ifndef HX_WINRT
 | ||
|  |       static const char *modules[] = { 0, "hxcpp", "hxcpp-debug" }; | ||
|  |       for(int i=0; i<3 && sResolveProc==0; i++) | ||
|  |       { | ||
|  |          HMODULE handle = GetModuleHandleA(modules[i]); | ||
|  |          if (handle) | ||
|  |          { | ||
|  |             sResolveProc = (ResolveProc)GetProcAddress(handle,"hx_cffi"); | ||
|  |             if (sResolveProc==0) | ||
|  |                FreeLibrary(handle); | ||
|  |          } | ||
|  |       } | ||
|  |       #endif
 | ||
|  | 
 | ||
|  |       #ifdef NEKO_COMPATIBLE
 | ||
|  |       if (sResolveProc==0) | ||
|  |       { | ||
|  |          sResolveProc = InitDynamicNekoLoader(); | ||
|  |       } | ||
|  |       #endif
 | ||
|  | 
 | ||
|  |       if (sResolveProc==0) | ||
|  |       { | ||
|  |          fprintf(stderr,"Could not link plugin to process (hxCFFILoader.h %d)\n",__LINE__); | ||
|  |          exit(1); | ||
|  |       } | ||
|  |       return ResolveDefault(inName); | ||
|  |    } | ||
|  | 
 | ||
|  |    #else // windows }  { not windows
 | ||
|  | 
 | ||
|  | 
 | ||
|  |    void *LoadFunc(const char *inName) | ||
|  |    { | ||
|  |       #ifndef ANDROID // {
 | ||
|  |          if (sResolveProc==0) | ||
|  |          { | ||
|  |             sResolveProc = (ResolveProc)dlsym(RTLD_DEFAULT,"hx_cffi"); | ||
|  |          } | ||
|  | 
 | ||
|  |          #ifdef NEKO_COMPATIBLE
 | ||
|  |          if (sResolveProc==0) | ||
|  |          { | ||
|  |             sResolveProc = InitDynamicNekoLoader(); | ||
|  |          } | ||
|  |          #endif
 | ||
|  |       #endif // !Android  }
 | ||
|  | 
 | ||
|  |       if (sResolveProc==0) | ||
|  |       { | ||
|  |          #ifdef ANDROID
 | ||
|  |          __android_log_print(ANDROID_LOG_ERROR, "CFFILoader.h", "Could not API %s", inName); | ||
|  |          return 0; | ||
|  |          #else
 | ||
|  |          #ifdef NEKO_COMPATIBLE
 | ||
|  |          fprintf(stderr,"Could not link plugin to process (CFFILoader.h %d) - with neko\n",__LINE__); | ||
|  |          #else
 | ||
|  |          fprintf(stderr,"Could not link plugin to process (CFFILoader.h %d)\n",__LINE__); | ||
|  |          #endif
 | ||
|  |          exit(1); | ||
|  |          #endif
 | ||
|  |       } | ||
|  |       return ResolveDefault(inName); | ||
|  |    } | ||
|  | 
 | ||
|  |    #undef EXT
 | ||
|  | 
 | ||
|  |    #endif // not windows }
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  |    #ifndef ANDROID // not android {
 | ||
|  | 
 | ||
|  |    #define DEFFUNC(name,ret,def_args,call_args) \
 | ||
|  |    typedef ret (*FUNC_##name)def_args; \ | ||
|  |    extern FUNC_##name name; \ | ||
|  |    ret IMPL_##name def_args \ | ||
|  |    { \ | ||
|  |       name = (FUNC_##name)LoadFunc(#name); \ | ||
|  |       if (!name) \ | ||
|  |       { \ | ||
|  |          fprintf(stderr,"Could not find function:" #name " \n"); \ | ||
|  |          exit(1); \ | ||
|  |       } \ | ||
|  |       return name call_args; \ | ||
|  |    }\ | ||
|  |    FUNC_##name name = IMPL_##name; | ||
|  |      | ||
|  |    #ifdef NEKO_COMPATIBLE
 | ||
|  |    DEFINE_PRIM(neko_init,5) | ||
|  |    #endif
 | ||
|  | 
 | ||
|  |    #else // not android }  { android
 | ||
|  | 
 | ||
|  | 
 | ||
|  |    #define DEFFUNC(name,ret,def_args,call_args) \
 | ||
|  |    typedef ret (*FUNC_##name)def_args; \ | ||
|  |    extern FUNC_##name name; \ | ||
|  |    ret IMPL_##name def_args \ | ||
|  |    { \ | ||
|  |       name = (FUNC_##name)LoadFunc(#name); \ | ||
|  |       if (!name) \ | ||
|  |       { \ | ||
|  |          __android_log_print(ANDROID_LOG_ERROR,"CFFILoader", "Could not find function:" #name "\n"); \ | ||
|  |       } \ | ||
|  |       return name call_args; \ | ||
|  |    }\ | ||
|  |    FUNC_##name name = IMPL_##name; | ||
|  |      | ||
|  | 
 | ||
|  |    #endif // android }
 | ||
|  | 
 | ||
|  | #endif // dynamic link }
 | ||
|  | 
 | ||
|  | #endif
 | ||
|  | 
 | ||
|  | 
 |