%% ------------------------------------------------------------------- %% %% Copyright (c) 2012 Andrew Tunnell-Jones. All Rights Reserved. %% %% This file is provided to you under the Apache License, %% Version 2.0 (the "License"); you may not use this file %% except in compliance with the License. You may obtain %% a copy of the License at %% %% http://www.apache.org/licenses/LICENSE-2.0 %% %% Unless required by applicable law or agreed to in writing, %% software distributed under the License is distributed on an %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY %% KIND, either express or implied. See the License for the %% specific language governing permissions and limitations %% under the License. %% %% ------------------------------------------------------------------- -if(?OTP_RELEASE >= 27). -define(MODULEDOC(Str), -moduledoc(Str)). -define(DOC(Str), -doc(Str)). -else. -define(MODULEDOC(Str), -compile([])). -define(DOC(Str), -compile([])). -endif. -module(base32). ?MODULEDOC(""" Base32 encoding and decoding """). -compile( {inline, [ {encode32upper, 1}, {encode32lower, 1}, {encode32hexupper, 1}, {encode32hexlower, 1}, {decode32, 1}, {decode32hex, 1}, {do_decode, 2}, {decode_offset, 1}, {error_info, 3} ]} ). -export([ encode/1, encode/2, decode/1, decode/2 ]). ?DOC(#{equiv => encode(Bin, [])}). -spec encode(binary() | string()) -> <<_:_*32>>. encode(Bin) when is_binary(Bin) -> encode(Bin, true, false, false); encode(List) when is_list(List) -> encode(iolist_to_binary(List), true, false, false). ?DOC(""" Encode a string into base 32. Options: - `hex`: whether to use hexadecimal encoding. Defaults to `false`. - `lower`: whether to use lowercase encoding. Defaults to `false`. - `nopad`: whether to skip padding. Defaults to `false`. """). -spec encode(binary() | string(), proplists:proplist()) -> <<_:_*32>>. encode(Bin, Opts) when is_binary(Bin) -> Hex = proplists:get_bool(hex, Opts), Lower = proplists:get_bool(lower, Opts), Pad = not proplists:get_bool(nopad, Opts), encode(Bin, Pad, Hex, Lower); encode(List, Opts) when is_list(List) -> encode(iolist_to_binary(List), Opts). ?DOC(#{equiv => decode(Bin, [])}). -spec decode(<<_:_*32>>) -> binary(). decode(Bin) when is_binary(Bin) -> do_decode(Bin, false); decode(List) when is_list(List) -> do_decode(iolist_to_binary(List), false). ?DOC(""" Decode a string into base 32. Options: - `hex`: whether decode the input as hexadecimal encoding. Defaults to `false`. """). -spec decode(<<_:_*32>> | string(), proplists:proplist()) -> binary(). decode(Bin, Opts) when is_binary(Bin) andalso is_list(Opts) -> Hex = proplists:get_bool(hex, Opts), do_decode(Bin, Hex); decode(List, Opts) when is_list(List) andalso is_list(Opts) -> Hex = proplists:get_bool(hex, Opts), do_decode(iolist_to_binary(List), Hex). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% encode(Bin, Pad, true, true) -> encode32hexlower(Bin, <<>>, Pad); encode(Bin, Pad, true, false) -> encode32hexupper(Bin, <<>>, Pad); encode(Bin, Pad, false, true) -> encode32lower(Bin, <<>>, Pad); encode(Bin, Pad, false, false) -> encode32upper(Bin, <<>>, Pad). encode32hexlower( <>, Acc, Pad ) -> encode32hexlower( Rest, <>, Pad ); encode32hexlower( <>, Acc, Pad ) -> maybe_pad( <>, Pad, 1 ); encode32hexlower( <>, Acc, Pad ) -> maybe_pad( <>, Pad, 3 ); encode32hexlower( <>, Acc, Pad ) -> maybe_pad( <>, Pad, 4 ); encode32hexlower( <>, Acc, Pad ) -> maybe_pad( <>, Pad, 6 ); encode32hexlower(<<>>, Acc, _) -> Acc. encode32hexupper( <>, Acc, Pad ) -> encode32hexupper( Rest, <>, Pad ); encode32hexupper( <>, Acc, Pad ) -> maybe_pad( <>, Pad, 1 ); encode32hexupper( <>, Acc, Pad ) -> maybe_pad( <>, Pad, 3 ); encode32hexupper( <>, Acc, Pad ) -> maybe_pad( <>, Pad, 4 ); encode32hexupper( <>, Acc, Pad ) -> maybe_pad( <>, Pad, 6 ); encode32hexupper(<<>>, Acc, _) -> Acc. encode32lower( <>, Acc, Pad ) -> encode32lower( Rest, <>, Pad ); encode32lower( <>, Acc, Pad ) -> maybe_pad( <>, Pad, 1 ); encode32lower( <>, Acc, Pad ) -> maybe_pad( <>, Pad, 3 ); encode32lower( <>, Acc, Pad ) -> maybe_pad( <>, Pad, 4 ); encode32lower(<>, Acc, Pad) -> maybe_pad( <>, Pad, 6 ); encode32lower(<<>>, Acc, _) -> Acc. encode32upper( <>, Acc, Pad ) -> encode32upper( Rest, <>, Pad ); encode32upper( <>, Acc, Pad ) -> maybe_pad( <>, Pad, 1 ); encode32upper( <>, Acc, Pad ) -> maybe_pad( <>, Pad, 3 ); encode32upper( <>, Acc, Pad ) -> maybe_pad( <>, Pad, 4 ); encode32upper(<>, Acc, Pad) -> maybe_pad( <>, Pad, 6 ); encode32upper(<<>>, Acc, _) -> Acc. do_decode(Bin, false) -> do_decode32(Bin); do_decode(Bin, true) -> do_decode32hex(Bin). do_decode32hex(<<>>) -> <<>>; do_decode32hex(Bin) -> Offset = decode_offset(Bin), <> = Bin, Main1 = << << (decode32hex(C1)):5/integer, (decode32hex(C2)):5/integer, (decode32hex(C3)):5/integer, (decode32hex(C4)):5/integer, (decode32hex(C5)):5/integer, (decode32hex(C6)):5/integer, (decode32hex(C7)):5/integer, (decode32hex(C8)):5/integer >> || <> <= Main >>, case Rest of <> -> <>; <> -> <>; <> -> <>; <> -> <>; <> -> <>; <> -> <>; <> -> <>; <> -> <>; <> -> <>; _ -> error_info(Bin, incorrect_padding, ?FUNCTION_NAME) end. do_decode32(<<>>) -> <<>>; do_decode32(Bin) -> Offset = decode_offset(Bin), <> = Bin, Main1 = << << (decode32(C1)):5/integer, (decode32(C2)):5/integer, (decode32(C3)):5/integer, (decode32(C4)):5/integer, (decode32(C5)):5/integer, (decode32(C6)):5/integer, (decode32(C7)):5/integer, (decode32(C8)):5/integer >> || <> <= Main >>, case Rest of <> -> <>; <> -> <>; <> -> <>; <> -> <>; <> -> <>; <> -> <>; <> -> <>; <> -> <>; <> -> <>; _ -> error_info(Bin, incorrect_padding, ?FUNCTION_NAME) end. maybe_pad(Acc, false, _) -> Acc; maybe_pad(Acc, true, 6) -> <>; maybe_pad(Acc, true, 4) -> <>; maybe_pad(Acc, true, 3) -> <>; maybe_pad(Acc, true, 1) -> <