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
 | |
| 
 | |
| 
 |