Skip to content

Commit fef18d6

Browse files
committed
Fixes sub array insertion
1 parent 902ed7d commit fef18d6

3 files changed

Lines changed: 55 additions & 8 deletions

File tree

cpp/utils.cpp

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -97,18 +97,48 @@ inline JSVariant to_variant(jsi::Runtime &rt, const jsi::Value &value) {
9797
return JSVariant(strVal);
9898
} else if (value.isObject()) {
9999
auto obj = value.asObject(rt);
100+
size_t byteOffset = 0;
101+
size_t byteLength = 0;
102+
uint8_t *sourceData = nullptr;
103+
104+
if (obj.isArrayBuffer(rt)) {
105+
auto buffer = obj.getArrayBuffer(rt);
106+
sourceData = buffer.data(rt);
107+
byteLength = buffer.size(rt);
108+
} else {
109+
jsi::Function arrayBufferCtor =
110+
rt.global().getPropertyAsFunction(rt, "ArrayBuffer");
111+
jsi::Function isViewFn =
112+
arrayBufferCtor.getPropertyAsFunction(rt, "isView");
113+
bool isArrayBufferView = isViewFn.call(rt, obj).getBool();
114+
115+
if (!isArrayBufferView) {
116+
throw std::runtime_error(
117+
"Object is not an ArrayBuffer or ArrayBuffer view, cannot bind "
118+
"to SQLite");
119+
}
120+
121+
jsi::Object bufferObject = obj.getPropertyAsObject(rt, "buffer");
122+
auto buffer = bufferObject.getArrayBuffer(rt);
123+
124+
byteOffset =
125+
static_cast<size_t>(obj.getProperty(rt, "byteOffset").asNumber());
126+
byteLength =
127+
static_cast<size_t>(obj.getProperty(rt, "byteLength").asNumber());
128+
129+
const size_t bufferSize = buffer.size(rt);
130+
if (byteOffset > bufferSize || byteLength > bufferSize - byteOffset) {
131+
throw std::runtime_error("Invalid ArrayBuffer view range");
132+
}
100133

101-
if (!obj.isArrayBuffer(rt)) {
102-
throw std::runtime_error(
103-
"Object is not an ArrayBuffer, cannot bind to SQLite");
134+
sourceData = buffer.data(rt) + byteOffset;
104135
}
105136

106-
auto buffer = obj.getArrayBuffer(rt);
107-
uint8_t *data = new uint8_t[buffer.size(rt)];
108-
memcpy(data, buffer.data(rt), buffer.size(rt));
137+
uint8_t *data = new uint8_t[byteLength];
138+
memcpy(data, sourceData, byteLength);
109139

110140
return JSVariant(ArrayBuffer{.data = std::shared_ptr<uint8_t>{data},
111-
.size = buffer.size(rt)});
141+
.size = byteLength});
112142
}
113143

114144
throw std::runtime_error("Cannot convert JSI value to C++ Variant value");

example/ios/Podfile.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2002,7 +2002,7 @@ EXTERNAL SOURCES:
20022002
SPEC CHECKSUMS:
20032003
FBLazyVector: 2e5b5553df729e080483373db6f045201ff4e6db
20042004
hermes-engine: 273e30e7fb618279934b0b95ffab60ecedb7acf5
2005-
op-sqlite: aec4b9ac1b22d981c2ddaf27a0acc199c1187a3c
2005+
op-sqlite: 4df330bec6c23e6d9c9a5e256831869c58a618ea
20062006
RCTDeprecation: c6b36da89aa26090c8684d29c2868dcca2cd4554
20072007
RCTRequired: 1413a0844770d00fa1f1bb2da4680adfa8698065
20082008
RCTTypeSafety: 354b4bb344998550c45d054ef66913837948f958

example/src/tests/blob.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,23 @@ describe("Blobs", () => {
6060
expect(finalUint8[0]).toBe(42);
6161
});
6262

63+
it("Uint8Array subarray", async () => {
64+
const uint8 = new Uint8Array([97, 98, 99, 100]);
65+
const subarray = uint8.subarray(1, 3);
66+
67+
await db.execute(`INSERT OR REPLACE INTO BlobTable VALUES (?, ?);`, [
68+
1,
69+
subarray,
70+
]);
71+
72+
const result = await db.execute("SELECT content FROM BlobTable");
73+
const content = result.rows[0]?.content;
74+
expect(content).toBeTruthy();
75+
76+
const finalUint8 = new Uint8Array(content as ArrayBuffer);
77+
expect(Array.from(finalUint8)).toEqual([98, 99]);
78+
});
79+
6380
it("Uint16Array", async () => {
6481
const uint8 = new Uint16Array(2);
6582
uint8[0] = 42;

0 commit comments

Comments
 (0)