diff --git a/flow/layers/performance_overlay_layer_unittests.cc b/flow/layers/performance_overlay_layer_unittests.cc index 0c4f7e11d3a2a..7537302d80fe7 100644 --- a/flow/layers/performance_overlay_layer_unittests.cc +++ b/flow/layers/performance_overlay_layer_unittests.cc @@ -111,10 +111,7 @@ static void TestPerformanceOverlayLayerGold(int refresh_rate) { wstream.write(snapshot_data->data(), snapshot_data->size()); wstream.flush(); - // 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::EncodedSize(snapshot_data->size()); 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/base64.cc b/shell/common/base64.cc index f026f9b8fc2bb..3232446705b39 100644 --- a/shell/common/base64.cc +++ b/shell/common/base64.cc @@ -116,42 +116,41 @@ Base64::Error Base64::Decode(const void* srcv, } size_t Base64::Encode(const void* srcv, size_t length, void* dstv) { + FML_DCHECK(dstv); const unsigned char* src = static_cast(srcv); unsigned char* dst = static_cast(dstv); const char* encode = kDefaultEncode; - 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]; + 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 EncodedSize(length); } } // namespace flutter diff --git a/shell/common/base64.h b/shell/common/base64.h index 9e24cea437887..18f8a56dad539 100644 --- a/shell/common/base64.h +++ b/shell/common/base64.h @@ -20,21 +20,27 @@ struct Base64 { /** 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 + @param dst 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); + /** + Returns the length of the buffer that needs to be allocated to encode + srcDataLength bytes. + */ + static size_t EncodedSize(size_t srcDataLength) { + // Take the floor of division by 3 to find the number of groups that need to + // be encoded. Each group takes 4 bytes to be represented in base64. + return ((srcDataLength + 2) / 3) * 4; + } + /** 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. + This can be called once with 'dst' nullptr to get the required size, + then again with an allocated 'dst' pointer to do the actual decoding. @param dst nullptr or a pointer to a buffer large enough to receive the result diff --git a/shell/common/base64_unittests.cc b/shell/common/base64_unittests.cc index 89ae026d034c1..c9b3a04d5e4a1 100644 --- a/shell/common/base64_unittests.cc +++ b/shell/common/base64_unittests.cc @@ -17,6 +17,7 @@ TEST(Base64, EncodeStrings) { char buffer[256]; size_t len = Base64::Encode(input.c_str(), input.length(), &buffer); FML_CHECK(len <= 256); + ASSERT_EQ(len, Base64::EncodedSize(input.length())); std::string actual(buffer, len); ASSERT_STREQ(actual.c_str(), output.c_str()); }; @@ -34,6 +35,7 @@ TEST(Base64, EncodeBytes) { char buffer[512]; size_t len = Base64::Encode(input, num, &buffer); FML_CHECK(len <= 512); + ASSERT_EQ(len, Base64::EncodedSize(num)); std::string actual(buffer, len); ASSERT_STREQ(actual.c_str(), output.c_str()); }; diff --git a/shell/common/rasterizer.cc b/shell/common/rasterizer.cc index 10c6429304ed5..0fc4d884c97bf 100644 --- a/shell/common/rasterizer.cc +++ b/shell/common/rasterizer.cc @@ -910,9 +910,7 @@ Rasterizer::Screenshot Rasterizer::ScreenshotLastLayerTree( } if (base64_encode) { - // 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); + size_t b64_size = Base64::EncodedSize(data->size()); auto b64_data = SkData::MakeUninitialized(b64_size); 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 20fcebeeb7d70..fc006308dec19 100644 --- a/shell/common/shell.cc +++ b/shell/common/shell.cc @@ -1840,10 +1840,7 @@ bool Shell::OnServiceProtocolGetSkSLs( PersistentCache* persistent_cache = PersistentCache::GetCacheForProcess(); std::vector sksls = persistent_cache->LoadSkSLs(); 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::EncodedSize(sksl.value->size()); 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);