aboutsummaryrefslogtreecommitdiff
path: root/src/xmlrpc_encode.erl
blob: a903360dc8825f32145e6807f15317b748930c8a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
%% Copyright (C) 2003 Joakim Greben� <jocke@gleipnir.com>.
%% 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

-type xmlrpc() :: number() | boolean() | binary() |
                  {base64, binary()} | {date, binary()} |
                  {array, [xmlrpc()]} | {struct, [{atom(), xmlrpc()}]}.

-spec payload({call, atom(), [xmlrpc()]} |
              {response, {fault, integer(), binary()} | [xmlrpc()]}) ->
                     binary().

payload({call, Name, Params}) ->
    <<"<?xml version=\"1.0\"?><methodCall><methodName>",
      (jlib:atom_to_binary(Name))/binary,
      "</methodName>",
      (encode_params(Params))/binary,
      "</methodCall>">>;
payload({response, {fault, Code, String}}) ->
    <<"<?xml version=\"1.0\"?><methodResponse><fault"
      "><value><struct><member><name>faultCode</name"
      "><value><int>",
      (jlib:integer_to_binary(Code))/binary,
      "</int></value></member><member><name>faultStr"
      "ing</name><value><string>",
      (escape_string(String))/binary,
      "</string></value></member></struct></value></"
      "fault></methodResponse>">>;
payload({response, []}) ->
    <<"<?xml version=\"1.0\"?><methodResponse></methodResponse>">>;
payload({response, [Param]}) ->
    <<"<?xml version=\"1.0\"?><methodResponse>",
      (encode_params([Param]))/binary,
      "</methodResponse>">>.

encode_params(Params) -> encode_params(Params, <<>>).

encode_params([], <<>>) -> <<>>;
encode_params([], Acc) ->
    <<"<params>", Acc/binary, "</params>">>;
encode_params([Param | Rest], Acc) ->
    EncodedParam = encode(Param),
    NewAcc = <<Acc/binary, "<param><value>",
               EncodedParam/binary, "</value></param>">>,
    encode_params(Rest, NewAcc).

encode({struct, Struct}) ->
    Members = encode_members(Struct),
    <<"<struct>", Members/binary, "</struct>">>;
encode({array, Array}) ->
    Values = encode_values(Array),
    <<"<array><data>", Values/binary, "</data></array>">>;
encode(Integer) when is_integer(Integer) ->
    <<"<int>", (jlib:integer_to_binary(Integer))/binary, "</int>">>;
encode(true) -> <<"<boolean>1</boolean>">>; % duh!
encode(false) -> <<"<boolean>0</boolean>">>; % duh!
encode(Double) when is_float(Double) ->
    list_to_binary(
      [<<"<double>">>, io_lib:format("~p", [Double]),
       <<"</double>">>]);
encode({date, Date}) ->
    <<"<dateTime.iso8601>", Date/binary, "</dateTime.iso8601>">>;
encode({base64, Base64}) ->
    <<"<base64>", Base64/binary, "</base64>">>;
encode(Value) ->
    escape_string(Value).

escape_string(<<>>) -> <<>>;
escape_string(<<$<, Rest/binary>>) ->
    <<"&lt;", (escape_string(Rest))/binary>>;
escape_string(<<$>, Rest/binary>>) ->
    <<"&gt;", (escape_string(Rest))/binary>>;
escape_string(<<$&, Rest/binary>>) ->
    <<"&amp;", (escape_string(Rest))/binary>>;
escape_string(<<C, Rest/binary>>) -> <<C, (escape_string(Rest))/binary>>.

encode_members(Struct) -> encode_members(Struct, <<>>).

encode_members([], Acc) -> Acc;
encode_members([{Name, Value} | Rest], Acc) ->
    NewAcc = <<Acc/binary,
               "<member><name>",
               (jlib:atom_to_binary(Name))/binary,
               "</name><value>",
               (encode(Value))/binary,
               "</value></member>">>,
    encode_members(Rest, NewAcc).

encode_values(Array) -> encode_values(Array, <<>>).

encode_values([], Acc) -> Acc;
encode_values([Value | Rest], Acc) ->
    NewAcc = <<Acc/binary,
               "<value>",
               (encode(Value))/binary,
               "</value>">>,
    encode_values(Rest, NewAcc).