VirtualBox

source: vbox/trunk/src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl_typelib.c@ 4837

Last change on this file since 4837 was 1, checked in by vboxsync, 54 years ago

import

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 41.4 KB
Line 
1/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/* ***** BEGIN LICENSE BLOCK *****
3 * Version: NPL 1.1/GPL 2.0/LGPL 2.1
4 *
5 * The contents of this file are subject to the Netscape Public License
6 * Version 1.1 (the "License"); you may not use this file except in
7 * compliance with the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/NPL/
9 *
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
14 *
15 * The Original Code is mozilla.org code.
16 *
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
21 *
22 * Contributor(s):
23 *
24 * Alternatively, the contents of this file may be used under the terms of
25 * either the GNU General Public License Version 2 or later (the "GPL"), or
26 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the NPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the NPL, the GPL or the LGPL.
35 *
36 * ***** END LICENSE BLOCK ***** */
37
38/*
39 * Generate typelib files for use with InterfaceInfo.
40 * http://www.mozilla.org/scriptable/typelib_file.html
41 */
42
43#include "xpidl.h"
44#include <xpt_xdr.h>
45#include <xpt_struct.h>
46#include <time.h> /* XXX XP? */
47
48struct priv_data {
49 XPTHeader *header;
50 uint16 ifaces;
51 GHashTable *interface_map;
52 XPTInterfaceDescriptor *current;
53 XPTArena *arena;
54 uint16 next_method;
55 uint16 next_const;
56 uint16 next_type; /* used for 'additional_types' for idl arrays */
57};
58
59#define HEADER(state) (((struct priv_data *)state->priv)->header)
60#define IFACES(state) (((struct priv_data *)state->priv)->ifaces)
61#define IFACE_MAP(state) (((struct priv_data *)state->priv)->interface_map)
62#define CURRENT(state) (((struct priv_data *)state->priv)->current)
63#define ARENA(state) (((struct priv_data *)state->priv)->arena)
64#define NEXT_METH(state) (((struct priv_data *)state->priv)->next_method)
65#define NEXT_CONST(state) (((struct priv_data *)state->priv)->next_const)
66#define NEXT_TYPE(state) (((struct priv_data *)state->priv)->next_type)
67
68#ifdef DEBUG_shaver
69/* #define DEBUG_shaver_sort */
70#endif
71
72typedef struct {
73 char *full_name;
74 char *name;
75 char *name_space;
76 char *iid;
77 gboolean is_forward_dcl;
78} NewInterfaceHolder;
79
80static NewInterfaceHolder*
81CreateNewInterfaceHolder(char *name, char *name_space, char *iid,
82 gboolean is_forward_dcl)
83{
84 NewInterfaceHolder *holder = calloc(1, sizeof(NewInterfaceHolder));
85 if (holder) {
86 holder->is_forward_dcl = is_forward_dcl;
87 if (name)
88 holder->name = xpidl_strdup(name);
89 if (name_space)
90 holder->name_space = xpidl_strdup(name_space);
91 if (holder->name && holder->name_space) {
92 holder->full_name = calloc(1, strlen(holder->name) +
93 strlen(holder->name_space) + 2);
94 }
95 if (holder->full_name) {
96 strcpy(holder->full_name, holder->name_space);
97 strcat(holder->full_name, ".");
98 strcat(holder->full_name, holder->name);
99 }
100 else
101 holder->full_name = holder->name;
102 if (iid)
103 holder->iid = xpidl_strdup(iid);
104 }
105 return holder;
106}
107
108static void
109DeleteNewInterfaceHolder(NewInterfaceHolder *holder)
110{
111 if (holder) {
112 if (holder->full_name && holder->full_name != holder->name)
113 free(holder->full_name);
114 if (holder->name)
115 free(holder->name);
116 if (holder->name_space)
117 free(holder->name_space);
118 if (holder->iid)
119 free(holder->iid);
120 free(holder);
121 }
122}
123
124/*
125 * If p is an ident for an interface, and we don't have an entry in the
126 * interface map yet, add one.
127 */
128static gboolean
129add_interface_maybe(IDL_tree_func_data *tfd, gpointer user_data)
130{
131 TreeState *state = user_data;
132 IDL_tree up;
133 if (IDL_NODE_TYPE(tfd->tree) == IDLN_IDENT) {
134 IDL_tree_type node_type = IDL_NODE_TYPE((up = IDL_NODE_UP(tfd->tree)));
135 if (node_type == IDLN_INTERFACE || node_type == IDLN_FORWARD_DCL) {
136
137 /* We only want to add a new entry if there is no entry by this
138 * name or if the previously found entry was just a forward
139 * declaration and the new entry is not.
140 */
141
142 char *iface = IDL_IDENT(tfd->tree).str;
143 NewInterfaceHolder *old_holder = (NewInterfaceHolder *)
144 g_hash_table_lookup(IFACE_MAP(state), iface);
145 if (old_holder && old_holder->is_forward_dcl &&
146 node_type != IDLN_FORWARD_DCL)
147 {
148 g_hash_table_remove(IFACE_MAP(state), iface);
149 DeleteNewInterfaceHolder(old_holder);
150 old_holder = NULL;
151 }
152 if (!old_holder) {
153 /* XXX should we parse here and store a struct nsID *? */
154 char *iid = (char *)IDL_tree_property_get(tfd->tree, "uuid");
155 char *name_space = (char *)
156 IDL_tree_property_get(tfd->tree, "namespace");
157 NewInterfaceHolder *holder =
158 CreateNewInterfaceHolder(iface, name_space, iid,
159 (gboolean) node_type == IDLN_FORWARD_DCL);
160 if (!holder)
161 return FALSE;
162 g_hash_table_insert(IFACE_MAP(state),
163 holder->full_name, holder);
164 IFACES(state)++;
165#ifdef DEBUG_shaver_ifaces
166 fprintf(stderr, "adding interface #%d: %s/%s\n", IFACES(state),
167 iface, iid[0] ? iid : "<unresolved>");
168#endif
169 }
170 } else {
171#ifdef DEBUG_shaver_ifaces
172 fprintf(stderr, "ident %s isn't an interface (%s)\n",
173 IDL_IDENT(tfd->tree).str, IDL_NODE_TYPE_NAME(up));
174#endif
175 }
176 }
177
178 return TRUE;
179}
180
181/* Find all the interfaces referenced in the tree (uses add_interface_maybe) */
182static gboolean
183find_interfaces(IDL_tree_func_data *tfd, gpointer user_data)
184{
185 IDL_tree node = NULL;
186
187 switch (IDL_NODE_TYPE(tfd->tree)) {
188 case IDLN_ATTR_DCL:
189 node = IDL_ATTR_DCL(tfd->tree).param_type_spec;
190 break;
191 case IDLN_OP_DCL:
192 IDL_tree_walk_in_order(IDL_OP_DCL(tfd->tree).parameter_dcls, find_interfaces,
193 user_data);
194 node = IDL_OP_DCL(tfd->tree).op_type_spec;
195 break;
196 case IDLN_PARAM_DCL:
197 node = IDL_PARAM_DCL(tfd->tree).param_type_spec;
198 break;
199 case IDLN_INTERFACE:
200 node = IDL_INTERFACE(tfd->tree).inheritance_spec;
201 if (node)
202 xpidl_list_foreach(node, add_interface_maybe, user_data);
203 node = IDL_INTERFACE(tfd->tree).ident;
204 break;
205 case IDLN_FORWARD_DCL:
206 node = IDL_FORWARD_DCL(tfd->tree).ident;
207 break;
208 default:
209 node = NULL;
210 }
211
212 if (node && IDL_NODE_TYPE(node) == IDLN_IDENT) {
213 IDL_tree_func_data new_tfd;
214 new_tfd.tree = node;
215 add_interface_maybe(&new_tfd, user_data);
216 }
217
218 return TRUE;
219}
220
221#ifdef DEBUG_shaver
222/* for calling from gdb */
223static void
224print_IID(struct nsID *iid, FILE *file)
225{
226 char iid_buf[UUID_LENGTH];
227
228 xpidl_sprint_iid(iid, iid_buf);
229 fprintf(file, "%s\n", iid_buf);
230}
231#endif
232
233/* fill the interface_directory IDE table from the interface_map */
234static gboolean
235fill_ide_table(gpointer key, gpointer value, gpointer user_data)
236{
237 TreeState *state = user_data;
238 NewInterfaceHolder *holder = (NewInterfaceHolder *) value;
239 struct nsID id;
240 XPTInterfaceDirectoryEntry *ide;
241
242 XPT_ASSERT(holder);
243
244#ifdef DEBUG_shaver_ifaces
245 fprintf(stderr, "filling %s\n", holder->full_name);
246#endif
247
248 if (holder->iid) {
249 if (strlen(holder->iid) != 36) {
250 IDL_tree_error(state->tree, "IID %s is the wrong length\n",
251 holder->iid);
252 return FALSE;
253 }
254 if (!xpidl_parse_iid(&id, holder->iid)) {
255 IDL_tree_error(state->tree, "cannot parse IID %s\n", holder->iid);
256 return FALSE;
257 }
258 } else {
259 memset(&id, 0, sizeof(id));
260 }
261
262 ide = &(HEADER(state)->interface_directory[IFACES(state)]);
263 if (!XPT_FillInterfaceDirectoryEntry(ARENA(state), ide, &id, holder->name,
264 holder->name_space, NULL)) {
265 IDL_tree_error(state->tree, "INTERNAL: XPT_FillIDE failed for %s\n",
266 holder->full_name);
267 return FALSE;
268 }
269
270 IFACES(state)++;
271 DeleteNewInterfaceHolder(holder);
272 return TRUE;
273}
274
275static int
276compare_IDEs(const void *ap, const void *bp)
277{
278 const XPTInterfaceDirectoryEntry *a = ap, *b = bp;
279 const nsID *aid = &a->iid, *bid = &b->iid;
280 const char *ans, *bns;
281
282 int i;
283#define COMPARE(field) if (aid->field > bid->field) return 1; \
284 if (bid->field > aid->field) return -1;
285 COMPARE(m0);
286 COMPARE(m1);
287 COMPARE(m2);
288 for (i = 0; i < 8; i++) {
289 COMPARE(m3[i]);
290 }
291
292 /* defend against NULL name_space by using empty string. */
293 ans = a->name_space ? a->name_space : "";
294 bns = b->name_space ? b->name_space : "";
295
296 if (a->name_space && b->name_space) {
297 if ((i = strcmp(a->name_space, b->name_space)))
298 return i;
299 } else {
300 if (a->name_space || b->name_space) {
301 if (a->name_space)
302 return -1;
303 return 1;
304 }
305 }
306 /* these had better not be NULL... */
307 return strcmp(a->name, b->name);
308#undef COMPARE
309}
310
311/* sort the IDE block as per the typelib spec: IID order, unresolved first */
312static void
313sort_ide_block(TreeState *state)
314{
315 XPTInterfaceDirectoryEntry *ide;
316 int i;
317
318 /* boy, I sure hope qsort works correctly everywhere */
319#ifdef DEBUG_shaver_sort
320 fputs("before sort:\n", stderr);
321 for (i = 0; i < IFACES(state); i++) {
322 fputs(" ", stderr);
323 print_IID(&HEADER(state)->interface_directory[i].iid, stderr);
324 fputc('\n', stderr);
325 }
326#endif
327 qsort(HEADER(state)->interface_directory, IFACES(state),
328 sizeof(*ide), compare_IDEs);
329#ifdef DEBUG_shaver_sort
330 fputs("after sort:\n", stderr);
331 for (i = 0; i < IFACES(state); i++) {
332 fputs(" ", stderr);
333 print_IID(&HEADER(state)->interface_directory[i].iid, stderr);
334 fputc('\n', stderr);
335 }
336#endif
337
338 for (i = 0; i < IFACES(state); i++) {
339 ide = HEADER(state)->interface_directory + i;
340 g_hash_table_insert(IFACE_MAP(state), ide->name, (void *)(i + 1));
341 }
342
343 return;
344}
345
346static gboolean
347typelib_list(TreeState *state)
348{
349 IDL_tree iter;
350 for (iter = state->tree; iter; iter = IDL_LIST(iter).next) {
351 state->tree = IDL_LIST(iter).data;
352 if (!xpidl_process_node(state))
353 return FALSE;
354 }
355 return TRUE;
356}
357
358static gboolean
359typelib_prolog(TreeState *state)
360{
361 state->priv = calloc(1, sizeof(struct priv_data));
362 if (!state->priv)
363 return FALSE;
364 IFACES(state) = 0;
365 IFACE_MAP(state) = g_hash_table_new(g_str_hash, g_str_equal);
366 if (!IFACE_MAP(state)) {
367 /* XXX report error */
368 free(state->priv);
369 return FALSE;
370 }
371 /* find all interfaces, top-level and referenced by others */
372 IDL_tree_walk_in_order(state->tree, find_interfaces, state);
373 ARENA(state) = XPT_NewArena(1024, sizeof(double), "main xpidl arena");
374 HEADER(state) = XPT_NewHeader(ARENA(state), IFACES(state),
375 major_version, minor_version);
376
377 /* fill IDEs from hash table */
378 IFACES(state) = 0;
379 g_hash_table_foreach_remove(IFACE_MAP(state), fill_ide_table, state);
380
381 /* if any are left then we must have failed in fill_ide_table */
382 if (g_hash_table_size(IFACE_MAP(state)))
383 return FALSE;
384
385 /* sort the IDEs by IID order and store indices in the interface map */
386 sort_ide_block(state);
387
388 return TRUE;
389}
390
391static gboolean
392typelib_epilog(TreeState *state)
393{
394 XPTState *xstate = XPT_NewXDRState(XPT_ENCODE, NULL, 0);
395 XPTCursor curs, *cursor = &curs;
396 PRUint32 i, len, header_sz;
397 PRUint32 oldOffset;
398 PRUint32 newOffset;
399 char *data;
400
401 /* Write any annotations */
402 if (emit_typelib_annotations) {
403 PRUint32 annotation_len, written_so_far;
404 char *annotate_val, *timestr;
405 time_t now;
406 static char *annotation_format =
407 "Created from %s.idl\nCreation date: %sInterfaces:";
408
409 /* fill in the annotations, listing resolved interfaces in order */
410
411 (void)time(&now);
412 timestr = ctime(&now);
413
414 /* Avoid dependence on nspr; no PR_smprintf and friends. */
415
416 /* How large should the annotation string be? */
417 annotation_len = strlen(annotation_format) + strlen(state->basename) +
418 strlen(timestr);
419 for (i = 0; i < HEADER(state)->num_interfaces; i++) {
420 XPTInterfaceDirectoryEntry *ide;
421 ide = &HEADER(state)->interface_directory[i];
422 if (ide->interface_descriptor) {
423 annotation_len += strlen(ide->name) + 1;
424 }
425 }
426
427 annotate_val = (char *) malloc(annotation_len);
428 written_so_far = sprintf(annotate_val, annotation_format,
429 state->basename, timestr);
430
431 for (i = 0; i < HEADER(state)->num_interfaces; i++) {
432 XPTInterfaceDirectoryEntry *ide;
433 ide = &HEADER(state)->interface_directory[i];
434 if (ide->interface_descriptor) {
435 written_so_far += sprintf(annotate_val + written_so_far, " %s",
436 ide->name);
437 }
438 }
439
440 HEADER(state)->annotations =
441 XPT_NewAnnotation(ARENA(state),
442 XPT_ANN_LAST | XPT_ANN_PRIVATE,
443 XPT_NewStringZ(ARENA(state), "xpidl 0.99.9"),
444 XPT_NewStringZ(ARENA(state), annotate_val));
445 free(annotate_val);
446 } else {
447 HEADER(state)->annotations =
448 XPT_NewAnnotation(ARENA(state), XPT_ANN_LAST, NULL, NULL);
449 }
450
451 if (!HEADER(state)->annotations) {
452 /* XXX report out of memory error */
453 return FALSE;
454 }
455
456 /* Write the typelib */
457 header_sz = XPT_SizeOfHeaderBlock(HEADER(state));
458
459 if (!xstate ||
460 !XPT_MakeCursor(xstate, XPT_HEADER, header_sz, cursor))
461 goto destroy_header;
462 oldOffset = cursor->offset;
463 if (!XPT_DoHeader(ARENA(state), cursor, &HEADER(state)))
464 goto destroy;
465 newOffset = cursor->offset;
466 XPT_GetXDRDataLength(xstate, XPT_HEADER, &len);
467 HEADER(state)->file_length = len;
468 XPT_GetXDRDataLength(xstate, XPT_DATA, &len);
469 HEADER(state)->file_length += len;
470 XPT_SeekTo(cursor, oldOffset);
471 if (!XPT_DoHeaderPrologue(ARENA(state), cursor, &HEADER(state), NULL))
472 goto destroy;
473 XPT_SeekTo(cursor, newOffset);
474 XPT_GetXDRData(xstate, XPT_HEADER, &data, &len);
475 fwrite(data, len, 1, state->file);
476 XPT_GetXDRData(xstate, XPT_DATA, &data, &len);
477 fwrite(data, len, 1, state->file);
478
479 destroy:
480 XPT_DestroyXDRState(xstate);
481 destroy_header:
482 /* XXX XPT_DestroyHeader(HEADER(state)) */
483
484 XPT_FreeHeader(ARENA(state), HEADER(state));
485 XPT_DestroyArena(ARENA(state));
486
487 /* XXX should destroy priv_data here */
488
489 return TRUE;
490}
491
492static XPTInterfaceDirectoryEntry *
493FindInterfaceByName(XPTInterfaceDirectoryEntry *ides, uint16 num_interfaces,
494 const char *name)
495{
496 uint16 i;
497 for (i = 0; i < num_interfaces; i++) {
498 if (!strcmp(ides[i].name, name))
499 return &ides[i];
500 }
501 return NULL;
502}
503
504static gboolean
505typelib_interface(TreeState *state)
506{
507 IDL_tree iface = state->tree, iter;
508 char *name = IDL_IDENT(IDL_INTERFACE(iface).ident).str;
509 XPTInterfaceDirectoryEntry *ide;
510 XPTInterfaceDescriptor *id;
511 uint16 parent_id = 0;
512 PRUint8 interface_flags = 0;
513
514 if (!verify_interface_declaration(iface))
515 return FALSE;
516
517 if (IDL_tree_property_get(IDL_INTERFACE(iface).ident, "scriptable"))
518 interface_flags |= XPT_ID_SCRIPTABLE;
519
520 if (IDL_tree_property_get(IDL_INTERFACE(iface).ident, "function"))
521 interface_flags |= XPT_ID_FUNCTION;
522
523 ide = FindInterfaceByName(HEADER(state)->interface_directory,
524 HEADER(state)->num_interfaces, name);
525 if (!ide) {
526 IDL_tree_error(iface, "ERROR: didn't find interface %s in "
527 "IDE block. Giving up.\n", name);
528 return FALSE;
529 }
530
531 if ((iter = IDL_INTERFACE(iface).inheritance_spec)) {
532 char *parent;
533 if (IDL_LIST(iter).next) {
534 IDL_tree_error(iface,
535 "ERROR: more than one parent interface for %s\n",
536 name);
537 return FALSE;
538 }
539 parent = IDL_IDENT(IDL_LIST(iter).data).str;
540 parent_id = (uint16)(uint32)g_hash_table_lookup(IFACE_MAP(state),
541 parent);
542 if (!parent_id) {
543 IDL_tree_error(iface,
544 "ERROR: no index found for %s. Giving up.\n",
545 parent);
546 return FALSE;
547 }
548 }
549
550 id = XPT_NewInterfaceDescriptor(ARENA(state), parent_id, 0, 0,
551 interface_flags);
552 if (!id)
553 return FALSE;
554
555 CURRENT(state) = ide->interface_descriptor = id;
556#ifdef DEBUG_shaver_ifaces
557 fprintf(stderr, "DBG: starting interface %s @ %p\n", name, id);
558#endif
559
560 NEXT_METH(state) = 0;
561 NEXT_CONST(state) = 0;
562 NEXT_TYPE(state) = 0;
563
564 state->tree = IDL_INTERFACE(iface).body;
565 if (state->tree && !xpidl_process_node(state))
566 return FALSE;
567#ifdef DEBUG_shaver_ifaces
568 fprintf(stderr, "DBG: ending interface %s\n", name);
569#endif
570 return TRUE;
571}
572
573static gboolean
574find_arg_with_name(TreeState *state, const char *name, int16 *argnum)
575{
576 int16 count;
577 IDL_tree params;
578
579 XPT_ASSERT(state);
580 XPT_ASSERT(name);
581 XPT_ASSERT(argnum);
582
583 params = IDL_OP_DCL(IDL_NODE_UP(IDL_NODE_UP(state->tree))).parameter_dcls;
584 for (count = 0;
585 params != NULL && IDL_LIST(params).data != NULL;
586 params = IDL_LIST(params).next, count++)
587 {
588 const char *cur_name = IDL_IDENT(
589 IDL_PARAM_DCL(IDL_LIST(params).data).simple_declarator).str;
590 if (!strcmp(cur_name, name)) {
591 /* XXX ought to verify that this is the right type here */
592 /* XXX for iid_is this must be an iid */
593 /* XXX for size_is and length_is this must be a uint32 */
594 *argnum = count;
595 return TRUE;
596 }
597 }
598 return FALSE;
599}
600
601/* return value is for success or failure */
602static gboolean
603get_size_and_length(TreeState *state, IDL_tree type,
604 int16 *size_is_argnum, int16 *length_is_argnum,
605 gboolean *has_size_is, gboolean *has_length_is)
606{
607 *has_size_is = FALSE;
608 *has_length_is = FALSE;
609
610 if (IDL_NODE_TYPE(state->tree) == IDLN_PARAM_DCL) {
611 IDL_tree sd = IDL_PARAM_DCL(state->tree).simple_declarator;
612 const char *size_is;
613 const char *length_is;
614
615 /* only if size_is is found does any of this matter */
616 size_is = IDL_tree_property_get(sd, "size_is");
617 if (!size_is)
618 return TRUE;
619
620 if (!find_arg_with_name(state, size_is, size_is_argnum)) {
621 IDL_tree_error(state->tree, "can't find matching argument for "
622 "[size_is(%s)]\n", size_is);
623 return FALSE;
624 }
625 *has_size_is = TRUE;
626
627 /* length_is is optional */
628 length_is = IDL_tree_property_get(sd, "length_is");
629 if (length_is) {
630 *has_length_is = TRUE;
631 if (!find_arg_with_name(state, length_is, length_is_argnum)) {
632 IDL_tree_error(state->tree, "can't find matching argument for "
633 "[length_is(%s)]\n", length_is);
634 return FALSE;
635 }
636 }
637 }
638 return TRUE;
639}
640
641static gboolean
642fill_td_from_type(TreeState *state, XPTTypeDescriptor *td, IDL_tree type)
643{
644 IDL_tree up;
645 int16 size_is_argnum;
646 int16 length_is_argnum;
647 gboolean has_size_is;
648 gboolean has_length_is;
649 gboolean is_array = FALSE;
650
651 if (type) {
652
653 /* deal with array */
654
655 if (IDL_NODE_TYPE(state->tree) == IDLN_PARAM_DCL) {
656 IDL_tree sd = IDL_PARAM_DCL(state->tree).simple_declarator;
657 if (IDL_tree_property_get(sd, "array")) {
658
659 is_array = TRUE;
660
661 /* size_is is required! */
662 if (!get_size_and_length(state, type,
663 &size_is_argnum, &length_is_argnum,
664 &has_size_is, &has_length_is)) {
665 /* error was reported by helper function */
666 return FALSE;
667 }
668
669 if (!has_size_is) {
670 IDL_tree_error(state->tree, "[array] requires [size_is()]\n");
671 return FALSE;
672 }
673
674 td->prefix.flags = TD_ARRAY | XPT_TDP_POINTER;
675 td->argnum = size_is_argnum;
676
677 if (has_length_is)
678 td->argnum2 = length_is_argnum;
679 else
680 td->argnum2 = size_is_argnum;
681
682 /*
683 * XXX - NOTE - this will be broken for multidimensional
684 * arrays because of the realloc XPT_InterfaceDescriptorAddTypes
685 * uses. The underlying 'td' can change as we recurse in to get
686 * additional dimensions. Luckily, we don't yet support more
687 * than on dimension in the arrays
688 */
689 /* setup the additional_type */
690 if (!XPT_InterfaceDescriptorAddTypes(ARENA(state),
691 CURRENT(state), 1)) {
692 g_error("out of memory\n");
693 return FALSE;
694 }
695 td->type.additional_type = NEXT_TYPE(state);
696 td = &CURRENT(state)->additional_types[NEXT_TYPE(state)];
697 NEXT_TYPE(state)++ ;
698 }
699 }
700
701handle_typedef:
702 switch (IDL_NODE_TYPE(type)) {
703 case IDLN_TYPE_INTEGER: {
704 gboolean sign = IDL_TYPE_INTEGER(type).f_signed;
705 switch(IDL_TYPE_INTEGER(type).f_type) {
706 case IDL_INTEGER_TYPE_SHORT:
707 td->prefix.flags = sign ? TD_INT16 : TD_UINT16;
708 break;
709 case IDL_INTEGER_TYPE_LONG:
710 td->prefix.flags = sign ? TD_INT32 : TD_UINT32;
711 break;
712 case IDL_INTEGER_TYPE_LONGLONG:
713 td->prefix.flags = sign ? TD_INT64 : TD_UINT64;
714 break;
715 }
716 break;
717 }
718 case IDLN_TYPE_CHAR:
719 td->prefix.flags = TD_CHAR;
720 break;
721 case IDLN_TYPE_WIDE_CHAR:
722 td->prefix.flags = TD_WCHAR;
723 break;
724 case IDLN_TYPE_STRING:
725 if (is_array) {
726 td->prefix.flags = TD_PSTRING | XPT_TDP_POINTER;
727 } else {
728 if (!get_size_and_length(state, type,
729 &size_is_argnum, &length_is_argnum,
730 &has_size_is, &has_length_is)) {
731 /* error was reported by helper function */
732 return FALSE;
733 }
734 if (has_size_is) {
735 td->prefix.flags = TD_PSTRING_SIZE_IS | XPT_TDP_POINTER;
736 td->argnum = size_is_argnum;
737 if (has_length_is)
738 td->argnum2 = length_is_argnum;
739 else
740 td->argnum2 = size_is_argnum;
741 } else {
742 td->prefix.flags = TD_PSTRING | XPT_TDP_POINTER;
743 }
744 }
745 break;
746 case IDLN_TYPE_WIDE_STRING:
747 if (is_array) {
748 td->prefix.flags = TD_PWSTRING | XPT_TDP_POINTER;
749 } else {
750 if (!get_size_and_length(state, type,
751 &size_is_argnum, &length_is_argnum,
752 &has_size_is, &has_length_is)) {
753 /* error was reported by helper function */
754 return FALSE;
755 }
756 if (has_size_is) {
757 td->prefix.flags = TD_PWSTRING_SIZE_IS | XPT_TDP_POINTER;
758 td->argnum = size_is_argnum;
759 if (has_length_is)
760 td->argnum2 = length_is_argnum;
761 else
762 td->argnum2 = size_is_argnum;
763 } else {
764 td->prefix.flags = TD_PWSTRING | XPT_TDP_POINTER;
765 }
766 }
767 break;
768 case IDLN_TYPE_BOOLEAN:
769 td->prefix.flags = TD_BOOL;
770 break;
771 case IDLN_TYPE_OCTET:
772 td->prefix.flags = TD_UINT8;
773 break;
774 case IDLN_TYPE_FLOAT:
775 switch (IDL_TYPE_FLOAT (type).f_type) {
776 case IDL_FLOAT_TYPE_FLOAT:
777 td->prefix.flags = TD_FLOAT;
778 break;
779 case IDL_FLOAT_TYPE_DOUBLE:
780 td->prefix.flags = TD_DOUBLE;
781 break;
782 /* XXX 'long double' just ignored, or what? */
783 default: break;
784 }
785 break;
786 case IDLN_IDENT:
787 if (!(up = IDL_NODE_UP(type))) {
788 IDL_tree_error(state->tree,
789 "ERROR: orphan ident %s in param list\n",
790 IDL_IDENT(type).str);
791 return FALSE;
792 }
793 switch (IDL_NODE_TYPE(up)) {
794 /* This whole section is abominably ugly */
795 case IDLN_FORWARD_DCL:
796 case IDLN_INTERFACE: {
797 XPTInterfaceDirectoryEntry *ide, *ides;
798 uint16 num_ifaces;
799 char *className;
800 const char *iid_is;
801handle_iid_is:
802 ides = HEADER(state)->interface_directory;
803 num_ifaces = HEADER(state)->num_interfaces;
804 /* might get here via the goto, so re-check type */
805 if (IDL_NODE_TYPE(up) == IDLN_INTERFACE)
806 className = IDL_IDENT(IDL_INTERFACE(up).ident).str;
807 else if (IDL_NODE_TYPE(up) == IDLN_FORWARD_DCL)
808 className = IDL_IDENT(IDL_FORWARD_DCL(up).ident).str;
809 else
810 className = IDL_IDENT(IDL_NATIVE(up).ident).str;
811 iid_is = NULL;
812
813 if (IDL_NODE_TYPE(state->tree) == IDLN_PARAM_DCL) {
814 iid_is =
815 IDL_tree_property_get(IDL_PARAM_DCL(state->tree).simple_declarator,
816 "iid_is");
817 }
818 if (iid_is) {
819 int16 argnum;
820 if (!find_arg_with_name(state, iid_is, &argnum)) {
821 IDL_tree_error(state->tree,
822 "can't find matching argument for "
823 "[iid_is(%s)]\n", iid_is);
824 return FALSE;
825 }
826 td->prefix.flags = TD_INTERFACE_IS_TYPE | XPT_TDP_POINTER;
827 td->argnum = argnum;
828 } else {
829 td->prefix.flags = TD_INTERFACE_TYPE | XPT_TDP_POINTER;
830 ide = FindInterfaceByName(ides, num_ifaces, className);
831 if (!ide || ide < ides || ide > ides + num_ifaces) {
832 IDL_tree_error(state->tree,
833 "unknown iface %s in param\n",
834 className);
835 return FALSE;
836 }
837 td->type.iface = ide - ides + 1;
838#ifdef DEBUG_shaver_index
839 fprintf(stderr, "DBG: index %d for %s\n",
840 td->type.iface, className);
841#endif
842 }
843 break;
844 }
845 case IDLN_NATIVE: {
846 char *ident;
847
848 /* jband - adding goto for iid_is when type is native */
849 if (IDL_NODE_TYPE(state->tree) == IDLN_PARAM_DCL &&
850 IDL_tree_property_get(IDL_PARAM_DCL(state->tree).simple_declarator,
851 "iid_is"))
852 goto handle_iid_is;
853
854 ident = IDL_IDENT(type).str;
855 if (IDL_tree_property_get(type, "nsid")) {
856 td->prefix.flags = TD_PNSIID;
857 if (IDL_tree_property_get(type, "ref"))
858 td->prefix.flags |= XPT_TDP_POINTER | XPT_TDP_REFERENCE;
859 else if (IDL_tree_property_get(type,"ptr"))
860 td->prefix.flags |= XPT_TDP_POINTER;
861 } else if (IDL_tree_property_get(type, "domstring")) {
862 td->prefix.flags = TD_DOMSTRING | XPT_TDP_POINTER;
863 if (IDL_tree_property_get(type, "ref"))
864 td->prefix.flags |= XPT_TDP_REFERENCE;
865 } else if (IDL_tree_property_get(type, "astring")) {
866 td->prefix.flags = TD_ASTRING | XPT_TDP_POINTER;
867 if (IDL_tree_property_get(type, "ref"))
868 td->prefix.flags |= XPT_TDP_REFERENCE;
869 } else if (IDL_tree_property_get(type, "utf8string")) {
870 td->prefix.flags = TD_UTF8STRING | XPT_TDP_POINTER;
871 if (IDL_tree_property_get(type, "ref"))
872 td->prefix.flags |= XPT_TDP_REFERENCE;
873 } else if (IDL_tree_property_get(type, "cstring")) {
874 td->prefix.flags = TD_CSTRING | XPT_TDP_POINTER;
875 if (IDL_tree_property_get(type, "ref"))
876 td->prefix.flags |= XPT_TDP_REFERENCE;
877 } else {
878 td->prefix.flags = TD_VOID | XPT_TDP_POINTER;
879 }
880 break;
881 }
882 default:
883 if (IDL_NODE_TYPE(IDL_NODE_UP(up)) == IDLN_TYPE_DCL) {
884 /* restart with the underlying type */
885 IDL_tree new_type;
886 new_type = IDL_TYPE_DCL(IDL_NODE_UP(up)).type_spec;
887#ifdef DEBUG_shaver_misc
888 fprintf(stderr, "following %s typedef to %s\n",
889 IDL_IDENT(type).str, IDL_NODE_TYPE_NAME(new_type));
890#endif
891 /*
892 * Do a nice messy goto rather than recursion so that
893 * we can avoid screwing up the *array* information.
894 */
895/* return fill_td_from_type(state, td, new_type); */
896 if (new_type) {
897 type = new_type;
898 goto handle_typedef;
899 } else {
900 /* do what we would do in recursion if !type */
901 td->prefix.flags = TD_VOID;
902 return TRUE;
903 }
904 }
905 IDL_tree_error(state->tree,
906 "can't handle %s ident in param list\n",
907#ifdef DEBUG_shaver
908 /* XXX is this safe to use on Win now? */
909 IDL_NODE_TYPE_NAME(IDL_NODE_UP(type))
910#else
911 "that type of"
912#endif
913 );
914#ifdef DEBUG_shaver
915 XPT_ASSERT(0);
916#endif
917 return FALSE;
918 }
919 break;
920 default:
921 IDL_tree_error(state->tree, "can't handle %s in param list\n",
922#ifdef DEBUG_shaver
923 /* XXX is this safe to use on Win now? */
924 IDL_NODE_TYPE_NAME(IDL_NODE_UP(type))
925#else
926 "that type"
927#endif
928 );
929 return FALSE;
930 }
931 } else {
932 td->prefix.flags = TD_VOID;
933 }
934
935 return TRUE;
936}
937
938static gboolean
939fill_pd_from_type(TreeState *state, XPTParamDescriptor *pd, uint8 flags,
940 IDL_tree type)
941{
942 pd->flags = flags;
943 return fill_td_from_type(state, &pd->type, type);
944}
945
946static gboolean
947fill_pd_from_param(TreeState *state, XPTParamDescriptor *pd, IDL_tree tree)
948{
949 uint8 flags = 0;
950 gboolean is_dipper_type = DIPPER_TYPE(IDL_PARAM_DCL(tree).param_type_spec);
951
952 switch (IDL_PARAM_DCL(tree).attr) {
953 case IDL_PARAM_IN:
954 flags = XPT_PD_IN;
955 break;
956 case IDL_PARAM_OUT:
957 flags = XPT_PD_OUT;
958 break;
959 case IDL_PARAM_INOUT:
960 flags = XPT_PD_IN | XPT_PD_OUT;
961 break;
962 }
963
964 if (IDL_tree_property_get(IDL_PARAM_DCL(tree).simple_declarator,
965 "retval")) {
966 if (flags != XPT_PD_OUT) {
967 IDL_tree_error(tree, "can't have [retval] with in%s param "
968 "(only out)\n",
969 flags & XPT_PD_OUT ? "out" : "");
970 return FALSE;
971 }
972 flags |= XPT_PD_RETVAL;
973 }
974
975 if (is_dipper_type && (flags & XPT_PD_OUT)) {
976 flags &= ~XPT_PD_OUT;
977 flags |= XPT_PD_IN | XPT_PD_DIPPER;
978 }
979
980 if (IDL_tree_property_get(IDL_PARAM_DCL(tree).simple_declarator,
981 "shared")) {
982 if (flags & XPT_PD_IN) {
983 IDL_tree_error(tree, "can't have [shared] with in%s param "
984 "(only out)\n",
985 flags & XPT_PD_OUT ? "out" : "");
986 return FALSE;
987 }
988 flags |= XPT_PD_SHARED;
989 }
990
991 /* stick param where we can see it later */
992 state->tree = tree;
993 return fill_pd_from_type(state, pd, flags,
994 IDL_PARAM_DCL(tree).param_type_spec);
995}
996
997/* XXXshaver common with xpidl_header.c */
998#define ATTR_IDENT(tree) (IDL_IDENT(IDL_LIST(IDL_ATTR_DCL(tree).simple_declarations).data))
999#define ATTR_TYPE_DECL(tree) (IDL_ATTR_DCL(tree).param_type_spec)
1000#define ATTR_TYPE(tree) (IDL_NODE_TYPE(ATTR_TYPE_DECL(tree)))
1001
1002static gboolean
1003fill_pd_as_nsresult(XPTParamDescriptor *pd)
1004{
1005 pd->type.prefix.flags = TD_UINT32; /* TD_NSRESULT */
1006 return TRUE;
1007}
1008
1009static gboolean
1010typelib_attr_accessor(TreeState *state, XPTMethodDescriptor *meth,
1011 gboolean getter, gboolean hidden)
1012{
1013 uint8 methflags = 0;
1014 uint8 pdflags = 0;
1015
1016 methflags |= getter ? XPT_MD_GETTER : XPT_MD_SETTER;
1017 methflags |= hidden ? XPT_MD_HIDDEN : 0;
1018 if (!XPT_FillMethodDescriptor(ARENA(state), meth, methflags,
1019 ATTR_IDENT(state->tree).str, 1))
1020 return FALSE;
1021
1022 if (getter) {
1023 if (DIPPER_TYPE(ATTR_TYPE_DECL(state->tree))) {
1024 pdflags |= (XPT_PD_RETVAL | XPT_PD_IN | XPT_PD_DIPPER);
1025 } else {
1026 pdflags |= (XPT_PD_RETVAL | XPT_PD_OUT);
1027 }
1028 } else {
1029 pdflags |= XPT_PD_IN;
1030 }
1031
1032 if (!fill_pd_from_type(state, meth->params, pdflags,
1033 ATTR_TYPE_DECL(state->tree)))
1034 return FALSE;
1035
1036 fill_pd_as_nsresult(meth->result);
1037 NEXT_METH(state)++;
1038 return TRUE;
1039}
1040
1041static gboolean
1042typelib_attr_dcl(TreeState *state)
1043{
1044 XPTInterfaceDescriptor *id = CURRENT(state);
1045 XPTMethodDescriptor *meth;
1046 gboolean read_only = IDL_ATTR_DCL(state->tree).f_readonly;
1047
1048 /* XXX this only handles the first ident; elsewhere too... */
1049 IDL_tree ident =
1050 IDL_LIST(IDL_ATTR_DCL(state->tree).simple_declarations).data;
1051
1052 /* If it's marked [noscript], mark it as hidden in the typelib. */
1053 gboolean hidden = (IDL_tree_property_get(ident, "noscript") != NULL);
1054
1055 if (!verify_attribute_declaration(state->tree))
1056 return FALSE;
1057
1058 if (!XPT_InterfaceDescriptorAddMethods(ARENA(state), id,
1059 (PRUint16) (read_only ? 1 : 2)))
1060 return FALSE;
1061
1062 meth = &id->method_descriptors[NEXT_METH(state)];
1063
1064 return typelib_attr_accessor(state, meth, TRUE, hidden) &&
1065 (read_only || typelib_attr_accessor(state, meth + 1, FALSE, hidden));
1066}
1067
1068static gboolean
1069typelib_op_dcl(TreeState *state)
1070{
1071 XPTInterfaceDescriptor *id = CURRENT(state);
1072 XPTMethodDescriptor *meth;
1073 struct _IDL_OP_DCL *op = &IDL_OP_DCL(state->tree);
1074 IDL_tree iter;
1075 uint16 num_args = 0;
1076 uint8 op_flags = 0;
1077 gboolean op_notxpcom = (IDL_tree_property_get(op->ident, "notxpcom")
1078 != NULL);
1079 gboolean op_noscript = (IDL_tree_property_get(op->ident, "noscript")
1080 != NULL);
1081
1082 if (!verify_method_declaration(state->tree))
1083 return FALSE;
1084
1085 if (!XPT_InterfaceDescriptorAddMethods(ARENA(state), id, 1))
1086 return FALSE;
1087
1088 meth = &id->method_descriptors[NEXT_METH(state)];
1089
1090 for (iter = op->parameter_dcls; iter; iter = IDL_LIST(iter).next)
1091 num_args++; /* count params */
1092 if (op->op_type_spec && !op_notxpcom)
1093 num_args++; /* fake param for _retval */
1094
1095 if (op_noscript)
1096 op_flags |= XPT_MD_HIDDEN;
1097 if (op_notxpcom)
1098 op_flags |= XPT_MD_NOTXPCOM;
1099
1100 /* XXXshaver constructor? */
1101
1102#ifdef DEBUG_shaver_method
1103 fprintf(stdout, "DBG: adding method %s (nargs %d)\n",
1104 IDL_IDENT(op->ident).str, num_args);
1105#endif
1106 if (!XPT_FillMethodDescriptor(ARENA(state), meth, op_flags,
1107 IDL_IDENT(op->ident).str,
1108 (uint8) num_args))
1109 return FALSE;
1110
1111 for (num_args = 0, iter = op->parameter_dcls; iter;
1112 iter = IDL_LIST(iter).next, num_args++) {
1113 XPTParamDescriptor *pd = &meth->params[num_args];
1114 if (!fill_pd_from_param(state, pd, IDL_LIST(iter).data))
1115 return FALSE;
1116 }
1117
1118 /* stick retval param where we can see it later */
1119 state->tree = op->op_type_spec;
1120
1121 /* XXX unless [notxpcom] */
1122 if (!op_notxpcom) {
1123 if (op->op_type_spec) {
1124 uint8 pdflags = DIPPER_TYPE(op->op_type_spec) ?
1125 (XPT_PD_RETVAL | XPT_PD_IN | XPT_PD_DIPPER) :
1126 (XPT_PD_RETVAL | XPT_PD_OUT);
1127
1128 if (!fill_pd_from_type(state, &meth->params[num_args],
1129 pdflags, op->op_type_spec))
1130 return FALSE;
1131 }
1132
1133 if (!fill_pd_as_nsresult(meth->result))
1134 return FALSE;
1135 } else {
1136#ifdef DEBUG_shaver_notxpcom
1137 fprintf(stderr, "%s is notxpcom\n", IDL_IDENT(op->ident).str);
1138#endif
1139 if (!fill_pd_from_type(state, meth->result, XPT_PD_RETVAL,
1140 op->op_type_spec))
1141 return FALSE;
1142 }
1143 NEXT_METH(state)++;
1144 return TRUE;
1145}
1146
1147static gboolean
1148typelib_const_dcl(TreeState *state)
1149{
1150 struct _IDL_CONST_DCL *dcl = &IDL_CONST_DCL(state->tree);
1151 const char *name = IDL_IDENT(dcl->ident).str;
1152 gboolean is_long;
1153 gboolean sign;
1154 IDL_tree real_type;
1155 XPTInterfaceDescriptor *id;
1156 XPTConstDescriptor *cd;
1157 IDL_longlong_t value;
1158
1159 if (!verify_const_declaration(state->tree))
1160 return FALSE;
1161
1162 /* Could be a typedef; try to map it to the real type. */
1163 real_type = find_underlying_type(dcl->const_type);
1164 real_type = real_type ? real_type : dcl->const_type;
1165 is_long = (IDL_TYPE_INTEGER(real_type).f_type == IDL_INTEGER_TYPE_LONG);
1166
1167 id = CURRENT(state);
1168 if (!XPT_InterfaceDescriptorAddConsts(ARENA(state), id, 1))
1169 return FALSE;
1170 cd = &id->const_descriptors[NEXT_CONST(state)];
1171
1172 cd->name = IDL_IDENT(dcl->ident).str;
1173#ifdef DEBUG_shaver_const
1174 fprintf(stderr, "DBG: adding const %s\n", cd->name);
1175#endif
1176 if (!fill_td_from_type(state, &cd->type, dcl->const_type))
1177 return FALSE;
1178
1179 value = IDL_INTEGER(dcl->const_exp).value;
1180 sign = IDL_TYPE_INTEGER(dcl->const_type).f_signed;
1181 if (is_long) {
1182 if (sign)
1183 cd->value.i32 = value;
1184 else
1185 cd->value.ui32 = value;
1186 } else {
1187 if (sign)
1188 cd->value.i16 = value;
1189 else
1190 cd->value.ui16 = value;
1191 }
1192 NEXT_CONST(state)++;
1193 return TRUE;
1194}
1195
1196static gboolean
1197typelib_enum(TreeState *state)
1198{
1199 XPIDL_WARNING((state->tree, IDL_WARNING1,
1200 "enums not supported, enum \'%s\' ignored",
1201 IDL_IDENT(IDL_TYPE_ENUM(state->tree).ident).str));
1202 return TRUE;
1203}
1204
1205backend *
1206xpidl_typelib_dispatch(void)
1207{
1208 static backend result;
1209 static nodeHandler table[IDLN_LAST];
1210 static gboolean initialized = FALSE;
1211
1212 result.emit_prolog = typelib_prolog;
1213 result.emit_epilog = typelib_epilog;
1214
1215 if (!initialized) {
1216 /* Initialize non-NULL elements */
1217 table[IDLN_LIST] = typelib_list;
1218 table[IDLN_ATTR_DCL] = typelib_attr_dcl;
1219 table[IDLN_OP_DCL] = typelib_op_dcl;
1220 table[IDLN_INTERFACE] = typelib_interface;
1221 table[IDLN_CONST_DCL] = typelib_const_dcl;
1222 table[IDLN_TYPE_ENUM] = typelib_enum;
1223 table[IDLN_NATIVE] = check_native;
1224 initialized = TRUE;
1225 }
1226
1227 result.dispatch_table = table;
1228 return &result;
1229}
1230
1231
1232
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use