1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
3
* ***** BEGIN LICENSE BLOCK *****
4
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
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/
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
16
* The Original Code is Mozilla Communicator client code, released
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.
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.
38
* ***** END LICENSE BLOCK ***** */
46
#include "jsutil.h" /* Added by JSIFY */
52
#include "jsobj.h" /* js_XDRObject */
53
#include "jsscript.h" /* js_XDRScript */
60
#define DBG(x) ((void)0)
63
typedef struct JSXDRMemState {
70
#define MEM_BLOCK 8192
71
#define MEM_PRIV(xdr) ((JSXDRMemState *)(xdr))
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)
77
#define MEM_LEFT(xdr, bytes) \
79
if ((xdr)->mode == JSXDR_DECODE && \
80
MEM_COUNT(xdr) + bytes > MEM_LIMIT(xdr)) { \
81
JS_ReportErrorNumber((xdr)->cx, js_GetErrorMessage, NULL, \
87
#define MEM_NEED(xdr, bytes) \
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_); \
96
MEM_BASE(xdr) = data_; \
97
MEM_LIMIT(xdr) = limit_; \
100
MEM_LEFT(xdr, bytes); \
104
#define MEM_DATA(xdr) ((void *)(MEM_BASE(xdr) + MEM_COUNT(xdr)))
105
#define MEM_INCR(xdr,bytes) (MEM_COUNT(xdr) += (bytes))
108
mem_get32(JSXDRState *xdr, uint32 *lp)
111
*lp = *(uint32 *)MEM_DATA(xdr);
117
mem_set32(JSXDRState *xdr, uint32 *lp)
120
*(uint32 *)MEM_DATA(xdr) = *lp;
126
mem_getbytes(JSXDRState *xdr, char *bytes, uint32 len)
129
memcpy(bytes, MEM_DATA(xdr), len);
135
mem_setbytes(JSXDRState *xdr, char *bytes, uint32 len)
138
memcpy(MEM_DATA(xdr), bytes, len);
144
mem_raw(JSXDRState *xdr, uint32 len)
147
if (xdr->mode == JSXDR_ENCODE) {
149
} else if (xdr->mode == JSXDR_DECODE) {
152
data = MEM_DATA(xdr);
158
mem_seek(JSXDRState *xdr, int32 offset, JSXDRWhence whence)
162
if ((int32)MEM_COUNT(xdr) + offset < 0) {
163
JS_ReportErrorNumber(xdr->cx, js_GetErrorMessage, NULL,
164
JSMSG_SEEK_BEYOND_START);
168
MEM_NEED(xdr, offset);
169
MEM_COUNT(xdr) += offset;
173
JS_ReportErrorNumber(xdr->cx, js_GetErrorMessage, NULL,
174
JSMSG_SEEK_BEYOND_START);
177
if (xdr->mode == JSXDR_ENCODE) {
178
if ((uint32)offset > MEM_COUNT(xdr))
179
MEM_NEED(xdr, offset - MEM_COUNT(xdr));
180
MEM_COUNT(xdr) = offset;
182
if ((uint32)offset > MEM_LIMIT(xdr)) {
183
JS_ReportErrorNumber(xdr->cx, js_GetErrorMessage, NULL,
184
JSMSG_SEEK_BEYOND_END);
187
MEM_COUNT(xdr) = offset;
192
xdr->mode == JSXDR_ENCODE ||
193
(int32)MEM_LIMIT(xdr) + offset < 0) {
194
JS_ReportErrorNumber(xdr->cx, js_GetErrorMessage, NULL,
198
MEM_COUNT(xdr) = MEM_LIMIT(xdr) + offset;
202
JS_snprintf(numBuf, sizeof numBuf, "%d", whence);
203
JS_ReportErrorNumber(xdr->cx, js_GetErrorMessage, NULL,
204
JSMSG_WHITHER_WHENCE, numBuf);
211
mem_tell(JSXDRState *xdr)
213
return MEM_COUNT(xdr);
217
mem_finalize(JSXDRState *xdr)
219
JS_free(xdr->cx, MEM_BASE(xdr));
222
static JSXDROps xdrmem_ops = {
223
mem_get32, mem_set32, mem_getbytes, mem_setbytes,
224
mem_raw, mem_seek, mem_tell, mem_finalize
228
JS_XDRInitBase(JSXDRState *xdr, JSXDRMode mode, JSContext *cx)
232
xdr->registry = NULL;
233
xdr->numclasses = xdr->maxclasses = 0;
235
xdr->userdata = NULL;
238
JS_PUBLIC_API(JSXDRState *)
239
JS_XDRNewMem(JSContext *cx, JSXDRMode mode)
241
JSXDRState *xdr = (JSXDRState *) JS_malloc(cx, sizeof(JSXDRMemState));
244
JS_XDRInitBase(xdr, mode, cx);
245
if (mode == JSXDR_ENCODE) {
246
if (!(MEM_BASE(xdr) = JS_malloc(cx, MEM_BLOCK))) {
251
/* XXXbe ok, so better not deref MEM_BASE(xdr) if not ENCODE */
252
MEM_BASE(xdr) = NULL;
254
xdr->ops = &xdrmem_ops;
256
MEM_LIMIT(xdr) = MEM_BLOCK;
260
JS_PUBLIC_API(void *)
261
JS_XDRMemGetData(JSXDRState *xdr, uint32 *lp)
263
if (xdr->ops != &xdrmem_ops)
265
*lp = MEM_COUNT(xdr);
266
return MEM_BASE(xdr);
270
JS_XDRMemSetData(JSXDRState *xdr, void *data, uint32 len)
272
if (xdr->ops != &xdrmem_ops)
274
MEM_LIMIT(xdr) = len;
275
MEM_BASE(xdr) = data;
279
JS_PUBLIC_API(uint32)
280
JS_XDRMemDataLeft(JSXDRState *xdr)
282
if (xdr->ops != &xdrmem_ops)
284
return MEM_LIMIT(xdr) - MEM_COUNT(xdr);
288
JS_XDRMemResetData(JSXDRState *xdr)
290
if (xdr->ops != &xdrmem_ops)
296
JS_XDRDestroy(JSXDRState *xdr)
298
JSContext *cx = xdr->cx;
299
xdr->ops->finalize(xdr);
301
JS_free(cx, xdr->registry);
303
JS_DHashTableDestroy(xdr->reghash);
308
JS_PUBLIC_API(JSBool)
309
JS_XDRUint8(JSXDRState *xdr, uint8 *b)
312
if (!JS_XDRUint32(xdr, &l))
318
JS_PUBLIC_API(JSBool)
319
JS_XDRUint16(JSXDRState *xdr, uint16 *s)
322
if (!JS_XDRUint32(xdr, &l))
328
JS_PUBLIC_API(JSBool)
329
JS_XDRUint32(JSXDRState *xdr, uint32 *lp)
332
if (xdr->mode == JSXDR_ENCODE) {
333
uint32 xl = JSXDR_SWAB32(*lp);
334
ok = xdr->ops->set32(xdr, &xl);
335
} else if (xdr->mode == JSXDR_DECODE) {
336
ok = xdr->ops->get32(xdr, lp);
337
*lp = JSXDR_SWAB32(*lp);
342
JS_PUBLIC_API(JSBool)
343
JS_XDRBytes(JSXDRState *xdr, char *bytes, uint32 len)
346
static char padbuf[JSXDR_ALIGN-1];
348
if (xdr->mode == JSXDR_ENCODE) {
349
if (!xdr->ops->setbytes(xdr, bytes, len))
352
if (!xdr->ops->getbytes(xdr, bytes, len))
355
len = xdr->ops->tell(xdr);
356
if (len % JSXDR_ALIGN) {
357
padlen = JSXDR_ALIGN - (len % JSXDR_ALIGN);
358
if (xdr->mode == JSXDR_ENCODE) {
359
if (!xdr->ops->setbytes(xdr, padbuf, padlen))
362
if (!xdr->ops->seek(xdr, padlen, JSXDR_SEEK_CUR))
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.
374
JS_PUBLIC_API(JSBool)
375
JS_XDRCString(JSXDRState *xdr, char **sp)
379
if (xdr->mode == JSXDR_ENCODE)
381
JS_XDRUint32(xdr, &len);
382
if (xdr->mode == JSXDR_DECODE) {
383
if (!(*sp = (char *) JS_malloc(xdr->cx, len + 1)))
386
if (!JS_XDRBytes(xdr, *sp, len)) {
387
if (xdr->mode == JSXDR_DECODE)
388
JS_free(xdr->cx, *sp);
391
if (xdr->mode == JSXDR_DECODE) {
393
} else if (xdr->mode == JSXDR_FREE) {
394
JS_free(xdr->cx, *sp);
400
JS_PUBLIC_API(JSBool)
401
JS_XDRCStringOrNull(JSXDRState *xdr, char **sp)
403
uint32 null = (*sp == NULL);
404
if (!JS_XDRUint32(xdr, &null))
410
return JS_XDRCString(xdr, sp);
414
* Convert between a JS (Unicode) string and the XDR representation.
416
JS_PUBLIC_API(JSBool)
417
JS_XDRString(JSXDRState *xdr, JSString **strp)
419
uint32 i, len, padlen, nbytes;
420
jschar *chars = NULL, *raw;
422
if (xdr->mode == JSXDR_ENCODE)
423
len = JSSTRING_LENGTH(*strp);
424
if (!JS_XDRUint32(xdr, &len))
426
nbytes = len * sizeof(jschar);
428
if (xdr->mode == JSXDR_DECODE) {
429
if (!(chars = (jschar *) JS_malloc(xdr->cx, nbytes + sizeof(jschar))))
432
chars = JSSTRING_CHARS(*strp);
435
padlen = nbytes % JSXDR_ALIGN;
437
padlen = JSXDR_ALIGN - padlen;
440
if (!(raw = (jschar *) xdr->ops->raw(xdr, nbytes)))
442
if (xdr->mode == JSXDR_ENCODE) {
443
for (i = 0; i < len; i++)
444
raw[i] = JSXDR_SWAB16(chars[i]);
446
memset((char *)raw + nbytes - padlen, 0, padlen);
447
} else if (xdr->mode == JSXDR_DECODE) {
448
for (i = 0; i < len; i++)
449
chars[i] = JSXDR_SWAB16(raw[i]);
452
if (!(*strp = JS_NewUCString(xdr->cx, chars, len)))
458
if (xdr->mode == JSXDR_DECODE)
459
JS_free(xdr->cx, chars);
463
JS_PUBLIC_API(JSBool)
464
JS_XDRStringOrNull(JSXDRState *xdr, JSString **strp)
466
uint32 null = (*strp == NULL);
467
if (!JS_XDRUint32(xdr, &null))
473
return JS_XDRString(xdr, strp);
476
JS_PUBLIC_API(JSBool)
477
JS_XDRDouble(JSXDRState *xdr, jsdouble **dp)
481
if (xdr->mode == JSXDR_ENCODE)
483
if (!JS_XDRUint32(xdr, &u.s.lo) || !JS_XDRUint32(xdr, &u.s.hi))
485
if (xdr->mode == JSXDR_DECODE) {
486
*dp = JS_NewDouble(xdr->cx, u.d);
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
497
JS_PUBLIC_API(JSBool)
498
JS_XDRValue(JSXDRState *xdr, jsval *vp)
502
if (xdr->mode == JSXDR_ENCODE) {
503
if (JSVAL_IS_NULL(*vp))
504
type = JSVAL_XDRNULL;
505
else if (JSVAL_IS_VOID(*vp))
506
type = JSVAL_XDRVOID;
508
type = JSVAL_TAG(*vp);
510
if (!JS_XDRUint32(xdr, &type))
522
if (xdr->mode == JSXDR_ENCODE)
523
str = JSVAL_TO_STRING(*vp);
524
if (!JS_XDRString(xdr, &str))
526
if (xdr->mode == JSXDR_DECODE)
527
*vp = STRING_TO_JSVAL(str);
532
if (xdr->mode == JSXDR_ENCODE)
533
dp = JSVAL_TO_DOUBLE(*vp);
534
if (!JS_XDRDouble(xdr, &dp))
536
if (xdr->mode == JSXDR_DECODE)
537
*vp = DOUBLE_TO_JSVAL(dp);
542
if (xdr->mode == JSXDR_ENCODE)
543
obj = JSVAL_TO_OBJECT(*vp);
544
if (!js_XDRObject(xdr, &obj))
546
if (xdr->mode == JSXDR_DECODE)
547
*vp = OBJECT_TO_JSVAL(obj);
550
case JSVAL_BOOLEAN: {
552
if (xdr->mode == JSXDR_ENCODE)
553
b = (uint32) JSVAL_TO_BOOLEAN(*vp);
554
if (!JS_XDRUint32(xdr, &b))
556
if (xdr->mode == JSXDR_DECODE)
557
*vp = BOOLEAN_TO_JSVAL((JSBool) b);
563
JS_ASSERT(type & JSVAL_INT);
564
if (xdr->mode == JSXDR_ENCODE)
565
i = (uint32) JSVAL_TO_INT(*vp);
566
if (!JS_XDRUint32(xdr, &i))
568
if (xdr->mode == JSXDR_DECODE)
569
*vp = INT_TO_JSVAL((int32) i);
576
JS_PUBLIC_API(JSBool)
577
JS_XDRScript(JSXDRState *xdr, JSScript **scriptp)
579
if (!js_XDRScript(xdr, scriptp, NULL))
581
if (xdr->mode == JSXDR_DECODE)
582
js_CallNewScriptHook(xdr->cx, *scriptp, NULL);
586
#define CLASS_REGISTRY_MIN 8
587
#define CLASS_INDEX_TO_ID(i) ((i)+1)
588
#define CLASS_ID_TO_INDEX(id) ((id)-1)
590
typedef struct JSRegHashEntry {
596
JS_PUBLIC_API(JSBool)
597
JS_XDRRegisterClass(JSXDRState *xdr, JSClass *clasp, uint32 *idp)
599
uintN numclasses, maxclasses;
602
numclasses = xdr->numclasses;
603
maxclasses = xdr->maxclasses;
604
if (numclasses == maxclasses) {
605
maxclasses = (maxclasses == 0) ? CLASS_REGISTRY_MIN : maxclasses << 1;
606
registry = (JSClass **)
607
JS_realloc(xdr->cx, xdr->registry, maxclasses * sizeof(JSClass *));
610
xdr->registry = registry;
611
xdr->maxclasses = maxclasses;
613
JS_ASSERT(numclasses && numclasses < maxclasses);
614
registry = xdr->registry;
617
registry[numclasses] = clasp;
619
JSRegHashEntry *entry = (JSRegHashEntry *)
620
JS_DHashTableOperate(xdr->reghash, clasp->name, JS_DHASH_ADD);
622
JS_ReportOutOfMemory(xdr->cx);
625
entry->name = clasp->name;
626
entry->index = numclasses;
628
*idp = CLASS_INDEX_TO_ID(numclasses);
629
xdr->numclasses = ++numclasses;
633
JS_PUBLIC_API(uint32)
634
JS_XDRFindClassIdByName(JSXDRState *xdr, const char *name)
638
numclasses = xdr->numclasses;
639
if (numclasses >= 10) {
640
JSRegHashEntry *entry;
642
/* Bootstrap reghash from registry on first overpopulated Find. */
644
xdr->reghash = JS_NewDHashTable(JS_DHashGetStubOps(), NULL,
645
sizeof(JSRegHashEntry),
648
for (i = 0; i < numclasses; i++) {
649
JSClass *clasp = xdr->registry[i];
650
entry = (JSRegHashEntry *)
651
JS_DHashTableOperate(xdr->reghash, clasp->name,
653
entry->name = clasp->name;
659
/* If we managed to create reghash, use it for O(1) Find. */
661
entry = (JSRegHashEntry *)
662
JS_DHashTableOperate(xdr->reghash, name, JS_DHASH_LOOKUP);
663
if (JS_DHASH_ENTRY_IS_BUSY(&entry->hdr))
664
return CLASS_INDEX_TO_ID(entry->index);
668
/* Only a few classes, or we couldn't malloc reghash: use linear search. */
669
for (i = 0; i < numclasses; i++) {
670
if (!strcmp(name, xdr->registry[i]->name))
671
return CLASS_INDEX_TO_ID(i);
676
JS_PUBLIC_API(JSClass *)
677
JS_XDRFindClassById(JSXDRState *xdr, uint32 id)
679
uintN i = CLASS_ID_TO_INDEX(id);
681
if (i >= xdr->numclasses)
683
return xdr->registry[i];
686
#endif /* JS_HAS_XDR */