Skip to content

Commit

Permalink
Core - Basic ArrayBuffer support for EvaluateScriptAsync
Browse files Browse the repository at this point in the history
  • Loading branch information
amaitland committed May 8, 2024
1 parent f21a973 commit f835a49
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@ namespace CefSharp
{
SetCefTime(list, index, obj->GetDateValue().val);
}
else if (obj->IsArrayBuffer())
{
SetArrayBuffer(list, index, obj->GetArrayBufferByteLength(), obj->GetArrayBufferData());
}
else if (obj->IsArray())
{
int arrLength = obj->GetArrayLength();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ namespace CefSharp
auto cefTime = GetCefTime(list, index);
result = CefTimeUtils::FromBaseTimeToDateTime(cefTime.val);
}
else if (IsArrayBuffer(list, index))
{
result = GetArrayBuffer(list, index);
}
else if (IsJsCallback(list, index) && javascriptCallbackFactory != nullptr)
{
auto jsCallbackDto = GetJsCallback(list, index);
Expand Down
36 changes: 35 additions & 1 deletion CefSharp.Core.Runtime/Internals/Serialization/Primitives.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ namespace CefSharp
{
INT64,
CEFTIME,
JSCALLBACK
JSCALLBACK,
ARRAYBUFFER
};

template<typename TList, typename TIndex>
Expand Down Expand Up @@ -91,6 +92,39 @@ namespace CefSharp
{
return IsType(PrimitiveType::CEFTIME, list, index);
}

template<typename TList, typename TIndex>
void SetArrayBuffer(const CefRefPtr<TList>& list, TIndex index, const size_t& size, const void* value)
{
const auto src = static_cast<const uint8_t*>(value);

auto dest = new uint8_t[size + 1];
dest[0] = static_cast<uint8_t>(PrimitiveType::ARRAYBUFFER);
memcpy(&dest[1], src, size);

list->SetBinary(index, CefBinaryValue::Create(dest, size + 1));
}

template<typename TList, typename TIndex>
cli::array<Byte>^ GetArrayBuffer(const CefRefPtr<TList>& list, TIndex index)
{
auto binaryValue = list->GetBinary(index);
auto size = binaryValue->GetSize() - 1;

auto bufferByte = gcnew cli::array<Byte>(static_cast<int>(size));
pin_ptr<Byte> src = &bufferByte[0]; // pin pointer to first element in arr

binaryValue->GetData(static_cast<void*>(src), size, 1);

return bufferByte;
}

template<typename TList, typename TIndex>
bool IsArrayBuffer(const CefRefPtr<TList>& list, TIndex index)
{
return IsType(PrimitiveType::ARRAYBUFFER, list, index);
}

template<typename TList, typename TIndex>
void SetJsCallback(const CefRefPtr<TList>& list, TIndex index, JavascriptCallback^ value)
{
Expand Down
17 changes: 17 additions & 0 deletions CefSharp.Core.Runtime/Internals/Serialization/Primitives.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,13 @@ namespace CefSharp
template<typename TList, typename TIndex>
bool IsCefTime(const CefRefPtr<TList>& list, TIndex index);

template<typename TList, typename TIndex>
void SetArrayBuffer(const CefRefPtr<TList>& list, TIndex index, const size_t& size, const void* value);
template<typename TList, typename TIndex>
cli::array<Byte>^ GetArrayBuffer(const CefRefPtr<TList>& list, TIndex index);
template<typename TList, typename TIndex>
bool IsArrayBuffer(const CefRefPtr<TList>& list, TIndex index);

template<typename TList, typename TIndex>
void SetJsCallback(const CefRefPtr<TList>& list, TIndex index, JavascriptCallback^ value);
template<typename TList, typename TIndex>
Expand Down Expand Up @@ -53,6 +60,16 @@ namespace CefSharp
template bool IsCefTime(const CefRefPtr<CefListValue>& list, int index);
template bool IsCefTime(const CefRefPtr<CefDictionaryValue>& list, CefString index);

template void SetArrayBuffer(const CefRefPtr<CefListValue>& list, int index, const size_t& size, const void* value);
template void SetArrayBuffer(const CefRefPtr<CefListValue>& list, size_t index, const size_t& size, const void* value);
template void SetArrayBuffer(const CefRefPtr<CefDictionaryValue>& list, CefString index, const size_t& size, const void* value);
template cli::array<Byte>^ GetArrayBuffer(const CefRefPtr<CefListValue>& list, int index);
template cli::array<Byte>^ GetArrayBuffer(const CefRefPtr<CefListValue>& list, size_t index);
template cli::array<Byte>^ GetArrayBuffer(const CefRefPtr<CefDictionaryValue>& list, CefString index);
template bool IsArrayBuffer(const CefRefPtr<CefListValue>& list, size_t index);
template bool IsArrayBuffer(const CefRefPtr<CefListValue>& list, int index);
template bool IsArrayBuffer(const CefRefPtr<CefDictionaryValue>& list, CefString index);

template void SetJsCallback(const CefRefPtr<CefListValue>& list, int index, JavascriptCallback^ value);
template void SetJsCallback(const CefRefPtr<CefListValue>& list, size_t index, JavascriptCallback^ value);
template void SetJsCallback(const CefRefPtr<CefDictionaryValue>& list, CefString index, JavascriptCallback^ value);
Expand Down
26 changes: 26 additions & 0 deletions CefSharp.Test/Javascript/EvaluateScriptAsyncTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,12 @@
using System;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Bogus;
using Xunit;
using Xunit.Abstractions;
using Xunit.Repeat;

namespace CefSharp.Test.Javascript
{
Expand Down Expand Up @@ -253,6 +256,29 @@ public async Task CanEvaluateScriptAsyncWithEncodedStringArguments()
}
}

[Theory]
[Repeat(20)]
public async Task CanEvaluateScriptAsyncReturnArrayBuffer(int iteration)
{
AssertInitialLoadComplete();

var randomizer = new Randomizer();

var expected = randomizer.Utf16String(minLength: iteration, maxLength:iteration);
var expectedBytes = Encoding.UTF8.GetBytes(expected);

var javascriptResponse = await Browser.EvaluateScriptAsync($"new TextEncoder().encode('{expected}').buffer");

Assert.True(javascriptResponse.Success);
Assert.IsType<byte[]>(javascriptResponse.Result);

var actualBytes = (byte[])javascriptResponse.Result;

Assert.Equal(expectedBytes, actualBytes);

Assert.Equal(expected, Encoding.UTF8.GetString(actualBytes));
}

[Theory]
[InlineData("(async () => { function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); }; await sleep(2000); return true; })();")]
public async Task ShouldTimeout(string script)
Expand Down

0 comments on commit f835a49

Please sign in to comment.