1 |
|
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
2 |
|
* |
3 |
|
* ***** BEGIN LICENSE BLOCK ***** |
4 |
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1 |
5 |
|
* |
6 |
|
* The contents of this file are subject to the Mozilla Public License Version |
7 |
|
* 1.1 (the "License"); you may not use this file except in compliance with |
8 |
|
* the License. You may obtain a copy of the License at |
9 |
|
* http://www.mozilla.org/MPL/ |
10 |
|
* |
11 |
|
* Software distributed under the License is distributed on an "AS IS" basis, |
12 |
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License |
13 |
|
* for the specific language governing rights and limitations under the |
14 |
|
* License. |
15 |
|
* |
16 |
|
* The Original Code is Mozilla Communicator client code, released |
17 |
|
* March 31, 1998. |
18 |
|
* |
19 |
|
* The Initial Developer of the Original Code is |
20 |
|
* Netscape Communications Corporation. |
21 |
|
* Portions created by the Initial Developer are Copyright (C) 1998 |
22 |
|
* the Initial Developer. All Rights Reserved. |
23 |
|
* |
24 |
|
* Contributor(s): |
25 |
|
* |
26 |
|
* Alternatively, the contents of this file may be used under the terms of |
27 |
|
* either of the GNU General Public License Version 2 or later (the "GPL"), |
28 |
|
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), |
29 |
|
* in which case the provisions of the GPL or the LGPL are applicable instead |
30 |
|
* of those above. If you wish to allow use of your version of this file only |
31 |
|
* under the terms of either the GPL or the LGPL, and not to allow others to |
32 |
|
* use your version of this file under the terms of the MPL, indicate your |
33 |
|
* decision by deleting the provisions above and replace them with the notice |
34 |
|
* and other provisions required by the GPL or the LGPL. If you do not delete |
35 |
|
* the provisions above, a recipient may use your version of this file under |
36 |
|
* the terms of any one of the MPL, the GPL or the LGPL. |
37 |
|
* |
38 |
|
* ***** END LICENSE BLOCK ***** */ |
39 |
|
#include "jsstddef.h" |
40 |
|
#include "jsconfig.h" |
41 |
|
|
42 |
|
#if JS_HAS_XDR |
43 |
|
|
44 |
|
#include <string.h> |
45 |
|
#include "jstypes.h" |
46 |
|
#include "jsutil.h" /* Added by JSIFY */ |
47 |
|
#include "jsdhash.h" |
48 |
|
#include "jsprf.h" |
49 |
|
#include "jsapi.h" |
50 |
|
#include "jscntxt.h" |
51 |
|
#include "jsnum.h" |
52 |
|
#include "jsobj.h" /* js_XDRObject */ |
53 |
|
#include "jsscript.h" /* js_XDRScript */ |
54 |
|
#include "jsstr.h" |
55 |
|
#include "jsxdrapi.h" |
56 |
|
|
57 |
|
#ifdef DEBUG |
58 |
|
#define DBG(x) x |
59 |
|
#else |
60 |
|
#define DBG(x) ((void)0) |
61 |
|
#endif |
62 |
|
|
63 |
|
typedef struct JSXDRMemState { |
64 |
|
JSXDRState state; |
65 |
|
char *base; |
66 |
|
uint32 count; |
67 |
|
uint32 limit; |
68 |
|
} JSXDRMemState; |
69 |
|
|
70 |
|
#define MEM_BLOCK 8192 |
71 |
|
#define MEM_PRIV(xdr) ((JSXDRMemState *)(xdr)) |
72 |
|
|
73 |
|
#define MEM_BASE(xdr) (MEM_PRIV(xdr)->base) |
74 |
|
#define MEM_COUNT(xdr) (MEM_PRIV(xdr)->count) |
75 |
|
#define MEM_LIMIT(xdr) (MEM_PRIV(xdr)->limit) |
76 |
|
|
77 |
|
#define MEM_LEFT(xdr, bytes) \ |
78 |
|
JS_BEGIN_MACRO \ |
79 |
|
if ((xdr)->mode == JSXDR_DECODE && \ |
80 |
|
MEM_COUNT(xdr) + bytes > MEM_LIMIT(xdr)) { \ |
81 |
|
JS_ReportErrorNumber((xdr)->cx, js_GetErrorMessage, NULL, \ |
82 |
|
JSMSG_END_OF_DATA); \ |
83 |
|
return 0; \ |
84 |
|
} \ |
85 |
|
JS_END_MACRO |
86 |
|
|
87 |
|
#define MEM_NEED(xdr, bytes) \ |
88 |
|
JS_BEGIN_MACRO \ |
89 |
|
if ((xdr)->mode == JSXDR_ENCODE) { \ |
90 |
|
if (MEM_LIMIT(xdr) && \ |
91 |
|
MEM_COUNT(xdr) + bytes > MEM_LIMIT(xdr)) { \ |
92 |
|
uint32 limit_ = JS_ROUNDUP(MEM_COUNT(xdr) + bytes, MEM_BLOCK);\ |
93 |
|
void *data_ = JS_realloc((xdr)->cx, MEM_BASE(xdr), limit_); \ |
94 |
|
if (!data_) \ |
95 |
|
return 0; \ |
96 |
|
MEM_BASE(xdr) = data_; \ |
97 |
|
MEM_LIMIT(xdr) = limit_; \ |
98 |
|
} \ |
99 |
|
} else { \ |
100 |
|
MEM_LEFT(xdr, bytes); \ |
101 |
|
} \ |
102 |
|
JS_END_MACRO |
103 |
|
|
104 |
|
#define MEM_DATA(xdr) ((void *)(MEM_BASE(xdr) + MEM_COUNT(xdr))) |
105 |
|
#define MEM_INCR(xdr,bytes) (MEM_COUNT(xdr) += (bytes)) |
106 |
|
|
107 |
|
static JSBool |
108 |
|
mem_get32(JSXDRState *xdr, uint32 *lp) |
109 |
0 |
{ |
110 |
0 |
MEM_LEFT(xdr, 4); |
111 |
0 |
*lp = *(uint32 *)MEM_DATA(xdr); |
112 |
0 |
MEM_INCR(xdr, 4); |
113 |
0 |
return JS_TRUE; |
114 |
|
} |
115 |
|
|
116 |
|
static JSBool |
117 |
|
mem_set32(JSXDRState *xdr, uint32 *lp) |
118 |
0 |
{ |
119 |
0 |
MEM_NEED(xdr, 4); |
120 |
0 |
*(uint32 *)MEM_DATA(xdr) = *lp; |
121 |
0 |
MEM_INCR(xdr, 4); |
122 |
0 |
return JS_TRUE; |
123 |
|
} |
124 |
|
|
125 |
|
static JSBool |
126 |
|
mem_getbytes(JSXDRState *xdr, char *bytes, uint32 len) |
127 |
0 |
{ |
128 |
0 |
MEM_LEFT(xdr, len); |
129 |
0 |
memcpy(bytes, MEM_DATA(xdr), len); |
130 |
0 |
MEM_INCR(xdr, len); |
131 |
0 |
return JS_TRUE; |
132 |
|
} |
133 |
|
|
134 |
|
static JSBool |
135 |
|
mem_setbytes(JSXDRState *xdr, char *bytes, uint32 len) |
136 |
0 |
{ |
137 |
0 |
MEM_NEED(xdr, len); |
138 |
0 |
memcpy(MEM_DATA(xdr), bytes, len); |
139 |
0 |
MEM_INCR(xdr, len); |
140 |
0 |
return JS_TRUE; |
141 |
|
} |
142 |
|
|
143 |
|
static void * |
144 |
|
mem_raw(JSXDRState *xdr, uint32 len) |
145 |
0 |
{ |
146 |
|
void *data; |
147 |
0 |
if (xdr->mode == JSXDR_ENCODE) { |
148 |
0 |
MEM_NEED(xdr, len); |
149 |
0 |
} else if (xdr->mode == JSXDR_DECODE) { |
150 |
0 |
MEM_LEFT(xdr, len); |
151 |
|
} |
152 |
0 |
data = MEM_DATA(xdr); |
153 |
0 |
MEM_INCR(xdr, len); |
154 |
0 |
return data; |
155 |
|
} |
156 |
|
|
157 |
|
static JSBool |
158 |
|
mem_seek(JSXDRState *xdr, int32 offset, JSXDRWhence whence) |
159 |
0 |
{ |
160 |
0 |
switch (whence) { |
161 |
|
case JSXDR_SEEK_CUR: |
162 |
0 |
if ((int32)MEM_COUNT(xdr) + offset < 0) { |
163 |
0 |
JS_ReportErrorNumber(xdr->cx, js_GetErrorMessage, NULL, |
164 |
|
JSMSG_SEEK_BEYOND_START); |
165 |
0 |
return JS_FALSE; |
166 |
|
} |
167 |
0 |
if (offset > 0) |
168 |
0 |
MEM_NEED(xdr, offset); |
169 |
0 |
MEM_COUNT(xdr) += offset; |
170 |
0 |
return JS_TRUE; |
171 |
|
case JSXDR_SEEK_SET: |
172 |
0 |
if (offset < 0) { |
173 |
0 |
JS_ReportErrorNumber(xdr->cx, js_GetErrorMessage, NULL, |
174 |
|
JSMSG_SEEK_BEYOND_START); |
175 |
0 |
return JS_FALSE; |
176 |
|
} |
177 |
0 |
if (xdr->mode == JSXDR_ENCODE) { |
178 |
0 |
if ((uint32)offset > MEM_COUNT(xdr)) |
179 |
0 |
MEM_NEED(xdr, offset - MEM_COUNT(xdr)); |
180 |
0 |
MEM_COUNT(xdr) = offset; |
181 |
|
} else { |
182 |
0 |
if ((uint32)offset > MEM_LIMIT(xdr)) { |
183 |
0 |
JS_ReportErrorNumber(xdr->cx, js_GetErrorMessage, NULL, |
184 |
|
JSMSG_SEEK_BEYOND_END); |
185 |
0 |
return JS_FALSE; |
186 |
|
} |
187 |
0 |
MEM_COUNT(xdr) = offset; |
188 |
|
} |
189 |
0 |
return JS_TRUE; |
190 |
|
case JSXDR_SEEK_END: |
191 |
0 |
if (offset >= 0 || |
192 |
|
xdr->mode == JSXDR_ENCODE || |
193 |
|
(int32)MEM_LIMIT(xdr) + offset < 0) { |
194 |
0 |
JS_ReportErrorNumber(xdr->cx, js_GetErrorMessage, NULL, |
195 |
|
JSMSG_END_SEEK); |
196 |
0 |
return JS_FALSE; |
197 |
|
} |
198 |
0 |
MEM_COUNT(xdr) = MEM_LIMIT(xdr) + offset; |
199 |
0 |
return JS_TRUE; |
200 |
|
default: { |
201 |
|
char numBuf[12]; |
202 |
0 |
JS_snprintf(numBuf, sizeof numBuf, "%d", whence); |
203 |
0 |
JS_ReportErrorNumber(xdr->cx, js_GetErrorMessage, NULL, |
204 |
|
JSMSG_WHITHER_WHENCE, numBuf); |
205 |
0 |
return JS_FALSE; |
206 |
|
} |
207 |
|
} |
208 |
|
} |
209 |
|
|
210 |
|
static uint32 |
211 |
|
mem_tell(JSXDRState *xdr) |
212 |
0 |
{ |
213 |
0 |
return MEM_COUNT(xdr); |
214 |
|
} |
215 |
|
|
216 |
|
static void |
217 |
|
mem_finalize(JSXDRState *xdr) |
218 |
0 |
{ |
219 |
0 |
JS_free(xdr->cx, MEM_BASE(xdr)); |
220 |
|
} |
221 |
|
|
222 |
|
static JSXDROps xdrmem_ops = { |
223 |
|
mem_get32, mem_set32, mem_getbytes, mem_setbytes, |
224 |
|
mem_raw, mem_seek, mem_tell, mem_finalize |
225 |
|
}; |
226 |
|
|
227 |
|
JS_PUBLIC_API(void) |
228 |
|
JS_XDRInitBase(JSXDRState *xdr, JSXDRMode mode, JSContext *cx) |
229 |
0 |
{ |
230 |
0 |
xdr->mode = mode; |
231 |
0 |
xdr->cx = cx; |
232 |
0 |
xdr->registry = NULL; |
233 |
0 |
xdr->numclasses = xdr->maxclasses = 0; |
234 |
0 |
xdr->reghash = NULL; |
235 |
0 |
xdr->userdata = NULL; |
236 |
|
} |
237 |
|
|
238 |
|
JS_PUBLIC_API(JSXDRState *) |
239 |
|
JS_XDRNewMem(JSContext *cx, JSXDRMode mode) |
240 |
0 |
{ |
241 |
0 |
JSXDRState *xdr = (JSXDRState *) JS_malloc(cx, sizeof(JSXDRMemState)); |
242 |
0 |
if (!xdr) |
243 |
0 |
return NULL; |
244 |
0 |
JS_XDRInitBase(xdr, mode, cx); |
245 |
0 |
if (mode == JSXDR_ENCODE) { |
246 |
0 |
if (!(MEM_BASE(xdr) = JS_malloc(cx, MEM_BLOCK))) { |
247 |
0 |
JS_free(cx, xdr); |
248 |
0 |
return NULL; |
249 |
|
} |
250 |
|
} else { |
251 |
|
/* XXXbe ok, so better not deref MEM_BASE(xdr) if not ENCODE */ |
252 |
0 |
MEM_BASE(xdr) = NULL; |
253 |
|
} |
254 |
0 |
xdr->ops = &xdrmem_ops; |
255 |
0 |
MEM_COUNT(xdr) = 0; |
256 |
0 |
MEM_LIMIT(xdr) = MEM_BLOCK; |
257 |
0 |
return xdr; |
258 |
|
} |
259 |
|
|
260 |
|
JS_PUBLIC_API(void *) |
261 |
|
JS_XDRMemGetData(JSXDRState *xdr, uint32 *lp) |
262 |
0 |
{ |
263 |
0 |
if (xdr->ops != &xdrmem_ops) |
264 |
0 |
return NULL; |
265 |
0 |
*lp = MEM_COUNT(xdr); |
266 |
0 |
return MEM_BASE(xdr); |
267 |
|
} |
268 |
|
|
269 |
|
JS_PUBLIC_API(void) |
270 |
|
JS_XDRMemSetData(JSXDRState *xdr, void *data, uint32 len) |
271 |
0 |
{ |
272 |
0 |
if (xdr->ops != &xdrmem_ops) |
273 |
0 |
return; |
274 |
0 |
MEM_LIMIT(xdr) = len; |
275 |
0 |
MEM_BASE(xdr) = data; |
276 |
0 |
MEM_COUNT(xdr) = 0; |
277 |
|
} |
278 |
|
|
279 |
|
JS_PUBLIC_API(uint32) |
280 |
|
JS_XDRMemDataLeft(JSXDRState *xdr) |
281 |
0 |
{ |
282 |
0 |
if (xdr->ops != &xdrmem_ops) |
283 |
0 |
return 0; |
284 |
0 |
return MEM_LIMIT(xdr) - MEM_COUNT(xdr); |
285 |
|
} |
286 |
|
|
287 |
|
JS_PUBLIC_API(void) |
288 |
|
JS_XDRMemResetData(JSXDRState *xdr) |
289 |
0 |
{ |
290 |
0 |
if (xdr->ops != &xdrmem_ops) |
291 |
0 |
return; |
292 |
0 |
MEM_COUNT(xdr) = 0; |
293 |
|
} |
294 |
|
|
295 |
|
JS_PUBLIC_API(void) |
296 |
|
JS_XDRDestroy(JSXDRState *xdr) |
297 |
0 |
{ |
298 |
0 |
JSContext *cx = xdr->cx; |
299 |
0 |
xdr->ops->finalize(xdr); |
300 |
0 |
if (xdr->registry) { |
301 |
0 |
JS_free(cx, xdr->registry); |
302 |
0 |
if (xdr->reghash) |
303 |
0 |
JS_DHashTableDestroy(xdr->reghash); |
304 |
|
} |
305 |
0 |
JS_free(cx, xdr); |
306 |
|
} |
307 |
|
|
308 |
|
JS_PUBLIC_API(JSBool) |
309 |
|
JS_XDRUint8(JSXDRState *xdr, uint8 *b) |
310 |
0 |
{ |
311 |
0 |
uint32 l = *b; |
312 |
0 |
if (!JS_XDRUint32(xdr, &l)) |
313 |
0 |
return JS_FALSE; |
314 |
0 |
*b = (uint8) l; |
315 |
0 |
return JS_TRUE; |
316 |
|
} |
317 |
|
|
318 |
|
JS_PUBLIC_API(JSBool) |
319 |
|
JS_XDRUint16(JSXDRState *xdr, uint16 *s) |
320 |
0 |
{ |
321 |
0 |
uint32 l = *s; |
322 |
0 |
if (!JS_XDRUint32(xdr, &l)) |
323 |
0 |
return JS_FALSE; |
324 |
0 |
*s = (uint16) l; |
325 |
0 |
return JS_TRUE; |
326 |
|
} |
327 |
|
|
328 |
|
JS_PUBLIC_API(JSBool) |
329 |
|
JS_XDRUint32(JSXDRState *xdr, uint32 *lp) |
330 |
0 |
{ |
331 |
0 |
JSBool ok = JS_TRUE; |
332 |
0 |
if (xdr->mode == JSXDR_ENCODE) { |
333 |
0 |
uint32 xl = JSXDR_SWAB32(*lp); |
334 |
0 |
ok = xdr->ops->set32(xdr, &xl); |
335 |
0 |
} else if (xdr->mode == JSXDR_DECODE) { |
336 |
0 |
ok = xdr->ops->get32(xdr, lp); |
337 |
0 |
*lp = JSXDR_SWAB32(*lp); |
338 |
|
} |
339 |
0 |
return ok; |
340 |
|
} |
341 |
|
|
342 |
|
JS_PUBLIC_API(JSBool) |
343 |
|
JS_XDRBytes(JSXDRState *xdr, char *bytes, uint32 len) |
344 |
0 |
{ |
345 |
|
uint32 padlen; |
346 |
|
static char padbuf[JSXDR_ALIGN-1]; |
347 |
|
|
348 |
0 |
if (xdr->mode == JSXDR_ENCODE) { |
349 |
0 |
if (!xdr->ops->setbytes(xdr, bytes, len)) |
350 |
0 |
return JS_FALSE; |
351 |
|
} else { |
352 |
0 |
if (!xdr->ops->getbytes(xdr, bytes, len)) |
353 |
0 |
return JS_FALSE; |
354 |
|
} |
355 |
0 |
len = xdr->ops->tell(xdr); |
356 |
0 |
if (len % JSXDR_ALIGN) { |
357 |
0 |
padlen = JSXDR_ALIGN - (len % JSXDR_ALIGN); |
358 |
0 |
if (xdr->mode == JSXDR_ENCODE) { |
359 |
0 |
if (!xdr->ops->setbytes(xdr, padbuf, padlen)) |
360 |
0 |
return JS_FALSE; |
361 |
|
} else { |
362 |
0 |
if (!xdr->ops->seek(xdr, padlen, JSXDR_SEEK_CUR)) |
363 |
0 |
return JS_FALSE; |
364 |
|
} |
365 |
|
} |
366 |
0 |
return JS_TRUE; |
367 |
|
} |
368 |
|
|
369 |
|
/** |
370 |
|
* Convert between a C string and the XDR representation: |
371 |
|
* leading 32-bit count, then counted vector of chars, |
372 |
|
* then possibly \0 padding to multiple of 4. |
373 |
|
*/ |
374 |
|
JS_PUBLIC_API(JSBool) |
375 |
|
JS_XDRCString(JSXDRState *xdr, char **sp) |
376 |
0 |
{ |
377 |
|
uint32 len; |
378 |
|
|
379 |
0 |
if (xdr->mode == JSXDR_ENCODE) |
380 |
0 |
len = strlen(*sp); |
381 |
0 |
JS_XDRUint32(xdr, &len); |
382 |
0 |
if (xdr->mode == JSXDR_DECODE) { |
383 |
0 |
if (!(*sp = (char *) JS_malloc(xdr->cx, len + 1))) |
384 |
0 |
return JS_FALSE; |
385 |
|
} |
386 |
0 |
if (!JS_XDRBytes(xdr, *sp, len)) { |
387 |
0 |
if (xdr->mode == JSXDR_DECODE) |
388 |
0 |
JS_free(xdr->cx, *sp); |
389 |
0 |
return JS_FALSE; |
390 |
|
} |
391 |
0 |
if (xdr->mode == JSXDR_DECODE) { |
392 |
0 |
(*sp)[len] = '\0'; |
393 |
0 |
} else if (xdr->mode == JSXDR_FREE) { |
394 |
0 |
JS_free(xdr->cx, *sp); |
395 |
0 |
*sp = NULL; |
396 |
|
} |
397 |
0 |
return JS_TRUE; |
398 |
|
} |
399 |
|
|
400 |
|
JS_PUBLIC_API(JSBool) |
401 |
|
JS_XDRCStringOrNull(JSXDRState *xdr, char **sp) |
402 |
0 |
{ |
403 |
0 |
uint32 null = (*sp == NULL); |
404 |
0 |
if (!JS_XDRUint32(xdr, &null)) |
405 |
0 |
return JS_FALSE; |
406 |
0 |
if (null) { |
407 |
0 |
*sp = NULL; |
408 |
0 |
return JS_TRUE; |
409 |
|
} |
410 |
0 |
return JS_XDRCString(xdr, sp); |
411 |
|
} |
412 |
|
|
413 |
|
/* |
414 |
|
* Convert between a JS (Unicode) string and the XDR representation. |
415 |
|
*/ |
416 |
|
JS_PUBLIC_API(JSBool) |
417 |
|
JS_XDRString(JSXDRState *xdr, JSString **strp) |
418 |
0 |
{ |
419 |
|
uint32 i, len, padlen, nbytes; |
420 |
0 |
jschar *chars = NULL, *raw; |
421 |
|
|
422 |
0 |
if (xdr->mode == JSXDR_ENCODE) |
423 |
0 |
len = JSSTRING_LENGTH(*strp); |
424 |
0 |
if (!JS_XDRUint32(xdr, &len)) |
425 |
0 |
return JS_FALSE; |
426 |
0 |
nbytes = len * sizeof(jschar); |
427 |
|
|
428 |
0 |
if (xdr->mode == JSXDR_DECODE) { |
429 |
0 |
if (!(chars = (jschar *) JS_malloc(xdr->cx, nbytes + sizeof(jschar)))) |
430 |
0 |
return JS_FALSE; |
431 |
|
} else { |
432 |
0 |
chars = JSSTRING_CHARS(*strp); |
433 |
|
} |
434 |
|
|
435 |
0 |
padlen = nbytes % JSXDR_ALIGN; |
436 |
0 |
if (padlen) { |
437 |
0 |
padlen = JSXDR_ALIGN - padlen; |
438 |
0 |
nbytes += padlen; |
439 |
|
} |
440 |
0 |
if (!(raw = (jschar *) xdr->ops->raw(xdr, nbytes))) |
441 |
0 |
goto bad; |
442 |
0 |
if (xdr->mode == JSXDR_ENCODE) { |
443 |
0 |
for (i = 0; i < len; i++) |
444 |
0 |
raw[i] = JSXDR_SWAB16(chars[i]); |
445 |
0 |
if (padlen) |
446 |
0 |
memset((char *)raw + nbytes - padlen, 0, padlen); |
447 |
0 |
} else if (xdr->mode == JSXDR_DECODE) { |
448 |
0 |
for (i = 0; i < len; i++) |
449 |
0 |
chars[i] = JSXDR_SWAB16(raw[i]); |
450 |
0 |
chars[len] = 0; |
451 |
|
|
452 |
0 |
if (!(*strp = JS_NewUCString(xdr->cx, chars, len))) |
453 |
0 |
goto bad; |
454 |
|
} |
455 |
0 |
return JS_TRUE; |
456 |
|
|
457 |
0 |
bad: |
458 |
0 |
if (xdr->mode == JSXDR_DECODE) |
459 |
0 |
JS_free(xdr->cx, chars); |
460 |
0 |
return JS_FALSE; |
461 |
|
} |
462 |
|
|
463 |
|
JS_PUBLIC_API(JSBool) |
464 |
|
JS_XDRStringOrNull(JSXDRState *xdr, JSString **strp) |
465 |
0 |
{ |
466 |
0 |
uint32 null = (*strp == NULL); |
467 |
0 |
if (!JS_XDRUint32(xdr, &null)) |
468 |
0 |
return JS_FALSE; |
469 |
0 |
if (null) { |
470 |
0 |
*strp = NULL; |
471 |
0 |
return JS_TRUE; |
472 |
|
} |
473 |
0 |
return JS_XDRString(xdr, strp); |
474 |
|
} |
475 |
|
|
476 |
|
JS_PUBLIC_API(JSBool) |
477 |
|
JS_XDRDouble(JSXDRState *xdr, jsdouble **dp) |
478 |
0 |
{ |
479 |
|
jsdpun u; |
480 |
|
|
481 |
0 |
if (xdr->mode == JSXDR_ENCODE) |
482 |
0 |
u.d = **dp; |
483 |
0 |
if (!JS_XDRUint32(xdr, &u.s.lo) || !JS_XDRUint32(xdr, &u.s.hi)) |
484 |
0 |
return JS_FALSE; |
485 |
0 |
if (xdr->mode == JSXDR_DECODE) { |
486 |
0 |
*dp = JS_NewDouble(xdr->cx, u.d); |
487 |
0 |
if (!*dp) |
488 |
0 |
return JS_FALSE; |
489 |
|
} |
490 |
0 |
return JS_TRUE; |
491 |
|
} |
492 |
|
|
493 |
|
/* These are magic pseudo-tags: see jsapi.h, near the top, for real tags. */ |
494 |
|
#define JSVAL_XDRNULL 0x8 |
495 |
|
#define JSVAL_XDRVOID 0xA |
496 |
|
|
497 |
|
JS_PUBLIC_API(JSBool) |
498 |
|
JS_XDRValue(JSXDRState *xdr, jsval *vp) |
499 |
0 |
{ |
500 |
|
uint32 type; |
501 |
|
|
502 |
0 |
if (xdr->mode == JSXDR_ENCODE) { |
503 |
0 |
if (JSVAL_IS_NULL(*vp)) |
504 |
0 |
type = JSVAL_XDRNULL; |
505 |
0 |
else if (JSVAL_IS_VOID(*vp)) |
506 |
0 |
type = JSVAL_XDRVOID; |
507 |
|
else |
508 |
0 |
type = JSVAL_TAG(*vp); |
509 |
|
} |
510 |
0 |
if (!JS_XDRUint32(xdr, &type)) |
511 |
0 |
return JS_FALSE; |
512 |
|
|
513 |
0 |
switch (type) { |
514 |
|
case JSVAL_XDRNULL: |
515 |
0 |
*vp = JSVAL_NULL; |
516 |
0 |
break; |
517 |
|
case JSVAL_XDRVOID: |
518 |
0 |
*vp = JSVAL_VOID; |
519 |
0 |
break; |
520 |
|
case JSVAL_STRING: { |
521 |
|
JSString *str; |
522 |
0 |
if (xdr->mode == JSXDR_ENCODE) |
523 |
0 |
str = JSVAL_TO_STRING(*vp); |
524 |
0 |
if (!JS_XDRString(xdr, &str)) |
525 |
0 |
return JS_FALSE; |
526 |
0 |
if (xdr->mode == JSXDR_DECODE) |
527 |
0 |
*vp = STRING_TO_JSVAL(str); |
528 |
|
break; |
529 |
|
} |
530 |
|
case JSVAL_DOUBLE: { |
531 |
|
jsdouble *dp; |
532 |
0 |
if (xdr->mode == JSXDR_ENCODE) |
533 |
0 |
dp = JSVAL_TO_DOUBLE(*vp); |
534 |
0 |
if (!JS_XDRDouble(xdr, &dp)) |
535 |
0 |
return JS_FALSE; |
536 |
0 |
if (xdr->mode == JSXDR_DECODE) |
537 |
0 |
*vp = DOUBLE_TO_JSVAL(dp); |
538 |
|
break; |
539 |
|
} |
540 |
|
case JSVAL_OBJECT: { |
541 |
|
JSObject *obj; |
542 |
0 |
if (xdr->mode == JSXDR_ENCODE) |
543 |
0 |
obj = JSVAL_TO_OBJECT(*vp); |
544 |
0 |
if (!js_XDRObject(xdr, &obj)) |
545 |
0 |
return JS_FALSE; |
546 |
0 |
if (xdr->mode == JSXDR_DECODE) |
547 |
0 |
*vp = OBJECT_TO_JSVAL(obj); |
548 |
|
break; |
549 |
|
} |
550 |
|
case JSVAL_BOOLEAN: { |
551 |
|
uint32 b; |
552 |
0 |
if (xdr->mode == JSXDR_ENCODE) |
553 |
0 |
b = (uint32) JSVAL_TO_BOOLEAN(*vp); |
554 |
0 |
if (!JS_XDRUint32(xdr, &b)) |
555 |
0 |
return JS_FALSE; |
556 |
0 |
if (xdr->mode == JSXDR_DECODE) |
557 |
0 |
*vp = BOOLEAN_TO_JSVAL((JSBool) b); |
558 |
|
break; |
559 |
|
} |
560 |
|
default: { |
561 |
|
uint32 i; |
562 |
|
|
563 |
|
JS_ASSERT(type & JSVAL_INT); |
564 |
0 |
if (xdr->mode == JSXDR_ENCODE) |
565 |
0 |
i = (uint32) JSVAL_TO_INT(*vp); |
566 |
0 |
if (!JS_XDRUint32(xdr, &i)) |
567 |
0 |
return JS_FALSE; |
568 |
0 |
if (xdr->mode == JSXDR_DECODE) |
569 |
0 |
*vp = INT_TO_JSVAL((int32) i); |
570 |
|
break; |
571 |
|
} |
572 |
|
} |
573 |
0 |
return JS_TRUE; |
574 |
|
} |
575 |
|
|
576 |
|
JS_PUBLIC_API(JSBool) |
577 |
|
JS_XDRScript(JSXDRState *xdr, JSScript **scriptp) |
578 |
0 |
{ |
579 |
0 |
if (!js_XDRScript(xdr, scriptp, NULL)) |
580 |
0 |
return JS_FALSE; |
581 |
0 |
if (xdr->mode == JSXDR_DECODE) |
582 |
0 |
js_CallNewScriptHook(xdr->cx, *scriptp, NULL); |
583 |
0 |
return JS_TRUE; |
584 |
|
} |
585 |
|
|
586 |
|
#define CLASS_REGISTRY_MIN 8 |
587 |
|
#define CLASS_INDEX_TO_ID(i) ((i)+1) |
588 |
|
#define CLASS_ID_TO_INDEX(id) ((id)-1) |
589 |
|
|
590 |
|
typedef struct JSRegHashEntry { |
591 |
|
JSDHashEntryHdr hdr; |
592 |
|
const char *name; |
593 |
|
uint32 index; |
594 |
|
} JSRegHashEntry; |
595 |
|
|
596 |
|
JS_PUBLIC_API(JSBool) |
597 |
|
JS_XDRRegisterClass(JSXDRState *xdr, JSClass *clasp, uint32 *idp) |
598 |
0 |
{ |
599 |
|
uintN numclasses, maxclasses; |
600 |
|
JSClass **registry; |
601 |
|
|
602 |
0 |
numclasses = xdr->numclasses; |
603 |
0 |
maxclasses = xdr->maxclasses; |
604 |
0 |
if (numclasses == maxclasses) { |
605 |
0 |
maxclasses = (maxclasses == 0) ? CLASS_REGISTRY_MIN : maxclasses << 1; |
606 |
0 |
registry = (JSClass **) |
607 |
|
JS_realloc(xdr->cx, xdr->registry, maxclasses * sizeof(JSClass *)); |
608 |
0 |
if (!registry) |
609 |
0 |
return JS_FALSE; |
610 |
0 |
xdr->registry = registry; |
611 |
0 |
xdr->maxclasses = maxclasses; |
612 |
|
} else { |
613 |
|
JS_ASSERT(numclasses && numclasses < maxclasses); |
614 |
0 |
registry = xdr->registry; |
615 |
|
} |
616 |
|
|
617 |
0 |
registry[numclasses] = clasp; |
618 |
0 |
if (xdr->reghash) { |
619 |
|
JSRegHashEntry *entry = (JSRegHashEntry *) |
620 |
0 |
JS_DHashTableOperate(xdr->reghash, clasp->name, JS_DHASH_ADD); |
621 |
0 |
if (!entry) { |
622 |
0 |
JS_ReportOutOfMemory(xdr->cx); |
623 |
0 |
return JS_FALSE; |
624 |
|
} |
625 |
0 |
entry->name = clasp->name; |
626 |
0 |
entry->index = numclasses; |
627 |
|
} |
628 |
0 |
*idp = CLASS_INDEX_TO_ID(numclasses); |
629 |
0 |
xdr->numclasses = ++numclasses; |
630 |
0 |
return JS_TRUE; |
631 |
|
} |
632 |
|
|
633 |
|
JS_PUBLIC_API(uint32) |
634 |
|
JS_XDRFindClassIdByName(JSXDRState *xdr, const char *name) |
635 |
0 |
{ |
636 |
|
uintN i, numclasses; |
637 |
|
|
638 |
0 |
numclasses = xdr->numclasses; |
639 |
0 |
if (numclasses >= 10) { |
640 |
|
JSRegHashEntry *entry; |
641 |
|
|
642 |
|
/* Bootstrap reghash from registry on first overpopulated Find. */ |
643 |
0 |
if (!xdr->reghash) { |
644 |
0 |
xdr->reghash = JS_NewDHashTable(JS_DHashGetStubOps(), NULL, |
645 |
|
sizeof(JSRegHashEntry), |
646 |
|
numclasses); |
647 |
0 |
if (xdr->reghash) { |
648 |
0 |
for (i = 0; i < numclasses; i++) { |
649 |
0 |
JSClass *clasp = xdr->registry[i]; |
650 |
0 |
entry = (JSRegHashEntry *) |
651 |
|
JS_DHashTableOperate(xdr->reghash, clasp->name, |
652 |
|
JS_DHASH_ADD); |
653 |
0 |
entry->name = clasp->name; |
654 |
0 |
entry->index = i; |
655 |
|
} |
656 |
|
} |
657 |
|
} |
658 |
|
|
659 |
|
/* If we managed to create reghash, use it for O(1) Find. */ |
660 |
0 |
if (xdr->reghash) { |
661 |
0 |
entry = (JSRegHashEntry *) |
662 |
|
JS_DHashTableOperate(xdr->reghash, name, JS_DHASH_LOOKUP); |
663 |
0 |
if (JS_DHASH_ENTRY_IS_BUSY(&entry->hdr)) |
664 |
0 |
return CLASS_INDEX_TO_ID(entry->index); |
665 |
|
} |
666 |
|
} |
667 |
|
|
668 |
|
/* Only a few classes, or we couldn't malloc reghash: use linear search. */ |
669 |
0 |
for (i = 0; i < numclasses; i++) { |
670 |
0 |
if (!strcmp(name, xdr->registry[i]->name)) |
671 |
0 |
return CLASS_INDEX_TO_ID(i); |
672 |
|
} |
673 |
0 |
return 0; |
674 |
|
} |
675 |
|
|
676 |
|
JS_PUBLIC_API(JSClass *) |
677 |
|
JS_XDRFindClassById(JSXDRState *xdr, uint32 id) |
678 |
0 |
{ |
679 |
0 |
uintN i = CLASS_ID_TO_INDEX(id); |
680 |
|
|
681 |
0 |
if (i >= xdr->numclasses) |
682 |
0 |
return NULL; |
683 |
0 |
return xdr->registry[i]; |
684 |
|
} |
685 |
|
|