File 5261-base64-allow-skipping-padding-characters.patch of Package erlang

From 4f33e446847d7a4d39719e458433ba2b323c7ba4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Micha=C5=82=20Muska=C5=82a?= <micmus@fb.com>
Date: Wed, 18 Jan 2023 22:57:38 +0000
Subject: [PATCH] base64: allow skipping padding = characters

This extends base64 encoding and decoding routines to allow
skipping emitting final = characters, or to accept encoded
data with final = characters skipped. This format is common
for some use-cases. Today, parsing it requires appending
the missing = characters, which incurs an unnecessary copy
of the input data, or re-implementing the entire routine.

This amends the interface in a backwards-incompatible way,
since the last change wasn't released yet, so should have
no expectation of backwards-compatibility.

Additionally, tests are slightly enhanced to cover more cases
directly with simple examples.
---
 lib/stdlib/doc/src/base64.xml                 |  52 +-
 lib/stdlib/src/base64.erl                     | 561 +++++++++++-------
 lib/stdlib/test/base64_SUITE.erl              | 180 ++++--
 lib/stdlib/test/property_test/base64_prop.erl |  28 +-
 4 files changed, 533 insertions(+), 288 deletions(-)

diff --git a/lib/stdlib/doc/src/base64.xml b/lib/stdlib/doc/src/base64.xml
index b58e7394f2..803943c296 100644
--- a/lib/stdlib/doc/src/base64.xml
+++ b/lib/stdlib/doc/src/base64.xml
@@ -47,12 +47,22 @@
     <datatype>
       <name name="base64_mode"/>
       <desc>
-        <p>Selector for the Base 64 Encoding alphabet used for encoding and decoding,
-         see <url href="https://datatracker.ietf.org/doc/html/rfc4648">RFC 4648</url>
+        <p>Selector for the Base 64 Encoding alphabet used for
+	<seemfa marker="#encode/2">encoding</seemfa> and
+	<seemfa marker="#decode/2">decoding</seemfa>.
+         See <url href="https://datatracker.ietf.org/doc/html/rfc4648">RFC 4648</url>
          Sections <url href="https://datatracker.ietf.org/doc/html/rfc4648#section-4">4</url>
          and <url href="https://datatracker.ietf.org/doc/html/rfc4648#section-5">5</url>.</p>
       </desc>
     </datatype>
+    <datatype>
+      <name name="options" />
+      <desc>
+        <p>Customises the behaviour of the encode and decode functions.
+	Default value if omitted entirely or partially is
+        <c>#{mode => standard, padding => true}</c>.</p>
+      </desc>
+    </datatype>
     <datatype>
       <name name="base64_string"/>
       <desc><p>Base 64 encoded string.</p>
@@ -87,6 +97,8 @@
         <p><c>mime_decode/1</c> and <c>mime_decode_to_string/1</c> strip away
           illegal characters, while <c>decode/1</c> and
           <c>decode_to_string/1</c> only strip away whitespace characters.</p>
+        <p>Checks the correct number of <c>=</c> padding characters
+          at the end of the encoded string.</p>
       </desc>
     </func>
 
@@ -97,19 +109,19 @@
       <name name="mime_decode_to_string" arity="2" since="OTP 25.1"/>
       <fsummary>Decode a base64 encoded string to data.</fsummary>
       <type variable="Base64"/>
-      <type variable="Mode" name_i="1"/>
+      <type variable="Options" name_i="1"/>
       <type variable="Data" name_i="1"/>
       <type variable="DataString" name_i="2"/>
       <desc>
         <p>Decodes a base64 string encoded using the alphabet indicated by the
-          <c><anno>Mode</anno></c> parameter to plain ASCII.</p>
+          <c>mode</c> option to plain ASCII.</p>
         <p><c>mime_decode/2</c> and <c>mime_decode_to_string/2</c> strip away
           illegal characters, while <c>decode/2</c> and
           <c>decode_to_string/2</c> only strip away whitespace characters.</p>
-        <p>The <c><anno>Mode</anno></c> parameter can be one of the following:</p>
+        <p>The <c>mode</c> option can be one of the following:</p>
         <taglist>
           <tag><c>standard</c></tag>
-          <item>Decode the given string using the standard base64 alphabet according
+          <item>Default. Decode the given string using the standard base64 alphabet according
             to <url href="https://datatracker.ietf.org/doc/html/rfc4648#section-4">RFC 4648
             Section 4</url>, that is <c>"+"</c> and <c>"/"</c> are representing bytes <c>62</c>
             and <c>63</c> respectively, while <c>"-"</c> and <c>"_"</c> are illegal
@@ -122,6 +134,15 @@
             and <c>63</c> respectively, while <c>"+"</c> and <c>"/"</c> are illegal
             characters.</item>
         </taglist>
+        <p>The <c>padding</c> option can be one of the following:</p>
+        <taglist>
+          <tag><c>true</c></tag>
+          <item>Default. Checks the correct number of <c>=</c> padding characters
+            at the end of the encoded string.</item>
+          <tag><c>false</c></tag>
+          <item>Accepts an encoded string with missing <c>=</c> padding characters
+            at the end.</item>
+        </taglist>
       </desc>
     </func>
 
@@ -136,6 +157,8 @@
         <p>Encodes a plain ASCII string into base64 using the standard alphabet
           according to <url href="https://datatracker.ietf.org/doc/html/rfc4648#section-4">RFC 4648
           Section 4</url>. The result is 33% larger than the data.</p>
+        <p>Always appends correct number of <c>=</c> padding characters
+          to the encoded string.</p>
       </desc>
     </func>
 
@@ -144,16 +167,16 @@
       <name name="encode_to_string" arity="2" since="OTP 25.1"/>
       <fsummary>Encode data into base64.</fsummary>
       <type variable="Data"/>
-      <type variable="Mode"/>
+      <type variable="Options"/>
       <type variable="Base64" name_i="1"/>
       <type variable="Base64String"/>
       <desc>
         <p>Encodes a plain ASCII string into base64 using the alphabet indicated by
-          the <c><anno>Mode</anno></c> parameter. The result is 33% larger than the data.</p>
-        <p>The <c><anno>Mode</anno></c> parameter can be one of the following:</p>
+          the <c>mode</c> option. The result is 33% larger than the data.</p>
+        <p>The <c>mode</c> option can be one of the following:</p>
         <taglist>
           <tag><c>standard</c></tag>
-          <item>Encode the given string using the standard base64 alphabet according
+          <item>Default. Encode the given string using the standard base64 alphabet according
             to <url href="https://datatracker.ietf.org/doc/html/rfc4648#section-4">RFC 4648
             Section 4</url>.</item>
           <tag><c>urlsafe</c></tag>
@@ -162,8 +185,15 @@
             <url href="https://datatracker.ietf.org/doc/html/rfc4648#section-5">RFC 4648
             Section 5</url>.</item>
         </taglist>
+        <p>The <c>padding</c> option can be one of the following:</p>
+        <taglist>
+          <tag><c>true</c></tag>
+          <item>Default. Appends correct number of <c>=</c> padding characters
+            to the encoded string.</item>
+          <tag><c>false</c></tag>
+          <item>Skips appending <c>=</c> padding characters to the encoded string.</item>
+        </taglist>
       </desc>
     </func>
   </funcs>
 </erlref>
-
diff --git a/lib/stdlib/src/base64.erl b/lib/stdlib/src/base64.erl
index eae9527a2d..2e692c254a 100644
--- a/lib/stdlib/src/base64.erl
+++ b/lib/stdlib/src/base64.erl
@@ -26,7 +26,8 @@
 	 mime_decode/1, mime_decode/2,
 	 encode_to_string/1, encode_to_string/2,
 	 decode_to_string/1, decode_to_string/2,
-	 mime_decode_to_string/1, mime_decode_to_string/2]).
+	 mime_decode_to_string/1, mime_decode_to_string/2,
+         format_error/2]).
 
 %% RFC 4648: Base 64 Encoding alphabet
 -type base64_alphabet() :: $A..$Z | $a..$z | $0..$9 | $+ | $/ | $- | $_ | $=.
@@ -35,6 +36,8 @@
 %% Section 4, `urlsafe'  for RFC 4648 Section 5.
 -type base64_mode() :: 'standard' | 'urlsafe'.
 
+-type options() :: #{padding => boolean(), mode => base64_mode()}.
+
 %% The following type is a subtype of string() for return values
 %% of encoding functions.
 -type base64_string() :: [base64_alphabet()].
@@ -48,53 +51,62 @@
       Base64String :: base64_string().
 
 encode_to_string(Data) ->
-    encode_to_string(Data, standard).
+    encode_to_string(Data, #{}).
 
--spec encode_to_string(Data, Mode) -> Base64String when
+-spec encode_to_string(Data, Options) -> Base64String when
       Data :: byte_string() | binary(),
-      Mode :: base64_mode(),
+      Options :: options(),
       Base64String :: base64_string().
 
-encode_to_string(Bin, Mode) when is_binary(Bin) ->
-    encode_to_string(binary_to_list(Bin), Mode);
-encode_to_string(List, Mode) when is_list(List) ->
-    encode_list_to_string(get_encoding_offset(Mode), List).
+encode_to_string(Bin, Options) when is_binary(Bin), is_map(Options) ->
+    encode_to_string(binary_to_list(Bin), Options);
+encode_to_string(List, Options) when is_list(List), is_map(Options) ->
+    encode_list_to_string(get_encoding_offset(Options), get_padding(Options), List).
 
 -spec encode(Data) -> Base64 when
       Data :: byte_string() | binary(),
       Base64 :: base64_binary().
 
 encode(Data) ->
-    encode(Data, standard).
+    encode(Data, #{}).
 
--spec encode(Data, Mode) -> Base64 when
+-spec encode(Data, Options) -> Base64 when
       Data :: byte_string() | binary(),
-      Mode :: base64_mode(),
+      Options :: options(),
       Base64 :: base64_binary().
 
-encode(Bin, Mode) when is_binary(Bin) ->
-    encode_binary(get_encoding_offset(Mode), Bin, <<>>);
-encode(List, Mode) when is_list(List) ->
-    encode_list(get_encoding_offset(Mode), List, <<>>).
+encode(Bin, Options) when is_binary(Bin), is_map(Options) ->
+    encode_binary(get_encoding_offset(Options), get_padding(Options), Bin, <<>>);
+encode(List, Options) when is_list(List) ->
+    encode_list(get_encoding_offset(Options), get_padding(Options), List, <<>>).
 
-encode_list_to_string(_ModeOffset, []) ->
+encode_list_to_string(_ModeOffset, _Padding, []) ->
     [];
-encode_list_to_string(ModeOffset, [B1]) ->
+encode_list_to_string(ModeOffset, Padding, [B1]) ->
     [b64e(B1 bsr 2, ModeOffset),
-     b64e((B1 band 3) bsl 4, ModeOffset), $=, $=];
-encode_list_to_string(ModeOffset, [B1,B2]) ->
+     b64e((B1 band 3) bsl 4, ModeOffset) |
+     case Padding of
+         true -> "==";
+         false -> ""
+     end];
+encode_list_to_string(ModeOffset, Padding, [B1,B2]) ->
     [b64e(B1 bsr 2, ModeOffset),
      b64e(((B1 band 3) bsl 4) bor (B2 bsr 4), ModeOffset),
-     b64e((B2 band 15) bsl 2, ModeOffset), $=];
-encode_list_to_string(ModeOffset, [B1,B2,B3|Ls]) ->
+     b64e((B2 band 15) bsl 2, ModeOffset) |
+     case Padding of
+         true -> "=";
+         false -> ""
+     end];
+encode_list_to_string(ModeOffset, Padding, [B1,B2,B3|Ls]) ->
     BB = (B1 bsl 16) bor (B2 bsl 8) bor B3,
     [b64e(BB bsr 18, ModeOffset),
-     b64e((BB bsr 12) band 63, ModeOffset), 
+     b64e((BB bsr 12) band 63, ModeOffset),
      b64e((BB bsr 6) band 63, ModeOffset),
-     b64e(BB band 63, ModeOffset) | encode_list_to_string(ModeOffset, Ls)].
+     b64e(BB band 63, ModeOffset) | encode_list_to_string(ModeOffset, Padding, Ls)].
 
-encode_binary(ModeOffset, <<B1:6, B2:6, B3:6, B4:6, B5:6, B6:6, B7:6, B8:6, Ls/bits>>, A) ->
+encode_binary(ModeOffset, Padding, <<B1:6, B2:6, B3:6, B4:6, B5:6, B6:6, B7:6, B8:6, Ls/bits>>, A) ->
     encode_binary(ModeOffset,
+                  Padding,
                   Ls,
                   <<A/bits,
                     (b64e(B1, ModeOffset)):8,
@@ -105,33 +117,55 @@ encode_binary(ModeOffset, <<B1:6, B2:6, B3:6, B4:6, B5:6, B6:6, B7:6, B8:6, Ls/b
                     (b64e(B6, ModeOffset)):8,
                     (b64e(B7, ModeOffset)):8,
                     (b64e(B8, ModeOffset)):8>>);
-encode_binary(_ModeOffset, <<>>, A) ->
+encode_binary(_ModeOffset, _Padding, <<>>, A) ->
     A;
-encode_binary(ModeOffset, <<B1:6, B2:6, B3:6, B4:6, Ls/bits>>, A) ->
+encode_binary(ModeOffset, Padding, <<B1:6, B2:6, B3:6, B4:6, Ls/bits>>, A) ->
     encode_binary(ModeOffset,
-		  Ls,
+                  Padding,
+                  Ls,
                   <<A/bits,
                     (b64e(B1, ModeOffset)):8,
                     (b64e(B2, ModeOffset)):8,
                     (b64e(B3, ModeOffset)):8,
                     (b64e(B4, ModeOffset)):8>>);
-encode_binary(ModeOffset, <<B1:6, B2:2>>, A) ->
-    <<A/bits,(b64e(B1, ModeOffset)):8,(b64e(B2 bsl 4, ModeOffset)):8,$=:8,$=:8>>;
-encode_binary(ModeOffset, <<B1:6, B2:6, B3:4>>, A) ->
-    <<A/bits,(b64e(B1, ModeOffset)):8,(b64e(B2, ModeOffset)):8,(b64e(B3 bsl 2, ModeOffset)):8, $=:8>>.
+encode_binary(ModeOffset, Padding, <<B1:6, B2:2>>, A) ->
+    E1 = b64e(B1, ModeOffset),
+    E2 = b64e(B2 bsl 4, ModeOffset),
+    case Padding of
+        true -> <<A/bits,E1,E2,$=,$=>>;
+        _ -> <<A/bits,E1,E2>>
+    end;
+encode_binary(ModeOffset, Padding, <<B1:6, B2:6, B3:4>>, A) ->
+    E1 = b64e(B1, ModeOffset),
+    E2 = b64e(B2, ModeOffset),
+    E3 = b64e(B3 bsl 2, ModeOffset),
+    case Padding of
+        true -> <<A/bits,E1,E2,E3,$=>>;
+        _ -> <<A/bits,E1,E2,E3>>
+    end.
 
-encode_list(_ModeOffset, [], A) ->
+encode_list(_ModeOffset, _Padding, [], A) ->
     A;
-encode_list(ModeOffset, [B1], A) ->
-    <<A/bits,(b64e(B1 bsr 2, ModeOffset)):8,(b64e((B1 band 3) bsl 4, ModeOffset)):8,$=:8,$=:8>>;
-encode_list(ModeOffset, [B1,B2], A) ->
-    <<A/bits,(b64e(B1 bsr 2, ModeOffset)):8,
-      (b64e(((B1 band 3) bsl 4) bor (B2 bsr 4), ModeOffset)):8,
-      (b64e((B2 band 15) bsl 2, ModeOffset)):8, $=:8>>;
-encode_list(ModeOffset, [B1,B2,B3|Ls], A) ->
+encode_list(ModeOffset, Padding, [B1], A) ->
+    E1 = b64e(B1 bsr 2, ModeOffset),
+    E2 = b64e((B1 band 3) bsl 4, ModeOffset),
+    case Padding of
+        true -> <<A/bits,E1,E2,$=,$=>>;
+        false -> <<A/bits,E1,E2>>
+    end;
+encode_list(ModeOffset, Padding, [B1,B2], A) ->
+    E1 = b64e(B1 bsr 2, ModeOffset),
+    E2 = b64e(((B1 band 3) bsl 4) bor (B2 bsr 4), ModeOffset),
+    E3 = b64e((B2 band 15) bsl 2, ModeOffset),
+    case Padding of
+        true -> <<A/bits,E1,E2,E3,$=>>;
+        false -> <<A/bits,E1,E2,E3>>
+    end;
+encode_list(ModeOffset, Padding, [B1,B2,B3|Ls], A) ->
     BB = (B1 bsl 16) bor (B2 bsl 8) bor B3,
     encode_list(ModeOffset,
-		Ls,
+                Padding,
+                Ls,
                 <<A/bits,(b64e(BB bsr 18, ModeOffset)):8,
                   (b64e((BB bsr 12) band 63, ModeOffset)):8,
                   (b64e((BB bsr 6) band 63, ModeOffset)):8,
@@ -145,34 +179,34 @@ encode_list(ModeOffset, [B1,B2,B3|Ls], A) ->
       Data :: binary().
 
 decode(Base64) ->
-    decode(Base64, standard).
+    decode(Base64, #{}).
 
--spec decode(Base64, Mode) -> Data when
+-spec decode(Base64, Options) -> Data when
       Base64 :: base64_string() | base64_binary(),
-      Mode :: base64_mode(),
+      Options :: options(),
       Data :: binary().
 
-decode(Bin, Mode) when is_binary(Bin) ->
-    decode_binary(get_decoding_offset(Mode), Bin, <<>>);
-decode(List, Mode) when is_list(List) ->
-    decode_list(get_decoding_offset(Mode), List, <<>>).
+decode(Bin, Options) when is_binary(Bin) ->
+    decode_binary(get_decoding_offset(Options), get_padding(Options), Bin, <<>>);
+decode(List, Options) when is_list(List) ->
+    decode_list(get_decoding_offset(Options), get_padding(Options), List, <<>>).
 
 -spec mime_decode(Base64) -> Data when
       Base64 :: base64_string() | base64_binary(),
       Data :: binary().
 
 mime_decode(Base64) ->
-    mime_decode(Base64, standard).
+    mime_decode(Base64, #{}).
 
--spec mime_decode(Base64, Mode) -> Data when
+-spec mime_decode(Base64, Options) -> Data when
       Base64 :: base64_string() | base64_binary(),
-      Mode :: base64_mode(),
+      Options :: options(),
       Data :: binary().
 
-mime_decode(Bin, Mode) when is_binary(Bin) ->
-    mime_decode_binary(get_decoding_offset(Mode), Bin, <<>>);
-mime_decode(List, Mode) when is_list(List) ->
-    mime_decode_list(get_decoding_offset(Mode), List, <<>>).
+mime_decode(Bin, Options) when is_binary(Bin) ->
+    mime_decode_binary(get_decoding_offset(Options), get_padding(Options), Bin, <<>>);
+mime_decode(List, Options) when is_list(List) ->
+    mime_decode_list(get_decoding_offset(Options), get_padding(Options), List, <<>>).
 
 %% mime_decode_to_string strips away all characters not Base64 before
 %% converting, whereas decode_to_string crashes if an illegal
@@ -183,347 +217,428 @@ mime_decode(List, Mode) when is_list(List) ->
       DataString :: byte_string().
 
 decode_to_string(Base64) ->
-    decode_to_string(Base64, standard).
+    decode_to_string(Base64, #{}).
 
--spec decode_to_string(Base64, Mode) -> DataString when
+-spec decode_to_string(Base64, Options) -> DataString when
       Base64 :: base64_string() | base64_binary(),
-      Mode :: base64_mode(),
+      Options :: options(),
       DataString :: byte_string().
 
-decode_to_string(Bin, Mode) when is_binary(Bin) ->
-    decode_to_string(binary_to_list(Bin), Mode);
-decode_to_string(List, Mode) when is_list(List) ->
-    decode_list_to_string(get_decoding_offset(Mode), List).
+decode_to_string(Bin, Options) when is_binary(Bin) ->
+    decode_to_string(binary_to_list(Bin), Options);
+decode_to_string(List, Options) when is_list(List) ->
+    decode_list_to_string(get_decoding_offset(Options), get_padding(Options), List).
 
 -spec mime_decode_to_string(Base64) -> DataString when
       Base64 :: base64_string() | base64_binary(),
       DataString :: byte_string().
 
 mime_decode_to_string(Base64) ->
-    mime_decode_to_string(Base64, standard).
+    mime_decode_to_string(Base64, #{}).
 
--spec mime_decode_to_string(Base64, Mode) -> DataString when
+-spec mime_decode_to_string(Base64, Options) -> DataString when
       Base64 :: base64_string() | base64_binary(),
-      Mode :: base64_mode(),
+      Options :: options(),
       DataString :: byte_string().
 
-mime_decode_to_string(Bin, Mode) when is_binary(Bin) ->
-    mime_decode_to_string(binary_to_list(Bin), Mode);
-mime_decode_to_string(List, Mode) when is_list(List) ->
-    mime_decode_list_to_string(get_decoding_offset(Mode), List).
+mime_decode_to_string(Bin, Options) when is_binary(Bin) ->
+    mime_decode_to_string(binary_to_list(Bin), Options);
+mime_decode_to_string(List, Options) when is_list(List) ->
+    mime_decode_list_to_string(get_decoding_offset(Options), get_padding(Options), List).
 
 %% Skipping pad character if not at end of string. Also liberal about
 %% excess padding and skipping of other illegal (non-base64 alphabet)
 %% characters. See section 3.3 of RFC4648
-mime_decode_list(ModeOffset, [C1 | Cs], A) ->
+mime_decode_list(ModeOffset, Padding, [C1 | Cs], A) ->
     case b64d(C1, ModeOffset) of
-        B1 when is_integer(B1) -> mime_decode_list(ModeOffset, Cs, A, B1);
-        _ -> mime_decode_list(ModeOffset, Cs, A)  % eq is padding
+        B1 when is_integer(B1) -> mime_decode_list(ModeOffset, Padding, Cs, A, B1);
+        _ -> mime_decode_list(ModeOffset, Padding, Cs, A)  % eq is padding
     end;
-mime_decode_list(_ModeOffset, [], A) ->
+mime_decode_list(_ModeOffset, _Padding, [], A) ->
     A.
 
-mime_decode_list(ModeOffset, [C2 | Cs], A, B1) ->
+mime_decode_list(ModeOffset, Padding, [C2 | Cs], A, B1) ->
     case b64d(C2, ModeOffset) of
         B2 when is_integer(B2) ->
-            mime_decode_list(ModeOffset, Cs, A, B1, B2);
-        _ -> mime_decode_list(ModeOffset, Cs, A, B1) % eq is padding
+            mime_decode_list(ModeOffset, Padding, Cs, A, B1, B2);
+        _ -> mime_decode_list(ModeOffset, Padding, Cs, A, B1) % eq is padding
     end.
 
-mime_decode_list(ModeOffset, [C3 | Cs], A, B1, B2) ->
+mime_decode_list(ModeOffset, Padding, [C3 | Cs], A, B1, B2) ->
     case b64d(C3, ModeOffset) of
         B3 when is_integer(B3) ->
-            mime_decode_list(ModeOffset, Cs, A, B1, B2, B3);
+            mime_decode_list(ModeOffset, Padding, Cs, A, B1, B2, B3);
         eq=B3 ->
-            mime_decode_list_after_eq(ModeOffset, Cs, A, B1, B2, B3);
-        _ -> mime_decode_list(ModeOffset, Cs, A, B1, B2)
+            mime_decode_list_after_eq(ModeOffset, Padding, Cs, A, B1, B2, B3);
+        _ -> mime_decode_list(ModeOffset, Padding, Cs, A, B1, B2)
+    end;
+mime_decode_list(ModeOffset, Padding, [], A, B1, B2) ->
+    case Padding of
+        true -> missing_padding_error();
+        false -> mime_decode_list_after_eq(ModeOffset, Padding, [], A, B1, B2, eq)
     end.
 
-mime_decode_list(ModeOffset, [C4 | Cs], A, B1, B2, B3) ->
+mime_decode_list(ModeOffset, Padding, [C4 | Cs], A, B1, B2, B3) ->
     case b64d(C4, ModeOffset) of
         B4 when is_integer(B4) ->
-            mime_decode_list(ModeOffset, Cs, <<A/bits,B1:6,B2:6,B3:6,B4:6>>);
+            mime_decode_list(ModeOffset, Padding, Cs, <<A/bits,B1:6,B2:6,B3:6,B4:6>>);
         eq ->
-            mime_decode_list_after_eq(ModeOffset, Cs, A, B1, B2, B3);
-        _ -> mime_decode_list(ModeOffset, Cs, A, B1, B2, B3)
+            mime_decode_list_after_eq(ModeOffset, Padding, Cs, A, B1, B2, B3);
+        _ -> mime_decode_list(ModeOffset, Padding, Cs, A, B1, B2, B3)
+    end;
+mime_decode_list(ModeOffset, Padding, [], A, B1, B2, B3) ->
+    case Padding of
+        true -> missing_padding_error();
+        false -> mime_decode_list_after_eq(ModeOffset, Padding, [], A, B1, B2, B3)
     end.
 
-mime_decode_list_after_eq(ModeOffset, [C | Cs], A, B1, B2, B3) ->
+mime_decode_list_after_eq(ModeOffset, Padding, [C | Cs], A, B1, B2, B3) ->
     case b64d(C, ModeOffset) of
         B when is_integer(B) ->
             %% More valid data, skip the eq as invalid
             case B3 of
-                eq -> mime_decode_list(ModeOffset, Cs, A, B1, B2, B);
-                _ -> mime_decode_list(ModeOffset, Cs, <<A/bits,B1:6,B2:6,B3:6,B:6>>)
+                eq -> mime_decode_list(ModeOffset, Padding, Cs, A, B1, B2, B);
+                _ -> mime_decode_list(ModeOffset, Padding, Cs, <<A/bits,B1:6,B2:6,B3:6,B:6>>)
             end;
-        _ -> mime_decode_list_after_eq(ModeOffset, Cs, A, B1, B2, B3)
+        _ -> mime_decode_list_after_eq(ModeOffset, Padding, Cs, A, B1, B2, B3)
     end;
-mime_decode_list_after_eq(_ModeOffset, [], A, B1, B2, eq) ->
+mime_decode_list_after_eq(_ModeOffset, _Padding, [], A, B1, B2, eq) ->
     <<A/bits,B1:6,(B2 bsr 4):2>>;
-mime_decode_list_after_eq(_ModeOffset, [], A, B1, B2, B3) ->
+mime_decode_list_after_eq(_ModeOffset, _Padding, [], A, B1, B2, B3) ->
     <<A/bits,B1:6,B2:6,(B3 bsr 2):4>>.
 
-mime_decode_binary(ModeOffset, <<C1:8, Cs/bits>>, A) ->
+mime_decode_binary(ModeOffset, Padding, <<C1:8, Cs/bits>>, A) ->
     case b64d(C1, ModeOffset) of
-        B1 when is_integer(B1) -> mime_decode_binary(ModeOffset, Cs, A, B1);
-        _ -> mime_decode_binary(ModeOffset, Cs, A)  % eq is padding
+        B1 when is_integer(B1) -> mime_decode_binary(ModeOffset, Padding, Cs, A, B1);
+        _ -> mime_decode_binary(ModeOffset, Padding, Cs, A)  % eq is padding
     end;
-mime_decode_binary(_ModeOffset, <<>>, A) ->
+mime_decode_binary(_ModeOffset, _Padding, <<>>, A) ->
     A.
 
-mime_decode_binary(ModeOffset, <<C2:8, Cs/bits>>, A, B1) ->
+mime_decode_binary(ModeOffset, Padding, <<C2:8, Cs/bits>>, A, B1) ->
     case b64d(C2, ModeOffset) of
         B2 when is_integer(B2) ->
-            mime_decode_binary(ModeOffset, Cs, A, B1, B2);
-        _ -> mime_decode_binary(ModeOffset, Cs, A, B1) % eq is padding
+            mime_decode_binary(ModeOffset, Padding, Cs, A, B1, B2);
+        _ -> mime_decode_binary(ModeOffset, Padding, Cs, A, B1) % eq is padding
     end.
 
-mime_decode_binary(ModeOffset, <<C3:8, Cs/bits>>, A, B1, B2) ->
+mime_decode_binary(ModeOffset, Padding, <<C3:8, Cs/bits>>, A, B1, B2) ->
     case b64d(C3, ModeOffset) of
         B3 when is_integer(B3) ->
-            mime_decode_binary(ModeOffset, Cs, A, B1, B2, B3);
+            mime_decode_binary(ModeOffset, Padding, Cs, A, B1, B2, B3);
         eq=B3 ->
-            mime_decode_binary_after_eq(ModeOffset, Cs, A, B1, B2, B3);
-        _ -> mime_decode_binary(ModeOffset, Cs, A, B1, B2)
+            mime_decode_binary_after_eq(ModeOffset, Padding, Cs, A, B1, B2, B3);
+        _ -> mime_decode_binary(ModeOffset, Padding, Cs, A, B1, B2)
+    end;
+mime_decode_binary(ModeOffset, Padding, <<Cs/bits>>, A, B1, B2) ->
+    case Padding of
+        true -> missing_padding_error();
+        false -> mime_decode_binary_after_eq(ModeOffset, Padding, Cs, A, B1, B2, eq)
     end.
 
-mime_decode_binary(ModeOffset, <<C4:8, Cs/bits>>, A, B1, B2, B3) ->
+mime_decode_binary(ModeOffset, Padding, <<C4:8, Cs/bits>>, A, B1, B2, B3) ->
     case b64d(C4, ModeOffset) of
         B4 when is_integer(B4) ->
-            mime_decode_binary(ModeOffset, Cs, <<A/bits,B1:6,B2:6,B3:6,B4:6>>);
+            mime_decode_binary(ModeOffset, Padding, Cs, <<A/bits,B1:6,B2:6,B3:6,B4:6>>);
         eq ->
-            mime_decode_binary_after_eq(ModeOffset, Cs, A, B1, B2, B3);
-        _ -> mime_decode_binary(ModeOffset, Cs, A, B1, B2, B3)
+            mime_decode_binary_after_eq(ModeOffset, Padding, Cs, A, B1, B2, B3);
+        _ -> mime_decode_binary(ModeOffset, Padding, Cs, A, B1, B2, B3)
+    end;
+mime_decode_binary(ModeOffset, Padding, <<Cs/bits>>, A, B1, B2, B3) ->
+    case Padding of
+        true -> missing_padding_error();
+        false -> mime_decode_binary_after_eq(ModeOffset, Padding, Cs, A, B1, B2, B3)
     end.
 
-mime_decode_binary_after_eq(ModeOffset, <<C:8, Cs/bits>>, A, B1, B2, B3) ->
+mime_decode_binary_after_eq(ModeOffset, Padding, <<C:8, Cs/bits>>, A, B1, B2, B3) ->
     case b64d(C, ModeOffset) of
         B when is_integer(B) ->
             %% More valid data, skip the eq as invalid
             case B3 of
-                eq -> mime_decode_binary(ModeOffset, Cs, A, B1, B2, B);
-                _ -> mime_decode_binary(ModeOffset, Cs, <<A/bits,B1:6,B2:6,B3:6,B:6>>)
+                eq -> mime_decode_binary(ModeOffset, Padding, Cs, A, B1, B2, B);
+                _ -> mime_decode_binary(ModeOffset, Padding, Cs, <<A/bits,B1:6,B2:6,B3:6,B:6>>)
             end;
-        _ -> mime_decode_binary_after_eq(ModeOffset, Cs, A, B1, B2, B3)
+        _ -> mime_decode_binary_after_eq(ModeOffset, Padding, Cs, A, B1, B2, B3)
     end;
-mime_decode_binary_after_eq(_ModeOffset, <<>>, A, B1, B2, eq) ->
+mime_decode_binary_after_eq(_ModeOffset, _Padding, <<>>, A, B1, B2, eq) ->
     <<A/bits,B1:6,(B2 bsr 4):2>>;
-mime_decode_binary_after_eq(_ModeOffset, <<>>, A, B1, B2, B3) ->
+mime_decode_binary_after_eq(_ModeOffset, _Padding, <<>>, A, B1, B2, B3) ->
     <<A/bits,B1:6,B2:6,(B3 bsr 2):4>>.
 
-mime_decode_list_to_string(ModeOffset, [C1 | Cs]) ->
+mime_decode_list_to_string(ModeOffset, Padding, [C1 | Cs]) ->
     case b64d(C1, ModeOffset) of
-        B1 when is_integer(B1) -> mime_decode_list_to_string(ModeOffset, Cs, B1);
-        _ -> mime_decode_list_to_string(ModeOffset, Cs) % eq is padding
+        B1 when is_integer(B1) -> mime_decode_list_to_string(ModeOffset, Padding, Cs, B1);
+        _ -> mime_decode_list_to_string(ModeOffset, Padding, Cs) % eq is padding
     end;
-mime_decode_list_to_string(_ModeOffset, []) ->
+mime_decode_list_to_string(_ModeOffset, _Padding, []) ->
     [].
 
-mime_decode_list_to_string(ModeOffset, [C2 | Cs], B1) ->
+mime_decode_list_to_string(ModeOffset, Padding, [C2 | Cs], B1) ->
     case b64d(C2, ModeOffset) of
         B2 when is_integer(B2) ->
-            mime_decode_list_to_string(ModeOffset, Cs, B1, B2);
-        _ -> mime_decode_list_to_string(ModeOffset, Cs, B1) % eq is padding
+            mime_decode_list_to_string(ModeOffset, Padding, Cs, B1, B2);
+        _ -> mime_decode_list_to_string(ModeOffset, Padding, Cs, B1) % eq is padding
     end.
 
-mime_decode_list_to_string(ModeOffset, [C3 | Cs], B1, B2) ->
+mime_decode_list_to_string(ModeOffset, Padding, [C3 | Cs], B1, B2) ->
     case b64d(C3, ModeOffset) of
         B3 when is_integer(B3) ->
-            mime_decode_list_to_string(ModeOffset, Cs, B1, B2, B3);
-        eq=B3 -> mime_decode_list_to_string_after_eq(ModeOffset, Cs, B1, B2, B3);
-        _ -> mime_decode_list_to_string(ModeOffset, Cs, B1, B2)
+            mime_decode_list_to_string(ModeOffset, Padding, Cs, B1, B2, B3);
+        eq=B3 -> mime_decode_list_to_string_after_eq(ModeOffset, Padding, Cs, B1, B2, B3);
+        _ -> mime_decode_list_to_string(ModeOffset, Padding, Cs, B1, B2)
+    end;
+mime_decode_list_to_string(ModeOffset, Padding, [], B1, B2) ->
+    case Padding of
+        true -> missing_padding_error();
+        false -> mime_decode_list_to_string_after_eq(ModeOffset, Padding, [], B1, B2, eq)
     end.
 
-mime_decode_list_to_string(ModeOffset, [C4 | Cs], B1, B2, B3) ->
+mime_decode_list_to_string(ModeOffset, Padding, [C4 | Cs], B1, B2, B3) ->
     case b64d(C4, ModeOffset) of
         B4 when is_integer(B4) ->
             Bits4x6 = (B1 bsl 18) bor (B2 bsl 12) bor (B3 bsl 6) bor B4,
             Octet1 = Bits4x6 bsr 16,
             Octet2 = (Bits4x6 bsr 8) band 16#ff,
             Octet3 = Bits4x6 band 16#ff,
-            [Octet1, Octet2, Octet3 | mime_decode_list_to_string(ModeOffset, Cs)];
+            [Octet1, Octet2, Octet3 | mime_decode_list_to_string(ModeOffset, Padding, Cs)];
         eq ->
-            mime_decode_list_to_string_after_eq(ModeOffset, Cs, B1, B2, B3);
-        _ -> mime_decode_list_to_string(ModeOffset, Cs, B1, B2, B3)
+            mime_decode_list_to_string_after_eq(ModeOffset, Padding, Cs, B1, B2, B3);
+        _ -> mime_decode_list_to_string(ModeOffset, Padding, Cs, B1, B2, B3)
+    end;
+mime_decode_list_to_string(ModeOffset, Padding, [], B1, B2, B3) ->
+    case Padding of
+        true -> missing_padding_error();
+        false -> mime_decode_list_to_string_after_eq(ModeOffset, Padding, [], B1, B2, B3)
     end.
 
-mime_decode_list_to_string_after_eq(ModeOffset, [C | Cs], B1, B2, B3) ->
+mime_decode_list_to_string_after_eq(ModeOffset, Padding, [C | Cs], B1, B2, B3) ->
     case b64d(C, ModeOffset) of
         B when is_integer(B) ->
             %% More valid data, skip the eq as invalid
             case B3 of
-                eq -> mime_decode_list_to_string(ModeOffset, Cs, B1, B2, B);
+                eq -> mime_decode_list_to_string(ModeOffset, Padding, Cs, B1, B2, B);
                 _ ->
                     Bits4x6 = (B1 bsl 18) bor (B2 bsl 12) bor (B3 bsl 6) bor B,
                     Octet1 = Bits4x6 bsr 16,
                     Octet2 = (Bits4x6 bsr 8) band 16#ff,
                     Octet3 = Bits4x6 band 16#ff,
-                    [Octet1, Octet2, Octet3 | mime_decode_list_to_string(ModeOffset, Cs)]
+                    [Octet1, Octet2, Octet3 | mime_decode_list_to_string(ModeOffset, Padding, Cs)]
             end;
-        _ -> mime_decode_list_to_string_after_eq(ModeOffset, Cs, B1, B2, B3)
+        _ -> mime_decode_list_to_string_after_eq(ModeOffset, Padding, Cs, B1, B2, B3)
     end;
-mime_decode_list_to_string_after_eq(_ModeOffset, [], B1, B2, eq) ->
+mime_decode_list_to_string_after_eq(_ModeOffset, _Padding, [], B1, B2, eq) ->
     binary_to_list(<<B1:6,(B2 bsr 4):2>>);
-mime_decode_list_to_string_after_eq(_ModeOffset, [], B1, B2, B3) ->
+mime_decode_list_to_string_after_eq(_ModeOffset, _Padding, [], B1, B2, B3) ->
     binary_to_list(<<B1:6,B2:6,(B3 bsr 2):4>>).
 
-decode_list(ModeOffset, [C1 | Cs], A) ->
+decode_list(ModeOffset, Padding, [C1 | Cs], A) ->
     case b64d(C1, ModeOffset) of
-        ws -> decode_list(ModeOffset, Cs, A);
-        B1 -> decode_list(ModeOffset, Cs, A, B1)
+        ws -> decode_list(ModeOffset, Padding, Cs, A);
+        B1 -> decode_list(ModeOffset, Padding, Cs, A, B1)
     end;
-decode_list(_ModeOffset, [], A) ->
+decode_list(_ModeOffset, _Padding, [], A) ->
     A.
 
-decode_list(ModeOffset, [C2 | Cs], A, B1) ->
+decode_list(ModeOffset, Padding, [C2 | Cs], A, B1) ->
     case b64d(C2, ModeOffset) of
-        ws -> decode_list(ModeOffset, Cs, A, B1);
-        B2 -> decode_list(ModeOffset, Cs, A, B1, B2)
+        ws -> decode_list(ModeOffset, Padding, Cs, A, B1);
+        B2 -> decode_list(ModeOffset, Padding, Cs, A, B1, B2)
     end.
 
-decode_list(ModeOffset, [C3 | Cs], A, B1, B2) ->
+decode_list(ModeOffset, Padding, [C3 | Cs], A, B1, B2) ->
     case b64d(C3, ModeOffset) of
-        ws -> decode_list(ModeOffset, Cs, A, B1, B2);
-        B3 -> decode_list(ModeOffset, Cs, A, B1, B2, B3)
+        ws -> decode_list(ModeOffset, Padding, Cs, A, B1, B2);
+        B3 -> decode_list(ModeOffset, Padding, Cs, A, B1, B2, B3)
+    end;
+decode_list(ModeOffset, Padding, [], A, B1, B2) ->
+    case Padding of
+        true -> missing_padding_error();
+        false -> decode_list(ModeOffset, Padding, [], A, B1, B2, eq)
     end.
 
-decode_list(ModeOffset, [C4 | Cs], A, B1, B2, B3) ->
+decode_list(ModeOffset, Padding, [C4 | Cs], A, B1, B2, B3) ->
     case b64d(C4, ModeOffset) of
-        ws                -> decode_list(ModeOffset, Cs, A, B1, B2, B3);
-        eq when B3 =:= eq -> only_ws(ModeOffset, Cs, <<A/bits,B1:6,(B2 bsr 4):2>>);
-        eq                -> only_ws(ModeOffset, Cs, <<A/bits,B1:6,B2:6,(B3 bsr 2):4>>);
-        B4                -> decode_list(ModeOffset, Cs, <<A/bits,B1:6,B2:6,B3:6,B4:6>>)
+        ws                -> decode_list(ModeOffset, Padding, Cs, A, B1, B2, B3);
+        eq when B3 =:= eq -> only_ws(ModeOffset, Padding, Cs, <<A/bits,B1:6,(B2 bsr 4):2>>);
+        eq                -> only_ws(ModeOffset, Padding, Cs, <<A/bits,B1:6,B2:6,(B3 bsr 2):4>>);
+        B4                -> decode_list(ModeOffset, Padding, Cs, <<A/bits,B1:6,B2:6,B3:6,B4:6>>)
+    end;
+decode_list(_ModeOffset, Padding, [], A, B1, B2, B3) ->
+    case Padding of
+        true -> missing_padding_error();
+        false when B3 == eq -> <<A/bits,B1:6,(B2 bsr 4):2>>;
+        false -> <<A/bits,B1:6,B2:6,(B3 bsr 2):4>>
     end.
 
-decode_binary(ModeOffset, <<C1:8, C2:8, C3:8, C4:8, Cs/bits>>, A) ->
+decode_binary(ModeOffset, Padding, <<C1:8, C2:8, C3:8, C4:8, Cs/bits>>, A) ->
     case {b64d(C1, ModeOffset), b64d(C2, ModeOffset), b64d(C3, ModeOffset), b64d(C4, ModeOffset)} of
         {B1, B2, B3, B4} when is_integer(B1), is_integer(B2),
                               is_integer(B3), is_integer(B4) ->
-            decode_binary(ModeOffset, Cs, <<A/bits,B1:6,B2:6,B3:6,B4:6>>);
+            decode_binary(ModeOffset, Padding, Cs, <<A/bits,B1:6,B2:6,B3:6,B4:6>>);
         {B1, B2, B3, B4} ->
-            dec_bin(ModeOffset, Cs, B1, B2, B3, B4, A)
+            dec_bin(ModeOffset, Padding, Cs, B1, B2, B3, B4, A)
     end;
-decode_binary(_ModeOffset, <<>>, A) ->
+decode_binary(_ModeOffset, _Padding, <<>>, A) ->
     A;
-decode_binary(ModeOffset, <<C1:8, Cs/bits>>, A) ->
+decode_binary(ModeOffset, Padding, <<C1:8, Cs/bits>>, A) ->
     case b64d(C1, ModeOffset) of
-        ws -> decode_binary(ModeOffset, Cs, A);
-        B1 -> decode_binary(ModeOffset, Cs, A, B1)
+        ws -> decode_binary(ModeOffset, Padding, Cs, A);
+        B1 -> decode_binary(ModeOffset, Padding, Cs, A, B1)
     end.
 
-dec_bin(ModeOffset, Cs, ws, B2, B3, B4, A) ->
-    dec_bin(ModeOffset, Cs, B2, B3, B4, A);
-dec_bin(ModeOffset, Cs, B1, ws, B3, B4, A) ->
-    dec_bin(ModeOffset, Cs, B1, B3, B4, A);
-dec_bin(ModeOffset, Cs, B1, B2, ws, B4, A) ->
-    dec_bin(ModeOffset, Cs, B1, B2, B4, A);
-dec_bin(ModeOffset, Cs, B1, B2, B3, B4, A) ->
+dec_bin(ModeOffset, Padding, Cs, ws, B2, B3, B4, A) ->
+    dec_bin(ModeOffset, Padding, Cs, B2, B3, B4, A);
+dec_bin(ModeOffset, Padding, Cs, B1, ws, B3, B4, A) ->
+    dec_bin(ModeOffset, Padding, Cs, B1, B3, B4, A);
+dec_bin(ModeOffset, Padding, Cs, B1, B2, ws, B4, A) ->
+    dec_bin(ModeOffset, Padding, Cs, B1, B2, B4, A);
+dec_bin(ModeOffset, Padding, Cs, B1, B2, B3, B4, A) ->
     case B4 of
-        ws                -> decode_binary(ModeOffset, Cs, A, B1, B2, B3);
-        eq when B3 =:= eq -> only_ws_binary(ModeOffset, Cs, <<A/bits,B1:6,(B2 bsr 4):2>>);
-        eq                -> only_ws_binary(ModeOffset, Cs, <<A/bits,B1:6,B2:6,(B3 bsr 2):4>>);
-        B4                -> decode_binary(ModeOffset, Cs, <<A/bits,B1:6,B2:6,B3:6,B4:6>>)
+        ws                -> decode_binary(ModeOffset, Padding, Cs, A, B1, B2, B3);
+        eq when B3 =:= eq -> only_ws_binary(ModeOffset, Padding, Cs, <<A/bits,B1:6,(B2 bsr 4):2>>);
+        eq                -> only_ws_binary(ModeOffset, Padding, Cs, <<A/bits,B1:6,B2:6,(B3 bsr 2):4>>);
+        B4                -> decode_binary(ModeOffset, Padding, Cs, <<A/bits,B1:6,B2:6,B3:6,B4:6>>)
     end.
 
-dec_bin(ModeOffset, Cs, ws, B2, B3, A) ->
-    dec_bin(ModeOffset, Cs, B2, B3, A);
-dec_bin(ModeOffset, Cs, B1, ws, B3, A) ->
-    dec_bin(ModeOffset, Cs, B1, B3, A);
-dec_bin(ModeOffset, Cs, B1, B2, ws, A) ->
-    dec_bin(ModeOffset, Cs, B1, B2, A);
-dec_bin(ModeOffset, Cs, B1, B2, B3, A) ->
-    decode_binary(ModeOffset, Cs, A, B1, B2, B3).
-
-dec_bin(ModeOffset, Cs, ws, B2, A) ->
-    dec_bin(ModeOffset, Cs, B2, A);
-dec_bin(ModeOffset, Cs, B1, ws, A) ->
-    dec_bin(ModeOffset, Cs, B1, A);
-dec_bin(ModeOffset, Cs, B1, B2, A) ->
-    decode_binary(ModeOffset, Cs, A, B1, B2).
-
-dec_bin(ModeOffset, Cs, ws, A) ->
-    decode_binary(ModeOffset, Cs, A);
-dec_bin(ModeOffset, Cs, B1, A) ->
-    decode_binary(ModeOffset, Cs, A, B1).
-
-decode_binary(ModeOffset, <<C2:8, Cs/bits>>, A, B1) ->
+dec_bin(ModeOffset, Padding, Cs, ws, B2, B3, A) ->
+    dec_bin(ModeOffset, Padding, Cs, B2, B3, A);
+dec_bin(ModeOffset, Padding, Cs, B1, ws, B3, A) ->
+    dec_bin(ModeOffset, Padding, Cs, B1, B3, A);
+dec_bin(ModeOffset, Padding, Cs, B1, B2, ws, A) ->
+    dec_bin(ModeOffset, Padding, Cs, B1, B2, A);
+dec_bin(ModeOffset, Padding, Cs, B1, B2, B3, A) ->
+    decode_binary(ModeOffset, Padding, Cs, A, B1, B2, B3).
+
+dec_bin(ModeOffset, Padding, Cs, ws, B2, A) ->
+    dec_bin(ModeOffset, Padding, Cs, B2, A);
+dec_bin(ModeOffset, Padding, Cs, B1, ws, A) ->
+    dec_bin(ModeOffset, Padding, Cs, B1, A);
+dec_bin(ModeOffset, Padding, Cs, B1, B2, A) ->
+    decode_binary(ModeOffset, Padding, Cs, A, B1, B2).
+
+dec_bin(ModeOffset, Padding, Cs, ws, A) ->
+    decode_binary(ModeOffset, Padding, Cs, A);
+dec_bin(ModeOffset, Padding, Cs, B1, A) ->
+    decode_binary(ModeOffset, Padding,Cs, A, B1).
+
+decode_binary(ModeOffset, Padding, <<C2:8, Cs/bits>>, A, B1) ->
     case b64d(C2, ModeOffset) of
-        ws -> decode_binary(ModeOffset, Cs, A, B1);
-        B2 -> decode_binary(ModeOffset, Cs, A, B1, B2)
+        ws -> decode_binary(ModeOffset, Padding, Cs, A, B1);
+        B2 -> decode_binary(ModeOffset, Padding, Cs, A, B1, B2)
     end.
 
-decode_binary(ModeOffset, <<C3:8, Cs/bits>>, A, B1, B2) ->
+decode_binary(ModeOffset, Padding, <<C3:8, Cs/bits>>, A, B1, B2) ->
     case b64d(C3, ModeOffset) of
-        ws -> decode_binary(ModeOffset, Cs, A, B1, B2);
-        B3 -> decode_binary(ModeOffset, Cs, A, B1, B2, B3)
+        ws -> decode_binary(ModeOffset, Padding, Cs, A, B1, B2);
+        B3 -> decode_binary(ModeOffset, Padding, Cs, A, B1, B2, B3)
+    end;
+decode_binary(ModeOffset, Padding, <<Cs/bits>>, A, B1, B2) ->
+    case Padding of
+        true -> missing_padding_error();
+        false -> decode_binary(ModeOffset, Padding, Cs, A, B1, B2, eq)
     end.
 
-decode_binary(ModeOffset, <<C4:8, Cs/bits>>, A, B1, B2, B3) ->
+decode_binary(ModeOffset, Padding, <<C4:8, Cs/bits>>, A, B1, B2, B3) ->
     case b64d(C4, ModeOffset) of
-        ws                -> decode_binary(ModeOffset, Cs, A, B1, B2, B3);
-        eq when B3 =:= eq -> only_ws_binary(ModeOffset, Cs, <<A/bits,B1:6,(B2 bsr 4):2>>);
-        eq                -> only_ws_binary(ModeOffset, Cs, <<A/bits,B1:6,B2:6,(B3 bsr 2):4>>);
-        B4                -> decode_binary(ModeOffset, Cs, <<A/bits,B1:6,B2:6,B3:6,B4:6>>)
+        ws                -> decode_binary(ModeOffset, Padding, Cs, A, B1, B2, B3);
+        eq when B3 =:= eq -> only_ws_binary(ModeOffset, Padding, Cs, <<A/bits,B1:6,(B2 bsr 4):2>>);
+        eq                -> only_ws_binary(ModeOffset, Padding, Cs, <<A/bits,B1:6,B2:6,(B3 bsr 2):4>>);
+        B4                -> decode_binary(ModeOffset, Padding, Cs, <<A/bits,B1:6,B2:6,B3:6,B4:6>>)
+    end;
+decode_binary(_ModeOffset, Padding, <<>>, A, B1, B2, B3) ->
+    case Padding of
+        true -> missing_padding_error();
+        false when B3 =:= eq -> <<A/bits,B1:6,(B2 bsr 4):2>>;
+        false -> <<A/bits,B1:6,B2:6,(B3 bsr 2):4>>
     end.
 
-only_ws_binary(_ModeOffset, <<>>, A) ->
+only_ws_binary(_ModeOffset, _Padding, <<>>, A) ->
     A;
-only_ws_binary(ModeOffset, <<C:8, Cs/bits>>, A) ->
+only_ws_binary(ModeOffset, Padding, <<C:8, Cs/bits>>, A) ->
     case b64d(C, ModeOffset) of
-        ws -> only_ws_binary(ModeOffset, Cs, A)
+        ws -> only_ws_binary(ModeOffset, Padding, Cs, A)
     end.
 
-decode_list_to_string(ModeOffset, [C1 | Cs]) ->
+decode_list_to_string(ModeOffset, Padding, [C1 | Cs]) ->
     case b64d(C1, ModeOffset) of
-        ws -> decode_list_to_string(ModeOffset, Cs);
-        B1 -> decode_list_to_string(ModeOffset, Cs, B1)
+        ws -> decode_list_to_string(ModeOffset, Padding, Cs);
+        B1 -> decode_list_to_string(ModeOffset, Padding, Cs, B1)
     end;
-decode_list_to_string(_ModeOffset, []) ->
+decode_list_to_string(_ModeOffset, _Padding, []) ->
     [].
 
-decode_list_to_string(ModeOffset, [C2 | Cs], B1) ->
+decode_list_to_string(ModeOffset, Padding, [C2 | Cs], B1) ->
     case b64d(C2, ModeOffset) of
-        ws -> decode_list_to_string(ModeOffset, Cs, B1);
-        B2 -> decode_list_to_string(ModeOffset, Cs, B1, B2)
+        ws -> decode_list_to_string(ModeOffset, Padding, Cs, B1);
+        B2 -> decode_list_to_string(ModeOffset, Padding, Cs, B1, B2)
     end.
 
-decode_list_to_string(ModeOffset, [C3 | Cs], B1, B2) ->
+decode_list_to_string(ModeOffset, Padding, [C3 | Cs], B1, B2) ->
     case b64d(C3, ModeOffset) of
-        ws -> decode_list_to_string(ModeOffset, Cs, B1, B2);
-        B3 -> decode_list_to_string(ModeOffset, Cs, B1, B2, B3)
+        ws -> decode_list_to_string(ModeOffset, Padding, Cs, B1, B2);
+        B3 -> decode_list_to_string(ModeOffset, Padding, Cs, B1, B2, B3)
+    end;
+decode_list_to_string(ModeOffset, Padding, [], B1, B2) ->
+    case Padding of
+        true -> missing_padding_error();
+        false -> decode_list_to_string(ModeOffset, Padding, [], B1, B2, eq)
     end.
 
-decode_list_to_string(ModeOffset, [C4 | Cs], B1, B2, B3) ->
+decode_list_to_string(ModeOffset, Padding, [C4 | Cs], B1, B2, B3) ->
     case b64d(C4, ModeOffset) of
         ws ->
-            decode_list_to_string(ModeOffset, Cs, B1, B2, B3);
+            decode_list_to_string(ModeOffset, Padding, Cs, B1, B2, B3);
         eq when B3 =:= eq ->
-            only_ws(ModeOffset, Cs, binary_to_list(<<B1:6,(B2 bsr 4):2>>));
+            only_ws(ModeOffset, Padding, Cs, binary_to_list(<<B1:6,(B2 bsr 4):2>>));
         eq ->
-            only_ws(ModeOffset, Cs, binary_to_list(<<B1:6,B2:6,(B3 bsr 2):4>>));
+            only_ws(ModeOffset, Padding, Cs, binary_to_list(<<B1:6,B2:6,(B3 bsr 2):4>>));
         B4 ->
             Bits4x6 = (B1 bsl 18) bor (B2 bsl 12) bor (B3 bsl 6) bor B4,
             Octet1 = Bits4x6 bsr 16,
             Octet2 = (Bits4x6 bsr 8) band 16#ff,
             Octet3 = Bits4x6 band 16#ff,
-            [Octet1, Octet2, Octet3 | decode_list_to_string(ModeOffset, Cs)]
+            [Octet1, Octet2, Octet3 | decode_list_to_string(ModeOffset, Padding, Cs)]
+    end;
+decode_list_to_string(_ModeOffset, Padding, [], B1, B2, B3) ->
+    case Padding of
+        true -> missing_padding_error();
+        false when B3 =:= eq -> binary_to_list(<<B1:6,(B2 bsr 4):2>>);
+        false -> binary_to_list(<<B1:6,B2:6,(B3 bsr 2):4>>)
     end.
 
-only_ws(_ModeOffset, [], A) ->
+only_ws(_ModeOffset, _Padding, [], A) ->
     A;
-only_ws(ModeOffset, [C | Cs], A) ->
+only_ws(ModeOffset, Padding, [C | Cs], A) ->
     case b64d(C, ModeOffset) of
-        ws -> only_ws(ModeOffset, Cs, A)
+        ws -> only_ws(ModeOffset, Padding, Cs, A)
     end.
 
+%%%========================================================================
+%%% Error handling functions
+%%%========================================================================
+
+% always inlined for useful stacktraces when called in tail position
+-compile({inline, missing_padding_error/0}).
+missing_padding_error() ->
+    error(missing_padding, none, [{error_info, #{}}]).
+
+format_error(missing_padding, _) ->
+    #{general => "data to decode is missing final = padding characters, if this is intended, use the `padding => false` option"};
+format_error(_, _) ->
+    #{}.
+
 %%%========================================================================
 %%% Internal functions
 %%%========================================================================
 
-%% accessors 
+%% accessors
+
+get_padding(#{padding := Bool}) when is_boolean(Bool) -> Bool;
+get_padding(#{}) -> true.
 
-get_decoding_offset(standard) -> 1;
-get_decoding_offset(urlsafe) -> 257.
+get_decoding_offset(#{mode := standard}) -> 1;
+get_decoding_offset(#{mode := urlsafe}) -> 257;
+get_decoding_offset(#{}) -> 1.
 
 -compile({inline, [{b64d, 2}]}).
 b64d(X, Off) ->
@@ -565,8 +680,9 @@ b64d(X, Off) ->
              bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,
              bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad}).
 
-get_encoding_offset(standard) -> 1;
-get_encoding_offset(urlsafe) -> 65.
+get_encoding_offset(#{mode := standard}) -> 1;
+get_encoding_offset(#{mode := urlsafe}) -> 65;
+get_encoding_offset(#{}) -> 1.
 
 -compile({inline, [{b64e, 2}]}).
 b64e(X, Off) ->
@@ -585,4 +701,3 @@ b64e(X, Off) ->
 	     $a, $b, $c, $d, $e, $f, $g, $h, $i, $j, $k, $l, $m, $n,
 	     $o, $p, $q, $r, $s, $t, $u, $v, $w, $x, $y, $z,
 	     $0, $1, $2, $3, $4, $5, $6, $7, $8, $9, $-, $_}).
-
diff --git a/lib/stdlib/test/base64_SUITE.erl b/lib/stdlib/test/base64_SUITE.erl
index d1625108bd..ad63dd4c57 100644
--- a/lib/stdlib/test/base64_SUITE.erl
+++ b/lib/stdlib/test/base64_SUITE.erl
@@ -26,8 +26,8 @@
 -export([all/0, suite/0, groups/0, group/1]).
 
 %% Test cases must be exported.
--export([base64_encode/1, base64_encode_modes/1,
-	 base64_decode/1, base64_decode_modes/1,
+-export([base64_encode/1, base64_encode_to_string/1, base64_encode_modes/1,
+	 base64_decode/1, base64_decode_to_string/1, base64_decode_modes/1,
 	 base64_otp_5635/1, base64_otp_6279/1, big/1, illegal/1,
 	 mime_decode/1, mime_decode_modes/1,
 	 mime_decode_to_string/1, mime_decode_to_string_modes/1,
@@ -42,8 +42,8 @@ suite() ->
      {timetrap,{minutes,4}}].
 
 all() ->
-    [base64_encode, base64_encode_modes,
-     base64_decode, base64_decode_modes,
+    [base64_encode, base64_encode_to_string, base64_encode_modes,
+     base64_decode, base64_decode_to_string, base64_decode_modes,
      base64_otp_5635, base64_otp_6279, big, illegal,
      mime_decode, mime_decode_modes,
      mime_decode_to_string, mime_decode_to_string_modes,
@@ -58,76 +58,176 @@ group(roundtrip) ->
     [{timetrap,{minutes,10}}].
 
 %%-------------------------------------------------------------------------
-%% Test base64:encode/1.
+%% Test base64:encode/1,2.
 base64_encode(Config) when is_list(Config) ->
     %% Two pads
     <<"QWxhZGRpbjpvcGVuIHNlc2FtZQ==">> =
 	base64:encode("Aladdin:open sesame"),
+    <<"QWxhZGRpbjpvcGVuIHNlc2FtZQ">> =
+        base64:encode("Aladdin:open sesame", #{padding => false}),
     %% One pad
     <<"SGVsbG8gV29ybGQ=">> = base64:encode(<<"Hello World">>),
+    <<"SGVsbG8gV29ybGQ">> = base64:encode(<<"Hello World">>, #{padding => false}),
+    %% No pad
+    <<"QWxhZGRpbjpvcGVuIHNlc2Ft">> = base64:encode("Aladdin:open sesam"),
+    <<"QWxhZGRpbjpvcGVuIHNlc2Ft">> =
+        base64:encode("Aladdin:open sesam", #{padding => false}),
+
+    <<"MDEyMzQ1Njc4OSFAIzBeJiooKTs6PD4sLiBbXXt9">> =
+	base64:encode(<<"0123456789!@#0^&*();:<>,. []{}">>),
+    ok.
+
+%%-------------------------------------------------------------------------
+%% Test base64:encode_to_string/1,2.
+base64_encode_to_string(Config) when is_list(Config) ->
+    %% Two pads
+    "QWxhZGRpbjpvcGVuIHNlc2FtZQ==" =
+        base64:encode_to_string("Aladdin:open sesame"),
+    "QWxhZGRpbjpvcGVuIHNlc2FtZQ" =
+        base64:encode_to_string("Aladdin:open sesame", #{padding => false}),
+    %% One pad
+    "SGVsbG8gV29ybGQ=" = base64:encode_to_string(<<"Hello World">>),
+    "SGVsbG8gV29ybGQ" =
+        base64:encode_to_string(<<"Hello World">>, #{padding => false}),
     %% No pad
     "QWxhZGRpbjpvcGVuIHNlc2Ft" =
 	base64:encode_to_string("Aladdin:open sesam"),
+    "QWxhZGRpbjpvcGVuIHNlc2Ft" =
+        base64:encode_to_string("Aladdin:open sesam", #{padding => false}),
 
     "MDEyMzQ1Njc4OSFAIzBeJiooKTs6PD4sLiBbXXt9" =
 	base64:encode_to_string(<<"0123456789!@#0^&*();:<>,. []{}">>),
     ok.
 
 %%-------------------------------------------------------------------------
-%% Test base64:encode/2.
+%% Test base64:encode/2 and base64:encode_to_string/2.
 base64_encode_modes(Config) when is_list(Config) ->
     Data = <<23, 234, 63, 163, 239, 129, 253, 175, 171>>,
 
-    <<"F+o/o++B/a+r">> = base64:encode(Data, standard),
-    <<"F-o_o--B_a-r">> = base64:encode(Data, urlsafe),
+    <<"F+o/o++B/a+r">> = base64:encode(Data, #{mode => standard}),
+    <<"F-o_o--B_a-r">> = base64:encode(Data, #{mode => urlsafe}),
 
-    "F+o/o++B/a+r" = base64:encode_to_string(Data, standard),
-    "F-o_o--B_a-r" = base64:encode_to_string(Data, urlsafe),
+    "F+o/o++B/a+r" = base64:encode_to_string(Data, #{mode => standard}),
+    "F-o_o--B_a-r" = base64:encode_to_string(Data, #{mode => urlsafe}),
 
     ok.
 
 %%-------------------------------------------------------------------------
-%% Test base64:decode/1.
+%% Test base64:decode/1,2.
 base64_decode(Config) when is_list(Config) ->
     %% Two pads
     <<"Aladdin:open sesame">> =
-	base64:decode("QWxhZGRpbjpvcGVuIHNlc2FtZQ=="),
+        base64:decode(<<"QWxhZGRpbjpvcGVuIHNlc2FtZQ==">>),
+    <<"Aladdin:open sesame">> =
+        base64:decode("QWxhZGRpbjpvcGVuIHNlc2FtZQ=="),
+    <<"Aladdin:open sesame">> =
+        base64:decode(<<"QWxhZGRpbjpvcGVuIHNlc2FtZQ">>, #{padding => false}),
+    <<"Aladdin:open sesame">> =
+        base64:decode("QWxhZGRpbjpvcGVuIHNlc2FtZQ", #{padding => false}),
+    {'EXIT', {'missing_padding', _}} =
+        catch base64:decode(<<"QWxhZGRpbjpvcGVuIHNlc2FtZQ">>),
+    {'EXIT', {'missing_padding', _}} =
+        catch base64:decode("QWxhZGRpbjpvcGVuIHNlc2FtZQ"),
     %% One pad
     <<"Hello World">> = base64:decode(<<"SGVsbG8gV29ybGQ=">>),
+    <<"Hello World">> = base64:decode("SGVsbG8gV29ybGQ="),
+    <<"Hello World">> = base64:decode(<<"SGVsbG8gV29ybGQ">>, #{padding => false}),
+    <<"Hello World">> = base64:decode("SGVsbG8gV29ybGQ", #{padding => false}),
+    {'EXIT', {'missing_padding', _}} =
+        catch base64:decode_to_string(<<"SGVsbG8gV29ybGQ">>),
+    {'EXIT', {'missing_padding', _}} =
+        catch base64:decode_to_string("SGVsbG8gV29ybGQ"),
     %% No pad
     <<"Aladdin:open sesam">> =
-	base64:decode("QWxhZGRpbjpvcGVuIHNlc2Ft"),
+        base64:decode(<<"QWxhZGRpbjpvcGVuIHNlc2Ft">>),
+    <<"Aladdin:open sesam">> =
+        base64:decode("QWxhZGRpbjpvcGVuIHNlc2Ft"),
+    <<"Aladdin:open sesam">> =
+        base64:decode(<<"QWxhZGRpbjpvcGVuIHNlc2Ft">>, #{padding => false}),
+    <<"Aladdin:open sesam">> =
+        base64:decode("QWxhZGRpbjpvcGVuIHNlc2Ft", #{padding => false}),
 
     Alphabet = list_to_binary(lists:seq(0, 255)),
     Alphabet = base64:decode(base64:encode(Alphabet)),
+    Alphabet = base64:decode(base64:encode_to_string(Alphabet)),
+
+    %% Encoded base 64 strings may be divided by non base 64 chars.
+    %% In this cases whitespaces.
+    <<"0123456789!@#0^&*();:<>,. []{}">> =
+        base64:decode(
+            "MDEy MzQ1Njc4 \tOSFAIzBeJ \niooKTs6 PD4sLi \r\nBbXXt9"),
+    <<"0123456789!@#0^&*();:<>,. []{}">> =
+        base64:decode(
+            <<"MDEy MzQ1Njc4 \tOSFAIzBeJ \niooKTs6 PD4sLi \r\nBbXXt9">>),
+    ok.
+
+%%-------------------------------------------------------------------------
+%% Test base64:decode_to_string/1,2.
+base64_decode_to_string(Config) when is_list(Config) ->
+    %% Two pads
+    "Aladdin:open sesame" =
+        base64:decode_to_string(<<"QWxhZGRpbjpvcGVuIHNlc2FtZQ==">>),
+    "Aladdin:open sesame" =
+        base64:decode_to_string("QWxhZGRpbjpvcGVuIHNlc2FtZQ=="),
+    "Aladdin:open sesame" =
+        base64:decode_to_string(<<"QWxhZGRpbjpvcGVuIHNlc2FtZQ">>, #{padding => false}),
+    "Aladdin:open sesame" =
+        base64:decode_to_string("QWxhZGRpbjpvcGVuIHNlc2FtZQ", #{padding => false}),
+    {'EXIT', {'missing_padding', _}} =
+        catch base64:decode_to_string(<<"QWxhZGRpbjpvcGVuIHNlc2FtZQ">>),
+    {'EXIT', {'missing_padding', _}} =
+        catch base64:decode_to_string("QWxhZGRpbjpvcGVuIHNlc2FtZQ"),
+    %% One pad
+    "Hello World" = base64:decode_to_string(<<"SGVsbG8gV29ybGQ=">>),
+    "Hello World" = base64:decode_to_string("SGVsbG8gV29ybGQ="),
+    "Hello World" = base64:decode_to_string(<<"SGVsbG8gV29ybGQ">>, #{padding => false}),
+    "Hello World" = base64:decode_to_string("SGVsbG8gV29ybGQ", #{padding => false}),
+    {'EXIT', {'missing_padding', _}} =
+        catch base64:decode_to_string(<<"SGVsbG8gV29ybGQ">>),
+    {'EXIT', {'missing_padding', _}} =
+        catch base64:decode_to_string("SGVsbG8gV29ybGQ"),
+    %% No pad
+    "Aladdin:open sesam" =
+        base64:decode_to_string(<<"QWxhZGRpbjpvcGVuIHNlc2Ft">>),
+    "Aladdin:open sesam" =
+        base64:decode_to_string("QWxhZGRpbjpvcGVuIHNlc2Ft"),
+    "Aladdin:open sesam" =
+        base64:decode_to_string(<<"QWxhZGRpbjpvcGVuIHNlc2Ft">>, #{padding => false}),
+    "Aladdin:open sesam" =
+        base64:decode_to_string("QWxhZGRpbjpvcGVuIHNlc2Ft", #{padding => false}),
+
+    Alphabet = lists:seq(0, 255),
+    Alphabet = base64:decode_to_string(base64:encode(Alphabet)),
+    Alphabet = base64:decode_to_string(base64:encode_to_string(Alphabet)),
 
     %% Encoded base 64 strings may be divided by non base 64 chars.
     %% In this cases whitespaces.
     "0123456789!@#0^&*();:<>,. []{}" =
-	base64:decode_to_string(
-	  "MDEy MzQ1Njc4 \tOSFAIzBeJ \niooKTs6 PD4sLi \r\nBbXXt9"),
+        base64:decode_to_string(
+            "MDEy MzQ1Njc4 \tOSFAIzBeJ \niooKTs6 PD4sLi \r\nBbXXt9"),
     "0123456789!@#0^&*();:<>,. []{}" =
-	base64:decode_to_string(
-	  <<"MDEy MzQ1Njc4 \tOSFAIzBeJ \niooKTs6 PD4sLi \r\nBbXXt9">>),
+        base64:decode_to_string(
+            <<"MDEy MzQ1Njc4 \tOSFAIzBeJ \niooKTs6 PD4sLi \r\nBbXXt9">>),
     ok.
 
 %%-------------------------------------------------------------------------
-%% Test base64:decode/2.
+%% Test base64:decode/2 and base64:decode_to_string/2
 base64_decode_modes(Config) when is_list(Config) ->
     DataBin = <<23, 234, 63, 163, 239, 129, 253, 175, 171>>,
     DataStr = [23, 234, 63, 163, 239, 129, 253, 175, 171],
 
-    DataBin = base64:decode("F+o/o++B/a+r", standard),
-    DataBin = base64:decode("F-o_o--B_a-r", urlsafe),
-    {'EXIT', _} = catch base64:decode("F-o_o--B_a-r", standard),
-    {'EXIT', _} = catch base64:decode("F+o/o++B/a+r", urlsafe),
+    DataBin = base64:decode("F+o/o++B/a+r", #{mode => standard}),
+    DataBin = base64:decode("F-o_o--B_a-r", #{mode => urlsafe}),
+    {'EXIT', _} = catch base64:decode("F-o_o--B_a-r", #{mode => standard}),
+    {'EXIT', _} = catch base64:decode("F+o/o++B/a+r", #{mode => urlsafe}),
 
-    DataStr = base64:decode_to_string("F+o/o++B/a+r", standard),
-    DataStr = base64:decode_to_string("F-o_o--B_a-r", urlsafe),
-    {'EXIT', _} = catch base64:decode_to_string("F-o_o--B_a-r", standard),
-    {'EXIT', _} = catch base64:decode_to_string("F+o/o++B/a+r", urlsafe),
+    DataStr = base64:decode_to_string("F+o/o++B/a+r", #{mode => standard}),
+    DataStr = base64:decode_to_string("F-o_o--B_a-r", #{mode => urlsafe}),
+    {'EXIT', _} = catch base64:decode_to_string("F-o_o--B_a-r", #{mode => standard}),
+    {'EXIT', _} = catch base64:decode_to_string("F+o/o++B/a+r", #{mode => urlsafe}),
 
     ok.
+
 %%-------------------------------------------------------------------------
 %% OTP-5635: Some data doesn't pass through base64:decode/1 correctly.
 base64_otp_5635(Config) when is_list(Config) ->
@@ -210,26 +310,26 @@ mime_decode(Config) when is_list(Config) ->
 
 %% Test base64:mime_decode/2.
 mime_decode_modes(Config) when is_list(Config) ->
-    MimeDecode = fun (In, Mode) ->
-                                Out = base64:mime_decode(In, Mode),
-                                Out = base64:mime_decode(binary_to_list(In), Mode)
+    MimeDecode = fun (In, Options) ->
+                                Out = base64:mime_decode(In, Options),
+                                Out = base64:mime_decode(binary_to_list(In), Options)
                  end,
 
     %% The following all decode to the same data.
     Data = <<23, 234, 63, 163, 239, 129, 253, 175, 171>>,
-    Data = MimeDecode(<<"F+o/o++B/a+r">>, standard),
-    Data = MimeDecode(<<"F-o_o--B_a-r">>, urlsafe),
+    Data = MimeDecode(<<"F+o/o++B/a+r">>, #{mode => standard}),
+    Data = MimeDecode(<<"F-o_o--B_a-r">>, #{mode => urlsafe}),
 
     %% The following decodes to different data depending on mode.
     Base64 = <<"AB+C+D/E/FG-H-I_J_KL">>,
     %% In standard mode, "-" and "_" are invalid and thus ignored.
     %% The base64 string to be decoded is equivalent to "AB+C+D/E/FGHIJKL".
     <<0, 31, 130, 248, 63, 196, 252, 81, 135, 32, 146, 139>> =
-        MimeDecode(Base64, standard),
+        MimeDecode(Base64, #{mode => standard}),
     %% In urlsafe mode, "+" and "/" are invalid and thus ignored.
     %% The base64 string to be decoded is equivalent to "ABCDEFG-H-I_J_KL".
     <<0, 16, 131, 16, 81, 190, 31, 226, 63, 39, 242, 139>> =
-        MimeDecode(Base64, urlsafe),
+        MimeDecode(Base64, #{mode => urlsafe}),
 
     ok.
 
@@ -286,26 +386,26 @@ mime_decode_to_string(Config) when is_list(Config) ->
 
 %% Test base64:mime_decode_to_string/2.
 mime_decode_to_string_modes(Config) when is_list(Config) ->
-    MimeDecode = fun (In, Mode) ->
-                                Out = base64:mime_decode_to_string(In, Mode),
-                                Out = base64:mime_decode_to_string(binary_to_list(In), Mode)
+    MimeDecode = fun (In, Options) ->
+                                Out = base64:mime_decode_to_string(In, Options),
+                                Out = base64:mime_decode_to_string(binary_to_list(In), Options)
                  end,
 
     %% The following all decode to the same data.
     Data = [23, 234, 63, 163, 239, 129, 253, 175, 171],
-    Data = MimeDecode(<<"F+o/o++B/a+r">>, standard),
-    Data = MimeDecode(<<"F-o_o--B_a-r">>, urlsafe),
+    Data = MimeDecode(<<"F+o/o++B/a+r">>, #{mode => standard}),
+    Data = MimeDecode(<<"F-o_o--B_a-r">>, #{mode => urlsafe}),
 
     %% The following decodes to different data depending on mode.
     Base64 = <<"AB+C+D/E/FG-H-I_J_KL">>,
     %% In standard mode, "-" and "_" are invalid and thus ignored.
     %% The base64 string to be decoded is equivalent to "AB+C+D/E/FGHIJKL".
     [0, 31, 130, 248, 63, 196, 252, 81, 135, 32, 146, 139] =
-        MimeDecode(Base64, standard),
+        MimeDecode(Base64, #{mode => standard}),
     %% In urlsafe mode, "+" and "/" are invalid and thus ignored.
     %% The base64 string to be decoded is equivalent to "ABCDEFG-H-I_J_KL".
     [0, 16, 131, 16, 81, 190, 31, 226, 63, 39, 242, 139] =
-        MimeDecode(Base64, urlsafe),
+        MimeDecode(Base64, #{mode => urlsafe}),
 
     ok.
 
diff --git a/lib/stdlib/test/property_test/base64_prop.erl b/lib/stdlib/test/property_test/base64_prop.erl
index f77ce9b664..da494eec21 100644
--- a/lib/stdlib/test/property_test/base64_prop.erl
+++ b/lib/stdlib/test/property_test/base64_prop.erl
@@ -70,8 +70,8 @@ prop_encode_2() ->
         {Str, Mode},
         {oneof([list(byte()), binary()]), mode()},
         begin
-            Enc = base64:encode(Str, Mode),
-            Dec = base64:decode(Enc, Mode),
+            Enc = base64:encode(Str, #{mode => Mode}),
+            Dec = base64:decode(Enc, #{mode => Mode}),
             is_b64_binary(Mode, Enc) andalso str_equals(Str, Dec)
         end
     ).
@@ -92,8 +92,8 @@ prop_encode_to_string_2() ->
         {Str, Mode},
         {oneof([list(byte()), binary()]), mode()},
         begin
-            Enc = base64:encode_to_string(Str, Mode),
-            Dec = base64:decode_to_string(Enc, Mode),
+            Enc = base64:encode_to_string(Str, #{mode => Mode}),
+            Dec = base64:decode_to_string(Enc, #{mode => Mode}),
             is_b64_string(Mode, Enc) andalso str_equals(Str, Dec)
         end
     ).
@@ -118,8 +118,8 @@ prop_decode_2() ->
             {wsped_b64(Mode), Mode}
         ),
         begin
-            Dec = base64:decode(WspedB64, Mode),
-            Enc = base64:encode(Dec, Mode),
+            Dec = base64:decode(WspedB64, #{mode => Mode}),
+            Enc = base64:encode(Dec, #{mode => Mode}),
             is_binary(Dec) andalso b64_equals(Mode, NormalizedB64, Enc)
         end
     ).
@@ -156,8 +156,8 @@ prop_decode_to_string_2() ->
             {wsped_b64(Mode), Mode}
         ),
         begin
-            Dec = base64:decode_to_string(WspedB64, Mode),
-            Enc = base64:encode(Dec, Mode),
+            Dec = base64:decode_to_string(WspedB64, #{mode => Mode}),
+            Enc = base64:encode(Dec, #{mode => Mode}),
             is_bytelist(Dec) andalso b64_equals(Mode, NormalizedB64, Enc)
         end
     ).
@@ -194,8 +194,8 @@ prop_mime_decode_2() ->
             {wsped_b64(Mode), Mode}
         ),
         begin
-            Dec = base64:mime_decode(NoisyB64, Mode),
-            Enc = base64:encode(Dec, Mode),
+            Dec = base64:mime_decode(NoisyB64, #{mode => Mode}),
+            Enc = base64:encode(Dec, #{mode => Mode}),
             is_binary(Dec) andalso b64_equals(Mode, NormalizedB64, Enc)
         end
     ).
@@ -226,8 +226,8 @@ prop_mime_decode_to_string_2() ->
             {wsped_b64(Mode), Mode}
         ),
         begin
-            Dec = base64:mime_decode_to_string(NoisyB64, Mode),
-            Enc = base64:encode(Dec, Mode),
+            Dec = base64:mime_decode_to_string(NoisyB64, #{mode => Mode}),
+            Enc = base64:encode(Dec, #{mode => Mode}),
             is_bytelist(Dec) andalso b64_equals(Mode, NormalizedB64, Enc)
         end
     ).
@@ -247,7 +247,7 @@ common_decode_noisy(ModeGen, Fn) ->
             {?SUCHTHAT({NormalizedB64, NoisyB64}, noisy_b64(Mode), NormalizedB64 =/= NoisyB64), Mode}
         ),
         try
-            Fn(NoisyB64, Mode)
+            Fn(NoisyB64, #{mode => Mode})
         of
             _ ->
                 false
@@ -280,7 +280,7 @@ common_decode_malformed(DataGen, ModeGen, Fn) ->
             )
         ),
         try
-            Fn(MalformedB64, Mode)
+            Fn(MalformedB64, #{mode => Mode})
         of
             _ ->
                 false
-- 
2.35.3

openSUSE Build Service is sponsored by