Add support for the alternative base64 encoding in RFC 4648 section 5 to `WhenBase64Unescaped`.

PiperOrigin-RevId: 507527786
Change-Id: Ie5e088b1814981f6c760d7e25418a430172705ec
diff --git a/docs/reference/matchers.md b/docs/reference/matchers.md
index be96281..243e3f9 100644
--- a/docs/reference/matchers.md
+++ b/docs/reference/matchers.md
@@ -102,7 +102,7 @@
 | `StrCaseNe(string)`      | `argument` is not equal to `string`, ignoring case. |
 | `StrEq(string)`          | `argument` is equal to `string`.                  |
 | `StrNe(string)`          | `argument` is not equal to `string`.              |
-| `WhenBase64Unescaped(m)` | `argument` is a base-64 escaped string whose unescaped string matches `m`. |
+| `WhenBase64Unescaped(m)` | `argument` is a base-64 escaped string whose unescaped string matches `m`.  The web-safe format from [RFC 4648](https://www.rfc-editor.org/rfc/rfc4648#section-5) is supported. |
 
 `ContainsRegex()` and `MatchesRegex()` take ownership of the `RE` object. They
 use the regular expression syntax defined
diff --git a/googlemock/src/gmock-internal-utils.cc b/googlemock/src/gmock-internal-utils.cc
index 7bfff02..31d5565 100644
--- a/googlemock/src/gmock-internal-utils.cc
+++ b/googlemock/src/gmock-internal-utils.cc
@@ -198,6 +198,10 @@
       "the variable in various places.");
 }
 
+constexpr char UndoWebSafeEncoding(char c) {
+  return c == '-' ? '+' : c == '_' ? '/' : c;
+}
+
 constexpr char UnBase64Impl(char c, const char* const base64, char carry) {
   return *base64 == 0 ? static_cast<char>(65)
          : *base64 == c
@@ -208,7 +212,8 @@
 template <size_t... I>
 constexpr std::array<char, 256> UnBase64Impl(IndexSequence<I...>,
                                              const char* const base64) {
-  return {{UnBase64Impl(static_cast<char>(I), base64, 0)...}};
+  return {
+      {UnBase64Impl(UndoWebSafeEncoding(static_cast<char>(I)), base64, 0)...}};
 }
 
 constexpr std::array<char, 256> UnBase64(const char* const base64) {
diff --git a/googlemock/test/gmock-matchers-comparisons_test.cc b/googlemock/test/gmock-matchers-comparisons_test.cc
index 3db9746..0738aaf 100644
--- a/googlemock/test/gmock-matchers-comparisons_test.cc
+++ b/googlemock/test/gmock-matchers-comparisons_test.cc
@@ -1802,11 +1802,13 @@
   EXPECT_FALSE(m1.Matches("invalid base64"));
   EXPECT_FALSE(m1.Matches("aGVsbG8gd29ybGQ="));  // hello world
   EXPECT_TRUE(m1.Matches("aGVsbG8gd29ybGQh"));   // hello world!
+  EXPECT_TRUE(m1.Matches("+/-_IQ"));             // \xfb\xff\xbf!
 
   const Matcher<const std::string&> m2 = WhenBase64Unescaped(EndsWith("!"));
   EXPECT_FALSE(m2.Matches("invalid base64"));
   EXPECT_FALSE(m2.Matches("aGVsbG8gd29ybGQ="));  // hello world
   EXPECT_TRUE(m2.Matches("aGVsbG8gd29ybGQh"));   // hello world!
+  EXPECT_TRUE(m2.Matches("+/-_IQ"));             // \xfb\xff\xbf!
 
 #if GTEST_INTERNAL_HAS_STRING_VIEW
   const Matcher<const internal::StringView&> m3 =
@@ -1814,6 +1816,7 @@
   EXPECT_FALSE(m3.Matches("invalid base64"));
   EXPECT_FALSE(m3.Matches("aGVsbG8gd29ybGQ="));  // hello world
   EXPECT_TRUE(m3.Matches("aGVsbG8gd29ybGQh"));   // hello world!
+  EXPECT_TRUE(m3.Matches("+/-_IQ"));             // \xfb\xff\xbf!
 #endif  // GTEST_INTERNAL_HAS_STRING_VIEW
 }