JSRequire.cpp 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. #include <assert.h>
  2. #include <Atomic/IO/FileSystem.h>
  3. #include <Atomic/Resource/ResourceCache.h>
  4. /*
  5. // subsystem requires
  6. #include <Atomic/Engine/Engine.h>
  7. #include <Atomic/Graphics/Graphics.h>
  8. #include <Atomic/Graphics/Renderer.h>
  9. #include <Atomic/Input/Input.h>
  10. #include <Atomic/Resource/ResourceCache.h>
  11. */
  12. #include "JSVM.h"
  13. #include "JSRequire.h"
  14. #include "JSPlugin.h"
  15. namespace Atomic
  16. {
  17. /*
  18. static bool js_require_subsystem(const String& name, JSVM* vm)
  19. {
  20. duk_context* ctx = vm->GetJSContext();
  21. String lowername = name.ToLower();
  22. if (lowername.ToLower() == "input")
  23. {
  24. js_push_class_object_instance(ctx, vm->GetSubsystem<Input>());
  25. return true;
  26. }
  27. if (lowername.ToLower() == "resourcecache")
  28. {
  29. js_push_class_object_instance(ctx, vm->GetSubsystem<ResourceCache>());
  30. return true;
  31. }
  32. if (lowername.ToLower() == "engine")
  33. {
  34. js_push_class_object_instance(ctx, vm->GetSubsystem<Engine>());
  35. return true;
  36. }
  37. if (lowername.ToLower() == "renderer")
  38. {
  39. js_push_class_object_instance(ctx, vm->GetSubsystem<Renderer>());
  40. return true;
  41. }
  42. if (lowername == "graphics")
  43. {
  44. js_push_class_object_instance(ctx, vm->GetSubsystem<Graphics>());
  45. return true;
  46. }
  47. if (lowername.ToLower() == "vm")
  48. {
  49. js_push_class_object_instance(ctx, vm);
  50. return true;
  51. }
  52. return false;
  53. }
  54. */
  55. // see http://duktape.org/guide.html#modules
  56. static int js_module_search(duk_context* ctx)
  57. {
  58. JSVM* vm = JSVM::GetJSVM(ctx);
  59. FileSystem* fs = vm->GetSubsystem<FileSystem>();
  60. ResourceCache* cache = vm->GetSubsystem<ResourceCache>();
  61. int top = duk_get_top(ctx);
  62. assert(top == 4);
  63. String moduleID = duk_to_string(ctx, 0);
  64. if (top > 1)
  65. {
  66. // require function
  67. assert(duk_is_function(ctx, 1));
  68. }
  69. if (top > 2)
  70. {
  71. // exports
  72. assert(duk_is_object(ctx, 2));
  73. }
  74. if (top > 3)
  75. {
  76. // module (module.id == a resolved absolute identifier for the module being loaded)
  77. assert(duk_is_object(ctx, 3));
  78. }
  79. String pathName, fileName, extension;
  80. SplitPath(moduleID, pathName, fileName, extension);
  81. String path = moduleID;
  82. // Do we really want this? It is nice to not have to specify the Atomic path
  83. if (fileName.StartsWith("Atomic"))
  84. {
  85. path = "AtomicModules/" + path + ".js";
  86. }
  87. else
  88. {
  89. path += ".js";
  90. if (!cache->Exists(path))
  91. {
  92. const Vector<String>& searchPaths = vm->GetModuleSearchPaths();
  93. for (unsigned i = 0; i < searchPaths.Size(); i++)
  94. {
  95. String search = searchPaths[i] + path;
  96. if (cache->Exists(search))
  97. {
  98. path = search;
  99. break;
  100. }
  101. }
  102. }
  103. }
  104. if (cache->Exists(path))
  105. {
  106. SharedPtr<File> jsfile(cache->GetFile(path, false));
  107. vm->SetLastModuleSearchFile(jsfile->GetFullPath());
  108. String source;
  109. jsfile->ReadText(source);
  110. //Appending a new line at the end of a script
  111. source.AppendUTF8(0x0D);
  112. source.AppendUTF8(0x0A);
  113. duk_push_string(ctx, source.CString());
  114. return 1;
  115. }
  116. else
  117. {
  118. // we're not a JS file, so check if we're a native module
  119. const Vector<String>& resourceDirs = cache->GetResourceDirs();
  120. for (unsigned i = 0; i < resourceDirs.Size(); i++)
  121. {
  122. String pluginLibrary;
  123. // TODO: proper platform folder detection
  124. #ifdef ATOMIC_PLATFORM_WINDOWS
  125. pluginLibrary = resourceDirs.At(i) + "Plugins/Windows/x64/" + moduleID + ".dll";
  126. #elif ATOMIC_PLATFORM_OSX
  127. pluginLibrary = resourceDirs.At(i) + "Plugins/Mac/x64/lib" + moduleID + ".dylib";
  128. #endif
  129. if (pluginLibrary.Length() && fs->FileExists(pluginLibrary))
  130. {
  131. // let duktape know we loaded a native module
  132. if (jsplugin_load(vm, pluginLibrary))
  133. {
  134. duk_push_undefined(ctx);
  135. return 1;
  136. }
  137. else
  138. {
  139. duk_push_sprintf(ctx, "Failed loading native plugins: %s", pluginLibrary.CString());
  140. duk_throw(ctx);
  141. }
  142. }
  143. }
  144. }
  145. duk_push_sprintf(ctx, "Failed loading module: %s", path.CString());
  146. duk_throw(ctx);
  147. }
  148. void js_init_require(JSVM* vm)
  149. {
  150. duk_context* ctx = vm->GetJSContext();
  151. duk_get_global_string(ctx, "Duktape");
  152. duk_push_c_function(ctx, js_module_search, 4);
  153. duk_put_prop_string(ctx, -2, "modSearch");
  154. duk_pop(ctx);
  155. }
  156. }