JSRequire.cpp 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. #include <assert.h>
  2. #include <Atomic/IO/FileSystem.h>
  3. #include <Atomic/Resource/ResourceCache.h>
  4. #include "JSVM.h"
  5. #include "JSRequire.h"
  6. namespace Atomic
  7. {
  8. static bool js_init_native_module(duk_context* ctx, const String& pluginLibrary)
  9. {
  10. #ifdef ATOMIC_PLATFORM_WINDOWS
  11. LOGINFOF("Loading Native Plugin: %s", pluginLibrary.CString());
  12. HMODULE hmodule = ::LoadLibrary(pluginLibrary.CString());
  13. if (hmodule == NULL)
  14. {
  15. LOGERRORF("Native Plugin: Unable to load %s", pluginLibrary.CString());
  16. return false;
  17. }
  18. duk_c_function func = (duk_c_function) ::GetProcAddress(hmodule, "atomic_plugin_init");
  19. if (!func)
  20. {
  21. LOGERRORF("Native Plugin: Unable to get atomic_plugin_init entry point in %s", pluginLibrary.CString());
  22. return false;
  23. }
  24. // just to verify that we're not doing anything funky with the stack
  25. int top = duk_get_top(ctx);
  26. // the import function is a standard duktape c function, neat
  27. duk_push_c_function(ctx, func, 1);
  28. // requires exports to be at index 2
  29. duk_dup(ctx, 2);
  30. bool success = true;
  31. if (duk_pcall(ctx, 1) != DUK_EXEC_SUCCESS)
  32. {
  33. success = false;
  34. LOGERRORF("Native Plugin: error calling atomic_plugin_init %s", pluginLibrary.CString());
  35. }
  36. else
  37. {
  38. if (!duk_is_boolean(ctx, -1) || !duk_to_boolean(ctx, -1))
  39. {
  40. success = false;
  41. LOGERRORF("Native Plugin: error calling atomic_plugin_init, didn't return true %s", pluginLibrary.CString());
  42. }
  43. }
  44. duk_pop(ctx);
  45. assert(top == duk_get_top(ctx));
  46. return success;
  47. #else
  48. return false;
  49. #endif
  50. }
  51. // see http://duktape.org/guide.html#modules
  52. static int js_module_search(duk_context* ctx)
  53. {
  54. JSVM* vm = JSVM::GetJSVM(ctx);
  55. FileSystem* fs = vm->GetSubsystem<FileSystem>();
  56. ResourceCache* cache = vm->GetSubsystem<ResourceCache>();
  57. int top = duk_get_top(ctx);
  58. assert(top == 4);
  59. String moduleID = duk_to_string(ctx, 0);
  60. if (top > 1)
  61. {
  62. // require function
  63. assert(duk_is_function(ctx, 1));
  64. }
  65. if (top > 2)
  66. {
  67. // exports
  68. assert(duk_is_object(ctx, 2));
  69. }
  70. if (top > 3)
  71. {
  72. // module (module.id == a resolved absolute identifier for the module being loaded)
  73. assert(duk_is_object(ctx, 3));
  74. }
  75. String pathName, fileName, extension;
  76. SplitPath(moduleID, pathName, fileName, extension);
  77. String path = moduleID;
  78. // Do we really want this? It is nice to not have to specify the Atomic path
  79. if (fileName.StartsWith("Atomic"))
  80. {
  81. path = "AtomicModules/" + path + ".js";
  82. }
  83. else
  84. {
  85. path += ".js";
  86. }
  87. SharedPtr<File> jsfile(cache->GetFile(path, false));
  88. if (!jsfile)
  89. {
  90. // we're not a JS file, so check if we're a native module
  91. const Vector<String>& resourceDirs = cache->GetResourceDirs();
  92. for (unsigned i = 0; i < resourceDirs.Size(); i++)
  93. {
  94. #ifdef ATOMIC_PLATFORM_WINDOWS
  95. // TODO: proper platform folder detection
  96. String pluginLibrary = resourceDirs.At(i) + "Plugins/Windows/x64/" + moduleID + ".dll";
  97. if (fs->FileExists(pluginLibrary))
  98. {
  99. // let duktape know we loaded a native module
  100. if (js_init_native_module(ctx, pluginLibrary))
  101. {
  102. duk_push_undefined(ctx);
  103. return 1;
  104. }
  105. }
  106. }
  107. #endif
  108. }
  109. else
  110. {
  111. vm->SetLastModuleSearchFile(jsfile->GetFullPath());
  112. String source;
  113. jsfile->ReadText(source);
  114. duk_push_string(ctx, source.CString());
  115. }
  116. return 1;
  117. }
  118. void js_init_require(JSVM* vm)
  119. {
  120. duk_context* ctx = vm->GetJSContext();
  121. duk_get_global_string(ctx, "Duktape");
  122. duk_push_c_function(ctx, js_module_search, 4);
  123. duk_put_prop_string(ctx, -2, "modSearch");
  124. duk_pop(ctx);
  125. }
  126. }