Skip to content

Commit

Permalink
refactor: update base64 basecode. (#5)
Browse files Browse the repository at this point in the history
* refactor: update base64 basecode.

---------

Co-authored-by: Jose E. Cribeiro Aneiros <[email protected]>
  • Loading branch information
mrrubinos and josecriane authored Mar 26, 2024
1 parent 72581d1 commit 14ec333
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 64 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# nuid
![nuid](https://github.com/nomasystems/nuid/actions/workflows/build.yml/badge.svg)
[![nuid](https://github.com/nomasystems/nuid/actions/workflows/ci.yml/badge.svg)](https://github.com/nomasystems/nuid/actions/workflows/ci.yml)

`nuid` is an OTP library to generate unique identifiers.

Expand Down
1 change: 1 addition & 0 deletions rebar.config
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
]}.

{cover_opts, [verbose]}.
{cover_excl_mods, [nuid_base64]}.
{cover_enabled, true}.

{xref_ignores, [nuid]}.
134 changes: 71 additions & 63 deletions src/nuid_base64.erl
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
%% Copyright Ericsson AB 2007-2021. All Rights Reserved.
%% Copyright Ericsson AB 2007-2023. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
Expand All @@ -21,68 +21,109 @@

-module(nuid_base64).

-export([encode/1, decode/1]).
-export([
encode/1,
decode/1
]).

%% RFC 4648§5: base64url - Base 64 Encoding alphabet
%-type base64_alphabet() :: $0..$9 | $- | $A..$Z | $_ | $a..$z.
%% Alphabet reordered to be lexicographically ordered.
%% RFC 4648: Base 64 Encoding alphabet
%% -type base64_alphabet() :: $A..$Z | $a..$z | $0..$9 | $- | $_.
%% Section 4, `urlsafe' for RFC 4648 Section 5.
%% It's been reordered to be lexicographically sortable.

%% The following type is a subtype of string() for return values
%% of encoding functions.
-type base64_binary() :: binary().

%% Decoded sequence of octets
-type byte_string() :: [byte()].

-spec encode(Data) -> Base64 when
Data :: binary(),
Data :: byte_string() | binary(),
Base64 :: base64_binary().

encode(Bin) ->
encode(Bin) when is_binary(Bin) ->
encode_binary(Bin, <<>>).

encode_binary(<<B1:6, B2:6, B3:6, B4:6, B5:6, B6:6, B7:6, B8:6, Ls/bits>>, A) ->
encode_binary(
Ls,
<<A/bits, (b64e(B1)):8, (b64e(B2)):8, (b64e(B3)):8, (b64e(B4)):8, (b64e(B5)):8,
(b64e(B6)):8, (b64e(B7)):8, (b64e(B8)):8>>
);
encode_binary(<<>>, A) ->
A;
encode_binary(<<B1:8>>, A) ->
<<A/bits, (b64e(B1 bsr 2)):8, (b64e((B1 band 3) bsl 4)):8>>;
encode_binary(<<B1:8, B2:8>>, A) ->
<<A/bits, (b64e(B1 bsr 2)):8, (b64e(((B1 band 3) bsl 4) bor (B2 bsr 4))):8,
(b64e((B2 band 15) bsl 2)):8>>;
encode_binary(<<B1:8, B2:8, B3:8, Ls/bits>>, A) ->
BB = (B1 bsl 16) bor (B2 bsl 8) bor B3,
encode_binary(<<B1:6, B2:6, B3:6, B4:6, Ls/bits>>, A) ->
encode_binary(
Ls,
<<A/bits, (b64e(BB bsr 18)):8, (b64e((BB bsr 12) band 63)):8, (b64e((BB bsr 6) band 63)):8,
(b64e(BB band 63)):8>>
).
<<A/bits, (b64e(B1)):8, (b64e(B2)):8, (b64e(B3)):8, (b64e(B4)):8>>
);
encode_binary(<<B1:6, B2:2>>, A) ->
E1 = b64e(B1),
E2 = b64e(B2 bsl 4),
<<A/bits, E1, E2, $=, $=>>;
encode_binary(<<B1:6, B2:6, B3:4>>, A) ->
E1 = b64e(B1),
E2 = b64e(B2),
E3 = b64e(B3 bsl 2),
<<A/bits, E1, E2, E3, $=>>.

%% mime_decode strips away all characters not Base64 before
%% converting, whereas decode crashes if an illegal character is found

-spec decode(Base64) -> Data when
Base64 :: base64_binary(),
Data :: binary().

decode(Bin) ->
decode_binary(Bin, <<>>).

decode_binary(<<C1:8, Cs/bits>>, A) ->
decode_binary(Cs, A, b64d(C1));
decode(Base64) when is_binary(Base64) ->
decode_binary(Base64, <<>>).

decode_binary(<<C1:8, C2:8, C3:8, C4:8, Cs/bits>>, A) ->
case {b64d(C1), b64d(C2), b64d(C3), b64d(C4)} of
{B1, B2, B3, B4} when
is_integer(B1),
is_integer(B2),
is_integer(B3),
is_integer(B4)
->
decode_binary(Cs, <<A/bits, B1:6, B2:6, B3:6, B4:6>>);
{B1, B2, B3, B4} ->
dec_bin(Cs, B1, B2, B3, B4, A)
end;
decode_binary(<<>>, A) ->
A.
A;
decode_binary(<<C1:8, Cs/bits>>, A) ->
B1 = b64d(C1),
decode_binary(Cs, A, B1).

dec_bin(Cs, B1, B2, B3, B4, A) ->
decode_binary(Cs, <<A/bits, B1:6, B2:6, B3:6, B4:6>>).

decode_binary(<<C2:8, Cs/bits>>, A, B1) ->
decode_binary(Cs, A, B1, b64d(C2)).
B2 = b64d(C2),
decode_binary(Cs, A, B1, B2).

decode_binary(<<C3:8, Cs/bits>>, A, B1, B2) ->
decode_binary(Cs, A, B1, B2, b64d(C3));
decode_binary(<<>>, A, B1, B2) ->
<<A/bits, B1:6, (B2 bsr 4):2>>.
B3 = b64d(C3),
decode_binary(Cs, A, B1, B2, B3);
decode_binary(<<_Cs/bits>>, _A, _B1, _B2) ->
missing_padding_error().

decode_binary(<<C4:8, Cs/bits>>, A, B1, B2, B3) ->
B4 = b64d(C4),
decode_binary(Cs, <<A/bits, B1:6, B2:6, B3:6, B4:6>>);
decode_binary(<<>>, A, B1, B2, B3) ->
<<A/bits, B1:6, B2:6, (B3 bsr 2):4>>.
decode_binary(<<>>, _A, _B1, _B2, _B3) ->
missing_padding_error().

%%%========================================================================
%%% Internal functions
%%% 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, #{}}]).

%%%========================================================================

%% accessors
Expand Down Expand Up @@ -178,36 +219,3 @@ b64e(X) ->
$z
}
).

%%-----------------------------------------------------------------------
%% Code to generate decode table
%%-----------------------------------------------------------------------
%% code({value, {Pos, _Value}}) ->
%% Pos;
%% code(_) ->
%% bad.
%%
%% alphabet_pos([], _Pos, Acc) ->
%% lists:reverse(Acc);
%% alphabet_pos([Char | Rest], Pos, Acc) ->
%% alphabet_pos(Rest, Pos + 1, [{Pos, Char} | Acc]).
%%
%% decode_tuple(AlphabetPos) ->
%% Seq = lists:seq(1, 256),
%% decode_tuple(AlphabetPos, Seq, []).
%%
%%
%% decode_tuple(_AlphabetPos, [], Acc) ->
%% list_to_tuple(lists:reverse(Acc));
%% decode_tuple(AlphabetPos, [Char | Rest], Acc) ->
%% Value = code(lists:keysearch(Char, 2, AlphabetPos)),
%% decode_tuple(AlphabetPos, Rest, [Value | Acc]).
%%
%% decode_table() ->
%% Alphabet = [$-, $0, $1, $2, $3, $4, $5, $6, $7, $8, $9,
%% $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,
%% $_, $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],
%% AlphabetPos = alphabet_pos(Alphabet, 0, []),
%% decode_tuple(AlphabetPos).

0 comments on commit 14ec333

Please sign in to comment.