diff --git a/bin/ch/ChakraRtInterface.cpp b/bin/ch/ChakraRtInterface.cpp index e2f2940f9f9..5102cd487da 100644 --- a/bin/ch/ChakraRtInterface.cpp +++ b/bin/ch/ChakraRtInterface.cpp @@ -144,6 +144,7 @@ bool ChakraRTInterface::LoadChakraDll(ArgInfo* argInfo, HINSTANCE *outLibrary) m_jsApiHooks.pfJsrtParse = (JsAPIHooks::JsrtParse)GetChakraCoreSymbol(library, "JsParse"); m_jsApiHooks.pfJsrtSerialize = (JsAPIHooks::JsrtSerialize)GetChakraCoreSymbol(library, "JsSerialize"); m_jsApiHooks.pfJsrtRunSerialized = (JsAPIHooks::JsrtRunSerialized)GetChakraCoreSymbol(library, "JsRunSerialized"); + m_jsApiHooks.pfJsrtGetStringLength = (JsAPIHooks::JsrtGetStringLength)GetChakraCoreSymbol(library, "JsGetStringLength"); m_jsApiHooks.pfJsrtCreateString = (JsAPIHooks::JsrtCreateString)GetChakraCoreSymbol(library, "JsCreateString"); m_jsApiHooks.pfJsrtCreateStringUtf16 = (JsAPIHooks::JsrtCreateStringUtf16)GetChakraCoreSymbol(library, "JsCreateStringUtf16"); m_jsApiHooks.pfJsrtCopyString = (JsAPIHooks::JsrtCopyString)GetChakraCoreSymbol(library, "JsCopyString"); diff --git a/bin/ch/ChakraRtInterface.h b/bin/ch/ChakraRtInterface.h index 9eb39e4df16..cde09412bed 100644 --- a/bin/ch/ChakraRtInterface.h +++ b/bin/ch/ChakraRtInterface.h @@ -77,7 +77,8 @@ struct JsAPIHooks typedef JsErrorCode(WINAPI *JsrtParse)(JsValueRef script, JsSourceContext sourceContext, JsValueRef sourceUrl, JsParseScriptAttributes parseAttributes, JsValueRef *result); typedef JsErrorCode(WINAPI *JsrtSerialize)(JsValueRef script, JsValueRef *buffer, JsParseScriptAttributes parseAttributes); typedef JsErrorCode(WINAPI *JsrtRunSerialized)(JsValueRef buffer, JsSerializedLoadScriptCallback scriptLoadCallback, JsSourceContext sourceContext, JsValueRef sourceUrl, JsValueRef * result); - typedef JsErrorCode(WINAPI *JsrtCopyString)(JsValueRef value, char* buffer, size_t bufferSize, size_t* written); + typedef JsErrorCode(WINAPI *JsrtGetStringLength)(JsValueRef value, int *stringLength); + typedef JsErrorCode(WINAPI *JsrtCopyString)(JsValueRef value, char* buffer, size_t bufferSize, size_t* writtenLength, size_t* actualLength); typedef JsErrorCode(WINAPI *JsrtCreateString)(const char *content, size_t length, JsValueRef *value); typedef JsErrorCode(WINAPI *JsrtCreateStringUtf16)(const uint16_t *content, size_t length, JsValueRef *value); @@ -172,6 +173,7 @@ struct JsAPIHooks JsrtParse pfJsrtParse; JsrtSerialize pfJsrtSerialize; JsrtRunSerialized pfJsrtRunSerialized; + JsrtGetStringLength pfJsrtGetStringLength; JsrtCreateString pfJsrtCreateString; JsrtCreateStringUtf16 pfJsrtCreateStringUtf16; JsrtCopyString pfJsrtCopyString; @@ -396,7 +398,8 @@ class ChakraRTInterface static JsErrorCode WINAPI JsParse(JsValueRef script, JsSourceContext sourceContext, JsValueRef sourceUrl, JsParseScriptAttributes parseAttributes, JsValueRef *result) { return HOOK_JS_API(Parse(script, sourceContext, sourceUrl, parseAttributes, result)); } static JsErrorCode WINAPI JsSerialize(JsValueRef script, JsValueRef *buffer, JsParseScriptAttributes parseAttributes) { return HOOK_JS_API(Serialize(script, buffer, parseAttributes)); } static JsErrorCode WINAPI JsRunSerialized(JsValueRef buffer, JsSerializedLoadScriptCallback scriptLoadCallback, JsSourceContext sourceContext, JsValueRef sourceUrl, JsValueRef * result) { return HOOK_JS_API(RunSerialized(buffer, scriptLoadCallback, sourceContext, sourceUrl, result)); } - static JsErrorCode WINAPI JsCopyString(JsValueRef value, char* buffer, size_t bufferSize, size_t* written) { return HOOK_JS_API(CopyString(value, buffer, bufferSize, written)); } + static JsErrorCode WINAPI JsGetStringLength(JsValueRef value, int *stringLength) { return HOOK_JS_API(GetStringLength(value, stringLength)); } + static JsErrorCode WINAPI JsCopyString(JsValueRef value, char* buffer, size_t bufferSize, size_t* writtenLength, size_t* actualLength) { return HOOK_JS_API(CopyString(value, buffer, bufferSize, writtenLength, actualLength)); } static JsErrorCode WINAPI JsCreateString(const char *content, size_t length, JsValueRef *value) { return HOOK_JS_API(CreateString(content, length, value)); } static JsErrorCode WINAPI JsCreateStringUtf16(const uint16_t *content, size_t length, JsValueRef *value) { return HOOK_JS_API(CreateStringUtf16(content, length, value)); } static JsErrorCode WINAPI JsCreatePropertyId(const char *name, size_t length, JsPropertyIdRef *propertyId) { return HOOK_JS_API(CreatePropertyId(name, length, propertyId)); } diff --git a/bin/ch/stdafx.h b/bin/ch/stdafx.h index 2dbcb55d411..4613f05110b 100644 --- a/bin/ch/stdafx.h +++ b/bin/ch/stdafx.h @@ -206,18 +206,39 @@ class AutoString { strValue = value; } + int strLen = 0; + size_t writtenLen = 0; + size_t actualLen = 0; if (errorCode == JsNoError) { - size_t len = 0; - errorCode = ChakraRTInterface::JsCopyString(strValue, nullptr, 0, &len); + errorCode = ChakraRTInterface::JsGetStringLength(strValue, &strLen); if (errorCode == JsNoError) { - data = (char*) malloc((len + 1) * sizeof(char)); - ChakraRTInterface::JsCopyString(strValue, data, len + 1, &length); - AssertMsg(len == length, "If you see this message.. There is something seriously wrong. Good Luck!"); - *(data + len) = char(0); + // Assume ascii characters + data = (char*)malloc((strLen + 1) * sizeof(char)); + errorCode = ChakraRTInterface::JsCopyString(strValue, data, strLen, &writtenLen, &actualLen); + if (errorCode == JsNoError) + { + // If non-ascii, take slow path + if (writtenLen != actualLen) + { + free(data); + data = (char*)malloc((actualLen + 1) * sizeof(char)); + + errorCode = ChakraRTInterface::JsCopyString(strValue, data, actualLen + 1, &writtenLen, nullptr); + if (errorCode == JsNoError) + { + AssertMsg(actualLen == writtenLen, "If you see this message.. There is something seriously wrong. Good Luck!"); + + } + } + } } } + if (errorCode == JsNoError) + { + *(data + actualLen) = char(0); + } return errorCode; } diff --git a/lib/Jsrt/ChakraCore.h b/lib/Jsrt/ChakraCore.h index 3ebefafd641..47eec84bfb9 100644 --- a/lib/Jsrt/ChakraCore.h +++ b/lib/Jsrt/ChakraCore.h @@ -286,13 +286,23 @@ CHAKRA_API /// /// When size of the `buffer` is unknown, /// `buffer` argument can be nullptr. -/// In that case, `written` argument will return the length needed. +/// In that case, `actualLength` argument will return the length needed to +/// accomodate all the UTF8 decoded bytes present in `value`. +/// `writtenLength` will only get populated when valid `buffer` is passed as +/// argument. /// /// /// JavascriptString value /// Pointer to buffer /// Buffer size -/// Total number of characters written +/// Total number of UTF8 decoded bytes written. This is only +/// populated when passed with non-null `buffer`,else is +/// set to 0. +/// +/// Total number of UTF8 decoded bytes present in `value`. +/// Useful to initialize buffer of appropriate size that +/// can be passed in to this API. +/// /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// @@ -301,7 +311,8 @@ CHAKRA_API _In_ JsValueRef value, _Out_opt_ char* buffer, _In_ size_t bufferSize, - _Out_opt_ size_t* written); + _Out_opt_ size_t* writtenLength, + _Out_opt_ size_t* actualLength); /// /// Write string value into Utf16 string buffer diff --git a/lib/Jsrt/Jsrt.cpp b/lib/Jsrt/Jsrt.cpp index eb705a0f472..05f2fe77f41 100644 --- a/lib/Jsrt/Jsrt.cpp +++ b/lib/Jsrt/Jsrt.cpp @@ -4252,7 +4252,8 @@ CHAKRA_API JsCopyString( _In_ JsValueRef value, _Out_opt_ char* buffer, _In_ size_t bufferSize, - _Out_opt_ size_t* length) + _Out_opt_ size_t* writtenLength, + _Out_opt_ size_t* actualLength) { PARAM_NOT_NULL(value); VALIDATE_JSREF(value); @@ -4266,14 +4267,12 @@ CHAKRA_API JsCopyString( } utf8::WideToNarrow utf8Str(str, strLength); - if (!buffer) + if (actualLength) { - if (length) - { - *length = utf8Str.Length(); - } + *actualLength = utf8Str.Length(); } - else + + if (buffer) { size_t count = min(bufferSize, utf8Str.Length()); // Try to copy whole characters if buffer size insufficient @@ -4284,11 +4283,15 @@ CHAKRA_API JsCopyString( (LPCUTF8)(const char*)utf8Str, utf8Str.Length(), maxFitChars); memmove(buffer, utf8Str, sizeof(char) * count); - if (length) + if (writtenLength) { - *length = count; + *writtenLength = count; } } + else if (writtenLength) + { + *writtenLength = 0; + } return JsNoError; } diff --git a/test/native-tests/test-c98/sample.cpp b/test/native-tests/test-c98/sample.cpp index b0c60996efb..34ff587edf7 100644 --- a/test/native-tests/test-c98/sample.cpp +++ b/test/native-tests/test-c98/sample.cpp @@ -63,9 +63,9 @@ int main() // Project script result back to C++. char *resultSTR = nullptr; size_t stringLength; - FAIL_CHECK(JsCopyString(resultJSString, nullptr, 0, &stringLength)); + FAIL_CHECK(JsCopyString(resultJSString, nullptr, 0, nullptr, &stringLength)); resultSTR = (char*)malloc(stringLength + 1); - FAIL_CHECK(JsCopyString(resultJSString, resultSTR, stringLength + 1, nullptr)); + FAIL_CHECK(JsCopyString(resultJSString, resultSTR, stringLength + 1, nullptr, nullptr)); resultSTR[stringLength] = 0; printf("Result -> %s \n", resultSTR); diff --git a/test/native-tests/test-char/sample.cpp b/test/native-tests/test-char/sample.cpp index d85ce9300b3..ea86ee1113b 100644 --- a/test/native-tests/test-char/sample.cpp +++ b/test/native-tests/test-char/sample.cpp @@ -73,9 +73,9 @@ int main() // Project script result back to C++. char *resultSTR = nullptr; size_t stringLength; - FAIL_CHECK(JsCopyString(resultJSString, nullptr, 0, &stringLength)); + FAIL_CHECK(JsCopyString(resultJSString, nullptr, 0, nullptr, &stringLength)); resultSTR = (char*)malloc(stringLength + 1); - FAIL_CHECK(JsCopyString(resultJSString, resultSTR, stringLength + 1, nullptr)); + FAIL_CHECK(JsCopyString(resultJSString, resultSTR, stringLength + 1, nullptr, nullptr)); resultSTR[stringLength] = 0; printf("Result -> %s \n", resultSTR); diff --git a/test/native-tests/test-char16/sample.cpp b/test/native-tests/test-char16/sample.cpp index 86cb78a4985..4e78b7677ec 100644 --- a/test/native-tests/test-char16/sample.cpp +++ b/test/native-tests/test-char16/sample.cpp @@ -69,9 +69,9 @@ int main() // Project script result back to C++. char *resultSTR = nullptr; size_t stringLength; - FAIL_CHECK(JsCopyString(resultJSString, nullptr, 0, &stringLength)); + FAIL_CHECK(JsCopyString(resultJSString, nullptr, 0, nullptr, &stringLength)); resultSTR = (char*) malloc(stringLength + 1); - FAIL_CHECK(JsCopyString(resultJSString, resultSTR, stringLength + 1, nullptr)); + FAIL_CHECK(JsCopyString(resultJSString, resultSTR, stringLength + 1, nullptr, nullptr)); resultSTR[stringLength] = 0; printf("Result -> %s \n", resultSTR); diff --git a/test/native-tests/test-python/helloWorld.py b/test/native-tests/test-python/helloWorld.py index 6283868d54f..10ccbcf3887 100755 --- a/test/native-tests/test-python/helloWorld.py +++ b/test/native-tests/test-python/helloWorld.py @@ -56,12 +56,12 @@ stringLength = c_size_t(); # Get buffer size needed for the result string -chakraCore.JsCopyString(resultJSString, 0, 0, byref(stringLength)); +chakraCore.JsCopyString(resultJSString, 0, 0, 0, byref(stringLength)); resultSTR = create_string_buffer(stringLength.value + 1); # buffer is big enough to store the result # Get String from JsValueRef -chakraCore.JsCopyString(resultJSString, byref(resultSTR), stringLength.value + 1, 0); +chakraCore.JsCopyString(resultJSString, byref(resultSTR), stringLength.value + 1, 0, 0); # Set `null-ending` to the end resultSTRLastByte = (c_char * stringLength.value).from_address(addressof(resultSTR)) diff --git a/test/native-tests/test-shared-basic/sample.cpp b/test/native-tests/test-shared-basic/sample.cpp index 56d985bf8bc..3018cc9ea16 100644 --- a/test/native-tests/test-shared-basic/sample.cpp +++ b/test/native-tests/test-shared-basic/sample.cpp @@ -57,9 +57,9 @@ int main() // Project script result back to C++. char *resultSTR = nullptr; size_t stringLength; - FAIL_CHECK(JsCopyString(resultJSString, nullptr, 0, &stringLength)); + FAIL_CHECK(JsCopyString(resultJSString, nullptr, 0, nullptr, &stringLength)); resultSTR = (char*) malloc(stringLength + 1); - FAIL_CHECK(JsCopyString(resultJSString, resultSTR, stringLength + 1, nullptr)); + FAIL_CHECK(JsCopyString(resultJSString, resultSTR, stringLength + 1, nullptr, nullptr)); resultSTR[stringLength] = 0; printf("Result -> %s \n", resultSTR); diff --git a/test/native-tests/test-static-native/sample.cpp b/test/native-tests/test-static-native/sample.cpp index 56d985bf8bc..3018cc9ea16 100644 --- a/test/native-tests/test-static-native/sample.cpp +++ b/test/native-tests/test-static-native/sample.cpp @@ -57,9 +57,9 @@ int main() // Project script result back to C++. char *resultSTR = nullptr; size_t stringLength; - FAIL_CHECK(JsCopyString(resultJSString, nullptr, 0, &stringLength)); + FAIL_CHECK(JsCopyString(resultJSString, nullptr, 0, nullptr, &stringLength)); resultSTR = (char*) malloc(stringLength + 1); - FAIL_CHECK(JsCopyString(resultJSString, resultSTR, stringLength + 1, nullptr)); + FAIL_CHECK(JsCopyString(resultJSString, resultSTR, stringLength + 1, nullptr, nullptr)); resultSTR[stringLength] = 0; printf("Result -> %s \n", resultSTR);