You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

108 lines
2.9 KiB

% This file is part of Jiffy released under the MIT license.
% See the LICENSE file for more information.
-module(jiffy).
-export([decode/1, encode/1, encode/2]).
-define(NOT_LOADED, not_loaded(?LINE)).
-on_load(init/0).
decode(Data) when is_binary(Data) ->
case nif_decode(Data) of
{error, _} = Error ->
throw(Error);
{partial, EJson} ->
finish_decode(EJson);
EJson ->
EJson
end;
decode(Data) when is_list(Data) ->
decode(iolist_to_binary(Data)).
encode(Data) ->
encode(Data, []).
encode(Data, Options) ->
ForceUTF8 = lists:member(force_utf8, Options),
case nif_encode(Data, Options) of
{error, invalid_string} when ForceUTF8 == true ->
FixedData = jiffy_utf8:fix(Data),
encode(FixedData, Options -- [force_utf8]);
{error, _} = Error ->
throw(Error);
{partial, IOData} ->
finish_encode(IOData, []);
IOData ->
IOData
end.
finish_decode({bignum, Value}) ->
list_to_integer(binary_to_list(Value));
finish_decode({bignum_e, Value}) ->
{IVal, EVal} = case string:to_integer(binary_to_list(Value)) of
{I, [$e | ExpStr]} ->
{E, []} = string:to_integer(ExpStr),
{I, E};
{I, [$E | ExpStr]} ->
{E, []} = string:to_integer(ExpStr),
{I, E}
end,
IVal * math:pow(10, EVal);
finish_decode({bigdbl, Value}) ->
list_to_float(binary_to_list(Value));
finish_decode({Pairs}) when is_list(Pairs) ->
finish_decode_obj(Pairs, []);
finish_decode(Vals) when is_list(Vals) ->
finish_decode_arr(Vals, []);
finish_decode(Val) ->
Val.
finish_decode_obj([], Acc) ->
{lists:reverse(Acc)};
finish_decode_obj([{K, V} | Pairs], Acc) ->
finish_decode_obj(Pairs, [{K, finish_decode(V)} | Acc]).
finish_decode_arr([], Acc) ->
lists:reverse(Acc);
finish_decode_arr([V | Vals], Acc) ->
finish_decode_arr(Vals, [finish_decode(V) | Acc]).
finish_encode([], Acc) ->
%% No reverse! The NIF returned us
%% the pieces in reverse order.
Acc;
finish_encode([<<_/binary>>=B | Rest], Acc) ->
finish_encode(Rest, [B | Acc]);
finish_encode([Val | Rest], Acc) when is_integer(Val) ->
Bin = list_to_binary(integer_to_list(Val)),
finish_encode(Rest, [Bin | Acc]);
finish_encode(_, _) ->
throw({error, invalid_ejson}).
init() ->
PrivDir = case code:priv_dir(?MODULE) of
{error, _} ->
EbinDir = filename:dirname(code:which(?MODULE)),
AppPath = filename:dirname(EbinDir),
filename:join(AppPath, "priv");
Path ->
Path
end,
catch(erlang:load_nif(filename:join(PrivDir, "jiffy"), 0)),
ok.
not_loaded(Line) ->
erlang:nif_error({not_loaded, [{module, ?MODULE}, {line, Line}]}).
nif_decode(_Data) ->
?NOT_LOADED.
nif_encode(_Data, _Options) ->
?NOT_LOADED.