diff options
Diffstat (limited to 'src/xmlrpc_decode.erl')
-rw-r--r-- | src/xmlrpc_decode.erl | 237 |
1 files changed, 130 insertions, 107 deletions
diff --git a/src/xmlrpc_decode.erl b/src/xmlrpc_decode.erl index af0d72c68..72c78cf4a 100644 --- a/src/xmlrpc_decode.erl +++ b/src/xmlrpc_decode.erl @@ -3,10 +3,10 @@ %% %% Redistribution and use in source and binary forms, with or without %% modification, are permitted provided that the following conditions -%% are met: +%% are met: %% %% 1. Redistributions of source code must retain the above copyright -%% notice, this list of conditions and the following disclaimer. +%% notice, this list of conditions and the following disclaimer. %% 2. Redistributions in binary form must reproduce the above %% copyright notice, this list of conditions and the following %% disclaimer in the documentation and/or other materials provided @@ -25,130 +25,156 @@ %% SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -module(xmlrpc_decode). + -author('jocke@gleipnir.com'). + -export([payload/1]). -include("log.hrl"). + -include_lib("xmerl/include/xmerl.hrl"). payload(Payload) -> ?DEBUG_LOG({scanning_payload, Payload}), case xmerl_scan:string(Payload) of - {error, Reason} -> - ?DEBUG_LOG({error_scanning, Payload, Reason}), - {error, Reason}; - {E, _} -> - ?DEBUG_LOG({decoding_element, E}), - case catch decode_element(E) of - {'EXIT', Reason} -> - ?DEBUG_LOG({error_deconding, E, Reason}), - exit(Reason); - Result -> - ?DEBUG_LOG({result_deconding, E, Result}), - Result - end + {error, Reason} -> + ?DEBUG_LOG({error_scanning, Payload, Reason}), + {error, Reason}; + {E, _} -> + ?DEBUG_LOG({decoding_element, E}), + case catch decode_element(E) of + {'EXIT', Reason} -> + ?DEBUG_LOG({error_deconding, E, Reason}), exit(Reason); + Result -> + ?DEBUG_LOG({result_deconding, E, Result}), Result + end end. -decode_element(#xmlElement{name = methodCall} = MethodCall) - when record(MethodCall, xmlElement) -> - {MethodName, Rest} = - match_element([methodName], MethodCall#xmlElement.content), - TextValue = get_text_value(MethodName#xmlElement.content), +decode_element(#xmlElement{name = methodCall} = + MethodCall) + when is_record(MethodCall, xmlElement) -> + {MethodName, Rest} = match_element([methodName], + MethodCall#xmlElement.content), + TextValue = + get_text_value(MethodName#xmlElement.content), case match_element(normal, [params], Rest) of - {error, {missing_element, _}} -> - {ok, {call, list_to_atom(TextValue), []}}; - {Params, _} -> - DecodedParams = decode_params(Params#xmlElement.content), - {ok, {call, list_to_atom(TextValue), DecodedParams}} + {error, {missing_element, _}} -> + {ok, {call, jlib:binary_to_atom(TextValue), []}}; + {Params, _} -> + DecodedParams = + decode_params(Params#xmlElement.content), + {ok, + {call, jlib:binary_to_atom(TextValue), DecodedParams}} end; -decode_element(#xmlElement{name = methodResponse} = MethodResponse) - when record(MethodResponse, xmlElement) -> - case match_element([fault, params], MethodResponse#xmlElement.content) of - {Fault, _} when Fault#xmlElement.name == fault -> - {Value, _} = match_element([value], Fault#xmlElement.content), - case decode(Value#xmlElement.content) of - {struct, [{faultCode, Code}, - {faultString, String}]} when integer(Code) -> - case xmlrpc_util:is_string(String) of - yes -> {ok, {response, {fault, Code, String}}}; - no -> {error, {bad_string, String}} - end; - _ -> - {error, {bad_element, MethodResponse}} - end; - {Params, _} -> - case decode_params(Params#xmlElement.content) of - [DecodedParam] -> {ok, {response, [DecodedParam]}}; - DecodedParams -> {error, {to_many_params, DecodedParams}} - end +decode_element(#xmlElement{name = methodResponse} = + MethodResponse) + when is_record(MethodResponse, xmlElement) -> + case match_element([fault, params], + MethodResponse#xmlElement.content) + of + {Fault, _} when Fault#xmlElement.name == fault -> + {Value, _} = match_element([value], + Fault#xmlElement.content), + case decode(Value#xmlElement.content) of + {struct, [{faultCode, Code}, {faultString, String}]} + when is_integer(Code) -> + case xmlrpc_util:is_string(String) of + yes -> {ok, {response, {fault, Code, String}}}; + no -> {error, {bad_string, String}} + end; + _ -> {error, {bad_element, MethodResponse}} + end; + {Params, _} -> + case decode_params(Params#xmlElement.content) of + [DecodedParam] -> {ok, {response, [DecodedParam]}}; + DecodedParams -> + {error, {to_many_params, DecodedParams}} + end end; decode_element(E) -> {error, {bad_element, E}}. -match_element(NameList, Content) -> match_element(throw, NameList, Content). +match_element(NameList, Content) -> + match_element(throw, NameList, Content). match_element(Type, NameList, []) -> return(Type, {error, {missing_element, NameList}}); -match_element(Type, NameList, [E|Rest]) when record(E, xmlElement) -> +match_element(Type, NameList, [E | Rest]) + when is_record(E, xmlElement) -> case lists:member(E#xmlElement.name, NameList) of - true -> {E, Rest}; - false -> return(Type, {error, {unexpected_element, E#xmlElement.name}}) + true -> {E, Rest}; + false -> + return(Type, + {error, {unexpected_element, E#xmlElement.name}}) end; -match_element(Type, NameList, [T|Rest]) when record(T, xmlText) -> +match_element(Type, NameList, [T | Rest]) + when is_record(T, xmlText) -> case only_whitespace(T#xmlText.value) of - yes -> match_element(Type, NameList, Rest); - no -> - return(Type, {error, {unexpected_text, T#xmlText.value, NameList}}) + yes -> match_element(Type, NameList, Rest); + no -> + return(Type, + {error, {unexpected_text, T#xmlText.value, NameList}}) end. return(throw, Result) -> throw(Result); return(normal, Result) -> Result. -only_whitespace([]) -> yes; -only_whitespace([$ |Rest]) -> only_whitespace(Rest); -only_whitespace([$\n|Rest]) -> only_whitespace(Rest); -only_whitespace([$\t|Rest]) -> only_whitespace(Rest); +only_whitespace(<<>>) -> yes; +only_whitespace(<<$\s, Rest/binary>>) -> + only_whitespace(Rest); +only_whitespace(<<$\n, Rest/binary>>) -> + only_whitespace(Rest); +only_whitespace(<<$\t, Rest/binary>>) -> + only_whitespace(Rest); only_whitespace(_) -> no. -get_text_value([]) -> []; -get_text_value([T|Rest]) when record(T, xmlText) -> - T#xmlText.value++get_text_value(Rest); +get_text_value([]) -> <<>>; +get_text_value([T | Rest]) when is_record(T, xmlText) -> + <<(list_to_binary(T#xmlText.value))/binary, (get_text_value(Rest))/binary>>; get_text_value(_) -> throw({error, missing_text}). decode_params([]) -> []; decode_params(Content) -> case match_element(normal, [param], Content) of - {error, {missing_element, _}} -> []; - {Param, Rest} -> - {Value, _} = match_element([value], Param#xmlElement.content), - [decode(Value#xmlElement.content)|decode_params(Rest)] + {error, {missing_element, _}} -> []; + {Param, Rest} -> + {Value, _} = match_element([value], + Param#xmlElement.content), + [decode(Value#xmlElement.content) | decode_params(Rest)] end. -decode(Content) when list(Content) -> +decode(Content) when is_list(Content) -> case get_value(Content) of - {text_value, TextValue} -> TextValue; - E -> decode(E) + {text_value, TextValue} -> TextValue; + E -> decode(E) end; -decode(String) when record(String, xmlText) -> String#xmlText.value; +decode(String) when is_record(String, xmlText) -> + String#xmlText.value; decode(Struct) when Struct#xmlElement.name == struct -> {struct, decode_members(Struct#xmlElement.content)}; decode(Array) when Array#xmlElement.name == array -> - {Data, _} = match_element([data], Array#xmlElement.content), + {Data, _} = match_element([data], + Array#xmlElement.content), {array, decode_values(Data#xmlElement.content)}; -decode(Int) when Int#xmlElement.name == int; Int#xmlElement.name == i4 -> +decode(Int) + when Int#xmlElement.name == int; + Int#xmlElement.name == i4 -> TextValue = get_text_value(Int#xmlElement.content), make_integer(TextValue); -decode(Boolean) when Boolean#xmlElement.name == boolean -> +decode(Boolean) + when Boolean#xmlElement.name == boolean -> case get_text_value(Boolean#xmlElement.content) of - "1" -> true; - "0" -> false; - TextValue -> throw({error, {invalid_boolean, TextValue}}) + <<"1">> -> true; + <<"0">> -> false; + TextValue -> + throw({error, {invalid_boolean, TextValue}}) end; decode(String) when String#xmlElement.name == string -> get_text_value(String#xmlElement.content); decode(Double) when Double#xmlElement.name == double -> TextValue = get_text_value(Double#xmlElement.content), make_double(TextValue); -decode(Date) when Date#xmlElement.name == 'dateTime.iso8601' -> +decode(Date) + when Date#xmlElement.name == 'dateTime.iso8601' -> TextValue = get_text_value(Date#xmlElement.content), {date, ensure_iso8601_date(TextValue)}; decode(Base64) when Base64#xmlElement.name == base64 -> @@ -158,61 +184,58 @@ decode(Value) -> throw({error, {bad_value, Value}}). get_value(Content) -> case any_element(Content) of - false -> {text_value, get_text_value(Content)}; - true -> get_element(Content) + false -> {text_value, get_text_value(Content)}; + true -> get_element(Content) end. any_element([]) -> false; -any_element([E|_]) when record(E, xmlElement) -> true; -any_element([_|Rest]) -> any_element(Rest). +any_element([E | _]) when is_record(E, xmlElement) -> true; +any_element([_ | Rest]) -> any_element(Rest). get_element([]) -> throw({error, missing_element}); -get_element([E|_]) when record(E, xmlElement) -> E; -get_element([T|Rest]) when record(T, xmlText) -> +get_element([E | _]) when is_record(E, xmlElement) -> E; +get_element([T | Rest]) when is_record(T, xmlText) -> case only_whitespace(T#xmlText.value) of - yes -> get_element(Rest); - no -> throw({error, {unexpected_text, T#xmlText.value}}) + yes -> get_element(Rest); + no -> throw({error, {unexpected_text, T#xmlText.value}}) end. decode_members(Content) -> case match_element(normal, [member], Content) of - {error, {missing_element, _}} -> []; - {Member, Rest} -> - {Name, Rest2} = match_element([name], Member#xmlElement.content), - TextValue = get_text_value(Name#xmlElement.content), - {Value, _} = match_element([value], Rest2), - [{list_to_atom(TextValue), - decode(Value#xmlElement.content)}|decode_members(Rest)] + {error, {missing_element, _}} -> []; + {Member, Rest} -> + {Name, Rest2} = match_element([name], + Member#xmlElement.content), + TextValue = get_text_value(Name#xmlElement.content), + {Value, _} = match_element([value], Rest2), + [{jlib:binary_to_atom(TextValue), + decode(Value#xmlElement.content)} + | decode_members(Rest)] end. decode_values([]) -> []; decode_values(Content) -> case match_element(normal, [value], Content) of - {error, {missing_element, _}} -> []; - {Value, Rest} -> - [decode(Value#xmlElement.content)|decode_values(Rest)] + {error, {missing_element, _}} -> []; + {Value, Rest} -> + [decode(Value#xmlElement.content) | decode_values(Rest)] end. make_integer(Integer) -> - case catch list_to_integer(Integer) of - {'EXIT', Reason} -> throw({error, {not_integer, Integer}}); - Value -> Value + case catch jlib:binary_to_integer(Integer) of + {'EXIT', _Reason} -> + throw({error, {not_integer, Integer}}); + Value -> Value end. make_double(Double) -> - case catch list_to_float(Double) of - {'EXIT', _} -> throw({error, {not_double, Double}}); - Value -> Value + case catch list_to_float(binary_to_list(Double)) of + {'EXIT', _} -> throw({error, {not_double, Double}}); + Value -> Value end. ensure_iso8601_date(Date) -> - case xmlrpc_util:is_iso8601_date(Date) of - no -> throw({error, {not_iso8601_date, Date}}); - yes -> Date - end. + xmlrpc_util:is_iso8601_date(Date). ensure_base64(Base64) -> - case xmlrpc_util:is_base64(Base64) of - no -> throw({error, {not_base64, Base64}}); - yes -> Base64 - end. + xmlrpc_util:is_base64(Base64). |