JSPlugin.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  1. //
  2. // Copyright (c) 2014-2015, THUNDERBEAST GAMES LLC All rights reserved
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to deal
  6. // in the Software without restriction, including without limitation the rights
  7. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. // copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. // THE SOFTWARE.
  21. //
  22. #include <Atomic/IO/Log.h>
  23. #include "JSPlugin.h"
  24. #include "JSPluginExports.h"
  25. #include "JSVM.h"
  26. #include <ThirdParty/SDL/include/SDL.h>
  27. namespace Atomic
  28. {
  29. typedef bool(*atomic_plugin_validate_function)(int version, void *jsvmImports, size_t jsvmImportsSize);
  30. static void jsplugin_bind_jsvmexports();
  31. static JSVMImports gJSVMExports;
  32. static bool jsplugin_get_entry_points(const String& pluginLibrary, atomic_plugin_validate_function* fvalidate,
  33. duk_c_function* finit, String& errorMsg)
  34. {
  35. *fvalidate = NULL;
  36. *finit = NULL;
  37. // TODO: cache and use SDL_UnloadObject (when no longer needed)
  38. void* handle = SDL_LoadObject(pluginLibrary.CString());
  39. if (handle == NULL)
  40. {
  41. errorMsg = ToString("Native Plugin: Unable to load %s with error %s",
  42. pluginLibrary.CString(),
  43. SDL_GetError());
  44. return false;
  45. }
  46. *fvalidate = (atomic_plugin_validate_function) SDL_LoadFunction(handle, "atomic_plugin_validate");
  47. if (!*fvalidate)
  48. {
  49. errorMsg = ToString("Native Plugin: Unable to get atomic_plugin_validate entry point in %s", pluginLibrary.CString());
  50. return false;
  51. }
  52. *finit = (duk_c_function) SDL_LoadFunction(handle, "atomic_plugin_init");
  53. if (!*finit)
  54. {
  55. ATOMIC_LOGERRORF("Native Plugin: Unable to get atomic_plugin_init entry point in %s", pluginLibrary.CString());
  56. return false;
  57. }
  58. return true;
  59. }
  60. bool jsplugin_load(JSVM* vm, const String& pluginLibrary)
  61. {
  62. String errorMsg;
  63. atomic_plugin_validate_function validatefunc;
  64. duk_c_function initfunc;
  65. duk_context* ctx = vm->GetJSContext();
  66. ATOMIC_LOGINFOF("Loading Native Plugin: %s", pluginLibrary.CString());
  67. if (!jsplugin_get_entry_points(pluginLibrary, &validatefunc, &initfunc, errorMsg))
  68. {
  69. ATOMIC_LOGERRORF("%s", errorMsg.CString());
  70. return false;
  71. }
  72. int version = ATOMIC_JSPLUGIN_VERSION;
  73. if (!validatefunc(version, &gJSVMExports, sizeof(JSVMImports)))
  74. {
  75. ATOMIC_LOGERRORF("Native Plugin: atomic_plugin_validate failed: %s", pluginLibrary.CString());
  76. return false;
  77. }
  78. // just to verify that we're not doing anything funky with the stack
  79. int top = duk_get_top(ctx);
  80. // the import function is a standard duktape c function, neat
  81. duk_push_c_function(ctx, initfunc, 1);
  82. // requires exports to be at index 2
  83. duk_dup(ctx, 2);
  84. bool success = true;
  85. if (duk_pcall(ctx, 1) != DUK_EXEC_SUCCESS)
  86. {
  87. success = false;
  88. ATOMIC_LOGERRORF("Native Plugin: error calling atomic_plugin_init %s with error %s",
  89. pluginLibrary.CString(),
  90. duk_safe_to_string(ctx, -1));
  91. }
  92. else
  93. {
  94. if (!duk_is_boolean(ctx, -1) || !duk_to_boolean(ctx, -1))
  95. {
  96. success = false;
  97. ATOMIC_LOGERRORF("Native Plugin: error calling atomic_plugin_init, didn't return true %s", pluginLibrary.CString());
  98. }
  99. }
  100. duk_pop(ctx);
  101. assert(top == duk_get_top(ctx));
  102. return success;
  103. }
  104. void js_init_jsplugin(JSVM* vm)
  105. {
  106. // bind the public Duktape API for export to plugins
  107. jsplugin_bind_jsvmexports();
  108. }
  109. void jsplugin_bind_jsvmexports()
  110. {
  111. gJSVMExports.duk_create_heap = duk_create_heap;
  112. gJSVMExports.duk_destroy_heap = duk_destroy_heap;
  113. gJSVMExports.duk_alloc_raw = duk_alloc_raw;
  114. gJSVMExports.duk_free_raw = duk_free_raw;
  115. gJSVMExports.duk_realloc_raw = duk_realloc_raw;
  116. gJSVMExports.duk_alloc = duk_alloc;
  117. gJSVMExports.duk_free = duk_free;
  118. gJSVMExports.duk_realloc = duk_realloc;
  119. gJSVMExports.duk_get_memory_functions = duk_get_memory_functions;
  120. gJSVMExports.duk_gc = duk_gc;
  121. gJSVMExports.duk_throw_raw = duk_throw_raw;
  122. gJSVMExports.duk_fatal_raw = duk_fatal_raw;
  123. gJSVMExports.duk_error_raw = duk_error_raw;
  124. gJSVMExports.duk_error_va_raw = duk_error_va_raw;
  125. gJSVMExports.duk_is_strict_call = duk_is_strict_call;
  126. gJSVMExports.duk_is_constructor_call = duk_is_constructor_call;
  127. gJSVMExports.duk_normalize_index = duk_normalize_index;
  128. gJSVMExports.duk_require_normalize_index = duk_require_normalize_index;
  129. gJSVMExports.duk_is_valid_index = duk_is_valid_index;
  130. gJSVMExports.duk_require_valid_index = duk_require_valid_index;
  131. gJSVMExports.duk_get_top = duk_get_top;
  132. gJSVMExports.duk_set_top = duk_set_top;
  133. gJSVMExports.duk_get_top_index = duk_get_top_index;
  134. gJSVMExports.duk_require_top_index = duk_require_top_index;
  135. gJSVMExports.duk_check_stack = duk_check_stack;
  136. gJSVMExports.duk_require_stack = duk_require_stack;
  137. gJSVMExports.duk_check_stack_top = duk_check_stack_top;
  138. gJSVMExports.duk_require_stack_top = duk_require_stack_top;
  139. gJSVMExports.duk_swap = duk_swap;
  140. gJSVMExports.duk_swap_top = duk_swap_top;
  141. gJSVMExports.duk_dup = duk_dup;
  142. gJSVMExports.duk_dup_top = duk_dup_top;
  143. gJSVMExports.duk_insert = duk_insert;
  144. gJSVMExports.duk_replace = duk_replace;
  145. gJSVMExports.duk_copy = duk_copy;
  146. gJSVMExports.duk_remove = duk_remove;
  147. gJSVMExports.duk_xcopymove_raw = duk_xcopymove_raw;
  148. gJSVMExports.duk_push_undefined = duk_push_undefined;
  149. gJSVMExports.duk_push_null = duk_push_null;
  150. gJSVMExports.duk_push_boolean = duk_push_boolean;
  151. gJSVMExports.duk_push_true = duk_push_true;
  152. gJSVMExports.duk_push_false = duk_push_false;
  153. gJSVMExports.duk_push_number = duk_push_number;
  154. gJSVMExports.duk_push_nan = duk_push_nan;
  155. gJSVMExports.duk_push_int = duk_push_int;
  156. gJSVMExports.duk_push_uint = duk_push_uint;
  157. gJSVMExports.duk_push_string = duk_push_string;
  158. gJSVMExports.duk_push_lstring = duk_push_lstring;
  159. gJSVMExports.duk_push_pointer = duk_push_pointer;
  160. gJSVMExports.duk_push_sprintf = duk_push_sprintf;
  161. gJSVMExports.duk_push_vsprintf = duk_push_vsprintf;
  162. //gJSVMExports.duk_push_string_file_raw = duk_push_string_file_raw;
  163. gJSVMExports.duk_push_this = duk_push_this;
  164. gJSVMExports.duk_push_current_function = duk_push_current_function;
  165. gJSVMExports.duk_push_current_thread = duk_push_current_thread;
  166. gJSVMExports.duk_push_global_object = duk_push_global_object;
  167. gJSVMExports.duk_push_heap_stash = duk_push_heap_stash;
  168. gJSVMExports.duk_push_global_stash = duk_push_global_stash;
  169. gJSVMExports.duk_push_thread_stash = duk_push_thread_stash;
  170. gJSVMExports.duk_push_object = duk_push_object;
  171. gJSVMExports.duk_push_array = duk_push_array;
  172. gJSVMExports.duk_push_c_function = duk_push_c_function;
  173. gJSVMExports.duk_push_c_lightfunc = duk_push_c_lightfunc;
  174. gJSVMExports.duk_push_thread_raw = duk_push_thread_raw;
  175. gJSVMExports.duk_push_error_object_raw = duk_push_error_object_raw;
  176. gJSVMExports.duk_push_error_object_va_raw = duk_push_error_object_va_raw;
  177. gJSVMExports.duk_push_buffer_raw = duk_push_buffer_raw;
  178. gJSVMExports.duk_push_heapptr = duk_push_heapptr;
  179. gJSVMExports.duk_pop = duk_pop;
  180. gJSVMExports.duk_pop_n = duk_pop_n;
  181. gJSVMExports.duk_pop_2 = duk_pop_2;
  182. gJSVMExports.duk_pop_3 = duk_pop_3;
  183. gJSVMExports.duk_get_type = duk_get_type;
  184. gJSVMExports.duk_check_type = duk_check_type;
  185. gJSVMExports.duk_get_type_mask = duk_get_type_mask;
  186. gJSVMExports.duk_check_type_mask = duk_check_type_mask;
  187. gJSVMExports.duk_is_undefined = duk_is_undefined;
  188. gJSVMExports.duk_is_null = duk_is_null;
  189. //gJSVMExports.duk_is_null_or_undefined = duk_is_null_or_undefined; This is a macro in Duktape 2.0.
  190. gJSVMExports.duk_is_boolean = duk_is_boolean;
  191. gJSVMExports.duk_is_number = duk_is_number;
  192. gJSVMExports.duk_is_nan = duk_is_nan;
  193. gJSVMExports.duk_is_string = duk_is_string;
  194. gJSVMExports.duk_is_object = duk_is_object;
  195. gJSVMExports.duk_is_buffer = duk_is_buffer;
  196. gJSVMExports.duk_is_pointer = duk_is_pointer;
  197. gJSVMExports.duk_is_lightfunc = duk_is_lightfunc;
  198. gJSVMExports.duk_is_array = duk_is_array;
  199. gJSVMExports.duk_is_function = duk_is_function;
  200. gJSVMExports.duk_is_c_function = duk_is_c_function;
  201. gJSVMExports.duk_is_ecmascript_function = duk_is_ecmascript_function;
  202. gJSVMExports.duk_is_bound_function = duk_is_bound_function;
  203. gJSVMExports.duk_is_thread = duk_is_thread;
  204. //gJSVMExports.duk_is_callable = duk_is_callable;
  205. gJSVMExports.duk_is_dynamic_buffer = duk_is_dynamic_buffer;
  206. gJSVMExports.duk_is_fixed_buffer = duk_is_fixed_buffer;
  207. //gJSVMExports.duk_is_primitive = duk_is_primitive;
  208. gJSVMExports.duk_get_error_code = duk_get_error_code;
  209. gJSVMExports.duk_get_boolean = duk_get_boolean;
  210. gJSVMExports.duk_get_number = duk_get_number;
  211. gJSVMExports.duk_get_int = duk_get_int;
  212. gJSVMExports.duk_get_uint = duk_get_uint;
  213. gJSVMExports.duk_get_string = duk_get_string;
  214. gJSVMExports.duk_get_lstring = duk_get_lstring;
  215. gJSVMExports.duk_get_buffer = duk_get_buffer;
  216. gJSVMExports.duk_get_pointer = duk_get_pointer;
  217. gJSVMExports.duk_get_c_function = duk_get_c_function;
  218. gJSVMExports.duk_get_context = duk_get_context;
  219. gJSVMExports.duk_get_heapptr = duk_get_heapptr;
  220. gJSVMExports.duk_get_length = duk_get_length;
  221. gJSVMExports.duk_require_undefined = duk_require_undefined;
  222. gJSVMExports.duk_require_null = duk_require_null;
  223. gJSVMExports.duk_require_boolean = duk_require_boolean;
  224. gJSVMExports.duk_require_number = duk_require_number;
  225. gJSVMExports.duk_require_int = duk_require_int;
  226. gJSVMExports.duk_require_uint = duk_require_uint;
  227. gJSVMExports.duk_require_string = duk_require_string;
  228. gJSVMExports.duk_require_lstring = duk_require_lstring;
  229. gJSVMExports.duk_require_buffer = duk_require_buffer;
  230. gJSVMExports.duk_require_pointer = duk_require_pointer;
  231. gJSVMExports.duk_require_c_function = duk_require_c_function;
  232. gJSVMExports.duk_require_context = duk_require_context;
  233. gJSVMExports.duk_require_heapptr = duk_require_heapptr;
  234. gJSVMExports.duk_to_undefined = duk_to_undefined;
  235. gJSVMExports.duk_to_null = duk_to_null;
  236. gJSVMExports.duk_to_boolean = duk_to_boolean;
  237. gJSVMExports.duk_to_number = duk_to_number;
  238. gJSVMExports.duk_to_int = duk_to_int;
  239. gJSVMExports.duk_to_uint = duk_to_uint;
  240. gJSVMExports.duk_to_int32 = duk_to_int32;
  241. gJSVMExports.duk_to_uint32 = duk_to_uint32;
  242. gJSVMExports.duk_to_uint16 = duk_to_uint16;
  243. gJSVMExports.duk_to_string = duk_to_string;
  244. gJSVMExports.duk_to_lstring = duk_to_lstring;
  245. gJSVMExports.duk_to_buffer_raw = duk_to_buffer_raw;
  246. gJSVMExports.duk_to_pointer = duk_to_pointer;
  247. gJSVMExports.duk_to_object = duk_to_object;
  248. gJSVMExports.duk_to_defaultvalue = duk_to_primitive; // In Duktape 2.0 duk_to_defaultvalue() has to be replaced by duk_to_primitive().
  249. gJSVMExports.duk_to_primitive = duk_to_primitive;
  250. gJSVMExports.duk_safe_to_lstring = duk_safe_to_lstring;
  251. gJSVMExports.duk_base64_encode = duk_base64_encode;
  252. gJSVMExports.duk_base64_decode = duk_base64_decode;
  253. gJSVMExports.duk_hex_encode = duk_hex_encode;
  254. gJSVMExports.duk_hex_decode = duk_hex_decode;
  255. gJSVMExports.duk_json_encode = duk_json_encode;
  256. gJSVMExports.duk_json_decode = duk_json_decode;
  257. gJSVMExports.duk_resize_buffer = duk_resize_buffer;
  258. gJSVMExports.duk_get_prop = duk_get_prop;
  259. gJSVMExports.duk_get_prop_string = duk_get_prop_string;
  260. gJSVMExports.duk_get_prop_index = duk_get_prop_index;
  261. gJSVMExports.duk_put_prop = duk_put_prop;
  262. gJSVMExports.duk_put_prop_string = duk_put_prop_string;
  263. gJSVMExports.duk_put_prop_index = duk_put_prop_index;
  264. gJSVMExports.duk_del_prop = duk_del_prop;
  265. gJSVMExports.duk_del_prop_string = duk_del_prop_string;
  266. gJSVMExports.duk_del_prop_index = duk_del_prop_index;
  267. gJSVMExports.duk_has_prop = duk_has_prop;
  268. gJSVMExports.duk_has_prop_string = duk_has_prop_string;
  269. gJSVMExports.duk_has_prop_index = duk_has_prop_index;
  270. gJSVMExports.duk_def_prop = duk_def_prop;
  271. gJSVMExports.duk_get_global_string = duk_get_global_string;
  272. gJSVMExports.duk_put_global_string = duk_put_global_string;
  273. gJSVMExports.duk_get_prototype = duk_get_prototype;
  274. gJSVMExports.duk_set_prototype = duk_set_prototype;
  275. gJSVMExports.duk_get_finalizer = duk_get_finalizer;
  276. gJSVMExports.duk_set_finalizer = duk_set_finalizer;
  277. gJSVMExports.duk_set_global_object = duk_set_global_object;
  278. gJSVMExports.duk_get_magic = duk_get_magic;
  279. gJSVMExports.duk_set_magic = duk_set_magic;
  280. gJSVMExports.duk_get_current_magic = duk_get_current_magic;
  281. gJSVMExports.duk_put_function_list = duk_put_function_list;
  282. gJSVMExports.duk_put_number_list = duk_put_number_list;
  283. gJSVMExports.duk_compact = duk_compact;
  284. gJSVMExports.duk_enum = duk_enum;
  285. gJSVMExports.duk_next = duk_next;
  286. gJSVMExports.duk_concat = duk_concat;
  287. gJSVMExports.duk_join = duk_join;
  288. gJSVMExports.duk_decode_string = duk_decode_string;
  289. gJSVMExports.duk_map_string = duk_map_string;
  290. gJSVMExports.duk_substring = duk_substring;
  291. gJSVMExports.duk_trim = duk_trim;
  292. gJSVMExports.duk_char_code_at = duk_char_code_at;
  293. gJSVMExports.duk_equals = duk_equals;
  294. gJSVMExports.duk_strict_equals = duk_strict_equals;
  295. gJSVMExports.duk_call = duk_call;
  296. gJSVMExports.duk_call_method = duk_call_method;
  297. gJSVMExports.duk_call_prop = duk_call_prop;
  298. gJSVMExports.duk_pcall = duk_pcall;
  299. gJSVMExports.duk_pcall_method = duk_pcall_method;
  300. gJSVMExports.duk_pcall_prop = duk_pcall_prop;
  301. gJSVMExports.duk_new = duk_new;
  302. gJSVMExports.duk_safe_call = duk_safe_call;
  303. gJSVMExports.duk_eval_raw = duk_eval_raw;
  304. gJSVMExports.duk_compile_raw = duk_compile_raw;
  305. gJSVMExports.duk_log = duk_log;
  306. gJSVMExports.duk_log_va = duk_log_va;
  307. gJSVMExports.duk_push_context_dump = duk_push_context_dump;
  308. gJSVMExports.duk_debugger_detach = duk_debugger_detach;
  309. gJSVMExports.duk_debugger_attach_custom = duk_debugger_attach;
  310. gJSVMExports.duk_debugger_cooperate = duk_debugger_cooperate;
  311. }
  312. }