summaryrefslogtreecommitdiffstats
path: root/src/libs/xpcom18a4/xpcom/typelib/xpt/src/xpt_xdr.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/xpcom18a4/xpcom/typelib/xpt/src/xpt_xdr.c')
-rw-r--r--src/libs/xpcom18a4/xpcom/typelib/xpt/src/xpt_xdr.c665
1 files changed, 665 insertions, 0 deletions
diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpt/src/xpt_xdr.c b/src/libs/xpcom18a4/xpcom/typelib/xpt/src/xpt_xdr.c
new file mode 100644
index 00000000..cd9261d0
--- /dev/null
+++ b/src/libs/xpcom18a4/xpcom/typelib/xpt/src/xpt_xdr.c
@@ -0,0 +1,665 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* Implementation of XDR primitives. */
+
+#include "xpt_xdr.h"
+#include "nspr.h"
+#include <string.h> /* strchr */
+
+static PRBool
+CheckForRepeat(XPTCursor *cursor, void **addrp, XPTPool pool, PRUint32 len,
+ XPTCursor *new_cursor, PRBool *already);
+
+#define ENCODING(cursor) \
+ ((cursor)->state->mode == XPT_ENCODE)
+
+#define CURS_POOL_OFFSET_RAW(cursor) \
+ ((cursor)->pool == XPT_HEADER \
+ ? (cursor)->offset \
+ : (XPT_ASSERT((cursor)->state->data_offset), \
+ (cursor)->offset + (cursor)->state->data_offset))
+
+#define CURS_POOL_OFFSET(cursor) \
+ (CURS_POOL_OFFSET_RAW(cursor) - 1)
+
+/* can be used as lvalue */
+#define CURS_POINT(cursor) \
+ ((cursor)->state->pool->data[CURS_POOL_OFFSET(cursor)])
+
+#if defined(DEBUG_shaver) || defined(DEBUG_jband) || defined(DEBUG_mccabe)
+#define DBG(x) printf##x
+#else
+#define DBG(x) (0)
+#endif
+
+/* XXX fail if XPT_DATA and !state->data_offset */
+#define CHECK_COUNT_(cursor, space) \
+ /* if we're in the header, then exceeding the data_offset is illegal */ \
+((cursor)->pool == XPT_HEADER ? \
+ (ENCODING(cursor) && \
+ ((cursor)->state->data_offset && \
+ ((cursor)->offset - 1 + (space) > (cursor)->state->data_offset)) \
+ ? (DBG(("no space left in HEADER %d + %d > %d\n", (cursor)->offset, \
+ (space), (cursor)->state->data_offset)) && PR_FALSE) \
+ : PR_TRUE) : \
+ /* if we're in the data area and we're about to exceed the allocation */ \
+ (CURS_POOL_OFFSET(cursor) + (space) > (cursor)->state->pool->allocated ? \
+ /* then grow if we're in ENCODE mode */ \
+ (ENCODING(cursor) ? GrowPool((cursor)->state->arena, \
+ (cursor)->state->pool, \
+ (cursor)->state->pool->allocated, \
+ 0, CURS_POOL_OFFSET(cursor) + (space)) \
+ /* and fail if we're in DECODE mode */ \
+ : (DBG(("can't extend in DECODE")) && PR_FALSE)) \
+ /* otherwise we're OK */ \
+ : PR_TRUE))
+
+#define CHECK_COUNT(cursor, space) \
+ (CHECK_COUNT_(cursor, space) \
+ ? PR_TRUE \
+ : (XPT_ASSERT(0), \
+ fprintf(stderr, "FATAL: can't no room for %d in cursor\n", space), \
+ PR_FALSE))
+
+/* increase the data allocation for the pool by XPT_GROW_CHUNK */
+#define XPT_GROW_CHUNK 8192
+
+/*
+ * quick and dirty hardcoded hashtable, to avoid dependence on nspr or glib.
+ * XXXmccabe it might turn out that we could use a simpler data structure here.
+ */
+typedef struct XPTHashRecord {
+ void *key;
+ void *value;
+ struct XPTHashRecord *next;
+} XPTHashRecord;
+
+#define XPT_HASHSIZE 512
+
+struct XPTHashTable { /* it's already typedef'ed from before. */
+ XPTHashRecord *buckets[XPT_HASHSIZE];
+ XPTArena *arena;
+};
+
+static XPTHashTable *
+XPT_NewHashTable(XPTArena *arena) {
+ XPTHashTable *table;
+ table = XPT_NEWZAP(arena, XPTHashTable);
+ if (table)
+ table->arena = arena;
+ return table;
+}
+
+static void trimrecord(XPTArena* arena, XPTHashRecord *record) {
+ if (record == NULL)
+ return;
+ trimrecord(arena, record->next);
+ XPT_DELETE(arena, record);
+}
+
+static void
+XPT_HashTableDestroy(XPTHashTable *table) {
+ int i;
+ for (i = 0; i < XPT_HASHSIZE; i++)
+ trimrecord(table->arena, table->buckets[i]);
+ XPT_FREE(table->arena, table);
+}
+
+static void *
+XPT_HashTableAdd(XPTHashTable *table, void *key, void *value) {
+ XPTHashRecord **bucketloc = table->buckets +
+ (((PRUint32)(uintptr_t)key) % XPT_HASHSIZE);
+ XPTHashRecord *bucket;
+
+ while (*bucketloc != NULL)
+ bucketloc = &((*bucketloc)->next);
+
+ bucket = XPT_NEW(table->arena, XPTHashRecord);
+ bucket->key = key;
+ bucket->value = value;
+ bucket->next = NULL;
+ *bucketloc = bucket;
+ return value;
+}
+
+static void *
+XPT_HashTableLookup(XPTHashTable *table, void *key) {
+ XPTHashRecord *bucket = table->buckets[(PRUint32)(uintptr_t)key % XPT_HASHSIZE];
+ while (bucket != NULL) {
+ if (bucket->key == key)
+ return bucket->value;
+ bucket = bucket->next;
+ }
+ return NULL;
+}
+
+XPT_PUBLIC_API(XPTState *)
+XPT_NewXDRState(XPTMode mode, char *data, PRUint32 len)
+{
+ XPTState *state;
+ XPTArena *arena;
+
+ arena = XPT_NewArena(512, sizeof(double), "an XDRState");
+ if (!arena)
+ return NULL;
+
+ state = XPT_NEWZAP(arena, XPTState);
+ if (!state)
+ goto err_free_arena;
+
+ state->arena = arena;
+ state->mode = mode;
+ state->pool = XPT_NEW(arena, XPTDatapool);
+ state->next_cursor[0] = state->next_cursor[1] = 1;
+ if (!state->pool)
+ goto err_free_state;
+
+ state->pool->count = 0;
+ state->pool->offset_map = XPT_NewHashTable(arena);
+
+ if (!state->pool->offset_map)
+ goto err_free_pool;
+ if (mode == XPT_DECODE) {
+ state->pool->data = data;
+ state->pool->allocated = len;
+ } else {
+ state->pool->data = XPT_MALLOC(arena, XPT_GROW_CHUNK);
+ if (!state->pool->data)
+ goto err_free_hash;
+ state->pool->allocated = XPT_GROW_CHUNK;
+ }
+
+ return state;
+
+ err_free_hash:
+ XPT_HashTableDestroy(state->pool->offset_map);
+ err_free_pool:
+ XPT_DELETE(arena, state->pool);
+ err_free_state:
+ XPT_DELETE(arena, state);
+ err_free_arena:
+ if (arena)
+ XPT_DestroyArena(arena);
+ return NULL;
+}
+
+XPT_PUBLIC_API(void)
+XPT_DestroyXDRState(XPTState *state)
+{
+ XPTArena *arena = state->arena;
+
+ if (state->pool->offset_map)
+ XPT_HashTableDestroy(state->pool->offset_map);
+ if (state->mode == XPT_ENCODE)
+ XPT_DELETE(arena, state->pool->data);
+ XPT_DELETE(arena, state->pool);
+ XPT_DELETE(arena, state);
+ if (arena)
+ XPT_DestroyArena(arena);
+}
+
+XPT_PUBLIC_API(void)
+XPT_GetXDRDataLength(XPTState *state, XPTPool pool, PRUint32 *len)
+{
+ *len = state->next_cursor[pool] - 1;
+}
+
+XPT_PUBLIC_API(void)
+XPT_GetXDRData(XPTState *state, XPTPool pool, char **data, PRUint32 *len)
+{
+ if (pool == XPT_HEADER) {
+ *data = state->pool->data;
+ } else {
+ *data = state->pool->data + state->data_offset;
+ }
+ *len = state->next_cursor[pool] - 1;
+}
+
+/* All offsets are 1-based */
+XPT_PUBLIC_API(void)
+XPT_DataOffset(XPTState *state, PRUint32 *data_offsetp)
+{
+ if (state->mode == XPT_DECODE)
+ XPT_SetDataOffset(state, *data_offsetp);
+ else
+ *data_offsetp = state->data_offset;
+}
+
+/* if 'exact' is set use that, else grow by the next chunk but
+ * be sure to grow no less that 'at_least' so that we can't get
+ * behind on required space.
+ */
+static PRBool
+GrowPool(XPTArena *arena, XPTDatapool *pool, PRUint32 old_size,
+ PRUint32 exact, PRUint32 at_least)
+{
+ PRUint32 total_size;
+ char *newdata;
+
+ if (exact) {
+ XPT_ASSERT(exact > pool->allocated);
+ total_size = exact;
+ } else {
+ total_size = pool->allocated + XPT_GROW_CHUNK;
+ if (at_least > total_size)
+ total_size = at_least;
+ }
+
+ newdata = XPT_MALLOC(arena, total_size);
+ if (!newdata)
+ return PR_FALSE;
+ if (pool->data) {
+ if (old_size)
+ memcpy(newdata, pool->data, old_size);
+ XPT_FREE(arena, pool->data);
+ }
+ pool->data = newdata;
+ pool->allocated = total_size;
+ return PR_TRUE;
+}
+
+XPT_PUBLIC_API(void)
+XPT_SetDataOffset(XPTState *state, PRUint32 data_offset)
+{
+ state->data_offset = data_offset;
+ /* make sure we've allocated enough space for the header */
+ if (state->mode == XPT_ENCODE &&
+ data_offset > state->pool->allocated) {
+ (void)GrowPool(state->arena, state->pool, state->pool->allocated,
+ data_offset, 0);
+ }
+}
+
+XPT_PUBLIC_API(PRBool)
+XPT_MakeCursor(XPTState *state, XPTPool pool, PRUint32 len, XPTCursor *cursor)
+{
+ cursor->state = state;
+ cursor->pool = pool;
+ cursor->bits = 0;
+ cursor->offset = state->next_cursor[pool];
+
+ if (!(CHECK_COUNT(cursor, len)))
+ return PR_FALSE;
+
+ /* this check should be in CHECK_CURSOR */
+ if (pool == XPT_DATA && !state->data_offset) {
+ fprintf(stderr, "no data offset for XPT_DATA cursor!\n");
+ return PR_FALSE;
+ }
+
+ state->next_cursor[pool] += len;
+
+ return PR_TRUE;
+}
+
+XPT_PUBLIC_API(PRBool)
+XPT_SeekTo(XPTCursor *cursor, PRUint32 offset)
+{
+ /* XXX do some real checking and update len and stuff */
+ cursor->offset = offset;
+ return PR_TRUE;
+}
+
+XPT_PUBLIC_API(XPTString *)
+XPT_NewString(XPTArena *arena, PRUint16 length, char *bytes)
+{
+ XPTString *str = XPT_NEW(arena, XPTString);
+ if (!str)
+ return NULL;
+ str->length = length;
+ /* Alloc one extra to store the trailing nul. */
+ str->bytes = XPT_MALLOC(arena, length + 1u);
+ if (!str->bytes) {
+ XPT_DELETE(arena, str);
+ return NULL;
+ }
+ memcpy(str->bytes, bytes, length);
+ /* nul-terminate it. */
+ str->bytes[length] = '\0';
+ return str;
+}
+
+XPT_PUBLIC_API(XPTString *)
+XPT_NewStringZ(XPTArena *arena, char *bytes)
+{
+ PRUint32 length = strlen(bytes);
+ if (length > 0xffff)
+ return NULL; /* too long */
+ return XPT_NewString(arena, (PRUint16)length, bytes);
+}
+
+XPT_PUBLIC_API(PRBool)
+XPT_DoStringInline(XPTArena *arena, XPTCursor *cursor, XPTString **strp)
+{
+ XPTString *str = *strp;
+ XPTMode mode = cursor->state->mode;
+ int i;
+
+ if (mode == XPT_DECODE) {
+ str = XPT_NEWZAP(arena, XPTString);
+ if (!str)
+ return PR_FALSE;
+ *strp = str;
+ }
+
+ if (!XPT_Do16(cursor, &str->length))
+ goto error;
+
+ if (mode == XPT_DECODE)
+ if (!(str->bytes = XPT_MALLOC(arena, str->length + 1u)))
+ goto error;
+
+ for (i = 0; i < str->length; i++)
+ if (!XPT_Do8(cursor, (PRUint8 *)&str->bytes[i]))
+ goto error_2;
+
+ if (mode == XPT_DECODE)
+ str->bytes[str->length] = 0;
+
+ return PR_TRUE;
+ error_2:
+ XPT_DELETE(arena, str->bytes);
+ error:
+ XPT_DELETE(arena, str);
+ return PR_FALSE;
+}
+
+XPT_PUBLIC_API(PRBool)
+XPT_DoString(XPTArena *arena, XPTCursor *cursor, XPTString **strp)
+{
+ XPTCursor my_cursor;
+ XPTString *str = *strp;
+ PRBool already;
+
+ XPT_PREAMBLE_NO_ALLOC(cursor, strp, XPT_DATA, str->length + 2, my_cursor,
+ already)
+
+ return XPT_DoStringInline(arena, &my_cursor, strp);
+}
+
+XPT_PUBLIC_API(PRBool)
+XPT_DoCString(XPTArena *arena, XPTCursor *cursor, char **identp)
+{
+ XPTCursor my_cursor;
+ char *ident = *identp;
+ PRUint32 offset = 0;
+
+ XPTMode mode = cursor->state->mode;
+
+ if (mode == XPT_DECODE) {
+ char *start, *end;
+ int len;
+
+ if (!XPT_Do32(cursor, &offset))
+ return PR_FALSE;
+
+ if (!offset) {
+ *identp = NULL;
+ return PR_TRUE;
+ }
+
+ my_cursor.pool = XPT_DATA;
+ my_cursor.offset = offset;
+ my_cursor.state = cursor->state;
+ start = &CURS_POINT(&my_cursor);
+
+ end = strchr(start, 0); /* find the end of the string */
+ if (!end) {
+ fprintf(stderr, "didn't find end of string on decode!\n");
+ return PR_FALSE;
+ }
+ len = end - start;
+ XPT_ASSERT(len > 0);
+
+ ident = XPT_MALLOC(arena, len + 1u);
+ if (!ident)
+ return PR_FALSE;
+
+ memcpy(ident, start, (size_t)len);
+ ident[len] = 0;
+ *identp = ident;
+
+ } else {
+
+ if (!ident) {
+ offset = 0;
+ if (!XPT_Do32(cursor, &offset))
+ return PR_FALSE;
+ return PR_TRUE;
+ }
+
+ if (!XPT_MakeCursor(cursor->state, XPT_DATA, strlen(ident) + 1,
+ &my_cursor) ||
+ !XPT_Do32(cursor, &my_cursor.offset))
+ return PR_FALSE;
+
+ while(*ident)
+ if (!XPT_Do8(&my_cursor, (PRUint8 *)ident++))
+ return PR_FALSE;
+ if (!XPT_Do8(&my_cursor, (PRUint8 *)ident)) /* write trailing zero */
+ return PR_FALSE;
+ }
+
+ return PR_TRUE;
+}
+
+/* XXXjband it bothers me that this is one hashtable instead of two.
+ */
+XPT_PUBLIC_API(PRUint32)
+XPT_GetOffsetForAddr(XPTCursor *cursor, void *addr)
+{
+ return (PRUint32)(uintptr_t)XPT_HashTableLookup(cursor->state->pool->offset_map, addr);
+}
+
+XPT_PUBLIC_API(PRBool)
+XPT_SetOffsetForAddr(XPTCursor *cursor, void *addr, PRUint32 offset)
+{
+ return XPT_HashTableAdd(cursor->state->pool->offset_map,
+ addr, (void *)(uintptr_t)offset) != NULL;
+}
+
+XPT_PUBLIC_API(PRBool)
+XPT_SetAddrForOffset(XPTCursor *cursor, PRUint32 offset, void *addr)
+{
+ return XPT_HashTableAdd(cursor->state->pool->offset_map,
+ (void *)(uintptr_t)offset, addr) != NULL;
+}
+
+XPT_PUBLIC_API(void *)
+XPT_GetAddrForOffset(XPTCursor *cursor, PRUint32 offset)
+{
+ return XPT_HashTableLookup(cursor->state->pool->offset_map, (void *)(uintptr_t)offset);
+}
+
+/* Used by XPT_PREAMBLE_NO_ALLOC. */
+static PRBool
+CheckForRepeat(XPTCursor *cursor, void **addrp, XPTPool pool, PRUint32 len,
+ XPTCursor *new_cursor, PRBool *already)
+{
+ void *last = *addrp;
+
+ *already = PR_FALSE;
+ new_cursor->state = cursor->state;
+ new_cursor->pool = pool;
+ new_cursor->bits = 0;
+
+ if (cursor->state->mode == XPT_DECODE) {
+
+ last = XPT_GetAddrForOffset(new_cursor, new_cursor->offset);
+
+ if (last) {
+ *already = PR_TRUE;
+ *addrp = last;
+ }
+
+ } else {
+
+ new_cursor->offset = XPT_GetOffsetForAddr(new_cursor, last);
+ if (new_cursor->offset) {
+ *already = PR_TRUE;
+ return PR_TRUE;
+ }
+
+ /* haven't already found it, so allocate room for it. */
+ if (!XPT_MakeCursor(cursor->state, pool, len, new_cursor) ||
+ !XPT_SetOffsetForAddr(new_cursor, *addrp, new_cursor->offset))
+ return PR_FALSE;
+ }
+ return PR_TRUE;
+}
+
+/*
+ * IIDs are written in struct order, in the usual big-endian way. From the
+ * typelib file spec:
+ *
+ * "For example, this IID:
+ * {00112233-4455-6677-8899-aabbccddeeff}
+ * is converted to the 128-bit value
+ * 0x00112233445566778899aabbccddeeff
+ * Note that the byte storage order corresponds to the layout of the nsIID
+ * C-struct on a big-endian architecture."
+ *
+ * (http://www.mozilla.org/scriptable/typelib_file.html#iid)
+ */
+XPT_PUBLIC_API(PRBool)
+XPT_DoIID(XPTCursor *cursor, nsID *iidp)
+{
+ int i;
+
+ if (!XPT_Do32(cursor, &iidp->m0) ||
+ !XPT_Do16(cursor, &iidp->m1) ||
+ !XPT_Do16(cursor, &iidp->m2))
+ return PR_FALSE;
+
+ for (i = 0; i < 8; i++)
+ if (!XPT_Do8(cursor, (PRUint8 *)&iidp->m3[i]))
+ return PR_FALSE;
+
+ return PR_TRUE;
+}
+
+XPT_PUBLIC_API(PRBool)
+XPT_Do64(XPTCursor *cursor, PRInt64 *u64p)
+{
+ return XPT_Do32(cursor, (PRUint32 *)u64p) &&
+ XPT_Do32(cursor, ((PRUint32 *)u64p) + 1);
+}
+
+/*
+ * When we're writing 32- or 16-bit quantities, we write a byte at a time to
+ * avoid alignment issues. Someone could come and optimize this to detect
+ * well-aligned cases and do a single store, if they cared. I might care
+ * later.
+ */
+XPT_PUBLIC_API(PRBool)
+XPT_Do32(XPTCursor *cursor, PRUint32 *u32p)
+{
+ union {
+ PRUint8 b8[4];
+ PRUint32 b32;
+ } u;
+
+ if (!CHECK_COUNT(cursor, 4))
+ return PR_FALSE;
+
+ if (ENCODING(cursor)) {
+ u.b32 = XPT_SWAB32(*u32p);
+ CURS_POINT(cursor) = u.b8[0];
+ cursor->offset++;
+ CURS_POINT(cursor) = u.b8[1];
+ cursor->offset++;
+ CURS_POINT(cursor) = u.b8[2];
+ cursor->offset++;
+ CURS_POINT(cursor) = u.b8[3];
+ } else {
+ u.b8[0] = CURS_POINT(cursor);
+ cursor->offset++;
+ u.b8[1] = CURS_POINT(cursor);
+ cursor->offset++;
+ u.b8[2] = CURS_POINT(cursor);
+ cursor->offset++;
+ u.b8[3] = CURS_POINT(cursor);
+ *u32p = XPT_SWAB32(u.b32);
+ }
+ cursor->offset++;
+ return PR_TRUE;
+}
+
+XPT_PUBLIC_API(PRBool)
+XPT_Do16(XPTCursor *cursor, PRUint16 *u16p)
+{
+ union {
+ PRUint8 b8[2];
+ PRUint16 b16;
+ } u;
+
+ if (!CHECK_COUNT(cursor, 2))
+ return PR_FALSE;
+
+ if (ENCODING(cursor)) {
+ u.b16 = XPT_SWAB16(*u16p);
+ CURS_POINT(cursor) = u.b8[0];
+ cursor->offset++;
+ CURS_POINT(cursor) = u.b8[1];
+ } else {
+ u.b8[0] = CURS_POINT(cursor);
+ cursor->offset++;
+ u.b8[1] = CURS_POINT(cursor);
+ *u16p = XPT_SWAB16(u.b16);
+ }
+ cursor->offset++;
+
+ return PR_TRUE;
+}
+
+XPT_PUBLIC_API(PRBool)
+XPT_Do8(XPTCursor *cursor, PRUint8 *u8p)
+{
+ if (!CHECK_COUNT(cursor, 1))
+ return PR_FALSE;
+ if (cursor->state->mode == XPT_ENCODE)
+ CURS_POINT(cursor) = *u8p;
+ else
+ *u8p = CURS_POINT(cursor);
+
+ cursor->offset++;
+
+ return PR_TRUE;
+}
+
+