mirror of
https://github.com/classilla/tenfourfox.git
synced 2024-07-05 12:29:01 +00:00
637 lines
18 KiB
C++
637 lines
18 KiB
C++
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
/* Implementation of XDR primitives. */
|
|
|
|
#include "xpt_xdr.h"
|
|
#include "nspr.h"
|
|
#include "nscore.h"
|
|
#include <string.h> /* strchr */
|
|
|
|
static PRBool
|
|
CheckForRepeat(XPTCursor *cursor, void **addrp, XPTPool pool, uint32_t 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 +
|
|
(NS_PTR_TO_UINT32(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[NS_PTR_TO_UINT32(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, uint32_t 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 = (char*)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, uint32_t *len)
|
|
{
|
|
*len = state->next_cursor[pool] - 1;
|
|
}
|
|
|
|
XPT_PUBLIC_API(void)
|
|
XPT_GetXDRData(XPTState *state, XPTPool pool, char **data, uint32_t *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, uint32_t *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, uint32_t old_size,
|
|
uint32_t exact, uint32_t at_least)
|
|
{
|
|
uint32_t 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 = (char*)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, uint32_t 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, uint32_t 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, uint32_t 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, uint16_t length, const 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 = (char*)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, const char *bytes)
|
|
{
|
|
uint32_t length = strlen(bytes);
|
|
if (length > 0xffff)
|
|
return NULL; /* too long */
|
|
return XPT_NewString(arena, (uint16_t)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 = (char*)XPT_MALLOC(arena, str->length + 1u)))
|
|
goto error;
|
|
|
|
for (i = 0; i < str->length; i++)
|
|
if (!XPT_Do8(cursor, (uint8_t *)&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 + 2u, 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;
|
|
uint32_t 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 = (char*)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, (uint8_t *)ident++))
|
|
return PR_FALSE;
|
|
if (!XPT_Do8(&my_cursor, (uint8_t *)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(uint32_t)
|
|
XPT_GetOffsetForAddr(XPTCursor *cursor, void *addr)
|
|
{
|
|
XPTHashTable *table = cursor->state->pool->offset_map;
|
|
return NS_PTR_TO_UINT32(XPT_HashTableLookup(table, addr));
|
|
}
|
|
|
|
XPT_PUBLIC_API(PRBool)
|
|
XPT_SetOffsetForAddr(XPTCursor *cursor, void *addr, uint32_t offset)
|
|
{
|
|
return XPT_HashTableAdd(cursor->state->pool->offset_map,
|
|
addr, NS_INT32_TO_PTR(offset)) != NULL;
|
|
}
|
|
|
|
XPT_PUBLIC_API(PRBool)
|
|
XPT_SetAddrForOffset(XPTCursor *cursor, uint32_t offset, void *addr)
|
|
{
|
|
return XPT_HashTableAdd(cursor->state->pool->offset_map,
|
|
NS_INT32_TO_PTR(offset), addr) != NULL;
|
|
}
|
|
|
|
XPT_PUBLIC_API(void *)
|
|
XPT_GetAddrForOffset(XPTCursor *cursor, uint32_t offset)
|
|
{
|
|
return XPT_HashTableLookup(cursor->state->pool->offset_map,
|
|
NS_INT32_TO_PTR(offset));
|
|
}
|
|
|
|
/* Used by XPT_PREAMBLE_NO_ALLOC. */
|
|
static PRBool
|
|
CheckForRepeat(XPTCursor *cursor, void **addrp, XPTPool pool, uint32_t 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, (uint8_t *)&iidp->m3[i]))
|
|
return PR_FALSE;
|
|
|
|
return PR_TRUE;
|
|
}
|
|
|
|
XPT_PUBLIC_API(PRBool)
|
|
XPT_Do64(XPTCursor *cursor, int64_t *u64p)
|
|
{
|
|
return XPT_Do32(cursor, (uint32_t *)u64p) &&
|
|
XPT_Do32(cursor, ((uint32_t *)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, uint32_t *u32p)
|
|
{
|
|
union {
|
|
uint8_t b8[4];
|
|
uint32_t 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, uint16_t *u16p)
|
|
{
|
|
union {
|
|
uint8_t b8[2];
|
|
uint16_t 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, uint8_t *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;
|
|
}
|
|
|
|
|