%%% vim:ts=4:sw=4:et %%%----------------------------------------------------------------------------- %%% Date: 2015-12-10 %%%----------------------------------------------------------------------------- %%% Copyright (c) 2015 Serge Aleynikov %%% %%% Permission is hereby granted, free of charge, to any person %%% obtaining a copy of this software and associated documentation %%% files (the "Software"), to deal in the Software without restriction, %%% including without limitation the rights to use, copy, modify, merge, %%% publish, distribute, sublicense, and/or sell copies of the Software, %%% and to permit persons to whom the Software is furnished to do %%% so, subject to the following conditions: %%% %%% The above copyright notice and this permission notice shall be included %%% in all copies or substantial portions of the Software. %%% %%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, %%% EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF %%% MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. %%% IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY %%% CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, %%% TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE %%% SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. %%%----------------------------------------------------------------------------- -module(hex). -moduledoc """ Hexadecimal conversion functions Author: Serge Aleynikov """. -author('saleyn@gmail.com'). -export([to_hex/1, to_bin/1, to_int/1]). -export([hex/1, dehex/1]). -ifdef(TEST). -include_lib("eunit/include/eunit.hrl"). -endif. %%%----------------------------------------------------------------------------- %%% External API %%%----------------------------------------------------------------------------- -doc "Convert an iolist to a hex string.". -spec to_hex(integer()|iolist()) -> binary(). to_hex(0) -> <<"0">>; to_hex(I) when is_integer(I), I > 0 -> to_hex_int(I, []); to_hex(L) when is_list(L) -> to_hex_bin(iolist_to_binary(L)); to_hex(B) when is_binary(B) -> to_hex_bin(B). -doc "Convert a hex string to binary.". -spec to_bin(string()) -> binary(). to_bin(Bin) when is_binary(Bin) -> << <<((dehex(A) bsl 4) bor dehex(B))>> || <> <= Bin >>; to_bin(L) when is_list(L) -> iolist_to_binary(to_bin2(L)). -doc "Convert a hex string/binary to integer.". -spec to_int(string()|binary()) -> integer(). to_int(S) when is_list(S) -> erlang:list_to_integer (S, 16); to_int(B) when is_binary(B) -> erlang:binary_to_integer(B, 16). -doc "Convert a hex digit in range [$0..$9,$a..$f,$A..$F] to integer.". -spec dehex(char()) -> integer(). dehex(C) when C >= $0, C =< $9 -> C - $0; dehex(C) when C >= $a, C =< $f -> C - ($a - 10); dehex(C) when C >= $A, C =< $F -> C - ($A - 10). -doc "Convert an integer to a hex digit in range [0..15].". -spec hex(integer()) -> char(). hex(C) when C >= 0, C =< 9 -> C + $0; hex(C) when C =< 15 -> C + ($a - 10). %%%----------------------------------------------------------------------------- %%% Internal functions %%%----------------------------------------------------------------------------- to_bin2([A,B | T]) -> [((dehex(A) bsl 4) bor dehex(B)) | to_bin2(T)]; to_bin2([]) -> []. to_hex_bin(Bin) -> << <<(hex(A)), (hex(B))>> || <> <= Bin >>. to_hex_int(0, Acc) -> list_to_binary(Acc); to_hex_int(I, Acc) -> to_hex_int(I bsr 4, [hex(I band 15) | Acc]). %%%----------------------------------------------------------------------------- %%% Tests %%%----------------------------------------------------------------------------- -ifdef(EUNIT). all_test() -> <<"0">> = to_hex(0), <<"912ec803b2ce49e4a541068d495ab570">> = to_hex([145,46,200,3,178,206,73,228,165,65,6,141,73,90,181,112]), <<"fffefdfcfbfa1009080701">> = to_hex(16#fffefdfcfbfa1009080701), <<>> = to_bin(<<"0">>), <<0>> = to_bin("00"), <<0>> = to_bin(<<"00">>), <<255,254,253,252,251,250,16,9,8,7,1>> = to_bin(<<"fffefdfcfbfa1009080701">>), <<255,254,253,252,251,250,16,9,8,7,1>> = to_bin(<<"FFFEFDFCFBFA1009080701">>), 0 = to_int("0"), 0 = to_int(<<"0">>), 16#fffefdfcfbfa1009080701 = to_int("fffefdfcfbfa1009080701"), 16#fffefdfcfbfa1009080701 = to_int(<<"fffefdfcfbfa1009080701">>), ok. -endif.