Fix Base64 duplicate padding (#12689)
* Remove unused Boost headers from FR module source * Declare encode/decode base64 utility methods * Implement Encode methods * Update packages.lock.json * Update packages.lock.json * Use string as return value to ensure lifetime See https://learn.microsoft.com/en-us/cpp/code-quality/c26816?view=msvc-170 * Apply padding for Boost variant * Remove decode from base64 wstring variant * Cover 4*3 (plus empty) cases in unit tests * Make output padding size match to input size % 4 * clang format * Implement DecodeBase64 * Replace scattered usage of Boost base64_from_binary * Remove Boost includes from BaseFrRc * Change files * Remove EncodeBase64(wstring_view) * Add test for non-text values * Pass string_view by value * Ensure binary data lifetime in test
This commit is contained in:
Родитель
0d65b8a7a5
Коммит
d9bd78f3dd
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"type": "prerelease",
|
||||
"comment": "Fix Base64 encoding padding",
|
||||
"packageName": "react-native-windows",
|
||||
"email": "julio.rocha@microsoft.com",
|
||||
"dependentChangeType": "patch"
|
||||
}
|
|
@ -64,7 +64,7 @@
|
|||
string literals. It prevents code like
|
||||
wchar_t* str = L"hello";
|
||||
from compiling. -->
|
||||
<AdditionalOptions>%(AdditionalOptions) /Zc:strictStrings</AdditionalOptions>
|
||||
<AdditionalOptions>%(AdditionalOptions) /Zc:strictStrings /await</AdditionalOptions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
|
||||
|
@ -78,12 +78,17 @@
|
|||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Unicode.cpp" />
|
||||
<ClCompile Include="Utilities.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Unicode.h" />
|
||||
<ClInclude Include="Utilities.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ItemGroup>
|
||||
<PackageReference Include="boost" Version="1.76.0.0" />
|
||||
<PackageReference Include="Microsoft.Windows.CppWinRT" Version="$(CppWinRTVersion)" PrivateAssets="all" />
|
||||
</ItemGroup>
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
<Target Name="Deploy" />
|
||||
|
|
|
@ -12,6 +12,9 @@
|
|||
<ClCompile Include="Unicode.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Utilities.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Unicode.h">
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#include "Utilities.h"
|
||||
|
||||
// Boost Library
|
||||
#include <boost/archive/iterators/base64_from_binary.hpp>
|
||||
#include <boost/archive/iterators/binary_from_base64.hpp>
|
||||
#include <boost/archive/iterators/ostream_iterator.hpp>
|
||||
#include <boost/archive/iterators/transform_width.hpp>
|
||||
|
||||
// Windows API
|
||||
#include <winrt/Windows.Security.Cryptography.h>
|
||||
|
||||
// Standard Library
|
||||
using std::string;
|
||||
using std::string_view;
|
||||
using std::wstring_view;
|
||||
using winrt::array_view;
|
||||
|
||||
using winrt::Windows::Security::Cryptography::BinaryStringEncoding;
|
||||
using winrt::Windows::Security::Cryptography::CryptographicBuffer;
|
||||
|
||||
namespace Microsoft::React::Utilities {
|
||||
|
||||
string DecodeBase64(string_view base64) noexcept {
|
||||
typedef array_view<char const> av_t;
|
||||
auto bytes = av_t(base64.data(), static_cast<av_t::size_type>(base64.size()));
|
||||
|
||||
using namespace boost::archive::iterators;
|
||||
typedef transform_width<binary_from_base64<const char *>, 8, 6> decode_base64;
|
||||
std::ostringstream oss;
|
||||
std::copy(decode_base64(bytes.cbegin()), decode_base64(bytes.cend()), ostream_iterator<char>(oss));
|
||||
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
// https://www.boost.org/doc/libs/1_76_0/libs/serialization/doc/dataflow.html
|
||||
string EncodeBase64(string_view text) noexcept {
|
||||
typedef array_view<char const> av_t;
|
||||
auto bytes = av_t(text.data(), static_cast<av_t::size_type>(text.size()));
|
||||
|
||||
using namespace boost::archive::iterators;
|
||||
typedef base64_from_binary<transform_width<const char *, 6, 8>> encode_base64;
|
||||
std::ostringstream oss;
|
||||
std::copy(encode_base64(bytes.cbegin()), encode_base64(bytes.cend()), ostream_iterator<char>(oss));
|
||||
|
||||
// https://unix.stackexchange.com/questions/631501
|
||||
auto padLength = (4 - (oss.tellp() % 4)) % 4;
|
||||
for (auto i = 0; i < padLength; ++i) {
|
||||
oss << '=';
|
||||
}
|
||||
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
} // namespace Microsoft::React::Utilities
|
|
@ -1,7 +1,20 @@
|
|||
{
|
||||
"version": 1,
|
||||
"dependencies": {
|
||||
"native,Version=v0.0": {},
|
||||
"native,Version=v0.0": {
|
||||
"boost": {
|
||||
"type": "Direct",
|
||||
"requested": "[1.76.0, )",
|
||||
"resolved": "1.76.0",
|
||||
"contentHash": "p+w3YvNdXL8Cu9Fzrmexssu0tZbWxuf6ywsQqHjDlKFE5ojXHof1HIyMC3zDLfLnh80dIeFcEUAuR2Asg/XHRA=="
|
||||
},
|
||||
"Microsoft.Windows.CppWinRT": {
|
||||
"type": "Direct",
|
||||
"requested": "[2.0.211028.7, )",
|
||||
"resolved": "2.0.211028.7",
|
||||
"contentHash": "JBGI0c3WLoU6aYJRy9Qo0MLDQfObEp+d4nrhR95iyzf7+HOgjRunHDp/6eGFREd7xq3OI1mll9ecJrMfzBvlyg=="
|
||||
}
|
||||
},
|
||||
"native,Version=v0.0/win10-arm": {},
|
||||
"native,Version=v0.0/win10-arm-aot": {},
|
||||
"native,Version=v0.0/win10-arm64-aot": {},
|
||||
|
|
|
@ -2,6 +2,9 @@
|
|||
// Licensed under the MIT License.
|
||||
|
||||
#pragma once
|
||||
|
||||
// Standard Library
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
|
@ -37,3 +40,11 @@ constexpr std::size_t ArraySize(T (&)[N]) noexcept {
|
|||
}
|
||||
|
||||
} // namespace Microsoft::Common::Utilities
|
||||
|
||||
namespace Microsoft::React::Utilities {
|
||||
|
||||
std::string DecodeBase64(std::string_view text) noexcept;
|
||||
|
||||
std::string EncodeBase64(std::string_view text) noexcept;
|
||||
|
||||
} // namespace Microsoft::React::Utilities
|
||||
|
|
|
@ -54,7 +54,10 @@
|
|||
"contentHash": "1tAtFgtbVpI/JgRIxy9j30R/W6B1zi9dYt0o5QwAk5V3X2mo9xrrHcbXlbczKQIftYoNHe0Mfq9ExIu9A1Cs0g=="
|
||||
},
|
||||
"common": {
|
||||
"type": "Project"
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"boost": "[1.76.0, )"
|
||||
}
|
||||
},
|
||||
"fmt": {
|
||||
"type": "Project"
|
||||
|
|
|
@ -47,7 +47,10 @@
|
|||
"contentHash": "WMcGpWKrmJmzrNeuaEb23bEMnbtR/vLmvZtkAP5qWu7vQsY59GqfRJd65sFpBszbd2k/bQ8cs8eWawQKAabkVg=="
|
||||
},
|
||||
"common": {
|
||||
"type": "Project"
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"boost": "[1.76.0, )"
|
||||
}
|
||||
},
|
||||
"fmt": {
|
||||
"type": "Project"
|
||||
|
|
|
@ -50,7 +50,10 @@
|
|||
"contentHash": "ksHjshj05AMAQ/v7Wet5Dwcwn9Up2BTOIrTv1yEW7+D23FQX0yILW5Zw0bmlWtV8MEtdY611z+06U3Xvu2ygSA=="
|
||||
},
|
||||
"common": {
|
||||
"type": "Project"
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"boost": "[1.76.0, )"
|
||||
}
|
||||
},
|
||||
"fmt": {
|
||||
"type": "Project"
|
||||
|
|
|
@ -3,10 +3,12 @@
|
|||
|
||||
#include <CppUnitTest.h>
|
||||
#include <Utils.h>
|
||||
#include <utilities.h>
|
||||
|
||||
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
|
||||
|
||||
using std::string;
|
||||
using std::string_view;
|
||||
|
||||
namespace Microsoft::React::Test {
|
||||
|
||||
|
@ -14,15 +16,17 @@ namespace Microsoft::React::Test {
|
|||
// test macros.
|
||||
// clang-format off
|
||||
|
||||
TEST_CLASS(UtilsTest) {
|
||||
TEST_CLASS(UtilsTest)
|
||||
{
|
||||
|
||||
void ExpectUrl(
|
||||
string urlString,
|
||||
string protocol,
|
||||
string host,
|
||||
string port = "",
|
||||
string path = "/",
|
||||
string query = "") {
|
||||
string urlString,
|
||||
string protocol,
|
||||
string host,
|
||||
string port = "",
|
||||
string path = "/",
|
||||
string query = "")
|
||||
{
|
||||
|
||||
Url url(std::move(urlString));
|
||||
|
||||
|
@ -35,96 +39,232 @@ TEST_CLASS(UtilsTest) {
|
|||
|
||||
#pragma region Url Tests
|
||||
|
||||
TEST_METHOD(UtilsTest_ValidProtocols) {
|
||||
string protocols[4]{"http", "https", "ws", "wss"};
|
||||
for (auto protocol : protocols) {
|
||||
TEST_METHOD(UtilsTest_ValidProtocols)
|
||||
{
|
||||
string protocols[4] { "http", "https", "ws", "wss" };
|
||||
for (auto protocol : protocols)
|
||||
{
|
||||
ExpectUrl(string(protocol + "://internal"), protocol, "internal");
|
||||
}
|
||||
}
|
||||
|
||||
TEST_METHOD(UtilsTest_IntraHost) {
|
||||
TEST_METHOD(UtilsTest_IntraHost)
|
||||
{
|
||||
ExpectUrl("ws://internal", "ws", "internal");
|
||||
}
|
||||
|
||||
TEST_METHOD(UtilsTest_IntraHostTrailing) {
|
||||
TEST_METHOD(UtilsTest_IntraHostTrailing)
|
||||
{
|
||||
ExpectUrl("ws://internal/", "ws", "internal");
|
||||
}
|
||||
|
||||
TEST_METHOD(UtilsTest_IntraHostQueryLeading) {
|
||||
TEST_METHOD(UtilsTest_IntraHostQueryLeading)
|
||||
{
|
||||
ExpectUrl("ws://internal?", "ws", "internal");
|
||||
}
|
||||
|
||||
TEST_METHOD(UtilsTest_IntraHostTrailingQueryLeading) {
|
||||
TEST_METHOD(UtilsTest_IntraHostTrailingQueryLeading)
|
||||
{
|
||||
ExpectUrl("ws://internal/?", "ws", "internal");
|
||||
}
|
||||
|
||||
TEST_METHOD(UtilsTest_NormalHostQueryLeading) {
|
||||
TEST_METHOD(UtilsTest_NormalHostQueryLeading)
|
||||
{
|
||||
ExpectUrl("ws://example.com?", "ws", "example.com");
|
||||
}
|
||||
|
||||
TEST_METHOD(UtilsTest_IntraPort) {
|
||||
TEST_METHOD(UtilsTest_IntraPort)
|
||||
{
|
||||
ExpectUrl("ws://internal:5000", "ws", "internal", "5000");
|
||||
}
|
||||
|
||||
TEST_METHOD(UtilsTest_NormalPort) {
|
||||
TEST_METHOD(UtilsTest_NormalPort)
|
||||
{
|
||||
ExpectUrl("ws://example.com:443", "ws", "example.com", "443");
|
||||
}
|
||||
|
||||
TEST_METHOD(UtilsTest_PortPath) {
|
||||
TEST_METHOD(UtilsTest_PortPath)
|
||||
{
|
||||
ExpectUrl("ws://example.com:5000/ws", "ws", "example.com", "5000", "/ws");
|
||||
}
|
||||
|
||||
TEST_METHOD(UtilsTest_Query) {
|
||||
TEST_METHOD(UtilsTest_Query)
|
||||
{
|
||||
ExpectUrl(
|
||||
"ws://example.com?a=1&b=2", "ws", "example.com", "", "/", "a=1&b=2");
|
||||
"ws://example.com?a=1&b=2", "ws", "example.com", "", "/", "a=1&b=2");
|
||||
}
|
||||
|
||||
TEST_METHOD(UtilsTest_TrailingPathQuery) {
|
||||
TEST_METHOD(UtilsTest_TrailingPathQuery)
|
||||
{
|
||||
ExpectUrl(
|
||||
"ws://example.com/?a=1&b=2", "ws", "example.com", "", "/", "a=1&b=2");
|
||||
"ws://example.com/?a=1&b=2", "ws", "example.com", "", "/", "a=1&b=2");
|
||||
}
|
||||
|
||||
TEST_METHOD(UtilsTest_HyphenHostInternal) {
|
||||
TEST_METHOD(UtilsTest_HyphenHostInternal)
|
||||
{
|
||||
ExpectUrl("wss://-my-hyphened-host--", "wss", "-my-hyphened-host--");
|
||||
}
|
||||
|
||||
TEST_METHOD(UtilsTest_NestedPathTrailingSlashLeadingQuestionMark) {
|
||||
TEST_METHOD(UtilsTest_NestedPathTrailingSlashLeadingQuestionMark)
|
||||
{
|
||||
ExpectUrl(
|
||||
"ws://example.com/the/nested/path/?",
|
||||
"ws",
|
||||
"example.com",
|
||||
"",
|
||||
"/the/nested/path/");
|
||||
"ws://example.com/the/nested/path/?",
|
||||
"ws",
|
||||
"example.com",
|
||||
"",
|
||||
"/the/nested/path/");
|
||||
}
|
||||
|
||||
TEST_METHOD(UtilsTest_NestedSubdomain) {
|
||||
TEST_METHOD(UtilsTest_NestedSubdomain)
|
||||
{
|
||||
ExpectUrl(
|
||||
"ws://nested.sub.domain.of.example.com",
|
||||
"ws",
|
||||
"nested.sub.domain.of.example.com");
|
||||
"ws://nested.sub.domain.of.example.com",
|
||||
"ws",
|
||||
"nested.sub.domain.of.example.com");
|
||||
}
|
||||
|
||||
#pragma region Url Negative Tests
|
||||
|
||||
TEST_METHOD(UtilsTest_EmptyStringFails) {
|
||||
Assert::ExpectException<std::exception>([]() { Url(""); });
|
||||
TEST_METHOD(UtilsTest_EmptyStringFails)
|
||||
{
|
||||
Assert::ExpectException<std::exception>([]()
|
||||
{
|
||||
Url("");
|
||||
});
|
||||
}
|
||||
|
||||
TEST_METHOD(UtilsTest_WrongProtocol) {
|
||||
Assert::ExpectException<std::exception>([]() { Url("foos://internal"); });
|
||||
TEST_METHOD(UtilsTest_WrongProtocol)
|
||||
{
|
||||
Assert::ExpectException<std::exception>([]()
|
||||
{
|
||||
Url("foos://internal");
|
||||
});
|
||||
}
|
||||
|
||||
TEST_METHOD(UtilsTest_BadCharsInPort) {
|
||||
Assert::ExpectException<std::exception>([]() { Url("ws://internal:50O0"); });
|
||||
TEST_METHOD(UtilsTest_BadCharsInPort)
|
||||
{
|
||||
Assert::ExpectException<std::exception>([]()
|
||||
{
|
||||
Url("ws://internal:50O0");
|
||||
});
|
||||
}
|
||||
|
||||
TEST_METHOD(UtilsTest_SpacesInProtocol) {
|
||||
Assert::ExpectException<std::exception>([]() { Url(" ws://internal"); });
|
||||
TEST_METHOD(UtilsTest_SpacesInProtocol)
|
||||
{
|
||||
Assert::ExpectException<std::exception>([]()
|
||||
{
|
||||
Url(" ws://internal");
|
||||
});
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Base64 Tests
|
||||
|
||||
TEST_METHOD(EncodeStdStringToBase64Succeeds)
|
||||
{
|
||||
string messages[]
|
||||
{
|
||||
"",
|
||||
"a",
|
||||
"ab",
|
||||
"abc",
|
||||
"abcd",
|
||||
"abcde",
|
||||
"abcdef",
|
||||
"abcdefg",
|
||||
"abcdefgh",
|
||||
"abcdefghi",
|
||||
"abcdefghij",
|
||||
"abcdefghijk",
|
||||
"abcdefghijkl"
|
||||
};
|
||||
|
||||
// Computed using [System.Convert]::ToBase64String
|
||||
constexpr const char* expected[] =
|
||||
{
|
||||
"",
|
||||
"YQ==",
|
||||
"YWI=",
|
||||
"YWJj",
|
||||
"YWJjZA==",
|
||||
"YWJjZGU=",
|
||||
"YWJjZGVm",
|
||||
"YWJjZGVmZw==",
|
||||
"YWJjZGVmZ2g=",
|
||||
"YWJjZGVmZ2hp",
|
||||
"YWJjZGVmZ2hpag==",
|
||||
"YWJjZGVmZ2hpams=",
|
||||
"YWJjZGVmZ2hpamts"
|
||||
};
|
||||
|
||||
for (auto i = 0; i < sizeof(messages)/sizeof(string); ++i)
|
||||
{
|
||||
auto actual = Utilities::EncodeBase64(string_view(messages[i]));
|
||||
Assert::AreEqual(expected[i], actual.data());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_METHOD(EncodeArrayViewToBase64Succeeds)
|
||||
{
|
||||
//[System.Convert]::ToBase64String([byte[]](0,1,2,3,4))
|
||||
constexpr const char* expected = "AAECAwQ=";
|
||||
|
||||
auto input = std::vector<uint8_t>{ 0, 1, 2, 3, 4 };
|
||||
auto bytes = winrt::array_view<const uint8_t>(input.data(), input.data() + input.size());
|
||||
auto chars = reinterpret_cast<const char*>(bytes.data());
|
||||
auto view = string_view(chars, bytes.size());
|
||||
|
||||
auto actual = Utilities::EncodeBase64(view);
|
||||
Assert::AreEqual(expected, actual.c_str());
|
||||
}
|
||||
|
||||
TEST_METHOD(DecodeStdStringFromBase64Succeeds)
|
||||
{
|
||||
constexpr const char* messages[] =
|
||||
{
|
||||
"",
|
||||
"YQ==",
|
||||
"YWI=",
|
||||
"YWJj",
|
||||
"YWJjZA==",
|
||||
"YWJjZGU=",
|
||||
"YWJjZGVm",
|
||||
"YWJjZGVmZw==",
|
||||
"YWJjZGVmZ2g=",
|
||||
"YWJjZGVmZ2hp",
|
||||
"YWJjZGVmZ2hpag==",
|
||||
"YWJjZGVmZ2hpams=",
|
||||
"YWJjZGVmZ2hpamts"
|
||||
};
|
||||
|
||||
constexpr const char* expected[]
|
||||
{
|
||||
"",
|
||||
"a",
|
||||
"ab",
|
||||
"abc",
|
||||
"abcd",
|
||||
"abcde",
|
||||
"abcdef",
|
||||
"abcdefg",
|
||||
"abcdefgh",
|
||||
"abcdefghi",
|
||||
"abcdefghij",
|
||||
"abcdefghijk",
|
||||
"abcdefghijkl"
|
||||
};
|
||||
|
||||
for (auto i = 0; i < sizeof(messages) / sizeof(string); ++i)
|
||||
{
|
||||
auto actual = Utilities::DecodeBase64(string_view(messages[i]));
|
||||
Assert::AreEqual(expected[i], actual.data());
|
||||
}
|
||||
}
|
||||
|
||||
#pragma endregion Base64 Tests
|
||||
};
|
||||
|
||||
// clang-format on
|
||||
|
|
|
@ -50,7 +50,10 @@
|
|||
"contentHash": "ksHjshj05AMAQ/v7Wet5Dwcwn9Up2BTOIrTv1yEW7+D23FQX0yILW5Zw0bmlWtV8MEtdY611z+06U3Xvu2ygSA=="
|
||||
},
|
||||
"common": {
|
||||
"type": "Project"
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"boost": "[1.76.0, )"
|
||||
}
|
||||
},
|
||||
"fmt": {
|
||||
"type": "Project"
|
||||
|
|
|
@ -53,7 +53,10 @@
|
|||
"contentHash": "WMcGpWKrmJmzrNeuaEb23bEMnbtR/vLmvZtkAP5qWu7vQsY59GqfRJd65sFpBszbd2k/bQ8cs8eWawQKAabkVg=="
|
||||
},
|
||||
"common": {
|
||||
"type": "Project"
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"boost": "[1.76.0, )"
|
||||
}
|
||||
},
|
||||
"fmt": {
|
||||
"type": "Project"
|
||||
|
|
|
@ -9,7 +9,10 @@
|
|||
"contentHash": "p+w3YvNdXL8Cu9Fzrmexssu0tZbWxuf6ywsQqHjDlKFE5ojXHof1HIyMC3zDLfLnh80dIeFcEUAuR2Asg/XHRA=="
|
||||
},
|
||||
"common": {
|
||||
"type": "Project"
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"boost": "[1.76.0, )"
|
||||
}
|
||||
},
|
||||
"fmt": {
|
||||
"type": "Project"
|
||||
|
@ -17,8 +20,8 @@
|
|||
"folly": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"boost": "[1.76.0, )",
|
||||
"fmt": "[1.0.0, )"
|
||||
"Fmt": "[1.0.0, )",
|
||||
"boost": "[1.76.0, )"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -50,7 +50,10 @@
|
|||
"contentHash": "1tAtFgtbVpI/JgRIxy9j30R/W6B1zi9dYt0o5QwAk5V3X2mo9xrrHcbXlbczKQIftYoNHe0Mfq9ExIu9A1Cs0g=="
|
||||
},
|
||||
"common": {
|
||||
"type": "Project"
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"boost": "[1.76.0, )"
|
||||
}
|
||||
},
|
||||
"fmt": {
|
||||
"type": "Project"
|
||||
|
|
|
@ -3,10 +3,7 @@
|
|||
|
||||
#include "BaseFileReaderResource.h"
|
||||
|
||||
// Boost Library
|
||||
#include <boost/archive/iterators/base64_from_binary.hpp>
|
||||
#include <boost/archive/iterators/ostream_iterator.hpp>
|
||||
#include <boost/archive/iterators/transform_width.hpp>
|
||||
#include <utilities.h>
|
||||
|
||||
// Windows API
|
||||
#include <winrt/base.h>
|
||||
|
@ -73,18 +70,9 @@ void BaseFileReaderResource::ReadAsDataUrl(
|
|||
result += type;
|
||||
result += ";base64,";
|
||||
|
||||
// https://www.boost.org/doc/libs/1_76_0/libs/serialization/doc/dataflow.html
|
||||
using namespace boost::archive::iterators;
|
||||
typedef base64_from_binary<transform_width<const char *, 6, 8>> encode_base64;
|
||||
std::ostringstream oss;
|
||||
std::copy(encode_base64(bytes.cbegin()), encode_base64(bytes.cend()), ostream_iterator<char>(oss));
|
||||
result += oss.str();
|
||||
|
||||
// https://unix.stackexchange.com/questions/631501
|
||||
auto padLength = 4 - (oss.tellp() % 4);
|
||||
for (auto i = 0; i < padLength; ++i) {
|
||||
result += '=';
|
||||
}
|
||||
auto chars = reinterpret_cast<const char *>(bytes.data());
|
||||
auto view = std::string_view(chars, bytes.size());
|
||||
result += Utilities::EncodeBase64(view);
|
||||
|
||||
resolver(std::move(result));
|
||||
}
|
||||
|
|
|
@ -7,11 +7,6 @@
|
|||
#include <ReactPropertyBag.h>
|
||||
#include <sstream>
|
||||
|
||||
// Boost Library
|
||||
#include <boost/archive/iterators/base64_from_binary.hpp>
|
||||
#include <boost/archive/iterators/ostream_iterator.hpp>
|
||||
#include <boost/archive/iterators/transform_width.hpp>
|
||||
|
||||
// React Native
|
||||
#include <cxxreact/JsArgumentHelpers.h>
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include <Modules/IHttpModuleProxy.h>
|
||||
#include <Modules/IWebSocketModuleProxy.h>
|
||||
#include <utilities.h>
|
||||
|
||||
// Boost Libraries
|
||||
#include <boost/uuid/uuid_io.hpp>
|
||||
|
@ -95,11 +96,9 @@ void DefaultBlobResource::SendOverSocket(string &&blobId, int64_t offset, int64_
|
|||
return m_callbacks.OnError(e.what());
|
||||
}
|
||||
|
||||
auto buffer = CryptographicBuffer::CreateFromByteArray(data);
|
||||
auto base64Hstring = CryptographicBuffer::EncodeToBase64String(std::move(buffer));
|
||||
auto base64String = winrt::to_string(base64Hstring);
|
||||
|
||||
wsProxy->SendBinary(std::move(base64String), socketId);
|
||||
auto chars = reinterpret_cast<const char *>(data.data());
|
||||
auto view = std::string_view(chars, data.size());
|
||||
wsProxy->SendBinary(Utilities::EncodeBase64(view), socketId);
|
||||
}
|
||||
|
||||
void DefaultBlobResource::CreateFromParts(msrn::JSValueArray &&parts, string &&blobId) noexcept /*override*/ {
|
||||
|
|
Загрузка…
Ссылка в новой задаче