[tint][utils] Add DecodeBase64() helper
Translates a character to a base64 decoded byte.
Change-Id: I222bc88dae55d41d7d5564399cde6b903b10dc67
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/162203
Reviewed-by: dan sinclair <dsinclair@chromium.org>
Kokoro: Kokoro <noreply+kokoro@google.com>
Kokoro: Ben Clayton <bclayton@google.com>
diff --git a/src/tint/utils/text/BUILD.bazel b/src/tint/utils/text/BUILD.bazel
index 384af8e..6e4f90d 100644
--- a/src/tint/utils/text/BUILD.bazel
+++ b/src/tint/utils/text/BUILD.bazel
@@ -44,6 +44,7 @@
"unicode.cc",
],
hdrs = [
+ "base64.h",
"string.h",
"string_stream.h",
"unicode.h",
@@ -64,6 +65,7 @@
name = "test",
alwayslink = True,
srcs = [
+ "base64_test.cc",
"string_stream_test.cc",
"string_test.cc",
"unicode_test.cc",
diff --git a/src/tint/utils/text/BUILD.cmake b/src/tint/utils/text/BUILD.cmake
index cd7e6b8..72a1258 100644
--- a/src/tint/utils/text/BUILD.cmake
+++ b/src/tint/utils/text/BUILD.cmake
@@ -39,6 +39,7 @@
# Kind: lib
################################################################################
tint_add_target(tint_utils_text lib
+ utils/text/base64.h
utils/text/string.cc
utils/text/string.h
utils/text/string_stream.cc
@@ -62,6 +63,7 @@
# Kind: test
################################################################################
tint_add_target(tint_utils_text_test test
+ utils/text/base64_test.cc
utils/text/string_stream_test.cc
utils/text/string_test.cc
utils/text/unicode_test.cc
diff --git a/src/tint/utils/text/BUILD.gn b/src/tint/utils/text/BUILD.gn
index df4c510..de1a835 100644
--- a/src/tint/utils/text/BUILD.gn
+++ b/src/tint/utils/text/BUILD.gn
@@ -44,6 +44,7 @@
libtint_source_set("text") {
sources = [
+ "base64.h",
"string.cc",
"string.h",
"string_stream.cc",
@@ -64,6 +65,7 @@
if (tint_build_unittests) {
tint_unittests_source_set("unittests") {
sources = [
+ "base64_test.cc",
"string_stream_test.cc",
"string_test.cc",
"unicode_test.cc",
diff --git a/src/tint/utils/text/base64.h b/src/tint/utils/text/base64.h
new file mode 100644
index 0000000..df5a2d9
--- /dev/null
+++ b/src/tint/utils/text/base64.h
@@ -0,0 +1,61 @@
+// Copyright 2023 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef SRC_TINT_UTILS_TEXT_BASE64_H_
+#define SRC_TINT_UTILS_TEXT_BASE64_H_
+
+#include <cstdint>
+#include <optional>
+
+namespace tint {
+
+/// Decodes a byte from a base64 encoded character
+/// @param c the character to decode
+/// @return the decoded value, or std::nullopt if the character is padding ('=') or an invalid
+/// character.
+inline std::optional<uint8_t> DecodeBase64(char c) {
+ if (c >= 'A' && c <= 'Z') {
+ return static_cast<uint8_t>(c - 'A');
+ }
+ if (c >= 'a' && c <= 'z') {
+ return static_cast<uint8_t>(26 + c - 'a');
+ }
+ if (c >= '0' && c <= '9') {
+ return static_cast<uint8_t>(52 + c - '0');
+ }
+ if (c == '+') {
+ return 62;
+ }
+ if (c == '/') {
+ return 63;
+ }
+ return std::nullopt;
+}
+
+} // namespace tint
+
+#endif // SRC_TINT_UTILS_TEXT_BASE64_H_
diff --git a/src/tint/utils/text/base64_test.cc b/src/tint/utils/text/base64_test.cc
new file mode 100644
index 0000000..b3dc404
--- /dev/null
+++ b/src/tint/utils/text/base64_test.cc
@@ -0,0 +1,133 @@
+// Copyright 2023 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "src/tint/utils/text/base64.h"
+
+#include <optional>
+
+#include "gtest/gtest.h"
+
+namespace tint::utils {
+namespace {
+
+struct Case {
+ char in;
+ std::optional<uint8_t> out;
+};
+
+using DecodeBase64Test = testing::TestWithParam<Case>;
+
+TEST_P(DecodeBase64Test, Char) {
+ EXPECT_EQ(DecodeBase64(GetParam().in), GetParam().out);
+}
+
+INSTANTIATE_TEST_SUITE_P(Valid,
+ DecodeBase64Test,
+ testing::Values(Case{'A', 0},
+ Case{'B', 1},
+ Case{'C', 2},
+ Case{'D', 3},
+ Case{'E', 4},
+ Case{'F', 5},
+ Case{'G', 6},
+ Case{'H', 7},
+ Case{'I', 8},
+ Case{'J', 9},
+ Case{'K', 10},
+ Case{'L', 11},
+ Case{'M', 12},
+ Case{'N', 13},
+ Case{'O', 14},
+ Case{'P', 15},
+ Case{'Q', 16},
+ Case{'R', 17},
+ Case{'S', 18},
+ Case{'T', 19},
+ Case{'U', 20},
+ Case{'V', 21},
+ Case{'W', 22},
+ Case{'X', 23},
+ Case{'Y', 24},
+ Case{'Z', 25},
+ Case{'a', 26},
+ Case{'b', 27},
+ Case{'c', 28},
+ Case{'d', 29},
+ Case{'e', 30},
+ Case{'f', 31},
+ Case{'g', 32},
+ Case{'h', 33},
+ Case{'i', 34},
+ Case{'j', 35},
+ Case{'k', 36},
+ Case{'l', 37},
+ Case{'m', 38},
+ Case{'n', 39},
+ Case{'o', 40},
+ Case{'p', 41},
+ Case{'q', 42},
+ Case{'r', 43},
+ Case{'s', 44},
+ Case{'t', 45},
+ Case{'u', 46},
+ Case{'v', 47},
+ Case{'w', 48},
+ Case{'x', 49},
+ Case{'y', 50},
+ Case{'z', 51},
+ Case{'0', 52},
+ Case{'1', 53},
+ Case{'2', 54},
+ Case{'3', 55},
+ Case{'4', 56},
+ Case{'5', 57},
+ Case{'6', 58},
+ Case{'7', 59},
+ Case{'8', 60},
+ Case{'9', 61},
+ Case{'+', 62},
+ Case{'/', 63}));
+
+INSTANTIATE_TEST_SUITE_P(Invalid,
+ DecodeBase64Test,
+ testing::Values(Case{'@', std::nullopt},
+ Case{'#', std::nullopt},
+ Case{'^', std::nullopt},
+ Case{'&', std::nullopt},
+ Case{'!', std::nullopt},
+ Case{'*', std::nullopt},
+ Case{'(', std::nullopt},
+ Case{')', std::nullopt},
+ Case{'-', std::nullopt},
+ Case{'.', std::nullopt},
+ Case{'\0', std::nullopt},
+ Case{'\n', std::nullopt}));
+
+INSTANTIATE_TEST_SUITE_P(Padding, DecodeBase64Test, testing::Values(Case{'=', std::nullopt}));
+
+} // namespace
+} // namespace tint::utils