/home/runner/work/klsn/klsn/_build/test/cover/eunit/klsn_binstr.html

1 -module(klsn_binstr).
2
3 -export([
4 urlencode/1
5 , urldecode/1
6 , from_any/1
7 , replace/2
8 , hash/1
9 ]).
10
11 %% UTF-8 binary string used as the canonical textual representation across
12 %% the klsn_* helper modules.
13 -export_type([
14 binstr/0
15 ]).
16
17 -type binstr() :: unicode:unicode_binary().
18
19
20 %% @doc
21 %% Return a lowercase hexadecimal SHA-256 digest of Binary.
22 -spec hash(binstr()) -> binstr().
23 hash(Binary) ->
24 3 list_to_binary(
25 string:lowercase(
26 binary_to_list(
27 binary:encode_hex(
28 crypto:hash(sha256, Binary)
29 )
30 )
31 )
32 ).
33
34 %% @doc
35 %% Apply each replacement rule {Before,After} to Sub using
36 %% binary:replace/4 with the global option. Rules are processed from
37 %% left to right so earlier replacements feed into later ones.
38 %%
39 %% Returns the transformed binary.
40 -spec replace([{binstr(), binstr()}], binstr()) -> binstr().
41 replace(Rule, Sub) ->
42 7 lists:foldl(fun({Before, After}, Acc) ->
43 8 binary:replace(Acc, Before, After, [global])
44 end, Sub, Rule).
45
46 %% @doc
47 %% Convert an integer, float, atom or arbitrary iolist to a UTF-8 binary.
48 %%
49 %% If the value is already a binary it is returned unchanged (through the
50 %% iolist clause).
51 -spec from_any(any()) -> binstr().
52 from_any(Integer) when is_integer(Integer) ->
53 1 integer_to_binary(Integer);
54 from_any(Float) when is_float(Float) ->
55 1 float_to_binary(Float);
56 from_any(Atom) when is_atom(Atom) ->
57 1 atom_to_binary(Atom);
58 from_any(IOList) ->
59 1 iolist_to_binary(IOList).
60
61 %% @doc
62 %% Percent-encode Bin so that it becomes safe to embed inside a URL.
63 %% The implementation keeps alphanumerics and the unreserved characters
64 %% - . _ ~ intact and encodes everything else as %XX.
65 -spec urlencode(binstr()) -> binstr().
66 urlencode(Bin) ->
67 8 IsSafe = fun
68 2 ($-) -> true;
69 2 ($.) -> true;
70 2 ($_) -> true;
71 2 ($~) -> true;
72 30 (C) when $A =< C, C =< $Z -> true;
73 54 (C) when $a =< C, C =< $z -> true;
74 13 (C) when $0 =< C, C =< $9 -> true;
75 76 (_) -> false
76 end,
77 8 urlencode(Bin, IsSafe, <<>>).
78
79 urlencode(<<>>, _, Acc) ->
80 7 Acc;
81 urlencode(<<Char/utf8, Rest/binary>>, IsSafe, Acc) ->
82 181 Encoded = case IsSafe(Char) of
83 false ->
84 76 percent_encode(<<Char/utf8>>, <<>>);
85 true ->
86 105 <<Char/utf8>>
87 end,
88 181 urlencode(Rest, IsSafe, <<Acc/binary, Encoded/binary>>);
89 urlencode(<<Char:1/binary, Rest/binary>>, IsSafe, Acc) ->
90 128 Encoded = percent_encode(<<Char/binary>>, <<>>),
91 128 urlencode(Rest, IsSafe, <<Acc/binary, Encoded/binary>>);
92 urlencode(_, _, _) ->
93 1 error(badarg).
94
95 percent_encode(<<>>, Acc) ->
96 204 Acc;
97 percent_encode(<<A:4, B:4, Rest/binary>>, Acc) ->
98 214 EncodedLeft = encode_half_char(A),
99 214 EncodedRight = encode_half_char(B),
100 214 percent_encode(Rest, <<
101 Acc/binary
102 , $%
103 , EncodedLeft
104 , EncodedRight
105 >>).
106
107 encode_half_char(HalfChar) ->
108 428 if
109 239 ((HalfChar) >= 0) andalso ((HalfChar) =< 9) -> (HalfChar) + $0;
110 189 ((HalfChar) >= 10) andalso ((HalfChar) =< 15) -> (HalfChar) + $A - 10
111 end.
112
113 -spec urldecode(binstr()) -> binstr().
114 urldecode(Bin) when is_binary(Bin) ->
115 8 urldecode(Bin, <<>>);
116 urldecode(_) ->
117 1 error(badarg).
118
119 urldecode(<<>>, Acc) ->
120 8 Acc;
121 urldecode(<<"%", H, L, Rest/binary>>, Acc) ->
122 217 V0 = hex_val(H),
123 217 V1 = hex_val(L),
124 217 Byte = V0 * 16 + V1,
125 217 urldecode(Rest, <<Acc/binary, Byte>>);
126 urldecode(<<Byte, Rest/binary>>, Acc) ->
127 117 urldecode(Rest, <<Acc/binary, Byte>>).
128
129 -spec hex_val(integer()) -> integer().
130 242 hex_val(H) when $0 =< H, H =< $9 -> H - $0;
131 189 hex_val(H) when $A =< H, H =< $F -> H - $A + 10;
132 3 hex_val(H) when $a =< H, H =< $f -> H - $a + 10.
133
134
135
Line Hits Source