reg: Stop parsing REG_SZ values containing NUL character sequences.
[wine/zf.git] / tools / widl / register.c
blob76bfc3c715c755fb5bc609aec3320019fdf26ca8
1 /*
2 * Generation of dll registration scripts
4 * Copyright 2010 Alexandre Julliard
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"
22 #include "wine/port.h"
24 #include <stdio.h>
25 #include <stdlib.h>
26 #ifdef HAVE_UNISTD_H
27 # include <unistd.h>
28 #endif
29 #include <string.h>
30 #include <ctype.h>
32 #include "widl.h"
33 #include "utils.h"
34 #include "parser.h"
35 #include "header.h"
36 #include "typegen.h"
37 #include "typelib.h"
39 static int indent;
41 static const char *format_uuid( const UUID *uuid )
43 static char buffer[40];
44 sprintf( buffer, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
45 uuid->Data1, uuid->Data2, uuid->Data3,
46 uuid->Data4[0], uuid->Data4[1], uuid->Data4[2], uuid->Data4[3],
47 uuid->Data4[4], uuid->Data4[5], uuid->Data4[6], uuid->Data4[7] );
48 return buffer;
51 static const char *get_coclass_threading( const type_t *class )
53 static const char * const models[] =
55 NULL,
56 "Apartment", /* THREADING_APARTMENT */
57 "Neutral", /* THREADING_NEUTRAL */
58 "Single", /* THREADING_SINGLE */
59 "Free", /* THREADING_FREE */
60 "Both", /* THREADING_BOTH */
62 return models[get_attrv( class->attrs, ATTR_THREADING )];
65 static const type_t *find_ps_factory( const statement_list_t *stmts )
67 const statement_t *stmt;
69 if (stmts) LIST_FOR_EACH_ENTRY( stmt, stmts, const statement_t, entry )
71 if (stmt->type == STMT_TYPE)
73 const type_t *type = stmt->u.type;
74 if (type_get_type(type) == TYPE_COCLASS && !strcmp( type->name, "PSFactoryBuffer" ))
75 return type;
78 return NULL;
81 static void write_interface( const type_t *iface, const type_t *ps_factory )
83 const UUID *uuid = get_attrp( iface->attrs, ATTR_UUID );
84 const UUID *ps_uuid = get_attrp( ps_factory->attrs, ATTR_UUID );
86 if (!uuid) return;
87 if (!is_object( iface )) return;
88 if (!type_iface_get_inherit(iface)) /* special case for IUnknown */
90 put_str( indent, "'%s' = s '%s'\n", format_uuid( uuid ), iface->name );
91 return;
93 if (is_local( iface->attrs )) return;
94 put_str( indent, "'%s' = s '%s'\n", format_uuid( uuid ), iface->name );
95 put_str( indent, "{\n" );
96 indent++;
97 put_str( indent, "NumMethods = s %u\n", count_methods( iface ));
98 put_str( indent, "ProxyStubClsid32 = s '%s'\n", format_uuid( ps_uuid ));
99 indent--;
100 put_str( indent, "}\n" );
103 static void write_interfaces( const statement_list_t *stmts, const type_t *ps_factory )
105 const statement_t *stmt;
107 if (stmts) LIST_FOR_EACH_ENTRY( stmt, stmts, const statement_t, entry )
109 if (stmt->type == STMT_TYPE && type_get_type( stmt->u.type ) == TYPE_INTERFACE)
110 write_interface( stmt->u.type, ps_factory );
114 static void write_typelib_interface( const type_t *iface, const typelib_t *typelib )
116 const UUID *typelib_uuid = get_attrp( typelib->attrs, ATTR_UUID );
117 const UUID *uuid = get_attrp( iface->attrs, ATTR_UUID );
118 unsigned int version = get_attrv( typelib->attrs, ATTR_VERSION );
120 if (!uuid) return;
121 if (!is_object( iface )) return;
122 put_str( indent, "'%s' = s '%s'\n", format_uuid( uuid ), iface->name );
123 put_str( indent, "{\n" );
124 indent++;
125 put_str( indent, "ProxyStubClsid = s '{00020424-0000-0000-C000-000000000046}'\n" );
126 put_str( indent, "ProxyStubClsid32 = s '{00020424-0000-0000-C000-000000000046}'\n" );
127 if (version)
128 put_str( indent, "TypeLib = s '%s' { val Version = s '%u.%u' }\n",
129 format_uuid( typelib_uuid ), MAJORVERSION(version), MINORVERSION(version) );
130 else
131 put_str( indent, "TypeLib = s '%s'", format_uuid( typelib_uuid ));
132 indent--;
133 put_str( indent, "}\n" );
136 static void write_typelib_interfaces( const typelib_t *typelib )
138 unsigned int i;
140 for (i = 0; i < typelib->reg_iface_count; ++i)
141 write_typelib_interface( typelib->reg_ifaces[i], typelib );
144 static int write_coclass( const type_t *class, const typelib_t *typelib )
146 const UUID *uuid = get_attrp( class->attrs, ATTR_UUID );
147 const char *descr = get_attrp( class->attrs, ATTR_HELPSTRING );
148 const char *progid = get_attrp( class->attrs, ATTR_PROGID );
149 const char *vi_progid = get_attrp( class->attrs, ATTR_VIPROGID );
150 const char *threading = get_coclass_threading( class );
151 unsigned int version = get_attrv( class->attrs, ATTR_VERSION );
153 if (!uuid) return 0;
154 if (typelib && !threading && !progid) return 0;
155 if (!descr) descr = class->name;
157 put_str( indent, "'%s' = s '%s'\n", format_uuid( uuid ), descr );
158 put_str( indent++, "{\n" );
159 if (threading) put_str( indent, "InprocServer32 = s '%%MODULE%%' { val ThreadingModel = s '%s' }\n",
160 threading );
161 if (progid) put_str( indent, "ProgId = s '%s'\n", progid );
162 if (typelib)
164 const UUID *typelib_uuid = get_attrp( typelib->attrs, ATTR_UUID );
165 put_str( indent, "TypeLib = s '%s'\n", format_uuid( typelib_uuid ));
166 if (!version) version = get_attrv( typelib->attrs, ATTR_VERSION );
168 if (version) put_str( indent, "Version = s '%u.%u'\n", MAJORVERSION(version), MINORVERSION(version) );
169 if (vi_progid) put_str( indent, "VersionIndependentProgId = s '%s'\n", vi_progid );
170 put_str( --indent, "}\n" );
171 return 1;
174 static void write_coclasses( const statement_list_t *stmts, const typelib_t *typelib )
176 const statement_t *stmt;
178 if (stmts) LIST_FOR_EACH_ENTRY( stmt, stmts, const statement_t, entry )
180 if (stmt->type == STMT_TYPE)
182 const type_t *type = stmt->u.type;
183 if (type_get_type(type) == TYPE_COCLASS) write_coclass( type, typelib );
188 static void write_runtimeclasses_registry( const statement_list_t *stmts )
190 const statement_t *stmt;
191 const type_t *type;
193 if (stmts) LIST_FOR_EACH_ENTRY( stmt, stmts, const statement_t, entry )
195 if (stmt->type != STMT_TYPE) continue;
196 if (type_get_type((type = stmt->u.type)) != TYPE_RUNTIMECLASS) continue;
197 put_str( indent, "ForceRemove %s\n", format_namespace( type->namespace, "", ".", type->name, NULL ) );
198 put_str( indent++, "{\n" );
199 put_str( indent, "val 'DllPath' = s '%%MODULE%%'\n" );
200 put_str( --indent, "}\n" );
204 static int write_progid( const type_t *class )
206 const UUID *uuid = get_attrp( class->attrs, ATTR_UUID );
207 const char *descr = get_attrp( class->attrs, ATTR_HELPSTRING );
208 const char *progid = get_attrp( class->attrs, ATTR_PROGID );
209 const char *vi_progid = get_attrp( class->attrs, ATTR_VIPROGID );
211 if (!uuid) return 0;
212 if (!descr) descr = class->name;
214 if (progid)
216 put_str( indent, "'%s' = s '%s'\n", progid, descr );
217 put_str( indent++, "{\n" );
218 put_str( indent, "CLSID = s '%s'\n", format_uuid( uuid ) );
219 put_str( --indent, "}\n" );
221 if (vi_progid)
223 put_str( indent, "'%s' = s '%s'\n", vi_progid, descr );
224 put_str( indent++, "{\n" );
225 put_str( indent, "CLSID = s '%s'\n", format_uuid( uuid ) );
226 if (progid && strcmp( progid, vi_progid )) put_str( indent, "CurVer = s '%s'\n", progid );
227 put_str( --indent, "}\n" );
229 return 1;
232 static void write_progids( const statement_list_t *stmts )
234 const statement_t *stmt;
236 if (stmts) LIST_FOR_EACH_ENTRY( stmt, stmts, const statement_t, entry )
238 if (stmt->type == STMT_TYPE)
240 const type_t *type = stmt->u.type;
241 if (type_get_type(type) == TYPE_COCLASS) write_progid( type );
246 void write_regscript( const statement_list_t *stmts )
248 const type_t *ps_factory;
250 if (!do_regscript) return;
251 if (do_everything && !need_proxy_file( stmts )) return;
253 init_output_buffer();
255 if (winrt_mode)
257 put_str( indent, "HKLM\n" );
258 put_str( indent++, "{\n" );
259 put_str( indent, "NoRemove Software\n" );
260 put_str( indent++, "{\n" );
261 put_str( indent, "NoRemove Microsoft\n" );
262 put_str( indent++, "{\n" );
263 put_str( indent, "NoRemove WindowsRuntime\n" );
264 put_str( indent++, "{\n" );
265 put_str( indent, "NoRemove ActivatableClassId\n" );
266 put_str( indent++, "{\n" );
267 write_runtimeclasses_registry( stmts );
268 put_str( --indent, "}\n" );
269 put_str( --indent, "}\n" );
270 put_str( --indent, "}\n" );
271 put_str( --indent, "}\n" );
272 put_str( --indent, "}\n" );
274 else
276 put_str( indent, "HKCR\n" );
277 put_str( indent++, "{\n" );
279 put_str( indent, "NoRemove Interface\n" );
280 put_str( indent++, "{\n" );
281 ps_factory = find_ps_factory( stmts );
282 if (ps_factory) write_interfaces( stmts, ps_factory );
283 put_str( --indent, "}\n" );
285 put_str( indent, "NoRemove CLSID\n" );
286 put_str( indent++, "{\n" );
287 write_coclasses( stmts, NULL );
288 put_str( --indent, "}\n" );
290 write_progids( stmts );
291 put_str( --indent, "}\n" );
294 if (strendswith( regscript_name, ".res" )) /* create a binary resource file */
296 add_output_to_resources( "WINE_REGISTRY", regscript_token );
297 flush_output_resources( regscript_name );
299 else
301 FILE *f = fopen( regscript_name, "w" );
302 if (!f) error( "Could not open %s for output\n", regscript_name );
303 if (fwrite( output_buffer, 1, output_buffer_pos, f ) != output_buffer_pos)
304 error( "Failed to write to %s\n", regscript_name );
305 if (fclose( f ))
306 error( "Failed to write to %s\n", regscript_name );
310 void write_typelib_regscript( const statement_list_t *stmts )
312 const statement_t *stmt;
313 unsigned int count = 0;
315 if (!do_typelib) return;
316 if (stmts) LIST_FOR_EACH_ENTRY( stmt, stmts, const statement_t, entry )
318 if (stmt->type != STMT_LIBRARY) continue;
319 if (count && !strendswith( typelib_name, ".res" ))
320 error( "Cannot store multiple typelibs into %s\n", typelib_name );
321 else
322 create_msft_typelib( stmt->u.lib );
323 count++;
325 if (count && strendswith( typelib_name, ".res" )) flush_output_resources( typelib_name );
328 void output_typelib_regscript( const typelib_t *typelib )
330 const UUID *typelib_uuid = get_attrp( typelib->attrs, ATTR_UUID );
331 const char *descr = get_attrp( typelib->attrs, ATTR_HELPSTRING );
332 const expr_t *lcid_expr = get_attrp( typelib->attrs, ATTR_LIBLCID );
333 unsigned int version = get_attrv( typelib->attrs, ATTR_VERSION );
334 unsigned int flags = 0;
335 char id_part[12] = "";
336 char *resname = typelib_name;
337 expr_t *expr;
339 if (is_attr( typelib->attrs, ATTR_RESTRICTED )) flags |= 1; /* LIBFLAG_FRESTRICTED */
340 if (is_attr( typelib->attrs, ATTR_CONTROL )) flags |= 2; /* LIBFLAG_FCONTROL */
341 if (is_attr( typelib->attrs, ATTR_HIDDEN )) flags |= 4; /* LIBFLAG_FHIDDEN */
343 put_str( indent, "HKCR\n" );
344 put_str( indent++, "{\n" );
346 put_str( indent, "NoRemove Typelib\n" );
347 put_str( indent++, "{\n" );
348 put_str( indent, "NoRemove '%s'\n", format_uuid( typelib_uuid ));
349 put_str( indent++, "{\n" );
350 put_str( indent, "'%u.%u' = s '%s'\n",
351 MAJORVERSION(version), MINORVERSION(version), descr ? descr : typelib->name );
352 put_str( indent++, "{\n" );
353 expr = get_attrp( typelib->attrs, ATTR_ID );
354 if (expr)
356 sprintf(id_part, "\\%d", expr->cval);
357 resname = strmake("%s\\%d", typelib_name, expr->cval);
359 put_str( indent, "'%x' { %s = s '%%MODULE%%%s' }\n",
360 lcid_expr ? lcid_expr->cval : 0, pointer_size == 8 ? "win64" : "win32", id_part );
361 put_str( indent, "FLAGS = s '%u'\n", flags );
362 put_str( --indent, "}\n" );
363 put_str( --indent, "}\n" );
364 put_str( --indent, "}\n" );
366 put_str( indent, "NoRemove Interface\n" );
367 put_str( indent++, "{\n" );
368 write_typelib_interfaces( typelib );
369 put_str( --indent, "}\n" );
371 put_str( indent, "NoRemove CLSID\n" );
372 put_str( indent++, "{\n" );
373 write_coclasses( typelib->stmts, typelib );
374 put_str( --indent, "}\n" );
376 write_progids( typelib->stmts );
377 put_str( --indent, "}\n" );
379 add_output_to_resources( "WINE_REGISTRY", resname );