%%%------------------------------------------------------------------- %%% @author cheese %%% @copyright (C) 2014, %%% @doc %%% %%% @end %%% Created : 11. Jan 2014 11:16 AM %%%------------------------------------------------------------------- -module(bytes_extension). -author("cheese"). -include_lib("kernel/include/logger.hrl"). %% API -export([bin_to_hexstr/1, list_to_hexstr/1, hex_to_bytes/1, bcd_int/1, bcd_int_list/1, bcd_string/1, int_as_hex/1, bcd_to_int/1, binary_length/1, binary_pad_left/3, int_to_bcd/1, int_to_bcd/2, last_byte/1, are_equal/2, generate_uuid/0, are_starts_from/2]). -export([hex/1, int_to_hex/1, hex_to_bytes_internal/2, hex_char_num/1, bcdlist_to_integer_list/2, integerlist_to_integer/3, get_int_bcd/1, integerlist_to_string/2, one_string_hex_to_int/1, internal_int_to_bcd/3, internal_last_byte/2, internal_string_to_bcd/2]). hex_char_num($0) -> 0; hex_char_num($1) -> 1; hex_char_num($2) -> 2; hex_char_num($3) -> 3; hex_char_num($4) -> 4; hex_char_num($5) -> 5; hex_char_num($6) -> 6; hex_char_num($7) -> 7; hex_char_num($8) -> 8; hex_char_num($9) -> 9; hex_char_num($A) -> 10; hex_char_num($a) -> 10; hex_char_num($B) -> 11; hex_char_num($b) -> 11; hex_char_num($C) -> 12; hex_char_num($c) -> 12; hex_char_num($D) -> 13; hex_char_num($d) -> 13; hex_char_num($E) -> 14; hex_char_num($e) -> 14; hex_char_num($F) -> 15; hex_char_num($f) -> 15. hex(N) when N == 0 -> $0; hex(N) when N == 1 -> $1; hex(N) when N == 2 -> $2; hex(N) when N == 3 -> $3; hex(N) when N == 4 -> $4; hex(N) when N == 5 -> $5; hex(N) when N == 6 -> $6; hex(N) when N == 7 -> $7; hex(N) when N == 8 -> $8; hex(N) when N == 9 -> $9; hex(N) when N == 10 -> $A; hex(N) when N == 11 -> $B; hex(N) when N == 12 -> $C; hex(N) when N == 13 -> $D; hex(N) when N == 14 -> $E; hex(N) when N == 15 -> $F; hex(_N) -> $?. int_to_hex(N) when N < 256 -> [hex(N div 16), hex(N rem 16)]. list_to_hexstr([]) -> []; list_to_hexstr([H | T]) -> int_to_hex(H) ++ list_to_hexstr(T). bin_to_hexstr(Bytes) -> list_to_bitstring(list_to_hexstr(binary_to_list(Bytes))). hex_to_bytes(Hex) -> Len = length(Hex), case Len rem 2 of 0 -> hex_to_bytes_internal(Hex, []); _ -> {error, {invalid_length, Len}} end. hex_to_bytes_internal([], Acc) -> binary:list_to_bin(lists:reverse(Acc)); hex_to_bytes_internal([L1 | [L2 | Tail]], Acc) -> hex_to_bytes_internal(Tail, [(16 * hex_char_num(L1) + hex_char_num(L2)) | Acc]); hex_to_bytes_internal(In, Acc) -> {error, {invalid_data, In, Acc}}. bcd_int_list(Data) -> HexStr = list_to_hexstr(binary_to_list(Data)), bcdlist_to_integer_list(HexStr, []). bcd_int(Data) -> integerlist_to_integer(lists:reverse(bcd_int_list(Data)), 1, 0). bcd_string(Data) -> integerlist_to_string(bcd_int_list(Data), []). integerlist_to_string([], Res) -> list_to_binary(lists:reverse(Res)); integerlist_to_string([Head | Tail], Res) -> Val = hex(Head), integerlist_to_string(Tail, [Val | Res]). integerlist_to_integer([], _Coef, Res) -> Res; integerlist_to_integer([Head | Tail], Coef, Res) -> integerlist_to_integer(Tail, Coef * 10, Res + Head * Coef). bcdlist_to_integer_list([], Res) -> lists:reverse(Res); bcdlist_to_integer_list([H | Tail], Res) -> bcdlist_to_integer_list(Tail, [get_int_bcd(H) | Res]). get_int_bcd(Val) when Val >= $0, Val < $9; Val == $9 -> Val - $0; get_int_bcd(Val) when Val >= $a, Val < $z; Val == $z -> (Val - $a) + 10; get_int_bcd(Val) when Val >= $A, Val < $Z; Val == $Z -> (Val - $A) + 10. int_as_hex(Int) -> Hi = Int div 10, Low = Int rem 10, Hi * 16 + Low. one_string_hex_to_int(<<"0">>) -> 0; one_string_hex_to_int(<<"1">>) -> 1; one_string_hex_to_int(<<"2">>) -> 2; one_string_hex_to_int(<<"3">>) -> 3; one_string_hex_to_int(<<"4">>) -> 4; one_string_hex_to_int(<<"5">>) -> 5; one_string_hex_to_int(<<"6">>) -> 6; one_string_hex_to_int(<<"7">>) -> 7; one_string_hex_to_int(<<"8">>) -> 8; one_string_hex_to_int(<<"9">>) -> 9; one_string_hex_to_int(<<"A">>) -> 10; one_string_hex_to_int(<<"B">>) -> 11; one_string_hex_to_int(<<"C">>) -> 12; one_string_hex_to_int(<<"D">>) -> 13; one_string_hex_to_int(<<"E">>) -> 14; one_string_hex_to_int(<<"F">>) -> 15. internal_bcd_to_int(<<>>, Res) -> trunc(Res); internal_bcd_to_int(<>, Res) -> N1 = Num div 16, N2 = Num rem 16, Len = binary_length(Tail), internal_bcd_to_int(Tail, (N1 * 10 + N2) * math:pow(10, 2 * Len) + Res). %% 17 -> 16*1+1 -> 11 bcd_to_int(Data) -> internal_bcd_to_int(Data, 0). binary_length(Bytes) -> byte_size(Bytes). %% 12345 => <> => <<1, 35, 69>> int_to_bcd(0) -> <<0>>; int_to_bcd(Num) -> Pow = trunc(math:log10(Num)) div 2 + 1, internal_int_to_bcd(Num, Pow, <<>>). %% 12345 => <> => <<1, 35, 69>> int_to_bcd(Num, CountBytes) -> bytes_extension:binary_pad_left(int_to_bcd(Num), CountBytes, 0). internal_int_to_bcd(Num, 1, Res) -> N_Hi = (Num rem 100) div 10, N_Low = Num rem 10, <>; internal_int_to_bcd(Num, Pow, Res) -> Pow100 = trunc(math:pow(10, Pow * 2)), Pow10 = trunc(math:pow(10, Pow * 2 - 1)), Pow1 = trunc(math:pow(10, Pow * 2 - 2)), N_Hi = (Num rem Pow100 - Num rem Pow10) div Pow10, N_Low = (Num rem Pow10 - Num rem Pow1) div Pow1, internal_int_to_bcd(Num, Pow - 1, <>). binary_pad_left(Bytes, Count, OneByte) -> case binary_length(Bytes) >= Count of true -> Bytes; false -> binary_pad_left(<>, Count, OneByte) end. internal_string_to_bcd(<<>>, Res) -> Res; internal_string_to_bcd(<>, Res) -> ?LOG_INFO("===========================================", []), ?LOG_INFO("Str1: ~w: Str2: ~w", [Str1, Str2]), Num1 = one_string_hex_to_int(<>), Num2 = one_string_hex_to_int(<>), Sum = Num1 * 16 + Num2, ?LOG_INFO("Num1: ~w: Num2: ~w, Val: ~w", [Num1, Num2, Sum]), internal_string_to_bcd(<>, <>); internal_string_to_bcd(InBytes, Res) -> error({error, {internal_string_to_bcd, invalid_param, InBytes, Res}}). last_byte(Data) -> Byte = internal_last_byte(Data, 0), ?LOG_INFO("LastByte: ~w: Data: ~w", [Byte, Data]), Byte. internal_last_byte(<<>>, Prev) -> Prev; internal_last_byte(<>, _Prev) -> internal_last_byte(<>, Head). are_equal(<<>>, <<>>) -> true; are_equal(<>, <>) when Head1 == Head2 -> are_equal(<>, <>); are_equal(_, _) -> false. generate_uuid() -> <> =crypto:strong_rand_bytes(16), Str = io_lib:format("~8.16.0b-~4.16.0b-4~3.16.0b-~4.16.0b-~12.16.0b", [A, B, C band 16#0fff, D band 16#3fff bor 16#8000, E]), list_to_binary(Str). are_starts_from(_, <<>>) -> true; are_starts_from(<>, <>) when HeadMessage == HeadPrefix -> are_starts_from(<>, <>); are_starts_from(_, _) -> false.