Skip to content

Commit 34ae417

Browse files
Fix FileReader Base64 padding (#12522)
* Add test BaseFileReaderResourceUnitTest::Base64EncodesCorrectly * Add BaseFileReaderResourceUnitTest.cpp * Use "string" reader type * Add '=' padding as needed * Fix typo * Change files * Update vnext/Shared/Shared.vcxitems.filters Co-authored-by: Jon Thysell <[email protected]> --------- Co-authored-by: Jon Thysell <[email protected]>
1 parent de27802 commit 34ae417

6 files changed

+104
-1
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"type": "prerelease",
3+
"comment": "Fix FileReader Base64 padding",
4+
"packageName": "react-native-windows",
5+
"email": "[email protected]",
6+
"dependentChangeType": "patch"
7+
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
4+
#include <CppUnitTest.h>
5+
6+
#include <BaseFileReaderResource.h>
7+
8+
// Windows Libraries
9+
#include <winrt/Windows.Security.Cryptography.h>
10+
11+
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
12+
13+
using std::shared_ptr;
14+
using std::string;
15+
using std::vector;
16+
using winrt::array_view;
17+
18+
namespace Microsoft::React::Test {
19+
20+
TEST_CLASS (BaseFileReaderResourceUnitTest) {
21+
TEST_METHOD(Base64EncodesCorrectly) {
22+
class DummyBlobPersistor final : public IBlobPersistor {
23+
std::unordered_map<string, vector<uint8_t>> m_blobs;
24+
25+
public:
26+
#pragma region IBlobPersistor
27+
28+
array_view<uint8_t const> ResolveMessage(string &&blobId, int64_t offset, int64_t size) override {
29+
auto dataItr = m_blobs.find(std::move(blobId));
30+
// Not found.
31+
if (dataItr == m_blobs.cend())
32+
throw std::invalid_argument("Blob object not found");
33+
34+
auto &bytes = (*dataItr).second;
35+
auto endBound = static_cast<size_t>(offset + size);
36+
// Out of bounds.
37+
if (endBound > bytes.size() || offset >= static_cast<int64_t>(bytes.size()) || offset < 0)
38+
throw std::out_of_range("Offset or size out of range");
39+
40+
return array_view<uint8_t const>(bytes.data() + offset, bytes.data() + endBound);
41+
}
42+
43+
void RemoveMessage(string && /*blobId*/) noexcept override {
44+
// Not implemented
45+
}
46+
47+
void StoreMessage(vector<uint8_t> &&message, string &&blobId) noexcept override {
48+
m_blobs.insert_or_assign(std::move(blobId), std::move(message));
49+
}
50+
51+
string StoreMessage(vector<uint8_t> && /*message*/) noexcept override {
52+
return "Not implemented";
53+
}
54+
55+
#pragma endregion IBlobPersistor
56+
};
57+
58+
string messageStr = "abcde";
59+
// Computed using [System.Convert]::ToBase64String('abcd'.ToCharArray())
60+
constexpr char expected[] = "data:string;base64,YWJjZGU=";
61+
constexpr char guid[] = "93252b5d-a419-4d98-a928-c3ef386f2445";
62+
63+
vector<uint8_t> message{};
64+
message.reserve(messageStr.size());
65+
message.insert(message.end(), messageStr.begin(), messageStr.end());
66+
67+
shared_ptr<IBlobPersistor> persistor = std::make_shared<DummyBlobPersistor>();
68+
shared_ptr<IFileReaderResource> reader = std::make_shared<BaseFileReaderResource>(persistor);
69+
string result;
70+
auto resolver = [&result](string &&value) { result = std::move(value); };
71+
auto rejecter = [&result](string &&) { result = "ERROR"; };
72+
73+
persistor->StoreMessage(std::move(message), string{guid});
74+
75+
reader->ReadAsDataUrl(guid, 0 /*offset*/, messageStr.size(), "string", std::move(resolver), std::move(rejecter));
76+
77+
Assert::AreEqual(expected, result.c_str());
78+
}
79+
};
80+
81+
} // namespace Microsoft::React::Test

vnext/Desktop.UnitTests/React.Windows.Desktop.UnitTests.vcxproj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@
8888
<Midl Include="$(ReactNativeWindowsDir)Microsoft.ReactNative\IJSValueWriter.idl" />
8989
</ItemGroup>
9090
<ItemGroup>
91+
<ClCompile Include="BaseFileReaderResourceUnitTest.cpp" />
9192
<ClCompile Include="BytecodeUnitTests.cpp" />
9293
<ClCompile Include="EmptyUIManagerModule.cpp" />
9394
<ClCompile Include="LayoutAnimationTests.cpp" />
@@ -128,4 +129,4 @@
128129
<Target Name="Test">
129130
<Exec Command="$(OutDir)$(TargetFileName)" IgnoreStandardErrorWarningFormat="true" />
130131
</Target>
131-
</Project>
132+
</Project>

vnext/Desktop.UnitTests/React.Windows.Desktop.UnitTests.vcxproj.filters

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@
5555
<ClCompile Include="RedirectHttpFilterUnitTest.cpp">
5656
<Filter>Unit Tests</Filter>
5757
</ClCompile>
58+
<ClCompile Include="BaseFileReaderResourceUnitTest.cpp">
59+
<Filter>Unit Tests</Filter>
60+
</ClCompile>
5861
</ItemGroup>
5962
<ItemGroup>
6063
<Filter Include="Source Files">
@@ -84,4 +87,8 @@
8487
<Filter>Header Files</Filter>
8588
</ClInclude>
8689
</ItemGroup>
90+
<ItemGroup>
91+
<Midl Include="$(ReactNativeWindowsDir)Microsoft.ReactNative\IJSValueReader.idl" />
92+
<Midl Include="$(ReactNativeWindowsDir)Microsoft.ReactNative\IJSValueWriter.idl" />
93+
</ItemGroup>
8794
</Project>

vnext/Shared/BaseFileReaderResource.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,12 @@ void BaseFileReaderResource::ReadAsDataUrl(
8080
std::copy(encode_base64(bytes.cbegin()), encode_base64(bytes.cend()), ostream_iterator<char>(oss));
8181
result += oss.str();
8282

83+
// https://unix.stackexchange.com/questions/631501
84+
auto padLength = 4 - (oss.tellp() % 4);
85+
for (auto i = 0; i < padLength; ++i) {
86+
result += '=';
87+
}
88+
8389
resolver(std::move(result));
8490
}
8591

vnext/Shared/Shared.vcxitems.filters

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,7 @@
287287
<ClCompile Include="$(MSBuildThisFileDirectory)..\Microsoft.ReactNative\Fabric\platform\react\renderer\graphics\PlatformColorUtils.cpp" />
288288
<ClCompile Include="$(MSBuildThisFileDirectory)..\Microsoft.ReactNative\Fabric\AbiViewShadowNode.cpp" />
289289
<ClCompile Include="$(MSBuildThisFileDirectory)..\Microsoft.ReactNative\Fabric\AbiState.cpp" />
290+
<ClCompile Include="$(MSBuildThisFileDirectory)..\Microsoft.ReactNative\Utils\ThemeUtils.cpp" />
290291
</ItemGroup>
291292
<ItemGroup>
292293
<Filter Include="Source Files">

0 commit comments

Comments
 (0)