2019-10-16 20:03:47 +03:00
|
|
|
/*
|
|
|
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
|
|
*
|
|
|
|
* This source code is licensed under the MIT license found in the
|
|
|
|
* LICENSE file in the root directory of this source tree.
|
|
|
|
*/
|
2016-11-23 17:31:43 +03:00
|
|
|
|
|
|
|
#include "JSIndexedRAMBundle.h"
|
2017-06-24 02:49:55 +03:00
|
|
|
|
2019-02-28 11:49:49 +03:00
|
|
|
#include <glog/logging.h>
|
2019-06-03 17:08:42 +03:00
|
|
|
#include <fstream>
|
|
|
|
#include <sstream>
|
2017-11-08 14:50:36 +03:00
|
|
|
#include <folly/Memory.h>
|
|
|
|
|
2016-11-23 17:31:43 +03:00
|
|
|
namespace facebook {
|
|
|
|
namespace react {
|
|
|
|
|
2017-11-09 22:55:37 +03:00
|
|
|
std::function<std::unique_ptr<JSModulesUnbundle>(std::string)> JSIndexedRAMBundle::buildFactory() {
|
|
|
|
return [](const std::string& bundlePath){
|
|
|
|
return folly::make_unique<JSIndexedRAMBundle>(bundlePath.c_str());
|
2017-11-08 14:50:36 +03:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2019-06-03 17:08:42 +03:00
|
|
|
JSIndexedRAMBundle::JSIndexedRAMBundle(const char *sourcePath) {
|
|
|
|
m_bundle = std::make_unique<std::ifstream>(sourcePath, std::ifstream::binary);
|
2016-11-23 17:31:43 +03:00
|
|
|
if (!m_bundle) {
|
|
|
|
throw std::ios_base::failure(
|
2018-02-05 22:47:10 +03:00
|
|
|
folly::to<std::string>("Bundle ", sourcePath,
|
2019-06-03 17:08:42 +03:00
|
|
|
"cannot be opened: ", m_bundle->rdstate()));
|
2016-11-23 17:31:43 +03:00
|
|
|
}
|
2019-06-03 17:08:42 +03:00
|
|
|
init();
|
|
|
|
}
|
|
|
|
|
|
|
|
JSIndexedRAMBundle::JSIndexedRAMBundle(std::unique_ptr<const JSBigString> script) {
|
|
|
|
// tmpStream is needed because m_bundle is std::istream type
|
|
|
|
// which has no member 'write'
|
|
|
|
std::unique_ptr<std::stringstream> tmpStream = std::make_unique<std::stringstream>();
|
|
|
|
tmpStream->write(script->c_str(), script->size());
|
|
|
|
m_bundle = std::move(tmpStream);
|
|
|
|
if (!m_bundle) {
|
|
|
|
throw std::ios_base::failure(
|
|
|
|
folly::to<std::string>("Bundle from string cannot be opened: ", m_bundle->rdstate()));
|
|
|
|
}
|
|
|
|
init();
|
|
|
|
}
|
2016-11-23 17:31:43 +03:00
|
|
|
|
2019-06-03 17:08:42 +03:00
|
|
|
void JSIndexedRAMBundle::init() {
|
2016-11-23 17:31:43 +03:00
|
|
|
// read in magic header, number of entries, and length of the startup section
|
|
|
|
uint32_t header[3];
|
|
|
|
static_assert(
|
|
|
|
sizeof(header) == 12,
|
|
|
|
"header size must exactly match the input file format");
|
|
|
|
|
|
|
|
readBundle(reinterpret_cast<char *>(header), sizeof(header));
|
2018-02-05 22:47:10 +03:00
|
|
|
const size_t numTableEntries = folly::Endian::little(header[1]);
|
|
|
|
const size_t startupCodeSize = folly::Endian::little(header[2]);
|
2016-11-23 17:31:43 +03:00
|
|
|
|
|
|
|
// allocate memory for meta data and lookup table.
|
|
|
|
m_table = ModuleTable(numTableEntries);
|
|
|
|
m_baseOffset = sizeof(header) + m_table.byteLength();
|
|
|
|
|
|
|
|
// read the lookup table from the file
|
|
|
|
readBundle(
|
|
|
|
reinterpret_cast<char *>(m_table.data.get()), m_table.byteLength());
|
|
|
|
|
|
|
|
// read the startup code
|
2016-12-03 13:18:59 +03:00
|
|
|
m_startupCode = std::unique_ptr<JSBigBufferString>(new JSBigBufferString{startupCodeSize - 1});
|
2016-11-23 17:31:43 +03:00
|
|
|
|
2016-12-03 13:18:59 +03:00
|
|
|
readBundle(m_startupCode->data(), startupCodeSize - 1);
|
2016-11-23 17:31:43 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
JSIndexedRAMBundle::Module JSIndexedRAMBundle::getModule(uint32_t moduleId) const {
|
|
|
|
Module ret;
|
2018-02-05 22:47:10 +03:00
|
|
|
ret.name = folly::to<std::string>(moduleId, ".js");
|
2016-11-23 17:31:43 +03:00
|
|
|
ret.code = getModuleCode(moduleId);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-02-02 01:10:34 +03:00
|
|
|
std::unique_ptr<const JSBigString> JSIndexedRAMBundle::getStartupCode() {
|
2016-11-23 17:31:43 +03:00
|
|
|
CHECK(m_startupCode) << "startup code for a RAM Bundle can only be retrieved once";
|
|
|
|
return std::move(m_startupCode);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string JSIndexedRAMBundle::getModuleCode(const uint32_t id) const {
|
|
|
|
const auto moduleData = id < m_table.numEntries ? &m_table.data[id] : nullptr;
|
|
|
|
|
|
|
|
// entries without associated code have offset = 0 and length = 0
|
2018-02-05 22:47:10 +03:00
|
|
|
const uint32_t length = moduleData ? folly::Endian::little(moduleData->length) : 0;
|
2016-11-23 17:31:43 +03:00
|
|
|
if (length == 0) {
|
|
|
|
throw std::ios_base::failure(
|
2018-02-05 22:47:10 +03:00
|
|
|
folly::to<std::string>("Error loading module", id, "from RAM Bundle"));
|
2016-11-23 17:31:43 +03:00
|
|
|
}
|
|
|
|
|
2016-12-03 13:18:59 +03:00
|
|
|
std::string ret(length - 1, '\0');
|
2018-02-05 22:47:10 +03:00
|
|
|
readBundle(&ret.front(), length - 1, m_baseOffset + folly::Endian::little(moduleData->offset));
|
2016-11-23 17:31:43 +03:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
void JSIndexedRAMBundle::readBundle(char *buffer, const std::streamsize bytes) const {
|
2019-06-03 17:08:42 +03:00
|
|
|
if (!m_bundle->read(buffer, bytes)) {
|
|
|
|
if (m_bundle->rdstate() & std::ios::eofbit) {
|
2016-11-23 17:31:43 +03:00
|
|
|
throw std::ios_base::failure("Unexpected end of RAM Bundle file");
|
|
|
|
}
|
|
|
|
throw std::ios_base::failure(
|
2019-06-03 17:08:42 +03:00
|
|
|
folly::to<std::string>("Error reading RAM Bundle: ", m_bundle->rdstate()));
|
2016-11-23 17:31:43 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void JSIndexedRAMBundle::readBundle(
|
|
|
|
char *buffer,
|
|
|
|
const std::streamsize bytes,
|
|
|
|
const std::ifstream::pos_type position) const {
|
|
|
|
|
2019-06-03 17:08:42 +03:00
|
|
|
if (!m_bundle->seekg(position)) {
|
2016-11-23 17:31:43 +03:00
|
|
|
throw std::ios_base::failure(
|
2019-06-03 17:08:42 +03:00
|
|
|
folly::to<std::string>("Error reading RAM Bundle: ", m_bundle->rdstate()));
|
2016-11-23 17:31:43 +03:00
|
|
|
}
|
|
|
|
readBundle(buffer, bytes);
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace react
|
|
|
|
} // namespace facebook
|