Skip to content

Commit

Permalink
Adding Jsrt function JsCopyStringOneByte
Browse files Browse the repository at this point in the history
For scenarios where a string is known to have values fitting in
one byte, this method allows directly copying those values into a
char* buffer rather than having to copy to a uint16_t* buffer
and then to a char* buffer, and treating the string as raw bytes
rather than a valid utf8 encoding.
  • Loading branch information
MSLaguana committed Jul 21, 2017
1 parent 1e7793c commit 9020556
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 10 deletions.
28 changes: 28 additions & 0 deletions bin/NativeTests/JsRTApiTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2143,4 +2143,32 @@ namespace JsRTApiTest
JsRTApiTest::RunWithAttributes(JsRTApiTest::ObjectHasOwnPropertyMethodTest);
}

void JsCopyStringOneByteMethodTest(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
{
size_t written = 0;
char buf[10] = {0};
JsValueRef value;
REQUIRE(JsCreateStringUtf16(reinterpret_cast<uint16_t*>(_u("0\x10\x80\xa9\uabcd\U000104377")), 8, &value) == JsNoError);
REQUIRE(JsCopyStringOneByte(value, 0, -1, nullptr, &written) == JsNoError);
CHECK(written == 8);
buf[written] = '\xff';

REQUIRE(JsCopyStringOneByte(value, 0, 10, buf, &written) == JsNoError);
CHECK(written == 8);
CHECK(buf[0] == '0');
CHECK(buf[1] == '\x10');
CHECK(buf[2] == '\x80');
CHECK(buf[3] == '\xA9');
CHECK(buf[4] == '\xcd');
CHECK(buf[5] == '\x01');
CHECK(buf[6] == '\x37');
CHECK(buf[7] == '7');
CHECK(buf[8] == '\xff');
}

TEST_CASE("ApiTest_JsCopyStringOneByteMethodTest", "[ApiTest]")
{
JsRTApiTest::RunWithAttributes(JsRTApiTest::JsCopyStringOneByteMethodTest);
}

}
38 changes: 38 additions & 0 deletions lib/Jsrt/ChakraCore.h
Original file line number Diff line number Diff line change
Expand Up @@ -679,5 +679,43 @@ CHAKRA_API
_In_ JsPropertyIdRef propertyId,
_Out_ bool *hasOwnProperty);

/// <summary>
/// Write JS string value into char string buffer without a null terminator
/// </summary>
/// <remarks>
/// <para>
/// When size of the `buffer` is unknown,
/// `buffer` argument can be nullptr.
/// In that case, `written` argument will return the length needed.
/// </para>
/// <para>
/// When start is out of range or &lt; 0, returns JsErrorInvalidArgument
/// and `written` will be equal to 0.
/// If calculated length is 0 (It can be due to string length or `start`
/// and length combination), then `written` will be equal to 0 and call
/// returns JsNoError
/// </para>
/// <para>
/// The JS string `value` will be converted one utf16 code point at a time,
/// and if it has code points that do not fit in one byte, those values
/// will be truncated.
/// </para>
/// </remarks>
/// <param name="value">JavascriptString value</param>
/// <param name="start">Start offset of buffer</param>
/// <param name="length">Number of characters to be written</param>
/// <param name="buffer">Pointer to buffer</param>
/// <param name="written">Total number of characters written</param>
/// <returns>
/// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise.
/// </returns>
CHAKRA_API
JsCopyStringOneByte(
_In_ JsValueRef value,
_In_ int start,
_In_ int length,
_Out_opt_ char* buffer,
_Out_opt_ size_t* written);

#endif // CHAKRACOREBUILD_
#endif // _CHAKRACORE_H_
40 changes: 30 additions & 10 deletions lib/Jsrt/Jsrt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4181,14 +4181,15 @@ JsErrorCode WriteStringCopy(
*written = 0; // init to 0 for default
}

const char16* str = nullptr;
size_t strLength = 0;
JsErrorCode errorCode = JsStringToPointer(value, &str, &strLength);
if (errorCode != JsNoError)
if (!Js::JavascriptString::Is(value))
{
return errorCode;
return JsErrorInvalidArgument;
}

Js::JavascriptString *jsString = Js::JavascriptString::FromVar(value);
const char16* str = jsString->GetSz();
size_t strLength = jsString->GetLength();

if (start < 0 || (size_t)start > strLength)
{
return JsErrorInvalidArgument; // start out of range, no chars written
Expand All @@ -4200,7 +4201,7 @@ JsErrorCode WriteStringCopy(
return JsNoError; // no chars written
}

errorCode = copyFunc(str + start, count, written);
JsErrorCode errorCode = copyFunc(str + start, count, written);
if (errorCode != JsNoError)
{
return errorCode;
Expand Down Expand Up @@ -4231,10 +4232,6 @@ CHAKRA_API JsCopyStringUtf16(
{
memmove(buffer, src, sizeof(char16) * count);
}
else
{
*needed = count;
}
return JsNoError;
});
}
Expand Down Expand Up @@ -4746,4 +4743,27 @@ CHAKRA_API JsHasOwnProperty(_In_ JsValueRef object, _In_ JsPropertyIdRef propert
});
}

CHAKRA_API JsCopyStringOneByte(
_In_ JsValueRef value,
_In_ int start,
_In_ int length,
_Out_opt_ char* buffer,
_Out_opt_ size_t* written)
{
PARAM_NOT_NULL(value);
VALIDATE_JSREF(value);
return WriteStringCopy(value, start, length, written,
[buffer](const char16* src, size_t count, size_t *needed)
{
if (buffer)
{
for (size_t i = 0; i < count; i++)
{
buffer[i] = (char)src[i];
}
}
return JsNoError;
});
}

#endif // CHAKRACOREBUILD_
1 change: 1 addition & 0 deletions lib/Jsrt/JsrtCommonExports.inc
Original file line number Diff line number Diff line change
Expand Up @@ -120,4 +120,5 @@
JsGetWeakReferenceValue
JsGetAndClearExceptionWithMetadata
JsHasOwnProperty
JsCopyStringOneByte
#endif

0 comments on commit 9020556

Please sign in to comment.