Move `ScriptTag` and `RCTJSModulesUnbundle` to `cxxreact`

Reviewed By: javache

Differential Revision: D4213662

fbshipit-source-id: fc2ec9717c24fe77bb022a48777049f88173ebeb
This commit is contained in:
David Aurelio 2016-11-23 06:31:43 -08:00 committed by Facebook Github Bot
parent f9d80a451a
commit 5db7484e8d
10 changed files with 396 additions and 100 deletions

View File

@ -11,55 +11,6 @@
#import "RCTDefines.h"
/**
* RCTScriptTag
*
* Scripts given to the JS Executors to run could be in any of the following
* formats. They are tagged so the executor knows how to run them.
*/
typedef NS_ENUM(NSInteger) {
RCTScriptString = 0,
RCTScriptRAMBundle,
RCTScriptBCBundle,
} RCTScriptTag;
/**
* RCTBundleHeader
*
* RAM bundles and BC bundles begin with headers. For RAM bundles this is
* 4 bytes, for BC bundles this is 12 bytes. This structure holds the first 12
* bytes from a bundle in a way that gives access to that information.
*/
typedef union {
// `allBytes` is the first field so that zero-initializing the union fills
// it completely with zeroes. Without it, only the first field of the union
// gets zero-initialized.
uint32_t allBytes[3];
uint32_t RAMMagic;
struct {
uint64_t BCMagic;
uint32_t BCVersion;
};
} RCTBundleHeader;
/**
* RCTParseTypeFromHeader
*
* Takes the first 8 bytes of a bundle, and returns a tag describing the
* bundle's format.
*/
RCT_EXTERN RCTScriptTag RCTParseTypeFromHeader(RCTBundleHeader header);
/**
* RCTStringForScriptTag
*
* Convert an `RCTScriptTag` enum into a string, useful for emitting in errors
* and diagnostic messages.
*/
RCT_EXTERN NSString *RCTStringForScriptTag(RCTScriptTag tag);
extern NSString *const RCTJavaScriptLoaderErrorDomain;
NS_ENUM(NSInteger) {

View File

@ -16,38 +16,11 @@
#import "RCTPerformanceLogger.h"
#import "RCTMultipartDataTask.h"
#include <cxxreact/JSBundleType.h>
#include <sys/stat.h>
static uint32_t const RCTRAMBundleMagicNumber = 0xFB0BD1E5;
static uint64_t const RCTBCBundleMagicNumber = 0xFF4865726D657300;
NSString *const RCTJavaScriptLoaderErrorDomain = @"RCTJavaScriptLoaderErrorDomain";
RCTScriptTag RCTParseTypeFromHeader(RCTBundleHeader header)
{
if (NSSwapLittleIntToHost(header.RAMMagic) == RCTRAMBundleMagicNumber) {
return RCTScriptRAMBundle;
}
if (NSSwapLittleLongLongToHost(header.BCMagic) == RCTBCBundleMagicNumber) {
return RCTScriptBCBundle;
}
return RCTScriptString;
}
NSString *RCTStringForScriptTag(RCTScriptTag tag)
{
switch (tag) {
case RCTScriptString:
return @"String";
case RCTScriptRAMBundle:
return @"RAM Bundle";
case RCTScriptBCBundle:
return @"BC Bundle";
}
}
@implementation RCTLoadingProgress
- (NSString *)description
@ -58,7 +31,7 @@ NSString *RCTStringForScriptTag(RCTScriptTag tag)
if (_total > 0) {
[desc appendFormat:@" %ld%% (%@/%@)", (long)(100 * [_done integerValue] / [_total integerValue]), _done, _total];
}
[desc appendString:@""];
[desc appendString:@"\u2026"];
return desc;
}
@ -140,7 +113,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init)
return nil;
}
RCTBundleHeader header = {};
facebook::react::BundleHeader header{};
size_t readResult = fread(&header, sizeof(header), 1, bundle);
fclose(bundle);
if (readResult != 1) {
@ -153,12 +126,12 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init)
return nil;
}
RCTScriptTag tag = RCTParseTypeFromHeader(header);
facebook::react::ScriptTag tag = facebook::react::parseTypeFromHeader(header);
switch (tag) {
case RCTScriptRAMBundle:
case facebook::react::ScriptTag::RAMBundle:
break;
case RCTScriptString:
case facebook::react::ScriptTag::String:
if (error) {
*error = [NSError errorWithDomain:RCTJavaScriptLoaderErrorDomain
code:RCTJavaScriptLoaderErrorCannotBeLoadedSynchronously
@ -167,7 +140,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init)
}
return nil;
case RCTScriptBCBundle:
case facebook::react::ScriptTag::BCBundle:
if (header.BCVersion != runtimeBCVersion) {
if (error) {
NSString *errDesc =

View File

@ -17,6 +17,8 @@
#import <UIKit/UIDevice.h>
#import <cxxreact/JSBundleType.h>
#import "RCTAssert.h"
#import "RCTBridge+Private.h"
#import "RCTDefines.h"
@ -66,7 +68,7 @@ struct RandomAccessBundleStartupCode {
};
struct TaggedScript {
const RCTScriptTag tag;
const facebook::react::ScriptTag tag;
const NSData *script;
};
@ -292,7 +294,7 @@ static NSThread *newJavaScriptThread(void)
return loadError;
}
if (taggedScript.tag == RCTScriptRAMBundle) {
if (taggedScript.tag == facebook::react::ScriptTag::RAMBundle) {
registerNativeRequire(_context.context, self);
}
@ -712,7 +714,7 @@ RCT_EXPORT_METHOD(setContextName:(nonnull NSString *)contextName)
return;
}
if (taggedScript.tag == RCTScriptRAMBundle) {
if (taggedScript.tag == facebook::react::ScriptTag::RAMBundle) {
registerNativeRequire(self.context.context, self);
}
@ -734,13 +736,13 @@ static TaggedScript loadTaggedScript(NSData *script,
{
RCT_PROFILE_BEGIN_EVENT(0, @"executeApplicationScript / prepare bundle", nil);
RCTBundleHeader header = {};
facebook::react::BundleHeader header{};
[script getBytes:&header length:sizeof(header)];
RCTScriptTag tag = RCTParseTypeFromHeader(header);
facebook::react::ScriptTag tag = facebook::react::parseTypeFromHeader(header);
NSData *loadedScript = NULL;
switch (tag) {
case RCTScriptRAMBundle:
case facebook::react::ScriptTag::RAMBundle:
[performanceLogger markStartForTag:RCTPLRAMBundleLoad];
loadedScript = loadRAMBundle(sourceURL, error, randomAccessBundle);
@ -749,11 +751,11 @@ static TaggedScript loadTaggedScript(NSData *script,
[performanceLogger setValue:loadedScript.length forTag:RCTPLRAMStartupCodeSize];
break;
case RCTScriptBCBundle:
case facebook::react::ScriptTag::BCBundle:
loadedScript = script;
break;
case RCTScriptString: {
case facebook::react::ScriptTag::String: {
NSMutableData *nullTerminatedScript = [NSMutableData dataWithData:script];
[nullTerminatedScript appendBytes:"" length:1];
loadedScript = nullTerminatedScript;
@ -785,16 +787,16 @@ static NSError *executeApplicationScript(TaggedScript taggedScript,
JSStringRef bundleURL = jscWrapper->JSStringCreateWithUTF8CString(sourceURL.absoluteString.UTF8String);
switch (taggedScript.tag) {
case RCTScriptRAMBundle:
case facebook::react::ScriptTag::RAMBundle:
/* fallthrough */
case RCTScriptString: {
case facebook::react::ScriptTag::String: {
JSStringRef execJSString = jscWrapper->JSStringCreateWithUTF8CString((const char *)taggedScript.script.bytes);
jscWrapper->JSEvaluateScript(ctx, execJSString, NULL, bundleURL, 0, &jsError);
jscWrapper->JSStringRelease(execJSString);
break;
}
case RCTScriptBCBundle: {
case facebook::react::ScriptTag::BCBundle: {
file_ptr source(fopen(sourceURL.path.UTF8String, "r"), fclose);
int sourceFD = fileno(source.get());

View File

@ -60,7 +60,6 @@
13E067591A70F44B002CDEE1 /* UIView+React.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E067541A70F44B002CDEE1 /* UIView+React.m */; };
13E41EEB1C05CA0B00CD8DAC /* RCTProfileTrampoline-i386.S in Sources */ = {isa = PBXBuildFile; fileRef = 14BF717F1C04793D00C97D0C /* RCTProfileTrampoline-i386.S */; };
13F17A851B8493E5007D4C75 /* RCTRedBox.m in Sources */ = {isa = PBXBuildFile; fileRef = 13F17A841B8493E5007D4C75 /* RCTRedBox.m */; };
14200DAA1AC179B3008EE6BA /* RCTJavaScriptLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 14200DA91AC179B3008EE6BA /* RCTJavaScriptLoader.m */; };
142014191B32094000CC17BA /* RCTPerformanceLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = 142014171B32094000CC17BA /* RCTPerformanceLogger.m */; };
14435CE51AAC4AE100FC20F4 /* RCTMap.m in Sources */ = {isa = PBXBuildFile; fileRef = 14435CE21AAC4AE100FC20F4 /* RCTMap.m */; };
14435CE61AAC4AE100FC20F4 /* RCTMapManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 14435CE41AAC4AE100FC20F4 /* RCTMapManager.m */; };
@ -90,7 +89,6 @@
2D3B5E9A1D9B089D00451313 /* RCTEventDispatcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 83CBBA661A601EF300E9B192 /* RCTEventDispatcher.m */; };
2D3B5E9B1D9B08A000451313 /* RCTFrameUpdate.m in Sources */ = {isa = PBXBuildFile; fileRef = 14C2CA751B3AC64F00E6CBB2 /* RCTFrameUpdate.m */; };
2D3B5E9C1D9B08A300451313 /* RCTImageSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 13BB3D011BECD54500932C10 /* RCTImageSource.m */; };
2D3B5E9D1D9B08A800451313 /* RCTJavaScriptLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 14200DA91AC179B3008EE6BA /* RCTJavaScriptLoader.m */; };
2D3B5E9E1D9B08AD00451313 /* RCTJSStackFrame.m in Sources */ = {isa = PBXBuildFile; fileRef = 008341F41D1DB34400876D9A /* RCTJSStackFrame.m */; };
2D3B5E9F1D9B08AF00451313 /* RCTKeyCommands.m in Sources */ = {isa = PBXBuildFile; fileRef = 13A1F71D1A75392D00D3D453 /* RCTKeyCommands.m */; };
2D3B5EA01D9B08B200451313 /* RCTLog.mm in Sources */ = {isa = PBXBuildFile; fileRef = 83CBBA4E1A601E3B00E9B192 /* RCTLog.mm */; };
@ -193,6 +191,8 @@
83CBBA981A6020BB00E9B192 /* RCTTouchHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 83CBBA971A6020BB00E9B192 /* RCTTouchHandler.m */; };
83CBBACC1A6023D300E9B192 /* RCTConvert.m in Sources */ = {isa = PBXBuildFile; fileRef = 83CBBACB1A6023D300E9B192 /* RCTConvert.m */; };
85C199EE1CD2407900DAD810 /* RCTJSCWrapper.mm in Sources */ = {isa = PBXBuildFile; fileRef = 85C199ED1CD2407900DAD810 /* RCTJSCWrapper.mm */; };
AC70D2E91DE489E4002E6351 /* RCTJavaScriptLoader.mm in Sources */ = {isa = PBXBuildFile; fileRef = AC70D2E81DE489E4002E6351 /* RCTJavaScriptLoader.mm */; };
AC70D2ED1DE48A22002E6351 /* JSBundleType.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AC70D2EB1DE48A22002E6351 /* JSBundleType.cpp */; };
B233E6EA1D2D845D00BC68BA /* RCTI18nManager.m in Sources */ = {isa = PBXBuildFile; fileRef = B233E6E91D2D845D00BC68BA /* RCTI18nManager.m */; };
B95154321D1B34B200FE7B80 /* RCTActivityIndicatorView.m in Sources */ = {isa = PBXBuildFile; fileRef = B95154311D1B34B200FE7B80 /* RCTActivityIndicatorView.m */; };
E9B20B7B1B500126007A2DA7 /* RCTAccessibilityManager.m in Sources */ = {isa = PBXBuildFile; fileRef = E9B20B7A1B500126007A2DA7 /* RCTAccessibilityManager.m */; };
@ -339,7 +339,6 @@
13F17A831B8493E5007D4C75 /* RCTRedBox.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTRedBox.h; sourceTree = "<group>"; };
13F17A841B8493E5007D4C75 /* RCTRedBox.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTRedBox.m; sourceTree = "<group>"; };
14200DA81AC179B3008EE6BA /* RCTJavaScriptLoader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTJavaScriptLoader.h; sourceTree = "<group>"; };
14200DA91AC179B3008EE6BA /* RCTJavaScriptLoader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTJavaScriptLoader.m; sourceTree = "<group>"; };
142014171B32094000CC17BA /* RCTPerformanceLogger.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTPerformanceLogger.m; sourceTree = "<group>"; };
142014181B32094000CC17BA /* RCTPerformanceLogger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTPerformanceLogger.h; sourceTree = "<group>"; };
1436DD071ADE7AA000A5ED7D /* RCTFrameUpdate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RCTFrameUpdate.h; sourceTree = "<group>"; };
@ -438,6 +437,10 @@
83F15A171B7CC46900F10295 /* UIView+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "UIView+Private.h"; sourceTree = "<group>"; };
85C199EC1CD2407900DAD810 /* RCTJSCWrapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTJSCWrapper.h; sourceTree = "<group>"; };
85C199ED1CD2407900DAD810 /* RCTJSCWrapper.mm */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.objcpp; fileEncoding = 4; path = RCTJSCWrapper.mm; sourceTree = "<group>"; };
AC70D2E81DE489E4002E6351 /* RCTJavaScriptLoader.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = RCTJavaScriptLoader.mm; sourceTree = "<group>"; };
AC70D2EB1DE48A22002E6351 /* JSBundleType.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = JSBundleType.cpp; path = cxxreact/JSBundleType.cpp; sourceTree = "<group>"; };
AC70D2EC1DE48A22002E6351 /* JSBundleType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JSBundleType.h; path = cxxreact/JSBundleType.h; sourceTree = "<group>"; };
AC70D2EE1DE48AC5002E6351 /* oss-compat-util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "oss-compat-util.h"; path = "cxxreact/oss-compat-util.h"; sourceTree = "<group>"; };
ACDD3FDA1BC7430D00E7DE33 /* RCTBorderStyle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTBorderStyle.h; sourceTree = "<group>"; };
B233E6E81D2D843200BC68BA /* RCTI18nManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTI18nManager.h; sourceTree = "<group>"; };
B233E6E91D2D845D00BC68BA /* RCTI18nManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTI18nManager.m; sourceTree = "<group>"; };
@ -665,6 +668,7 @@
isa = PBXGroup;
children = (
133683431D37ACA10077D0C3 /* CSSLayout */,
AC70D2EA1DE489FC002E6351 /* cxxreact */,
);
name = ReactCommon;
path = ../ReactCommon;
@ -733,7 +737,7 @@
83CBBA4C1A601E3B00E9B192 /* RCTInvalidating.h */,
83CBBA631A601ECA00E9B192 /* RCTJavaScriptExecutor.h */,
14200DA81AC179B3008EE6BA /* RCTJavaScriptLoader.h */,
14200DA91AC179B3008EE6BA /* RCTJavaScriptLoader.m */,
AC70D2E81DE489E4002E6351 /* RCTJavaScriptLoader.mm */,
008341F51D1DB34400876D9A /* RCTJSStackFrame.h */,
008341F41D1DB34400876D9A /* RCTJSStackFrame.m */,
13A1F71C1A75392D00D3D453 /* RCTKeyCommands.h */,
@ -773,6 +777,16 @@
path = Base;
sourceTree = "<group>";
};
AC70D2EA1DE489FC002E6351 /* cxxreact */ = {
isa = PBXGroup;
children = (
AC70D2EB1DE48A22002E6351 /* JSBundleType.cpp */,
AC70D2EC1DE48A22002E6351 /* JSBundleType.h */,
AC70D2EE1DE48AC5002E6351 /* oss-compat-util.h */,
);
name = cxxreact;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
@ -932,7 +946,6 @@
2D3B5E9B1D9B08A000451313 /* RCTFrameUpdate.m in Sources */,
2D3B5EE41D9B09BB00451313 /* RCTSegmentedControlManager.m in Sources */,
2D3B5EE31D9B09B700451313 /* RCTSegmentedControl.m in Sources */,
2D3B5E9D1D9B08A800451313 /* RCTJavaScriptLoader.m in Sources */,
2D3B5EB71D9B091800451313 /* RCTRedBox.m in Sources */,
2D3B5ED11D9B097500451313 /* RCTMapAnnotation.m in Sources */,
2D3B5EAB1D9B08EC00451313 /* RCTJSCErrorHandling.m in Sources */,
@ -1042,12 +1055,12 @@
58C571C11AA56C1900CDF9C8 /* RCTDatePickerManager.m in Sources */,
1450FF8A1BCFF28A00208362 /* RCTProfileTrampoline-x86_64.S in Sources */,
13D9FEEB1CDCCECF00158BD7 /* RCTEventEmitter.m in Sources */,
AC70D2E91DE489E4002E6351 /* RCTJavaScriptLoader.mm in Sources */,
14F7A0EC1BDA3B3C003C6C10 /* RCTPerfMonitor.m in Sources */,
1450FF881BCFF28A00208362 /* RCTProfileTrampoline-arm64.S in Sources */,
13E41EEB1C05CA0B00CD8DAC /* RCTProfileTrampoline-i386.S in Sources */,
3D37B5821D522B190042D5B5 /* RCTFont.mm in Sources */,
13B080061A6947C200A75B9A /* RCTScrollViewManager.m in Sources */,
14200DAA1AC179B3008EE6BA /* RCTJavaScriptLoader.m in Sources */,
137327EA1AA5CF210034F82E /* RCTTabBarManager.m in Sources */,
369123E11DDC75850095B341 /* JSCSamplingProfiler.m in Sources */,
13B080261A694A8400A75B9A /* RCTWrapperViewController.m in Sources */,
@ -1089,6 +1102,7 @@
83A1FE8C1B62640A00BE0E65 /* RCTModalHostView.m in Sources */,
13E067551A70F44B002CDEE1 /* RCTShadowView.m in Sources */,
1450FF871BCFF28A00208362 /* RCTProfileTrampoline-arm.S in Sources */,
AC70D2ED1DE48A22002E6351 /* JSBundleType.cpp in Sources */,
131B6AF51AF1093D00FFC3E0 /* RCTSegmentedControlManager.m in Sources */,
58114A171AAE854800E7D092 /* RCTPickerManager.m in Sources */,
191E3EBE1C29D9AF00C180A6 /* RCTRefreshControlManager.m in Sources */,

View File

@ -117,6 +117,8 @@ CXXREACT_PUBLIC_HEADERS = [
'JSCExecutor.h',
'JSCNativeModules.h',
'JSCWebWorker.h',
'JSBundleType.h',
'JSIndexedRAMBundle.h',
'JSModulesUnbundle.h',
'MessageQueueThread.h',
'MethodCall.h',

View File

@ -0,0 +1,37 @@
// Copyright 2004-present Facebook. All Rights Reserved.
#include "JSBundleType.h"
#include "oss-compat-util.h"
namespace facebook {
namespace react {
static uint32_t constexpr RAMBundleMagicNumber = 0xFB0BD1E5;
static uint64_t constexpr BCBundleMagicNumber = 0xFF4865726D657300;
ScriptTag parseTypeFromHeader(const BundleHeader& header) {
if (littleEndianToHost(header.RAMMagic) == RAMBundleMagicNumber) {
return ScriptTag::RAMBundle;
}
if (littleEndianToHost(header.BCMagic) == BCBundleMagicNumber) {
return ScriptTag::BCBundle;
}
return ScriptTag::String;
}
const char *stringForScriptTag(const ScriptTag& tag) {
switch (tag) {
case ScriptTag::String:
return "String";
case ScriptTag::RAMBundle:
return "RAM Bundle";
case ScriptTag::BCBundle:
return "BC Bundle";
}
return "";
}
} // namespace react
} // namespace facebook

View File

@ -0,0 +1,59 @@
// Copyright 2004-present Facebook. All Rights Reserved.
#pragma once
#include <cstdint>
#include <cstring>
namespace facebook {
namespace react {
/*
* ScriptTag
*
* Scripts given to the JS Executors to run could be in any of the following
* formats. They are tagged so the executor knows how to run them.
*/
enum struct ScriptTag {
String = 0,
RAMBundle,
BCBundle,
};
/**
* BundleHeader
*
* RAM bundles and BC bundles begin with headers. For RAM bundles this is
* 4 bytes, for BC bundles this is 12 bytes. This structure holds the first 12
* bytes from a bundle in a way that gives access to that information.
*/
union BundleHeader {
BundleHeader() {
std::memset(this, 0, sizeof(BundleHeader));
}
uint32_t RAMMagic;
struct {
uint64_t BCMagic;
uint32_t BCVersion;
};
};
/**
* parseTypeFromHeader
*
* Takes the first 8 bytes of a bundle, and returns a tag describing the
* bundle's format.
*/
ScriptTag parseTypeFromHeader(const BundleHeader& header);
/**
* stringForScriptTag
*
* Convert an `ScriptTag` enum into a string, useful for emitting in errors
* and diagnostic messages.
*/
const char* stringForScriptTag(const ScriptTag& tag);
} // namespace react
} // namespace facebook

View File

@ -0,0 +1,92 @@
// Copyright 2004-present Facebook. All Rights Reserved.
#include "JSIndexedRAMBundle.h"
#include "oss-compat-util.h"
namespace facebook {
namespace react {
JSIndexedRAMBundle::JSIndexedRAMBundle(const char *sourcePath) :
m_bundle (sourcePath, std::ios_base::in) {
if (!m_bundle) {
throw std::ios_base::failure(
toString("Bundle ", sourcePath,
"cannot be opened: ", m_bundle.rdstate()));
}
// 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));
const size_t numTableEntries = littleEndianToHost(header[1]);
const size_t startupCodeSize = littleEndianToHost(header[2]);
// 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
m_startupCode =
std::make_unique<facebook::react::JSBigBufferString>(startupCodeSize);
readBundle(m_startupCode->data(), startupCodeSize);
}
JSIndexedRAMBundle::Module JSIndexedRAMBundle::getModule(uint32_t moduleId) const {
Module ret;
ret.name = toString(moduleId, ".js");
ret.code = getModuleCode(moduleId);
return ret;
}
std::unique_ptr<const facebook::react::JSBigString> JSIndexedRAMBundle::getStartupCode() {
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
const uint32_t length = moduleData ? littleEndianToHost(moduleData->length) : 0;
if (length == 0) {
throw std::ios_base::failure(
toString("Error loading module", id, "from RAM Bundle"));
}
std::string ret(moduleData->length, '\0');
readBundle(&ret.front(), length, m_baseOffset + littleEndianToHost(moduleData->offset));
return ret;
}
void JSIndexedRAMBundle::readBundle(char *buffer, const std::streamsize bytes) const {
if (!m_bundle.read(buffer, bytes)) {
if (m_bundle.rdstate() & std::ios::eofbit) {
throw std::ios_base::failure("Unexpected end of RAM Bundle file");
}
throw std::ios_base::failure(
toString("Error reading RAM Bundle: ", m_bundle.rdstate()));
}
}
void JSIndexedRAMBundle::readBundle(
char *buffer,
const std::streamsize bytes,
const std::ifstream::pos_type position) const {
if (!m_bundle.seekg(position)) {
throw std::ios_base::failure(
toString("Error reading RAM Bundle: ", m_bundle.rdstate()));
}
readBundle(buffer, bytes);
}
} // namespace react
} // namespace facebook

View File

@ -0,0 +1,63 @@
// Copyright 2004-present Facebook. All Rights Reserved.
#pragma once
#include <fstream>
#include <memory>
#include "Executor.h"
#include "JSBundleType.h"
namespace facebook {
namespace react {
class JSBigString;
#include <cxxreact/JSModulesUnbundle.h>
class JSIndexedRAMBundle : public facebook::react::JSModulesUnbundle {
public:
// Throws std::runtime_error on failure.
JSIndexedRAMBundle(const char *sourceURL);
// Throws std::runtime_error on failure.
std::unique_ptr<const facebook::react::JSBigString> getStartupCode();
// Throws std::runtime_error on failure.
Module getModule(uint32_t moduleId) const override;
private:
struct ModuleData {
uint32_t offset;
uint32_t length;
};
static_assert(
sizeof(ModuleData) == 8,
"ModuleData must not have any padding and use sizes matching input files");
struct ModuleTable {
size_t numEntries;
std::unique_ptr<ModuleData[]> data;
ModuleTable() : numEntries(0) {};
ModuleTable(size_t entries) :
numEntries(entries),
data(std::make_unique<ModuleData[]>(numEntries)) {};
size_t byteLength() const {
return numEntries * sizeof(ModuleData);
}
};
std::string getModuleCode(const uint32_t id) const;
void readBundle(char *buffer, const std::streamsize bytes) const;
void readBundle(
char *buffer, const
std::streamsize bytes,
const std::ifstream::pos_type position) const;
mutable std::ifstream m_bundle;
ModuleTable m_table;
size_t m_baseOffset;
std::unique_ptr<facebook::react::JSBigBufferString> m_startupCode;
};
} // namespace react
} // namespace facebook

View File

@ -0,0 +1,103 @@
// Copyright 2004-present Facebook. All Rights Reserved.
//TODO #14683310 remove this header as soon as RN iOS OSS links against folly
#pragma once
#if defined(ANDROID)
#define USE_FOLLY_FOR_ENDIAN_SWAP 1
#define USE_FOLLY_FOR_TO_STRING 1
#elif defined(__has_include)
#define USE_FOLLY_FOR_ENDIAN_SWAP __has_include(<folly/Bits.h>)
#define USE_FOLLY_FOR_TO_STRING __has_include(<folly/String.h>)
#else
#define USE_FOLLY_FOR_ENDIAN_SWAP 0
#define USE_FOLLY_FOR_TO_STRING 0
#endif
#if USE_FOLLY_FOR_ENDIAN_SWAP
#include <folly/Bits.h>
#elif defined(__APPLE__)
#include <cstdint>
#include <CoreFoundation/CFByteOrder.h>
#endif // USE_FOLLY_FOR_ENDIAN_SWAP
#if USE_FOLLY_FOR_TO_STRING
#include <folly/String.h>
#else
#include <sstream>
#include <string>
#endif // USE_FOLLY_FOR_TO_STRING
#if USE_FOLLY_FOR_ENDIAN_SWAP
namespace facebook {
namespace react {
template <typename T>
inline T littleEndianToHost(T x) {
return folly::Endian::little(x);
}
#elif defined(__APPLE__)
namespace facebook {
namespace react {
// Yes, this is horrible. #14683310
inline int32_t littleEndianToHost(int32_t x) {
return CFSwapInt32LittleToHost(x);
}
inline uint32_t littleEndianToHost(uint32_t x) {
return CFSwapInt32LittleToHost(x);
}
inline int64_t littleEndianToHost(int64_t x) {
return CFSwapInt64LittleToHost(x);
}
inline uint64_t littleEndianToHost(uint64_t x) {
return CFSwapInt64LittleToHost(x);
}
#endif // USE_FOLLY_FOR_ENDIAN_SWAP
#if USE_FOLLY_FOR_TO_STRING
template <typename ...Ts>
inline std::string toString(Ts... values) {
return folly::to<std::string>(std::forward<Ts>(values)...);
}
#else
namespace {
template <typename ...Ts>
std::string toString(const std::stringstream& buf) {
return buf.str();
}
template <typename T, typename ...Ts>
std::string toString(std::stringstream& buf, T value, Ts... values) {
buf << value;
return toString(buf, std::forward<Ts>(values)...);
}
} // anonymous namespace
template <typename ...Ts>
std::string toString(Ts... values) {
std::stringstream buf{};
return toString(buf, std::forward<Ts>(values)...);
}
#endif // USE_FOLLY_FOR_TO_STRING
} // namespace react
} // namespace facebook
#undef USE_FOLLY_FOR_ENDIAN_SWAP
#undef USE_FOLLY_FOR_TO_STRING