r19051: JSON-RPC server work-in-progress. It's almost working.
[jelmer/samba4-debian.git] / jsonrpc / json.esp
1 <%
2
3 /*
4  * Copyright:
5  *   (C) 2006 by Derrell Lipman
6  *       All rights reserved
7  *
8  * License:
9  *   LGPL 2.1: http://creativecommons.org/licenses/LGPL/2.1/
10  */
11
12 /*
13  * This module provides a JSON encoder.
14  */
15
16
17 /* escape a string as required by json */
18 function _escape(s)
19 {
20     var i;
21     var arr = new Array();
22
23     for (i = 0; i < strlen(s); i++)
24     {
25         var c = substr(s, i, 1);
26         if (c == '\x00')
27         {
28             arr[i] = '\\u0000';
29         }
30         if (Json._internal.convert[c] != undefined)
31         {
32             arr[i] = Json._internal.convert[c];
33         }
34         else
35         {
36             arr[i] = c;
37         }
38     }
39
40     if (arr.length == 0)
41     {
42         return "";
43     }
44     
45     return join("", arr);
46 }
47
48 /* encode an arbitrary object.  called recursively, for object and array */
49 function _encode(o)
50 {
51     var type = nativeTypeOf(o);
52
53     if (type == "undefined")
54     {
55         return "null";          /* you really shouldn't count on this! */
56     }
57     else if (type == "null")
58     {
59         return "null";
60     }
61     else if (type == "boolean")
62     {
63         if (o)
64         {
65             return "true";
66         }
67         else
68         {
69             return "false";
70         }
71     }
72     else if (type == "c_function" ||
73              type == "js_function" ||
74              type == "string_c_function")
75     {
76         /* no output */
77     }
78     else if (type == "float" ||
79              type == "integer" ||
80              type == "integer64")
81     {
82         return o + 0;
83     }
84     else if (type == "pointer")
85     {
86         var x = "" + o;
87         return '"' + substr(x, 16, strlen(x) - 16 - 1) + '"';
88     }
89     else if (type == "object")
90     {
91         var buf;
92
93         /* Is this an array or an ordinary object? */
94         if (o["length"] != undefined)
95         {
96             var i;
97
98             /* Assume it's an array if there's a length field */
99             buf = "[";
100             for (i = 0; i < o.length; i++)
101             {
102                 /*
103                  * NOTE: We don't support sparse arrays nor associative
104                  * arrays.  Should we later want to do either, we're supposed
105                  * to send it as an object rather than as an array.
106                  */
107                 if (i > 0)
108                 {
109                     buf = buf + ",";
110                 }
111                 buf = buf + this.encode(o[i]);
112             }
113             buf = buf + "]";
114         }
115         else
116         {
117             /* No length field, so it must be an ordinary object */
118             var key;
119             var first = true;
120
121             buf = "{";
122             for (key in o)
123             {
124                 if (! first)
125                 {
126                     buf = buf + ",";
127                 }
128                 buf = buf + '"' + key + '":' + this.encode(o[key]);
129                 first = false;
130             }
131             buf = buf + "}";
132         }
133
134         return buf;
135     }
136     else if (type == "string")
137     {
138         return '"' + this._internal.escape(o) + '"';
139     }
140     else
141     {
142         return '{ "unknown_object":"' + type + '"}';
143     }
144 }
145
146 /* Allocate the public Json access object */
147 Json = new Object();
148
149 /* Json.encode(): encode an arbitrary object */
150 Json.encode = _encode;
151 _encode = null;
152
153 /* Json.decode(): decode a string into its object form */
154 Json.decode = literal_to_var;
155
156 /* Internal stuff, not for external access */
157 Json._internal = new Object();
158
159 Json._internal.escape = _escape;
160 _escape = null;
161
162 Json._internal.convert = new Object();
163 Json._internal.convert['\b'] = '\\b';
164 Json._internal.convert['\t'] = '\\t';
165 Json._internal.convert['\n'] = '\\n';
166 Json._internal.convert['\f'] = '\\f';
167 Json._internal.convert['\r'] = '\\r';
168 Json._internal.convert['"'] = '\\"';
169 Json._internal.convert['\\'] = '\\\\';
170 Json._internal.convert['\x01'] = '\\u0001';
171 Json._internal.convert['\x02'] = '\\u0002';
172 Json._internal.convert['\x03'] = '\\u0003';
173 Json._internal.convert['\x04'] = '\\u0004';
174 Json._internal.convert['\x05'] = '\\u0005';
175 Json._internal.convert['\x06'] = '\\u0006';
176 Json._internal.convert['\x07'] = '\\u0007';
177 Json._internal.convert['\x08'] = '\\u0008';
178 Json._internal.convert['\x09'] = '\\u0009';
179 Json._internal.convert['\x0a'] = '\\u000a';
180 Json._internal.convert['\x0b'] = '\\u000b';
181 Json._internal.convert['\x0c'] = '\\u000c';
182 Json._internal.convert['\x0d'] = '\\u000d';
183 Json._internal.convert['\x0e'] = '\\u000e';
184 Json._internal.convert['\x0f'] = '\\u000f';
185 Json._internal.convert['\x10'] = '\\u0010';
186 Json._internal.convert['\x11'] = '\\u0011';
187 Json._internal.convert['\x12'] = '\\u0012';
188 Json._internal.convert['\x13'] = '\\u0013';
189 Json._internal.convert['\x14'] = '\\u0014';
190 Json._internal.convert['\x15'] = '\\u0015';
191 Json._internal.convert['\x16'] = '\\u0016';
192 Json._internal.convert['\x17'] = '\\u0017';
193 Json._internal.convert['\x18'] = '\\u0018';
194 Json._internal.convert['\x19'] = '\\u0019';
195 Json._internal.convert['\x1a'] = '\\u001a';
196 Json._internal.convert['\x1b'] = '\\u001b';
197 Json._internal.convert['\x1c'] = '\\u001c';
198 Json._internal.convert['\x1d'] = '\\u001d';
199 Json._internal.convert['\x1e'] = '\\u001e';
200 Json._internal.convert['\x1f'] = '\\u001f';
201 /*
202  * At some point, we probably want to add \x80-\xff as well, and it's then
203  * probably more efficient to generate these strings dynamically.  (Even now
204  * it may be, but this was the the way I started, and so it remains.)
205  */
206
207
208 /* Test it */
209 /*
210 libinclude("base.js");
211 function testFormat()
212 {
213     var test = new Object();
214     test.int = 23;
215     test.str = "hello world";
216     test.float = 223.1;
217     test.bool = true;
218     test.array = new Array();
219     test.array[0] = "hello";
220     test.array[1] = "world";
221     test.obj = new Object();
222     test.obj.int = 1000;
223     test.obj.array = new Array();
224     test.obj.array[0] = 42;
225     test.obj.array[1] = 223;
226     printf("%s\n", Json.encode(test));
227 }
228 testFormat();
229 */
230
231 /*
232 libinclude("base.js");
233 function testParse()
234 {
235     var s;
236
237     s = '{ "x" : 23 }';
238     obj = Json.decode(s);
239     printf("Decode/encode of\n\t%s\nyielded\n\t%s\n\n", s, Json.encode(obj));
240
241     s = '{ "x" : [ 23, 42] }';
242     obj = Json.decode(s);
243     printf("Decode/encode of\n\t%s\nyielded\n\t%s\n\n", s, Json.encode(obj));
244
245     s = '[ 13, 19, { "x" : [ 23, 42] }, 223 ]';
246     obj = Json.decode(s);
247     printf("Decode/encode of\n\t%s\nyielded\n\t%s\n\n", s, Json.encode(obj));
248
249     s = '{ "x" : [ "hi" ] }';
250     obj = Json.decode(s);
251     printf("Decode/encode of\n\t%s\nyielded\n\t%s\n\n", s, Json.encode(obj));
252
253     s = '[ 13, 19, { "x" : [ 23, 42, { "y":{"a":"hello", "b":"world", "c":[1,2,3]}}] }, 223 ]';
254     obj = Json.decode(s);
255     printf("Decode/encode of\n\t%s\nyielded\n\t%s\n\n", s, Json.encode(obj));
256 }
257 testParse();
258 */
259 %>