Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 16 additions & 6 deletions packages/react-native/ReactCommon/cxxreact/JSIndexedRAMBundle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,26 @@

#ifndef RCT_REMOVE_LEGACY_ARCH

#include <glog/logging.h>
#include <bit>
#include <cstdint>
#include <fstream>
#include <memory>
#include <sstream>

#include <folly/lang/Bits.h>
#include <glog/logging.h>

namespace facebook::react {

namespace {
uint32_t littleEndianToHost(uint32_t value) {
if constexpr (std::endian::native == std::endian::big) {
return (value << 24) | ((value & 0x0000FF00U) << 8) |
((value & 0x00FF0000U) >> 8) | (value >> 24);
}
return value;
}
} // namespace

std::function<std::unique_ptr<JSModulesUnbundle>(std::string)>
JSIndexedRAMBundle::buildFactory() {
return [](const std::string& bundlePath) {
Expand Down Expand Up @@ -60,8 +70,8 @@ void JSIndexedRAMBundle::init() {
"header size must exactly match the input file format");

readBundle(reinterpret_cast<char*>(header), sizeof(header));
size_t numTableEntries = folly::Endian::little(header[1]);
std::streamsize startupCodeSize = folly::Endian::little(header[2]);
size_t numTableEntries = littleEndianToHost(header[1]);
std::streamsize startupCodeSize = littleEndianToHost(header[2]);

// allocate memory for meta data and lookup table.
m_table = ModuleTable(numTableEntries);
Expand Down Expand Up @@ -95,7 +105,7 @@ std::string JSIndexedRAMBundle::getModuleCode(const uint32_t id) const {

// entries without associated code have offset = 0 and length = 0
const uint32_t length =
moduleData != nullptr ? folly::Endian::little(moduleData->length) : 0;
moduleData != nullptr ? littleEndianToHost(moduleData->length) : 0;
if (length == 0) {
throw std::ios_base::failure(
"Error loading module" + std::to_string(id) + "from RAM Bundle");
Expand All @@ -105,7 +115,7 @@ std::string JSIndexedRAMBundle::getModuleCode(const uint32_t id) const {
readBundle(
&ret.front(),
length - 1,
m_baseOffset + folly::Endian::little(moduleData->offset));
m_baseOffset + littleEndianToHost(moduleData->offset));
return ret;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

#include <cstdint>
#include <memory>
#include <string>

#include <cxxreact/JSBigString.h>
#include <cxxreact/JSIndexedRAMBundle.h>
#include <gtest/gtest.h>

#ifndef RCT_REMOVE_LEGACY_ARCH

using namespace facebook::react;

namespace {
constexpr uint32_t kRAMBundleMagic = 0xFB0BD1E5;

void appendLittleEndian32(std::string& out, uint32_t value) {
out.push_back(static_cast<char>(value & 0xFF));
out.push_back(static_cast<char>((value >> 8) & 0xFF));
out.push_back(static_cast<char>((value >> 16) & 0xFF));
out.push_back(static_cast<char>((value >> 24) & 0xFF));
}

void appendNullTerminatedSection(std::string& out, const std::string& section) {
out += section;
out.push_back('\0');
}
} // namespace

TEST(JSIndexedRAMBundleTest, ReadsLittleEndianStartupAndModules) {
const std::string startup = "var startup = true;";
const std::string moduleZero = "module zero code";
const std::string moduleOne = "m1";

const auto startupCodeSize = static_cast<uint32_t>(startup.size() + 1);
const auto lengthZero = static_cast<uint32_t>(moduleZero.size() + 1);
const auto lengthOne = static_cast<uint32_t>(moduleOne.size() + 1);
const uint32_t offsetZero = startupCodeSize;
const uint32_t offsetOne = offsetZero + lengthZero;

std::string bundle;
appendLittleEndian32(bundle, kRAMBundleMagic);
appendLittleEndian32(bundle, 2);
appendLittleEndian32(bundle, startupCodeSize);
appendLittleEndian32(bundle, offsetZero);
appendLittleEndian32(bundle, lengthZero);
appendLittleEndian32(bundle, offsetOne);
appendLittleEndian32(bundle, lengthOne);
appendNullTerminatedSection(bundle, startup);
appendNullTerminatedSection(bundle, moduleZero);
appendNullTerminatedSection(bundle, moduleOne);

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
JSIndexedRAMBundle ramBundle(std::make_unique<JSBigStdString>(bundle));

const auto startupCode = ramBundle.getStartupCode();
EXPECT_EQ(std::string(startupCode->c_str(), startupCode->size()), startup);

const auto firstModule = ramBundle.getModule(0);
EXPECT_EQ(firstModule.name, "0.js");
EXPECT_EQ(firstModule.code, moduleZero);

const auto secondModule = ramBundle.getModule(1);
EXPECT_EQ(secondModule.name, "1.js");
EXPECT_EQ(secondModule.code, moduleOne);
#pragma GCC diagnostic pop
}

#endif // RCT_REMOVE_LEGACY_ARCH
Loading