Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
home:Ledest:erlang:25
erlang
2691-base64-allow-skipping-padding-characters.p...
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File 2691-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
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor