JSIndexedRAMBundle.cpp 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. /*
  2. * Copyright (c) Facebook, Inc. and its affiliates.
  3. *
  4. * This source code is licensed under the MIT license found in the
  5. * LICENSE file in the root directory of this source tree.
  6. */
  7. #include "JSIndexedRAMBundle.h"
  8. #include <glog/logging.h>
  9. #include <fstream>
  10. #include <memory>
  11. #include <sstream>
  12. namespace facebook {
  13. namespace react {
  14. std::function<std::unique_ptr<JSModulesUnbundle>(std::string)>
  15. JSIndexedRAMBundle::buildFactory() {
  16. return [](const std::string &bundlePath) {
  17. return std::make_unique<JSIndexedRAMBundle>(bundlePath.c_str());
  18. };
  19. }
  20. JSIndexedRAMBundle::JSIndexedRAMBundle(const char *sourcePath) {
  21. m_bundle = std::make_unique<std::ifstream>(sourcePath, std::ifstream::binary);
  22. if (!m_bundle) {
  23. throw std::ios_base::failure(folly::to<std::string>(
  24. "Bundle ", sourcePath, "cannot be opened: ", m_bundle->rdstate()));
  25. }
  26. init();
  27. }
  28. JSIndexedRAMBundle::JSIndexedRAMBundle(
  29. std::unique_ptr<const JSBigString> script) {
  30. // tmpStream is needed because m_bundle is std::istream type
  31. // which has no member 'write'
  32. std::unique_ptr<std::stringstream> tmpStream =
  33. std::make_unique<std::stringstream>();
  34. tmpStream->write(script->c_str(), script->size());
  35. m_bundle = std::move(tmpStream);
  36. if (!m_bundle) {
  37. throw std::ios_base::failure(folly::to<std::string>(
  38. "Bundle from string cannot be opened: ", m_bundle->rdstate()));
  39. }
  40. init();
  41. }
  42. void JSIndexedRAMBundle::init() {
  43. // read in magic header, number of entries, and length of the startup section
  44. uint32_t header[3];
  45. static_assert(
  46. sizeof(header) == 12,
  47. "header size must exactly match the input file format");
  48. readBundle(reinterpret_cast<char *>(header), sizeof(header));
  49. const size_t numTableEntries = folly::Endian::little(header[1]);
  50. const size_t startupCodeSize = folly::Endian::little(header[2]);
  51. // allocate memory for meta data and lookup table.
  52. m_table = ModuleTable(numTableEntries);
  53. m_baseOffset = sizeof(header) + m_table.byteLength();
  54. // read the lookup table from the file
  55. readBundle(
  56. reinterpret_cast<char *>(m_table.data.get()), m_table.byteLength());
  57. // read the startup code
  58. m_startupCode = std::unique_ptr<JSBigBufferString>(
  59. new JSBigBufferString{startupCodeSize - 1});
  60. readBundle(m_startupCode->data(), startupCodeSize - 1);
  61. }
  62. JSIndexedRAMBundle::Module JSIndexedRAMBundle::getModule(
  63. uint32_t moduleId) const {
  64. Module ret;
  65. ret.name = folly::to<std::string>(moduleId, ".js");
  66. ret.code = getModuleCode(moduleId);
  67. return ret;
  68. }
  69. std::unique_ptr<const JSBigString> JSIndexedRAMBundle::getStartupCode() {
  70. CHECK(m_startupCode)
  71. << "startup code for a RAM Bundle can only be retrieved once";
  72. return std::move(m_startupCode);
  73. }
  74. std::string JSIndexedRAMBundle::getModuleCode(const uint32_t id) const {
  75. const auto moduleData = id < m_table.numEntries ? &m_table.data[id] : nullptr;
  76. // entries without associated code have offset = 0 and length = 0
  77. const uint32_t length =
  78. moduleData ? folly::Endian::little(moduleData->length) : 0;
  79. if (length == 0) {
  80. throw std::ios_base::failure(
  81. folly::to<std::string>("Error loading module", id, "from RAM Bundle"));
  82. }
  83. std::string ret(length - 1, '\0');
  84. readBundle(
  85. &ret.front(),
  86. length - 1,
  87. m_baseOffset + folly::Endian::little(moduleData->offset));
  88. return ret;
  89. }
  90. void JSIndexedRAMBundle::readBundle(char *buffer, const std::streamsize bytes)
  91. const {
  92. if (!m_bundle->read(buffer, bytes)) {
  93. if (m_bundle->rdstate() & std::ios::eofbit) {
  94. throw std::ios_base::failure("Unexpected end of RAM Bundle file");
  95. }
  96. throw std::ios_base::failure(folly::to<std::string>(
  97. "Error reading RAM Bundle: ", m_bundle->rdstate()));
  98. }
  99. }
  100. void JSIndexedRAMBundle::readBundle(
  101. char *buffer,
  102. const std::streamsize bytes,
  103. const std::ifstream::pos_type position) const {
  104. if (!m_bundle->seekg(position)) {
  105. throw std::ios_base::failure(folly::to<std::string>(
  106. "Error reading RAM Bundle: ", m_bundle->rdstate()));
  107. }
  108. readBundle(buffer, bytes);
  109. }
  110. } // namespace react
  111. } // namespace facebook