-module(nitro_conv).
%%-author('Maxim Sokhatsky').
%% N2O Formatter: JSON, BERT
-compile(export_all).
-include_lib("nitro/include/nitro.hrl").
% WF to_list to_atom to_binary to_integer
-define(IS_STRING(Term),
(erlang:is_list(Term) andalso Term /= [] andalso erlang:is_integer(hd(Term)))).
-ifndef(N2O_JSON).
-define(N2O_JSON, (application:get_env(n2o,json,jsone))).
-endif.
to_list(L) when ?IS_STRING(L) -> L;
to_list(L) when erlang:is_list(L) ->
SubLists = [inner_to_list(X) || X <- L],
lists:flatten(SubLists);
to_list(A) -> inner_to_list(A).
inner_to_list(A) when erlang:is_atom(A) -> erlang:atom_to_list(A);
inner_to_list(B) when erlang:is_binary(B) -> erlang:binary_to_list(B);
inner_to_list(I) when erlang:is_integer(I) -> erlang:integer_to_list(I);
inner_to_list(L) when erlang:is_tuple(L) -> lists:flatten(io_lib:format("~p", [L]));
inner_to_list(L) when erlang:is_list(L) -> L;
inner_to_list(F) when erlang:is_float(F) -> erlang:float_to_list(F, [{decimals, 9}, compact]).
to_atom(A) when erlang:is_atom(A) -> A;
to_atom(B) when erlang:is_binary(B) -> erlang:binary_to_atom(B);
to_atom(I) when erlang:is_integer(I) -> to_atom(erlang:integer_to_list(I));
to_atom(F) when erlang:is_float(F) -> to_atom(erlang:float_to_list(F, [{decimals, 9}, compact]));
to_atom(L) when erlang:is_list(L) -> erlang:list_to_atom(L).
to_binary(A) when erlang:is_atom(A) -> erlang:atom_to_binary(A, latin1);
to_binary(B) when erlang:is_binary(B) -> B;
to_binary(I) when erlang:is_integer(I) -> erlang:integer_to_binary(I);
to_binary(F) when erlang:is_float(F) -> erlang:float_to_binary(F, [{decimals, 9}, compact]);
to_binary(L) when erlang:is_list(L) -> erlang:iolist_to_binary(L);
to_binary(X) when erlang:is_tuple(X) -> erlang:term_to_binary(X).
to_integer(A) when erlang:is_atom(A) -> to_integer(erlang:atom_to_list(A));
to_integer(B) when erlang:is_binary(B) -> to_integer(erlang:binary_to_list(B));
to_integer(I) when erlang:is_integer(I) -> I;
to_integer([]) -> 0;
to_integer(L) when erlang:is_list(L) -> erlang:list_to_integer(L);
to_integer(F) when erlang:is_float(F) -> erlang:round(F).
%% HTML encode/decode
%% html_encode(B, normal)
html_encode(L, Fun) when erlang:is_function(Fun) ->
Fun(L);
html_encode(L, EncType) when erlang:is_atom(L) ->
html_encode(nitro:to_list(L), EncType);
html_encode(L, EncType) when erlang:is_integer(L) ->
html_encode(erlang:integer_to_list(L), EncType);
html_encode(L, EncType) when erlang:is_float(L) ->
html_encode(erlang:float_to_list(L, [{decimals, 9}, compact]), EncType);
html_encode(L, false) ->
L;
html_encode(L, true) ->
L;
html_encode(L, whites) ->
html_encode_whites(nitro:to_list(lists:flatten([L]))).
html_encode(<<>>) ->
[];
html_encode([]) ->
[];
html_encode(B) when is_binary(B) ->
nitro:to_binary(
html_encode(erlang:binary_to_list(B))
);
html_encode([$\n |T]) ->
"
" ++ html_encode(T);
html_encode([H|T]) ->
case H of
$< -> "<" ++ html_encode(T);
$> -> ">" ++ html_encode(T);
$" -> """ ++ html_encode(T);
$' -> "'" ++ html_encode(T);
$& -> "&" ++ html_encode(T);
$\\ -> "\" ++ html_encode(T);
BigNum when erlang:is_integer(BigNum) andalso BigNum > 255 ->
%% Any integers above 255 are converted to their HTML encode equivalent
%% Example: 7534 gets turned into ᵮ
[$&, $# | nitro:to_list(BigNum)] ++ ";" ++ html_encode(T);
Tup when erlang:is_tuple(Tup) ->
erlang:throw({html_encode, encountered_tuple, Tup});
_ ->
[H|html_encode(T)]
end.
html_encode_whites([]) -> [];
html_encode_whites([H|T]) ->
case H of
$\s -> " " ++ html_encode_whites(T);
$\t -> " " ++ html_encode_whites(T);
$< -> "<" ++ html_encode_whites(T);
$> -> ">" ++ html_encode_whites(T);
$" -> """ ++ html_encode_whites(T);
$' -> "'" ++ html_encode_whites(T);
$& -> "&" ++ html_encode_whites(T);
$\n -> "
" ++ html_encode_whites(T);
$\\ -> "\" ++ html_encode_whites(T);
_ -> [H|html_encode_whites(T)]
end.
%% URL encode/decode
-define(PERCENT, 37). % $\%
-define(FULLSTOP, 46). % $\.
-define(IS_HEX(C), ((C >= $0 andalso C =< $9) orelse
(C >= $a andalso C =< $f) orelse
(C >= $A andalso C =< $F))).
-define(QS_SAFE(C), ((C >= $a andalso C =< $z) orelse
(C >= $A andalso C =< $Z) orelse
(C >= $0 andalso C =< $9) orelse
(C =:= ?FULLSTOP orelse C =:= $- orelse
C =:= $~ orelse C =:= $_))).
url_encode(Atom) when erlang:is_atom(Atom) ->
url_encode(erlang:atom_to_list(Atom));
url_encode(Int) when erlang:is_integer(Int) ->
url_encode(erlang:integer_to_list(Int));
url_encode(Bin) when erlang:is_binary(Bin) ->
url_encode(erlang:binary_to_list(Bin));
url_encode(String) ->
url_encode(String, []).
url_encode([], Acc) ->
lists:reverse(Acc);
url_encode([C | Rest], Acc) when ?QS_SAFE(C) ->
url_encode(Rest, [C | Acc]);
url_encode([$\s | Rest], Acc) ->
url_encode(Rest, [$+ | Acc]);
url_encode([C | Rest], Acc) ->
<> = <>,
url_encode(Rest, [digit(Lo), digit(Hi), ?PERCENT | Acc]).
url_decode(Binary) when erlang:is_binary(Binary) ->
url_decode(erlang:binary_to_list(Binary));
url_decode(String) -> url_decode_h(lists:reverse(String)).
unhexdigit(C) when C >= $0, C =< $9 ->
C - $0;
unhexdigit(C) when C >= $a, C =< $f ->
C - $a + 10;
unhexdigit(C) when C >= $A, C =< $F ->
C - $A + 10.
url_decode_h(S) -> url_decode_h(S, []).
url_decode_h([], Acc) -> Acc;
url_decode_h([$+ | Rest], Acc) ->
url_decode_h(Rest, [$\s | Acc]);
url_decode_h([Lo, Hi, ?PERCENT | Rest], Acc) when ?IS_HEX(Lo), ?IS_HEX(Hi) ->
url_decode_h(Rest, [(unhexdigit(Lo) bor (unhexdigit(Hi) bsl 4)) | Acc]);
url_decode_h([C | Rest], Acc) -> url_decode_h(Rest, [C | Acc]).
%% JavaScript escape
js_escape(undefined) -> [];
js_escape(Value) when erlang:is_list(Value) ->
erlang:binary_to_list( js_escape( erlang:iolist_to_binary(Value) ) );
js_escape(Value) -> js_escape(Value, <<>>).
js_escape(<<"\\", Rest/binary>>, Acc) -> %"
js_escape(Rest, <>); %"
js_escape(<<"\r", Rest/binary>>, Acc) ->
js_escape(Rest, <>);
js_escape(<<"\n", Rest/binary>>, Acc) ->
js_escape(Rest, <>);
js_escape(<<"\"", Rest/binary>>, Acc) ->
js_escape(Rest, <>);
js_escape(<<"'", Rest/binary>>, Acc) ->
js_escape(Rest, <>);
js_escape(<<"`", Rest/binary>>, Acc) ->
js_escape(Rest, <>);
js_escape(<<"