widl: Use generic 'struct sltg_data' for collecting data.
[wine.git] / tools / widl / write_sltg.c
blob880bfcfbe5c1020f17b9f51c6d7169f24c69b3b7
1 /*
2 * Typelib (SLTG) generation
4 * Copyright 2015 Dmitry Timoshkov
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include "config.h"
23 #include <stdlib.h>
24 #include <string.h>
25 #include <stdarg.h>
26 #include <stdio.h>
27 #include <ctype.h>
28 #include <time.h>
30 #include "widl.h"
31 #include "windef.h"
32 #include "winbase.h"
34 #include "typelib.h"
35 #include "typelib_struct.h"
36 #include "utils.h"
37 #include "header.h"
38 #include "typetree.h"
40 static const GUID sltg_library_guid = { 0x204ff,0,0,{ 0xc0,0,0,0,0,0,0,0x46 } };
42 struct sltg_data
44 int size, allocated;
45 char *data;
48 struct sltg_library
50 short name;
51 char *helpstring;
52 char *helpfile;
53 int helpcontext;
54 int syskind;
55 LCID lcid;
56 int libflags;
57 int version;
58 GUID uuid;
61 struct sltg_block
63 int length;
64 int index_string;
65 void *data;
68 struct sltg_typelib
70 typelib_t *typelib;
71 struct sltg_data index;
72 struct sltg_data name_table;
73 struct sltg_library library;
74 struct sltg_block *blocks;
75 int block_count;
76 int first_block;
77 short typeinfo_count;
80 static void init_sltg_data(struct sltg_data *data)
82 data->size = 0;
83 data->allocated = 0;
84 data->data = NULL;
87 static int add_index(struct sltg_data *index, const char *name)
89 int name_offset = index->size;
90 int new_size = index->size + strlen(name) + 1;
92 if (new_size > index->allocated)
94 index->allocated = index->allocated ? max(index->allocated * 2, new_size) : new_size;
95 index->data = xrealloc(index->data, index->allocated);
98 strcpy(index->data + index->size, name);
99 index->size = new_size;
101 return name_offset;
104 static void init_index(struct sltg_data *index)
106 static const char compobj[] = { 1,'C','o','m','p','O','b','j',0 };
108 init_sltg_data(index);
110 add_index(index, compobj);
113 static int add_name(struct sltg_data *name_table, const char *name)
115 int name_offset = name_table->size;
116 int new_size = name_table->size + strlen(name) + 1 + 8;
118 new_size = (new_size + 1) & ~1; /* align */
120 if (new_size > name_table->allocated)
122 name_table->allocated = name_table->allocated ? max(name_table->allocated * 2, new_size) : new_size;
123 name_table->data = xrealloc(name_table->data, name_table->allocated);
126 memset(name_table->data + name_table->size, 0xff, 8);
127 strcpy(name_table->data + name_table->size + 8, name);
128 name_table->size = new_size;
129 name_table->data[name_table->size - 1] = 0; /* clear alignment */
131 return name_offset;
134 static void init_name_table(struct sltg_data *name_table)
136 init_sltg_data(name_table);
139 static void init_library(struct sltg_typelib *sltg)
141 const attr_t *attr;
143 sltg->library.name = add_name(&sltg->name_table, sltg->typelib->name);
144 sltg->library.helpstring = NULL;
145 sltg->library.helpcontext = 0;
146 sltg->library.syskind = SYS_WIN32;
147 sltg->library.lcid = 0x0409;
148 sltg->library.libflags = 0;
149 sltg->library.version = 0;
150 sltg->library.helpfile = NULL;
151 memset(&sltg->library.uuid, 0, sizeof(sltg->library.uuid));
153 if (!sltg->typelib->attrs) return;
155 LIST_FOR_EACH_ENTRY(attr, sltg->typelib->attrs, const attr_t, entry)
157 const expr_t *expr;
159 switch (attr->type)
161 case ATTR_VERSION:
162 sltg->library.version = attr->u.ival;
163 break;
164 case ATTR_HELPSTRING:
165 sltg->library.helpstring = attr->u.pval;
166 break;
167 case ATTR_HELPFILE:
168 sltg->library.helpfile = attr->u.pval;
169 break;
170 case ATTR_UUID:
171 sltg->library.uuid = *(GUID *)attr->u.pval;
172 break;
173 case ATTR_HELPCONTEXT:
174 expr = attr->u.pval;
175 sltg->library.helpcontext = expr->cval;
176 break;
177 case ATTR_LIBLCID:
178 expr = attr->u.pval;
179 sltg->library.lcid = expr->cval;
180 break;
181 case ATTR_CONTROL:
182 sltg->library.libflags |= 0x02; /* LIBFLAG_FCONTROL */
183 break;
184 case ATTR_HIDDEN:
185 sltg->library.libflags |= 0x04; /* LIBFLAG_FHIDDEN */
186 break;
187 case ATTR_RESTRICTED:
188 sltg->library.libflags |= 0x01; /* LIBFLAG_FRESTRICTED */
189 break;
190 default:
191 break;
196 static void add_block(struct sltg_typelib *sltg, void *data, int length, const char *name)
198 sltg->blocks = xrealloc(sltg->blocks, sizeof(sltg->blocks[0]) * (sltg->block_count + 1));
199 sltg->blocks[sltg->block_count].length = length;
200 sltg->blocks[sltg->block_count].data = data;
201 sltg->blocks[sltg->block_count].index_string = add_index(&sltg->index, name);
202 sltg->block_count++;
205 static void add_library_block(struct sltg_typelib *typelib)
207 void *block;
208 short *p;
209 int size;
211 size = sizeof(short) * 9 + sizeof(int) * 3 + sizeof(GUID);
212 if (typelib->library.helpstring) size += strlen(typelib->library.helpstring);
213 if (typelib->library.helpfile) size += strlen(typelib->library.helpfile);
215 block = xmalloc(size);
216 p = block;
217 *p++ = 0x51cc; /* magic */
218 *p++ = 3; /* res02 */
219 *p++ = typelib->library.name;
220 *p++ = 0xffff; /* res06 */
221 if (typelib->library.helpstring)
223 *p++ = strlen(typelib->library.helpstring);
224 strcpy((char *)p, typelib->library.helpstring);
225 p = (short *)((char *)p + strlen(typelib->library.helpstring));
227 else
228 *p++ = 0xffff;
229 if (typelib->library.helpfile)
231 *p++ = strlen(typelib->library.helpfile);
232 strcpy((char *)p, typelib->library.helpfile);
233 p = (short *)((char *)p + strlen(typelib->library.helpfile));
235 else
236 *p++ = 0xffff;
237 *(int *)p = typelib->library.helpcontext;
238 p += 2;
239 *p++ = typelib->library.syskind;
240 *p++ = typelib->library.lcid;
241 *(int *)p = 0; /* res12 */
242 p += 2;
243 *p++ = typelib->library.libflags;
244 *(int *)p = typelib->library.version;
245 p += 2;
246 *(GUID *)p = typelib->library.uuid;
248 add_block(typelib, block, size, "dir");
251 static void add_typedef_typeinfo(struct sltg_typelib *typelib, type_t *type)
253 error("add_typedef_typeinfo: %s not implemented\n", type->name);
256 static void add_module_typeinfo(struct sltg_typelib *typelib, type_t *type)
258 error("add_module_typeinfo: %s not implemented\n", type->name);
261 static void add_interface_typeinfo(struct sltg_typelib *typelib, type_t *type)
263 error("add_interface_typeinfo: %s not implemented\n", type->name);
266 static void add_structure_typeinfo(struct sltg_typelib *typelib, type_t *type)
268 error("add_structure_typeinfo: %s not implemented\n", type->name);
271 static void add_enum_typeinfo(struct sltg_typelib *typelib, type_t *type)
273 error("add_enum_typeinfo: %s not implemented\n", type->name);
276 static void add_union_typeinfo(struct sltg_typelib *typelib, type_t *type)
278 error("add_union_typeinfo: %s not implemented\n", type->name);
281 static void add_coclass_typeinfo(struct sltg_typelib *typelib, type_t *type)
283 error("add_coclass_typeinfo: %s not implemented\n", type->name);
286 static void add_type_typeinfo(struct sltg_typelib *typelib, type_t *type)
288 chat("add_type_typeinfo: adding %s, type %d\n", type->name, type_get_type(type));
290 switch (type_get_type(type))
292 case TYPE_INTERFACE:
293 add_interface_typeinfo(typelib, type);
294 break;
295 case TYPE_STRUCT:
296 add_structure_typeinfo(typelib, type);
297 break;
298 case TYPE_ENUM:
299 add_enum_typeinfo(typelib, type);
300 break;
301 case TYPE_UNION:
302 add_union_typeinfo(typelib, type);
303 break;
304 case TYPE_COCLASS:
305 add_coclass_typeinfo(typelib, type);
306 break;
307 case TYPE_BASIC:
308 case TYPE_POINTER:
309 break;
310 default:
311 error("add_type_typeinfo: unhandled type %d for %s\n", type_get_type(type), type->name);
312 break;
316 static void add_statement(struct sltg_typelib *typelib, const statement_t *stmt)
318 switch(stmt->type)
320 case STMT_LIBRARY:
321 case STMT_IMPORT:
322 case STMT_PRAGMA:
323 case STMT_CPPQUOTE:
324 case STMT_DECLARATION:
325 /* not included in typelib */
326 break;
327 case STMT_IMPORTLIB:
328 /* not processed here */
329 break;
331 case STMT_TYPEDEF:
333 typeref_t *ref;
335 if (!stmt->u.type_list)
336 break;
338 LIST_FOR_EACH_ENTRY(ref, stmt->u.type_list, typeref_t, entry)
340 /* if the type is public then add the typedef, otherwise attempt
341 * to add the aliased type */
342 if (is_attr(ref->type->attrs, ATTR_PUBLIC))
343 add_typedef_typeinfo(typelib, ref->type);
344 else
345 add_type_typeinfo(typelib, type_alias_get_aliasee_type(ref->type));
347 break;
350 case STMT_MODULE:
351 add_module_typeinfo(typelib, stmt->u.type);
352 break;
354 case STMT_TYPE:
355 case STMT_TYPEREF:
357 type_t *type = stmt->u.type;
358 add_type_typeinfo(typelib, type);
359 break;
362 default:
363 error("add_statement: unhandled statement type %d\n", stmt->type);
364 break;
368 static void sltg_write_header(struct sltg_typelib *sltg, int *library_block_start)
370 char pad[0x40];
371 struct sltg_header
373 int magic;
374 short block_count;
375 short res06;
376 short size_of_index;
377 short first_blk;
378 GUID uuid;
379 int res1c;
380 int res20;
381 } header;
382 struct sltg_block_entry
384 int length;
385 short index_string;
386 short next;
387 } entry;
388 int i;
390 header.magic = 0x47544c53;
391 header.block_count = sltg->block_count + 1; /* 1-based */
392 header.res06 = 9;
393 header.size_of_index = sltg->index.size;
394 header.first_blk = 1; /* 1-based */
395 header.uuid = sltg_library_guid;
396 header.res1c = 0x00000044;
397 header.res20 = 0xffff0000;
399 put_data(&header, sizeof(header));
401 /* library block is written separately */
402 for (i = 0; i < sltg->block_count - 1; i++)
404 entry.length = sltg->blocks[i].length;
405 entry.index_string = sltg->blocks[i].index_string;
406 entry.next = header.first_blk + i;
407 put_data(&entry, sizeof(entry));
410 /* library block length includes helpstrings and name table */
411 entry.length = sltg->blocks[sltg->block_count - 1].length + 0x40 /* pad after library block */ +
412 sizeof(sltg->typeinfo_count) + 4 /* library block offset */ + 6 /* dummy help strings */ +
413 12 /* name table header */ + 0x200 /* name table hash */ + sltg->name_table.size;
414 entry.index_string = sltg->blocks[sltg->block_count - 1].index_string;
415 entry.next = 0;
416 put_data(&entry, sizeof(entry));
418 put_data(sltg->index.data, sltg->index.size);
419 memset(pad, 0, 9);
420 put_data(pad, 9);
422 /* library block is written separately */
423 for (i = 0; i < sltg->block_count - 1; i++)
425 chat("sltg_write_header: writing block %d: %d bytes\n", i, sltg->blocks[i].length);
426 put_data(sltg->blocks[i].data, sltg->blocks[i].length);
429 /* library block */
430 *library_block_start = output_buffer_pos;
431 put_data(sltg->blocks[sltg->block_count - 1].data, sltg->blocks[sltg->block_count - 1].length);
433 memset(pad, 0xff, 0x40);
434 put_data(pad, 0x40);
437 static void sltg_write_typeinfo(struct sltg_typelib *typelib)
439 put_data(&typelib->typeinfo_count, sizeof(typelib->typeinfo_count));
442 static void sltg_write_helpstrings(struct sltg_typelib *typelib)
444 static const char dummy[6];
446 put_data(dummy, sizeof(dummy));
449 static void sltg_write_nametable(struct sltg_typelib *typelib)
451 static const short dummy[6] = { 0xffff,1,2,0xff00,0xffff,0xffff };
452 char pad[0x200];
454 put_data(dummy, sizeof(dummy));
455 memset(pad, 0xff, 0x200);
456 put_data(pad, 0x200);
457 put_data(&typelib->name_table.size, sizeof(typelib->name_table.size));
458 put_data(typelib->name_table.data, typelib->name_table.size);
461 static void sltg_write_remainder(void)
463 static const short dummy1[] = { 1,0xfffe,0x0a03,0,0xffff,0xffff };
464 static const short dummy2[] = { 0xffff,0xffff,0x0200,0,0,0 };
465 static const char dummy3[] = { 0xf4,0x39,0xb2,0x71,0,0,0,0,0,0,0,0,0,0,0,0 };
466 static const char TYPELIB[] = { 8,0,0,0,'T','Y','P','E','L','I','B',0 };
467 int pad;
469 pad = 0x01ffff01;
470 put_data(&pad, sizeof(pad));
471 pad = 0;
472 put_data(&pad, sizeof(pad));
474 put_data(dummy1, sizeof(dummy1));
476 put_data(&sltg_library_guid, sizeof(sltg_library_guid));
478 put_data(TYPELIB, sizeof(TYPELIB));
480 put_data(dummy2, sizeof(dummy2));
481 put_data(dummy3, sizeof(dummy3));
484 static void save_all_changes(struct sltg_typelib *typelib)
486 int library_block_start;
487 int *name_table_offset;
489 sltg_write_header(typelib, &library_block_start);
490 sltg_write_typeinfo(typelib);
492 name_table_offset = (int *)(output_buffer + output_buffer_pos);
493 put_data(&library_block_start, sizeof(library_block_start));
495 sltg_write_helpstrings(typelib);
497 *name_table_offset = output_buffer_pos - library_block_start;
499 sltg_write_nametable(typelib);
500 sltg_write_remainder();
502 if (strendswith(typelib_name, ".res")) /* create a binary resource file */
504 char typelib_id[13] = "#1";
506 expr_t *expr = get_attrp(typelib->typelib->attrs, ATTR_ID);
507 if (expr)
508 sprintf(typelib_id, "#%d", expr->cval);
509 add_output_to_resources("TYPELIB", typelib_id);
510 if (strendswith(typelib_name, "_t.res")) /* add typelib registration */
511 output_typelib_regscript(typelib->typelib);
513 else flush_output_buffer(typelib_name);
516 int create_sltg_typelib(typelib_t *typelib)
518 struct sltg_typelib sltg;
519 const statement_t *stmt;
521 sltg.typelib = typelib;
522 sltg.typeinfo_count = 0;
523 sltg.blocks = NULL;
524 sltg.block_count = 0;
525 sltg.first_block = 1;
527 init_index(&sltg.index);
528 init_name_table(&sltg.name_table);
529 init_library(&sltg);
531 add_library_block(&sltg);
533 if (typelib->stmts)
534 LIST_FOR_EACH_ENTRY(stmt, typelib->stmts, const statement_t, entry)
535 add_statement(&sltg, stmt);
537 save_all_changes(&sltg);
539 return 1;