diff --git a/packages/react-native/ReactCommon/cxxreact/JSIndexedRAMBundle.cpp b/packages/react-native/ReactCommon/cxxreact/JSIndexedRAMBundle.cpp index f2320b002614..c17685de39fd 100644 --- a/packages/react-native/ReactCommon/cxxreact/JSIndexedRAMBundle.cpp +++ b/packages/react-native/ReactCommon/cxxreact/JSIndexedRAMBundle.cpp @@ -9,16 +9,26 @@ #ifndef RCT_REMOVE_LEGACY_ARCH -#include +#include +#include #include #include #include -#include #include 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::string)> JSIndexedRAMBundle::buildFactory() { return [](const std::string& bundlePath) { @@ -60,8 +70,8 @@ void JSIndexedRAMBundle::init() { "header size must exactly match the input file format"); readBundle(reinterpret_cast(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); @@ -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"); @@ -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; } diff --git a/packages/react-native/ReactCommon/cxxreact/tests/JSIndexedRAMBundleTest.cpp b/packages/react-native/ReactCommon/cxxreact/tests/JSIndexedRAMBundleTest.cpp new file mode 100644 index 000000000000..4c4cd90a7d21 --- /dev/null +++ b/packages/react-native/ReactCommon/cxxreact/tests/JSIndexedRAMBundleTest.cpp @@ -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 +#include +#include + +#include +#include +#include + +#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(value & 0xFF)); + out.push_back(static_cast((value >> 8) & 0xFF)); + out.push_back(static_cast((value >> 16) & 0xFF)); + out.push_back(static_cast((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(startup.size() + 1); + const auto lengthZero = static_cast(moduleZero.size() + 1); + const auto lengthOne = static_cast(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(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