From 6cb26c06617853091c6ea89d56b8a145d35c44e9 Mon Sep 17 00:00:00 2001 From: Osei Fortune Date: Mon, 4 May 2026 11:00:07 -0400 Subject: [PATCH] fix: typed array offset --- NativeScript/runtime/NSDataAdapter.mm | 8 ++++-- TestFixtures/Marshalling/TNSObjCTypes.h | 1 + TestFixtures/Marshalling/TNSObjCTypes.m | 9 +++++++ .../app/tests/Marshalling/ObjCTypesTests.js | 25 +++++++++++++++++++ 4 files changed, 41 insertions(+), 2 deletions(-) diff --git a/NativeScript/runtime/NSDataAdapter.mm b/NativeScript/runtime/NSDataAdapter.mm index 67c34fd7..b0f7bbb7 100644 --- a/NativeScript/runtime/NSDataAdapter.mm +++ b/NativeScript/runtime/NSDataAdapter.mm @@ -41,8 +41,12 @@ - (void*)mutableBytes { Local bufferView = obj.As(); if (bufferView->HasBuffer()) { - void* data = bufferView->Buffer()->GetBackingStore()->Data(); - return data; + uint8_t* data = static_cast(bufferView->Buffer()->GetBackingStore()->Data()); + if (data == nullptr) { + return nullptr; + } + + return data + bufferView->ByteOffset(); } size_t length = bufferView->ByteLength(); diff --git a/TestFixtures/Marshalling/TNSObjCTypes.h b/TestFixtures/Marshalling/TNSObjCTypes.h index bd4a5ee9..33929677 100644 --- a/TestFixtures/Marshalling/TNSObjCTypes.h +++ b/TestFixtures/Marshalling/TNSObjCTypes.h @@ -36,6 +36,7 @@ typedef int (^NumberReturner)(int, int, int); - (id)methodWithNSArrayWrappingDictionary:(id)array; - (NSDictionary*)methodWithNSDictionary:(NSDictionary*)dictionary; - (NSData*)methodWithNSData:(NSData*)data; +- (NSMutableData*)methodWithNSMutableData:(NSMutableData*)data; - (NSDecimalNumber*)methodWithNSDecimalNumber:(NSDecimalNumber*)number; - (NSNumber*)methodWithNSCFBool; - (NSNull*)methodWithNSNull; diff --git a/TestFixtures/Marshalling/TNSObjCTypes.m b/TestFixtures/Marshalling/TNSObjCTypes.m index c60c808f..49cee6dd 100644 --- a/TestFixtures/Marshalling/TNSObjCTypes.m +++ b/TestFixtures/Marshalling/TNSObjCTypes.m @@ -115,6 +115,15 @@ - (NSData*)methodWithNSData:(NSData*)data { return data; } +- (NSMutableData*)methodWithNSMutableData:(NSMutableData*)data { + if (data.length > 0) { + uint8_t* bytes = (uint8_t*)data.mutableBytes; + bytes[0] = 'A'; + } + + return data; +} + - (NSDecimalNumber*)methodWithNSDecimalNumber:(NSDecimalNumber*)number { TNSLog([number stringValue]); return number; diff --git a/TestRunner/app/tests/Marshalling/ObjCTypesTests.js b/TestRunner/app/tests/Marshalling/ObjCTypesTests.js index f135317f..f08a5a94 100644 --- a/TestRunner/app/tests/Marshalling/ObjCTypesTests.js +++ b/TestRunner/app/tests/Marshalling/ObjCTypesTests.js @@ -263,6 +263,31 @@ describe(module.id, function () { TNSClearOutput(); }); + it("should respect ArrayBufferView byteOffset when wrapping in NSData", function () { + var source = new Uint8Array([48, 49, 50, 51, 52, 53]); + var view = new Uint8Array(source.buffer, 1, 4); + + var wrappedArrayBufferViewData = TNSObjCTypes.alloc().init().methodWithNSData(view); + + expect(TNSGetOutput()).toBe('1234'); + expect(wrappedArrayBufferViewData).toBe(view); + TNSClearOutput(); + }); + + it("should respect ArrayBufferView byteOffset when mutating NSMutableData", function () { + var source = new Uint8Array([48, 49, 50, 51, 52]); + var view = new Uint8Array(source.buffer, 2, 2); + + var wrappedArrayBufferViewData = TNSObjCTypes.alloc().init().methodWithNSMutableData(view); + + expect(wrappedArrayBufferViewData).toBe(view); + expect(source[0]).toEqual(48); + expect(source[1]).toEqual(49); + expect(source[2]).toEqual(65); + expect(source[3]).toEqual(51); + expect(source[4]).toEqual(52); + }); + it("should be possible to wrap NSData in an ArrayBuffer", function () { var data = NSString.stringWithString("test").dataUsingEncoding(NSUTF8StringEncoding);