Skip to content

Commit

Permalink
ArrayBuffer.fromString & String.fromArrayBuffer handle nulls #1271
Browse files Browse the repository at this point in the history
  • Loading branch information
phoddie committed Dec 19, 2023
1 parent d65b532 commit 9133fb3
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 11 deletions.
2 changes: 1 addition & 1 deletion tests/xs/built-ins/String/fromArrayBuffer.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,4 @@ assert.throws(TypeError, () => String.fromArrayBuffer("string"), "string");
assert.throws(TypeError, () => String.fromArrayBuffer(), "no argument");
assert.throws(TypeError, () => String.fromArrayBuffer(String.fromArrayBuffer), "host function");
assert.throws(TypeError, () => String.fromArrayBuffer(new Uint8Array(12)), "Uint8Array");
assert.sameValue("", String.fromArrayBuffer(new $TESTMC.HostBuffer(16)), "empty HostBuffer");
assert.sameValue("\0\0\0\0", String.fromArrayBuffer(new $TESTMC.HostBuffer(4)), "HostBuffer with nulls");
34 changes: 29 additions & 5 deletions xs/sources/xsDataView.c
Original file line number Diff line number Diff line change
Expand Up @@ -494,12 +494,36 @@ void fx_ArrayBuffer_fromBigInt(txMachine* the)
#ifndef mxCESU8
void fx_ArrayBuffer_fromString(txMachine* the)
{
txSize length;
txSize length = 0;
if (mxArgc < 1)
mxTypeError("no argument");
length = mxStringLength(fxToString(the, mxArgv(0)));
fxConstructArrayBufferResult(the, mxThis, length);
c_memcpy(mxResult->value.reference->next->value.arrayBuffer.address, mxArgv(0)->value.string, length);

txString c = mxArgv(0)->value.string;
txInteger nulls = 0;
while (true) {
uint8_t b = (uint8_t)c_read8(c++);
if (!b) break;

length += 1;
if ((0xc0 == b) && (0x80 == (uint8_t)c_read8(c)))
nulls += 1;
}

fxConstructArrayBufferResult(the, mxThis, length - nulls);
if (!nulls)
c_memcpy(mxResult->value.reference->next->value.arrayBuffer.address, mxArgv(0)->value.string, length);
else {
txString c = mxArgv(0)->value.string, end = c + length;
txByte *out = mxResult->value.reference->next->value.arrayBuffer.address;
while (c < end) {
uint8_t b = (uint8_t)c_read8(c++);
if ((0xc0 == (uint8_t)b) && (0x80 == (uint8_t)c_read8(c))) {
b = 0;
c += 1;
}
*out++ = b;
}
}
}
#endif

Expand Down Expand Up @@ -1365,7 +1389,7 @@ void fx_TypedArray(txMachine* the)
size = fxArgToByteLength(the, 2, -1);
info = fxGetBufferInfo(the, mxArgv(0));
if (size >= 0) {
txInteger delta = size << shift;
txInteger delta = size << shift; //@@ overflow
txInteger end = fxAddChunkSizes(the, offset, delta);
if ((info->value.bufferInfo.length < end) || (end < offset))
mxRangeError("out of range length %ld", size);
Expand Down
24 changes: 19 additions & 5 deletions xs/sources/xsString.c
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,7 @@ void fx_String_fromArrayBuffer(txMachine* the)
txSlot* arrayBuffer = C_NULL, *sharedArrayBuffer = C_NULL;
txSlot* bufferInfo;
txInteger limit, offset;
txInteger inLength, outLength = 0;
txInteger inLength, outLength = 0, nulls = 0;
unsigned char *in;
txString string;
if (mxArgc < 1)
Expand Down Expand Up @@ -381,7 +381,7 @@ void fx_String_fromArrayBuffer(txMachine* the)
unsigned char first = c_read8(in++), clen;
if (first < 0x80){
if (0 == first)
break;
nulls += 1;
inLength -= 1;
outLength += 1;
continue;
Expand All @@ -408,9 +408,23 @@ void fx_String_fromArrayBuffer(txMachine* the)
} while (--clen > 0);
}

string = fxNewChunk(the, outLength + 1);
c_memcpy(string, offset + (txString)(arrayBuffer ? arrayBuffer->value.arrayBuffer.address : sharedArrayBuffer->value.host.data), outLength);
string[outLength] = 0;
string = fxNewChunk(the, outLength + nulls + 1);
if (!nulls)
c_memcpy(string, offset + (txString)(arrayBuffer ? arrayBuffer->value.arrayBuffer.address : sharedArrayBuffer->value.host.data), outLength);
else {
txString c = string, end = c + outLength + nulls;
txString buf = offset + (txString)(arrayBuffer ? arrayBuffer->value.arrayBuffer.address : sharedArrayBuffer->value.host.data);
while (c < end) {
txByte b = c_read8(buf++);
if (b)
*c++ = b;
else {
*c++ = 0xC0;
*c++ = 0x80;
}
}
}
string[outLength + nulls] = 0;
mxResult->value.string = string;
mxResult->kind = XS_STRING_KIND;

Expand Down

0 comments on commit 9133fb3

Please sign in to comment.