%% Copyright (C) 2003 Joakim Grebenö . %% All rights reserved. %% %% Redistribution and use in source and binary forms, with or without %% modification, are permitted provided that the following conditions %% are met: %% %% 1. Redistributions of source code must retain the above copyright %% 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 %% with the distribution. %% %% THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS %% OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED %% WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE %% ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY %% DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL %% DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE %% GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS %% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, %% WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING %% NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS %% SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -module(xmlrpc_encode). -author('jocke@gleipnir.com'). -export([payload/1]). %% Exported: payload/1 payload({call, Name, Params}) when atom(Name), list(Params) -> case encode_params(Params) of {error, Reason} -> {error, Reason}; EncodedParams -> EncodedPayload = ["", atom_to_list(Name), "", EncodedParams, ""], {ok, EncodedPayload} end; payload({response, {fault, Code, String}}) when integer(Code) -> case xmlrpc_util:is_string(String) of yes -> EncodedPayload = ["" "faultCode", integer_to_list(Code), "" "faultString", escape_string(String), "", ""], {ok, EncodedPayload}; no -> {error, {bad_string, String}} end; payload({response, []} = Payload) -> {ok, [""]}; payload({response, [Param]} = Payload) -> case encode_params([Param]) of {error, Reason} -> {error, Reason}; EncodedParam -> {ok, ["", EncodedParam, ""]} end; payload(Payload) -> {error, {bad_payload, Payload}}. encode_params(Params) -> encode_params(Params, []). encode_params([], []) -> []; encode_params([], Acc) -> ["", Acc, ""]; encode_params([Param|Rest], Acc) -> case encode(Param) of {error, Reason} -> {error, Reason}; EncodedParam -> NewAcc = Acc++["", EncodedParam, ""], encode_params(Rest, NewAcc) end. encode({struct, Struct}) -> case encode_members(Struct) of {error, Reason} -> {error, Reason}; Members -> ["", Members, ""] end; encode({array, Array}) when list(Array) -> case encode_values(Array)of {error, Reason} -> {error, Reason}; Values -> ["", Values, ""] end; encode(Integer) when integer(Integer) -> ["", integer_to_list(Integer), ""]; encode(true) -> "1"; % duh! encode(false) -> "0"; % duh! encode(Double) when float(Double) -> ["", io_lib:format("~p", [Double]), ""]; encode({date, Date}) -> case xmlrpc_util:is_iso8601_date(Date) of yes -> ["", Date, ""]; no -> {error, {bad_date, Date}} end; encode({base64, Base64}) -> case xmlrpc_util:is_base64(Base64) of yes -> ["", Base64, ""]; no -> {error, {bad_base64, Base64}} end; encode(Value) -> case xmlrpc_util:is_string(Value) of yes -> escape_string(Value); no -> {error, {bad_value, Value}} end. escape_string([]) -> []; escape_string([$<|Rest]) -> ["<", escape_string(Rest)]; escape_string([$>|Rest]) -> [">", escape_string(Rest)]; escape_string([$&|Rest]) -> ["&", escape_string(Rest)]; escape_string([C|Rest]) -> [C|escape_string(Rest)]. encode_members(Struct) -> encode_members(Struct, []). encode_members([], Acc) -> Acc; encode_members([{Name, Value}|Rest], Acc) when atom(Name) -> case encode(Value) of {error, Reason} -> {error, Reason}; EncodedValue -> NewAcc = Acc++["", atom_to_list(Name), "", EncodedValue, ""], encode_members(Rest, NewAcc) end; encode_members([{Name, Value}|Rest], Acc) -> {error, {invalid_name, Name}}; encode_members(UnknownMember, Acc) -> {error, {unknown_member, UnknownMember}}. encode_values(Array) -> encode_values(Array, []). encode_values([], Acc) -> Acc; encode_values([Value|Rest], Acc) -> case encode(Value) of {error, Reason} -> {error, Reason}; EncodedValue -> NewAcc = Acc++["", EncodedValue, ""], encode_values(Rest, NewAcc) end; encode_values([{Name, Value}|Rest], Acc) -> {error, {invalid_name, Name}}; encode_values(UnknownMember, Acc) -> {error, {unknown_member, UnknownMember}}.