Skip to content

Commit 705346f

Browse files
edusperoniNathanWalker
authored andcommitted
fix: support null characters on NSString marshalling
1 parent 2cbc4c4 commit 705346f

File tree

4 files changed

+63
-13
lines changed

4 files changed

+63
-13
lines changed

NativeScript/runtime/ArgConverter.mm

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@
163163
void* errorParam = argValues[errorParamIndex];
164164
NSError*__strong** outPtr = static_cast<NSError*__strong**>(errorParam);
165165
if (outPtr && *outPtr) {
166-
NSError* error = [NSError errorWithDomain:@"TNSErrorDomain" code:164 userInfo:@{ @"TNSJavaScriptError": [NSString stringWithUTF8String:message.c_str()] }];
166+
NSError* error = [NSError errorWithDomain:@"TNSErrorDomain" code:164 userInfo:@{ @"TNSJavaScriptError": tns::ToNSString(message) }];
167167
**static_cast<NSError*__strong**>(outPtr) = error;
168168
}
169169
}
@@ -248,8 +248,7 @@
248248
} else if (value->IsString()) {
249249
if (type == BinaryTypeEncodingType::IdEncoding ||
250250
type == BinaryTypeEncodingType::InterfaceDeclarationReference) {
251-
std::string strValue = tns::ToString(isolate, value);
252-
id data = [[NSString alloc] initWithBytes:strValue.c_str() length:strValue.length() encoding:NSUTF8StringEncoding];
251+
id data = tns::ToNSString(isolate, value);
253252
*(CFTypeRef*)retValue = CFBridgingRetain(data);
254253
return;
255254
}

NativeScript/runtime/DictionaryAdapter.mm

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,7 @@ - (id)nextObject {
4646
bool success = array->Get(context, self->index_).ToLocal(&key);
4747
tns::Assert(success, isolate);
4848
self->index_ += 2;
49-
std::string keyStr = tns::ToString(self->isolate_, key);
50-
NSString* result = [NSString stringWithUTF8String:keyStr.c_str()];
49+
NSString* result = tns::ToNSString(self->isolate_, key);
5150
return result;
5251
}
5352

NativeScript/runtime/Helpers.h

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,38 @@ extern "C" void NSLog(CFStringRef format, ...);
1515

1616
namespace tns {
1717

18-
inline v8::Local<v8::String> ToV8String(v8::Isolate* isolate, std::string value) {
18+
inline v8::Local<v8::String> ToV8String(v8::Isolate* isolate,const std::string& value) {
1919
return v8::String::NewFromUtf8(isolate, value.c_str(), v8::NewStringType::kNormal, (int)value.length()).ToLocalChecked();
2020
}
21+
#ifdef __OBJC__
22+
inline v8::Local<v8::String> ToV8String(v8::Isolate* isolate,const NSString* value) {
23+
/*
24+
// TODO: profile if this is faster
25+
// maybe have multiple conversion
26+
if([value fastestEncoding] == NSUTF16StringEncoding) {
27+
uint16_t static_buffer[256];
28+
uint16_t* targetBuffer = static_buffer;
29+
bool isDynamic = false;
30+
auto length = [value maximumLengthOfBytesUsingEncoding:NSUTF16StringEncoding];
31+
auto numberOfBytes = length * sizeof(uint16_t);
32+
if (length > 256) {
33+
targetBuffer = (uint16_t*)malloc(numberOfBytes);
34+
isDynamic = true;
35+
}
36+
NSUInteger usedLength = 0;
37+
NSRange range = NSMakeRange(0, [value length]);
38+
[value getBytes:targetBuffer maxLength:numberOfBytes usedLength:&usedLength encoding:NSUTF16StringEncoding options:0 range:range remainingRange:NULL];
39+
40+
auto result = v8::String::NewFromTwoByte(isolate, targetBuffer, v8::NewStringType::kNormal, (int)[value length]).ToLocalChecked();
41+
if (isDynamic) {
42+
free(targetBuffer);
43+
}
44+
return result;
45+
}
46+
*/
47+
return v8::String::NewFromUtf8(isolate, [value UTF8String], v8::NewStringType::kNormal, (int)[value lengthOfBytesUsingEncoding:NSUTF8StringEncoding]).ToLocalChecked();
48+
}
49+
#endif
2150
inline std::string ToString(v8::Isolate* isolate, const v8::Local<v8::Value>& value) {
2251
if (value.IsEmpty()) {
2352
return std::string();
@@ -35,8 +64,34 @@ inline std::string ToString(v8::Isolate* isolate, const v8::Local<v8::Value>& va
3564
return std::string();
3665
}
3766

38-
return std::string(*result);
67+
return std::string(*result, result.length());
3968
}
69+
70+
#ifdef __OBJC__
71+
inline NSString* ToNSString(const std::string& v) {
72+
return [[NSString alloc] initWithBytes:v.c_str() length:v.length() encoding:NSUTF8StringEncoding];
73+
}
74+
// this method is a copy of ToString to avoid needless std::string<->NSString conversions
75+
inline NSString* ToNSString(v8::Isolate* isolate, const v8::Local<v8::Value>& value) {
76+
if (value.IsEmpty()) {
77+
return @"";
78+
}
79+
80+
if (value->IsStringObject()) {
81+
v8::Local<v8::String> obj = value.As<v8::StringObject>()->ValueOf();
82+
return ToNSString(isolate, obj);
83+
}
84+
85+
v8::String::Utf8Value result(isolate, value);
86+
87+
const char* val = *result;
88+
if (val == nullptr) {
89+
return @"";
90+
}
91+
92+
return [[NSString alloc] initWithBytes:*result length:result.length() encoding:NSUTF8StringEncoding];
93+
}
94+
#endif
4095
std::u16string ToUtf16String(v8::Isolate* isolate, const v8::Local<v8::Value>& value);
4196
inline double ToNumber(v8::Isolate* isolate, const v8::Local<v8::Value>& value) {
4297
double result = NAN;

NativeScript/runtime/Interop.mm

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -265,8 +265,7 @@ inline bool isBool() {
265265
unichar c = (vector.size() == 0) ? 0 : vector[0];
266266
Interop::SetValue(dest, c);
267267
} else if (argHelper.isString() && (typeEncoding->type == BinaryTypeEncodingType::InterfaceDeclarationReference || typeEncoding->type == BinaryTypeEncodingType::IdEncoding)) {
268-
std::string str = tns::ToString(isolate, arg);
269-
NSString* result = [NSString stringWithUTF8String:str.c_str()];
268+
NSString* result = tns::ToNSString(isolate, arg);
270269
Interop::SetValue(dest, result);
271270
} else if (Interop::IsNumbericType(typeEncoding->type) || tns::IsNumber(arg)) {
272271
double value = tns::ToNumber(isolate, arg);
@@ -603,8 +602,7 @@ inline bool isBool() {
603602
if (arg.IsEmpty() || arg->IsNullOrUndefined()) {
604603
return nil;
605604
} else if (tns::IsString(arg)) {
606-
std::string value = tns::ToString(isolate, arg);
607-
NSString* result = [NSString stringWithUTF8String:value.c_str()];
605+
NSString* result = tns::ToNSString(isolate, arg);
608606
return result;
609607
} else if (tns::IsNumber(arg)) {
610608
double value = tns::ToNumber(isolate, arg);
@@ -1092,8 +1090,7 @@ inline bool isBool() {
10921090

10931091
if (marshalToPrimitive) {
10941092
// Convert NSString instances to javascript strings for all instance method calls
1095-
const char* str = [result UTF8String];
1096-
return tns::ToV8String(isolate, str);
1093+
return tns::ToV8String(isolate, result);
10971094
}
10981095
}
10991096

0 commit comments

Comments
 (0)