1 /*
2 * TYPELIB2
3 *
4 * Copyright 2004 Alastair Bridgewater
5 *
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.
10 *
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.
15 *
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
19 *
20 * --------------------------------------------------------------------------------------
21 * Known problems:
22 *
23 * Badly incomplete.
24 *
25 * Only works on little-endian systems.
26 *
27 */
28
29 #include "config.h"
30 #include "wine/port.h"
31
32 #include <stdlib.h>
33 #include <string.h>
34 #include <stdarg.h>
35 #include <stdio.h>
36 #include <ctype.h>
37
38 #define COBJMACROS
39 #define NONAMELESSUNION
40 #define NONAMELESSSTRUCT
41
42 #include "winerror.h"
43 #include "windef.h"
44 #include "winbase.h"
45 #include "winnls.h"
46 #include "winuser.h"
47
48 #include "wine/unicode.h"
49 #include "objbase.h"
50 #include "typelib.h"
51 #include "wine/debug.h"
52
53 WINE_DEFAULT_DEBUG_CHANNEL(typelib2);
54 /* WINE_DEFAULT_DEBUG_CHANNEL(ole); */
55
56
57 /******************************************************************************
58 * ICreateTypeLib2 {OLEAUT32}
59 *
60 * NOTES
61 * The ICreateTypeLib2 interface provides an interface whereby one may create
62 * new type library (.tlb) files.
63 *
64 * This interface inherits from ICreateTypeLib, and can be freely cast back
65 * and forth between an ICreateTypeLib and an ICreateTypeLib2 on local clients.
66 * This dispensation applies only to ICreateTypeLib objects obtained on MSFT
67 * format type libraries (those made through CreateTypeLib2).
68 *
69 * METHODS
70 */
71
72 /******************************************************************************
73 * ICreateTypeInfo2 {OLEAUT32}
74 *
75 * NOTES
76 * The ICreateTypeInfo2 interface provides an interface whereby one may add
77 * type information to type library (.tlb) files.
78 *
79 * This interface inherits from ICreateTypeInfo, and can be freely cast back
80 * and forth between an ICreateTypeInfo and an ICreateTypeInfo2 on local clients.
81 * This dispensation applies only to ICreateTypeInfo objects obtained on MSFT
82 * format type libraries (those made through CreateTypeLib2).
83 *
84 * METHODS
85 */
86
87 /******************************************************************************
88 * ITypeLib2 {OLEAUT32}
89 *
90 * NOTES
91 * The ITypeLib2 interface provides an interface whereby one may query MSFT
92 * format type library (.tlb) files.
93 *
94 * This interface inherits from ITypeLib, and can be freely cast back and
95 * forth between an ITypeLib and an ITypeLib2 on local clients. This
96 * dispensation applies only to ITypeLib objects obtained on MSFT format type
97 * libraries (those made through CreateTypeLib2).
98 *
99 * METHODS
100 */
101
102 /******************************************************************************
103 * ITypeInfo2 {OLEAUT32}
104 *
105 * NOTES
106 * The ITypeInfo2 interface provides an interface whereby one may query type
107 * information stored in MSFT format type library (.tlb) files.
108 *
109 * This interface inherits from ITypeInfo, and can be freely cast back and
110 * forth between an ITypeInfo and an ITypeInfo2 on local clients. This
111 * dispensation applies only to ITypeInfo objects obtained on MSFT format type
112 * libraries (those made through CreateTypeLib2).
113 *
114 * METHODS
115 */
116
117 /*================== Implementation Structures ===================================*/
118
119 enum MSFT_segment_index {
120 MSFT_SEG_TYPEINFO = 0, /* type information */
121 MSFT_SEG_IMPORTINFO, /* import information */
122 MSFT_SEG_IMPORTFILES, /* import filenames */
123 MSFT_SEG_REFERENCES, /* references (?) */
124 MSFT_SEG_GUIDHASH, /* hash table for guids? */
125 MSFT_SEG_GUID, /* guid storage */
126 MSFT_SEG_NAMEHASH, /* hash table for names */
127 MSFT_SEG_NAME, /* name storage */
128 MSFT_SEG_STRING, /* string storage */
129 MSFT_SEG_TYPEDESC, /* type descriptions */
130 MSFT_SEG_ARRAYDESC, /* array descriptions */
131 MSFT_SEG_CUSTDATA, /* custom data */
132 MSFT_SEG_CUSTDATAGUID, /* custom data guids */
133 MSFT_SEG_UNKNOWN, /* ??? */
134 MSFT_SEG_UNKNOWN2, /* ??? */
135 MSFT_SEG_MAX /* total number of segments */
136 };
137
138 typedef struct tagMSFT_ImpFile {
139 int guid;
140 LCID lcid;
141 int version;
142 char filename[0]; /* preceded by two bytes of encoded (length << 2) + flags in the low two bits. */
143 } MSFT_ImpFile;
144
145 typedef struct tagICreateTypeLib2Impl
146 {
147 const ICreateTypeLib2Vtbl *lpVtbl;
148 const ITypeLib2Vtbl *lpVtblTypeLib2;
149
150 LONG ref;
151
152 WCHAR *filename;
153
154 MSFT_Header typelib_header;
155 INT helpStringDll;
156 MSFT_pSeg typelib_segdir[MSFT_SEG_MAX];
157 char *typelib_segment_data[MSFT_SEG_MAX];
158 int typelib_segment_block_length[MSFT_SEG_MAX];
159
160 INT typelib_typeinfo_offsets[0x200]; /* Hope that's enough. */
161
162 INT *typelib_namehash_segment;
163 INT *typelib_guidhash_segment;
164
165 struct tagICreateTypeInfo2Impl *typeinfos;
166 struct tagICreateTypeInfo2Impl *last_typeinfo;
167 } ICreateTypeLib2Impl;
168
169 static inline ICreateTypeLib2Impl *impl_from_ITypeLib2( ITypeLib2 *iface )
170 {
171 return (ICreateTypeLib2Impl *)((char*)iface - FIELD_OFFSET(ICreateTypeLib2Impl, lpVtblTypeLib2));
172 }
173
174 typedef struct tagICreateTypeInfo2Impl
175 {
176 const ICreateTypeInfo2Vtbl *lpVtbl;
177 const ITypeInfo2Vtbl *lpVtblTypeInfo2;
178
179 LONG ref;
180
181 ICreateTypeLib2Impl *typelib;
182 MSFT_TypeInfoBase *typeinfo;
183
184 INT *typedata;
185 int typedata_allocated;
186 int typedata_length;
187
188 int indices[42];
189 int names[42];
190 int offsets[42];
191
192 int datawidth;
193
194 struct tagICreateTypeInfo2Impl *next_typeinfo;
195 } ICreateTypeInfo2Impl;
196
197 static inline ICreateTypeInfo2Impl *impl_from_ITypeInfo2( ITypeInfo2 *iface )
198 {
199 return (ICreateTypeInfo2Impl *)((char*)iface - FIELD_OFFSET(ICreateTypeInfo2Impl, lpVtblTypeInfo2));
200 }
201
202 static ULONG WINAPI ICreateTypeLib2_fnRelease(ICreateTypeLib2 *iface);
203
204
205 /*================== Internal functions ===================================*/
206
207 /****************************************************************************
208 * ctl2_init_header
209 *
210 * Initializes the type library header of a new typelib.
211 */
212 static void ctl2_init_header(
213 ICreateTypeLib2Impl *This) /* [I] The typelib to initialize. */
214 {
215 This->typelib_header.magic1 = 0x5446534d;
216 This->typelib_header.magic2 = 0x00010002;
217 This->typelib_header.posguid = -1;
218 This->typelib_header.lcid = This->typelib_header.lcid2 = GetUserDefaultLCID();
219 This->typelib_header.varflags = 0x40;
220 This->typelib_header.version = 0;
221 This->typelib_header.flags = 0;
222 This->typelib_header.nrtypeinfos = 0;
223 This->typelib_header.helpstring = -1;
224 This->typelib_header.helpstringcontext = 0;
225 This->typelib_header.helpcontext = 0;
226 This->typelib_header.nametablecount = 0;
227 This->typelib_header.nametablechars = 0;
228 This->typelib_header.NameOffset = -1;
229 This->typelib_header.helpfile = -1;
230 This->typelib_header.CustomDataOffset = -1;
231 This->typelib_header.res44 = 0x20;
232 This->typelib_header.res48 = 0x80;
233 This->typelib_header.dispatchpos = -1;
234 This->typelib_header.nimpinfos = 0;
235 This->helpStringDll = -1;
236 }
237
238 /****************************************************************************
239 * ctl2_init_segdir
240 *
241 * Initializes the segment directory of a new typelib.
242 */
243 static void ctl2_init_segdir(
244 ICreateTypeLib2Impl *This) /* [I] The typelib to initialize. */
245 {
246 int i;
247 MSFT_pSeg *segdir;
248
249 segdir = &This->typelib_segdir[MSFT_SEG_TYPEINFO];
250
251 for (i = 0; i < 15; i++) {
252 segdir[i].offset = -1;
253 segdir[i].length = 0;
254 segdir[i].res08 = -1;
255 segdir[i].res0c = 0x0f;
256 }
257 }
258
259 /****************************************************************************
260 * ctl2_hash_guid
261 *
262 * Generates a hash key from a GUID.
263 *
264 * RETURNS
265 *
266 * The hash key for the GUID.
267 */
268 static int ctl2_hash_guid(
269 REFGUID guid) /* [I] The guid to find. */
270 {
271 int hash;
272 int i;
273
274 hash = 0;
275 for (i = 0; i < 8; i ++) {
276 hash ^= ((const short *)guid)[i];
277 }
278
279 return hash & 0x1f;
280 }
281
282 /****************************************************************************
283 * ctl2_find_guid
284 *
285 * Locates a guid in a type library.
286 *
287 * RETURNS
288 *
289 * The offset into the GUID segment of the guid, or -1 if not found.
290 */
291 static int ctl2_find_guid(
292 ICreateTypeLib2Impl *This, /* [I] The typelib to operate against. */
293 int hash_key, /* [I] The hash key for the guid. */
294 REFGUID guid) /* [I] The guid to find. */
295 {
296 int offset;
297 MSFT_GuidEntry *guidentry;
298
299 offset = This->typelib_guidhash_segment[hash_key];
300 while (offset != -1) {
301 guidentry = (MSFT_GuidEntry *)&This->typelib_segment_data[MSFT_SEG_GUID][offset];
302
303 if (!memcmp(guidentry, guid, sizeof(GUID))) return offset;
304
305 offset = guidentry->next_hash;
306 }
307
308 return offset;
309 }
310
311 /****************************************************************************
312 * ctl2_find_name
313 *
314 * Locates a name in a type library.
315 *
316 * RETURNS
317 *
318 * The offset into the NAME segment of the name, or -1 if not found.
319 *
320 * NOTES
321 *
322 * The name must be encoded as with ctl2_encode_name().
323 */
324 static int ctl2_find_name(
325 ICreateTypeLib2Impl *This, /* [I] The typelib to operate against. */
326 const char *name) /* [I] The encoded name to find. */
327 {
328 int offset;
329 int *namestruct;
330
331 offset = This->typelib_namehash_segment[name[2] & 0x7f];
332 while (offset != -1) {
333 namestruct = (int *)&This->typelib_segment_data[MSFT_SEG_NAME][offset];
334
335 if (!((namestruct[2] ^ *((const int *)name)) & 0xffff00ff)) {
336 /* hash codes and lengths match, final test */
337 if (!strncasecmp(name+4, (void *)(namestruct+3), name[0])) break;
338 }
339
340 /* move to next item in hash bucket */
341 offset = namestruct[1];
342 }
343
344 return offset;
345 }
346
347 /****************************************************************************
348 * ctl2_encode_name
349 *
350 * Encodes a name string to a form suitable for storing into a type library
351 * or comparing to a name stored in a type library.
352 *
353 * RETURNS
354 *
355 * The length of the encoded name, including padding and length+hash fields.
356 *
357 * NOTES
358 *
359 * Will throw an exception if name or result are NULL. Is not multithread
360 * safe in the slightest.
361 */
362 static int ctl2_encode_name(
363 ICreateTypeLib2Impl *This, /* [I] The typelib to operate against (used for LCID only). */
364 const WCHAR *name, /* [I] The name string to encode. */
365 char **result) /* [O] A pointer to a pointer to receive the encoded name. */
366 {
367 int length;
368 static char converted_name[0x104];
369 int offset;
370 int value;
371
372 length = WideCharToMultiByte(CP_ACP, 0, name, strlenW(name), converted_name+4, 0x100, NULL, NULL);
373 converted_name[0] = length & 0xff;
374
375 converted_name[length + 4] = 0;
376
377 converted_name[1] = 0x00;
378
379 value = LHashValOfNameSysA(This->typelib_header.varflags & 0x0f, This->typelib_header.lcid, converted_name + 4);
380
381 converted_name[2] = value;
382 converted_name[3] = value >> 8;
383
384 for (offset = (4 - length) & 3; offset; offset--) converted_name[length + offset + 3] = 0x57;
385
386 *result = converted_name;
387
388 return (length + 7) & ~3;
389 }
390
391 /****************************************************************************
392 * ctl2_encode_string
393 *
394 * Encodes a string to a form suitable for storing into a type library or
395 * comparing to a string stored in a type library.
396 *
397 * RETURNS
398 *
399 * The length of the encoded string, including padding and length fields.
400 *
401 * NOTES
402 *
403 * Will throw an exception if string or result are NULL. Is not multithread
404 * safe in the slightest.
405 */
406 static int ctl2_encode_string(
407 ICreateTypeLib2Impl *This, /* [I] The typelib to operate against (not used?). */
408 const WCHAR *string, /* [I] The string to encode. */
409 char **result) /* [O] A pointer to a pointer to receive the encoded string. */
410 {
411 int length;
412 static char converted_string[0x104];
413 int offset;
414
415 length = WideCharToMultiByte(CP_ACP, 0, string, strlenW(string), converted_string+2, 0x102, NULL, NULL);
416 converted_string[0] = length & 0xff;
417 converted_string[1] = (length >> 8) & 0xff;
418
419 for (offset = (4 - (length + 2)) & 3; offset; offset--) converted_string[length + offset + 1] = 0x57;
420
421 *result = converted_string;
422
423 return (length + 5) & ~3;
424 }
425
426 /****************************************************************************
427 * ctl2_alloc_segment
428 *
429 * Allocates memory from a segment in a type library.
430 *
431 * RETURNS
432 *
433 * Success: The offset within the segment of the new data area.
434 * Failure: -1 (this is invariably an out of memory condition).
435 *
436 * BUGS
437 *
438 * Does not (yet) handle the case where the allocated segment memory needs to grow.
439 */
440 static int ctl2_alloc_segment(
441 ICreateTypeLib2Impl *This, /* [I] The type library in which to allocate. */
442 enum MSFT_segment_index segment, /* [I] The segment in which to allocate. */
443 int size, /* [I] The amount to allocate. */
444 int block_size) /* [I] Initial allocation block size, or 0 for default. */
445 {
446 int offset;
447
448 if(!This->typelib_segment_data[segment]) {
449 if (!block_size) block_size = 0x2000;
450
451 This->typelib_segment_block_length[segment] = block_size;
452 This->typelib_segment_data[segment] = HeapAlloc(GetProcessHeap(), 0, block_size);
453 if (!This->typelib_segment_data[segment]) return -1;
454 memset(This->typelib_segment_data[segment], 0x57, block_size);
455 }
456
457 while ((This->typelib_segdir[segment].length + size) > This->typelib_segment_block_length[segment]) {
458 char *block;
459
460 block_size = This->typelib_segment_block_length[segment];
461 block = HeapReAlloc(GetProcessHeap(), 0, This->typelib_segment_data[segment], block_size << 1);
462 if (!block) return -1;
463
464 if (segment == MSFT_SEG_TYPEINFO) {
465 /* TypeInfos have a direct pointer to their memory space, so we have to fix them up. */
466 ICreateTypeInfo2Impl *typeinfo;
467
468 for (typeinfo = This->typeinfos; typeinfo; typeinfo = typeinfo->next_typeinfo) {
469 typeinfo->typeinfo = (void *)&block[((char *)typeinfo->typeinfo) - This->typelib_segment_data[segment]];
470 }
471 }
472
473 memset(block + block_size, 0x57, block_size);
474 This->typelib_segment_block_length[segment] = block_size << 1;
475 This->typelib_segment_data[segment] = block;
476 }
477
478 offset = This->typelib_segdir[segment].length;
479 This->typelib_segdir[segment].length += size;
480
481 return offset;
482 }
483
484 /****************************************************************************
485 * ctl2_alloc_typeinfo
486 *
487 * Allocates and initializes a typeinfo structure in a type library.
488 *
489 * RETURNS
490 *
491 * Success: The offset of the new typeinfo.
492 * Failure: -1 (this is invariably an out of memory condition).
493 */
494 static int ctl2_alloc_typeinfo(
495 ICreateTypeLib2Impl *This, /* [I] The type library to allocate in. */
496 int nameoffset) /* [I] The offset of the name for this typeinfo. */
497 {
498 int offset;
499 MSFT_TypeInfoBase *typeinfo;
500
501 offset = ctl2_alloc_segment(This, MSFT_SEG_TYPEINFO, sizeof(MSFT_TypeInfoBase), 0);
502 if (offset == -1) return -1;
503
504 This->typelib_typeinfo_offsets[This->typelib_header.nrtypeinfos++] = offset;
505
506 typeinfo = (void *)(This->typelib_segment_data[MSFT_SEG_TYPEINFO] + offset);
507
508 typeinfo->typekind = (This->typelib_header.nrtypeinfos - 1) << 16;
509 typeinfo->memoffset = -1; /* should be EOF if no elements */
510 typeinfo->res2 = 0;
511 typeinfo->res3 = -1;
512 typeinfo->res4 = 3;
513 typeinfo->res5 = 0;
514 typeinfo->cElement = 0;
515 typeinfo->res7 = 0;
516 typeinfo->res8 = 0;
517 typeinfo->res9 = 0;
518 typeinfo->resA = 0;
519 typeinfo->posguid = -1;
520 typeinfo->flags = 0;
521 typeinfo->NameOffset = nameoffset;
522 typeinfo->version = 0;
523 typeinfo->docstringoffs = -1;
524 typeinfo->helpstringcontext = 0;
525 typeinfo->helpcontext = 0;
526 typeinfo->oCustData = -1;
527 typeinfo->cbSizeVft = 0;
528 typeinfo->cImplTypes = 0;
529 typeinfo->size = 0;
530 typeinfo->datatype1 = -1;
531 typeinfo->datatype2 = 0;
532 typeinfo->res18 = 0;
533 typeinfo->res19 = -1;
534
535 return offset;
536 }
537
538 /****************************************************************************
539 * ctl2_alloc_guid
540 *
541 * Allocates and initializes a GUID structure in a type library. Also updates
542 * the GUID hash table as needed.
543 *
544 * RETURNS
545 *
546 * Success: The offset of the new GUID.
547 * Failure: -1 (this is invariably an out of memory condition).
548 */
549 static int ctl2_alloc_guid(
550 ICreateTypeLib2Impl *This, /* [I] The type library to allocate in. */
551 MSFT_GuidEntry *guid) /* [I] The GUID to store. */
552 {
553 int offset;
554 MSFT_GuidEntry *guid_space;
555 int hash_key;
556
557 hash_key = ctl2_hash_guid(&guid->guid);
558
559 offset = ctl2_find_guid(This, hash_key, &guid->guid);
560 if (offset != -1) return offset;
561
562 offset = ctl2_alloc_segment(This, MSFT_SEG_GUID, sizeof(MSFT_GuidEntry), 0);
563 if (offset == -1) return -1;
564
565 guid_space = (void *)(This->typelib_segment_data[MSFT_SEG_GUID] + offset);
566 *guid_space = *guid;
567
568 guid_space->next_hash = This->typelib_guidhash_segment[hash_key];
569 This->typelib_guidhash_segment[hash_key] = offset;
570
571 return offset;
572 }
573
574 /****************************************************************************
575 * ctl2_alloc_name
576 *
577 * Allocates and initializes a name within a type library. Also updates the
578 * name hash table as needed.
579 *
580 * RETURNS
581 *
582 * Success: The offset within the segment of the new name.
583 * Failure: -1 (this is invariably an out of memory condition).
584 */
585 static int ctl2_alloc_name(
586 ICreateTypeLib2Impl *This, /* [I] The type library to allocate in. */
587 const WCHAR *name) /* [I] The name to store. */
588 {
589 int length;
590 int offset;
591 MSFT_NameIntro *name_space;
592 char *encoded_name;
593
594 length = ctl2_encode_name(This, name, &encoded_name);
595
596 offset = ctl2_find_name(This, encoded_name);
597 if (offset != -1) return offset;
598
599 offset = ctl2_alloc_segment(This, MSFT_SEG_NAME, length + 8, 0);
600 if (offset == -1) return -1;
601
602 name_space = (void *)(This->typelib_segment_data[MSFT_SEG_NAME] + offset);
603 name_space->hreftype = -1;
604 name_space->next_hash = -1;
605 memcpy(&name_space->namelen, encoded_name, length);
606
607 if (This->typelib_namehash_segment[encoded_name[2] & 0x7f] != -1)
608 name_space->next_hash = This->typelib_namehash_segment[encoded_name[2] & 0x7f];
609
610 This->typelib_namehash_segment[encoded_name[2] & 0x7f] = offset;
611
612 This->typelib_header.nametablecount += 1;
613 This->typelib_header.nametablechars += *encoded_name;
614
615 return offset;
616 }
617
618 /****************************************************************************
619 * ctl2_alloc_string
620 *
621 * Allocates and initializes a string in a type library.
622 *
623 * RETURNS
624 *
625 * Success: The offset within the segment of the new string.
626 * Failure: -1 (this is invariably an out of memory condition).
627 */
628 static int ctl2_alloc_string(
629 ICreateTypeLib2Impl *This, /* [I] The type library to allocate in. */
630 const WCHAR *string) /* [I] The string to store. */
631 {
632 int length;
633 int offset;
634 char *string_space;
635 char *encoded_string;
636
637 length = ctl2_encode_string(This, string, &encoded_string);
638
639 for (offset = 0; offset < This->typelib_segdir[MSFT_SEG_STRING].length;
640 offset += ((((This->typelib_segment_data[MSFT_SEG_STRING][offset + 1] << 8) & 0xff)
641 | (This->typelib_segment_data[MSFT_SEG_STRING][offset + 0] & 0xff)) + 5) & ~3) {
642 if (!memcmp(encoded_string, This->typelib_segment_data[MSFT_SEG_STRING] + offset, length)) return offset;
643 }
644
645 offset = ctl2_alloc_segment(This, MSFT_SEG_STRING, length, 0);
646 if (offset == -1) return -1;
647
648 string_space = This->typelib_segment_data[MSFT_SEG_STRING] + offset;
649 memcpy(string_space, encoded_string, length);
650
651 return offset;
652 }
653
654 /****************************************************************************
655 * ctl2_alloc_importinfo
656 *
657 * Allocates and initializes an import information structure in a type library.
658 *
659 * RETURNS
660 *
661 * Success: The offset of the new importinfo.
662 * Failure: -1 (this is invariably an out of memory condition).
663 */
664 static int ctl2_alloc_importinfo(
665 ICreateTypeLib2Impl *This, /* [I] The type library to allocate in. */
666 MSFT_ImpInfo *impinfo) /* [I] The import information to store. */
667 {
668 int offset;
669 MSFT_ImpInfo *impinfo_space;
670
671 for (offset = 0;
672 offset < This->typelib_segdir[MSFT_SEG_IMPORTINFO].length;
673 offset += sizeof(MSFT_ImpInfo)) {
674 if (!memcmp(&(This->typelib_segment_data[MSFT_SEG_IMPORTINFO][offset]),
675 impinfo, sizeof(MSFT_ImpInfo))) {
676 return offset;
677 }
678 }
679
680 impinfo->flags |= This->typelib_header.nimpinfos++;
681
682 offset = ctl2_alloc_segment(This, MSFT_SEG_IMPORTINFO, sizeof(MSFT_ImpInfo), 0);
683 if (offset == -1) return -1;
684
685 impinfo_space = (void *)(This->typelib_segment_data[MSFT_SEG_IMPORTINFO] + offset);
686 *impinfo_space = *impinfo;
687
688 return offset;
689 }
690
691 /****************************************************************************
692 * ctl2_alloc_importfile
693 *
694 * Allocates and initializes an import file definition in a type library.
695 *
696 * RETURNS
697 *
698 * Success: The offset of the new importinfo.
699 * Failure: -1 (this is invariably an out of memory condition).
700 */
701 static int ctl2_alloc_importfile(
702 ICreateTypeLib2Impl *This, /* [I] The type library to allocate in. */
703 int guidoffset, /* [I] The offset to the GUID for the imported library. */
704 int major_version, /* [I] The major version number of the imported library. */
705 int minor_version, /* [I] The minor version number of the imported library. */
706 const WCHAR *filename) /* [I] The filename of the imported library. */
707 {
708 int length;
709 int offset;
710 MSFT_ImpFile *importfile;
711 char *encoded_string;
712
713 length = ctl2_encode_string(This, filename, &encoded_string);
714
715 encoded_string[0] <<= 2;
716 encoded_string[0] |= 1;
717
718 for (offset = 0; offset < This->typelib_segdir[MSFT_SEG_IMPORTFILES].length;
719 offset += ((((This->typelib_segment_data[MSFT_SEG_IMPORTFILES][offset + 0xd] << 8) & 0xff)
720 | (This->typelib_segment_data[MSFT_SEG_IMPORTFILES][offset + 0xc] & 0xff)) >> 2) + 0xc) {
721 if (!memcmp(encoded_string, This->typelib_segment_data[MSFT_SEG_IMPORTFILES] + offset + 0xc, length)) return offset;
722 }
723
724 offset = ctl2_alloc_segment(This, MSFT_SEG_IMPORTFILES, length + 0xc, 0);
725 if (offset == -1) return -1;
726
727 importfile = (MSFT_ImpFile *)&This->typelib_segment_data[MSFT_SEG_IMPORTFILES][offset];
728 importfile->guid = guidoffset;
729 importfile->lcid = This->typelib_header.lcid2;
730 importfile->version = major_version | (minor_version << 16);
731 memcpy(importfile->filename, encoded_string, length);
732
733 return offset;
734 }
735
736 /****************************************************************************
737 * ctl2_alloc_custdata
738 *
739 * Allocates and initializes a "custom data" value in a type library.
740 *
741 * RETURNS
742 *
743 * Success: The offset of the new custdata.
744 * Failure:
745 *
746 * -1: Out of memory.
747 * -2: Unable to encode VARIANT data (typically a bug).
748 */
749 static int ctl2_alloc_custdata(
750 ICreateTypeLib2Impl *This, /* [I] The type library in which to encode the value. */
751 VARIANT *pVarVal) /* [I] The value to encode. */
752 {
753 int offset;
754
755 TRACE("(%p,%p(%d))\n",This,pVarVal,V_VT(pVarVal));
756
757 switch (V_VT(pVarVal)) {
758 case VT_UI4:
759 offset = ctl2_alloc_segment(This, MSFT_SEG_CUSTDATA, 8, 0);
760 if (offset == -1) return offset;
761
762 *((unsigned short *)&This->typelib_segment_data[MSFT_SEG_CUSTDATA][offset]) = VT_UI4;
763 *((unsigned long *)&This->typelib_segment_data[MSFT_SEG_CUSTDATA][offset+2]) = V_UI4(pVarVal);
764 break;
765
766 default:
767 FIXME("Unknown variable encoding vt %d.\n", V_VT(pVarVal));
768 return -2;
769 }
770
771 return offset;
772 }
773
774 /****************************************************************************
775 * ctl2_set_custdata
776 *
777 * Adds a custom data element to an object in a type library.
778 *
779 * RETURNS
780 *
781 * Success: S_OK.
782 * Failure: One of E_INVALIDARG or E_OUTOFMEMORY.
783 */
784 static HRESULT ctl2_set_custdata(
785 ICreateTypeLib2Impl *This, /* [I] The type library to store the custom data in. */
786 REFGUID guid, /* [I] The GUID used as a key to retrieve the custom data. */
787 VARIANT *pVarVal, /* [I] The custom data itself. */
788 int *offset) /* [I/O] The list of custom data to prepend to. */
789 {
790 MSFT_GuidEntry guidentry;
791 int dataoffset;
792 int guidoffset;
793 int custoffset;
794 int *custdata;
795
796 guidentry.guid = *guid;
797
798 guidentry.hreftype = -1;
799 guidentry.next_hash = -1;
800
801 guidoffset = ctl2_alloc_guid(This, &guidentry);
802 if (guidoffset == -1) return E_OUTOFMEMORY;
803 dataoffset = ctl2_alloc_custdata(This, pVarVal);
804 if (dataoffset == -1) return E_OUTOFMEMORY;
805 if (dataoffset == -2) return E_INVALIDARG;
806
807 custoffset = ctl2_alloc_segment(This, MSFT_SEG_CUSTDATAGUID, 12, 0);
808 if (custoffset == -1) return E_OUTOFMEMORY;
809
810 custdata = (int *)&This->typelib_segment_data[MSFT_SEG_CUSTDATAGUID][custoffset];
811 custdata[0] = guidoffset;
812 custdata[1] = dataoffset;
813 custdata[2] = *offset;
814 *offset = custoffset;
815
816 return S_OK;
817 }
818
819 /****************************************************************************
820 * ctl2_encode_typedesc
821 *
822 * Encodes a type description, storing information in the TYPEDESC and ARRAYDESC
823 * segments as needed.
824 *
825 * RETURNS
826 *
827 * Success: 0.
828 * Failure: -1.
829 */
830 static int ctl2_encode_typedesc(
831 ICreateTypeLib2Impl *This, /* [I] The type library in which to encode the TYPEDESC. */
832 const TYPEDESC *tdesc, /* [I] The type description to encode. */
833 int *encoded_tdesc, /* [O] The encoded type description. */
834 int *width, /* [O] The width of the type, or NULL. */
835 int *alignment, /* [O] The alignment of the type, or NULL. */
836 int *decoded_size) /* [O] The total size of the unencoded TYPEDESCs, including nested descs. */
837 {
838 int default_tdesc;
839 int scratch;
840 int typeoffset;
841 int arrayoffset;
842 int *typedata;
843 int *arraydata;
844 int target_type;
845 int child_size;
846
847 default_tdesc = 0x80000000 | (tdesc->vt << 16) | tdesc->vt;
848 if (!width) width = &scratch;
849 if (!alignment) alignment = &scratch;
850 if (!decoded_size) decoded_size = &scratch;
851
852 *decoded_size = 0;
853
854 switch (tdesc->vt) {
855 case VT_UI1:
856 case VT_I1:
857 *encoded_tdesc = default_tdesc;
858 *width = 1;
859 *alignment = 1;
860 break;
861
862 case VT_INT:
863 *encoded_tdesc = 0x80000000 | (VT_I4 << 16) | VT_INT;
864 if ((This->typelib_header.varflags & 0x0f) == SYS_WIN16) {
865 *width = 2;
866 *alignment = 2;
867 } else {
868 *width = 4;
869 *alignment = 4;
870 }
871 break;
872
873 case VT_UINT:
874 *encoded_tdesc = 0x80000000 | (VT_UI4 << 16) | VT_UINT;
875 if ((This->typelib_header.varflags & 0x0f) == SYS_WIN16) {
876 *width = 2;
877 *alignment = 2;
878 } else {
879 *width = 4;
880 *alignment = 4;
881 }
882 break;
883
884 case VT_UI2:
885 case VT_I2:
886 case VT_BOOL:
887 *encoded_tdesc = default_tdesc;
888 *width = 2;
889 *alignment = 2;
890 break;
891
892 case VT_I4:
893 case VT_UI4:
894 case VT_R4:
895 case VT_ERROR:
896 case VT_BSTR:
897 case VT_HRESULT:
898 *encoded_tdesc = default_tdesc;
899 *width = 4;
900 *alignment = 4;
901 break;
902
903 case VT_CY:
904 *encoded_tdesc = default_tdesc;
905 *width = 8;
906 *alignment = 4; /* guess? */
907 break;
908
909 case VT_VOID:
910 *encoded_tdesc = 0x80000000 | (VT_EMPTY << 16) | tdesc->vt;
911 *width = 0;
912 *alignment = 1;
913 break;
914
915 case VT_PTR:
916 /* FIXME: Make with the error checking. */
917 FIXME("PTR vartype, may not work correctly.\n");
918
919 ctl2_encode_typedesc(This, tdesc->u.lptdesc, &target_type, NULL, NULL, &child_size);
920
921 for (typeoffset = 0; typeoffset < This->typelib_segdir[MSFT_SEG_TYPEDESC].length; typeoffset += 8) {
922 typedata = (void *)&This->typelib_segment_data[MSFT_SEG_TYPEDESC][typeoffset];
923 if (((typedata[0] & 0xffff) == VT_PTR) && (typedata[1] == target_type)) break;
924 }
925
926 if (typeoffset == This->typelib_segdir[MSFT_SEG_TYPEDESC].length) {
927 int mix_field;
928
929 if (target_type & 0x80000000) {
930 mix_field = ((target_type >> 16) & 0x3fff) | VT_BYREF;
931 } else {
932 typedata = (void *)&This->typelib_segment_data[MSFT_SEG_TYPEDESC][target_type];
933 mix_field = ((typedata[0] >> 16) == 0x7fff)? 0x7fff: 0x7ffe;
934 }
935
936 typeoffset = ctl2_alloc_segment(This, MSFT_SEG_TYPEDESC, 8, 0);
937 typedata = (void *)&This->typelib_segment_data[MSFT_SEG_TYPEDESC][typeoffset];
938
939 typedata[0] = (mix_field << 16) | VT_PTR;
940 typedata[1] = target_type;
941 }
942
943 *encoded_tdesc = typeoffset;
944
945 *width = 4;
946 *alignment = 4;
947 *decoded_size = sizeof(TYPEDESC) + child_size;
948 break;
949
950 case VT_SAFEARRAY:
951 /* FIXME: Make with the error checking. */
952 FIXME("SAFEARRAY vartype, may not work correctly.\n");
953
954 ctl2_encode_typedesc(This, tdesc->u.lptdesc, &target_type, NULL, NULL, &child_size);
955
956 for (typeoffset = 0; typeoffset < This->typelib_segdir[MSFT_SEG_TYPEDESC].length; typeoffset += 8) {
957 typedata = (void *)&This->typelib_segment_data[MSFT_SEG_TYPEDESC][typeoffset];
958 if (((typedata[0] & 0xffff) == VT_SAFEARRAY) && (typedata[1] == target_type)) break;
959 }
960
961 if (typeoffset == This->typelib_segdir[MSFT_SEG_TYPEDESC].length) {
962 int mix_field;
963
964 if (target_type & 0x80000000) {
965 mix_field = ((target_type >> 16) & VT_TYPEMASK) | VT_ARRAY;