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 routines for typelib structures. */
7 :
8 : #include "xpt_xdr.h"
9 : #include "xpt_struct.h"
10 : #include <string.h>
11 : #include <stdio.h>
12 :
13 : using mozilla::WrapNotNull;
14 :
15 : /***************************************************************************/
16 : /* Forward declarations. */
17 :
18 : static bool
19 : DoInterfaceDirectoryEntry(XPTArena *arena, NotNull<XPTCursor*> cursor,
20 : XPTInterfaceDirectoryEntry *ide);
21 :
22 : static bool
23 : DoConstDescriptor(XPTArena *arena, NotNull<XPTCursor*> cursor,
24 : XPTConstDescriptor *cd, XPTInterfaceDescriptor *id);
25 :
26 : static bool
27 : DoMethodDescriptor(XPTArena *arena, NotNull<XPTCursor*> cursor,
28 : XPTMethodDescriptor *md, XPTInterfaceDescriptor *id);
29 :
30 : static bool
31 : SkipAnnotation(NotNull<XPTCursor*> cursor, bool *isLast);
32 :
33 : static bool
34 : DoInterfaceDescriptor(XPTArena *arena, NotNull<XPTCursor*> outer,
35 : XPTInterfaceDescriptor **idp);
36 :
37 : static bool
38 : DoTypeDescriptorPrefix(XPTArena *arena, NotNull<XPTCursor*> cursor,
39 : XPTTypeDescriptorPrefix *tdp);
40 :
41 : static bool
42 : DoTypeDescriptor(XPTArena *arena, NotNull<XPTCursor*> cursor,
43 : XPTTypeDescriptor *td, XPTInterfaceDescriptor *id);
44 :
45 : static bool
46 : DoParamDescriptor(XPTArena *arena, NotNull<XPTCursor*> cursor,
47 : XPTParamDescriptor *pd, XPTInterfaceDescriptor *id);
48 :
49 : /***************************************************************************/
50 :
51 : XPT_PUBLIC_API(bool)
52 522 : XPT_DoHeader(XPTArena *arena, NotNull<XPTCursor*> cursor, XPTHeader **headerp)
53 : {
54 : unsigned int i;
55 522 : uint32_t file_length = 0;
56 : uint32_t ide_offset;
57 :
58 522 : XPTHeader* header = XPT_NEWZAP(arena, XPTHeader);
59 522 : if (!header)
60 0 : return false;
61 522 : *headerp = header;
62 :
63 : uint8_t magic[16];
64 8874 : for (i = 0; i < sizeof(magic); i++) {
65 8352 : if (!XPT_Do8(cursor, &magic[i]))
66 0 : return false;
67 : }
68 :
69 522 : if (strncmp((const char*)magic, XPT_MAGIC, 16) != 0) {
70 : /* Require that the header contain the proper magic */
71 : fprintf(stderr,
72 : "libxpt: bad magic header in input file; "
73 : "found '%s', expected '%s'\n",
74 0 : magic, XPT_MAGIC_STRING);
75 0 : return false;
76 : }
77 :
78 1044 : if (!XPT_Do8(cursor, &header->major_version) ||
79 522 : !XPT_Do8(cursor, &header->minor_version)) {
80 0 : return false;
81 : }
82 :
83 522 : if (header->major_version >= XPT_MAJOR_INCOMPATIBLE_VERSION) {
84 : /* This file is newer than we are and set to an incompatible version
85 : * number. We must set the header state thusly and return.
86 : */
87 0 : header->num_interfaces = 0;
88 0 : return true;
89 : }
90 :
91 1566 : if (!XPT_Do16(cursor, &header->num_interfaces) ||
92 1044 : !XPT_Do32(cursor, &file_length) ||
93 522 : !XPT_Do32(cursor, &ide_offset)) {
94 0 : return false;
95 : }
96 :
97 : /*
98 : * Make sure the file length reported in the header is the same size as
99 : * as our buffer unless it is zero (not set)
100 : */
101 1044 : if (file_length != 0 &&
102 522 : cursor->state->pool_allocated < file_length) {
103 : fputs("libxpt: File length in header does not match actual length. File may be corrupt\n",
104 0 : stderr);
105 0 : return false;
106 : }
107 :
108 : uint32_t data_pool;
109 522 : if (!XPT_Do32(cursor, &data_pool))
110 0 : return false;
111 :
112 522 : XPT_SetDataOffset(cursor->state, data_pool);
113 :
114 522 : if (header->num_interfaces) {
115 483 : size_t n = header->num_interfaces * sizeof(XPTInterfaceDirectoryEntry);
116 483 : header->interface_directory =
117 483 : static_cast<XPTInterfaceDirectoryEntry*>(XPT_CALLOC8(arena, n));
118 483 : if (!header->interface_directory)
119 0 : return false;
120 : }
121 :
122 : /*
123 : * Iterate through the annotations rather than recurring, to avoid blowing
124 : * the stack on large xpt files. We don't actually store annotations, we
125 : * just skip over them.
126 : */
127 : bool isLast;
128 0 : do {
129 522 : if (!SkipAnnotation(cursor, &isLast))
130 0 : return false;
131 522 : } while (!isLast);
132 :
133 : /* shouldn't be necessary now, but maybe later */
134 522 : XPT_SeekTo(cursor, ide_offset);
135 :
136 6924 : for (i = 0; i < header->num_interfaces; i++) {
137 6402 : if (!DoInterfaceDirectoryEntry(arena, cursor,
138 6402 : &header->interface_directory[i]))
139 0 : return false;
140 : }
141 :
142 522 : return true;
143 : }
144 :
145 : /* InterfaceDirectoryEntry records go in the header */
146 : bool
147 6402 : DoInterfaceDirectoryEntry(XPTArena *arena, NotNull<XPTCursor*> cursor,
148 : XPTInterfaceDirectoryEntry *ide)
149 : {
150 : char* dummy_name_space;
151 :
152 : /* write the IID in our cursor space */
153 19206 : if (!XPT_DoIID(cursor, &(ide->iid)) ||
154 :
155 : /* write the name string in the data pool, and the offset in our
156 : cursor space */
157 12804 : !XPT_DoCString(arena, cursor, &(ide->name)) ||
158 :
159 : /* don't write the name_space string in the data pool, because we don't
160 : * need it. Do write the offset in our cursor space */
161 19206 : !XPT_DoCString(arena, cursor, &dummy_name_space, /* ignore = */ true) ||
162 :
163 : /* do InterfaceDescriptors */
164 6402 : !DoInterfaceDescriptor(arena, cursor, &ide->interface_descriptor)) {
165 0 : return false;
166 : }
167 :
168 6402 : return true;
169 : }
170 :
171 : static bool
172 759 : InterfaceDescriptorAddTypes(XPTArena *arena, XPTInterfaceDescriptor *id,
173 : uint16_t num)
174 : {
175 759 : XPTTypeDescriptor *old = id->additional_types;
176 : XPTTypeDescriptor *new_;
177 759 : size_t old_size = id->num_additional_types * sizeof(XPTTypeDescriptor);
178 759 : size_t new_size = (num * sizeof(XPTTypeDescriptor)) + old_size;
179 :
180 : /* XXX should grow in chunks to minimize alloc overhead */
181 759 : new_ = static_cast<XPTTypeDescriptor*>(XPT_CALLOC8(arena, new_size));
182 759 : if (!new_)
183 0 : return false;
184 759 : if (old) {
185 432 : memcpy(new_, old, old_size);
186 : }
187 759 : id->additional_types = new_;
188 :
189 759 : if (num + uint16_t(id->num_additional_types) > 256)
190 0 : return false;
191 :
192 759 : id->num_additional_types += num;
193 759 : return true;
194 : }
195 :
196 : bool
197 6402 : DoInterfaceDescriptor(XPTArena *arena, NotNull<XPTCursor*> outer,
198 : XPTInterfaceDescriptor **idp)
199 : {
200 : XPTInterfaceDescriptor *id;
201 : XPTCursor curs;
202 6402 : NotNull<XPTCursor*> cursor = WrapNotNull(&curs);
203 6402 : uint32_t i, id_sz = 0;
204 :
205 6402 : id = XPT_NEWZAP(arena, XPTInterfaceDescriptor);
206 6402 : if (!id)
207 0 : return false;
208 6402 : *idp = id;
209 :
210 6402 : if (!XPT_MakeCursor(outer->state, XPT_DATA, id_sz, cursor))
211 0 : return false;
212 :
213 6402 : if (!XPT_Do32(outer, &cursor->offset))
214 0 : return false;
215 6402 : if (!cursor->offset) {
216 2520 : *idp = NULL;
217 2520 : return true;
218 : }
219 7764 : if(!XPT_Do16(cursor, &id->parent_interface) ||
220 3882 : !XPT_Do16(cursor, &id->num_methods)) {
221 0 : return false;
222 : }
223 :
224 3882 : if (id->num_methods) {
225 3732 : size_t n = id->num_methods * sizeof(XPTMethodDescriptor);
226 3732 : id->method_descriptors =
227 3732 : static_cast<XPTMethodDescriptor*>(XPT_CALLOC8(arena, n));
228 3732 : if (!id->method_descriptors)
229 0 : return false;
230 : }
231 :
232 29610 : for (i = 0; i < id->num_methods; i++) {
233 25728 : if (!DoMethodDescriptor(arena, cursor, &id->method_descriptors[i], id))
234 0 : return false;
235 : }
236 :
237 3882 : if (!XPT_Do16(cursor, &id->num_constants)) {
238 0 : return false;
239 : }
240 :
241 3882 : if (id->num_constants) {
242 786 : size_t n = id->num_constants * sizeof(XPTConstDescriptor);
243 786 : id->const_descriptors =
244 786 : static_cast<XPTConstDescriptor*>(XPT_CALLOC8(arena, n));
245 786 : if (!id->const_descriptors)
246 0 : return false;
247 : }
248 :
249 11463 : for (i = 0; i < id->num_constants; i++) {
250 7581 : if (!DoConstDescriptor(arena, cursor, &id->const_descriptors[i], id)) {
251 0 : return false;
252 : }
253 : }
254 :
255 3882 : if (!XPT_Do8(cursor, &id->flags)) {
256 0 : return false;
257 : }
258 :
259 3882 : return true;
260 : }
261 :
262 : bool
263 7581 : DoConstDescriptor(XPTArena *arena, NotNull<XPTCursor*> cursor,
264 : XPTConstDescriptor *cd, XPTInterfaceDescriptor *id)
265 : {
266 7581 : bool ok = false;
267 :
268 15162 : if (!XPT_DoCString(arena, cursor, &cd->name) ||
269 7581 : !DoTypeDescriptor(arena, cursor, &cd->type, id)) {
270 :
271 0 : return false;
272 : }
273 :
274 7581 : switch(XPT_TDP_TAG(cd->type.prefix)) {
275 : case TD_INT8:
276 0 : ok = XPT_Do8(cursor, (uint8_t*) &cd->value.i8);
277 0 : break;
278 : case TD_INT16:
279 762 : ok = XPT_Do16(cursor, (uint16_t*) &cd->value.i16);
280 762 : break;
281 : case TD_INT32:
282 1278 : ok = XPT_Do32(cursor, (uint32_t*) &cd->value.i32);
283 1278 : break;
284 : case TD_INT64:
285 0 : ok = XPT_Do64(cursor, &cd->value.i64);
286 0 : break;
287 : case TD_UINT8:
288 0 : ok = XPT_Do8(cursor, &cd->value.ui8);
289 0 : break;
290 : case TD_UINT16:
291 831 : ok = XPT_Do16(cursor, &cd->value.ui16);
292 831 : break;
293 : case TD_UINT32:
294 4710 : ok = XPT_Do32(cursor, &cd->value.ui32);
295 4710 : break;
296 : case TD_UINT64:
297 0 : ok = XPT_Do64(cursor, (int64_t *)&cd->value.ui64);
298 0 : break;
299 : case TD_CHAR:
300 0 : ok = XPT_Do8(cursor, (uint8_t*) &cd->value.ch);
301 0 : break;
302 : case TD_WCHAR:
303 0 : ok = XPT_Do16(cursor, &cd->value.wch);
304 0 : break;
305 : /* fall-through */
306 : default:
307 0 : fprintf(stderr, "illegal type!\n");
308 0 : break;
309 : }
310 :
311 7581 : return ok;
312 :
313 : }
314 :
315 : bool
316 25728 : DoMethodDescriptor(XPTArena *arena, NotNull<XPTCursor*> cursor,
317 : XPTMethodDescriptor *md, XPTInterfaceDescriptor *id)
318 : {
319 : int i;
320 :
321 77184 : if (!XPT_Do8(cursor, &md->flags) ||
322 51456 : !XPT_DoCString(arena, cursor, &md->name) ||
323 25728 : !XPT_Do8(cursor, &md->num_args))
324 0 : return false;
325 :
326 25728 : if (md->num_args) {
327 23832 : size_t n = md->num_args * sizeof(XPTParamDescriptor);
328 23832 : md->params = static_cast<XPTParamDescriptor*>(XPT_CALLOC8(arena, n));
329 23832 : if (!md->params)
330 0 : return false;
331 : }
332 :
333 67218 : for(i = 0; i < md->num_args; i++) {
334 41490 : if (!DoParamDescriptor(arena, cursor, &md->params[i], id))
335 0 : return false;
336 : }
337 :
338 25728 : if (!DoParamDescriptor(arena, cursor, &md->result, id))
339 0 : return false;
340 :
341 25728 : return true;
342 : }
343 :
344 : bool
345 67218 : DoParamDescriptor(XPTArena *arena, NotNull<XPTCursor*> cursor,
346 : XPTParamDescriptor *pd, XPTInterfaceDescriptor *id)
347 : {
348 134436 : if (!XPT_Do8(cursor, &pd->flags) ||
349 67218 : !DoTypeDescriptor(arena, cursor, &pd->type, id))
350 0 : return false;
351 :
352 67218 : return true;
353 : }
354 :
355 : bool
356 75558 : DoTypeDescriptorPrefix(XPTArena *arena, NotNull<XPTCursor*> cursor,
357 : XPTTypeDescriptorPrefix *tdp)
358 : {
359 75558 : return XPT_Do8(cursor, &tdp->flags);
360 : }
361 :
362 : bool
363 75558 : DoTypeDescriptor(XPTArena *arena, NotNull<XPTCursor*> cursor,
364 : XPTTypeDescriptor *td, XPTInterfaceDescriptor *id)
365 : {
366 75558 : if (!DoTypeDescriptorPrefix(arena, cursor, &td->prefix)) {
367 0 : return false;
368 : }
369 :
370 75558 : switch (XPT_TDP_TAG(td->prefix)) {
371 : case TD_INTERFACE_TYPE:
372 : uint16_t iface;
373 12303 : if (!XPT_Do16(cursor, &iface))
374 0 : return false;
375 12303 : td->u.iface.iface_hi8 = (iface >> 8) & 0xff;
376 12303 : td->u.iface.iface_lo8 = iface & 0xff;
377 87861 : break;
378 : case TD_INTERFACE_IS_TYPE:
379 99 : if (!XPT_Do8(cursor, &td->u.interface_is.argnum))
380 0 : return false;
381 99 : break;
382 : case TD_ARRAY: {
383 : // argnum2 appears in the on-disk format but it isn't used.
384 759 : uint8_t argnum2 = 0;
385 1518 : if (!XPT_Do8(cursor, &td->u.array.argnum) ||
386 759 : !XPT_Do8(cursor, &argnum2))
387 0 : return false;
388 :
389 759 : if (!InterfaceDescriptorAddTypes(arena, id, 1))
390 0 : return false;
391 759 : td->u.array.additional_type = id->num_additional_types - 1;
392 :
393 759 : if (!DoTypeDescriptor(arena, cursor,
394 759 : &id->additional_types[td->u.array.additional_type],
395 : id))
396 0 : return false;
397 759 : break;
398 : }
399 : case TD_PSTRING_SIZE_IS:
400 : case TD_PWSTRING_SIZE_IS: {
401 : // argnum2 appears in the on-disk format but it isn't used.
402 63 : uint8_t argnum2 = 0;
403 126 : if (!XPT_Do8(cursor, &td->u.pstring_is.argnum) ||
404 63 : !XPT_Do8(cursor, &argnum2))
405 0 : return false;
406 63 : break;
407 : }
408 : default:
409 : /* nothing special */
410 62334 : break;
411 : }
412 75558 : return true;
413 : }
414 :
415 : bool
416 522 : SkipAnnotation(NotNull<XPTCursor*> cursor, bool *isLast)
417 : {
418 : uint8_t flags;
419 522 : if (!XPT_Do8(cursor, &flags))
420 0 : return false;
421 :
422 522 : *isLast = XPT_ANN_IS_LAST(flags);
423 :
424 522 : if (XPT_ANN_IS_PRIVATE(flags)) {
425 0 : if (!XPT_SkipStringInline(cursor) ||
426 0 : !XPT_SkipStringInline(cursor))
427 0 : return false;
428 : }
429 :
430 522 : return true;
431 : }
432 :
|