From e5e00a0a9764094aa7888b5853bc6afea3f5f777 Mon Sep 17 00:00:00 2001 From: Kevin Lubick Date: Tue, 3 Oct 2023 18:58:08 +0000 Subject: [PATCH 1/8] WIP --- shell/common/BUILD.gn | 3 + shell/common/base64.cc | 159 +++++++++++++++++++++++++++++++ shell/common/base64.h | 48 ++++++++++ shell/common/base64_unittests.cc | 43 +++++++++ 4 files changed, 253 insertions(+) create mode 100644 shell/common/base64.cc create mode 100644 shell/common/base64.h create mode 100644 shell/common/base64_unittests.cc diff --git a/shell/common/BUILD.gn b/shell/common/BUILD.gn index c5a4db91e4333..2c31578a60cb8 100644 --- a/shell/common/BUILD.gn +++ b/shell/common/BUILD.gn @@ -81,6 +81,8 @@ source_set("common") { sources = [ "animator.cc", "animator.h", + "base64.cc", + "base64.h", "context_options.cc", "context_options.h", "display_manager.cc", @@ -293,6 +295,7 @@ if (enable_unittests) { sources = [ "animator_unittests.cc", + "base64_unittests.cc", "context_options_unittests.cc", "dl_op_spy_unittests.cc", "engine_unittests.cc", diff --git a/shell/common/base64.cc b/shell/common/base64.cc new file mode 100644 index 0000000000000..d3f89c37f1a69 --- /dev/null +++ b/shell/common/base64.cc @@ -0,0 +1,159 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "shell/common/base64.h" + +#include "fml/logging.h" + +#include + +#define DecodePad -2 +#define EncodePad 64 + +static const char default_encode[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/="; + +static const signed char decodeData[] = { + 62, -1, -1, -1, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, DecodePad, -1, -1, + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, + -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 +}; + +namespace flutter { + +Base64::Error Base64::Decode(const void* srcv, size_t srcLength, void* dstv, size_t* dstLength){ + const unsigned char* src = static_cast(srcv); + unsigned char* dst = static_cast(dstv); + + int i = 0; + bool padTwo = false; + bool padThree = false; + char unsigned const * const end = src + srcLength; + while (src < end) { + unsigned char bytes[4]; + int byte = 0; + do { + unsigned char srcByte = *src++; + if (srcByte == 0) { + *dstLength = i; + return Error::kNone; + } + if (srcByte <= ' ') { + continue; // treat as white space + } + if (srcByte < '+' || srcByte > 'z') { + return Error::kBadChar; + } + signed char decoded = decodeData[srcByte - '+']; + bytes[byte] = decoded; + if (decoded != DecodePad) { + if (decoded < 0) { + return Error::kBadChar; + } + byte++; + if (*src) { + continue; + } + if (byte == 0) { + *dstLength = i; + return Error::kNone; + } + if (byte == 4) { + break; + } + } + // Handle padding + if (byte < 2) { + return Error::kBadPadding; + } + padThree = true; + if (byte == 2) { + padTwo = true; + } + break; + } while (byte < 4); + int two = 0; + int three = 0; + if (dst) { + int one = (uint8_t) (bytes[0] << 2); + two = bytes[1]; + one |= two >> 4; + two = (uint8_t) ((two << 4) & 0xFF); + three = bytes[2]; + two |= three >> 2; + three = (uint8_t) ((three << 6) & 0xFF); + three |= bytes[3]; + FML_DCHECK(one < 256 && two < 256 && three < 256); + dst[i] = (unsigned char) one; + } + i++; + if (padTwo) { + break; + } + if (dst) { + dst[i] = (unsigned char) two; + } + i++; + if (padThree) { + break; + } + if (dst) { + dst[i] = (unsigned char) three; + } + i++; + } + *dstLength = i; + return Error::kNone; +} + +#if defined _WIN32 +#pragma warning ( pop ) +#endif + +size_t Base64::Encode(const void* srcv, size_t length, void* dstv) { + const unsigned char* src = static_cast(srcv); + unsigned char* dst = static_cast(dstv); + + const char* encode = default_encode; + if (dst) { + size_t remainder = length % 3; + char unsigned const * const end = &src[length - remainder]; + while (src < end) { + unsigned a = *src++; + unsigned b = *src++; + unsigned c = *src++; + int d = c & 0x3F; + c = (c >> 6 | b << 2) & 0x3F; + b = (b >> 4 | a << 4) & 0x3F; + a = a >> 2; + *dst++ = encode[a]; + *dst++ = encode[b]; + *dst++ = encode[c]; + *dst++ = encode[d]; + } + if (remainder > 0) { + int k1 = 0; + int k2 = EncodePad; + int a = (uint8_t) *src++; + if (remainder == 2) + { + int b = *src++; + k1 = b >> 4; + k2 = (b << 2) & 0x3F; + } + *dst++ = encode[a >> 2]; + *dst++ = encode[(k1 | a << 4) & 0x3F]; + *dst++ = encode[k2]; + *dst++ = encode[EncodePad]; + } + } + return (length + 2) / 3 * 4; +} + +} // namespace flutter \ No newline at end of file diff --git a/shell/common/base64.h b/shell/common/base64.h new file mode 100644 index 0000000000000..02c06ae3700ef --- /dev/null +++ b/shell/common/base64.h @@ -0,0 +1,48 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_COMMON_BASE64_H_ +#define FLUTTER_SHELL_COMMON_BASE64_H_ + +#include + +namespace flutter { + +struct Base64 { +public: + enum class Error { + kNone, + kBadPadding, + kBadChar, + }; + + /** + Base64 encodes src into dst. + + Normally this is called once with 'dst' nullptr to get the required size, then again with an + allocated 'dst' pointer to do the actual encoding. + + @param dst nullptr or a pointer to a buffer large enough to receive the result + + @return the required length of dst for encoding. + */ + static size_t Encode(const void* src, size_t length, void* dst); + + /** + Base64 decodes src into dst. + + Normally this is called once with 'dst' nullptr to get the required size, then again with an + allocated 'dst' pointer to do the actual encoding. + + @param dst nullptr or a pointer to a buffer large enough to receive the result + + @param dstLength assigned the length dst is required to be. Must not be nullptr. + */ + [[nodiscard]] static Error Decode(const void* src, size_t srcLength, + void* dst, size_t* dstLength); +}; + +} // namespace flutter + +#endif // FLUTTER_SHELL_COMMON_BASE64_H_ diff --git a/shell/common/base64_unittests.cc b/shell/common/base64_unittests.cc new file mode 100644 index 0000000000000..33e569ee654fc --- /dev/null +++ b/shell/common/base64_unittests.cc @@ -0,0 +1,43 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/shell/common/base64.h" + +#include "fml/logging.h" +#include "gtest/gtest.h" + +#include + +namespace flutter { +namespace testing { + +TEST(Base64, EncodeStrings) { + auto test = [](std::string input, std::string output) { + char buffer[256]; + size_t len = Base64::Encode(input.c_str(), input.length(), &buffer); + FML_CHECK(len <= 256); + std::string actual(buffer, len); + ASSERT_STREQ(actual.c_str(), output.c_str()); + }; + test("apple", "YXBwbGU="); + test("BANANA", "QkFOQU5B"); + test("Cherry Pie", "Q2hlcnJ5IFBpZQ=="); + test("fLoCcInAuCiNiHiLiPiLiFiCaTiOn", "ZkxvQ2NJbkF1Q2lOaUhpTGlQaUxpRmlDYVRpT24="); + test("", ""); +} + +TEST(Base64, EncodeBytes) { + auto test = [](const uint8_t input[], size_t num, std::string output) { + char buffer[256]; + size_t len = Base64::Encode(input, num, &buffer); + FML_CHECK(len <= 256); + std::string actual(buffer, len); + ASSERT_STREQ(actual.c_str(), output.c_str()); + }; + uint8_t buffer[] = {0x03, 0x14, 0x15, 0x92, 0x65}; + test(buffer, sizeof(buffer), "AxQVkmU="); +} + +} // namespace testing +} // namespace flutter \ No newline at end of file From 723a2e8cf4f942adcbe3c03080a90eb47cd876bb Mon Sep 17 00:00:00 2001 From: Kevin Lubick Date: Tue, 3 Oct 2023 23:59:52 +0000 Subject: [PATCH 2/8] Tests pass --- shell/common/base64.cc | 6 ++- shell/common/base64_unittests.cc | 85 ++++++++++++++++++++++++++++++-- 2 files changed, 85 insertions(+), 6 deletions(-) diff --git a/shell/common/base64.cc b/shell/common/base64.cc index d3f89c37f1a69..adee202fac25e 100644 --- a/shell/common/base64.cc +++ b/shell/common/base64.cc @@ -27,7 +27,7 @@ static const signed char decodeData[] = { namespace flutter { -Base64::Error Base64::Decode(const void* srcv, size_t srcLength, void* dstv, size_t* dstLength){ +Base64::Error Base64::Decode(const void* srcv, size_t srcLength, void* dstv, size_t* dstLength) { const unsigned char* src = static_cast(srcv); unsigned char* dst = static_cast(dstv); @@ -68,7 +68,9 @@ Base64::Error Base64::Decode(const void* srcv, size_t srcLength, void* dstv, siz break; } } - // Handle padding + // As an optimization, if we find an equals sign + // we assume all future bytes to read are the + // appropriate number of padding equals signs. if (byte < 2) { return Error::kBadPadding; } diff --git a/shell/common/base64_unittests.cc b/shell/common/base64_unittests.cc index 33e569ee654fc..767459a8d777e 100644 --- a/shell/common/base64_unittests.cc +++ b/shell/common/base64_unittests.cc @@ -20,23 +20,100 @@ TEST(Base64, EncodeStrings) { std::string actual(buffer, len); ASSERT_STREQ(actual.c_str(), output.c_str()); }; + // Some arbitrary strings test("apple", "YXBwbGU="); test("BANANA", "QkFOQU5B"); test("Cherry Pie", "Q2hlcnJ5IFBpZQ=="); - test("fLoCcInAuCiNiHiLiPiLiFiCaTiOn", "ZkxvQ2NJbkF1Q2lOaUhpTGlQaUxpRmlDYVRpT24="); + test("fLoCcInAuCiNiHiLiPiLiFiCaTiOn", + "ZkxvQ2NJbkF1Q2lOaUhpTGlQaUxpRmlDYVRpT24="); test("", ""); } TEST(Base64, EncodeBytes) { auto test = [](const uint8_t input[], size_t num, std::string output) { - char buffer[256]; + char buffer[512]; size_t len = Base64::Encode(input, num, &buffer); + FML_CHECK(len <= 512); + std::string actual(buffer, len); + ASSERT_STREQ(actual.c_str(), output.c_str()); + }; + // Some arbitrary raw bytes + uint8_t e[] = {0x02, 0x71, 0x82, 0x81, 0x82, 0x84, 0x59}; + test(e, sizeof(e), "AnGCgYKEWQ=="); + + uint8_t pi[] = {0x03, 0x24, 0x3F, 0x6A, 0x88, 0x85}; + test(pi, sizeof(pi), "AyQ/aoiF"); + + uint8_t bytes[256]; + for (int i = 0; i < 256; i++) { + bytes[i] = i; + } + test(bytes, sizeof(bytes), "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gIS" + "IjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFV" + "WV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJ" + "iouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8v" + "b6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8P" + "Hy8/T19vf4+fr7/P3+/w=="); +} + +TEST(Base64, DecodeStrings_Success) { + auto test = [](std::string input, std::string output) { + char buffer[256]; + size_t len = 0; + auto err = Base64::Decode(input.c_str(), input.length(), &buffer, &len); + ASSERT_EQ(err, Base64::Error::kNone); FML_CHECK(len <= 256); std::string actual(buffer, len); ASSERT_STREQ(actual.c_str(), output.c_str()); }; - uint8_t buffer[] = {0x03, 0x14, 0x15, 0x92, 0x65}; - test(buffer, sizeof(buffer), "AxQVkmU="); + // Some arbitrary strings + test("ZGF0ZQ==", "date"); + test("RWdncGxhbnQ=", "Eggplant"); + test("RmlzaCAmIENoaXBz", "Fish & Chips"); + test("U3VQZVJjQWxJZlJhR2lMaVN0SWNFeFBpQWxJZE9jSW9Vcw==", + "SuPeRcAlIfRaGiLiStIcExPiAlIdOcIoUs"); + + // Spaces are ignored + test("Y X Bwb GU=", "apple"); +} + +TEST(Base64, DecodeStrings_Errors) { + auto test = [](std::string input, Base64::Error expectedError) { + char buffer[256]; + size_t len = 0; + auto err = Base64::Decode(input.c_str(), input.length(), &buffer, &len); + ASSERT_EQ(err, expectedError) << input; + }; + + test("Nuts&Bolts", Base64::Error::kBadChar); + test("Error!", Base64::Error::kBadChar); + test(":", Base64::Error::kBadChar); + + test("RmlzaCAmIENoaXBz=", Base64::Error::kBadPadding); + // Some cases of bad padding may be ignored due to an internal optimization + // test("ZGF0ZQ=", Base64::Error::kBadPadding); + // test("RWdncGxhbnQ", Base64::Error::kBadPadding); +} + +TEST(Base64, DecodeBytes) { + auto test = [](std::string input, const uint8_t output[], size_t num) { + char buffer[256]; + size_t len = 0; + auto err = Base64::Decode(input.c_str(), input.length(), &buffer, &len); + ASSERT_EQ(err, Base64::Error::kNone); + FML_CHECK(len <= 256); + ASSERT_EQ(num, len) << input; + for (int i = 0; i < int(len); i++) { + ASSERT_EQ(uint8_t(buffer[i]), output[i]) << input << i; + } + }; + // Some arbitrary raw bytes, same as the byte output above + uint8_t e[] = {0x02, 0x71, 0x82, 0x81, 0x82, 0x84, 0x59}; + test("AnGCgYKEWQ==", e, sizeof(e)); + + uint8_t pi[] = {0x03, 0x24, 0x3F, 0x6A, 0x88, 0x85}; + test("AyQ/aoiF", pi, sizeof(pi)); + } } // namespace testing From bedf953c5c0895c1faf81f13a5569da38b5859d9 Mon Sep 17 00:00:00 2001 From: Kevin Lubick Date: Wed, 4 Oct 2023 12:57:59 +0000 Subject: [PATCH 3/8] GN rework --- common/graphics/BUILD.gn | 1 + common/graphics/persistent_cache.cc | 16 ++++++++-------- shell/common/BUILD.gn | 12 ++++++++++-- shell/common/base64.cc | 6 +++--- 4 files changed, 22 insertions(+), 13 deletions(-) diff --git a/common/graphics/BUILD.gn b/common/graphics/BUILD.gn index 70fbc1ad5a614..77f529198a497 100644 --- a/common/graphics/BUILD.gn +++ b/common/graphics/BUILD.gn @@ -25,6 +25,7 @@ source_set("graphics") { "//flutter/display_list", "//flutter/fml", "//flutter/shell/version:version", + "//flutter/shell/common:base64", "//third_party/boringssl", "//third_party/rapidjson", "//third_party/skia", diff --git a/common/graphics/persistent_cache.cc b/common/graphics/persistent_cache.cc index 50d09bb8fcbc6..a7c1990083d4e 100644 --- a/common/graphics/persistent_cache.cc +++ b/common/graphics/persistent_cache.cc @@ -19,10 +19,10 @@ #include "flutter/fml/paths.h" #include "flutter/fml/trace_event.h" #include "flutter/shell/version/version.h" +#include "flutter/shell/common/base64.h" #include "openssl/sha.h" #include "rapidjson/document.h" #include "third_party/skia/include/gpu/GrDirectContext.h" -#include "third_party/skia/include/utils/SkBase64.h" namespace flutter { @@ -169,21 +169,21 @@ sk_sp ParseBase32(const std::string& input) { } sk_sp ParseBase64(const std::string& input) { - SkBase64::Error error; + Base64::Error error; size_t output_len; - error = SkBase64::Decode(input.c_str(), input.length(), nullptr, &output_len); - if (error != SkBase64::Error::kNoError) { - FML_LOG(ERROR) << "Base64 decode error: " << error; + error = Base64::Decode(input.c_str(), input.length(), nullptr, &output_len); + if (error != Base64::Error::kNone) { + FML_LOG(ERROR) << "Base64 decode error: " << (int)error; FML_LOG(ERROR) << "Base64 can't decode: " << input; return nullptr; } sk_sp data = SkData::MakeUninitialized(output_len); void* output = data->writable_data(); - error = SkBase64::Decode(input.c_str(), input.length(), output, &output_len); - if (error != SkBase64::Error::kNoError) { - FML_LOG(ERROR) << "Base64 decode error: " << error; + error = Base64::Decode(input.c_str(), input.length(), output, &output_len); + if (error != Base64::Error::kNone) { + FML_LOG(ERROR) << "Base64 decode error: " << (int)error; FML_LOG(ERROR) << "Base64 can't decode: " << input; return nullptr; } diff --git a/shell/common/BUILD.gn b/shell/common/BUILD.gn index 2c31578a60cb8..ade97006eaddb 100644 --- a/shell/common/BUILD.gn +++ b/shell/common/BUILD.gn @@ -81,8 +81,6 @@ source_set("common") { sources = [ "animator.cc", "animator.h", - "base64.cc", - "base64.h", "context_options.cc", "context_options.h", "display_manager.cc", @@ -146,6 +144,7 @@ source_set("common") { "//flutter/lib/ui", "//flutter/runtime", "//flutter/shell/profiling", + "//flutter/shell/common:base64", "//third_party/dart/runtime:dart_api", "//third_party/skia", ] @@ -160,6 +159,14 @@ source_set("common") { } } +# These are in their own source_set to avoid a dependency cycle with //common/graphics +source_set("base64") { + sources = [ + "base64.cc", + "base64.h", + ] +} + template("shell_host_executable") { executable(target_name) { testonly = true @@ -315,6 +322,7 @@ if (enable_unittests) { ":shell_unittests_fixtures", "//flutter/assets", "//flutter/common/graphics", + "//flutter/shell/common:base64", "//flutter/shell/profiling:profiling_unittests", "//flutter/shell/version", "//flutter/testing:fixture_test", diff --git a/shell/common/base64.cc b/shell/common/base64.cc index adee202fac25e..2ef8b1ab0c184 100644 --- a/shell/common/base64.cc +++ b/shell/common/base64.cc @@ -2,9 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "shell/common/base64.h" +#include "flutter/shell/common/base64.h" -#include "fml/logging.h" +#include "flutter/fml/logging.h" #include @@ -158,4 +158,4 @@ size_t Base64::Encode(const void* srcv, size_t length, void* dstv) { return (length + 2) / 3 * 4; } -} // namespace flutter \ No newline at end of file +} // namespace flutter From 2681791882763126e1b908ae878cafeaa5f162bd Mon Sep 17 00:00:00 2001 From: Kevin Lubick Date: Wed, 4 Oct 2023 13:07:57 +0000 Subject: [PATCH 4/8] Replace all uses of SkBase64 encoding --- flow/BUILD.gn | 1 + flow/layers/performance_overlay_layer_unittests.cc | 9 +++++---- shell/common/BUILD.gn | 1 + shell/common/rasterizer.cc | 8 +++++--- shell/common/shell.cc | 9 +++++---- 5 files changed, 17 insertions(+), 11 deletions(-) diff --git a/flow/BUILD.gn b/flow/BUILD.gn index a75605749c7aa..4fd85368c6b8a 100644 --- a/flow/BUILD.gn +++ b/flow/BUILD.gn @@ -186,6 +186,7 @@ if (enable_unittests) { ":flow_fixtures", ":flow_testing", "//flutter/common/graphics", + "//flutter/shell/common:base64", "//flutter/display_list/testing:display_list_testing", "//flutter/fml", "//flutter/testing:skia", diff --git a/flow/layers/performance_overlay_layer_unittests.cc b/flow/layers/performance_overlay_layer_unittests.cc index e1bbb29893268..becbca9ab0cc4 100644 --- a/flow/layers/performance_overlay_layer_unittests.cc +++ b/flow/layers/performance_overlay_layer_unittests.cc @@ -10,6 +10,7 @@ #include "flutter/flow/flow_test_utils.h" #include "flutter/flow/raster_cache.h" #include "flutter/flow/testing/layer_test.h" +#include "flutter/shell/common/base64.h" #include "flutter/testing/mock_canvas.h" #include "third_party/skia/include/core/SkData.h" #include "third_party/skia/include/core/SkImage.h" @@ -18,7 +19,6 @@ #include "third_party/skia/include/core/SkSurface.h" #include "third_party/skia/include/core/SkTextBlob.h" #include "third_party/skia/include/encode/SkPngEncoder.h" -#include "third_party/skia/include/utils/SkBase64.h" namespace flutter { namespace testing { @@ -111,11 +111,12 @@ static void TestPerformanceOverlayLayerGold(int refresh_rate) { wstream.write(snapshot_data->data(), snapshot_data->size()); wstream.flush(); - size_t b64_size = - SkBase64::Encode(snapshot_data->data(), snapshot_data->size(), nullptr); + // TODO(kjlubick) We shouldn't need to call Encode once to pre-flight the + // encode length. It should be ceil(4/3 * sksl.value->size()). + size_t b64_size = Base64::Encode(snapshot_data->data(), snapshot_data->size(), nullptr); sk_sp b64_data = SkData::MakeUninitialized(b64_size + 1); char* b64_char = static_cast(b64_data->writable_data()); - SkBase64::Encode(snapshot_data->data(), snapshot_data->size(), b64_char); + Base64::Encode(snapshot_data->data(), snapshot_data->size(), b64_char); b64_char[b64_size] = 0; // make it null terminated for printing EXPECT_TRUE(golden_data_matches) diff --git a/shell/common/BUILD.gn b/shell/common/BUILD.gn index ade97006eaddb..696f4f251a3bb 100644 --- a/shell/common/BUILD.gn +++ b/shell/common/BUILD.gn @@ -165,6 +165,7 @@ source_set("base64") { "base64.cc", "base64.h", ] + deps = ["//flutter/fml"] } template("shell_host_executable") { diff --git a/shell/common/rasterizer.cc b/shell/common/rasterizer.cc index 7ab349d353f37..a8c3104cd4d36 100644 --- a/shell/common/rasterizer.cc +++ b/shell/common/rasterizer.cc @@ -15,6 +15,7 @@ #include "flutter/fml/time/time_delta.h" #include "flutter/fml/time/time_point.h" #include "flutter/shell/common/serialization_callbacks.h" +#include "flutter/shell/common/base64.h" #include "fml/make_copyable.h" #include "third_party/skia/include/core/SkColorSpace.h" #include "third_party/skia/include/core/SkData.h" @@ -32,7 +33,6 @@ #include "third_party/skia/include/gpu/GrDirectContext.h" #include "third_party/skia/include/gpu/GrTypes.h" #include "third_party/skia/include/gpu/ganesh/SkSurfaceGanesh.h" -#include "third_party/skia/include/utils/SkBase64.h" namespace flutter { @@ -910,9 +910,11 @@ Rasterizer::Screenshot Rasterizer::ScreenshotLastLayerTree( } if (base64_encode) { - size_t b64_size = SkBase64::Encode(data->data(), data->size(), nullptr); + // TODO(kjlubick) We shouldn't need to call Encode once to pre-flight the + // encode length. It should be ceil(4/3 * sksl.value->size()). + size_t b64_size = Base64::Encode(data->data(), data->size(), nullptr); auto b64_data = SkData::MakeUninitialized(b64_size); - SkBase64::Encode(data->data(), data->size(), b64_data->writable_data()); + Base64::Encode(data->data(), data->size(), b64_data->writable_data()); return Rasterizer::Screenshot{b64_data, layer_tree->frame_size(), format}; } diff --git a/shell/common/shell.cc b/shell/common/shell.cc index 44e5d2a65e110..3ec4890020daf 100644 --- a/shell/common/shell.cc +++ b/shell/common/shell.cc @@ -24,6 +24,7 @@ #include "flutter/fml/trace_event.h" #include "flutter/runtime/dart_vm.h" #include "flutter/shell/common/engine.h" +#include "flutter/shell/common/base64.h" #include "flutter/shell/common/skia_event_tracer_impl.h" #include "flutter/shell/common/switches.h" #include "flutter/shell/common/vsync_waiter.h" @@ -39,7 +40,6 @@ #include "third_party/skia/include/codec/SkWbmpDecoder.h" #include "third_party/skia/include/codec/SkWebpDecoder.h" #include "third_party/skia/include/core/SkGraphics.h" -#include "third_party/skia/include/utils/SkBase64.h" #include "third_party/tonic/common/log.h" namespace flutter { @@ -1840,11 +1840,12 @@ bool Shell::OnServiceProtocolGetSkSLs( PersistentCache* persistent_cache = PersistentCache::GetCacheForProcess(); std::vector sksls = persistent_cache->LoadSkSLs(); for (const auto& sksl : sksls) { - size_t b64_size = - SkBase64::Encode(sksl.value->data(), sksl.value->size(), nullptr); + // TODO(kjlubick) We shouldn't need to call Encode once to pre-flight the + // encode length. It should be ceil(4/3 * sksl.value->size()). + size_t b64_size = Base64::Encode(sksl.value->data(), sksl.value->size(), nullptr); sk_sp b64_data = SkData::MakeUninitialized(b64_size + 1); char* b64_char = static_cast(b64_data->writable_data()); - SkBase64::Encode(sksl.value->data(), sksl.value->size(), b64_char); + Base64::Encode(sksl.value->data(), sksl.value->size(), b64_char); b64_char[b64_size] = 0; // make it null terminated for printing rapidjson::Value shader_value(b64_char, response->GetAllocator()); std::string_view key_view(reinterpret_cast(sksl.key->data()), From a18d3c6c49c7b9474c1f13cd9752b4058fdd8745 Mon Sep 17 00:00:00 2001 From: Kevin Lubick Date: Wed, 4 Oct 2023 13:09:01 +0000 Subject: [PATCH 5/8] format --- common/graphics/BUILD.gn | 2 +- common/graphics/persistent_cache.cc | 2 +- flow/BUILD.gn | 2 +- .../performance_overlay_layer_unittests.cc | 3 +- shell/common/BUILD.gn | 12 +- shell/common/base64.cc | 244 +++++++++--------- shell/common/base64.h | 67 ++--- shell/common/base64_unittests.cc | 176 ++++++------- shell/common/rasterizer.cc | 2 +- shell/common/shell.cc | 5 +- 10 files changed, 261 insertions(+), 254 deletions(-) diff --git a/common/graphics/BUILD.gn b/common/graphics/BUILD.gn index 77f529198a497..61d410d4f864d 100644 --- a/common/graphics/BUILD.gn +++ b/common/graphics/BUILD.gn @@ -24,8 +24,8 @@ source_set("graphics") { "//flutter/assets", "//flutter/display_list", "//flutter/fml", - "//flutter/shell/version:version", "//flutter/shell/common:base64", + "//flutter/shell/version:version", "//third_party/boringssl", "//third_party/rapidjson", "//third_party/skia", diff --git a/common/graphics/persistent_cache.cc b/common/graphics/persistent_cache.cc index a7c1990083d4e..0d24125d1f00b 100644 --- a/common/graphics/persistent_cache.cc +++ b/common/graphics/persistent_cache.cc @@ -18,8 +18,8 @@ #include "flutter/fml/mapping.h" #include "flutter/fml/paths.h" #include "flutter/fml/trace_event.h" -#include "flutter/shell/version/version.h" #include "flutter/shell/common/base64.h" +#include "flutter/shell/version/version.h" #include "openssl/sha.h" #include "rapidjson/document.h" #include "third_party/skia/include/gpu/GrDirectContext.h" diff --git a/flow/BUILD.gn b/flow/BUILD.gn index 4fd85368c6b8a..492126c2a3086 100644 --- a/flow/BUILD.gn +++ b/flow/BUILD.gn @@ -186,9 +186,9 @@ if (enable_unittests) { ":flow_fixtures", ":flow_testing", "//flutter/common/graphics", - "//flutter/shell/common:base64", "//flutter/display_list/testing:display_list_testing", "//flutter/fml", + "//flutter/shell/common:base64", "//flutter/testing:skia", "//flutter/testing:testing_lib", "//third_party/dart/runtime:libdart_jit", # for tracing diff --git a/flow/layers/performance_overlay_layer_unittests.cc b/flow/layers/performance_overlay_layer_unittests.cc index becbca9ab0cc4..0c4f7e11d3a2a 100644 --- a/flow/layers/performance_overlay_layer_unittests.cc +++ b/flow/layers/performance_overlay_layer_unittests.cc @@ -113,7 +113,8 @@ static void TestPerformanceOverlayLayerGold(int refresh_rate) { // TODO(kjlubick) We shouldn't need to call Encode once to pre-flight the // encode length. It should be ceil(4/3 * sksl.value->size()). - size_t b64_size = Base64::Encode(snapshot_data->data(), snapshot_data->size(), nullptr); + size_t b64_size = + Base64::Encode(snapshot_data->data(), snapshot_data->size(), nullptr); sk_sp b64_data = SkData::MakeUninitialized(b64_size + 1); char* b64_char = static_cast(b64_data->writable_data()); Base64::Encode(snapshot_data->data(), snapshot_data->size(), b64_char); diff --git a/shell/common/BUILD.gn b/shell/common/BUILD.gn index 696f4f251a3bb..31d89012a58d3 100644 --- a/shell/common/BUILD.gn +++ b/shell/common/BUILD.gn @@ -143,8 +143,8 @@ source_set("common") { "//flutter/fml", "//flutter/lib/ui", "//flutter/runtime", - "//flutter/shell/profiling", "//flutter/shell/common:base64", + "//flutter/shell/profiling", "//third_party/dart/runtime:dart_api", "//third_party/skia", ] @@ -161,11 +161,11 @@ source_set("common") { # These are in their own source_set to avoid a dependency cycle with //common/graphics source_set("base64") { - sources = [ - "base64.cc", - "base64.h", - ] - deps = ["//flutter/fml"] + sources = [ + "base64.cc", + "base64.h", + ] + deps = [ "//flutter/fml" ] } template("shell_host_executable") { diff --git a/shell/common/base64.cc b/shell/common/base64.cc index 2ef8b1ab0c184..9f58f9056cb24 100644 --- a/shell/common/base64.cc +++ b/shell/common/base64.cc @@ -17,145 +17,145 @@ static const char default_encode[] = "0123456789+/="; static const signed char decodeData[] = { - 62, -1, -1, -1, 63, - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, DecodePad, -1, -1, - -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, - -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, - 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 -}; + 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, + -1, -1, DecodePad, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, + 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51}; namespace flutter { -Base64::Error Base64::Decode(const void* srcv, size_t srcLength, void* dstv, size_t* dstLength) { - const unsigned char* src = static_cast(srcv); - unsigned char* dst = static_cast(dstv); +Base64::Error Base64::Decode(const void* srcv, + size_t srcLength, + void* dstv, + size_t* dstLength) { + const unsigned char* src = static_cast(srcv); + unsigned char* dst = static_cast(dstv); - int i = 0; - bool padTwo = false; - bool padThree = false; - char unsigned const * const end = src + srcLength; - while (src < end) { - unsigned char bytes[4]; - int byte = 0; - do { - unsigned char srcByte = *src++; - if (srcByte == 0) { - *dstLength = i; - return Error::kNone; - } - if (srcByte <= ' ') { - continue; // treat as white space - } - if (srcByte < '+' || srcByte > 'z') { - return Error::kBadChar; - } - signed char decoded = decodeData[srcByte - '+']; - bytes[byte] = decoded; - if (decoded != DecodePad) { - if (decoded < 0) { - return Error::kBadChar; - } - byte++; - if (*src) { - continue; - } - if (byte == 0) { - *dstLength = i; - return Error::kNone; - } - if (byte == 4) { - break; - } - } - // As an optimization, if we find an equals sign - // we assume all future bytes to read are the - // appropriate number of padding equals signs. - if (byte < 2) { - return Error::kBadPadding; - } - padThree = true; - if (byte == 2) { - padTwo = true; - } - break; - } while (byte < 4); - int two = 0; - int three = 0; - if (dst) { - int one = (uint8_t) (bytes[0] << 2); - two = bytes[1]; - one |= two >> 4; - two = (uint8_t) ((two << 4) & 0xFF); - three = bytes[2]; - two |= three >> 2; - three = (uint8_t) ((three << 6) & 0xFF); - three |= bytes[3]; - FML_DCHECK(one < 256 && two < 256 && three < 256); - dst[i] = (unsigned char) one; - } - i++; - if (padTwo) { - break; + int i = 0; + bool padTwo = false; + bool padThree = false; + char unsigned const* const end = src + srcLength; + while (src < end) { + unsigned char bytes[4]; + int byte = 0; + do { + unsigned char srcByte = *src++; + if (srcByte == 0) { + *dstLength = i; + return Error::kNone; + } + if (srcByte <= ' ') { + continue; // treat as white space + } + if (srcByte < '+' || srcByte > 'z') { + return Error::kBadChar; + } + signed char decoded = decodeData[srcByte - '+']; + bytes[byte] = decoded; + if (decoded != DecodePad) { + if (decoded < 0) { + return Error::kBadChar; } - if (dst) { - dst[i] = (unsigned char) two; + byte++; + if (*src) { + continue; } - i++; - if (padThree) { - break; + if (byte == 0) { + *dstLength = i; + return Error::kNone; } - if (dst) { - dst[i] = (unsigned char) three; + if (byte == 4) { + break; } - i++; + } + // As an optimization, if we find an equals sign + // we assume all future bytes to read are the + // appropriate number of padding equals signs. + if (byte < 2) { + return Error::kBadPadding; + } + padThree = true; + if (byte == 2) { + padTwo = true; + } + break; + } while (byte < 4); + int two = 0; + int three = 0; + if (dst) { + int one = (uint8_t)(bytes[0] << 2); + two = bytes[1]; + one |= two >> 4; + two = (uint8_t)((two << 4) & 0xFF); + three = bytes[2]; + two |= three >> 2; + three = (uint8_t)((three << 6) & 0xFF); + three |= bytes[3]; + FML_DCHECK(one < 256 && two < 256 && three < 256); + dst[i] = (unsigned char)one; + } + i++; + if (padTwo) { + break; + } + if (dst) { + dst[i] = (unsigned char)two; + } + i++; + if (padThree) { + break; } - *dstLength = i; - return Error::kNone; + if (dst) { + dst[i] = (unsigned char)three; + } + i++; + } + *dstLength = i; + return Error::kNone; } #if defined _WIN32 -#pragma warning ( pop ) +#pragma warning(pop) #endif size_t Base64::Encode(const void* srcv, size_t length, void* dstv) { - const unsigned char* src = static_cast(srcv); - unsigned char* dst = static_cast(dstv); + const unsigned char* src = static_cast(srcv); + unsigned char* dst = static_cast(dstv); - const char* encode = default_encode; - if (dst) { - size_t remainder = length % 3; - char unsigned const * const end = &src[length - remainder]; - while (src < end) { - unsigned a = *src++; - unsigned b = *src++; - unsigned c = *src++; - int d = c & 0x3F; - c = (c >> 6 | b << 2) & 0x3F; - b = (b >> 4 | a << 4) & 0x3F; - a = a >> 2; - *dst++ = encode[a]; - *dst++ = encode[b]; - *dst++ = encode[c]; - *dst++ = encode[d]; - } - if (remainder > 0) { - int k1 = 0; - int k2 = EncodePad; - int a = (uint8_t) *src++; - if (remainder == 2) - { - int b = *src++; - k1 = b >> 4; - k2 = (b << 2) & 0x3F; - } - *dst++ = encode[a >> 2]; - *dst++ = encode[(k1 | a << 4) & 0x3F]; - *dst++ = encode[k2]; - *dst++ = encode[EncodePad]; - } + const char* encode = default_encode; + if (dst) { + size_t remainder = length % 3; + char unsigned const* const end = &src[length - remainder]; + while (src < end) { + unsigned a = *src++; + unsigned b = *src++; + unsigned c = *src++; + int d = c & 0x3F; + c = (c >> 6 | b << 2) & 0x3F; + b = (b >> 4 | a << 4) & 0x3F; + a = a >> 2; + *dst++ = encode[a]; + *dst++ = encode[b]; + *dst++ = encode[c]; + *dst++ = encode[d]; + } + if (remainder > 0) { + int k1 = 0; + int k2 = EncodePad; + int a = (uint8_t)*src++; + if (remainder == 2) { + int b = *src++; + k1 = b >> 4; + k2 = (b << 2) & 0x3F; + } + *dst++ = encode[a >> 2]; + *dst++ = encode[(k1 | a << 4) & 0x3F]; + *dst++ = encode[k2]; + *dst++ = encode[EncodePad]; } - return (length + 2) / 3 * 4; + } + return (length + 2) / 3 * 4; } } // namespace flutter diff --git a/shell/common/base64.h b/shell/common/base64.h index 02c06ae3700ef..9e24cea437887 100644 --- a/shell/common/base64.h +++ b/shell/common/base64.h @@ -10,37 +10,42 @@ namespace flutter { struct Base64 { -public: - enum class Error { - kNone, - kBadPadding, - kBadChar, - }; - - /** - Base64 encodes src into dst. - - Normally this is called once with 'dst' nullptr to get the required size, then again with an - allocated 'dst' pointer to do the actual encoding. - - @param dst nullptr or a pointer to a buffer large enough to receive the result - - @return the required length of dst for encoding. - */ - static size_t Encode(const void* src, size_t length, void* dst); - - /** - Base64 decodes src into dst. - - Normally this is called once with 'dst' nullptr to get the required size, then again with an - allocated 'dst' pointer to do the actual encoding. - - @param dst nullptr or a pointer to a buffer large enough to receive the result - - @param dstLength assigned the length dst is required to be. Must not be nullptr. - */ - [[nodiscard]] static Error Decode(const void* src, size_t srcLength, - void* dst, size_t* dstLength); + public: + enum class Error { + kNone, + kBadPadding, + kBadChar, + }; + + /** + Base64 encodes src into dst. + + Normally this is called once with 'dst' nullptr to get the required size, + then again with an allocated 'dst' pointer to do the actual encoding. + + @param dst nullptr or a pointer to a buffer large enough to receive the + result + + @return the required length of dst for encoding. + */ + static size_t Encode(const void* src, size_t length, void* dst); + + /** + Base64 decodes src into dst. + + Normally this is called once with 'dst' nullptr to get the required size, + then again with an allocated 'dst' pointer to do the actual encoding. + + @param dst nullptr or a pointer to a buffer large enough to receive the + result + + @param dstLength assigned the length dst is required to be. Must not be + nullptr. + */ + [[nodiscard]] static Error Decode(const void* src, + size_t srcLength, + void* dst, + size_t* dstLength); }; } // namespace flutter diff --git a/shell/common/base64_unittests.cc b/shell/common/base64_unittests.cc index 767459a8d777e..5ceef215f9643 100644 --- a/shell/common/base64_unittests.cc +++ b/shell/common/base64_unittests.cc @@ -13,107 +13,107 @@ namespace flutter { namespace testing { TEST(Base64, EncodeStrings) { - auto test = [](std::string input, std::string output) { - char buffer[256]; - size_t len = Base64::Encode(input.c_str(), input.length(), &buffer); - FML_CHECK(len <= 256); - std::string actual(buffer, len); - ASSERT_STREQ(actual.c_str(), output.c_str()); - }; - // Some arbitrary strings - test("apple", "YXBwbGU="); - test("BANANA", "QkFOQU5B"); - test("Cherry Pie", "Q2hlcnJ5IFBpZQ=="); - test("fLoCcInAuCiNiHiLiPiLiFiCaTiOn", - "ZkxvQ2NJbkF1Q2lOaUhpTGlQaUxpRmlDYVRpT24="); - test("", ""); + auto test = [](std::string input, std::string output) { + char buffer[256]; + size_t len = Base64::Encode(input.c_str(), input.length(), &buffer); + FML_CHECK(len <= 256); + std::string actual(buffer, len); + ASSERT_STREQ(actual.c_str(), output.c_str()); + }; + // Some arbitrary strings + test("apple", "YXBwbGU="); + test("BANANA", "QkFOQU5B"); + test("Cherry Pie", "Q2hlcnJ5IFBpZQ=="); + test("fLoCcInAuCiNiHiLiPiLiFiCaTiOn", + "ZkxvQ2NJbkF1Q2lOaUhpTGlQaUxpRmlDYVRpT24="); + test("", ""); } TEST(Base64, EncodeBytes) { - auto test = [](const uint8_t input[], size_t num, std::string output) { - char buffer[512]; - size_t len = Base64::Encode(input, num, &buffer); - FML_CHECK(len <= 512); - std::string actual(buffer, len); - ASSERT_STREQ(actual.c_str(), output.c_str()); - }; - // Some arbitrary raw bytes - uint8_t e[] = {0x02, 0x71, 0x82, 0x81, 0x82, 0x84, 0x59}; - test(e, sizeof(e), "AnGCgYKEWQ=="); - - uint8_t pi[] = {0x03, 0x24, 0x3F, 0x6A, 0x88, 0x85}; - test(pi, sizeof(pi), "AyQ/aoiF"); - - uint8_t bytes[256]; - for (int i = 0; i < 256; i++) { - bytes[i] = i; - } - test(bytes, sizeof(bytes), "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gIS" - "IjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFV" - "WV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJ" - "iouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8v" - "b6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8P" - "Hy8/T19vf4+fr7/P3+/w=="); + auto test = [](const uint8_t input[], size_t num, std::string output) { + char buffer[512]; + size_t len = Base64::Encode(input, num, &buffer); + FML_CHECK(len <= 512); + std::string actual(buffer, len); + ASSERT_STREQ(actual.c_str(), output.c_str()); + }; + // Some arbitrary raw bytes + uint8_t e[] = {0x02, 0x71, 0x82, 0x81, 0x82, 0x84, 0x59}; + test(e, sizeof(e), "AnGCgYKEWQ=="); + + uint8_t pi[] = {0x03, 0x24, 0x3F, 0x6A, 0x88, 0x85}; + test(pi, sizeof(pi), "AyQ/aoiF"); + + uint8_t bytes[256]; + for (int i = 0; i < 256; i++) { + bytes[i] = i; + } + test(bytes, sizeof(bytes), + "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gIS" + "IjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFV" + "WV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJ" + "iouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8v" + "b6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8P" + "Hy8/T19vf4+fr7/P3+/w=="); } TEST(Base64, DecodeStrings_Success) { - auto test = [](std::string input, std::string output) { - char buffer[256]; - size_t len = 0; - auto err = Base64::Decode(input.c_str(), input.length(), &buffer, &len); - ASSERT_EQ(err, Base64::Error::kNone); - FML_CHECK(len <= 256); - std::string actual(buffer, len); - ASSERT_STREQ(actual.c_str(), output.c_str()); - }; - // Some arbitrary strings - test("ZGF0ZQ==", "date"); - test("RWdncGxhbnQ=", "Eggplant"); - test("RmlzaCAmIENoaXBz", "Fish & Chips"); - test("U3VQZVJjQWxJZlJhR2lMaVN0SWNFeFBpQWxJZE9jSW9Vcw==", - "SuPeRcAlIfRaGiLiStIcExPiAlIdOcIoUs"); - - // Spaces are ignored - test("Y X Bwb GU=", "apple"); + auto test = [](std::string input, std::string output) { + char buffer[256]; + size_t len = 0; + auto err = Base64::Decode(input.c_str(), input.length(), &buffer, &len); + ASSERT_EQ(err, Base64::Error::kNone); + FML_CHECK(len <= 256); + std::string actual(buffer, len); + ASSERT_STREQ(actual.c_str(), output.c_str()); + }; + // Some arbitrary strings + test("ZGF0ZQ==", "date"); + test("RWdncGxhbnQ=", "Eggplant"); + test("RmlzaCAmIENoaXBz", "Fish & Chips"); + test("U3VQZVJjQWxJZlJhR2lMaVN0SWNFeFBpQWxJZE9jSW9Vcw==", + "SuPeRcAlIfRaGiLiStIcExPiAlIdOcIoUs"); + + // Spaces are ignored + test("Y X Bwb GU=", "apple"); } TEST(Base64, DecodeStrings_Errors) { - auto test = [](std::string input, Base64::Error expectedError) { - char buffer[256]; - size_t len = 0; - auto err = Base64::Decode(input.c_str(), input.length(), &buffer, &len); - ASSERT_EQ(err, expectedError) << input; - }; - - test("Nuts&Bolts", Base64::Error::kBadChar); - test("Error!", Base64::Error::kBadChar); - test(":", Base64::Error::kBadChar); - - test("RmlzaCAmIENoaXBz=", Base64::Error::kBadPadding); - // Some cases of bad padding may be ignored due to an internal optimization - // test("ZGF0ZQ=", Base64::Error::kBadPadding); - // test("RWdncGxhbnQ", Base64::Error::kBadPadding); + auto test = [](std::string input, Base64::Error expectedError) { + char buffer[256]; + size_t len = 0; + auto err = Base64::Decode(input.c_str(), input.length(), &buffer, &len); + ASSERT_EQ(err, expectedError) << input; + }; + + test("Nuts&Bolts", Base64::Error::kBadChar); + test("Error!", Base64::Error::kBadChar); + test(":", Base64::Error::kBadChar); + + test("RmlzaCAmIENoaXBz=", Base64::Error::kBadPadding); + // Some cases of bad padding may be ignored due to an internal optimization + // test("ZGF0ZQ=", Base64::Error::kBadPadding); + // test("RWdncGxhbnQ", Base64::Error::kBadPadding); } TEST(Base64, DecodeBytes) { - auto test = [](std::string input, const uint8_t output[], size_t num) { - char buffer[256]; - size_t len = 0; - auto err = Base64::Decode(input.c_str(), input.length(), &buffer, &len); - ASSERT_EQ(err, Base64::Error::kNone); - FML_CHECK(len <= 256); - ASSERT_EQ(num, len) << input; - for (int i = 0; i < int(len); i++) { - ASSERT_EQ(uint8_t(buffer[i]), output[i]) << input << i; - } - }; - // Some arbitrary raw bytes, same as the byte output above - uint8_t e[] = {0x02, 0x71, 0x82, 0x81, 0x82, 0x84, 0x59}; - test("AnGCgYKEWQ==", e, sizeof(e)); - - uint8_t pi[] = {0x03, 0x24, 0x3F, 0x6A, 0x88, 0x85}; - test("AyQ/aoiF", pi, sizeof(pi)); + auto test = [](std::string input, const uint8_t output[], size_t num) { + char buffer[256]; + size_t len = 0; + auto err = Base64::Decode(input.c_str(), input.length(), &buffer, &len); + ASSERT_EQ(err, Base64::Error::kNone); + FML_CHECK(len <= 256); + ASSERT_EQ(num, len) << input; + for (int i = 0; i < int(len); i++) { + ASSERT_EQ(uint8_t(buffer[i]), output[i]) << input << i; + } + }; + // Some arbitrary raw bytes, same as the byte output above + uint8_t e[] = {0x02, 0x71, 0x82, 0x81, 0x82, 0x84, 0x59}; + test("AnGCgYKEWQ==", e, sizeof(e)); + uint8_t pi[] = {0x03, 0x24, 0x3F, 0x6A, 0x88, 0x85}; + test("AyQ/aoiF", pi, sizeof(pi)); } } // namespace testing diff --git a/shell/common/rasterizer.cc b/shell/common/rasterizer.cc index a8c3104cd4d36..10c6429304ed5 100644 --- a/shell/common/rasterizer.cc +++ b/shell/common/rasterizer.cc @@ -14,8 +14,8 @@ #include "flutter/flow/layers/offscreen_surface.h" #include "flutter/fml/time/time_delta.h" #include "flutter/fml/time/time_point.h" -#include "flutter/shell/common/serialization_callbacks.h" #include "flutter/shell/common/base64.h" +#include "flutter/shell/common/serialization_callbacks.h" #include "fml/make_copyable.h" #include "third_party/skia/include/core/SkColorSpace.h" #include "third_party/skia/include/core/SkData.h" diff --git a/shell/common/shell.cc b/shell/common/shell.cc index 3ec4890020daf..20fcebeeb7d70 100644 --- a/shell/common/shell.cc +++ b/shell/common/shell.cc @@ -23,8 +23,8 @@ #include "flutter/fml/paths.h" #include "flutter/fml/trace_event.h" #include "flutter/runtime/dart_vm.h" -#include "flutter/shell/common/engine.h" #include "flutter/shell/common/base64.h" +#include "flutter/shell/common/engine.h" #include "flutter/shell/common/skia_event_tracer_impl.h" #include "flutter/shell/common/switches.h" #include "flutter/shell/common/vsync_waiter.h" @@ -1842,7 +1842,8 @@ bool Shell::OnServiceProtocolGetSkSLs( for (const auto& sksl : sksls) { // TODO(kjlubick) We shouldn't need to call Encode once to pre-flight the // encode length. It should be ceil(4/3 * sksl.value->size()). - size_t b64_size = Base64::Encode(sksl.value->data(), sksl.value->size(), nullptr); + size_t b64_size = + Base64::Encode(sksl.value->data(), sksl.value->size(), nullptr); sk_sp b64_data = SkData::MakeUninitialized(b64_size + 1); char* b64_char = static_cast(b64_data->writable_data()); Base64::Encode(sksl.value->data(), sksl.value->size(), b64_char); From a40cb6f15f5b6061e916c3fc76c4da6a1e945121 Mon Sep 17 00:00:00 2001 From: Kevin Lubick Date: Thu, 5 Oct 2023 12:36:23 +0000 Subject: [PATCH 6/8] Fix presubmits --- ci/licenses_golden/excluded_files | 1 + ci/licenses_golden/licenses_flutter | 4 ++++ shell/common/base64.cc | 4 ---- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/ci/licenses_golden/excluded_files b/ci/licenses_golden/excluded_files index b4d58de3f1185..718d678c8c559 100644 --- a/ci/licenses_golden/excluded_files +++ b/ci/licenses_golden/excluded_files @@ -231,6 +231,7 @@ ../../../flutter/runtime/no_dart_plugin_registrant_unittests.cc ../../../flutter/runtime/type_conversions_unittests.cc ../../../flutter/shell/common/animator_unittests.cc +../../../flutter/shell/common/base64_unittests.cc ../../../flutter/shell/common/context_options_unittests.cc ../../../flutter/shell/common/dl_op_spy_unittests.cc ../../../flutter/shell/common/engine_unittests.cc diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 84d3c9fd3f98a..3a9223f770030 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -2246,6 +2246,8 @@ ORIGIN: ../../../flutter/runtime/test_font_data.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/runtime/test_font_data.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/common/animator.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/common/animator.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/common/base64.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/common/base64.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/common/context_options.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/common/context_options.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/common/dart_native_benchmarks.cc + ../../../flutter/LICENSE @@ -5005,6 +5007,8 @@ FILE: ../../../flutter/runtime/test_font_data.cc FILE: ../../../flutter/runtime/test_font_data.h FILE: ../../../flutter/shell/common/animator.cc FILE: ../../../flutter/shell/common/animator.h +FILE: ../../../flutter/shell/common/base64.cc +FILE: ../../../flutter/shell/common/base64.h FILE: ../../../flutter/shell/common/context_options.cc FILE: ../../../flutter/shell/common/context_options.h FILE: ../../../flutter/shell/common/dart_native_benchmarks.cc diff --git a/shell/common/base64.cc b/shell/common/base64.cc index 9f58f9056cb24..9f7c98e56aba5 100644 --- a/shell/common/base64.cc +++ b/shell/common/base64.cc @@ -115,10 +115,6 @@ Base64::Error Base64::Decode(const void* srcv, return Error::kNone; } -#if defined _WIN32 -#pragma warning(pop) -#endif - size_t Base64::Encode(const void* srcv, size_t length, void* dstv) { const unsigned char* src = static_cast(srcv); unsigned char* dst = static_cast(dstv); From 8e65924dc9c76e7b16f848723e7a993a7e2b4ea8 Mon Sep 17 00:00:00 2001 From: Kevin Lubick Date: Thu, 5 Oct 2023 13:09:55 +0000 Subject: [PATCH 7/8] more tidy --- shell/common/base64.cc | 10 +++++----- shell/common/base64_unittests.cc | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/shell/common/base64.cc b/shell/common/base64.cc index 9f7c98e56aba5..f026f9b8fc2bb 100644 --- a/shell/common/base64.cc +++ b/shell/common/base64.cc @@ -11,12 +11,12 @@ #define DecodePad -2 #define EncodePad 64 -static const char default_encode[] = +static const char kDefaultEncode[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" "0123456789+/="; -static const signed char decodeData[] = { +static const signed char kDecodeData[] = { 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, DecodePad, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, @@ -37,7 +37,7 @@ Base64::Error Base64::Decode(const void* srcv, bool padThree = false; char unsigned const* const end = src + srcLength; while (src < end) { - unsigned char bytes[4]; + unsigned char bytes[4] = {0, 0, 0, 0}; int byte = 0; do { unsigned char srcByte = *src++; @@ -51,7 +51,7 @@ Base64::Error Base64::Decode(const void* srcv, if (srcByte < '+' || srcByte > 'z') { return Error::kBadChar; } - signed char decoded = decodeData[srcByte - '+']; + signed char decoded = kDecodeData[srcByte - '+']; bytes[byte] = decoded; if (decoded != DecodePad) { if (decoded < 0) { @@ -119,7 +119,7 @@ size_t Base64::Encode(const void* srcv, size_t length, void* dstv) { const unsigned char* src = static_cast(srcv); unsigned char* dst = static_cast(dstv); - const char* encode = default_encode; + const char* encode = kDefaultEncode; if (dst) { size_t remainder = length % 3; char unsigned const* const end = &src[length - remainder]; diff --git a/shell/common/base64_unittests.cc b/shell/common/base64_unittests.cc index 5ceef215f9643..633bb9064bc8d 100644 --- a/shell/common/base64_unittests.cc +++ b/shell/common/base64_unittests.cc @@ -13,7 +13,7 @@ namespace flutter { namespace testing { TEST(Base64, EncodeStrings) { - auto test = [](std::string input, std::string output) { + auto test = [](const std::string& input, const std::string& output) { char buffer[256]; size_t len = Base64::Encode(input.c_str(), input.length(), &buffer); FML_CHECK(len <= 256); @@ -30,7 +30,7 @@ TEST(Base64, EncodeStrings) { } TEST(Base64, EncodeBytes) { - auto test = [](const uint8_t input[], size_t num, std::string output) { + auto test = [](const uint8_t input[], size_t num, const std::string& output) { char buffer[512]; size_t len = Base64::Encode(input, num, &buffer); FML_CHECK(len <= 512); @@ -58,7 +58,7 @@ TEST(Base64, EncodeBytes) { } TEST(Base64, DecodeStrings_Success) { - auto test = [](std::string input, std::string output) { + auto test = [](const std::string& input, const std::string& output) { char buffer[256]; size_t len = 0; auto err = Base64::Decode(input.c_str(), input.length(), &buffer, &len); @@ -79,7 +79,7 @@ TEST(Base64, DecodeStrings_Success) { } TEST(Base64, DecodeStrings_Errors) { - auto test = [](std::string input, Base64::Error expectedError) { + auto test = [](const std::string& input, Base64::Error expectedError) { char buffer[256]; size_t len = 0; auto err = Base64::Decode(input.c_str(), input.length(), &buffer, &len); @@ -97,7 +97,7 @@ TEST(Base64, DecodeStrings_Errors) { } TEST(Base64, DecodeBytes) { - auto test = [](std::string input, const uint8_t output[], size_t num) { + auto test = [](const std::string& input, const uint8_t output[], size_t num) { char buffer[256]; size_t len = 0; auto err = Base64::Decode(input.c_str(), input.length(), &buffer, &len); From c58a0c6d7b676ef28a097bb9fa58d5d348bb0ed6 Mon Sep 17 00:00:00 2001 From: Kevin Lubick Date: Thu, 5 Oct 2023 13:45:20 +0000 Subject: [PATCH 8/8] fix test names --- shell/common/base64_unittests.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/shell/common/base64_unittests.cc b/shell/common/base64_unittests.cc index 633bb9064bc8d..89ae026d034c1 100644 --- a/shell/common/base64_unittests.cc +++ b/shell/common/base64_unittests.cc @@ -57,7 +57,7 @@ TEST(Base64, EncodeBytes) { "Hy8/T19vf4+fr7/P3+/w=="); } -TEST(Base64, DecodeStrings_Success) { +TEST(Base64, DecodeStringsSuccess) { auto test = [](const std::string& input, const std::string& output) { char buffer[256]; size_t len = 0; @@ -78,7 +78,7 @@ TEST(Base64, DecodeStrings_Success) { test("Y X Bwb GU=", "apple"); } -TEST(Base64, DecodeStrings_Errors) { +TEST(Base64, DecodeStringsHasErrors) { auto test = [](const std::string& input, Base64::Error expectedError) { char buffer[256]; size_t len = 0;