Line data Source code
1 : /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /* This Source Code Form is subject to the terms of the Mozilla Public
3 : * License, v. 2.0. If a copy of the MPL was not distributed with this
4 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 :
6 : /* Implementation of XDR primitives. */
7 :
8 : #include "xpt_xdr.h"
9 : #include "nscore.h"
10 : #include <string.h> /* strchr */
11 : #include "mozilla/EndianUtils.h"
12 :
13 : #define CURS_POOL_OFFSET_RAW(cursor) \
14 : ((cursor)->pool == XPT_HEADER \
15 : ? (cursor)->offset \
16 : : (XPT_ASSERT((cursor)->state->data_offset), \
17 : (cursor)->offset + (cursor)->state->data_offset))
18 :
19 : #define CURS_POOL_OFFSET(cursor) \
20 : (CURS_POOL_OFFSET_RAW(cursor) - 1)
21 :
22 : /* can be used as lvalue */
23 : #define CURS_POINT(cursor) \
24 : ((cursor)->state->pool_data[CURS_POOL_OFFSET(cursor)])
25 :
26 : static bool
27 373254 : CHECK_COUNT(NotNull<XPTCursor*> cursor, uint32_t space)
28 : {
29 : // Fail if we're in the data area and about to exceed the allocation.
30 : // XXX Also fail if we're in the data area and !state->data_offset
31 644352 : if (cursor->pool == XPT_DATA &&
32 271098 : (CURS_POOL_OFFSET(cursor) + space > (cursor)->state->pool_allocated)) {
33 0 : XPT_ASSERT(0);
34 0 : fprintf(stderr, "FATAL: no room for %d in cursor\n", space);
35 0 : return false;
36 : }
37 :
38 373254 : return true;
39 : }
40 :
41 : XPT_PUBLIC_API(void)
42 522 : XPT_InitXDRState(XPTState* state, char *data, uint32_t len)
43 : {
44 522 : state->next_cursor[0] = state->next_cursor[1] = 1;
45 522 : state->pool_data = data;
46 522 : state->pool_allocated = len;
47 522 : }
48 :
49 : /* All offsets are 1-based */
50 : XPT_PUBLIC_API(void)
51 522 : XPT_SetDataOffset(XPTState *state, uint32_t data_offset)
52 : {
53 522 : state->data_offset = data_offset;
54 522 : }
55 :
56 : XPT_PUBLIC_API(bool)
57 6924 : XPT_MakeCursor(XPTState *state, XPTPool pool, uint32_t len,
58 : NotNull<XPTCursor*> cursor)
59 : {
60 6924 : cursor->state = state;
61 6924 : cursor->pool = pool;
62 6924 : cursor->bits = 0;
63 6924 : cursor->offset = state->next_cursor[pool];
64 :
65 6924 : if (!(CHECK_COUNT(cursor, len)))
66 0 : return false;
67 :
68 : /* this check should be in CHECK_CURSOR */
69 6924 : if (pool == XPT_DATA && !state->data_offset) {
70 0 : fprintf(stderr, "no data offset for XPT_DATA cursor!\n");
71 0 : return false;
72 : }
73 :
74 6924 : state->next_cursor[pool] += len;
75 :
76 6924 : return true;
77 : }
78 :
79 : XPT_PUBLIC_API(bool)
80 522 : XPT_SeekTo(NotNull<XPTCursor*> cursor, uint32_t offset)
81 : {
82 : /* XXX do some real checking and update len and stuff */
83 522 : cursor->offset = offset;
84 522 : return true;
85 : }
86 :
87 : XPT_PUBLIC_API(bool)
88 0 : XPT_SkipStringInline(NotNull<XPTCursor*> cursor)
89 : {
90 : uint16_t length;
91 0 : if (!XPT_Do16(cursor, &length))
92 0 : return false;
93 :
94 : uint8_t byte;
95 0 : for (uint16_t i = 0; i < length; i++)
96 0 : if (!XPT_Do8(cursor, &byte))
97 0 : return false;
98 :
99 0 : return true;
100 : }
101 :
102 : XPT_PUBLIC_API(bool)
103 46113 : XPT_DoCString(XPTArena *arena, NotNull<XPTCursor*> cursor, char **identp,
104 : bool ignore)
105 : {
106 46113 : uint32_t offset = 0;
107 46113 : if (!XPT_Do32(cursor, &offset))
108 0 : return false;
109 :
110 46113 : if (!offset) {
111 6402 : *identp = NULL;
112 6402 : return true;
113 : }
114 :
115 : XPTCursor my_cursor;
116 39711 : my_cursor.pool = XPT_DATA;
117 39711 : my_cursor.offset = offset;
118 39711 : my_cursor.state = cursor->state;
119 39711 : char* start = &CURS_POINT(&my_cursor);
120 :
121 39711 : char* end = strchr(start, 0); /* find the end of the string */
122 39711 : if (!end) {
123 0 : fprintf(stderr, "didn't find end of string on decode!\n");
124 0 : return false;
125 : }
126 39711 : int len = end - start;
127 39711 : XPT_ASSERT(len > 0);
128 :
129 39711 : if (!ignore) {
130 39711 : char *ident = (char*)XPT_CALLOC1(arena, len + 1u);
131 39711 : if (!ident)
132 0 : return false;
133 :
134 39711 : memcpy(ident, start, (size_t)len);
135 39711 : ident[len] = 0;
136 39711 : *identp = ident;
137 : }
138 :
139 39711 : return true;
140 : }
141 :
142 : /*
143 : * IIDs are written in struct order, in the usual big-endian way. From the
144 : * typelib file spec:
145 : *
146 : * "For example, this IID:
147 : * {00112233-4455-6677-8899-aabbccddeeff}
148 : * is converted to the 128-bit value
149 : * 0x00112233445566778899aabbccddeeff
150 : * Note that the byte storage order corresponds to the layout of the nsIID
151 : * C-struct on a big-endian architecture."
152 : *
153 : * (http://www.mozilla.org/scriptable/typelib_file.html#iid)
154 : */
155 : XPT_PUBLIC_API(bool)
156 6402 : XPT_DoIID(NotNull<XPTCursor*> cursor, nsID *iidp)
157 : {
158 : int i;
159 :
160 19206 : if (!XPT_Do32(cursor, &iidp->m0) ||
161 12804 : !XPT_Do16(cursor, &iidp->m1) ||
162 6402 : !XPT_Do16(cursor, &iidp->m2))
163 0 : return false;
164 :
165 57618 : for (i = 0; i < 8; i++)
166 51216 : if (!XPT_Do8(cursor, (uint8_t *)&iidp->m3[i]))
167 0 : return false;
168 :
169 6402 : return true;
170 : }
171 :
172 : // MSVC apparently cannot handle functions as template parameters very well,
173 : // so we need to use a macro approach here.
174 :
175 : #define XPT_DOINT(T, func, valuep) \
176 : do { \
177 : const size_t sz = sizeof(T); \
178 : \
179 : if (!CHECK_COUNT(cursor, sz)) { \
180 : return false; \
181 : } \
182 : \
183 : *valuep = func(&CURS_POINT(cursor)); \
184 : cursor->offset += sz; \
185 : return true; \
186 : } while(0)
187 :
188 : XPT_PUBLIC_API(bool)
189 0 : XPT_Do64(NotNull<XPTCursor*> cursor, int64_t *u64p)
190 : {
191 0 : XPT_DOINT(int64_t, mozilla::BigEndian::readInt64, u64p);
192 : }
193 :
194 : /*
195 : * When we're handling 32- or 16-bit quantities, we handle a byte at a time to
196 : * avoid alignment issues. Someone could come and optimize this to detect
197 : * well-aligned cases and do a single store, if they cared. I might care
198 : * later.
199 : */
200 : XPT_PUBLIC_API(bool)
201 66471 : XPT_Do32(NotNull<XPTCursor*> cursor, uint32_t *u32p)
202 : {
203 66471 : XPT_DOINT(uint32_t, mozilla::BigEndian::readUint32, u32p);
204 : }
205 :
206 : XPT_PUBLIC_API(bool)
207 38868 : XPT_Do16(NotNull<XPTCursor*> cursor, uint16_t *u16p)
208 : {
209 38868 : XPT_DOINT(uint16_t, mozilla::BigEndian::readUint16, u16p);
210 : }
211 :
212 : #undef XPT_DOINT
213 :
214 : XPT_PUBLIC_API(bool)
215 260991 : XPT_Do8(NotNull<XPTCursor*> cursor, uint8_t *u8p)
216 : {
217 260991 : if (!CHECK_COUNT(cursor, 1))
218 0 : return false;
219 :
220 260991 : *u8p = CURS_POINT(cursor);
221 :
222 260991 : cursor->offset++;
223 :
224 260991 : return true;
225 : }
226 :
227 :
|